/* workspace object */ /* vim: set sw=2 et: */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2003 Kim Woelders * Copyright (C) 2003 Red Hat, Inc. * Copyright (C) 2006-2007 Vincent Untz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, see . */ #include #include #include "workspace.h" #include "xutils.h" #include "private.h" #include /** * SECTION:workspace * @short_description: an object representing a workspace. * @see_also: #WnckScreen * @stability: Unstable * * The #WnckWorkspace represents what is called virtual * desktops in the EWMH. * A workspace is a virtualization of a #WnckScreen: only one workspace * can be shown on a #WnckScreen at a time. It makes it possible, for example, * to put windows on different workspaces to organize them. * * If the #WnckWorkspace size is bigger that the #WnckScreen size, the * workspace contains a viewport. Viewports are defined in the large * desktops section of the EWMH. * The notion of workspaces and viewports are quite similar, and generally both * are not used at the same time: there are generally either multiple * workspaces with no viewport, or one workspace with a viewport. libwnck * supports all situations, even multiple workspaces with viewports. * * Workspaces are organized according to a layout set on the #WnckScreen. See * wnck_screen_try_set_workspace_layout() and * wnck_screen_release_workspace_layout() for more information about the * layout. * * The #WnckWorkspace objects are always owned by libwnck and must not be * referenced or unreferenced. */ struct _WnckWorkspacePrivate { WnckScreen *screen; int number; char *name; int width, height; /* Workspace size */ int viewport_x, viewport_y; /* Viewport origin */ gboolean is_virtual; }; G_DEFINE_TYPE_WITH_PRIVATE (WnckWorkspace, wnck_workspace, G_TYPE_OBJECT); enum { NAME_CHANGED, LAST_SIGNAL }; static void wnck_workspace_finalize (GObject *object); static void emit_name_changed (WnckWorkspace *space); static guint signals[LAST_SIGNAL] = { 0 }; static void wnck_workspace_init (WnckWorkspace *workspace) { workspace->priv = wnck_workspace_get_instance_private (workspace); workspace->priv->number = -1; } static void wnck_workspace_class_init (WnckWorkspaceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = wnck_workspace_finalize; /** * WnckWorkspace::name-changed: * @space: the #WnckWorkspace which emitted the signal. * * Emitted when the name of @space changes. */ signals[NAME_CHANGED] = g_signal_new ("name_changed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (WnckWorkspaceClass, name_changed), NULL, NULL, NULL, G_TYPE_NONE, 0); } static void wnck_workspace_finalize (GObject *object) { WnckWorkspace *workspace; workspace = WNCK_WORKSPACE (object); g_free (workspace->priv->name); workspace->priv->name = NULL; G_OBJECT_CLASS (wnck_workspace_parent_class)->finalize (object); } /** * wnck_workspace_get_number: * @space: a #WnckWorkspace. * * Gets the index of @space on the #WnckScreen to which it belongs. The * first workspace has an index of 0. * * Return value: the index of @space on its #WnckScreen, or -1 on errors. **/ int wnck_workspace_get_number (WnckWorkspace *space) { g_return_val_if_fail (WNCK_IS_WORKSPACE (space), -1); return space->priv->number; } /** * wnck_workspace_get_name: * @space: a #WnckWorkspace. * * Gets the human-readable name that should be used to refer to @space. If * the user has not set a special name, a fallback like "Workspace 3" will be * used. * * Return value: the name of @space. **/ const char* wnck_workspace_get_name (WnckWorkspace *space) { g_return_val_if_fail (WNCK_IS_WORKSPACE (space), NULL); return space->priv->name; } /** * wnck_workspace_change_name: * @space: a #WnckWorkspace. * @name: new name for @space. * * Changes the name of @space. * * Since: 2.2 **/ void wnck_workspace_change_name (WnckWorkspace *space, const char *name) { g_return_if_fail (WNCK_IS_WORKSPACE (space)); g_return_if_fail (name != NULL); _wnck_screen_change_workspace_name (space->priv->screen, space->priv->number, name); } /** * wnck_workspace_get_screen: * @space: a #WnckWorkspace. * * Gets the #WnckScreen @space is on. * * Return value: (transfer none): the #WnckScreen @space is on. The returned * #WnckScreen is owned by libwnck and must not be referenced or unreferenced. **/ WnckScreen* wnck_workspace_get_screen (WnckWorkspace *space) { g_return_val_if_fail (WNCK_IS_WORKSPACE (space), NULL); return space->priv->screen; } /** * wnck_workspace_activate: * @space: a #WnckWorkspace. * @timestamp: the X server timestamp of the user interaction event that caused * this call to occur. * * Asks the window manager to make @space the active workspace. The window * manager may decide to refuse the request (to not steal the focus if there is * a more recent user activity, for example). * * This function existed before 2.10, but the @timestamp argument was missing * in earlier versions. * * Since: 2.10 **/ void wnck_workspace_activate (WnckWorkspace *space, guint32 timestamp) { g_return_if_fail (WNCK_IS_WORKSPACE (space)); _wnck_activate_workspace (WNCK_SCREEN_XSCREEN (space->priv->screen), space->priv->number, timestamp); } WnckWorkspace* _wnck_workspace_create (int number, WnckScreen *screen) { WnckWorkspace *space; space = g_object_new (WNCK_TYPE_WORKSPACE, NULL); space->priv->number = number; space->priv->name = NULL; space->priv->screen = screen; _wnck_workspace_update_name (space, NULL); /* Just set reasonable defaults */ space->priv->width = wnck_screen_get_width (screen); space->priv->height = wnck_screen_get_height (screen); space->priv->is_virtual = FALSE; space->priv->viewport_x = 0; space->priv->viewport_y = 0; return space; } void _wnck_workspace_update_name (WnckWorkspace *space, const char *name) { char *old; g_return_if_fail (WNCK_IS_WORKSPACE (space)); old = space->priv->name; space->priv->name = g_strdup (name); if (space->priv->name == NULL) space->priv->name = g_strdup_printf (_("Workspace %d"), space->priv->number + 1); if ((old && !name) || (!old && name) || (old && name && strcmp (old, name) != 0)) emit_name_changed (space); g_free (old); } static void emit_name_changed (WnckWorkspace *space) { g_signal_emit (G_OBJECT (space), signals[NAME_CHANGED], 0); } gboolean _wnck_workspace_set_geometry (WnckWorkspace *space, int w, int h) { if (space->priv->width != w || space->priv->height != h) { space->priv->width = w; space->priv->height = h; space->priv->is_virtual = w > wnck_screen_get_width (space->priv->screen) || h > wnck_screen_get_height (space->priv->screen); return TRUE; /* change was made */ } else return FALSE; } gboolean _wnck_workspace_set_viewport (WnckWorkspace *space, int x, int y) { if (space->priv->viewport_x != x || space->priv->viewport_y != y) { space->priv->viewport_x = x; space->priv->viewport_y = y; return TRUE; /* change was made */ } else return FALSE; } /** * wnck_workspace_get_width: * @space: a #WnckWorkspace. * * Gets the width of @space. * * Returns: the width of @space. * * Since: 2.4 */ int wnck_workspace_get_width (WnckWorkspace *space) { g_return_val_if_fail (WNCK_IS_WORKSPACE (space), 0); return space->priv->width; } /** * wnck_workspace_get_height: * @space: a #WnckWorkspace. * * Gets the height of @space. * * Returns: the height of @space. * * Since: 2.4 */ int wnck_workspace_get_height (WnckWorkspace *space) { g_return_val_if_fail (WNCK_IS_WORKSPACE (space), 0); return space->priv->height; } /** * wnck_workspace_get_viewport_x: * @space: a #WnckWorkspace. * * Gets the X coordinate of the viewport in @space. * * Returns: the X coordinate of the viewport in @space, or 0 if @space does not * contain a viewport. * * Since: 2.4 */ int wnck_workspace_get_viewport_x (WnckWorkspace *space) { g_return_val_if_fail (WNCK_IS_WORKSPACE (space), 0); return space->priv->viewport_x; } /** * wnck_workspace_get_viewport_y: * @space: a #WnckWorkspace. * * Gets the Y coordinate of the viewport in @space. * * Returns: the Y coordinate of the viewport in @space, or 0 if @space does not * contain a viewport. * * Since: 2.4 */ int wnck_workspace_get_viewport_y (WnckWorkspace *space) { g_return_val_if_fail (WNCK_IS_WORKSPACE (space), 0); return space->priv->viewport_y; } /** * wnck_workspace_is_virtual: * @space: a #WnckWorkspace. * * Gets whether @space contains a viewport. * * Returns: %TRUE if @space contains a viewport, %FALSE otherwise. * * Since: 2.4 */ gboolean wnck_workspace_is_virtual (WnckWorkspace *space) { g_return_val_if_fail (WNCK_IS_WORKSPACE (space), FALSE); return space->priv->is_virtual; } /** * wnck_workspace_get_layout_row: * @space: a #WnckWorkspace. * * Gets the row of @space in the #WnckWorkspace layout. The first row has an * index of 0 and is always the top row, regardless of the starting corner set * for the layout. * * Return value: the row of @space in the #WnckWorkspace layout, or -1 on * errors. * * Since: 2.20 **/ int wnck_workspace_get_layout_row (WnckWorkspace *space) { _WnckLayoutOrientation orientation; _WnckLayoutCorner corner; int n_rows; int n_cols; int row; g_return_val_if_fail (WNCK_IS_WORKSPACE (space), -1); _wnck_screen_get_workspace_layout (space->priv->screen, &orientation, &n_rows, &n_cols, &corner); if (orientation == WNCK_LAYOUT_ORIENTATION_HORIZONTAL) row = space->priv->number / n_cols; else row = space->priv->number % n_rows; if (corner == WNCK_LAYOUT_CORNER_BOTTOMRIGHT || corner == WNCK_LAYOUT_CORNER_BOTTOMLEFT) row = n_rows - row; return row; } /** * wnck_workspace_get_layout_column: * @space: a #WnckWorkspace. * * Gets the column of @space in the #WnckWorkspace layout. The first column * has an index of 0 and is always the left column, regardless of the starting * corner set for the layout and regardless of the default direction of the * environment (i.e., in both Left-To-Right and Right-To-Left environments). * * Return value: the column of @space in the #WnckWorkspace layout, or -1 on * errors. * * Since: 2.20 **/ int wnck_workspace_get_layout_column (WnckWorkspace *space) { _WnckLayoutOrientation orientation; _WnckLayoutCorner corner; int n_rows; int n_cols; int col; g_return_val_if_fail (WNCK_IS_WORKSPACE (space), -1); _wnck_screen_get_workspace_layout (space->priv->screen, &orientation, &n_rows, &n_cols, &corner); if (orientation == WNCK_LAYOUT_ORIENTATION_HORIZONTAL) col = space->priv->number % n_cols; else col = space->priv->number / n_rows; if (corner == WNCK_LAYOUT_CORNER_TOPRIGHT || corner == WNCK_LAYOUT_CORNER_BOTTOMRIGHT) col = n_cols - col; return col; } /** * wnck_workspace_get_neighbor: * @space: a #WnckWorkspace. * @direction: direction in which to search the neighbor. * * Gets the neighbor #WnckWorkspace of @space in the @direction direction. * * Return value: (transfer none): the neighbor #WnckWorkspace of @space in the * @direction direction, or %NULL if no such neighbor #WnckWorkspace exists. * The returned #WnckWorkspace is owned by libwnck and must not be referenced * or unreferenced. * * Since: 2.20 **/ WnckWorkspace* wnck_workspace_get_neighbor (WnckWorkspace *space, WnckMotionDirection direction) { _WnckLayoutOrientation orientation; _WnckLayoutCorner corner; int n_rows; int n_cols; int row; int col; int add; int index; g_return_val_if_fail (WNCK_IS_WORKSPACE (space), NULL); _wnck_screen_get_workspace_layout (space->priv->screen, &orientation, &n_rows, &n_cols, &corner); row = wnck_workspace_get_layout_row (space); col = wnck_workspace_get_layout_column (space); index = space->priv->number; switch (direction) { case WNCK_MOTION_LEFT: if (col == 0) return NULL; if (orientation == WNCK_LAYOUT_ORIENTATION_HORIZONTAL) add = 1; else add = n_rows; if (corner == WNCK_LAYOUT_CORNER_TOPRIGHT || corner == WNCK_LAYOUT_CORNER_BOTTOMRIGHT) index += add; else index -= add; break; case WNCK_MOTION_RIGHT: if (col == n_cols - 1) return NULL; if (orientation == WNCK_LAYOUT_ORIENTATION_HORIZONTAL) add = 1; else add = n_rows; if (corner == WNCK_LAYOUT_CORNER_TOPRIGHT || corner == WNCK_LAYOUT_CORNER_BOTTOMRIGHT) index -= add; else index += add; break; case WNCK_MOTION_UP: if (row == 0) return NULL; if (orientation == WNCK_LAYOUT_ORIENTATION_HORIZONTAL) add = n_cols; else add = 1; if (corner == WNCK_LAYOUT_CORNER_BOTTOMLEFT || corner == WNCK_LAYOUT_CORNER_BOTTOMRIGHT) index += add; else index -= add; break; case WNCK_MOTION_DOWN: if (row == n_rows - 1) return NULL; if (orientation == WNCK_LAYOUT_ORIENTATION_HORIZONTAL) add = n_cols; else add = 1; if (corner == WNCK_LAYOUT_CORNER_BOTTOMLEFT || corner == WNCK_LAYOUT_CORNER_BOTTOMRIGHT) index -= add; else index += add; break; default: break; } if (index == space->priv->number) return NULL; return wnck_screen_get_workspace (space->priv->screen, index); }