Citadel changes to Mutter

This commit is contained in:
Bruce Leidl 2021-12-03 14:07:17 -05:00
parent 94bd385bf3
commit 56e7b774e9
15 changed files with 768 additions and 81 deletions

View File

@ -641,8 +641,13 @@ meta_compositor_switch_workspace (MetaCompositor *compositor,
meta_compositor_get_instance_private (compositor);
gint to_indx, from_indx;
to_indx = meta_workspace_index (to);
from_indx = meta_workspace_index (from);
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);
from_indx = meta_workspace_index (from);
}
priv->switch_workspace_in_progress++;

View File

@ -30,6 +30,36 @@
#include "meta/types.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
{
GObject parent;
@ -37,8 +67,21 @@ struct _MetaWorkspaceManager
MetaDisplay *display;
MetaWorkspace *active_workspace;
GList *all_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 columns_of_workspaces;
MetaDisplayCorner starting_corner;
@ -93,4 +136,30 @@ void meta_workspace_manager_update_num_workspaces (MetaWorkspaceManager *workspa
guint32 timestamp,
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);
#endif /* META_WORKSPACE_MANAGER_PRIVATE_H */

View File

@ -44,6 +44,9 @@ enum
WORKSPACES_REORDERED,
ACTIVE_WORKSPACE_CHANGED,
SHOWING_DESKTOP_CHANGED,
CONTEXT_SWITCHED,
CONTEXT_WINDOW_MOVED,
CONTEXT_REMOVED,
LAST_SIGNAL
};
@ -178,6 +181,29 @@ meta_workspace_manager_class_init (MetaWorkspaceManagerClass *klass)
0, NULL, NULL, NULL,
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,
PROP_LAYOUT_COLUMNS,
g_param_spec_int ("layout-columns",
@ -201,6 +227,7 @@ meta_workspace_manager_class_init (MetaWorkspaceManagerClass *klass)
"Number of workspaces",
1, G_MAXINT, 1,
G_PARAM_READABLE));
}
static void
@ -213,7 +240,7 @@ meta_workspace_manager_reload_work_areas (MetaWorkspaceManager *workspace_manage
{
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;
@ -230,12 +257,24 @@ meta_workspace_manager_new (MetaDisplay *display)
workspace_manager->display = display;
workspace_manager->active_workspace = NULL;
workspace_manager->all_workspaces = NULL;
workspace_manager->workspaces = NULL;
workspace_manager->rows_of_workspaces = 1;
workspace_manager->columns_of_workspaces = -1;
workspace_manager->vertical_workspaces = FALSE;
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
* variable values in update_num_workspaces ()
* This can be overridden using _NET_DESKTOP_LAYOUT in
@ -246,11 +285,6 @@ meta_workspace_manager_new (MetaDisplay *display)
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_prefs_add_listener (prefs_changed_callback, workspace_manager);
@ -301,6 +335,9 @@ MetaWorkspace *
meta_workspace_manager_get_workspace_by_index (MetaWorkspaceManager *workspace_manager,
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);
}
@ -1009,7 +1046,7 @@ meta_workspace_manager_unshow_desktop (MetaWorkspaceManager *workspace_manager)
GList *
meta_workspace_manager_get_workspaces (MetaWorkspaceManager *workspace_manager)
{
return workspace_manager->workspaces;
return workspace_manager->all_workspaces;
}
int
@ -1023,6 +1060,17 @@ meta_workspace_manager_get_active_workspace_index (MetaWorkspaceManager *workspa
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:
* @workspace_manager: A #MetaWorkspaceManager
@ -1041,9 +1089,15 @@ meta_workspace_manager_workspace_switched (MetaWorkspaceManager *workspace_manag
int to,
MetaMotionDirection direction)
{
g_signal_emit (workspace_manager,
workspace_manager_signals[WORKSPACE_SWITCHED], 0,
from, to, 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,
workspace_manager_signals[WORKSPACE_SWITCHED], 0,
from, to, direction);
}
}
static void
@ -1066,3 +1120,379 @@ prefs_changed_callback (MetaPreference pref,
timestamp, new_num);
}
}
/**
* meta_workspace_manager_set_builtin_struts_all:
* @workspace_manager: a #MetaWorkspaceManager
* @struts: (element-type Meta.Strut) (transfer none): list of #MetaStrut
*
* Sets a list of struts on every workspace that will be used in addition to the struts
* of the windows in the workspace when computing the work area of
* the workspace.
*/
void meta_workspace_manager_set_builtin_struts_all(MetaWorkspaceManager *workspace_manager,
GSList *struts)
{
GList *context_iter = workspace_manager->context_list;
while (context_iter) {
MetaWorkspaceContext *context = context_iter->data;
for (GList *ws_iter = context->workspaces; ws_iter; ws_iter = ws_iter->next) {
MetaWorkspace *workspace = ws_iter->data;
meta_workspace_set_builtin_struts(workspace, struts);
}
context_iter = context_iter->next;
}
}
/**
* 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

@ -54,4 +54,6 @@ void meta_init_debug_utils (void);
(ycoord) >= (rect).y && \
(ycoord) < ((rect).y + (rect).height))
char * meta_read_pid_namespace (pid_t pid);
#endif

View File

@ -730,3 +730,51 @@ meta_get_debug_paint_flags (void)
{
return debug_paint_flags;
}
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

@ -561,6 +561,9 @@ struct _MetaWindow
gboolean has_valid_cgroup;
GFile *cgroup_path;
guint namespace_set: 1;
gchar *namespace;
unsigned int events_during_ping;
};

View File

@ -327,6 +327,7 @@ meta_window_finalize (GObject *object)
g_free (window->gtk_app_menu_object_path);
g_free (window->gtk_menubar_object_path);
g_free (window->placement.rule);
g_free (window->namespace);
G_OBJECT_CLASS (meta_window_parent_class)->finalize (object);
}
@ -1554,7 +1555,7 @@ meta_window_unmanage (MetaWindow *window,
g_assert (window->workspace == NULL);
#ifndef G_DISABLE_CHECKS
tmp = workspace_manager->workspaces;
tmp = workspace_manager->all_workspaces;
while (tmp != NULL)
{
MetaWorkspace *workspace = tmp->data;
@ -4606,7 +4607,7 @@ set_workspace_state (MetaWindow *window,
else if (window->on_all_workspaces)
{
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;
meta_workspace_remove_window (ws, window);
@ -4621,7 +4622,7 @@ set_workspace_state (MetaWindow *window,
else if (window->on_all_workspaces)
{
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;
meta_workspace_add_window (ws, window);
@ -4982,8 +4983,10 @@ meta_window_change_workspace_by_index (MetaWindow *window,
workspace =
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);
}
if (workspace)
meta_window_change_workspace (window, workspace);
@ -5265,7 +5268,7 @@ meta_window_get_workspaces (MetaWindow *window)
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
if (window->on_all_workspaces)
return workspace_manager->workspaces;
return workspace_manager->all_workspaces;
else if (window->workspace != NULL)
return window->workspace->list_containing_self;
else if (window->constructing)
@ -8603,3 +8606,31 @@ meta_window_calculate_bounds (MetaWindow *window,
return FALSE;
}
}
/**
* 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

@ -39,6 +39,7 @@ struct _MetaWorkspace
GObject parent_instance;
MetaDisplay *display;
MetaWorkspaceManager *manager;
guint context_id;
GList *windows;
@ -74,6 +75,8 @@ struct _MetaWorkspaceClass
};
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_add_window (MetaWorkspace *workspace,
MetaWindow *window);

View File

@ -237,7 +237,7 @@ meta_workspace_init (MetaWorkspace *workspace)
}
MetaWorkspace *
meta_workspace_new (MetaWorkspaceManager *workspace_manager)
meta_workspace_new_with_context_id (MetaWorkspaceManager *workspace_manager, guint context_id)
{
MetaDisplay *display = workspace_manager->display;
MetaWorkspace *workspace;
@ -247,9 +247,11 @@ meta_workspace_new (MetaWorkspaceManager *workspace_manager)
workspace->display = display;
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->mru_list = NULL;
@ -276,9 +278,17 @@ meta_workspace_new (MetaWorkspaceManager *workspace_manager)
meta_workspace_add_window (workspace, l->data);
g_slist_free (windows);
meta_workspace_manager_append_context_workspace (workspace_manager, 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: The workspace.
@ -333,8 +343,7 @@ meta_workspace_remove (MetaWorkspace *workspace)
assert_workspace_empty (workspace);
manager->workspaces =
g_list_remove (manager->workspaces, workspace);
meta_workspace_manager_remove_context_workspace (manager, workspace);
meta_workspace_clear_logical_monitor_data (workspace);
@ -403,8 +412,8 @@ meta_workspace_add_window (MetaWorkspace *workspace,
if (window->struts)
{
meta_topic (META_DEBUG_WORKAREA,
"Invalidating work area of workspace %d since we're adding window %s to it",
meta_workspace_index (workspace), window->desc);
"Invalidating work area of workspace %08x since we're adding window %s to it",
meta_workspace_get_id (workspace), window->desc);
meta_workspace_invalidate_work_area (workspace);
}
@ -432,8 +441,8 @@ meta_workspace_remove_window (MetaWorkspace *workspace,
if (window->struts)
{
meta_topic (META_DEBUG_WORKAREA,
"Invalidating work area of workspace %d since we're removing window %s from it",
meta_workspace_index (workspace), window->desc);
"Invalidating work area of workspace %08x since we're removing window %s from it",
meta_workspace_get_id (workspace), window->desc);
meta_workspace_invalidate_work_area (workspace);
}
@ -486,6 +495,11 @@ workspace_switch_sound(MetaWorkspace *from,
int i, nw, x, y, fi, ti;
const char *e;
if (from->context_id != to->context_id) {
/* XXX: There is no sound for context switches, but there should be (?) */
return;
}
nw = meta_workspace_manager_get_n_workspaces (from->manager);
fi = meta_workspace_index(from);
ti = meta_workspace_index(to);
@ -566,9 +580,15 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
MetaWorkspaceLayout layout1, layout2;
gint num_workspaces, current_space, new_space;
MetaMotionDirection direction;
MetaWorkspaceContext *context;
meta_verbose ("Activating workspace %d",
meta_workspace_index (workspace));
meta_verbose ("Activating workspace %08x",
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)
{
@ -631,52 +651,59 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
comp = meta_display_get_compositor (workspace->display);
direction = 0;
current_space = meta_workspace_index (old);
new_space = meta_workspace_index (workspace);
num_workspaces = meta_workspace_manager_get_n_workspaces (workspace->manager);
meta_workspace_manager_calc_workspace_layout (workspace->manager, num_workspaces,
current_space, &layout1);
meta_workspace_manager_calc_workspace_layout (workspace->manager, num_workspaces,
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);
new_space = meta_workspace_index (workspace);
num_workspaces = meta_workspace_manager_get_n_workspaces (workspace->manager);
meta_workspace_manager_calc_workspace_layout (workspace->manager, num_workspaces,
current_space, &layout1);
meta_workspace_manager_calc_workspace_layout (workspace->manager, num_workspaces,
new_space, &layout2);
if (meta_get_locale_direction () == META_LOCALE_DIRECTION_RTL)
{
if (layout1.current_col > layout2.current_col)
direction = META_MOTION_RIGHT;
else if (layout1.current_col < layout2.current_col)
direction = META_MOTION_LEFT;
}
else
{
if (layout1.current_col < layout2.current_col)
direction = META_MOTION_RIGHT;
else if (layout1.current_col > layout2.current_col)
direction = META_MOTION_LEFT;
}
if (meta_get_locale_direction () == META_LOCALE_DIRECTION_RTL)
{
if (layout1.current_col > layout2.current_col)
direction = META_MOTION_RIGHT;
else if (layout1.current_col < layout2.current_col)
direction = META_MOTION_LEFT;
}
else
{
if (layout1.current_col < layout2.current_col)
direction = META_MOTION_RIGHT;
else if (layout1.current_col > layout2.current_col)
direction = META_MOTION_LEFT;
}
if (layout1.current_row < layout2.current_row)
{
if (!direction)
direction = META_MOTION_DOWN;
else if (direction == META_MOTION_RIGHT)
direction = META_MOTION_DOWN_RIGHT;
else
direction = META_MOTION_DOWN_LEFT;
}
if (layout1.current_row < layout2.current_row)
{
if (!direction)
direction = META_MOTION_DOWN;
else if (direction == META_MOTION_RIGHT)
direction = META_MOTION_DOWN_RIGHT;
else
direction = META_MOTION_DOWN_LEFT;
}
if (layout1.current_row > layout2.current_row)
{
if (!direction)
direction = META_MOTION_UP;
else if (direction == META_MOTION_RIGHT)
direction = META_MOTION_UP_RIGHT;
else
direction = META_MOTION_UP_LEFT;
}
if (layout1.current_row > layout2.current_row)
{
if (!direction)
direction = META_MOTION_UP;
else if (direction == META_MOTION_RIGHT)
direction = META_MOTION_UP_RIGHT;
else
direction = META_MOTION_UP_LEFT;
}
meta_workspace_manager_free_workspace_layout (&layout1);
meta_workspace_manager_free_workspace_layout (&layout2);
meta_workspace_manager_free_workspace_layout (&layout1);
meta_workspace_manager_free_workspace_layout (&layout2);
}
meta_compositor_switch_workspace (comp, old, workspace, direction);
@ -714,12 +741,19 @@ meta_workspace_activate (MetaWorkspace *workspace,
int
meta_workspace_index (MetaWorkspace *workspace)
{
int ret;
return meta_workspace_manager_context_workspace_index (workspace->manager, workspace);
}
ret = g_list_index (workspace->manager->workspaces, workspace);
g_return_val_if_fail (ret >= 0, -1);
int
meta_workspace_get_id (MetaWorkspace *workspace)
{
return meta_workspace_manager_get_workspace_id (workspace->manager, workspace);
}
return ret;
guint
meta_workspace_get_context_id (MetaWorkspace *workspace)
{
return workspace->context_id;
}
void
@ -776,14 +810,14 @@ meta_workspace_invalidate_work_area (MetaWorkspace *workspace)
if (workspace->work_areas_invalid)
{
meta_topic (META_DEBUG_WORKAREA,
"Work area for workspace %d is already invalid",
meta_workspace_index (workspace));
"Work area for workspace %08x is already invalid",
meta_workspace_get_id (workspace));
return;
}
meta_topic (META_DEBUG_WORKAREA,
"Invalidating work area for workspace %d",
meta_workspace_index (workspace));
"Invalidating work area for workspace %08x",
meta_workspace_get_id (workspace));
/* If we are in the middle of a resize or move operation, we
* might have cached pointers to the workspace's edges */
@ -954,8 +988,8 @@ ensure_work_areas_validated (MetaWorkspace *workspace)
}
workspace->work_area_screen = work_area;
meta_topic (META_DEBUG_WORKAREA,
"Computed work area for workspace %d: %d,%d %d x %d",
meta_workspace_index (workspace),
"Computed work area for workspace %08x: %d,%d %d x %d",
meta_workspace_get_id (workspace),
workspace->work_area_screen.x,
workspace->work_area_screen.y,
workspace->work_area_screen.width,
@ -985,8 +1019,8 @@ ensure_work_areas_validated (MetaWorkspace *workspace)
meta_topic (META_DEBUG_WORKAREA,
"Computed work area for workspace %d "
"monitor %d: %d,%d %d x %d",
meta_workspace_index (workspace),
"monitor %08x: %d,%d %d x %d",
meta_workspace_get_id (workspace),
logical_monitor->number,
data->logical_monitor_work_area.x,
data->logical_monitor_work_area.y,
@ -1228,6 +1262,8 @@ meta_motion_direction_to_string (MetaMotionDirection direction)
return "Up-Left";
case META_MOTION_DOWN_LEFT:
return "Down-Left";
case META_MOTION_CONTEXT_SWITCH:
return "Switch-Context";
}
return "Unknown";

View File

@ -1039,6 +1039,7 @@ libmutter = shared_library(libmutter_name,
libmutter_dep = declare_dependency(
link_with: libmutter,
include_directories: mutter_includes,
sources: mutter_built_sources,
dependencies: [
libmutter_cogl_dep,
libmutter_clutter_dep,

View File

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

View File

@ -30,6 +30,14 @@
#include <meta/prefs.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 ())
META_EXPORT
@ -66,6 +74,9 @@ void meta_workspace_manager_reorder_workspace (MetaWorkspaceManager *workspace_m
META_EXPORT
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
MetaWorkspace *meta_workspace_manager_get_active_workspace (MetaWorkspaceManager *workspace_manager);
@ -75,4 +86,37 @@ void meta_workspace_manager_override_workspace_layout (MetaWorkspaceManager *wor
gboolean vertical_layout,
int n_rows,
int n_columns);
META_EXPORT
guint meta_workspace_manager_active_context_id (MetaWorkspaceManager *workspace_manager);
META_EXPORT
void meta_workspace_manager_set_builtin_struts_all(MetaWorkspaceManager *workspace_manager,
GSList *struts);
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);
#endif /* META_WORKSPACE_MANAGER_H */

View File

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

View File

@ -453,4 +453,10 @@ uint64_t meta_window_get_id (MetaWindow *window);
META_EXPORT
MetaWindowClientType meta_window_get_client_type (MetaWindow *window);
META_EXPORT
const char *meta_window_namespace (MetaWindow *window);
META_EXPORT
gboolean meta_window_is_on_foreign_workspace_context (MetaWindow *window);
#endif

View File

@ -39,6 +39,12 @@ GType meta_workspace_get_type (void);
META_EXPORT
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
MetaDisplay *meta_workspace_get_display (MetaWorkspace *workspace);