]> Dogcows Code - chaz/openbox/blob - src/screen.cc
add some comments
[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
288 // set supporting window
289 Openbox::instance->property()->set(_info->rootWindow(),
290 otk::OBProperty::net_supporting_wm_check,
291 otk::OBProperty::Atom_Window,
292 _supportwindow);
293
294 //set properties on the supporting window
295 Openbox::instance->property()->set(_supportwindow,
296 otk::OBProperty::net_wm_name,
297 otk::OBProperty::utf8,
298 "Openbox");
299 Openbox::instance->property()->set(_supportwindow,
300 otk::OBProperty::net_supporting_wm_check,
301 otk::OBProperty::Atom_Window,
302 _supportwindow);
303
304
305 Atom supported[] = {
306 otk::OBProperty::net_current_desktop,
307 otk::OBProperty::net_number_of_desktops,
308 otk::OBProperty::net_desktop_geometry,
309 otk::OBProperty::net_desktop_viewport,
310 otk::OBProperty::net_active_window,
311 otk::OBProperty::net_workarea,
312 otk::OBProperty::net_client_list,
313 otk::OBProperty::net_client_list_stacking,
314 otk::OBProperty::net_desktop_names,
315 otk::OBProperty::net_close_window,
316 otk::OBProperty::net_wm_name,
317 otk::OBProperty::net_wm_visible_name,
318 otk::OBProperty::net_wm_icon_name,
319 otk::OBProperty::net_wm_visible_icon_name,
320 /*
321 otk::OBProperty::net_wm_desktop,
322 */
323 otk::OBProperty::net_wm_strut,
324 otk::OBProperty::net_wm_window_type,
325 otk::OBProperty::net_wm_window_type_desktop,
326 otk::OBProperty::net_wm_window_type_dock,
327 otk::OBProperty::net_wm_window_type_toolbar,
328 otk::OBProperty::net_wm_window_type_menu,
329 otk::OBProperty::net_wm_window_type_utility,
330 otk::OBProperty::net_wm_window_type_splash,
331 otk::OBProperty::net_wm_window_type_dialog,
332 otk::OBProperty::net_wm_window_type_normal,
333 /*
334 otk::OBProperty::net_wm_moveresize,
335 otk::OBProperty::net_wm_moveresize_size_topleft,
336 otk::OBProperty::net_wm_moveresize_size_topright,
337 otk::OBProperty::net_wm_moveresize_size_bottomleft,
338 otk::OBProperty::net_wm_moveresize_size_bottomright,
339 otk::OBProperty::net_wm_moveresize_move,
340 */
341 /*
342 otk::OBProperty::net_wm_allowed_actions,
343 otk::OBProperty::net_wm_action_move,
344 otk::OBProperty::net_wm_action_resize,
345 otk::OBProperty::net_wm_action_shade,
346 otk::OBProperty::net_wm_action_maximize_horz,
347 otk::OBProperty::net_wm_action_maximize_vert,
348 otk::OBProperty::net_wm_action_change_desktop,
349 otk::OBProperty::net_wm_action_close,
350 */
351 otk::OBProperty::net_wm_state,
352 otk::OBProperty::net_wm_state_modal,
353 otk::OBProperty::net_wm_state_maximized_vert,
354 otk::OBProperty::net_wm_state_maximized_horz,
355 otk::OBProperty::net_wm_state_shaded,
356 otk::OBProperty::net_wm_state_skip_taskbar,
357 otk::OBProperty::net_wm_state_skip_pager,
358 otk::OBProperty::net_wm_state_hidden,
359 otk::OBProperty::net_wm_state_fullscreen,
360 otk::OBProperty::net_wm_state_above,
361 otk::OBProperty::net_wm_state_below,
362 };
363 const int num_supported = sizeof(supported)/sizeof(Atom);
364
365 // convert to the atom values
366 for (int i = 0; i < num_supported; ++i)
367 supported[i] =
368 Openbox::instance->property()->atom((otk::OBProperty::Atoms)supported[i]);
369
370 Openbox::instance->property()->set(_info->rootWindow(),
371 otk::OBProperty::net_supported,
372 otk::OBProperty::Atom_Atom,
373 supported, num_supported);
374 }
375
376
377 void OBScreen::changeClientList()
378 {
379 Window *windows;
380 unsigned int size = clients.size();
381
382 // create an array of the window ids
383 if (size > 0) {
384 Window *win_it;
385
386 windows = new Window[size];
387 win_it = windows;
388 OBClient::List::const_iterator it = clients.begin();
389 const OBClient::List::const_iterator end = clients.end();
390 for (; it != end; ++it, ++win_it)
391 *win_it = (*it)->window();
392 } else
393 windows = (Window*) 0;
394
395 Openbox::instance->property()->set(_info->rootWindow(),
396 otk::OBProperty::net_client_list,
397 otk::OBProperty::Atom_Window,
398 windows, size);
399
400 if (size)
401 delete [] windows;
402
403 changeStackingList();
404 }
405
406
407 void OBScreen::changeStackingList()
408 {
409 Window *windows;
410 unsigned int size = _stacking.size();
411
412 assert(size == clients.size()); // just making sure.. :)
413
414
415 // create an array of the window ids
416 if (size > 0) {
417 Window *win_it;
418
419 windows = new Window[size];
420 win_it = windows;
421 OBClient::List::const_iterator it = _stacking.begin();
422 const OBClient::List::const_iterator end = _stacking.end();
423 for (; it != end; ++it, ++win_it)
424 *win_it = (*it)->window();
425 } else
426 windows = (Window*) 0;
427
428 Openbox::instance->property()->set(_info->rootWindow(),
429 otk::OBProperty::net_client_list_stacking,
430 otk::OBProperty::Atom_Window,
431 windows, size);
432
433 if (size)
434 delete [] windows;
435 }
436
437
438 void OBScreen::changeWorkArea() {
439 unsigned long *dims = new unsigned long[4 * _num_desktops];
440 for (long i = 0; i < _num_desktops; ++i) {
441 // XXX: this could be different for each workspace
442 dims[(i * 4) + 0] = _area.x();
443 dims[(i * 4) + 1] = _area.y();
444 dims[(i * 4) + 2] = _area.width();
445 dims[(i * 4) + 3] = _area.height();
446 }
447 Openbox::instance->property()->set(_info->rootWindow(),
448 otk::OBProperty::net_workarea,
449 otk::OBProperty::Atom_Cardinal,
450 dims, 4 * _num_desktops);
451 delete [] dims;
452 }
453
454
455 void OBScreen::manageWindow(Window window)
456 {
457 OBClient *client = 0;
458 XWMHints *wmhint;
459 XSetWindowAttributes attrib_set;
460
461 otk::OBDisplay::grab();
462
463 // is the window a docking app
464 if ((wmhint = XGetWMHints(otk::OBDisplay::display, window))) {
465 if ((wmhint->flags & StateHint) &&
466 wmhint->initial_state == WithdrawnState) {
467 //slit->addClient(w); // XXX: make dock apps work!
468 otk::OBDisplay::ungrab();
469
470 XFree(wmhint);
471 return;
472 }
473 XFree(wmhint);
474 }
475
476 // choose the events we want to receive on the CLIENT window
477 attrib_set.event_mask = OBClient::event_mask;
478 attrib_set.do_not_propagate_mask = OBClient::no_propagate_mask;
479 XChangeWindowAttributes(otk::OBDisplay::display, window,
480 CWEventMask|CWDontPropagate, &attrib_set);
481
482 // create the OBClient class, which gets all of the hints on the window
483 client = new OBClient(_number, window);
484 // register for events
485 Openbox::instance->registerHandler(window, client);
486 // add to the wm's map
487 Openbox::instance->addClient(window, client);
488
489 // we dont want a border on the client
490 client->toggleClientBorder(false);
491
492 // specify that if we exit, the window should not be destroyed and should be
493 // reparented back to root automatically
494 XChangeSaveSet(otk::OBDisplay::display, window, SetModeInsert);
495
496 if (!(Openbox::instance->state() == Openbox::State_Starting ||
497 client->positionRequested())) {
498 // position the window intelligenty .. hopefully :)
499 // call the python PLACEWINDOW binding
500 EventData *data = new_event_data(_number, window, EventPlaceWindow, 0);
501 Openbox::instance->bindings()->fireEvent(data);
502 Py_DECREF((PyObject*)data);
503 }
504
505 // create the decoration frame for the client window
506 client->frame = new OBFrame(client, &_style);
507
508 // add to the wm's map
509 Openbox::instance->addClient(client->frame->window(), client);
510 Openbox::instance->addClient(client->frame->plate(), client);
511 Openbox::instance->addClient(client->frame->titlebar(), client);
512 Openbox::instance->addClient(client->frame->label(), client);
513 Openbox::instance->addClient(client->frame->button_max(), client);
514 Openbox::instance->addClient(client->frame->button_iconify(), client);
515 Openbox::instance->addClient(client->frame->button_stick(), client);
516 Openbox::instance->addClient(client->frame->button_close(), client);
517 Openbox::instance->addClient(client->frame->handle(), client);
518 Openbox::instance->addClient(client->frame->grip_left(), client);
519 Openbox::instance->addClient(client->frame->grip_right(), client);
520
521 // reparent the client to the frame
522 client->frame->grabClient();
523
524 // if on the current desktop.. (or all desktops)
525 if (client->desktop() == _desktop ||
526 client->desktop() == (signed)0xffffffff) {
527 client->frame->show();
528 }
529
530 // XXX: handle any requested states such as maximized
531
532 otk::OBDisplay::ungrab();
533
534 // add to the screen's list
535 clients.push_back(client);
536 // this puts into the stacking order, then raises it
537 _stacking.push_back(client);
538 restack(true, client);
539 // update the root properties
540 changeClientList();
541
542 Openbox::instance->bindings()->grabButtons(true, client);
543
544 // call the python NEWWINDOW binding
545 EventData *data = new_event_data(_number, window, EventNewWindow, 0);
546 Openbox::instance->bindings()->fireEvent(data);
547 Py_DECREF((PyObject*)data);
548
549 #ifdef DEBUG
550 printf("Managed window 0x%lx\n", window);
551 #endif
552 }
553
554
555 void OBScreen::unmanageWindow(OBClient *client)
556 {
557 OBFrame *frame = client->frame;
558
559 // call the python CLOSEWINDOW binding
560 EventData *data = new_event_data(_number, client->window(),
561 EventCloseWindow, 0);
562 Openbox::instance->bindings()->fireEvent(data);
563 Py_DECREF((PyObject*)data);
564
565 Openbox::instance->bindings()->grabButtons(false, client);
566
567 // remove from the wm's map
568 Openbox::instance->removeClient(client->window());
569 Openbox::instance->removeClient(frame->window());
570 Openbox::instance->removeClient(frame->plate());
571 Openbox::instance->removeClient(frame->titlebar());
572 Openbox::instance->removeClient(frame->label());
573 Openbox::instance->removeClient(frame->button_max());
574 Openbox::instance->removeClient(frame->button_iconify());
575 Openbox::instance->removeClient(frame->button_stick());
576 Openbox::instance->removeClient(frame->button_close());
577 Openbox::instance->removeClient(frame->handle());
578 Openbox::instance->removeClient(frame->grip_left());
579 Openbox::instance->removeClient(frame->grip_right());
580 // unregister for handling events
581 Openbox::instance->clearHandler(client->window());
582
583 // remove the window from our save set
584 XChangeSaveSet(otk::OBDisplay::display, client->window(), SetModeDelete);
585
586 // we dont want events no more
587 XSelectInput(otk::OBDisplay::display, client->window(), NoEventMask);
588
589 frame->hide();
590
591 // give the client its border back
592 client->toggleClientBorder(true);
593
594 // reparent the window out of the frame
595 frame->releaseClient();
596
597 delete client->frame;
598 client->frame = 0;
599
600 // remove from the stacking order
601 _stacking.remove(client);
602
603 // remove from the screen's list
604 clients.remove(client);
605
606 // unfocus the client (calls the focus callbacks)
607 client->unfocus();
608
609 #ifdef DEBUG
610 printf("Unmanaged window 0x%lx\n", client->window());
611 #endif
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.069834 seconds and 4 git commands to generate.