]> Dogcows Code - chaz/openbox/blob - src/xeventhandler.cc
position the client inside the frame correctly.
[chaz/openbox] / 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 void OBXEventHandler::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 void OBXEventHandler::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 }
This page took 0.062979 seconds and 4 git commands to generate.