1 /*
2  * Oroborus Window Manager
3  *
4  * Copyright (C) 2001 Ken Lynch
5  * Copyright (C) 2002-2005 Stefan Pfetzing
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include <X11/Xlib.h>
27 #include <X11/Xmd.h>
28 #include <X11/extensions/shape.h>
29 #include <X11/Xatom.h>
30 #include <X11/xpm.h>
31 
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/time.h>
39 #include <sys/select.h>
40 
41 #ifdef DEBUG
42 #include <stdio.h>
43 #endif
44 
45 #include "client.h"
46 #include "events.h"
47 #include "frame.h"
48 #include "getopt.h"
49 #include "hints.h"
50 #include "i18n.h"
51 #include "keyboard.h"
52 #include "misc.h"
53 #include "oroborus.h"
54 #include "pixmap.h"
55 #include "session.h"
56 #include "workspaces.h"
57 
58 #include "globals.h"
59 
60 Bool raise_current_window = False;
61 
62 void
handleKeyPress(XKeyEvent * ev)63 handleKeyPress (XKeyEvent * ev)
64 {
65   client_t *c;
66   int state, key;
67   XEvent e;
68   XWindowChanges wc;
69 
70 #ifdef DEBUG
71   printf ("entering handleKeyEvent\n");
72 #endif
73 
74   c = clientGetFocus ();
75   state = ev->state & (Mod1Mask | Mod4Mask | ControlMask | ShiftMask);
76   for (key = 0; key < KEY_ENUM_MAX; key++)
77     if (keys[key].keycode == ev->keycode && keys[key].modifier == state)
78       break;
79 
80   if (c)
81     {
82       switch (key)
83 	{
84 	case KEY_QUIT:
85 	  quit = True;
86 	  break;
87 	case KEY_MOVE_UP:
88 	case KEY_MOVE_DOWN:
89 	case KEY_MOVE_LEFT:
90 	case KEY_MOVE_RIGHT:
91 	  clientMove (c, (XEvent *) ev);
92 	  clientWarpMouse (c);
93 	  break;
94 	case KEY_TOP_LEFT:
95 	  wc.x = frameLeft (c) + margins[MARGIN_LEFT];
96 	  wc.y = frameTop (c) + margins[MARGIN_TOP];
97 	  clientConfigure (c, &wc, CWX | CWY);
98 	  clientWarpMouse (c);
99 	  break;
100 	case KEY_TOP_RIGHT:
101 	  wc.x =
102 	    XDisplayWidth (dpy,
103 			   screen) - c->width - frameRight (c) -
104 	    margins[MARGIN_RIGHT];
105 	  wc.y = frameTop (c) + margins[MARGIN_TOP];
106 	  clientConfigure (c, &wc, CWX | CWY);
107 	  clientWarpMouse (c);
108 	  break;
109 	case KEY_BOTTOM_LEFT:
110 	  wc.x = frameLeft (c) + margins[MARGIN_LEFT];
111 	  wc.y =
112 	    XDisplayHeight (dpy,
113 			    screen) - c->height - frameBottom (c) -
114 	    margins[MARGIN_BOTTOM];
115 	  clientConfigure (c, &wc, CWX | CWY);
116 	  clientWarpMouse (c);
117 	  break;
118 	case KEY_BOTTOM_RIGHT:
119 	  wc.x =
120 	    XDisplayWidth (dpy,
121 			   screen) - c->width - frameRight (c) -
122 	    margins[MARGIN_RIGHT];
123 	  wc.y =
124 	    XDisplayHeight (dpy,
125 			    screen) - c->height - frameBottom (c) -
126 	    margins[MARGIN_BOTTOM];
127 	  clientConfigure (c, &wc, CWX | CWY);
128 	  clientWarpMouse (c);
129 	  break;
130 	case KEY_RESIZE_UP:
131 	case KEY_RESIZE_DOWN:
132 	case KEY_RESIZE_LEFT:
133 	case KEY_RESIZE_RIGHT:
134 	  clientResize (c, (XEvent *) ev);
135 	  clientWarpMouse (c);
136 	  break;
137 	case KEY_CYCLE_WINDOWS:
138 	  clientCycle (c);
139 	  break;
140 	case KEY_CLOSE_WINDOW:
141 	  clientClose (c);
142 	  break;
143 	case KEY_HIDE_WINDOW:
144 	  clientHide (c, True);
145 	  break;
146 	case KEY_TOGGLE_FULLSCREEN_WINDOW:
147 	  clientToggleFullscreen (c);
148 	  break;
149 	case KEY_MAXIMIZE_WINDOW:
150 	  clientToggleMaximized (c, WIN_STATE_MAXIMIZED);
151 	  clientWarpMouse (c);
152 	  break;
153 	case KEY_MAXIMIZE_VERT:
154 	  clientToggleMaximized (c, WIN_STATE_MAXIMIZED_VERT);
155 	  clientWarpMouse (c);
156 	  break;
157 	case KEY_MAXIMIZE_HORIZ:
158 	  clientToggleMaximized (c, WIN_STATE_MAXIMIZED_HORIZ);
159 	  clientWarpMouse (c);
160 	  break;
161 	case KEY_SHADE_WINDOW:
162 	  clientToggleShaded (c);
163 	  break;
164 	case KEY_RAISE_WINDOW_LAYER:
165 	  clientSetLayer (c, c->win_layer + 1);
166 	  break;
167 	case KEY_LOWER_WINDOW_LAYER:
168 	  clientSetLayer (c, c->win_layer - 1);
169 	  break;
170 	case KEY_NEXT_WORKSPACE:
171 	  workspaceSwitch (workspace + 1, NULL);
172 	  clientWarpMouse (clientGetFocus ());
173 	  break;
174 	case KEY_PREV_WORKSPACE:
175 	  workspaceSwitch (workspace - 1, NULL);
176 	  clientWarpMouse (clientGetFocus ());
177 	  break;
178 	case KEY_ADD_WORKSPACE:
179 	  workspaceSetCount (workspace_count + 1);
180 	  setNetWorkarea (margins, workspace_count);
181 	  break;
182 	case KEY_DEL_WORKSPACE:
183 	  workspaceSetCount (workspace_count - 1);
184 	  setNetWorkarea (margins, workspace_count);
185 	  break;
186 	case KEY_STICK_WINDOW:
187 	  clientToggleSticky (c);
188 	  break;
189 	case KEY_WORKSPACE_1:
190 	  workspaceSwitch (0, NULL);
191 	  clientWarpMouse (clientGetFocus ());
192 	  break;
193 	case KEY_WORKSPACE_2:
194 	  workspaceSwitch (1, NULL);
195 	  clientWarpMouse (clientGetFocus ());
196 	  break;
197 	case KEY_WORKSPACE_3:
198 	  workspaceSwitch (2, NULL);
199 	  clientWarpMouse (clientGetFocus ());
200 	  break;
201 	case KEY_WORKSPACE_4:
202 	  workspaceSwitch (3, NULL);
203 	  clientWarpMouse (clientGetFocus ());
204 	  break;
205 	case KEY_WORKSPACE_5:
206 	  workspaceSwitch (4, NULL);
207 	  clientWarpMouse (clientGetFocus ());
208 	  break;
209 	case KEY_WORKSPACE_6:
210 	  workspaceSwitch (5, NULL);
211 	  clientWarpMouse (clientGetFocus ());
212 	  break;
213 	case KEY_WORKSPACE_7:
214 	  workspaceSwitch (6, NULL);
215 	  clientWarpMouse (clientGetFocus ());
216 	  break;
217 	case KEY_WORKSPACE_8:
218 	  workspaceSwitch (7, NULL);
219 	  clientWarpMouse (clientGetFocus ());
220 	  break;
221 	case KEY_WORKSPACE_9:
222 	  workspaceSwitch (8, NULL);
223 	  clientWarpMouse (clientGetFocus ());
224 	  break;
225 	case KEY_MOVE_NEXT_WORKSPACE:
226 	  workspaceSwitch (workspace + 1, c);
227 	  clientWarpMouse (clientGetFocus ());
228 	  break;
229 	case KEY_MOVE_PREV_WORKSPACE:
230 	  workspaceSwitch (workspace - 1, c);
231 	  clientWarpMouse (clientGetFocus ());
232 	  break;
233 	case KEY_MOVE_WORKSPACE_1:
234 	  workspaceSwitch (0, c);
235 	  clientWarpMouse (clientGetFocus ());
236 	  break;
237 	case KEY_MOVE_WORKSPACE_2:
238 	  workspaceSwitch (1, c);
239 	  clientWarpMouse (clientGetFocus ());
240 	  break;
241 	case KEY_MOVE_WORKSPACE_3:
242 	  workspaceSwitch (2, c);
243 	  clientWarpMouse (clientGetFocus ());
244 	  break;
245 	case KEY_MOVE_WORKSPACE_4:
246 	  workspaceSwitch (3, c);
247 	  clientWarpMouse (clientGetFocus ());
248 	  break;
249 	case KEY_MOVE_WORKSPACE_5:
250 	  workspaceSwitch (4, c);
251 	  clientWarpMouse (clientGetFocus ());
252 	  break;
253 	case KEY_MOVE_WORKSPACE_6:
254 	  workspaceSwitch (5, c);
255 	  clientWarpMouse (clientGetFocus ());
256 	  break;
257 	case KEY_MOVE_WORKSPACE_7:
258 	  workspaceSwitch (6, c);
259 	  clientWarpMouse (clientGetFocus ());
260 	  break;
261 	case KEY_MOVE_WORKSPACE_8:
262 	  workspaceSwitch (7, c);
263 	  clientWarpMouse (clientGetFocus ());
264 	  break;
265 	case KEY_MOVE_WORKSPACE_9:
266 	  workspaceSwitch (8, c);
267 	  clientWarpMouse (clientGetFocus ());
268 	  break;
269 	}
270     }
271   else
272     {
273       switch (key)
274 	{
275 	case KEY_QUIT:
276 	  quit = True;
277 	  break;
278 	case KEY_CYCLE_WINDOWS:
279 	  if (clients)
280 	    clientCycle (clients->prev);
281 	  break;
282 	case KEY_NEXT_WORKSPACE:
283 	  workspaceSwitch (workspace + 1, NULL);
284 	  clientWarpMouse (clientGetFocus ());
285 	  break;
286 	case KEY_PREV_WORKSPACE:
287 	  workspaceSwitch (workspace - 1, NULL);
288 	  clientWarpMouse (clientGetFocus ());
289 	  break;
290 	case KEY_ADD_WORKSPACE:
291 	  workspaceSetCount (workspace_count + 1);
292 	  setNetWorkarea (margins, workspace_count);
293 	  break;
294 	case KEY_DEL_WORKSPACE:
295 	  workspaceSetCount (workspace_count - 1);
296 	  setNetWorkarea (margins, workspace_count);
297 	  break;
298 	case KEY_WORKSPACE_1:
299 	  workspaceSwitch (0, NULL);
300 	  clientWarpMouse (clientGetFocus ());
301 	  break;
302 	case KEY_WORKSPACE_2:
303 	  workspaceSwitch (1, NULL);
304 	  clientWarpMouse (clientGetFocus ());
305 	  break;
306 	case KEY_WORKSPACE_3:
307 	  workspaceSwitch (2, NULL);
308 	  clientWarpMouse (clientGetFocus ());
309 	  break;
310 	case KEY_WORKSPACE_4:
311 	  workspaceSwitch (3, NULL);
312 	  clientWarpMouse (clientGetFocus ());
313 	  break;
314 	case KEY_WORKSPACE_5:
315 	  workspaceSwitch (4, NULL);
316 	  clientWarpMouse (clientGetFocus ());
317 	  break;
318 	case KEY_WORKSPACE_6:
319 	  workspaceSwitch (5, NULL);
320 	  clientWarpMouse (clientGetFocus ());
321 	  break;
322 	case KEY_WORKSPACE_7:
323 	  workspaceSwitch (6, NULL);
324 	  clientWarpMouse (clientGetFocus ());
325 	  break;
326 	case KEY_WORKSPACE_8:
327 	  workspaceSwitch (7, NULL);
328 	  clientWarpMouse (clientGetFocus ());
329 	  break;
330 	case KEY_WORKSPACE_9:
331 	  workspaceSwitch (8, NULL);
332 	  clientWarpMouse (clientGetFocus ());
333 	  break;
334 	}
335     }
336 
337   while (XCheckTypedEvent (dpy, EnterNotify, &e));
338 }
339 
340 void
handleButtonPress(XButtonEvent * ev)341 handleButtonPress (XButtonEvent * ev)
342 {
343   client_t *c;
344   Window win;
345   int state, replay = False;
346   static Time last_button_time;
347 
348 #ifdef DEBUG
349   printf ("entering handleButtonPress\n");
350 #endif
351 
352   while (XCheckTypedEvent (dpy, ButtonPress, (XEvent *) ev));
353 
354   state = ev->state & (Mod1Mask | Mod4Mask | ShiftMask | ControlMask);
355 
356   c = clientGetFromWindow (ev->window, FRAME);
357   if (c)
358     {
359       state = ev->state & (Mod1Mask | Mod4Mask | ShiftMask | ControlMask);
360       win = getMouseWindow (dpy, c->frame);
361 
362       clientSetFocus (c, True);
363 
364       if (win == c->buttons[HIDE_BUTTON] ||
365 	  win == c->buttons[CLOSE_BUTTON] ||
366 	  win == c->buttons[MAXIMIZE_BUTTON] ||
367 	  win == c->buttons[SHADE_BUTTON])
368 	{
369 	  clientRaise (c);
370 	  clientButtonPress (c, win, ev);
371 	}
372       else if (((win == c->title || win == c->sides[SIDE_BOTTOM] ||
373 		 win == c->sides[SIDE_LEFT] || win == c->sides[SIDE_RIGHT]) &&
374 		ev->button == Button1 && state == 0) || (ev->button == Button1
375 							 && state ==
376 							 keys[KEY_WINDOW_OPS].
377 							 modifier))
378 	{
379 	  clientRaise (c);
380 	  if (ev->time - last_button_time <= 250 && last_button_time != 0)
381 	    {
382 	      switch (double_click_action)
383 		{
384 		case ACTION_MAXIMIZE:
385 		  clientToggleMaximized (c, WIN_STATE_MAXIMIZED);
386 		  break;
387 		case ACTION_SHADE:
388 		  clientToggleShaded (c);
389 		  break;
390 		case ACTION_HIDE:
391 		  clientHide (c, True);
392 		  break;
393 		}
394 	      last_button_time = 0;
395 	    }
396 	  else
397 	    {
398 	      clientMove (c, (XEvent *) ev);
399 	      last_button_time = ev->time;
400 	    }
401 	}
402       else if ((win == c->corners[CORNER_TOP_LEFT] ||
403 		win == c->corners[CORNER_TOP_RIGHT] ||
404 		win == c->corners[CORNER_BOTTOM_LEFT] ||
405 		win == c->corners[CORNER_BOTTOM_RIGHT]) &&
406 	       ev->button == Button1 && state == 0)
407 	{
408 	  clientRaise (c);
409 	  clientResize (c, (XEvent *) ev);
410 	}
411       else if (win != c->window && ev->button == Button2 && state == 0
412 	       && !typeDesktop (c->window))
413 	{
414 	  clientRaise (c);
415 	  clientToggleSticky (c);
416 	}
417       else if (ev->button == Button2
418 	       && state == keys[KEY_WINDOW_OPS].modifier
419 	       && !typeDesktop (c->window))
420 	{
421 	  clientRaise (c);
422 	  clientResize (c, (XEvent *) ev);
423 	}
424       else if (((win != c->window && ev->button == Button3 && state == 0) ||
425 		(ev->button == Button3
426 		 && state == keys[KEY_WINDOW_OPS].modifier))
427 	       && !typeDesktop (c->window))
428 	clientLower (c);
429       else if (win != c->window && ev->button == Button1 && state == Mod1Mask)
430 	clientSetLayer (c, c->win_layer + 1);
431       else if (win != c->window && ev->button == Button3 && state == Mod1Mask)
432 	clientSetLayer (c, c->win_layer - 1);
433       else
434 	{
435 	  if (raise_on_click)
436 	    clientRaise (c);
437 	  if (win == c->window)
438 	    replay = True;
439 	}
440 
441       if (replay)
442 	XAllowEvents (dpy, ReplayPointer, CurrentTime);
443       else
444 	XAllowEvents (dpy, SyncPointer, CurrentTime);
445 
446       switch_timer(False);
447     }
448   else
449     {
450       XUngrabPointer (dpy, CurrentTime);
451       XSendEvent (dpy, gnome_win, False, SubstructureNotifyMask,
452 		  (XEvent *) ev);
453     }
454 }
455 
456 void
handleButtonRelease(XButtonEvent * ev)457 handleButtonRelease (XButtonEvent * ev)
458 {
459 #ifdef DEBUG
460   printf ("entering handleButtonRelease\n");
461 #endif
462 
463   XSendEvent (dpy, gnome_win, False, SubstructureNotifyMask, (XEvent *) ev);
464 }
465 
466 void
handleDestroyNotify(XDestroyWindowEvent * ev)467 handleDestroyNotify (XDestroyWindowEvent * ev)
468 {
469   client_t *c;
470 
471 #ifdef DEBUG
472   printf ("entering handleDestroyNotify\n");
473 #endif
474 
475   c = clientGetFromWindow (ev->window, WINDOW);
476   if (c)
477     {
478       clientUnframe (c, False);
479       if (clients)
480 	{
481 	  c = clientGetTopMostShaded (WIN_LAYER_NORMAL, True);
482 	  if (!c)
483 	    c = clientGetTopMost (WIN_LAYER_NORMAL);
484 
485 	  clientSetFocus (c, True);
486 	}
487       else
488 	clientSetFocus (NULL, True);
489     }
490 }
491 
492 void
handleUnmapNotify(XUnmapEvent * ev)493 handleUnmapNotify (XUnmapEvent * ev)
494 {
495   client_t *c;
496 
497 #ifdef DEBUG
498   printf ("entering handleUnmapNotify\n");
499 #endif
500 
501   c = clientGetFromWindow (ev->window, WINDOW);
502   if (c)
503     {
504       if (c->ignore_unmap)
505 	c->ignore_unmap--;
506       else
507 	{
508 	  clientUnframe (c, False);
509 	  if (clients)
510 	    {
511 	      c = clientGetTopMostShaded (WIN_LAYER_NORMAL, True);
512 	      if (!c)
513 		c = clientGetTopMost (WIN_LAYER_NORMAL);
514 	      clientSetFocus (c, True);
515 	    }
516 	  else
517 	    clientSetFocus (NULL, True);
518 	}
519     }
520 }
521 
522 void
handleMapRequest(XMapRequestEvent * ev)523 handleMapRequest (XMapRequestEvent * ev)
524 {
525   client_t *c;
526 
527 #ifdef DEBUG
528   printf ("entering handleMapRequest\n");
529 #endif
530 
531   c = clientGetFromWindow (ev->window, WINDOW);
532   if (c)
533     clientShow (c, True);
534   else
535     clientFrame (ev->window);
536 }
537 
538 void
handleConfigureRequest(XConfigureRequestEvent * ev)539 handleConfigureRequest (XConfigureRequestEvent * ev)
540 {
541   client_t *c;
542   XWindowChanges wc;
543 
544 #ifdef DEBUG
545   printf ("entering handleConfigureRequest\n");
546 #endif
547 
548   wc.x = ev->x;
549   wc.y = ev->y;
550   wc.width = ev->width;
551   wc.height = ev->height;
552   wc.sibling = ev->above;
553   wc.stack_mode = ev->detail;
554   wc.border_width = ev->border_width;
555 
556   c = clientGetFromWindow (ev->window, WINDOW);
557 
558   if (c)
559     {
560       if (! (c->above || c->was_above))
561 	{
562 	  wc.x += frameLeft(c);
563 	  wc.y += frameTop(c);
564 	}
565       clientConfigure (c, &wc, ev->value_mask);
566     }
567   else
568     XConfigureWindow (dpy, ev->window, ev->value_mask, &wc);
569 }
570 
571 void
handleEnterNotify(XCrossingEvent * ev)572 handleEnterNotify (XCrossingEvent * ev)
573 {
574   client_t *c;
575 
576 #ifdef DEBUG
577   printf ("entering handleEnterNotify\n");
578 #endif
579 
580   while (XCheckTypedEvent (dpy, EnterNotify, (XEvent *) ev));
581 
582   c = clientGetFromWindow (ev->window, FRAME);
583   if (c && !click_to_focus)
584     clientSetFocus (c, True);
585 
586 }
587 
588 void
handleFocusIn(XFocusChangeEvent * ev)589 handleFocusIn (XFocusChangeEvent * ev)
590 {
591   client_t *c;
592 
593 #ifdef DEBUG
594   printf ("entering handleFocusIn\n");
595 #endif
596 
597   c = clientGetFromWindow (ev->window, WINDOW);
598   if (c)
599     frameDraw (c);
600   else if (clients)
601     clientSetFocus (clientGetNext (clients->prev, 0), True);
602   else
603     clientSetFocus (NULL, True);
604 
605   if (raise_on_focus)
606     switch_timer(True);
607 }
608 
609 void
handleFocusOut(XFocusChangeEvent * ev)610 handleFocusOut (XFocusChangeEvent * ev)
611 {
612   client_t *c;
613 
614 #ifdef DEBUG
615   printf ("entering handleFocusOut\n");
616 #endif
617 
618   c = clientGetFromWindow (ev->window, WINDOW);
619   if (c)
620     frameDraw (c);
621 }
622 
623 void
handlePropertyNotify(XPropertyEvent * ev)624 handlePropertyNotify (XPropertyEvent * ev)
625 {
626   client_t *c;
627   long dummy;
628 
629 #ifdef DEBUG
630   printf ("entering handlePropertyNotify\n");
631 #endif
632 
633   c = clientGetFromWindow (ev->window, WINDOW);
634   if (c)
635     {
636       if (ev->atom == XA_WM_NORMAL_HINTS)
637 	XGetWMNormalHints (dpy, c->window, c->size, &dummy);
638       else if (ev->atom == XA_WM_NAME)
639 	{
640 	  if (c->name)
641 	    free (c->name);
642 	  getWindowName (dpy, c->window, &c->name);
643 	  frameDraw (c);
644 	}
645       else if (ev->atom == win_hints)
646 	getGnomeHint (c->window, win_hints, &c->win_hints);
647       else if (ev->atom == net_atoms[NET_WM_STRUT])
648 	{
649 	  delNetWMStrut (margins, c->margins);
650 	  getNetWMStrut (c->window, margins, c->margins);
651 	}
652       else if (ev->atom == win_layer)
653 	{
654 	  getGnomeHint (c->window, win_layer, &dummy);
655 	  clientSetLayer (c, dummy);
656 	}
657       else if (ev->atom == win_workspace)
658 	{
659 	  getGnomeHint (c->window, win_workspace, &dummy);
660 	  clientSetWorkspace (c, dummy);
661 	}
662     }
663   else
664     {
665       if (ev->atom == win_workspace_count)
666 	{
667 	  getGnomeHint (root, win_workspace_count, &dummy);
668 	  workspaceSetCount (dummy);
669 	  setNetWorkarea (margins, workspace_count);
670 	}
671       else if (ev->atom == gnome_panel_desktop_area)
672 	{
673 	  getGnomeDesktopMargins (margins);
674 	  setNetWorkarea (margins, workspace_count);
675 	}
676     }
677 }
678 
679 void
handleClientMessage(XClientMessageEvent * ev)680 handleClientMessage (XClientMessageEvent * ev)
681 {
682   client_t *c;
683 
684 #ifdef DEBUG
685   printf ("entering handleClientMessage\n");
686 #endif
687 
688   c = clientGetFromWindow (ev->window, WINDOW);
689   if (c)
690     {
691       if (ev->message_type == wm_change_state && ev->format == 32 &&
692 	  ev->data.l[0] == IconicState)
693 	clientHide (c, True);
694       else if (ev->message_type == win_layer && ev->format == 32)
695 	{
696 	  setGnomeHint (c->window, ev->data.l[0], win_hints);
697 	  clientSetLayer (c, ev->data.l[0]);
698 	  if (ev->data.l[0] == 6)
699 	    clientToggleAbove (c);
700 	  clientRaise (c);
701 	}
702       else if (ev->message_type == win_state && ev->format == 32)
703 	clientSetState (c, ev->data.l[0], ev->data.l[1]);
704       else
705 	if ((ev->message_type == win_workspace
706 	     || ev->message_type == net_atoms[NET_WM_DESKTOP])
707 	    && ev->format == 32)
708 	clientSetWorkspace (c, ev->data.l[0]);
709       else if (ev->message_type == net_atoms[NET_ACTIVE_WINDOW]
710 	       && ev->format == 32)
711 	{
712 	  if (getWMState (c->window) == IconicState)
713 	    clientShow (c, False);
714 	  clientSetFocus (c, True);
715 	  clientRaise (c);
716 	  setWMState (c->window, NormalState);
717 	}
718       else if (ev->message_type == net_atoms[NET_CLOSE_WINDOW]
719 	       && ev->format == 32)
720 	clientClose (c);
721       else if (ev->message_type == net_atoms[NET_WM_STATE]
722 	       && ev->format == 32)
723 	{
724 	  switch (ev->data.l[0])
725 	    {
726 	    case NET_WM_STATE_ADD:
727 	    case NET_WM_STATE_REMOVE:
728 	    case NET_WM_STATE_TOGGLE:
729 	      if (ev->data.l[1] == net_atoms[NET_WM_STATE_ABOVE]
730 		  || ev->data.l[2] == net_atoms[NET_WM_STATE_ABOVE])
731 		clientToggleAbove (c);
732 	      if (ev->data.l[1] == net_atoms[NET_WM_STATE_FULLSCREEN]
733 		  || ev->data.l[2] == net_atoms[NET_WM_STATE_FULLSCREEN])
734 		clientToggleFullscreen(c);
735 	      break;
736 	    }
737 	}
738     }
739   else
740     {
741       if ((ev->message_type == win_workspace
742 	   || ev->message_type == net_atoms[NET_WM_DESKTOP]
743 	   || ev->message_type == net_atoms[NET_CURRENT_DESKTOP])
744 	  && ev->format == 32)
745 	workspaceSwitch (ev->data.l[0], NULL);
746       else
747 	if ((ev->message_type == win_workspace_count
748 	     || ev->message_type == net_atoms[NET_NUMBER_OF_DESKTOPS])
749 	    && ev->format == 32)
750 	{
751 	  workspaceSetCount (ev->data.l[0]);
752 	  setNetWorkarea (margins, workspace_count);
753 	}
754     }
755 }
756 
757 void
handleShape(XShapeEvent * ev)758 handleShape (XShapeEvent * ev)
759 {
760   client_t *c;
761 
762 #ifdef DEBUG
763   printf ("entering handleShape\n");
764 #endif
765 
766   c = clientGetFromWindow (ev->window, WINDOW);
767   if (c)
768     frameDraw (c);
769 }
770 
771 void
handleEvent(XEvent * ev)772 handleEvent (XEvent * ev)
773 {
774 #ifdef DEBUG
775   printf ("entering handleEvent\n");
776 #endif
777 
778   switch (ev->type)
779     {
780     case KeyPress:
781 #ifdef DEBUG
782       printf ("KeyPress\n");
783 #endif
784       handleKeyPress ((XKeyEvent *) ev);
785       break;
786     case ButtonPress:
787 #ifdef DEBUG
788       printf ("ButtonPress\n");
789 #endif
790       handleButtonPress ((XButtonEvent *) ev);
791       break;
792     case ButtonRelease:
793 #ifdef DEBUG
794       printf ("ButtonRelease\n");
795 #endif
796       handleButtonRelease ((XButtonEvent *) ev);
797       break;
798     case DestroyNotify:
799 #ifdef DEBUG
800       printf ("DestroyNotify\n");
801 #endif
802       handleDestroyNotify ((XDestroyWindowEvent *) ev);
803       break;
804     case UnmapNotify:
805 #ifdef DEBUG
806       printf ("UnmapNotify\n");
807 #endif
808       handleUnmapNotify ((XUnmapEvent *) ev);
809       break;
810     case MapRequest:
811 #ifdef DEBUG
812       printf ("MapRequest\n");
813 #endif
814       handleMapRequest ((XMapRequestEvent *) ev);
815       break;
816     case ConfigureRequest:
817 #ifdef DEBUG
818       printf ("ConfigureRequest\n");
819 #endif
820       handleConfigureRequest ((XConfigureRequestEvent *) ev);
821       break;
822     case EnterNotify:
823 #ifdef DEBUG
824       printf ("EnterNotify\n");
825 #endif
826       handleEnterNotify ((XCrossingEvent *) ev);
827       break;
828     case FocusIn:
829 #ifdef DEBUG
830       printf ("FocusIn\n");
831 #endif
832       handleFocusIn ((XFocusChangeEvent *) ev);
833       break;
834     case FocusOut:
835 #ifdef DEBUG
836       printf ("FocusOut\n");
837 #endif
838       handleFocusOut ((XFocusChangeEvent *) ev);
839       break;
840     case PropertyNotify:
841 #ifdef DEBUG
842       printf ("PropertyNotify\n");
843 #endif
844       handlePropertyNotify ((XPropertyEvent *) ev);
845       break;
846     case ClientMessage:
847 #ifdef DEBUG
848       printf ("clientMessage\n");
849 #endif
850       handleClientMessage ((XClientMessageEvent *) ev);
851       break;
852     default:
853 #ifdef DEBUG
854       printf ("default\n");
855 #endif
856       if (shape && ev->type == shape_event)
857 	handleShape ((XShapeEvent *) ev);
858     }
859 }
860 
861 void
eventLoop()862 eventLoop ()
863 {
864   fd_set readset;
865   int x_fd;
866   XEvent ev;
867   int nfds;
868 
869 #ifdef DEBUG
870   printf ("entering eventLoop\n");
871 #endif
872 
873   /* first get the X11 fd */
874   x_fd = XConnectionNumber (dpy);
875 
876   while (1)
877     {
878       /* then zero the readset and add the x_fd to it */
879       FD_ZERO (&readset);
880       FD_SET (x_fd, &readset);
881 
882       /* if the ice_fd exists, add it to the readset too. */
883       if (ice_fd != -1)
884 	FD_SET (ice_fd, &readset);
885 
886       /* compute the number of the highest fd for the select call */
887       nfds = (x_fd > ice_fd) ? x_fd+1 : ice_fd+1;
888 
889       /* did we catch a -1 (interrupted / error) in the select call? */
890 INT:  if (-1 == select (nfds, &readset, NULL, NULL, NULL))
891 	{
892 	  if (errno == EINTR)
893 	    {
894 	      /* do we need to reload oroborus? */
895 	      if (reload)
896 		{
897 		  cleanUp ();
898 #ifdef DEBUG
899 		  printf ("executing: %s\n", progname);
900 #endif
901 		  /* exec oroborus itself */
902 		  execvp (progname, stat_argv);
903 		}
904 
905 	      /* do we need to raise the current window?
906 	       * raise_current_window is set in the SIGALRM handler.
907 	       */
908 	      if (raise_current_window)
909 		{
910 		  client_t *c = clientGetFocus();
911 
912 		  raise_current_window = False;
913 		  /* is there a client, then raise it */
914 		  if (c)
915 		    {
916 #ifdef DEBUG
917 		      printf ("raising client (%#lx)\n", c->window);
918 #endif
919 		      clientRaise (c);
920 		      XFlush(dpy);
921 		    }
922 		}
923 
924 	      /* shall we quit? */
925 	      if (quit)
926 		return;
927 
928 	      /* EINTR means, we just can re-execute the select call.
929 	       * Sorry, but in this case just the best is a goto.
930 	       */
931 	      goto INT;
932 	    }
933 
934 	  /* now comes the case, select fails, and errno is not EINTR. */
935 	  else
936 	    return;
937 
938 	}
939       else
940 	{
941 	  /* now lets check the fd's */
942 	  if (FD_ISSET (x_fd, &readset))
943 	    /* process all pending requests */
944 	    while (XPending (dpy))
945 	      {
946 		XNextEvent (dpy, &ev);
947 		handleEvent (&ev);
948 	      }
949 	  else if (FD_ISSET (ice_fd, &readset))
950 	    /* process the ice messages */
951 	    process_ice_msgs ();
952 	}
953 
954     }
955 
956 #ifdef DEBUG
957   printf ("leaving eventLoop\n");
958 #endif
959 }
960 
961 void
switch_timer(Bool enable)962 switch_timer (Bool enable)
963 {
964   struct itimerval itimer;
965 
966 #ifdef DEBUG
967   if (enable)
968     printf ("TIMER: enabling\n");
969   else
970     printf ("TIMER: disabling\n");
971 #endif
972 
973   /* we don't need an interval */
974   itimer.it_interval.tv_usec = 0;
975   itimer.it_interval.tv_sec = 0;
976 
977   if (enable)
978     /* insert the timer value here */
979     itimer.it_value.tv_usec = raise_delay*1000;
980   else
981     itimer.it_value.tv_usec = 0;
982 
983   itimer.it_value.tv_sec = 0;
984 
985   setitimer (ITIMER_REAL, &itimer, NULL);
986 }
987 
988 /***This must remain at the end of the file.***********************************************
989  * vi:set sw=2 cindent cinoptions={1s,>2s,^-1s,n-1s foldmethod=marker foldmarker=���,���: *
990  * arch-tag: event handling for oroborus-wm                                               *
991  ******************************************************************************************/
992