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