]> Dogcows Code - chaz/openbox/blob - src/xeventhandler.cc
maps and unmaps windows!
[chaz/openbox] / src / xeventhandler.cc
1 // -*- mode: C++; indent-tabs-mode: nil; -*-
2
3 #include "xeventhandler.hh"
4 #include "client.hh"
5 #include "openbox.hh"
6 #include "otk/display.hh"
7 #include "otk/rect.hh"
8
9 extern "C" {
10 #include <X11/Xlib.h>
11 #include <X11/Xutil.h>
12 }
13
14 namespace ob {
15
16
17 OBXEventHandler::OBXEventHandler()
18 {
19 _lasttime = 1; // 0 is CurrentTime, so set to minimum
20 }
21
22 void OBXEventHandler::buttonPress(const XButtonEvent &e)
23 {
24 _lasttime = e.time;
25
26 }
27
28
29 void OBXEventHandler::buttonRelease(const XButtonEvent &e)
30 {
31 _lasttime = e.time;
32
33 }
34
35
36 void OBXEventHandler::keyPress(const XKeyEvent &e)
37 {
38 _lasttime = e.time;
39 }
40
41
42 void OBXEventHandler::motion(const XMotionEvent &e)
43 {
44 _lasttime = e.time;
45
46 // the pointer is on the wrong screen
47 if (! e.same_screen) return;
48
49 }
50
51
52 void OBXEventHandler::enterNotify(const XCrossingEvent &e)
53 {
54 _lasttime = e.time;
55
56 OBClient *client = Openbox::instance->findClient(e.window);
57 if (!client) return;
58
59 /*
60 BScreen *screen = (BScreen *) 0;
61 BlackboxWindow *win = (BlackboxWindow *) 0;
62
63 if (e->xcrossing.mode == NotifyGrab) break;
64
65 if ((e->xcrossing.window == e->xcrossing.root) &&
66 (screen = searchScreen(e->xcrossing.window))) {
67 screen->getImageControl()->installRootColormap();
68 } else if ((win = searchWindow(e->xcrossing.window))) {
69 if (! no_focus)
70 win->enterNotifyEvent(&e->xcrossing);
71 }
72 */
73 }
74
75
76 void OBXEventHandler::leaveNotify(const XCrossingEvent &e)
77 {
78 _lasttime = e.time;
79
80 OBClient *client = Openbox::instance->findClient(e.window);
81 if (!client) return;
82
83 /*
84 BlackboxWindow *win = (BlackboxWindow *) 0;
85
86 if ((win = searchWindow(e->xcrossing.window)))
87 win->leaveNotifyEvent(&e->xcrossing);
88 */
89 }
90
91
92 void OBXEventHandler::configureRequest(const XConfigureRequestEvent &e)
93 {
94 OBClient *client = Openbox::instance->findClient(e.window);
95 if (!client) return;
96
97 /* BlackboxWindow *win = (BlackboxWindow *) 0;
98
99 if ((win = searchWindow(e->xconfigurerequest.window))) {
100 win->configureRequestEvent(&e->xconfigurerequest);
101 } else {
102 if (validateWindow(e->xconfigurerequest.window)) {
103 XWindowChanges xwc;
104
105 xwc.x = e->xconfigurerequest.x;
106 xwc.y = e->xconfigurerequest.y;
107 xwc.width = e->xconfigurerequest.width;
108 xwc.height = e->xconfigurerequest.height;
109 xwc.border_width = e->xconfigurerequest.border_width;
110 xwc.sibling = e->xconfigurerequest.above;
111 xwc.stack_mode = e->xconfigurerequest.detail;
112
113 XConfigureWindow(otk::OBDisplay::display, e->xconfigurerequest.window,
114 e->xconfigurerequest.value_mask, &xwc);
115 }
116 }
117 */
118 }
119
120
121 // XXX: put this into the OBScreen class!
122 static void manageWindow(Window window)
123 {
124 OBClient *client = 0;
125 XWMHints *wmhint;
126 XSetWindowAttributes attrib_set;
127
128 // XXX: manage the window, i.e. grab events n shit
129
130 // is the window a docking app
131 if ((wmhint = XGetWMHints(otk::OBDisplay::display, window))) {
132 if ((wmhint->flags & StateHint) &&
133 wmhint->initial_state == WithdrawnState) {
134 //slit->addClient(w); // XXX: make dock apps work!
135 XFree(wmhint);
136 return;
137 }
138 XFree(wmhint);
139 }
140
141 // choose the events we want to receive on the CLIENT window
142 attrib_set.event_mask = PropertyChangeMask | FocusChangeMask |
143 StructureNotifyMask;
144 attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
145 ButtonMotionMask;
146 XChangeWindowAttributes(otk::OBDisplay::display, window,
147 CWEventMask|CWDontPropagate, &attrib_set);
148
149 // create the OBClient class, which gets all of the hints on the window
150 Openbox::instance->addClient(window, client = new OBClient(window));
151
152 // we dont want a border on the client
153 XSetWindowBorderWidth(otk::OBDisplay::display, window, 0);
154
155 // specify that if we exit, the window should not be destroyed and should be
156 // reparented back to root automatically
157 XChangeSaveSet(otk::OBDisplay::display, window, SetModeInsert);
158
159 if (!client->positionRequested()) {
160 // XXX: position the window intelligenty
161 }
162
163 // XXX: grab server, reparent client to the frame, ungrab server
164
165 // XXX: if shaped, shape the frame..
166
167 // XXX: if on the current desktop..
168 /// XMapSubwindows(otk::OBDisplay::display, FRAMEWINDOW);
169 XMapWindow(otk::OBDisplay::display, window);
170
171 // handle any requested states such as shaded/maximized
172 }
173
174 static void unmanageWindow(OBClient *client)
175 {
176 bool remap = false; // remap the window when we're done?
177
178 Window window = client->window();
179
180 // XXX: pass around focus if this window was focused
181
182 // remove the window from our save set
183 XChangeSaveSet(otk::OBDisplay::display, window, SetModeDelete);
184
185 // we dont want events no more
186 XSelectInput(otk::OBDisplay::display, window, NoEventMask);
187
188 // XXX: XUnmapWindow(otk::OBDisplay::display, FRAME);
189 XUnmapWindow(otk::OBDisplay::display, window);
190
191 // we dont want a border on the client
192 XSetWindowBorderWidth(otk::OBDisplay::display, window,client->borderWidth());
193
194 // remove the client class from the search list
195 Openbox::instance->removeClient(window);
196
197 // check if the app has already reparented its window to the root window
198 XEvent ev;
199 if (XCheckTypedWindowEvent(otk::OBDisplay::display, window, ReparentNotify,
200 &ev)) {
201 remap = true; // XXX: why do we remap the window if they already
202 // reparented to root?
203 } else {
204 // according to the ICCCM - if the client doesn't reparent to
205 // root, then we have to do it for them
206 XReparentWindow(otk::OBDisplay::display, window,
207 RootWindow(otk::OBDisplay::display,
208 DefaultScreen(otk::OBDisplay::display)),
209 // XXX: screen->getRootWindow(),
210 client->area().x(), client->area().y());
211 }
212
213 // if we want to remap the window, do so now
214 if (remap)
215 XMapWindow(otk::OBDisplay::display, window);
216
217 delete client;
218 }
219
220 void OBXEventHandler::mapRequest(const XMapRequestEvent &e)
221 {
222 #ifdef DEBUG
223 printf("MapRequest for 0x%lx\n", e.window);
224 #endif // DEBUG
225
226 OBClient *client = Openbox::instance->findClient(e.window);
227
228 if (client) {
229 // XXX: uniconify and/or unshade the window
230 } else {
231 manageWindow(e.window);
232 }
233
234 /*
235 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
236
237 if (win) {
238 bool focus = False;
239 if (win->isIconic()) {
240 win->deiconify();
241 focus = True;
242 }
243 if (win->isShaded()) {
244 win->shade();
245 focus = True;
246 }
247
248 if (focus && (win->isTransient() || win->getScreen()->doFocusNew()) &&
249 win->isVisible())
250 win->setInputFocus();
251 } else {
252 BScreen *screen = searchScreen(e->xmaprequest.parent);
253
254 if (! screen) {
255 */
256 /*
257 we got a map request for a window who's parent isn't root. this
258 can happen in only one circumstance:
259
260 a client window unmapped a managed window, and then remapped it
261 somewhere between unmapping the client window and reparenting it
262 to root.
263
264 regardless of how it happens, we need to find the screen that
265 the window is on
266 */
267 /*
268 XWindowAttributes wattrib;
269 if (! XGetWindowAttributes(otk::OBDisplay::display,
270 e->xmaprequest.window,
271 &wattrib)) {
272 // failed to get the window attributes, perhaps the window has
273 // now been destroyed?
274 break;
275 }
276
277 screen = searchScreen(wattrib.root);
278 assert(screen != 0); // this should never happen
279 }
280 screen->manageWindow(e->xmaprequest.window);
281 }
282 */
283 }
284
285
286 void OBXEventHandler::unmapNotify(const XUnmapEvent &e)
287 {
288 OBClient *client = Openbox::instance->findClient(e.window);
289 if (!client) return;
290
291 unmanageWindow(client);
292 }
293
294
295 void OBXEventHandler::destroyNotify(const XDestroyWindowEvent &e)
296 {
297 // XXX: window group leaders can come through here too!
298
299 OBClient *client = Openbox::instance->findClient(e.window);
300 if (!client) return;
301
302 unmanageWindow(client);
303 }
304
305
306 void OBXEventHandler::reparentNotify(const XReparentEvent &e)
307 {
308 /*
309 this event is quite rare and is usually handled in unmapNotify
310 however, if the window is unmapped when the reparent event occurs
311 the window manager never sees it because an unmap event is not sent
312 to an already unmapped window.
313 */
314 OBClient *client = Openbox::instance->findClient(e.window);
315 if (!client) return;
316
317 /*
318 BlackboxWindow *win = searchWindow(e->xreparent.window);
319 if (win)
320 win->reparentNotifyEvent(&e->xreparent);
321 */
322 }
323
324
325 void OBXEventHandler::propertyNotify(const XPropertyEvent &e)
326 {
327 _lasttime = e.time;
328
329 OBClient *client = Openbox::instance->findClient(e.window);
330 if (!client) return;
331
332 client->update(e);
333 }
334
335
336 void OBXEventHandler::expose(const XExposeEvent &first)
337 {
338 OBClient *client = Openbox::instance->findClient(first.window);
339 if (!client) return;
340
341 // compress expose events
342 XEvent e; e.xexpose = first;
343 unsigned int i = 0;
344 otk::Rect area(e.xexpose.x, e.xexpose.y, e.xexpose.width,
345 e.xexpose.height);
346 while (XCheckTypedWindowEvent(otk::OBDisplay::display,
347 e.xexpose.window, Expose, &e)) {
348 i++;
349 // merge expose area
350 area |= otk::Rect(e.xexpose.x, e.xexpose.y, e.xexpose.width,
351 e.xexpose.height);
352 }
353 if ( i > 0 ) {
354 // use the merged area
355 e.xexpose.x = area.x();
356 e.xexpose.y = area.y();
357 e.xexpose.width = area.width();
358 e.xexpose.height = area.height();
359 }
360
361 // XXX: make the decorations redraw!
362 }
363
364
365 void OBXEventHandler::colormapNotify(const XColormapEvent &e)
366 {
367 (void)e;
368 /*
369 BScreen *screen = searchScreen(e->xcolormap.window);
370 if (screen)
371 screen->setRootColormapInstalled((e->xcolormap.state ==
372 ColormapInstalled) ? True : False);
373 */
374 }
375
376
377 void OBXEventHandler::focusIn(const XFocusChangeEvent &e)
378 {
379 if (e.detail != NotifyNonlinear &&
380 e.detail != NotifyAncestor) {
381 /*
382 don't process FocusIns when:
383 1. the new focus window isn't an ancestor or inferior of the old
384 focus window (NotifyNonlinear)
385 make sure to allow the FocusIn when the old focus window was an
386 ancestor but didn't have a parent, such as root (NotifyAncestor)
387 */
388 return;
389 }
390 /*
391 BlackboxWindow *win = searchWindow(e.window);
392 if (win) {
393 if (! win->isFocused())
394 win->setFocusFlag(True);
395 */
396 /*
397 set the event window to None. when the FocusOut event handler calls
398 this function recursively, it uses this as an indication that focus
399 has moved to a known window.
400 */
401 /*
402 e->xfocus.window = None;
403
404 no_focus = False; // focusing is back on
405 }
406 */
407 }
408
409
410 void OBXEventHandler::focusOut(const XFocusChangeEvent &e)
411 {
412 if (e.detail != NotifyNonlinear) {
413 /*
414 don't process FocusOuts when:
415 2. the new focus window isn't an ancestor or inferior of the old
416 focus window (NotifyNonlinear)
417 */
418 return;
419 }
420
421 /*
422 BlackboxWindow *win = searchWindow(e->xfocus.window);
423 if (win && win->isFocused()) {
424 */
425 /*
426 before we mark "win" as unfocused, we need to verify that focus is
427 going to a known location, is in a known location, or set focus
428 to a known location.
429 */
430 /*
431 XEvent event;
432 // don't check the current focus if FocusOut was generated during a grab
433 bool check_focus = (e->xfocus.mode == NotifyNormal);
434 */
435 /*
436 First, check if there is a pending FocusIn event waiting. if there
437 is, process it and determine if focus has moved to another window
438 (the FocusIn event handler sets the window in the event
439 structure to None to indicate this).
440 */
441 /*
442 if (XCheckTypedEvent(otk::OBDisplay::display, FocusIn, &event)) {
443
444 process_event(&event);
445 if (event.xfocus.window == None) {
446 // focus has moved
447 check_focus = False;
448 }
449 }
450
451 if (check_focus) {
452 */
453 /*
454 Second, we query the X server for the current input focus.
455 to make sure that we keep a consistent state.
456 */
457 /*
458 BlackboxWindow *focus;
459 Window w;
460 int revert;
461 XGetInputFocus(otk::OBDisplay::display, &w, &revert);
462 focus = searchWindow(w);
463 if (focus) {
464 */
465 /*
466 focus got from "win" to "focus" under some very strange
467 circumstances, and we need to make sure that the focus indication
468 is correct.
469 */
470 /*
471 setFocusedWindow(focus);
472 } else {
473 // we have no idea where focus went... so we set it to somewhere
474 setFocusedWindow(0);
475 }
476 }
477 }
478 */
479 }
480
481
482 #ifdef SHAPE
483 void OBXEventHandler::shapeEvent(const XShapeEvent &e)
484 {
485 XShapeEvent *shape_event = (XShapeEvent *) e;
486 BlackboxWindow *win = searchWindow(e->xany.window);
487
488 if (win && shape_event->kind == ShapeBounding)
489 win->shapeEvent(shape_event);
490 }
491 #endif // SHAPE
492
493
494 void OBXEventHandler::clientMessage(const XClientMessageEvent &e)
495 {
496 if (e.format != 32)
497 return;
498 /*
499 } else if (e->xclient.message_type ==
500 xatom->getAtom(XAtom::blackbox_change_workspace) ||
501 e->xclient.message_type ==
502 xatom->getAtom(XAtom::net_current_desktop)) {
503 // NET_CURRENT_DESKTOP message
504 BScreen *screen = searchScreen(e->xclient.window);
505
506 unsigned int workspace = e->xclient.data.l[0];
507 if (screen && workspace < screen->getWorkspaceCount())
508 screen->changeWorkspaceID(workspace);
509 } else if (e->xclient.message_type ==
510 xatom->getAtom(XAtom::net_active_window)) {
511 // NET_ACTIVE_WINDOW
512 BlackboxWindow *win = searchWindow(e->xclient.window);
513
514 if (win) {
515 BScreen *screen = win->getScreen();
516
517 if (win->isIconic())
518 win->deiconify(False, False);
519 if (! win->isStuck() &&
520 (win->getWorkspaceNumber() != screen->getCurrentWorkspaceID())) {
521 no_focus = True;
522 screen->changeWorkspaceID(win->getWorkspaceNumber());
523 }
524 if (win->isVisible() && win->setInputFocus()) {
525 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
526 raiseWindow(win);
527 win->installColormap(True);
528 }
529 }
530 } else if (e->xclient.message_type ==
531 xatom->getAtom(XAtom::net_number_of_desktops)) {
532 // NET_NUMBER_OF_DESKTOPS
533 BScreen *screen = searchScreen(e->xclient.window);
534
535 if (e->xclient.data.l[0] > 0)
536 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
537 } else if (e->xclient.message_type ==
538 xatom->getAtom(XAtom::net_close_window)) {
539 // NET_CLOSE_WINDOW
540 BlackboxWindow *win = searchWindow(e->xclient.window);
541 if (win && win->validateClient())
542 win->close(); // could this be smarter?
543 } else if (e->xclient.message_type ==
544 xatom->getAtom(XAtom::net_wm_moveresize)) {
545 // NET_WM_MOVERESIZE
546 BlackboxWindow *win = searchWindow(e->xclient.window);
547 if (win && win->validateClient()) {
548 int x_root = e->xclient.data.l[0],
549 y_root = e->xclient.data.l[1];
550 if ((Atom) e->xclient.data.l[2] ==
551 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
552 win->beginMove(x_root, y_root);
553 } else {
554 if ((Atom) e->xclient.data.l[2] ==
555 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
556 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
557 else if ((Atom) e->xclient.data.l[2] ==
558 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
559 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
560 else if ((Atom) e->xclient.data.l[2] ==
561 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
562 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
563 else if ((Atom) e->xclient.data.l[2] ==
564 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
565 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
566 }
567 }
568 }
569 */
570 }
571
572
573 void OBXEventHandler::handle(const XEvent &e)
574 {
575 /* mouse button events can get translated into:
576 press - button was pressed down
577 release - buttons was released
578 click - button was pressed and released on the same window
579 double click - clicked twice on the same widget in a given time and area
580
581 key events are only bindable to presses. key releases are ignored.
582
583 mouse enter/leave can be bound to for the entire window
584 */
585
586 switch (e.type) {
587
588 // These types of XEvent's can be bound to actions by the user, and so end
589 // up getting passed off to the OBBindingMapper class at some point
590 case ButtonPress:
591 buttonPress(e.xbutton);
592 break;
593 case ButtonRelease:
594 buttonRelease(e.xbutton);
595 break;
596 case KeyPress:
597 keyPress(e.xkey);
598 break;
599 case MotionNotify:
600 motion(e.xmotion);
601 break;
602 case EnterNotify:
603 enterNotify(e.xcrossing);
604 break;
605 case LeaveNotify:
606 leaveNotify(e.xcrossing);
607 break;
608
609
610 // These types of XEvent's can not be bound to actions by the user and so
611 // will simply be handled in this class
612 case ConfigureRequest:
613 configureRequest(e.xconfigurerequest);
614 break;
615
616 case MapRequest:
617 mapRequest(e.xmaprequest);
618 break;
619
620 case UnmapNotify:
621 unmapNotify(e.xunmap);
622 break;
623
624 case DestroyNotify:
625 destroyNotify(e.xdestroywindow);
626 break;
627
628 case ReparentNotify:
629 reparentNotify(e.xreparent);
630 break;
631
632 case PropertyNotify:
633 propertyNotify(e.xproperty);
634 break;
635
636 case Expose:
637 expose(e.xexpose);
638 break;
639
640 case ColormapNotify:
641 colormapNotify(e.xcolormap);
642 break;
643
644 case FocusIn:
645 focusIn(e.xfocus);
646 break;
647
648 case FocusOut:
649 focusOut(e.xfocus);
650 break;
651
652 case ClientMessage:
653 clientMessage(e.xclient);
654
655 default:
656 #ifdef SHAPE
657 if (e.type == otk::OBDisplay::shapeEventBase())
658 shapeEvent(e);
659 #endif // SHAPE
660 break;
661
662 /*
663 case ClientMessage: {
664 break;
665 }
666
667 */
668 } // switch
669 }
670
671
672 }
This page took 0.062196 seconds and 5 git commands to generate.