1 /*
2 * Copyright (C) 2003 Sasha Vasko
3 * Copyright (C) 1995 Bo Yang
4 * Copyright (C) 1993 Robert Nation
5 * Copyright (C) 1993 Frank Fejes
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 of the License, or
10 * (at your option) 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
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23 #define LOCAL_DEBUG
24 #define EVENT_TRACE
25
26 #include "../../configure.h"
27
28 #include "asinternals.h"
29
30 #include <limits.h>
31 #include <sys/types.h>
32 #if TIME_WITH_SYS_TIME
33 # include <sys/time.h>
34 # include <time.h>
35 #else
36 # if HAVE_SYS_TIME_H
37 # include <sys/time.h>
38 # else
39 # include <time.h>
40 # endif
41 #endif
42 #include <unistd.h>
43 #include <signal.h>
44
45 #include "../../libAfterStep/wmprops.h"
46 #include "../../libAfterStep/moveresize.h"
47
48 #include <X11/keysym.h>
49 #ifdef XSHMIMAGE
50 # include <sys/ipc.h>
51 # include <sys/shm.h>
52 # include <X11/extensions/XShm.h>
53 #endif
54
55 /***********************************************************************
56 * _______________________EVENT HANDLING ______________________________
57 *
58 * HandleEvents - event loop
59 * DigestEvent - preprocesses event - finds ASWindow, context etc.
60 * DispatchEvent - calls appropriate handler for the event
61 ************************************************************************/
62 void DigestEvent (ASEvent * event);
63 void afterstep_wait_pipes_input (int timeout_sec);
64
65 static int
_exec_while_x_pending()66 _exec_while_x_pending ()
67 {
68 int handled_count = 0;
69 ASEvent event;
70 while (XPending (dpy)) {
71 if (ASNextEvent (&(event.x), True)) {
72 DigestEvent (&event);
73 DispatchEvent (&event, False);
74 ++handled_count;
75 }
76 ASSync (False);
77 /* before we exec any function - we ought to process any Unmap and Destroy
78 * events to handle all the pending window destroys : */
79 while (ASCheckTypedEvent (DestroyNotify, &(event.x)) ||
80 ASCheckTypedEvent (UnmapNotify, &(event.x)) ||
81 ASCheckMaskEvent (FocusChangeMask, &(event.x))) {
82 DigestEvent (&event);
83 DispatchEvent (&event, False);
84 ++handled_count;
85 }
86 ExecutePendingFunctions ();
87 }
88 return handled_count;
89 }
90
91
HandleEvents()92 void HandleEvents ()
93 {
94 /* this is the only loop that allowed to run ExecutePendingFunctions(); */
95 while (True) {
96 _exec_while_x_pending ();
97 afterstep_wait_pipes_input (0);
98 ExecutePendingFunctions ();
99 }
100 }
101
HandleEventsWhileFunctionsPending()102 void HandleEventsWhileFunctionsPending ()
103 {
104 int events_handled = 1;
105 /* this is the only loop that allowed to run ExecutePendingFunctions(); */
106 while (FunctionsPending () || events_handled > 0) {
107 ExecutePendingFunctions ();
108 afterstep_wait_pipes_input (3);
109 events_handled = _exec_while_x_pending ();
110 }
111 }
112
113
114 /***************************************************************************
115 * Wait for all mouse buttons to be released
116 * This can ease some confusion on the part of the user sometimes
117 *
118 * Discard superflous button events during this wait period.
119 ***************************************************************************/
120 #define MOVERESIZE_LOOP_MASK (KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \
121 EnterWindowMask|LeaveWindowMask|PointerMotionMask|PointerMotionHintMask| \
122 Button1MotionMask|Button2MotionMask|Button3MotionMask|Button4MotionMask| \
123 Button5MotionMask|ButtonMotionMask|KeymapStateMask| \
124 StructureNotifyMask|SubstructureNotifyMask)
125
126
InteractiveMoveLoop()127 void InteractiveMoveLoop ()
128 {
129 ASEvent event;
130 Bool has_x_events = False;
131 while (Scr.moveresize_in_progress != NULL) {
132 LOCAL_DEBUG_OUT ("checking masked events ...%s", "");
133 while ((has_x_events =
134 ASCheckMaskEvent (MOVERESIZE_LOOP_MASK, &(event.x)))) {
135 DigestEvent (&event);
136 DispatchEvent (&event, False);
137 if (Scr.moveresize_in_progress == NULL)
138 return;
139 }
140 afterstep_wait_pipes_input (0);
141 }
142 }
143
144
145
WaitForButtonsUpLoop()146 void WaitForButtonsUpLoop ()
147 {
148 XEvent JunkEvent;
149 unsigned int mask;
150
151 if (!get_flags (AfterStepState, ASS_PointerOutOfScreen)) {
152 do {
153 XAllowEvents (dpy, ReplayPointer, CurrentTime);
154 ASQueryPointerMask (&mask);
155 ASFlushAndSync ();
156 } while ((mask &
157 (Button1Mask | Button2Mask | Button3Mask | Button4Mask |
158 Button5Mask)) != 0);
159
160 while (ASCheckMaskEvent
161 (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
162 &JunkEvent))
163 XAllowEvents (dpy, ReplayPointer, CurrentTime);
164 }
165 }
166
167 Bool
WaitEventLoop(ASEvent * event,int finish_event_type,long timeout,ASHintWindow * hint)168 WaitEventLoop (ASEvent * event, int finish_event_type, long timeout,
169 ASHintWindow * hint)
170 {
171 unsigned long mask = ButtonPressMask | ButtonReleaseMask |
172 ExposureMask | KeyPressMask | ButtonMotionMask |
173 PointerMotionMask /* | EnterWindowMask | LeaveWindowMask */ ;
174 Bool done = False;
175
176 while (!done) {
177 /* block until there is an event */
178 ASFlushIfEmpty ();
179 ASMaskEvent (mask, &(event->x));
180
181 if (event->x.type == KeyPress)
182 KeyboardShortcuts (&(event->x), finish_event_type, 20);
183 /* above line might have changed event code !!! */
184 else if (event->x.type == ButtonPress)
185 XAllowEvents (dpy, ReplayPointer, CurrentTime);
186
187 if (event->x.type == finish_event_type) {
188 done = True;
189 if (event->x.xbutton.window == Scr.Root)
190 event->x.xbutton.window = event->x.xbutton.subwindow;
191 /* otherwise event will be reported as if it occured relative to
192 root window */
193 }
194 DigestEvent (event);
195 DispatchEvent (event, done);
196 if (event->x.type == MotionNotify && hint)
197 update_ashint_geometry (hint, False);
198 }
199
200 return True;
201 }
202
203 /*****************************************************************************
204 * Waits click_time, or until it is evident that the user is not
205 * clicking, but is moving the cursor
206 ****************************************************************************/
207 Bool
IsClickLoop(ASEvent * event,unsigned int end_mask,unsigned int click_time)208 IsClickLoop (ASEvent * event, unsigned int end_mask,
209 unsigned int click_time)
210 {
211 int dx = 0, dy = 0;
212 int x_orig = event->x.xbutton.x_root;
213 int y_orig = event->x.xbutton.y_root;
214 /* we are in the middle of running Complex function - we must only do mandatory
215 * processing on received events, but do not actually handle them !!
216 * Client window affected, as well as the context must not change -
217 * only the X event could */
218 ASEvent tmp_event;
219 register XEvent *xevt = &(tmp_event.x);
220
221 ASSync (False);
222 start_ticker (click_time);
223 do {
224 sleep_a_millisec (10);
225 if (ASCheckMaskEvent (end_mask, xevt)) {
226 DigestEvent (&tmp_event);
227 event->x = *xevt; /* everything else must remain the same !!! */
228 DispatchEvent (event, True);
229 return True;
230 }
231 if (is_tick ())
232 break;
233
234 if (ASCheckMaskEvent (ButtonMotionMask | PointerMotionMask, xevt)) {
235 dx = x_orig - xevt->xmotion.x_root;
236 dy = y_orig - xevt->xmotion.y_root;
237 DigestEvent (&tmp_event);
238 event->x = *xevt; /* everything else must remain the same !!! */
239 }
240 } while (dx > -5 && dx < 5 && dy > -5 && dy < 5);
241
242 return False;
243 }
244
WaitWindowLoop(char * pattern,long timeout)245 ASWindow *WaitWindowLoop (char *pattern, long timeout)
246 {
247 Bool done = False;
248 ASEvent event;
249 Bool has_x_events;
250 time_t end_time =
251 (timeout <= 0 ? DEFAULT_WINDOW_WAIT_TIMEOUT : timeout) / 100;
252 time_t click_end_time = end_time / 4;
253 time_t start_time = time (NULL);
254 ASWindow *asw = NULL;
255 ASHintWindow *hint;
256 char *text;
257
258 end_time += start_time;
259 click_end_time += start_time;
260
261 if (pattern == NULL || pattern[0] == '\0')
262 return NULL;
263
264 LOCAL_DEBUG_OUT ("waiting for \"%s\"", pattern);
265 if ((asw = complex_pattern2ASWindow (pattern)) != NULL)
266 return asw;
267
268 text = safemalloc (64 + strlen (pattern) + 1);
269 sprintf (text,
270 "Waiting for window matching \"%s\" ... Press button to cancel.",
271 pattern);
272 hint = create_ashint_window (ASDefaultScr, &(Scr.Look), text);
273 free (text);
274 while (!done) {
275 do {
276 ASFlush ();
277 while ((has_x_events = XPending (dpy))) {
278 if (ASNextEvent (&(event.x), True)) {
279
280 DigestEvent (&event);
281 /* we do not want user to do anything interactive at that time - hence
282 deffered == True */
283 DispatchEvent (&event, True);
284 if (event.x.type == ButtonPress || event.x.type == KeyPress) {
285 end_time = click_end_time;
286 break;
287 } else if (event.x.type == MotionNotify && hint)
288 update_ashint_geometry (hint, False);
289
290 if ((event.x.type == MapNotify || event.x.type == PropertyNotify)
291 && event.client)
292 if ((asw = complex_pattern2ASWindow (pattern)) != NULL) {
293 destroy_ashint_window (&hint);
294 return asw;
295 }
296 }
297 }
298 if (time (NULL) > end_time) {
299 done = True;
300 break;
301 }
302
303 } while (has_x_events);
304
305 if (time (NULL) > end_time)
306 break;
307 afterstep_wait_pipes_input (1);
308 }
309 destroy_ashint_window (&hint);
310 return NULL;
311 }
312
313 /*************************************************************************
314 * This loop handles all the pending Configure Notifys so that canvases get
315 * all nicely synchronized. This is generaly needed when we need to do
316 * reparenting.
317 *************************************************************************/
ConfigureNotifyLoop()318 void ConfigureNotifyLoop ()
319 {
320 ASEvent event;
321 while (ASCheckTypedEvent (ConfigureNotify, &(event.x))) {
322 DigestEvent (&event);
323 DispatchEvent (&event, False);
324 ASSync (False);
325 }
326 }
327
MapConfigureNotifyLoop()328 void MapConfigureNotifyLoop ()
329 {
330 ASEvent event;
331
332 do {
333 if (!ASCheckTypedEvent (MapNotify, &(event.x)))
334 if (!ASCheckTypedEvent (ConfigureNotify, &(event.x)))
335 return;
336 DigestEvent (&event);
337 DispatchEvent (&event, False);
338 ASSync (False);
339 } while (1);
340 }
341
DigestEvent(ASEvent * event)342 void DigestEvent (ASEvent * event)
343 {
344 register int i;
345 setup_asevent_from_xevent (event);
346 event->client = NULL;
347 SHOW_EVENT_TRACE (event);
348 /* in housekeeping mode we handle pointer events only as applied to root window ! */
349 if (Scr.moveresize_in_progress
350 && (event->eclass & ASE_POINTER_EVENTS) != 0) {
351 event->context = C_ROOT;
352 event->widget = Scr.RootCanvas;
353 /* we have to do this at all times !!!! */
354 if (event->x.type == ButtonRelease && Scr.Windows->pressed)
355 release_pressure ();
356 } else {
357 XButtonEvent *xbtn = &(event->x.xbutton);
358
359 if (event->w == Scr.Root) {
360 event->context = C_ROOT;
361 #ifndef NO_VIRTUAL
362 if ((event->eclass & ASE_MousePressEvent) != 0
363 && xbtn->subwindow != None) {
364 LOCAL_DEBUG_OUT ("subwindow = %lX", event->x.xbutton.subwindow);
365 for (i = 0; i < PAN_FRAME_SIDES; i++) {
366 LOCAL_DEBUG_OUT ("checking panframe %d, mapped %d", i,
367 Scr.PanFrame[i].isMapped);
368 if (Scr.PanFrame[i].isMapped && xbtn->subwindow == Scr.PanFrame[i].win) { /* we should try and pass through this click onto any client that
369 maybe under the pan frames */
370 LOCAL_DEBUG_OUT ("looking for client at %+d%+d", xbtn->x_root,
371 xbtn->y_root);
372 if ((event->client =
373 find_topmost_client (Scr.CurrentDesk, xbtn->x_root,
374 xbtn->y_root)) != NULL) {
375 ASCanvas *cc = event->client->client_canvas;
376 LOCAL_DEBUG_OUT ("underlying new client %p", event->client);
377 if (cc && cc->root_x <= xbtn->x_root
378 && cc->root_y <= xbtn->y_root
379 && cc->root_x + cc->width > xbtn->x_root
380 && cc->root_y + cc->height > xbtn->y_root) {
381 event->w = xbtn->window = event->client->w;
382 xbtn->subwindow = None;
383 XSendEvent (dpy, event->client->w, False,
384 (xbtn->type ==
385 ButtonPress) ? ButtonPressMask :
386 ButtonReleaseMask, &(event->x));
387 xbtn->subwindow = event->client->w;
388 xbtn->window = Scr.Root;
389 /* xbtn->window should still be Root, so we can proxy it down to the app */
390 } else {
391 event->w = xbtn->window = event->client->frame;
392 xbtn->subwindow = None;
393 }
394 LOCAL_DEBUG_OUT ("new event window %lX", event->w);
395 event->context = C_NO_CONTEXT;
396 }
397 break;
398 }
399 }
400 }
401 #endif
402 } else if (event->w == Scr.ServiceWin || event->w == Scr.SizeWindow) {
403 event->context = C_ROOT;
404 } else
405 event->context = C_NO_CONTEXT;
406
407 if (event->context == C_ROOT) {
408 event->widget = Scr.RootCanvas;
409 event->client = NULL;
410 } else if (event->client == NULL) {
411 if ((event->eclass & ASE_POINTER_EVENTS) != 0
412 && is_balloon_click (&(event->x)) != NULL) {
413 event->client = NULL;
414 event->widget = NULL;
415 } else {
416 event->widget = NULL;
417 event->client = window2ASWindow (event->w);
418 }
419 }
420 }
421
422 if ((event->eclass & ASE_POINTER_EVENTS) != 0 && event->client) {
423 /* now lets determine the context of the event : (former GetContext) */
424 Window w = event->w;
425 ASWindow *asw = event->client;
426 XKeyEvent *xk = &(event->x.xkey);
427 ASCanvas *canvas = asw->frame_canvas;
428 ASTBarData *pointer_bar = NULL;
429 int pointer_root_x = xk->x_root;
430 int pointer_root_y = xk->y_root;
431 static int last_pointer_root_x = -1, last_pointer_root_y = -1;
432 int tbar_side = ASWIN_HFLAGS (asw, AS_VerticalTitle) ? FR_W : FR_N;
433
434 /* Since key presses and button presses are grabbed in the frame
435 * when we have re-parented windows, we need to find out the real
436 * window where the event occured */
437 if (!ASWIN_GET_FLAGS (asw, AS_Iconic)) {
438 if (w != asw->client_canvas->w)
439 if (xk->subwindow != None)
440 w = xk->subwindow;
441 if (w == asw->client_canvas->w) {
442 canvas = asw->client_canvas;
443 event->context = C_CLIENT;
444 } else if (w != asw->frame) {
445 i = FRAME_SIDES;
446 while (--i >= 0)
447 if (asw->frame_sides[i] != NULL && asw->frame_sides[i]->w == w) {
448 canvas = asw->frame_sides[i];
449 /* determine what part of the frame : */
450 event->context = C_FRAME;
451 break;
452 }
453 } else { /* we are on the border of the frame : see what side ofthe frame we are on */
454 event->context = C_FRAME;
455 if (pointer_root_x <
456 asw->frame_canvas->root_x + (int)asw->frame_canvas->bw)
457 pointer_root_x =
458 asw->frame_canvas->root_x + (int)asw->frame_canvas->bw;
459 else if (pointer_root_x >=
460 asw->frame_canvas->root_x + (int)asw->frame_canvas->bw +
461 (int)asw->frame_canvas->width)
462 pointer_root_x =
463 asw->frame_canvas->root_x + (int)asw->frame_canvas->bw +
464 (int)asw->frame_canvas->width - 1;
465 if (pointer_root_y <
466 asw->frame_canvas->root_y + (int)asw->frame_canvas->bw)
467 pointer_root_y =
468 asw->frame_canvas->root_y + (int)asw->frame_canvas->bw;
469 else if (pointer_root_y >=
470 asw->frame_canvas->root_y + (int)asw->frame_canvas->bw +
471 (int)asw->frame_canvas->height)
472 pointer_root_y =
473 asw->frame_canvas->root_y + (int)asw->frame_canvas->bw +
474 (int)asw->frame_canvas->height - 1;
475 else
476 event->context = C_CLIENT;
477
478 }
479
480 if (ASWIN_GET_FLAGS (asw, AS_Shaded)
481 && canvas != asw->frame_sides[tbar_side]) {
482 event->context = C_NO_CONTEXT;
483 if (asw->frame_sides[tbar_side])
484 XRaiseWindow (dpy, asw->frame_sides[tbar_side]->w);
485 } else if (w != asw->frame) {
486 if (event->w == asw->frame) {
487 xk->x = pointer_root_x - (canvas->root_x + (int)canvas->bw);
488 xk->y = pointer_root_y - (canvas->root_y + (int)canvas->bw);
489 } else {
490 Window dumm;
491 XTranslateCoordinates (dpy, Scr.Root, w, xk->x_root, xk->y_root,
492 &(xk->x), &(xk->y), &dumm);
493 }
494 }
495 if (event->context == C_FRAME) {
496 int tbar_context;
497 if (asw->tbar != NULL &&
498 (tbar_context =
499 check_astbar_point (asw->tbar, pointer_root_x,
500 pointer_root_y)) != C_NO_CONTEXT) {
501 event->context = tbar_context;
502 pointer_bar = asw->tbar;
503 } else {
504 for (i = 0; i < FRAME_PARTS; ++i)
505 if (asw->frame_bars[i] != NULL &&
506 (tbar_context =
507 check_astbar_point (asw->frame_bars[i], pointer_root_x,
508 pointer_root_y)) != C_NO_CONTEXT) {
509 event->context = tbar_context;
510 pointer_bar = asw->frame_bars[i];
511 break;
512 }
513 }
514 }
515 if (event->context == C_NO_CONTEXT
516 && get_flags (Scr.Feel.flags, ClickToFocus)) {
517 w = asw->frame;
518 event->context = C_FRAME;
519 }
520 event->w = w;
521 } else {
522 if (asw->icon_canvas && w == asw->icon_canvas->w) {
523 event->context = C_IconButton;
524 canvas = asw->icon_canvas;
525 pointer_bar = asw->icon_button;
526 if (canvas == asw->icon_title_canvas) {
527 int c =
528 check_astbar_point (asw->icon_title, pointer_root_x,
529 pointer_root_y);
530 if (c != C_NO_CONTEXT) {
531 event->context = c;
532 pointer_bar = asw->icon_title;
533 }
534 }
535 } else if (asw->icon_title_canvas && w == asw->icon_title_canvas->w) {
536 canvas = asw->icon_title_canvas;
537 event->context = C_IconTitle;
538 pointer_bar = asw->icon_title;
539 }
540 }
541
542 if (pointer_bar != NULL) {
543 on_astbar_pointer_action (pointer_bar, event->context,
544 (event->x.type == LeaveNotify),
545 (last_pointer_root_x != pointer_root_x
546 || last_pointer_root_y !=
547 pointer_root_y));
548 }
549 if (event->x.type == LeaveNotify) {
550 withdraw_active_balloon_from (TitlebarBalloons);
551 }
552 last_pointer_root_x = pointer_root_x;
553 last_pointer_root_y = pointer_root_y;
554
555 if (asw != NULL && w != asw->w && w != asw->frame
556 && event->context != C_NO_CONTEXT)
557 apply_context_cursor (w, &(Scr.Feel), event->context);
558 event->widget = canvas;
559 /* we have to do this at all times !!!! */
560 /* if( event->x.type == ButtonRelease && Scr.Windows->pressed )
561 release_pressure(); */
562 }
563 SHOW_EVENT_TRACE (event);
564 }
565
566 /****************************************************************************
567 * For menus, move, and resize operations, we can effect keyboard
568 * shortcuts by warping the pointer.
569 ****************************************************************************/
KeyboardShortcuts(XEvent * xevent,int return_event,int move_size)570 Bool KeyboardShortcuts (XEvent * xevent, int return_event, int move_size)
571 {
572 int x, y, x_root, y_root;
573 int x_move, y_move;
574 KeySym keysym;
575
576 /* Pick the size of the cursor movement */
577 if (xevent->xkey.state & ControlMask)
578 move_size = 1;
579 if (xevent->xkey.state & ShiftMask)
580 move_size = 100;
581
582 keysym = XLookupKeysym (&(xevent->xkey), 0);
583
584 x_move = 0;
585 y_move = 0;
586 switch (keysym) {
587 case XK_Up:
588 case XK_k:
589 case XK_p:
590 y_move = -move_size;
591 break;
592 case XK_Down:
593 case XK_n:
594 case XK_j:
595 y_move = move_size;
596 break;
597 case XK_Left:
598 case XK_b:
599 case XK_h:
600 x_move = -move_size;
601 break;
602 case XK_Right:
603 case XK_f:
604 case XK_l:
605 x_move = move_size;
606 break;
607 case XK_Return:
608 case XK_space:
609 /* beat up the event */
610 xevent->type = return_event;
611 break;
612 default:
613 return False;
614 }
615 ASQueryPointerXY (&xevent->xany.window, &x_root, &y_root, &x, &y);
616
617 if ((x_move != 0) || (y_move != 0)) {
618 /* beat up the event */
619 XWarpPointer (dpy, None, Scr.Root, 0, 0, 0, 0, x_root + x_move,
620 y_root + y_move);
621
622 /* beat up the event */
623 xevent->type = MotionNotify;
624 xevent->xkey.x += x_move;
625 xevent->xkey.y += y_move;
626 xevent->xkey.x_root += x_move;
627 xevent->xkey.y_root += y_move;
628 }
629 return True;
630 }
631
632
633
DispatchEvent(ASEvent * event,Bool deffered)634 void DispatchEvent (ASEvent * event, Bool deffered)
635 {
636 if (Scr.moveresize_in_progress)
637 if (check_moveresize_event (event))
638 return;
639
640 /* handle menu events specially */
641 /* if (HandleMenuEvent (NULL, event) == True)
642 * return;
643 */
644
645 switch (event->x.type) {
646 case KeyPress:
647 /* if a key has been pressed and it's not one of those that cause
648 warping, we know the warping is finished */
649 HandleKeyPress (event);
650 break;
651 case ButtonPress:
652 /* if warping, a button press, non-warp keypress, or pointer motion
653 * indicates that the warp is done */
654 if (get_flags (AfterStepState, ASS_WarpingMode))
655 EndWarping ();
656 if (event->x.xbutton.button > Button3) { /* buttons 4 and 5 are for scrollwheel */
657 ASInternalWindow *internal =
658 event->client ? event->client->internal : NULL;
659 if (internal && internal->on_scroll_event)
660 internal->on_scroll_event (internal, event);
661 } else
662 HandleButtonPress (event, deffered);
663 break;
664 case ButtonRelease:
665 /* if warping, a button press, non-warp keypress, or pointer motion
666 * indicates that the warp is done */
667 if (get_flags (AfterStepState, ASS_WarpingMode))
668 EndWarping ();
669 if (Scr.Windows->pressed)
670 HandleButtonRelease (event, deffered);
671 break;
672 case MotionNotify:
673 /* if warping, a button press, non-warp keypress, or pointer motion
674 * indicates that the warp is done */
675 if (get_flags (AfterStepState, ASS_WarpingMode))
676 EndWarping ();
677 if (event->client && event->client->internal)
678 event->client->internal->on_pointer_event (event->client->internal,
679 event);
680 break;
681 case EnterNotify:
682 HandleEnterNotify (event);
683 break;
684 case LeaveNotify:
685 HandleLeaveNotify (event);
686 break;
687 case FocusIn:
688 HandleFocusIn (event);
689 break;
690 case Expose:
691 HandleExpose (event);
692 break;
693 case DestroyNotify:
694 HandleDestroyNotify (event);
695 break;
696 case UnmapNotify:
697 HandleUnmapNotify (event);
698 break;
699 case MapNotify:
700 HandleMapNotify (event);
701 break;
702 case MapRequest:
703 HandleMapRequest (event);
704 break;
705 case ConfigureNotify:
706 if (event->client) {
707 LOCAL_DEBUG_CALLER_OUT
708 ("ConfigureNotify:(%p,%lx,asw->w=%lx,(%dx%d%+d%+d)",
709 event->client, event->w, event->client->w,
710 event->x.xconfigure.width, event->x.xconfigure.height,
711 event->x.xconfigure.x, event->x.xconfigure.y);
712 on_window_moveresize (event->client, event->w);
713 }
714 break;
715 case ConfigureRequest:
716 HandleConfigureRequest (event);
717 break;
718 case PropertyNotify:
719 HandlePropertyNotify (event);
720 break;
721 case ColormapNotify:
722 HandleColormapNotify (event);
723 break;
724 case ClientMessage:
725 HandleClientMessage (event);
726 break;
727 case SelectionClear:
728 HandleSelectionClear (event);
729 break;
730 default:
731 #ifdef SHAPE
732 if (event->x.type == (Scr.ShapeEventBase + ShapeNotify))
733 HandleShapeNotify (event);
734 #endif /* SHAPE */
735 #ifdef XSHMIMAGE
736 LOCAL_DEBUG_OUT
737 ("XSHMIMAGE> EVENT : completion_type = %d, event->type = %d ",
738 Scr.ShmCompletionEventType, event->x.type);
739 if (event->x.type == Scr.ShmCompletionEventType)
740 HandleShmCompletion (event);
741 #endif /* SHAPE */
742
743 break;
744 }
745 return;
746 }
747
748 /***********************************************************************
749 * ___________________________ EVENT HANDLERS __________________________
750 * Now its time for event handlers :
751 ***********************************************************************/
752
753 /***********************************************************************
754 * Procedure:
755 * HandleFocusIn - client received focus
756 ************************************************************************/
HandleFocusIn(ASEvent * event)757 void HandleFocusIn (ASEvent * event)
758 {
759 int events_count = 0;
760 while (ASCheckTypedEvent (FocusIn, &event->x))
761 events_count++;
762 if (events_count > 0)
763 DigestEvent (event);
764
765 if (get_flags (AfterStepState, ASS_WarpingMode))
766 ChangeWarpingFocus (event->client);
767
768 LOCAL_DEBUG_OUT ("focused = %p, this event for %p", Scr.Windows->focused,
769 event->client);
770 if (Scr.Windows->focused != event->client) {
771 LOCAL_DEBUG_OUT ("CHANGE Scr.Windows->focused from %p to NULL",
772 Scr.Windows->focused);
773 unset_focused_window();
774 }
775 if (event->client == NULL
776 && get_flags (AfterStepState, ASS_HousekeepingMode))
777 return;
778 /* note that hilite_aswindow changes value of Scr.Hilite!!! */
779 hilite_aswindow (event->client);
780 }
781
782 /***********************************************************************
783 *
784 * Procedure:
785 * HandleKeyPress - key press event handler
786 *
787 ************************************************************************/
HandleKeyPress(ASEvent * event)788 void HandleKeyPress (ASEvent * event)
789 {
790 FuncKey *key;
791 XKeyEvent *xk = &(event->x.xkey);
792 unsigned int modifier = (xk->state & nonlock_mods);
793 int m;
794
795 /* Here's a real hack - some systems have two keys with the
796 * same keysym and different keycodes. This converts all
797 * the cases to one keycode. */
798 for (m = 0; m < 8; ++m) {
799 KeySym keysym = XkbKeycodeToKeysym (dpy, xk->keycode, m, 0);
800 int keycode;
801 if (keysym == NoSymbol)
802 continue;
803 if ((keycode = XKeysymToKeycode (dpy, keysym)) == 0)
804 continue;
805 xk->keycode = keycode;
806
807 for (key = Scr.Feel.FuncKeyRoot; key != NULL; key = key->next) {
808 if ((key->keycode == xk->keycode) &&
809 ((key->mods == (modifier & (~LockMask))) ||
810 (key->mods == AnyModifier)) && (key->cont & event->context)) {
811 /* check if the warp key was pressed */
812 ExecuteFunction (key->fdata, event, -1);
813 return;
814 }
815 }
816 }
817 /* if a key has been pressed and it's not one of those that cause
818 warping, we know the warping is finished */
819 if (get_flags (AfterStepState, ASS_WarpingMode))
820 EndWarping ();
821
822 LOCAL_DEBUG_OUT ("client = %p, context = %s", event->client,
823 context2text ((event)->context));
824 /* if we get here, no function key was bound to the key. Send it
825 * to the client if it was in a window we know about: */
826 if (event->client) {
827 LOCAL_DEBUG_OUT ("internal = %p", event->client->internal);
828 if (event->client->internal
829 && event->client->internal->on_keyboard_event)
830 event->client->internal->on_keyboard_event (event->client->internal,
831 event);
832 else if (xk->window != event->client->w) {
833 xk->window = event->client->w;
834 XSendEvent (dpy, event->client->w, False, KeyPressMask, &(event->x));
835 }
836 }
837 }
838
839
840 /***********************************************************************
841 *
842 * Procedure:
843 * HandlePropertyNotify - property notify event handler
844 *
845 ***********************************************************************/
846 #define MAX_NAME_LEN 200L /* truncate to this many */
847 #define MAX_ICON_NAME_LEN 200L /* ditto */
848
849
update_transp_iter_func(void * data,void * aux_data)850 Bool update_transp_iter_func (void *data, void *aux_data)
851 {
852 ASWindow *asw = (ASWindow *) data;
853
854 if (!check_window_offscreen (asw))
855 if (asw->internal && asw->internal->on_root_background_changed)
856 asw->internal->on_root_background_changed (asw->internal);
857
858 if (!check_frame_offscreen (asw))
859 update_window_transparency (asw, True);
860 return True;
861 }
862
check_wm_hints_changed(ASWindow * asw)863 static Bool check_wm_hints_changed (ASWindow * asw)
864 {
865 unsigned char *ptr = (unsigned char *)&(asw->saved_wm_hints);
866 XWMHints *tmp = XGetWMHints (dpy, asw->w);
867 Bool changed = False;
868 if (tmp == NULL) {
869 int i;
870 for (i = 0; i < sizeof (XWMHints); ++i)
871 if (ptr[i] != 0)
872 return True;
873 } else {
874 changed = (memcmp (tmp, ptr, sizeof (XWMHints)) != 0);
875 XFree (tmp);
876 }
877 return changed;
878 }
879
check_wm_normal_hints_changed(ASWindow * asw)880 static Bool check_wm_normal_hints_changed (ASWindow * asw)
881 {
882 unsigned char *ptr = (unsigned char *)&(asw->saved_wm_normal_hints);
883 XSizeHints *tmp = XAllocSizeHints ();
884 unsigned char *ptr2 = (unsigned char *)tmp;
885 Bool changed = False;
886 long unused;
887 int i;
888
889 if (XGetWMNormalHints (dpy, asw->w, tmp, &unused) == 0) {
890 for (i = 0; i < sizeof (XSizeHints); ++i)
891 if (ptr[i] != 0) {
892 changed = True;
893 break;
894 }
895 } else
896 for (i = 0; i < sizeof (XSizeHints); ++i)
897 if (ptr[i] != ptr2[i]) {
898 changed = True;
899 break;
900 }
901 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
902 if (changed) {
903 LOCAL_DEBUG_OUT ("normal hints differ at offset %d", i);
904 LOCAL_DEBUG_OUT ("Old hints : %s", "");
905 print_wm_normal_hints (NULL, NULL, (XSizeHints *) ptr);
906 LOCAL_DEBUG_OUT ("New hints : %s", "");
907 print_wm_normal_hints (NULL, NULL, tmp);
908 }
909 #endif
910 XFree (tmp);
911 return changed;
912 }
913
914
HandlePropertyNotify(ASEvent * event)915 void HandlePropertyNotify (ASEvent * event)
916 {
917 ASWindow *asw;
918 XPropertyEvent *xprop = &(event->x.xproperty);
919 Atom atom = xprop->atom;
920 XEvent prop_xev;
921
922 /* force updates for "transparent" windows */
923 if (atom == _XROOTPMAP_ID && event->w == Scr.Root) {
924 read_xrootpmap_id (Scr.wmprops, (xprop->state == PropertyDelete));
925 if (Scr.RootImage) {
926
927 safe_asimage_destroy (Scr.RootImage);
928 Scr.RootImage = NULL;
929 }
930 if (Scr.RootBackground && Scr.RootBackground->im != NULL) {
931 if (Scr.RootBackground->pmap
932 && Scr.wmprops->root_pixmap == Scr.RootBackground->pmap)
933 Scr.RootImage = dup_asimage (Scr.RootBackground->im);
934 }
935 if (Scr.wmprops->as_root_pixmap != Scr.wmprops->root_pixmap)
936 set_as_background (Scr.wmprops, Scr.wmprops->root_pixmap);
937
938 iterate_asbidirlist (Scr.Windows->clients, update_transp_iter_func,
939 NULL, NULL, False);
940
941 /* use move_menu() to update transparent menus; this is a kludge, but it works */
942 #if 0 /* reimplement menu redrawing : */
943 if ((*Scr.MSMenuTitle).texture_type == 129
944 || (*Scr.MSMenuItem).texture_type == 129
945 || (*Scr.MSMenuHilite).texture_type == 129) {
946 MenuRoot *menu;
947
948 for (menu = Scr.first_menu; menu != NULL; menu = menu->next)
949 if ((*menu).is_mapped)
950 move_menu (menu, (*menu).x, (*menu).y);
951 }
952 #endif
953 return;
954 }
955
956 if ((asw = event->client) == NULL || ASWIN_GET_FLAGS (asw, AS_Dead)) {
957 if (event->w != Scr.Root)
958 while (XCheckTypedWindowEvent
959 (dpy, event->w, PropertyNotify, &prop_xev)) ;
960 return;
961 } else {
962 char *prop_name = NULL;
963 LOCAL_DEBUG_OUT ("property %s",
964 (prop_name = XGetAtomName (dpy, atom)));
965 if (prop_name)
966 XFree (prop_name);
967 }
968 if (IsNameProp (atom)) {
969 char *old_name =
970 get_flags (asw->internal_flags,
971 ASWF_NameChanged) ? NULL : mystrdup (ASWIN_NAME (asw));
972
973 /* we want to check if there were some more events generated
974 * as window names tend to change multiple properties : */
975 while (XCheckTypedWindowEvent (dpy, asw->w, PropertyNotify, &prop_xev))
976 if (!IsNameProp (prop_xev.xproperty.atom)) {
977 XPutBackEvent (dpy, &prop_xev);
978 break;
979 }
980
981 /*ASFlagType old_hflags = asw->hints->flags ; */
982 show_debug (__FILE__, __FUNCTION__, __LINE__, "name prop changed...");
983 if (get_flags (Scr.Feel.flags, FollowTitleChanges))
984 on_window_hints_changed (asw);
985 else if (update_property_hints_manager (asw->w, xprop->atom,
986 Scr.Look.supported_hints,
987 Database,
988 asw->hints, asw->status)) {
989 if (ASWIN_GET_FLAGS (asw, AS_Dead))
990 return;
991 show_debug (__FILE__, __FUNCTION__, __LINE__,
992 "New name is \"%s\", icon_name \"%s\", following title change ? %s",
993 ASWIN_NAME (asw), ASWIN_ICON_NAME (asw),
994 get_flags (Scr.Feel.flags,
995 FollowTitleChanges) ? "yes" : "no");
996 LOCAL_DEBUG_OUT ("hints flags = %lX, ShortLived ? %lX ",
997 asw->hints->flags, ASWIN_HFLAGS (asw,
998 AS_ShortLived));
999 if (old_name && strcmp (old_name, ASWIN_NAME (asw)) != 0)
1000 set_flags (asw->internal_flags, ASWF_NameChanged);
1001 /* fix the name in the title bar */
1002 if (!ASWIN_GET_FLAGS (asw, AS_Iconic))
1003 on_window_title_changed (asw, True);
1004 broadcast_res_names (asw);
1005 broadcast_window_name (asw);
1006 broadcast_icon_name (asw);
1007 }
1008 if (old_name)
1009 free (old_name);
1010 LOCAL_DEBUG_OUT ("hints flags = %lX, ShortLived ? %lX ",
1011 asw->hints->flags, ASWIN_HFLAGS (asw, AS_ShortLived));
1012 #if (defined(LOCAL_DEBUG)||defined(DEBUG)) && defined(DEBUG_ALLOCS)
1013 {
1014 static time_t old_t = 0;
1015 time_t t = time (NULL);
1016 if (old_t < t) {
1017 char fname[256];
1018 sprintf (fname, "afterstep.allocs.name_change.%lu.log", t);
1019 // spool_unfreed_mem( fname, NULL );
1020 old_t = t;
1021 }
1022 }
1023 #endif
1024
1025 /* otherwise we should check if this is the status property that we change ourselves : */
1026 } else if (atom == XA_WM_COMMAND || atom == XA_WM_CLIENT_MACHINE) {
1027 update_cmd_line_hints (asw->w, atom, asw->hints, asw->status);
1028 } else if (atom == _XA_NET_WM_WINDOW_OPACITY) {
1029 if (event->context == C_WINDOW && event->w != asw->frame)
1030 on_window_opacity_changed (asw);
1031 } else if (atom == XA_WM_HINTS) {
1032 if (check_wm_hints_changed (asw))
1033 on_window_hints_changed (asw);
1034 else {
1035 LOCAL_DEBUG_OUT ("ignoring WM_HINTS change - data is the same%s",
1036 "");
1037 }
1038 } else if (atom == XA_WM_NORMAL_HINTS) {
1039 if (check_wm_normal_hints_changed (asw))
1040 on_window_hints_changed (asw);
1041 else {
1042 LOCAL_DEBUG_OUT
1043 ("ignoring WM_NORMAL_HINTS change - data is the same%s", "");
1044 }
1045 } else if (NeedToTrackPropChanges (atom))
1046 on_window_hints_changed (asw);
1047
1048 /* we have to do the complete refresh of hints, since we have to override WH_HINTS with database, etc. */
1049 }
1050
1051
1052 #ifdef NAME_CHANGE_TEST
1053 /* our status */
1054 ASFlagType AfterStepState = 0; /* default status */
1055
1056 /* Config : */
1057 ASVector *Modules = NULL;
1058 int Module_fd = 0;
1059 int Module_npipes = 8;
1060
1061 ASBalloonState *MenuBalloons = NULL;
1062 ASBalloonState *TitlebarBalloons = NULL;
1063
Done(Bool restart,char * command)1064 void Done (Bool restart, char *command)
1065 {
1066 exit (0);
1067 }
1068
main(int argc,char ** argv)1069 int main (int argc, char **argv)
1070 {
1071 Window w;
1072 int i = 0;
1073 char window_name[512];
1074
1075 InitMyApp ("test_title_change", argc, argv, NULL, NULL, 0);
1076
1077 ConnectX (ASDefaultScr, 0);
1078
1079 w = create_visual_window (Scr.asv, Scr.Root, 0, 0, 300, 300, 0,
1080 InputOutput, 0, NULL);
1081
1082 sprintf (window_name, "test title change - iter %d", i);
1083 set_client_names (w, window_name, window_name, "test",
1084 "test_title_change");
1085
1086 XSetWindowBackground (dpy, w, 0);
1087 XMapWindow (dpy, w);
1088 while (1) {
1089 ASSync (False);
1090 sleep_a_millisec (100);
1091 sprintf (window_name, "test title change - iter %d", ++i);
1092 set_client_names (w, window_name, window_name, "test",
1093 "test_title_change");
1094 }
1095 return 0;
1096 }
1097 #endif
1098 /***********************************************************************
1099 *
1100 * Procedure:
1101 * HandleClientMessage - client message event handler
1102 *
1103 ************************************************************************/
HandleClientMessage(ASEvent * event)1104 void HandleClientMessage (ASEvent * event)
1105 {
1106 char *aname = NULL;
1107 LOCAL_DEBUG_OUT ("ClientMessage(\"%s\")",
1108 (aname =
1109 XGetAtomName (dpy, event->x.xclient.message_type)));
1110 if (aname != NULL)
1111 XFree (aname);
1112
1113 if ((event->x.xclient.message_type == _XA_WM_CHANGE_STATE) &&
1114 (event->client) &&
1115 (event->x.xclient.data.l[0] == IconicState) &&
1116 !ASWIN_GET_FLAGS (event->client, AS_Iconic)) {
1117 set_window_wm_state (event->client, True, False);
1118 #ifdef ENABLE_DND
1119 /* Pass the event to the client window */
1120 if (event->x.xclient.window != event->client->w) {
1121 event->x.xclient.window = event->client->w;
1122 XSendEvent (dpy, event->client->w, True, NoEventMask, &(event->x));
1123 }
1124 #endif
1125 } else if (event->x.xclient.message_type == _AS_BACKGROUND) {
1126 HandleBackgroundRequest (event);
1127 } else if (event->x.xclient.message_type == _XA_NET_WM_STATE
1128 && event->client != NULL) {
1129 ASFlagType extwm_flags = 0, as_flags = 0;
1130 CARD32 props[2];
1131 XClientMessageEvent *xcli = &(event->x.xclient);
1132
1133 props[0] = xcli->data.l[1];
1134 props[1] = xcli->data.l[2];
1135
1136 translate_atom_list (&extwm_flags, EXTWM_State, &props[0], 2);
1137 /* now we need to translate EXTWM flags into AS flags : */
1138 as_flags = extwm_state2as_state_flags (extwm_flags);
1139 if (xcli->data.l[0] == EXTWM_StateRemove) {
1140 as_flags = ASWIN_GET_FLAGS (event->client, as_flags);
1141 } else if (xcli->data.l[0] == EXTWM_StateAdd)
1142 as_flags = as_flags & (~ASWIN_GET_FLAGS (event->client, as_flags));
1143
1144 if (props[0] == _XA_NET_WM_STATE_DEMANDS_ATTENTION || props[1] == _XA_NET_WM_STATE_DEMANDS_ATTENTION) { /* requires special treatment as it competes with ICCCM HintUrgency in WM_HINTS */
1145 Bool set = True;
1146 if (xcli->data.l[0] == EXTWM_StateRemove ||
1147 (xcli->data.l[0] == EXTWM_StateToggle
1148 && ASWIN_GET_FLAGS (event->client, AS_Urgent)))
1149 set = False;
1150 set_extwm_urgency_state (event->client->w, set);
1151 }
1152
1153 if (as_flags != 0)
1154 toggle_aswindow_status (event->client, as_flags);
1155 } else if (event->x.xclient.message_type == _XA_NET_CURRENT_DESKTOP) {
1156 CARD32 desktop_idx, timestamp;
1157 XClientMessageEvent *xcli = &(event->x.xclient);
1158
1159 desktop_idx = xcli->data.l[0];
1160 timestamp = xcli->data.l[1];
1161
1162 if (desktop_idx < Scr.wmprops->as_desk_num && get_flags (AfterStepState, ASS_NormalOperation))
1163 ChangeDesks (Scr.wmprops->as_desk_numbers[desktop_idx]);
1164 }
1165 }
1166
1167 /***********************************************************************
1168 *
1169 * Procedure:
1170 * HandleExpose - expose event handler
1171 *
1172 ***********************************************************************/
HandleExpose(ASEvent * event)1173 void HandleExpose (ASEvent * event)
1174 {
1175 /* do nothing on expose - we use doublebuffering !!! */
1176 }
1177
1178
1179
1180 /***********************************************************************
1181 *
1182 * Procedure:
1183 * HandleDestroyNotify - DestroyNotify event handler
1184 *
1185 ***********************************************************************/
HandleDestroyNotify(ASEvent * event)1186 void HandleDestroyNotify (ASEvent * event)
1187 {
1188 if (event->client) {
1189 Destroy (event->client, True);
1190 }
1191 }
1192
1193 /***********************************************************************
1194 * Procedure:
1195 * HandleMapRequest - MapRequest event handler
1196 ************************************************************************/
delayed_add_window(void * vdata)1197 void delayed_add_window (void *vdata)
1198 {
1199 if (window2ASWindow ((Window) vdata) == NULL)
1200 AddWindow ((Window) vdata, True);
1201 }
1202
HandleMapRequest(ASEvent * event)1203 void HandleMapRequest (ASEvent * event)
1204 {
1205 /* If the window has never been mapped before ... */
1206 if (event->client == NULL) { /* lets delay handling map request in case client needs time to update its properties */
1207 if (get_flags (AfterStepState, ASS_NormalOperation))
1208 timer_new (200, delayed_add_window, (void *)event->w);
1209 else
1210 AddWindow (event->w, True);
1211
1212 /* if( (event->client = AddWindow (event->w, True)) == NULL ) */
1213 return;
1214 } else /* If no hints, or currently an icon, just "deiconify" */
1215 set_window_wm_state (event->client, False, True);
1216 }
1217
1218 /***********************************************************************
1219 *
1220 * Procedure:
1221 * HandleMapNotify - MapNotify event handler
1222 *
1223 ***********************************************************************/
HandleMapNotify(ASEvent * event)1224 void HandleMapNotify (ASEvent * event)
1225 {
1226 ASWindow *asw = event->client;
1227 Bool force_activation = False;
1228 Bool no_focus = False;
1229
1230 if (asw == NULL || event->w == Scr.Root)
1231 return;
1232
1233 LOCAL_DEBUG_OUT ("asw->w = %lX, event->w = %lX", asw->w, event->w);
1234 if (event->w != asw->w) {
1235 if (asw->wm_state_transition == ASWT_Withdrawn2Iconic && event->w == asw->status->icon_window) { /* we finally reached iconic state : */
1236 complete_wm_state_transition (asw, IconicState);
1237 }
1238 return;
1239 }
1240
1241 if (asw->wm_state_transition == ASWT_Withdrawn2Normal) {
1242 if (ASWIN_HFLAGS (asw, AS_FocusOnMap))
1243 force_activation = True;
1244 else
1245 no_focus = True;
1246 }
1247 LOCAL_DEBUG_OUT ("asw->wm_state_transition = %d",
1248 asw->wm_state_transition);
1249
1250 if (asw->wm_state_transition == ASWT_StableState) {
1251 if (ASWIN_GET_FLAGS (asw, AS_Iconic))
1252 set_window_wm_state (asw, False, False); /* client has requested deiconification */
1253 return; /* otherwise it is redundand event */
1254 }
1255 if (get_flags (asw->wm_state_transition, ASWT_FROM_ICONIC))
1256 if (get_flags (Scr.Feel.flags, ClickToFocus))
1257 force_activation = True;
1258
1259 ASWIN_SET_FLAGS (asw, AS_Mapped);
1260 ASWIN_CLEAR_FLAGS (asw, AS_IconMapped);
1261 ASWIN_CLEAR_FLAGS (asw, AS_Iconic);
1262 complete_wm_state_transition (asw, NormalState);
1263 LOCAL_DEBUG_OUT
1264 ("no_focus = %d, force_activation = %d, AcceptsFocus = %ld",
1265 no_focus, force_activation, ASWIN_HFLAGS (asw, AS_AcceptsFocus));
1266 if (!no_focus && ASWIN_FOCUSABLE (asw))
1267 activate_aswindow (asw, force_activation, False);
1268 broadcast_config (M_MAP, asw);
1269 /* finally reaches Normal state */
1270 }
1271
1272
1273 /***********************************************************************
1274 *
1275 * Procedure:
1276 * HandleUnmapNotify - UnmapNotify event handler
1277 *
1278 ************************************************************************/
HandleUnmapNotify(ASEvent * event)1279 void HandleUnmapNotify (ASEvent * event)
1280 {
1281 XEvent dummy;
1282 ASWindow *asw = event->client;
1283 Bool destroyed = False;
1284
1285 if (event->x.xunmap.event == Scr.Root && asw == NULL)
1286 asw = window2ASWindow (event->x.xunmap.window);
1287
1288 if (asw == NULL || event->x.xunmap.window != asw->w)
1289 return;
1290
1291 ASWIN_CLEAR_FLAGS (asw, AS_Mapped);
1292 ASWIN_CLEAR_FLAGS (asw, AS_UnMapPending);
1293 /* Window remains hilited even when unmapped !!!! */
1294 /* if (Scr.Hilite == asw )
1295 Scr.Hilite = NULL; */
1296
1297 if (Scr.Windows->previous_active == asw)
1298 Scr.Windows->previous_active = NULL;
1299
1300 if (Scr.Windows->focused == asw)
1301 focus_next_aswindow (asw);
1302
1303 if (get_flags (asw->wm_state_transition, ASWT_TO_WITHDRAWN)) { /* redundand UnmapNotify - ignoring */
1304 return;
1305 }
1306 if (get_flags (asw->wm_state_transition, ASWT_TO_ICONIC)) { /* we finally reached iconic state : */
1307 complete_wm_state_transition (asw, IconicState);
1308 return;
1309 }
1310 /*
1311 * The program may have unmapped the client window, from either
1312 * NormalState or IconicState. Handle the transition to WithdrawnState.
1313 */
1314
1315 grab_server ();
1316 destroyed = ASCheckTypedWindowEvent (event->w, DestroyNotify, &dummy);
1317 LOCAL_DEBUG_OUT ("wm_state_transition = 0x%X", asw->wm_state_transition);
1318 if (!get_flags (asw->wm_state_transition, ASWT_FROM_WITHDRAWN))
1319 asw->wm_state_transition =
1320 ASWIN_GET_FLAGS (asw,
1321 AS_Iconic) ? ASWT_Iconic2Withdrawn :
1322 ASWT_Normal2Withdrawn;
1323 else
1324 asw->wm_state_transition = ASWT_Withdrawn2Withdrawn;
1325 Destroy (asw, destroyed); /* do not need to mash event before */
1326 ungrab_server ();
1327 ASFlush ();
1328 }
1329
1330
1331 /***********************************************************************
1332 * Procedure:
1333 * HandleButtonPress - ButtonPress event handler
1334 ***********************************************************************/
HandleButtonPress(ASEvent * event,Bool deffered)1335 void HandleButtonPress (ASEvent * event, Bool deffered)
1336 {
1337 unsigned int modifier;
1338 MouseButton *MouseEntry;
1339 Bool AShandled = False;
1340 ASWindow *asw = event->client;
1341 XButtonEvent *xbtn = &(event->x.xbutton);
1342 Bool raise_on_click = False;
1343 Bool focus_accepted = False;
1344 Bool eat_click = False;
1345 Bool activate_window = False;
1346
1347 /* click to focus stuff goes here */
1348 if (asw != NULL) {
1349 LOCAL_DEBUG_OUT ("deferred = %d, button = %X", deffered,
1350 (event->context & (~C_TButtonAll)));
1351 /* if all we do is pressing titlebar buttons - then we should not raise/focus window !!! */
1352 if (!deffered) {
1353 if ((event->context & (~C_TButtonAll)) != 0) {
1354 if (get_flags (Scr.Feel.flags, ClickToFocus)) {
1355 LOCAL_DEBUG_OUT ("asw = %p, ungrabbed = %p, nonlock_mods = %x",
1356 asw, Scr.Windows->ungrabbed,
1357 (xbtn->state & nonlock_mods));
1358 if (asw != Scr.Windows->ungrabbed
1359 && (xbtn->state & nonlock_mods) == 0) {
1360 if (get_flags (Scr.Feel.flags, EatFocusClick)) {
1361 if (Scr.Windows->focused != asw)
1362 if ((focus_accepted =
1363 activate_aswindow (asw, False, False)))
1364 eat_click = True;
1365 } else if (Scr.Windows->focused != asw)
1366 activate_window = True;
1367 LOCAL_DEBUG_OUT ("eat_click = %d", eat_click);
1368 }
1369 }
1370
1371 if (get_flags (Scr.Feel.flags, ClickToRaise))
1372 raise_on_click = (Scr.Feel.RaiseButtons == 0
1373 || (Scr.Feel.
1374 RaiseButtons & (1 << xbtn->button)));
1375 }
1376
1377 if (!ASWIN_GET_FLAGS (asw, AS_Iconic)) {
1378 XSync (dpy, 0);
1379 XAllowEvents (dpy,
1380 (event->context ==
1381 C_WINDOW) ? ReplayPointer : AsyncPointer,
1382 CurrentTime);
1383 XSync (dpy, 0);
1384 }
1385 }
1386 /* !deffered */
1387 press_aswindow (asw, event->context);
1388 }
1389
1390
1391 if (!deffered && !eat_click) {
1392 LOCAL_DEBUG_OUT ("checking for associated functions...%s", "");
1393 /* we have to execute a function or pop up a menu : */
1394 modifier = (xbtn->state & nonlock_mods);
1395 LOCAL_DEBUG_OUT ("state = %X, modifier = %X", xbtn->state, modifier);
1396 /* need to search for an appropriate mouse binding */
1397 MouseEntry = Scr.Feel.MouseButtonRoot;
1398 while (MouseEntry != NULL) {
1399 /*LOCAL_DEBUG_OUT( "mouse fdata %p button %d + modifier %X has context %lx", MouseEntry->fdata, MouseEntry->Button, MouseEntry->Modifier, get_flags(MouseEntry->Context, event->context) ); */
1400 if ((MouseEntry->Button == xbtn->button || MouseEntry->Button == 0)
1401 && (MouseEntry->Context & event->context)
1402 && (MouseEntry->Modifier == AnyModifier
1403 || MouseEntry->Modifier == modifier)) {
1404 /* got a match, now process it */
1405 if (MouseEntry->fdata != NULL) {
1406 ExecuteFunction (MouseEntry->fdata, event, -1);
1407 raise_on_click = False;
1408 AShandled = True;
1409 break;
1410 }
1411 }
1412 MouseEntry = MouseEntry->NextButton;
1413 }
1414 }
1415
1416 LOCAL_DEBUG_OUT ("ashandled = %d, context = %X", AShandled,
1417 (event->context & (C_CLIENT | C_TITLE)));
1418 if (activate_window
1419 && (!AShandled || (event->context & (C_CLIENT | C_TITLE))))
1420 focus_accepted = activate_aswindow (asw, False, False);
1421
1422 if (raise_on_click
1423 && (asw->internal == NULL || (event->context & C_CLIENT) == 0))
1424 restack_window (asw, None, focus_accepted ? Above : TopIf);
1425
1426 /* GNOME this click hasn't been taken by AfterStep */
1427 if (!deffered && !AShandled && !eat_click && xbtn->window == Scr.Root) {
1428 XUngrabPointer (dpy, CurrentTime);
1429 XSendEvent (dpy, Scr.wmprops->wm_event_proxy, False,
1430 SubstructureNotifyMask, &(event->x));
1431 }
1432 }
1433
1434 /***********************************************************************
1435 * Procedure:
1436 * HandleButtonRelease - De-press currently pressed window if all buttons are up
1437 ***********************************************************************/
HandleButtonRelease(ASEvent * event,Bool deffered)1438 void HandleButtonRelease (ASEvent * event, Bool deffered)
1439 { /* click to focus stuff goes here */
1440 LOCAL_DEBUG_CALLER_OUT ("pressed(%p)->state(0x%X)", Scr.Windows->pressed,
1441 (event->x.xbutton.
1442 state & (Button1Mask | Button2Mask | Button3Mask
1443 | Button4Mask | Button5Mask)));
1444 if ((event->x.xbutton.state & AllButtonMask) ==
1445 (Button1Mask << (event->x.xbutton.button - Button1)))
1446 release_pressure ();
1447 }
1448
1449 /***********************************************************************
1450 *
1451 * Procedure:
1452 * HandleEnterNotify - EnterNotify event handler
1453 *
1454 ************************************************************************/
HandleEnterNotify(ASEvent * event)1455 void HandleEnterNotify (ASEvent * event)
1456 {
1457 XEnterWindowEvent *ewp = &(event->x.xcrossing);
1458 XEvent d;
1459 ASWindow *asw = event->client;
1460 int i;
1461 /*fprintf (stderr, "XCROSSING: EnterNotify for window %lX\n", ewp->window); fflush(stderr);*/
1462 /* look for a matching leaveNotify which would nullify this enterNotify */
1463 if (ewp->window != Scr.Root)
1464 if (ASCheckTypedWindowEvent (ewp->window, LeaveNotify, &d)) {
1465 /*fprintf (stderr, "XCROSSING: LeaveNotify in queue for window %lX\n", ewp->window); fflush(stderr);*/
1466 on_astbar_pointer_action (NULL, 0, True, False);
1467 if ((d.xcrossing.mode == NotifyNormal)
1468 && (d.xcrossing.detail != NotifyInferior)) {
1469 /*fprintf (stderr, "XCROSSING: ignoring EnterNotify for window %lX\n", ewp->window); fflush(stderr);*/
1470 return;
1471 }
1472 }
1473 /* an EnterEvent in one of the PanFrameWindows activates the Paging */
1474 #ifndef NO_VIRTUAL
1475 for (i = 0; i < PAN_FRAME_SIDES; i++) {
1476 LOCAL_DEBUG_OUT ("checking panframe %d, mapped %d", i,
1477 Scr.PanFrame[i].isMapped);
1478 fflush (stderr);
1479 if (Scr.PanFrame[i].isMapped && ewp->window == Scr.PanFrame[i].win) {
1480 int delta_x = 0, delta_y = 0;
1481 if (!get_flags (Scr.Feel.flags, ClickToFocus)) {
1482 /* After HandlePaging the configuration of windows on screen will change and
1483 we can no longer keep old focused window still focused, as it may be off-screen
1484 or otherwise not under the pointer, resulting in input going into the wrong window.
1485 */
1486 if (Scr.Windows->focused != NULL)
1487 hide_focus ();
1488 if (Scr.Windows->hilited != NULL)
1489 hide_hilite ();
1490 }
1491 /*fprintf (stderr, "XCROSSING: EnterNotify for panframe %d\n", i); fflush(stderr);*/
1492 /* this was in the HandleMotionNotify before, HEDU */
1493 HandlePaging (Scr.Feel.EdgeScrollX, Scr.Feel.EdgeScrollY,
1494 &(ewp->x_root), &(ewp->y_root), &delta_x, &delta_y,
1495 True, event);
1496
1497 return;
1498 }
1499 }
1500 #endif /* NO_VIRTUAL */
1501
1502 if (ewp->window == Scr.Root) {
1503 if (!get_flags (Scr.Feel.flags, ClickToFocus | SloppyFocus))
1504 hide_focus ();
1505 InstallRootColormap ();
1506 return;
1507 } else if (event->context != C_WINDOW)
1508 InstallAfterStepColormap ();
1509
1510 /* make sure its for one of our windows */
1511 if (asw == NULL)
1512 return;
1513 /*fprintf (stderr, "XCROSSING: focused = %lX active = %lX\n", Scr.Windows->focused?Scr.Windows->focused->w:0, Scr.Windows->active?Scr.Windows->active->w:0); fflush(stderr);*/
1514 if (ASWIN_FOCUSABLE (asw)) {
1515 if (!get_flags (Scr.Feel.flags, ClickToFocus) || asw->internal != NULL) {
1516 if (Scr.Windows->focused != asw)
1517 activate_aswindow (asw, False, False);
1518 }
1519 if (!ASWIN_GET_FLAGS (asw, AS_Iconic) && event->context == C_WINDOW)
1520 InstallWindowColormaps (asw);
1521 }
1522 }
1523
1524
1525 /***********************************************************************
1526 *
1527 * Procedure:
1528 * HandleLeaveNotify - LeaveNotify event handler
1529 *
1530 ************************************************************************/
HandleLeaveNotify(ASEvent * event)1531 void HandleLeaveNotify (ASEvent * event)
1532 {
1533 XEnterWindowEvent *ewp = &(event->x.xcrossing);
1534 /* If we leave the root window, then we're really moving
1535 * another screen on a multiple screen display, and we
1536 * need to de-focus and unhighlight to make sure that we
1537 * don't end up with more than one highlighted window at a time */
1538 /*fprintf (stderr, "XCROSSING: LeaveNotify for window %lX\n", ewp->window); fflush(stderr);*/
1539 if (ewp->window == Scr.Root) {
1540 if (ewp->mode == NotifyNormal) {
1541 if (ewp->detail != NotifyInferior) {
1542 if (Scr.Windows->focused != NULL)
1543 hide_focus ();
1544 if (Scr.Windows->hilited != NULL)
1545 hide_hilite ();
1546 }
1547 }
1548 }
1549 }
1550
1551 /***********************************************************************
1552 *
1553 * Procedure:
1554 * HandleConfigureRequest - ConfigureRequest event handler
1555 *
1556 ************************************************************************/
HandleConfigureRequest(ASEvent * event)1557 void HandleConfigureRequest (ASEvent * event)
1558 {
1559 XConfigureRequestEvent *cre = &(event->x.xconfigurerequest);
1560 ASWindow *asw = event->client;
1561 XWindowChanges xwc;
1562 unsigned long xwcm;
1563
1564 /*
1565 * According to the July 27, 1988 ICCCM draft, we should ignore size and
1566 * position fields in the WM_NORMAL_HINTS property when we map a window.
1567 * Instead, we'll read the current geometry. Therefore, we should respond
1568 * to configuration requests for windows which have never been mapped.
1569 */
1570
1571 LOCAL_DEBUG_OUT ("cre={0x%lx, geom = %dx%d%+d%+d} ", cre->value_mask,
1572 cre->width, cre->height, cre->x, cre->y);
1573 if (asw == NULL) {
1574 xwcm =
1575 cre->value_mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
1576 if (xwcm == 0) {
1577 LOCAL_DEBUG_OUT
1578 ("Ignoring ConfigureRequest for untracked window %lX - no supported changes detected.",
1579 (unsigned long)event->w);
1580 } else {
1581 xwc.x = cre->x;
1582 xwc.y = cre->y;
1583 xwc.width = cre->width;
1584 xwc.height = cre->height;
1585 xwc.border_width = cre->border_width;
1586 LOCAL_DEBUG_OUT
1587 ("Configuring untracked window %lX to %dx%d%+d%+d and bw = %d, (flags=%lX)",
1588 (unsigned long)event->w, cre->width, cre->height, cre->x,
1589 cre->y, cre->border_width, xwcm);
1590 XConfigureWindow (dpy, event->w, xwcm, &xwc);
1591 ASSync (False);
1592 }
1593 return;
1594 }
1595
1596 if (asw->icon_canvas && event->w == asw->icon_canvas->w) { /* we really should ignore that ! - let's see how it will play out */
1597 /* we may need to add code to iconbox to handle custom icon geometry for client icons */
1598 xwcm = cre->value_mask & (CWWidth | CWHeight);
1599 if (xwcm == 0) {
1600 LOCAL_DEBUG_OUT
1601 ("Ignoring ConfigureRequest for iconic window %lX - no supported changes detected.",
1602 (unsigned long)event->w);
1603 } else {
1604 xwc.width = cre->width;
1605 xwc.height = cre->height;
1606 LOCAL_DEBUG_OUT
1607 ("Configuring iconic window %lX to %dx%d, (flags=%lX)",
1608 (unsigned long)event->w, cre->width, cre->height, xwcm);
1609 XConfigureWindow (dpy, event->w, xwcm, &xwc);
1610 ASSync (False);
1611 }
1612 return;
1613 }
1614
1615 if (event->w != asw->w) {
1616 LOCAL_DEBUG_OUT
1617 ("Ignoring ConfigureRequest for window %lX. Not a client or client's icon!",
1618 (unsigned long)event->w);
1619 return;
1620 }
1621
1622 if (cre->value_mask & CWStackMode) {
1623 if (!ASWIN_HFLAGS (asw, AS_IgnoreRestackRequest)) {
1624 restack_window (asw,
1625 (cre->value_mask & CWSibling) ? cre->above : None,
1626 cre->detail);
1627 } else {
1628 LOCAL_DEBUG_OUT
1629 ("Ignoring Stacking order Request for client %p as required by hints",
1630 asw);
1631 }
1632 }
1633
1634 if ((ASWIN_HFLAGS (asw, AS_IgnoreConfigRequest)
1635 && !get_flags (cre->value_mask, CWWidth | CWHeight))
1636 || ASWIN_GET_FLAGS (asw, AS_Fullscreen)) {
1637 LOCAL_DEBUG_OUT
1638 ("Ignoring ConfigureRequest for client %p as required by hints",
1639 asw);
1640 SendConfigureNotify (asw);
1641 return;
1642 }
1643
1644 /* check_aswindow_shaped( asw ); */
1645
1646 /* for restoring */
1647 if (cre->value_mask & CWBorderWidth)
1648 asw->status->border_width = cre->border_width;
1649
1650 /* now we need to update window's anchor : */
1651
1652 if (cre->value_mask & (CWWidth | CWHeight | CWX | CWY)) {
1653 XRectangle new_anchor = asw->anchor;
1654
1655 if (cre->value_mask & CWWidth)
1656 new_anchor.width = cre->width;
1657 if (cre->value_mask & CWHeight)
1658 new_anchor.height = cre->height;
1659 if (!ASWIN_HFLAGS (asw, AS_IgnoreConfigRequest)) {
1660 int grav_x, grav_y;
1661 get_gravity_offsets (asw->hints, &grav_x, &grav_y);
1662 if (cre->value_mask & CWX)
1663 new_anchor.x =
1664 make_anchor_pos (asw->status, cre->x, new_anchor.width, Scr.Vx,
1665 grav_x, Scr.VxMax + Scr.MyDisplayWidth);
1666 if (cre->value_mask & CWY)
1667 new_anchor.y =
1668 make_anchor_pos (asw->status, cre->y, new_anchor.height,
1669 Scr.Vy, grav_y,
1670 Scr.VyMax + Scr.MyDisplayHeight);
1671 }
1672 LOCAL_DEBUG_OUT ("old anchor(%dx%d%+d%+d), new_anchor(%dx%d%+d%+d)",
1673 asw->anchor.width, asw->anchor.height, asw->anchor.x,
1674 asw->anchor.y, new_anchor.width, new_anchor.height,
1675 new_anchor.x, new_anchor.y);
1676 validate_window_anchor (asw, &new_anchor, False);
1677 LOCAL_DEBUG_OUT ("validated_anchor(%dx%d%+d%+d)", new_anchor.width,
1678 new_anchor.height, new_anchor.x, new_anchor.y);
1679 asw->anchor = new_anchor;
1680 on_window_anchor_changed (asw);
1681 enforce_avoid_cover (asw);
1682 if ((cre->value_mask & (CWWidth | CWHeight)) == 0)
1683 SendConfigureNotify (asw);
1684 }
1685 }
1686
HandleSelectionClear(ASEvent * event)1687 void HandleSelectionClear (ASEvent * event)
1688 {
1689 LOCAL_DEBUG_OUT
1690 ("SelectionClearEvent : window = %lx, selection = %lx, time = %ld. our( %lx,%lx,%ld )",
1691 event->x.xselectionclear.window, event->x.xselectionclear.selection,
1692 event->x.xselectionclear.time, Scr.wmprops->selection_window,
1693 Scr.wmprops->_XA_WM_S, Scr.wmprops->selection_time);
1694 if (event->x.xselectionclear.window == Scr.wmprops->selection_window
1695 && event->x.xselectionclear.selection == Scr.wmprops->_XA_WM_S) {
1696 /* must give up window manager's selection if time of the event
1697 * after time of us accuring the selection */
1698 if (event->x.xselectionclear.time > Scr.wmprops->selection_time)
1699 Done (False, NULL);
1700 }
1701 }
1702
1703 /***********************************************************************
1704 *
1705 * Procedure:
1706 * HandleShapeNotify - shape notification event handler
1707 *
1708 ***********************************************************************/
HandleShapeNotify(ASEvent * event)1709 void HandleShapeNotify (ASEvent * event)
1710 {
1711 #ifdef SHAPE
1712 XShapeEvent *sev = (XShapeEvent *) & (event->x);
1713 Window w;
1714 Bool needs_update = (sev->kind == ShapeBounding);
1715 Bool shaped = sev->shaped;
1716
1717 if (!event->client)
1718 return;
1719 if (event->client->w != sev->window)
1720 return;
1721
1722 w = event->client->w;
1723 while (ASCheckTypedWindowEvent
1724 (w, Scr.ShapeEventBase + ShapeNotify, &(event->x))) {
1725 if (sev->kind == ShapeBounding) {
1726 needs_update = True;
1727 shaped = sev->shaped;
1728 }
1729 ASSync (False);
1730 sleep_a_millisec (10);
1731 }
1732
1733 if (needs_update) {
1734 if (shaped)
1735 ASWIN_SET_FLAGS (event->client, AS_Shaped);
1736 else
1737 ASWIN_CLEAR_FLAGS (event->client, AS_Shaped);
1738 if (refresh_container_shape (event->client->client_canvas))
1739 SetShape (event->client, 0);
1740 }
1741 #endif /* SHAPE */
1742 }
1743
HandleShmCompletion(ASEvent * event)1744 void HandleShmCompletion (ASEvent * event)
1745 {
1746 #ifdef XSHMIMAGE
1747 XShmCompletionEvent *sev = (XShmCompletionEvent *) & (event->x);
1748 LOCAL_DEBUG_OUT ("XSHMIMAGE> EVENT : offset %ld(%lx), shmseg = %lx",
1749 (long)sev->offset, (unsigned long)(sev->offset),
1750 sev->shmseg);
1751 if (!is_background_xfer_ximage (sev->shmseg))
1752 destroy_xshm_segment (sev->shmseg);
1753 #endif /* SHAPE */
1754 }
1755
1756
1757
1758 /***************************************************************************
1759 *
1760 * Waits for next X event, or for an auto-raise timeout.
1761 *
1762 ****************************************************************************/
afterstep_wait_pipes_input(int timeout_sec)1763 void afterstep_wait_pipes_input (int timeout_sec)
1764 {
1765 fd_set in_fdset, out_fdset;
1766 int retval;
1767 struct timeval tv;
1768 struct timeval *t = NULL;
1769 int max_fd = 0;
1770 LOCAL_DEBUG_OUT ("waiting pipes%s", "");
1771 FD_ZERO (&in_fdset);
1772 FD_ZERO (&out_fdset);
1773
1774 FD_SET (x_fd, &in_fdset);
1775 max_fd = x_fd;
1776 #define AS_FD_SET(fd,fdset) \
1777 do{ if (fd>=0) { FD_SET((fd),(fdset)); if ((fd)>max_fd) max_fd = (fd);}}while(0)
1778
1779 AS_FD_SET (ASDBus_fd, &in_fdset);
1780 AS_FD_SET (Module_fd, &in_fdset);
1781
1782 if (Modules != NULL) { /* adding all the modules pipes to our wait list */
1783 register int i = MIN (MODULES_NUM, Module_npipes);
1784 register module_t *list = MODULES_LIST;
1785 while (--i >= 0) {
1786 if (list[i].fd >= 0) {
1787 AS_FD_SET (list[i].fd, &in_fdset);
1788 if (list[i].output_queue != NULL)
1789 FD_SET (list[i].fd, &out_fdset);
1790 } else /* man, this modules is dead! get rid of it - it stinks! */
1791 vector_remove_index (Modules, i);
1792 }
1793 }
1794
1795 /* watch for timeouts */
1796 if (timer_delay_till_next_alarm
1797 ((time_t *) & tv.tv_sec, (time_t *) & tv.tv_usec))
1798 t = &tv;
1799 else if (timeout_sec > 0) {
1800 t = &tv;
1801 tv.tv_sec = timeout_sec;
1802 tv.tv_usec = 0;
1803 }
1804
1805 LOCAL_DEBUG_OUT ("selecting ... ");
1806 retval =
1807 PORTABLE_SELECT (min (max_fd + 1, fd_width), &in_fdset, &out_fdset,
1808 NULL, t);
1809
1810 LOCAL_DEBUG_OUT ("select ret val = %d", retval);
1811 if (retval > 0) {
1812 register module_t *list;
1813 register int i;
1814 /* check for incoming module connections */
1815 if (Module_fd >= 0)
1816 if (FD_ISSET (Module_fd, &in_fdset))
1817 if (AcceptModuleConnection (Module_fd) != -1)
1818 show_progress ("accepted module connection");
1819 /* note that we have to do it AFTER we accepted incoming connections as those alter the list */
1820 list = MODULES_LIST;
1821 i = MIN (MODULES_NUM, Module_npipes);
1822 /* Check for module input. */
1823 while (--i >= 0)
1824 if (list[i].fd > 0) {
1825 Bool has_input = FD_ISSET (list[i].fd, &in_fdset);
1826 Bool has_output = FD_ISSET (list[i].fd, &out_fdset);
1827 if (has_input || has_output)
1828 HandleModuleInOut (i, has_input, has_output);
1829 }
1830 if (ASDBus_fd >= 0)
1831 if (FD_ISSET (ASDBus_fd, &in_fdset))
1832 asdbus_process_messages ();
1833 }
1834
1835 /* handle timeout events */
1836 timer_handle ();
1837 }
1838