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