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