diff --git a/src/core/meta-launch-context.c b/src/core/meta-launch-context.c new file mode 100644 index 000000000..d70f5a5e7 --- /dev/null +++ b/src/core/meta-launch-context.c @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2018 Red Hat + * + * 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. + * + * Author: Carlos Garnacho + */ + +#include "config.h" + +#include + +#include "core/display-private.h" +#include "meta/meta-launch-context.h" +#include "x11/meta-startup-notification-x11.h" + +typedef struct _MetaLaunchContext MetaLaunchContext; + +struct _MetaLaunchContext +{ + GAppLaunchContext parent_instance; + MetaDisplay *display; + MetaWorkspace *workspace; + uint32_t timestamp; +}; + +G_DEFINE_TYPE (MetaLaunchContext, meta_launch_context, + G_TYPE_APP_LAUNCH_CONTEXT) + +enum +{ + PROP_DISPLAY = 1, + PROP_WORKSPACE, + PROP_TIMESTAMP, + N_PROPS +}; + +static GParamSpec *props[N_PROPS] = { 0, }; + +static void +meta_launch_context_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaLaunchContext *context = META_LAUNCH_CONTEXT (object); + + switch (prop_id) + { + case PROP_DISPLAY: + context->display = g_value_get_object (value); + break; + case PROP_WORKSPACE: + meta_launch_context_set_workspace (context, + g_value_get_object (value)); + break; + case PROP_TIMESTAMP: + meta_launch_context_set_timestamp (context, + g_value_get_uint (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_launch_context_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MetaLaunchContext *context = META_LAUNCH_CONTEXT (object); + + switch (prop_id) + { + case PROP_DISPLAY: + g_value_set_object (value, context->display); + break; + case PROP_WORKSPACE: + g_value_set_object (value, context->workspace); + break; + case PROP_TIMESTAMP: + g_value_set_uint (value, context->timestamp); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_launch_context_finalize (GObject *object) +{ + G_OBJECT_CLASS (meta_launch_context_parent_class)->finalize (object); +} + +static void +meta_launch_context_constructed (GObject *object) +{ + MetaLaunchContext *context = META_LAUNCH_CONTEXT (object); + + G_OBJECT_CLASS (meta_launch_context_parent_class)->constructed (object); + + g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (context), + "DISPLAY", getenv ("DISPLAY")); + g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (context), + "WAYLAND_DISPLAY", getenv ("WAYLAND_DISPLAY")); +} + +static gchar * +meta_launch_context_get_startup_notify_id (GAppLaunchContext *launch_context, + GAppInfo *info, + GList *files) +{ + MetaLaunchContext *context = META_LAUNCH_CONTEXT (launch_context); + MetaDisplay *display = context->display; + int workspace_idx = -1; + gchar *startup_id; + + if (context->workspace) + workspace_idx = meta_workspace_index (context->workspace); + + if (display->x11_display) + { + /* If there is a X11 display, we prefer going entirely through + * libsn, as SnMonitor expects to keep a view of the full lifetime + * of the startup sequence. We can't avoid it when launching and + * expect that a "remove" message from a X11 client will be handled. + */ + startup_id = + meta_x11_startup_notification_launch (display->x11_display, + info, + workspace_idx, + context->timestamp); + } + + if (!startup_id) + { + const gchar *application_id = NULL; + MetaStartupNotification *sn; + MetaStartupSequence *seq; + + startup_id = g_uuid_string_random (); + + /* Fallback through inserting our own startup sequence, this + * will be enough for wayland clients. + */ + if (G_IS_DESKTOP_APP_INFO (info)) + { + application_id = + g_desktop_app_info_get_filename (G_DESKTOP_APP_INFO (info)); + } + + sn = meta_display_get_startup_notification (context->display); + seq = g_object_new (META_TYPE_STARTUP_SEQUENCE, + "id", startup_id, + "application-id", application_id, + "name", g_app_info_get_name (info), + "workspace", workspace_idx, + "timestamp", context->timestamp, + NULL); + + meta_startup_notification_add_sequence (sn, seq); + g_object_unref (seq); + } + + return startup_id; +} + +static void +meta_launch_context_launch_failed (GAppLaunchContext *launch_context, + const gchar *startup_notify_id) +{ + MetaLaunchContext *context = META_LAUNCH_CONTEXT (launch_context); + MetaStartupNotification *sn; + MetaStartupSequence *seq; + + sn = meta_display_get_startup_notification (context->display); + seq = meta_startup_notification_lookup_sequence (sn, startup_notify_id); + + if (seq) + { + meta_startup_sequence_complete (seq); + meta_startup_notification_remove_sequence (sn, seq); + } +} + +static void +meta_launch_context_class_init (MetaLaunchContextClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GAppLaunchContextClass *ctx_class = G_APP_LAUNCH_CONTEXT_CLASS (klass); + + object_class->finalize = meta_launch_context_finalize; + object_class->constructed = meta_launch_context_constructed; + object_class->set_property = meta_launch_context_set_property; + object_class->get_property = meta_launch_context_get_property; + + ctx_class->get_startup_notify_id = meta_launch_context_get_startup_notify_id; + ctx_class->launch_failed = meta_launch_context_launch_failed; + + props[PROP_DISPLAY] = + g_param_spec_object ("display", + "display", + "Display", + META_TYPE_DISPLAY, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + props[PROP_WORKSPACE] = + g_param_spec_object ("workspace", + "workspace", + "Workspace", + META_TYPE_WORKSPACE, + G_PARAM_READWRITE); + props[PROP_TIMESTAMP] = + g_param_spec_uint ("timestamp", + "timestamp", + "Timestamp", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE); + + g_object_class_install_properties (object_class, N_PROPS, props); +} + +static void +meta_launch_context_init (MetaLaunchContext *context) +{ +} + +void +meta_launch_context_set_workspace (MetaLaunchContext *context, + MetaWorkspace *workspace) +{ + g_return_if_fail (META_IS_LAUNCH_CONTEXT (context)); + g_return_if_fail (META_IS_WORKSPACE (workspace)); + + g_set_object (&context->workspace, workspace); +} + +void +meta_launch_context_set_timestamp (MetaLaunchContext *context, + uint32_t timestamp) +{ + g_return_if_fail (META_IS_LAUNCH_CONTEXT (context)); + + context->timestamp = timestamp; +} diff --git a/src/core/startup-notification.c b/src/core/startup-notification.c index 43260d59b..546891065 100644 --- a/src/core/startup-notification.c +++ b/src/core/startup-notification.c @@ -631,3 +631,21 @@ meta_startup_notification_get_sequences (MetaStartupNotification *sn) { return sn->startup_sequences; } + +/** + * meta_startup_notification_create_launcher: + * @sn: a #MetaStartupNotification + * + * Creates an app launch context. + * + * Returns: (transfer full): a launch context. + **/ +MetaLaunchContext * +meta_startup_notification_create_launcher (MetaStartupNotification *sn) +{ + MetaDisplay *display = sn->display; + + return g_object_new (META_TYPE_LAUNCH_CONTEXT, + "display", sn->display, + NULL); +} diff --git a/src/meson.build b/src/meson.build index ae41194ed..65f768662 100644 --- a/src/meson.build +++ b/src/meson.build @@ -334,6 +334,7 @@ mutter_sources = [ 'core/meta-inhibit-shortcuts-dialog.c', 'core/meta-inhibit-shortcuts-dialog-default.c', 'core/meta-inhibit-shortcuts-dialog-default-private.h', + 'core/meta-launch-context.c', 'core/meta-sound-player.c', 'core/meta-workspace-manager.c', 'core/meta-workspace-manager-private.h', diff --git a/src/meta/meson.build b/src/meta/meson.build index a5a6ad2be..53c4723a2 100644 --- a/src/meta/meson.build +++ b/src/meta/meson.build @@ -18,6 +18,7 @@ mutter_public_headers = [ 'meta-dnd.h', 'meta-idle-monitor.h', 'meta-inhibit-shortcuts-dialog.h', + 'meta-launch-context.h', 'meta-monitor-manager.h', 'meta-plugin.h', 'meta-remote-access-controller.h', diff --git a/src/meta/meta-launch-context.h b/src/meta/meta-launch-context.h new file mode 100644 index 000000000..eb4414ce7 --- /dev/null +++ b/src/meta/meta-launch-context.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2018 Red Hat + * + * 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. + * + * Author: Carlos Garnacho + */ +#ifndef META_LAUNCH_CONTEXT_H +#define META_LAUNCH_CONTEXT_H + +#include + +G_DECLARE_FINAL_TYPE (MetaLaunchContext, meta_launch_context, META, LAUNCH_CONTEXT, GAppLaunchContext) + +#define META_TYPE_LAUNCH_CONTEXT (meta_launch_context_get_type ()) + +void meta_launch_context_set_timestamp (MetaLaunchContext *context, + uint32_t timestamp); +void meta_launch_context_set_workspace (MetaLaunchContext *context, + MetaWorkspace *workspace); + +#endif /* META_LAUNCH_CONTEXT_H */ diff --git a/src/meta/meta-startup-notification.h b/src/meta/meta-startup-notification.h index 5b4d51559..106f336a0 100644 --- a/src/meta/meta-startup-notification.h +++ b/src/meta/meta-startup-notification.h @@ -19,6 +19,8 @@ #ifndef META_STARTUP_NOTIFICATION_H #define META_STARTUP_NOTIFICATION_H +#include + #define META_TYPE_STARTUP_SEQUENCE (meta_startup_sequence_get_type ()) #define META_TYPE_STARTUP_NOTIFICATION (meta_startup_notification_get_type ()) @@ -32,6 +34,9 @@ GType meta_startup_notification_get_type (void); */ GSList * meta_startup_notification_get_sequences (MetaStartupNotification *sn); +MetaLaunchContext * + meta_startup_notification_create_launcher (MetaStartupNotification *sn); + GType meta_startup_sequence_get_type (void); const char * meta_startup_sequence_get_id (MetaStartupSequence *sequence);