Atlas - SDL_x11events.c

Home / ext / SDL2 / src / video / x11 Lines: 52 | Size: 54108 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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 "../../core/unix/SDL_poll.h" 35#include "../../events/SDL_events_c.h" 36#include "../../events/SDL_mouse_c.h" 37#include "../../events/SDL_touch_c.h" 38 39#include "SDL_hints.h" 40#include "SDL_timer.h" 41#include "SDL_syswm.h" 42#include "SDL_assert.h" 43 44#include <stdio.h> 45 46/*#define DEBUG_XEVENTS*/ 47 48#ifndef _NET_WM_MOVERESIZE_SIZE_TOPLEFT 49#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 50#endif 51 52#ifndef _NET_WM_MOVERESIZE_SIZE_TOP 53#define _NET_WM_MOVERESIZE_SIZE_TOP 1 54#endif 55 56#ifndef _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 57#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 58#endif 59 60#ifndef _NET_WM_MOVERESIZE_SIZE_RIGHT 61#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 62#endif 63 64#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 65#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 66#endif 67 68#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOM 69#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 70#endif 71 72#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 73#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 74#endif 75 76#ifndef _NET_WM_MOVERESIZE_SIZE_LEFT 77#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 78#endif 79 80#ifndef _NET_WM_MOVERESIZE_MOVE 81#define _NET_WM_MOVERESIZE_MOVE 8 82#endif 83 84typedef struct { 85 unsigned char *data; 86 int format, count; 87 Atom type; 88} SDL_x11Prop; 89 90/* Reads property 91 Must call X11_XFree on results 92 */ 93static void X11_ReadProperty(SDL_x11Prop *p, Display *disp, Window w, Atom prop) 94{ 95 unsigned char *ret=NULL; 96 Atom type; 97 int fmt; 98 unsigned long count; 99 unsigned long bytes_left; 100 int bytes_fetch = 0; 101 102 do { 103 if (ret != 0) X11_XFree(ret); 104 X11_XGetWindowProperty(disp, w, prop, 0, bytes_fetch, False, AnyPropertyType, &type, &fmt, &count, &bytes_left, &ret); 105 bytes_fetch += bytes_left; 106 } while (bytes_left != 0); 107 108 p->data=ret; 109 p->format=fmt; 110 p->count=count; 111 p->type=type; 112} 113 114/* Find text-uri-list in a list of targets and return it's atom 115 if available, else return None */ 116static Atom X11_PickTarget(Display *disp, Atom list[], int list_count) 117{ 118 Atom request = None; 119 char *name; 120 int i; 121 for (i=0; i < list_count && request == None; i++) { 122 name = X11_XGetAtomName(disp, list[i]); 123 if ((SDL_strcmp("text/uri-list", name) == 0) || (SDL_strcmp("text/plain", name) == 0)) { 124 request = list[i]; 125 } 126 X11_XFree(name); 127 } 128 return request; 129} 130 131/* Wrapper for X11_PickTarget for a maximum of three targets, a special 132 case in the Xdnd protocol */ 133static Atom X11_PickTargetFromAtoms(Display *disp, Atom a0, Atom a1, Atom a2) 134{ 135 int count=0; 136 Atom atom[3]; 137 if (a0 != None) atom[count++] = a0; 138 if (a1 != None) atom[count++] = a1; 139 if (a2 != None) atom[count++] = a2; 140 return X11_PickTarget(disp, atom, count); 141} 142 143struct KeyRepeatCheckData 144{ 145 XEvent *event; 146 SDL_bool found; 147}; 148 149static Bool X11_KeyRepeatCheckIfEvent(Display *display, XEvent *chkev, 150 XPointer arg) 151{ 152 struct KeyRepeatCheckData *d = (struct KeyRepeatCheckData *) arg; 153 if (chkev->type == KeyPress && 154 chkev->xkey.keycode == d->event->xkey.keycode && 155 chkev->xkey.time - d->event->xkey.time < 2) 156 d->found = SDL_TRUE; 157 return False; 158} 159 160/* Check to see if this is a repeated key. 161 (idea shamelessly lifted from GII -- thanks guys! :) 162 */ 163static SDL_bool X11_KeyRepeat(Display *display, XEvent *event) 164{ 165 XEvent dummyev; 166 struct KeyRepeatCheckData d; 167 d.event = event; 168 d.found = SDL_FALSE; 169 if (X11_XPending(display)) 170 X11_XCheckIfEvent(display, &dummyev, X11_KeyRepeatCheckIfEvent, 171 (XPointer) &d); 172 return d.found; 173} 174 175static SDL_bool 176X11_IsWheelEvent(Display * display,XEvent * event,int * xticks,int * yticks) 177{ 178 /* according to the xlib docs, no specific mouse wheel events exist. 179 However, the defacto standard is that the vertical wheel is X buttons 180 4 (up) and 5 (down) and a horizontal wheel is 6 (left) and 7 (right). */ 181 182 /* Xlib defines "Button1" through 5, so we just use literals here. */ 183 switch (event->xbutton.button) { 184 case 4: *yticks = 1; return SDL_TRUE; 185 case 5: *yticks = -1; return SDL_TRUE; 186 case 6: *xticks = 1; return SDL_TRUE; 187 case 7: *xticks = -1; return SDL_TRUE; 188 default: break; 189 } 190 return SDL_FALSE; 191} 192 193/* Decodes URI escape sequences in string buf of len bytes 194 (excluding the terminating NULL byte) in-place. Since 195 URI-encoded characters take three times the space of 196 normal characters, this should not be an issue. 197 198 Returns the number of decoded bytes that wound up in 199 the buffer, excluding the terminating NULL byte. 200 201 The buffer is guaranteed to be NULL-terminated but 202 may contain embedded NULL bytes. 203 204 On error, -1 is returned. 205 */ 206static int X11_URIDecode(char *buf, int len) { 207 int ri, wi, di; 208 char decode = '\0'; 209 if (buf == NULL || len < 0) { 210 errno = EINVAL; 211 return -1; 212 } 213 if (len == 0) { 214 len = SDL_strlen(buf); 215 } 216 for (ri = 0, wi = 0, di = 0; ri < len && wi < len; ri += 1) { 217 if (di == 0) { 218 /* start decoding */ 219 if (buf[ri] == '%') { 220 decode = '\0'; 221 di += 1; 222 continue; 223 } 224 /* normal write */ 225 buf[wi] = buf[ri]; 226 wi += 1; 227 continue; 228 } else if (di == 1 || di == 2) { 229 char off = '\0'; 230 char isa = buf[ri] >= 'a' && buf[ri] <= 'f'; 231 char isA = buf[ri] >= 'A' && buf[ri] <= 'F'; 232 char isn = buf[ri] >= '0' && buf[ri] <= '9'; 233 if (!(isa || isA || isn)) { 234 /* not a hexadecimal */ 235 int sri; 236 for (sri = ri - di; sri <= ri; sri += 1) { 237 buf[wi] = buf[sri]; 238 wi += 1; 239 } 240 di = 0; 241 continue; 242 } 243 /* itsy bitsy magicsy */ 244 if (isn) { 245 off = 0 - '0'; 246 } else if (isa) { 247 off = 10 - 'a'; 248 } else if (isA) { 249 off = 10 - 'A'; 250 } 251 decode |= (buf[ri] + off) << (2 - di) * 4; 252 if (di == 2) { 253 buf[wi] = decode; 254 wi += 1; 255 di = 0; 256 } else { 257 di += 1; 258 } 259 continue; 260 } 261 } 262 buf[wi] = '\0'; 263 return wi; 264} 265 266/* Convert URI to local filename 267 return filename if possible, else NULL 268*/ 269static char* X11_URIToLocal(char* uri) { 270 char *file = NULL; 271 SDL_bool local; 272 273 if (memcmp(uri,"file:/",6) == 0) uri += 6; /* local file? */ 274 else if (strstr(uri,":/") != NULL) return file; /* wrong scheme */ 275 276 local = uri[0] != '/' || (uri[0] != '\0' && uri[1] == '/'); 277 278 /* got a hostname? */ 279 if (!local && uri[0] == '/' && uri[2] != '/') { 280 char* hostname_end = strchr(uri+1, '/'); 281 if (hostname_end != NULL) { 282 char hostname[ 257 ]; 283 if (gethostname(hostname, 255) == 0) { 284 hostname[ 256 ] = '\0'; 285 if (memcmp(uri+1, hostname, hostname_end - (uri+1)) == 0) { 286 uri = hostname_end + 1; 287 local = SDL_TRUE; 288 } 289 } 290 } 291 } 292 if (local) { 293 file = uri; 294 /* Convert URI escape sequences to real characters */ 295 X11_URIDecode(file, 0); 296 if (uri[1] == '/') { 297 file++; 298 } else { 299 file--; 300 } 301 } 302 return file; 303} 304 305#if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 306static void X11_HandleGenericEvent(SDL_VideoData *videodata, XEvent *xev) 307{ 308 /* event is a union, so cookie == &event, but this is type safe. */ 309 XGenericEventCookie *cookie = &xev->xcookie; 310 if (X11_XGetEventData(videodata->display, cookie)) { 311 X11_HandleXinput2Event(videodata, cookie); 312 X11_XFreeEventData(videodata->display, cookie); 313 } 314} 315#endif /* SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS */ 316 317static unsigned 318X11_GetNumLockModifierMask(_THIS) 319{ 320 SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; 321 Display *display = viddata->display; 322 unsigned num_mask = 0; 323 int i, j; 324 XModifierKeymap *xmods; 325 unsigned n; 326 327 xmods = X11_XGetModifierMapping(display); 328 n = xmods->max_keypermod; 329 for(i = 3; i < 8; i++) { 330 for(j = 0; j < n; j++) { 331 KeyCode kc = xmods->modifiermap[i * n + j]; 332 if (viddata->key_layout[kc] == SDL_SCANCODE_NUMLOCKCLEAR) { 333 num_mask = 1 << i; 334 break; 335 } 336 } 337 } 338 X11_XFreeModifiermap(xmods); 339 340 return num_mask; 341} 342 343static void 344X11_ReconcileKeyboardState(_THIS) 345{ 346 SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; 347 Display *display = viddata->display; 348 char keys[32]; 349 int keycode; 350 Window junk_window; 351 int x, y; 352 unsigned int mask; 353 const Uint8 *keyboardState; 354 355 X11_XQueryKeymap(display, keys); 356 357 /* Sync up the keyboard modifier state */ 358 if (X11_XQueryPointer(display, DefaultRootWindow(display), &junk_window, &junk_window, &x, &y, &x, &y, &mask)) { 359 SDL_ToggleModState(KMOD_CAPS, (mask & LockMask) != 0); 360 SDL_ToggleModState(KMOD_NUM, (mask & X11_GetNumLockModifierMask(_this)) != 0); 361 } 362 363 keyboardState = SDL_GetKeyboardState(0); 364 for (keycode = 0; keycode < 256; ++keycode) { 365 SDL_Scancode scancode = viddata->key_layout[keycode]; 366 SDL_bool x11KeyPressed = (keys[keycode / 8] & (1 << (keycode % 8))) != 0; 367 SDL_bool sdlKeyPressed = keyboardState[scancode] == SDL_PRESSED; 368 369 if (x11KeyPressed && !sdlKeyPressed) { 370 SDL_SendKeyboardKey(SDL_PRESSED, scancode); 371 } else if (!x11KeyPressed && sdlKeyPressed) { 372 SDL_SendKeyboardKey(SDL_RELEASED, scancode); 373 } 374 } 375} 376 377 378static void 379X11_DispatchFocusIn(_THIS, SDL_WindowData *data) 380{ 381#ifdef DEBUG_XEVENTS 382 printf("window %p: Dispatching FocusIn\n", data); 383#endif 384 SDL_SetKeyboardFocus(data->window); 385 X11_ReconcileKeyboardState(_this); 386#ifdef X_HAVE_UTF8_STRING 387 if (data->ic) { 388 X11_XSetICFocus(data->ic); 389 } 390#endif 391#ifdef SDL_USE_IME 392 SDL_IME_SetFocus(SDL_TRUE); 393#endif 394} 395 396static void 397X11_DispatchFocusOut(_THIS, SDL_WindowData *data) 398{ 399#ifdef DEBUG_XEVENTS 400 printf("window %p: Dispatching FocusOut\n", data); 401#endif 402 /* If another window has already processed a focus in, then don't try to 403 * remove focus here. Doing so will incorrectly remove focus from that 404 * window, and the focus lost event for this window will have already 405 * been dispatched anyway. */ 406 if (data->window == SDL_GetKeyboardFocus()) { 407 SDL_SetKeyboardFocus(NULL); 408 } 409#ifdef X_HAVE_UTF8_STRING 410 if (data->ic) { 411 X11_XUnsetICFocus(data->ic); 412 } 413#endif 414#ifdef SDL_USE_IME 415 SDL_IME_SetFocus(SDL_FALSE); 416#endif 417} 418 419static void 420X11_DispatchMapNotify(SDL_WindowData *data) 421{ 422 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0); 423 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESTORED, 0, 0); 424} 425 426static void 427X11_DispatchUnmapNotify(SDL_WindowData *data) 428{ 429 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0); 430 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0); 431} 432 433static void 434InitiateWindowMove(_THIS, const SDL_WindowData *data, const SDL_Point *point) 435{ 436 SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; 437 SDL_Window* window = data->window; 438 Display *display = viddata->display; 439 XEvent evt; 440 441 /* !!! FIXME: we need to regrab this if necessary when the drag is done. */ 442 X11_XUngrabPointer(display, 0L); 443 X11_XFlush(display); 444 445 evt.xclient.type = ClientMessage; 446 evt.xclient.window = data->xwindow; 447 evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True); 448 evt.xclient.format = 32; 449 evt.xclient.data.l[0] = window->x + point->x; 450 evt.xclient.data.l[1] = window->y + point->y; 451 evt.xclient.data.l[2] = _NET_WM_MOVERESIZE_MOVE; 452 evt.xclient.data.l[3] = Button1; 453 evt.xclient.data.l[4] = 0; 454 X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt); 455 456 X11_XSync(display, 0); 457} 458 459static void 460InitiateWindowResize(_THIS, const SDL_WindowData *data, const SDL_Point *point, int direction) 461{ 462 SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; 463 SDL_Window* window = data->window; 464 Display *display = viddata->display; 465 XEvent evt; 466 467 if (direction < _NET_WM_MOVERESIZE_SIZE_TOPLEFT || direction > _NET_WM_MOVERESIZE_SIZE_LEFT) 468 return; 469 470 /* !!! FIXME: we need to regrab this if necessary when the drag is done. */ 471 X11_XUngrabPointer(display, 0L); 472 X11_XFlush(display); 473 474 evt.xclient.type = ClientMessage; 475 evt.xclient.window = data->xwindow; 476 evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True); 477 evt.xclient.format = 32; 478 evt.xclient.data.l[0] = window->x + point->x; 479 evt.xclient.data.l[1] = window->y + point->y; 480 evt.xclient.data.l[2] = direction; 481 evt.xclient.data.l[3] = Button1; 482 evt.xclient.data.l[4] = 0; 483 X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt); 484 485 X11_XSync(display, 0); 486} 487 488static SDL_bool 489ProcessHitTest(_THIS, const SDL_WindowData *data, const XEvent *xev) 490{ 491 SDL_Window *window = data->window; 492 493 if (window->hit_test) { 494 const SDL_Point point = { xev->xbutton.x, xev->xbutton.y }; 495 const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data); 496 static const int directions[] = { 497 _NET_WM_MOVERESIZE_SIZE_TOPLEFT, _NET_WM_MOVERESIZE_SIZE_TOP, 498 _NET_WM_MOVERESIZE_SIZE_TOPRIGHT, _NET_WM_MOVERESIZE_SIZE_RIGHT, 499 _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT, _NET_WM_MOVERESIZE_SIZE_BOTTOM, 500 _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT, _NET_WM_MOVERESIZE_SIZE_LEFT 501 }; 502 503 switch (rc) { 504 case SDL_HITTEST_DRAGGABLE: 505 InitiateWindowMove(_this, data, &point); 506 return SDL_TRUE; 507 508 case SDL_HITTEST_RESIZE_TOPLEFT: 509 case SDL_HITTEST_RESIZE_TOP: 510 case SDL_HITTEST_RESIZE_TOPRIGHT: 511 case SDL_HITTEST_RESIZE_RIGHT: 512 case SDL_HITTEST_RESIZE_BOTTOMRIGHT: 513 case SDL_HITTEST_RESIZE_BOTTOM: 514 case SDL_HITTEST_RESIZE_BOTTOMLEFT: 515 case SDL_HITTEST_RESIZE_LEFT: 516 InitiateWindowResize(_this, data, &point, directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]); 517 return SDL_TRUE; 518 519 default: return SDL_FALSE; 520 } 521 } 522 523 return SDL_FALSE; 524} 525 526static void 527X11_UpdateUserTime(SDL_WindowData *data, const unsigned long latest) 528{ 529 if (latest && (latest != data->user_time)) { 530 SDL_VideoData *videodata = data->videodata; 531 Display *display = videodata->display; 532 X11_XChangeProperty(display, data->xwindow, videodata->_NET_WM_USER_TIME, 533 XA_CARDINAL, 32, PropModeReplace, 534 (const unsigned char *) &latest, 1); 535#ifdef DEBUG_XEVENTS 536 printf("window %p: updating _NET_WM_USER_TIME to %lu\n", data, latest); 537#endif 538 data->user_time = latest; 539 } 540} 541 542static void 543X11_HandleClipboardEvent(_THIS, const XEvent *xevent) 544{ 545 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; 546 Display *display = videodata->display; 547 548 SDL_assert(videodata->clipboard_window != None); 549 SDL_assert(xevent->xany.window == videodata->clipboard_window); 550 551 switch (xevent->type) { 552 /* Copy the selection from our own CUTBUFFER to the requested property */ 553 case SelectionRequest: { 554 const XSelectionRequestEvent *req = &xevent->xselectionrequest; 555 XEvent sevent; 556 int seln_format; 557 unsigned long nbytes; 558 unsigned long overflow; 559 unsigned char *seln_data; 560 561#ifdef DEBUG_XEVENTS 562 printf("window CLIPBOARD: SelectionRequest (requestor = %ld, target = %ld)\n", 563 req->requestor, req->target); 564#endif 565 566 SDL_zero(sevent); 567 sevent.xany.type = SelectionNotify; 568 sevent.xselection.selection = req->selection; 569 sevent.xselection.target = None; 570 sevent.xselection.property = None; /* tell them no by default */ 571 sevent.xselection.requestor = req->requestor; 572 sevent.xselection.time = req->time; 573 574 /* !!! FIXME: We were probably storing this on the root window 575 because an SDL window might go away...? but we don't have to do 576 this now (or ever, really). */ 577 if (X11_XGetWindowProperty(display, DefaultRootWindow(display), 578 X11_GetSDLCutBufferClipboardType(display), 0, INT_MAX/4, False, req->target, 579 &sevent.xselection.target, &seln_format, &nbytes, 580 &overflow, &seln_data) == Success) { 581 /* !!! FIXME: cache atoms */ 582 Atom XA_TARGETS = X11_XInternAtom(display, "TARGETS", 0); 583 if (sevent.xselection.target == req->target) { 584 X11_XChangeProperty(display, req->requestor, req->property, 585 sevent.xselection.target, seln_format, PropModeReplace, 586 seln_data, nbytes); 587 sevent.xselection.property = req->property; 588 } else if (XA_TARGETS == req->target) { 589 Atom SupportedFormats[] = { XA_TARGETS, sevent.xselection.target }; 590 X11_XChangeProperty(display, req->requestor, req->property, 591 XA_ATOM, 32, PropModeReplace, 592 (unsigned char*)SupportedFormats, 593 SDL_arraysize(SupportedFormats)); 594 sevent.xselection.property = req->property; 595 sevent.xselection.target = XA_TARGETS; 596 } 597 X11_XFree(seln_data); 598 } 599 X11_XSendEvent(display, req->requestor, False, 0, &sevent); 600 X11_XSync(display, False); 601 } 602 break; 603 604 case SelectionNotify: { 605#ifdef DEBUG_XEVENTS 606 printf("window CLIPBOARD: SelectionNotify (requestor = %ld, target = %ld)\n", 607 xevent->xselection.requestor, xevent->xselection.target); 608#endif 609 videodata->selection_waiting = SDL_FALSE; 610 } 611 break; 612 613 case SelectionClear: { 614 /* !!! FIXME: cache atoms */ 615 Atom XA_CLIPBOARD = X11_XInternAtom(display, "CLIPBOARD", 0); 616 617#ifdef DEBUG_XEVENTS 618 printf("window CLIPBOARD: SelectionClear (requestor = %ld, target = %ld)\n", 619 xevent->xselection.requestor, xevent->xselection.target); 620#endif 621 622 if (xevent->xselectionclear.selection == XA_PRIMARY || 623 (XA_CLIPBOARD != None && xevent->xselectionclear.selection == XA_CLIPBOARD)) { 624 SDL_SendClipboardUpdate(); 625 } 626 } 627 break; 628 } 629} 630 631 632static void 633X11_DispatchEvent(_THIS) 634{ 635 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; 636 Display *display; 637 SDL_WindowData *data; 638 XEvent xevent; 639 int orig_event_type; 640 KeyCode orig_keycode; 641 XClientMessageEvent m; 642 int i; 643 644 if (!videodata) { 645 return; 646 } 647 display = videodata->display; 648 649 SDL_zero(xevent); /* valgrind fix. --ryan. */ 650 X11_XNextEvent(display, &xevent); 651 652 /* Save the original keycode for dead keys, which are filtered out by 653 the XFilterEvent() call below. 654 */ 655 orig_event_type = xevent.type; 656 if (orig_event_type == KeyPress || orig_event_type == KeyRelease) { 657 orig_keycode = xevent.xkey.keycode; 658 } else { 659 orig_keycode = 0; 660 } 661 662 /* filter events catchs XIM events and sends them to the correct handler */ 663 if (X11_XFilterEvent(&xevent, None) == True) { 664#if 0 665 printf("Filtered event type = %d display = %d window = %d\n", 666 xevent.type, xevent.xany.display, xevent.xany.window); 667#endif 668 /* Make sure dead key press/release events are sent */ 669 /* But only if we're using one of the DBus IMEs, otherwise 670 some XIM IMEs will generate duplicate events */ 671 if (orig_keycode) { 672#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H) 673 SDL_Scancode scancode = videodata->key_layout[orig_keycode]; 674 videodata->filter_code = orig_keycode; 675 videodata->filter_time = xevent.xkey.time; 676 677 if (orig_event_type == KeyPress) { 678 SDL_SendKeyboardKey(SDL_PRESSED, scancode); 679 } else { 680 SDL_SendKeyboardKey(SDL_RELEASED, scancode); 681 } 682#endif 683 } 684 return; 685 } 686 687 /* Send a SDL_SYSWMEVENT if the application wants them */ 688 if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) { 689 SDL_SysWMmsg wmmsg; 690 691 SDL_VERSION(&wmmsg.version); 692 wmmsg.subsystem = SDL_SYSWM_X11; 693 wmmsg.msg.x11.event = xevent; 694 SDL_SendSysWMEvent(&wmmsg); 695 } 696 697#if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 698 if(xevent.type == GenericEvent) { 699 X11_HandleGenericEvent(videodata, &xevent); 700 return; 701 } 702#endif 703 704#if 0 705 printf("type = %d display = %d window = %d\n", 706 xevent.type, xevent.xany.display, xevent.xany.window); 707#endif 708 709 if ((videodata->clipboard_window != None) && 710 (videodata->clipboard_window == xevent.xany.window)) { 711 X11_HandleClipboardEvent(_this, &xevent); 712 return; 713 } 714 715 data = NULL; 716 if (videodata && videodata->windowlist) { 717 for (i = 0; i < videodata->numwindows; ++i) { 718 if ((videodata->windowlist[i] != NULL) && 719 (videodata->windowlist[i]->xwindow == xevent.xany.window)) { 720 data = videodata->windowlist[i]; 721 break; 722 } 723 } 724 } 725 if (!data) { 726 /* The window for KeymapNotify, etc events is 0 */ 727 if (xevent.type == KeymapNotify) { 728 if (SDL_GetKeyboardFocus() != NULL) { 729 X11_ReconcileKeyboardState(_this); 730 } 731 } else if (xevent.type == MappingNotify) { 732 /* Has the keyboard layout changed? */ 733 const int request = xevent.xmapping.request; 734 735#ifdef DEBUG_XEVENTS 736 printf("window %p: MappingNotify!\n", data); 737#endif 738 if ((request == MappingKeyboard) || (request == MappingModifier)) { 739 X11_XRefreshKeyboardMapping(&xevent.xmapping); 740 } 741 742 X11_UpdateKeymap(_this); 743 SDL_SendKeymapChangedEvent(); 744 } 745 return; 746 } 747 748 switch (xevent.type) { 749 750 /* Gaining mouse coverage? */ 751 case EnterNotify:{ 752 SDL_Mouse *mouse = SDL_GetMouse(); 753#ifdef DEBUG_XEVENTS 754 printf("window %p: EnterNotify! (%d,%d,%d)\n", data, 755 xevent.xcrossing.x, 756 xevent.xcrossing.y, 757 xevent.xcrossing.mode); 758 if (xevent.xcrossing.mode == NotifyGrab) 759 printf("Mode: NotifyGrab\n"); 760 if (xevent.xcrossing.mode == NotifyUngrab) 761 printf("Mode: NotifyUngrab\n"); 762#endif 763 SDL_SetMouseFocus(data->window); 764 765 mouse->last_x = xevent.xcrossing.x; 766 mouse->last_y = xevent.xcrossing.y; 767 768 if (!mouse->relative_mode) { 769 SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y); 770 } 771 } 772 break; 773 /* Losing mouse coverage? */ 774 case LeaveNotify:{ 775#ifdef DEBUG_XEVENTS 776 printf("window %p: LeaveNotify! (%d,%d,%d)\n", data, 777 xevent.xcrossing.x, 778 xevent.xcrossing.y, 779 xevent.xcrossing.mode); 780 if (xevent.xcrossing.mode == NotifyGrab) 781 printf("Mode: NotifyGrab\n"); 782 if (xevent.xcrossing.mode == NotifyUngrab) 783 printf("Mode: NotifyUngrab\n"); 784#endif 785 if (!SDL_GetMouse()->relative_mode) { 786 SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y); 787 } 788 789 if (xevent.xcrossing.mode != NotifyGrab && 790 xevent.xcrossing.mode != NotifyUngrab && 791 xevent.xcrossing.detail != NotifyInferior) { 792 SDL_SetMouseFocus(NULL); 793 } 794 } 795 break; 796 797 /* Gaining input focus? */ 798 case FocusIn:{ 799 if (xevent.xfocus.mode == NotifyGrab || xevent.xfocus.mode == NotifyUngrab) { 800 /* Someone is handling a global hotkey, ignore it */ 801#ifdef DEBUG_XEVENTS 802 printf("window %p: FocusIn (NotifyGrab/NotifyUngrab, ignoring)\n", data); 803#endif 804 break; 805 } 806 807 if (xevent.xfocus.detail == NotifyInferior) { 808#ifdef DEBUG_XEVENTS 809 printf("window %p: FocusIn (NotifierInferior, ignoring)\n", data); 810#endif 811 break; 812 } 813#ifdef DEBUG_XEVENTS 814 printf("window %p: FocusIn!\n", data); 815#endif 816 if (!videodata->last_mode_change_deadline) /* no recent mode changes */ 817 { 818 data->pending_focus = PENDING_FOCUS_NONE; 819 data->pending_focus_time = 0; 820 X11_DispatchFocusIn(_this, data); 821 } 822 else 823 { 824 data->pending_focus = PENDING_FOCUS_IN; 825 data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_TIME; 826 } 827 data->last_focus_event_time = SDL_GetTicks(); 828 } 829 break; 830 831 /* Losing input focus? */ 832 case FocusOut:{ 833 if (xevent.xfocus.mode == NotifyGrab || xevent.xfocus.mode == NotifyUngrab) { 834 /* Someone is handling a global hotkey, ignore it */ 835#ifdef DEBUG_XEVENTS 836 printf("window %p: FocusOut (NotifyGrab/NotifyUngrab, ignoring)\n", data); 837#endif 838 break; 839 } 840 if (xevent.xfocus.detail == NotifyInferior) { 841 /* We still have focus if a child gets focus */ 842#ifdef DEBUG_XEVENTS 843 printf("window %p: FocusOut (NotifierInferior, ignoring)\n", data); 844#endif 845 break; 846 } 847#ifdef DEBUG_XEVENTS 848 printf("window %p: FocusOut!\n", data); 849#endif 850 if (!videodata->last_mode_change_deadline) /* no recent mode changes */ 851 { 852 data->pending_focus = PENDING_FOCUS_NONE; 853 data->pending_focus_time = 0; 854 X11_DispatchFocusOut(_this, data); 855 } 856 else 857 { 858 data->pending_focus = PENDING_FOCUS_OUT; 859 data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_TIME; 860 } 861 } 862 break; 863 864 /* Key press? */ 865 case KeyPress:{ 866 KeyCode keycode = xevent.xkey.keycode; 867 KeySym keysym = NoSymbol; 868 char text[SDL_TEXTINPUTEVENT_TEXT_SIZE]; 869 Status status = 0; 870 SDL_bool handled_by_ime = SDL_FALSE; 871 872#ifdef DEBUG_XEVENTS 873 printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode); 874#endif 875#if 1 876 if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) { 877 int min_keycode, max_keycode; 878 X11_XDisplayKeycodes(display, &min_keycode, &max_keycode); 879 keysym = X11_KeyCodeToSym(_this, keycode, xevent.xkey.state >> 13); 880 fprintf(stderr, 881 "The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL forums/mailing list <https://discourse.libsdl.org/> X11 KeyCode %d (%d), X11 KeySym 0x%lX (%s).\n", 882 keycode, keycode - min_keycode, keysym, 883 X11_XKeysymToString(keysym)); 884 } 885#endif 886 /* */ 887 SDL_zero(text); 888#ifdef X_HAVE_UTF8_STRING 889 if (data->ic) { 890 X11_Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text), 891 &keysym, &status); 892 } else { 893 X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL); 894 } 895#else 896 X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL); 897#endif 898 899#ifdef SDL_USE_IME 900 if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ 901 handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode); 902 } 903#endif 904 if (!handled_by_ime) { 905 /* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */ 906 if (xevent.xkey.keycode != videodata->filter_code || xevent.xkey.time != videodata->filter_time) { 907 SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]); 908 } 909 if(*text) { 910 SDL_SendKeyboardText(text); 911 } 912 } 913 914 X11_UpdateUserTime(data, xevent.xkey.time); 915 } 916 break; 917 918 /* Key release? */ 919 case KeyRelease:{ 920 KeyCode keycode = xevent.xkey.keycode; 921 922#ifdef DEBUG_XEVENTS 923 printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode); 924#endif 925 if (X11_KeyRepeat(display, &xevent)) { 926 /* We're about to get a repeated key down, ignore the key up */ 927 break; 928 } 929 SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]); 930 } 931 break; 932 933 /* Have we been iconified? */ 934 case UnmapNotify:{ 935#ifdef DEBUG_XEVENTS 936 printf("window %p: UnmapNotify!\n", data); 937#endif 938 X11_DispatchUnmapNotify(data); 939 } 940 break; 941 942 /* Have we been restored? */ 943 case MapNotify:{ 944#ifdef DEBUG_XEVENTS 945 printf("window %p: MapNotify!\n", data); 946#endif 947 X11_DispatchMapNotify(data); 948 } 949 break; 950 951 /* Have we been resized or moved? */ 952 case ConfigureNotify:{ 953#ifdef DEBUG_XEVENTS 954 printf("window %p: ConfigureNotify! (position: %d,%d, size: %dx%d)\n", data, 955 xevent.xconfigure.x, xevent.xconfigure.y, 956 xevent.xconfigure.width, xevent.xconfigure.height); 957#endif 958 /* Real configure notify events are relative to the parent, synthetic events are absolute. */ 959 if (!xevent.xconfigure.send_event) { 960 unsigned int NumChildren; 961 Window ChildReturn, Root, Parent; 962 Window * Children; 963 /* Translate these coodinates back to relative to root */ 964 X11_XQueryTree(data->videodata->display, xevent.xconfigure.window, &Root, &Parent, &Children, &NumChildren); 965 X11_XTranslateCoordinates(xevent.xconfigure.display, 966 Parent, DefaultRootWindow(xevent.xconfigure.display), 967 xevent.xconfigure.x, xevent.xconfigure.y, 968 &xevent.xconfigure.x, &xevent.xconfigure.y, 969 &ChildReturn); 970 } 971 972 if (xevent.xconfigure.x != data->last_xconfigure.x || 973 xevent.xconfigure.y != data->last_xconfigure.y) { 974 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, 975 xevent.xconfigure.x, xevent.xconfigure.y); 976#ifdef SDL_USE_IME 977 if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ 978 /* Update IME candidate list position */ 979 SDL_IME_UpdateTextRect(NULL); 980 } 981#endif 982 } 983 if (xevent.xconfigure.width != data->last_xconfigure.width || 984 xevent.xconfigure.height != data->last_xconfigure.height) { 985 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, 986 xevent.xconfigure.width, 987 xevent.xconfigure.height); 988 } 989 data->last_xconfigure = xevent.xconfigure; 990 } 991 break; 992 993 /* Have we been requested to quit (or another client message?) */ 994 case ClientMessage:{ 995 996 static int xdnd_version=0; 997 998 if (xevent.xclient.message_type == videodata->XdndEnter) { 999 1000 SDL_bool use_list = xevent.xclient.data.l[1] & 1; 1001 data->xdnd_source = xevent.xclient.data.l[0]; 1002 xdnd_version = (xevent.xclient.data.l[1] >> 24); 1003#ifdef DEBUG_XEVENTS 1004 printf("XID of source window : %ld\n", data->xdnd_source); 1005 printf("Protocol version to use : %d\n", xdnd_version); 1006 printf("More then 3 data types : %d\n", (int) use_list); 1007#endif 1008 1009 if (use_list) { 1010 /* fetch conversion targets */ 1011 SDL_x11Prop p; 1012 X11_ReadProperty(&p, display, data->xdnd_source, videodata->XdndTypeList); 1013 /* pick one */ 1014 data->xdnd_req = X11_PickTarget(display, (Atom*)p.data, p.count); 1015 X11_XFree(p.data); 1016 } else { 1017 /* pick from list of three */ 1018 data->xdnd_req = X11_PickTargetFromAtoms(display, xevent.xclient.data.l[2], xevent.xclient.data.l[3], xevent.xclient.data.l[4]); 1019 } 1020 } 1021 else if (xevent.xclient.message_type == videodata->XdndPosition) { 1022 1023#ifdef DEBUG_XEVENTS 1024 Atom act= videodata->XdndActionCopy; 1025 if(xdnd_version >= 2) { 1026 act = xevent.xclient.data.l[4]; 1027 } 1028 printf("Action requested by user is : %s\n", X11_XGetAtomName(display , act)); 1029#endif 1030 1031 1032 /* reply with status */ 1033 memset(&m, 0, sizeof(XClientMessageEvent)); 1034 m.type = ClientMessage; 1035 m.display = xevent.xclient.display; 1036 m.window = xevent.xclient.data.l[0]; 1037 m.message_type = videodata->XdndStatus; 1038 m.format=32; 1039 m.data.l[0] = data->xwindow; 1040 m.data.l[1] = (data->xdnd_req != None); 1041 m.data.l[2] = 0; /* specify an empty rectangle */ 1042 m.data.l[3] = 0; 1043 m.data.l[4] = videodata->XdndActionCopy; /* we only accept copying anyway */ 1044 1045 X11_XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m); 1046 X11_XFlush(display); 1047 } 1048 else if(xevent.xclient.message_type == videodata->XdndDrop) { 1049 if (data->xdnd_req == None) { 1050 /* say again - not interested! */ 1051 memset(&m, 0, sizeof(XClientMessageEvent)); 1052 m.type = ClientMessage; 1053 m.display = xevent.xclient.display; 1054 m.window = xevent.xclient.data.l[0]; 1055 m.message_type = videodata->XdndFinished; 1056 m.format=32; 1057 m.data.l[0] = data->xwindow; 1058 m.data.l[1] = 0; 1059 m.data.l[2] = None; /* fail! */ 1060 X11_XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m); 1061 } else { 1062 /* convert */ 1063 if(xdnd_version >= 1) { 1064 X11_XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, xevent.xclient.data.l[2]); 1065 } else { 1066 X11_XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, CurrentTime); 1067 } 1068 } 1069 } 1070 else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) && 1071 (xevent.xclient.format == 32) && 1072 (xevent.xclient.data.l[0] == videodata->_NET_WM_PING)) { 1073 Window root = DefaultRootWindow(display); 1074 1075#ifdef DEBUG_XEVENTS 1076 printf("window %p: _NET_WM_PING\n", data); 1077#endif 1078 xevent.xclient.window = root; 1079 X11_XSendEvent(display, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &xevent); 1080 break; 1081 } 1082 1083 else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) && 1084 (xevent.xclient.format == 32) && 1085 (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) { 1086 1087#ifdef DEBUG_XEVENTS 1088 printf("window %p: WM_DELETE_WINDOW\n", data); 1089#endif 1090 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0); 1091 break; 1092 } 1093 else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) && 1094 (xevent.xclient.format == 32) && 1095 (xevent.xclient.data.l[0] == videodata->WM_TAKE_FOCUS)) { 1096 1097#ifdef DEBUG_XEVENTS 1098 printf("window %p: WM_TAKE_FOCUS\n", data); 1099#endif 1100 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_TAKE_FOCUS, 0, 0); 1101 break; 1102 } 1103 } 1104 break; 1105 1106 /* Do we need to refresh ourselves? */ 1107 case Expose:{ 1108#ifdef DEBUG_XEVENTS 1109 printf("window %p: Expose (count = %d)\n", data, xevent.xexpose.count); 1110#endif 1111 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0); 1112 } 1113 break; 1114 1115 case MotionNotify:{ 1116 SDL_Mouse *mouse = SDL_GetMouse(); 1117 if(!mouse->relative_mode || mouse->relative_mode_warp) { 1118#ifdef DEBUG_MOTION 1119 printf("window %p: X11 motion: %d,%d\n", data, xevent.xmotion.x, xevent.xmotion.y); 1120#endif 1121 1122 SDL_SendMouseMotion(data->window, 0, 0, xevent.xmotion.x, xevent.xmotion.y); 1123 } 1124 } 1125 break; 1126 1127 case ButtonPress:{ 1128 int xticks = 0, yticks = 0; 1129#ifdef DEBUG_XEVENTS 1130 printf("window %p: ButtonPress (X11 button = %d)\n", data, xevent.xbutton.button); 1131#endif 1132 if (X11_IsWheelEvent(display,&xevent,&xticks, &yticks)) { 1133 SDL_SendMouseWheel(data->window, 0, (float) xticks, (float) yticks, SDL_MOUSEWHEEL_NORMAL); 1134 } else { 1135 SDL_bool ignore_click = SDL_FALSE; 1136 int button = xevent.xbutton.button; 1137 if(button == Button1) { 1138 if (ProcessHitTest(_this, data, &xevent)) { 1139 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0); 1140 break; /* don't pass this event on to app. */ 1141 } 1142 } 1143 else if(button > 7) { 1144 /* X button values 4-7 are used for scrolling, so X1 is 8, X2 is 9, ... 1145 => subtract (8-SDL_BUTTON_X1) to get value SDL expects */ 1146 button -= (8-SDL_BUTTON_X1); 1147 } 1148 if (data->last_focus_event_time) { 1149 const int X11_FOCUS_CLICK_TIMEOUT = 10; 1150 if (!SDL_TICKS_PASSED(SDL_GetTicks(), data->last_focus_event_time + X11_FOCUS_CLICK_TIMEOUT)) { 1151 ignore_click = !SDL_GetHintBoolean(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, SDL_FALSE); 1152 } 1153 data->last_focus_event_time = 0; 1154 } 1155 if (!ignore_click) { 1156 SDL_SendMouseButton(data->window, 0, SDL_PRESSED, button); 1157 } 1158 } 1159 X11_UpdateUserTime(data, xevent.xbutton.time); 1160 } 1161 break; 1162 1163 case ButtonRelease:{ 1164 int button = xevent.xbutton.button; 1165 /* The X server sends a Release event for each Press for wheels. Ignore them. */ 1166 int xticks = 0, yticks = 0; 1167#ifdef DEBUG_XEVENTS 1168 printf("window %p: ButtonRelease (X11 button = %d)\n", data, xevent.xbutton.button); 1169#endif 1170 if (!X11_IsWheelEvent(display, &xevent, &xticks, &yticks)) { 1171 if (button > 7) { 1172 /* see explanation at case ButtonPress */ 1173 button -= (8-SDL_BUTTON_X1); 1174 } 1175 SDL_SendMouseButton(data->window, 0, SDL_RELEASED, button); 1176 } 1177 } 1178 break; 1179 1180 case PropertyNotify:{ 1181#ifdef DEBUG_XEVENTS 1182 unsigned char *propdata; 1183 int status, real_format; 1184 Atom real_type; 1185 unsigned long items_read, items_left; 1186 1187 char *name = X11_XGetAtomName(display, xevent.xproperty.atom); 1188 if (name) { 1189 printf("window %p: PropertyNotify: %s %s time=%lu\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed", xevent.xproperty.time); 1190 X11_XFree(name); 1191 } 1192 1193 status = X11_XGetWindowProperty(display, data->xwindow, xevent.xproperty.atom, 0L, 8192L, False, AnyPropertyType, &real_type, &real_format, &items_read, &items_left, &propdata); 1194 if (status == Success && items_read > 0) { 1195 if (real_type == XA_INTEGER) { 1196 int *values = (int *)propdata; 1197 1198 printf("{"); 1199 for (i = 0; i < items_read; i++) { 1200 printf(" %d", values[i]); 1201 } 1202 printf(" }\n"); 1203 } else if (real_type == XA_CARDINAL) { 1204 if (real_format == 32) { 1205 Uint32 *values = (Uint32 *)propdata; 1206 1207 printf("{"); 1208 for (i = 0; i < items_read; i++) { 1209 printf(" %d", values[i]); 1210 } 1211 printf(" }\n"); 1212 } else if (real_format == 16) { 1213 Uint16 *values = (Uint16 *)propdata; 1214 1215 printf("{"); 1216 for (i = 0; i < items_read; i++) { 1217 printf(" %d", values[i]); 1218 } 1219 printf(" }\n"); 1220 } else if (real_format == 8) { 1221 Uint8 *values = (Uint8 *)propdata; 1222 1223 printf("{"); 1224 for (i = 0; i < items_read; i++) { 1225 printf(" %d", values[i]); 1226 } 1227 printf(" }\n"); 1228 } 1229 } else if (real_type == XA_STRING || 1230 real_type == videodata->UTF8_STRING) { 1231 printf("{ \"%s\" }\n", propdata); 1232 } else if (real_type == XA_ATOM) { 1233 Atom *atoms = (Atom *)propdata; 1234 1235 printf("{"); 1236 for (i = 0; i < items_read; i++) { 1237 char *atomname = X11_XGetAtomName(display, atoms[i]); 1238 if (atomname) { 1239 printf(" %s", atomname); 1240 X11_XFree(atomname); 1241 } 1242 } 1243 printf(" }\n"); 1244 } else { 1245 char *atomname = X11_XGetAtomName(display, real_type); 1246 printf("Unknown type: %ld (%s)\n", real_type, atomname ? atomname : "UNKNOWN"); 1247 if (atomname) { 1248 X11_XFree(atomname); 1249 } 1250 } 1251 } 1252 if (status == Success) { 1253 X11_XFree(propdata); 1254 } 1255#endif /* DEBUG_XEVENTS */ 1256 1257 /* Take advantage of this moment to make sure user_time has a 1258 valid timestamp from the X server, so if we later try to 1259 raise/restore this window, _NET_ACTIVE_WINDOW can have a 1260 non-zero timestamp, even if there's never been a mouse or 1261 key press to this window so far. Note that we don't try to 1262 set _NET_WM_USER_TIME here, though. That's only for legit 1263 user interaction with the window. */ 1264 if (!data->user_time) { 1265 data->user_time = xevent.xproperty.time; 1266 } 1267 1268 if (xevent.xproperty.atom == data->videodata->_NET_WM_STATE) { 1269 /* Get the new state from the window manager. 1270 Compositing window managers can alter visibility of windows 1271 without ever mapping / unmapping them, so we handle that here, 1272 because they use the NETWM protocol to notify us of changes. 1273 */ 1274 const Uint32 flags = X11_GetNetWMState(_this, xevent.xproperty.window); 1275 const Uint32 changed = flags ^ data->window->flags; 1276 1277 if ((changed & SDL_WINDOW_HIDDEN) || (changed & SDL_WINDOW_FULLSCREEN)) { 1278 if (flags & SDL_WINDOW_HIDDEN) { 1279 X11_DispatchUnmapNotify(data); 1280 } else { 1281 X11_DispatchMapNotify(data); 1282 } 1283 } 1284 1285 if (changed & SDL_WINDOW_MAXIMIZED) { 1286 if (flags & SDL_WINDOW_MAXIMIZED) { 1287 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0); 1288 } else { 1289 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESTORED, 0, 0); 1290 } 1291 } 1292 } else if (xevent.xproperty.atom == videodata->XKLAVIER_STATE) { 1293 /* Hack for Ubuntu 12.04 (etc) that doesn't send MappingNotify 1294 events when the keyboard layout changes (for example, 1295 changing from English to French on the menubar's keyboard 1296 icon). Since it changes the XKLAVIER_STATE property, we 1297 notice and reinit our keymap here. This might not be the 1298 right approach, but it seems to work. */ 1299 X11_UpdateKeymap(_this); 1300 SDL_SendKeymapChangedEvent(); 1301 } else if (xevent.xproperty.atom == videodata->_NET_FRAME_EXTENTS) { 1302 Atom type; 1303 int format; 1304 unsigned long nitems, bytes_after; 1305 unsigned char *property; 1306 if (X11_XGetWindowProperty(display, data->xwindow, videodata->_NET_FRAME_EXTENTS, 0, 16, 0, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &property) == Success) { 1307 if (type != None && nitems == 4) { 1308 data->border_left = (int) ((long*)property)[0]; 1309 data->border_right = (int) ((long*)property)[1]; 1310 data->border_top = (int) ((long*)property)[2]; 1311 data->border_bottom = (int) ((long*)property)[3]; 1312 } 1313 X11_XFree(property); 1314 1315 #ifdef DEBUG_XEVENTS 1316 printf("New _NET_FRAME_EXTENTS: left=%d right=%d, top=%d, bottom=%d\n", data->border_left, data->border_right, data->border_top, data->border_bottom); 1317 #endif 1318 } 1319 } 1320 } 1321 break; 1322 1323 case SelectionNotify: { 1324 Atom target = xevent.xselection.target; 1325#ifdef DEBUG_XEVENTS 1326 printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data, 1327 xevent.xselection.requestor, xevent.xselection.target); 1328#endif 1329 if (target == data->xdnd_req) { 1330 /* read data */ 1331 SDL_x11Prop p; 1332 X11_ReadProperty(&p, display, data->xwindow, videodata->PRIMARY); 1333 1334 if (p.format == 8) { 1335 /* !!! FIXME: don't use strtok here. It's not reentrant and not in SDL_stdinc. */ 1336 char* name = X11_XGetAtomName(display, target); 1337 char *token = strtok((char *) p.data, "\r\n"); 1338 while (token != NULL) { 1339 if (SDL_strcmp("text/plain", name)==0) { 1340 SDL_SendDropText(data->window, token); 1341 } else if (SDL_strcmp("text/uri-list", name)==0) { 1342 char *fn = X11_URIToLocal(token); 1343 if (fn) { 1344 SDL_SendDropFile(data->window, fn); 1345 } 1346 } 1347 token = strtok(NULL, "\r\n"); 1348 } 1349 SDL_SendDropComplete(data->window); 1350 } 1351 X11_XFree(p.data); 1352 1353 /* send reply */ 1354 SDL_memset(&m, 0, sizeof(XClientMessageEvent)); 1355 m.type = ClientMessage; 1356 m.display = display; 1357 m.window = data->xdnd_source; 1358 m.message_type = videodata->XdndFinished; 1359 m.format = 32; 1360 m.data.l[0] = data->xwindow; 1361 m.data.l[1] = 1; 1362 m.data.l[2] = videodata->XdndActionCopy; 1363 X11_XSendEvent(display, data->xdnd_source, False, NoEventMask, (XEvent*)&m); 1364 1365 X11_XSync(display, False); 1366 } 1367 } 1368 break; 1369 1370 default:{ 1371#ifdef DEBUG_XEVENTS 1372 printf("window %p: Unhandled event %d\n", data, xevent.type); 1373#endif 1374 } 1375 break; 1376 } 1377} 1378 1379static void 1380X11_HandleFocusChanges(_THIS) 1381{ 1382 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; 1383 int i; 1384 1385 if (videodata && videodata->windowlist) { 1386 for (i = 0; i < videodata->numwindows; ++i) { 1387 SDL_WindowData *data = videodata->windowlist[i]; 1388 if (data && data->pending_focus != PENDING_FOCUS_NONE) { 1389 Uint32 now = SDL_GetTicks(); 1390 if (SDL_TICKS_PASSED(now, data->pending_focus_time)) { 1391 if (data->pending_focus == PENDING_FOCUS_IN) { 1392 X11_DispatchFocusIn(_this, data); 1393 } else { 1394 X11_DispatchFocusOut(_this, data); 1395 } 1396 data->pending_focus = PENDING_FOCUS_NONE; 1397 } 1398 } 1399 } 1400 } 1401} 1402/* Ack! X11_XPending() actually performs a blocking read if no events available */ 1403static int 1404X11_Pending(Display * display) 1405{ 1406 /* Flush the display connection and look to see if events are queued */ 1407 X11_XFlush(display); 1408 if (X11_XEventsQueued(display, QueuedAlready)) { 1409 return (1); 1410 } 1411 1412 /* More drastic measures are required -- see if X is ready to talk */ 1413 if (SDL_IOReady(ConnectionNumber(display), SDL_FALSE, 0)) { 1414 return (X11_XPending(display)); 1415 } 1416 1417 /* Oh well, nothing is ready .. */ 1418 return (0); 1419} 1420 1421void 1422X11_PumpEvents(_THIS) 1423{ 1424 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 1425 1426 if (data->last_mode_change_deadline) { 1427 if (SDL_TICKS_PASSED(SDL_GetTicks(), data->last_mode_change_deadline)) { 1428 data->last_mode_change_deadline = 0; /* assume we're done. */ 1429 } 1430 } 1431 1432 /* Update activity every 30 seconds to prevent screensaver */ 1433 if (_this->suspend_screensaver) { 1434 const Uint32 now = SDL_GetTicks(); 1435 if (!data->screensaver_activity || 1436 SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) { 1437 X11_XResetScreenSaver(data->display); 1438 1439#if SDL_USE_LIBDBUS 1440 SDL_DBus_ScreensaverTickle(); 1441#endif 1442 1443 data->screensaver_activity = now; 1444 } 1445 } 1446 1447 /* Keep processing pending events */ 1448 while (X11_Pending(data->display)) { 1449 X11_DispatchEvent(_this); 1450 } 1451 1452#ifdef SDL_USE_IME 1453 if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ 1454 SDL_IME_PumpEvents(); 1455 } 1456#endif 1457 1458 /* FIXME: Only need to do this when there are pending focus changes */ 1459 X11_HandleFocusChanges(_this); 1460} 1461 1462 1463void 1464X11_SuspendScreenSaver(_THIS) 1465{ 1466#if SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1467 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 1468 int dummy; 1469 int major_version, minor_version; 1470#endif /* SDL_VIDEO_DRIVER_X11_XSCRNSAVER */ 1471 1472#if SDL_USE_LIBDBUS 1473 if (SDL_DBus_ScreensaverInhibit(_this->suspend_screensaver)) { 1474 return; 1475 } 1476 1477 if (_this->suspend_screensaver) { 1478 SDL_DBus_ScreensaverTickle(); 1479 } 1480#endif 1481 1482#if SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1483 if (SDL_X11_HAVE_XSS) { 1484 /* X11_XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */ 1485 if (!X11_XScreenSaverQueryExtension(data->display, &dummy, &dummy) || 1486 !X11_XScreenSaverQueryVersion(data->display, 1487 &major_version, &minor_version) || 1488 major_version < 1 || (major_version == 1 && minor_version < 1)) { 1489 return; 1490 } 1491 1492 X11_XScreenSaverSuspend(data->display, _this->suspend_screensaver); 1493 X11_XResetScreenSaver(data->display); 1494 } 1495#endif 1496} 1497 1498#endif /* SDL_VIDEO_DRIVER_X11 */ 1499 1500/* vi: set ts=4 sw=4 expandtab: */ 1501
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.