1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
3
/* Metacity X screen handler */
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
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA
30
#include "screen-private.h"
33
#include "window-private.h"
34
#include "frame-private.h"
36
#include "workspace.h"
37
#include "keybindings.h"
40
#include "compositor.h"
42
#ifdef HAVE_SOLARIS_XINERAMA
43
#include <X11/extensions/xinerama.h>
45
#ifdef HAVE_XFREE_XINERAMA
46
#include <X11/extensions/Xinerama.h>
49
#include <X11/Xatom.h>
54
static char* get_screen_name (MetaDisplay *display,
57
static void update_num_workspaces (MetaScreen *screen,
59
static void update_focus_mode (MetaScreen *screen);
60
static void set_workspace_names (MetaScreen *screen);
61
static void prefs_changed_callback (MetaPreference pref,
64
static void set_desktop_geometry_hint (MetaScreen *screen);
65
static void set_desktop_viewport_hint (MetaScreen *screen);
67
#ifdef HAVE_STARTUP_NOTIFICATION
68
static void meta_screen_sn_event (SnMonitorEvent *event,
73
set_wm_check_hint (MetaScreen *screen)
75
unsigned long data[1];
77
g_return_val_if_fail (screen->display->leader_window != None, 0);
79
data[0] = screen->display->leader_window;
81
XChangeProperty (screen->display->xdisplay, screen->xroot,
82
screen->display->atom__NET_SUPPORTING_WM_CHECK,
84
32, PropModeReplace, (guchar*) data, 1);
90
unset_wm_check_hint (MetaScreen *screen)
92
XDeleteProperty (screen->display->xdisplay, screen->xroot,
93
screen->display->atom__NET_SUPPORTING_WM_CHECK);
97
set_supported_hint (MetaScreen *screen)
100
#define EWMH_ATOMS_ONLY
101
#define item(x) screen->display->atom_##x,
102
#include "atomnames.h"
104
#undef EWMH_ATOMS_ONLY
107
XChangeProperty (screen->display->xdisplay, screen->xroot,
108
screen->display->atom__NET_SUPPORTED,
111
(guchar*) atoms, G_N_ELEMENTS(atoms));
117
set_wm_icon_size_hint (MetaScreen *screen)
122
/* min width, min height, max w, max h, width inc, height inc */
123
vals[0] = META_ICON_WIDTH;
124
vals[1] = META_ICON_HEIGHT;
125
vals[2] = META_ICON_WIDTH;
126
vals[3] = META_ICON_HEIGHT;
130
XChangeProperty (screen->display->xdisplay, screen->xroot,
131
screen->display->atom_WM_ICON_SIZE,
133
32, PropModeReplace, (guchar*) vals, N_VALS);
140
reload_xinerama_infos (MetaScreen *screen)
142
MetaDisplay *display;
147
tmp = screen->workspaces;
150
MetaWorkspace *space = tmp->data;
152
meta_workspace_invalidate_work_area (space);
158
display = screen->display;
160
if (screen->xinerama_infos)
161
g_free (screen->xinerama_infos);
163
screen->xinerama_infos = NULL;
164
screen->n_xinerama_infos = 0;
165
screen->last_xinerama_index = 0;
167
screen->display->xinerama_cache_invalidated = TRUE;
169
#ifdef HAVE_XFREE_XINERAMA
170
if (XineramaIsActive (display->xdisplay))
172
XineramaScreenInfo *infos;
177
infos = XineramaQueryScreens (display->xdisplay, &n_infos);
179
meta_topic (META_DEBUG_XINERAMA,
180
"Found %d Xinerama screens on display %s\n",
181
n_infos, display->name);
185
screen->xinerama_infos = g_new (MetaXineramaScreenInfo, n_infos);
186
screen->n_xinerama_infos = n_infos;
191
screen->xinerama_infos[i].number = infos[i].screen_number;
192
screen->xinerama_infos[i].rect.x = infos[i].x_org;
193
screen->xinerama_infos[i].rect.y = infos[i].y_org;
194
screen->xinerama_infos[i].rect.width = infos[i].width;
195
screen->xinerama_infos[i].rect.height = infos[i].height;
197
meta_topic (META_DEBUG_XINERAMA,
198
"Xinerama %d is %d,%d %d x %d\n",
199
screen->xinerama_infos[i].number,
200
screen->xinerama_infos[i].rect.x,
201
screen->xinerama_infos[i].rect.y,
202
screen->xinerama_infos[i].rect.width,
203
screen->xinerama_infos[i].rect.height);
213
meta_topic (META_DEBUG_XINERAMA,
214
"No XFree86 Xinerama extension or XFree86 Xinerama inactive on display %s\n",
218
meta_topic (META_DEBUG_XINERAMA,
219
"Metacity compiled without XFree86 Xinerama support\n");
220
#endif /* HAVE_XFREE_XINERAMA */
222
#ifdef HAVE_SOLARIS_XINERAMA
223
/* This code from GDK, Copyright (C) 2002 Sun Microsystems */
224
if (screen->n_xinerama_infos == 0 &&
225
XineramaGetState (screen->display->xdisplay,
228
XRectangle monitors[MAXFRAMEBUFFERS];
229
unsigned char hints[16];
235
result = XineramaGetInfo (screen->display->xdisplay,
239
/* Yes I know it should be Success but the current implementation
240
* returns the num of monitor
244
g_assert (n_monitors > 0);
246
screen->xinerama_infos = g_new (MetaXineramaScreenInfo, n_monitors);
247
screen->n_xinerama_infos = n_monitors;
250
while (i < n_monitors)
252
screen->xinerama_infos[i].number = i;
253
screen->xinerama_infos[i].rect.x = monitors[i].x;
254
screen->xinerama_infos[i].rect.y = monitors[i].y;
255
screen->xinerama_infos[i].rect.width = monitors[i].width;
256
screen->xinerama_infos[i].rect.height = monitors[i].height;
258
meta_topic (META_DEBUG_XINERAMA,
259
"Xinerama %d is %d,%d %d x %d\n",
260
screen->xinerama_infos[i].number,
261
screen->xinerama_infos[i].rect.x,
262
screen->xinerama_infos[i].rect.y,
263
screen->xinerama_infos[i].rect.width,
264
screen->xinerama_infos[i].rect.height);
270
else if (screen->n_xinerama_infos == 0)
272
meta_topic (META_DEBUG_XINERAMA,
273
"No Solaris Xinerama extension or Solaris Xinerama inactive on display %s\n",
277
meta_topic (META_DEBUG_XINERAMA,
278
"Metacity compiled without Solaris Xinerama support\n");
279
#endif /* HAVE_SOLARIS_XINERAMA */
282
/* If no Xinerama, fill in the single screen info so
283
* we can use the field unconditionally
285
if (screen->n_xinerama_infos == 0)
287
if (g_getenv ("METACITY_DEBUG_XINERAMA"))
289
meta_topic (META_DEBUG_XINERAMA,
290
"Pretending a single monitor has two Xinerama screens\n");
292
screen->xinerama_infos = g_new (MetaXineramaScreenInfo, 2);
293
screen->n_xinerama_infos = 2;
295
screen->xinerama_infos[0].number = 0;
296
screen->xinerama_infos[0].rect = screen->rect;
297
screen->xinerama_infos[0].rect.width = screen->rect.width / 2;
299
screen->xinerama_infos[1].number = 1;
300
screen->xinerama_infos[1].rect = screen->rect;
301
screen->xinerama_infos[1].rect.x = screen->rect.width / 2;
302
screen->xinerama_infos[1].rect.width = screen->rect.width / 2;
306
meta_topic (META_DEBUG_XINERAMA,
307
"No Xinerama screens, using default screen info\n");
309
screen->xinerama_infos = g_new (MetaXineramaScreenInfo, 1);
310
screen->n_xinerama_infos = 1;
312
screen->xinerama_infos[0].number = 0;
313
screen->xinerama_infos[0].rect = screen->rect;
317
g_assert (screen->n_xinerama_infos > 0);
318
g_assert (screen->xinerama_infos != NULL);
322
meta_screen_new (MetaDisplay *display,
329
XWindowAttributes attr;
330
Window new_wm_sn_owner;
331
Window current_wm_sn_owner;
332
gboolean replace_current_wm;
335
guint32 manager_timestamp;
336
gulong current_workspace;
338
replace_current_wm = meta_get_replace_current_wm ();
340
/* Only display->name, display->xdisplay, and display->error_traps
341
* can really be used in this function, since normally screens are
342
* created from the MetaDisplay constructor
345
xdisplay = display->xdisplay;
347
meta_verbose ("Trying screen %d on display '%s'\n",
348
number, display->name);
350
xroot = RootWindow (xdisplay, number);
352
/* FVWM checks for None here, I don't know if this
353
* ever actually happens
357
meta_warning (_("Screen %d on display '%s' is invalid\n"),
358
number, display->name);
362
sprintf (buf, "WM_S%d", number);
363
wm_sn_atom = XInternAtom (xdisplay, buf, False);
365
current_wm_sn_owner = XGetSelectionOwner (xdisplay, wm_sn_atom);
367
if (current_wm_sn_owner != None)
369
XSetWindowAttributes attrs;
371
if (!replace_current_wm)
373
meta_warning (_("Screen %d on display \"%s\" already has a window manager; try using the --replace option to replace the current window manager.\n"),
374
number, display->name);
379
/* We want to find out when the current selection owner dies */
380
meta_error_trap_push_with_return (display);
381
attrs.event_mask = StructureNotifyMask;
382
XChangeWindowAttributes (xdisplay,
383
current_wm_sn_owner, CWEventMask, &attrs);
384
if (meta_error_trap_pop_with_return (display, FALSE) != Success)
385
current_wm_sn_owner = None; /* don't wait for it to die later on */
388
/* We need SelectionClear and SelectionRequest events on the new_wm_sn_owner,
389
* but those cannot be masked, so we only need NoEventMask.
391
new_wm_sn_owner = meta_create_offscreen_window (xdisplay, xroot, NoEventMask);
393
manager_timestamp = timestamp;
395
XSetSelectionOwner (xdisplay, wm_sn_atom, new_wm_sn_owner,
398
if (XGetSelectionOwner (xdisplay, wm_sn_atom) != new_wm_sn_owner)
400
meta_warning (_("Could not acquire window manager selection on screen %d display \"%s\"\n"),
401
number, display->name);
403
XDestroyWindow (xdisplay, new_wm_sn_owner);
409
/* Send client message indicating that we are now the WM */
410
XClientMessageEvent ev;
412
ev.type = ClientMessage;
414
ev.message_type = display->atom_MANAGER;
416
ev.data.l[0] = manager_timestamp;
417
ev.data.l[1] = wm_sn_atom;
419
XSendEvent (xdisplay, xroot, False, StructureNotifyMask, (XEvent*)&ev);
422
/* Wait for old window manager to go away */
423
if (current_wm_sn_owner != None)
427
/* We sort of block infinitely here which is probably lame. */
429
meta_verbose ("Waiting for old window manager to exit\n");
432
XWindowEvent (xdisplay, current_wm_sn_owner,
433
StructureNotifyMask, &event);
435
while (event.type != DestroyNotify);
438
/* select our root window events */
439
meta_error_trap_push_with_return (display);
441
/* We need to or with the existing event mask since
442
* gtk+ may be interested in other events.
444
XGetWindowAttributes (xdisplay, xroot, &attr);
445
XSelectInput (xdisplay,
447
SubstructureRedirectMask | SubstructureNotifyMask |
448
ColormapChangeMask | PropertyChangeMask |
449
LeaveWindowMask | EnterWindowMask |
450
KeyPressMask | KeyReleaseMask |
451
FocusChangeMask | StructureNotifyMask |
452
#ifdef HAVE_COMPOSITE_EXTENSIONS
455
attr.your_event_mask);
456
if (meta_error_trap_pop_with_return (display, FALSE) != Success)
458
meta_warning (_("Screen %d on display \"%s\" already has a window manager\n"),
459
number, display->name);
461
XDestroyWindow (xdisplay, new_wm_sn_owner);
466
screen = g_new (MetaScreen, 1);
469
screen->display = display;
470
screen->number = number;
471
screen->screen_name = get_screen_name (display, number);
472
screen->xscreen = ScreenOfDisplay (xdisplay, number);
473
screen->xroot = xroot;
474
screen->rect.x = screen->rect.y = 0;
475
screen->rect.width = WidthOfScreen (screen->xscreen);
476
screen->rect.height = HeightOfScreen (screen->xscreen);
477
screen->current_cursor = -1; /* invalid/unset */
478
screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen);
479
screen->default_depth = DefaultDepthOfScreen (screen->xscreen);
480
screen->flash_window = None;
482
screen->wm_sn_selection_window = new_wm_sn_owner;
483
screen->wm_sn_atom = wm_sn_atom;
484
screen->wm_sn_timestamp = manager_timestamp;
486
#ifdef HAVE_COMPOSITE_EXTENSIONS
487
screen->wm_cm_selection_window = meta_create_offscreen_window (xdisplay,
491
screen->work_area_idle = 0;
493
screen->active_workspace = NULL;
494
screen->workspaces = NULL;
495
screen->rows_of_workspaces = 1;
496
screen->columns_of_workspaces = -1;
497
screen->vertical_workspaces = FALSE;
498
screen->starting_corner = META_SCREEN_TOPLEFT;
499
screen->compositor_data = NULL;
502
XFontStruct *font_info;
504
gulong value_mask = 0;
506
gc_values.subwindow_mode = IncludeInferiors;
507
value_mask |= GCSubwindowMode;
508
gc_values.function = GXinvert;
509
value_mask |= GCFunction;
510
gc_values.line_width = META_WIREFRAME_XOR_LINE_WIDTH;
511
value_mask |= GCLineWidth;
513
font_info = XLoadQueryFont (screen->display->xdisplay, "fixed");
515
if (font_info != NULL)
517
gc_values.font = font_info->fid;
518
value_mask |= GCFont;
519
XFreeFontInfo (NULL, font_info, 1);
522
meta_warning ("xserver doesn't have 'fixed' font.\n");
524
screen->root_xor_gc = XCreateGC (screen->display->xdisplay,
530
screen->xinerama_infos = NULL;
531
screen->n_xinerama_infos = 0;
532
screen->last_xinerama_index = 0;
534
reload_xinerama_infos (screen);
536
meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
538
/* Handle creating a no_focus_window for this screen */
539
screen->no_focus_window =
540
meta_create_offscreen_window (display->xdisplay,
542
FocusChangeMask|KeyPressMask|KeyReleaseMask);
543
XMapWindow (display->xdisplay, screen->no_focus_window);
544
/* Done with no_focus_window stuff */
546
set_wm_icon_size_hint (screen);
548
set_supported_hint (screen);
550
set_wm_check_hint (screen);
552
set_desktop_viewport_hint (screen);
554
set_desktop_geometry_hint (screen);
556
meta_screen_update_workspace_layout (screen);
558
/* Get current workspace */
559
current_workspace = 0;
560
if (meta_prop_get_cardinal (screen->display,
562
screen->display->atom__NET_CURRENT_DESKTOP,
564
meta_verbose ("Read existing _NET_CURRENT_DESKTOP = %d\n",
565
(int) current_workspace);
567
meta_verbose ("No _NET_CURRENT_DESKTOP present\n");
569
/* Screens must have at least one workspace at all times,
570
* so create that required workspace.
572
meta_workspace_activate (meta_workspace_new (screen), timestamp);
573
update_num_workspaces (screen, timestamp);
575
set_workspace_names (screen);
577
screen->all_keys_grabbed = FALSE;
578
screen->keys_grabbed = FALSE;
579
meta_screen_grab_keys (screen);
581
screen->ui = meta_ui_new (screen->display->xdisplay,
584
screen->tab_popup = NULL;
586
screen->stack = meta_stack_new (screen);
588
meta_prefs_add_listener (prefs_changed_callback, screen);
590
#ifdef HAVE_STARTUP_NOTIFICATION
592
sn_monitor_context_new (screen->display->sn_display,
594
meta_screen_sn_event,
597
screen->startup_sequences = NULL;
598
screen->startup_sequence_timeout = 0;
601
/* Switch to the _NET_CURRENT_DESKTOP workspace */
603
MetaWorkspace *space;
605
space = meta_screen_get_workspace_by_index (screen,
609
meta_workspace_activate (space, timestamp);
612
meta_verbose ("Added screen %d ('%s') root 0x%lx\n",
613
screen->number, screen->screen_name, screen->xroot);
619
meta_screen_free (MetaScreen *screen,
622
MetaDisplay *display;
623
XGCValues gc_values = { 0 };
625
display = screen->display;
627
screen->closing += 1;
629
meta_display_grab (display);
631
if (screen->display->compositor)
633
meta_compositor_unmanage_screen (screen->display->compositor,
637
meta_display_unmanage_windows_for_screen (display, screen, timestamp);
639
meta_prefs_remove_listener (prefs_changed_callback, screen);
641
meta_screen_ungrab_keys (screen);
643
#ifdef HAVE_STARTUP_NOTIFICATION
644
g_slist_foreach (screen->startup_sequences,
645
(GFunc) sn_startup_sequence_unref, NULL);
646
g_slist_free (screen->startup_sequences);
647
screen->startup_sequences = NULL;
649
if (screen->startup_sequence_timeout != 0)
651
g_source_remove (screen->startup_sequence_timeout);
652
screen->startup_sequence_timeout = 0;
654
if (screen->sn_context)
656
sn_monitor_context_unref (screen->sn_context);
657
screen->sn_context = NULL;
661
meta_ui_free (screen->ui);
663
meta_stack_free (screen->stack);
665
meta_error_trap_push_with_return (screen->display);
666
XSelectInput (screen->display->xdisplay, screen->xroot, 0);
667
if (meta_error_trap_pop_with_return (screen->display, FALSE) != Success)
668
meta_warning (_("Could not release screen %d on display \"%s\"\n"),
669
screen->number, screen->display->name);
671
unset_wm_check_hint (screen);
673
XDestroyWindow (screen->display->xdisplay,
674
screen->wm_sn_selection_window);
676
if (screen->work_area_idle != 0)
677
g_source_remove (screen->work_area_idle);
680
if (XGetGCValues (screen->display->xdisplay,
685
XUnloadFont (screen->display->xdisplay,
689
XFreeGC (screen->display->xdisplay,
690
screen->root_xor_gc);
692
if (screen->xinerama_infos)
693
g_free (screen->xinerama_infos);
695
g_free (screen->screen_name);
698
XFlush (display->xdisplay);
699
meta_display_ungrab (display);
705
XWindowAttributes attrs;
709
list_windows (MetaScreen *screen)
711
Window ignored1, ignored2;
716
XQueryTree (screen->display->xdisplay,
718
&ignored1, &ignored2, &children, &n_children);
721
for (i = 0; i < n_children; ++i)
723
WindowInfo *info = g_new0 (WindowInfo, 1);
725
meta_error_trap_push_with_return (screen->display);
727
XGetWindowAttributes (screen->display->xdisplay,
728
children[i], &info->attrs);
730
if (meta_error_trap_pop_with_return (screen->display, TRUE))
732
meta_verbose ("Failed to get attributes for window 0x%lx\n",
738
info->xwindow = children[i];
741
result = g_list_prepend (result, info);
747
return g_list_reverse (result);
751
meta_screen_manage_all_windows (MetaScreen *screen)
756
meta_display_grab (screen->display);
758
windows = list_windows (screen);
760
meta_stack_freeze (screen->stack);
761
for (list = windows; list != NULL; list = list->next)
763
WindowInfo *info = list->data;
766
window = meta_window_new_with_attrs (screen->display, info->xwindow, TRUE,
768
if (info->xwindow == screen->no_focus_window ||
769
info->xwindow == screen->flash_window ||
770
#ifdef HAVE_COMPOSITE_EXTENSIONS
771
info->xwindow == screen->wm_cm_selection_window ||
773
info->xwindow == screen->wm_sn_selection_window) {
774
meta_verbose ("Not managing our own windows\n");
778
if (screen->display->compositor)
779
meta_compositor_add_window (screen->display->compositor, window,
780
info->xwindow, &info->attrs);
782
meta_stack_thaw (screen->stack);
784
g_list_foreach (windows, (GFunc)g_free, NULL);
785
g_list_free (windows);
787
meta_display_ungrab (screen->display);
791
meta_screen_composite_all_windows (MetaScreen *screen)
793
#ifdef HAVE_COMPOSITE_EXTENSIONS
794
MetaDisplay *display;
795
GList *windows, *list;
797
display = screen->display;
798
if (!display->compositor)
801
windows = list_windows (screen);
803
meta_stack_freeze (screen->stack);
805
for (list = windows; list != NULL; list = list->next)
807
WindowInfo *info = list->data;
809
if (info->xwindow == screen->no_focus_window ||
810
info->xwindow == screen->flash_window ||
811
info->xwindow == screen->wm_sn_selection_window ||
812
info->xwindow == screen->wm_cm_selection_window) {
813
meta_verbose ("Not managing our own windows\n");
817
meta_compositor_add_window (display->compositor,
818
meta_display_lookup_x_window (display,
820
info->xwindow, &info->attrs);
823
meta_stack_thaw (screen->stack);
825
g_list_foreach (windows, (GFunc)g_free, NULL);
826
g_list_free (windows);
831
meta_screen_for_x_screen (Screen *xscreen)
833
MetaDisplay *display;
835
display = meta_display_for_x_display (DisplayOfScreen (xscreen));
840
return meta_display_screen_for_x_screen (display, xscreen);
844
prefs_changed_callback (MetaPreference pref,
847
MetaScreen *screen = data;
849
if (pref == META_PREF_NUM_WORKSPACES)
851
/* GConf doesn't provide timestamps, but luckily update_num_workspaces
852
* often doesn't need it...
855
meta_display_get_current_time_roundtrip (screen->display);
856
update_num_workspaces (screen, timestamp);
858
else if (pref == META_PREF_FOCUS_MODE)
860
update_focus_mode (screen);
862
else if (pref == META_PREF_WORKSPACE_NAMES)
864
set_workspace_names (screen);
870
get_screen_name (MetaDisplay *display,
877
/* DisplayString gives us a sort of canonical display,
878
* vs. the user-entered name from XDisplayName()
880
dname = g_strdup (DisplayString (display->xdisplay));
882
/* Change display name to specify this screen.
884
p = strrchr (dname, ':');
892
scr = g_strdup_printf ("%s.%d", dname, number);
900
ptrcmp (gconstpointer a, gconstpointer b)
911
listify_func (gpointer key, gpointer value, gpointer data)
917
*listp = g_slist_prepend (*listp, value);
921
meta_screen_foreach_window (MetaScreen *screen,
922
MetaScreenWindowFunc func,
928
/* If we end up doing this often, just keeping a list
929
* of windows might be sensible.
933
g_hash_table_foreach (screen->display->window_ids,
937
winlist = g_slist_sort (winlist, ptrcmp);
942
/* If the next node doesn't contain this window
943
* a second time, delete the window.
945
if (tmp->next == NULL ||
946
(tmp->next && tmp->next->data != tmp->data))
948
MetaWindow *window = tmp->data;
950
if (window->screen == screen)
951
(* func) (screen, window, data);
956
g_slist_free (winlist);
960
queue_draw (MetaScreen *screen, MetaWindow *window, gpointer data)
963
meta_frame_queue_draw (window->frame);
967
meta_screen_queue_frame_redraws (MetaScreen *screen)
969
meta_screen_foreach_window (screen, queue_draw, NULL);
973
queue_resize (MetaScreen *screen, MetaWindow *window, gpointer data)
975
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
979
meta_screen_queue_window_resizes (MetaScreen *screen)
981
meta_screen_foreach_window (screen, queue_resize, NULL);
985
meta_screen_get_n_workspaces (MetaScreen *screen)
987
return g_list_length (screen->workspaces);
991
meta_screen_get_workspace_by_index (MetaScreen *screen,
997
/* should be robust, idx is maybe from an app */
1002
tmp = screen->workspaces;
1005
MetaWorkspace *w = tmp->data;
1018
set_number_of_spaces_hint (MetaScreen *screen,
1021
unsigned long data[1];
1023
if (screen->closing > 0)
1028
meta_verbose ("Setting _NET_NUMBER_OF_DESKTOPS to %lu\n", data[0]);
1030
meta_error_trap_push (screen->display);
1031
XChangeProperty (screen->display->xdisplay, screen->xroot,
1032
screen->display->atom__NET_NUMBER_OF_DESKTOPS,
1034
32, PropModeReplace, (guchar*) data, 1);
1035
meta_error_trap_pop (screen->display, FALSE);
1039
set_desktop_geometry_hint (MetaScreen *screen)
1041
unsigned long data[2];
1043
if (screen->closing > 0)
1046
data[0] = screen->rect.width;
1047
data[1] = screen->rect.height;
1049
meta_verbose ("Setting _NET_DESKTOP_GEOMETRY to %lu, %lu\n", data[0], data[1]);
1051
meta_error_trap_push (screen->display);
1052
XChangeProperty (screen->display->xdisplay, screen->xroot,
1053
screen->display->atom__NET_DESKTOP_GEOMETRY,
1055
32, PropModeReplace, (guchar*) data, 2);
1056
meta_error_trap_pop (screen->display, FALSE);
1060
set_desktop_viewport_hint (MetaScreen *screen)
1062
unsigned long data[2];
1064
if (screen->closing > 0)
1068
* Metacity does not implement viewports, so this is a fixed 0,0
1073
meta_verbose ("Setting _NET_DESKTOP_VIEWPORT to 0, 0\n");
1075
meta_error_trap_push (screen->display);
1076
XChangeProperty (screen->display->xdisplay, screen->xroot,
1077
screen->display->atom__NET_DESKTOP_VIEWPORT,
1079
32, PropModeReplace, (guchar*) data, 2);
1080
meta_error_trap_pop (screen->display, FALSE);
1084
update_num_workspaces (MetaScreen *screen,
1091
MetaWorkspace *last_remaining;
1092
gboolean need_change_space;
1094
new_num = meta_prefs_get_num_workspaces ();
1096
g_assert (new_num > 0);
1098
last_remaining = NULL;
1101
tmp = screen->workspaces;
1104
MetaWorkspace *w = tmp->data;
1107
extras = g_list_prepend (extras, w);
1115
g_assert (last_remaining);
1117
/* Get rid of the extra workspaces by moving all their windows
1118
* to last_remaining, then activating last_remaining if
1119
* one of the removed workspaces was active. This will be a bit
1120
* wacky if the config tool for changing number of workspaces
1121
* is on a removed workspace ;-)
1123
need_change_space = FALSE;
1127
MetaWorkspace *w = tmp->data;
1129
meta_workspace_relocate_windows (w, last_remaining);
1131
if (w == screen->active_workspace)
1132
need_change_space = TRUE;
1137
if (need_change_space)
1138
meta_workspace_activate (last_remaining, timestamp);
1140
/* Should now be safe to free the workspaces */
1144
MetaWorkspace *w = tmp->data;
1146
g_assert (w->windows == NULL);
1147
meta_workspace_free (w);
1152
g_list_free (extras);
1156
meta_workspace_new (screen);
1160
set_number_of_spaces_hint (screen, new_num);
1162
meta_screen_queue_workarea_recalc (screen);
1166
update_focus_mode (MetaScreen *screen)
1168
/* nothing to do anymore */ ;
1172
meta_screen_set_cursor (MetaScreen *screen,
1177
if (cursor == screen->current_cursor)
1180
screen->current_cursor = cursor;
1182
xcursor = meta_display_create_x_cursor (screen->display, cursor);
1183
XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
1184
XFlush (screen->display->xdisplay);
1185
XFreeCursor (screen->display->xdisplay, xcursor);
1189
meta_screen_update_cursor (MetaScreen *screen)
1193
xcursor = meta_display_create_x_cursor (screen->display,
1194
screen->current_cursor);
1195
XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
1196
XFlush (screen->display->xdisplay);
1197
XFreeCursor (screen->display->xdisplay, xcursor);
1200
#define MAX_PREVIEW_SIZE 150.0
1203
get_window_pixbuf (MetaWindow *window,
1208
GdkPixbuf *pixbuf, *scaled;
1211
pmap = meta_compositor_get_window_pixmap (window->display->compositor,
1216
pixbuf = meta_ui_get_pixbuf_from_pixmap (pmap);
1220
*width = gdk_pixbuf_get_width (pixbuf);
1221
*height = gdk_pixbuf_get_height (pixbuf);
1223
/* Scale pixbuf to max dimension MAX_PREVIEW_SIZE */
1224
if (*width > *height)
1226
ratio = ((double) *width) / MAX_PREVIEW_SIZE;
1227
*width = (int) MAX_PREVIEW_SIZE;
1228
*height = (int) (((double) *height) / ratio);
1232
ratio = ((double) *height) / MAX_PREVIEW_SIZE;
1233
*height = (int) MAX_PREVIEW_SIZE;
1234
*width = (int) (((double) *width) / ratio);
1237
scaled = gdk_pixbuf_scale_simple (pixbuf, *width, *height,
1238
GDK_INTERP_BILINEAR);
1239
g_object_unref (pixbuf);
1244
meta_screen_ensure_tab_popup (MetaScreen *screen,
1245
MetaTabList list_type,
1246
MetaTabShowType show_type)
1248
MetaTabEntry *entries;
1254
if (screen->tab_popup)
1257
tab_list = meta_display_get_tab_list (screen->display,
1260
screen->active_workspace);
1262
len = g_list_length (tab_list);
1264
entries = g_new (MetaTabEntry, len + 1);
1265
entries[len].key = NULL;
1266
entries[len].title = NULL;
1267
entries[len].icon = NULL;
1275
GdkPixbuf *win_pixbuf;
1280
entries[i].key = (MetaTabEntryKey) window->xwindow;
1281
entries[i].title = window->title;
1283
win_pixbuf = get_window_pixbuf (window, &width, &height);
1284
if (win_pixbuf == NULL)
1285
entries[i].icon = g_object_ref (window->icon);
1288
int icon_width, icon_height, t_width, t_height;
1289
#define ICON_OFFSET 6
1291
icon_width = gdk_pixbuf_get_width (window->icon);
1292
icon_height = gdk_pixbuf_get_height (window->icon);
1294
t_width = width + ICON_OFFSET;
1295
t_height = height + ICON_OFFSET;
1297
entries[i].icon = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
1299
gdk_pixbuf_fill (entries[i].icon, 0x00000000);
1300
gdk_pixbuf_copy_area (win_pixbuf, 0, 0, width, height,
1301
entries[i].icon, 0, 0);
1302
g_object_unref (win_pixbuf);
1303
gdk_pixbuf_composite (window->icon, entries[i].icon,
1304
t_width - icon_width, t_height - icon_height,
1305
icon_width, icon_height,
1306
t_width - icon_width, t_height - icon_height,
1307
1.0, 1.0, GDK_INTERP_BILINEAR, 255);
1310
entries[i].blank = FALSE;
1311
entries[i].hidden = !meta_window_showing_on_its_workspace (window);
1312
entries[i].demands_attention = window->wm_state_demands_attention;
1314
if (show_type == META_TAB_SHOW_INSTANTLY ||
1315
!entries[i].hidden ||
1316
!meta_window_get_icon_geometry (window, &r))
1317
meta_window_get_outer_rect (window, &r);
1319
entries[i].rect = r;
1321
/* Find inside of highlight rectangle to be used when window is
1322
* outlined for tabbing. This should be the size of the
1323
* east/west frame, and the size of the south frame, on those
1324
* sides. On the top it should be the size of the south frame
1327
#define OUTLINE_WIDTH 5
1329
if (!entries[i].hidden &&
1330
window->frame && window->frame->bottom_height > 0 &&
1331
window->frame->child_y >= window->frame->bottom_height)
1332
entries[i].inner_rect.y = window->frame->bottom_height;
1334
entries[i].inner_rect.y = OUTLINE_WIDTH;
1337
if (!entries[i].hidden &&
1338
window->frame && window->frame->bottom_height != 0)
1339
entries[i].inner_rect.height = r.height
1340
- entries[i].inner_rect.y - window->frame->bottom_height;
1342
entries[i].inner_rect.height = r.height
1343
- entries[i].inner_rect.y - OUTLINE_WIDTH;
1346
if (!entries[i].hidden && window->frame && window->frame->child_x != 0)
1347
entries[i].inner_rect.x = window->frame->child_x;
1349
entries[i].inner_rect.x = OUTLINE_WIDTH;
1352
if (!entries[i].hidden &&
1353
window->frame && window->frame->right_width != 0)
1354
entries[i].inner_rect.width = r.width
1355
- entries[i].inner_rect.x - window->frame->right_width;
1357
entries[i].inner_rect.width = r.width
1358
- entries[i].inner_rect.x - OUTLINE_WIDTH;
1364
screen->tab_popup = meta_ui_tab_popup_new (entries,
1370
for (i = 0; i < len; i++)
1371
g_object_unref (entries[i].icon);
1375
g_list_free (tab_list);
1377
/* don't show tab popup, since proper window isn't selected yet */
1381
meta_screen_ensure_workspace_popup (MetaScreen *screen)
1383
MetaTabEntry *entries;
1386
MetaWorkspaceLayout layout;
1388
int current_workspace;
1390
if (screen->tab_popup)
1393
current_workspace = meta_workspace_index (screen->active_workspace);
1394
n_workspaces = meta_screen_get_n_workspaces (screen);
1396
meta_screen_calc_workspace_layout (screen, n_workspaces,
1397
current_workspace, &layout);
1399
len = layout.grid_area;
1401
entries = g_new (MetaTabEntry, len + 1);
1402
entries[len].key = NULL;
1403
entries[len].title = NULL;
1404
entries[len].icon = NULL;
1409
if (layout.grid[i] >= 0)
1411
MetaWorkspace *workspace;
1413
workspace = meta_screen_get_workspace_by_index (screen,
1416
entries[i].key = (MetaTabEntryKey) workspace;
1417
entries[i].title = meta_workspace_get_name (workspace);
1418
entries[i].icon = NULL;
1419
entries[i].blank = FALSE;
1421
g_assert (entries[i].title != NULL);
1425
entries[i].key = NULL;
1426
entries[i].title = NULL;
1427
entries[i].icon = NULL;
1428
entries[i].blank = TRUE;
1430
entries[i].hidden = FALSE;
1431
entries[i].demands_attention = FALSE;
1436
screen->tab_popup = meta_ui_tab_popup_new (entries,
1443
meta_screen_free_workspace_layout (&layout);
1445
/* don't show tab popup, since proper space isn't selected yet */
1449
meta_screen_get_mouse_window (MetaScreen *screen,
1450
MetaWindow *not_this_one)
1453
Window root_return, child_return;
1454
int root_x_return, root_y_return;
1455
int win_x_return, win_y_return;
1456
unsigned int mask_return;
1459
meta_topic (META_DEBUG_FOCUS,
1460
"Focusing mouse window excluding %s\n", not_this_one->desc);
1462
meta_error_trap_push (screen->display);
1463
XQueryPointer (screen->display->xdisplay,
1472
meta_error_trap_pop (screen->display, TRUE);
1474
window = meta_stack_get_default_focus_window_at_point (screen->stack,
1475
screen->active_workspace,
1483
const MetaXineramaScreenInfo*
1484
meta_screen_get_xinerama_for_rect (MetaScreen *screen,
1485
MetaRectangle *rect)
1488
int best_xinerama, xinerama_score;
1490
if (screen->n_xinerama_infos == 1)
1491
return &screen->xinerama_infos[0];
1496
for (i = 0; i < screen->n_xinerama_infos; i++)
1499
if (meta_rectangle_intersect (&screen->xinerama_infos[i].rect,
1503
int cur = meta_rectangle_area (&dest);
1504
if (cur > xinerama_score)
1506
xinerama_score = cur;
1512
return &screen->xinerama_infos[best_xinerama];
1515
const MetaXineramaScreenInfo*
1516
meta_screen_get_xinerama_for_window (MetaScreen *screen,
1519
MetaRectangle window_rect;
1521
meta_window_get_outer_rect (window, &window_rect);
1523
return meta_screen_get_xinerama_for_rect (screen, &window_rect);
1526
const MetaXineramaScreenInfo*
1527
meta_screen_get_xinerama_neighbor (MetaScreen *screen,
1529
MetaScreenDirection direction)
1531
MetaXineramaScreenInfo* input = screen->xinerama_infos + which_xinerama;
1532
MetaXineramaScreenInfo* current;
1535
for (i = 0; i < screen->n_xinerama_infos; i++)
1537
current = screen->xinerama_infos + i;
1539
if ((direction == META_SCREEN_RIGHT &&
1540
current->rect.x == input->rect.x + input->rect.width &&
1541
meta_rectangle_vert_overlap(¤t->rect, &input->rect)) ||
1542
(direction == META_SCREEN_LEFT &&
1543
input->rect.x == current->rect.x + current->rect.width &&
1544
meta_rectangle_vert_overlap(¤t->rect, &input->rect)) ||
1545
(direction == META_SCREEN_UP &&
1546
input->rect.y == current->rect.y + current->rect.height &&
1547
meta_rectangle_horiz_overlap(¤t->rect, &input->rect)) ||
1548
(direction == META_SCREEN_DOWN &&
1549
current->rect.y == input->rect.y + input->rect.height &&
1550
meta_rectangle_horiz_overlap(¤t->rect, &input->rect)))
1560
meta_screen_get_natural_xinerama_list (MetaScreen *screen,
1561
int** xineramas_list,
1564
const MetaXineramaScreenInfo* current;
1565
const MetaXineramaScreenInfo* tmp;
1566
GQueue* xinerama_queue;
1571
*n_xineramas = screen->n_xinerama_infos;
1572
*xineramas_list = g_new (int, screen->n_xinerama_infos);
1574
/* we calculate a natural ordering by which to choose xineramas for
1575
* window placement. We start at the current xinerama, and perform
1576
* a breadth-first search of the xineramas starting from that
1577
* xinerama. We choose preferentially left, then right, then down,
1578
* then up. The visitation order produced by this traversal is the
1579
* natural xinerama ordering.
1582
visited = g_new (int, screen->n_xinerama_infos);
1583
for (i = 0; i < screen->n_xinerama_infos; i++)
1588
current = meta_screen_get_current_xinerama (screen);
1589
xinerama_queue = g_queue_new ();
1590
g_queue_push_tail (xinerama_queue, (gpointer) current);
1591
visited[current->number] = TRUE;
1593
while (!g_queue_is_empty (xinerama_queue))
1595
current = (const MetaXineramaScreenInfo*)
1596
g_queue_pop_head (xinerama_queue);
1598
(*xineramas_list)[cur++] = current->number;
1600
/* enqueue each of the directions */
1601
tmp = meta_screen_get_xinerama_neighbor (screen,
1604
if (tmp && !visited[tmp->number])
1606
g_queue_push_tail (xinerama_queue,
1607
(MetaXineramaScreenInfo*) tmp);
1608
visited[tmp->number] = TRUE;
1610
tmp = meta_screen_get_xinerama_neighbor (screen,
1613
if (tmp && !visited[tmp->number])
1615
g_queue_push_tail (xinerama_queue,
1616
(MetaXineramaScreenInfo*) tmp);
1617
visited[tmp->number] = TRUE;
1619
tmp = meta_screen_get_xinerama_neighbor (screen,
1622
if (tmp && !visited[tmp->number])
1624
g_queue_push_tail (xinerama_queue,
1625
(MetaXineramaScreenInfo*) tmp);
1626
visited[tmp->number] = TRUE;
1628
tmp = meta_screen_get_xinerama_neighbor (screen,
1631
if (tmp && !visited[tmp->number])
1633
g_queue_push_tail (xinerama_queue,
1634
(MetaXineramaScreenInfo*) tmp);
1635
visited[tmp->number] = TRUE;
1639
/* in case we somehow missed some set of xineramas, go through the
1640
* visited list and add in any xineramas that were missed
1642
for (i = 0; i < screen->n_xinerama_infos; i++)
1644
if (visited[i] == FALSE)
1646
(*xineramas_list)[cur++] = i;
1651
g_queue_free (xinerama_queue);
1654
const MetaXineramaScreenInfo*
1655
meta_screen_get_current_xinerama (MetaScreen *screen)
1657
if (screen->n_xinerama_infos == 1)
1658
return &screen->xinerama_infos[0];
1660
/* Sadly, we have to do it this way. Yuck.
1663
if (screen->display->xinerama_cache_invalidated)
1665
Window root_return, child_return;
1666
int win_x_return, win_y_return;
1667
unsigned int mask_return;
1669
MetaRectangle pointer_position;
1671
screen->display->xinerama_cache_invalidated = FALSE;
1673
pointer_position.width = pointer_position.height = 1;
1674
XQueryPointer (screen->display->xdisplay,
1678
&pointer_position.x,
1679
&pointer_position.y,
1684
screen->last_xinerama_index = 0;
1685
for (i = 0; i < screen->n_xinerama_infos; i++)
1687
if (meta_rectangle_contains_rect (&screen->xinerama_infos[i].rect,
1690
screen->last_xinerama_index = i;
1695
meta_topic (META_DEBUG_XINERAMA,
1696
"Rechecked current Xinerama, now %d\n",
1697
screen->last_xinerama_index);
1700
return &screen->xinerama_infos[screen->last_xinerama_index];
1703
#define _NET_WM_ORIENTATION_HORZ 0
1704
#define _NET_WM_ORIENTATION_VERT 1
1706
#define _NET_WM_TOPLEFT 0
1707
#define _NET_WM_TOPRIGHT 1
1708
#define _NET_WM_BOTTOMRIGHT 2
1709
#define _NET_WM_BOTTOMLEFT 3
1712
meta_screen_update_workspace_layout (MetaScreen *screen)
1720
if (meta_prop_get_cardinal_list (screen->display,
1722
screen->display->atom__NET_DESKTOP_LAYOUT,
1725
if (n_items == 3 || n_items == 4)
1731
case _NET_WM_ORIENTATION_HORZ:
1732
screen->vertical_workspaces = FALSE;
1734
case _NET_WM_ORIENTATION_VERT:
1735
screen->vertical_workspaces = TRUE;
1738
meta_warning ("Someone set a weird orientation in _NET_DESKTOP_LAYOUT\n");
1745
if (rows <= 0 && cols <= 0)
1747
meta_warning ("Columns = %d rows = %d in _NET_DESKTOP_LAYOUT makes no sense\n", rows, cols);
1752
screen->rows_of_workspaces = rows;
1754
screen->rows_of_workspaces = -1;
1757
screen->columns_of_workspaces = cols;
1759
screen->columns_of_workspaces = -1;
1766
case _NET_WM_TOPLEFT:
1767
screen->starting_corner = META_SCREEN_TOPLEFT;
1769
case _NET_WM_TOPRIGHT:
1770
screen->starting_corner = META_SCREEN_TOPRIGHT;
1772
case _NET_WM_BOTTOMRIGHT:
1773
screen->starting_corner = META_SCREEN_BOTTOMRIGHT;
1775
case _NET_WM_BOTTOMLEFT:
1776
screen->starting_corner = META_SCREEN_BOTTOMLEFT;
1779
meta_warning ("Someone set a weird starting corner in _NET_DESKTOP_LAYOUT\n");
1784
screen->starting_corner = META_SCREEN_TOPLEFT;
1788
meta_warning ("Someone set _NET_DESKTOP_LAYOUT to %d integers instead of 4 "
1789
"(3 is accepted for backwards compat)\n", n_items);
1795
meta_verbose ("Workspace layout rows = %d cols = %d orientation = %d starting corner = %u\n",
1796
screen->rows_of_workspaces,
1797
screen->columns_of_workspaces,
1798
screen->vertical_workspaces,
1799
screen->starting_corner);
1803
set_workspace_names (MetaScreen *screen)
1805
/* This updates names on root window when the pref changes,
1806
* note we only get prefs change notify if things have
1813
/* flatten to nul-separated list */
1814
n_spaces = meta_screen_get_n_workspaces (screen);
1815
flattened = g_string_new ("");
1817
while (i < n_spaces)
1821
name = meta_prefs_get_workspace_name (i);
1824
g_string_append_len (flattened, name,
1827
g_string_append_len (flattened, "", 1);
1832
meta_error_trap_push (screen->display);
1833
XChangeProperty (screen->display->xdisplay,
1835
screen->display->atom__NET_DESKTOP_NAMES,
1836
screen->display->atom_UTF8_STRING,
1838
(unsigned char *)flattened->str, flattened->len);
1839
meta_error_trap_pop (screen->display, FALSE);
1841
g_string_free (flattened, TRUE);
1845
meta_screen_update_workspace_names (MetaScreen *screen)
1851
/* this updates names in prefs when the root window property changes,
1852
* iff the new property contents don't match what's already in prefs
1857
if (!meta_prop_get_utf8_list (screen->display,
1859
screen->display->atom__NET_DESKTOP_NAMES,
1862
meta_verbose ("Failed to get workspace names from root window %d\n",
1870
meta_topic (META_DEBUG_PREFS,
1871
"Setting workspace %d name to \"%s\" due to _NET_DESKTOP_NAMES change\n",
1872
i, names[i] ? names[i] : "null");
1873
meta_prefs_change_workspace_name (i, names[i]);
1882
meta_create_offscreen_window (Display *xdisplay,
1886
XSetWindowAttributes attrs;
1888
/* we want to be override redirect because sometimes we
1889
* create a window on a screen we aren't managing.
1890
* (but on a display we are managing at least one screen for)
1892
attrs.override_redirect = True;
1893
attrs.event_mask = valuemask;
1895
return XCreateWindow (xdisplay,
1901
(Visual *)CopyFromParent,
1902
CWOverrideRedirect | CWEventMask,
1907
set_work_area_hint (MetaScreen *screen)
1911
unsigned long *data, *tmp;
1914
num_workspaces = meta_screen_get_n_workspaces (screen);
1915
data = g_new (unsigned long, num_workspaces * 4);
1916
tmp_list = screen->workspaces;
1919
while (tmp_list != NULL)
1921
MetaWorkspace *workspace = tmp_list->data;
1923
if (workspace->screen == screen)
1925
meta_workspace_get_work_area_all_xineramas (workspace, &area);
1928
tmp[2] = area.width;
1929
tmp[3] = area.height;
1934
tmp_list = tmp_list->next;
1937
meta_error_trap_push (screen->display);
1938
XChangeProperty (screen->display->xdisplay, screen->xroot,
1939
screen->display->atom__NET_WORKAREA,
1940
XA_CARDINAL, 32, PropModeReplace,
1941
(guchar*) data, num_workspaces*4);
1943
meta_error_trap_pop (screen->display, FALSE);
1947
set_work_area_idle_func (MetaScreen *screen)
1949
meta_topic (META_DEBUG_WORKAREA,
1950
"Running work area idle function\n");
1952
screen->work_area_idle = 0;
1954
set_work_area_hint (screen);
1960
meta_screen_queue_workarea_recalc (MetaScreen *screen)
1962
/* Recompute work area in an idle */
1963
if (screen->work_area_idle == 0)
1965
meta_topic (META_DEBUG_WORKAREA,
1966
"Adding work area hint idle function\n");
1967
screen->work_area_idle =
1968
g_idle_add_full (META_PRIORITY_WORK_AREA_HINT,
1969
(GSourceFunc) set_work_area_idle_func,
1976
#ifdef WITH_VERBOSE_MODE
1978
meta_screen_corner_to_string (MetaScreenCorner corner)
1982
case META_SCREEN_TOPLEFT:
1984
case META_SCREEN_TOPRIGHT:
1986
case META_SCREEN_BOTTOMLEFT:
1987
return "BottomLeft";
1988
case META_SCREEN_BOTTOMRIGHT:
1989
return "BottomRight";
1994
#endif /* WITH_VERBOSE_MODE */
1997
meta_screen_calc_workspace_layout (MetaScreen *screen,
2000
MetaWorkspaceLayout *layout)
2006
int current_row, current_col;
2008
rows = screen->rows_of_workspaces;
2009
cols = screen->columns_of_workspaces;
2010
if (rows <= 0 && cols <= 0)
2011
cols = num_workspaces;
2014
rows = num_workspaces / cols + ((num_workspaces % cols) > 0 ? 1 : 0);
2016
cols = num_workspaces / rows + ((num_workspaces % rows) > 0 ? 1 : 0);
2024
g_assert (rows != 0 && cols != 0);
2026
grid_area = rows * cols;
2028
meta_verbose ("Getting layout rows = %d cols = %d current = %d "
2029
"num_spaces = %d vertical = %s corner = %s\n",
2030
rows, cols, current_space, num_workspaces,
2031
screen->vertical_workspaces ? "(true)" : "(false)",
2032
meta_screen_corner_to_string (screen->starting_corner));
2034
/* ok, we want to setup the distances in the workspace array to go
2035
* in each direction. Remember, there are many ways that a workspace
2036
* array can be setup.
2037
* see http://www.freedesktop.org/standards/wm-spec/1.2/html/x109.html
2038
* and look at the _NET_DESKTOP_LAYOUT section for details.
2041
/* starting_corner = META_SCREEN_TOPLEFT
2042
* vertical_workspaces = 0 vertical_workspaces=1
2046
* starting_corner = META_SCREEN_TOPRIGHT
2047
* vertical_workspaces = 0 vertical_workspaces=1
2051
* starting_corner = META_SCREEN_BOTTOMLEFT
2052
* vertical_workspaces = 0 vertical_workspaces=1
2056
* starting_corner = META_SCREEN_BOTTOMRIGHT
2057
* vertical_workspaces = 0 vertical_workspaces=1
2062
/* keep in mind that we could have a ragged layout, e.g. the "8"
2063
* in the above grids could be missing
2067
grid = g_new (int, grid_area);
2073
switch (screen->starting_corner)
2075
case META_SCREEN_TOPLEFT:
2076
if (screen->vertical_workspaces)
2107
case META_SCREEN_TOPRIGHT:
2108
if (screen->vertical_workspaces)
2139
case META_SCREEN_BOTTOMLEFT:
2140
if (screen->vertical_workspaces)
2171
case META_SCREEN_BOTTOMRIGHT:
2172
if (screen->vertical_workspaces)
2206
meta_bug ("did not fill in the whole workspace grid in %s (%d filled)\n",
2217
if (grid[r*cols+c] == current_space)
2222
else if (grid[r*cols+c] >= num_workspaces)
2224
/* flag nonexistent spaces with -1 */
2225
grid[r*cols+c] = -1;
2232
layout->rows = rows;
2233
layout->cols = cols;
2234
layout->grid = grid;
2235
layout->grid_area = grid_area;
2236
layout->current_row = current_row;
2237
layout->current_col = current_col;
2239
#ifdef WITH_VERBOSE_MODE
2240
if (meta_is_verbose ())
2243
while (r < layout->rows)
2246
meta_push_no_msg_prefix ();
2248
while (c < layout->cols)
2250
if (r == layout->current_row &&
2251
c == layout->current_col)
2252
meta_verbose ("*%2d ", layout->grid[r*layout->cols+c]);
2254
meta_verbose ("%3d ", layout->grid[r*layout->cols+c]);
2257
meta_verbose ("\n");
2258
meta_pop_no_msg_prefix ();
2262
#endif /* WITH_VERBOSE_MODE */
2266
meta_screen_free_workspace_layout (MetaWorkspaceLayout *layout)
2268
g_free (layout->grid);
2272
meta_screen_resize_func (MetaScreen *screen,
2278
meta_window_update_struts (window);
2280
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
2282
meta_window_recalc_features (window);
2286
meta_screen_resize (MetaScreen *screen,
2290
screen->rect.width = width;
2291
screen->rect.height = height;
2293
reload_xinerama_infos (screen);
2294
set_desktop_geometry_hint (screen);
2296
/* Queue a resize on all the windows */
2297
meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
2301
meta_screen_update_showing_desktop_hint (MetaScreen *screen)
2303
unsigned long data[1];
2305
data[0] = screen->active_workspace->showing_desktop ? 1 : 0;
2307
meta_error_trap_push (screen->display);
2308
XChangeProperty (screen->display->xdisplay, screen->xroot,
2309
screen->display->atom__NET_SHOWING_DESKTOP,
2311
32, PropModeReplace, (guchar*) data, 1);
2312
meta_error_trap_pop (screen->display, FALSE);
2316
queue_windows_showing (MetaScreen *screen)
2321
/* Must operate on all windows on display instead of just on the
2322
* active_workspace's window list, because the active_workspace's
2323
* window list may not contain the on_all_workspace windows.
2325
windows = meta_display_list_windows (screen->display);
2330
MetaWindow *w = tmp->data;
2332
if (w->screen == screen)
2333
meta_window_queue (w, META_QUEUE_CALC_SHOWING);
2338
g_slist_free (windows);
2342
meta_screen_minimize_all_on_active_workspace_except (MetaScreen *screen,
2348
windows = screen->active_workspace->windows;
2353
MetaWindow *w = tmp->data;
2355
if (w->screen == screen &&
2356
w->has_minimize_func &&
2358
meta_window_minimize (w);
2365
meta_screen_show_desktop (MetaScreen *screen,
2370
if (screen->active_workspace->showing_desktop)
2373
screen->active_workspace->showing_desktop = TRUE;
2375
queue_windows_showing (screen);
2377
/* Focus the most recently used META_WINDOW_DESKTOP window, if there is one;
2380
windows = screen->active_workspace->mru_list;
2381
while (windows != NULL)
2383
MetaWindow *w = windows->data;
2385
if (w->screen == screen &&
2386
w->type == META_WINDOW_DESKTOP)
2388
meta_window_focus (w, timestamp);
2392
windows = windows->next;
2396
meta_screen_update_showing_desktop_hint (screen);
2400
meta_screen_unshow_desktop (MetaScreen *screen)
2402
if (!screen->active_workspace->showing_desktop)
2405
screen->active_workspace->showing_desktop = FALSE;
2407
queue_windows_showing (screen);
2409
meta_screen_update_showing_desktop_hint (screen);
2413
#ifdef HAVE_STARTUP_NOTIFICATION
2414
static gboolean startup_sequence_timeout (void *data);
2417
update_startup_feedback (MetaScreen *screen)
2419
if (screen->startup_sequences != NULL)
2421
meta_topic (META_DEBUG_STARTUP,
2422
"Setting busy cursor\n");
2423
meta_screen_set_cursor (screen, META_CURSOR_BUSY);
2427
meta_topic (META_DEBUG_STARTUP,
2428
"Setting default cursor\n");
2429
meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
2434
add_sequence (MetaScreen *screen,
2435
SnStartupSequence *sequence)
2437
meta_topic (META_DEBUG_STARTUP,
2438
"Adding sequence %s\n",
2439
sn_startup_sequence_get_id (sequence));
2440
sn_startup_sequence_ref (sequence);
2441
screen->startup_sequences = g_slist_prepend (screen->startup_sequences,
2444
/* our timeout just polls every second, instead of bothering
2445
* to compute exactly when we may next time out
2447
if (screen->startup_sequence_timeout == 0)
2448
screen->startup_sequence_timeout = g_timeout_add (1000,
2449
startup_sequence_timeout,
2452
update_startup_feedback (screen);
2456
remove_sequence (MetaScreen *screen,
2457
SnStartupSequence *sequence)
2459
meta_topic (META_DEBUG_STARTUP,
2460
"Removing sequence %s\n",
2461
sn_startup_sequence_get_id (sequence));
2463
screen->startup_sequences = g_slist_remove (screen->startup_sequences,
2465
sn_startup_sequence_unref (sequence);
2467
if (screen->startup_sequences == NULL &&
2468
screen->startup_sequence_timeout != 0)
2470
g_source_remove (screen->startup_sequence_timeout);
2471
screen->startup_sequence_timeout = 0;
2474
update_startup_feedback (screen);
2481
} CollectTimedOutData;
2483
/* This should be fairly long, as it should never be required unless
2484
* apps or .desktop files are buggy, and it's confusing if
2485
* OpenOffice or whatever seems to stop launching - people
2486
* might decide they need to launch it again.
2488
#define STARTUP_TIMEOUT 15000
2491
collect_timed_out_foreach (void *element,
2494
CollectTimedOutData *ctod = data;
2495
SnStartupSequence *sequence = element;
2496
long tv_sec, tv_usec;
2499
sn_startup_sequence_get_last_active_time (sequence, &tv_sec, &tv_usec);
2502
((((double)ctod->now.tv_sec - tv_sec) * G_USEC_PER_SEC +
2503
(ctod->now.tv_usec - tv_usec))) / 1000.0;
2505
meta_topic (META_DEBUG_STARTUP,
2506
"Sequence used %g seconds vs. %g max: %s\n",
2507
elapsed, (double) STARTUP_TIMEOUT,
2508
sn_startup_sequence_get_id (sequence));
2510
if (elapsed > STARTUP_TIMEOUT)
2511
ctod->list = g_slist_prepend (ctod->list, sequence);
2515
startup_sequence_timeout (void *data)
2517
MetaScreen *screen = data;
2518
CollectTimedOutData ctod;
2522
g_get_current_time (&ctod.now);
2523
g_slist_foreach (screen->startup_sequences,
2524
collect_timed_out_foreach,
2530
SnStartupSequence *sequence = tmp->data;
2532
meta_topic (META_DEBUG_STARTUP,
2533
"Timed out sequence %s\n",
2534
sn_startup_sequence_get_id (sequence));
2536
sn_startup_sequence_complete (sequence);
2541
g_slist_free (ctod.list);
2543
if (screen->startup_sequences != NULL)
2550
screen->startup_sequence_timeout = 0;
2556
meta_screen_sn_event (SnMonitorEvent *event,
2560
SnStartupSequence *sequence;
2564
sequence = sn_monitor_event_get_startup_sequence (event);
2566
switch (sn_monitor_event_get_type (event))
2568
case SN_MONITOR_EVENT_INITIATED:
2570
const char *wmclass;
2572
wmclass = sn_startup_sequence_get_wmclass (sequence);
2574
meta_topic (META_DEBUG_STARTUP,
2575
"Received startup initiated for %s wmclass %s\n",
2576
sn_startup_sequence_get_id (sequence),
2577
wmclass ? wmclass : "(unset)");
2578
add_sequence (screen, sequence);
2582
case SN_MONITOR_EVENT_COMPLETED:
2584
meta_topic (META_DEBUG_STARTUP,
2585
"Received startup completed for %s\n",
2586
sn_startup_sequence_get_id (sequence));
2587
remove_sequence (screen,
2588
sn_monitor_event_get_startup_sequence (event));
2592
case SN_MONITOR_EVENT_CHANGED:
2593
meta_topic (META_DEBUG_STARTUP,
2594
"Received startup changed for %s\n",
2595
sn_startup_sequence_get_id (sequence));
2598
case SN_MONITOR_EVENT_CANCELED:
2599
meta_topic (META_DEBUG_STARTUP,
2600
"Received startup canceled for %s\n",
2601
sn_startup_sequence_get_id (sequence));
2607
/* Sets the initial_timestamp and initial_workspace properties
2608
* of a window according to information given us by the
2609
* startup-notification library.
2611
* Returns TRUE if startup properties have been applied, and
2612
* FALSE if they have not (for example, if they had already
2616
meta_screen_apply_startup_properties (MetaScreen *screen,
2619
#ifdef HAVE_STARTUP_NOTIFICATION
2620
const char *startup_id;
2622
SnStartupSequence *sequence;
2624
/* Does the window have a startup ID stored? */
2625
startup_id = meta_window_get_startup_id (window);
2627
meta_topic (META_DEBUG_STARTUP,
2628
"Applying startup props to %s id \"%s\"\n",
2630
startup_id ? startup_id : "(none)");
2633
if (startup_id == NULL)
2635
/* No startup ID stored for the window. Let's ask the
2636
* startup-notification library whether there's anything
2637
* stored for the resource name or resource class hints.
2639
tmp = screen->startup_sequences;
2642
const char *wmclass;
2644
wmclass = sn_startup_sequence_get_wmclass (tmp->data);
2646
if (wmclass != NULL &&
2647
((window->res_class &&
2648
strcmp (wmclass, window->res_class) == 0) ||
2649
(window->res_name &&
2650
strcmp (wmclass, window->res_name) == 0)))
2652
sequence = tmp->data;
2654
g_assert (window->startup_id == NULL);
2655
window->startup_id = g_strdup (sn_startup_sequence_get_id (sequence));
2656
startup_id = window->startup_id;
2658
meta_topic (META_DEBUG_STARTUP,
2659
"Ending legacy sequence %s due to window %s\n",
2660
sn_startup_sequence_get_id (sequence),
2663
sn_startup_sequence_complete (sequence);
2671
/* Still no startup ID? Bail. */
2672
if (startup_id == NULL)
2675
/* We might get this far and not know the sequence ID (if the window
2676
* already had a startup ID stored), so let's look for one if we don't
2679
if (sequence == NULL)
2681
tmp = screen->startup_sequences;
2686
id = sn_startup_sequence_get_id (tmp->data);
2688
if (strcmp (id, startup_id) == 0)
2690
sequence = tmp->data;
2698
if (sequence != NULL)
2700
gboolean changed_something = FALSE;
2702
meta_topic (META_DEBUG_STARTUP,
2703
"Found startup sequence for window %s ID \"%s\"\n",
2704
window->desc, startup_id);
2706
if (!window->initial_workspace_set)
2708
int space = sn_startup_sequence_get_workspace (sequence);
2711
meta_topic (META_DEBUG_STARTUP,
2712
"Setting initial window workspace to %d based on startup info\n",
2715
window->initial_workspace_set = TRUE;
2716
window->initial_workspace = space;
2717
changed_something = TRUE;
2721
if (!window->initial_timestamp_set)
2723
guint32 timestamp = sn_startup_sequence_get_timestamp (sequence);
2724
meta_topic (META_DEBUG_STARTUP,
2725
"Setting initial window timestamp to %u based on startup info\n",
2728
window->initial_timestamp_set = TRUE;
2729
window->initial_timestamp = timestamp;
2730
changed_something = TRUE;
2733
return changed_something;
2737
meta_topic (META_DEBUG_STARTUP,
2738
"Did not find startup sequence for window %s ID \"%s\"\n",
2739
window->desc, startup_id);
2742
#endif /* HAVE_STARTUP_NOTIFICATION */
2748
meta_screen_get_screen_number (MetaScreen *screen)
2750
return screen->number;
2754
meta_screen_get_display (MetaScreen *screen)
2756
return screen->display;
2760
meta_screen_get_xroot (MetaScreen *screen)
2762
return screen->xroot;
2766
meta_screen_get_size (MetaScreen *screen,
2770
*width = screen->rect.width;
2771
*height = screen->rect.height;
2775
meta_screen_get_compositor_data (MetaScreen *screen)
2777
return screen->compositor_data;
2781
meta_screen_set_compositor_data (MetaScreen *screen,
2782
gpointer compositor)
2784
screen->compositor_data = compositor;
2787
#ifdef HAVE_COMPOSITE_EXTENSIONS
2789
meta_screen_set_cm_selection (MetaScreen *screen)
2794
screen->wm_cm_timestamp = meta_display_get_current_time_roundtrip (
2797
g_snprintf (selection, sizeof(selection), "_NET_WM_CM_S%d", screen->number);
2798
meta_verbose ("Setting selection: %s\n", selection);
2799
a = XInternAtom (screen->display->xdisplay, selection, FALSE);
2800
XSetSelectionOwner (screen->display->xdisplay, a,
2801
screen->wm_cm_selection_window, screen->wm_cm_timestamp);
2805
meta_screen_unset_cm_selection (MetaScreen *screen)
2810
g_snprintf (selection, sizeof(selection), "_NET_WM_CM_S%d", screen->number);
2811
a = XInternAtom (screen->display->xdisplay, selection, FALSE);
2812
XSetSelectionOwner (screen->display->xdisplay, a,
2813
None, screen->wm_cm_timestamp);
2815
#endif /* HAVE_COMPOSITE_EXTENSIONS */