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