Map windows to realms by calling realmsd pid lookup method

This commit is contained in:
Bruce Leidl 2022-09-19 10:13:41 -04:00
parent 3f794cbe00
commit 2f4a1ed647
13 changed files with 426 additions and 229 deletions

View File

@ -56,4 +56,3 @@ var RealmManager = class {
}
};

View File

@ -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})`;

View File

@ -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;

View File

@ -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));
}
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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));
}
}

View File

@ -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);

View File

@ -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);