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