]> Dogcows Code - chaz/openbox/blob - src/xeventhandler.cc
fully documented OBClient
[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 or OBClient 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 // XXX: handle any requested states such as shaded/maximized
172 }
173
174 // XXX: move this to the OBScreen or OBClient class!
175 static void unmanageWindow(OBClient *client)
176 {
177 bool remap = false; // remap the window when we're done?
178
179 Window window = client->window();
180
181 // XXX: pass around focus if this window was focused
182
183 // remove the window from our save set
184 XChangeSaveSet(otk::OBDisplay::display, window, SetModeDelete);
185
186 // we dont want events no more
187 XSelectInput(otk::OBDisplay::display, window, NoEventMask);
188
189 // XXX: XUnmapWindow(otk::OBDisplay::display, FRAME);
190 XUnmapWindow(otk::OBDisplay::display, window);
191
192 // we dont want a border on the client
193 XSetWindowBorderWidth(otk::OBDisplay::display, window,client->borderWidth());
194
195 // remove the client class from the search list
196 Openbox::instance->removeClient(window);
197
198 // check if the app has already reparented its window to the root window
199 XEvent ev;
200 if (XCheckTypedWindowEvent(otk::OBDisplay::display, window, ReparentNotify,
201 &ev)) {
202 remap = true; // XXX: why do we remap the window if they already
203 // reparented to root?
204 } else {
205 // according to the ICCCM - if the client doesn't reparent to
206 // root, then we have to do it for them
207 XReparentWindow(otk::OBDisplay::display, window,
208 RootWindow(otk::OBDisplay::display,
209 DefaultScreen(otk::OBDisplay::display)),
210 // XXX: screen->getRootWindow(),
211 client->area().x(), client->area().y());
212 }
213
214 // if we want to remap the window, do so now
215 if (remap)
216 XMapWindow(otk::OBDisplay::display, window);
217
218 delete client;
219 }
220
221 void OBXEventHandler::mapRequest(const XMapRequestEvent &e)
222 {
223 #ifdef DEBUG
224 printf("MapRequest for 0x%lx\n", e.window);
225 #endif // DEBUG
226
227 OBClient *client = Openbox::instance->findClient(e.window);
228
229 if (client) {
230 // XXX: uniconify and/or unshade the window
231 } else {
232 manageWindow(e.window);
233 }
234
235 /*
236 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
237
238 if (win) {
239 bool focus = False;
240 if (win->isIconic()) {
241 win->deiconify();
242 focus = True;
243 }
244 if (win->isShaded()) {
245 win->shade();
246 focus = True;
247 }
248
249 if (focus && (win->isTransient() || win->getScreen()->doFocusNew()) &&
250 win->isVisible())
251 win->setInputFocus();
252 } else {
253 BScreen *screen = searchScreen(e->xmaprequest.parent);
254
255 if (! screen) {
256 */
257 /*
258 we got a map request for a window who's parent isn't root. this
259 can happen in only one circumstance:
260
261 a client window unmapped a managed window, and then remapped it
262 somewhere between unmapping the client window and reparenting it
263 to root.
264
265 regardless of how it happens, we need to find the screen that
266 the window is on
267 */
268 /*
269 XWindowAttributes wattrib;
270 if (! XGetWindowAttributes(otk::OBDisplay::display,
271 e->xmaprequest.window,
272 &wattrib)) {
273 // failed to get the window attributes, perhaps the window has
274 // now been destroyed?
275 break;
276 }
277
278 screen = searchScreen(wattrib.root);
279 assert(screen != 0); // this should never happen
280 }
281 screen->manageWindow(e->xmaprequest.window);
282 }
283 */
284 }
285
286
287 void OBXEventHandler::unmapNotify(const XUnmapEvent &e)
288 {
289 OBClient *client = Openbox::instance->findClient(e.window);
290 if (!client) return;
291
292 unmanageWindow(client);
293 }
294
295
296 void OBXEventHandler::destroyNotify(const XDestroyWindowEvent &e)
297 {
298 // XXX: window group leaders can come through here too!
299
300 OBClient *client = Openbox::instance->findClient(e.window);
301 if (!client) return;
302
303 unmanageWindow(client);
304 }
305
306
307 void OBXEventHandler::reparentNotify(const XReparentEvent &e)
308 {
309 /*
310 this event is quite rare and is usually handled in unmapNotify
311 however, if the window is unmapped when the reparent event occurs
312 the window manager never sees it because an unmap event is not sent
313 to an already unmapped window.
314 */
315 OBClient *client = Openbox::instance->findClient(e.window);
316 if (!client) return;
317
318 /*
319 BlackboxWindow *win = searchWindow(e->xreparent.window);
320 if (win)
321 win->reparentNotifyEvent(&e->xreparent);
322 */
323 }
324
325
326 void OBXEventHandler::propertyNotify(const XPropertyEvent &e)
327 {
328 _lasttime = e.time;
329
330 OBClient *client = Openbox::instance->findClient(e.window);
331 if (!client) return;
332
333 client->update(e);
334 }
335
336
337 void OBXEventHandler::expose(const XExposeEvent &first)
338 {
339 OBClient *client = Openbox::instance->findClient(first.window);
340 if (!client) return;
341
342 // compress expose events
343 XEvent e; e.xexpose = first;
344 unsigned int i = 0;
345 otk::Rect area(e.xexpose.x, e.xexpose.y, e.xexpose.width,
346 e.xexpose.height);
347 while (XCheckTypedWindowEvent(otk::OBDisplay::display,
348 e.xexpose.window, Expose, &e)) {
349 i++;
350 // merge expose area
351 area |= otk::Rect(e.xexpose.x, e.xexpose.y, e.xexpose.width,
352 e.xexpose.height);
353 }
354 if ( i > 0 ) {
355 // use the merged area
356 e.xexpose.x = area.x();
357 e.xexpose.y = area.y();
358 e.xexpose.width = area.width();
359 e.xexpose.height = area.height();
360 }
361
362 // XXX: make the decorations redraw!
363 }
364
365
366 void OBXEventHandler::colormapNotify(const XColormapEvent &e)
367 {
368 (void)e;
369 /*
370 BScreen *screen = searchScreen(e->xcolormap.window);
371 if (screen)
372 screen->setRootColormapInstalled((e->xcolormap.state ==
373 ColormapInstalled) ? True : False);
374 */
375 }
376
377
378 void OBXEventHandler::focusIn(const XFocusChangeEvent &e)
379 {
380 if (e.detail != NotifyNonlinear &&
381 e.detail != NotifyAncestor) {
382 /*
383 don't process FocusIns when:
384 1. the new focus window isn't an ancestor or inferior of the old
385 focus window (NotifyNonlinear)
386 make sure to allow the FocusIn when the old focus window was an
387 ancestor but didn't have a parent, such as root (NotifyAncestor)
388 */
389 return;
390 }
391 /*
392 BlackboxWindow *win = searchWindow(e.window);
393 if (win) {
394 if (! win->isFocused())
395 win->setFocusFlag(True);
396 */
397 /*
398 set the event window to None. when the FocusOut event handler calls
399 this function recursively, it uses this as an indication that focus
400 has moved to a known window.
401 */
402 /*
403 e->xfocus.window = None;
404
405 no_focus = False; // focusing is back on
406 }
407 */
408 }
409
410
411 void OBXEventHandler::focusOut(const XFocusChangeEvent &e)
412 {
413 if (e.detail != NotifyNonlinear) {
414 /*
415 don't process FocusOuts when:
416 2. the new focus window isn't an ancestor or inferior of the old
417 focus window (NotifyNonlinear)
418 */
419 return;
420 }
421
422 /*
423 BlackboxWindow *win = searchWindow(e->xfocus.window);
424 if (win && win->isFocused()) {
425 */
426 /*
427 before we mark "win" as unfocused, we need to verify that focus is
428 going to a known location, is in a known location, or set focus
429 to a known location.
430 */
431 /*
432 XEvent event;
433 // don't check the current focus if FocusOut was generated during a grab
434 bool check_focus = (e->xfocus.mode == NotifyNormal);
435 */
436 /*
437 First, check if there is a pending FocusIn event waiting. if there
438 is, process it and determine if focus has moved to another window
439 (the FocusIn event handler sets the window in the event
440 structure to None to indicate this).
441 */
442 /*
443 if (XCheckTypedEvent(otk::OBDisplay::display, FocusIn, &event)) {
444
445 process_event(&event);
446 if (event.xfocus.window == None) {
447 // focus has moved
448 check_focus = False;
449 }
450 }
451
452 if (check_focus) {
453 */
454 /*
455 Second, we query the X server for the current input focus.
456 to make sure that we keep a consistent state.
457 */
458 /*
459 BlackboxWindow *focus;
460 Window w;
461 int revert;
462 XGetInputFocus(otk::OBDisplay::display, &w, &revert);
463 focus = searchWindow(w);
464 if (focus) {
465 */
466 /*
467 focus got from "win" to "focus" under some very strange
468 circumstances, and we need to make sure that the focus indication
469 is correct.
470 */
471 /*
472 setFocusedWindow(focus);
473 } else {
474 // we have no idea where focus went... so we set it to somewhere
475 setFocusedWindow(0);
476 }
477 }
478 }
479 */
480 }
481
482
483 #ifdef SHAPE
484 void OBXEventHandler::shapeEvent(const XShapeEvent &e)
485 {
486 XShapeEvent *shape_event = (XShapeEvent *) e;
487 BlackboxWindow *win = searchWindow(e->xany.window);
488
489 if (win && shape_event->kind == ShapeBounding)
490 win->shapeEvent(shape_event);
491 }
492 #endif // SHAPE
493
494
495 void OBXEventHandler::clientMessage(const XClientMessageEvent &e)
496 {
497 if (e.format != 32)
498 return;
499 /*
500 } else if (e->xclient.message_type ==
501 xatom->getAtom(XAtom::blackbox_change_workspace) ||
502 e->xclient.message_type ==
503 xatom->getAtom(XAtom::net_current_desktop)) {
504 // NET_CURRENT_DESKTOP message
505 BScreen *screen = searchScreen(e->xclient.window);
506
507 unsigned int workspace = e->xclient.data.l[0];
508 if (screen && workspace < screen->getWorkspaceCount())
509 screen->changeWorkspaceID(workspace);
510 } else if (e->xclient.message_type ==
511 xatom->getAtom(XAtom::net_active_window)) {
512 // NET_ACTIVE_WINDOW
513 BlackboxWindow *win = searchWindow(e->xclient.window);
514
515 if (win) {
516 BScreen *screen = win->getScreen();
517
518 if (win->isIconic())
519 win->deiconify(False, False);
520 if (! win->isStuck() &&
521 (win->getWorkspaceNumber() != screen->getCurrentWorkspaceID())) {
522 no_focus = True;
523 screen->changeWorkspaceID(win->getWorkspaceNumber());
524 }
525 if (win->isVisible() && win->setInputFocus()) {
526 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
527 raiseWindow(win);
528 win->installColormap(True);
529 }
530 }
531 } else if (e->xclient.message_type ==
532 xatom->getAtom(XAtom::net_number_of_desktops)) {
533 // NET_NUMBER_OF_DESKTOPS
534 BScreen *screen = searchScreen(e->xclient.window);
535
536 if (e->xclient.data.l[0] > 0)
537 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
538 } else if (e->xclient.message_type ==
539 xatom->getAtom(XAtom::net_close_window)) {
540 // NET_CLOSE_WINDOW
541 BlackboxWindow *win = searchWindow(e->xclient.window);
542 if (win && win->validateClient())
543 win->close(); // could this be smarter?
544 } else if (e->xclient.message_type ==
545 xatom->getAtom(XAtom::net_wm_moveresize)) {
546 // NET_WM_MOVERESIZE
547 BlackboxWindow *win = searchWindow(e->xclient.window);
548 if (win && win->validateClient()) {
549 int x_root = e->xclient.data.l[0],
550 y_root = e->xclient.data.l[1];
551 if ((Atom) e->xclient.data.l[2] ==
552 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
553 win->beginMove(x_root, y_root);
554 } else {
555 if ((Atom) e->xclient.data.l[2] ==
556 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
557 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
558 else if ((Atom) e->xclient.data.l[2] ==
559 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
560 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
561 else if ((Atom) e->xclient.data.l[2] ==
562 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
563 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
564 else if ((Atom) e->xclient.data.l[2] ==
565 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
566 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
567 }
568 }
569 }
570 */
571 }
572
573
574 void OBXEventHandler::handle(const XEvent &e)
575 {
576 /* mouse button events can get translated into:
577 press - button was pressed down
578 release - buttons was released
579 click - button was pressed and released on the same window
580 double click - clicked twice on the same widget in a given time and area
581
582 key events are only bindable to presses. key releases are ignored.
583
584 mouse enter/leave can be bound to for the entire window
585 */
586
587 switch (e.type) {
588
589 // These types of XEvent's can be bound to actions by the user, and so end
590 // up getting passed off to the OBBindingMapper class at some point
591 case ButtonPress:
592 buttonPress(e.xbutton);
593 break;
594 case ButtonRelease:
595 buttonRelease(e.xbutton);
596 break;
597 case KeyPress:
598 keyPress(e.xkey);
599 break;
600 case MotionNotify:
601 motion(e.xmotion);
602 break;
603 case EnterNotify:
604 enterNotify(e.xcrossing);
605 break;
606 case LeaveNotify:
607 leaveNotify(e.xcrossing);
608 break;
609
610
611 // These types of XEvent's can not be bound to actions by the user and so
612 // will simply be handled in this class
613 case ConfigureRequest:
614 configureRequest(e.xconfigurerequest);
615 break;
616
617 case MapRequest:
618 mapRequest(e.xmaprequest);
619 break;
620
621 case UnmapNotify:
622 unmapNotify(e.xunmap);
623 break;
624
625 case DestroyNotify:
626 destroyNotify(e.xdestroywindow);
627 break;
628
629 case ReparentNotify:
630 reparentNotify(e.xreparent);
631 break;
632
633 case PropertyNotify:
634 propertyNotify(e.xproperty);
635 break;
636
637 case Expose:
638 expose(e.xexpose);
639 break;
640
641 case ColormapNotify:
642 colormapNotify(e.xcolormap);
643 break;
644
645 case FocusIn:
646 focusIn(e.xfocus);
647 break;
648
649 case FocusOut:
650 focusOut(e.xfocus);
651 break;
652
653 case ClientMessage:
654 clientMessage(e.xclient);
655
656 default:
657 #ifdef SHAPE
658 if (e.type == otk::OBDisplay::shapeEventBase())
659 shapeEvent(e);
660 #endif // SHAPE
661 break;
662
663 /*
664 case ClientMessage: {
665 break;
666 }
667
668 */
669 } // switch
670 }
671
672
673 }
This page took 0.0633280000000001 seconds and 4 git commands to generate.