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