diff --git a/js/ui/realms/realmManager.js b/js/ui/realms/realmManager.js index bb60f60fd..b19de575c 100644 --- a/js/ui/realms/realmManager.js +++ b/js/ui/realms/realmManager.js @@ -56,4 +56,3 @@ var RealmManager = class { } }; - diff --git a/js/ui/realms/realmWindowMenu.js b/js/ui/realms/realmWindowMenu.js index 6418724a2..d41fe2efe 100644 --- a/js/ui/realms/realmWindowMenu.js +++ b/js/ui/realms/realmWindowMenu.js @@ -17,10 +17,11 @@ function _windowAppId(window) { function windowMenuDebugString(window) { const id = _windowAppId(window); const realm_name = windowRealmName(window); + const realms = Shell.Realms.get_default(); if (!realm_name) { return id; - } else if (window.is_on_foreign_workspace_context()) { + } else if (realms.is_foreign_window(window)) { return `${id} [${realm_name}]`; } else { return `${id} (${realm_name})`; diff --git a/src/shell-app-system.c b/src/shell-app-system.c index 033e73172..af3c02dc2 100644 --- a/src/shell-app-system.c +++ b/src/shell-app-system.c @@ -123,7 +123,7 @@ realm_name_from_application_id (const char *id) } -char * +static char * current_realm_name (gboolean name_only) { gchar *link = NULL; @@ -399,6 +399,10 @@ shell_app_system_lookup_app (ShellAppSystem *self, ShellApp *app; GDesktopAppInfo *info; + if (id == NULL) { + return NULL; + } + app = g_hash_table_lookup (priv->id_to_app, id); if (app) return app; diff --git a/src/shell-realm-item.c b/src/shell-realm-item.c index ddb662ca4..fc241042d 100644 --- a/src/shell-realm-item.c +++ b/src/shell-realm-item.c @@ -8,16 +8,14 @@ struct _ShellRealmItem { GObject parent; char *realm_name; char *description; - char *namespace; + guint64 namespace; MetaWorkspaceContext *context; - guint8 status; + ShellRealmItemStatus status; gboolean tagged; - gboolean disposed; }; G_DEFINE_TYPE (ShellRealmItem, shell_realm_item, G_TYPE_OBJECT); - enum { PROP_0, PROP_ITEM_REALM_NAME, @@ -25,45 +23,45 @@ enum { PROP_ITEM_NAMESPACE }; -#define REALM_STATUS_RUNNING 1 -#define REALM_STATUS_CURRENT 2 -#define REALM_STATUS_SYSTEM 4 static void -shell_realm_item_init(ShellRealmItem *item) +shell_realm_item_init (ShellRealmItem *item) { } ShellRealmItem * -shell_realm_item_new (const char *realm_name, const char *description, const char *namespace, guint8 status) +shell_realm_item_new (const char *realm_name, const char *description, guint64 namespace, guint8 status) { ShellRealmItem *item = g_object_new (SHELL_TYPE_REALM_ITEM, NULL); item->realm_name = g_strdup (realm_name); item->description = g_strdup (description); - item->namespace = g_strdup (namespace); + item->namespace = namespace; item->status = status; item->context = NULL; item->tagged = FALSE; - item->disposed = FALSE; return item; } -void -shell_realm_item_acquire_context (ShellRealmItem *item) +/** + * shell_realm_item_get_context: + * @item: A #ShellRealmItem instance + * + * Returns the #MetaWorkspaceContext associated with this realm if any. + * + * Returns: (transfer none) (nullable): a #MetaWorkspaceContext instance or + * %NULL if no context is associated with this realm. + */ +MetaWorkspaceContext * +shell_realm_item_get_context (ShellRealmItem *item) { - if (item->context || item->disposed || shell_realm_item_is_system (item)) { - return; - } + return item->context; +} - if (!item->namespace || !shell_realm_item_is_running (item)) { - g_warning ("ShellRealmItem: Cannot acquire workspace context for realm '%s' because not running or no namespace", item->realm_name); - return; - } - - MetaDisplay *display = shell_global_get_display (shell_global_get()); - MetaWorkspaceManager *workspace_manager = meta_display_get_workspace_manager (display); - item->context = meta_workspace_manager_context_for_namespace (workspace_manager, item->namespace); +void +shell_realm_item_set_context (ShellRealmItem *item, MetaWorkspaceContext *context) +{ + item->context = context; } /** @@ -98,15 +96,12 @@ shell_realm_item_get_description (ShellRealmItem *item) * shell_realm_item_get_namespace: * @item: A #ShellRealmItem instance * - * Returns: The namespace field for this realm or an empty string if no namespace is set + * Returns: The namespace field for this realm or 0 if no namespace is set */ -const char * +guint64 shell_realm_item_get_namespace (ShellRealmItem *item) { - if (item->namespace) - return item->namespace; - else - return ""; + return item->namespace; } /** @@ -119,10 +114,6 @@ shell_realm_item_get_namespace (ShellRealmItem *item) guint shell_realm_item_get_context_id (ShellRealmItem *item) { - if (shell_realm_item_is_running (item) && !item->context) { - shell_realm_item_acquire_context (item); - } - if (item->context) { return meta_workspace_context_id (item->context); } else { @@ -140,10 +131,6 @@ shell_realm_item_get_context_id (ShellRealmItem *item) MetaWorkspace * shell_realm_item_get_active_workspace (ShellRealmItem *item) { - if (shell_realm_item_is_running (item) && !item->context) { - shell_realm_item_acquire_context (item); - } - if (item->context) { return meta_workspace_context_get_active_workspace (item->context); } else { @@ -151,23 +138,6 @@ shell_realm_item_get_active_workspace (ShellRealmItem *item) } } -/** - * shell_realm_item_activate_context: - * @item: A #ShellRealmItem instance for a running realm - * - * If a #MetaWorkspaceContext is associated with this realm - * set it as the active workspace context. - */ -void -shell_realm_item_activate_context (ShellRealmItem *item) -{ - shell_realm_item_acquire_context (item); - - if (item->context) { - meta_workspace_context_activate (item->context); - } -} - /** * shell_realm_item_set_current: * @item: A #ShellRealmItem instance for a running realm @@ -178,7 +148,7 @@ shell_realm_item_activate_context (ShellRealmItem *item) */ void shell_realm_item_set_current (ShellRealmItem *item) { - ShellRealmTracker *tracker = shell_realm_tracker_get_default(); + ShellRealmTracker *tracker = shell_realm_tracker_get_default (); if (item && item->realm_name) { shell_realm_tracker_call_set_current (tracker, item->realm_name); } @@ -195,8 +165,6 @@ shell_realm_item_set_current (ShellRealmItem *item) { void shell_realm_item_move_window_to_context (ShellRealmItem *item, MetaWindow *window) { - shell_realm_item_acquire_context (item); - if (item->context) { meta_workspace_context_move_window_to_context (item->context, window); } else { @@ -204,20 +172,20 @@ shell_realm_item_move_window_to_context (ShellRealmItem *item, MetaWindow *windo } } -static gboolean -is_flag_set(guint8 status, guchar flag) +gboolean +shell_realm_is_flag_set(guint8 status, ShellRealmItemStatus flag) { return ((status & flag) != 0) ? TRUE : FALSE; } static gboolean -has_status_flag (ShellRealmItem *item, guchar flag) +has_status_flag (ShellRealmItem *item, ShellRealmItemStatus flag) { - return is_flag_set (item->status, flag); + return shell_realm_is_flag_set (item->status, flag); } static void -set_status_flag (ShellRealmItem *item, guint8 flag, gboolean value) +set_status_flag (ShellRealmItem *item, ShellRealmItemStatus flag, gboolean value) { if (value) { item->status |= flag; @@ -235,7 +203,7 @@ set_status_flag (ShellRealmItem *item, guint8 flag, gboolean value) gboolean shell_realm_item_is_current (ShellRealmItem *item) { - return has_status_flag (item, REALM_STATUS_CURRENT); + return has_status_flag (item, SHELL_REALM_ITEM_STATUS_CURRENT); } /** @@ -247,7 +215,7 @@ shell_realm_item_is_current (ShellRealmItem *item) gboolean shell_realm_item_is_running (ShellRealmItem *item) { - return has_status_flag (item, REALM_STATUS_RUNNING); + return has_status_flag (item, SHELL_REALM_ITEM_STATUS_RUNNING); } /** @@ -259,27 +227,22 @@ shell_realm_item_is_running (ShellRealmItem *item) gboolean shell_realm_item_is_system (ShellRealmItem *item) { - return has_status_flag (item, REALM_STATUS_SYSTEM); + return has_status_flag (item, SHELL_REALM_ITEM_STATUS_SYSTEM); } void shell_realm_item_set_current_flag (ShellRealmItem *item, gboolean value) { - set_status_flag (item, REALM_STATUS_CURRENT, value); + set_status_flag (item, SHELL_REALM_ITEM_STATUS_CURRENT, value); } void shell_realm_item_set_running_flag (ShellRealmItem *item, gboolean value) { - set_status_flag (item, REALM_STATUS_RUNNING, value); - - if (!value && item->context) { - meta_workspace_context_remove (item->context); - item->context = NULL; - } + set_status_flag (item, SHELL_REALM_ITEM_STATUS_RUNNING, value); } -void shell_realm_item_update (ShellRealmItem *item, const char *realm_name, const char *namespace, guint8 status) +void shell_realm_item_update (ShellRealmItem *item, const char *realm_name, guint64 namespace, guint8 status) { if (g_strcmp0 (item->realm_name, realm_name)) { g_message ("ShellRealmItem: Realm name changed from %s to %s", item->realm_name, realm_name); @@ -287,23 +250,8 @@ void shell_realm_item_update (ShellRealmItem *item, const char *realm_name, cons item->realm_name = g_strdup (realm_name); } - if (g_strcmp0 (item->namespace, namespace)) { - g_free(item->namespace); - item->namespace = g_strdup (namespace); - } - - if (item->status != status) { - gboolean was_running = has_status_flag (item, REALM_STATUS_RUNNING); - gboolean is_running = is_flag_set (status, REALM_STATUS_RUNNING); - gboolean stopped = was_running && !is_running; - - item->status = status; - - if (stopped) { - meta_workspace_context_remove (item->context); - item->context = NULL; - } - } + item->namespace = namespace; + item->status = status; } void @@ -332,7 +280,7 @@ static void shell_realm_item_get_property (GObject *gobject, g_value_set_string (value, shell_realm_item_get_description (item)); break; case PROP_ITEM_NAMESPACE: - g_value_set_string (value, shell_realm_item_get_namespace (item)); + g_value_set_uint64 (value, shell_realm_item_get_namespace (item)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); @@ -347,7 +295,6 @@ static void shell_realm_item_dispose (GObject *object) meta_workspace_context_remove (item->context); item->context = NULL; } - item->disposed = TRUE; G_OBJECT_CLASS(shell_realm_item_parent_class)->dispose (object); } @@ -357,7 +304,6 @@ shell_realm_item_finalize (GObject *object) ShellRealmItem *item = SHELL_REALM_ITEM (object); g_free (item->realm_name); g_free (item->description); - g_free (item->namespace); G_OBJECT_CLASS(shell_realm_item_parent_class)->finalize (object); } @@ -373,10 +319,10 @@ shell_realm_item_class_init (ShellRealmItemClass *klass) g_object_class_install_property (gobject_class, PROP_ITEM_NAMESPACE, - g_param_spec_string ("namespace", + g_param_spec_uint64 ("namespace", "Context Namespace", "PID namespace of context", - NULL, + 0, UINT64_MAX, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_ITEM_REALM_NAME, @@ -393,4 +339,4 @@ shell_realm_item_class_init (ShellRealmItemClass *klass) "Optional description of realm", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); -} \ No newline at end of file +} diff --git a/src/shell-realm-item.h b/src/shell-realm-item.h index 8e9d8ec8d..2c468e83b 100644 --- a/src/shell-realm-item.h +++ b/src/shell-realm-item.h @@ -7,26 +7,36 @@ #define SHELL_TYPE_REALM_ITEM (shell_realm_item_get_type()) G_DECLARE_FINAL_TYPE (ShellRealmItem, shell_realm_item, SHELL, REALM_ITEM, GObject) -ShellRealmItem *shell_realm_item_new (const char *realm_name, const char *description, const char *namespace, guint8 status); +typedef enum { + SHELL_REALM_ITEM_STATUS_RUNNING = 1 << 0, + SHELL_REALM_ITEM_STATUS_CURRENT = 1 << 1, + SHELL_REALM_ITEM_STATUS_SYSTEM = 1 << 2, +} ShellRealmItemStatus; + +gboolean shell_realm_is_flag_set (guint8 status, ShellRealmItemStatus flag); + +ShellRealmItem *shell_realm_item_new (const char *realm_name, const char *description, guint64 namespace, guint8 status); const char *shell_realm_item_get_realm_name (ShellRealmItem *item); const char *shell_realm_item_get_description (ShellRealmItem *item); -const char *shell_realm_item_get_namespace (ShellRealmItem *item); +guint64 shell_realm_item_get_namespace (ShellRealmItem *item); guint shell_realm_item_get_context_id (ShellRealmItem *item); +MetaWorkspaceContext *shell_realm_item_get_context (ShellRealmItem *item); +void shell_realm_item_set_context (ShellRealmItem *item, MetaWorkspaceContext *context); + MetaWorkspace *shell_realm_item_get_active_workspace (ShellRealmItem *item); -void shell_realm_item_update (ShellRealmItem *item, const char *realm_name, const char *namespace, guint8 status); +void shell_realm_item_update (ShellRealmItem *item, const char *realm_name, guint64 namespace, guint8 status); void shell_realm_item_set_current_flag (ShellRealmItem *item, gboolean value); void shell_realm_item_set_running_flag (ShellRealmItem *item, gboolean value); -void shell_realm_item_activate_context (ShellRealmItem *item); void shell_realm_item_set_current (ShellRealmItem *item); void shell_realm_item_move_window_to_context (ShellRealmItem *item, MetaWindow *window); -gboolean shell_realm_item_is_current(ShellRealmItem *item); -gboolean shell_realm_item_is_running(ShellRealmItem *item); -gboolean shell_realm_item_is_system(ShellRealmItem *item); +gboolean shell_realm_item_is_current (ShellRealmItem *item); +gboolean shell_realm_item_is_running (ShellRealmItem *item); +gboolean shell_realm_item_is_system (ShellRealmItem *item); void shell_realm_item_set_tagged (ShellRealmItem *item, gboolean is_tagged); gboolean shell_realm_item_is_tagged (ShellRealmItem *item); diff --git a/src/shell-realm-tracker.c b/src/shell-realm-tracker.c index 2b3c10d7e..5c9ffaada 100644 --- a/src/shell-realm-tracker.c +++ b/src/shell-realm-tracker.c @@ -7,6 +7,12 @@ #define REALMS_OBJECT_PATH "/com/subgraph/realms" #define REALMS_MANAGER_INTERFACE "com.subgraph.realms.Manager" +enum { + REALM_PID_LOOKUP_UNKNOWN = 1, + REALM_PID_LOOKUP_REALM = 2, + REALM_PID_LOOKUP_CITADEL = 3, +}; + struct _ShellRealmTracker { GObject parent; GDBusConnection *dbus; @@ -43,12 +49,12 @@ on_realm_bus_signal(GDBusConnection *connection, const gchar *realm_name = NULL; const gchar *description = NULL; - const gchar *namespace = NULL; + guint64 namespace; guint8 status = 0; if (g_str_equal (signal_name, "RealmStarted")) { - g_variant_get (parameters, "(&s&sy)", &realm_name, &namespace, &status); + g_variant_get (parameters, "(&sty)", &realm_name, &namespace, &status); shell_realms_on_realm_started (realms, realm_name, namespace, status); } else if (g_str_equal (signal_name, "RealmStopped")) { @@ -76,6 +82,50 @@ on_realm_bus_signal(GDBusConnection *connection, } } +static guint +bus_signal_subscribe (ShellRealmTracker *self, const gchar *signal_name) +{ + g_assert(self->dbus); + + return g_dbus_connection_signal_subscribe (self->dbus, + REALMS_BUS_NAME, + REALMS_MANAGER_INTERFACE, + signal_name, + REALMS_OBJECT_PATH, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + on_realm_bus_signal, + self, + NULL); +} + +static void +subscribe_bus_signals (ShellRealmTracker *self) +{ + if (self->dbus) { + int idx = 0; + self->bus_signal_ids[idx++] = bus_signal_subscribe (self, "RealmStarted"); + self->bus_signal_ids[idx++] = bus_signal_subscribe (self, "RealmStopped"); + self->bus_signal_ids[idx++] = bus_signal_subscribe (self, "RealmCurrent"); + self->bus_signal_ids[idx++] = bus_signal_subscribe (self, "RealmNew"); + self->bus_signal_ids[idx++] = bus_signal_subscribe (self, "RealmRemoved"); + g_assert(idx == NUM_BUS_SIGNAL_IDS); + } +} + +static void +unsubscribe_signals (ShellRealmTracker *self) +{ + for (int i = 0; i < NUM_BUS_SIGNAL_IDS; i++) { + if (self->bus_signal_ids[i]) { + if (self->dbus) { + g_dbus_connection_signal_unsubscribe (self->dbus, self->bus_signal_ids[i]); + } + self->bus_signal_ids[i] = 0; + } + } +} + static void realm_state_process_elements (ShellRealmTracker *self, GVariant *response) { @@ -83,25 +133,26 @@ realm_state_process_elements (ShellRealmTracker *self, GVariant *response) GVariantIter *iter = NULL; const gchar *name = NULL; const gchar *description = NULL; - const gchar *namespace = NULL; + guint64 namespace = 0; guchar status = 0; - ShellRealms *realms = shell_realms_get_default(); + ShellRealms *realms = shell_realms_get_default (); shell_realms_untag_all (realms); - g_variant_get(response, "(a(ssssy))", &iter); + g_variant_get (response, "(a(sssty))", &iter); // (name, desc, realmfs, namespace, status) - while (g_variant_iter_next(iter, "(&s&ss&sy)", &name, &description, NULL, &namespace, &status)) { - shell_realms_update_realm (realms, name, description, namespace, status); + while (g_variant_iter_next (iter, "(&s&ssty)", &name, &description, NULL, &namespace, &status)) { + shell_realms_process_list_realm (realms, name, description, namespace, status); } shell_realms_remove_untagged (realms); - g_variant_iter_free(iter); + shell_realms_update_contexts (realms); + g_variant_iter_free (iter); } static void -request_realm_state_finish(GObject *object, GAsyncResult *result, gpointer data) +request_realm_state_finish (GObject *object, GAsyncResult *result, gpointer data) { ShellRealmTracker *self = data; @@ -111,7 +162,7 @@ request_realm_state_finish(GObject *object, GAsyncResult *result, gpointer data) if (!response) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - g_warning("MetaRealmDbus: Error calling 'List' bus method: %s", error->message); + g_warning ("ShellRealmTracker: Error calling 'List' bus method: %s", error->message); } g_clear_error (&error); return; @@ -122,8 +173,9 @@ request_realm_state_finish(GObject *object, GAsyncResult *result, gpointer data) return; } - realm_state_process_elements(self, response); - g_variant_unref(response); + realm_state_process_elements (self, response); + g_variant_unref (response); + subscribe_bus_signals (self); } static void @@ -163,6 +215,26 @@ call_dbus_method (ShellRealmTracker *self, const gchar *method, GVariant *parame user_data); } +static GVariant * +call_dbus_method_sync (ShellRealmTracker *self, const gchar *method, GVariant *parameters, const GVariantType *reply_type, GError **error) +{ + if (!self->dbus) { + g_warning("ShellRealmTracker: call_dbus_method_sync (%s) called when no bus connection present", method); + return NULL; + } + return g_dbus_connection_call_sync (self->dbus, + REALMS_BUS_NAME, + REALMS_OBJECT_PATH, + REALMS_MANAGER_INTERFACE, + method, + parameters, + reply_type, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); +} + static void request_realm_state(ShellRealmTracker *self) { @@ -175,49 +247,42 @@ shell_realm_tracker_call_set_current (ShellRealmTracker *self, const char *realm call_dbus_method (self, "SetCurrent", g_variant_new("(s)", realm_name), set_realm_current_finish, NULL); } - -static void -unsubscribe_signals (ShellRealmTracker *self) +gchar * +shell_realm_tracker_call_realm_from_citadel_pid (ShellRealmTracker *self, pid_t pid) { - for (int i = 0; i < NUM_BUS_SIGNAL_IDS; i++) { - if (self->bus_signal_ids[i]) { - if (self->dbus) { - g_dbus_connection_signal_unsubscribe(self->dbus, self->bus_signal_ids[i]); - } - self->bus_signal_ids[i] = 0; - } + GError *error = NULL; + GVariant *result; + + guint32 code = 0; + gchar *realm_name = NULL; + gchar *retval = NULL; + + if (!self->dbus) { + return NULL; } -} -static guint -bus_signal_subscribe (ShellRealmTracker *self, const gchar *signal_name) -{ - g_assert(self->dbus); + result = call_dbus_method_sync (self, "RealmFromCitadelPid", + g_variant_new("(u)", pid), + G_VARIANT_TYPE("(us)"), + &error); - return g_dbus_connection_signal_subscribe(self->dbus, - REALMS_BUS_NAME, - REALMS_MANAGER_INTERFACE, - signal_name, - REALMS_OBJECT_PATH, - NULL, - G_DBUS_SIGNAL_FLAGS_NONE, - on_realm_bus_signal, - self, - NULL); -} - -static void -subscribe_bus_signals (ShellRealmTracker *self) -{ - if (self->dbus) { - int idx = 0; - self->bus_signal_ids[idx++] = bus_signal_subscribe(self, "RealmStarted"); - self->bus_signal_ids[idx++] = bus_signal_subscribe(self, "RealmStopped"); - self->bus_signal_ids[idx++] = bus_signal_subscribe(self, "RealmCurrent"); - self->bus_signal_ids[idx++] = bus_signal_subscribe(self, "RealmNew"); - self->bus_signal_ids[idx++] = bus_signal_subscribe(self, "RealmRemoved"); - g_assert(idx == NUM_BUS_SIGNAL_IDS); + if (!result) { + if (error != NULL) { + g_warning ("Error calling RealmCitadelFromPid(%d): %s", pid, error->message); } + return NULL; + } + + g_variant_get (result, "(u&s)", &code, &realm_name); + // g_warning("Calling RealmFromCitadelPid(%u) -> (%d,'%s')", pid, code, realm_name); + + if (code == REALM_PID_LOOKUP_REALM) { + retval = g_strdup (realm_name); + } else if (code == REALM_PID_LOOKUP_CITADEL) { + retval = g_strdup (CITADEL_REALM_TAG); + } + g_variant_unref (result); + return retval; } static void @@ -231,8 +296,7 @@ on_realm_manager_appeared (GDBusConnection *connection, const gchar *name, const } if (!self->dbus) { - self->dbus = g_object_ref(connection); - subscribe_bus_signals (self); + self->dbus = g_object_ref (connection); } else { g_warning("Realm tracker already has a connection in on_realm_manager_appeared()"); } @@ -240,7 +304,6 @@ on_realm_manager_appeared (GDBusConnection *connection, const gchar *name, const request_realm_state (self); } - static void on_realm_manager_vanished (GDBusConnection *connection, const gchar *name, gpointer user_data) { @@ -255,7 +318,7 @@ on_realm_manager_vanished (GDBusConnection *connection, const gchar *name, gpoin g_clear_object (&self->dbus); } - unsubscribe_signals(self); + unsubscribe_signals (self); } /** @@ -273,7 +336,7 @@ shell_realm_tracker_get_default(void) return instance; } -void shell_realm_tracker_start () +void shell_realm_tracker_start (void) { ShellRealmTracker *tracker = shell_realm_tracker_get_default(); @@ -282,7 +345,7 @@ void shell_realm_tracker_start () return; } - tracker->realms_watch_id = g_bus_watch_name(G_BUS_TYPE_SYSTEM, + tracker->realms_watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM, REALMS_BUS_NAME, G_BUS_NAME_WATCHER_FLAGS_NONE, on_realm_manager_appeared, @@ -305,6 +368,6 @@ shell_realm_tracker_destroy(ShellRealmTracker *self) self->destroy_in_progress = TRUE; // frees 'self' in destroy notifier - g_bus_unwatch_name(self->realms_watch_id); + g_bus_unwatch_name (self->realms_watch_id); } diff --git a/src/shell-realm-tracker.h b/src/shell-realm-tracker.h index a979f9510..7bc04e76f 100644 --- a/src/shell-realm-tracker.h +++ b/src/shell-realm-tracker.h @@ -7,8 +7,10 @@ G_DECLARE_FINAL_TYPE (ShellRealmTracker, shell_realm_tracker, SHELL, REALM_TRACKER, GObject) -ShellRealmTracker *shell_realm_tracker_get_default(void); +ShellRealmTracker *shell_realm_tracker_get_default (void); void shell_realm_tracker_call_set_current (ShellRealmTracker *self, const char *realm_name); -void shell_realm_tracker_start (); +gchar *shell_realm_tracker_call_realm_from_citadel_pid (ShellRealmTracker *self, pid_t pid); +void shell_realm_tracker_start (void); +void shell_realm_tracker_destroy (ShellRealmTracker *self); #endif /* __SHELL_REALM_TRACKER_H__ */ diff --git a/src/shell-realms-private.h b/src/shell-realms-private.h index 571f110f4..466a82267 100644 --- a/src/shell-realms-private.h +++ b/src/shell-realms-private.h @@ -4,16 +4,18 @@ #include "shell-realms.h" #include "shell-realms-window-frames.h" +#define CITADEL_REALM_TAG "[CITADEL]" void shell_realms_untag_all (ShellRealms *realms); void shell_realms_remove_untagged (ShellRealms *realms); -void shell_realms_update_realm (ShellRealms *realms, - const char *realm_name, - const char *description, - const char *namespace, - guint8 status); +void shell_realms_update_contexts (ShellRealms *realms); +void shell_realms_process_list_realm (ShellRealms *realms, + const char *realm_name, + const char *description, + guint64 namespace, + guint8 status); -void shell_realms_on_realm_started (ShellRealms *realms, const gchar *realm_name, const gchar *namespace, guint8 status); +void shell_realms_on_realm_started (ShellRealms *realms, const gchar *realm_name, guint64 namespace, guint8 status); void shell_realms_on_realm_current (ShellRealms *realms, const gchar *realm_name); void shell_realms_on_realm_stopped (ShellRealms *realms, const gchar *realm_name); void shell_realms_on_realm_removed (ShellRealms *realms, const gchar *realm_name); diff --git a/src/shell-realms-window-frames.c b/src/shell-realms-window-frames.c index 99a3aa7b3..e05b8592b 100644 --- a/src/shell-realms-window-frames.c +++ b/src/shell-realms-window-frames.c @@ -9,6 +9,7 @@ struct _ShellRealmsWindowFrames { GObject parent; + ShellRealms *realms; GSettings *settings; GHashTable *realm_frame_colors; GList *default_colors; @@ -24,6 +25,17 @@ enum { static guint shell_realms_window_frames_signals [LAST_SIGNAL] = { 0 }; +ShellRealmsWindowFrames * +shell_realms_window_frames_new (ShellRealms *realms) +{ + ShellRealmsWindowFrames *frames; + + frames = g_object_new (SHELL_TYPE_REALMS_WINDOW_FRAMES, NULL); + + frames->realms = realms; + return frames; +} + static void shell_realms_window_frames_process_color (ShellRealmsWindowFrames *frames, const char *entry) { @@ -32,13 +44,13 @@ shell_realms_window_frames_process_color (ShellRealmsWindowFrames *frames, const gchar **split = g_strsplit (entry, ":", -1); if (g_strv_length (split) != 2) { - g_warning("ShellRealmsWindowFrames: Unable to parse realm-frame-colors entry: %s", entry); + g_warning ("ShellRealmsWindowFrames: Unable to parse realm-frame-colors entry: %s", entry); g_strfreev (split); return; } if (!gdk_rgba_parse (&rgba, split[1])) { - g_warning("ShellRealmsWindowFrames: Failed to parse RGBA component of realm frame color entry: %s", entry); + g_warning ("ShellRealmsWindowFrames: Failed to parse RGBA component of realm frame color entry: %s", entry); } else { g_hash_table_insert (frames->realm_frame_colors, g_strdup (split[0]), gdk_rgba_copy (&rgba)); } @@ -62,7 +74,7 @@ load_realm_frame_colors (ShellRealmsWindowFrames *frames) } static void -on_realm_frame_colors_changed(GSettings *settings, const gchar *key, ShellRealmsWindowFrames *frames) +on_realm_frame_colors_changed (GSettings *settings, const gchar *key, ShellRealmsWindowFrames *frames) { load_realm_frame_colors (frames); g_signal_emit (frames, shell_realms_window_frames_signals[REALM_FRAME_COLORS_CHANGED], 0); @@ -78,7 +90,7 @@ load_default_colors (ShellRealmsWindowFrames *frames) entries = g_settings_get_strv (frames->settings, FRAME_COLOR_LIST_KEY); n_entries = g_strv_length (entries); - g_clear_list(&frames->default_colors, (GDestroyNotify) gdk_rgba_free); + g_clear_list (&frames->default_colors, (GDestroyNotify) gdk_rgba_free); for (i = 0; i < n_entries; i++) { if (gdk_rgba_parse (&rgba, entries[i])) { @@ -102,12 +114,12 @@ shell_realms_window_frames_init (ShellRealmsWindowFrames *frames) frames->default_colors = NULL; frames->frame_disabled_windows = NULL; - g_signal_connect(frames->settings, + g_signal_connect (frames->settings, "changed::" FRAME_COLOR_LIST_KEY, G_CALLBACK(on_frame_color_list_changed), frames); - g_signal_connect(frames->settings, + g_signal_connect (frames->settings, "changed::" REALM_FRAME_COLORS_KEY, G_CALLBACK(on_realm_frame_colors_changed), frames); @@ -172,7 +184,7 @@ add_to_disabled_list (ShellRealmsWindowFrames *frames, guint32 window_id) } static gint -color_compare(gconstpointer c1, gconstpointer c2) { +color_compare (gconstpointer c1, gconstpointer c2) { return gdk_rgba_equal (c1, c2) ? 0 : 1; } @@ -199,7 +211,7 @@ allocate_color (ShellRealmsWindowFrames *frames) g_list_free (used_colors); // 3) Choose a random element of the default list - guint index = (guint) g_random_int_range(0, (gint32) n_colors); + guint index = (guint) g_random_int_range (0, (gint32) n_colors); return g_list_nth_data (frames->default_colors, index); } @@ -209,11 +221,11 @@ shell_realms_window_frames_store_colors (ShellRealmsWindowFrames *frames) GHashTableIter iter; gpointer key, value; - GPtrArray *entries = g_ptr_array_new_with_free_func(g_free); + GPtrArray *entries = g_ptr_array_new_with_free_func (g_free); g_hash_table_iter_init (&iter, frames->realm_frame_colors); - while (g_hash_table_iter_next(&iter, &key, &value)) { + while (g_hash_table_iter_next (&iter, &key, &value)) { gchar *name = key; GdkRGBA *rgba = value; char *rgba_str = gdk_rgba_to_string (rgba); @@ -230,10 +242,10 @@ shell_realms_window_frames_store_colors (ShellRealmsWindowFrames *frames) } static const char * -shell_realms_window_frames_realm_name_for_window (ShellRealmsWindowFrames *frames, ShellRealms *realms, MetaWindow *window) +shell_realms_window_frames_realm_name_for_window (ShellRealmsWindowFrames *frames, MetaWindow *window) { - ShellRealmItem *realm = shell_realms_realm_by_window (realms, window); + ShellRealmItem *realm = shell_realms_realm_by_window (frames->realms, window); if (realm) { return shell_realm_item_get_realm_name (realm); @@ -292,7 +304,7 @@ shell_realms_window_frames_is_frame_enabled (ShellRealmsWindowFrames *frames, Me gboolean shell_realms_window_frames_has_frame (ShellRealmsWindowFrames *frames, MetaWindow *window) { - return !is_ignored_window(window) && meta_window_is_on_foreign_workspace_context (window); + return !is_ignored_window (window) && shell_realms_is_foreign_window (frames->realms, window); } /** @@ -342,9 +354,11 @@ shell_realms_window_frames_color_for_window (ShellRealmsWindowFrames *frames, Me return NULL; } - ShellRealms *realms = shell_realms_get_default(); + const gchar *name = shell_realms_window_frames_realm_name_for_window (frames, window); - const gchar *name = shell_realms_window_frames_realm_name_for_window (frames, realms, window); + if (name == NULL) { + return NULL; + } GdkRGBA *rgba = g_hash_table_lookup (frames->realm_frame_colors, name); @@ -376,11 +390,9 @@ shell_realms_window_frames_label_for_window (ShellRealmsWindowFrames *frames, Me return NULL; } - ShellRealms *realms = shell_realms_get_default(); - - if (shell_realms_is_citadel_window (realms, window)) { + if (shell_realms_is_citadel_window (frames->realms, window)) { return "Citadel"; } else { - return shell_realms_window_frames_realm_name_for_window (frames, realms, window); + return shell_realms_window_frames_realm_name_for_window (frames, window); } } diff --git a/src/shell-realms-window-frames.h b/src/shell-realms-window-frames.h index 02354736a..f95d249c6 100644 --- a/src/shell-realms-window-frames.h +++ b/src/shell-realms-window-frames.h @@ -8,6 +8,9 @@ #define SHELL_TYPE_REALMS_WINDOW_FRAMES (shell_realms_window_frames_get_type()) G_DECLARE_FINAL_TYPE (ShellRealmsWindowFrames, shell_realms_window_frames, SHELL, REALMS_WINDOW_FRAMES, GObject) +typedef struct _ShellRealms ShellRealms; + +ShellRealmsWindowFrames *shell_realms_window_frames_new (ShellRealms *realms); gboolean shell_realms_window_frames_has_frame (ShellRealmsWindowFrames *frames, MetaWindow *window); gboolean shell_realms_window_frames_is_frame_enabled (ShellRealmsWindowFrames *frames, MetaWindow *window); void shell_realms_window_frames_set_frame_enabled (ShellRealmsWindowFrames *frames, MetaWindow *window, gboolean enabled); diff --git a/src/shell-realms.c b/src/shell-realms.c index 01718b07d..de0b87558 100644 --- a/src/shell-realms.c +++ b/src/shell-realms.c @@ -50,8 +50,12 @@ shell_realms_current_realm (ShellRealms *realms) * if name not found */ ShellRealmItem * -shell_realms_realm_by_name(ShellRealms *realms, const gchar *realm_name) +shell_realms_realm_by_name (ShellRealms *realms, const gchar *realm_name) { + if (realm_name == NULL) { + return NULL; + } + ShellRealmItem *item = g_hash_table_lookup (realms->realms, realm_name); if (!item) { g_warning("ShellRealms: No realm found for name '%s'", realm_name); @@ -83,6 +87,17 @@ shell_realms_realm_by_context_id (ShellRealms *realms, guint context_id) return NULL; } +static gchar * +realm_name_from_window_pid (ShellRealms *realms, MetaWindow *window) +{ + ShellRealmTracker *tracker = shell_realm_tracker_get_default(); + pid_t pid = meta_window_get_pid (window); + if (pid > 0) { + return shell_realm_tracker_call_realm_from_citadel_pid (tracker, pid); + } + return NULL; +} + /** * shell_realms_realm_by_window: * @realms: a #ShellRealms instance @@ -94,19 +109,14 @@ shell_realms_realm_by_context_id (ShellRealms *realms, guint context_id) ShellRealmItem * shell_realms_realm_by_window (ShellRealms *realms, MetaWindow *window) { - const char *window_ns = meta_window_namespace (window); - - if (!window_ns) { - return NULL; + ShellRealmItem *realm = NULL; + gchar *realm_name = realm_name_from_window_pid (realms, window); + // g_warning("shell_realms_realm_by_window() realm_name=%s", realm_name); + if (realm_name && g_strcmp0 (CITADEL_REALM_TAG, realm_name)) { + realm = shell_realms_realm_by_name (realms, realm_name); } - - for (GList *iter = realms->running_realms; iter; iter = iter->next) { - ShellRealmItem *item = iter->data; - if (g_strcmp0 (window_ns, shell_realm_item_get_namespace (item)) == 0) { - return item; - } - } - return NULL; + g_free(realm_name); + return realm; } /** @@ -122,13 +132,26 @@ shell_realms_realm_by_window (ShellRealms *realms, MetaWindow *window) gboolean shell_realms_is_citadel_window (ShellRealms *realms, MetaWindow *window) { - MetaDisplay *display = shell_global_get_display (shell_global_get()); - MetaWorkspaceManager *workspace_manager = meta_display_get_workspace_manager (display); + gchar *realm_name = realm_name_from_window_pid (realms, window); + gboolean is_citadel = g_strcmp0 (CITADEL_REALM_TAG, realm_name) == 0; + g_free(realm_name); + return is_citadel; +} - const char *mutter_ns = meta_workspace_manager_mutter_namespace (workspace_manager); - const char *window_ns = meta_window_namespace (window); - return g_strcmp0 (mutter_ns, window_ns) == 0; +gboolean +shell_realms_is_foreign_window (ShellRealms *realms, MetaWindow *window) +{ + MetaWorkspace *workspace = meta_window_get_workspace (window); + guint current_id = meta_workspace_get_context_id (workspace); + + ShellRealmItem *realm_item = shell_realms_realm_by_window (realms, window); + + if (current_id && realm_item) { + guint realm_id = shell_realm_item_get_context_id (realm_item); + return current_id != realm_id; + } + return FALSE; } /** @@ -237,9 +260,11 @@ static ShellRealmItem * shell_realms_add_realm_item (ShellRealms *realms, const char *realm_name, const char *description, - const char *namespace, + guint64 namespace, guint8 status) { + g_assert (realm_name != NULL); + ShellRealmItem *item = g_hash_table_lookup (realms->realms, realm_name); if (item) { shell_realm_item_update (item, realm_name, namespace, status); @@ -249,27 +274,120 @@ shell_realms_add_realm_item (ShellRealms *realms, item = shell_realm_item_new (realm_name, description, namespace, status); if (shell_realm_item_is_system (item)) { - g_clear_object(&item); + g_clear_object (&item); return NULL; } g_hash_table_insert (realms->realms, g_strdup (realm_name), item); return item; } -void -shell_realms_update_realm (ShellRealms *realms, - const char *realm_name, - const char *description, - const char *namespace, - guint8 status) +static void +remove_workspace_context (ShellRealmItem *realm) { - ShellRealmItem *item = shell_realms_add_realm_item (realms, realm_name, description, namespace, status); + MetaWorkspaceContext *context = shell_realm_item_get_context (realm); + if (context) { + shell_realm_item_set_context (realm, NULL); + if (!meta_workspace_context_is_current (context)) { + meta_workspace_context_remove (context); + } + } +} - // Ignore system realms - if (!item) { +static ShellRealmItem * +find_realm_with_context (ShellRealms *realms, MetaWorkspaceContext *context) +{ + GHashTableIter iter; + gpointer value; + + if (context == NULL) { + return NULL; + } + + g_hash_table_iter_init (&iter, realms->realms); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + ShellRealmItem *item = value; + if (shell_realm_item_get_context (item) == context) { + return item; + } + } + return NULL; +} + +static void +acquire_active_workspace_context (ShellRealms *realms, ShellRealmItem *realm) +{ + + MetaDisplay *display = shell_global_get_display (shell_global_get ()); + MetaWorkspaceManager *workspace_manager = meta_display_get_workspace_manager (display); + MetaWorkspaceContext *active_context = meta_workspace_manager_active_context (workspace_manager); + + if (shell_realm_item_get_context (realm) == active_context) { return; } + if (!shell_realm_item_is_current (realm)) { + g_warning ("ShellRealms: Cannot acquire active workspace context for realm that is not the current realm"); + return; + } + + ShellRealmItem *other_realm = find_realm_with_context (realms, active_context); + + if (other_realm) { + g_warning ("Stealing active workspace context from realm-%s for realm-%s", + shell_realm_item_get_realm_name(other_realm), + shell_realm_item_get_realm_name(realm)); + + if (shell_realm_item_is_current (other_realm)) { + shell_realm_item_set_current_flag (other_realm, false); + } + + shell_realm_item_set_context (other_realm, NULL); + + if (shell_realm_item_is_running (other_realm)) { + MetaWorkspaceContext *context = meta_workspace_context_new(workspace_manager); + shell_realm_item_set_context(other_realm, context); + } + } + + shell_realm_item_set_context (realm, active_context); +} + +static void +acquire_workspace_context (ShellRealms *realms, ShellRealmItem *realm) +{ + + if (shell_realm_item_is_system (realm) || shell_realm_item_get_context (realm) != NULL) { + return; + } + + if (shell_realm_item_is_current (realm)) { + acquire_active_workspace_context (realms, realm); + return; + } + + MetaDisplay *display = shell_global_get_display(shell_global_get()); + MetaWorkspaceManager *workspace_manager = meta_display_get_workspace_manager(display); + MetaWorkspaceContext *context = meta_workspace_context_new(workspace_manager); + + shell_realm_item_set_context(realm, context); + +} + +void +shell_realms_process_list_realm (ShellRealms *realms, + const char *realm_name, + const char *description, + guint64 namespace, + guint8 status) +{ + + // Ignore system realms + if (shell_realm_is_flag_set (status, SHELL_REALM_ITEM_STATUS_SYSTEM)) { + return; + } + + ShellRealmItem *item = shell_realms_add_realm_item (realms, realm_name, description, namespace, status); + shell_realms_update_running_list_for_item (realms, item); shell_realm_item_set_tagged (item, TRUE); @@ -277,7 +395,11 @@ shell_realms_update_realm (ShellRealms *realms, // first context requested is for the current realm. if (shell_realm_item_is_current (item)) { shell_realms_set_current_item (realms, item); - shell_realm_item_acquire_context (item); + acquire_workspace_context (realms, item); + } + + if (!shell_realm_item_is_running (item) && shell_realm_item_get_context (item) != NULL) { + remove_workspace_context (item); } } @@ -312,26 +434,47 @@ shell_realms_remove_untagged (ShellRealms *realms) ShellRealmItem *item = value; if (!shell_realm_item_is_tagged (item)) { shell_realms_remove_running_realm (realms, item); + remove_workspace_context (item); g_hash_table_iter_remove (&iter); } } } +void +shell_realms_update_contexts (ShellRealms *realms) { + for (GList *iter = realms->running_realms; iter; iter = iter->next) { + ShellRealmItem *item = iter->data; + if (shell_realm_item_get_context (item) == NULL) { + acquire_workspace_context (realms, item); + } + } +} + // Signal handlers void -shell_realms_on_realm_started (ShellRealms *realms, const gchar *realm_name, const gchar *namespace, guint8 status) +shell_realms_on_realm_started (ShellRealms *realms, const gchar *realm_name, guint64 namespace, guint8 status) { ShellRealmItem *item = shell_realms_realm_by_name (realms, realm_name); if (item) { shell_realm_item_update (item, realm_name, namespace, status); if (!shell_realm_item_is_system (item)) { shell_realms_update_running_list_for_item (realms, item); - shell_realm_item_acquire_context (item); + acquire_workspace_context(realms, item); } } } +static void +activate_workspace_context (ShellRealmItem *realm) +{ + MetaWorkspaceContext *context = shell_realm_item_get_context (realm); + if (context) { + meta_workspace_context_activate (context); + } +} + + void shell_realms_on_realm_current (ShellRealms *realms, const gchar *realm_name) { @@ -340,7 +483,7 @@ shell_realms_on_realm_current (ShellRealms *realms, const gchar *realm_name) if (item && realms->current_realm != item) { shell_realms_set_current_item (realms, item); shell_realms_update_running_list_for_item (realms, item); - shell_realm_item_activate_context (item); + activate_workspace_context (item); g_signal_emit (realms, shell_realms_signals[REALM_CONTEXT_SWITCHED], 0); } } @@ -351,6 +494,7 @@ shell_realms_on_realm_stopped (ShellRealms *realms, const gchar *realm_name) ShellRealmItem *item = shell_realms_realm_by_name (realms, realm_name); if (item) { shell_realm_item_set_running_flag (item, FALSE); + remove_workspace_context (item); shell_realms_remove_running_realm (realms, item); } } @@ -360,6 +504,9 @@ shell_realms_on_realm_removed (ShellRealms *realms, const gchar *realm_name) { ShellRealmItem *item = shell_realms_realm_by_name (realms, realm_name); if (item) { + shell_realm_item_set_running_flag (item, FALSE); + remove_workspace_context (item); + shell_realms_remove_running_realm (realms, item); g_hash_table_remove (realms->realms, realm_name); } @@ -368,10 +515,14 @@ shell_realms_on_realm_removed (ShellRealms *realms, const gchar *realm_name) void shell_realms_on_realm_new (ShellRealms *realms, const gchar *realm_name, const gchar *description, guint8 status) { + if (realm_name == NULL || shell_realm_is_flag_set (status, SHELL_REALM_ITEM_STATUS_SYSTEM)) { + return; + } + if (!g_hash_table_contains (realms->realms, realm_name)) { - (void) shell_realms_add_realm_item (realms, realm_name, description, NULL, status); + (void) shell_realms_add_realm_item (realms, realm_name, description, 0, status); } else { - g_warning("ShellRealms: RealmNew signal received for realm '%s' but it already exists", realm_name); + g_warning ("ShellRealms: RealmNew signal received for realm '%s' but it already exists", realm_name); } } @@ -397,7 +548,7 @@ shell_realms_init(ShellRealms *realms) realms->realms = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); realms->running_realms = NULL; realms->current_realm = NULL; - realms->frames = g_object_new (SHELL_TYPE_REALMS_WINDOW_FRAMES, NULL); + realms->frames = shell_realms_window_frames_new (realms); } static void @@ -457,4 +608,4 @@ shell_realms_class_init (ShellRealmsClass *klass) "The currently active realm", SHELL_TYPE_REALM_ITEM, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); -} \ No newline at end of file +} diff --git a/src/shell-realms.h b/src/shell-realms.h index 198b510af..7e4759629 100644 --- a/src/shell-realms.h +++ b/src/shell-realms.h @@ -13,10 +13,11 @@ ShellRealms *shell_realms_get_default(void); ShellRealmItem *shell_realms_current_realm (ShellRealms *realms); -ShellRealmItem *shell_realms_realm_by_name(ShellRealms *realms, const gchar *realm_name); +ShellRealmItem *shell_realms_realm_by_name (ShellRealms *realms, const gchar *realm_name); ShellRealmItem *shell_realms_realm_by_context_id (ShellRealms *realms, guint context_id); ShellRealmItem *shell_realms_realm_by_window (ShellRealms *realms, MetaWindow *window); gboolean shell_realms_is_citadel_window (ShellRealms *realms, MetaWindow *window); +gboolean shell_realms_is_foreign_window (ShellRealms *realms, MetaWindow *window); ShellRealmsWindowFrames *shell_realms_window_frames (ShellRealms *realms); diff --git a/src/shell-window-tracker.c b/src/shell-window-tracker.c index dc8fc64bd..4bd840ee0 100644 --- a/src/shell-window-tracker.c +++ b/src/shell-window-tracker.c @@ -217,6 +217,9 @@ get_app_from_window_wmclass (MetaWindow *window) /* first try a match from WM_CLASS (instance part) to StartupWMClass */ wm_instance = meta_window_get_wm_class_instance (window); + if (realm_name) { + // g_warning ("ShellWindowTracker: get_app_from_window_class(wmclass: %s, realm: %s)", wm_instance, realm_name); + } app = shell_app_system_lookup_startup_wmclass (appsys, wm_instance, realm_name); if (app != NULL && check_app_id_prefix (app, app_prefix)) return g_object_ref (app);