gnome-shell-3.6.3.1/src/shell-global.c

No issues found

   1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
   2 
   3 #include "config.h"
   4 
   5 #include <dirent.h>
   6 #include <errno.h>
   7 #include <fcntl.h>
   8 #include <math.h>
   9 #include <stdarg.h>
  10 #include <stdlib.h>
  11 #include <string.h>
  12 #include <unistd.h>
  13 #ifdef HAVE_SYS_RESOURCE_H
  14 #include <sys/resource.h>
  15 #endif
  16 
  17 #include <X11/extensions/Xfixes.h>
  18 #include <cogl-pango/cogl-pango.h>
  19 #include <canberra.h>
  20 #include <clutter/glx/clutter-glx.h>
  21 #include <clutter/x11/clutter-x11.h>
  22 #include <gdk/gdkx.h>
  23 #include <gio/gio.h>
  24 #include <gjs/gjs-module.h>
  25 #include <girepository.h>
  26 #include <meta/display.h>
  27 #include <meta/util.h>
  28 #include <meta/meta-shaped-texture.h>
  29 
  30 /* Memory report bits */
  31 #ifdef HAVE_MALLINFO
  32 #include <malloc.h>
  33 #endif
  34 
  35 #include "shell-enum-types.h"
  36 #include "shell-global-private.h"
  37 #include "shell-jsapi-compat-private.h"
  38 #include "shell-perf-log.h"
  39 #include "shell-window-tracker.h"
  40 #include "shell-wm.h"
  41 #include "st.h"
  42 
  43 static ShellGlobal *the_object = NULL;
  44 
  45 static void grab_notify (GtkWidget *widget, gboolean is_grab, gpointer user_data);
  46 static void shell_global_on_gc (GjsContext   *context,
  47                                 ShellGlobal  *global);
  48 
  49 struct _ShellGlobal {
  50   GObject parent;
  51 
  52   ClutterStage *stage;
  53   Window stage_xwindow;
  54   GdkWindow *stage_gdk_window;
  55 
  56   MetaDisplay *meta_display;
  57   GdkDisplay *gdk_display;
  58   Display *xdisplay;
  59   MetaScreen *meta_screen;
  60   GdkScreen *gdk_screen;
  61 
  62   char *session_mode;
  63 
  64   /* We use this window to get a notification from GTK+ when
  65    * a widget in our process does a GTK+ grab.  See
  66    * http://bugzilla.gnome.org/show_bug.cgi?id=570641
  67    * 
  68    * This window is never mapped or shown.
  69    */
  70   GtkWindow *grab_notifier;
  71   gboolean gtk_grab_active;
  72 
  73   ShellStageInputMode input_mode;
  74   XserverRegion input_region;
  75 
  76   GjsContext *js_context;
  77   MetaPlugin *plugin;
  78   ShellWM *wm;
  79   GSettings *settings;
  80   const char *datadir;
  81   const char *imagedir;
  82   const char *userdatadir;
  83   StFocusManager *focus_manager;
  84 
  85   guint work_count;
  86   GSList *leisure_closures;
  87   guint leisure_function_id;
  88 
  89   /* For sound notifications */
  90   ca_context *sound_context;
  91 
  92   guint32 xdnd_timestamp;
  93 
  94   gint64 last_gc_end_time;
  95 };
  96 
  97 enum {
  98   PROP_0,
  99 
 100   PROP_SESSION_MODE,
 101   PROP_OVERLAY_GROUP,
 102   PROP_SCREEN,
 103   PROP_GDK_SCREEN,
 104   PROP_DISPLAY,
 105   PROP_SCREEN_WIDTH,
 106   PROP_SCREEN_HEIGHT,
 107   PROP_STAGE,
 108   PROP_STAGE_INPUT_MODE,
 109   PROP_WINDOW_GROUP,
 110   PROP_BACKGROUND_ACTOR,
 111   PROP_WINDOW_MANAGER,
 112   PROP_SETTINGS,
 113   PROP_DATADIR,
 114   PROP_IMAGEDIR,
 115   PROP_USERDATADIR,
 116   PROP_FOCUS_MANAGER,
 117 };
 118 
 119 /* Signals */
 120 enum
 121 {
 122  XDND_POSITION_CHANGED,
 123  XDND_LEAVE,
 124  XDND_ENTER,
 125  NOTIFY_ERROR,
 126  LAST_SIGNAL
 127 };
 128 
 129 G_DEFINE_TYPE(ShellGlobal, shell_global, G_TYPE_OBJECT);
 130 
 131 static guint shell_global_signals [LAST_SIGNAL] = { 0 };
 132 
 133 static void
 134 shell_global_set_property(GObject         *object,
 135                           guint            prop_id,
 136                           const GValue    *value,
 137                           GParamSpec      *pspec)
 138 {
 139   ShellGlobal *global = SHELL_GLOBAL (object);
 140 
 141   switch (prop_id)
 142     {
 143     case PROP_STAGE_INPUT_MODE:
 144       shell_global_set_stage_input_mode (global, g_value_get_enum (value));
 145       break;
 146     case PROP_SESSION_MODE:
 147       g_clear_pointer (&global->session_mode, g_free);
 148       global->session_mode = g_ascii_strdown (g_value_get_string (value), -1);
 149       break;
 150     default:
 151       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 152       break;
 153     }
 154 }
 155 
 156 static void
 157 shell_global_get_property(GObject         *object,
 158                           guint            prop_id,
 159                           GValue          *value,
 160                           GParamSpec      *pspec)
 161 {
 162   ShellGlobal *global = SHELL_GLOBAL (object);
 163 
 164   switch (prop_id)
 165     {
 166     case PROP_SESSION_MODE:
 167       g_value_set_string (value, shell_global_get_session_mode (global));
 168       break;
 169     case PROP_OVERLAY_GROUP:
 170       g_value_set_object (value, meta_get_overlay_group_for_screen (global->meta_screen));
 171       break;
 172     case PROP_SCREEN:
 173       g_value_set_object (value, global->meta_screen);
 174       break;
 175     case PROP_GDK_SCREEN:
 176       g_value_set_object (value, global->gdk_screen);
 177       break;
 178     case PROP_DISPLAY:
 179       g_value_set_object (value, global->meta_display);
 180       break;
 181     case PROP_SCREEN_WIDTH:
 182       {
 183         int width, height;
 184 
 185         meta_screen_get_size (global->meta_screen, &width, &height);
 186         g_value_set_int (value, width);
 187       }
 188       break;
 189     case PROP_SCREEN_HEIGHT:
 190       {
 191         int width, height;
 192 
 193         meta_screen_get_size (global->meta_screen, &width, &height);
 194         g_value_set_int (value, height);
 195       }
 196       break;
 197     case PROP_STAGE:
 198       g_value_set_object (value, global->stage);
 199       break;
 200     case PROP_STAGE_INPUT_MODE:
 201       g_value_set_enum (value, global->input_mode);
 202       break;
 203     case PROP_WINDOW_GROUP:
 204       g_value_set_object (value, meta_get_window_group_for_screen (global->meta_screen));
 205       break;
 206     case PROP_BACKGROUND_ACTOR:
 207       g_value_set_object (value, meta_get_background_actor_for_screen (global->meta_screen));
 208       break;
 209     case PROP_WINDOW_MANAGER:
 210       g_value_set_object (value, global->wm);
 211       break;
 212     case PROP_SETTINGS:
 213       g_value_set_object (value, global->settings);
 214       break;
 215     case PROP_DATADIR:
 216       g_value_set_string (value, global->datadir);
 217       break;
 218     case PROP_IMAGEDIR:
 219       g_value_set_string (value, global->imagedir);
 220       break;
 221     case PROP_USERDATADIR:
 222       g_value_set_string (value, global->userdatadir);
 223       break;
 224     case PROP_FOCUS_MANAGER:
 225       g_value_set_object (value, global->focus_manager);
 226       break;
 227     default:
 228       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 229       break;
 230     }
 231 }
 232 
 233 static void
 234 shell_global_init (ShellGlobal *global)
 235 {
 236   const char *datadir = g_getenv ("GNOME_SHELL_DATADIR");
 237   const char *shell_js = g_getenv("GNOME_SHELL_JS");
 238   char *imagedir, **search_path;
 239 
 240   if (!datadir)
 241     datadir = GNOME_SHELL_DATADIR;
 242   global->datadir = datadir;
 243 
 244   /* We make sure imagedir ends with a '/', since the JS won't have
 245    * access to g_build_filename() and so will end up just
 246    * concatenating global.imagedir to a filename.
 247    */
 248   imagedir = g_build_filename (datadir, "images/", NULL);
 249   if (g_file_test (imagedir, G_FILE_TEST_IS_DIR))
 250     global->imagedir = imagedir;
 251   else
 252     {
 253       g_free (imagedir);
 254       global->imagedir = g_strdup_printf ("%s/", datadir);
 255     }
 256 
 257   /* Ensure config dir exists for later use */
 258   global->userdatadir = g_build_filename (g_get_user_data_dir (), "gnome-shell", NULL);
 259   g_mkdir_with_parents (global->userdatadir, 0700);
 260 
 261   global->settings = g_settings_new ("org.gnome.shell");
 262   
 263   global->grab_notifier = GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL));
 264   g_signal_connect (global->grab_notifier, "grab-notify", G_CALLBACK (grab_notify), global);
 265   global->gtk_grab_active = FALSE;
 266 
 267   global->input_mode = SHELL_STAGE_INPUT_MODE_NORMAL;
 268 
 269   ca_context_create (&global->sound_context);
 270   ca_context_change_props (global->sound_context, CA_PROP_APPLICATION_NAME, PACKAGE_NAME, CA_PROP_APPLICATION_ID, "org.gnome.Shell", NULL);
 271   ca_context_open (global->sound_context);
 272 
 273   if (!shell_js)
 274     shell_js = JSDIR;
 275   search_path = g_strsplit (shell_js, ":", -1);
 276   global->js_context = g_object_new (GJS_TYPE_CONTEXT,
 277                                      "search-path", search_path,
 278                                      "js-version", "1.8",
 279                                      "gc-notifications", TRUE,
 280                                      NULL);
 281   g_signal_connect (global->js_context, "gc", G_CALLBACK (shell_global_on_gc), global);
 282 
 283   g_strfreev (search_path);
 284 }
 285 
 286 static void
 287 shell_global_finalize (GObject *object)
 288 {
 289   ShellGlobal *global = SHELL_GLOBAL (object);
 290 
 291   g_object_unref (global->js_context);
 292   gtk_widget_destroy (GTK_WIDGET (global->grab_notifier));
 293   g_object_unref (global->settings);
 294 
 295   the_object = NULL;
 296 
 297   G_OBJECT_CLASS(shell_global_parent_class)->finalize (object);
 298 }
 299 
 300 static void
 301 shell_global_class_init (ShellGlobalClass *klass)
 302 {
 303   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 304 
 305   gobject_class->get_property = shell_global_get_property;
 306   gobject_class->set_property = shell_global_set_property;
 307   gobject_class->finalize = shell_global_finalize;
 308 
 309   /* Emitted from gnome-shell-plugin.c during event handling */
 310   shell_global_signals[XDND_POSITION_CHANGED] =
 311       g_signal_new ("xdnd-position-changed",
 312                     G_TYPE_FROM_CLASS (klass),
 313                     G_SIGNAL_RUN_LAST,
 314                     0,
 315                     NULL, NULL, NULL,
 316                     G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
 317 
 318   /* Emitted from gnome-shell-plugin.c during event handling */
 319   shell_global_signals[XDND_LEAVE] =
 320       g_signal_new ("xdnd-leave",
 321                     G_TYPE_FROM_CLASS (klass),
 322                     G_SIGNAL_RUN_LAST,
 323                     0,
 324                     NULL, NULL, NULL,
 325                     G_TYPE_NONE, 0);
 326 
 327   /* Emitted from gnome-shell-plugin.c during event handling */
 328   shell_global_signals[XDND_ENTER] =
 329       g_signal_new ("xdnd-enter",
 330                     G_TYPE_FROM_CLASS (klass),
 331                     G_SIGNAL_RUN_LAST,
 332                     0,
 333                     NULL, NULL, NULL,
 334                     G_TYPE_NONE, 0);
 335 
 336   shell_global_signals[NOTIFY_ERROR] =
 337       g_signal_new ("notify-error",
 338                     G_TYPE_FROM_CLASS (klass),
 339                     G_SIGNAL_RUN_LAST,
 340                     0,
 341                     NULL, NULL, NULL,
 342                     G_TYPE_NONE, 2,
 343                     G_TYPE_STRING,
 344                     G_TYPE_STRING);
 345 
 346   g_object_class_install_property (gobject_class,
 347                                    PROP_SESSION_MODE,
 348                                    g_param_spec_string ("session-mode",
 349                                                         "Session Mode",
 350                                                         "The session mode to use",
 351                                                         "user",
 352                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 353   g_object_class_install_property (gobject_class,
 354                                    PROP_OVERLAY_GROUP,
 355                                    g_param_spec_object ("overlay-group",
 356                                                         "Overlay Group",
 357                                                         "Actor holding objects that appear above the desktop contents",
 358                                                         CLUTTER_TYPE_ACTOR,
 359                                                         G_PARAM_READABLE));
 360   g_object_class_install_property (gobject_class,
 361                                    PROP_SCREEN,
 362                                    g_param_spec_object ("screen",
 363                                                         "Screen",
 364                                                         "Metacity screen object for the shell",
 365                                                         META_TYPE_SCREEN,
 366                                                         G_PARAM_READABLE));
 367 
 368   g_object_class_install_property (gobject_class,
 369                                    PROP_GDK_SCREEN,
 370                                    g_param_spec_object ("gdk-screen",
 371                                                         "GdkScreen",
 372                                                         "Gdk screen object for the shell",
 373                                                         GDK_TYPE_SCREEN,
 374                                                         G_PARAM_READABLE));
 375 
 376   g_object_class_install_property (gobject_class,
 377                                    PROP_SCREEN_WIDTH,
 378                                    g_param_spec_int ("screen-width",
 379                                                      "Screen Width",
 380                                                      "Screen width, in pixels",
 381                                                      0, G_MAXINT, 1,
 382                                                      G_PARAM_READABLE));
 383 
 384   g_object_class_install_property (gobject_class,
 385                                    PROP_SCREEN_HEIGHT,
 386                                    g_param_spec_int ("screen-height",
 387                                                      "Screen Height",
 388                                                      "Screen height, in pixels",
 389                                                      0, G_MAXINT, 1,
 390                                                      G_PARAM_READABLE));
 391   g_object_class_install_property (gobject_class,
 392                                    PROP_DISPLAY,
 393                                    g_param_spec_object ("display",
 394                                                         "Display",
 395                                                         "Metacity display object for the shell",
 396                                                         META_TYPE_DISPLAY,
 397                                                         G_PARAM_READABLE));
 398 
 399   g_object_class_install_property (gobject_class,
 400                                    PROP_STAGE,
 401                                    g_param_spec_object ("stage",
 402                                                         "Stage",
 403                                                         "Stage holding the desktop scene graph",
 404                                                         CLUTTER_TYPE_ACTOR,
 405                                                         G_PARAM_READABLE));
 406   g_object_class_install_property (gobject_class,
 407                                    PROP_STAGE_INPUT_MODE,
 408                                    g_param_spec_enum ("stage-input-mode",
 409                                                       "Stage input mode",
 410                                                       "The stage input mode",
 411                                                       SHELL_TYPE_STAGE_INPUT_MODE,
 412                                                       SHELL_STAGE_INPUT_MODE_NORMAL,
 413                                                       G_PARAM_READWRITE));
 414   g_object_class_install_property (gobject_class,
 415                                    PROP_WINDOW_GROUP,
 416                                    g_param_spec_object ("window-group",
 417                                                         "Window Group",
 418                                                         "Actor holding window actors",
 419                                                         CLUTTER_TYPE_ACTOR,
 420                                                         G_PARAM_READABLE));
 421   g_object_class_install_property (gobject_class,
 422                                    PROP_BACKGROUND_ACTOR,
 423                                    g_param_spec_object ("background-actor",
 424                                                         "Background Actor",
 425                                                         "Actor drawing root window background",
 426                                                         CLUTTER_TYPE_ACTOR,
 427                                                         G_PARAM_READABLE));
 428   g_object_class_install_property (gobject_class,
 429                                    PROP_WINDOW_MANAGER,
 430                                    g_param_spec_object ("window-manager",
 431                                                         "Window Manager",
 432                                                         "Window management interface",
 433                                                         SHELL_TYPE_WM,
 434                                                         G_PARAM_READABLE));
 435   g_object_class_install_property (gobject_class,
 436                                    PROP_SETTINGS,
 437                                    g_param_spec_object ("settings",
 438                                                         "Settings",
 439                                                         "GSettings instance for gnome-shell configuration",
 440                                                         G_TYPE_SETTINGS,
 441                                                         G_PARAM_READABLE));
 442   g_object_class_install_property (gobject_class,
 443                                    PROP_DATADIR,
 444                                    g_param_spec_string ("datadir",
 445                                                         "Data directory",
 446                                                         "Directory containing gnome-shell data files",
 447                                                         NULL,
 448                                                         G_PARAM_READABLE));
 449   g_object_class_install_property (gobject_class,
 450                                    PROP_IMAGEDIR,
 451                                    g_param_spec_string ("imagedir",
 452                                                         "Image directory",
 453                                                         "Directory containing gnome-shell image files",
 454                                                         NULL,
 455                                                         G_PARAM_READABLE));
 456   g_object_class_install_property (gobject_class,
 457                                    PROP_USERDATADIR,
 458                                    g_param_spec_string ("userdatadir",
 459                                                         "User data directory",
 460                                                         "Directory containing gnome-shell user data",
 461                                                         NULL,
 462                                                         G_PARAM_READABLE));
 463   g_object_class_install_property (gobject_class,
 464                                    PROP_FOCUS_MANAGER,
 465                                    g_param_spec_object ("focus-manager",
 466                                                         "Focus manager",
 467                                                         "The shell's StFocusManager",
 468                                                         ST_TYPE_FOCUS_MANAGER,
 469                                                         G_PARAM_READABLE));
 470 }
 471 
 472 /**•
 473  * _shell_global_init: (skip)•
 474  * @first_property_name: the name of the first property
 475  * @...: the value of the first property, followed optionally by more
 476  *  name/value pairs, followed by %NULL
 477  *•
 478  * Initializes the shell global singleton with the construction-time
 479  * properties.
 480  *
 481  * There are currently no such properties, so @first_property_name should
 482  * always be %NULL.
 483  *
 484  * This call must be called before shell_global_get() and shouldn't be called
 485  * more than once.
 486  */
 487 void
 488 _shell_global_init (const char *first_property_name,
 489                     ...)
 490 {
 491   va_list argument_list;
 492 
 493   g_return_if_fail (the_object == NULL);
 494 
 495   va_start (argument_list, first_property_name);
 496   the_object = SHELL_GLOBAL (g_object_new_valist (SHELL_TYPE_GLOBAL,
 497                                                   first_property_name,
 498                                                   argument_list));
 499   va_end (argument_list);
 500 
 501 }
 502 
 503 /**
 504  * shell_global_get:
 505  *
 506  * Gets the singleton global object that represents the desktop.
 507  *
 508  * Return value: (transfer none): the singleton global object
 509  */
 510 ShellGlobal *
 511 shell_global_get (void)
 512 {
 513   return the_object;
 514 }
 515 
 516 static void
 517 focus_window_changed (MetaDisplay *display,
 518                       GParamSpec  *param,
 519                       gpointer     user_data)
 520 {
 521   ShellGlobal *global = user_data;
 522 
 523   if (global->input_mode == SHELL_STAGE_INPUT_MODE_FOCUSED &&
 524       meta_display_get_focus_window (display) != NULL)
 525     shell_global_set_stage_input_mode (global, SHELL_STAGE_INPUT_MODE_NORMAL);
 526 }
 527 
 528 static void
 529 shell_global_focus_stage (ShellGlobal *global)
 530 {
 531   XSetInputFocus (global->xdisplay, global->stage_xwindow,
 532                   RevertToPointerRoot,
 533                   shell_global_get_current_time (global));
 534 }
 535 
 536 /**
 537  * shell_global_set_stage_input_mode:
 538  * @global: the #ShellGlobal
 539  * @mode: the stage input mode
 540  *
 541  * Sets the input mode of the stage; when @mode is
 542  * %SHELL_STAGE_INPUT_MODE_NONREACTIVE, then the stage does not absorb
 543  * any clicks, but just passes them through to underlying windows.
 544  * When it is %SHELL_STAGE_INPUT_MODE_NORMAL, then the stage accepts
 545  * clicks in the region defined by
 546  * shell_global_set_stage_input_region() but passes through clicks
 547  * outside that region. When it is %SHELL_STAGE_INPUT_MODE_FULLSCREEN,
 548  * the stage absorbs all input.
 549  *
 550  * When the input mode is %SHELL_STAGE_INPUT_MODE_FOCUSED, the pointer
 551  * is handled as with %SHELL_STAGE_INPUT_MODE_NORMAL, but additionally
 552  * the stage window has the keyboard focus. If the stage loses the
 553  * focus (eg, because the user clicked into a window) the input mode
 554  * will revert to %SHELL_STAGE_INPUT_MODE_NORMAL.
 555  *
 556  * Note that whenever a mutter-internal Gtk widget has a pointer grab,
 557  * the shell behaves as though it was in
 558  * %SHELL_STAGE_INPUT_MODE_NONREACTIVE, to ensure that the widget gets
 559  * any clicks it is expecting.
 560  */
 561 void
 562 shell_global_set_stage_input_mode (ShellGlobal         *global,
 563                                    ShellStageInputMode  mode)
 564 {
 565   MetaScreen *screen;
 566 
 567   g_return_if_fail (SHELL_IS_GLOBAL (global));
 568 
 569   screen = meta_plugin_get_screen (global->plugin);
 570 
 571   if (mode == SHELL_STAGE_INPUT_MODE_NONREACTIVE || global->gtk_grab_active)
 572     meta_empty_stage_input_region (screen);
 573   else if (mode == SHELL_STAGE_INPUT_MODE_FULLSCREEN || !global->input_region)
 574     meta_set_stage_input_region (screen, None);
 575   else
 576     meta_set_stage_input_region (screen, global->input_region);
 577 
 578   if (mode == SHELL_STAGE_INPUT_MODE_FOCUSED)
 579     shell_global_focus_stage (global);
 580 
 581   if (mode != global->input_mode)
 582     {
 583       global->input_mode = mode;
 584       g_object_notify (G_OBJECT (global), "stage-input-mode");
 585     }
 586 }
 587 
 588 /**
 589  * shell_global_set_cursor:
 590  * @global: A #ShellGlobal
 591  * @type: the type of the cursor
 592  *
 593  * Set the cursor on the stage window.
 594  */
 595 void
 596 shell_global_set_cursor (ShellGlobal *global,
 597                          ShellCursor type)
 598 {
 599   const char *name;
 600   GdkCursor *cursor;
 601 
 602   switch (type)
 603     {
 604     case SHELL_CURSOR_DND_IN_DRAG:
 605       name = "dnd-none";
 606       break;
 607     case SHELL_CURSOR_DND_MOVE:
 608       name = "dnd-move";
 609       break;
 610     case SHELL_CURSOR_DND_COPY:
 611       name = "dnd-copy";
 612       break;
 613     case SHELL_CURSOR_DND_UNSUPPORTED_TARGET:
 614       name = "dnd-none";
 615       break;
 616     case SHELL_CURSOR_POINTING_HAND:
 617       name = "hand";
 618       break;
 619     default:
 620       g_return_if_reached ();
 621     }
 622 
 623   cursor = gdk_cursor_new_from_name (global->gdk_display, name);
 624   if (!cursor)
 625     {
 626       GdkCursorType cursor_type;
 627       switch (type)
 628         {
 629         case SHELL_CURSOR_DND_IN_DRAG:
 630           cursor_type = GDK_FLEUR;
 631           break;
 632         case SHELL_CURSOR_DND_MOVE:
 633           cursor_type = GDK_TARGET;
 634           break;
 635         case SHELL_CURSOR_DND_COPY:
 636           cursor_type = GDK_PLUS;
 637           break;
 638         case SHELL_CURSOR_POINTING_HAND:
 639           cursor_type = GDK_HAND2;
 640           break;
 641         case SHELL_CURSOR_DND_UNSUPPORTED_TARGET:
 642           cursor_type = GDK_X_CURSOR;
 643           break;
 644         default:
 645           g_return_if_reached ();
 646         }
 647       cursor = gdk_cursor_new (cursor_type);
 648     }
 649 
 650   gdk_window_set_cursor (global->stage_gdk_window, cursor);
 651 
 652   g_object_unref (cursor);
 653 }
 654 
 655 /**
 656  * shell_global_unset_cursor:
 657  * @global: A #ShellGlobal
 658  *
 659  * Unset the cursor on the stage window.
 660  */
 661 void
 662 shell_global_unset_cursor (ShellGlobal  *global)
 663 {
 664   gdk_window_set_cursor (global->stage_gdk_window, NULL);
 665 }
 666 
 667 /**
 668  * shell_global_set_stage_input_region:
 669  * @global: the #ShellGlobal
 670  * @rectangles: (element-type Meta.Rectangle): a list of #MetaRectangle
 671  * describing the input region.
 672  *
 673  * Sets the area of the stage that is responsive to mouse clicks when
 674  * the stage mode is %SHELL_STAGE_INPUT_MODE_NORMAL (but does not change the
 675  * current stage mode).
 676  */
 677 void
 678 shell_global_set_stage_input_region (ShellGlobal *global,
 679                                      GSList      *rectangles)
 680 {
 681   MetaRectangle *rect;
 682   XRectangle *rects;
 683   int nrects, i;
 684   GSList *r;
 685 
 686   g_return_if_fail (SHELL_IS_GLOBAL (global));
 687 
 688   nrects = g_slist_length (rectangles);
 689   rects = g_new (XRectangle, nrects);
 690   for (r = rectangles, i = 0; r; r = r->next, i++)
 691     {
 692       rect = (MetaRectangle *)r->data;
 693       rects[i].x = rect->x;
 694       rects[i].y = rect->y;
 695       rects[i].width = rect->width;
 696       rects[i].height = rect->height;
 697     }
 698 
 699   if (global->input_region)
 700     XFixesDestroyRegion (global->xdisplay, global->input_region);
 701 
 702   global->input_region = XFixesCreateRegion (global->xdisplay, rects, nrects);
 703   g_free (rects);
 704 
 705   /* set_stage_input_mode() will figure out whether or not we
 706    * should actually change the input region right now.
 707    */
 708   shell_global_set_stage_input_mode (global, global->input_mode);
 709 }
 710 
 711 /**
 712  * shell_global_get_stage:
 713  *
 714  * Return value: (transfer none): The default #ClutterStage
 715  */
 716 ClutterStage *
 717 shell_global_get_stage (ShellGlobal  *global)
 718 {
 719   return global->stage;
 720 }
 721 
 722 /**
 723  * shell_global_get_screen:
 724  *
 725  * Return value: (transfer none): The default #MetaScreen
 726  */
 727 MetaScreen *
 728 shell_global_get_screen (ShellGlobal  *global)
 729 {
 730   return global->meta_screen;
 731 }
 732 
 733 /**
 734  * shell_global_get_gdk_screen:
 735  *
 736  * Return value: (transfer none): Gdk screen object for the shell
 737  */
 738 GdkScreen *
 739 shell_global_get_gdk_screen (ShellGlobal *global)
 740 {
 741   g_return_val_if_fail (SHELL_IS_GLOBAL (global), NULL);
 742 
 743   return global->gdk_screen;
 744 }
 745 
 746 /**
 747  * shell_global_get_display:
 748  *
 749  * Return value: (transfer none): The default #MetaDisplay
 750  */
 751 MetaDisplay *
 752 shell_global_get_display (ShellGlobal  *global)
 753 {
 754   return global->meta_display;
 755 }
 756 
 757 /**
 758  * shell_global_get_window_actors:
 759  *
 760  * Gets the list of #MetaWindowActor for the plugin's screen
 761  *
 762  * Return value: (element-type Meta.WindowActor) (transfer none): the list of windows
 763  */
 764 GList *
 765 shell_global_get_window_actors (ShellGlobal *global)
 766 {
 767   g_return_val_if_fail (SHELL_IS_GLOBAL (global), NULL);
 768 
 769   return meta_get_window_actors (global->meta_screen);
 770 }
 771 
 772 static void
 773 global_stage_notify_width (GObject    *gobject,
 774                            GParamSpec *pspec,
 775                            gpointer    data)
 776 {
 777   ShellGlobal *global = SHELL_GLOBAL (data);
 778 
 779   g_object_notify (G_OBJECT (global), "screen-width");
 780 }
 781 
 782 static void
 783 global_stage_notify_height (GObject    *gobject,
 784                             GParamSpec *pspec,
 785                             gpointer    data)
 786 {
 787   ShellGlobal *global = SHELL_GLOBAL (data);
 788 
 789   g_object_notify (G_OBJECT (global), "screen-height");
 790 }
 791 
 792 static void
 793 global_stage_before_paint (ClutterStage *stage,
 794                            ShellGlobal  *global)
 795 {
 796   shell_perf_log_event (shell_perf_log_get_default (),
 797                         "clutter.stagePaintStart");
 798 }
 799 
 800 static void
 801 global_stage_after_paint (ClutterStage *stage,
 802                           ShellGlobal  *global)
 803 {
 804   shell_perf_log_event (shell_perf_log_get_default (),
 805                         "clutter.stagePaintDone");
 806 }
 807 
 808 static void
 809 shell_fonts_init (ClutterStage *stage)
 810 {
 811   CoglPangoFontMap *fontmap;
 812 
 813   /* Disable text mipmapping; it causes problems on pre-GEM Intel
 814    * drivers and we should just be rendering text at the right
 815    * size rather than scaling it. If we do effects where we dynamically
 816    * zoom labels, then we might want to reconsider.
 817    */
 818   fontmap = COGL_PANGO_FONT_MAP (clutter_get_font_map ());
 819   cogl_pango_font_map_set_use_mipmapping (fontmap, FALSE);
 820 }
 821 
 822 /* This is an IBus workaround. The flow of events with IBus is that every time
 823  * it gets gets a key event, it:
 824  *
 825  *  Sends it to the daemon via D-Bus asynchronously
 826  *  When it gets an reply, synthesizes a new GdkEvent and puts it into the
 827  *   GDK event queue with gdk_event_put(), including
 828  *   IBUS_FORWARD_MASK = 1 << 25 in the state to prevent a loop.
 829  *
 830  * (Normally, IBus uses the GTK+ key snooper mechanism to get the key
 831  * events early, but since our key events aren't visible to GTK+ key snoopers,
 832  * IBus will instead get the events via the standard
 833  * GtkIMContext.filter_keypress() mechanism.)
 834  *
 835  * There are a number of potential problems here; probably the worst
 836  * problem is that IBus doesn't forward the timestamp with the event
 837  * so that every key event that gets delivered ends up with
 838  * GDK_CURRENT_TIME.  This creates some very subtle bugs; for example
 839  * if you have IBus running and a keystroke is used to trigger
 840  * launching an application, focus stealing prevention won't work
 841  * right. http://code.google.com/p/ibus/issues/detail?id=1184
 842  *
 843  * In any case, our normal flow of key events is:
 844  *
 845  *  GDK filter function => clutter_x11_handle_event => clutter actor
 846  *
 847  * So, if we see a key event that gets delivered via the GDK event handler
 848  * function - then we know it must be one of these synthesized events, and
 849  * we should push it back to clutter.
 850  *
 851  * To summarize, the full key event flow with IBus is:
 852  *
 853  *   GDK filter function
 854  *     => Mutter
 855  *     => gnome_shell_plugin_xevent_filter()
 856  *     => clutter_x11_handle_event()
 857  *     => clutter event delivery to actor
 858  *     => gtk_im_context_filter_event()
 859  *     => sent to IBus daemon
 860  *     => response received from IBus daemon
 861  *     => gdk_event_put()
 862  *     => GDK event handler
 863  *     => <this function>
 864  *     => clutter_event_put()
 865  *     => clutter event delivery to actor
 866  *
 867  * Anything else we see here we just pass on to the normal GDK event handler
 868  * gtk_main_do_event().
 869  */
 870 static void
 871 gnome_shell_gdk_event_handler (GdkEvent *event_gdk,
 872                                gpointer  data)
 873 {
 874   if (event_gdk->type == GDK_KEY_PRESS || event_gdk->type == GDK_KEY_RELEASE)
 875     {
 876       ClutterActor *stage;
 877       Window stage_xwindow;
 878 
 879       stage = CLUTTER_ACTOR (data);
 880       stage_xwindow = clutter_x11_get_stage_window (CLUTTER_STAGE (stage));
 881 
 882       if (GDK_WINDOW_XID (event_gdk->key.window) == stage_xwindow)
 883         {
 884           ClutterDeviceManager *device_manager = clutter_device_manager_get_default ();
 885           ClutterInputDevice *keyboard = clutter_device_manager_get_core_device (device_manager,
 886                                                                                  CLUTTER_KEYBOARD_DEVICE);
 887 
 888           ClutterEvent *event_clutter = clutter_event_new ((event_gdk->type == GDK_KEY_PRESS) ?
 889                                                            CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE);
 890           event_clutter->key.time = event_gdk->key.time;
 891           event_clutter->key.flags = CLUTTER_EVENT_NONE;
 892           event_clutter->key.stage = CLUTTER_STAGE (stage);
 893           event_clutter->key.source = NULL;
 894 
 895           /* This depends on ClutterModifierType and GdkModifierType being
 896            * identical, which they are currently. (They both match the X
 897            * modifier state in the low 16-bits and have the same extensions.) */
 898           event_clutter->key.modifier_state = event_gdk->key.state;
 899 
 900           event_clutter->key.keyval = event_gdk->key.keyval;
 901           event_clutter->key.hardware_keycode = event_gdk->key.hardware_keycode;
 902           event_clutter->key.unicode_value = gdk_keyval_to_unicode (event_clutter->key.keyval);
 903           event_clutter->key.device = keyboard;
 904 
 905           clutter_event_put (event_clutter);
 906           clutter_event_free (event_clutter);
 907 
 908           return;
 909         }
 910     }
 911 
 912   gtk_main_do_event (event_gdk);
 913 }
 914 
 915 void
 916 _shell_global_set_plugin (ShellGlobal *global,
 917                           MetaPlugin  *plugin)
 918 {
 919   g_return_if_fail (SHELL_IS_GLOBAL (global));
 920   g_return_if_fail (global->plugin == NULL);
 921 
 922   global->plugin = plugin;
 923   global->wm = shell_wm_new (plugin);
 924 
 925   global->meta_screen = meta_plugin_get_screen (plugin);
 926   global->meta_display = meta_screen_get_display (global->meta_screen);
 927   global->xdisplay = meta_display_get_xdisplay (global->meta_display);
 928 
 929   global->gdk_display = gdk_x11_lookup_xdisplay (global->xdisplay);
 930   global->gdk_screen = gdk_display_get_screen (global->gdk_display,
 931                                                meta_screen_get_screen_number (global->meta_screen));
 932 
 933   global->stage = CLUTTER_STAGE (meta_get_stage_for_screen (global->meta_screen));
 934   global->stage_xwindow = clutter_x11_get_stage_window (global->stage);
 935   global->stage_gdk_window = gdk_x11_window_foreign_new_for_display (global->gdk_display,
 936                                                                      global->stage_xwindow);
 937 
 938   g_signal_connect (global->stage, "notify::width",
 939                     G_CALLBACK (global_stage_notify_width), global);
 940   g_signal_connect (global->stage, "notify::height",
 941                     G_CALLBACK (global_stage_notify_height), global);
 942 
 943   g_signal_connect (global->stage, "paint",
 944                     G_CALLBACK (global_stage_before_paint), global);
 945   g_signal_connect_after (global->stage, "paint",
 946                           G_CALLBACK (global_stage_after_paint), global);
 947 
 948   shell_perf_log_define_event (shell_perf_log_get_default(),
 949                                "clutter.stagePaintStart",
 950                                "Start of stage page repaint",
 951                                "");
 952   shell_perf_log_define_event (shell_perf_log_get_default(),
 953                                "clutter.stagePaintDone",
 954                                "End of stage page repaint",
 955                                "");
 956 
 957   g_signal_connect (global->meta_display, "notify::focus-window",
 958                     G_CALLBACK (focus_window_changed), global);
 959 
 960   shell_fonts_init (global->stage);
 961 
 962   gdk_event_handler_set (gnome_shell_gdk_event_handler, global->stage, NULL);
 963 
 964   global->focus_manager = st_focus_manager_get_for_stage (global->stage);
 965 }
 966 
 967 GjsContext *
 968 _shell_global_get_gjs_context (ShellGlobal *global)
 969 {
 970   return global->js_context;
 971 }
 972 
 973 /**
 974  * shell_global_begin_modal:
 975  * @global: a #ShellGlobal
 976  *
 977  * Grabs the keyboard and mouse to the stage window. The stage will
 978  * receive all keyboard and mouse events until shell_global_end_modal()
 979  * is called. This is used to implement "modes" for the shell, such as the
 980  * overview mode or the "looking glass" debug overlay, that block
 981  * application and normal key shortcuts.
 982  *
 983  * Returns: %TRUE if we succesfully entered the mode. %FALSE if we couldn't
 984  *  enter the mode. Failure may occur because an application has the pointer
 985  *  or keyboard grabbed, because Mutter is in a mode itself like moving a
 986  *  window or alt-Tab window selection, or because shell_global_begin_modal()
 987  *  was previouly called.
 988  */
 989 gboolean
 990 shell_global_begin_modal (ShellGlobal       *global,
 991                           guint32           timestamp,
 992                           MetaModalOptions  options)
 993 {
 994   return meta_plugin_begin_modal (global->plugin, global->stage_xwindow, None, options, timestamp);
 995 }
 996 
 997 /**
 998  * shell_global_end_modal:
 999  * @global: a #ShellGlobal
1000  *
1001  * Undoes the effect of shell_global_begin_modal().
1002  */
1003 void
1004 shell_global_end_modal (ShellGlobal *global,
1005                         guint32      timestamp)
1006 {
1007   meta_plugin_end_modal (global->plugin, timestamp);
1008 }
1009 
1010 /**
1011  * shell_global_create_pointer_barrier:
1012  * @global: a #ShellGlobal
1013  * @x1: left X coordinate
1014  * @y1: top Y coordinate
1015  * @x2: right X coordinate
1016  * @y2: bottom Y coordinate
1017  * @directions: The directions we're allowed to pass through
1018  *
1019  * If supported by X creates a pointer barrier.
1020  *
1021  * Return value: value you can pass to shell_global_destroy_pointer_barrier()
1022  */
1023 guint32
1024 shell_global_create_pointer_barrier (ShellGlobal *global,
1025                                      int x1, int y1, int x2, int y2,
1026                                      int directions)
1027 {
1028 #if HAVE_XFIXESCREATEPOINTERBARRIER
1029   return (guint32)
1030     XFixesCreatePointerBarrier (global->xdisplay,
1031                                 DefaultRootWindow (global->xdisplay),
1032                                 x1, y1,
1033                                 x2, y2,
1034                                 directions,
1035                                 0, NULL);
1036 #else
1037   return 0;
1038 #endif
1039 }
1040 
1041 /**
1042  * shell_global_destroy_pointer_barrier:
1043  * @global: a #ShellGlobal
1044  * @barrier: a pointer barrier
1045  *
1046  * Destroys the @barrier created by shell_global_create_pointer_barrier().
1047  */
1048 void
1049 shell_global_destroy_pointer_barrier (ShellGlobal *global, guint32 barrier)
1050 {
1051 #if HAVE_XFIXESCREATEPOINTERBARRIER
1052   g_return_if_fail (barrier > 0);
1053 
1054   XFixesDestroyPointerBarrier (global->xdisplay, (PointerBarrier)barrier);
1055 #endif
1056 }
1057 
1058 /* Code to close all file descriptors before we exec; copied from gspawn.c in GLib.
1059  *
1060  * Authors: Padraig O'Briain, Matthias Clasen, Lennart Poettering
1061  *
1062  * http://bugzilla.gnome.org/show_bug.cgi?id=469231
1063  * http://bugzilla.gnome.org/show_bug.cgi?id=357585
1064  */
1065 
1066 static int
1067 set_cloexec (void *data, gint fd)
1068 {
1069   if (fd >= GPOINTER_TO_INT (data))
1070     fcntl (fd, F_SETFD, FD_CLOEXEC);
1071 
1072   return 0;
1073 }
1074 
1075 #ifndef HAVE_FDWALK
1076 static int
1077 fdwalk (int (*cb)(void *data, int fd), void *data)
1078 {
1079   gint open_max;
1080   gint fd;
1081   gint res = 0;
1082 
1083 #ifdef HAVE_SYS_RESOURCE_H
1084   struct rlimit rl;
1085 #endif
1086 
1087 #ifdef __linux__
1088   DIR *d;
1089 
1090   if ((d = opendir("/proc/self/fd"))) {
1091       struct dirent *de;
1092 
1093       while ((de = readdir(d))) {
1094           glong l;
1095           gchar *e = NULL;
1096 
1097           if (de->d_name[0] == '.')
1098               continue;
1099 
1100           errno = 0;
1101           l = strtol(de->d_name, &e, 10);
1102           if (errno != 0 || !e || *e)
1103               continue;
1104 
1105           fd = (gint) l;
1106 
1107           if ((glong) fd != l)
1108               continue;
1109 
1110           if (fd == dirfd(d))
1111               continue;
1112 
1113           if ((res = cb (data, fd)) != 0)
1114               break;
1115         }
1116 
1117       closedir(d);
1118       return res;
1119   }
1120 
1121   /* If /proc is not mounted or not accessible we fall back to the old
1122    * rlimit trick */
1123 
1124 #endif
1125 
1126 #ifdef HAVE_SYS_RESOURCE_H
1127   if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY)
1128       open_max = rl.rlim_max;
1129   else
1130 #endif
1131       open_max = sysconf (_SC_OPEN_MAX);
1132 
1133   for (fd = 0; fd < open_max; fd++)
1134       if ((res = cb (data, fd)) != 0)
1135           break;
1136 
1137   return res;
1138 }
1139 #endif
1140 
1141 static void
1142 pre_exec_close_fds(void)
1143 {
1144   fdwalk (set_cloexec, GINT_TO_POINTER(3));
1145 }
1146 
1147 /**
1148  * shell_global_reexec_self:
1149  * @global: A #ShellGlobal
1150  * 
1151  * Restart the current process.  Only intended for development purposes. 
1152  */
1153 void 
1154 shell_global_reexec_self (ShellGlobal *global)
1155 {
1156   GPtrArray *arr;
1157   gsize len;
1158   char *buf;
1159   char *buf_p;
1160   char *buf_end;
1161   GError *error = NULL;
1162   
1163   /* Linux specific (I think, anyways). */
1164   if (!g_file_get_contents ("/proc/self/cmdline", &buf, &len, &error))
1165     {
1166       g_warning ("failed to get /proc/self/cmdline: %s", error->message);
1167       return;
1168     }
1169       
1170   buf_end = buf+len;
1171   arr = g_ptr_array_new ();
1172   /* The cmdline file is NUL-separated */
1173   for (buf_p = buf; buf_p < buf_end; buf_p = buf_p + strlen (buf_p) + 1)
1174     g_ptr_array_add (arr, buf_p);
1175   
1176   g_ptr_array_add (arr, NULL);
1177 
1178   /* Close all file descriptors other than stdin/stdout/stderr, otherwise
1179    * they will leak and stay open after the exec. In particular, this is
1180    * important for file descriptors that represent mapped graphics buffer
1181    * objects.
1182    */
1183   pre_exec_close_fds ();
1184 
1185   meta_display_unmanage_screen (shell_global_get_display (global),
1186                                 shell_global_get_screen (global),
1187                                 shell_global_get_current_time (global));
1188 
1189   execvp (arr->pdata[0], (char**)arr->pdata);
1190   g_warning ("failed to reexec: %s", g_strerror (errno));
1191   g_ptr_array_free (arr, TRUE);
1192 }
1193 
1194 static void
1195 shell_global_on_gc (GjsContext   *context,
1196                     ShellGlobal  *global)
1197 {
1198   global->last_gc_end_time = g_get_monotonic_time ();
1199 }
1200 
1201 /**
1202  * shell_global_get_memory_info:
1203  * @global:
1204  * @meminfo: (out caller-allocates): Output location for memory information
1205  *
1206  * Load process-global data about memory usage.
1207  */
1208 void
1209 shell_global_get_memory_info (ShellGlobal        *global,
1210                               ShellMemoryInfo    *meminfo)
1211 {
1212   JSContext *context;
1213   gint64 now;
1214 
1215 #ifdef HAVE_MALLINFO
1216   {
1217     struct mallinfo info = mallinfo ();
1218     meminfo->glibc_uordblks = info.uordblks;
1219   }
1220 #else
1221   meminfo->glibc_uordblks = 0;
1222 #endif
1223 
1224   context = gjs_context_get_native_context (global->js_context);
1225 
1226   meminfo->js_bytes = JS_GetGCParameter (JS_GetRuntime (context), JSGC_BYTES);
1227 
1228   meminfo->gjs_boxed = (unsigned int) gjs_counter_boxed.value;
1229   meminfo->gjs_gobject = (unsigned int) gjs_counter_object.value;
1230   meminfo->gjs_function = (unsigned int) gjs_counter_function.value;
1231   meminfo->gjs_closure = (unsigned int) gjs_counter_closure.value;
1232 
1233   now = g_get_monotonic_time ();
1234 
1235   meminfo->last_gc_seconds_ago = (now - global->last_gc_end_time) / G_TIME_SPAN_SECOND;
1236 }
1237 
1238 
1239 /**
1240  * shell_global_notify_error:
1241  * @global: a #ShellGlobal
1242  * @msg: Error message
1243  * @details: Error details
1244  *
1245  * Show a system error notification.  Use this function
1246  * when a user-initiated action results in a non-fatal problem
1247  * from causes that may not be under system control.  For
1248  * example, an application crash.
1249  */
1250 void
1251 shell_global_notify_error (ShellGlobal  *global,
1252                            const char   *msg,
1253                            const char   *details)
1254 {
1255   g_signal_emit_by_name (global, "notify-error", msg, details);
1256 }
1257 
1258 static void
1259 grab_notify (GtkWidget *widget, gboolean was_grabbed, gpointer user_data)
1260 {
1261   ShellGlobal *global = SHELL_GLOBAL (user_data);
1262   
1263   global->gtk_grab_active = !was_grabbed;
1264 
1265   /* Update for the new setting of gtk_grab_active */
1266   shell_global_set_stage_input_mode (global, global->input_mode);
1267 }
1268 
1269 /**
1270  * shell_global_init_xdnd:
1271  * @global: the #ShellGlobal
1272  *
1273  * Enables tracking of Xdnd events
1274  */
1275 void shell_global_init_xdnd (ShellGlobal *global)
1276 {
1277   Window output_window = meta_get_overlay_window (global->meta_screen);
1278   long xdnd_version = 5;
1279 
1280   XChangeProperty (global->xdisplay, global->stage_xwindow,
1281                    gdk_x11_get_xatom_by_name ("XdndAware"), XA_ATOM,
1282                    32, PropModeReplace, (const unsigned char *)&xdnd_version, 1);
1283 
1284   XChangeProperty (global->xdisplay, output_window,
1285                    gdk_x11_get_xatom_by_name ("XdndProxy"), XA_WINDOW,
1286                    32, PropModeReplace, (const unsigned char *)&global->stage_xwindow, 1);
1287 
1288   /*
1289    * XdndProxy is additionally set on the proxy window as verification that the
1290    * XdndProxy property on the target window isn't a left-over
1291    */
1292   XChangeProperty (global->xdisplay, global->stage_xwindow,
1293                    gdk_x11_get_xatom_by_name ("XdndProxy"), XA_WINDOW,
1294                    32, PropModeReplace, (const unsigned char *)&global->stage_xwindow, 1);
1295 }
1296 
1297 /**
1298  * shell_global_get_pointer:
1299  * @global: the #ShellGlobal
1300  * @x: (out): the X coordinate of the pointer, in global coordinates
1301  * @y: (out): the Y coordinate of the pointer, in global coordinates
1302  * @mods: (out): the current set of modifier keys that are pressed down
1303  *
1304  * Gets the pointer coordinates and current modifier key state.
1305  * This is a wrapper around gdk_display_get_pointer() that strips
1306  * out any un-declared modifier flags, to make gjs happy; see
1307  * https://bugzilla.gnome.org/show_bug.cgi?id=597292.
1308  */
1309 void
1310 shell_global_get_pointer (ShellGlobal         *global,
1311                           int                 *x,
1312                           int                 *y,
1313                           ClutterModifierType *mods)
1314 {
1315   GdkDeviceManager *gmanager;
1316   GdkDevice *gdevice;
1317   GdkScreen *gscreen;
1318   GdkModifierType raw_mods;
1319 
1320   gmanager = gdk_display_get_device_manager (global->gdk_display);
1321   gdevice = gdk_device_manager_get_client_pointer (gmanager);
1322   gdk_device_get_position (gdevice, &gscreen, x, y);
1323   gdk_device_get_state (gdevice,
1324                         gdk_screen_get_root_window (gscreen),
1325                         NULL, &raw_mods);
1326   *mods = raw_mods & GDK_MODIFIER_MASK;
1327 }
1328 
1329 /**
1330  * shell_global_sync_pointer:
1331  * @global: the #ShellGlobal
1332  *
1333  * Ensures that clutter is aware of the current pointer position,
1334  * causing enter and leave events to be emitted if the pointer moved
1335  * behind our back (ie, during a pointer grab).
1336  */
1337 void
1338 shell_global_sync_pointer (ShellGlobal *global)
1339 {
1340   int x, y;
1341   GdkModifierType mods;
1342   GdkDeviceManager *gmanager;
1343   GdkDevice *gdevice;
1344   GdkScreen *gscreen;
1345   ClutterMotionEvent event;
1346 
1347   gmanager = gdk_display_get_device_manager (global->gdk_display);
1348   gdevice = gdk_device_manager_get_client_pointer (gmanager);
1349 
1350   gdk_device_get_position (gdevice, &gscreen, &x, &y);
1351   gdk_device_get_state (gdevice,
1352                         gdk_screen_get_root_window (gscreen),
1353                         NULL, &mods);
1354 
1355   event.type = CLUTTER_MOTION;
1356   event.time = shell_global_get_current_time (global);
1357   event.flags = 0;
1358   /* This is wrong: we should be setting event.stage to NULL if the
1359    * pointer is not inside the bounds of the stage given the current
1360    * stage_input_mode. For our current purposes however, this works.
1361    */
1362   event.stage = global->stage;
1363   event.x = x;
1364   event.y = y;
1365   event.modifier_state = mods;
1366   event.axes = NULL;
1367   event.device = clutter_device_manager_get_core_device (clutter_device_manager_get_default (),
1368                                                          CLUTTER_POINTER_DEVICE);
1369 
1370   /* Leaving event.source NULL will force clutter to look it up, which
1371    * will generate enter/leave events as a side effect, if they are
1372    * needed. We need a better way to do this though... see
1373    * http://bugzilla.clutter-project.org/show_bug.cgi?id=2615.
1374    */
1375   event.source = NULL;
1376 
1377   clutter_event_put ((ClutterEvent *)&event);
1378 }
1379 
1380 /**
1381  * shell_global_get_settings:
1382  * @global: A #ShellGlobal
1383  *
1384  * Get the global GSettings instance.
1385  *
1386  * Return value: (transfer none): The GSettings object
1387  */
1388 GSettings *
1389 shell_global_get_settings (ShellGlobal *global)
1390 {
1391   return global->settings;
1392 }
1393 
1394 /**
1395  * shell_global_get_current_time:
1396  * @global: A #ShellGlobal
1397  *
1398  * Returns: the current X server time from the current Clutter, Gdk, or X
1399  * event. If called from outside an event handler, this may return
1400  * %Clutter.CURRENT_TIME (aka 0), or it may return a slightly
1401  * out-of-date timestamp.
1402  */
1403 guint32
1404 shell_global_get_current_time (ShellGlobal *global)
1405 {
1406   guint32 time;
1407   const ClutterEvent *clutter_event;
1408 
1409   /* In case we have a xdnd timestamp use it */
1410   if (global->xdnd_timestamp != 0)
1411     return global->xdnd_timestamp;
1412 
1413   /* meta_display_get_current_time() will return the correct time
1414      when handling an X or Gdk event, but will return CurrentTime
1415      from some Clutter event callbacks.
1416 
1417      clutter_get_current_event_time() will return the correct time
1418      from a Clutter event callback, but may return an out-of-date
1419      timestamp if called at other times.
1420 
1421      So we try meta_display_get_current_time() first, since we
1422      can recognize a "wrong" answer from that, and then fall back
1423      to clutter_get_current_event_time().
1424    */
1425 
1426   time = meta_display_get_current_time (global->meta_display);
1427   if (time != CLUTTER_CURRENT_TIME)
1428       return time;
1429   /*
1430    * We don't use clutter_get_current_event_time as it can give us a
1431    * too old timestamp if there is no current event.
1432    */
1433   clutter_event = clutter_get_current_event ();
1434 
1435   if (clutter_event != NULL)
1436     return clutter_event_get_time (clutter_event);
1437   else
1438     return CLUTTER_CURRENT_TIME;
1439 }
1440 
1441 /**
1442  * shell_global_create_app_launch_context:
1443  * @global: A #ShellGlobal
1444  *
1445  * Create a #GAppLaunchContext set up with the correct timestamp, and
1446  * targeted to activate on the current workspace.
1447  *
1448  * Return value: (transfer full): A new #GAppLaunchContext
1449  */
1450 GAppLaunchContext *
1451 shell_global_create_app_launch_context (ShellGlobal *global)
1452 {
1453   GdkAppLaunchContext *context;
1454 
1455   context = gdk_display_get_app_launch_context (global->gdk_display);
1456   gdk_app_launch_context_set_timestamp (context, shell_global_get_current_time (global));
1457 
1458   // Make sure that the app is opened on the current workspace even if
1459   // the user switches before it starts
1460   gdk_app_launch_context_set_desktop (context, meta_screen_get_active_workspace_index (global->meta_screen));
1461 
1462   return (GAppLaunchContext *)context;
1463 }
1464 
1465 typedef struct
1466 {
1467   ShellLeisureFunction func;
1468   gpointer user_data;
1469   GDestroyNotify notify;
1470 } LeisureClosure;
1471 
1472 static gboolean
1473 run_leisure_functions (gpointer data)
1474 {
1475   ShellGlobal *global = data;
1476   GSList *closures;
1477   GSList *iter;
1478 
1479   global->leisure_function_id = 0;
1480 
1481   /* We started more work since we scheduled the idle */
1482   if (global->work_count > 0)
1483     return FALSE;
1484 
1485   /* No leisure closures, so we are done */
1486   if (global->leisure_closures == NULL)
1487     return FALSE;
1488 
1489   closures = global->leisure_closures;
1490   global->leisure_closures = NULL;
1491 
1492   for (iter = closures; iter; iter = iter->next)
1493     {
1494       LeisureClosure *closure = closures->data;
1495       closure->func (closure->user_data);
1496 
1497       if (closure->notify)
1498         closure->notify (closure->user_data);
1499 
1500       g_slice_free (LeisureClosure, closure);
1501     }
1502 
1503   g_slist_free (closures);
1504 
1505   return FALSE;
1506 }
1507 
1508 static void
1509 schedule_leisure_functions (ShellGlobal *global)
1510 {
1511   /* This is called when we think we are ready to run leisure functions
1512    * by our own accounting. We try to handle other types of business
1513    * (like ClutterAnimation) by adding a low priority idle function.
1514    *
1515    * This won't work properly if the mainloop goes idle waiting for
1516    * the vertical blanking interval or waiting for work being done
1517    * in another thread.
1518    */
1519   if (!global->leisure_function_id)
1520     global->leisure_function_id = g_idle_add_full (G_PRIORITY_LOW,
1521                                                    run_leisure_functions,
1522                                                    global, NULL);
1523 }
1524 
1525 /**
1526  * shell_global_begin_work:
1527  * @global: the #ShellGlobal
1528  *
1529  * Marks that we are currently doing work. This is used to to track
1530  * whether we are busy for the purposes of shell_global_run_at_leisure().
1531  * A count is kept and shell_global_end_work() must be called exactly
1532  * as many times as shell_global_begin_work().
1533  */
1534 void
1535 shell_global_begin_work (ShellGlobal *global)
1536 {
1537   global->work_count++;
1538 }
1539 
1540 /**
1541  * shell_global_end_work:
1542  * @global: the #ShellGlobal
1543  *
1544  * Marks the end of work that we started with shell_global_begin_work().
1545  * If no other work is ongoing and functions have been added with
1546  * shell_global_run_at_leisure(), they will be run at the next
1547  * opportunity.
1548  */
1549 void
1550 shell_global_end_work (ShellGlobal *global)
1551 {
1552   g_return_if_fail (global->work_count > 0);
1553 
1554   global->work_count--;
1555   if (global->work_count == 0)
1556     schedule_leisure_functions (global);
1557 
1558 }
1559 
1560 /**
1561  * shell_global_run_at_leisure:
1562  * @global: the #ShellGlobal
1563  * @func: function to call at leisure
1564  * @user_data: data to pass to @func
1565  * @notify: function to call to free @user_data
1566  *
1567  * Schedules a function to be called the next time the shell is idle.
1568  * Idle means here no animations, no redrawing, and no ongoing background
1569  * work. Since there is currently no way to hook into the Clutter master
1570  * clock and know when is running, the implementation here is somewhat
1571  * approximation. Animations done through the shell's Tweener module will
1572  * be handled properly, but other animations may be detected as terminating
1573  * early if they can be drawn fast enough so that the event loop goes idle
1574  * between frames.
1575  *
1576  * The intent of this function is for performance measurement runs
1577  * where a number of actions should be run serially and each action is
1578  * timed individually. Using this function for other purposes will
1579  * interfere with the ability to use it for performance measurement so
1580  * should be avoided.
1581  */
1582 void
1583 shell_global_run_at_leisure (ShellGlobal         *global,
1584                              ShellLeisureFunction func,
1585                              gpointer             user_data,
1586                              GDestroyNotify       notify)
1587 {
1588   LeisureClosure *closure = g_slice_new (LeisureClosure);
1589   closure->func = func;
1590   closure->user_data = user_data;
1591   closure->notify = notify;
1592 
1593   global->leisure_closures = g_slist_append (global->leisure_closures,
1594                                              closure);
1595 
1596   if (global->work_count == 0)
1597     schedule_leisure_functions (global);
1598 }
1599 
1600 /**
1601  * shell_global_play_theme_sound:
1602  * @global: the #ShellGlobal
1603  * @id: an id, used to cancel later (0 if not needed)
1604  * @name: the sound name
1605  *
1606  * Plays a simple sound picked according to Freedesktop sound theme.
1607  * Really just a workaround for libcanberra not being introspected.
1608  */
1609 void
1610 shell_global_play_theme_sound (ShellGlobal *global,
1611                                guint        id,
1612                                const char  *name)
1613 {
1614   ca_context_play (global->sound_context, id, CA_PROP_EVENT_ID, name, NULL);
1615 }
1616 
1617 /**
1618  * shell_global_cancel_theme_sound:
1619  * @global: the #ShellGlobal
1620  * @id: the id previously passed to shell_global_play_theme_sound()
1621  *
1622  * Cancels a sound notification.
1623  */
1624 void
1625 shell_global_cancel_theme_sound (ShellGlobal *global,
1626                                  guint id)
1627 {
1628   ca_context_cancel (global->sound_context, id);
1629 }
1630 
1631 /*
1632  * Process Xdnd events
1633  *
1634  * We pass the position and leave events to JS via a signal
1635  * where the actual drag & drop handling happens.
1636  *
1637  * http://www.freedesktop.org/wiki/Specifications/XDND
1638  */
1639 gboolean _shell_global_check_xdnd_event (ShellGlobal  *global,
1640                                          XEvent       *xev)
1641 {
1642   Window output_window = meta_get_overlay_window (global->meta_screen);
1643 
1644   if (xev->xany.window != output_window && xev->xany.window != global->stage_xwindow)
1645     return FALSE;
1646 
1647   if (xev->xany.type == ClientMessage && xev->xclient.message_type == gdk_x11_get_xatom_by_name ("XdndPosition"))
1648     {
1649       XEvent xevent;
1650       Window src = xev->xclient.data.l[0];
1651 
1652       memset (&xevent, 0, sizeof(xevent));
1653       xevent.xany.type = ClientMessage;
1654       xevent.xany.display = global->xdisplay;
1655       xevent.xclient.window = src;
1656       xevent.xclient.message_type = gdk_x11_get_xatom_by_name ("XdndStatus");
1657       xevent.xclient.format = 32;
1658       xevent.xclient.data.l[0] = output_window;
1659       /* flags: bit 0: will we accept the drop? bit 1: do we want more position messages */
1660       xevent.xclient.data.l[1] = 2;
1661       xevent.xclient.data.l[4] = None;
1662 
1663       XSendEvent (global->xdisplay, src, False, 0, &xevent);
1664 
1665       /* Store the timestamp of the xdnd position event */
1666       global->xdnd_timestamp = xev->xclient.data.l[3];
1667       g_signal_emit_by_name (G_OBJECT (global), "xdnd-position-changed",
1668                             (int)(xev->xclient.data.l[2] >> 16), (int)(xev->xclient.data.l[2] & 0xFFFF));
1669       global->xdnd_timestamp = 0;
1670 
1671       return TRUE;
1672     }
1673    else if (xev->xany.type == ClientMessage && xev->xclient.message_type == gdk_x11_get_xatom_by_name ("XdndLeave"))
1674     {
1675       g_signal_emit_by_name (G_OBJECT (global), "xdnd-leave");
1676 
1677       return TRUE;
1678     }
1679    else if (xev->xany.type == ClientMessage && xev->xclient.message_type == gdk_x11_get_xatom_by_name ("XdndEnter"))
1680     {
1681       g_signal_emit_by_name (G_OBJECT (global), "xdnd-enter");
1682 
1683       return TRUE;
1684     }
1685 
1686     return FALSE;
1687 }
1688 
1689 const char *
1690 shell_global_get_session_mode (ShellGlobal *global)
1691 {
1692   g_return_val_if_fail (SHELL_IS_GLOBAL (global), "user");
1693 
1694   return global->session_mode;
1695 }
1696 
1697 /**
1698  * shell_global_create_xrootpmap_texture:
1699  * @global: The #ShellGlobal
1700  *
1701  * This returns the _XROOTPMAP_ID pixmap that gdm should have stuffed
1702  * in the root window. The goal here is to allow a smooth fade between
1703  * plymouth and the shell greeter. This is also a workaround for gjs not
1704  * supporting raw xlib types.
1705  *
1706  * Returns: (transfer floating): A #ClutterActor that represents the
1707  * _XROOTPMAP_ID pixmap property from the root window.
1708  */
1709 ClutterActor *
1710 shell_global_create_xrootpmap_texture (ShellGlobal *global)
1711 {
1712   Atom res_type;
1713   int res_format;
1714   unsigned long res_nitems, bytesafter;
1715   unsigned char *data;
1716   Pixmap root_pixmap_id = None;
1717 
1718   g_return_val_if_fail (SHELL_IS_GLOBAL (global), NULL);
1719 
1720   if (XGetWindowProperty (global->xdisplay,
1721                           DefaultRootWindow (global->xdisplay),
1722                           XInternAtom (global->xdisplay, "_XROOTPMAP_ID", False),
1723                           0, G_MAXLONG, False, XA_PIXMAP,
1724                           &res_type, &res_format, &res_nitems, &bytesafter, &data) == Success)
1725     {
1726       if (res_type == XA_PIXMAP && res_format == 32 && res_nitems == 1)
1727         root_pixmap_id = * (Pixmap *) data;
1728       XFree (data);
1729     }
1730 
1731   if (root_pixmap_id != None)
1732     return clutter_x11_texture_pixmap_new_with_pixmap (root_pixmap_id);
1733   else
1734     return NULL;
1735 }