root/events.c

Revision 1, 10.4 KB (checked in by root, 3 years ago)

Initial commit

Line 
1/* evilwm - Minimalist Window Manager for X
2 * Copyright (C) 1999-2006 Ciaran Anscomb <evilwm@6809.org.uk>
3 * see README for license and other details. */
4
5#include <stdlib.h>
6#include <sys/select.h>
7//#include <X11/Intrinsic.h>
8#include "evilwm.h"
9#include "log.h"
10
11static void current_to_head(void) {
12  Client *c;
13  if (current && current != head_client) {
14    for (c = head_client; c; c = c->next) {
15      if (c->next == current) {
16        c->next = current->next;
17        current->next = head_client;
18        head_client = current;
19        break;
20      }
21    }
22  }
23}
24
25
26PyObject *key_hook = NULL;
27PyObject* set_key_hook(PyObject *_,  PyObject* pyargs)
28{
29  if(!PyTuple_Check(pyargs)) return PyExc_TypeError;
30  if(PyTuple_Size(pyargs) != 1) return PyExc_TypeError;
31
32  PyObject* hook = PyTuple_GetItem(pyargs, 0);
33  PyObject *ret = key_hook;
34  if(!PyCallable_Check(hook)) return PyExc_TypeError;
35
36  Py_INCREF(hook);
37  key_hook = hook;
38
39  //run_post_geometry_hook(NULL);
40  if(ret) return ret;
41  Py_RETURN_NONE;
42}
43
44void run_key_hook(int code)
45{
46  if(!key_hook) return;
47  PyGILState_STATE s = PyGILState_Ensure();
48  PyObject *arg = PyTuple_New(1);
49  PyTuple_SetItem(arg, 0,  PyLong_FromLong(code));
50  PyObject_CallObject(key_hook, arg);
51  Py_DECREF(arg);
52  PyGILState_Release(s);
53}
54
55static void handle_key_event2(XKeyEvent *e)
56{
57  int i = 0;
58
59  KeySym key = XKeycodeToKeysym(dpy,e->keycode,0);
60  for(i = 0; i < kbs_len; ++i)
61    if(kbs[i] && kbs[i]->key == key && kbs[i]->mask == e->state) {
62      PyObject *arg = PyTuple_New(0);
63      PyGILState_STATE s = PyGILState_Ensure();
64      PyObject_CallObject(kbs[i]->cb, arg);
65      PyGILState_Release(s);
66      Py_DECREF(arg);
67    }
68}
69
70static void handle_key_event(XKeyEvent *e) {
71  KeySym key = XKeycodeToKeysym(dpy,e->keycode,0);
72  Client *c;
73  int width_inc, height_inc;
74#ifdef VWM
75  ScreenInfo *current_screen = find_current_screen();
76#endif
77
78  run_key_hook(key);
79  run_key_hook(e->state);
80  switch(key) {
81  case KEY_NEW:
82    spawn(opt_term);
83    break;
84  case KEY_NEXT:
85    next();
86    if (XGrabKeyboard(dpy, e->root, False, GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess) {
87      XEvent ev;
88      do {
89        XMaskEvent(dpy, KeyPressMask|KeyReleaseMask, &ev);
90        if (ev.type == KeyPress && XKeycodeToKeysym(dpy,ev.xkey.keycode,0) == KEY_NEXT)
91          next();
92      } while (ev.type == KeyPress || XKeycodeToKeysym(dpy,ev.xkey.keycode,0) == KEY_NEXT);
93      XUngrabKeyboard(dpy, CurrentTime);
94    }
95    current_to_head();
96    break;
97#ifdef VWM
98  case XK_1: case XK_2: case XK_3: case XK_4:
99  case XK_5: case XK_6: case XK_7: case XK_8:
100    switch_vdesk(current_screen, KEY_TO_VDESK(key));
101    break;
102  case KEY_PREVDESK:
103    if (current_screen->vdesk > KEY_TO_VDESK(XK_1)) {
104      switch_vdesk(current_screen,
105                   current_screen->vdesk - 1);
106    }
107    break;
108  case KEY_NEXTDESK:
109    if (current_screen->vdesk < KEY_TO_VDESK(XK_8)) {
110      switch_vdesk(current_screen,
111                   current_screen->vdesk + 1);
112    }
113    break;
114#endif
115  default: break;
116  }
117  c = current;
118  if (c == NULL) return;
119  width_inc = (c->width_inc > 1) ? c->width_inc : 16;
120  height_inc = (c->height_inc > 1) ? c->height_inc : 16;
121  switch (key) {
122  case KEY_LEFT:
123    if (e->state & altmask) {
124      if ((c->width - width_inc) >= c->min_width)
125        c->width -= width_inc;
126    } else {
127      c->x -= 16;
128    }
129    goto move_client;
130  case KEY_DOWN:
131    if (e->state & altmask) {
132      if (!c->max_height || (c->height + height_inc) <= c->max_height)
133        c->height += height_inc;
134    } else {
135      c->y += 16;
136    }
137    goto move_client;
138  case KEY_UP:
139    if (e->state & altmask) {
140      if ((c->height - height_inc) >= c->min_height)
141        c->height -= height_inc;
142    } else {
143      c->y -= 16;
144    }
145    goto move_client;
146  case KEY_RIGHT:
147    if (e->state & altmask) {
148      if (!c->max_width || (c->width + width_inc) <= c->max_width)
149        c->width += width_inc;
150    } else {
151      c->x += 16;
152    }
153    goto move_client;
154  case KEY_TOPLEFT:
155    c->x = c->border;
156    c->y = c->border;
157    goto move_client;
158  case KEY_TOPRIGHT:
159    c->x = DisplayWidth(dpy, c->screen->screen)
160      - c->width-c->border;
161    c->y = c->border;
162    goto move_client;
163  case KEY_BOTTOMLEFT:
164    c->x = c->border;
165    c->y = DisplayHeight(dpy, c->screen->screen)
166      - c->height-c->border;
167    goto move_client;
168  case KEY_BOTTOMRIGHT:
169    c->x = DisplayWidth(dpy, c->screen->screen)
170      - c->width-c->border;
171    c->y = DisplayHeight(dpy, c->screen->screen)
172      - c->height-c->border;
173    goto move_client;
174  case KEY_KILL:
175    send_wm_delete(c, e->state & altmask);
176    break;
177  case KEY_LOWER: case KEY_ALTLOWER:
178    XLowerWindow(dpy, c->parent);
179    break;
180  case KEY_INFO:
181    show_info(c, key);
182    break;
183  case KEY_MAX:
184    maximise_client(c, MAXIMISE_HORZ|MAXIMISE_VERT);
185    break;
186  case KEY_MAXVERT:
187    maximise_client(c, MAXIMISE_VERT);
188    break;
189#ifdef VWM
190  case KEY_FIX:
191    fix_client(c);
192    break;
193#endif
194  default: break;
195  }
196  return;
197 move_client:
198  moveresize(c);
199  setmouse(c->window, c->width + c->border - 1,
200           c->height + c->border - 1);
201  discard_enter_events();
202  return;
203}
204
205#ifdef MOUSE
206static void handle_button_event(XButtonEvent *e) {
207  Client *c = find_client(e->window);
208
209  if (c) {
210    switch (e->button) {
211    case Button1:
212      drag(c);
213      run_mouse_button1_hook(c);
214      break;
215    case Button2:
216      sweep(c);
217      run_mouse_button2_hook(c);
218      break;
219    case Button3:
220      XLowerWindow(dpy, c->parent);
221      run_mouse_button3_hook(c);
222      break;
223    default: break;
224    }
225  }
226}
227#endif
228
229static void handle_configure_request(XConfigureRequestEvent *e) {
230  Client *c = find_client(e->window);
231  XWindowChanges wc;
232  unsigned int value_mask = e->value_mask;
233
234  wc.sibling = e->above;
235  wc.stack_mode = e->detail;
236  wc.width = e->width;
237  wc.height = e->height;
238  if (c) {
239    ungravitate(c);
240    if (value_mask & CWWidth) c->width = e->width;
241    if (value_mask & CWHeight) c->height = e->height;
242    if (value_mask & CWX) c->x = e->x;
243    if (value_mask & CWY) c->y = e->y;
244    if (value_mask & CWStackMode && value_mask & CWSibling) {
245      Client *sibling = find_client(e->above);
246      if (sibling) {
247        wc.sibling = sibling->parent;
248      }
249    }
250    if (c->x == 0 && c->width >= DisplayWidth(dpy, c->screen->screen)) {
251      c->x -= c->border;
252    }
253    if (c->y == 0 && c->height >= DisplayHeight(dpy, c->screen->screen)) {
254      c->y -= c->border;
255    }
256    gravitate(c);
257
258    wc.x = c->x - c->border;
259    wc.y = c->y - c->border;
260    wc.border_width = c->border;
261    LOG_XDEBUG("XConfigureWindow(dpy, parent(%x), %lx, &wc);\n", (unsigned int)c->parent, value_mask);
262    XConfigureWindow(dpy, c->parent, value_mask, &wc);
263    XMoveResizeWindow(dpy, c->window, 0, 0, c->width, c->height);
264    if ((value_mask & (CWX|CWY)) && !(value_mask & (CWWidth|CWHeight))) {
265      send_config(c);
266    }
267    wc.border_width = 0;
268  } else {
269    wc.x = c ? 0 : e->x;
270    wc.y = c ? 0 : e->y;
271    LOG_XDEBUG("XConfigureWindow(dpy, window(%x), %lx, &wc);\n", (unsigned int)e->window, value_mask);
272    XConfigureWindow(dpy, e->window, value_mask, &wc);
273  }
274}
275
276static void handle_map_request(XMapRequestEvent *e) {
277  Client *c = find_client(e->window);
278
279  if (c) {
280#ifdef VWM
281    if (c->vdesk != c->screen->vdesk)
282      switch_vdesk(c->screen, c->vdesk);
283#endif
284    unhide(c, RAISE);
285  } else {
286    XWindowAttributes attr;
287    LOG_DEBUG("handle_map_request() : don't know this window, calling make_new_client();\n");
288    XGetWindowAttributes(dpy, e->window, &attr);
289    make_new_client(e->window, find_screen(attr.root));
290  }
291}
292
293static void handle_unmap_event(XUnmapEvent *e) {
294  Client *c = find_client(e->window);
295       
296  LOG_DEBUG("handle_unmap_event(): ");
297  if (c) {
298    if (c->ignore_unmap) {
299      c->ignore_unmap--;
300      LOG_DEBUG("ignored (%d ignores remaining)\n", c->ignore_unmap);
301    } else {
302      LOG_DEBUG("flagging client for removal\n");
303      c->remove = 1;
304      need_client_tidy = 1;
305    }
306  } else {
307    LOG_DEBUG("unknown client!\n");
308  }
309}
310
311#ifdef COLOURMAP
312static void handle_colormap_change(XColormapEvent *e) {
313  Client *c = find_client(e->window);
314
315  if (c && e->new) {
316    c->cmap = e->colormap;
317    XInstallColormap(dpy, c->cmap);
318  }
319}
320#endif
321
322static void handle_property_change(XPropertyEvent *e) {
323  Client *c = find_client(e->window);
324
325  if (c) {
326    if (e->atom == XA_WM_NORMAL_HINTS) {
327      get_wm_normal_hints(c);
328    }
329  }
330}
331
332static void handle_leave_event(XCrossingEvent *e) {
333  Client *c;
334
335  if ((c = find_client(e->window))) {
336         
337#ifdef VWM
338    if (c->vdesk != c->screen->vdesk)
339      return;
340#endif
341    run_mouse_leave_hook(c);
342  }
343}
344
345static void handle_enter_event(XCrossingEvent *e) {
346  Client *c;
347
348  if ((c = find_client(e->window))) {
349         
350#ifdef VWM
351    if (c->vdesk != c->screen->vdesk)
352      return;
353#endif
354    run_mouse_enter_hook(c);
355  }
356}
357
358static void handle_mappingnotify_event(XMappingEvent *e) {
359  XRefreshKeyboardMapping(e);
360  if (e->request == MappingKeyboard) {
361    int i;
362    for (i = 0; i < num_screens; i++) {
363      grab_keys_for_screen(&screens[i]);
364    }
365  }
366}
367
368#ifdef SHAPE
369static void handle_shape_event(XShapeEvent *e) {
370  Client *c = find_client(e->window);
371  if (c)
372    set_shape(c);
373}
374#endif
375
376void event_main_loop(void) {
377  XEvent ev;
378  /* main event loop here */
379  int fd = ConnectionNumber(dpy);
380  for (;;) {
381    fd_set rfset;
382    FD_ZERO(&rfset);
383    FD_SET(fd, &rfset);
384    struct timeval tv;
385    tv.tv_sec = 0;
386    tv.tv_usec = 1000*100;
387
388    select(fd + 1, &rfset, NULL, NULL, &tv);
389
390    //while(XEventsQueued(dpy, QueuedAfterReading) >= 0) {
391    while(XPending(dpy)) {
392      XNextEvent(dpy, &ev);
393     
394      switch (ev.type) {
395      case KeyPress:
396        handle_key_event2(&ev.xkey); break;
397        //handle_key_event(&ev.xkey); break;
398#ifdef MOUSE
399      case ButtonPress:
400        handle_button_event(&ev.xbutton); break;
401#endif
402      case ConfigureRequest:
403        handle_configure_request(&ev.xconfigurerequest); break;
404      case MapRequest:
405        handle_map_request(&ev.xmaprequest); break;
406#ifdef COLOURMAP
407      case ColormapNotify:
408        handle_colormap_change(&ev.xcolormap); break;
409#endif
410      case EnterNotify:
411        handle_enter_event(&ev.xcrossing); break;
412      case LeaveNotify:
413        handle_leave_event(&ev.xcrossing); break;
414      case PropertyNotify:
415        handle_property_change(&ev.xproperty); break;
416      case UnmapNotify:
417        handle_unmap_event(&ev.xunmap); break;
418      case MappingNotify:
419        handle_mappingnotify_event(&ev.xmapping); break;
420#ifdef SHAPE
421      default:
422        if (have_shape && ev.type == shape_event) {
423          handle_shape_event((XShapeEvent *)&ev);
424        }
425#endif
426      }
427      if (need_client_tidy) {
428        Client *c, *nc;
429        for (c = head_client; c; c = nc) {
430          nc = c->next;
431          if (c->remove)
432            remove_client(c);
433        }
434      }
435    }
436  }
437}
Note: See TracBrowser for help on using the browser.