]> icculus.org git repositories - dana/openbox.git/blob - src/screen.cc
redo otk::Property. make it static.
[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 #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   XMapWindow(**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   if (!(openbox->state() == Openbox::State_Starting ||
475         client->positionRequested())) {
476     // position the window intelligenty .. hopefully :)
477     // call the python PLACEWINDOW binding
478     EventData data(_number, client, EventPlaceWindow, 0);
479     openbox->bindings()->fireEvent(&data);
480   }
481
482   // create the decoration frame for the client window
483   client->frame = new Frame(client, &_style);
484
485   // add to the wm's map
486   openbox->addClient(client->frame->window(), client);
487   openbox->addClient(client->frame->plate(), client);
488   openbox->addClient(client->frame->titlebar(), client);
489   openbox->addClient(client->frame->label(), client);
490   openbox->addClient(client->frame->button_max(), client);
491   openbox->addClient(client->frame->button_iconify(), client);
492   openbox->addClient(client->frame->button_stick(), client);
493   openbox->addClient(client->frame->button_close(), client);
494   openbox->addClient(client->frame->handle(), client);
495   openbox->addClient(client->frame->grip_left(), client);
496   openbox->addClient(client->frame->grip_right(), client);
497
498   // reparent the client to the frame
499   client->frame->grabClient();
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   restack(true, 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::restack(bool raise, Client *client)
594 {
595   const int layer = client->layer();
596   std::vector<Window> wins;
597
598   _stacking.remove(client);
599
600   // the stacking list is from highest to lowest
601   
602   Client::List::iterator it = _stacking.begin(), end = _stacking.end();
603   // insert the windows above this window
604   for (; it != end; ++it) {
605     if ((*it)->layer() < layer || (raise && (*it)->layer() == layer))
606       break;
607     wins.push_back((*it)->frame->window());
608   }
609   // insert our client
610   wins.push_back(client->frame->window());
611   _stacking.insert(it, client);
612   // insert the remaining below this window
613   for (; it != end; ++it)
614     wins.push_back((*it)->frame->window());
615
616   XRestackWindows(**otk::display, &wins[0], wins.size());
617   changeStackingList();
618 }
619
620 void Screen::changeDesktop(long desktop)
621 {
622   if (!(desktop >= 0 && desktop < _num_desktops)) return;
623
624   printf("Moving to desktop %ld\n", desktop);
625   
626   long old = _desktop;
627   
628   _desktop = desktop;
629   otk::Property::set(_info->rootWindow(),
630                      otk::Property::atoms.net_current_desktop,
631                      otk::Property::atoms.cardinal, _desktop);
632
633   if (old == _desktop) return;
634
635   Client::List::iterator it, end = clients.end();
636   for (it = clients.begin(); it != end; ++it) {
637     if ((*it)->desktop() == old) {
638       (*it)->frame->hide();
639     } else if ((*it)->desktop() == _desktop) {
640       (*it)->frame->show();
641     }
642   }
643
644   // force the callbacks to fire
645   if (!openbox->focusedClient())
646     openbox->setFocusedClient(0);
647 }
648
649 void Screen::changeNumDesktops(long num)
650 {
651   assert(num > 0);
652   
653   if (!(num > 0)) return;
654
655   // XXX: move windows on desktops that will no longer exist!
656   
657   _num_desktops = num;
658   otk::Property::set(_info->rootWindow(),
659                      otk::Property::atoms.net_number_of_desktops,
660                      otk::Property::atoms.cardinal, _num_desktops);
661
662   // set the viewport hint
663   unsigned long *viewport = new unsigned long[_num_desktops * 2];
664   memset(viewport, 0, sizeof(unsigned long) * _num_desktops * 2);
665   otk::Property::set(_info->rootWindow(),
666                      otk::Property::atoms.net_desktop_viewport,
667                      otk::Property::atoms.cardinal,
668                      viewport, _num_desktops * 2);
669   delete [] viewport;
670
671   // update the work area hint
672   changeWorkArea();
673 }
674
675
676 void Screen::updateDesktopNames()
677 {
678   unsigned long num = (unsigned) -1;
679   
680   if (!otk::Property::get(_info->rootWindow(),
681                           otk::Property::atoms.net_desktop_names,
682                           otk::Property::utf8, &num, &_desktop_names))
683     _desktop_names.clear();
684   while ((long)_desktop_names.size() < _num_desktops)
685     _desktop_names.push_back("Unnamed");
686 }
687
688
689 void Screen::setDesktopName(long i, const otk::ustring &name)
690 {
691   assert(i >= 0);
692
693   if (i >= _num_desktops) return;
694
695   otk::Property::StringVect newnames = _desktop_names;
696   newnames[i] = name;
697   otk::Property::set(_info->rootWindow(),
698                      otk::Property::atoms.net_desktop_names,
699                      otk::Property::utf8, newnames);
700 }
701
702
703 void Screen::propertyHandler(const XPropertyEvent &e)
704 {
705   otk::EventHandler::propertyHandler(e);
706
707   // compress changes to a single property into a single change
708   XEvent ce;
709   while (XCheckTypedEvent(**otk::display, e.type, &ce)) {
710     // XXX: it would be nice to compress ALL changes to a property, not just
711     //      changes in a row without other props between.
712     if (ce.xproperty.atom != e.atom) {
713       XPutBackEvent(**otk::display, &ce);
714       break;
715     }
716   }
717
718   if (e.atom == otk::Property::atoms.net_desktop_names)
719     updateDesktopNames();
720 }
721
722
723 void Screen::clientMessageHandler(const XClientMessageEvent &e)
724 {
725   otk::EventHandler::clientMessageHandler(e);
726
727   if (e.format != 32) return;
728
729   if (e.message_type == otk::Property::atoms.net_current_desktop) {
730     changeDesktop(e.data.l[0]);
731   } else if (e.message_type == otk::Property::atoms.net_number_of_desktops) {
732     changeNumDesktops(e.data.l[0]);
733   }
734   // XXX: so many client messages to handle here! ..or not.. they go to clients
735 }
736
737
738 void Screen::mapRequestHandler(const XMapRequestEvent &e)
739 {
740   otk::EventHandler::mapRequestHandler(e);
741
742 #ifdef    DEBUG
743   printf("MapRequest for 0x%lx\n", e.window);
744 #endif // DEBUG
745
746   /*
747     MapRequest events come here even after the window exists instead of going
748     right to the client window, because of how they are sent and their struct
749     layout.
750   */
751   Client *c = openbox->findClient(e.window);
752
753   if (c) {
754     // send a net_active_window message
755     XEvent ce;
756     ce.xclient.type = ClientMessage;
757     ce.xclient.message_type = otk::Property::atoms.net_active_window;
758     ce.xclient.display = **otk::display;
759     ce.xclient.window = c->window();
760     ce.xclient.format = 32;
761     ce.xclient.data.l[0] = 0l;
762     ce.xclient.data.l[1] = 0l;
763     ce.xclient.data.l[2] = 0l;
764     ce.xclient.data.l[3] = 0l;
765     ce.xclient.data.l[4] = 0l;
766     XSendEvent(**otk::display, _info->rootWindow(), false,
767                SubstructureRedirectMask | SubstructureNotifyMask,
768                &ce);
769   } else
770     manageWindow(e.window);
771 }
772 }