Citadel changes to Mutter

This commit is contained in:
Bruce Leidl 2021-12-03 14:07:17 -05:00
parent c4753689e3
commit db5ce3d87d
14 changed files with 740 additions and 84 deletions

View File

@ -563,8 +563,13 @@ meta_compositor_switch_workspace (MetaCompositor *compositor,
meta_compositor_get_instance_private (compositor); meta_compositor_get_instance_private (compositor);
gint to_indx, from_indx; gint to_indx, from_indx;
if (direction == META_MOTION_CONTEXT_SWITCH) {
to_indx = meta_workspace_get_id (to);
from_indx = meta_workspace_get_id (from);
} else {
to_indx = meta_workspace_index (to); to_indx = meta_workspace_index (to);
from_indx = meta_workspace_index (from); from_indx = meta_workspace_index (from);
}
priv->switch_workspace_in_progress++; priv->switch_workspace_in_progress++;

View File

@ -29,6 +29,36 @@
#include "meta/types.h" #include "meta/types.h"
#include "meta/meta-workspace-manager.h" #include "meta/meta-workspace-manager.h"
//
// Stores list of MetaWorkspaces and pointer to an active MetaWorkspace. When this context becomes
// the current context, the workspace fields are swapped into the corresponding fields in
// MetaWorkspaceManager.
//
//
struct _MetaWorkspaceContext
{
GObject parent;
// Link back to MetaWorkspaceManager
MetaWorkspaceManager *manager;
// MetaWorkspace list belonging to this context. Copied to field with same name in
// MetaWorkspaceManager when this context is active. Any code which changes this list
// must make sure this context is not currently active in which case the list in
// MetaWorkspaceManager must be changed instead.
GList *workspaces;
// Active MetaWorkspace for this context. Also copied to workspace manager upon activation.
// The rule above about not writing if context is currently active also applies to this field.
MetaWorkspace *active_workspace;
// PID namespace
gchar *namespace;
// A unique ID value for this context.
guint id;
};
struct _MetaWorkspaceManager struct _MetaWorkspaceManager
{ {
GObject parent; GObject parent;
@ -36,8 +66,21 @@ struct _MetaWorkspaceManager
MetaDisplay *display; MetaDisplay *display;
MetaWorkspace *active_workspace; MetaWorkspace *active_workspace;
GList *all_workspaces;
GList *workspaces; GList *workspaces;
// List of WorkspaceContext
GList *context_list;
gchar *mutter_namespace;
// Current active WorkspaceContext. MetaWorkspaceManager state (workspaces, active_workspace)
// will be saved here when a new WorkspaceContext is made active.
MetaWorkspaceContext *active_context;
// The next id value to allocate when creating a new WorkspaceContext
guint next_context_id;
int rows_of_workspaces; int rows_of_workspaces;
int columns_of_workspaces; int columns_of_workspaces;
MetaDisplayCorner starting_corner; MetaDisplayCorner starting_corner;
@ -91,3 +134,29 @@ META_EXPORT_TEST
void meta_workspace_manager_update_num_workspaces (MetaWorkspaceManager *workspace_manager, void meta_workspace_manager_update_num_workspaces (MetaWorkspaceManager *workspace_manager,
guint32 timestamp, guint32 timestamp,
int new_num); int new_num);
MetaWorkspaceContext *meta_workspace_context_new (MetaWorkspaceManager *manager, const char *namespace);
void meta_workspace_context_make_active (MetaWorkspaceContext *context);
MetaWorkspaceContext *meta_workspace_manager_lookup_context (MetaWorkspaceManager *workspace_manager,
guint context_id);
void meta_workspace_manager_append_context_workspace (MetaWorkspaceManager *manager,
MetaWorkspace *workspace);
void meta_workspace_manager_remove_context_workspace (MetaWorkspaceManager *manager,
MetaWorkspace *workspace);
int meta_workspace_manager_context_workspace_index (MetaWorkspaceManager *workspace_manager,
MetaWorkspace *workspace);
int meta_workspace_manager_get_workspace_id (MetaWorkspaceManager *workspace_manager,
MetaWorkspace *workspace);
MetaWorkspace *
meta_workspace_manager_lookup_workspace_by_id (MetaWorkspaceManager *workspace_manager, int workspace_id);
gboolean
meta_workspace_manager_is_window_on_foreign_context (MetaWorkspaceManager *workspace_manager, MetaWindow *window);

View File

@ -44,6 +44,9 @@ enum
WORKSPACES_REORDERED, WORKSPACES_REORDERED,
ACTIVE_WORKSPACE_CHANGED, ACTIVE_WORKSPACE_CHANGED,
SHOWING_DESKTOP_CHANGED, SHOWING_DESKTOP_CHANGED,
CONTEXT_SWITCHED,
CONTEXT_WINDOW_MOVED,
CONTEXT_REMOVED,
LAST_SIGNAL LAST_SIGNAL
}; };
@ -165,6 +168,29 @@ meta_workspace_manager_class_init (MetaWorkspaceManagerClass *klass)
0, NULL, NULL, NULL, 0, NULL, NULL, NULL,
G_TYPE_NONE, 0); G_TYPE_NONE, 0);
workspace_manager_signals[CONTEXT_SWITCHED] =
g_signal_new ("context-switched",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
workspace_manager_signals[CONTEXT_WINDOW_MOVED] =
g_signal_new("context-window-moved",
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 1,
META_TYPE_WINDOW);
workspace_manager_signals[CONTEXT_REMOVED] =
g_signal_new("context-removed",
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 1,
G_TYPE_INT);
g_object_class_install_property (object_class, g_object_class_install_property (object_class,
PROP_LAYOUT_COLUMNS, PROP_LAYOUT_COLUMNS,
g_param_spec_int ("layout-columns", NULL, NULL, g_param_spec_int ("layout-columns", NULL, NULL,
@ -182,6 +208,7 @@ meta_workspace_manager_class_init (MetaWorkspaceManagerClass *klass)
g_param_spec_int ("n-workspaces", NULL, NULL, g_param_spec_int ("n-workspaces", NULL, NULL,
1, G_MAXINT, 1, 1, G_MAXINT, 1,
G_PARAM_READABLE)); G_PARAM_READABLE));
} }
static void static void
@ -194,7 +221,7 @@ meta_workspace_manager_reload_work_areas (MetaWorkspaceManager *workspace_manage
{ {
GList *l; GList *l;
for (l = workspace_manager->workspaces; l; l = l->next) for (l = workspace_manager->all_workspaces; l; l = l->next)
{ {
MetaWorkspace *workspace = l->data; MetaWorkspace *workspace = l->data;
@ -211,12 +238,24 @@ meta_workspace_manager_new (MetaDisplay *display)
workspace_manager->display = display; workspace_manager->display = display;
workspace_manager->active_workspace = NULL; workspace_manager->active_workspace = NULL;
workspace_manager->all_workspaces = NULL;
workspace_manager->workspaces = NULL; workspace_manager->workspaces = NULL;
workspace_manager->rows_of_workspaces = 1; workspace_manager->rows_of_workspaces = 1;
workspace_manager->columns_of_workspaces = -1; workspace_manager->columns_of_workspaces = -1;
workspace_manager->vertical_workspaces = FALSE; workspace_manager->vertical_workspaces = FALSE;
workspace_manager->starting_corner = META_DISPLAY_TOPLEFT; workspace_manager->starting_corner = META_DISPLAY_TOPLEFT;
workspace_manager->context_list = NULL;
workspace_manager->active_context = NULL;
workspace_manager->next_context_id = 1;
workspace_manager->mutter_namespace = meta_read_pid_namespace (getpid());
MetaWorkspaceContext *context = meta_workspace_context_new (workspace_manager, NULL);
workspace_manager->workspaces = g_steal_pointer (&context->workspaces);
workspace_manager->active_workspace = g_steal_pointer (&context->active_workspace);
workspace_manager->active_context = context;
/* This is the default layout extracted from default /* This is the default layout extracted from default
* variable values in update_num_workspaces () * variable values in update_num_workspaces ()
* This can be overridden using _NET_DESKTOP_LAYOUT in * This can be overridden using _NET_DESKTOP_LAYOUT in
@ -227,11 +266,6 @@ meta_workspace_manager_new (MetaDisplay *display)
1, 1,
-1); -1);
/* There must be at least one workspace at all times,
* so create that required workspace.
*/
meta_workspace_new (workspace_manager);
meta_workspace_manager_init_workspaces (workspace_manager); meta_workspace_manager_init_workspaces (workspace_manager);
meta_prefs_add_listener (prefs_changed_callback, workspace_manager); meta_prefs_add_listener (prefs_changed_callback, workspace_manager);
@ -282,6 +316,9 @@ MetaWorkspace *
meta_workspace_manager_get_workspace_by_index (MetaWorkspaceManager *workspace_manager, meta_workspace_manager_get_workspace_by_index (MetaWorkspaceManager *workspace_manager,
int idx) int idx)
{ {
if ((idx >> 16) & 0xFFFF) {
return meta_workspace_manager_lookup_workspace_by_id (workspace_manager, idx);
}
return g_list_nth_data (workspace_manager->workspaces, idx); return g_list_nth_data (workspace_manager->workspaces, idx);
} }
@ -990,7 +1027,7 @@ meta_workspace_manager_unshow_desktop (MetaWorkspaceManager *workspace_manager)
GList * GList *
meta_workspace_manager_get_workspaces (MetaWorkspaceManager *workspace_manager) meta_workspace_manager_get_workspaces (MetaWorkspaceManager *workspace_manager)
{ {
return workspace_manager->workspaces; return workspace_manager->all_workspaces;
} }
int int
@ -1004,6 +1041,17 @@ meta_workspace_manager_get_active_workspace_index (MetaWorkspaceManager *workspa
return meta_workspace_index (active); return meta_workspace_index (active);
} }
int
meta_workspace_manager_get_active_workspace_id (MetaWorkspaceManager *workspace_manager)
{
MetaWorkspace *active = workspace_manager->active_workspace;
if (!active)
return -1;
return meta_workspace_get_id (active);
}
/** /**
* meta_workspace_manager_get_active_workspace: * meta_workspace_manager_get_active_workspace:
* @workspace_manager: A #MetaWorkspaceManager * @workspace_manager: A #MetaWorkspaceManager
@ -1022,10 +1070,16 @@ meta_workspace_manager_workspace_switched (MetaWorkspaceManager *workspace_manag
int to, int to,
MetaMotionDirection direction) MetaMotionDirection direction)
{ {
if (direction == META_MOTION_CONTEXT_SWITCH) {
g_signal_emit (workspace_manager,
workspace_manager_signals[CONTEXT_SWITCHED],
0, NULL);
} else {
g_signal_emit (workspace_manager, g_signal_emit (workspace_manager,
workspace_manager_signals[WORKSPACE_SWITCHED], 0, workspace_manager_signals[WORKSPACE_SWITCHED], 0,
from, to, direction); from, to, direction);
} }
}
static void static void
prefs_changed_callback (MetaPreference pref, prefs_changed_callback (MetaPreference pref,
@ -1063,3 +1117,353 @@ meta_workspace_manager_get_layout_rows (MetaWorkspaceManager *workspace_manager)
return workspace_manager->rows_of_workspaces; return workspace_manager->rows_of_workspaces;
} }
/**
* meta_workspace_manager_lookup_context:
* @workspace_manager: a #MetaWorkspaceManager
* @context_id: id value of context to look up
*
* Look up WorkspaceContext by id and return it. If no context is found with
* the specified id the return value is %NULL.
*
* Return value: (transfer none) (nullable): the workspace context with the specified id
* or %NULL if no context with matching id exists.
*/
MetaWorkspaceContext *
meta_workspace_manager_lookup_context (MetaWorkspaceManager *workspace_manager, guint context_id)
{
for (GList *iter = workspace_manager->context_list; iter; iter = iter->next) {
MetaWorkspaceContext *context = iter->data;
if (context_id == context->id) {
return context;
}
}
return NULL;
}
const char *
meta_workspace_manager_mutter_namespace (MetaWorkspaceManager *workspace_manager)
{
if (!workspace_manager->mutter_namespace) {
workspace_manager->mutter_namespace = meta_read_pid_namespace (getpid());
}
return workspace_manager->mutter_namespace;
}
/*
* Return pointer to the live workspace list depending on whether or not the context is currently active.
* While a workspace context is active, the list must be accessed through the pointer workspace_manager->workspaces
*/
GList **
meta_workspace_manager_workspace_list_for_context (MetaWorkspaceManager *workspace_manager, guint context_id)
{
if (workspace_manager->active_context && workspace_manager->active_context->id == context_id) {
return &workspace_manager->workspaces;
}
MetaWorkspaceContext *context = meta_workspace_manager_lookup_context (workspace_manager, context_id);
if (context) {
return &context->workspaces;
} else {
g_warning ("MetaWorkspaceManager: Failed to find context workspace list (context_id = %d)", context_id);
return NULL;
}
}
void
meta_workspace_manager_append_context_workspace (MetaWorkspaceManager *workspace_manager, MetaWorkspace *workspace)
{
GList **p_workspaces = meta_workspace_manager_workspace_list_for_context (workspace_manager, workspace->context_id);
if (p_workspaces) {
*p_workspaces = g_list_append (*p_workspaces, workspace);
}
}
void
meta_workspace_manager_remove_context_workspace (MetaWorkspaceManager *workspace_manager, MetaWorkspace *workspace)
{
GList **p_workspaces = meta_workspace_manager_workspace_list_for_context (workspace_manager, workspace->context_id);
if (p_workspaces) {
*p_workspaces = g_list_remove (*p_workspaces, workspace);
}
workspace_manager->all_workspaces = g_list_remove (workspace_manager->all_workspaces, workspace);
}
static int
workspace_index_in_context (MetaWorkspaceManager *workspace_manager, MetaWorkspace *workspace)
{
GList **p_workspaces = meta_workspace_manager_workspace_list_for_context (workspace_manager, workspace->context_id);
if (p_workspaces) {
return g_list_index (*p_workspaces, workspace);
} else {
g_warning ("MetaWorkspaceManager: Could not find context for id=%d in workspace_index_in_context()", workspace->context_id);
return -1;
}
}
int
meta_workspace_manager_get_workspace_id (MetaWorkspaceManager *workspace_manager, MetaWorkspace *workspace)
{
int idx = workspace_index_in_context (workspace_manager, workspace);
if (idx >= 0) {
idx |= (int)(workspace->context_id << 16);
} else {
g_warning ("MetaWorkspaceManager: Workspace with context_id = %d not found in meta_workspace_manager_get_workspace_id()", workspace->context_id);
}
return idx;
}
int
meta_workspace_manager_context_workspace_index (MetaWorkspaceManager *workspace_manager, MetaWorkspace *workspace)
{
if (!(workspace_manager->active_context && workspace_manager->active_context->id == workspace->context_id)) {
guint active = (workspace_manager->active_context) ? (workspace_manager->active_context->id) : 0;
g_warning ("MetaWorkspaceManager: context_workspace_index() called on workspace not in active context. (ws->context_id = %d, active->context_id=%d)",
workspace->context_id, active);
}
int idx = workspace_index_in_context (workspace_manager, workspace);
if (idx < 0) {
g_warning ("MetaWorkspaceManager: Failed to find workspace with context_id=%d in context_workspace_index()",
workspace->context_id);
}
return idx;
}
MetaWorkspace *
meta_workspace_manager_lookup_workspace_by_id (MetaWorkspaceManager *workspace_manager, int workspace_id)
{
uint context_id = (workspace_id >> 16) & 0xFFFF;
if (context_id) {
GList **p_workspaces = meta_workspace_manager_workspace_list_for_context (workspace_manager, context_id);
int idx = workspace_id & 0xFFFF;
if (p_workspaces) {
return g_list_nth_data (*p_workspaces, idx);
}
}
return NULL;
}
/**
* meta_workspace_manager_context_for_namespace:
* @workspace_manager: a #MetaWorkspaceManager
* @namespace: namespace of context
*
* Find an existing WorkspaceContext for the specified namespace. If no WorkspaceContext
* currently exists for namespace create a new one.
*
* Return value: (transfer none): the workspace context for the specified namespace
*/
MetaWorkspaceContext *
meta_workspace_manager_context_for_namespace (MetaWorkspaceManager *workspace_manager, const gchar *namespace)
{
MetaWorkspaceContext *anonymous_context = NULL;
for (GList *iter = workspace_manager->context_list; iter; iter = iter->next) {
MetaWorkspaceContext *context = iter->data;
if (context->namespace == NULL && anonymous_context == NULL) {
anonymous_context = context;
} else if (!g_strcmp0 (context->namespace, namespace )) {
return context;
}
}
if (anonymous_context) {
anonymous_context->namespace = g_strdup (namespace);
return anonymous_context;
}
return meta_workspace_context_new (workspace_manager, namespace);
}
guint
meta_workspace_manager_active_context_id (MetaWorkspaceManager *workspace_manager)
{
if (workspace_manager->active_context) {
return workspace_manager->active_context->id;
} else {
return 0;
}
}
G_DEFINE_TYPE (MetaWorkspaceContext, meta_workspace_context, G_TYPE_OBJECT)
guint
meta_workspace_context_id (MetaWorkspaceContext *context)
{
return context->id;
}
void
meta_workspace_context_remove (MetaWorkspaceContext *context)
{
if (meta_workspace_context_is_current (context)) {
g_warning ("MetaWorkspaceManager: attempt to remove active context ignored");
return;
}
for (GList *iter = context->workspaces; iter; iter = iter->next) {
MetaWorkspace *workspace = iter->data;
meta_workspace_relocate_windows (workspace, context->manager->active_workspace);
}
context->active_workspace = NULL;
g_list_free_full (g_steal_pointer(&context->workspaces), (GDestroyNotify) meta_workspace_remove);
g_signal_emit (context->manager, workspace_manager_signals[CONTEXT_REMOVED],
0, context->id);
g_clear_pointer (&context->namespace, g_free);
context->manager->context_list = g_list_remove (context->manager->context_list, context);
g_object_unref (context);
}
static void
meta_workspace_context_class_init (MetaWorkspaceContextClass *klass)
{
}
static void
meta_workspace_context_init (MetaWorkspaceContext *context)
{
}
MetaWorkspaceContext *
meta_workspace_context_new (MetaWorkspaceManager *manager, const char *namespace)
{
guint context_id = manager->next_context_id++;
MetaWorkspaceContext *context = g_object_new (META_TYPE_WORKSPACE_CONTEXT, NULL);
context->manager = manager;
context->workspaces = NULL;
context->active_workspace = NULL;
context->namespace = NULL;
context->id = context_id;
if (namespace) {
context->namespace = g_strdup (namespace);
}
manager->context_list = g_list_append (manager->context_list, context);
context->active_workspace = meta_workspace_new_with_context_id (manager, context_id);
g_object_notify (G_OBJECT (manager), "n-workspaces");
return context;
}
/*
* Synchronize the state stored in the MetaWorkspaceManager to 'context'
* by copying the relevant fields to the WorkspaceContext structure.
*
* The state which is saved is the list of workspaces and the active
* workspace pointer:
*
* workspace_manager->active_workspace
* workspace_manager->workspaces
*/
static void
workspace_context_sync_manager_state (MetaWorkspaceContext *context)
{
context->active_workspace = context->manager->active_workspace;
context->workspaces = context->manager->workspaces;
}
gboolean
meta_workspace_context_is_current (MetaWorkspaceContext *context)
{
return context && context->manager->active_context == context;
}
/**
* meta_workspace_context_get_active_workspace:
* @context: A #MetaWorkspaceContext
*
* Returns: (transfer none): The current workspace for this context
*/
MetaWorkspace *
meta_workspace_context_get_active_workspace (MetaWorkspaceContext *context)
{
if (meta_workspace_context_is_current (context)) {
return context->manager->active_workspace;
} else {
return context->active_workspace;
}
}
void
meta_workspace_context_move_window_to_context (MetaWorkspaceContext *context, MetaWindow *window)
{
if (!context->active_workspace) {
g_warning ("MetaWorkspaceContext: Cannot move window to context (%d) because no workspace is active", context->id);
return;
}
if (window->workspace->context_id != context->id) {
meta_window_change_workspace (window, context->active_workspace);
g_signal_emit (context->manager, workspace_manager_signals[CONTEXT_WINDOW_MOVED], 0, window);
}
}
void
meta_workspace_context_make_active (MetaWorkspaceContext *context) {
MetaWorkspaceManager *manager = context->manager;
workspace_context_sync_manager_state (manager->active_context);
manager->active_context = context;
/*
* Do not update manager->active_workspace because meta_workspace_activate() expects
* old value
*/
/* steal pointer to avoid writing code elsewhere that changes this list while context is active */
manager->workspaces = g_steal_pointer (&context->workspaces);
}
/*
* Activate a WorkspaceContext instance by copying the context state fields
* into the MetaWorkspaceManager structure.
*
* If 'context' is already the current WorkspaceContext do nothing.
*
* If some other context is active, save the context fields by calling
*
* workspace_context_sync_manager_state()
*/
void
meta_workspace_context_activate (MetaWorkspaceContext *context)
{
if (meta_workspace_context_is_current (context)) {
return;
}
meta_workspace_context_make_active (context);
guint32 timestamp;
timestamp = meta_display_get_current_time_roundtrip (context->manager->display);
/* Will set manager->active_workspace from context->active_workspace */
meta_workspace_activate ( g_steal_pointer (&context->active_workspace), timestamp);
}
gboolean
meta_workspace_manager_is_window_on_foreign_context (MetaWorkspaceManager *workspace_manager, MetaWindow *window)
{
const char *ns = meta_window_namespace (window);
if (!ns || !g_strcmp0 (ns, workspace_manager->mutter_namespace) || !window->workspace) {
return FALSE;
}
MetaWorkspaceContext *context = meta_workspace_manager_context_for_namespace (workspace_manager, ns);
return context->id != window->workspace->context_id;
}

View File

@ -55,3 +55,6 @@ meta_timeval_to_microseconds (const struct timeval *tv)
#define META_CONTAINER_OF(ptr, type, member) \ #define META_CONTAINER_OF(ptr, type, member) \
(type *) ((uint8_t *) (ptr) - G_STRUCT_OFFSET (type, member)) (type *) ((uint8_t *) (ptr) - G_STRUCT_OFFSET (type, member))
char * meta_read_pid_namespace (pid_t pid);

View File

@ -598,3 +598,50 @@ meta_log (const char *format, ...)
g_logv (G_LOG_DOMAIN, mutter_log_level, format, args); g_logv (G_LOG_DOMAIN, mutter_log_level, format, args);
va_end (args); va_end (args);
} }
static GFileInfo *
pid_namespace_file_info (pid_t pid)
{
char *filename = g_strdup_printf("/proc/%u/ns/pid", pid);
GFile *file = g_file_new_for_path(filename);
g_free(filename);
GError *error = NULL;
GFileInfo *info = g_file_query_info(file,
G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK "," G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
NULL,
&error);
g_object_unref(file);
if (info == NULL) {
g_warning("MetaWindow: Error attempting to read /proc/%u/ns/pid symlink: %s", pid, error->message);
g_error_free (error);
return NULL;
}
if (!g_file_info_get_is_symlink (info)) {
g_warning("MetaWindow: /proc/%u/ns/pid exists but is not a symlink?", pid);
g_object_unref (info);
return NULL;
}
return info;
}
char *
meta_read_pid_namespace (pid_t pid)
{
char *value = NULL;
GFileInfo *info = pid_namespace_file_info (pid);
const char *target = g_file_info_get_symlink_target (info);
if (target) {
value = g_strdup (target);
}
g_object_unref (info);
return value;
}

View File

@ -558,6 +558,10 @@ struct _MetaWindow
guint is_alive : 1; guint is_alive : 1;
guint in_workspace_change : 1; guint in_workspace_change : 1;
guint namespace_set: 1;
gchar *namespace;
}; };
struct _MetaWindowClass struct _MetaWindowClass

View File

@ -336,6 +336,7 @@ meta_window_finalize (GObject *object)
g_free (window->gtk_app_menu_object_path); g_free (window->gtk_app_menu_object_path);
g_free (window->gtk_menubar_object_path); g_free (window->gtk_menubar_object_path);
g_free (window->placement.rule); g_free (window->placement.rule);
g_free (window->namespace);
G_OBJECT_CLASS (meta_window_parent_class)->finalize (object); G_OBJECT_CLASS (meta_window_parent_class)->finalize (object);
} }
@ -1514,7 +1515,7 @@ meta_window_unmanage (MetaWindow *window,
g_assert (window->workspace == NULL); g_assert (window->workspace == NULL);
#ifndef G_DISABLE_CHECKS #ifndef G_DISABLE_CHECKS
tmp = workspace_manager->workspaces; tmp = workspace_manager->all_workspaces;
while (tmp != NULL) while (tmp != NULL)
{ {
MetaWorkspace *workspace = tmp->data; MetaWorkspace *workspace = tmp->data;
@ -4741,7 +4742,7 @@ set_workspace_state (MetaWindow *window,
else if (window->on_all_workspaces) else if (window->on_all_workspaces)
{ {
GList *l; GList *l;
for (l = workspace_manager->workspaces; l != NULL; l = l->next) for (l = workspace_manager->all_workspaces; l != NULL; l = l->next)
{ {
MetaWorkspace *ws = l->data; MetaWorkspace *ws = l->data;
meta_workspace_remove_window (ws, window); meta_workspace_remove_window (ws, window);
@ -4756,7 +4757,7 @@ set_workspace_state (MetaWindow *window,
else if (window->on_all_workspaces) else if (window->on_all_workspaces)
{ {
GList *l; GList *l;
for (l = workspace_manager->workspaces; l != NULL; l = l->next) for (l = workspace_manager->all_workspaces; l != NULL; l = l->next)
{ {
MetaWorkspace *ws = l->data; MetaWorkspace *ws = l->data;
meta_workspace_add_window (ws, window); meta_workspace_add_window (ws, window);
@ -5141,8 +5142,10 @@ meta_window_change_workspace_by_index (MetaWindow *window,
workspace = workspace =
meta_workspace_manager_get_workspace_by_index (workspace_manager, space_index); meta_workspace_manager_get_workspace_by_index (workspace_manager, space_index);
if (!workspace && append) if (!workspace && append) {
workspace = meta_workspace_manager_append_new_workspace (workspace_manager, FALSE, META_CURRENT_TIME); workspace = meta_workspace_manager_append_new_workspace (workspace_manager, FALSE, META_CURRENT_TIME);
}
if (workspace) if (workspace)
meta_window_change_workspace (window, workspace); meta_window_change_workspace (window, workspace);
@ -5371,7 +5374,7 @@ meta_window_get_workspaces (MetaWindow *window)
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager; MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
if (window->on_all_workspaces) if (window->on_all_workspaces)
return workspace_manager->workspaces; return workspace_manager->all_workspaces;
else if (window->workspace != NULL) else if (window->workspace != NULL)
return window->workspace->list_containing_self; return window->workspace->list_containing_self;
else if (window->constructing) else if (window->constructing)
@ -7761,3 +7764,32 @@ meta_get_window_suspend_timeout_s (void)
{ {
return SUSPEND_HIDDEN_TIMEOUT_S; return SUSPEND_HIDDEN_TIMEOUT_S;
} }
/**
* meta_window_namespace:
* @window: a #MetaWindow
*
* Returns string identifying PID namespace this window belongs to
* if known
*
* Return value: (transfer none): the pid namespace string, or %NULL
*/
const char *
meta_window_namespace (MetaWindow *window)
{
if (!window->namespace_set) {
window->namespace_set = TRUE;
pid_t pid = meta_window_get_pid (window);
if (pid) {
window->namespace = meta_read_pid_namespace (pid);
}
}
return window->namespace;
}
gboolean
meta_window_is_on_foreign_workspace_context (MetaWindow *window)
{
return meta_workspace_manager_is_window_on_foreign_context (window->display->workspace_manager, window);
}

View File

@ -38,6 +38,7 @@ struct _MetaWorkspace
GObject parent_instance; GObject parent_instance;
MetaDisplay *display; MetaDisplay *display;
MetaWorkspaceManager *manager; MetaWorkspaceManager *manager;
guint context_id;
GList *windows; GList *windows;
@ -73,6 +74,8 @@ struct _MetaWorkspaceClass
}; };
MetaWorkspace* meta_workspace_new (MetaWorkspaceManager *workspace_manager); MetaWorkspace* meta_workspace_new (MetaWorkspaceManager *workspace_manager);
MetaWorkspace* meta_workspace_new_with_context_id (MetaWorkspaceManager *workspace_manager,
guint context_id);
void meta_workspace_remove (MetaWorkspace *workspace); void meta_workspace_remove (MetaWorkspace *workspace);
void meta_workspace_add_window (MetaWorkspace *workspace, void meta_workspace_add_window (MetaWorkspace *workspace,
MetaWindow *window); MetaWindow *window);

View File

@ -208,7 +208,7 @@ meta_workspace_init (MetaWorkspace *workspace)
} }
MetaWorkspace * MetaWorkspace *
meta_workspace_new (MetaWorkspaceManager *workspace_manager) meta_workspace_new_with_context_id (MetaWorkspaceManager *workspace_manager, guint context_id)
{ {
MetaDisplay *display = workspace_manager->display; MetaDisplay *display = workspace_manager->display;
MetaWorkspace *workspace; MetaWorkspace *workspace;
@ -218,9 +218,11 @@ meta_workspace_new (MetaWorkspaceManager *workspace_manager)
workspace->display = display; workspace->display = display;
workspace->manager = workspace_manager; workspace->manager = workspace_manager;
workspace->context_id = context_id;
workspace_manager->all_workspaces =
g_list_append (workspace_manager->all_workspaces, workspace);
workspace_manager->workspaces =
g_list_append (workspace_manager->workspaces, workspace);
workspace->windows = NULL; workspace->windows = NULL;
workspace->mru_list = NULL; workspace->mru_list = NULL;
@ -247,9 +249,17 @@ meta_workspace_new (MetaWorkspaceManager *workspace_manager)
meta_workspace_add_window (workspace, l->data); meta_workspace_add_window (workspace, l->data);
g_slist_free (windows); g_slist_free (windows);
meta_workspace_manager_append_context_workspace (workspace_manager, workspace);
return workspace; return workspace;
} }
MetaWorkspace *
meta_workspace_new (MetaWorkspaceManager *workspace_manager)
{
return meta_workspace_new_with_context_id (workspace_manager, workspace_manager->active_context->id);
}
/** /**
* workspace_free_all_struts: * workspace_free_all_struts:
* @workspace: The workspace. * @workspace: The workspace.
@ -304,8 +314,7 @@ meta_workspace_remove (MetaWorkspace *workspace)
assert_workspace_empty (workspace); assert_workspace_empty (workspace);
manager->workspaces = meta_workspace_manager_remove_context_workspace (manager, workspace);
g_list_remove (manager->workspaces, workspace);
meta_workspace_clear_logical_monitor_data (workspace); meta_workspace_clear_logical_monitor_data (workspace);
@ -374,8 +383,8 @@ meta_workspace_add_window (MetaWorkspace *workspace,
if (window->struts) if (window->struts)
{ {
meta_topic (META_DEBUG_WORKAREA, meta_topic (META_DEBUG_WORKAREA,
"Invalidating work area of workspace %d since we're adding window %s to it", "Invalidating work area of workspace %08x since we're adding window %s to it",
meta_workspace_index (workspace), window->desc); meta_workspace_get_id (workspace), window->desc);
meta_workspace_invalidate_work_area (workspace); meta_workspace_invalidate_work_area (workspace);
} }
@ -403,8 +412,8 @@ meta_workspace_remove_window (MetaWorkspace *workspace,
if (window->struts) if (window->struts)
{ {
meta_topic (META_DEBUG_WORKAREA, meta_topic (META_DEBUG_WORKAREA,
"Invalidating work area of workspace %d since we're removing window %s from it", "Invalidating work area of workspace %08x since we're removing window %s from it",
meta_workspace_index (workspace), window->desc); meta_workspace_get_id (workspace), window->desc);
meta_workspace_invalidate_work_area (workspace); meta_workspace_invalidate_work_area (workspace);
} }
@ -460,6 +469,11 @@ workspace_switch_sound (MetaWorkspace *from,
int x, y; int x, y;
const char *sound_name; const char *sound_name;
if (from->context_id != to->context_id) {
/* XXX: There is no sound for context switches, but there should be (?) */
return;
}
n_workspaces = meta_workspace_manager_get_n_workspaces (from->manager); n_workspaces = meta_workspace_manager_get_n_workspaces (from->manager);
from_idx = meta_workspace_index(from); from_idx = meta_workspace_index(from);
to_idx = meta_workspace_index(to); to_idx = meta_workspace_index(to);
@ -544,13 +558,19 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
MetaWorkspaceLayout layout1, layout2; MetaWorkspaceLayout layout1, layout2;
gint num_workspaces, current_space, new_space; gint num_workspaces, current_space, new_space;
MetaMotionDirection direction; MetaMotionDirection direction;
MetaWorkspaceContext *context;
MetaWindowDrag *window_drag; MetaWindowDrag *window_drag;
g_return_if_fail (META_IS_WORKSPACE (workspace)); g_return_if_fail (META_IS_WORKSPACE (workspace));
g_return_if_fail (meta_workspace_index (workspace) != -1); g_return_if_fail (meta_workspace_index (workspace) != -1);
meta_verbose ("Activating workspace %d", meta_verbose ("Activating workspace %08x",
meta_workspace_index (workspace)); meta_workspace_get_id (workspace));
context = meta_workspace_manager_lookup_context (workspace->manager, workspace->context_id);
if(context && !meta_workspace_context_is_current (context)) {
meta_workspace_context_make_active (context);
}
if (workspace->manager->active_workspace == workspace) if (workspace->manager->active_workspace == workspace)
{ {
@ -618,6 +638,12 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
comp = meta_display_get_compositor (workspace->display); comp = meta_display_get_compositor (workspace->display);
direction = 0; direction = 0;
if (workspace->context_id != old->context_id) {
direction = META_MOTION_CONTEXT_SWITCH;
current_space = meta_workspace_get_id (old);
new_space = meta_workspace_get_id (workspace);
} else {
current_space = meta_workspace_index (old); current_space = meta_workspace_index (old);
new_space = meta_workspace_index (workspace); new_space = meta_workspace_index (workspace);
num_workspaces = meta_workspace_manager_get_n_workspaces (workspace->manager); num_workspaces = meta_workspace_manager_get_n_workspaces (workspace->manager);
@ -664,6 +690,7 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
meta_workspace_manager_free_workspace_layout (&layout1); meta_workspace_manager_free_workspace_layout (&layout1);
meta_workspace_manager_free_workspace_layout (&layout2); meta_workspace_manager_free_workspace_layout (&layout2);
}
meta_compositor_switch_workspace (comp, old, workspace, direction); meta_compositor_switch_workspace (comp, old, workspace, direction);
@ -701,15 +728,19 @@ meta_workspace_activate (MetaWorkspace *workspace,
int int
meta_workspace_index (MetaWorkspace *workspace) meta_workspace_index (MetaWorkspace *workspace)
{ {
int ret; return meta_workspace_manager_context_workspace_index (workspace->manager, workspace);
}
g_return_val_if_fail (META_IS_WORKSPACE (workspace), -1); int
meta_workspace_get_id (MetaWorkspace *workspace)
{
return meta_workspace_manager_get_workspace_id (workspace->manager, workspace);
}
ret = g_list_index (workspace->manager->workspaces, workspace); guint
meta_workspace_get_context_id (MetaWorkspace *workspace)
g_return_val_if_fail (ret >= 0, -1); {
return workspace->context_id;
return ret;
} }
void void
@ -767,14 +798,14 @@ meta_workspace_invalidate_work_area (MetaWorkspace *workspace)
if (workspace->work_areas_invalid) if (workspace->work_areas_invalid)
{ {
meta_topic (META_DEBUG_WORKAREA, meta_topic (META_DEBUG_WORKAREA,
"Work area for workspace %d is already invalid", "Work area for workspace %08x is already invalid",
meta_workspace_index (workspace)); meta_workspace_get_id (workspace));
return; return;
} }
meta_topic (META_DEBUG_WORKAREA, meta_topic (META_DEBUG_WORKAREA,
"Invalidating work area for workspace %d", "Invalidating work area for workspace %08x",
meta_workspace_index (workspace)); meta_workspace_get_id (workspace));
window_drag = window_drag =
meta_compositor_get_current_window_drag (workspace->display->compositor); meta_compositor_get_current_window_drag (workspace->display->compositor);
@ -950,8 +981,8 @@ ensure_work_areas_validated (MetaWorkspace *workspace)
} }
workspace->work_area_screen = work_area; workspace->work_area_screen = work_area;
meta_topic (META_DEBUG_WORKAREA, meta_topic (META_DEBUG_WORKAREA,
"Computed work area for workspace %d: %d,%d %d x %d", "Computed work area for workspace %08x: %d,%d %d x %d",
meta_workspace_index (workspace), meta_workspace_get_id (workspace),
workspace->work_area_screen.x, workspace->work_area_screen.x,
workspace->work_area_screen.y, workspace->work_area_screen.y,
workspace->work_area_screen.width, workspace->work_area_screen.width,
@ -981,8 +1012,8 @@ ensure_work_areas_validated (MetaWorkspace *workspace)
meta_topic (META_DEBUG_WORKAREA, meta_topic (META_DEBUG_WORKAREA,
"Computed work area for workspace %d " "Computed work area for workspace %d "
"monitor %d: %d,%d %d x %d", "monitor %08x: %d,%d %d x %d",
meta_workspace_index (workspace), meta_workspace_get_id (workspace),
logical_monitor->number, logical_monitor->number,
data->logical_monitor_work_area.x, data->logical_monitor_work_area.x,
data->logical_monitor_work_area.y, data->logical_monitor_work_area.y,
@ -1226,6 +1257,8 @@ meta_motion_direction_to_string (MetaMotionDirection direction)
return "Up-Left"; return "Up-Left";
case META_MOTION_DOWN_LEFT: case META_MOTION_DOWN_LEFT:
return "Down-Left"; return "Down-Left";
case META_MOTION_CONTEXT_SWITCH:
return "Switch-Context";
} }
return "Unknown"; return "Unknown";

View File

@ -228,6 +228,7 @@ typedef enum
* @META_MOTION_UP_RIGHT: Motion up and to the right * @META_MOTION_UP_RIGHT: Motion up and to the right
* @META_MOTION_DOWN_LEFT: Motion down and to the left * @META_MOTION_DOWN_LEFT: Motion down and to the left
* @META_MOTION_DOWN_RIGHT: Motion down and to the right * @META_MOTION_DOWN_RIGHT: Motion down and to the right
* @META_MOTION_CONTEXT_SWITCH: Workspace switch is a change of current realm
*/ */
/* Negative to avoid conflicting with real workspace /* Negative to avoid conflicting with real workspace
@ -243,7 +244,8 @@ typedef enum
META_MOTION_UP_LEFT = -5, META_MOTION_UP_LEFT = -5,
META_MOTION_UP_RIGHT = -6, META_MOTION_UP_RIGHT = -6,
META_MOTION_DOWN_LEFT = -7, META_MOTION_DOWN_LEFT = -7,
META_MOTION_DOWN_RIGHT = -8 META_MOTION_DOWN_RIGHT = -8,
META_MOTION_CONTEXT_SWITCH = -9,
} MetaMotionDirection; } MetaMotionDirection;
/** /**

View File

@ -29,6 +29,14 @@
#include "meta/prefs.h" #include "meta/prefs.h"
#include "meta/types.h" #include "meta/types.h"
#define META_TYPE_WORKSPACE_CONTEXT (meta_workspace_context_get_type ())
META_EXPORT
G_DECLARE_FINAL_TYPE (MetaWorkspaceContext,
meta_workspace_context,
META, WORKSPACE_CONTEXT,
GObject)
#define META_TYPE_WORKSPACE_MANAGER (meta_workspace_manager_get_type ()) #define META_TYPE_WORKSPACE_MANAGER (meta_workspace_manager_get_type ())
META_EXPORT META_EXPORT
@ -65,6 +73,9 @@ void meta_workspace_manager_reorder_workspace (MetaWorkspaceManager *workspace_m
META_EXPORT META_EXPORT
int meta_workspace_manager_get_active_workspace_index (MetaWorkspaceManager *workspace_manager); int meta_workspace_manager_get_active_workspace_index (MetaWorkspaceManager *workspace_manager);
META_EXPORT
int meta_workspace_manager_get_active_workspace_id (MetaWorkspaceManager *workspace_manager);
META_EXPORT META_EXPORT
MetaWorkspace *meta_workspace_manager_get_active_workspace (MetaWorkspaceManager *workspace_manager); MetaWorkspace *meta_workspace_manager_get_active_workspace (MetaWorkspaceManager *workspace_manager);
@ -80,3 +91,32 @@ int meta_workspace_manager_get_layout_columns (MetaWorkspaceManager *workspace_m
META_EXPORT META_EXPORT
int meta_workspace_manager_get_layout_rows (MetaWorkspaceManager *workspace_manager); int meta_workspace_manager_get_layout_rows (MetaWorkspaceManager *workspace_manager);
META_EXPORT
guint meta_workspace_manager_active_context_id (MetaWorkspaceManager *workspace_manager);
META_EXPORT
MetaWorkspaceContext *meta_workspace_manager_context_for_namespace (MetaWorkspaceManager *workspace_manager,
const gchar *namespace);
META_EXPORT
const char *meta_workspace_manager_mutter_namespace (MetaWorkspaceManager *workspace_manager);
META_EXPORT
void meta_workspace_context_activate (MetaWorkspaceContext *context);
META_EXPORT
void meta_workspace_context_remove (MetaWorkspaceContext *context);
META_EXPORT
gboolean meta_workspace_context_is_current (MetaWorkspaceContext *context);
META_EXPORT
MetaWorkspace *
meta_workspace_context_get_active_workspace (MetaWorkspaceContext *context);
META_EXPORT
guint meta_workspace_context_id (MetaWorkspaceContext *context);
META_EXPORT
void meta_workspace_context_move_window_to_context (MetaWorkspaceContext *context, MetaWindow *window);

View File

@ -36,5 +36,6 @@ typedef struct _MetaCursorTracker MetaCursorTracker;
typedef struct _MetaDnd MetaDnd; typedef struct _MetaDnd MetaDnd;
typedef struct _MetaSettings MetaSettings; typedef struct _MetaSettings MetaSettings;
typedef struct _MetaWorkspaceContext MetaWorkspaceContext;
typedef struct _MetaWorkspaceManager MetaWorkspaceManager; typedef struct _MetaWorkspaceManager MetaWorkspaceManager;
typedef struct _MetaSelection MetaSelection; typedef struct _MetaSelection MetaSelection;

View File

@ -440,3 +440,10 @@ MetaWindowClientType meta_window_get_client_type (MetaWindow *window);
META_EXPORT META_EXPORT
gboolean meta_window_has_pointer (MetaWindow *window); gboolean meta_window_has_pointer (MetaWindow *window);
META_EXPORT
const char *meta_window_namespace (MetaWindow *window);
META_EXPORT
gboolean meta_window_is_on_foreign_workspace_context (MetaWindow *window);

View File

@ -38,6 +38,12 @@ GType meta_workspace_get_type (void);
META_EXPORT META_EXPORT
int meta_workspace_index (MetaWorkspace *workspace); int meta_workspace_index (MetaWorkspace *workspace);
META_EXPORT
int meta_workspace_get_id (MetaWorkspace *workspace);
META_EXPORT
guint meta_workspace_get_context_id (MetaWorkspace *workspace);
META_EXPORT META_EXPORT
MetaDisplay *meta_workspace_get_display (MetaWorkspace *workspace); MetaDisplay *meta_workspace_get_display (MetaWorkspace *workspace);