SDL_x11events.c (46328B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23#if SDL_VIDEO_DRIVER_X11 24 25#include <sys/types.h> 26#include <sys/time.h> 27#include <signal.h> 28#include <unistd.h> 29#include <limits.h> /* For INT_MAX */ 30 31#include "SDL_x11video.h" 32#include "SDL_x11touch.h" 33#include "SDL_x11xinput2.h" 34#include "../../events/SDL_events_c.h" 35#include "../../events/SDL_mouse_c.h" 36#include "../../events/SDL_touch_c.h" 37 38#include "SDL_timer.h" 39#include "SDL_syswm.h" 40 41#include <stdio.h> 42 43#ifndef _NET_WM_MOVERESIZE_SIZE_TOPLEFT 44#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 45#endif 46 47#ifndef _NET_WM_MOVERESIZE_SIZE_TOP 48#define _NET_WM_MOVERESIZE_SIZE_TOP 1 49#endif 50 51#ifndef _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 52#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 53#endif 54 55#ifndef _NET_WM_MOVERESIZE_SIZE_RIGHT 56#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 57#endif 58 59#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 60#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 61#endif 62 63#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOM 64#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 65#endif 66 67#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 68#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 69#endif 70 71#ifndef _NET_WM_MOVERESIZE_SIZE_LEFT 72#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 73#endif 74 75#ifndef _NET_WM_MOVERESIZE_MOVE 76#define _NET_WM_MOVERESIZE_MOVE 8 77#endif 78 79typedef struct { 80 unsigned char *data; 81 int format, count; 82 Atom type; 83} SDL_x11Prop; 84 85/* Reads property 86 Must call X11_XFree on results 87 */ 88static void X11_ReadProperty(SDL_x11Prop *p, Display *disp, Window w, Atom prop) 89{ 90 unsigned char *ret=NULL; 91 Atom type; 92 int fmt; 93 unsigned long count; 94 unsigned long bytes_left; 95 int bytes_fetch = 0; 96 97 do { 98 if (ret != 0) X11_XFree(ret); 99 X11_XGetWindowProperty(disp, w, prop, 0, bytes_fetch, False, AnyPropertyType, &type, &fmt, &count, &bytes_left, &ret); 100 bytes_fetch += bytes_left; 101 } while (bytes_left != 0); 102 103 p->data=ret; 104 p->format=fmt; 105 p->count=count; 106 p->type=type; 107} 108 109/* Find text-uri-list in a list of targets and return it's atom 110 if available, else return None */ 111static Atom X11_PickTarget(Display *disp, Atom list[], int list_count) 112{ 113 Atom request = None; 114 char *name; 115 int i; 116 for (i=0; i < list_count && request == None; i++) { 117 name = X11_XGetAtomName(disp, list[i]); 118 if (strcmp("text/uri-list", name)==0) request = list[i]; 119 X11_XFree(name); 120 } 121 return request; 122} 123 124/* Wrapper for X11_PickTarget for a maximum of three targets, a special 125 case in the Xdnd protocol */ 126static Atom X11_PickTargetFromAtoms(Display *disp, Atom a0, Atom a1, Atom a2) 127{ 128 int count=0; 129 Atom atom[3]; 130 if (a0 != None) atom[count++] = a0; 131 if (a1 != None) atom[count++] = a1; 132 if (a2 != None) atom[count++] = a2; 133 return X11_PickTarget(disp, atom, count); 134} 135/* #define DEBUG_XEVENTS */ 136 137struct KeyRepeatCheckData 138{ 139 XEvent *event; 140 SDL_bool found; 141}; 142 143static Bool X11_KeyRepeatCheckIfEvent(Display *display, XEvent *chkev, 144 XPointer arg) 145{ 146 struct KeyRepeatCheckData *d = (struct KeyRepeatCheckData *) arg; 147 if (chkev->type == KeyPress && 148 chkev->xkey.keycode == d->event->xkey.keycode && 149 chkev->xkey.time - d->event->xkey.time < 2) 150 d->found = SDL_TRUE; 151 return False; 152} 153 154/* Check to see if this is a repeated key. 155 (idea shamelessly lifted from GII -- thanks guys! :) 156 */ 157static SDL_bool X11_KeyRepeat(Display *display, XEvent *event) 158{ 159 XEvent dummyev; 160 struct KeyRepeatCheckData d; 161 d.event = event; 162 d.found = SDL_FALSE; 163 if (X11_XPending(display)) 164 X11_XCheckIfEvent(display, &dummyev, X11_KeyRepeatCheckIfEvent, 165 (XPointer) &d); 166 return d.found; 167} 168 169static Bool X11_IsWheelCheckIfEvent(Display *display, XEvent *chkev, 170 XPointer arg) 171{ 172 XEvent *event = (XEvent *) arg; 173 /* we only handle buttons 4 and 5 - false positive avoidance */ 174 if (chkev->type == ButtonRelease && 175 (event->xbutton.button == Button4 || event->xbutton.button == Button5) && 176 chkev->xbutton.button == event->xbutton.button && 177 chkev->xbutton.time == event->xbutton.time) 178 return True; 179 return False; 180} 181 182static SDL_bool X11_IsWheelEvent(Display * display,XEvent * event,int * ticks) 183{ 184 XEvent relevent; 185 if (X11_XPending(display)) { 186 /* according to the xlib docs, no specific mouse wheel events exist. 187 however, mouse wheel events trigger a button press and a button release 188 immediately. thus, checking if the same button was released at the same 189 time as it was pressed, should be an adequate hack to derive a mouse 190 wheel event. 191 However, there is broken and unusual hardware out there... 192 - False positive: a button for which a release event is 193 generated (or synthesised) immediately. 194 - False negative: a wheel which, when rolled, doesn't have 195 a release event generated immediately. */ 196 if (X11_XCheckIfEvent(display, &relevent, X11_IsWheelCheckIfEvent, 197 (XPointer) event)) { 198 199 /* by default, X11 only knows 5 buttons. on most 3 button + wheel mouse, 200 Button4 maps to wheel up, Button5 maps to wheel down. */ 201 if (event->xbutton.button == Button4) { 202 *ticks = 1; 203 } 204 else if (event->xbutton.button == Button5) { 205 *ticks = -1; 206 } 207 return SDL_TRUE; 208 } 209 } 210 return SDL_FALSE; 211} 212 213/* Decodes URI escape sequences in string buf of len bytes 214 (excluding the terminating NULL byte) in-place. Since 215 URI-encoded characters take three times the space of 216 normal characters, this should not be an issue. 217 218 Returns the number of decoded bytes that wound up in 219 the buffer, excluding the terminating NULL byte. 220 221 The buffer is guaranteed to be NULL-terminated but 222 may contain embedded NULL bytes. 223 224 On error, -1 is returned. 225 */ 226int X11_URIDecode(char *buf, int len) { 227 int ri, wi, di; 228 char decode = '\0'; 229 if (buf == NULL || len < 0) { 230 errno = EINVAL; 231 return -1; 232 } 233 if (len == 0) { 234 len = SDL_strlen(buf); 235 } 236 for (ri = 0, wi = 0, di = 0; ri < len && wi < len; ri += 1) { 237 if (di == 0) { 238 /* start decoding */ 239 if (buf[ri] == '%') { 240 decode = '\0'; 241 di += 1; 242 continue; 243 } 244 /* normal write */ 245 buf[wi] = buf[ri]; 246 wi += 1; 247 continue; 248 } else if (di == 1 || di == 2) { 249 char off = '\0'; 250 char isa = buf[ri] >= 'a' && buf[ri] <= 'f'; 251 char isA = buf[ri] >= 'A' && buf[ri] <= 'F'; 252 char isn = buf[ri] >= '0' && buf[ri] <= '9'; 253 if (!(isa || isA || isn)) { 254 /* not a hexadecimal */ 255 int sri; 256 for (sri = ri - di; sri <= ri; sri += 1) { 257 buf[wi] = buf[sri]; 258 wi += 1; 259 } 260 di = 0; 261 continue; 262 } 263 /* itsy bitsy magicsy */ 264 if (isn) { 265 off = 0 - '0'; 266 } else if (isa) { 267 off = 10 - 'a'; 268 } else if (isA) { 269 off = 10 - 'A'; 270 } 271 decode |= (buf[ri] + off) << (2 - di) * 4; 272 if (di == 2) { 273 buf[wi] = decode; 274 wi += 1; 275 di = 0; 276 } else { 277 di += 1; 278 } 279 continue; 280 } 281 } 282 buf[wi] = '\0'; 283 return wi; 284} 285 286/* Convert URI to local filename 287 return filename if possible, else NULL 288*/ 289static char* X11_URIToLocal(char* uri) { 290 char *file = NULL; 291 SDL_bool local; 292 293 if (memcmp(uri,"file:/",6) == 0) uri += 6; /* local file? */ 294 else if (strstr(uri,":/") != NULL) return file; /* wrong scheme */ 295 296 local = uri[0] != '/' || ( uri[0] != '\0' && uri[1] == '/' ); 297 298 /* got a hostname? */ 299 if ( !local && uri[0] == '/' && uri[2] != '/' ) { 300 char* hostname_end = strchr( uri+1, '/' ); 301 if ( hostname_end != NULL ) { 302 char hostname[ 257 ]; 303 if ( gethostname( hostname, 255 ) == 0 ) { 304 hostname[ 256 ] = '\0'; 305 if ( memcmp( uri+1, hostname, hostname_end - ( uri+1 )) == 0 ) { 306 uri = hostname_end + 1; 307 local = SDL_TRUE; 308 } 309 } 310 } 311 } 312 if ( local ) { 313 file = uri; 314 /* Convert URI escape sequences to real characters */ 315 X11_URIDecode(file, 0); 316 if ( uri[1] == '/' ) { 317 file++; 318 } else { 319 file--; 320 } 321 } 322 return file; 323} 324 325#if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 326static void X11_HandleGenericEvent(SDL_VideoData *videodata,XEvent event) 327{ 328 /* event is a union, so cookie == &event, but this is type safe. */ 329 XGenericEventCookie *cookie = &event.xcookie; 330 if (X11_XGetEventData(videodata->display, cookie)) { 331 X11_HandleXinput2Event(videodata, cookie); 332 X11_XFreeEventData(videodata->display, cookie); 333 } 334} 335#endif /* SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS */ 336 337 338static void 339X11_DispatchFocusIn(SDL_WindowData *data) 340{ 341#ifdef DEBUG_XEVENTS 342 printf("window %p: Dispatching FocusIn\n", data); 343#endif 344 SDL_SetKeyboardFocus(data->window); 345#ifdef X_HAVE_UTF8_STRING 346 if (data->ic) { 347 X11_XSetICFocus(data->ic); 348 } 349#endif 350#ifdef SDL_USE_IBUS 351 SDL_IBus_SetFocus(SDL_TRUE); 352#endif 353} 354 355static void 356X11_DispatchFocusOut(SDL_WindowData *data) 357{ 358#ifdef DEBUG_XEVENTS 359 printf("window %p: Dispatching FocusOut\n", data); 360#endif 361 /* If another window has already processed a focus in, then don't try to 362 * remove focus here. Doing so will incorrectly remove focus from that 363 * window, and the focus lost event for this window will have already 364 * been dispatched anyway. */ 365 if (data->window == SDL_GetKeyboardFocus()) { 366 SDL_SetKeyboardFocus(NULL); 367 } 368#ifdef X_HAVE_UTF8_STRING 369 if (data->ic) { 370 X11_XUnsetICFocus(data->ic); 371 } 372#endif 373#ifdef SDL_USE_IBUS 374 SDL_IBus_SetFocus(SDL_FALSE); 375#endif 376} 377 378static void 379X11_DispatchMapNotify(SDL_WindowData *data) 380{ 381 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0); 382 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESTORED, 0, 0); 383} 384 385static void 386X11_DispatchUnmapNotify(SDL_WindowData *data) 387{ 388 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0); 389 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0); 390} 391 392static void 393InitiateWindowMove(_THIS, const SDL_WindowData *data, const SDL_Point *point) 394{ 395 SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; 396 SDL_Window* window = data->window; 397 Display *display = viddata->display; 398 XEvent evt; 399 400 /* !!! FIXME: we need to regrab this if necessary when the drag is done. */ 401 X11_XUngrabPointer(display, 0L); 402 X11_XFlush(display); 403 404 evt.xclient.type = ClientMessage; 405 evt.xclient.window = data->xwindow; 406 evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True); 407 evt.xclient.format = 32; 408 evt.xclient.data.l[0] = window->x + point->x; 409 evt.xclient.data.l[1] = window->y + point->y; 410 evt.xclient.data.l[2] = _NET_WM_MOVERESIZE_MOVE; 411 evt.xclient.data.l[3] = Button1; 412 evt.xclient.data.l[4] = 0; 413 X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt); 414 415 X11_XSync(display, 0); 416} 417 418static void 419InitiateWindowResize(_THIS, const SDL_WindowData *data, const SDL_Point *point, int direction) 420{ 421 SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; 422 SDL_Window* window = data->window; 423 Display *display = viddata->display; 424 XEvent evt; 425 426 if (direction < _NET_WM_MOVERESIZE_SIZE_TOPLEFT || direction > _NET_WM_MOVERESIZE_SIZE_LEFT) 427 return; 428 429 /* !!! FIXME: we need to regrab this if necessary when the drag is done. */ 430 X11_XUngrabPointer(display, 0L); 431 X11_XFlush(display); 432 433 evt.xclient.type = ClientMessage; 434 evt.xclient.window = data->xwindow; 435 evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True); 436 evt.xclient.format = 32; 437 evt.xclient.data.l[0] = window->x + point->x; 438 evt.xclient.data.l[1] = window->y + point->y; 439 evt.xclient.data.l[2] = direction; 440 evt.xclient.data.l[3] = Button1; 441 evt.xclient.data.l[4] = 0; 442 X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt); 443 444 X11_XSync(display, 0); 445} 446 447static SDL_bool 448ProcessHitTest(_THIS, const SDL_WindowData *data, const XEvent *xev) 449{ 450 SDL_Window *window = data->window; 451 SDL_bool ret = SDL_FALSE; 452 453 if (window->hit_test) { 454 const SDL_Point point = { xev->xbutton.x, xev->xbutton.y }; 455 const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data); 456 switch (rc) { 457 case SDL_HITTEST_DRAGGABLE: { 458 InitiateWindowMove(_this, data, &point); 459 ret = SDL_TRUE; 460 } 461 break; 462 case SDL_HITTEST_RESIZE_TOPLEFT: { 463 InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOPLEFT); 464 ret = SDL_TRUE; 465 } 466 break; 467 case SDL_HITTEST_RESIZE_TOP: { 468 InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOP); 469 ret = SDL_TRUE; 470 } 471 break; 472 case SDL_HITTEST_RESIZE_TOPRIGHT: { 473 InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOPRIGHT); 474 ret = SDL_TRUE; 475 } 476 break; 477 case SDL_HITTEST_RESIZE_RIGHT: { 478 InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_RIGHT); 479 ret = SDL_TRUE; 480 } 481 break; 482 case SDL_HITTEST_RESIZE_BOTTOMRIGHT: { 483 InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT); 484 ret = SDL_TRUE; 485 } 486 break; 487 case SDL_HITTEST_RESIZE_BOTTOM: { 488 InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOM); 489 ret = SDL_TRUE; 490 } 491 break; 492 case SDL_HITTEST_RESIZE_BOTTOMLEFT: { 493 InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT); 494 ret = SDL_TRUE; 495 } 496 break; 497 case SDL_HITTEST_RESIZE_LEFT: { 498 InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_LEFT); 499 ret = SDL_TRUE; 500 } 501 break; 502 default: 503 break; 504 } 505 } 506 507 return ret; 508} 509 510static void 511ReconcileKeyboardState(_THIS, const SDL_WindowData *data) 512{ 513 SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; 514 SDL_Window* window = data->window; 515 Display *display = viddata->display; 516 char keys[32]; 517 int keycode = 0; 518 519 X11_XQueryKeymap( display, keys ); 520 521 while ( keycode < 256 ) { 522 if ( keys[keycode / 8] & (1 << (keycode % 8)) ) { 523 SDL_SendKeyboardKey(SDL_PRESSED, viddata->key_layout[keycode]); 524 } else { 525 SDL_SendKeyboardKey(SDL_RELEASED, viddata->key_layout[keycode]); 526 } 527 keycode++; 528 } 529} 530 531static void 532X11_DispatchEvent(_THIS) 533{ 534 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; 535 Display *display = videodata->display; 536 SDL_WindowData *data; 537 XEvent xevent; 538 int orig_event_type; 539 KeyCode orig_keycode; 540 XClientMessageEvent m; 541 int i; 542 543 SDL_zero(xevent); /* valgrind fix. --ryan. */ 544 X11_XNextEvent(display, &xevent); 545 546 /* Save the original keycode for dead keys, which are filtered out by 547 the XFilterEvent() call below. 548 */ 549 orig_event_type = xevent.type; 550 if (orig_event_type == KeyPress || orig_event_type == KeyRelease) { 551 orig_keycode = xevent.xkey.keycode; 552 } else { 553 orig_keycode = 0; 554 } 555 556 /* filter events catchs XIM events and sends them to the correct handler */ 557 if (X11_XFilterEvent(&xevent, None) == True) { 558#if 0 559 printf("Filtered event type = %d display = %d window = %d\n", 560 xevent.type, xevent.xany.display, xevent.xany.window); 561#endif 562 if (orig_keycode) { 563 /* Make sure dead key press/release events are sent */ 564 /* Actually, don't do this because it causes double-delivery 565 of some keys on Ubuntu 14.04 (bug 2526) 566 SDL_Scancode scancode = videodata->key_layout[orig_keycode]; 567 if (orig_event_type == KeyPress) { 568 SDL_SendKeyboardKey(SDL_PRESSED, scancode); 569 } else { 570 SDL_SendKeyboardKey(SDL_RELEASED, scancode); 571 } 572 */ 573 } 574 return; 575 } 576 577 /* Send a SDL_SYSWMEVENT if the application wants them */ 578 if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) { 579 SDL_SysWMmsg wmmsg; 580 581 SDL_VERSION(&wmmsg.version); 582 wmmsg.subsystem = SDL_SYSWM_X11; 583 wmmsg.msg.x11.event = xevent; 584 SDL_SendSysWMEvent(&wmmsg); 585 } 586 587#if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 588 if(xevent.type == GenericEvent) { 589 X11_HandleGenericEvent(videodata,xevent); 590 return; 591 } 592#endif 593 594#if 0 595 printf("type = %d display = %d window = %d\n", 596 xevent.type, xevent.xany.display, xevent.xany.window); 597#endif 598 599 data = NULL; 600 if (videodata && videodata->windowlist) { 601 for (i = 0; i < videodata->numwindows; ++i) { 602 if ((videodata->windowlist[i] != NULL) && 603 (videodata->windowlist[i]->xwindow == xevent.xany.window)) { 604 data = videodata->windowlist[i]; 605 break; 606 } 607 } 608 } 609 if (!data) { 610 return; 611 } 612 613 switch (xevent.type) { 614 615 /* Gaining mouse coverage? */ 616 case EnterNotify:{ 617#ifdef DEBUG_XEVENTS 618 printf("window %p: EnterNotify! (%d,%d,%d)\n", data, 619 xevent.xcrossing.x, 620 xevent.xcrossing.y, 621 xevent.xcrossing.mode); 622 if (xevent.xcrossing.mode == NotifyGrab) 623 printf("Mode: NotifyGrab\n"); 624 if (xevent.xcrossing.mode == NotifyUngrab) 625 printf("Mode: NotifyUngrab\n"); 626#endif 627 SDL_SetMouseFocus(data->window); 628 629 if (!SDL_GetMouse()->relative_mode) { 630 SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y); 631 } 632 } 633 break; 634 /* Losing mouse coverage? */ 635 case LeaveNotify:{ 636#ifdef DEBUG_XEVENTS 637 printf("window %p: LeaveNotify! (%d,%d,%d)\n", data, 638 xevent.xcrossing.x, 639 xevent.xcrossing.y, 640 xevent.xcrossing.mode); 641 if (xevent.xcrossing.mode == NotifyGrab) 642 printf("Mode: NotifyGrab\n"); 643 if (xevent.xcrossing.mode == NotifyUngrab) 644 printf("Mode: NotifyUngrab\n"); 645#endif 646 if (!SDL_GetMouse()->relative_mode) { 647 SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y); 648 } 649 650 if (xevent.xcrossing.mode != NotifyGrab && 651 xevent.xcrossing.mode != NotifyUngrab && 652 xevent.xcrossing.detail != NotifyInferior) { 653 SDL_SetMouseFocus(NULL); 654 } 655 } 656 break; 657 658 /* Gaining input focus? */ 659 case FocusIn:{ 660 if (xevent.xfocus.mode == NotifyGrab || xevent.xfocus.mode == NotifyUngrab) { 661 /* Someone is handling a global hotkey, ignore it */ 662#ifdef DEBUG_XEVENTS 663 printf("window %p: FocusIn (NotifyGrab/NotifyUngrab, ignoring)\n", data); 664#endif 665 break; 666 } 667 668 if (xevent.xfocus.detail == NotifyInferior) { 669#ifdef DEBUG_XEVENTS 670 printf("window %p: FocusIn (NotifierInferior, ignoring)\n", data); 671#endif 672 break; 673 } 674#ifdef DEBUG_XEVENTS 675 printf("window %p: FocusIn!\n", data); 676#endif 677 if (data->pending_focus == PENDING_FOCUS_OUT && 678 data->window == SDL_GetKeyboardFocus()) { 679 ReconcileKeyboardState(_this, data); 680 } 681 data->pending_focus = PENDING_FOCUS_IN; 682 data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_IN_TIME; 683 } 684 break; 685 686 /* Losing input focus? */ 687 case FocusOut:{ 688 if (xevent.xfocus.mode == NotifyGrab || xevent.xfocus.mode == NotifyUngrab) { 689 /* Someone is handling a global hotkey, ignore it */ 690#ifdef DEBUG_XEVENTS 691 printf("window %p: FocusOut (NotifyGrab/NotifyUngrab, ignoring)\n", data); 692#endif 693 break; 694 } 695 if (xevent.xfocus.detail == NotifyInferior) { 696 /* We still have focus if a child gets focus */ 697#ifdef DEBUG_XEVENTS 698 printf("window %p: FocusOut (NotifierInferior, ignoring)\n", data); 699#endif 700 break; 701 } 702#ifdef DEBUG_XEVENTS 703 printf("window %p: FocusOut!\n", data); 704#endif 705 data->pending_focus = PENDING_FOCUS_OUT; 706 data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_OUT_TIME; 707 } 708 break; 709 710 /* Generated upon EnterWindow and FocusIn */ 711 case KeymapNotify:{ 712#ifdef DEBUG_XEVENTS 713 printf("window %p: KeymapNotify!\n", data); 714#endif 715 /* FIXME: 716 X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector); 717 */ 718 } 719 break; 720 721 /* Has the keyboard layout changed? */ 722 case MappingNotify:{ 723#ifdef DEBUG_XEVENTS 724 printf("window %p: MappingNotify!\n", data); 725#endif 726 X11_UpdateKeymap(_this); 727 } 728 break; 729 730 /* Key press? */ 731 case KeyPress:{ 732 KeyCode keycode = xevent.xkey.keycode; 733 KeySym keysym = NoSymbol; 734 char text[SDL_TEXTINPUTEVENT_TEXT_SIZE]; 735 Status status = 0; 736 SDL_bool handled_by_ime = SDL_FALSE; 737 738#ifdef DEBUG_XEVENTS 739 printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode); 740#endif 741#if 1 742 if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) { 743 int min_keycode, max_keycode; 744 X11_XDisplayKeycodes(display, &min_keycode, &max_keycode); 745#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM 746 keysym = X11_XkbKeycodeToKeysym(display, keycode, 0, 0); 747#else 748 keysym = XKeycodeToKeysym(display, keycode, 0); 749#endif 750 fprintf(stderr, 751 "The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL mailing list <sdl@libsdl.org> X11 KeyCode %d (%d), X11 KeySym 0x%lX (%s).\n", 752 keycode, keycode - min_keycode, keysym, 753 X11_XKeysymToString(keysym)); 754 } 755#endif 756 /* */ 757 SDL_zero(text); 758#ifdef X_HAVE_UTF8_STRING 759 if (data->ic) { 760 X11_Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text), 761 &keysym, &status); 762 } 763#else 764 XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL); 765#endif 766#ifdef SDL_USE_IBUS 767 if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ 768 if(!(handled_by_ime = SDL_IBus_ProcessKeyEvent(keysym, keycode))){ 769#endif 770 if(*text){ 771 SDL_SendKeyboardText(text); 772 } 773#ifdef SDL_USE_IBUS 774 } 775 } 776#endif 777 if (!handled_by_ime) { 778 SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]); 779 } 780 781 } 782 break; 783 784 /* Key release? */ 785 case KeyRelease:{ 786 KeyCode keycode = xevent.xkey.keycode; 787 788#ifdef DEBUG_XEVENTS 789 printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode); 790#endif 791 if (X11_KeyRepeat(display, &xevent)) { 792 /* We're about to get a repeated key down, ignore the key up */ 793 break; 794 } 795 SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]); 796 } 797 break; 798 799 /* Have we been iconified? */ 800 case UnmapNotify:{ 801#ifdef DEBUG_XEVENTS 802 printf("window %p: UnmapNotify!\n", data); 803#endif 804 X11_DispatchUnmapNotify(data); 805 } 806 break; 807 808 /* Have we been restored? */ 809 case MapNotify:{ 810#ifdef DEBUG_XEVENTS 811 printf("window %p: MapNotify!\n", data); 812#endif 813 X11_DispatchMapNotify(data); 814 } 815 break; 816 817 /* Have we been resized or moved? */ 818 case ConfigureNotify:{ 819#ifdef DEBUG_XEVENTS 820 printf("window %p: ConfigureNotify! (position: %d,%d, size: %dx%d)\n", data, 821 xevent.xconfigure.x, xevent.xconfigure.y, 822 xevent.xconfigure.width, xevent.xconfigure.height); 823#endif 824 long border_left = 0; 825 long border_top = 0; 826 if (data->xwindow) { 827 Atom _net_frame_extents = X11_XInternAtom(display, "_NET_FRAME_EXTENTS", 0); 828 Atom type; 829 int format; 830 unsigned long nitems, bytes_after; 831 unsigned char *property; 832 if (X11_XGetWindowProperty(display, data->xwindow, 833 _net_frame_extents, 0, 16, 0, 834 XA_CARDINAL, &type, &format, 835 &nitems, &bytes_after, &property) == Success) { 836 if (type != None && nitems == 4) 837 { 838 border_left = ((long*)property)[0]; 839 border_top = ((long*)property)[2]; 840 } 841 X11_XFree(property); 842 } 843 } 844 845 if (xevent.xconfigure.x != data->last_xconfigure.x || 846 xevent.xconfigure.y != data->last_xconfigure.y) { 847 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, 848 xevent.xconfigure.x - border_left, 849 xevent.xconfigure.y - border_top); 850#ifdef SDL_USE_IBUS 851 if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ 852 /* Update IBus candidate list position */ 853 SDL_IBus_UpdateTextRect(NULL); 854 } 855#endif 856 } 857 if (xevent.xconfigure.width != data->last_xconfigure.width || 858 xevent.xconfigure.height != data->last_xconfigure.height) { 859 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, 860 xevent.xconfigure.width, 861 xevent.xconfigure.height); 862 } 863 data->last_xconfigure = xevent.xconfigure; 864 } 865 break; 866 867 /* Have we been requested to quit (or another client message?) */ 868 case ClientMessage:{ 869 870 int xdnd_version=0; 871 872 if (xevent.xclient.message_type == videodata->XdndEnter) { 873 SDL_bool use_list = xevent.xclient.data.l[1] & 1; 874 data->xdnd_source = xevent.xclient.data.l[0]; 875 xdnd_version = ( xevent.xclient.data.l[1] >> 24); 876 if (use_list) { 877 /* fetch conversion targets */ 878 SDL_x11Prop p; 879 X11_ReadProperty(&p, display, data->xdnd_source, videodata->XdndTypeList); 880 /* pick one */ 881 data->xdnd_req = X11_PickTarget(display, (Atom*)p.data, p.count); 882 X11_XFree(p.data); 883 } else { 884 /* pick from list of three */ 885 data->xdnd_req = X11_PickTargetFromAtoms(display, xevent.xclient.data.l[2], xevent.xclient.data.l[3], xevent.xclient.data.l[4]); 886 } 887 } 888 else if (xevent.xclient.message_type == videodata->XdndPosition) { 889 890 /* reply with status */ 891 memset(&m, 0, sizeof(XClientMessageEvent)); 892 m.type = ClientMessage; 893 m.display = xevent.xclient.display; 894 m.window = xevent.xclient.data.l[0]; 895 m.message_type = videodata->XdndStatus; 896 m.format=32; 897 m.data.l[0] = data->xwindow; 898 m.data.l[1] = (data->xdnd_req != None); 899 m.data.l[2] = 0; /* specify an empty rectangle */ 900 m.data.l[3] = 0; 901 m.data.l[4] = videodata->XdndActionCopy; /* we only accept copying anyway */ 902 903 X11_XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m); 904 X11_XFlush(display); 905 } 906 else if(xevent.xclient.message_type == videodata->XdndDrop) { 907 if (data->xdnd_req == None) { 908 /* say again - not interested! */ 909 memset(&m, 0, sizeof(XClientMessageEvent)); 910 m.type = ClientMessage; 911 m.display = xevent.xclient.display; 912 m.window = xevent.xclient.data.l[0]; 913 m.message_type = videodata->XdndFinished; 914 m.format=32; 915 m.data.l[0] = data->xwindow; 916 m.data.l[1] = 0; 917 m.data.l[2] = None; /* fail! */ 918 X11_XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m); 919 } else { 920 /* convert */ 921 if(xdnd_version >= 1) { 922 X11_XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, xevent.xclient.data.l[2]); 923 } else { 924 X11_XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, CurrentTime); 925 } 926 } 927 } 928 else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) && 929 (xevent.xclient.format == 32) && 930 (xevent.xclient.data.l[0] == videodata->_NET_WM_PING)) { 931 Window root = DefaultRootWindow(display); 932 933#ifdef DEBUG_XEVENTS 934 printf("window %p: _NET_WM_PING\n", data); 935#endif 936 xevent.xclient.window = root; 937 X11_XSendEvent(display, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &xevent); 938 break; 939 } 940 941 else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) && 942 (xevent.xclient.format == 32) && 943 (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) { 944 945#ifdef DEBUG_XEVENTS 946 printf("window %p: WM_DELETE_WINDOW\n", data); 947#endif 948 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0); 949 break; 950 } 951 } 952 break; 953 954 /* Do we need to refresh ourselves? */ 955 case Expose:{ 956#ifdef DEBUG_XEVENTS 957 printf("window %p: Expose (count = %d)\n", data, xevent.xexpose.count); 958#endif 959 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0); 960 } 961 break; 962 963 case MotionNotify:{ 964 SDL_Mouse *mouse = SDL_GetMouse(); 965 if(!mouse->relative_mode || mouse->relative_mode_warp) { 966#ifdef DEBUG_MOTION 967 printf("window %p: X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y); 968#endif 969 970 SDL_SendMouseMotion(data->window, 0, 0, xevent.xmotion.x, xevent.xmotion.y); 971 } 972 } 973 break; 974 975 case ButtonPress:{ 976 int ticks = 0; 977 if (X11_IsWheelEvent(display,&xevent,&ticks)) { 978 SDL_SendMouseWheel(data->window, 0, 0, ticks); 979 } else { 980 if(xevent.xbutton.button == Button1) { 981 if (ProcessHitTest(_this, data, &xevent)) { 982 break; /* don't pass this event on to app. */ 983 } 984 } 985 SDL_SendMouseButton(data->window, 0, SDL_PRESSED, xevent.xbutton.button); 986 } 987 } 988 break; 989 990 case ButtonRelease:{ 991 SDL_SendMouseButton(data->window, 0, SDL_RELEASED, xevent.xbutton.button); 992 } 993 break; 994 995 case PropertyNotify:{ 996#ifdef DEBUG_XEVENTS 997 unsigned char *propdata; 998 int status, real_format; 999 Atom real_type; 1000 unsigned long items_read, items_left, i; 1001 1002 char *name = X11_XGetAtomName(display, xevent.xproperty.atom); 1003 if (name) { 1004 printf("window %p: PropertyNotify: %s %s\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed"); 1005 X11_XFree(name); 1006 } 1007 1008 status = X11_XGetWindowProperty(display, data->xwindow, xevent.xproperty.atom, 0L, 8192L, False, AnyPropertyType, &real_type, &real_format, &items_read, &items_left, &propdata); 1009 if (status == Success && items_read > 0) { 1010 if (real_type == XA_INTEGER) { 1011 int *values = (int *)propdata; 1012 1013 printf("{"); 1014 for (i = 0; i < items_read; i++) { 1015 printf(" %d", values[i]); 1016 } 1017 printf(" }\n"); 1018 } else if (real_type == XA_CARDINAL) { 1019 if (real_format == 32) { 1020 Uint32 *values = (Uint32 *)propdata; 1021 1022 printf("{"); 1023 for (i = 0; i < items_read; i++) { 1024 printf(" %d", values[i]); 1025 } 1026 printf(" }\n"); 1027 } else if (real_format == 16) { 1028 Uint16 *values = (Uint16 *)propdata; 1029 1030 printf("{"); 1031 for (i = 0; i < items_read; i++) { 1032 printf(" %d", values[i]); 1033 } 1034 printf(" }\n"); 1035 } else if (real_format == 8) { 1036 Uint8 *values = (Uint8 *)propdata; 1037 1038 printf("{"); 1039 for (i = 0; i < items_read; i++) { 1040 printf(" %d", values[i]); 1041 } 1042 printf(" }\n"); 1043 } 1044 } else if (real_type == XA_STRING || 1045 real_type == videodata->UTF8_STRING) { 1046 printf("{ \"%s\" }\n", propdata); 1047 } else if (real_type == XA_ATOM) { 1048 Atom *atoms = (Atom *)propdata; 1049 1050 printf("{"); 1051 for (i = 0; i < items_read; i++) { 1052 char *name = X11_XGetAtomName(display, atoms[i]); 1053 if (name) { 1054 printf(" %s", name); 1055 X11_XFree(name); 1056 } 1057 } 1058 printf(" }\n"); 1059 } else { 1060 char *name = X11_XGetAtomName(display, real_type); 1061 printf("Unknown type: %ld (%s)\n", real_type, name ? name : "UNKNOWN"); 1062 if (name) { 1063 X11_XFree(name); 1064 } 1065 } 1066 } 1067 if (status == Success) { 1068 X11_XFree(propdata); 1069 } 1070#endif /* DEBUG_XEVENTS */ 1071 1072 if (xevent.xproperty.atom == data->videodata->_NET_WM_STATE) { 1073 /* Get the new state from the window manager. 1074 Compositing window managers can alter visibility of windows 1075 without ever mapping / unmapping them, so we handle that here, 1076 because they use the NETWM protocol to notify us of changes. 1077 */ 1078 Uint32 flags = X11_GetNetWMState(_this, xevent.xproperty.window); 1079 if ((flags^data->window->flags) & SDL_WINDOW_HIDDEN || 1080 (flags^data->window->flags) & SDL_WINDOW_FULLSCREEN ) { 1081 if (flags & SDL_WINDOW_HIDDEN) { 1082 X11_DispatchUnmapNotify(data); 1083 } else { 1084 X11_DispatchMapNotify(data); 1085 } 1086 } 1087 } 1088 } 1089 break; 1090 1091 /* Copy the selection from XA_CUT_BUFFER0 to the requested property */ 1092 case SelectionRequest: { 1093 XSelectionRequestEvent *req; 1094 XEvent sevent; 1095 int seln_format; 1096 unsigned long nbytes; 1097 unsigned long overflow; 1098 unsigned char *seln_data; 1099 1100 req = &xevent.xselectionrequest; 1101#ifdef DEBUG_XEVENTS 1102 printf("window %p: SelectionRequest (requestor = %ld, target = %ld)\n", data, 1103 req->requestor, req->target); 1104#endif 1105 1106 SDL_zero(sevent); 1107 sevent.xany.type = SelectionNotify; 1108 sevent.xselection.selection = req->selection; 1109 sevent.xselection.target = None; 1110 sevent.xselection.property = None; 1111 sevent.xselection.requestor = req->requestor; 1112 sevent.xselection.time = req->time; 1113 if (X11_XGetWindowProperty(display, DefaultRootWindow(display), 1114 XA_CUT_BUFFER0, 0, INT_MAX/4, False, req->target, 1115 &sevent.xselection.target, &seln_format, &nbytes, 1116 &overflow, &seln_data) == Success) { 1117 Atom XA_TARGETS = X11_XInternAtom(display, "TARGETS", 0); 1118 if (sevent.xselection.target == req->target) { 1119 X11_XChangeProperty(display, req->requestor, req->property, 1120 sevent.xselection.target, seln_format, PropModeReplace, 1121 seln_data, nbytes); 1122 sevent.xselection.property = req->property; 1123 } else if (XA_TARGETS == req->target) { 1124 Atom SupportedFormats[] = { sevent.xselection.target, XA_TARGETS }; 1125 X11_XChangeProperty(display, req->requestor, req->property, 1126 XA_ATOM, 32, PropModeReplace, 1127 (unsigned char*)SupportedFormats, 1128 sizeof(SupportedFormats)/sizeof(*SupportedFormats)); 1129 sevent.xselection.property = req->property; 1130 } 1131 X11_XFree(seln_data); 1132 } 1133 X11_XSendEvent(display, req->requestor, False, 0, &sevent); 1134 X11_XSync(display, False); 1135 } 1136 break; 1137 1138 case SelectionNotify: { 1139#ifdef DEBUG_XEVENTS 1140 printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data, 1141 xevent.xselection.requestor, xevent.xselection.target); 1142#endif 1143 Atom target = xevent.xselection.target; 1144 if (target == data->xdnd_req) { 1145 /* read data */ 1146 SDL_x11Prop p; 1147 X11_ReadProperty(&p, display, data->xwindow, videodata->PRIMARY); 1148 1149 if (p.format == 8) { 1150 SDL_bool expect_lf = SDL_FALSE; 1151 char *start = NULL; 1152 char *scan = (char*)p.data; 1153 char *fn; 1154 char *uri; 1155 int length = 0; 1156 while (p.count--) { 1157 if (!expect_lf) { 1158 if (*scan == 0x0D) { 1159 expect_lf = SDL_TRUE; 1160 } 1161 if (start == NULL) { 1162 start = scan; 1163 length = 0; 1164 } 1165 length++; 1166 } else { 1167 if (*scan == 0x0A && length > 0) { 1168 uri = SDL_malloc(length--); 1169 SDL_memcpy(uri, start, length); 1170 uri[length] = '\0'; 1171 fn = X11_URIToLocal(uri); 1172 if (fn) { 1173 SDL_SendDropFile(fn); 1174 } 1175 SDL_free(uri); 1176 } 1177 expect_lf = SDL_FALSE; 1178 start = NULL; 1179 } 1180 scan++; 1181 } 1182 } 1183 1184 X11_XFree(p.data); 1185 1186 /* send reply */ 1187 SDL_memset(&m, 0, sizeof(XClientMessageEvent)); 1188 m.type = ClientMessage; 1189 m.display = display; 1190 m.window = data->xdnd_source; 1191 m.message_type = videodata->XdndFinished; 1192 m.format = 32; 1193 m.data.l[0] = data->xwindow; 1194 m.data.l[1] = 1; 1195 m.data.l[2] = videodata->XdndActionCopy; 1196 X11_XSendEvent(display, data->xdnd_source, False, NoEventMask, (XEvent*)&m); 1197 1198 X11_XSync(display, False); 1199 1200 } else { 1201 videodata->selection_waiting = SDL_FALSE; 1202 } 1203 } 1204 break; 1205 1206 default:{ 1207#ifdef DEBUG_XEVENTS 1208 printf("window %p: Unhandled event %d\n", data, xevent.type); 1209#endif 1210 } 1211 break; 1212 } 1213} 1214 1215static void 1216X11_HandleFocusChanges(_THIS) 1217{ 1218 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; 1219 int i; 1220 1221 if (videodata && videodata->windowlist) { 1222 for (i = 0; i < videodata->numwindows; ++i) { 1223 SDL_WindowData *data = videodata->windowlist[i]; 1224 if (data && data->pending_focus != PENDING_FOCUS_NONE) { 1225 Uint32 now = SDL_GetTicks(); 1226 if (SDL_TICKS_PASSED(now, data->pending_focus_time)) { 1227 if ( data->pending_focus == PENDING_FOCUS_IN ) { 1228 X11_DispatchFocusIn(data); 1229 } else { 1230 X11_DispatchFocusOut(data); 1231 } 1232 data->pending_focus = PENDING_FOCUS_NONE; 1233 } 1234 } 1235 } 1236 } 1237} 1238/* Ack! X11_XPending() actually performs a blocking read if no events available */ 1239static int 1240X11_Pending(Display * display) 1241{ 1242 /* Flush the display connection and look to see if events are queued */ 1243 X11_XFlush(display); 1244 if (X11_XEventsQueued(display, QueuedAlready)) { 1245 return (1); 1246 } 1247 1248 /* More drastic measures are required -- see if X is ready to talk */ 1249 { 1250 static struct timeval zero_time; /* static == 0 */ 1251 int x11_fd; 1252 fd_set fdset; 1253 1254 x11_fd = ConnectionNumber(display); 1255 FD_ZERO(&fdset); 1256 FD_SET(x11_fd, &fdset); 1257 if (select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1) { 1258 return (X11_XPending(display)); 1259 } 1260 } 1261 1262 /* Oh well, nothing is ready .. */ 1263 return (0); 1264} 1265 1266void 1267X11_PumpEvents(_THIS) 1268{ 1269 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 1270 1271 /* Update activity every 30 seconds to prevent screensaver */ 1272 if (_this->suspend_screensaver) { 1273 Uint32 now = SDL_GetTicks(); 1274 if (!data->screensaver_activity || 1275 SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) { 1276 X11_XResetScreenSaver(data->display); 1277 1278#if SDL_USE_LIBDBUS 1279 SDL_DBus_ScreensaverTickle(); 1280#endif 1281 1282 data->screensaver_activity = now; 1283 } 1284 } 1285 1286#ifdef SDL_USE_IBUS 1287 if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ 1288 SDL_IBus_PumpEvents(); 1289 } 1290#endif 1291 1292 /* Keep processing pending events */ 1293 while (X11_Pending(data->display)) { 1294 X11_DispatchEvent(_this); 1295 } 1296 1297 /* FIXME: Only need to do this when there are pending focus changes */ 1298 X11_HandleFocusChanges(_this); 1299} 1300 1301 1302void 1303X11_SuspendScreenSaver(_THIS) 1304{ 1305#if SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1306 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 1307 int dummy; 1308 int major_version, minor_version; 1309#endif /* SDL_VIDEO_DRIVER_X11_XSCRNSAVER */ 1310 1311#if SDL_USE_LIBDBUS 1312 if (SDL_DBus_ScreensaverInhibit(_this->suspend_screensaver)) { 1313 return; 1314 } 1315 1316 if (_this->suspend_screensaver) { 1317 SDL_DBus_ScreensaverTickle(); 1318 } 1319#endif 1320 1321#if SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1322 if (SDL_X11_HAVE_XSS) { 1323 /* X11_XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */ 1324 if (!X11_XScreenSaverQueryExtension(data->display, &dummy, &dummy) || 1325 !X11_XScreenSaverQueryVersion(data->display, 1326 &major_version, &minor_version) || 1327 major_version < 1 || (major_version == 1 && minor_version < 1)) { 1328 return; 1329 } 1330 1331 X11_XScreenSaverSuspend(data->display, _this->suspend_screensaver); 1332 X11_XResetScreenSaver(data->display); 1333 } 1334#endif 1335} 1336 1337#endif /* SDL_VIDEO_DRIVER_X11 */ 1338 1339/* vi: set ts=4 sw=4 expandtab: */