/**
 * cinnamon_startup_sequence_create_icon:
 * @sequence:
 * @size: Size in pixels of icon
 *
 * Returns: (transfer none): A new #ClutterTexture containing an icon for the sequence
 */
ClutterActor *
cinnamon_startup_sequence_create_icon (CinnamonStartupSequence *sequence, guint size)
{
  GIcon *themed;
  const char *icon_name;
  ClutterActor *texture;

  icon_name = sn_startup_sequence_get_icon_name ((SnStartupSequence*)sequence);
  if (!icon_name)
    {
      gint scale;
      CinnamonGlobal *global;
      StThemeContext *context;

      texture = clutter_texture_new ();

      global = cinnamon_global_get ();
      context = st_theme_context_get_for_stage (cinnamon_global_get_stage (global));
      g_object_get (context, "scale-factor", &scale, NULL);

      clutter_actor_set_size (texture, size * scale, size * scale);
      return texture;
    }

  themed = g_themed_icon_new (icon_name);
  texture = g_object_new (ST_TYPE_ICON, "gicon", themed, "icon-size", size, NULL);
  g_object_unref (G_OBJECT (themed));
  return texture;
}
Esempio n. 2
0
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);
}
Esempio n. 4
0
static ClutterActor *
window_backed_app_get_icon (CinnamonApp *app,
                            int       size)
{
  MetaWindow *window;
  ClutterActor *actor;
  gint scale;
  CinnamonGlobal *global;
  StThemeContext *context;

  global = cinnamon_global_get ();
  context = st_theme_context_get_for_stage (cinnamon_global_get_stage (global));
  g_object_get (context, "scale-factor", &scale, NULL);

  size *= scale;

  /* During a state transition from running to not-running for
   * window-backend apps, it's possible we get a request for the icon.
   * Avoid asserting here and just return an empty image.
   */
  if (app->running_state == NULL)
    {
      actor = clutter_texture_new ();
      g_object_set (actor, "opacity", 0, "width", (float) size, "height", (float) size, NULL);
      return actor;
    }

  window = window_backed_app_get_window (app);
  actor = st_texture_cache_bind_pixbuf_property (st_texture_cache_get_default (),
                                                               G_OBJECT (window),
                                                               "icon");
  g_object_set (actor, "width", (float) size, "height", (float) size, NULL);
  return actor;
}
Esempio n. 5
0
/**
 * 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
update_focus_app (CinnamonWindowTracker *self)
{
  MetaWindow *new_focus_win;
  CinnamonApp *new_focus_app;

  new_focus_win = meta_display_get_focus_window (cinnamon_global_get_display (cinnamon_global_get ()));
  new_focus_app = new_focus_win ? cinnamon_window_tracker_get_window_app (self, new_focus_win) : NULL;

  set_focus_app (self, new_focus_app);
}
Esempio n. 7
0
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
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);
}
Esempio n. 9
0
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);
}
Esempio n. 10
0
/**
 * cinnamon_app_get_faded_icon:
 * @app: A #CinnamonApp
 * @size: Size in pixels
 *
 * Return an actor with a horizontally faded look.
 *
 * Return value: (transfer none): A floating #ClutterActor, or %NULL if no icon
 */
ClutterActor *
cinnamon_app_get_faded_icon (CinnamonApp *app, int size)
{
  CoglHandle texture;
  ClutterActor *result;
  char *cache_key;
  CreateFadedIconData data;
  gint scale;
  CinnamonGlobal *global;
  StThemeContext *context;

  /* Don't fade for window backed apps for now...easier to reuse the
   * property tracking bits, and this helps us visually distinguish
   * app-tracked from not.
   */
  if (!app->entry)
    return window_backed_app_get_icon (app, size);

  global = cinnamon_global_get ();
  context = st_theme_context_get_for_stage (cinnamon_global_get_stage (global));
  g_object_get (context, "scale-factor", &scale, NULL);

  cache_key = g_strdup_printf ("faded-icon:%s,size=%d,scale=%d", cinnamon_app_get_id (app), size, scale);
  data.app = app;
  data.size = size;
  data.scale = scale;
  texture = st_texture_cache_load (st_texture_cache_get_default (),
                                   cache_key,
                                   ST_TEXTURE_CACHE_POLICY_FOREVER,
                                   cinnamon_app_create_faded_icon_cpu,
                                   &data,
                                   NULL);
  g_free (cache_key);

  if (texture != COGL_INVALID_HANDLE)
    {
      result = clutter_texture_new ();
      clutter_texture_set_cogl_texture (CLUTTER_TEXTURE (result), texture);
    }
  else
    {
      result = clutter_texture_new ();
      g_object_set (result, "opacity", 0, "width", (float) size * scale, "height", (float) size * scale, NULL);

    }
  return result;
}
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);
}
Esempio n. 12
0
/**
 * cinnamon_app_activate_full:
 * @app: a #CinnamonApp
 * @workspace: launch on this workspace, or -1 for default. Ignored if
 *   activating an existing window
 * @timestamp: Event timestamp
 *
 * Perform an appropriate default action for operating on this application,
 * dependent on its current state.  For example, if the application is not
 * currently running, launch it.  If it is running, activate the most
 * recently used NORMAL window (or if that window has a transient, the most
 * recently used transient for that window).
 */
void
cinnamon_app_activate_full (CinnamonApp      *app,
                         int            workspace,
                         guint32        timestamp)
{
  CinnamonGlobal *global;

  global = cinnamon_global_get ();

  if (timestamp == 0)
    timestamp = cinnamon_global_get_current_time (global);

  switch (app->state)
    {
      case CINNAMON_APP_STATE_STOPPED:
        {
          GError *error = NULL;
          if (!cinnamon_app_launch (app,
                                 timestamp,
                                 NULL,
                                 workspace,
                                 NULL,
                                 &error))
            {
              char *msg;
              msg = g_strdup_printf (_("Failed to launch '%s'"), cinnamon_app_get_name (app));
              cinnamon_global_notify_error (global,
                                         msg,
                                         error->message);
              g_free (msg);
              g_clear_error (&error);
            }
        }
        break;
      case CINNAMON_APP_STATE_STARTING:
        break;
      case CINNAMON_APP_STATE_RUNNING:
        cinnamon_app_activate_window (app, NULL, timestamp);
        break;
    }
}
Esempio n. 13
0
/**
 * cinnamon_app_request_quit:
 * @app: A #CinnamonApp
 *
 * Initiate an asynchronous request to quit this application.
 * The application may interact with the user, and the user
 * might cancel the quit request from the application UI.
 *
 * This operation may not be supported for all applications.
 *
 * Returns: %TRUE if a quit request is supported for this application
 */
gboolean
cinnamon_app_request_quit (CinnamonApp   *app)
{
  GSList *iter;

  if (cinnamon_app_get_state (app) != CINNAMON_APP_STATE_RUNNING)
    return FALSE;

  /* TODO - check for an XSMP connection; we could probably use that */

  for (iter = app->running_state->windows; iter; iter = iter->next)
    {
      MetaWindow *win = iter->data;

      if (!cinnamon_window_tracker_is_window_interesting (win))
        continue;

      meta_window_delete (win, cinnamon_global_get_current_time (cinnamon_global_get ()));
    }
  return TRUE;
}
Esempio n. 14
0
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);
    }
}
Esempio n. 16
0
int
main (int argc, char **argv)
{
  GOptionContext *ctx;
  GError *error = NULL;
  int ecode;
  g_setenv ("CLUTTER_DISABLE_XINPUT", "1", TRUE);
  g_setenv ("CLUTTER_BACKEND", "x11", TRUE);

  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
  textdomain (GETTEXT_PACKAGE);

  g_setenv ("GDK_SCALE", "1", TRUE);

  ctx = meta_get_option_context ();
  g_option_context_add_main_entries (ctx, gnome_cinnamon_options, GETTEXT_PACKAGE);
  if (!g_option_context_parse (ctx, &argc, &argv, &error))
    {
      g_printerr ("%s: %s\n", argv[0], error->message);
      exit (1);
    }

  g_option_context_free (ctx);

  meta_plugin_manager_set_plugin_type (gnome_cinnamon_plugin_get_type ());

  /* Prevent meta_init() from causing gtk to load gail and at-bridge */
  g_setenv ("NO_GAIL", "1", TRUE);
  g_setenv ("NO_AT_BRIDGE", "1", TRUE);
  meta_init ();
  g_unsetenv ("NO_GAIL");
  g_unsetenv ("NO_AT_BRIDGE");
  g_unsetenv ("CLUTTER_DISABLE_XINPUT");
  g_unsetenv ("CLUTTER_BACKEND");

  /* FIXME: Add gjs API to set this stuff and don't depend on the
   * environment.  These propagate to child processes.
   */
  g_setenv ("GJS_DEBUG_OUTPUT", "stderr", TRUE);
  g_setenv ("GJS_DEBUG_TOPICS", "JS ERROR;JS LOG", TRUE);

  g_setenv ("CINNAMON_VERSION", VERSION, TRUE);


  center_pointer_on_screen();

  cinnamon_dbus_init (meta_get_replace_current_wm ());
  cinnamon_a11y_init ();
  cinnamon_perf_log_init ();

  g_irepository_prepend_search_path (CINNAMON_PKGLIBDIR);
#if HAVE_BLUETOOTH
  g_irepository_prepend_search_path (BLUETOOTH_DIR);
#endif

  /* Disable debug spew from various libraries */
  g_log_set_handler ("Cvc", G_LOG_LEVEL_DEBUG,
                     muted_log_handler, NULL);
  g_log_set_handler ("AccountsService", G_LOG_LEVEL_DEBUG,
                     muted_log_handler, NULL);
  g_log_set_handler ("Bluetooth", G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_MESSAGE,
                     muted_log_handler, NULL);

  /* Initialize the global object */
  _cinnamon_global_init (NULL);

  g_unsetenv ("GDK_SCALE");

  ecode = meta_run ();

  if (g_getenv ("CINNAMON_ENABLE_CLEANUP"))
    {
      g_printerr ("Doing final cleanup...\n");
      g_object_unref (cinnamon_global_get ());
    }

  return ecode;
}
Esempio n. 17
0
int
main (int argc, char **argv)
{
  GOptionContext *ctx;
  GError *error = NULL;
  CinnamonSessionType session_type;
  int ecode;
  TpDebugSender *sender;

  g_type_init ();

  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
  textdomain (GETTEXT_PACKAGE);

  ctx = meta_get_option_context ();
  g_option_context_add_main_entries (ctx, gnome_cinnamon_options, GETTEXT_PACKAGE);
  if (!g_option_context_parse (ctx, &argc, &argv, &error))
    {
      g_printerr ("%s: %s\n", argv[0], error->message);
      exit (1);
    }

  g_option_context_free (ctx);

  meta_plugin_type_register (gnome_cinnamon_plugin_get_type ());

  /* Prevent meta_init() from causing gtk to load gail and at-bridge */
  g_setenv ("NO_GAIL", "1", TRUE);
  g_setenv ("NO_AT_BRIDGE", "1", TRUE);
  meta_init ();
  g_unsetenv ("NO_GAIL");
  g_unsetenv ("NO_AT_BRIDGE");

  /* FIXME: Add gjs API to set this stuff and don't depend on the
   * environment.  These propagate to child processes.
   */
  g_setenv ("GJS_DEBUG_OUTPUT", "stderr", TRUE);
  g_setenv ("GJS_DEBUG_TOPICS", "JS ERROR;JS LOG", TRUE);

  cinnamon_dbus_init (meta_get_replace_current_wm ());
  cinnamon_a11y_init ();
  cinnamon_fonts_init ();
  cinnamon_perf_log_init ();
  cinnamon_prefs_init ();

  gdk_event_handler_set (gnome_cinnamon_gdk_event_handler, NULL, NULL);

  g_irepository_prepend_search_path (CINNAMON_PKGLIBDIR);
#if HAVE_BLUETOOTH
  g_irepository_prepend_search_path (BLUETOOTH_DIR);
#endif

  /* Disable debug spew from various libraries */
  g_log_set_handler ("Gvc", G_LOG_LEVEL_DEBUG,
                     muted_log_handler, NULL);
  g_log_set_handler ("AccountsService", G_LOG_LEVEL_DEBUG,
                     muted_log_handler, NULL);
  g_log_set_handler ("Bluetooth", G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_MESSAGE,
                     muted_log_handler, NULL);
  g_log_set_handler ("tp-glib/proxy", G_LOG_LEVEL_DEBUG,
                     muted_log_handler, NULL);

  /* Turn on telepathy-glib debugging but filter it out in
   * default_log_handler. This handler also exposes all the logs over D-Bus
   * using TpDebugSender. */
  tp_debug_set_flags ("all");

  sender = tp_debug_sender_dup ();
  g_log_set_default_handler (default_log_handler, sender);

  /* Initialize the global object */
  if (is_gdm_mode)
      session_type = CINNAMON_SESSION_GDM;
  else
      session_type = CINNAMON_SESSION_USER;

  _cinnamon_global_init ("session-type", session_type, NULL);

  ecode = meta_run ();

  if (g_getenv ("CINNAMON_ENABLE_CLEANUP"))
    {
      g_printerr ("Doing final cleanup...\n");
      g_object_unref (cinnamon_global_get ());
    }

  g_object_unref (sender);

  return ecode;
}
Esempio n. 18
0
int
main(int argc, char **argv)
{
  GOptionContext *context;
  ClutterActor *stage;
  GError *error = NULL;
  CinnamonGlobal *global;
  GjsContext *js_context;
  char *script;
  const char *filename;
  char *title;
  gsize len;
  int code;


  gtk_init (&argc, &argv);

  clutter_x11_set_display (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
  clutter_x11_disable_event_retrieval ();

  if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
    return 1;

  gdk_window_add_filter (NULL, event_filter, NULL);

  context = g_option_context_new (NULL);

  /* pass unknown through to the JS script */
  g_option_context_set_ignore_unknown_options (context, TRUE);

  g_option_context_add_main_entries (context, entries, NULL);
  if (!g_option_context_parse (context, &argc, &argv, &error))
    g_error ("option parsing failed: %s", error->message);

  setlocale (LC_ALL, "");
  g_type_init ();

  _cinnamon_global_init (NULL);
  global = cinnamon_global_get ();
  js_context = _cinnamon_global_get_gjs_context (global);

  /* prepare command line arguments */
  if (!gjs_context_define_string_array (js_context, "ARGV",
                                        argc - 2, (const char**)argv + 2,
                                        &error)) {
    g_printerr ("Failed to defined ARGV: %s", error->message);
    exit (1);
  }

  if (command != NULL) {
    script = command;
    len = strlen (script);
    filename = "<command line>";
  } else if (argc <= 1) {
    script = g_strdup ("const Console = imports.console; Console.interact();");
    len = strlen (script);
    filename = "<stdin>";
  } else /*if (argc >= 2)*/ {
    error = NULL;
    if (!g_file_get_contents (argv[1], &script, &len, &error)) {
      g_printerr ("%s\n", error->message);
      exit (1);
    }
    filename = argv[1];
  }

  stage = clutter_stage_get_default ();
  title = g_filename_display_basename (filename);
  clutter_stage_set_title (CLUTTER_STAGE (stage), title);
  g_free (title);

#if HAVE_BLUETOOTH
  /* The module imports are all so intertwined that if the test
   * imports anything in js/ui, it will probably eventually end up
   * pulling in ui/status/bluetooth.js. So we need this.
   */
  g_irepository_prepend_search_path (BLUETOOTH_DIR);
#endif

  /* evaluate the script */
  error = NULL;
  if (!gjs_context_eval (js_context, script, len,
                         filename, &code, &error)) {
    g_free (script);
    g_printerr ("%s\n", error->message);
    exit (1);
  }

  g_free (script);
  exit (code);
}
Esempio n. 19
0
/**
 * 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;
}
Esempio n. 20
0
/**
 * 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);
    }
}