1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 
3 /* Marco X screen handler */
4 
5 /*
6  * Copyright (C) 2001, 2002 Havoc Pennington
7  * Copyright (C) 2002, 2003 Red Hat Inc.
8  * Some ICCCM manager selection code derived from fvwm2,
9  * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
10  * Copyright (C) 2003 Rob Adams
11  * Copyright (C) 2004-2006 Elijah Newren
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License as
15  * published by the Free Software Foundation; either version 2 of the
16  * License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26  * 02110-1301, USA.
27  */
28 
29 #include <config.h>
30 #include <glib/gi18n-lib.h>
31 
32 #include "screen-private.h"
33 #include "util.h"
34 #include "errors.h"
35 #include "window-private.h"
36 #include "frame-private.h"
37 #include "prefs.h"
38 #include "workspace.h"
39 #include "keybindings.h"
40 #include "prefs.h"
41 #include "stack.h"
42 #include "xprops.h"
43 #include "compositor.h"
44 
45 #ifdef HAVE_SOLARIS_XINERAMA
46 #include <X11/extensions/xinerama.h>
47 #endif
48 #ifdef HAVE_XFREE_XINERAMA
49 #include <X11/extensions/Xinerama.h>
50 #endif
51 
52 #include <X11/Xatom.h>
53 #include <cairo/cairo-xlib.h>
54 #include <locale.h>
55 #include <string.h>
56 #include <stdio.h>
57 
58 static char* get_screen_name (MetaDisplay *display,
59                               int          number);
60 
61 static void update_num_workspaces  (MetaScreen *screen,
62                                     guint32     timestamp);
63 static void update_focus_mode      (MetaScreen *screen);
64 static void set_workspace_names    (MetaScreen *screen);
65 static void prefs_changed_callback (MetaPreference pref,
66                                     gpointer       data);
67 
68 static void set_desktop_geometry_hint (MetaScreen *screen);
69 static void set_desktop_viewport_hint (MetaScreen *screen);
70 
71 #ifdef HAVE_STARTUP_NOTIFICATION
72 static void meta_screen_sn_event   (SnMonitorEvent *event,
73                                     void           *user_data);
74 #endif
75 
76 static int
set_wm_check_hint(MetaScreen * screen)77 set_wm_check_hint (MetaScreen *screen)
78 {
79   unsigned long data[1];
80 
81   g_return_val_if_fail (screen->display->leader_window != None, 0);
82 
83   data[0] = screen->display->leader_window;
84 
85   XChangeProperty (screen->display->xdisplay, screen->xroot,
86                    screen->display->atom__NET_SUPPORTING_WM_CHECK,
87                    XA_WINDOW,
88                    32, PropModeReplace, (guchar*) data, 1);
89 
90   return Success;
91 }
92 
93 static void
unset_wm_check_hint(MetaScreen * screen)94 unset_wm_check_hint (MetaScreen *screen)
95 {
96   XDeleteProperty (screen->display->xdisplay, screen->xroot,
97                    screen->display->atom__NET_SUPPORTING_WM_CHECK);
98 }
99 
100 static int
set_supported_hint(MetaScreen * screen)101 set_supported_hint (MetaScreen *screen)
102 {
103   Atom atoms[] = {
104 #define EWMH_ATOMS_ONLY
105 #define item(x)  screen->display->atom_##x,
106 #include "atomnames.h"
107 #undef item
108 #undef EWMH_ATOMS_ONLY
109     screen->display->atom__GTK_FRAME_EXTENTS,
110     screen->display->atom__GTK_SHOW_WINDOW_MENU,
111     screen->display->atom__GTK_WORKAREAS
112   };
113 
114   XChangeProperty (screen->display->xdisplay, screen->xroot,
115                    screen->display->atom__NET_SUPPORTED,
116                    XA_ATOM,
117                    32, PropModeReplace,
118                    (guchar*) atoms, G_N_ELEMENTS(atoms));
119 
120   return Success;
121 }
122 
123 static int
set_wm_icon_size_hint(MetaScreen * screen)124 set_wm_icon_size_hint (MetaScreen *screen)
125 {
126   int icon_size = meta_prefs_get_icon_size();
127 #define N_VALS 6
128   gulong vals[N_VALS];
129 
130   /* min width, min height, max w, max h, width inc, height inc */
131   vals[0] = icon_size; /* width */
132   vals[1] = icon_size; /* height */
133   vals[2] = icon_size; /* width */
134   vals[3] = icon_size; /* height */
135   vals[4] = 0;
136   vals[5] = 0;
137 
138   XChangeProperty (screen->display->xdisplay, screen->xroot,
139                    screen->display->atom_WM_ICON_SIZE,
140                    XA_CARDINAL,
141                    32, PropModeReplace, (guchar*) vals, N_VALS);
142 
143   return Success;
144 #undef N_VALS
145 }
146 
147 static void
reload_xinerama_infos(MetaScreen * screen)148 reload_xinerama_infos (MetaScreen *screen)
149 {
150   MetaDisplay *display;
151 
152   {
153     GList *tmp;
154 
155     tmp = screen->workspaces;
156     while (tmp != NULL)
157       {
158         MetaWorkspace *space = tmp->data;
159 
160         meta_workspace_invalidate_work_area (space);
161 
162         tmp = tmp->next;
163       }
164   }
165 
166   display = screen->display;
167 
168   if (screen->xinerama_infos)
169     g_free (screen->xinerama_infos);
170 
171   screen->xinerama_infos = NULL;
172   screen->n_xinerama_infos = 0;
173   screen->last_xinerama_index = 0;
174 
175   screen->display->xinerama_cache_invalidated = TRUE;
176 
177 #ifdef HAVE_XFREE_XINERAMA
178   if (XineramaIsActive (display->xdisplay))
179     {
180       XineramaScreenInfo *infos;
181       int n_infos;
182       int i;
183 
184       n_infos = 0;
185       infos = XineramaQueryScreens (display->xdisplay, &n_infos);
186 
187       meta_topic (META_DEBUG_XINERAMA,
188                   "Found %d Xinerama screens on display %s\n",
189                   n_infos, display->name);
190 
191       if (n_infos > 0)
192         {
193           screen->xinerama_infos = g_new (MetaXineramaScreenInfo, n_infos);
194           screen->n_xinerama_infos = n_infos;
195 
196           i = 0;
197           while (i < n_infos)
198             {
199               screen->xinerama_infos[i].number = infos[i].screen_number;
200               screen->xinerama_infos[i].rect.x = infos[i].x_org;
201               screen->xinerama_infos[i].rect.y = infos[i].y_org;
202               screen->xinerama_infos[i].rect.width = infos[i].width;
203               screen->xinerama_infos[i].rect.height = infos[i].height;
204 
205               meta_topic (META_DEBUG_XINERAMA,
206                           "Xinerama %d is %d,%d %d x %d\n",
207                           screen->xinerama_infos[i].number,
208                           screen->xinerama_infos[i].rect.x,
209                           screen->xinerama_infos[i].rect.y,
210                           screen->xinerama_infos[i].rect.width,
211                           screen->xinerama_infos[i].rect.height);
212 
213               ++i;
214             }
215         }
216 
217       meta_XFree (infos);
218     }
219   else
220     {
221       meta_topic (META_DEBUG_XINERAMA,
222                   "No XFree86 Xinerama extension or XFree86 Xinerama inactive on display %s\n",
223                   display->name);
224     }
225 #else
226   meta_topic (META_DEBUG_XINERAMA,
227               "Marco compiled without XFree86 Xinerama support\n");
228 #endif /* HAVE_XFREE_XINERAMA */
229 
230 #ifdef HAVE_SOLARIS_XINERAMA
231   /* This code from GDK, Copyright (C) 2002 Sun Microsystems */
232   if (screen->n_xinerama_infos == 0 &&
233       XineramaGetState (screen->display->xdisplay,
234                         screen->number))
235     {
236       XRectangle monitors[MAXFRAMEBUFFERS];
237       unsigned char hints[16];
238       int result;
239       int n_monitors;
240       int i;
241 
242       n_monitors = 0;
243       result = XineramaGetInfo (screen->display->xdisplay,
244                                 screen->number,
245 				monitors, hints,
246                                 &n_monitors);
247       /* Yes I know it should be Success but the current implementation
248        * returns the num of monitor
249        */
250       if (result > 0)
251 	{
252           g_assert (n_monitors > 0);
253 
254           screen->xinerama_infos = g_new (MetaXineramaScreenInfo, n_monitors);
255           screen->n_xinerama_infos = n_monitors;
256 
257           i = 0;
258           while (i < n_monitors)
259             {
260               screen->xinerama_infos[i].number = i;
261               screen->xinerama_infos[i].rect.x = monitors[i].x;
262               screen->xinerama_infos[i].rect.y = monitors[i].y;
263               screen->xinerama_infos[i].rect.width = monitors[i].width;
264               screen->xinerama_infos[i].rect.height = monitors[i].height;
265 
266               meta_topic (META_DEBUG_XINERAMA,
267                           "Xinerama %d is %d,%d %d x %d\n",
268                           screen->xinerama_infos[i].number,
269                           screen->xinerama_infos[i].rect.x,
270                           screen->xinerama_infos[i].rect.y,
271                           screen->xinerama_infos[i].rect.width,
272                           screen->xinerama_infos[i].rect.height);
273 
274               ++i;
275             }
276 	}
277     }
278   else if (screen->n_xinerama_infos == 0)
279     {
280       meta_topic (META_DEBUG_XINERAMA,
281                   "No Solaris Xinerama extension or Solaris Xinerama inactive on display %s\n",
282                   display->name);
283     }
284 #else
285   meta_topic (META_DEBUG_XINERAMA,
286               "Marco compiled without Solaris Xinerama support\n");
287 #endif /* HAVE_SOLARIS_XINERAMA */
288 
289   /* If no Xinerama, fill in the single screen info so
290    * we can use the field unconditionally
291    */
292   if (screen->n_xinerama_infos == 0)
293     {
294       if (g_getenv ("MARCO_DEBUG_XINERAMA"))
295         {
296           meta_topic (META_DEBUG_XINERAMA,
297                       "Pretending a single monitor has two Xinerama screens\n");
298 
299           screen->xinerama_infos = g_new (MetaXineramaScreenInfo, 2);
300           screen->n_xinerama_infos = 2;
301 
302           screen->xinerama_infos[0].number = 0;
303           screen->xinerama_infos[0].rect = screen->rect;
304           screen->xinerama_infos[0].rect.width = screen->rect.width / 2;
305 
306           screen->xinerama_infos[1].number = 1;
307           screen->xinerama_infos[1].rect = screen->rect;
308           screen->xinerama_infos[1].rect.x = screen->rect.width / 2;
309           screen->xinerama_infos[1].rect.width = screen->rect.width / 2;
310         }
311       else
312         {
313           meta_topic (META_DEBUG_XINERAMA,
314                       "No Xinerama screens, using default screen info\n");
315 
316           screen->xinerama_infos = g_new (MetaXineramaScreenInfo, 1);
317           screen->n_xinerama_infos = 1;
318 
319           screen->xinerama_infos[0].number = 0;
320           screen->xinerama_infos[0].rect = screen->rect;
321         }
322     }
323 
324   g_assert (screen->n_xinerama_infos > 0);
325   g_assert (screen->xinerama_infos != NULL);
326 }
327 
328 MetaScreen*
meta_screen_new(MetaDisplay * display,int number,guint32 timestamp)329 meta_screen_new (MetaDisplay *display,
330                  int          number,
331                  guint32      timestamp)
332 {
333   MetaScreen *screen;
334   Window xroot;
335   Display *xdisplay;
336   XWindowAttributes attr;
337   Window new_wm_sn_owner;
338   Window current_wm_sn_owner;
339   gboolean replace_current_wm;
340   Atom wm_sn_atom;
341   char buf[128];
342   guint32 manager_timestamp;
343   gulong current_workspace;
344 
345   replace_current_wm = meta_get_replace_current_wm ();
346 
347   /* Only display->name, display->xdisplay, and display->error_traps
348    * can really be used in this function, since normally screens are
349    * created from the MetaDisplay constructor
350    */
351 
352   xdisplay = display->xdisplay;
353 
354   meta_verbose ("Trying screen %d on display '%s'\n",
355                 number, display->name);
356 
357   xroot = RootWindow (xdisplay, number);
358 
359   /* FVWM checks for None here, I don't know if this
360    * ever actually happens
361    */
362   if (xroot == None)
363     {
364       meta_warning (_("Screen %d on display '%s' is invalid\n"),
365                     number, display->name);
366       return NULL;
367     }
368 
369   sprintf (buf, "WM_S%d", number);
370   wm_sn_atom = XInternAtom (xdisplay, buf, False);
371 
372   current_wm_sn_owner = XGetSelectionOwner (xdisplay, wm_sn_atom);
373 
374   if (current_wm_sn_owner != None)
375     {
376       XSetWindowAttributes attrs;
377 
378       if (!replace_current_wm)
379         {
380           meta_warning (_("Screen %d on display \"%s\" already has a window manager; try using the --replace option to replace the current window manager.\n"),
381                         number, display->name);
382 
383           return NULL;
384         }
385 
386       /* We want to find out when the current selection owner dies */
387       meta_error_trap_push (display);
388       attrs.event_mask = StructureNotifyMask;
389       XChangeWindowAttributes (xdisplay,
390                                current_wm_sn_owner, CWEventMask, &attrs);
391       if (meta_error_trap_pop_with_return (display, FALSE) != Success)
392         current_wm_sn_owner = None; /* don't wait for it to die later on */
393     }
394 
395   /* We need SelectionClear and SelectionRequest events on the new_wm_sn_owner,
396    * but those cannot be masked, so we only need NoEventMask.
397    */
398   new_wm_sn_owner = meta_create_offscreen_window (xdisplay, xroot, NoEventMask);
399 
400   manager_timestamp = timestamp;
401 
402   XSetSelectionOwner (xdisplay, wm_sn_atom, new_wm_sn_owner,
403                       manager_timestamp);
404 
405   if (XGetSelectionOwner (xdisplay, wm_sn_atom) != new_wm_sn_owner)
406     {
407       meta_warning (_("Could not acquire window manager selection on screen %d display \"%s\"\n"),
408                     number, display->name);
409 
410       XDestroyWindow (xdisplay, new_wm_sn_owner);
411 
412       return NULL;
413     }
414 
415   {
416     /* Send client message indicating that we are now the WM */
417     XClientMessageEvent ev;
418 
419     ev.type = ClientMessage;
420     ev.window = xroot;
421     ev.message_type = display->atom_MANAGER;
422     ev.format = 32;
423     ev.data.l[0] = manager_timestamp;
424     ev.data.l[1] = wm_sn_atom;
425 
426     XSendEvent (xdisplay, xroot, False, StructureNotifyMask, (XEvent*)&ev);
427   }
428 
429   /* Wait for old window manager to go away */
430   if (current_wm_sn_owner != None)
431     {
432       XEvent event;
433 
434       /* We sort of block infinitely here which is probably lame. */
435 
436       meta_verbose ("Waiting for old window manager to exit\n");
437       do
438         {
439           XWindowEvent (xdisplay, current_wm_sn_owner,
440                         StructureNotifyMask, &event);
441         }
442       while (event.type != DestroyNotify);
443     }
444 
445   /* select our root window events */
446   meta_error_trap_push (display);
447 
448   /* We need to or with the existing event mask since
449    * gtk+ may be interested in other events.
450    */
451   XGetWindowAttributes (xdisplay, xroot, &attr);
452   XSelectInput (xdisplay,
453                 xroot,
454                 SubstructureRedirectMask | SubstructureNotifyMask |
455                 ColormapChangeMask | PropertyChangeMask |
456                 LeaveWindowMask | EnterWindowMask |
457                 KeyPressMask | KeyReleaseMask |
458                 FocusChangeMask | StructureNotifyMask |
459 #ifdef HAVE_COMPOSITE_EXTENSIONS
460                 ExposureMask |
461 #endif
462 		attr.your_event_mask);
463   if (meta_error_trap_pop_with_return (display, FALSE) != Success)
464     {
465       meta_warning (_("Screen %d on display \"%s\" already has a window manager\n"),
466                     number, display->name);
467 
468       XDestroyWindow (xdisplay, new_wm_sn_owner);
469 
470       return NULL;
471     }
472 
473   screen = g_new (MetaScreen, 1);
474   screen->closing = 0;
475 
476   screen->display = display;
477   screen->number = number;
478   screen->screen_name = get_screen_name (display, number);
479   screen->xscreen = ScreenOfDisplay (xdisplay, number);
480   screen->xroot = xroot;
481   screen->rect.x = screen->rect.y = 0;
482   screen->rect.width = WidthOfScreen (screen->xscreen);
483   screen->rect.height = HeightOfScreen (screen->xscreen);
484   screen->current_cursor = -1; /* invalid/unset */
485   screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen);
486   screen->default_depth = DefaultDepthOfScreen (screen->xscreen);
487   screen->flash_window = None;
488 
489   screen->wm_sn_selection_window = new_wm_sn_owner;
490   screen->wm_sn_atom = wm_sn_atom;
491   screen->wm_sn_timestamp = manager_timestamp;
492 
493 #ifdef HAVE_COMPOSITE_EXTENSIONS
494   g_snprintf (buf, sizeof(buf), "_NET_WM_CM_S%d", screen->number);
495   screen->wm_cm_atom = XInternAtom (screen->display->xdisplay, buf, FALSE);
496   screen->wm_cm_selection_window = meta_create_offscreen_window (xdisplay,
497                                                                  xroot,
498                                                                  NoEventMask);
499 #endif
500   screen->work_area_idle = 0;
501 
502   screen->active_workspace = NULL;
503   screen->workspaces = NULL;
504   screen->rows_of_workspaces = 1;
505   screen->columns_of_workspaces = -1;
506   screen->vertical_workspaces = FALSE;
507   screen->starting_corner = META_SCREEN_TOPLEFT;
508   screen->compositor_data = NULL;
509 
510   {
511     XFontStruct *font_info;
512     XGCValues gc_values;
513     gulong value_mask = 0;
514 
515     gc_values.subwindow_mode = IncludeInferiors;
516     value_mask |= GCSubwindowMode;
517     gc_values.function = GXinvert;
518     value_mask |= GCFunction;
519     gc_values.line_width = META_WIREFRAME_XOR_LINE_WIDTH;
520     value_mask |= GCLineWidth;
521 
522     font_info = XLoadQueryFont (screen->display->xdisplay, "fixed");
523 
524     if (font_info != NULL)
525       {
526         gc_values.font = font_info->fid;
527         value_mask |= GCFont;
528         XFreeFontInfo (NULL, font_info, 1);
529       }
530     else
531       meta_warning ("xserver doesn't have 'fixed' font.\n");
532 
533     screen->root_xor_gc = XCreateGC (screen->display->xdisplay,
534                                      screen->xroot,
535                                      value_mask,
536                                      &gc_values);
537   }
538 
539   screen->xinerama_infos = NULL;
540   screen->n_xinerama_infos = 0;
541   screen->last_xinerama_index = 0;
542 
543   reload_xinerama_infos (screen);
544 
545   meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
546 
547   /* Handle creating a no_focus_window for this screen */
548   screen->no_focus_window =
549     meta_create_offscreen_window (display->xdisplay,
550                                   screen->xroot,
551                                   FocusChangeMask|KeyPressMask|KeyReleaseMask);
552   XMapWindow (display->xdisplay, screen->no_focus_window);
553   /* Done with no_focus_window stuff */
554 
555   set_wm_icon_size_hint (screen);
556 
557   set_supported_hint (screen);
558 
559   set_wm_check_hint (screen);
560 
561   set_desktop_viewport_hint (screen);
562 
563   set_desktop_geometry_hint (screen);
564 
565   meta_screen_update_workspace_layout (screen);
566 
567   /* Get current workspace */
568   current_workspace = 0;
569   if (meta_prop_get_cardinal (screen->display,
570                               screen->xroot,
571                               screen->display->atom__NET_CURRENT_DESKTOP,
572                               &current_workspace))
573     meta_verbose ("Read existing _NET_CURRENT_DESKTOP = %d\n",
574                   (int) current_workspace);
575   else
576     meta_verbose ("No _NET_CURRENT_DESKTOP present\n");
577 
578   /* Screens must have at least one workspace at all times,
579    * so create that required workspace.
580    */
581   meta_workspace_activate (meta_workspace_new (screen), timestamp);
582   update_num_workspaces (screen, timestamp);
583 
584   set_workspace_names (screen);
585 
586   screen->all_keys_grabbed = FALSE;
587   screen->keys_grabbed = FALSE;
588   meta_screen_grab_keys (screen);
589 
590   screen->ui = meta_ui_new (screen->display->xdisplay,
591                             screen->xscreen);
592 
593   screen->tab_popup = NULL;
594   screen->tile_preview = NULL;
595 
596   screen->tile_preview_timeout_id = 0;
597 
598   screen->stack = meta_stack_new (screen);
599 
600   meta_prefs_add_listener (prefs_changed_callback, screen);
601 
602 #ifdef HAVE_STARTUP_NOTIFICATION
603   screen->sn_context =
604     sn_monitor_context_new (screen->display->sn_display,
605                             screen->number,
606                             meta_screen_sn_event,
607                             screen,
608                             NULL);
609   screen->startup_sequences = NULL;
610   screen->startup_sequence_timeout = 0;
611 #endif
612 
613   /* Switch to the _NET_CURRENT_DESKTOP workspace */
614   {
615     MetaWorkspace *space;
616 
617     space = meta_screen_get_workspace_by_index (screen,
618                                                 current_workspace);
619 
620     if (space != NULL)
621       meta_workspace_activate (space, timestamp);
622   }
623 
624   meta_verbose ("Added screen %d ('%s') root 0x%lx\n",
625                 screen->number, screen->screen_name, screen->xroot);
626 
627   return screen;
628 }
629 
630 void
meta_screen_free(MetaScreen * screen,guint32 timestamp)631 meta_screen_free (MetaScreen *screen,
632                   guint32     timestamp)
633 {
634   MetaDisplay *display;
635   XGCValues gc_values = { 0 };
636 
637   display = screen->display;
638 
639   screen->closing += 1;
640 
641   meta_display_grab (display);
642 
643   if (screen->display->compositor)
644     {
645       meta_compositor_unmanage_screen (screen->display->compositor,
646 				       screen);
647     }
648 
649   meta_display_unmanage_windows_for_screen (display, screen, timestamp);
650 
651   meta_prefs_remove_listener (prefs_changed_callback, screen);
652 
653   meta_screen_ungrab_keys (screen);
654 
655 #ifdef HAVE_STARTUP_NOTIFICATION
656   g_slist_free_full (screen->startup_sequences,
657                      (GDestroyNotify) sn_startup_sequence_unref);
658   screen->startup_sequences = NULL;
659 
660   if (screen->startup_sequence_timeout != 0)
661     {
662       g_source_remove (screen->startup_sequence_timeout);
663       screen->startup_sequence_timeout = 0;
664     }
665   if (screen->sn_context)
666     {
667       sn_monitor_context_unref (screen->sn_context);
668       screen->sn_context = NULL;
669     }
670 #endif
671 
672   meta_ui_free (screen->ui);
673 
674   meta_stack_free (screen->stack);
675 
676   meta_error_trap_push (screen->display);
677   XSelectInput (screen->display->xdisplay, screen->xroot, 0);
678   if (meta_error_trap_pop_with_return (screen->display, FALSE) != Success)
679     meta_warning (_("Could not release screen %d on display \"%s\"\n"),
680                   screen->number, screen->display->name);
681 
682   unset_wm_check_hint (screen);
683 
684   XDestroyWindow (screen->display->xdisplay,
685                   screen->wm_sn_selection_window);
686 
687   if (screen->work_area_idle != 0)
688     g_source_remove (screen->work_area_idle);
689 
690   if (XGetGCValues (screen->display->xdisplay,
691                     screen->root_xor_gc,
692                     GCFont,
693                     &gc_values))
694     {
695       XUnloadFont (screen->display->xdisplay,
696                    gc_values.font);
697     }
698 
699   XFreeGC (screen->display->xdisplay,
700            screen->root_xor_gc);
701 
702   if (screen->xinerama_infos)
703     g_free (screen->xinerama_infos);
704 
705   if (screen->tile_preview_timeout_id)
706     g_source_remove (screen->tile_preview_timeout_id);
707 
708   if (screen->tile_preview)
709     meta_tile_preview_free (screen->tile_preview);
710 
711   g_free (screen->screen_name);
712   g_free (screen);
713 
714   XFlush (display->xdisplay);
715   meta_display_ungrab (display);
716 }
717 
718 typedef struct
719 {
720   Window		xwindow;
721   XWindowAttributes	attrs;
722 } WindowInfo;
723 
724 static GList *
list_windows(MetaScreen * screen)725 list_windows (MetaScreen *screen)
726 {
727   Window ignored1, ignored2;
728   Window *children;
729   guint n_children, i;
730   GList *result;
731 
732   XQueryTree (screen->display->xdisplay,
733               screen->xroot,
734               &ignored1, &ignored2, &children, &n_children);
735 
736   result = NULL;
737   for (i = 0; i < n_children; ++i)
738     {
739       WindowInfo *info = g_new0 (WindowInfo, 1);
740 
741       meta_error_trap_push (screen->display);
742 
743       XGetWindowAttributes (screen->display->xdisplay,
744                             children[i], &info->attrs);
745 
746       if (meta_error_trap_pop_with_return (screen->display, TRUE))
747 	{
748           meta_verbose ("Failed to get attributes for window 0x%lx\n",
749                         children[i]);
750 	  g_free (info);
751         }
752       else
753         {
754 	  info->xwindow = children[i];
755           result = g_list_prepend (result, info);
756 	}
757     }
758 
759   if (children)
760     XFree (children);
761 
762   return g_list_reverse (result);
763 }
764 
765 void
meta_screen_manage_all_windows(MetaScreen * screen)766 meta_screen_manage_all_windows (MetaScreen *screen)
767 {
768   GList *windows;
769   GList *list;
770 
771   meta_display_grab (screen->display);
772 
773   windows = list_windows (screen);
774 
775   meta_stack_freeze (screen->stack);
776   for (list = windows; list != NULL; list = list->next)
777     {
778       WindowInfo *info = list->data;
779       MetaWindow *window;
780       gboolean test_window_owner;
781 
782       window = meta_window_new_with_attrs (screen->display, info->xwindow, TRUE,
783                                            &info->attrs);
784       test_window_owner = info->xwindow == screen->no_focus_window ||
785        info->xwindow == screen->flash_window ||
786        info->xwindow == screen->wm_sn_selection_window;
787 
788 #ifdef HAVE_COMPOSITE_EXTENSIONS
789       test_window_owner = test_window_owner ||  info->xwindow == screen->wm_cm_selection_window;
790 #endif
791       if (test_window_owner)
792       {
793         meta_verbose ("Not managing our own windows\n");
794         continue;
795       }
796 
797       if (screen->display->compositor)
798         meta_compositor_add_window (screen->display->compositor, window,
799                                     info->xwindow, &info->attrs);
800     }
801   meta_stack_thaw (screen->stack);
802 
803   g_list_free_full (windows, g_free);
804 
805   meta_display_ungrab (screen->display);
806 }
807 
808 void
meta_screen_composite_all_windows(MetaScreen * screen)809 meta_screen_composite_all_windows (MetaScreen *screen)
810 {
811 #ifdef HAVE_COMPOSITE_EXTENSIONS
812   MetaDisplay *display;
813   GList *windows, *list;
814 
815   display = screen->display;
816   if (!display->compositor)
817     return;
818 
819   windows = list_windows (screen);
820 
821   meta_stack_freeze (screen->stack);
822 
823   for (list = windows; list != NULL; list = list->next)
824     {
825       WindowInfo *info = list->data;
826 
827       if (info->xwindow == screen->no_focus_window ||
828           info->xwindow == screen->flash_window ||
829           info->xwindow == screen->wm_sn_selection_window ||
830           info->xwindow == screen->wm_cm_selection_window) {
831         meta_verbose ("Not managing our own windows\n");
832         continue;
833       }
834 
835       meta_compositor_add_window (display->compositor,
836                                   meta_display_lookup_x_window (display,
837                                                                 info->xwindow),
838 				  info->xwindow, &info->attrs);
839     }
840 
841   meta_stack_thaw (screen->stack);
842 
843   g_list_free_full (windows, g_free);
844 #endif
845 }
846 
847 MetaScreen*
meta_screen_for_x_screen(Screen * xscreen)848 meta_screen_for_x_screen (Screen *xscreen)
849 {
850   MetaDisplay *display;
851 
852   display = meta_display_for_x_display (DisplayOfScreen (xscreen));
853 
854   if (display == NULL)
855     return NULL;
856 
857   return meta_display_screen_for_x_screen (display, xscreen);
858 }
859 
860 static void
prefs_changed_callback(MetaPreference pref,gpointer data)861 prefs_changed_callback (MetaPreference pref,
862                         gpointer       data)
863 {
864   MetaScreen *screen = data;
865 
866   if (pref == META_PREF_NUM_WORKSPACES)
867     {
868       /* GSettings doesn't provide timestamps, but luckily update_num_workspaces
869        * often doesn't need it...
870        */
871       guint32 timestamp =
872         meta_display_get_current_time_roundtrip (screen->display);
873       update_num_workspaces (screen, timestamp);
874     }
875   else if (pref == META_PREF_FOCUS_MODE)
876     {
877       update_focus_mode (screen);
878     }
879   else if (pref == META_PREF_WORKSPACE_NAMES)
880     {
881       set_workspace_names (screen);
882     }
883 }
884 
885 static char*
get_screen_name(MetaDisplay * display,int number)886 get_screen_name (MetaDisplay *display,
887                  int          number)
888 {
889   char *p;
890   char *dname;
891   char *scr;
892 
893   /* DisplayString gives us a sort of canonical display,
894    * vs. the user-entered name from XDisplayName()
895    */
896   dname = g_strdup (DisplayString (display->xdisplay));
897 
898   /* Change display name to specify this screen.
899    */
900   p = strrchr (dname, ':');
901   if (p)
902     {
903       p = strchr (p, '.');
904       if (p)
905         *p = '\0';
906     }
907 
908   scr = g_strdup_printf ("%s.%d", dname, number);
909 
910   g_free (dname);
911 
912   return scr;
913 }
914 
915 static gint
ptrcmp(gconstpointer a,gconstpointer b)916 ptrcmp (gconstpointer a, gconstpointer b)
917 {
918   if (a < b)
919     return -1;
920   else if (a > b)
921     return 1;
922   else
923     return 0;
924 }
925 
926 static void
listify_func(gpointer key,gpointer value,gpointer data)927 listify_func (gpointer key, gpointer value, gpointer data)
928 {
929   GSList **listp;
930 
931   listp = data;
932 
933   *listp = g_slist_prepend (*listp, value);
934 }
935 
936 void
meta_screen_foreach_window(MetaScreen * screen,MetaScreenWindowFunc func,gpointer data)937 meta_screen_foreach_window (MetaScreen *screen,
938                             MetaScreenWindowFunc func,
939                             gpointer data)
940 {
941   GSList *winlist;
942   GSList *tmp;
943 
944   /* If we end up doing this often, just keeping a list
945    * of windows might be sensible.
946    */
947 
948   winlist = NULL;
949   g_hash_table_foreach (screen->display->window_ids,
950                         listify_func,
951                         &winlist);
952 
953   winlist = g_slist_sort (winlist, ptrcmp);
954 
955   tmp = winlist;
956   while (tmp != NULL)
957     {
958       /* If the next node doesn't contain this window
959        * a second time, delete the window.
960        */
961       if (tmp->next == NULL ||
962           (tmp->next && tmp->next->data != tmp->data))
963         {
964           MetaWindow *window = tmp->data;
965 
966           if (window->screen == screen)
967             (* func) (screen, window, data);
968         }
969 
970       tmp = tmp->next;
971     }
972   g_slist_free (winlist);
973 }
974 
975 static void
queue_draw(MetaScreen * screen,MetaWindow * window,gpointer data)976 queue_draw (MetaScreen *screen, MetaWindow *window, gpointer data)
977 {
978   if (window->frame)
979     meta_frame_queue_draw (window->frame);
980 }
981 
982 void
meta_screen_queue_frame_redraws(MetaScreen * screen)983 meta_screen_queue_frame_redraws (MetaScreen *screen)
984 {
985   meta_screen_foreach_window (screen, queue_draw, NULL);
986 }
987 
988 static void
queue_resize(MetaScreen * screen,MetaWindow * window,gpointer data)989 queue_resize (MetaScreen *screen, MetaWindow *window, gpointer data)
990 {
991   meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
992 }
993 
994 void
meta_screen_queue_window_resizes(MetaScreen * screen)995 meta_screen_queue_window_resizes (MetaScreen *screen)
996 {
997   meta_screen_foreach_window (screen, queue_resize, NULL);
998 }
999 
1000 int
meta_screen_get_n_workspaces(MetaScreen * screen)1001 meta_screen_get_n_workspaces (MetaScreen *screen)
1002 {
1003   return g_list_length (screen->workspaces);
1004 }
1005 
1006 MetaWorkspace*
meta_screen_get_workspace_by_index(MetaScreen * screen,int idx)1007 meta_screen_get_workspace_by_index (MetaScreen  *screen,
1008                                     int          idx)
1009 {
1010   GList *tmp;
1011   int i;
1012 
1013   /* should be robust, idx is maybe from an app */
1014   if (idx < 0)
1015     return NULL;
1016 
1017   i = 0;
1018   tmp = screen->workspaces;
1019   while (tmp != NULL)
1020     {
1021       MetaWorkspace *w = tmp->data;
1022 
1023       if (i == idx)
1024         return w;
1025 
1026       ++i;
1027       tmp = tmp->next;
1028     }
1029 
1030   return NULL;
1031 }
1032 
1033 static void
set_number_of_spaces_hint(MetaScreen * screen,int n_spaces)1034 set_number_of_spaces_hint (MetaScreen *screen,
1035 			   int         n_spaces)
1036 {
1037   unsigned long data[1];
1038 
1039   if (screen->closing > 0)
1040     return;
1041 
1042   data[0] = n_spaces;
1043 
1044   meta_verbose ("Setting _NET_NUMBER_OF_DESKTOPS to %lu\n", data[0]);
1045 
1046   meta_error_trap_push (screen->display);
1047   XChangeProperty (screen->display->xdisplay, screen->xroot,
1048                    screen->display->atom__NET_NUMBER_OF_DESKTOPS,
1049                    XA_CARDINAL,
1050                    32, PropModeReplace, (guchar*) data, 1);
1051   meta_error_trap_pop (screen->display, FALSE);
1052 }
1053 
1054 static void
set_desktop_geometry_hint(MetaScreen * screen)1055 set_desktop_geometry_hint (MetaScreen *screen)
1056 {
1057   unsigned long data[2];
1058 
1059   if (screen->closing > 0)
1060     return;
1061 
1062   data[0] = screen->rect.width;
1063   data[1] = screen->rect.height;
1064 
1065   meta_verbose ("Setting _NET_DESKTOP_GEOMETRY to %lu, %lu\n", data[0], data[1]);
1066 
1067   meta_error_trap_push (screen->display);
1068   XChangeProperty (screen->display->xdisplay, screen->xroot,
1069                    screen->display->atom__NET_DESKTOP_GEOMETRY,
1070                    XA_CARDINAL,
1071                    32, PropModeReplace, (guchar*) data, 2);
1072   meta_error_trap_pop (screen->display, FALSE);
1073 }
1074 
1075 static void
set_desktop_viewport_hint(MetaScreen * screen)1076 set_desktop_viewport_hint (MetaScreen *screen)
1077 {
1078   unsigned long data[2];
1079 
1080   if (screen->closing > 0)
1081     return;
1082 
1083   /*
1084    * Marco does not implement viewports, so this is a fixed 0,0
1085    */
1086   data[0] = 0;
1087   data[1] = 0;
1088 
1089   meta_verbose ("Setting _NET_DESKTOP_VIEWPORT to 0, 0\n");
1090 
1091   meta_error_trap_push (screen->display);
1092   XChangeProperty (screen->display->xdisplay, screen->xroot,
1093                    screen->display->atom__NET_DESKTOP_VIEWPORT,
1094                    XA_CARDINAL,
1095                    32, PropModeReplace, (guchar*) data, 2);
1096   meta_error_trap_pop (screen->display, FALSE);
1097 }
1098 
1099 static void
update_num_workspaces(MetaScreen * screen,guint32 timestamp)1100 update_num_workspaces (MetaScreen *screen,
1101                        guint32     timestamp)
1102 {
1103   int new_num;
1104   GList *tmp;
1105   int i;
1106   GList *extras;
1107   MetaWorkspace *last_remaining;
1108   gboolean need_change_space;
1109 
1110   new_num = meta_prefs_get_num_workspaces ();
1111 
1112   g_assert (new_num > 0);
1113 
1114   last_remaining = NULL;
1115   extras = NULL;
1116   i = 0;
1117   tmp = screen->workspaces;
1118   while (tmp != NULL)
1119     {
1120       MetaWorkspace *w = tmp->data;
1121 
1122       if (i >= new_num)
1123         extras = g_list_prepend (extras, w);
1124       else
1125         last_remaining = w;
1126 
1127       ++i;
1128       tmp = tmp->next;
1129     }
1130 
1131   g_assert (last_remaining);
1132 
1133   /* Get rid of the extra workspaces by moving all their windows
1134    * to last_remaining, then activating last_remaining if
1135    * one of the removed workspaces was active. This will be a bit
1136    * wacky if the config tool for changing number of workspaces
1137    * is on a removed workspace ;-)
1138    */
1139   need_change_space = FALSE;
1140   tmp = extras;
1141   while (tmp != NULL)
1142     {
1143       MetaWorkspace *w = tmp->data;
1144 
1145       meta_workspace_relocate_windows (w, last_remaining);
1146 
1147       if (w == screen->active_workspace)
1148         need_change_space = TRUE;
1149 
1150       tmp = tmp->next;
1151     }
1152 
1153   if (need_change_space)
1154     meta_workspace_activate (last_remaining, timestamp);
1155 
1156   /* Should now be safe to free the workspaces */
1157   tmp = extras;
1158   while (tmp != NULL)
1159     {
1160       MetaWorkspace *w = tmp->data;
1161 
1162       g_assert (w->windows == NULL);
1163       meta_workspace_free (w);
1164 
1165       tmp = tmp->next;
1166     }
1167 
1168   g_list_free (extras);
1169 
1170   while (i < new_num)
1171     {
1172       meta_workspace_new (screen);
1173       ++i;
1174     }
1175 
1176   set_number_of_spaces_hint (screen, new_num);
1177 
1178   meta_screen_queue_workarea_recalc (screen);
1179 }
1180 
1181 static void
update_focus_mode(MetaScreen * screen)1182 update_focus_mode (MetaScreen *screen)
1183 {
1184   /* nothing to do anymore */ ;
1185 }
1186 
1187 void
meta_screen_set_cursor(MetaScreen * screen,MetaCursor cursor)1188 meta_screen_set_cursor (MetaScreen *screen,
1189                         MetaCursor  cursor)
1190 {
1191   Cursor xcursor;
1192 
1193   if (cursor == screen->current_cursor)
1194     return;
1195 
1196   screen->current_cursor = cursor;
1197 
1198   xcursor = meta_display_create_x_cursor (screen->display, cursor);
1199   XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
1200   XFlush (screen->display->xdisplay);
1201   XFreeCursor (screen->display->xdisplay, xcursor);
1202 }
1203 
1204 void
meta_screen_update_cursor(MetaScreen * screen)1205 meta_screen_update_cursor (MetaScreen *screen)
1206 {
1207   Cursor xcursor;
1208 
1209   xcursor = meta_display_create_x_cursor (screen->display,
1210 					  screen->current_cursor);
1211   XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
1212   XFlush (screen->display->xdisplay);
1213   XFreeCursor (screen->display->xdisplay, xcursor);
1214 }
1215 
1216 #define MAX_PREVIEW_SCREEN_FRACTION 0.33
1217 #define MAX_PREVIEW_SIZE 300
1218 
1219 static cairo_surface_t *
get_window_surface(MetaWindow * window)1220 get_window_surface (MetaWindow *window)
1221 {
1222   cairo_surface_t *surface, *scaled;
1223   cairo_t *cr;
1224   const MetaXineramaScreenInfo *current;
1225   int width, height, max_columns, max_size;
1226   double ratio;
1227 
1228   surface = meta_compositor_get_window_surface (window->display->compositor, window);
1229 
1230   if (surface == NULL)
1231     return NULL;
1232 
1233   width = cairo_xlib_surface_get_width (surface);
1234   height = cairo_xlib_surface_get_height (surface);
1235 
1236   current = meta_screen_get_current_xinerama (window->screen);
1237   max_columns = meta_prefs_get_alt_tab_max_columns ();
1238 
1239   /* Scale surface to fit current screen */
1240   if (width > height)
1241     {
1242       max_size = MIN (MAX_PREVIEW_SIZE, current->rect.width / max_columns * MAX_PREVIEW_SCREEN_FRACTION);
1243       ratio = ((double) width) / max_size;
1244       width = (int) max_size;
1245       height = (int) (((double) height) / ratio);
1246     }
1247   else
1248     {
1249       max_size = MIN (MAX_PREVIEW_SIZE, current->rect.height / max_columns * MAX_PREVIEW_SCREEN_FRACTION);
1250       ratio = ((double) height) / max_size;
1251       height = (int) max_size;
1252       width = (int) (((double) width) / ratio);
1253     }
1254 
1255   meta_error_trap_push (window->display);
1256   scaled = cairo_surface_create_similar (surface,
1257                                          cairo_surface_get_content (surface),
1258                                          width, height);
1259   if (meta_error_trap_pop_with_return (window->display, FALSE) != Success)
1260     return NULL;
1261 
1262   cr = cairo_create (scaled);
1263   cairo_scale (cr, 1/ratio, 1/ratio);
1264   cairo_set_source_surface (cr, surface, 0, 0);
1265   cairo_paint (cr);
1266 
1267   cairo_destroy (cr);
1268   cairo_surface_destroy (surface);
1269 
1270   return scaled;
1271 }
1272 
1273 void
meta_screen_ensure_tab_popup(MetaScreen * screen,MetaTabList list_type,MetaTabShowType show_type)1274 meta_screen_ensure_tab_popup (MetaScreen      *screen,
1275                               MetaTabList      list_type,
1276                               MetaTabShowType  show_type)
1277 {
1278   MetaTabEntry *entries;
1279   GList *tab_list;
1280   GList *tmp;
1281   int len;
1282   int i;
1283   gint border;
1284   int scale;
1285 
1286   if (screen->tab_popup)
1287     return;
1288 
1289   tab_list = meta_display_get_tab_list (screen->display,
1290                                         list_type,
1291                                         screen,
1292                                         screen->active_workspace);
1293 
1294   len = g_list_length (tab_list);
1295   scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
1296 
1297   entries = g_new (MetaTabEntry, len + 1);
1298   entries[len].key = NULL;
1299   entries[len].title = NULL;
1300   entries[len].icon = NULL;
1301   entries[len].win_surface = NULL;
1302 
1303   border = meta_prefs_show_tab_border() ? BORDER_OUTLINE_TAB |
1304     BORDER_OUTLINE_WINDOW : BORDER_OUTLINE_TAB;
1305   i = 0;
1306   tmp = tab_list;
1307   while (i < len)
1308     {
1309       MetaWindow *window;
1310       MetaRectangle r;
1311 
1312       window = tmp->data;
1313 
1314       entries[i].key = (MetaTabEntryKey) window->xwindow;
1315       entries[i].title = window->title;
1316       entries[i].win_surface = NULL;
1317 
1318       entries[i].icon = g_object_ref (window->icon);
1319 
1320       /* Only get the window thumbnail surface if the user has a compositor
1321        * enabled and does NOT have compositing-fast-alt-tab-set to true in
1322        * GSettings. There is an obvious lag when the surface is retrieved. */
1323       if (meta_prefs_get_compositing_manager() && !meta_prefs_get_compositing_fast_alt_tab())
1324         {
1325           cairo_surface_t *win_surface;
1326 
1327           /* Get window thumbnail */
1328           win_surface = get_window_surface (window);
1329 
1330           if (win_surface != NULL)
1331             {
1332               cairo_surface_t *surface, *icon;
1333               cairo_t *cr;
1334               int width, height, icon_width, icon_height;
1335 
1336 #define ICON_OFFSET 6
1337 
1338               width = cairo_xlib_surface_get_width (win_surface);
1339               height = cairo_xlib_surface_get_height (win_surface);
1340 
1341               /* Create a new surface to overlap the window icon into */
1342               surface = cairo_surface_create_similar (win_surface,
1343                                                       cairo_surface_get_content (win_surface),
1344                                                       width, height);
1345 
1346               cr = cairo_create (surface);
1347               cairo_set_source_surface (cr, win_surface, 0, 0);
1348               cairo_paint (cr);
1349 
1350               /* Get the window icon as a surface */
1351               icon = gdk_cairo_surface_create_from_pixbuf (window->icon, scale, NULL);
1352 
1353               icon_width = cairo_image_surface_get_width (icon) / scale;
1354               icon_height = cairo_image_surface_get_height (icon) / scale;
1355 
1356               /* Overlap the window icon surface over the window thumbnail */
1357               cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
1358               cairo_set_source_surface (cr, icon,
1359                                         width  - icon_width - ICON_OFFSET,
1360                                         height - icon_height - ICON_OFFSET);
1361               cairo_paint (cr);
1362 
1363               entries[i].win_surface = surface;
1364 
1365               cairo_destroy (cr);
1366               cairo_surface_destroy (icon);
1367               cairo_surface_destroy (win_surface);
1368             }
1369         }
1370 
1371       entries[i].blank = FALSE;
1372       entries[i].hidden = !meta_window_showing_on_its_workspace (window);
1373       entries[i].demands_attention = window->wm_state_demands_attention;
1374 
1375       if (show_type == META_TAB_SHOW_INSTANTLY ||
1376           !entries[i].hidden                   ||
1377           !meta_window_get_icon_geometry (window, &r))
1378         meta_window_get_outer_rect (window, &r);
1379 
1380       entries[i].rect = r;
1381 
1382       /* Find inside of highlight rectangle to be used when window is
1383        * outlined for tabbing.  This should be the size of the
1384        * east/west frame, and the size of the south frame, on those
1385        * sides.  On the top it should be the size of the south frame
1386        * edge.
1387        */
1388        if (border & BORDER_OUTLINE_WINDOW)
1389        {
1390 #define OUTLINE_WIDTH 5
1391          /* Top side */
1392          entries[i].inner_rect.y = OUTLINE_WIDTH;
1393 
1394          /* Bottom side */
1395          entries[i].inner_rect.height = r.height - entries[i].inner_rect.y - OUTLINE_WIDTH;
1396 
1397          /* Left side */
1398          entries[i].inner_rect.x = OUTLINE_WIDTH;
1399 
1400          /* Right side */
1401          entries[i].inner_rect.width = r.width - entries[i].inner_rect.x - OUTLINE_WIDTH;
1402        }
1403 
1404       ++i;
1405       tmp = tmp->next;
1406     }
1407 
1408   screen->tab_popup = meta_ui_tab_popup_new (entries,
1409                                              len,
1410                                              meta_prefs_get_alt_tab_max_columns(),
1411                                              meta_prefs_get_alt_tab_expand_to_fit_title(),
1412                                              border);
1413 
1414   for (i = 0; i < len; i++)
1415     {
1416       g_object_unref (entries[i].icon);
1417       if (entries[i].win_surface)
1418         cairo_surface_destroy (entries[i].win_surface);
1419     }
1420 
1421   g_free (entries);
1422 
1423   g_list_free (tab_list);
1424 
1425   /* don't show tab popup, since proper window isn't selected yet */
1426 }
1427 
1428 void
meta_screen_ensure_workspace_popup(MetaScreen * screen)1429 meta_screen_ensure_workspace_popup (MetaScreen *screen)
1430 {
1431   MetaTabEntry *entries;
1432   int len;
1433   int i;
1434   MetaWorkspaceLayout layout;
1435   int n_workspaces;
1436   int current_workspace;
1437 
1438   if (screen->tab_popup)
1439     return;
1440 
1441   current_workspace = meta_workspace_index (screen->active_workspace);
1442   n_workspaces = meta_screen_get_n_workspaces (screen);
1443 
1444   meta_screen_calc_workspace_layout (screen, n_workspaces,
1445                                      current_workspace, &layout);
1446 
1447   len = layout.grid_area;
1448 
1449   entries = g_new (MetaTabEntry, len + 1);
1450   entries[len].key = NULL;
1451   entries[len].title = NULL;
1452   entries[len].icon = NULL;
1453   entries[len].win_surface = NULL;
1454 
1455   i = 0;
1456   while (i < len)
1457     {
1458       if (layout.grid[i] >= 0)
1459         {
1460           MetaWorkspace *workspace;
1461 
1462           workspace = meta_screen_get_workspace_by_index (screen,
1463                                                           layout.grid[i]);
1464 
1465           entries[i].key = (MetaTabEntryKey) workspace;
1466           entries[i].title = meta_workspace_get_name (workspace);
1467           entries[i].icon = NULL;
1468           entries[i].win_surface = NULL;
1469           entries[i].blank = FALSE;
1470 
1471           g_assert (entries[i].title != NULL);
1472         }
1473       else
1474         {
1475           entries[i].key = NULL;
1476           entries[i].title = NULL;
1477           entries[i].icon = NULL;
1478           entries[i].win_surface = NULL;
1479           entries[i].blank = TRUE;
1480         }
1481       entries[i].hidden = FALSE;
1482       entries[i].demands_attention = FALSE;
1483 
1484       ++i;
1485     }
1486 
1487   screen->tab_popup = meta_ui_tab_popup_new (entries,
1488                                              len,
1489                                              layout.cols,
1490                                              FALSE, /* expand_for_titles */
1491                                              BORDER_OUTLINE_WORKSPACE);
1492 
1493   g_free (entries);
1494   meta_screen_free_workspace_layout (&layout);
1495 
1496   /* don't show tab popup, since proper space isn't selected yet */
1497 }
1498 
1499 static gboolean
meta_screen_tile_preview_update_timeout(gpointer data)1500 meta_screen_tile_preview_update_timeout (gpointer data)
1501 {
1502   MetaScreen *screen = data;
1503   MetaWindow *window = screen->display->grab_window;
1504   gboolean needs_preview = FALSE;
1505 
1506   screen->tile_preview_timeout_id = 0;
1507 
1508   if (!screen->tile_preview)
1509     screen->tile_preview = meta_tile_preview_new ();
1510 
1511   if (window)
1512     {
1513       switch (window->tile_mode)
1514         {
1515         case META_TILE_MAXIMIZED:
1516           if (!META_WINDOW_MAXIMIZED (window))
1517             needs_preview = TRUE;
1518           break;
1519 
1520         case META_TILE_NONE:
1521           needs_preview = FALSE;
1522           break;
1523 
1524         default:
1525           if (!META_WINDOW_SIDE_TILED (window))
1526             needs_preview = TRUE;
1527           break;
1528 
1529         }
1530     }
1531 
1532   if (needs_preview)
1533     {
1534       MetaRectangle tile_rect;
1535 
1536       meta_window_get_current_tile_area (window, &tile_rect);
1537       meta_tile_preview_show (screen->tile_preview, &tile_rect, screen);
1538     }
1539   else
1540     meta_tile_preview_hide (screen->tile_preview);
1541 
1542   return FALSE;
1543 }
1544 
1545 #define TILE_PREVIEW_TIMEOUT_MS 200
1546 
1547 void
meta_screen_tile_preview_update(MetaScreen * screen,gboolean delay)1548 meta_screen_tile_preview_update (MetaScreen *screen,
1549                                  gboolean    delay)
1550 {
1551   if (delay)
1552     {
1553       if (screen->tile_preview_timeout_id > 0)
1554         return;
1555 
1556       screen->tile_preview_timeout_id =
1557         g_timeout_add (TILE_PREVIEW_TIMEOUT_MS,
1558                        meta_screen_tile_preview_update_timeout,
1559                        screen);
1560     }
1561   else
1562     {
1563       if (screen->tile_preview_timeout_id > 0)
1564         g_source_remove (screen->tile_preview_timeout_id);
1565 
1566       meta_screen_tile_preview_update_timeout ((gpointer)screen);
1567     }
1568 }
1569 
1570 void
meta_screen_tile_preview_hide(MetaScreen * screen)1571 meta_screen_tile_preview_hide (MetaScreen *screen)
1572 {
1573   if (screen->tile_preview_timeout_id > 0)
1574     g_source_remove (screen->tile_preview_timeout_id);
1575 
1576   if (screen->tile_preview)
1577     meta_tile_preview_hide (screen->tile_preview);
1578 }
1579 
1580 MetaWindow*
meta_screen_get_mouse_window(MetaScreen * screen,MetaWindow * not_this_one)1581 meta_screen_get_mouse_window (MetaScreen  *screen,
1582                               MetaWindow  *not_this_one)
1583 {
1584   MetaWindow *window;
1585   Window root_return, child_return;
1586   int root_x_return, root_y_return;
1587   int win_x_return, win_y_return;
1588   unsigned int mask_return;
1589 
1590   if (not_this_one)
1591     meta_topic (META_DEBUG_FOCUS,
1592                 "Focusing mouse window excluding %s\n", not_this_one->desc);
1593 
1594   meta_error_trap_push (screen->display);
1595   XQueryPointer (screen->display->xdisplay,
1596                  screen->xroot,
1597                  &root_return,
1598                  &child_return,
1599                  &root_x_return,
1600                  &root_y_return,
1601                  &win_x_return,
1602                  &win_y_return,
1603                  &mask_return);
1604   meta_error_trap_pop (screen->display, TRUE);
1605 
1606   window = meta_stack_get_default_focus_window_at_point (screen->stack,
1607                                                          screen->active_workspace,
1608                                                          not_this_one,
1609                                                          root_x_return,
1610                                                          root_y_return);
1611 
1612   return window;
1613 }
1614 
1615 const MetaXineramaScreenInfo*
meta_screen_get_xinerama_for_rect(MetaScreen * screen,MetaRectangle * rect)1616 meta_screen_get_xinerama_for_rect (MetaScreen    *screen,
1617 				   MetaRectangle *rect)
1618 {
1619   int i;
1620   int best_xinerama, xinerama_score;
1621 
1622   if (screen->n_xinerama_infos == 1)
1623     return &screen->xinerama_infos[0];
1624 
1625   best_xinerama = 0;
1626   xinerama_score = 0;
1627 
1628   for (i = 0; i < screen->n_xinerama_infos; i++)
1629     {
1630       MetaRectangle dest;
1631       if (meta_rectangle_intersect (&screen->xinerama_infos[i].rect,
1632                                     rect,
1633                                     &dest))
1634         {
1635           int cur = meta_rectangle_area (&dest);
1636           if (cur > xinerama_score)
1637             {
1638               xinerama_score = cur;
1639               best_xinerama = i;
1640             }
1641         }
1642     }
1643 
1644   return &screen->xinerama_infos[best_xinerama];
1645 }
1646 
1647 const MetaXineramaScreenInfo*
meta_screen_get_xinerama_for_window(MetaScreen * screen,MetaWindow * window)1648 meta_screen_get_xinerama_for_window (MetaScreen *screen,
1649 				     MetaWindow *window)
1650 {
1651   MetaRectangle window_rect;
1652 
1653   meta_window_get_outer_rect (window, &window_rect);
1654 
1655   return meta_screen_get_xinerama_for_rect (screen, &window_rect);
1656 }
1657 
1658 const MetaXineramaScreenInfo*
meta_screen_get_xinerama_neighbor(MetaScreen * screen,int which_xinerama,MetaScreenDirection direction)1659 meta_screen_get_xinerama_neighbor (MetaScreen         *screen,
1660                                    int                 which_xinerama,
1661                                    MetaScreenDirection direction)
1662 {
1663   MetaXineramaScreenInfo* input = screen->xinerama_infos + which_xinerama;
1664   MetaXineramaScreenInfo* current;
1665   int i;
1666 
1667   for (i = 0; i < screen->n_xinerama_infos; i++)
1668     {
1669       current = screen->xinerama_infos + i;
1670 
1671       if ((direction == META_SCREEN_RIGHT &&
1672            current->rect.x == input->rect.x + input->rect.width &&
1673            meta_rectangle_vert_overlap(&current->rect, &input->rect)) ||
1674           (direction == META_SCREEN_LEFT &&
1675            input->rect.x == current->rect.x + current->rect.width &&
1676            meta_rectangle_vert_overlap(&current->rect, &input->rect)) ||
1677           (direction == META_SCREEN_UP &&
1678            input->rect.y == current->rect.y + current->rect.height &&
1679            meta_rectangle_horiz_overlap(&current->rect, &input->rect)) ||
1680           (direction == META_SCREEN_DOWN &&
1681            current->rect.y == input->rect.y + input->rect.height &&
1682            meta_rectangle_horiz_overlap(&current->rect, &input->rect)))
1683         {
1684           return current;
1685         }
1686     }
1687 
1688   return NULL;
1689 }
1690 
1691 void
meta_screen_get_natural_xinerama_list(MetaScreen * screen,int ** xineramas_list,int * n_xineramas)1692 meta_screen_get_natural_xinerama_list (MetaScreen *screen,
1693                                        int**       xineramas_list,
1694                                        int*        n_xineramas)
1695 {
1696   const MetaXineramaScreenInfo* current;
1697   const MetaXineramaScreenInfo* tmp;
1698   GQueue* xinerama_queue;
1699   int* visited;
1700   int cur = 0;
1701   int i;
1702 
1703   *n_xineramas = screen->n_xinerama_infos;
1704   *xineramas_list = g_new (int, screen->n_xinerama_infos);
1705 
1706   /* we calculate a natural ordering by which to choose xineramas for
1707    * window placement.  We start at the current xinerama, and perform
1708    * a breadth-first search of the xineramas starting from that
1709    * xinerama.  We choose preferentially left, then right, then down,
1710    * then up.  The visitation order produced by this traversal is the
1711    * natural xinerama ordering.
1712    */
1713 
1714   visited = g_new (int, screen->n_xinerama_infos);
1715   for (i = 0; i < screen->n_xinerama_infos; i++)
1716     {
1717       visited[i] = FALSE;
1718     }
1719 
1720   current = meta_screen_get_current_xinerama (screen);
1721   xinerama_queue = g_queue_new ();
1722   g_queue_push_tail (xinerama_queue, (gpointer) current);
1723   visited[current->number] = TRUE;
1724 
1725   while (!g_queue_is_empty (xinerama_queue))
1726     {
1727       current = (const MetaXineramaScreenInfo*)
1728         g_queue_pop_head (xinerama_queue);
1729 
1730       (*xineramas_list)[cur++] = current->number;
1731 
1732       /* enqueue each of the directions */
1733       tmp = meta_screen_get_xinerama_neighbor (screen,
1734                                                current->number,
1735                                                META_SCREEN_LEFT);
1736       if (tmp && !visited[tmp->number])
1737         {
1738           g_queue_push_tail (xinerama_queue,
1739                              (MetaXineramaScreenInfo*) tmp);
1740           visited[tmp->number] = TRUE;
1741         }
1742       tmp = meta_screen_get_xinerama_neighbor (screen,
1743                                                current->number,
1744                                                META_SCREEN_RIGHT);
1745       if (tmp && !visited[tmp->number])
1746         {
1747           g_queue_push_tail (xinerama_queue,
1748                              (MetaXineramaScreenInfo*) tmp);
1749           visited[tmp->number] = TRUE;
1750         }
1751       tmp = meta_screen_get_xinerama_neighbor (screen,
1752                                                current->number,
1753                                                META_SCREEN_UP);
1754       if (tmp && !visited[tmp->number])
1755         {
1756           g_queue_push_tail (xinerama_queue,
1757                              (MetaXineramaScreenInfo*) tmp);
1758           visited[tmp->number] = TRUE;
1759         }
1760       tmp = meta_screen_get_xinerama_neighbor (screen,
1761                                                current->number,
1762                                                META_SCREEN_DOWN);
1763       if (tmp && !visited[tmp->number])
1764         {
1765           g_queue_push_tail (xinerama_queue,
1766                              (MetaXineramaScreenInfo*) tmp);
1767           visited[tmp->number] = TRUE;
1768         }
1769     }
1770 
1771   /* in case we somehow missed some set of xineramas, go through the
1772    * visited list and add in any xineramas that were missed
1773    */
1774   for (i = 0; i < screen->n_xinerama_infos; i++)
1775     {
1776       if (visited[i] == FALSE)
1777         {
1778           (*xineramas_list)[cur++] = i;
1779         }
1780     }
1781 
1782   g_free (visited);
1783   g_queue_free (xinerama_queue);
1784 }
1785 
1786 const MetaXineramaScreenInfo*
meta_screen_get_current_xinerama(MetaScreen * screen)1787 meta_screen_get_current_xinerama (MetaScreen *screen)
1788 {
1789   if (screen->n_xinerama_infos == 1)
1790     return &screen->xinerama_infos[0];
1791 
1792   /* Sadly, we have to do it this way. Yuck.
1793    */
1794 
1795   if (screen->display->xinerama_cache_invalidated)
1796     {
1797       Window root_return, child_return;
1798       int win_x_return, win_y_return;
1799       unsigned int mask_return;
1800       int i;
1801       MetaRectangle pointer_position;
1802 
1803       screen->display->xinerama_cache_invalidated = FALSE;
1804 
1805       pointer_position.width = pointer_position.height = 1;
1806       XQueryPointer (screen->display->xdisplay,
1807                      screen->xroot,
1808                      &root_return,
1809                      &child_return,
1810                      &pointer_position.x,
1811                      &pointer_position.y,
1812                      &win_x_return,
1813                      &win_y_return,
1814                      &mask_return);
1815 
1816       screen->last_xinerama_index = 0;
1817       for (i = 0; i < screen->n_xinerama_infos; i++)
1818         {
1819           if (meta_rectangle_contains_rect (&screen->xinerama_infos[i].rect,
1820                                             &pointer_position))
1821             {
1822               screen->last_xinerama_index = i;
1823               break;
1824             }
1825         }
1826 
1827       meta_topic (META_DEBUG_XINERAMA,
1828                   "Rechecked current Xinerama, now %d\n",
1829                   screen->last_xinerama_index);
1830     }
1831 
1832   return &screen->xinerama_infos[screen->last_xinerama_index];
1833 }
1834 
1835 #define _NET_WM_ORIENTATION_HORZ 0
1836 #define _NET_WM_ORIENTATION_VERT 1
1837 
1838 #define _NET_WM_TOPLEFT     0
1839 #define _NET_WM_TOPRIGHT    1
1840 #define _NET_WM_BOTTOMRIGHT 2
1841 #define _NET_WM_BOTTOMLEFT  3
1842 
1843 void
meta_screen_update_workspace_layout(MetaScreen * screen)1844 meta_screen_update_workspace_layout (MetaScreen *screen)
1845 {
1846   gulong *list;
1847   int n_items;
1848 
1849   list = NULL;
1850   n_items = 0;
1851 
1852   if (meta_prop_get_cardinal_list (screen->display,
1853                                    screen->xroot,
1854                                    screen->display->atom__NET_DESKTOP_LAYOUT,
1855                                    &list, &n_items))
1856     {
1857       if (n_items == 3 || n_items == 4)
1858         {
1859           int cols, rows;
1860 
1861           switch (list[0])
1862             {
1863             case _NET_WM_ORIENTATION_HORZ:
1864               screen->vertical_workspaces = FALSE;
1865               break;
1866             case _NET_WM_ORIENTATION_VERT:
1867               screen->vertical_workspaces = TRUE;
1868               break;
1869             default:
1870               meta_warning ("Someone set a weird orientation in _NET_DESKTOP_LAYOUT\n");
1871               break;
1872             }
1873 
1874           cols = list[1];
1875           rows = list[2];
1876 
1877           if (rows <= 0 && cols <= 0)
1878             {
1879               meta_warning ("Columns = %d rows = %d in _NET_DESKTOP_LAYOUT makes no sense\n", rows, cols);
1880             }
1881           else
1882             {
1883               if (rows > 0)
1884                 screen->rows_of_workspaces = rows;
1885               else
1886                 screen->rows_of_workspaces = -1;
1887 
1888               if (cols > 0)
1889                 screen->columns_of_workspaces = cols;
1890               else
1891                 screen->columns_of_workspaces = -1;
1892             }
1893 
1894           if (n_items == 4)
1895             {
1896               switch (list[3])
1897                 {
1898                   case _NET_WM_TOPLEFT:
1899                     screen->starting_corner = META_SCREEN_TOPLEFT;
1900                     break;
1901                   case _NET_WM_TOPRIGHT:
1902                     screen->starting_corner = META_SCREEN_TOPRIGHT;
1903                     break;
1904                   case _NET_WM_BOTTOMRIGHT:
1905                     screen->starting_corner = META_SCREEN_BOTTOMRIGHT;
1906                     break;
1907                   case _NET_WM_BOTTOMLEFT:
1908                     screen->starting_corner = META_SCREEN_BOTTOMLEFT;
1909                     break;
1910                   default:
1911                     meta_warning ("Someone set a weird starting corner in _NET_DESKTOP_LAYOUT\n");
1912                     break;
1913                 }
1914             }
1915           else
1916             screen->starting_corner = META_SCREEN_TOPLEFT;
1917         }
1918       else
1919         {
1920           meta_warning ("Someone set _NET_DESKTOP_LAYOUT to %d integers instead of 4 "
1921                         "(3 is accepted for backwards compat)\n", n_items);
1922         }
1923 
1924       meta_XFree (list);
1925     }
1926 
1927   meta_verbose ("Workspace layout rows = %d cols = %d orientation = %d starting corner = %u\n",
1928                 screen->rows_of_workspaces,
1929                 screen->columns_of_workspaces,
1930                 screen->vertical_workspaces,
1931                 screen->starting_corner);
1932 }
1933 
1934 static void
set_workspace_names(MetaScreen * screen)1935 set_workspace_names (MetaScreen *screen)
1936 {
1937   /* This updates names on root window when the pref changes,
1938    * note we only get prefs change notify if things have
1939    * really changed.
1940    */
1941   GString *flattened;
1942   int i;
1943   int n_spaces;
1944 
1945   /* flatten to nul-separated list */
1946   n_spaces = meta_screen_get_n_workspaces (screen);
1947   flattened = g_string_new ("");
1948   i = 0;
1949   while (i < n_spaces)
1950     {
1951       const char *name;
1952 
1953       name = meta_prefs_get_workspace_name (i);
1954 
1955       if (name)
1956         g_string_append_len (flattened, name,
1957                              strlen (name) + 1);
1958       else
1959         g_string_append_len (flattened, "", 1);
1960 
1961       ++i;
1962     }
1963 
1964   meta_error_trap_push (screen->display);
1965   XChangeProperty (screen->display->xdisplay,
1966                    screen->xroot,
1967                    screen->display->atom__NET_DESKTOP_NAMES,
1968 		   screen->display->atom_UTF8_STRING,
1969                    8, PropModeReplace,
1970 		   (unsigned char *)flattened->str, flattened->len);
1971   meta_error_trap_pop (screen->display, FALSE);
1972 
1973   g_string_free (flattened, TRUE);
1974 }
1975 
1976 void
meta_screen_update_workspace_names(MetaScreen * screen)1977 meta_screen_update_workspace_names (MetaScreen *screen)
1978 {
1979   char **names;
1980   int n_names;
1981   int i;
1982 
1983   /* this updates names in prefs when the root window property changes,
1984    * iff the new property contents don't match what's already in prefs
1985    */
1986 
1987   names = NULL;
1988   n_names = 0;
1989   if (!meta_prop_get_utf8_list (screen->display,
1990                                 screen->xroot,
1991                                 screen->display->atom__NET_DESKTOP_NAMES,
1992                                 &names, &n_names))
1993     {
1994       meta_verbose ("Failed to get workspace names from root window %d\n",
1995                     screen->number);
1996       return;
1997     }
1998 
1999   i = 0;
2000   while (i < n_names)
2001     {
2002       meta_topic (META_DEBUG_PREFS,
2003                   "Setting workspace %d name to \"%s\" due to _NET_DESKTOP_NAMES change\n",
2004                   i, names[i] ? names[i] : "null");
2005       meta_prefs_change_workspace_name (i, names[i]);
2006 
2007       ++i;
2008     }
2009 
2010   g_strfreev (names);
2011 }
2012 
2013 Window
meta_create_offscreen_window(Display * xdisplay,Window parent,long valuemask)2014 meta_create_offscreen_window (Display *xdisplay,
2015                               Window   parent,
2016                               long     valuemask)
2017 {
2018   XSetWindowAttributes attrs;
2019 
2020   /* we want to be override redirect because sometimes we
2021    * create a window on a screen we aren't managing.
2022    * (but on a display we are managing at least one screen for)
2023    */
2024   attrs.override_redirect = True;
2025   attrs.event_mask = valuemask;
2026 
2027   return XCreateWindow (xdisplay,
2028                         parent,
2029                         -100, -100, 1, 1,
2030                         0,
2031                         CopyFromParent,
2032                         CopyFromParent,
2033                         (Visual *)CopyFromParent,
2034                         CWOverrideRedirect | CWEventMask,
2035                         &attrs);
2036 }
2037 
2038 static void
set_workspace_work_area_hint(MetaWorkspace * workspace,MetaScreen * screen)2039 set_workspace_work_area_hint (MetaWorkspace *workspace,
2040                               MetaScreen    *screen)
2041 {
2042   unsigned long *data;
2043   unsigned long *tmp;
2044   int i;
2045   gchar *workarea_name;
2046   Atom workarea_atom;
2047 
2048   data = g_new (unsigned long, screen->n_xinerama_infos * 4);
2049   tmp = data;
2050 
2051   for (i = 0; i < screen->n_xinerama_infos; i++)
2052     {
2053       MetaRectangle area;
2054 
2055       meta_workspace_get_work_area_for_xinerama (workspace, i, &area);
2056 
2057       tmp[0] = area.x;
2058       tmp[1] = area.y;
2059       tmp[2] = area.width;
2060       tmp[3] = area.height;
2061 
2062       tmp += 4;
2063     }
2064 
2065   workarea_name = g_strdup_printf ("_GTK_WORKAREAS_D%d",
2066                                    meta_workspace_index (workspace));
2067 
2068   workarea_atom = XInternAtom (screen->display->xdisplay, workarea_name, False);
2069   g_free (workarea_name);
2070 
2071   meta_error_trap_push (screen->display);
2072   XChangeProperty (screen->display->xdisplay, screen->xroot, workarea_atom,
2073                    XA_CARDINAL, 32, PropModeReplace,
2074                    (guchar*) data, screen->n_xinerama_infos * 4);
2075   meta_error_trap_pop (screen->display, TRUE);
2076 
2077   g_free (data);
2078 }
2079 
2080 static void
set_work_area_hint(MetaScreen * screen)2081 set_work_area_hint (MetaScreen *screen)
2082 {
2083   int num_workspaces;
2084   GList *tmp_list;
2085   unsigned long *data, *tmp;
2086   MetaRectangle area;
2087 
2088   num_workspaces = meta_screen_get_n_workspaces (screen);
2089   data = g_new (unsigned long, num_workspaces * 4);
2090   tmp_list = screen->workspaces;
2091   tmp = data;
2092 
2093   while (tmp_list != NULL)
2094     {
2095       MetaWorkspace *workspace = tmp_list->data;
2096 
2097       if (workspace->screen == screen)
2098         {
2099           meta_workspace_get_work_area_all_xineramas (workspace, &area);
2100           set_workspace_work_area_hint (workspace, screen);
2101           tmp[0] = area.x;
2102           tmp[1] = area.y;
2103           tmp[2] = area.width;
2104           tmp[3] = area.height;
2105 
2106 	  tmp += 4;
2107         }
2108 
2109       tmp_list = tmp_list->next;
2110     }
2111 
2112   meta_error_trap_push (screen->display);
2113   XChangeProperty (screen->display->xdisplay, screen->xroot,
2114 		   screen->display->atom__NET_WORKAREA,
2115 		   XA_CARDINAL, 32, PropModeReplace,
2116 		   (guchar*) data, num_workspaces*4);
2117   g_free (data);
2118   meta_error_trap_pop (screen->display, FALSE);
2119 }
2120 
2121 static gboolean
set_work_area_idle_func(MetaScreen * screen)2122 set_work_area_idle_func (MetaScreen *screen)
2123 {
2124   meta_topic (META_DEBUG_WORKAREA,
2125               "Running work area idle function\n");
2126 
2127   screen->work_area_idle = 0;
2128 
2129   set_work_area_hint (screen);
2130 
2131   return FALSE;
2132 }
2133 
2134 void
meta_screen_queue_workarea_recalc(MetaScreen * screen)2135 meta_screen_queue_workarea_recalc (MetaScreen *screen)
2136 {
2137   /* Recompute work area in an idle */
2138   if (screen->work_area_idle == 0)
2139     {
2140       meta_topic (META_DEBUG_WORKAREA,
2141                   "Adding work area hint idle function\n");
2142       screen->work_area_idle =
2143         g_idle_add_full (META_PRIORITY_WORK_AREA_HINT,
2144                          (GSourceFunc) set_work_area_idle_func,
2145                          screen,
2146                          NULL);
2147     }
2148 }
2149 
2150 #ifdef WITH_VERBOSE_MODE
2151 static char *
meta_screen_corner_to_string(MetaScreenCorner corner)2152 meta_screen_corner_to_string (MetaScreenCorner corner)
2153 {
2154   switch (corner)
2155     {
2156     case META_SCREEN_TOPLEFT:
2157       return "TopLeft";
2158     case META_SCREEN_TOPRIGHT:
2159       return "TopRight";
2160     case META_SCREEN_BOTTOMLEFT:
2161       return "BottomLeft";
2162     case META_SCREEN_BOTTOMRIGHT:
2163       return "BottomRight";
2164     }
2165 
2166   return "Unknown";
2167 }
2168 #endif /* WITH_VERBOSE_MODE */
2169 
2170 void
meta_screen_calc_workspace_layout(MetaScreen * screen,int num_workspaces,int current_space,MetaWorkspaceLayout * layout)2171 meta_screen_calc_workspace_layout (MetaScreen          *screen,
2172                                    int                  num_workspaces,
2173                                    int                  current_space,
2174                                    MetaWorkspaceLayout *layout)
2175 {
2176   int rows, cols;
2177   int grid_area;
2178   int *grid;
2179   int i, r, c;
2180   int current_row, current_col;
2181 
2182   rows = screen->rows_of_workspaces;
2183   cols = screen->columns_of_workspaces;
2184   if (rows <= 0 && cols <= 0)
2185     cols = num_workspaces;
2186 
2187   if (rows <= 0)
2188     rows = num_workspaces / cols + ((num_workspaces % cols) > 0 ? 1 : 0);
2189   if (cols <= 0)
2190     cols = num_workspaces / rows + ((num_workspaces % rows) > 0 ? 1 : 0);
2191 
2192   /* paranoia */
2193   if (rows < 1)
2194     rows = 1;
2195   if (cols < 1)
2196     cols = 1;
2197 
2198   g_assert (rows != 0 && cols != 0);
2199 
2200   grid_area = rows * cols;
2201 
2202   meta_verbose ("Getting layout rows = %d cols = %d current = %d "
2203                 "num_spaces = %d vertical = %s corner = %s\n",
2204                 rows, cols, current_space, num_workspaces,
2205                 screen->vertical_workspaces ? "(true)" : "(false)",
2206                 meta_screen_corner_to_string (screen->starting_corner));
2207 
2208   /* ok, we want to setup the distances in the workspace array to go
2209    * in each direction. Remember, there are many ways that a workspace
2210    * array can be setup.
2211    * see http://www.freedesktop.org/standards/wm-spec/1.2/html/x109.html
2212    * and look at the _NET_DESKTOP_LAYOUT section for details.
2213    * For instance:
2214    */
2215   /* starting_corner = META_SCREEN_TOPLEFT
2216    *  vertical_workspaces = 0                 vertical_workspaces=1
2217    *       1234                                    1357
2218    *       5678                                    2468
2219    *
2220    * starting_corner = META_SCREEN_TOPRIGHT
2221    *  vertical_workspaces = 0                 vertical_workspaces=1
2222    *       4321                                    7531
2223    *       8765                                    8642
2224    *
2225    * starting_corner = META_SCREEN_BOTTOMLEFT
2226    *  vertical_workspaces = 0                 vertical_workspaces=1
2227    *       5678                                    2468
2228    *       1234                                    1357
2229    *
2230    * starting_corner = META_SCREEN_BOTTOMRIGHT
2231    *  vertical_workspaces = 0                 vertical_workspaces=1
2232    *       8765                                    8642
2233    *       4321                                    7531
2234    *
2235    */
2236   /* keep in mind that we could have a ragged layout, e.g. the "8"
2237    * in the above grids could be missing
2238    */
2239 
2240   grid = g_new (int, grid_area);
2241 
2242   i = 0;
2243   switch (screen->starting_corner)
2244     {
2245     case META_SCREEN_TOPLEFT:
2246       if (screen->vertical_workspaces)
2247         {
2248           c = 0;
2249           while (c < cols)
2250             {
2251               r = 0;
2252               while (r < rows)
2253                 {
2254                   grid[r*cols+c] = i;
2255                   ++i;
2256                   ++r;
2257                 }
2258               ++c;
2259             }
2260         }
2261       else
2262         {
2263           r = 0;
2264           while (r < rows)
2265             {
2266               c = 0;
2267               while (c < cols)
2268                 {
2269                   grid[r*cols+c] = i;
2270                   ++i;
2271                   ++c;
2272                 }
2273               ++r;
2274             }
2275         }
2276       break;
2277     case META_SCREEN_TOPRIGHT:
2278       if (screen->vertical_workspaces)
2279         {
2280           c = cols - 1;
2281           while (c >= 0)
2282             {
2283               r = 0;
2284               while (r < rows)
2285                 {
2286                   grid[r*cols+c] = i;
2287                   ++i;
2288                   ++r;
2289                 }
2290               --c;
2291             }
2292         }
2293       else
2294         {
2295           r = 0;
2296           while (r < rows)
2297             {
2298               c = cols - 1;
2299               while (c >= 0)
2300                 {
2301                   grid[r*cols+c] = i;
2302                   ++i;
2303                   --c;
2304                 }
2305               ++r;
2306             }
2307         }
2308       break;
2309     case META_SCREEN_BOTTOMLEFT:
2310       if (screen->vertical_workspaces)
2311         {
2312           c = 0;
2313           while (c < cols)
2314             {
2315               r = rows - 1;
2316               while (r >= 0)
2317                 {
2318                   grid[r*cols+c] = i;
2319                   ++i;
2320                   --r;
2321                 }
2322               ++c;
2323             }
2324         }
2325       else
2326         {
2327           r = rows - 1;
2328           while (r >= 0)
2329             {
2330               c = 0;
2331               while (c < cols)
2332                 {
2333                   grid[r*cols+c] = i;
2334                   ++i;
2335                   ++c;
2336                 }
2337               --r;
2338             }
2339         }
2340       break;
2341     case META_SCREEN_BOTTOMRIGHT:
2342       if (screen->vertical_workspaces)
2343         {
2344           c = cols - 1;
2345           while (c >= 0)
2346             {
2347               r = rows - 1;
2348               while (r >= 0)
2349                 {
2350                   grid[r*cols+c] = i;
2351                   ++i;
2352                   --r;
2353                 }
2354               --c;
2355             }
2356         }
2357       else
2358         {
2359           r = rows - 1;
2360           while (r >= 0)
2361             {
2362               c = cols - 1;
2363               while (c >= 0)
2364                 {
2365                   grid[r*cols+c] = i;
2366                   ++i;
2367                   --c;
2368                 }
2369               --r;
2370             }
2371         }
2372       break;
2373     }
2374 
2375   if (i != grid_area)
2376     meta_bug ("did not fill in the whole workspace grid in %s (%d filled)\n",
2377               G_STRFUNC, i);
2378 
2379   current_row = 0;
2380   current_col = 0;
2381   r = 0;
2382   while (r < rows)
2383     {
2384       c = 0;
2385       while (c < cols)
2386         {
2387           if (grid[r*cols+c] == current_space)
2388             {
2389               current_row = r;
2390               current_col = c;
2391             }
2392           else if (grid[r*cols+c] >= num_workspaces)
2393             {
2394               /* flag nonexistent spaces with -1 */
2395               grid[r*cols+c] = -1;
2396             }
2397           ++c;
2398         }
2399       ++r;
2400     }
2401 
2402   layout->rows = rows;
2403   layout->cols = cols;
2404   layout->grid = grid;
2405   layout->grid_area = grid_area;
2406   layout->current_row = current_row;
2407   layout->current_col = current_col;
2408 
2409 #ifdef WITH_VERBOSE_MODE
2410   if (meta_is_verbose ())
2411     {
2412       r = 0;
2413       while (r < layout->rows)
2414         {
2415           meta_verbose (" ");
2416           meta_push_no_msg_prefix ();
2417           c = 0;
2418           while (c < layout->cols)
2419             {
2420               if (r == layout->current_row &&
2421                   c == layout->current_col)
2422                 meta_verbose ("*%2d ", layout->grid[r*layout->cols+c]);
2423               else
2424                 meta_verbose ("%3d ", layout->grid[r*layout->cols+c]);
2425               ++c;
2426             }
2427           meta_verbose ("\n");
2428           meta_pop_no_msg_prefix ();
2429           ++r;
2430         }
2431     }
2432 #endif /* WITH_VERBOSE_MODE */
2433 }
2434 
2435 void
meta_screen_free_workspace_layout(MetaWorkspaceLayout * layout)2436 meta_screen_free_workspace_layout (MetaWorkspaceLayout *layout)
2437 {
2438   g_free (layout->grid);
2439 }
2440 
2441 static void
meta_screen_resize_func(MetaScreen * screen,MetaWindow * window,void * user_data)2442 meta_screen_resize_func (MetaScreen *screen,
2443                          MetaWindow *window,
2444                          void       *user_data)
2445 {
2446   if (window->struts)
2447     {
2448       meta_window_update_struts (window);
2449     }
2450   meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
2451 
2452   meta_window_recalc_features (window);
2453 }
2454 
2455 void
meta_screen_resize(MetaScreen * screen,int width,int height)2456 meta_screen_resize (MetaScreen *screen,
2457                     int         width,
2458                     int         height)
2459 {
2460   screen->rect.width = width;
2461   screen->rect.height = height;
2462 
2463   reload_xinerama_infos (screen);
2464   set_desktop_geometry_hint (screen);
2465 
2466   /* Queue a resize on all the windows */
2467   meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
2468 }
2469 
2470 void
meta_screen_update_showing_desktop_hint(MetaScreen * screen)2471 meta_screen_update_showing_desktop_hint (MetaScreen *screen)
2472 {
2473   unsigned long data[1];
2474 
2475   data[0] = screen->active_workspace->showing_desktop ? 1 : 0;
2476 
2477   meta_error_trap_push (screen->display);
2478   XChangeProperty (screen->display->xdisplay, screen->xroot,
2479                    screen->display->atom__NET_SHOWING_DESKTOP,
2480                    XA_CARDINAL,
2481                    32, PropModeReplace, (guchar*) data, 1);
2482   meta_error_trap_pop (screen->display, FALSE);
2483 }
2484 
2485 static void
queue_windows_showing(MetaScreen * screen)2486 queue_windows_showing (MetaScreen *screen)
2487 {
2488   GSList *windows;
2489   GSList *tmp;
2490 
2491   /* Must operate on all windows on display instead of just on the
2492    * active_workspace's window list, because the active_workspace's
2493    * window list may not contain the on_all_workspace windows.
2494    */
2495   windows = meta_display_list_windows (screen->display);
2496 
2497   tmp = windows;
2498   while (tmp != NULL)
2499     {
2500       MetaWindow *w = tmp->data;
2501 
2502       if (w->screen == screen && !meta_prefs_is_in_skip_list (w->res_class))
2503         meta_window_queue (w, META_QUEUE_CALC_SHOWING);
2504 
2505       tmp = tmp->next;
2506     }
2507 
2508   g_slist_free (windows);
2509 }
2510 
2511 void
meta_screen_minimize_all_on_active_workspace_except(MetaScreen * screen,MetaWindow * keep)2512 meta_screen_minimize_all_on_active_workspace_except (MetaScreen *screen,
2513                                                      MetaWindow *keep)
2514 {
2515   GList *windows;
2516   GList *tmp;
2517 
2518   windows = screen->active_workspace->windows;
2519 
2520   tmp = windows;
2521   while (tmp != NULL)
2522     {
2523       MetaWindow *w = tmp->data;
2524 
2525       if (w->screen == screen  &&
2526           w->has_minimize_func &&
2527 	  w != keep)
2528 	meta_window_minimize (w);
2529 
2530       tmp = tmp->next;
2531     }
2532 }
2533 
2534 void
meta_screen_show_desktop(MetaScreen * screen,guint32 timestamp)2535 meta_screen_show_desktop (MetaScreen *screen,
2536                           guint32     timestamp)
2537 {
2538   GList *windows;
2539 
2540   if (screen->active_workspace->showing_desktop)
2541     return;
2542 
2543   screen->active_workspace->showing_desktop = TRUE;
2544 
2545   queue_windows_showing (screen);
2546 
2547   /* Focus the most recently used META_WINDOW_DESKTOP window, if there is one;
2548    * see bug 159257.
2549    */
2550   windows = screen->active_workspace->mru_list;
2551   while (windows != NULL)
2552     {
2553       MetaWindow *w = windows->data;
2554 
2555       if (w->screen == screen  &&
2556           w->type == META_WINDOW_DESKTOP &&
2557           !meta_prefs_is_in_skip_list (w->res_class))
2558         {
2559           meta_window_focus (w, timestamp);
2560           break;
2561         }
2562 
2563       windows = windows->next;
2564     }
2565 
2566   meta_screen_update_showing_desktop_hint (screen);
2567 }
2568 
2569 void
meta_screen_unshow_desktop(MetaScreen * screen)2570 meta_screen_unshow_desktop (MetaScreen *screen)
2571 {
2572   if (!screen->active_workspace->showing_desktop)
2573     return;
2574 
2575   screen->active_workspace->showing_desktop = FALSE;
2576 
2577   queue_windows_showing (screen);
2578 
2579   meta_screen_update_showing_desktop_hint (screen);
2580 }
2581 
2582 #ifdef HAVE_STARTUP_NOTIFICATION
2583 static gboolean startup_sequence_timeout (void *data);
2584 
2585 static void
update_startup_feedback(MetaScreen * screen)2586 update_startup_feedback (MetaScreen *screen)
2587 {
2588   if (screen->startup_sequences != NULL)
2589     {
2590       meta_topic (META_DEBUG_STARTUP,
2591                   "Setting busy cursor\n");
2592       meta_screen_set_cursor (screen, META_CURSOR_BUSY);
2593     }
2594   else
2595     {
2596       meta_topic (META_DEBUG_STARTUP,
2597                   "Setting default cursor\n");
2598       meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
2599     }
2600 }
2601 
2602 static void
add_sequence(MetaScreen * screen,SnStartupSequence * sequence)2603 add_sequence (MetaScreen        *screen,
2604               SnStartupSequence *sequence)
2605 {
2606   meta_topic (META_DEBUG_STARTUP,
2607               "Adding sequence %s\n",
2608               sn_startup_sequence_get_id (sequence));
2609   sn_startup_sequence_ref (sequence);
2610   screen->startup_sequences = g_slist_prepend (screen->startup_sequences,
2611                                                sequence);
2612 
2613   /* our timeout just polls every second, instead of bothering
2614    * to compute exactly when we may next time out
2615    */
2616   if (screen->startup_sequence_timeout == 0)
2617     screen->startup_sequence_timeout = g_timeout_add (1000,
2618                                                       startup_sequence_timeout,
2619                                                       screen);
2620 
2621   update_startup_feedback (screen);
2622 }
2623 
2624 static void
remove_sequence(MetaScreen * screen,SnStartupSequence * sequence)2625 remove_sequence (MetaScreen        *screen,
2626                  SnStartupSequence *sequence)
2627 {
2628   meta_topic (META_DEBUG_STARTUP,
2629               "Removing sequence %s\n",
2630               sn_startup_sequence_get_id (sequence));
2631 
2632   screen->startup_sequences = g_slist_remove (screen->startup_sequences,
2633                                               sequence);
2634   sn_startup_sequence_unref (sequence);
2635 
2636   if (screen->startup_sequences == NULL &&
2637       screen->startup_sequence_timeout != 0)
2638     {
2639       g_source_remove (screen->startup_sequence_timeout);
2640       screen->startup_sequence_timeout = 0;
2641     }
2642 
2643   update_startup_feedback (screen);
2644 }
2645 
2646 typedef struct
2647 {
2648   GSList *list;
2649   gint64 now;
2650 } CollectTimedOutData;
2651 
2652 /* This should be fairly long, as it should never be required unless
2653  * apps or .desktop files are buggy, and it's confusing if
2654  * OpenOffice or whatever seems to stop launching - people
2655  * might decide they need to launch it again.
2656  */
2657 #define STARTUP_TIMEOUT 15000
2658 
2659 static void
collect_timed_out_foreach(void * element,void * data)2660 collect_timed_out_foreach (void *element,
2661                            void *data)
2662 {
2663   CollectTimedOutData *ctod = data;
2664   SnStartupSequence *sequence = element;
2665   double elapsed;
2666 
2667   time_t tv_sec;
2668   suseconds_t  tv_usec;
2669   gint64 tv;
2670 
2671   sn_startup_sequence_get_last_active_time (sequence, &tv_sec, &tv_usec);
2672   tv = (tv_sec * G_USEC_PER_SEC) + tv_usec;
2673   elapsed = (ctod->now - tv) / 1000.0;
2674 
2675   meta_topic (META_DEBUG_STARTUP,
2676               "Sequence used %g seconds vs. %g max: %s\n",
2677               elapsed, (double) STARTUP_TIMEOUT,
2678               sn_startup_sequence_get_id (sequence));
2679 
2680   if (elapsed > STARTUP_TIMEOUT)
2681     ctod->list = g_slist_prepend (ctod->list, sequence);
2682 }
2683 
2684 static gboolean
startup_sequence_timeout(void * data)2685 startup_sequence_timeout (void *data)
2686 {
2687   MetaScreen *screen = data;
2688   CollectTimedOutData ctod;
2689   GSList *tmp;
2690 
2691   ctod.list = NULL;
2692 
2693   ctod.now = g_get_real_time ();
2694   g_slist_foreach (screen->startup_sequences,
2695                    collect_timed_out_foreach,
2696                    &ctod);
2697 
2698   tmp = ctod.list;
2699   while (tmp != NULL)
2700     {
2701       SnStartupSequence *sequence = tmp->data;
2702 
2703       meta_topic (META_DEBUG_STARTUP,
2704                   "Timed out sequence %s\n",
2705                   sn_startup_sequence_get_id (sequence));
2706 
2707       sn_startup_sequence_complete (sequence);
2708 
2709       tmp = tmp->next;
2710     }
2711 
2712   g_slist_free (ctod.list);
2713 
2714   if (screen->startup_sequences != NULL)
2715     {
2716       return TRUE;
2717     }
2718   else
2719     {
2720       /* remove */
2721       screen->startup_sequence_timeout = 0;
2722       return FALSE;
2723     }
2724 }
2725 
2726 static void
meta_screen_sn_event(SnMonitorEvent * event,void * user_data)2727 meta_screen_sn_event (SnMonitorEvent *event,
2728                       void           *user_data)
2729 {
2730   MetaScreen *screen;
2731   SnStartupSequence *sequence;
2732 
2733   screen = user_data;
2734 
2735   sequence = sn_monitor_event_get_startup_sequence (event);
2736 
2737   switch (sn_monitor_event_get_type (event))
2738     {
2739     case SN_MONITOR_EVENT_INITIATED:
2740       {
2741         const char *wmclass;
2742 
2743         wmclass = sn_startup_sequence_get_wmclass (sequence);
2744 
2745         meta_topic (META_DEBUG_STARTUP,
2746                     "Received startup initiated for %s wmclass %s\n",
2747                     sn_startup_sequence_get_id (sequence),
2748                     wmclass ? wmclass : "(unset)");
2749         add_sequence (screen, sequence);
2750       }
2751       break;
2752 
2753     case SN_MONITOR_EVENT_COMPLETED:
2754       {
2755         meta_topic (META_DEBUG_STARTUP,
2756                     "Received startup completed for %s\n",
2757                     sn_startup_sequence_get_id (sequence));
2758         remove_sequence (screen,
2759                          sn_monitor_event_get_startup_sequence (event));
2760       }
2761       break;
2762 
2763     case SN_MONITOR_EVENT_CHANGED:
2764       meta_topic (META_DEBUG_STARTUP,
2765                   "Received startup changed for %s\n",
2766                   sn_startup_sequence_get_id (sequence));
2767       break;
2768 
2769     case SN_MONITOR_EVENT_CANCELED:
2770       meta_topic (META_DEBUG_STARTUP,
2771                   "Received startup canceled for %s\n",
2772                   sn_startup_sequence_get_id (sequence));
2773       break;
2774     }
2775 }
2776 #endif
2777 
2778 /* Sets the initial_timestamp and initial_workspace properties
2779  * of a window according to information given us by the
2780  * startup-notification library.
2781  *
2782  * Returns TRUE if startup properties have been applied, and
2783  * FALSE if they have not (for example, if they had already
2784  * been applied.)
2785  */
2786 gboolean
meta_screen_apply_startup_properties(MetaScreen * screen,MetaWindow * window)2787 meta_screen_apply_startup_properties (MetaScreen *screen,
2788                                       MetaWindow *window)
2789 {
2790 #ifdef HAVE_STARTUP_NOTIFICATION
2791   const char *startup_id;
2792   GSList *tmp;
2793   SnStartupSequence *sequence;
2794 
2795   /* Does the window have a startup ID stored? */
2796   startup_id = meta_window_get_startup_id (window);
2797 
2798   meta_topic (META_DEBUG_STARTUP,
2799               "Applying startup props to %s id \"%s\"\n",
2800               window->desc,
2801               startup_id ? startup_id : "(none)");
2802 
2803   sequence = NULL;
2804   if (startup_id == NULL)
2805     {
2806       /* No startup ID stored for the window. Let's ask the
2807        * startup-notification library whether there's anything
2808        * stored for the resource name or resource class hints.
2809        */
2810       tmp = screen->startup_sequences;
2811       while (tmp != NULL)
2812         {
2813           const char *wmclass;
2814 
2815           wmclass = sn_startup_sequence_get_wmclass (tmp->data);
2816 
2817           if (wmclass != NULL &&
2818               ((window->res_class &&
2819                 strcmp (wmclass, window->res_class) == 0) ||
2820                (window->res_name &&
2821                 strcmp (wmclass, window->res_name) == 0)))
2822             {
2823               sequence = tmp->data;
2824 
2825               g_assert (window->startup_id == NULL);
2826               window->startup_id = g_strdup (sn_startup_sequence_get_id (sequence));
2827               startup_id = window->startup_id;
2828 
2829               meta_topic (META_DEBUG_STARTUP,
2830                           "Ending legacy sequence %s due to window %s\n",
2831                           sn_startup_sequence_get_id (sequence),
2832                           window->desc);
2833 
2834               sn_startup_sequence_complete (sequence);
2835               break;
2836             }
2837 
2838           tmp = tmp->next;
2839         }
2840     }
2841 
2842   /* Still no startup ID? Bail. */
2843   if (startup_id == NULL)
2844     return FALSE;
2845 
2846   /* We might get this far and not know the sequence ID (if the window
2847    * already had a startup ID stored), so let's look for one if we don't
2848    * already know it.
2849    */
2850   if (sequence == NULL)
2851     {
2852       tmp = screen->startup_sequences;
2853       while (tmp != NULL)
2854         {
2855           const char *id;
2856 
2857           id = sn_startup_sequence_get_id (tmp->data);
2858 
2859           if (strcmp (id, startup_id) == 0)
2860             {
2861               sequence = tmp->data;
2862               break;
2863             }
2864 
2865           tmp = tmp->next;
2866         }
2867     }
2868 
2869   if (sequence != NULL)
2870     {
2871       gboolean changed_something = FALSE;
2872 
2873       meta_topic (META_DEBUG_STARTUP,
2874                   "Found startup sequence for window %s ID \"%s\"\n",
2875                   window->desc, startup_id);
2876 
2877       if (!window->initial_workspace_set)
2878         {
2879           int space = sn_startup_sequence_get_workspace (sequence);
2880           if (space >= 0)
2881             {
2882               meta_topic (META_DEBUG_STARTUP,
2883                           "Setting initial window workspace to %d based on startup info\n",
2884                           space);
2885 
2886               window->initial_workspace_set = TRUE;
2887               window->initial_workspace = space;
2888               changed_something = TRUE;
2889             }
2890         }
2891 
2892       if (!window->initial_timestamp_set)
2893         {
2894           guint32 timestamp = sn_startup_sequence_get_timestamp (sequence);
2895           meta_topic (META_DEBUG_STARTUP,
2896                       "Setting initial window timestamp to %u based on startup info\n",
2897                       timestamp);
2898 
2899           window->initial_timestamp_set = TRUE;
2900           window->initial_timestamp = timestamp;
2901           changed_something = TRUE;
2902         }
2903 
2904       return changed_something;
2905     }
2906   else
2907     {
2908       meta_topic (META_DEBUG_STARTUP,
2909                   "Did not find startup sequence for window %s ID \"%s\"\n",
2910                   window->desc, startup_id);
2911     }
2912 
2913 #endif /* HAVE_STARTUP_NOTIFICATION */
2914 
2915   return FALSE;
2916 }
2917 
2918 int
meta_screen_get_screen_number(MetaScreen * screen)2919 meta_screen_get_screen_number (MetaScreen *screen)
2920 {
2921   return screen->number;
2922 }
2923 
2924 MetaDisplay *
meta_screen_get_display(MetaScreen * screen)2925 meta_screen_get_display (MetaScreen *screen)
2926 {
2927   return screen->display;
2928 }
2929 
2930 Window
meta_screen_get_xroot(MetaScreen * screen)2931 meta_screen_get_xroot (MetaScreen *screen)
2932 {
2933   return screen->xroot;
2934 }
2935 
2936 void
meta_screen_get_size(MetaScreen * screen,int * width,int * height)2937 meta_screen_get_size (MetaScreen *screen,
2938                       int        *width,
2939                       int        *height)
2940 {
2941   *width = screen->rect.width;
2942   *height = screen->rect.height;
2943 }
2944 
2945 gpointer
meta_screen_get_compositor_data(MetaScreen * screen)2946 meta_screen_get_compositor_data (MetaScreen *screen)
2947 {
2948   return screen->compositor_data;
2949 }
2950 
2951 void
meta_screen_set_compositor_data(MetaScreen * screen,gpointer compositor)2952 meta_screen_set_compositor_data (MetaScreen *screen,
2953                                  gpointer    compositor)
2954 {
2955   screen->compositor_data = compositor;
2956 }
2957 
2958 #ifdef HAVE_COMPOSITE_EXTENSIONS
2959 void
meta_screen_set_cm_selection(MetaScreen * screen)2960 meta_screen_set_cm_selection (MetaScreen *screen)
2961 {
2962   screen->wm_cm_timestamp = meta_display_get_current_time_roundtrip (
2963                                                                screen->display);
2964 
2965   meta_verbose ("Setting selection for screen: %d\n", screen->number);
2966   XSetSelectionOwner (screen->display->xdisplay, screen->wm_cm_atom,
2967                       screen->wm_cm_selection_window, screen->wm_cm_timestamp);
2968 }
2969 
2970 void
meta_screen_unset_cm_selection(MetaScreen * screen)2971 meta_screen_unset_cm_selection (MetaScreen *screen)
2972 {
2973   XSetSelectionOwner (screen->display->xdisplay, screen->wm_cm_atom,
2974                       None, screen->wm_cm_timestamp);
2975 }
2976 
2977 gboolean
meta_screen_is_cm_selected(MetaScreen * screen)2978 meta_screen_is_cm_selected (MetaScreen *screen)
2979 {
2980   Window owner = XGetSelectionOwner (screen->display->xdisplay, screen->wm_cm_atom);
2981   return owner != None;
2982 }
2983 #endif /* HAVE_COMPOSITE_EXTENSIONS */
2984