static void stack_do_window_additions (MetaStack *stack) { GList *tmp; gint i, n_added; n_added = g_list_length (stack->added); if (n_added > 0) { Window *end; int old_size; meta_topic (META_DEBUG_STACK, "Adding %d windows to sorted list\n", n_added); old_size = stack->windows->len; g_array_set_size (stack->windows, old_size + n_added); end = &g_array_index (stack->windows, Window, old_size); /* stack->added has the most recent additions at the * front of the list, so we need to reverse it */ stack->added = g_list_reverse (stack->added); i = 0; tmp = stack->added; while (tmp != NULL) { MetaWindow *w; w = tmp->data; end[i] = w->xwindow; /* add to the main list */ stack->sorted = g_list_prepend (stack->sorted, w); ++i; tmp = tmp->next; } stack->need_resort = TRUE; /* may not be needed as we add to top */ stack->need_constrain = TRUE; stack->need_relayer = TRUE; } g_list_free (stack->added); stack->added = NULL; }
static void compute_layer (MetaWindow *window) { window->layer = get_standalone_layer (window); /* We can only do promotion-due-to-group for dialogs and other * transients, or weird stuff happens like the desktop window and * caja windows getting in the same layer, or all mate-terminal * windows getting in fullscreen layer if any terminal is * fullscreen. */ if (WINDOW_HAS_TRANSIENT_TYPE(window) && (window->xtransient_for == None || window->transient_parent_is_root_window)) { /* We only do the group thing if the dialog is NOT transient for * a particular window. Imagine a group with a normal window, a dock, * and a dialog transient for the normal window; you don't want the dialog * above the dock if it wouldn't normally be. */ MetaStackLayer group_max; group_max = get_maximum_layer_in_group (window); if (group_max > window->layer) { meta_topic (META_DEBUG_STACK, "Promoting window %s from layer %u to %u due to group membership\n", window->desc, window->layer, group_max); window->layer = group_max; } } meta_topic (META_DEBUG_STACK, "Window %s on layer %u type = %u has_focus = %d\n", window->desc, window->layer, window->type, window->has_focus); }
static void ensure_above (MetaWindow *above, MetaWindow *below) { if (WINDOW_HAS_TRANSIENT_TYPE(above) && above->layer < below->layer) { meta_topic (META_DEBUG_STACK, "Promoting window %s from layer %u to %u due to contraint\n", above->desc, above->layer, below->layer); above->layer = below->layer; } if (above->stack_position < below->stack_position) { /* move above to below->stack_position bumping below down the stack */ meta_window_set_stack_position_no_sync (above, below->stack_position); g_assert (below->stack_position + 1 == above->stack_position); } meta_topic (META_DEBUG_STACK, "%s above at %d > %s below at %d\n", above->desc, above->stack_position, below->desc, below->stack_position); }
/** * stack_do_resort: * * Sort stack->sorted with layers having priority over stack_position. */ static void stack_do_resort (MetaStack *stack) { if (!stack->need_resort) return; meta_topic (META_DEBUG_STACK, "Sorting stack list\n"); stack->sorted = g_list_sort (stack->sorted, (GCompareFunc) compare_window_position); stack->need_resort = FALSE; }
static void interact_callback (SmcConn smc_conn, SmPointer client_data) { /* nothing */ gboolean shutdown; meta_topic (META_DEBUG_SM, "Interaction permission received\n"); shutdown = GPOINTER_TO_INT (client_data); current_state = STATE_DONE_WITH_INTERACT; warn_about_lame_clients_and_finish_interact (shutdown); }
static void save_phase_2_callback (SmcConn smc_conn, SmPointer client_data) { gboolean shutdown; meta_topic (META_DEBUG_SM, "Phase 2 save"); shutdown = GPOINTER_TO_INT (client_data); current_state = STATE_SAVING_PHASE_2; save_state (); save_yourself_possibly_done (shutdown, TRUE); }
void meta_workspace_add_window (MetaWorkspace *workspace, MetaWindow *window) { g_return_if_fail (window->workspace == NULL); /* If the window is on all workspaces, we want to add it to all mru * lists, otherwise just add it to this workspaces mru list */ if (window->on_all_workspaces) { if (window->workspace == NULL) { GList* tmp = window->screen->workspaces; while (tmp) { MetaWorkspace* work = (MetaWorkspace*) tmp->data; if (!g_list_find (work->mru_list, window)) work->mru_list = g_list_prepend (work->mru_list, window); tmp = tmp->next; } } } else { g_assert (g_list_find (workspace->mru_list, window) == NULL); workspace->mru_list = g_list_prepend (workspace->mru_list, window); } workspace->windows = g_list_prepend (workspace->windows, window); window->workspace = workspace; meta_window_set_current_workspace_hint (window); if (window->struts) { meta_topic (META_DEBUG_WORKAREA, "Invalidating work area of workspace %d since we're adding window %s to it\n", meta_workspace_index (workspace), window->desc); meta_workspace_invalidate_work_area (workspace); } /* queue a move_resize since changing workspaces may change * the relevant struts */ meta_window_queue (window, META_QUEUE_CALC_SHOWING|META_QUEUE_MOVE_RESIZE); }
void meta_workspace_remove_window (MetaWorkspace *workspace, MetaWindow *window) { g_return_if_fail (window->workspace == workspace); workspace->windows = g_list_remove (workspace->windows, window); window->workspace = NULL; /* If the window is on all workspaces, we don't want to remove it * from the MRU list unless this causes it to be removed from all * workspaces */ if (window->on_all_workspaces) { GList* tmp = window->screen->workspaces; while (tmp) { MetaWorkspace* work = (MetaWorkspace*) tmp->data; work->mru_list = g_list_remove (work->mru_list, window); tmp = tmp->next; } } else { workspace->mru_list = g_list_remove (workspace->mru_list, window); g_assert (g_list_find (workspace->mru_list, window) == NULL); } meta_window_set_current_workspace_hint (window); if (window->struts) { meta_topic (META_DEBUG_WORKAREA, "Invalidating work area of workspace %d since we're removing window %s from it\n", meta_workspace_index (workspace), window->desc); meta_workspace_invalidate_work_area (workspace); } /* queue a move_resize since changing workspaces may change * the relevant struts */ meta_window_queue (window, META_QUEUE_CALC_SHOWING|META_QUEUE_MOVE_RESIZE); g_signal_emit (workspace, signals[WINDOW_REMOVED], 0, window); g_object_notify (G_OBJECT (workspace), "n-windows"); }
static void remove_window_from_group (MetaWindow *window) { if (window->group != NULL) { meta_topic (META_DEBUG_GROUPS, "Removing %s from group with leader 0x%lx\n", window->desc, window->group->group_leader); window->group->windows = g_slist_remove (window->group->windows, window); meta_group_unref (window->group); window->group = NULL; } }
static void delete_ping_timeout_func (MetaDisplay *display, Window xwindow, guint32 timestamp, void *user_data) { MetaWindow *window = user_data; char *window_title; gchar *window_content, *tmp; GPid dialog_pid; meta_topic (META_DEBUG_PING, "Got delete ping timeout for %s\n", window->desc); if (window->dialog_pid >= 0) { meta_window_present_delete_dialog (window, timestamp); return; } window_title = g_locale_from_utf8 (window->title, -1, NULL, NULL, NULL); /* Translators: %s is a window title */ tmp = g_strdup_printf (_("<tt>%s</tt> is not responding."), window_title); window_content = g_strdup_printf ( "<big><b>%s</b></big>\n\n<i>%s</i>", tmp, _("You may choose to wait a short while for it to " "continue or force the application to quit entirely.")); g_free (window_title); dialog_pid = meta_show_dialog ("--question", window_content, 0, window->screen->number, _("_Wait"), _("_Force Quit"), window->xwindow, NULL, NULL); g_free (window_content); g_free (tmp); window->dialog_pid = dialog_pid; g_child_watch_add (dialog_pid, dialog_exited, window); }
static void delete_ping_timeout_func (MetaDisplay *display, Window xwindow, guint32 timestamp, void *user_data) { MetaWindow *window = user_data; char *window_title; gchar *window_content; GPid dialog_pid; meta_topic (META_DEBUG_PING, "Got delete ping timeout for %s\n", window->desc); if (window->dialog_pid >= 0) { meta_window_present_delete_dialog (window, timestamp); return; } window_title = g_locale_from_utf8 (window->title, -1, NULL, NULL, NULL); window_content = g_strdup_printf( _("<big><b><tt>%s</tt> is not responding.</b></big>\n\n" "<i>You may choose to wait a short while for it to " "continue or force the application to quit entirely.</i>"), window_title); g_free (window_title); dialog_pid = meta_show_dialog ("--question", window_content, 0, window->screen->number, _("_Wait"), _("_Force Quit"), window->xwindow, NULL, NULL); g_free (window_content); window->dialog_pid = dialog_pid; g_signal_connect (sigchld_nexus, "sigchld", G_CALLBACK (sigchld_handler), window); }
void meta_error_trap_pop (MetaDisplay *display, gboolean last_request_was_roundtrip) { gboolean need_sync; /* we only have to sync when popping the outermost trap */ need_sync = (display->error_traps == 1 && !last_request_was_roundtrip); if (need_sync) meta_topic (META_DEBUG_SYNC, "Syncing on error_trap_pop, traps = %d, roundtrip = %d\n", display->error_traps, last_request_was_roundtrip); display->error_trap_synced_at_last_pop = need_sync || last_request_was_roundtrip; meta_error_trap_pop_internal (display, need_sync); }
LOCAL_SYMBOL gboolean meta_frame_sync_to_window (MetaFrame *frame, int resize_gravity, gboolean need_move, gboolean need_resize) { meta_topic (META_DEBUG_GEOMETRY, "Syncing frame geometry %d,%d %dx%d (SE: %d,%d)\n", frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height, frame->rect.x + frame->rect.width, frame->rect.y + frame->rect.height); /* set bg to none to avoid flicker */ if (need_resize) { meta_ui_unflicker_frame_bg (frame->window->screen->ui, frame->xwindow, frame->rect.width, frame->rect.height); } meta_ui_move_resize_frame (frame->window->screen->ui, frame->xwindow, frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height); if (need_resize) { meta_ui_reset_frame_bg (frame->window->screen->ui, frame->xwindow); /* If we're interactively resizing the frame, repaint * it immediately so we don't start to lag. */ if (frame->window->display->grab_window == frame->window) meta_ui_repaint_frame (frame->window->screen->ui, frame->xwindow); } return need_resize; }
gboolean meta_frame_sync_to_window (MetaFrame *frame, gboolean need_resize) { meta_topic (META_DEBUG_GEOMETRY, "Syncing frame geometry %d,%d %dx%d (SE: %d,%d)\n", frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height, frame->rect.x + frame->rect.width, frame->rect.y + frame->rect.height); meta_ui_frame_move_resize (frame->ui_frame, frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height); return need_resize; }
static MetaGroup* meta_group_new (MetaDisplay *display, Window group_leader) { MetaGroup *group; #define N_INITIAL_PROPS 3 Atom initial_props[N_INITIAL_PROPS]; int i; g_assert (N_INITIAL_PROPS == (int) G_N_ELEMENTS (initial_props)); group = g_new0 (MetaGroup, 1); group->display = display; group->windows = NULL; group->group_leader = group_leader; group->refcount = 1; /* owned by caller, hash table has only weak ref */ if (display->groups_by_leader == NULL) display->groups_by_leader = g_hash_table_new (meta_unsigned_long_hash, meta_unsigned_long_equal); g_assert (g_hash_table_lookup (display->groups_by_leader, &group_leader) == NULL); g_hash_table_insert (display->groups_by_leader, &group->group_leader, group); /* Fill these in the order we want them to be gotten */ i = 0; initial_props[i++] = display->atom_WM_CLIENT_MACHINE; initial_props[i++] = display->atom__NET_WM_PID; initial_props[i++] = display->atom__NET_STARTUP_ID; g_assert (N_INITIAL_PROPS == i); meta_group_reload_properties (group, initial_props, N_INITIAL_PROPS); meta_topic (META_DEBUG_GROUPS, "Created new group with leader 0x%lx\n", group->group_leader); return group; }
static void avoid_being_obscured_as_second_modal_dialog (MetaWindow *window, MetaFrameGeometry *fgeom, int *x, int *y) { /* We can't center this dialog if it was denied focus and it * overlaps with the focus window and this dialog is modal and this * dialog is in the same app as the focus window (*phew*...please * don't make me say that ten times fast). See bug 307875 comment 11 * and 12 for details, but basically it means this is probably a * second modal dialog for some app while the focus window is the * first modal dialog. We should probably make them simultaneously * visible in general, but it becomes mandatory to do so due to * buggy apps (e.g. those using gtk+ *sigh*) because in those cases * this second modal dialog also happens to be modal to the first * dialog in addition to the main window, while it has only let us * know about the modal-to-the-main-window part. */ MetaWindow *focus_window; MetaRectangle overlap; focus_window = window->display->focus_window; if (window->denied_focus_and_not_transient && window->wm_state_modal && /* FIXME: Maybe do this for all transients? */ meta_window_same_application (window, focus_window) && meta_rectangle_intersect (&window->rect, &focus_window->rect, &overlap)) { find_most_freespace (window, fgeom, focus_window, *x, *y, x, y); meta_topic (META_DEBUG_PLACEMENT, "Dialog window %s was denied focus but may be modal " "to the focus window; had to move it to avoid the " "focus window\n", window->desc); } }
void meta_stack_set_positions (MetaStack *stack, GList *windows) { int i; GList *tmp; /* Make sure any adds or removes aren't in limbo -- is this needed? */ stack_ensure_sorted (stack); if (!lists_contain_same_windows (windows, stack->sorted)) { meta_warning ("This list of windows has somehow changed; not resetting " "positions of the windows.\n"); return; } g_list_free (stack->sorted); stack->sorted = g_list_copy (windows); stack->need_resort = TRUE; stack->need_constrain = TRUE; i = 0; tmp = windows; while (tmp != NULL) { MetaWindow *w = tmp->data; w->stack_position = i++; tmp = tmp->next; } meta_topic (META_DEBUG_STACK, "Reset the stack positions of (nearly) all windows\n"); stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, NULL); }
const char* meta_prefs_get_workspace_name (int i) { const char *name; g_return_val_if_fail (i >= 0, NULL); if (!workspace_names || g_strv_length (workspace_names) < (guint)i + 1 || !*workspace_names[i]) { char *generated_name = g_strdup_printf (_("Workspace %d"), i + 1); name = g_intern_string (generated_name); g_free (generated_name); } else name = workspace_names[i]; meta_topic (META_DEBUG_PREFS, "Getting name of workspace %d: \"%s\"\n", i, name); return name; }
/** * Prints a list of which configure script options were used to * build this copy of Metacity. This is actually always called * on startup, but it's all no-op unless we're in verbose mode * (see meta_set_verbose). */ static void meta_print_compilation_info (void) { #ifdef HAVE_SHAPE meta_verbose ("Compiled with shape extension\n"); #else meta_verbose ("Compiled without shape extension\n"); #endif #ifdef HAVE_XINERAMA meta_topic (META_DEBUG_XINERAMA, "Compiled with Xinerama extension\n"); #else meta_topic (META_DEBUG_XINERAMA, "Compiled without Xinerama extension\n"); #endif #ifdef HAVE_XFREE_XINERAMA meta_topic (META_DEBUG_XINERAMA, " (using XFree86 Xinerama)\n"); #else meta_topic (META_DEBUG_XINERAMA, " (not using XFree86 Xinerama)\n"); #endif #ifdef HAVE_SOLARIS_XINERAMA meta_topic (META_DEBUG_XINERAMA, " (using Solaris Xinerama)\n"); #else meta_topic (META_DEBUG_XINERAMA, " (not using Solaris Xinerama)\n"); #endif #ifdef HAVE_XSYNC meta_verbose ("Compiled with sync extension\n"); #else meta_verbose ("Compiled without sync extension\n"); #endif #ifdef HAVE_RANDR meta_verbose ("Compiled with randr extension\n"); #else meta_verbose ("Compiled without randr extension\n"); #endif #ifdef HAVE_STARTUP_NOTIFICATION meta_verbose ("Compiled with startup notification\n"); #else meta_verbose ("Compiled without startup notification\n"); #endif #ifdef HAVE_COMPOSITE_EXTENSIONS meta_verbose ("Compiled with composite extensions\n"); #else meta_verbose ("Compiled without composite extensions\n"); #endif }
static void emit_changed (MetaPreference pref) { GList *tmp; GList *copy; meta_topic (META_DEBUG_PREFS, "Notifying listeners that pref %s changed\n", meta_preference_to_string (pref)); copy = g_list_copy (listeners); tmp = copy; while (tmp != NULL) { MetaPrefsListener *l = tmp->data; (* l->func) (pref, l->data); tmp = tmp->next; } g_list_free (copy); }
static void meta_window_present_delete_dialog (MetaWindow *window, guint32 timestamp) { meta_topic (META_DEBUG_PING, "Presenting existing ping dialog for %s\n", window->desc); if (window->dialog_pid >= 0) { GSList *windows; GSList *tmp; /* Activate transient for window that belongs to * metacity-dialog */ windows = meta_display_list_windows (window->display); tmp = windows; while (tmp != NULL) { MetaWindow *w = tmp->data; if (w->xtransient_for == window->xwindow && w->res_class && g_ascii_strcasecmp (w->res_class, "metacity-dialog") == 0) { meta_window_activate (w, timestamp); break; } tmp = tmp->next; } g_slist_free (windows); } }
static void create_constraints (Constraint **constraints, GList *windows) { GList *tmp; tmp = windows; while (tmp != NULL) { MetaWindow *w = tmp->data; if (!WINDOW_IN_STACK (w)) { meta_topic (META_DEBUG_STACK, "Window %s not in the stack, not constraining it\n", w->desc); tmp = tmp->next; continue; } if (WINDOW_TRANSIENT_FOR_WHOLE_GROUP (w)) { GSList *group_windows; GSList *tmp2; MetaGroup *group; group = meta_window_get_group (w); if (group != NULL) group_windows = meta_group_list_windows (group); else group_windows = NULL; tmp2 = group_windows; while (tmp2 != NULL) { MetaWindow *group_window = tmp2->data; if (!WINDOW_IN_STACK (group_window) || w->screen != group_window->screen || group_window->override_redirect) { tmp2 = tmp2->next; continue; } #if 0 /* old way of doing it */ if (!(meta_window_is_ancestor_of_transient (w, group_window)) && !WINDOW_TRANSIENT_FOR_WHOLE_GROUP (group_window)) /* note */;/*note*/ #else /* better way I think, so transient-for-group are constrained * only above non-transient-type windows in their group */ if (!WINDOW_HAS_TRANSIENT_TYPE (group_window)) #endif { meta_topic (META_DEBUG_STACK, "Constraining %s above %s as it's transient for its group\n", w->desc, group_window->desc); add_constraint (constraints, w, group_window); } tmp2 = tmp2->next; } g_slist_free (group_windows); } else if (w->transient_for != NULL) { MetaWindow *parent; parent = w->transient_for; if (parent && WINDOW_IN_STACK (parent)) { meta_topic (META_DEBUG_STACK, "Constraining %s above %s due to transiency\n", w->desc, parent->desc); add_constraint (constraints, w, parent); } } tmp = tmp->next; } }
static void ensure_work_areas_validated (MetaWorkspace *workspace) { GList *windows; GList *tmp; MetaRectangle work_area; int i; /* C89 absolutely sucks... */ if (!workspace->work_areas_invalid) return; g_assert (workspace->all_struts == NULL); g_assert (workspace->monitor_region == NULL); g_assert (workspace->screen_region == NULL); g_assert (workspace->screen_edges == NULL); g_assert (workspace->monitor_edges == NULL); /* STEP 1: Get the list of struts */ workspace->all_struts = copy_strut_list (workspace->builtin_struts); windows = meta_workspace_list_windows (workspace); for (tmp = windows; tmp != NULL; tmp = tmp->next) { MetaWindow *win = tmp->data; GSList *s_iter; for (s_iter = win->struts; s_iter != NULL; s_iter = s_iter->next) { workspace->all_struts = g_slist_prepend (workspace->all_struts, copy_strut(s_iter->data)); } } g_list_free (windows); /* STEP 2: Get the maximal/spanning rects for the onscreen and * on-single-monitor regions */ g_assert (workspace->monitor_region == NULL); g_assert (workspace->screen_region == NULL); workspace->monitor_region = g_new (GList*, workspace->screen->n_monitor_infos); for (i = 0; i < workspace->screen->n_monitor_infos; i++) { workspace->monitor_region[i] = meta_rectangle_get_minimal_spanning_set_for_region ( &workspace->screen->monitor_infos[i].rect, workspace->all_struts); } workspace->screen_region = meta_rectangle_get_minimal_spanning_set_for_region ( &workspace->screen->rect, workspace->all_struts); /* STEP 3: Get the work areas (region-to-maximize-to) for the screen and * monitors. */ work_area = workspace->screen->rect; /* start with the screen */ if (workspace->screen_region == NULL) work_area = meta_rect (0, 0, -1, -1); else meta_rectangle_clip_to_region (workspace->screen_region, FIXED_DIRECTION_NONE, &work_area); /* Lots of paranoia checks, forcing work_area_screen to be sane */ #define MIN_SANE_AREA 100 if (work_area.width < MIN_SANE_AREA) { meta_warning ("struts occupy an unusually large percentage of the screen; " "available remaining width = %d < %d", work_area.width, MIN_SANE_AREA); if (work_area.width < 1) { work_area.x = (workspace->screen->rect.width - MIN_SANE_AREA)/2; work_area.width = MIN_SANE_AREA; } else { int amount = (MIN_SANE_AREA - work_area.width)/2; work_area.x -= amount; work_area.width += 2*amount; } } if (work_area.height < MIN_SANE_AREA) { meta_warning ("struts occupy an unusually large percentage of the screen; " "available remaining height = %d < %d", work_area.height, MIN_SANE_AREA); if (work_area.height < 1) { work_area.y = (workspace->screen->rect.height - MIN_SANE_AREA)/2; work_area.height = MIN_SANE_AREA; } else { int amount = (MIN_SANE_AREA - work_area.height)/2; work_area.y -= amount; work_area.height += 2*amount; } } workspace->work_area_screen = work_area; meta_topic (META_DEBUG_WORKAREA, "Computed work area for workspace %d: %d,%d %d x %d\n", meta_workspace_index (workspace), workspace->work_area_screen.x, workspace->work_area_screen.y, workspace->work_area_screen.width, workspace->work_area_screen.height); /* Now find the work areas for each monitor */ g_free (workspace->work_area_monitor); workspace->work_area_monitor = g_new (MetaRectangle, workspace->screen->n_monitor_infos); for (i = 0; i < workspace->screen->n_monitor_infos; i++) { work_area = workspace->screen->monitor_infos[i].rect; if (workspace->monitor_region[i] == NULL) /* FIXME: constraints.c untested with this, but it might be nice for * a screen reader or magnifier. */ work_area = meta_rect (work_area.x, work_area.y, -1, -1); else meta_rectangle_clip_to_region (workspace->monitor_region[i], FIXED_DIRECTION_NONE, &work_area); workspace->work_area_monitor[i] = work_area; meta_topic (META_DEBUG_WORKAREA, "Computed work area for workspace %d " "monitor %d: %d,%d %d x %d\n", meta_workspace_index (workspace), i, workspace->work_area_monitor[i].x, workspace->work_area_monitor[i].y, workspace->work_area_monitor[i].width, workspace->work_area_monitor[i].height); } /* STEP 4: Make sure the screen_region is nonempty (separate from step 2 * since it relies on step 3). */ if (workspace->screen_region == NULL) { MetaRectangle *nonempty_region; nonempty_region = g_new (MetaRectangle, 1); *nonempty_region = workspace->work_area_screen; workspace->screen_region = g_list_prepend (NULL, nonempty_region); } /* STEP 5: Cache screen and monitor edges for edge resistance and snapping */ g_assert (workspace->screen_edges == NULL); g_assert (workspace->monitor_edges == NULL); workspace->screen_edges = meta_rectangle_find_onscreen_edges (&workspace->screen->rect, workspace->all_struts); tmp = NULL; for (i = 0; i < workspace->screen->n_monitor_infos; i++) tmp = g_list_prepend (tmp, &workspace->screen->monitor_infos[i].rect); workspace->monitor_edges = meta_rectangle_find_nonintersected_monitor_edges (tmp, workspace->all_struts); g_list_free (tmp); /* We're all done, YAAY! Record that everything has been validated. */ workspace->work_areas_invalid = FALSE; { /* * Notify the compositor that the workspace geometry has changed. */ MetaScreen *screen = workspace->screen; MetaDisplay *display = meta_screen_get_display (screen); MetaCompositor *comp = meta_display_get_compositor (display); if (comp) meta_compositor_update_workspace_geometry (comp, workspace); } }
/** * 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); }
/* Focus ancestor of not_this_one if there is one */ static void focus_ancestor_or_top_window (MetaWorkspace *workspace, MetaWindow *not_this_one, guint32 timestamp) { MetaWindow *window = NULL; if (not_this_one) meta_topic (META_DEBUG_FOCUS, "Focusing MRU window excluding %s\n", not_this_one->desc); else meta_topic (META_DEBUG_FOCUS, "Focusing MRU window\n"); /* First, check to see if we need to focus an ancestor of a window */ if (not_this_one) { MetaWindow *ancestor; ancestor = NULL; meta_window_foreach_ancestor (not_this_one, record_ancestor, &ancestor); if (ancestor != NULL && (ancestor->on_all_workspaces || ancestor->workspace == workspace) && meta_window_showing_on_its_workspace (ancestor)) { meta_topic (META_DEBUG_FOCUS, "Focusing %s, ancestor of %s\n", ancestor->desc, not_this_one->desc); meta_window_focus (ancestor, timestamp); /* Also raise the window if in click-to-focus */ if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK) meta_window_raise (ancestor); return; } } window = meta_stack_get_default_focus_window (workspace->screen->stack, workspace, NULL); if (window) { meta_topic (META_DEBUG_FOCUS, "Focusing workspace MRU window %s\n", window->desc); meta_window_focus (window, timestamp); /* Also raise the window if in click-to-focus */ if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK) meta_window_raise (window); } else { meta_topic (META_DEBUG_FOCUS, "No MRU window to focus found; focusing no_focus_window.\n"); meta_display_focus_the_no_focus_window (workspace->screen->display, workspace->screen, timestamp); } }
void meta_workspace_focus_default_window (MetaWorkspace *workspace, MetaWindow *not_this_one, guint32 timestamp) { if (timestamp == CurrentTime) { meta_warning ("CurrentTime used to choose focus window; " "focus window may not be correct.\n"); } if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK || !workspace->screen->display->mouse_mode) focus_ancestor_or_top_window (workspace, not_this_one, timestamp); else { MetaWindow * window; window = meta_screen_get_mouse_window (workspace->screen, not_this_one); if (window && window->type != META_WINDOW_DOCK && window->type != META_WINDOW_DESKTOP) { if (timestamp == CurrentTime) { /* We would like for this to never happen. However, if * it does happen then we kludge since using CurrentTime * can mean ugly race conditions--and we can avoid these * by allowing EnterNotify events (which come with * timestamps) to handle focus. */ meta_topic (META_DEBUG_FOCUS, "Not focusing mouse window %s because EnterNotify events should handle that\n", window->desc); } else { meta_topic (META_DEBUG_FOCUS, "Focusing mouse window %s\n", window->desc); meta_window_focus (window, timestamp); } if (workspace->screen->display->autoraise_window != window && meta_prefs_get_auto_raise ()) { meta_display_queue_autoraise_callback (workspace->screen->display, window); } } else if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_SLOPPY) focus_ancestor_or_top_window (workspace, not_this_one, timestamp); else if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_MOUSE) { meta_topic (META_DEBUG_FOCUS, "Setting focus to no_focus_window, since no valid " "window to focus found.\n"); meta_display_focus_the_no_focus_window (workspace->screen->display, workspace->screen, timestamp); } } }
/* Focus ancestor of not_this_one if there is one, otherwise focus the MRU * window on active workspace */ static void focus_ancestor_or_mru_window (MetaWorkspace *workspace, MetaWindow *not_this_one, guint32 timestamp) { MetaWindow *window = NULL; MetaWindow *desktop_window = NULL; GList *tmp; if (not_this_one) meta_topic (META_DEBUG_FOCUS, "Focusing MRU window excluding %s\n", not_this_one->desc); else meta_topic (META_DEBUG_FOCUS, "Focusing MRU window\n"); /* First, check to see if we need to focus an ancestor of a window */ if (not_this_one) { MetaWindow *ancestor; ancestor = NULL; meta_window_foreach_ancestor (not_this_one, record_ancestor, &ancestor); if (ancestor != NULL) { meta_topic (META_DEBUG_FOCUS, "Focusing %s, ancestor of %s\n", ancestor->desc, not_this_one->desc); meta_window_focus (ancestor, timestamp); /* Also raise the window if in click-to-focus */ if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK) meta_window_raise (ancestor); return; } } /* No ancestor, look for the MRU window */ tmp = workspace->mru_list; while (tmp) { MetaWindow* tmp_window; tmp_window = ((MetaWindow*) tmp->data); if (tmp_window != not_this_one && meta_window_showing_on_its_workspace (tmp_window) && tmp_window->type != META_WINDOW_DOCK && tmp_window->type != META_WINDOW_DESKTOP) { window = tmp->data; break; } else if (tmp_window != not_this_one && desktop_window == NULL && meta_window_showing_on_its_workspace (tmp_window) && tmp_window->type == META_WINDOW_DESKTOP) { /* Found the most recently used desktop window */ desktop_window = tmp_window; } tmp = tmp->next; } /* If no window was found, default to the MRU desktop-window */ if (window == NULL) window = desktop_window; if (window) { meta_topic (META_DEBUG_FOCUS, "Focusing workspace MRU window %s\n", window->desc); meta_window_focus (window, timestamp); /* Also raise the window if in click-to-focus */ if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK) meta_window_raise (window); } else { meta_topic (META_DEBUG_FOCUS, "No MRU window to focus found; focusing no_focus_window.\n"); meta_display_focus_the_no_focus_window (workspace->screen->display, workspace->screen, timestamp); } }
void meta_workspace_activate_with_focus (MetaWorkspace *workspace, MetaWindow *focus_this, guint32 timestamp) { MetaWorkspace *old; MetaWindow *move_window; meta_verbose ("Activating workspace %d\n", meta_workspace_index (workspace)); if (workspace->screen->active_workspace == workspace) return; 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; set_active_space_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); if (focus_this) { meta_window_focus (focus_this, timestamp); meta_window_raise (focus_this); } 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); } }
void meta_window_place (MetaWindow *window, int x, int y, int *new_x, int *new_y) { GList *windows = NULL; const MetaMonitorInfo *xi; meta_topic (META_DEBUG_PLACEMENT, "Placing window %s\n", window->desc); switch (window->type) { /* Run placement algorithm on these. */ case META_WINDOW_NORMAL: case META_WINDOW_DIALOG: case META_WINDOW_MODAL_DIALOG: case META_WINDOW_SPLASHSCREEN: break; /* Assume the app knows best how to place these, no placement * algorithm ever (other than "leave them as-is") */ case META_WINDOW_DESKTOP: case META_WINDOW_DOCK: case META_WINDOW_TOOLBAR: case META_WINDOW_MENU: case META_WINDOW_UTILITY: /* override redirect window types: */ case META_WINDOW_DROPDOWN_MENU: case META_WINDOW_POPUP_MENU: case META_WINDOW_TOOLTIP: case META_WINDOW_NOTIFICATION: case META_WINDOW_COMBO: case META_WINDOW_DND: case META_WINDOW_OVERRIDE_OTHER: goto done; } if (meta_prefs_get_disable_workarounds ()) { switch (window->type) { /* Only accept USPosition on normal windows because the app is full * of shit claiming the user set -geometry for a dialog or dock */ case META_WINDOW_NORMAL: if (window->size_hints.flags & USPosition) { /* don't constrain with placement algorithm */ meta_topic (META_DEBUG_PLACEMENT, "Honoring USPosition for %s instead of using placement algorithm\n", window->desc); goto done; } break; /* Ignore even USPosition on dialogs, splashscreen */ case META_WINDOW_DIALOG: case META_WINDOW_MODAL_DIALOG: case META_WINDOW_SPLASHSCREEN: break; /* Assume the app knows best how to place these. */ case META_WINDOW_DESKTOP: case META_WINDOW_DOCK: case META_WINDOW_TOOLBAR: case META_WINDOW_MENU: case META_WINDOW_UTILITY: /* override redirect window types: */ case META_WINDOW_DROPDOWN_MENU: case META_WINDOW_POPUP_MENU: case META_WINDOW_TOOLTIP: case META_WINDOW_NOTIFICATION: case META_WINDOW_COMBO: case META_WINDOW_DND: case META_WINDOW_OVERRIDE_OTHER: if (window->size_hints.flags & PPosition) { meta_topic (META_DEBUG_PLACEMENT, "Not placing non-normal non-dialog window with PPosition set\n"); goto done; } break; } } else { /* workarounds enabled */ if ((window->size_hints.flags & PPosition) || (window->size_hints.flags & USPosition)) { meta_topic (META_DEBUG_PLACEMENT, "Not placing window with PPosition or USPosition set\n"); avoid_being_obscured_as_second_modal_dialog (window, &x, &y); goto done; } } if (window->type == META_WINDOW_DIALOG || window->type == META_WINDOW_MODAL_DIALOG) { MetaWindow *parent = meta_window_get_transient_for (window); if (parent) { MetaRectangle frame_rect, parent_frame_rect; meta_window_get_frame_rect (window, &frame_rect); meta_window_get_frame_rect (parent, &parent_frame_rect); y = parent_frame_rect.y; /* center of parent */ x = parent_frame_rect.x + parent_frame_rect.width / 2; /* center of child over center of parent */ x -= frame_rect.width / 2; /* "visually" center window over parent, leaving twice as * much space below as on top. */ y += (parent_frame_rect.height - frame_rect.height)/3; meta_topic (META_DEBUG_PLACEMENT, "Centered window %s over transient parent\n", window->desc); avoid_being_obscured_as_second_modal_dialog (window, &x, &y); goto done; } } /* FIXME UTILITY with transient set should be stacked up * on the sides of the parent window or something. */ if (window_place_centered (window)) { /* Center on current monitor */ int w, h; MetaRectangle frame_rect; meta_window_get_frame_rect (window, &frame_rect); /* Warning, this function is a round trip! */ xi = meta_screen_get_current_monitor_info (window->screen); w = xi->rect.width; h = xi->rect.height; x = (w - frame_rect.width) / 2; y = (h - frame_rect.height) / 2; x += xi->rect.x; y += xi->rect.y; meta_topic (META_DEBUG_PLACEMENT, "Centered window %s on screen %d monitor %d\n", window->desc, window->screen->number, xi->number); goto done_check_denied_focus; } /* Find windows that matter (not minimized, on same workspace * as placed window, may be shaded - if shaded we pretend it isn't * for placement purposes) */ { GSList *all_windows; GSList *tmp; all_windows = meta_display_list_windows (window->display, META_LIST_DEFAULT); tmp = all_windows; while (tmp != NULL) { MetaWindow *w = tmp->data; if (w != window && meta_window_showing_on_its_workspace (w) && meta_window_located_on_workspace (w, window->workspace)) windows = g_list_prepend (windows, w); tmp = tmp->next; } g_slist_free (all_windows); } /* Warning, this is a round trip! */ xi = meta_screen_get_current_monitor_info (window->screen); /* Maximize windows if they are too big for their work area (bit of * a hack here). Assume undecorated windows probably don't intend to * be maximized. */ if (window->has_maximize_func && window->decorated && !window->fullscreen) { MetaRectangle workarea; MetaRectangle frame_rect; meta_window_get_work_area_for_monitor (window, xi->number, &workarea); meta_window_get_frame_rect (window, &frame_rect); /* If the window is bigger than the screen, then automaximize. Do NOT * auto-maximize the directions independently. See #419810. */ if (frame_rect.width >= workarea.width && frame_rect.height >= workarea.height) { window->maximize_horizontally_after_placement = TRUE; window->maximize_vertically_after_placement = TRUE; } } /* "Origin" placement algorithm */ x = xi->rect.x; y = xi->rect.y; if (find_first_fit (window, windows, xi->number, x, y, &x, &y)) goto done_check_denied_focus; /* No good fit? Fall back to cascading... */ find_next_cascade (window, windows, x, y, &x, &y); done_check_denied_focus: /* If the window is being denied focus and isn't a transient of the * focus window, we do NOT want it to overlap with the focus window * if at all possible. This is guaranteed to only be called if the * focus_window is non-NULL, and we try to avoid that window. */ if (window->denied_focus_and_not_transient) { MetaWindow *focus_window; gboolean found_fit; focus_window = window->display->focus_window; g_assert (focus_window != NULL); /* No need to do anything if the window doesn't overlap at all */ found_fit = !window_overlaps_focus_window (window); /* Try to do a first fit again, this time only taking into account the * focus window. */ if (!found_fit) { GList *focus_window_list; focus_window_list = g_list_prepend (NULL, focus_window); /* Reset x and y ("origin" placement algorithm) */ x = xi->rect.x; y = xi->rect.y; found_fit = find_first_fit (window, focus_window_list, xi->number, x, y, &x, &y); g_list_free (focus_window_list); } /* If that still didn't work, just place it where we can see as much * as possible. */ if (!found_fit) find_most_freespace (window, focus_window, x, y, &x, &y); } done: if (windows) g_list_free (windows); *new_x = x; *new_y = y; }
/** * stack_sync_to_server: * * Order the windows on the X server to be the same as in our structure. * We do this using XRestackWindows if we don't know the previous order, * or XConfigureWindow on a few particular windows if we do and can figure * out the minimum set of changes. After that, we set __NET_CLIENT_LIST * and __NET_CLIENT_LIST_STACKING. * * FIXME: Now that we have a good view of the stacking order on the server * with MetaStackTracker it should be possible to do a simpler and better * job of computing the minimal set of stacking requests needed. */ static void stack_sync_to_xserver (MetaStack *stack) { GArray *x11_stacked; GArray *all_root_children_stacked; /* wayland OR x11 */ GList *tmp; GArray *x11_hidden_stack_ids; /* Bail out if frozen */ if (stack->freeze_count > 0) return; meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n"); stack_ensure_sorted (stack); /* Create stacked xwindow arrays, in bottom-to-top order */ x11_stacked = g_array_new (FALSE, FALSE, sizeof (Window)); all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (guint64)); x11_hidden_stack_ids = g_array_new (FALSE, FALSE, sizeof (guint64)); meta_topic (META_DEBUG_STACK, "Top to bottom: "); meta_push_no_msg_prefix (); for (tmp = g_list_last(stack->sorted); tmp != NULL; tmp = tmp->prev) { MetaWindow *w = tmp->data; Window top_level_window; guint64 stack_id; if (w->unmanaging) continue; meta_topic (META_DEBUG_STACK, "%u:%d - %s ", w->layer, w->stack_position, w->desc); g_array_append_val (x11_stacked, w->xwindow); if (w->frame) top_level_window = w->frame->xwindow; else top_level_window = w->xwindow; if (w->client_type == META_WINDOW_CLIENT_TYPE_X11) stack_id = top_level_window; else stack_id = w->stamp; /* We don't restack hidden windows along with the rest, though they are * reflected in the _NET hints. Hidden windows all get pushed below * the screens fullscreen guard_window. */ if (w->hidden) { if (w->client_type == META_WINDOW_CLIENT_TYPE_X11) { guint64 stack_id = top_level_window; g_array_append_val (x11_hidden_stack_ids, stack_id); } continue; } g_array_append_val (all_root_children_stacked, stack_id); } meta_topic (META_DEBUG_STACK, "\n"); meta_pop_no_msg_prefix (); /* The screen guard window sits above all hidden windows and acts as * a barrier to input reaching these windows. */ g_array_append_val (x11_hidden_stack_ids, stack->screen->guard_window); /* Sync to server */ meta_topic (META_DEBUG_STACK, "Restacking %u windows\n", all_root_children_stacked->len); meta_stack_tracker_restack_managed (stack->screen->stack_tracker, (guint64 *)all_root_children_stacked->data, all_root_children_stacked->len); meta_stack_tracker_restack_at_bottom (stack->screen->stack_tracker, (guint64 *)x11_hidden_stack_ids->data, x11_hidden_stack_ids->len); /* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */ XChangeProperty (stack->screen->display->xdisplay, stack->screen->xroot, stack->screen->display->atom__NET_CLIENT_LIST, XA_WINDOW, 32, PropModeReplace, (unsigned char *)stack->xwindows->data, stack->xwindows->len); XChangeProperty (stack->screen->display->xdisplay, stack->screen->xroot, stack->screen->display->atom__NET_CLIENT_LIST_STACKING, XA_WINDOW, 32, PropModeReplace, (unsigned char *)x11_stacked->data, x11_stacked->len); g_array_free (x11_stacked, TRUE); g_array_free (all_root_children_stacked, TRUE); }