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