74fcdb9a62
The service channel D-Bus interface aims to be a "back door" for services that needs special casing in Mutter, e.g. have custom private protocols only meant to be used by that particular service. There are currently no special casing implemented; only the basic service channel infrastructure is added. There is a single method on the interface, that is meant to eventually be used by xdg-desktop-portal-gnome to open a Wayland connection with a private protocol needed for the portal backend's rather special window management needs. The service channel Wayland client works by allowing one instance of each "type", where each time needs to be defined to work in parallel. If a new service client connects, the old one will be disconnected. MetaWaylandClient's are used to manage the service clients, and are assigned the service client type. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2810>
816 lines
21 KiB
C
816 lines
21 KiB
C
/*
|
|
* Copyright (C) 2019 Red Hat Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
* 02111-1307, USA.
|
|
*
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "core/meta-context-private.h"
|
|
|
|
#include <locale.h>
|
|
#include <sys/resource.h>
|
|
|
|
#include "backends/meta-backend-private.h"
|
|
#include "compositor/meta-plugin-manager.h"
|
|
#include "core/display-private.h"
|
|
#include "core/meta-service-channel.h"
|
|
#include "core/prefs-private.h"
|
|
#include "core/util-private.h"
|
|
|
|
#ifdef HAVE_PROFILER
|
|
#include "core/meta-profiler.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_WAYLAND
|
|
#include "wayland/meta-wayland.h"
|
|
#endif
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
|
|
PROP_NAME,
|
|
PROP_UNSAFE_MODE,
|
|
|
|
N_PROPS
|
|
};
|
|
|
|
static GParamSpec *obj_props[N_PROPS];
|
|
|
|
enum
|
|
{
|
|
STARTED,
|
|
PREPARE_SHUTDOWN,
|
|
|
|
N_SIGNALS
|
|
};
|
|
|
|
static guint signals[N_SIGNALS];
|
|
|
|
typedef enum _MetaContextState
|
|
{
|
|
META_CONTEXT_STATE_INIT,
|
|
META_CONTEXT_STATE_CONFIGURED,
|
|
META_CONTEXT_STATE_SETUP,
|
|
META_CONTEXT_STATE_STARTED,
|
|
META_CONTEXT_STATE_RUNNING,
|
|
META_CONTEXT_STATE_TERMINATED,
|
|
} MetaContextState;
|
|
|
|
typedef struct _MetaContextPrivate
|
|
{
|
|
char *name;
|
|
char *plugin_name;
|
|
GType plugin_gtype;
|
|
char *gnome_wm_keybindings;
|
|
|
|
gboolean unsafe_mode;
|
|
|
|
MetaContextState state;
|
|
|
|
GOptionContext *option_context;
|
|
|
|
MetaBackend *backend;
|
|
MetaDisplay *display;
|
|
#ifdef HAVE_WAYLAND
|
|
MetaWaylandCompositor *wayland_compositor;
|
|
#endif
|
|
|
|
GMainLoop *main_loop;
|
|
GError *termination_error;
|
|
#ifdef RLIMIT_NOFILE
|
|
struct rlimit saved_rlimit_nofile;
|
|
#endif
|
|
|
|
#ifdef HAVE_PROFILER
|
|
MetaProfiler *profiler;
|
|
#endif
|
|
|
|
#ifdef HAVE_WAYLAND
|
|
MetaServiceChannel *service_channel;
|
|
#endif
|
|
} MetaContextPrivate;
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (MetaContext, meta_context, G_TYPE_OBJECT)
|
|
|
|
/**
|
|
* meta_context_add_option_entries:
|
|
* @context: a #MetaContext
|
|
* @entries: (array zero-terminated=1): a %NULL-terminated array of #GOptionEntrys
|
|
* @translation_domain: (nullable): a translation domain to use, or %NULL
|
|
*
|
|
* See g_option_context_add_main_entries() for more details.
|
|
**/
|
|
void
|
|
meta_context_add_option_entries (MetaContext *context,
|
|
const GOptionEntry *entries,
|
|
const char *translation_domain)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
g_warn_if_fail (priv->state == META_CONTEXT_STATE_INIT);
|
|
|
|
g_option_context_add_main_entries (priv->option_context,
|
|
entries,
|
|
translation_domain);
|
|
}
|
|
|
|
/**
|
|
* meta_context_add_option_group:
|
|
* @context: a #MetaContext
|
|
* @group: (transfer full): the group to add
|
|
*
|
|
* See g_option_context_add_group() for more details.
|
|
**/
|
|
void
|
|
meta_context_add_option_group (MetaContext *context,
|
|
GOptionGroup *group)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
g_warn_if_fail (priv->state == META_CONTEXT_STATE_INIT);
|
|
g_return_if_fail (priv->option_context);
|
|
|
|
g_option_context_add_group (priv->option_context, group);
|
|
}
|
|
|
|
void
|
|
meta_context_set_plugin_gtype (MetaContext *context,
|
|
GType plugin_gtype)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
g_return_if_fail (priv->state <= META_CONTEXT_STATE_CONFIGURED);
|
|
g_return_if_fail (!priv->plugin_name);
|
|
|
|
priv->plugin_gtype = plugin_gtype;
|
|
}
|
|
|
|
void
|
|
meta_context_set_plugin_name (MetaContext *context,
|
|
const char *plugin_name)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
g_return_if_fail (priv->state <= META_CONTEXT_STATE_CONFIGURED);
|
|
g_return_if_fail (priv->plugin_gtype == G_TYPE_NONE);
|
|
|
|
priv->plugin_name = g_strdup (plugin_name);
|
|
}
|
|
|
|
void
|
|
meta_context_set_gnome_wm_keybindings (MetaContext *context,
|
|
const char *wm_keybindings)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
g_return_if_fail (priv->state <= META_CONTEXT_STATE_CONFIGURED);
|
|
|
|
g_clear_pointer (&priv->gnome_wm_keybindings, g_free);
|
|
priv->gnome_wm_keybindings = g_strdup (wm_keybindings);
|
|
}
|
|
|
|
const char *
|
|
meta_context_get_gnome_wm_keybindings (MetaContext *context)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
return priv->gnome_wm_keybindings;
|
|
}
|
|
|
|
void
|
|
meta_context_notify_ready (MetaContext *context)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
g_return_if_fail (priv->state == META_CONTEXT_STATE_STARTED ||
|
|
priv->state == META_CONTEXT_STATE_RUNNING);
|
|
|
|
META_CONTEXT_GET_CLASS (context)->notify_ready (context);
|
|
}
|
|
|
|
const char *
|
|
meta_context_get_name (MetaContext *context)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
return priv->name;
|
|
}
|
|
|
|
/**
|
|
* meta_context_get_backend:
|
|
* @context: The #MetaContext
|
|
*
|
|
* Returns: (transfer none): the #MetaBackend
|
|
*/
|
|
MetaBackend *
|
|
meta_context_get_backend (MetaContext *context)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
return priv->backend;
|
|
}
|
|
|
|
/**
|
|
* meta_context_get_display:
|
|
* @context: The #MetaContext
|
|
*
|
|
* Returns: (transfer none): the #MetaDisplay
|
|
*/
|
|
MetaDisplay *
|
|
meta_context_get_display (MetaContext *context)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
return priv->display;
|
|
}
|
|
|
|
#ifdef HAVE_WAYLAND
|
|
MetaWaylandCompositor *
|
|
meta_context_get_wayland_compositor (MetaContext *context)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
return priv->wayland_compositor;
|
|
}
|
|
|
|
MetaServiceChannel *
|
|
meta_context_get_service_channel (MetaContext *context)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
return priv->service_channel;
|
|
}
|
|
#endif
|
|
|
|
MetaCompositorType
|
|
meta_context_get_compositor_type (MetaContext *context)
|
|
{
|
|
return META_CONTEXT_GET_CLASS (context)->get_compositor_type (context);
|
|
}
|
|
|
|
gboolean
|
|
meta_context_is_replacing (MetaContext *context)
|
|
{
|
|
return META_CONTEXT_GET_CLASS (context)->is_replacing (context);
|
|
}
|
|
|
|
MetaX11DisplayPolicy
|
|
meta_context_get_x11_display_policy (MetaContext *context)
|
|
{
|
|
return META_CONTEXT_GET_CLASS (context)->get_x11_display_policy (context);
|
|
}
|
|
|
|
#ifdef HAVE_X11
|
|
gboolean
|
|
meta_context_is_x11_sync (MetaContext *context)
|
|
{
|
|
return META_CONTEXT_GET_CLASS (context)->is_x11_sync (context);
|
|
}
|
|
#endif
|
|
|
|
static gboolean
|
|
meta_context_real_configure (MetaContext *context,
|
|
int *argc,
|
|
char ***argv,
|
|
GError **error)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
g_autoptr (GOptionContext) option_context = NULL;
|
|
|
|
if (!priv->option_context)
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"Tried to configure multiple times");
|
|
return FALSE;
|
|
}
|
|
|
|
option_context = g_steal_pointer (&priv->option_context);
|
|
return g_option_context_parse (option_context, argc, argv, error);
|
|
}
|
|
|
|
/**
|
|
* meta_context_configure:
|
|
* @context: a #MetaContext
|
|
* @argc: (inout): Address of the `argc` parameter of your main() function (or 0
|
|
* if @argv is %NULL).
|
|
* @argv: (array length=argc) (inout) (nullable): Address of the`argv` parameter
|
|
* of main(), or %NULL.
|
|
* @error: a return location for errors
|
|
*
|
|
* Returns: %TRUE if the commandline arguments (if any) were valid and if the
|
|
* configuration has been successfull, %FALSE otherwise
|
|
*/
|
|
gboolean
|
|
meta_context_configure (MetaContext *context,
|
|
int *argc,
|
|
char ***argv,
|
|
GError **error)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
MetaCompositorType compositor_type;
|
|
|
|
g_warn_if_fail (priv->state == META_CONTEXT_STATE_INIT);
|
|
|
|
if (!META_CONTEXT_GET_CLASS (context)->configure (context, argc, argv, error))
|
|
{
|
|
priv->state = META_CONTEXT_STATE_TERMINATED;
|
|
return FALSE;
|
|
}
|
|
|
|
compositor_type = meta_context_get_compositor_type (context);
|
|
switch (compositor_type)
|
|
{
|
|
case META_COMPOSITOR_TYPE_WAYLAND:
|
|
meta_set_is_wayland_compositor (TRUE);
|
|
break;
|
|
case META_COMPOSITOR_TYPE_X11:
|
|
meta_set_is_wayland_compositor (FALSE);
|
|
break;
|
|
}
|
|
|
|
priv->state = META_CONTEXT_STATE_CONFIGURED;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static const char *
|
|
compositor_type_to_description (MetaCompositorType compositor_type)
|
|
{
|
|
switch (compositor_type)
|
|
{
|
|
case META_COMPOSITOR_TYPE_WAYLAND:
|
|
return "Wayland display server";
|
|
case META_COMPOSITOR_TYPE_X11:
|
|
return "X11 window and compositing manager";
|
|
}
|
|
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
static void
|
|
init_introspection (MetaContext *context)
|
|
{
|
|
#ifdef HAVE_INTROSPECTION
|
|
g_irepository_prepend_search_path (MUTTER_PKGLIBDIR);
|
|
#endif
|
|
}
|
|
|
|
static gboolean
|
|
meta_context_real_setup (MetaContext *context,
|
|
GError **error)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
MetaBackend *backend;
|
|
|
|
backend = META_CONTEXT_GET_CLASS (context)->create_backend (context, error);
|
|
if (!backend)
|
|
return FALSE;
|
|
|
|
priv->backend = backend;
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
meta_context_setup (MetaContext *context,
|
|
GError **error)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
MetaCompositorType compositor_type;
|
|
|
|
g_warn_if_fail (priv->state == META_CONTEXT_STATE_CONFIGURED);
|
|
|
|
if (!priv->plugin_name && priv->plugin_gtype == G_TYPE_NONE)
|
|
{
|
|
priv->state = META_CONTEXT_STATE_TERMINATED;
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"No compositor plugin set");
|
|
return FALSE;
|
|
}
|
|
|
|
meta_init_debug_utils ();
|
|
|
|
compositor_type = meta_context_get_compositor_type (context);
|
|
g_message ("Running %s (using mutter %s) as a %s",
|
|
priv->name, VERSION,
|
|
compositor_type_to_description (compositor_type));
|
|
|
|
if (priv->plugin_name)
|
|
meta_plugin_manager_load (priv->plugin_name);
|
|
else
|
|
meta_plugin_manager_set_plugin_type (priv->plugin_gtype);
|
|
|
|
init_introspection (context);
|
|
|
|
if (!META_CONTEXT_GET_CLASS (context)->setup (context, error))
|
|
{
|
|
priv->state = META_CONTEXT_STATE_TERMINATED;
|
|
return FALSE;
|
|
}
|
|
|
|
priv->state = META_CONTEXT_STATE_SETUP;
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
meta_context_start (MetaContext *context,
|
|
GError **error)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
g_warn_if_fail (priv->state == META_CONTEXT_STATE_SETUP);
|
|
|
|
meta_prefs_init ();
|
|
|
|
#ifdef HAVE_WAYLAND
|
|
if (meta_context_get_compositor_type (context) ==
|
|
META_COMPOSITOR_TYPE_WAYLAND)
|
|
priv->wayland_compositor = meta_wayland_compositor_new (context);
|
|
#endif
|
|
|
|
priv->display = meta_display_new (context, error);
|
|
if (!priv->display)
|
|
{
|
|
priv->state = META_CONTEXT_STATE_TERMINATED;
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef HAVE_WAYLAND
|
|
priv->service_channel = meta_service_channel_new (context);
|
|
#endif
|
|
|
|
priv->main_loop = g_main_loop_new (NULL, FALSE);
|
|
|
|
priv->state = META_CONTEXT_STATE_STARTED;
|
|
|
|
g_signal_emit (context, signals[STARTED], 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
meta_context_run_main_loop (MetaContext *context,
|
|
GError **error)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
g_warn_if_fail (priv->state == META_CONTEXT_STATE_STARTED);
|
|
if (!priv->main_loop)
|
|
{
|
|
priv->state = META_CONTEXT_STATE_TERMINATED;
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"Tried to run main loop without having started");
|
|
return FALSE;
|
|
}
|
|
|
|
priv->state = META_CONTEXT_STATE_RUNNING;
|
|
g_main_loop_run (priv->main_loop);
|
|
priv->state = META_CONTEXT_STATE_TERMINATED;
|
|
g_clear_pointer (&priv->main_loop, g_main_loop_unref);
|
|
|
|
if (priv->termination_error)
|
|
{
|
|
g_propagate_error (error, g_steal_pointer (&priv->termination_error));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
meta_context_terminate (MetaContext *context)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
g_warn_if_fail (priv->state == META_CONTEXT_STATE_RUNNING);
|
|
g_warn_if_fail (g_main_loop_is_running (priv->main_loop));
|
|
|
|
g_main_loop_quit (priv->main_loop);
|
|
}
|
|
|
|
void
|
|
meta_context_terminate_with_error (MetaContext *context,
|
|
GError *error)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
priv->termination_error = g_steal_pointer (&error);
|
|
meta_context_terminate (context);
|
|
}
|
|
|
|
void
|
|
meta_context_destroy (MetaContext *context)
|
|
{
|
|
g_object_run_dispose (G_OBJECT (context));
|
|
g_object_unref (context);
|
|
}
|
|
|
|
gboolean
|
|
meta_context_get_unsafe_mode (MetaContext *context)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
return priv->unsafe_mode;
|
|
}
|
|
|
|
void
|
|
meta_context_set_unsafe_mode (MetaContext *context,
|
|
gboolean enable)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
if (priv->unsafe_mode == enable)
|
|
return;
|
|
|
|
priv->unsafe_mode = enable;
|
|
g_object_notify_by_pspec (G_OBJECT (context), obj_props[PROP_UNSAFE_MODE]);
|
|
}
|
|
|
|
static gboolean
|
|
meta_context_save_rlimit_nofile (MetaContext *context,
|
|
GError **error)
|
|
{
|
|
#ifdef RLIMIT_NOFILE
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
if (getrlimit (RLIMIT_NOFILE, &priv->saved_rlimit_nofile) != 0)
|
|
{
|
|
priv->saved_rlimit_nofile.rlim_cur = 0;
|
|
priv->saved_rlimit_nofile.rlim_max = 0;
|
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
|
"getrlimit failed: %s", g_strerror (errno));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
#else
|
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOSYS,
|
|
"Missing support for RLIMIT_NOFILE");
|
|
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* meta_context_raise_rlimit_nofile:
|
|
* @context: a #MetaContext
|
|
* @error: a return location for errors
|
|
*
|
|
* Raises the RLIMIT_NOFILE limit value to the hard limit.
|
|
*/
|
|
gboolean
|
|
meta_context_raise_rlimit_nofile (MetaContext *context,
|
|
GError **error)
|
|
{
|
|
#ifdef RLIMIT_NOFILE
|
|
struct rlimit new_rlimit;
|
|
|
|
if (getrlimit (RLIMIT_NOFILE, &new_rlimit) != 0)
|
|
{
|
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
|
"getrlimit failed: %s", g_strerror (errno));
|
|
return FALSE;
|
|
}
|
|
|
|
/* Raise the rlimit_nofile value to the hard limit */
|
|
new_rlimit.rlim_cur = new_rlimit.rlim_max;
|
|
|
|
if (setrlimit (RLIMIT_NOFILE, &new_rlimit) != 0)
|
|
{
|
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
|
"setrlimit failed: %s", g_strerror (errno));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
#else
|
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOSYS,
|
|
"Missing support for RLIMIT_NOFILE");
|
|
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* meta_context_restore_rlimit_nofile:
|
|
* @context: a #MetaContext
|
|
* @error: a return location for errors
|
|
*
|
|
* Restores the RLIMIT_NOFILE limits from when the #MetaContext was created.
|
|
*/
|
|
gboolean
|
|
meta_context_restore_rlimit_nofile (MetaContext *context,
|
|
GError **error)
|
|
{
|
|
#ifdef RLIMIT_NOFILE
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
if (priv->saved_rlimit_nofile.rlim_cur == 0)
|
|
{
|
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT,
|
|
"RLIMIT_NOFILE not saved");
|
|
return FALSE;
|
|
}
|
|
|
|
if (setrlimit (RLIMIT_NOFILE, &priv->saved_rlimit_nofile) != 0)
|
|
{
|
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
|
"setrlimit failed: %s", g_strerror (errno));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
#else
|
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOSYS,
|
|
"Missing support for RLIMIT_NOFILE");
|
|
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
meta_context_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
MetaContext *context = META_CONTEXT (object);
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_NAME:
|
|
g_value_set_string (value, priv->name);
|
|
break;
|
|
case PROP_UNSAFE_MODE:
|
|
g_value_set_boolean (value, priv->unsafe_mode);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
meta_context_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
MetaContext *context = META_CONTEXT (object);
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_NAME:
|
|
priv->name = g_value_dup_string (value);
|
|
break;
|
|
case PROP_UNSAFE_MODE:
|
|
meta_context_set_unsafe_mode (META_CONTEXT (object),
|
|
g_value_get_boolean (value));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
meta_context_dispose (GObject *object)
|
|
{
|
|
MetaContext *context = META_CONTEXT (object);
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
g_signal_emit (context, signals[PREPARE_SHUTDOWN], 0);
|
|
|
|
#ifdef HAVE_WAYLAND
|
|
g_clear_object (&priv->service_channel);
|
|
|
|
if (priv->wayland_compositor)
|
|
meta_wayland_compositor_prepare_shutdown (priv->wayland_compositor);
|
|
#endif
|
|
|
|
if (priv->display)
|
|
meta_display_close (priv->display, META_CURRENT_TIME);
|
|
g_clear_object (&priv->display);
|
|
|
|
#ifdef HAVE_WAYLAND
|
|
g_clear_object (&priv->wayland_compositor);
|
|
#endif
|
|
|
|
g_clear_pointer (&priv->backend, meta_backend_destroy);
|
|
|
|
g_clear_pointer (&priv->option_context, g_option_context_free);
|
|
g_clear_pointer (&priv->main_loop, g_main_loop_unref);
|
|
|
|
G_OBJECT_CLASS (meta_context_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
meta_context_finalize (GObject *object)
|
|
{
|
|
MetaContext *context = META_CONTEXT (object);
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
#ifdef HAVE_PROFILER
|
|
g_clear_object (&priv->profiler);
|
|
#endif
|
|
|
|
g_clear_pointer (&priv->gnome_wm_keybindings, g_free);
|
|
g_clear_pointer (&priv->plugin_name, g_free);
|
|
g_clear_pointer (&priv->name, g_free);
|
|
|
|
G_OBJECT_CLASS (meta_context_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
meta_context_class_init (MetaContextClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->get_property = meta_context_get_property;
|
|
object_class->set_property = meta_context_set_property;
|
|
object_class->dispose = meta_context_dispose;
|
|
object_class->finalize = meta_context_finalize;
|
|
|
|
klass->configure = meta_context_real_configure;
|
|
klass->setup = meta_context_real_setup;
|
|
|
|
obj_props[PROP_NAME] =
|
|
g_param_spec_string ("name",
|
|
"name",
|
|
"Human readable name",
|
|
NULL,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
obj_props[PROP_UNSAFE_MODE] =
|
|
g_param_spec_boolean ("unsafe-mode",
|
|
"unsafe mode",
|
|
"Unsafe mode",
|
|
FALSE,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_EXPLICIT_NOTIFY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
g_object_class_install_properties (object_class, N_PROPS, obj_props);
|
|
|
|
signals[STARTED] =
|
|
g_signal_new ("started",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
0,
|
|
NULL, NULL, NULL,
|
|
G_TYPE_NONE, 0);
|
|
signals[PREPARE_SHUTDOWN] =
|
|
g_signal_new ("prepare-shutdown",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
0,
|
|
NULL, NULL, NULL,
|
|
G_TYPE_NONE, 0);
|
|
}
|
|
|
|
static void
|
|
meta_context_init (MetaContext *context)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
#ifdef HAVE_PROFILER
|
|
priv->profiler = meta_profiler_new ();
|
|
#endif
|
|
|
|
priv->plugin_gtype = G_TYPE_NONE;
|
|
priv->gnome_wm_keybindings = g_strdup ("Mutter");
|
|
|
|
if (!setlocale (LC_ALL, ""))
|
|
g_warning ("Locale not understood by C library");
|
|
bindtextdomain (GETTEXT_PACKAGE, MUTTER_LOCALEDIR);
|
|
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
|
|
|
priv->option_context = g_option_context_new (NULL);
|
|
g_option_context_set_main_group (priv->option_context,
|
|
g_option_group_new (NULL, NULL, NULL,
|
|
context, NULL));
|
|
|
|
if (!meta_context_save_rlimit_nofile (context, &error))
|
|
{
|
|
if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOSYS))
|
|
g_warning ("Failed to save the nofile limit: %s", error->message);
|
|
}
|
|
}
|