]> Dogcows Code - chaz/openbox/blob - src/screen.cc
b95c1908a1b8aae6e51cc5ffb5a47dd53c13202b
[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 /*
332 otk::Property::atoms.net_wm_allowed_actions,
333 otk::Property::atoms.net_wm_action_move,
334 otk::Property::atoms.net_wm_action_resize,
335 otk::Property::atoms.net_wm_action_shade,
336 otk::Property::atoms.net_wm_action_maximize_horz,
337 otk::Property::atoms.net_wm_action_maximize_vert,
338 otk::Property::atoms.net_wm_action_change_desktop,
339 otk::Property::atoms.net_wm_action_close,
340 */
341 otk::Property::atoms.net_wm_state,
342 otk::Property::atoms.net_wm_state_modal,
343 otk::Property::atoms.net_wm_state_maximized_vert,
344 otk::Property::atoms.net_wm_state_maximized_horz,
345 otk::Property::atoms.net_wm_state_shaded,
346 otk::Property::atoms.net_wm_state_skip_taskbar,
347 otk::Property::atoms.net_wm_state_skip_pager,
348 otk::Property::atoms.net_wm_state_hidden,
349 otk::Property::atoms.net_wm_state_fullscreen,
350 otk::Property::atoms.net_wm_state_above,
351 otk::Property::atoms.net_wm_state_below,
352 };
353 const int num_supported = sizeof(supported)/sizeof(Atom);
354
355 otk::Property::set(_info->rootWindow(), otk::Property::atoms.net_supported,
356 otk::Property::atoms.atom, supported, num_supported);
357 }
358
359
360 void Screen::changeClientList()
361 {
362 Window *windows;
363 unsigned int size = clients.size();
364
365 // create an array of the window ids
366 if (size > 0) {
367 Window *win_it;
368
369 windows = new Window[size];
370 win_it = windows;
371 Client::List::const_iterator it = clients.begin();
372 const Client::List::const_iterator end = clients.end();
373 for (; it != end; ++it, ++win_it)
374 *win_it = (*it)->window();
375 } else
376 windows = (Window*) 0;
377
378 otk::Property::set(_info->rootWindow(), otk::Property::atoms.net_client_list,
379 otk::Property::atoms.window, windows, size);
380
381 if (size)
382 delete [] windows;
383
384 changeStackingList();
385 }
386
387
388 void Screen::changeStackingList()
389 {
390 Window *windows;
391 unsigned int size = _stacking.size();
392
393 assert(size == clients.size()); // just making sure.. :)
394
395
396 // create an array of the window ids (from bottom to top, reverse order!)
397 if (size > 0) {
398 Window *win_it;
399
400 windows = new Window[size];
401 win_it = windows;
402 Client::List::const_reverse_iterator it = _stacking.rbegin();
403 const Client::List::const_reverse_iterator end = _stacking.rend();
404 for (; it != end; ++it, ++win_it)
405 *win_it = (*it)->window();
406 } else
407 windows = (Window*) 0;
408
409 otk::Property::set(_info->rootWindow(),
410 otk::Property::atoms.net_client_list_stacking,
411 otk::Property::atoms.window, windows, size);
412
413 if (size)
414 delete [] windows;
415 }
416
417
418 void Screen::changeWorkArea() {
419 unsigned long *dims = new unsigned long[4 * _num_desktops];
420 for (long i = 0; i < _num_desktops; ++i) {
421 // XXX: this could be different for each workspace
422 dims[(i * 4) + 0] = _area.x();
423 dims[(i * 4) + 1] = _area.y();
424 dims[(i * 4) + 2] = _area.width();
425 dims[(i * 4) + 3] = _area.height();
426 }
427 otk::Property::set(_info->rootWindow(), otk::Property::atoms.net_workarea,
428 otk::Property::atoms.cardinal, dims, 4 * _num_desktops);
429 delete [] dims;
430 }
431
432
433 void Screen::manageWindow(Window window)
434 {
435 Client *client = 0;
436 XWMHints *wmhint;
437 XSetWindowAttributes attrib_set;
438
439 otk::display->grab();
440
441 // is the window a docking app
442 if ((wmhint = XGetWMHints(**otk::display, window))) {
443 if ((wmhint->flags & StateHint) &&
444 wmhint->initial_state == WithdrawnState) {
445 //slit->addClient(w); // XXX: make dock apps work!
446 otk::display->ungrab();
447
448 XFree(wmhint);
449 return;
450 }
451 XFree(wmhint);
452 }
453
454 // choose the events we want to receive on the CLIENT window
455 attrib_set.event_mask = Client::event_mask;
456 attrib_set.do_not_propagate_mask = Client::no_propagate_mask;
457 XChangeWindowAttributes(**otk::display, window,
458 CWEventMask|CWDontPropagate, &attrib_set);
459
460 // create the Client class, which gets all of the hints on the window
461 client = new Client(_number, window);
462 // register for events
463 openbox->registerHandler(window, client);
464 // add to the wm's map
465 openbox->addClient(window, client);
466
467 // we dont want a border on the client
468 client->toggleClientBorder(false);
469
470 // specify that if we exit, the window should not be destroyed and should be
471 // reparented back to root automatically
472 XChangeSaveSet(**otk::display, window, SetModeInsert);
473
474 // create the decoration frame for the client window
475 client->frame = new Frame(client, &_style);
476
477 // add to the wm's map
478 openbox->addClient(client->frame->window(), client);
479 openbox->addClient(client->frame->plate(), client);
480 openbox->addClient(client->frame->titlebar(), client);
481 openbox->addClient(client->frame->label(), client);
482 openbox->addClient(client->frame->button_max(), client);
483 openbox->addClient(client->frame->button_iconify(), client);
484 openbox->addClient(client->frame->button_stick(), client);
485 openbox->addClient(client->frame->button_close(), client);
486 openbox->addClient(client->frame->handle(), client);
487 openbox->addClient(client->frame->grip_left(), client);
488 openbox->addClient(client->frame->grip_right(), client);
489
490 // reparent the client to the frame
491 client->frame->grabClient();
492
493 if (!(openbox->state() == Openbox::State_Starting ||
494 client->positionRequested())) {
495 // position the window intelligenty .. hopefully :)
496 // call the python PLACEWINDOW binding
497 EventData data(_number, client, EventPlaceWindow, 0);
498 openbox->bindings()->fireEvent(&data);
499 }
500
501 // if on the current desktop.. (or all desktops)
502 if (client->desktop() == _desktop ||
503 client->desktop() == (signed)0xffffffff) {
504 client->frame->show();
505 }
506
507 // XXX: handle any requested states such as maximized
508
509 otk::display->ungrab();
510
511 // add to the screen's list
512 clients.push_back(client);
513 // this puts into the stacking order, then raises it
514 _stacking.push_back(client);
515 raiseWindow(client);
516 // update the root properties
517 changeClientList();
518
519 openbox->bindings()->grabButtons(true, client);
520
521 // call the python NEWWINDOW binding
522 EventData data(_number, client, EventNewWindow, 0);
523 openbox->bindings()->fireEvent(&data);
524
525 #ifdef DEBUG
526 printf("Managed window 0x%lx\n", window);
527 #endif
528 }
529
530
531 void Screen::unmanageWindow(Client *client)
532 {
533 Frame *frame = client->frame;
534
535 // call the python CLOSEWINDOW binding
536 EventData data(_number, client, EventCloseWindow, 0);
537 openbox->bindings()->fireEvent(&data);
538
539 openbox->bindings()->grabButtons(false, client);
540
541 // remove from the wm's map
542 openbox->removeClient(client->window());
543 openbox->removeClient(frame->window());
544 openbox->removeClient(frame->plate());
545 openbox->removeClient(frame->titlebar());
546 openbox->removeClient(frame->label());
547 openbox->removeClient(frame->button_max());
548 openbox->removeClient(frame->button_iconify());
549 openbox->removeClient(frame->button_stick());
550 openbox->removeClient(frame->button_close());
551 openbox->removeClient(frame->handle());
552 openbox->removeClient(frame->grip_left());
553 openbox->removeClient(frame->grip_right());
554 // unregister for handling events
555 openbox->clearHandler(client->window());
556
557 // remove the window from our save set
558 XChangeSaveSet(**otk::display, client->window(), SetModeDelete);
559
560 // we dont want events no more
561 XSelectInput(**otk::display, client->window(), NoEventMask);
562
563 frame->hide();
564
565 // give the client its border back
566 client->toggleClientBorder(true);
567
568 // reparent the window out of the frame
569 frame->releaseClient();
570
571 delete client->frame;
572 client->frame = 0;
573
574 // remove from the stacking order
575 _stacking.remove(client);
576
577 // remove from the screen's list
578 clients.remove(client);
579
580 // unfocus the client (calls the focus callbacks)
581 client->unfocus();
582
583 #ifdef DEBUG
584 printf("Unmanaged window 0x%lx\n", client->window());
585 #endif
586
587 delete client;
588
589 // update the root properties
590 changeClientList();
591 }
592
593 void Screen::lowerWindow(Client *client)
594 {
595 Window wins[2]; // only ever restack 2 windows.
596
597 assert(!_stacking.empty()); // this would be bad
598
599 Client::List::iterator it = --_stacking.end();
600 Client::List::const_iterator end = _stacking.begin();
601
602 for (; it != end && (*it)->layer() < client->layer(); --it);
603 if (*it == client) return; // already the bottom, return
604
605 wins[0] = (*it)->frame->window();
606 wins[1] = client->frame->window();
607
608 _stacking.remove(client);
609 _stacking.insert(++it, client);
610
611 XRestackWindows(**otk::display, wins, 2);
612 changeStackingList();
613 }
614
615 void Screen::raiseWindow(Client *client)
616 {
617 Window wins[2]; // only ever restack 2 windows.
618
619 assert(!_stacking.empty()); // this would be bad
620
621 // remove the client before looking so we can't run into ourselves
622 _stacking.remove(client);
623
624 Client::List::iterator it = _stacking.begin();
625 Client::List::const_iterator end = _stacking.end();
626
627 // the stacking list is from highest to lowest
628 for (; it != end && (*it)->layer() > client->layer(); ++it);
629
630 /*
631 if our new position is the top, we want to stack under the _focuswindow
632 otherwise, we want to stack under the previous window in the stack.
633 */
634 wins[0] = (it == _stacking.begin() ? _focuswindow :
635 ((*(--Client::List::const_iterator(it)))->frame->window()));
636 wins[1] = client->frame->window();
637
638 _stacking.insert(it, client);
639
640 XRestackWindows(**otk::display, wins, 2);
641 changeStackingList();
642 }
643
644 void Screen::changeDesktop(long desktop)
645 {
646 if (!(desktop >= 0 && desktop < _num_desktops)) return;
647
648 printf("Moving to desktop %ld\n", desktop);
649
650 long old = _desktop;
651
652 _desktop = desktop;
653 otk::Property::set(_info->rootWindow(),
654 otk::Property::atoms.net_current_desktop,
655 otk::Property::atoms.cardinal, _desktop);
656
657 if (old == _desktop) return;
658
659 Client::List::iterator it, end = clients.end();
660 for (it = clients.begin(); it != end; ++it) {
661 if ((*it)->desktop() == old) {
662 (*it)->frame->hide();
663 } else if ((*it)->desktop() == _desktop) {
664 (*it)->frame->show();
665 }
666 }
667
668 // force the callbacks to fire
669 if (!openbox->focusedClient())
670 openbox->setFocusedClient(0);
671 }
672
673 void Screen::changeNumDesktops(long num)
674 {
675 assert(num > 0);
676
677 if (!(num > 0)) return;
678
679 // XXX: move windows on desktops that will no longer exist!
680
681 _num_desktops = num;
682 otk::Property::set(_info->rootWindow(),
683 otk::Property::atoms.net_number_of_desktops,
684 otk::Property::atoms.cardinal, _num_desktops);
685
686 // set the viewport hint
687 unsigned long *viewport = new unsigned long[_num_desktops * 2];
688 memset(viewport, 0, sizeof(unsigned long) * _num_desktops * 2);
689 otk::Property::set(_info->rootWindow(),
690 otk::Property::atoms.net_desktop_viewport,
691 otk::Property::atoms.cardinal,
692 viewport, _num_desktops * 2);
693 delete [] viewport;
694
695 // update the work area hint
696 changeWorkArea();
697 }
698
699
700 void Screen::updateDesktopNames()
701 {
702 unsigned long num = (unsigned) -1;
703
704 if (!otk::Property::get(_info->rootWindow(),
705 otk::Property::atoms.net_desktop_names,
706 otk::Property::utf8, &num, &_desktop_names))
707 _desktop_names.clear();
708 while ((long)_desktop_names.size() < _num_desktops)
709 _desktop_names.push_back("Unnamed");
710 }
711
712
713 void Screen::setDesktopName(long i, const otk::ustring &name)
714 {
715 assert(i >= 0);
716
717 if (i >= _num_desktops) return;
718
719 otk::Property::StringVect newnames = _desktop_names;
720 newnames[i] = name;
721 otk::Property::set(_info->rootWindow(),
722 otk::Property::atoms.net_desktop_names,
723 otk::Property::utf8, newnames);
724 }
725
726
727 void Screen::propertyHandler(const XPropertyEvent &e)
728 {
729 otk::EventHandler::propertyHandler(e);
730
731 // compress changes to a single property into a single change
732 XEvent ce;
733 while (XCheckTypedEvent(**otk::display, e.type, &ce)) {
734 // XXX: it would be nice to compress ALL changes to a property, not just
735 // changes in a row without other props between.
736 if (ce.xproperty.atom != e.atom) {
737 XPutBackEvent(**otk::display, &ce);
738 break;
739 }
740 }
741
742 if (e.atom == otk::Property::atoms.net_desktop_names)
743 updateDesktopNames();
744 }
745
746
747 void Screen::clientMessageHandler(const XClientMessageEvent &e)
748 {
749 otk::EventHandler::clientMessageHandler(e);
750
751 if (e.format != 32) return;
752
753 if (e.message_type == otk::Property::atoms.net_current_desktop) {
754 changeDesktop(e.data.l[0]);
755 } else if (e.message_type == otk::Property::atoms.net_number_of_desktops) {
756 changeNumDesktops(e.data.l[0]);
757 }
758 // XXX: so many client messages to handle here! ..or not.. they go to clients
759 }
760
761
762 void Screen::mapRequestHandler(const XMapRequestEvent &e)
763 {
764 otk::EventHandler::mapRequestHandler(e);
765
766 #ifdef DEBUG
767 printf("MapRequest for 0x%lx\n", e.window);
768 #endif // DEBUG
769
770 /*
771 MapRequest events come here even after the window exists instead of going
772 right to the client window, because of how they are sent and their struct
773 layout.
774 */
775 Client *c = openbox->findClient(e.window);
776
777 if (c) {
778 // send a net_active_window message
779 XEvent ce;
780 ce.xclient.type = ClientMessage;
781 ce.xclient.message_type = otk::Property::atoms.net_active_window;
782 ce.xclient.display = **otk::display;
783 ce.xclient.window = c->window();
784 ce.xclient.format = 32;
785 ce.xclient.data.l[0] = 0l;
786 ce.xclient.data.l[1] = 0l;
787 ce.xclient.data.l[2] = 0l;
788 ce.xclient.data.l[3] = 0l;
789 ce.xclient.data.l[4] = 0l;
790 XSendEvent(**otk::display, _info->rootWindow(), false,
791 SubstructureRedirectMask | SubstructureNotifyMask,
792 &ce);
793 } else
794 manageWindow(e.window);
795 }
796 }
This page took 0.069546 seconds and 3 git commands to generate.