void _cinnamon_app_handle_startup_sequence (CinnamonApp *app, SnStartupSequence *sequence) { gboolean starting = !sn_startup_sequence_get_completed (sequence); /* The Cinnamon design calls for on application launch, the app title * appears at top, and no X window is focused. So when we get * a startup-notification for this app, transition it to STARTING * if it's currently stopped, set it as our application focus, * but focus the no_focus window. */ if (starting && cinnamon_app_get_state (app) == CINNAMON_APP_STATE_STOPPED) { MetaScreen *screen = cinnamon_global_get_screen (cinnamon_global_get ()); MetaDisplay *display = meta_screen_get_display (screen); cinnamon_app_state_transition (app, CINNAMON_APP_STATE_STARTING); meta_display_focus_the_no_focus_window (display, screen, sn_startup_sequence_get_timestamp (sequence)); app->started_on_workspace = sn_startup_sequence_get_workspace (sequence); } if (!starting) { if (app->running_state && app->running_state->windows) cinnamon_app_state_transition (app, CINNAMON_APP_STATE_RUNNING); else /* application have > 1 .desktop file */ cinnamon_app_state_transition (app, CINNAMON_APP_STATE_STOPPED); } }
/** * cinnamon_window_tracker_get_startup_sequences: * @tracker: * * Returns: (transfer none) (element-type CinnamonStartupSequence): Currently active startup sequences */ GSList * cinnamon_window_tracker_get_startup_sequences (CinnamonWindowTracker *self) { CinnamonGlobal *global = cinnamon_global_get (); MetaScreen *screen = cinnamon_global_get_screen (global); return meta_screen_get_startup_sequences (screen); }
/** * cinnamon_app_launch: * @timestamp: Event timestamp, or 0 for current event timestamp * @uris: (element-type utf8): List of uris to pass to application * @workspace: Start on this workspace, or -1 for default * @startup_id: (out): Returned startup notification ID, or %NULL if none * @error: A #GError */ gboolean cinnamon_app_launch (CinnamonApp *app, guint timestamp, GList *uris, int workspace, char **startup_id, GError **error) { GDesktopAppInfo *gapp; GdkAppLaunchContext *context; gboolean ret; CinnamonGlobal *global; MetaScreen *screen; GdkDisplay *gdisplay; if (startup_id) *startup_id = NULL; if (app->entry == NULL) { MetaWindow *window = window_backed_app_get_window (app); /* We can't pass URIs into a window; shouldn't hit this * code path. If we do, fix the caller to disallow it. */ g_return_val_if_fail (uris == NULL, TRUE); meta_window_activate (window, timestamp); return TRUE; } global = cinnamon_global_get (); screen = cinnamon_global_get_screen (global); gdisplay = gdk_screen_get_display (cinnamon_global_get_gdk_screen (global)); if (timestamp == 0) timestamp = cinnamon_global_get_current_time (global); if (workspace < 0) workspace = meta_screen_get_active_workspace_index (screen); context = gdk_display_get_app_launch_context (gdisplay); gdk_app_launch_context_set_timestamp (context, timestamp); gdk_app_launch_context_set_desktop (context, workspace); gapp = gmenu_tree_entry_get_app_info (app->entry); ret = g_desktop_app_info_launch_uris_as_manager (gapp, uris, G_APP_LAUNCH_CONTEXT (context), G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, _gather_pid_callback, app, error); g_object_unref (context); return ret; }
static void create_running_state (CinnamonApp *app) { MetaScreen *screen; g_assert (app->running_state == NULL); screen = cinnamon_global_get_screen (cinnamon_global_get ()); app->running_state = g_slice_new0 (CinnamonAppRunningState); app->running_state->refcount = 1; app->running_state->workspace_switch_id = g_signal_connect (screen, "workspace-switched", G_CALLBACK(cinnamon_app_on_ws_switch), app); }
static void unref_running_state (CinnamonAppRunningState *state) { MetaScreen *screen; state->refcount--; if (state->refcount > 0) return; screen = cinnamon_global_get_screen (cinnamon_global_get ()); g_signal_handler_disconnect (screen, state->workspace_switch_id); g_slice_free (CinnamonAppRunningState, state); }
static void init_window_tracking (CinnamonWindowTracker *self) { MetaDisplay *display; MetaScreen *screen = cinnamon_global_get_screen (cinnamon_global_get ()); g_signal_connect (screen, "notify::n-workspaces", G_CALLBACK (cinnamon_window_tracker_on_n_workspaces_changed), self); display = meta_screen_get_display (screen); g_signal_connect (display, "notify::focus-window", G_CALLBACK (on_focus_window_changed), self); cinnamon_window_tracker_on_n_workspaces_changed (screen, NULL, self); }
/** * cinnamon_app_get_windows: * @app: * * Get the toplevel, interesting windows which are associated with this * application. The returned list will be sorted first by whether * they're on the active workspace, then by whether they're visible, * and finally by the time the user last interacted with them. * * Returns: (transfer none) (element-type MetaWindow): List of windows */ GSList * cinnamon_app_get_windows (CinnamonApp *app) { if (app->running_state == NULL) return NULL; if (app->running_state->window_sort_stale) { CompareWindowsData data; data.app = app; data.active_workspace = meta_screen_get_active_workspace (cinnamon_global_get_screen (cinnamon_global_get ())); app->running_state->windows = g_slist_sort_with_data (app->running_state->windows, cinnamon_app_compare_windows, &data); app->running_state->window_sort_stale = FALSE; } return app->running_state->windows; }
static void cinnamon_window_tracker_init (CinnamonWindowTracker *self) { MetaScreen *screen; self->window_to_app = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_object_unref); self->launched_pid_to_app = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_object_unref); screen = cinnamon_global_get_screen (cinnamon_global_get ()); g_signal_connect (G_OBJECT (screen), "startup-sequence-changed", G_CALLBACK (on_startup_sequence_changed), self); load_initial_windows (self); init_window_tracking (self); }
static void constrain_tooltip (StTooltip *tooltip, const ClutterGeometry *geometry, ClutterGeometry *adjusted_geometry, gpointer data) { const ClutterGeometry *tip_area = st_tooltip_get_tip_area (tooltip); CinnamonGlobal *global = cinnamon_global_get (); MetaScreen *screen = cinnamon_global_get_screen (global); int n_monitors = meta_screen_get_n_monitors (screen); int i; *adjusted_geometry = *geometry; /* A point that determines what screen we'll constrain to */ int x = tip_area->x + tip_area->width / 2; int y = tip_area->y + tip_area->height / 2; for (i = 0; i < n_monitors; i++) { MetaRectangle rect; meta_screen_get_monitor_geometry (screen, i, &rect); if (x >= rect.x && x < rect.x + rect.width && y >= rect.y && y < rect.y + rect.height) { if (adjusted_geometry->x + adjusted_geometry->width > rect.x + rect.width) adjusted_geometry->x = rect.x + rect.width - adjusted_geometry->width; if (adjusted_geometry->x < rect.x) adjusted_geometry->x = rect.x; if (adjusted_geometry->y + adjusted_geometry->height > rect.y + rect.height) adjusted_geometry->y = rect.y + rect.height - adjusted_geometry->height; if (adjusted_geometry->y < rect.y) adjusted_geometry->y = rect.y; return; } } }
static void load_initial_windows (CinnamonWindowTracker *tracker) { GList *workspaces, *iter; MetaScreen *screen = cinnamon_global_get_screen (cinnamon_global_get ()); workspaces = meta_screen_get_workspaces (screen); for (iter = workspaces; iter; iter = iter->next) { MetaWorkspace *workspace = iter->data; GList *windows = meta_workspace_list_windows (workspace); GList *window_iter; for (window_iter = windows; window_iter; window_iter = window_iter->next) { MetaWindow *window = window_iter->data; track_window (tracker, window); } g_list_free (windows); } }
/** * cinnamon_app_activate_window: * @app: a #CinnamonApp * @window: (allow-none): Window to be focused * @timestamp: Event timestamp * * Bring all windows for the given app to the foreground, * but ensure that @window is on top. If @window is %NULL, * the window with the most recent user time for the app * will be used. * * This function has no effect if @app is not currently running. */ void cinnamon_app_activate_window (CinnamonApp *app, MetaWindow *window, guint32 timestamp) { GSList *windows; if (cinnamon_app_get_state (app) != CINNAMON_APP_STATE_RUNNING) return; windows = cinnamon_app_get_windows (app); if (window == NULL && windows) window = windows->data; if (!g_slist_find (windows, window)) return; else { GSList *iter; CinnamonGlobal *global = cinnamon_global_get (); MetaScreen *screen = cinnamon_global_get_screen (global); MetaDisplay *display = meta_screen_get_display (screen); MetaWorkspace *active = meta_screen_get_active_workspace (screen); MetaWorkspace *workspace = meta_window_get_workspace (window); guint32 last_user_timestamp = meta_display_get_last_user_time (display); MetaWindow *most_recent_transient; if (meta_display_xserver_time_is_before (display, timestamp, last_user_timestamp)) { meta_window_set_demands_attention (window); return; } /* Now raise all the other windows for the app that are on * the same workspace, in reverse order to preserve the stacking. */ for (iter = windows; iter; iter = iter->next) { MetaWindow *other_window = iter->data; if (other_window != window) meta_window_raise (other_window); } /* If we have a transient that the user's interacted with more recently than * the window, pick that. */ most_recent_transient = find_most_recent_transient_on_same_workspace (display, window); if (most_recent_transient && meta_display_xserver_time_is_before (display, meta_window_get_user_time (window), meta_window_get_user_time (most_recent_transient))) window = most_recent_transient; if (!cinnamon_window_tracker_is_window_interesting (window)) { /* We won't get notify::user-time signals for uninteresting windows, * which means that an app's last_user_time won't get updated. * Update it here instead. */ app->running_state->last_user_time = timestamp; } if (active != workspace) meta_workspace_activate_with_focus (workspace, window, timestamp); else meta_window_activate (window, timestamp); } }