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 ¤t_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(¤t->rect, &input->rect)) ||
1674 (direction == META_SCREEN_LEFT &&
1675 input->rect.x == current->rect.x + current->rect.width &&
1676 meta_rectangle_vert_overlap(¤t->rect, &input->rect)) ||
1677 (direction == META_SCREEN_UP &&
1678 input->rect.y == current->rect.y + current->rect.height &&
1679 meta_rectangle_horiz_overlap(¤t->rect, &input->rect)) ||
1680 (direction == META_SCREEN_DOWN &&
1681 current->rect.y == input->rect.y + input->rect.height &&
1682 meta_rectangle_horiz_overlap(¤t->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