/** * meta_workspace_get_neighbor: * @workspace: a #MetaWorkspace * @direction: a #MetaMotionDirection, direction in which to look for the neighbor * * Gets the neighbor of the #MetaWorkspace in the given direction * * Return value: (transfer none): the neighbor #MetaWorkspace */ MetaWorkspace* meta_workspace_get_neighbor (MetaWorkspace *workspace, MetaMotionDirection direction) { MetaWorkspaceLayout layout; int i, current_space, num_workspaces; gboolean ltr; current_space = meta_workspace_index (workspace); num_workspaces = meta_screen_get_n_workspaces (workspace->screen); meta_screen_calc_workspace_layout (workspace->screen, num_workspaces, current_space, &layout); meta_verbose ("Getting neighbor of %d in direction %s\n", current_space, meta_motion_direction_to_string (direction)); ltr = meta_ui_get_direction() == META_UI_DIRECTION_LTR; switch (direction) { case META_MOTION_LEFT: layout.current_col -= ltr ? 1 : -1; break; case META_MOTION_RIGHT: layout.current_col += ltr ? 1 : -1; break; case META_MOTION_UP: layout.current_row -= 1; break; case META_MOTION_DOWN: layout.current_row += 1; break; default:; } if (layout.current_col < 0) layout.current_col = 0; if (layout.current_col >= layout.cols) layout.current_col = layout.cols - 1; if (layout.current_row < 0) layout.current_row = 0; if (layout.current_row >= layout.rows) layout.current_row = layout.rows - 1; i = layout.grid[layout.current_row * layout.cols + layout.current_col]; if (i < 0) i = current_space; if (i >= num_workspaces) meta_bug ("calc_workspace_layout left an invalid (too-high) workspace number %d in the grid\n", i); meta_verbose ("Neighbor workspace is %d at row %d col %d\n", i, layout.current_row, layout.current_col); meta_screen_free_workspace_layout (&layout); return meta_screen_get_workspace_by_index (workspace->screen, i); }
static void workspace_switch_sound(MetaWorkspace *from, MetaWorkspace *to) { MetaWorkspaceLayout layout; int i, nw, x, y, fi, ti; const char *e; nw = meta_screen_get_n_workspaces(from->screen); fi = meta_workspace_index(from); ti = meta_workspace_index(to); meta_screen_calc_workspace_layout(from->screen, nw, fi, &layout); for (i = 0; i < nw; i++) if (layout.grid[i] == ti) break; if (i >= nw) { meta_bug("Failed to find destination workspace in layout\n"); goto finish; } y = i / layout.cols; x = i % layout.cols; /* We priorize horizontal over vertical movements here. The rationale for this is that horizontal movements are probably more interesting for sound effects because speakers are usually positioned on a horizontal and not a vertical axis. i.e. your spatial "Woosh!" effects will easily be able to encode horizontal movement but not such much vertical movement. */ if (x < layout.current_col) e = "desktop-switch-left"; else if (x > layout.current_col) e = "desktop-switch-right"; else if (y < layout.current_row) e = "desktop-switch-up"; else if (y > layout.current_row) e = "desktop-switch-down"; else { meta_bug("Uh, origin and destination workspace at same logic position!\n"); goto finish; } #ifdef HAVE_CANBERRA ca_context_play(ca_gtk_context_get(), 1, CA_PROP_EVENT_ID, e, CA_PROP_EVENT_DESCRIPTION, "Desktop switched", CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", NULL); #endif finish: meta_screen_free_workspace_layout (&layout); }
int meta_core_get_num_workspaces (Screen *xscreen) { MetaScreen *screen; screen = meta_screen_for_x_screen (xscreen); return meta_screen_get_n_workspaces (screen); }
/** * meta_workspace_activate_with_focus: * @workspace: a #MetaWorkspace * @focus_this: the #MetaWindow to be focused, or %NULL * @timestamp: timestamp for @focus_this * * Switches to @workspace and possibly activates the window @focus_this. * * The window @focus_this is activated by calling meta_window_activate() * which will unminimize it and transient parents, raise it and give it * the focus. * * If a window is currently being moved by the user, it will be * moved to @workspace. * * The advantage of calling this function instead of meta_workspace_activate() * followed by meta_window_activate() is that it happens as a unit, so * no other window gets focused first before @focus_this. */ void meta_workspace_activate_with_focus (MetaWorkspace *workspace, MetaWindow *focus_this, guint32 timestamp) { MetaWorkspace *old; MetaWindow *move_window; MetaScreen *screen; MetaDisplay *display; MetaCompositor *comp; MetaWorkspaceLayout layout1, layout2; gint num_workspaces, current_space, new_space; MetaMotionDirection direction; meta_verbose ("Activating workspace %d\n", meta_workspace_index (workspace)); if (workspace->screen->active_workspace == workspace) return; /* Free any cached pointers to the workspaces's edges from * a current resize or move operation */ meta_display_cleanup_edges (workspace->screen->display); if (workspace->screen->active_workspace) workspace_switch_sound (workspace->screen->active_workspace, workspace); /* Note that old can be NULL; e.g. when starting up */ old = workspace->screen->active_workspace; workspace->screen->active_workspace = workspace; meta_screen_set_active_workspace_hint (workspace->screen); /* If the "show desktop" mode is active for either the old workspace * or the new one *but not both*, then update the * _net_showing_desktop hint */ if (old && (old->showing_desktop ^ workspace->showing_desktop)) meta_screen_update_showing_desktop_hint (workspace->screen); if (old == NULL) return; move_window = NULL; if (workspace->screen->display->grab_op == META_GRAB_OP_MOVING || workspace->screen->display->grab_op == META_GRAB_OP_KEYBOARD_MOVING) move_window = workspace->screen->display->grab_window; if (move_window != NULL) { if (move_window->on_all_workspaces) move_window = NULL; /* don't move it after all */ /* We put the window on the new workspace, flip spaces, * then remove from old workspace, so the window * never gets unmapped and we maintain the button grab * on it. * * \bug This comment appears to be the reverse of what happens */ if (move_window && (move_window->workspace != workspace)) { meta_workspace_remove_window (old, move_window); meta_workspace_add_window (workspace, move_window); } } meta_workspace_queue_calc_showing (old); meta_workspace_queue_calc_showing (workspace); /* FIXME: Why do we need this?!? Isn't it handled in the lines above? */ if (move_window) /* Removes window from other spaces */ meta_window_change_workspace (move_window, workspace); /* * Notify the compositor that the active workspace is changing. */ screen = workspace->screen; display = meta_screen_get_display (screen); comp = meta_display_get_compositor (display); direction = 0; current_space = meta_workspace_index (old); new_space = meta_workspace_index (workspace); num_workspaces = meta_screen_get_n_workspaces (workspace->screen); meta_screen_calc_workspace_layout (workspace->screen, num_workspaces, current_space, &layout1); meta_screen_calc_workspace_layout (workspace->screen, num_workspaces, new_space, &layout2); if (meta_ui_get_direction() == META_UI_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_UP; else if (direction == META_MOTION_RIGHT) direction = META_MOTION_UP_RIGHT; else direction = META_MOTION_UP_LEFT; } meta_screen_free_workspace_layout (&layout1); meta_screen_free_workspace_layout (&layout2); meta_compositor_switch_workspace (comp, screen, old, workspace, direction); /* This needs to be done after telling the compositor we are switching * workspaces since focusing a window will cause it to be immediately * shown and that would confuse the compositor if it didn't know we * were in a workspace switch. */ if (focus_this) { meta_window_activate (focus_this, timestamp); } else if (move_window) { meta_window_raise (move_window); } else { meta_topic (META_DEBUG_FOCUS, "Focusing default window on new workspace\n"); meta_workspace_focus_default_window (workspace, NULL, timestamp); } /* Emit switched signal from screen.c */ meta_screen_workspace_switched (screen, current_space, new_space, direction); }
MetaWorkspace* meta_workspace_get_neighbor (MetaWorkspace *workspace, MetaMotionDirection direction) { MetaWorkspaceLayout layout; int i, current_space, num_workspaces; gboolean ltr; MetaWrapStyle wrap; current_space = meta_workspace_index (workspace); num_workspaces = meta_screen_get_n_workspaces (workspace->screen); meta_screen_calc_workspace_layout (workspace->screen, num_workspaces, current_space, &layout); wrap = meta_prefs_get_wrap_style(); meta_verbose ("Getting neighbor of %d in direction %s\n", current_space, meta_motion_direction_to_string (direction)); ltr = meta_ui_get_direction() == META_UI_DIRECTION_LTR; switch (direction) { case META_MOTION_LEFT: layout.current_col -= ltr ? 1 : -1; break; case META_MOTION_RIGHT: layout.current_col += ltr ? 1 : -1; break; case META_MOTION_UP: layout.current_row -= 1; break; case META_MOTION_DOWN: layout.current_row += 1; break; } /* LEFT */ if (layout.current_col < 0) switch (wrap) { case META_WRAP_NONE: layout.current_col = 0; break; case META_WRAP_TOROIDAL: layout.current_row = layout.current_row > 0 ? layout.current_row - 1 : layout.rows - 1; /* fall through */ case META_WRAP_CLASSIC: layout.current_col = layout.cols - 1; } /* RIGHT */ if (layout.current_col >= layout.cols) switch (wrap) { case META_WRAP_NONE: layout.current_col = layout.cols - 1; break; case META_WRAP_TOROIDAL: layout.current_row = layout.current_row < layout.rows - 1 ? layout.current_row + 1 : 0; /* fall through */ case META_WRAP_CLASSIC: layout.current_col = 0; } /* UP */ if (layout.current_row < 0) switch (wrap) { case META_WRAP_NONE: layout.current_row = 0; break; case META_WRAP_TOROIDAL: layout.current_col = layout.current_col > 0 ? layout.current_col - 1 : layout.cols - 1; /* fall through */ case META_WRAP_CLASSIC: layout.current_row = layout.rows - 1; } /* DOWN */ if (layout.current_row >= layout.rows) switch (wrap) { case META_WRAP_NONE: layout.current_row = layout.rows - 1; break; case META_WRAP_TOROIDAL: layout.current_col = layout.current_col < layout.cols - 1 ? layout.current_col + 1 : 0; /* fall through */ case META_WRAP_CLASSIC: layout.current_row = 0; } /* If we have an uneven arrangement of workspaces, (layout.cols - n, layout.rows - 1) may be an invalid workspace e.g. we have 7 workspaces on a 3x3 pane */ if (wrap != META_WRAP_NONE && (layout.current_row * layout.cols + layout.current_col >= num_workspaces)) switch (direction) { case META_MOTION_LEFT: layout.current_col = num_workspaces - (layout.current_row * layout.cols + 1); break; case META_MOTION_RIGHT: layout.current_col = 0; if (wrap == META_WRAP_TOROIDAL) layout.current_row = 0; break; case META_MOTION_UP: layout.current_row -= 1; break; case META_MOTION_DOWN: layout.current_row = 0; if (wrap == META_WRAP_TOROIDAL) layout.current_col = layout.current_col < layout.cols - 1 ? layout.current_col + 1 : 0; break; } i = layout.grid[layout.current_row * layout.cols + layout.current_col]; if (i < 0) i = current_space; if (i >= num_workspaces) meta_bug ("calc_workspace_layout left an invalid (too-high) workspace number %d in the grid\n", i); meta_verbose ("Neighbor workspace is %d at row %d col %d\n", i, layout.current_row, layout.current_col); meta_screen_free_workspace_layout (&layout); return meta_screen_get_workspace_by_index (workspace->screen, i); }
/* * This is the Metacity entry point for the effect. */ void mnb_switch_zones_effect (MetaPlugin *plugin, gint from, gint to, MetaMotionDirection direction) { GList *w; gint width, height; MetaScreen *screen; ClutterActor *window_group; if (running++) { /* * We have been called while the effect is already in progress; we need to * mutter know that we completed the previous run. */ if (--running < 0) { g_warning (G_STRLOC ": error in running effect accounting!"); running = 0; } meta_plugin_switch_workspace_completed (plugin); } if ((from == to) && !zones_preview) { if (--running < 0) { g_warning (G_STRLOC ": error in running effect accounting!"); running = 0; } meta_plugin_switch_workspace_completed (plugin); return; } screen = meta_plugin_get_screen (plugin); if (!zones_preview) { ClutterActor *stage; /* Construct the zones preview actor */ zones_preview = mnb_zones_preview_new (); g_object_set (G_OBJECT (zones_preview), "workspace", (gdouble)from, NULL); /* Add it to the stage */ stage = meta_get_stage_for_screen (screen); clutter_container_add_actor (CLUTTER_CONTAINER (stage), zones_preview); /* Attach to completed signal */ g_signal_connect (zones_preview, "switch-completed", G_CALLBACK (mnb_switch_zones_completed_cb), plugin); } meta_screen_get_size (screen, &width, &height); g_object_set (G_OBJECT (zones_preview), "workspace-width", (guint)width, "workspace-height", (guint)height, NULL); mnb_zones_preview_clear (MNB_ZONES_PREVIEW (zones_preview)); mnb_zones_preview_set_n_workspaces (MNB_ZONES_PREVIEW (zones_preview), meta_screen_get_n_workspaces (screen)); /* Add windows to zone preview actor */ for (w = meta_get_window_actors (screen); w; w = w->next) { MetaWindowActor *window_actor = w->data; gint workspace = meta_window_actor_get_workspace (window_actor); MetaWindow *window = meta_window_actor_get_meta_window (window_actor); MetaWindowType type = meta_window_get_window_type (window); /* * Only show regular windows that are not sticky (getting stacking order * right for sticky windows would be really hard, and since they appear * on each workspace, they do not help in identifying which workspace * it is). */ if ((workspace < 0) || meta_window_actor_is_override_redirect (window_actor) || (type != META_WINDOW_NORMAL)) continue; mnb_zones_preview_add_window (MNB_ZONES_PREVIEW (zones_preview), window_actor); } /* Make sure it's on top */ window_group = meta_get_window_group_for_screen (screen); clutter_actor_raise (zones_preview, window_group); /* Initiate animation */ mnb_zones_preview_change_workspace (MNB_ZONES_PREVIEW (zones_preview), to); }