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