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