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