/** * 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 popup_position_func(GtkMenu* menu, gint* x, gint* y, gboolean* push_in, gpointer user_data) { GtkRequisition req; GdkPoint* pos; pos = user_data; #if GTK_CHECK_VERSION (3, 0, 0) gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL); #else gtk_widget_size_request(GTK_WIDGET(menu), &req); #endif *x = pos->x; *y = pos->y; if (meta_ui_get_direction() == META_UI_DIRECTION_RTL) { *x = MAX (0, *x - req.width); } /* Ensure onscreen */ *x = CLAMP (*x, 0, MAX(0, gdk_screen_width() - req.width)); *y = CLAMP (*y, 0, MAX(0, gdk_screen_height() - req.height)); }
void meta_fixed_tip_show (Display *xdisplay, int screen_number, int root_x, int root_y, const char *markup_text) { int w, h; if (tip == NULL) { tip = gtk_window_new (GTK_WINDOW_POPUP); gtk_window_set_type_hint (GTK_WINDOW(tip), GDK_WINDOW_TYPE_HINT_TOOLTIP); { GdkScreen *gdk_screen; GdkRectangle monitor; gint mon_num; gdk_screen = gdk_display_get_screen (gdk_display_get_default (), screen_number); gtk_window_set_screen (GTK_WINDOW (tip), gdk_screen); mon_num = gdk_screen_get_monitor_at_point (gdk_screen, root_x, root_y); gdk_screen_get_monitor_geometry (gdk_screen, mon_num, &monitor); screen_right_edge = monitor.x + monitor.width; screen_bottom_edge = monitor.y + monitor.height; } gtk_widget_set_app_paintable (tip, TRUE); gtk_window_set_resizable (GTK_WINDOW (tip), FALSE); gtk_widget_set_name (tip, "gtk-tooltips"); gtk_container_set_border_width (GTK_CONTAINER (tip), 4); g_signal_connect_swapped (tip, "expose_event", G_CALLBACK (expose_handler), NULL); label = gtk_label_new (NULL); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5); gtk_widget_show (label); gtk_container_add (GTK_CONTAINER (tip), label); g_signal_connect (tip, "destroy", G_CALLBACK (gtk_widget_destroyed), &tip); } gtk_label_set_markup (GTK_LABEL (label), markup_text); gtk_window_get_size (GTK_WINDOW (tip), &w, &h); if (meta_ui_get_direction() == META_UI_DIRECTION_RTL) root_x = MAX(0, root_x - w); if ((root_x + w) > screen_right_edge) root_x -= (root_x + w) - screen_right_edge; gtk_window_move (GTK_WINDOW (tip), root_x, root_y); gtk_widget_show (tip); }
/** * 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); }
static gboolean button_layout_handler (GVariant *value, gpointer *result, gpointer data) { MetaButtonLayout new_layout; const gchar *string_value; char **sides = NULL; int i; /* We need to ignore unknown button functions, for * compat with future versions */ *result = NULL; /* ignored */ string_value = g_variant_get_string (value, NULL); if (string_value) sides = g_strsplit (string_value, ":", 2); i = 0; if (sides != NULL && sides[0] != NULL) { char **buttons; int b; gboolean used[META_BUTTON_FUNCTION_LAST]; while (i < META_BUTTON_FUNCTION_LAST) { used[i] = FALSE; new_layout.left_buttons_has_spacer[i] = FALSE; i++; } buttons = g_strsplit (sides[0], ",", -1); i = 0; b = 0; while (buttons[b] != NULL) { MetaButtonFunction f = button_function_from_string (buttons[b]); if (i > 0 && strcmp("spacer", buttons[b]) == 0) { new_layout.left_buttons_has_spacer[i-1] = TRUE; f = button_opposite_function (f); if (f != META_BUTTON_FUNCTION_LAST) { new_layout.left_buttons_has_spacer[i-2] = TRUE; } } else { if (f != META_BUTTON_FUNCTION_LAST && !used[f]) { new_layout.left_buttons[i] = f; used[f] = TRUE; i++; f = button_opposite_function (f); if (f != META_BUTTON_FUNCTION_LAST) new_layout.left_buttons[i++] = f; } else { meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n", buttons[b]); } } ++b; } g_strfreev (buttons); } /* Close the buttons list even if it's empty */ new_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST; new_layout.left_buttons_has_spacer[i] = FALSE; i = 0; if (sides != NULL && sides[0] != NULL && sides[1] != NULL) { char **buttons; int b; gboolean used[META_BUTTON_FUNCTION_LAST]; while (i < META_BUTTON_FUNCTION_LAST) { used[i] = FALSE; new_layout.right_buttons_has_spacer[i] = FALSE; i++; } buttons = g_strsplit (sides[1], ",", -1); i = 0; b = 0; while (buttons[b] != NULL) { MetaButtonFunction f = button_function_from_string (buttons[b]); if (i > 0 && strcmp("spacer", buttons[b]) == 0) { new_layout.right_buttons_has_spacer[i-1] = TRUE; f = button_opposite_function (f); if (f != META_BUTTON_FUNCTION_LAST) { new_layout.right_buttons_has_spacer[i-2] = TRUE; } } else { if (f != META_BUTTON_FUNCTION_LAST && !used[f]) { new_layout.right_buttons[i] = f; used[f] = TRUE; i++; f = button_opposite_function (f); if (f != META_BUTTON_FUNCTION_LAST) new_layout.right_buttons[i++] = f; } else { meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n", buttons[b]); } } ++b; } g_strfreev (buttons); } /* Close the buttons list even if it's empty */ new_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST; new_layout.right_buttons_has_spacer[i] = FALSE; if (sides) g_strfreev (sides); /* Invert the button layout for RTL languages */ if (meta_ui_get_direction() == META_UI_DIRECTION_RTL) { MetaButtonLayout rtl_layout; int j; for (i = 0; new_layout.left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++); for (j = 0; j < i; j++) { rtl_layout.right_buttons[j] = new_layout.left_buttons[i - j - 1]; if (j == 0) rtl_layout.right_buttons_has_spacer[i - 1] = new_layout.left_buttons_has_spacer[i - j - 1]; else rtl_layout.right_buttons_has_spacer[j - 1] = new_layout.left_buttons_has_spacer[i - j - 1]; } rtl_layout.right_buttons[j] = META_BUTTON_FUNCTION_LAST; rtl_layout.right_buttons_has_spacer[j] = FALSE; for (i = 0; new_layout.right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++); for (j = 0; j < i; j++) { rtl_layout.left_buttons[j] = new_layout.right_buttons[i - j - 1]; if (j == 0) rtl_layout.left_buttons_has_spacer[i - 1] = new_layout.right_buttons_has_spacer[i - j - 1]; else rtl_layout.left_buttons_has_spacer[j - 1] = new_layout.right_buttons_has_spacer[i - j - 1]; } rtl_layout.left_buttons[j] = META_BUTTON_FUNCTION_LAST; rtl_layout.left_buttons_has_spacer[j] = FALSE; new_layout = rtl_layout; } if (!button_layout_equal (&button_layout, &new_layout)) { button_layout = new_layout; emit_changed (META_PREF_BUTTON_LAYOUT); } return TRUE; }