1/* 2 * Core event handling 3 * 4 * Copyright 1988 by Evans & Sutherland Computer Corporation, 5 * Salt Lake City, Utah 6 * Portions Copyright 1989 by the Massachusetts Institute of Technology 7 * Cambridge, Massachusetts 8 * 9 * Copyright 1992 Claude Lecommandeur. 10 */ 11 12/*********************************************************************** 13 * 14 * $XConsortium: events.c,v 1.182 91/07/17 13:59:14 dave Exp $ 15 * 16 * twm event handling 17 * 18 * 17-Nov-87 Thomas E. LaStrange File created 19 * 20 * Do the necessary modification to be integrated in ctwm. 21 * Can no longer be used for the standard twm. 22 * 23 * 22-April-92 Claude Lecommandeur. 24 * 25 * 26 ***********************************************************************/ 27 28#include "ctwm.h" 29 30#include <stdio.h> 31#include <stdlib.h> 32#include <errno.h> 33#include <sys/time.h> 34 35#include <X11/extensions/shape.h> 36 37#include "animate.h" 38#ifdef CAPTIVE 39#include "captive.h" 40#endif 41#include "colormaps.h" 42#include "events.h" 43#include "event_handlers.h" 44#include "event_internal.h" 45#include "event_names.h" 46#include "functions.h" 47#include "iconmgr.h" 48#include "image.h" 49#include "screen.h" 50#include "signals.h" 51#include "util.h" 52#include "version.h" 53#include "win_utils.h" 54#ifdef SOUNDS 55#include "sound.h" 56#endif 57 58 59static void CtwmNextEvent(Display *display, XEvent *event); 60static bool StashEventTime(XEvent *ev); 61static void dumpevent(const XEvent *e); 62 63#define MAX_X_EVENT 256 64event_proc EventHandler[MAX_X_EVENT]; /* event handler jump table */ 65int Context = C_NO_CONTEXT; /* current button press context */ 66XEvent Event; /* the current event */ 67 68Window DragWindow; /* variables used in moving windows */ 69int origDragX; 70int origDragY; 71int DragX; 72int DragY; 73unsigned int DragWidth; 74unsigned int DragHeight; 75unsigned int DragBW; 76int CurrentDragX; 77int CurrentDragY; 78 79Time EventTime = CurrentTime; /* until Xlib does this for us */ 80 81/* Maybe more staticizable later? */ 82bool enter_flag; 83bool leave_flag; 84TwmWindow *enter_win, *raise_win, *leave_win, *lower_win; 85 86/* 87 * Not static because shared with colormaps.c and other events files, but 88 * not listed in events.h since nowhere else needs it. 89 */ 90bool ColortableThrashing; 91TwmWindow *Tmp_win; // the current twm window; shared with other event code 92 93int ButtonPressed = -1; 94bool Cancel = false; 95 96 97 98/* 99 * Initialize the event handling bits. Mainly the jump table for event 100 * handling, plus various event vars. Called during startup. 101 */ 102void 103InitEvents(void) 104{ 105 /* Clear out vars */ 106 ResizeWindow = (Window) 0; 107 DragWindow = (Window) 0; 108 enter_flag = false; 109 enter_win = raise_win = NULL; 110 leave_flag = false; 111 leave_win = lower_win = NULL; 112 113 /* Set everything to unknown to start */ 114 for(int i = 0; i < MAX_X_EVENT; i++) { 115 EventHandler[i] = HandleUnknown; 116 } 117 118#define STDH(evt) EventHandler[evt] = Handle##evt 119 120 /* Init the standard events */ 121 STDH(Expose); 122 STDH(CreateNotify); 123 STDH(DestroyNotify); 124 STDH(MapRequest); 125 STDH(MapNotify); 126 STDH(UnmapNotify); 127 STDH(MotionNotify); 128 STDH(ButtonRelease); 129 STDH(ButtonPress); 130 STDH(EnterNotify); 131 STDH(LeaveNotify); 132 STDH(ConfigureRequest); 133 STDH(ClientMessage); 134 STDH(PropertyNotify); 135 STDH(KeyPress); 136 STDH(KeyRelease); 137 STDH(ColormapNotify); 138 STDH(VisibilityNotify); 139 STDH(CirculateNotify); 140 141 /* Focus handlers are special; see comment on HandleFocusChange() */ 142 EventHandler[FocusIn] = HandleFocusChange; 143 EventHandler[FocusOut] = HandleFocusChange; 144 145 /* Some more conditional bits */ 146#ifdef EWMH 147 STDH(SelectionClear); 148#endif 149 150 /* 151 * Optional extensions are registered dynamically, so their events 152 * are put by the X server at some offset into the event number tree 153 * when it starts. 154 */ 155 if(HasShape) { 156 EventHandler[ShapeEventBase + ShapeNotify] = HandleShapeNotify; 157 } 158 159#undef STDH 160 161 /* And done */ 162 return; 163} 164 165 166 167/* 168 * Main event loop. 169 * 170 * This is the last thing called during ctwm startup, and never returns. 171 * So in essence, this is everything ctwm does except starting up and 172 * shutting down (and that latter winds up called through us as well). 173 */ 174void 175HandleEvents(void) 176{ 177 while(1) { 178 if(enter_flag && !QLength(dpy)) { 179 if(enter_win && enter_win != raise_win) { 180 AutoRaiseWindow(enter_win); /* sets enter_flag T */ 181 } 182 else { 183 enter_flag = false; 184 } 185 } 186 if(leave_flag && !QLength(dpy)) { 187 if(leave_win && leave_win != lower_win) { 188 AutoLowerWindow(leave_win); /* sets leave_flag T */ 189 } 190 else { 191 leave_flag = false; 192 } 193 } 194 if(ColortableThrashing && !QLength(dpy) && Scr) { 195 InstallColormaps(ColormapNotify, NULL); 196 } 197 WindowMoved = false; 198 199 CtwmNextEvent(dpy, &Event); 200 201 if(Event.type < 0 || Event.type >= MAX_X_EVENT) { 202 XtDispatchEvent(&Event); 203 } 204 else { 205 DispatchEvent(); 206 } 207 } 208 209 /* NOTREACHED */ 210 fprintf(stderr, "Error: Should never reach the end of HandleEvents()\n"); 211 exit(1); 212} 213 214 215/* 216 * Grab the next event in the queue to process. 217 */ 218static void 219CtwmNextEvent(Display *display, XEvent *event) 220{ 221 int fd; 222 struct timeval timeout, *tout = NULL; 223 const bool animate = (AnimationActive && MaybeAnimate); 224 225#define NEXTEVENT XtAppNextEvent(appContext, event) 226 227 if(SignalFlag) { 228 handle_signal_flag(CurrentTime); 229 } 230 if(XEventsQueued(display, QueuedAfterFlush) != 0) { 231 NEXTEVENT; 232 return; 233 } 234 fd = ConnectionNumber(display); 235 236 if(animate) { 237 TryToAnimate(); 238 } 239 if(SignalFlag) { 240 handle_signal_flag(CurrentTime); 241 } 242 if(! MaybeAnimate) { 243 NEXTEVENT; 244 return; 245 } 246 if(animate) { 247 tout = (AnimationSpeed > 0) ? &timeout : NULL; 248 } 249 while(1) { 250 fd_set mask; 251 int found; 252 253 FD_ZERO(&mask); 254 FD_SET(fd, &mask); 255 if(animate) { 256 timeout = AnimateTimeout; 257 } 258 found = select(fd + 1, &mask, NULL, NULL, tout); 259 if(SignalFlag) { 260 handle_signal_flag(CurrentTime); 261 } 262 if(found < 0) { 263 if(errno != EINTR) { 264 perror("select"); 265 } 266 continue; 267 } 268 if(FD_ISSET(fd, &mask)) { 269 NEXTEVENT; 270 return; 271 } 272 if(found == 0) { 273 if(animate) { 274 TryToAnimate(); 275 } 276 if(SignalFlag) { 277 handle_signal_flag(CurrentTime); 278 } 279 if(! MaybeAnimate) { 280 NEXTEVENT; 281 return; 282 } 283 continue; 284 } 285 } 286 287#undef NEXTEVENT 288 289 /* NOTREACHED */ 290} 291 292 293 294/* 295 * And dispatchers. These look at the global Event and run with it from 296 * there. 297 * 298 * There are slight differences between the two, and it's not at all 299 * clear to what extent there should be or why they're different. At 300 * least some of the difference seem gratuitous; this requires further 301 * research. They probably can and should be collapsed together. 302 */ 303/* Main dispatcher, from the loop above and a few other places */ 304bool 305DispatchEvent(void) 306{ 307 Window w = Event.xany.window; 308 ScreenInfo *thisScr; 309 310 StashEventTime(&Event); 311 Tmp_win = GetTwmWindow(w); 312 thisScr = GetTwmScreen(&Event); 313 314 dumpevent(&Event); 315 316 if(!thisScr) { 317 return false; 318 } 319 Scr = thisScr; 320 321#ifdef CAPTIVE 322 if(CLarg.is_captive) { 323 if((Event.type == ConfigureNotify) 324 && (Event.xconfigure.window == Scr->CaptiveRoot)) { 325 ConfigureCaptiveRootWindow(&Event); 326 return false; 327 } 328 } 329#endif 330 FixRootEvent(&Event); 331 if(Event.type >= 0 && Event.type < MAX_X_EVENT) { 332#ifdef SOUNDS 333 play_sound(Event.type); 334#endif 335 (*EventHandler[Event.type])(); 336 } 337 return true; 338} 339 340 341/* Alternate; called from various function and menu code */ 342bool 343DispatchEvent2(void) 344{ 345 Window w = Event.xany.window; 346 ScreenInfo *thisScr; 347 348 StashEventTime(&Event); 349 Tmp_win = GetTwmWindow(w); 350 thisScr = GetTwmScreen(&Event); 351 352 dumpevent(&Event); 353 354 if(!thisScr) { 355 return false; 356 } 357 Scr = thisScr; 358 359 FixRootEvent(&Event); 360 361#ifdef SOUNDS 362 play_sound(Event.type); 363#endif 364 365 if(menuFromFrameOrWindowOrTitlebar) { 366 if(Event.type == Expose) { 367 HandleExpose(); 368 } 369 } 370 else { 371 if(Event.type >= 0 && Event.type < MAX_X_EVENT) { 372 (*EventHandler[Event.type])(); 373 } 374 } 375 376 return true; 377} 378 379 380 381 382/* 383 * Stash the time of the given event in our EventTime global. Called 384 * during dispatching the event. 385 */ 386static bool 387StashEventTime(XEvent *ev) 388{ 389 switch(ev->type) { 390 case KeyPress: 391 case KeyRelease: 392 EventTime = ev->xkey.time; 393 return true; 394 case ButtonPress: 395 case ButtonRelease: 396 EventTime = ev->xbutton.time; 397 return true; 398 case MotionNotify: 399 EventTime = ev->xmotion.time; 400 return true; 401 case EnterNotify: 402 case LeaveNotify: 403 EventTime = ev->xcrossing.time; 404 return true; 405 case PropertyNotify: 406 EventTime = ev->xproperty.time; 407 return true; 408 case SelectionClear: 409 EventTime = ev->xselectionclear.time; 410 return true; 411 case SelectionRequest: 412 EventTime = ev->xselectionrequest.time; 413 return true; 414 case SelectionNotify: 415 EventTime = ev->xselection.time; 416 return true; 417 } 418 return false; 419} 420 421 422/* 423 * Debugging: output details of an event. Or at least, details of a few 424 * events, presumably those which somebody doing debugging needed at the 425 * time. 426 */ 427static void 428dumpevent(const XEvent *e) 429{ 430 const char *name; 431 432 if(! tracefile) { 433 return; 434 } 435 436 /* Whatsit? */ 437 name = event_name_by_num(e->type); 438 if(!name) { 439 name = "Unknown event"; 440 } 441 442 /* Tell about it */ 443 fprintf(tracefile, "event: %s in window 0x%x\n", name, 444 (unsigned int)e->xany.window); 445 switch(e->type) { 446 case KeyPress: 447 case KeyRelease: 448 fprintf(tracefile, " : +%d,+%d (+%d,+%d) state=%d, keycode=%d\n", 449 e->xkey.x, e->xkey.y, 450 e->xkey.x_root, e->xkey.y_root, 451 e->xkey.state, e->xkey.keycode); 452 break; 453 case ButtonPress: 454 case ButtonRelease: 455 fprintf(tracefile, " : +%d,+%d (+%d,+%d) state=%d, button=%d\n", 456 e->xbutton.x, e->xbutton.y, 457 e->xbutton.x_root, e->xbutton.y_root, 458 e->xbutton.state, e->xbutton.button); 459 break; 460 } 461} 462