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