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