
The debug controller can optionally, when passing --debug-control, enable manipulating debug state, so far enabling/disabling HDR, via D-Bus. It's always created, in order to have a place to store debug state and emit signals etc when it changes, but so far, it doesn't have its own state it tracks, it just mirrors that of the monitor manager. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3432>
860 lines
22 KiB
C
860 lines
22 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#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
|
|
char *trace_file;
|
|
MetaProfiler *profiler;
|
|
#endif
|
|
|
|
#ifdef HAVE_WAYLAND
|
|
MetaServiceChannel *service_channel;
|
|
#endif
|
|
|
|
MetaDebugControl *debug_control;
|
|
} 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
|
|
/**
|
|
* meta_context_get_wayland_compositor:
|
|
* @context: The #MetaContext
|
|
*
|
|
* Get the #MetaWaylandCompositor associated with the MetaContext. The might be
|
|
* none currently associated if the context hasn't been started or if the
|
|
* requested compositor type is not %META_COMPOSITOR_TYPE_WAYLAND.
|
|
*
|
|
* Returns: (transfer none) (nullable): the #MetaWaylandCompositor
|
|
*/
|
|
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
|
|
|
|
#ifdef HAVE_PROFILER
|
|
MetaProfiler *
|
|
meta_context_get_profiler (MetaContext *context)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
return priv->profiler;
|
|
}
|
|
|
|
void
|
|
meta_context_set_trace_file (MetaContext *context,
|
|
const char *trace_file)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
priv->trace_file = g_strdup (trace_file);
|
|
}
|
|
#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);
|
|
if (!g_option_context_parse (option_context, argc, argv, error))
|
|
return FALSE;
|
|
|
|
priv->debug_control = g_object_new (META_TYPE_DEBUG_CONTROL,
|
|
"context", context,
|
|
NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* 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 successful, %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;
|
|
}
|
|
|
|
#ifdef HAVE_PROFILER
|
|
priv->profiler = meta_profiler_new (priv->trace_file);
|
|
#endif
|
|
|
|
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_object (&priv->debug_control);
|
|
|
|
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);
|
|
g_clear_pointer (&priv->trace_file, g_free);
|
|
#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", NULL, NULL,
|
|
NULL,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
obj_props[PROP_UNSAFE_MODE] =
|
|
g_param_spec_boolean ("unsafe-mode", NULL, NULL,
|
|
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;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
MetaDebugControl *
|
|
meta_context_get_debug_control (MetaContext *context)
|
|
{
|
|
MetaContextPrivate *priv = meta_context_get_instance_private (context);
|
|
|
|
return priv->debug_control;
|
|
}
|