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