]> Dogcows Code - chaz/openbox/blob - openbox/screen.c
g_spawn_async wants a char**, not const
[chaz/openbox] / openbox / screen.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 screen.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "debug.h"
21 #include "openbox.h"
22 #include "dock.h"
23 #include "xerror.h"
24 #include "prop.h"
25 #include "grab.h"
26 #include "startupnotify.h"
27 #include "moveresize.h"
28 #include "config.h"
29 #include "screen.h"
30 #include "client.h"
31 #include "session.h"
32 #include "frame.h"
33 #include "event.h"
34 #include "focus.h"
35 #include "popup.h"
36 #include "extensions.h"
37 #include "render/render.h"
38 #include "gettext.h"
39
40 #include <X11/Xlib.h>
41 #ifdef HAVE_UNISTD_H
42 # include <sys/types.h>
43 # include <unistd.h>
44 #endif
45 #include <assert.h>
46
47 /*! The event mask to grab on the root window */
48 #define ROOT_EVENTMASK (StructureNotifyMask | PropertyChangeMask | \
49 EnterWindowMask | LeaveWindowMask | \
50 SubstructureRedirectMask | FocusChangeMask | \
51 ButtonPressMask | ButtonReleaseMask | ButtonMotionMask)
52
53 static gboolean screen_validate_layout(ObDesktopLayout *l);
54 static gboolean replace_wm();
55 static void screen_tell_ksplash();
56
57 guint screen_num_desktops;
58 guint screen_num_monitors;
59 guint screen_desktop;
60 guint screen_last_desktop;
61 Size screen_physical_size;
62 gboolean screen_showing_desktop;
63 ObDesktopLayout screen_desktop_layout;
64 gchar **screen_desktop_names;
65 Window screen_support_win;
66 Time screen_desktop_user_time = CurrentTime;
67
68 static Rect **area; /* array of desktop holding array of xinerama areas */
69 static Rect *monitor_area;
70
71 static ObPagerPopup *desktop_cycle_popup;
72
73 static gboolean replace_wm()
74 {
75 gchar *wm_sn;
76 Atom wm_sn_atom;
77 Window current_wm_sn_owner;
78 Time timestamp;
79
80 wm_sn = g_strdup_printf("WM_S%d", ob_screen);
81 wm_sn_atom = XInternAtom(ob_display, wm_sn, FALSE);
82 g_free(wm_sn);
83
84 current_wm_sn_owner = XGetSelectionOwner(ob_display, wm_sn_atom);
85 if (current_wm_sn_owner == screen_support_win)
86 current_wm_sn_owner = None;
87 if (current_wm_sn_owner) {
88 if (!ob_replace_wm) {
89 g_message(_("A window manager is already running on screen %d"),
90 ob_screen);
91 return FALSE;
92 }
93 xerror_set_ignore(TRUE);
94 xerror_occured = FALSE;
95
96 /* We want to find out when the current selection owner dies */
97 XSelectInput(ob_display, current_wm_sn_owner, StructureNotifyMask);
98 XSync(ob_display, FALSE);
99
100 xerror_set_ignore(FALSE);
101 if (xerror_occured)
102 current_wm_sn_owner = None;
103 }
104
105 {
106 /* Generate a timestamp */
107 XEvent event;
108
109 XSelectInput(ob_display, screen_support_win, PropertyChangeMask);
110
111 XChangeProperty(ob_display, screen_support_win,
112 prop_atoms.wm_class, prop_atoms.string,
113 8, PropModeAppend, NULL, 0);
114 XWindowEvent(ob_display, screen_support_win,
115 PropertyChangeMask, &event);
116
117 XSelectInput(ob_display, screen_support_win, NoEventMask);
118
119 timestamp = event.xproperty.time;
120 }
121
122 XSetSelectionOwner(ob_display, wm_sn_atom, screen_support_win,
123 timestamp);
124
125 if (XGetSelectionOwner(ob_display, wm_sn_atom) != screen_support_win) {
126 g_message(_("Could not acquire window manager selection on screen %d"),
127 ob_screen);
128 return FALSE;
129 }
130
131 /* Wait for old window manager to go away */
132 if (current_wm_sn_owner) {
133 XEvent event;
134 gulong wait = 0;
135 const gulong timeout = G_USEC_PER_SEC * 15; /* wait for 15s max */
136
137 while (wait < timeout) {
138 if (XCheckWindowEvent(ob_display, current_wm_sn_owner,
139 StructureNotifyMask, &event) &&
140 event.type == DestroyNotify)
141 break;
142 g_usleep(G_USEC_PER_SEC / 10);
143 wait += G_USEC_PER_SEC / 10;
144 }
145
146 if (wait >= timeout) {
147 g_message(_("The WM on screen %d is not exiting"), ob_screen);
148 return FALSE;
149 }
150 }
151
152 /* Send client message indicating that we are now the WM */
153 prop_message(RootWindow(ob_display, ob_screen), prop_atoms.manager,
154 timestamp, wm_sn_atom, screen_support_win, 0,
155 SubstructureNotifyMask);
156
157 return TRUE;
158 }
159
160 gboolean screen_annex()
161 {
162 XSetWindowAttributes attrib;
163 pid_t pid;
164 gint i, num_support;
165 Atom *prop_atoms_start, *wm_supported_pos;
166 gulong *supported;
167
168 /* create the netwm support window */
169 attrib.override_redirect = TRUE;
170 screen_support_win = XCreateWindow(ob_display,
171 RootWindow(ob_display, ob_screen),
172 -100, -100, 1, 1, 0,
173 CopyFromParent, InputOutput,
174 CopyFromParent,
175 CWOverrideRedirect, &attrib);
176 XMapWindow(ob_display, screen_support_win);
177 XLowerWindow(ob_display, screen_support_win);
178
179 if (!replace_wm()) {
180 XDestroyWindow(ob_display, screen_support_win);
181 return FALSE;
182 }
183
184 xerror_set_ignore(TRUE);
185 xerror_occured = FALSE;
186 XSelectInput(ob_display, RootWindow(ob_display, ob_screen),
187 ROOT_EVENTMASK);
188 xerror_set_ignore(FALSE);
189 if (xerror_occured) {
190 g_message(_("A window manager is already running on screen %d"),
191 ob_screen);
192
193 XDestroyWindow(ob_display, screen_support_win);
194 return FALSE;
195 }
196
197 screen_set_root_cursor();
198
199 /* set the OPENBOX_PID hint */
200 pid = getpid();
201 PROP_SET32(RootWindow(ob_display, ob_screen),
202 openbox_pid, cardinal, pid);
203
204 /* set supporting window */
205 PROP_SET32(RootWindow(ob_display, ob_screen),
206 net_supporting_wm_check, window, screen_support_win);
207
208 /* set properties on the supporting window */
209 PROP_SETS(screen_support_win, net_wm_name, "Openbox");
210 PROP_SET32(screen_support_win, net_supporting_wm_check,
211 window, screen_support_win);
212
213 /* set the _NET_SUPPORTED_ATOMS hint */
214
215 /* this is all the atoms after net_supported in the prop_atoms struct */
216 prop_atoms_start = (Atom*)&prop_atoms;
217 wm_supported_pos = (Atom*)&(prop_atoms.net_supported);
218 num_support = sizeof(prop_atoms) / sizeof(Atom) -
219 (wm_supported_pos - prop_atoms_start) - 1;
220 i = 0;
221 supported = g_new(gulong, num_support);
222 supported[i++] = prop_atoms.net_supporting_wm_check;
223 supported[i++] = prop_atoms.net_wm_full_placement;
224 supported[i++] = prop_atoms.net_current_desktop;
225 supported[i++] = prop_atoms.net_number_of_desktops;
226 supported[i++] = prop_atoms.net_desktop_geometry;
227 supported[i++] = prop_atoms.net_desktop_viewport;
228 supported[i++] = prop_atoms.net_active_window;
229 supported[i++] = prop_atoms.net_workarea;
230 supported[i++] = prop_atoms.net_client_list;
231 supported[i++] = prop_atoms.net_client_list_stacking;
232 supported[i++] = prop_atoms.net_desktop_names;
233 supported[i++] = prop_atoms.net_close_window;
234 supported[i++] = prop_atoms.net_desktop_layout;
235 supported[i++] = prop_atoms.net_showing_desktop;
236 supported[i++] = prop_atoms.net_wm_name;
237 supported[i++] = prop_atoms.net_wm_visible_name;
238 supported[i++] = prop_atoms.net_wm_icon_name;
239 supported[i++] = prop_atoms.net_wm_visible_icon_name;
240 supported[i++] = prop_atoms.net_wm_desktop;
241 supported[i++] = prop_atoms.net_wm_strut;
242 supported[i++] = prop_atoms.net_wm_strut_partial;
243 supported[i++] = prop_atoms.net_wm_icon;
244 supported[i++] = prop_atoms.net_wm_icon_geometry;
245 supported[i++] = prop_atoms.net_wm_window_type;
246 supported[i++] = prop_atoms.net_wm_window_type_desktop;
247 supported[i++] = prop_atoms.net_wm_window_type_dock;
248 supported[i++] = prop_atoms.net_wm_window_type_toolbar;
249 supported[i++] = prop_atoms.net_wm_window_type_menu;
250 supported[i++] = prop_atoms.net_wm_window_type_utility;
251 supported[i++] = prop_atoms.net_wm_window_type_splash;
252 supported[i++] = prop_atoms.net_wm_window_type_dialog;
253 supported[i++] = prop_atoms.net_wm_window_type_normal;
254 supported[i++] = prop_atoms.net_wm_allowed_actions;
255 supported[i++] = prop_atoms.net_wm_action_move;
256 supported[i++] = prop_atoms.net_wm_action_resize;
257 supported[i++] = prop_atoms.net_wm_action_minimize;
258 supported[i++] = prop_atoms.net_wm_action_shade;
259 supported[i++] = prop_atoms.net_wm_action_maximize_horz;
260 supported[i++] = prop_atoms.net_wm_action_maximize_vert;
261 supported[i++] = prop_atoms.net_wm_action_fullscreen;
262 supported[i++] = prop_atoms.net_wm_action_change_desktop;
263 supported[i++] = prop_atoms.net_wm_action_close;
264 supported[i++] = prop_atoms.net_wm_action_above;
265 supported[i++] = prop_atoms.net_wm_action_below;
266 supported[i++] = prop_atoms.net_wm_state;
267 supported[i++] = prop_atoms.net_wm_state_modal;
268 supported[i++] = prop_atoms.net_wm_state_maximized_vert;
269 supported[i++] = prop_atoms.net_wm_state_maximized_horz;
270 supported[i++] = prop_atoms.net_wm_state_shaded;
271 supported[i++] = prop_atoms.net_wm_state_skip_taskbar;
272 supported[i++] = prop_atoms.net_wm_state_skip_pager;
273 supported[i++] = prop_atoms.net_wm_state_hidden;
274 supported[i++] = prop_atoms.net_wm_state_fullscreen;
275 supported[i++] = prop_atoms.net_wm_state_above;
276 supported[i++] = prop_atoms.net_wm_state_below;
277 supported[i++] = prop_atoms.net_wm_state_demands_attention;
278 supported[i++] = prop_atoms.net_moveresize_window;
279 supported[i++] = prop_atoms.net_wm_moveresize;
280 supported[i++] = prop_atoms.net_wm_user_time;
281 supported[i++] = prop_atoms.net_wm_user_time_window;
282 supported[i++] = prop_atoms.net_frame_extents;
283 supported[i++] = prop_atoms.net_request_frame_extents;
284 supported[i++] = prop_atoms.net_restack_window;
285 supported[i++] = prop_atoms.net_startup_id;
286 #ifdef SYNC
287 supported[i++] = prop_atoms.net_wm_sync_request;
288 supported[i++] = prop_atoms.net_wm_sync_request_counter;
289 #endif
290
291 supported[i++] = prop_atoms.kde_wm_change_state;
292 supported[i++] = prop_atoms.kde_net_wm_frame_strut;
293 supported[i++] = prop_atoms.kde_net_wm_window_type_override;
294
295 supported[i++] = prop_atoms.ob_wm_action_undecorate;
296 supported[i++] = prop_atoms.ob_wm_state_undecorated;
297 supported[i++] = prop_atoms.openbox_pid;
298 supported[i++] = prop_atoms.ob_theme;
299 supported[i++] = prop_atoms.ob_control;
300 g_assert(i == num_support);
301
302 PROP_SETA32(RootWindow(ob_display, ob_screen),
303 net_supported, atom, supported, num_support);
304 g_free(supported);
305
306 screen_tell_ksplash();
307
308 return TRUE;
309 }
310
311 static void screen_tell_ksplash()
312 {
313 XEvent e;
314 char **argv;
315
316 argv = g_new(gchar*, 6);
317 argv[0] = g_strdup("dcop");
318 argv[1] = g_strdup("ksplash");
319 argv[2] = g_strdup("ksplash");
320 argv[3] = g_strdup("upAndRunning(QString)");
321 argv[4] = g_strdup("wm started");
322 argv[5] = NULL;
323
324 /* tell ksplash through the dcop server command line interface */
325 g_spawn_async(NULL, argv, NULL,
326 G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
327 NULL, NULL, NULL, NULL);
328 g_strfreev(argv);
329
330 /* i'm not sure why we do this, kwin does it, but ksplash doesn't seem to
331 hear it anyways. perhaps it is for old ksplash. or new ksplash. or
332 something. oh well. */
333 e.xclient.type = ClientMessage;
334 e.xclient.display = ob_display;
335 e.xclient.window = RootWindow(ob_display, ob_screen);
336 e.xclient.message_type =
337 XInternAtom(ob_display, "_KDE_SPLASH_PROGRESS", False );
338 e.xclient.format = 8;
339 strcpy(e.xclient.data.b, "wm started");
340 XSendEvent(ob_display, RootWindow(ob_display, ob_screen),
341 False, SubstructureNotifyMask, &e );
342 }
343
344 void screen_startup(gboolean reconfig)
345 {
346 gchar **names = NULL;
347 guint32 d;
348 gboolean namesexist = FALSE;
349
350 desktop_cycle_popup = pager_popup_new(FALSE);
351 pager_popup_height(desktop_cycle_popup, POPUP_HEIGHT);
352
353 if (reconfig) {
354 /* update the pager popup's width */
355 pager_popup_text_width_to_strings(desktop_cycle_popup,
356 screen_desktop_names,
357 screen_num_desktops);
358 return;
359 }
360
361 /* get the initial size */
362 screen_resize();
363
364 /* have names already been set for the desktops? */
365 if (PROP_GETSS(RootWindow(ob_display, ob_screen),
366 net_desktop_names, utf8, &names))
367 {
368 g_strfreev(names);
369 namesexist = TRUE;
370 }
371
372 /* if names don't exist and we have session names, set those.
373 do this stuff BEFORE setting the number of desktops, because that
374 will create default names for them
375 */
376 if (!namesexist && session_desktop_names != NULL) {
377 guint i, numnames;
378 GSList *it;
379
380 /* get the desktop names */
381 numnames = g_slist_length(session_desktop_names);
382 names = g_new(gchar*, numnames + 1);
383 names[numnames] = NULL;
384 for (i = 0, it = session_desktop_names; it; ++i, it = g_slist_next(it))
385 names[i] = g_strdup(it->data);
386
387 /* set the root window property */
388 PROP_SETSS(RootWindow(ob_display, ob_screen), net_desktop_names,names);
389
390 g_strfreev(names);
391 }
392
393 /* set the number of desktops, if it's not already set.
394
395 this will also set the default names from the config file up for
396 desktops that don't have names yet */
397 screen_num_desktops = 0;
398 if (PROP_GET32(RootWindow(ob_display, ob_screen),
399 net_number_of_desktops, cardinal, &d))
400 screen_set_num_desktops(d);
401 /* restore from session if possible */
402 else if (session_num_desktops)
403 screen_set_num_desktops(session_num_desktops);
404 else
405 screen_set_num_desktops(config_desktops_num);
406
407 screen_desktop = screen_num_desktops; /* something invalid */
408 /* start on the current desktop when a wm was already running */
409 if (PROP_GET32(RootWindow(ob_display, ob_screen),
410 net_current_desktop, cardinal, &d) &&
411 d < screen_num_desktops)
412 {
413 screen_set_desktop(d, FALSE);
414 } else if (session_desktop >= 0)
415 screen_set_desktop(MIN((guint)session_desktop,
416 screen_num_desktops), FALSE);
417 else
418 screen_set_desktop(MIN(config_screen_firstdesk,
419 screen_num_desktops) - 1, FALSE);
420 screen_last_desktop = screen_desktop;
421
422 /* don't start in showing-desktop mode */
423 screen_showing_desktop = FALSE;
424 PROP_SET32(RootWindow(ob_display, ob_screen),
425 net_showing_desktop, cardinal, screen_showing_desktop);
426
427 if (session_desktop_layout_present &&
428 screen_validate_layout(&session_desktop_layout))
429 {
430 screen_desktop_layout = session_desktop_layout;
431 }
432 else
433 screen_update_layout();
434 }
435
436 void screen_shutdown(gboolean reconfig)
437 {
438 Rect **r;
439
440 pager_popup_free(desktop_cycle_popup);
441
442 if (reconfig)
443 return;
444
445 XSelectInput(ob_display, RootWindow(ob_display, ob_screen),
446 NoEventMask);
447
448 /* we're not running here no more! */
449 PROP_ERASE(RootWindow(ob_display, ob_screen), openbox_pid);
450 /* not without us */
451 PROP_ERASE(RootWindow(ob_display, ob_screen), net_supported);
452 /* don't keep this mode */
453 PROP_ERASE(RootWindow(ob_display, ob_screen), net_showing_desktop);
454
455 XDestroyWindow(ob_display, screen_support_win);
456
457 g_strfreev(screen_desktop_names);
458 screen_desktop_names = NULL;
459
460 for (r = area; *r; ++r)
461 g_free(*r);
462 g_free(area);
463 area = NULL;
464 }
465
466 void screen_resize()
467 {
468 static gint oldw = 0, oldh = 0;
469 gint w, h;
470 GList *it;
471 gulong geometry[2];
472
473 w = WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen));
474 h = HeightOfScreen(ScreenOfDisplay(ob_display, ob_screen));
475
476 if (w == oldw && h == oldh) return;
477
478 oldw = w; oldh = h;
479
480 /* Set the _NET_DESKTOP_GEOMETRY hint */
481 screen_physical_size.width = geometry[0] = w;
482 screen_physical_size.height = geometry[1] = h;
483 PROP_SETA32(RootWindow(ob_display, ob_screen),
484 net_desktop_geometry, cardinal, geometry, 2);
485
486 if (ob_state() == OB_STATE_STARTING)
487 return;
488
489 screen_update_areas();
490 dock_configure();
491
492 for (it = client_list; it; it = g_list_next(it))
493 client_move_onscreen(it->data, FALSE);
494 }
495
496 void screen_set_num_desktops(guint num)
497 {
498 guint old;
499 gulong *viewport;
500 GList *it;
501
502 g_assert(num > 0);
503
504 if (screen_num_desktops == num) return;
505
506 old = screen_num_desktops;
507 screen_num_desktops = num;
508 PROP_SET32(RootWindow(ob_display, ob_screen),
509 net_number_of_desktops, cardinal, num);
510
511 /* set the viewport hint */
512 viewport = g_new0(gulong, num * 2);
513 PROP_SETA32(RootWindow(ob_display, ob_screen),
514 net_desktop_viewport, cardinal, viewport, num * 2);
515 g_free(viewport);
516
517 /* the number of rows/columns will differ */
518 screen_update_layout();
519
520 /* move windows on desktops that will no longer exist! */
521 for (it = client_list; it; it = g_list_next(it)) {
522 ObClient *c = it->data;
523 if (c->desktop >= num && c->desktop != DESKTOP_ALL)
524 client_set_desktop(c, num - 1, FALSE);
525 }
526
527 /* change our struts/area to match (after moving windows) */
528 screen_update_areas();
529
530 /* may be some unnamed desktops that we need to fill in with names
531 (after updating the areas so the popup can resize) */
532 screen_update_desktop_names();
533
534 /* change our desktop if we're on one that no longer exists! */
535 if (screen_desktop >= screen_num_desktops)
536 screen_set_desktop(num - 1, TRUE);
537 }
538
539 void screen_set_desktop(guint num, gboolean dofocus)
540 {
541 ObClient *c;
542 GList *it;
543 guint old;
544
545 g_assert(num < screen_num_desktops);
546
547 old = screen_desktop;
548 screen_desktop = num;
549
550 if (old == num) return;
551
552 PROP_SET32(RootWindow(ob_display, ob_screen),
553 net_current_desktop, cardinal, num);
554
555 screen_last_desktop = old;
556
557 ob_debug("Moving to desktop %d\n", num+1);
558
559 if (moveresize_client)
560 client_set_desktop(moveresize_client, num, TRUE);
561
562 /* show windows before hiding the rest to lessen the enter/leave events */
563
564 /* show windows from top to bottom */
565 for (it = stacking_list; it; it = g_list_next(it)) {
566 if (WINDOW_IS_CLIENT(it->data)) {
567 ObClient *c = it->data;
568 client_show(c);
569 }
570 }
571
572 if (focus_client && ((client_normal(focus_client) &&
573 focus_client->desktop == DESKTOP_ALL) ||
574 focus_client->desktop == screen_desktop))
575 dofocus = FALSE;
576
577 /* have to try focus here because when you leave an empty desktop
578 there is no focus out to watch for. also, we have different rules
579 here. we always allow it to look under the mouse pointer if
580 config_focus_last is FALSE
581
582 do this before hiding the windows so if helper windows are coming
583 with us, they don't get hidden
584 */
585 if (dofocus && (c = focus_fallback(TRUE, !config_focus_last)))
586 {
587 /* only do the flicker reducing stuff ahead of time if we are going
588 to call xsetinputfocus on the window ourselves. otherwise there is
589 no guarantee the window will actually take focus.. */
590 if (c->can_focus) {
591 /* reduce flicker by hiliting now rather than waiting for the
592 server FocusIn event */
593 frame_adjust_focus(c->frame, TRUE);
594 /* do this here so that if you switch desktops to a window with
595 helper windows then the helper windows won't flash */
596 client_bring_helper_windows(c);
597 }
598 }
599
600 /* hide windows from bottom to top */
601 for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) {
602 if (WINDOW_IS_CLIENT(it->data)) {
603 ObClient *c = it->data;
604 client_hide(c);
605 }
606 }
607
608 event_ignore_all_queued_enters();
609
610 if (event_curtime != CurrentTime)
611 screen_desktop_user_time = event_curtime;
612 }
613
614 static void get_row_col(guint d, guint *r, guint *c)
615 {
616 switch (screen_desktop_layout.orientation) {
617 case OB_ORIENTATION_HORZ:
618 switch (screen_desktop_layout.start_corner) {
619 case OB_CORNER_TOPLEFT:
620 *r = d / screen_desktop_layout.columns;
621 *c = d % screen_desktop_layout.columns;
622 break;
623 case OB_CORNER_BOTTOMLEFT:
624 *r = screen_desktop_layout.rows - 1 -
625 d / screen_desktop_layout.columns;
626 *c = d % screen_desktop_layout.columns;
627 break;
628 case OB_CORNER_TOPRIGHT:
629 *r = d / screen_desktop_layout.columns;
630 *c = screen_desktop_layout.columns - 1 -
631 d % screen_desktop_layout.columns;
632 break;
633 case OB_CORNER_BOTTOMRIGHT:
634 *r = screen_desktop_layout.rows - 1 -
635 d / screen_desktop_layout.columns;
636 *c = screen_desktop_layout.columns - 1 -
637 d % screen_desktop_layout.columns;
638 break;
639 }
640 break;
641 case OB_ORIENTATION_VERT:
642 switch (screen_desktop_layout.start_corner) {
643 case OB_CORNER_TOPLEFT:
644 *r = d % screen_desktop_layout.rows;
645 *c = d / screen_desktop_layout.rows;
646 break;
647 case OB_CORNER_BOTTOMLEFT:
648 *r = screen_desktop_layout.rows - 1 -
649 d % screen_desktop_layout.rows;
650 *c = d / screen_desktop_layout.rows;
651 break;
652 case OB_CORNER_TOPRIGHT:
653 *r = d % screen_desktop_layout.rows;
654 *c = screen_desktop_layout.columns - 1 -
655 d / screen_desktop_layout.rows;
656 break;
657 case OB_CORNER_BOTTOMRIGHT:
658 *r = screen_desktop_layout.rows - 1 -
659 d % screen_desktop_layout.rows;
660 *c = screen_desktop_layout.columns - 1 -
661 d / screen_desktop_layout.rows;
662 break;
663 }
664 break;
665 }
666 }
667
668 static guint translate_row_col(guint r, guint c)
669 {
670 switch (screen_desktop_layout.orientation) {
671 case OB_ORIENTATION_HORZ:
672 switch (screen_desktop_layout.start_corner) {
673 case OB_CORNER_TOPLEFT:
674 return r % screen_desktop_layout.rows *
675 screen_desktop_layout.columns +
676 c % screen_desktop_layout.columns;
677 case OB_CORNER_BOTTOMLEFT:
678 return (screen_desktop_layout.rows - 1 -
679 r % screen_desktop_layout.rows) *
680 screen_desktop_layout.columns +
681 c % screen_desktop_layout.columns;
682 case OB_CORNER_TOPRIGHT:
683 return r % screen_desktop_layout.rows *
684 screen_desktop_layout.columns +
685 (screen_desktop_layout.columns - 1 -
686 c % screen_desktop_layout.columns);
687 case OB_CORNER_BOTTOMRIGHT:
688 return (screen_desktop_layout.rows - 1 -
689 r % screen_desktop_layout.rows) *
690 screen_desktop_layout.columns +
691 (screen_desktop_layout.columns - 1 -
692 c % screen_desktop_layout.columns);
693 }
694 case OB_ORIENTATION_VERT:
695 switch (screen_desktop_layout.start_corner) {
696 case OB_CORNER_TOPLEFT:
697 return c % screen_desktop_layout.columns *
698 screen_desktop_layout.rows +
699 r % screen_desktop_layout.rows;
700 case OB_CORNER_BOTTOMLEFT:
701 return c % screen_desktop_layout.columns *
702 screen_desktop_layout.rows +
703 (screen_desktop_layout.rows - 1 -
704 r % screen_desktop_layout.rows);
705 case OB_CORNER_TOPRIGHT:
706 return (screen_desktop_layout.columns - 1 -
707 c % screen_desktop_layout.columns) *
708 screen_desktop_layout.rows +
709 r % screen_desktop_layout.rows;
710 case OB_CORNER_BOTTOMRIGHT:
711 return (screen_desktop_layout.columns - 1 -
712 c % screen_desktop_layout.columns) *
713 screen_desktop_layout.rows +
714 (screen_desktop_layout.rows - 1 -
715 r % screen_desktop_layout.rows);
716 }
717 }
718 g_assert_not_reached();
719 return 0;
720 }
721
722 void screen_desktop_popup(guint d, gboolean show)
723 {
724 Rect *a;
725
726 if (!show) {
727 pager_popup_hide(desktop_cycle_popup);
728 } else {
729 a = screen_physical_area_monitor(0);
730 pager_popup_position(desktop_cycle_popup, CenterGravity,
731 a->x + a->width / 2, a->y + a->height / 2);
732 pager_popup_icon_size_multiplier(desktop_cycle_popup,
733 (screen_desktop_layout.columns /
734 screen_desktop_layout.rows) / 2,
735 (screen_desktop_layout.rows/
736 screen_desktop_layout.columns) / 2);
737 pager_popup_max_width(desktop_cycle_popup,
738 MAX(a->width/3, POPUP_WIDTH));
739 pager_popup_show(desktop_cycle_popup, screen_desktop_names[d], d);
740 }
741 }
742
743 guint screen_cycle_desktop(ObDirection dir, gboolean wrap, gboolean linear,
744 gboolean dialog, gboolean done, gboolean cancel)
745 {
746 guint r, c;
747 static guint d = (guint)-1;
748 guint ret, oldd;
749
750 if (d == (guint)-1)
751 d = screen_desktop;
752
753 if ((cancel || done) && dialog)
754 goto show_cycle_dialog;
755
756 oldd = d;
757 get_row_col(d, &r, &c);
758
759 if (linear) {
760 switch (dir) {
761 case OB_DIRECTION_EAST:
762 if (d < screen_num_desktops - 1)
763 ++d;
764 else if (wrap)
765 d = 0;
766 break;
767 case OB_DIRECTION_WEST:
768 if (d > 0)
769 --d;
770 else if (wrap)
771 d = screen_num_desktops - 1;
772 break;
773 default:
774 assert(0);
775 return screen_desktop;
776 }
777 } else {
778 switch (dir) {
779 case OB_DIRECTION_EAST:
780 ++c;
781 if (c >= screen_desktop_layout.columns) {
782 if (wrap)
783 c = 0;
784 else
785 goto show_cycle_dialog;
786 }
787 d = translate_row_col(r, c);
788 if (d >= screen_num_desktops) {
789 if (wrap) {
790 ++c;
791 } else {
792 d = oldd;
793 goto show_cycle_dialog;
794 }
795 }
796 break;
797 case OB_DIRECTION_WEST:
798 --c;
799 if (c >= screen_desktop_layout.columns) {
800 if (wrap)
801 c = screen_desktop_layout.columns - 1;
802 else
803 goto show_cycle_dialog;
804 }
805 d = translate_row_col(r, c);
806 if (d >= screen_num_desktops) {
807 if (wrap) {
808 --c;
809 } else {
810 d = oldd;
811 goto show_cycle_dialog;
812 }
813 }
814 break;
815 case OB_DIRECTION_SOUTH:
816 ++r;
817 if (r >= screen_desktop_layout.rows) {
818 if (wrap)
819 r = 0;
820 else
821 goto show_cycle_dialog;
822 }
823 d = translate_row_col(r, c);
824 if (d >= screen_num_desktops) {
825 if (wrap) {
826 ++r;
827 } else {
828 d = oldd;
829 goto show_cycle_dialog;
830 }
831 }
832 break;
833 case OB_DIRECTION_NORTH:
834 --r;
835 if (r >= screen_desktop_layout.rows) {
836 if (wrap)
837 r = screen_desktop_layout.rows - 1;
838 else
839 goto show_cycle_dialog;
840 }
841 d = translate_row_col(r, c);
842 if (d >= screen_num_desktops) {
843 if (wrap) {
844 --r;
845 } else {
846 d = oldd;
847 goto show_cycle_dialog;
848 }
849 }
850 break;
851 default:
852 assert(0);
853 return d = screen_desktop;
854 }
855
856 d = translate_row_col(r, c);
857 }
858
859 show_cycle_dialog:
860 if (dialog && !cancel && !done) {
861 screen_desktop_popup(d, TRUE);
862 } else
863 screen_desktop_popup(0, FALSE);
864 ret = d;
865
866 if (!dialog || cancel || done)
867 d = (guint)-1;
868
869 return ret;
870 }
871
872 static gboolean screen_validate_layout(ObDesktopLayout *l)
873 {
874 if (l->columns == 0 && l->rows == 0) /* both 0's is bad data.. */
875 return FALSE;
876
877 /* fill in a zero rows/columns */
878 if (l->columns == 0) {
879 l->columns = screen_num_desktops / l->rows;
880 if (l->rows * l->columns < screen_num_desktops)
881 l->columns++;
882 if (l->rows * l->columns >= screen_num_desktops + l->columns)
883 l->rows--;
884 } else if (l->rows == 0) {
885 l->rows = screen_num_desktops / l->columns;
886 if (l->columns * l->rows < screen_num_desktops)
887 l->rows++;
888 if (l->columns * l->rows >= screen_num_desktops + l->rows)
889 l->columns--;
890 }
891
892 /* bounds checking */
893 if (l->orientation == OB_ORIENTATION_HORZ) {
894 l->columns = MIN(screen_num_desktops, l->columns);
895 l->rows = MIN(l->rows,
896 (screen_num_desktops + l->columns - 1) / l->columns);
897 l->columns = screen_num_desktops / l->rows +
898 !!(screen_num_desktops % l->rows);
899 } else {
900 l->rows = MIN(screen_num_desktops, l->rows);
901 l->columns = MIN(l->columns,
902 (screen_num_desktops + l->rows - 1) / l->rows);
903 l->rows = screen_num_desktops / l->columns +
904 !!(screen_num_desktops % l->columns);
905 }
906 return TRUE;
907 }
908
909 void screen_update_layout()
910
911 {
912 ObDesktopLayout l;
913 guint32 *data;
914 guint num;
915
916 screen_desktop_layout.orientation = OB_ORIENTATION_HORZ;
917 screen_desktop_layout.start_corner = OB_CORNER_TOPLEFT;
918 screen_desktop_layout.rows = 1;
919 screen_desktop_layout.columns = screen_num_desktops;
920
921 if (PROP_GETA32(RootWindow(ob_display, ob_screen),
922 net_desktop_layout, cardinal, &data, &num)) {
923 if (num == 3 || num == 4) {
924
925 if (data[0] == prop_atoms.net_wm_orientation_vert)
926 l.orientation = OB_ORIENTATION_VERT;
927 else if (data[0] == prop_atoms.net_wm_orientation_horz)
928 l.orientation = OB_ORIENTATION_HORZ;
929 else
930 return;
931
932 if (num < 4)
933 l.start_corner = OB_CORNER_TOPLEFT;
934 else {
935 if (data[3] == prop_atoms.net_wm_topleft)
936 l.start_corner = OB_CORNER_TOPLEFT;
937 else if (data[3] == prop_atoms.net_wm_topright)
938 l.start_corner = OB_CORNER_TOPRIGHT;
939 else if (data[3] == prop_atoms.net_wm_bottomright)
940 l.start_corner = OB_CORNER_BOTTOMRIGHT;
941 else if (data[3] == prop_atoms.net_wm_bottomleft)
942 l.start_corner = OB_CORNER_BOTTOMLEFT;
943 else
944 return;
945 }
946
947 l.columns = data[1];
948 l.rows = data[2];
949
950 if (screen_validate_layout(&l))
951 screen_desktop_layout = l;
952
953 g_free(data);
954 }
955 }
956 }
957
958 void screen_update_desktop_names()
959 {
960 guint i;
961
962 /* empty the array */
963 g_strfreev(screen_desktop_names);
964 screen_desktop_names = NULL;
965
966 if (PROP_GETSS(RootWindow(ob_display, ob_screen),
967 net_desktop_names, utf8, &screen_desktop_names))
968 for (i = 0; screen_desktop_names[i] && i < screen_num_desktops; ++i);
969 else
970 i = 0;
971 if (i < screen_num_desktops) {
972 GSList *it;
973
974 screen_desktop_names = g_renew(gchar*, screen_desktop_names,
975 screen_num_desktops + 1);
976 screen_desktop_names[screen_num_desktops] = NULL;
977
978 it = g_slist_nth(config_desktops_names, i);
979
980 for (; i < screen_num_desktops; ++i) {
981 if (it && ((char*)it->data)[0]) /* not empty */
982 /* use the names from the config file when possible */
983 screen_desktop_names[i] = g_strdup(it->data);
984 else
985 /* make up a nice name if it's not though */
986 screen_desktop_names[i] = g_strdup_printf(_("desktop %i"),
987 i + 1);
988 if (it) it = g_slist_next(it);
989 }
990
991 /* if we changed any names, then set the root property so we can
992 all agree on the names */
993 PROP_SETSS(RootWindow(ob_display, ob_screen), net_desktop_names,
994 screen_desktop_names);
995 }
996
997 /* resize the pager for these names */
998 pager_popup_text_width_to_strings(desktop_cycle_popup,
999 screen_desktop_names,
1000 screen_num_desktops);
1001 }
1002
1003 void screen_show_desktop(gboolean show, ObClient *show_only)
1004 {
1005 GList *it;
1006
1007 if (show == screen_showing_desktop) return; /* no change */
1008
1009 screen_showing_desktop = show;
1010
1011 if (show) {
1012 /* hide windows bottom to top */
1013 for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) {
1014 if (WINDOW_IS_CLIENT(it->data)) {
1015 ObClient *client = it->data;
1016 client_showhide(client);
1017 }
1018 }
1019 }
1020 else {
1021 /* restore windows top to bottom */
1022 for (it = stacking_list; it; it = g_list_next(it)) {
1023 if (WINDOW_IS_CLIENT(it->data)) {
1024 ObClient *client = it->data;
1025 if (client_should_show(client)) {
1026 if (!show_only || client == show_only)
1027 client_show(client);
1028 else
1029 client_iconify(client, TRUE, FALSE, TRUE);
1030 }
1031 }
1032 }
1033 }
1034
1035 if (show) {
1036 /* focus the desktop */
1037 for (it = focus_order; it; it = g_list_next(it)) {
1038 ObClient *c = it->data;
1039 if (c->type == OB_CLIENT_TYPE_DESKTOP &&
1040 (c->desktop == screen_desktop || c->desktop == DESKTOP_ALL) &&
1041 client_focus(it->data))
1042 break;
1043 }
1044 }
1045 else if (!show_only) {
1046 ObClient *c;
1047
1048 if ((c = focus_fallback(TRUE, FALSE))) {
1049 /* only do the flicker reducing stuff ahead of time if we are going
1050 to call xsetinputfocus on the window ourselves. otherwise there
1051 is no guarantee the window will actually take focus.. */
1052 if (c->can_focus) {
1053 /* reduce flicker by hiliting now rather than waiting for the
1054 server FocusIn event */
1055 frame_adjust_focus(c->frame, TRUE);
1056 }
1057 }
1058 }
1059
1060 show = !!show; /* make it boolean */
1061 PROP_SET32(RootWindow(ob_display, ob_screen),
1062 net_showing_desktop, cardinal, show);
1063 }
1064
1065 void screen_install_colormap(ObClient *client, gboolean install)
1066 {
1067 if (client == NULL || client->colormap == None) {
1068 if (install)
1069 XInstallColormap(RrDisplay(ob_rr_inst), RrColormap(ob_rr_inst));
1070 else
1071 XUninstallColormap(RrDisplay(ob_rr_inst), RrColormap(ob_rr_inst));
1072 } else {
1073 xerror_set_ignore(TRUE);
1074 if (install)
1075 XInstallColormap(RrDisplay(ob_rr_inst), client->colormap);
1076 else
1077 XUninstallColormap(RrDisplay(ob_rr_inst), client->colormap);
1078 xerror_set_ignore(FALSE);
1079 }
1080 }
1081
1082 static inline void
1083 screen_area_add_strut_left(const StrutPartial *s, const Rect *monitor_area,
1084 gint edge, Strut *ret)
1085 {
1086 if (s->left &&
1087 ((s->left_end <= s->left_start) ||
1088 (RECT_TOP(*monitor_area) < s->left_end &&
1089 RECT_BOTTOM(*monitor_area) > s->left_start)))
1090 ret->left = MAX(ret->left, edge);
1091 }
1092
1093 static inline void
1094 screen_area_add_strut_top(const StrutPartial *s, const Rect *monitor_area,
1095 gint edge, Strut *ret)
1096 {
1097 if (s->top &&
1098 ((s->top_end <= s->top_start) ||
1099 (RECT_LEFT(*monitor_area) < s->top_end &&
1100 RECT_RIGHT(*monitor_area) > s->top_start)))
1101 ret->top = MAX(ret->top, edge);
1102 }
1103
1104 static inline void
1105 screen_area_add_strut_right(const StrutPartial *s, const Rect *monitor_area,
1106 gint edge, Strut *ret)
1107 {
1108 if (s->right &&
1109 ((s->right_end <= s->right_start) ||
1110 (RECT_TOP(*monitor_area) < s->right_end &&
1111 RECT_BOTTOM(*monitor_area) > s->right_start)))
1112 ret->right = MAX(ret->right, edge);
1113 }
1114
1115 static inline void
1116 screen_area_add_strut_bottom(const StrutPartial *s, const Rect *monitor_area,
1117 gint edge, Strut *ret)
1118 {
1119 if (s->bottom &&
1120 ((s->bottom_end <= s->bottom_start) ||
1121 (RECT_LEFT(*monitor_area) < s->bottom_end &&
1122 RECT_RIGHT(*monitor_area) > s->bottom_start)))
1123 ret->bottom = MAX(ret->bottom, edge);
1124 }
1125
1126 void screen_update_areas()
1127 {
1128 guint i, x;
1129 gulong *dims;
1130 GList *it;
1131 gint o;
1132
1133 g_free(monitor_area);
1134 extensions_xinerama_screens(&monitor_area, &screen_num_monitors);
1135
1136 if (area) {
1137 for (i = 0; area[i]; ++i)
1138 g_free(area[i]);
1139 g_free(area);
1140 }
1141
1142 area = g_new(Rect*, screen_num_desktops + 2);
1143 for (i = 0; i < screen_num_desktops + 1; ++i)
1144 area[i] = g_new0(Rect, screen_num_monitors + 1);
1145 area[i] = NULL;
1146
1147 dims = g_new(gulong, 4 * screen_num_desktops);
1148
1149 for (i = 0; i < screen_num_desktops + 1; ++i) {
1150 Strut *struts;
1151 gint l, r, t, b;
1152
1153 struts = g_new0(Strut, screen_num_monitors);
1154
1155 /* calc the xinerama areas */
1156 for (x = 0; x < screen_num_monitors; ++x) {
1157 area[i][x] = monitor_area[x];
1158 if (x == 0) {
1159 l = monitor_area[x].x;
1160 t = monitor_area[x].y;
1161 r = monitor_area[x].x + monitor_area[x].width - 1;
1162 b = monitor_area[x].y + monitor_area[x].height - 1;
1163 } else {
1164 l = MIN(l, monitor_area[x].x);
1165 t = MIN(t, monitor_area[x].y);
1166 r = MAX(r, monitor_area[x].x + monitor_area[x].width - 1);
1167 b = MAX(b, monitor_area[x].y + monitor_area[x].height - 1);
1168 }
1169 }
1170 RECT_SET(area[i][x], l, t, r - l + 1, b - t + 1);
1171
1172 /* apply the struts */
1173
1174 /* find the left-most xin heads, i do this in 2 loops :| */
1175 o = area[i][0].x;
1176 for (x = 1; x < screen_num_monitors; ++x)
1177 o = MIN(o, area[i][x].x);
1178
1179 for (x = 0; x < screen_num_monitors; ++x) {
1180 for (it = client_list; it; it = g_list_next(it)) {
1181 ObClient *c = it->data;
1182 screen_area_add_strut_left(&c->strut,
1183 &monitor_area[x],
1184 o + c->strut.left - area[i][x].x,
1185 &struts[x]);
1186 }
1187 screen_area_add_strut_left(&dock_strut,
1188 &monitor_area[x],
1189 o + dock_strut.left - area[i][x].x,
1190 &struts[x]);
1191
1192 area[i][x].x += struts[x].left;
1193 area[i][x].width -= struts[x].left;
1194 }
1195
1196 /* find the top-most xin heads, i do this in 2 loops :| */
1197 o = area[i][0].y;
1198 for (x = 1; x < screen_num_monitors; ++x)
1199 o = MIN(o, area[i][x].y);
1200
1201 for (x = 0; x < screen_num_monitors; ++x) {
1202 for (it = client_list; it; it = g_list_next(it)) {
1203 ObClient *c = it->data;
1204 screen_area_add_strut_top(&c->strut,
1205 &monitor_area[x],
1206 o + c->strut.top - area[i][x].y,
1207 &struts[x]);
1208 }
1209 screen_area_add_strut_top(&dock_strut,
1210 &monitor_area[x],
1211 o + dock_strut.top - area[i][x].y,
1212 &struts[x]);
1213
1214 area[i][x].y += struts[x].top;
1215 area[i][x].height -= struts[x].top;
1216 }
1217
1218 /* find the right-most xin heads, i do this in 2 loops :| */
1219 o = area[i][0].x + area[i][0].width - 1;
1220 for (x = 1; x < screen_num_monitors; ++x)
1221 o = MAX(o, area[i][x].x + area[i][x].width - 1);
1222
1223 for (x = 0; x < screen_num_monitors; ++x) {
1224 for (it = client_list; it; it = g_list_next(it)) {
1225 ObClient *c = it->data;
1226 screen_area_add_strut_right(&c->strut,
1227 &monitor_area[x],
1228 (area[i][x].x +
1229 area[i][x].width - 1) -
1230 (o - c->strut.right),
1231 &struts[x]);
1232 }
1233 screen_area_add_strut_right(&dock_strut,
1234 &monitor_area[x],
1235 (area[i][x].x +
1236 area[i][x].width - 1) -
1237 (o - dock_strut.right),
1238 &struts[x]);
1239
1240 area[i][x].width -= struts[x].right;
1241 }
1242
1243 /* find the bottom-most xin heads, i do this in 2 loops :| */
1244 o = area[i][0].y + area[i][0].height - 1;
1245 for (x = 1; x < screen_num_monitors; ++x)
1246 o = MAX(o, area[i][x].y + area[i][x].height - 1);
1247
1248 for (x = 0; x < screen_num_monitors; ++x) {
1249 for (it = client_list; it; it = g_list_next(it)) {
1250 ObClient *c = it->data;
1251 screen_area_add_strut_bottom(&c->strut,
1252 &monitor_area[x],
1253 (area[i][x].y +
1254 area[i][x].height - 1) - \
1255 (o - c->strut.bottom),
1256 &struts[x]);
1257 }
1258 screen_area_add_strut_bottom(&dock_strut,
1259 &monitor_area[x],
1260 (area[i][x].y +
1261 area[i][x].height - 1) - \
1262 (o - dock_strut.bottom),
1263 &struts[x]);
1264
1265 area[i][x].height -= struts[x].bottom;
1266 }
1267
1268 l = RECT_LEFT(area[i][0]);
1269 t = RECT_TOP(area[i][0]);
1270 r = RECT_RIGHT(area[i][0]);
1271 b = RECT_BOTTOM(area[i][0]);
1272 for (x = 1; x < screen_num_monitors; ++x) {
1273 l = MIN(l, RECT_LEFT(area[i][x]));
1274 t = MIN(l, RECT_TOP(area[i][x]));
1275 r = MAX(r, RECT_RIGHT(area[i][x]));
1276 b = MAX(b, RECT_BOTTOM(area[i][x]));
1277 }
1278 RECT_SET(area[i][screen_num_monitors], l, t,
1279 r - l + 1, b - t + 1);
1280
1281 /* XXX optimize when this is run? */
1282
1283 /* the area has changed, adjust all the maximized
1284 windows */
1285 for (it = client_list; it; it = g_list_next(it)) {
1286 ObClient *c = it->data;
1287 if (i < screen_num_desktops) {
1288 if (c->desktop == i)
1289 client_reconfigure(c);
1290 } else if (c->desktop == DESKTOP_ALL)
1291 client_reconfigure(c);
1292 }
1293 if (i < screen_num_desktops) {
1294 /* don't set these for the 'all desktops' area */
1295 dims[(i * 4) + 0] = area[i][screen_num_monitors].x;
1296 dims[(i * 4) + 1] = area[i][screen_num_monitors].y;
1297 dims[(i * 4) + 2] = area[i][screen_num_monitors].width;
1298 dims[(i * 4) + 3] = area[i][screen_num_monitors].height;
1299 }
1300
1301 g_free(struts);
1302 }
1303
1304 PROP_SETA32(RootWindow(ob_display, ob_screen), net_workarea, cardinal,
1305 dims, 4 * screen_num_desktops);
1306
1307 g_free(dims);
1308 }
1309
1310 Rect *screen_area(guint desktop)
1311 {
1312 return screen_area_monitor(desktop, screen_num_monitors);
1313 }
1314
1315 Rect *screen_area_monitor(guint desktop, guint head)
1316 {
1317 if (head > screen_num_monitors)
1318 return NULL;
1319 if (desktop >= screen_num_desktops) {
1320 if (desktop == DESKTOP_ALL)
1321 return &area[screen_num_desktops][head];
1322 return NULL;
1323 }
1324 return &area[desktop][head];
1325 }
1326
1327 guint screen_find_monitor(Rect *search)
1328 {
1329 guint i;
1330 guint most = 0;
1331 guint mostv = 0;
1332
1333 for (i = 0; i < screen_num_monitors; ++i) {
1334 Rect *area = screen_physical_area_monitor(i);
1335 if (RECT_INTERSECTS_RECT(*area, *search)) {
1336 Rect r;
1337 guint v;
1338
1339 RECT_SET_INTERSECTION(r, *area, *search);
1340 v = r.width * r.height;
1341
1342 if (v > mostv) {
1343 mostv = v;
1344 most = i;
1345 }
1346 }
1347 }
1348 return most;
1349 }
1350
1351 Rect *screen_physical_area()
1352 {
1353 return screen_physical_area_monitor(screen_num_monitors);
1354 }
1355
1356 Rect *screen_physical_area_monitor(guint head)
1357 {
1358 if (head > screen_num_monitors)
1359 return NULL;
1360 return &monitor_area[head];
1361 }
1362
1363 void screen_set_root_cursor()
1364 {
1365 if (sn_app_starting())
1366 XDefineCursor(ob_display, RootWindow(ob_display, ob_screen),
1367 ob_cursor(OB_CURSOR_BUSYPOINTER));
1368 else
1369 XDefineCursor(ob_display, RootWindow(ob_display, ob_screen),
1370 ob_cursor(OB_CURSOR_POINTER));
1371 }
1372
1373 gboolean screen_pointer_pos(gint *x, gint *y)
1374 {
1375 Window w;
1376 gint i;
1377 guint u;
1378 gboolean ret;
1379
1380 ret = !!XQueryPointer(ob_display, RootWindow(ob_display, ob_screen),
1381 &w, &w, x, y, &i, &i, &u);
1382 if (!ret) {
1383 for (i = 0; i < ScreenCount(ob_display); ++i)
1384 if (i != ob_screen)
1385 if (XQueryPointer(ob_display, RootWindow(ob_display, i),
1386 &w, &w, x, y, &i, &i, &u))
1387 break;
1388 }
1389 return ret;
1390 }
This page took 0.105773 seconds and 5 git commands to generate.