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