]> Dogcows Code - chaz/openbox/blob - src/screen.cc
Some cleanups in the mapping procedure. Apply requested states during the process.
[chaz/openbox] / src / screen.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #ifdef HAVE_CONFIG_H
4 # include "../config.h"
5 #endif
6
7 extern "C" {
8 #ifdef HAVE_STDIO_H
9 # include <stdio.h>
10 #endif // HAVE_STDIO_H
11
12 #ifdef HAVE_STRING_H
13 # include <string.h>
14 #endif // HAVE_STRING_H
15
16 #ifdef HAVE_UNISTD_H
17 # include <sys/types.h>
18 # include <unistd.h>
19 #endif // HAVE_UNISTD_H
20
21 #include "gettext.h"
22 #define _(str) gettext(str)
23 }
24
25 #include "screen.hh"
26 #include "client.hh"
27 #include "openbox.hh"
28 #include "frame.hh"
29 #include "bindings.hh"
30 #include "python.hh"
31 #include "otk/display.hh"
32 #include "otk/property.hh"
33
34 #include <vector>
35 #include <algorithm>
36
37 static bool running;
38 static int anotherWMRunning(Display *display, XErrorEvent *) {
39 printf(_("Another window manager already running on display %s.\n"),
40 DisplayString(display));
41 running = true;
42 return -1;
43 }
44
45
46 namespace ob {
47
48
49 Screen::Screen(int screen)
50 : WidgetBase(WidgetBase::Type_Root),
51 _number(screen)
52 {
53 assert(screen >= 0); assert(screen < ScreenCount(**otk::display));
54 _info = otk::display->screenInfo(screen);
55
56 ::running = false;
57 XErrorHandler old = XSetErrorHandler(::anotherWMRunning);
58 XSelectInput(**otk::display, _info->rootWindow(),
59 Screen::event_mask);
60 XSync(**otk::display, false);
61 XSetErrorHandler(old);
62
63 _managed = !::running;
64 if (! _managed) return; // was unable to manage the screen
65
66 printf(_("Managing screen %d: visual 0x%lx, depth %d\n"),
67 _number, XVisualIDFromVisual(_info->visual()), _info->depth());
68
69 otk::Property::set(_info->rootWindow(), otk::Property::atoms.openbox_pid,
70 otk::Property::atoms.cardinal, (unsigned long) getpid());
71
72 // set the mouse cursor for the root window (the default cursor)
73 XDefineCursor(**otk::display, _info->rootWindow(),
74 openbox->cursors().session);
75
76 // initialize the shit that is used for all drawing on the screen
77 _image_control = new otk::ImageControl(_info, true);
78 _image_control->installRootColormap();
79 _root_cmap_installed = True;
80
81 // initialize the screen's style
82 _style.setImageControl(_image_control);
83 otk::ustring stylepath;
84 python_get_string("theme", &stylepath);
85 otk::Configuration sconfig(false);
86 sconfig.setFile(otk::expandTilde(stylepath.c_str()));
87 if (!sconfig.load()) {
88 sconfig.setFile(otk::expandTilde(DEFAULTSTYLE));
89 if (!sconfig.load()) {
90 printf(_("Unable to load default style: %s. Aborting.\n"), DEFAULTSTYLE);
91 ::exit(1);
92 }
93 }
94 _style.load(sconfig);
95
96 // set up notification of netwm support
97 changeSupportedAtoms();
98
99 // Set the netwm properties for geometry
100 unsigned long geometry[] = { _info->width(),
101 _info->height() };
102 otk::Property::set(_info->rootWindow(),
103 otk::Property::atoms.net_desktop_geometry,
104 otk::Property::atoms.cardinal, geometry, 2);
105
106 // Set the net_desktop_names property
107 std::vector<otk::ustring> names;
108 python_get_stringlist("desktop_names", &names);
109 otk::Property::set(_info->rootWindow(),
110 otk::Property::atoms.net_desktop_names,
111 otk::Property::utf8, names);
112 // the above set() will cause the updateDesktopNames to fire right away so
113 // we have a list of desktop names
114
115 if (!python_get_long("number_of_desktops", &_num_desktops))
116 _num_desktops = 1;
117 changeNumDesktops(_num_desktops); // set the hint
118
119 _desktop = 0;
120 changeDesktop(0); // set the hint
121
122 // create the window which gets focus when no clients get it
123 XSetWindowAttributes attr;
124 attr.override_redirect = true;
125 _focuswindow = XCreateWindow(**otk::display, _info->rootWindow(),
126 -100, -100, 1, 1, 0, 0, InputOnly,
127 _info->visual(), CWOverrideRedirect, &attr);
128 XMapRaised(**otk::display, _focuswindow);
129
130 // these may be further updated if any pre-existing windows are found in
131 // the manageExising() function
132 changeClientList(); // initialize the client lists, which will be empty
133 calcArea(); // initialize the available working area
134
135 // register this class as the event handler for the root window
136 openbox->registerHandler(_info->rootWindow(), this);
137
138 // call the python Startup callbacks
139 EventData data(_number, 0, EventShutdown, 0);
140 openbox->bindings()->fireEvent(&data);
141 }
142
143
144 Screen::~Screen()
145 {
146 if (! _managed) return;
147
148 XSelectInput(**otk::display, _info->rootWindow(), NoEventMask);
149
150 // unmanage all windows
151 while (!clients.empty())
152 unmanageWindow(clients.front());
153
154 // call the python Shutdown callbacks
155 EventData data(_number, 0, EventShutdown, 0);
156 openbox->bindings()->fireEvent(&data);
157
158 XDestroyWindow(**otk::display, _focuswindow);
159 XDestroyWindow(**otk::display, _supportwindow);
160
161 delete _image_control;
162 }
163
164
165 void Screen::manageExisting()
166 {
167 unsigned int i, j, nchild;
168 Window r, p, *children;
169 XQueryTree(**otk::display, _info->rootWindow(), &r, &p,
170 &children, &nchild);
171
172 // preen the window list of all icon windows... for better dockapp support
173 for (i = 0; i < nchild; i++) {
174 if (children[i] == None) continue;
175
176 XWMHints *wmhints = XGetWMHints(**otk::display,
177 children[i]);
178
179 if (wmhints) {
180 if ((wmhints->flags & IconWindowHint) &&
181 (wmhints->icon_window != children[i])) {
182 for (j = 0; j < nchild; j++) {
183 if (children[j] == wmhints->icon_window) {
184 children[j] = None;
185 break;
186 }
187 }
188 }
189
190 XFree(wmhints);
191 }
192 }
193
194 // manage shown windows
195 for (i = 0; i < nchild; ++i) {
196 if (children[i] == None)
197 continue;
198
199 XWindowAttributes attrib;
200 if (XGetWindowAttributes(**otk::display, children[i], &attrib)) {
201 if (attrib.override_redirect) continue;
202
203 if (attrib.map_state != IsUnmapped) {
204 manageWindow(children[i]);
205 }
206 }
207 }
208
209 XFree(children);
210 }
211
212
213 void Screen::updateStrut()
214 {
215 _strut.left = _strut.right = _strut.top = _strut.bottom = 0;
216
217 Client::List::iterator it, end = clients.end();
218 for (it = clients.begin(); it != end; ++it) {
219 const otk::Strut &s = (*it)->strut();
220 _strut.left = std::max(_strut.left, s.left);
221 _strut.right = std::max(_strut.right, s.right);
222 _strut.top = std::max(_strut.top, s.top);
223 _strut.bottom = std::max(_strut.bottom, s.bottom);
224 }
225 calcArea();
226 }
227
228
229 void Screen::calcArea()
230 {
231 otk::Rect old_area = _area;
232
233 /*
234 #ifdef XINERAMA
235 // reset to the full areas
236 if (isXineramaActive())
237 xineramaUsableArea = getXineramaAreas();
238 #endif // XINERAMA
239 */
240
241 _area.setRect(_strut.left, _strut.top,
242 _info->width() - (_strut.left + _strut.right),
243 _info->height() - (_strut.top + _strut.bottom));
244
245 /*
246 #ifdef XINERAMA
247 if (isXineramaActive()) {
248 // keep each of the ximerama-defined areas inside the strut
249 RectList::iterator xit, xend = xineramaUsableArea.end();
250 for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
251 if (xit->x() < usableArea.x()) {
252 xit->setX(usableArea.x());
253 xit->setWidth(xit->width() - usableArea.x());
254 }
255 if (xit->y() < usableArea.y()) {
256 xit->setY(usableArea.y());
257 xit->setHeight(xit->height() - usableArea.y());
258 }
259 if (xit->x() + xit->width() > usableArea.width())
260 xit->setWidth(usableArea.width() - xit->x());
261 if (xit->y() + xit->height() > usableArea.height())
262 xit->setHeight(usableArea.height() - xit->y());
263 }
264 }
265 #endif // XINERAMA
266 */
267
268 if (old_area != _area)
269 // XXX: re-maximize windows
270
271 changeWorkArea();
272 }
273
274
275 void Screen::changeSupportedAtoms()
276 {
277 // create the netwm support window
278 _supportwindow = XCreateSimpleWindow(**otk::display,
279 _info->rootWindow(),
280 0, 0, 1, 1, 0, 0, 0);
281
282 // set supporting window
283 otk::Property::set(_info->rootWindow(),
284 otk::Property::atoms.net_supporting_wm_check,
285 otk::Property::atoms.window, _supportwindow);
286
287 //set properties on the supporting window
288 otk::Property::set(_supportwindow, otk::Property::atoms.net_wm_name,
289 otk::Property::utf8, "Openbox");
290 otk::Property::set(_supportwindow,
291 otk::Property::atoms.net_supporting_wm_check,
292 otk::Property::atoms.window, _supportwindow);
293
294
295 Atom supported[] = {
296 otk::Property::atoms.net_current_desktop,
297 otk::Property::atoms.net_number_of_desktops,
298 otk::Property::atoms.net_desktop_geometry,
299 otk::Property::atoms.net_desktop_viewport,
300 otk::Property::atoms.net_active_window,
301 otk::Property::atoms.net_workarea,
302 otk::Property::atoms.net_client_list,
303 otk::Property::atoms.net_client_list_stacking,
304 otk::Property::atoms.net_desktop_names,
305 otk::Property::atoms.net_close_window,
306 otk::Property::atoms.net_wm_name,
307 otk::Property::atoms.net_wm_visible_name,
308 otk::Property::atoms.net_wm_icon_name,
309 otk::Property::atoms.net_wm_visible_icon_name,
310 /*
311 otk::Property::atoms.net_wm_desktop,
312 */
313 otk::Property::atoms.net_wm_strut,
314 otk::Property::atoms.net_wm_window_type,
315 otk::Property::atoms.net_wm_window_type_desktop,
316 otk::Property::atoms.net_wm_window_type_dock,
317 otk::Property::atoms.net_wm_window_type_toolbar,
318 otk::Property::atoms.net_wm_window_type_menu,
319 otk::Property::atoms.net_wm_window_type_utility,
320 otk::Property::atoms.net_wm_window_type_splash,
321 otk::Property::atoms.net_wm_window_type_dialog,
322 otk::Property::atoms.net_wm_window_type_normal,
323 /*
324 otk::Property::atoms.net_wm_moveresize,
325 otk::Property::atoms.net_wm_moveresize_size_topleft,
326 otk::Property::atoms.net_wm_moveresize_size_topright,
327 otk::Property::atoms.net_wm_moveresize_size_bottomleft,
328 otk::Property::atoms.net_wm_moveresize_size_bottomright,
329 otk::Property::atoms.net_wm_moveresize_move,
330 */
331 otk::Property::atoms.net_wm_allowed_actions,
332 otk::Property::atoms.net_wm_action_move,
333 otk::Property::atoms.net_wm_action_resize,
334 otk::Property::atoms.net_wm_action_minimize,
335 otk::Property::atoms.net_wm_action_shade,
336 /* otk::Property::atoms.net_wm_action_stick,*/
337 otk::Property::atoms.net_wm_action_maximize_horz,
338 otk::Property::atoms.net_wm_action_maximize_vert,
339 otk::Property::atoms.net_wm_action_fullscreen,
340 otk::Property::atoms.net_wm_action_change_desktop,
341 otk::Property::atoms.net_wm_action_close,
342
343 otk::Property::atoms.net_wm_state,
344 otk::Property::atoms.net_wm_state_modal,
345 otk::Property::atoms.net_wm_state_maximized_vert,
346 otk::Property::atoms.net_wm_state_maximized_horz,
347 otk::Property::atoms.net_wm_state_shaded,
348 otk::Property::atoms.net_wm_state_skip_taskbar,
349 otk::Property::atoms.net_wm_state_skip_pager,
350 otk::Property::atoms.net_wm_state_hidden,
351 otk::Property::atoms.net_wm_state_fullscreen,
352 otk::Property::atoms.net_wm_state_above,
353 otk::Property::atoms.net_wm_state_below,
354 };
355 const int num_supported = sizeof(supported)/sizeof(Atom);
356
357 otk::Property::set(_info->rootWindow(), otk::Property::atoms.net_supported,
358 otk::Property::atoms.atom, supported, num_supported);
359 }
360
361
362 void Screen::changeClientList()
363 {
364 Window *windows;
365 unsigned int size = clients.size();
366
367 // create an array of the window ids
368 if (size > 0) {
369 Window *win_it;
370
371 windows = new Window[size];
372 win_it = windows;
373 Client::List::const_iterator it = clients.begin();
374 const Client::List::const_iterator end = clients.end();
375 for (; it != end; ++it, ++win_it)
376 *win_it = (*it)->window();
377 } else
378 windows = (Window*) 0;
379
380 otk::Property::set(_info->rootWindow(), otk::Property::atoms.net_client_list,
381 otk::Property::atoms.window, windows, size);
382
383 if (size)
384 delete [] windows;
385
386 changeStackingList();
387 }
388
389
390 void Screen::changeStackingList()
391 {
392 Window *windows;
393 unsigned int size = _stacking.size();
394
395 assert(size == clients.size()); // just making sure.. :)
396
397
398 // create an array of the window ids (from bottom to top, reverse order!)
399 if (size > 0) {
400 Window *win_it;
401
402 windows = new Window[size];
403 win_it = windows;
404 Client::List::const_reverse_iterator it = _stacking.rbegin();
405 const Client::List::const_reverse_iterator end = _stacking.rend();
406 for (; it != end; ++it, ++win_it)
407 *win_it = (*it)->window();
408 } else
409 windows = (Window*) 0;
410
411 otk::Property::set(_info->rootWindow(),
412 otk::Property::atoms.net_client_list_stacking,
413 otk::Property::atoms.window, windows, size);
414
415 if (size)
416 delete [] windows;
417 }
418
419
420 void Screen::changeWorkArea() {
421 unsigned long *dims = new unsigned long[4 * _num_desktops];
422 for (long i = 0; i < _num_desktops; ++i) {
423 // XXX: this could be different for each workspace
424 dims[(i * 4) + 0] = _area.x();
425 dims[(i * 4) + 1] = _area.y();
426 dims[(i * 4) + 2] = _area.width();
427 dims[(i * 4) + 3] = _area.height();
428 }
429 otk::Property::set(_info->rootWindow(), otk::Property::atoms.net_workarea,
430 otk::Property::atoms.cardinal, dims, 4 * _num_desktops);
431 delete [] dims;
432 }
433
434
435 void Screen::manageWindow(Window window)
436 {
437 Client *client = 0;
438 XWMHints *wmhint;
439 XSetWindowAttributes attrib_set;
440
441 otk::display->grab();
442
443 // is the window a docking app
444 if ((wmhint = XGetWMHints(**otk::display, window))) {
445 if ((wmhint->flags & StateHint) &&
446 wmhint->initial_state == WithdrawnState) {
447 //slit->addClient(w); // XXX: make dock apps work!
448 otk::display->ungrab();
449
450 XFree(wmhint);
451 return;
452 }
453 XFree(wmhint);
454 }
455
456 // choose the events we want to receive on the CLIENT window
457 attrib_set.event_mask = Client::event_mask;
458 attrib_set.do_not_propagate_mask = Client::no_propagate_mask;
459 XChangeWindowAttributes(**otk::display, window,
460 CWEventMask|CWDontPropagate, &attrib_set);
461
462 // create the Client class, which gets all of the hints on the window
463 client = new Client(_number, window);
464 // register for events
465 openbox->registerHandler(window, client);
466 // add to the wm's map
467 openbox->addClient(window, client);
468
469 // we dont want a border on the client
470 client->toggleClientBorder(false);
471
472 // specify that if we exit, the window should not be destroyed and should be
473 // reparented back to root automatically
474 XChangeSaveSet(**otk::display, window, SetModeInsert);
475
476 // create the decoration frame for the client window
477 client->frame = new Frame(client, &_style);
478
479 // add to the wm's map
480 openbox->addClient(client->frame->window(), client);
481 openbox->addClient(client->frame->plate(), client);
482 openbox->addClient(client->frame->titlebar(), client);
483 openbox->addClient(client->frame->label(), client);
484 openbox->addClient(client->frame->button_max(), client);
485 openbox->addClient(client->frame->button_iconify(), client);
486 openbox->addClient(client->frame->button_stick(), client);
487 openbox->addClient(client->frame->button_close(), client);
488 openbox->addClient(client->frame->handle(), client);
489 openbox->addClient(client->frame->grip_left(), client);
490 openbox->addClient(client->frame->grip_right(), client);
491
492 // reparent the client to the frame
493 client->frame->grabClient();
494
495 if (!(openbox->state() == Openbox::State_Starting ||
496 client->positionRequested())) {
497 // position the window intelligenty .. hopefully :)
498 // call the python PLACEWINDOW binding
499 EventData data(_number, client, EventPlaceWindow, 0);
500 openbox->bindings()->fireEvent(&data);
501 }
502
503 // if on the current desktop.. (or all desktops)
504 if (client->desktop() == _desktop ||
505 client->desktop() == (signed)0xffffffff) {
506 client->frame->show();
507 }
508
509 client->applyStartupState();
510
511 otk::display->ungrab();
512
513 // add to the screen's list
514 clients.push_back(client);
515 // this puts into the stacking order, then raises it
516 _stacking.push_back(client);
517 raiseWindow(client);
518 // update the root properties
519 changeClientList();
520
521 openbox->bindings()->grabButtons(true, client);
522
523 // call the python NEWWINDOW binding
524 EventData data(_number, client, EventNewWindow, 0);
525 openbox->bindings()->fireEvent(&data);
526
527 #ifdef DEBUG
528 printf("Managed window 0x%lx\n", window);
529 #endif
530 }
531
532
533 void Screen::unmanageWindow(Client *client)
534 {
535 Frame *frame = client->frame;
536
537 // call the python CLOSEWINDOW binding
538 EventData data(_number, client, EventCloseWindow, 0);
539 openbox->bindings()->fireEvent(&data);
540
541 openbox->bindings()->grabButtons(false, client);
542
543 // remove from the wm's map
544 openbox->removeClient(client->window());
545 openbox->removeClient(frame->window());
546 openbox->removeClient(frame->plate());
547 openbox->removeClient(frame->titlebar());
548 openbox->removeClient(frame->label());
549 openbox->removeClient(frame->button_max());
550 openbox->removeClient(frame->button_iconify());
551 openbox->removeClient(frame->button_stick());
552 openbox->removeClient(frame->button_close());
553 openbox->removeClient(frame->handle());
554 openbox->removeClient(frame->grip_left());
555 openbox->removeClient(frame->grip_right());
556 // unregister for handling events
557 openbox->clearHandler(client->window());
558
559 // remove the window from our save set
560 XChangeSaveSet(**otk::display, client->window(), SetModeDelete);
561
562 // we dont want events no more
563 XSelectInput(**otk::display, client->window(), NoEventMask);
564
565 frame->hide();
566
567 // give the client its border back
568 client->toggleClientBorder(true);
569
570 // reparent the window out of the frame
571 frame->releaseClient();
572
573 delete client->frame;
574 client->frame = 0;
575
576 // remove from the stacking order
577 _stacking.remove(client);
578
579 // remove from the screen's list
580 clients.remove(client);
581
582 // unfocus the client (calls the focus callbacks)
583 client->unfocus();
584
585 #ifdef DEBUG
586 printf("Unmanaged window 0x%lx\n", client->window());
587 #endif
588
589 delete client;
590
591 // update the root properties
592 changeClientList();
593 }
594
595 void Screen::lowerWindow(Client *client)
596 {
597 Window wins[2]; // only ever restack 2 windows.
598
599 assert(!_stacking.empty()); // this would be bad
600
601 Client::List::iterator it = --_stacking.end();
602 Client::List::const_iterator end = _stacking.begin();
603
604 for (; it != end && (*it)->layer() < client->layer(); --it);
605 if (*it == client) return; // already the bottom, return
606
607 wins[0] = (*it)->frame->window();
608 wins[1] = client->frame->window();
609
610 _stacking.remove(client);
611 _stacking.insert(++it, client);
612
613 XRestackWindows(**otk::display, wins, 2);
614 changeStackingList();
615 }
616
617 void Screen::raiseWindow(Client *client)
618 {
619 Window wins[2]; // only ever restack 2 windows.
620
621 assert(!_stacking.empty()); // this would be bad
622
623 // remove the client before looking so we can't run into ourselves
624 _stacking.remove(client);
625
626 Client::List::iterator it = _stacking.begin();
627 Client::List::const_iterator end = _stacking.end();
628
629 // the stacking list is from highest to lowest
630 for (; it != end && (*it)->layer() > client->layer(); ++it);
631
632 /*
633 if our new position is the top, we want to stack under the _focuswindow
634 otherwise, we want to stack under the previous window in the stack.
635 */
636 wins[0] = (it == _stacking.begin() ? _focuswindow :
637 ((*(--Client::List::const_iterator(it)))->frame->window()));
638 wins[1] = client->frame->window();
639
640 _stacking.insert(it, client);
641
642 XRestackWindows(**otk::display, wins, 2);
643 changeStackingList();
644 }
645
646 void Screen::changeDesktop(long desktop)
647 {
648 if (!(desktop >= 0 && desktop < _num_desktops)) return;
649
650 printf("Moving to desktop %ld\n", desktop);
651
652 long old = _desktop;
653
654 _desktop = desktop;
655 otk::Property::set(_info->rootWindow(),
656 otk::Property::atoms.net_current_desktop,
657 otk::Property::atoms.cardinal, _desktop);
658
659 if (old == _desktop) return;
660
661 Client::List::iterator it, end = clients.end();
662 for (it = clients.begin(); it != end; ++it) {
663 if ((*it)->desktop() == old) {
664 (*it)->frame->hide();
665 } else if ((*it)->desktop() == _desktop) {
666 (*it)->frame->show();
667 }
668 }
669
670 // force the callbacks to fire
671 if (!openbox->focusedClient())
672 openbox->setFocusedClient(0);
673 }
674
675 void Screen::changeNumDesktops(long num)
676 {
677 assert(num > 0);
678
679 if (!(num > 0)) return;
680
681 // XXX: move windows on desktops that will no longer exist!
682
683 _num_desktops = num;
684 otk::Property::set(_info->rootWindow(),
685 otk::Property::atoms.net_number_of_desktops,
686 otk::Property::atoms.cardinal, _num_desktops);
687
688 // set the viewport hint
689 unsigned long *viewport = new unsigned long[_num_desktops * 2];
690 memset(viewport, 0, sizeof(unsigned long) * _num_desktops * 2);
691 otk::Property::set(_info->rootWindow(),
692 otk::Property::atoms.net_desktop_viewport,
693 otk::Property::atoms.cardinal,
694 viewport, _num_desktops * 2);
695 delete [] viewport;
696
697 // update the work area hint
698 changeWorkArea();
699 }
700
701
702 void Screen::updateDesktopNames()
703 {
704 unsigned long num = (unsigned) -1;
705
706 if (!otk::Property::get(_info->rootWindow(),
707 otk::Property::atoms.net_desktop_names,
708 otk::Property::utf8, &num, &_desktop_names))
709 _desktop_names.clear();
710 while ((long)_desktop_names.size() < _num_desktops)
711 _desktop_names.push_back("Unnamed");
712 }
713
714
715 void Screen::setDesktopName(long i, const otk::ustring &name)
716 {
717 assert(i >= 0);
718
719 if (i >= _num_desktops) return;
720
721 otk::Property::StringVect newnames = _desktop_names;
722 newnames[i] = name;
723 otk::Property::set(_info->rootWindow(),
724 otk::Property::atoms.net_desktop_names,
725 otk::Property::utf8, newnames);
726 }
727
728
729 void Screen::propertyHandler(const XPropertyEvent &e)
730 {
731 otk::EventHandler::propertyHandler(e);
732
733 // compress changes to a single property into a single change
734 XEvent ce;
735 while (XCheckTypedEvent(**otk::display, e.type, &ce)) {
736 // XXX: it would be nice to compress ALL changes to a property, not just
737 // changes in a row without other props between.
738 if (ce.xproperty.atom != e.atom) {
739 XPutBackEvent(**otk::display, &ce);
740 break;
741 }
742 }
743
744 if (e.atom == otk::Property::atoms.net_desktop_names)
745 updateDesktopNames();
746 }
747
748
749 void Screen::clientMessageHandler(const XClientMessageEvent &e)
750 {
751 otk::EventHandler::clientMessageHandler(e);
752
753 if (e.format != 32) return;
754
755 if (e.message_type == otk::Property::atoms.net_current_desktop) {
756 changeDesktop(e.data.l[0]);
757 } else if (e.message_type == otk::Property::atoms.net_number_of_desktops) {
758 changeNumDesktops(e.data.l[0]);
759 }
760 // XXX: so many client messages to handle here! ..or not.. they go to clients
761 }
762
763
764 void Screen::mapRequestHandler(const XMapRequestEvent &e)
765 {
766 otk::EventHandler::mapRequestHandler(e);
767
768 #ifdef DEBUG
769 printf("MapRequest for 0x%lx\n", e.window);
770 #endif // DEBUG
771
772 /*
773 MapRequest events come here even after the window exists instead of going
774 right to the client window, because of how they are sent and their struct
775 layout.
776 */
777 Client *c = openbox->findClient(e.window);
778
779 if (c) {
780 // send a net_active_window message
781 XEvent ce;
782 ce.xclient.type = ClientMessage;
783 ce.xclient.message_type = otk::Property::atoms.net_active_window;
784 ce.xclient.display = **otk::display;
785 ce.xclient.window = c->window();
786 ce.xclient.format = 32;
787 ce.xclient.data.l[0] = 0l;
788 ce.xclient.data.l[1] = 0l;
789 ce.xclient.data.l[2] = 0l;
790 ce.xclient.data.l[3] = 0l;
791 ce.xclient.data.l[4] = 0l;
792 XSendEvent(**otk::display, _info->rootWindow(), false,
793 SubstructureRedirectMask | SubstructureNotifyMask,
794 &ce);
795 } else
796 manageWindow(e.window);
797 }
798 }
This page took 0.069088 seconds and 5 git commands to generate.