From db98e267f04be6ee34cdfbfec940e82d7b21d3e9 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 28 Sep 2012 10:24:28 -0700 Subject: [PATCH 1/7] A few more tweaks for the legacy fullscreen support --- src/video/x11/SDL_x11window.c | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index c4e180366..5fab13684 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -56,14 +56,6 @@ static Bool isConfigureNotify(Display *dpy, XEvent *ev, XPointer win) { return ev->type == ConfigureNotify && ev->xconfigure.window == *((Window*)win); } -static Bool isFocusIn(Display *dpy, XEvent *ev, XPointer win) -{ - return ev->type == FocusIn && ev->xfocus.window == *((Window*)win); -} -static Bool isFocusOut(Display *dpy, XEvent *ev, XPointer win) -{ - return ev->type == FocusOut && ev->xfocus.window == *((Window*)win); -} static SDL_bool X11_IsWindowLegacyFullscreen(_THIS, SDL_Window * window) @@ -1019,10 +1011,12 @@ X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _ XSelectInput(display, data->fswindow, StructureNotifyMask); XSetWindowBackground(display, data->fswindow, 0); + XInstallColormap(display, data->colormap); XClearWindow(display, data->fswindow); XMapRaised(display, data->fswindow); /* Make sure the fswindow is in view by warping mouse to the corner */ + XUngrabPointer(display, CurrentTime); XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y); /* Wait to be mapped, filter Unmap event out if it arrives. */ @@ -1034,7 +1028,6 @@ X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _ XF86VidModeLockModeSwitch(display, screen, True); } #endif - XInstallColormap(display, data->colormap); SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE); @@ -1052,10 +1045,6 @@ X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _ XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow); XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow); - /* Set the input focus because we're about to grab input */ - window->flags |= SDL_WINDOW_INPUT_FOCUS; - SDL_SetKeyboardFocus(data->window); - X11_SetWindowGrab(_this, window); } @@ -1214,9 +1203,9 @@ X11_SetWindowGrab(_THIS, SDL_Window * window) /* ICCCM2.0-compliant window managers can handle fullscreen windows */ oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window); - if (((window->flags & SDL_WINDOW_INPUT_GRABBED) || oldstyle_fullscreen) - && (window->flags & SDL_WINDOW_INPUT_FOCUS)) { - XEvent ev; + if (oldstyle_fullscreen || + ((window->flags & SDL_WINDOW_INPUT_GRABBED) && + (window->flags & SDL_WINDOW_INPUT_FOCUS))) { /* Try to grab the mouse */ for (;;) { @@ -1235,15 +1224,11 @@ X11_SetWindowGrab(_THIS, SDL_Window * window) /* Now grab the keyboard */ XGrabKeyboard(display, data->xwindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); - - /* flush these events so they don't confuse normal event handling */ - XSync(display, False); - XCheckIfEvent(display, &ev, &isFocusIn, (XPointer)&data->xwindow); - XCheckIfEvent(display, &ev, &isFocusOut, (XPointer)&data->xwindow); } else { XUngrabPointer(display, CurrentTime); XUngrabKeyboard(display, CurrentTime); } + XSync(display, False); } void From a41528bc9d9ad834c83830d93a595ab80140fbe1 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 28 Sep 2012 10:54:26 -0700 Subject: [PATCH 2/7] Theoretically fixed the position of the child window, though it's always ending up at the upper left corner for some reason. --- src/video/x11/SDL_x11window.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index 5fab13684..bdce26acf 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -1032,13 +1032,12 @@ X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _ SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE); /* Center actual window within our cover-the-screen window. */ - rect.x += (rect.w - window->w) / 2; - rect.y += (rect.h - window->h) / 2; - XReparentWindow(display, data->xwindow, data->fswindow, rect.x, rect.y); + XReparentWindow(display, data->xwindow, data->fswindow, + (rect.w - window->w) / 2, (rect.h - window->h) / 2); - /* Center mouse in the window. */ - rect.x += (window->w / 2); - rect.y += (window->h / 2); + /* Center mouse in the fullscreen window. */ + rect.x += (rect.w / 2); + rect.y += (rect.h / 2); XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y); /* Wait to be mapped, filter Unmap event out if it arrives. */ From 4232c9019c93594f6b55683de5ccc0708339da7f Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 28 Sep 2012 11:51:16 -0700 Subject: [PATCH 3/7] Fixed detection of display bounds after a mode switch when Xinerama is enabled. --- src/video/x11/SDL_x11modes.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/video/x11/SDL_x11modes.c b/src/video/x11/SDL_x11modes.c index f0c6bc12d..4c82c5dae 100644 --- a/src/video/x11/SDL_x11modes.c +++ b/src/video/x11/SDL_x11modes.c @@ -637,6 +637,16 @@ get_real_resolution(Display * display, SDL_DisplayData * data, int *w, int *h, #if SDL_VIDEO_DRIVER_X11_XINERAMA if (data->use_xinerama) { + int screencount; + XineramaScreenInfo *xinerama; + + /* Update the current screen layout information */ + xinerama = XineramaQueryScreens(display, &screencount); + if (xinerama && data->screen < screencount) { + data->xinerama_info = xinerama[data->screen]; + } + if (xinerama) XFree(xinerama); + *w = data->xinerama_info.width; *h = data->xinerama_info.height; *rate = 0; @@ -789,21 +799,20 @@ X11_QuitModes(_THIS) int X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect) { + Display *display = ((SDL_VideoData *) _this->driverdata)->display; SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata; + int real_rate; + + rect->x = 0; + rect->y = 0; + get_real_resolution(display, data, &rect->w, &rect->h, &real_rate); #if SDL_VIDEO_DRIVER_X11_XINERAMA - if (data && data->use_xinerama) { + if (data->use_xinerama) { rect->x = data->xinerama_info.x_org; rect->y = data->xinerama_info.y_org; - rect->w = data->xinerama_info.width; - rect->h = data->xinerama_info.height; - return 0; } #endif - rect->x = 0; - rect->y = 0; - rect->w = sdl_display->current_mode.w; - rect->h = sdl_display->current_mode.h; return 0; } From c3872b6d5b780e5a45fe5357966a4162d148acfb Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 28 Sep 2012 14:00:43 -0700 Subject: [PATCH 4/7] Don't warn about the window size changing if the window is resizable --- test/common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/common.c b/test/common.c index c09cc2db5..fb6411c36 100644 --- a/test/common.c +++ b/test/common.c @@ -736,7 +736,8 @@ CommonInit(CommonState * state) return SDL_FALSE; } SDL_GetWindowSize(state->windows[i], &w, &h); - if (w != state->window_w || h != state->window_h) { + if (!(state->window_flags & SDL_WINDOW_RESIZABLE) && + (w != state->window_w || h != state->window_h)) { printf("Window requested size %dx%d, got %dx%d\n", state->window_w, state->window_h, w, h); state->window_w = w; state->window_h = h; From 5ea5ff410c88cda7a2adb0f58c26650ef331455e Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 28 Sep 2012 14:01:55 -0700 Subject: [PATCH 5/7] We need to queue the focus in/out changes because they may occur during video mode changes and we can respond to them by triggering more mode changes. --- src/video/x11/SDL_x11events.c | 106 ++++++++++++++++++++++++---------- src/video/x11/SDL_x11window.h | 16 +++++ 2 files changed, 93 insertions(+), 29 deletions(-) diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 8755dcac8..821176333 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -28,6 +28,7 @@ #include #include /* For INT_MAX */ +#include "SDL_x11video.h" #include "SDL_x11video.h" #include "SDL_x11touch.h" #include "SDL_x11xinput2.h" @@ -109,6 +110,34 @@ static void X11_HandleGenericEvent(SDL_VideoData *videodata,XEvent event) #endif /* SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS */ +static void +X11_DispatchFocusIn(SDL_WindowData *data) +{ +#ifdef DEBUG_XEVENTS + printf("window %p: Dispatching FocusIn\n", data); +#endif + SDL_SetKeyboardFocus(data->window); +#ifdef X_HAVE_UTF8_STRING + if (data->ic) { + XSetICFocus(data->ic); + } +#endif +} + +static void +X11_DispatchFocusOut(SDL_WindowData *data) +{ +#ifdef DEBUG_XEVENTS + printf("window %p: Dispatching FocusOut\n", data); +#endif + SDL_SetKeyboardFocus(NULL); +#ifdef X_HAVE_UTF8_STRING + if (data->ic) { + XUnsetICFocus(data->ic); + } +#endif +} + static void X11_DispatchMapNotify(SDL_WindowData *data) { @@ -186,7 +215,7 @@ X11_DispatchEvent(_THIS) /* Gaining mouse coverage? */ case EnterNotify:{ #ifdef DEBUG_XEVENTS - printf("EnterNotify! (%d,%d,%d)\n", + printf("window %p: EnterNotify! (%d,%d,%d)\n", data, xevent.xcrossing.x, xevent.xcrossing.y, xevent.xcrossing.mode); @@ -201,7 +230,7 @@ X11_DispatchEvent(_THIS) /* Losing mouse coverage? */ case LeaveNotify:{ #ifdef DEBUG_XEVENTS - printf("LeaveNotify! (%d,%d,%d)\n", + printf("window %p: LeaveNotify! (%d,%d,%d)\n", data, xevent.xcrossing.x, xevent.xcrossing.y, xevent.xcrossing.mode); @@ -221,35 +250,27 @@ X11_DispatchEvent(_THIS) /* Gaining input focus? */ case FocusIn:{ #ifdef DEBUG_XEVENTS - printf("FocusIn!\n"); -#endif - SDL_SetKeyboardFocus(data->window); -#ifdef X_HAVE_UTF8_STRING - if (data->ic) { - XSetICFocus(data->ic); - } + printf("window %p: FocusIn!\n", data); #endif + data->pending_focus = PENDING_FOCUS_IN; + data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_IN_TIME; } break; /* Losing input focus? */ case FocusOut:{ #ifdef DEBUG_XEVENTS - printf("FocusOut!\n"); -#endif - SDL_SetKeyboardFocus(NULL); -#ifdef X_HAVE_UTF8_STRING - if (data->ic) { - XUnsetICFocus(data->ic); - } + printf("window %p: FocusOut!\n", data); #endif + data->pending_focus = PENDING_FOCUS_OUT; + data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_OUT_TIME; } break; /* Generated upon EnterWindow and FocusIn */ case KeymapNotify:{ #ifdef DEBUG_XEVENTS - printf("KeymapNotify!\n"); + printf("window %p: KeymapNotify!\n", data); #endif /* FIXME: X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector); @@ -260,7 +281,7 @@ X11_DispatchEvent(_THIS) /* Has the keyboard layout changed? */ case MappingNotify:{ #ifdef DEBUG_XEVENTS - printf("MappingNotify!\n"); + printf("window %p: MappingNotify!\n", data); #endif X11_UpdateKeymap(_this); } @@ -274,7 +295,7 @@ X11_DispatchEvent(_THIS) Status status = 0; #ifdef DEBUG_XEVENTS - printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode); + printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode); #endif SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]); #if 1 @@ -313,7 +334,7 @@ X11_DispatchEvent(_THIS) KeyCode keycode = xevent.xkey.keycode; #ifdef DEBUG_XEVENTS - printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode); + printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode); #endif if (X11_KeyRepeat(display, &xevent)) { /* We're about to get a repeated key down, ignore the key up */ @@ -326,7 +347,7 @@ X11_DispatchEvent(_THIS) /* Have we been iconified? */ case UnmapNotify:{ #ifdef DEBUG_XEVENTS - printf("UnmapNotify!\n"); + printf("window %p: UnmapNotify!\n", data); #endif X11_DispatchUnmapNotify(data); } @@ -335,7 +356,7 @@ X11_DispatchEvent(_THIS) /* Have we been restored? */ case MapNotify:{ #ifdef DEBUG_XEVENTS - printf("MapNotify!\n"); + printf("window %p: MapNotify!\n", data); #endif X11_DispatchMapNotify(data); } @@ -344,7 +365,7 @@ X11_DispatchEvent(_THIS) /* Have we been resized or moved? */ case ConfigureNotify:{ #ifdef DEBUG_XEVENTS - printf("ConfigureNotify! (resize: %dx%d)\n", + printf("window %p: ConfigureNotify! (resize: %dx%d)\n", data, xevent.xconfigure.width, xevent.xconfigure.height); #endif SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, @@ -368,7 +389,7 @@ X11_DispatchEvent(_THIS) /* Do we need to refresh ourselves? */ case Expose:{ #ifdef DEBUG_XEVENTS - printf("Expose (count = %d)\n", xevent.xexpose.count); + printf("window %p: Expose (count = %d)\n", data, xevent.xexpose.count); #endif SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0); } @@ -378,7 +399,7 @@ X11_DispatchEvent(_THIS) SDL_Mouse *mouse = SDL_GetMouse(); if(!mouse->relative_mode) { #ifdef DEBUG_MOTION - printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y); + printf("window %p: X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y); #endif SDL_SendMouseMotion(data->window, 0, xevent.xmotion.x, xevent.xmotion.y); @@ -411,7 +432,7 @@ X11_DispatchEvent(_THIS) char *name = XGetAtomName(display, xevent.xproperty.atom); if (name) { - printf("PropertyNotify: %s %s\n", name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed"); + printf("window %p: PropertyNotify: %s %s\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed"); XFree(name); } @@ -508,7 +529,7 @@ X11_DispatchEvent(_THIS) req = &xevent.xselectionrequest; #ifdef DEBUG_XEVENTS - printf("SelectionRequest (requestor = %ld, target = %ld)\n", + printf("window %p: SelectionRequest (requestor = %ld, target = %ld)\n", data, req->requestor, req->target); #endif @@ -538,7 +559,7 @@ X11_DispatchEvent(_THIS) case SelectionNotify: { #ifdef DEBUG_XEVENTS - printf("SelectionNotify (requestor = %ld, target = %ld)\n", + printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data, xevent.xselection.requestor, xevent.xselection.target); #endif videodata->selection_waiting = SDL_FALSE; @@ -547,13 +568,36 @@ X11_DispatchEvent(_THIS) default:{ #ifdef DEBUG_XEVENTS - printf("Unhandled event %d\n", xevent.type); + printf("window %p: Unhandled event %d\n", data, xevent.type); #endif } break; } } +static void +X11_HandleFocusChanges(_THIS) +{ + SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; + int i; + + if (videodata && videodata->windowlist) { + for (i = 0; i < videodata->numwindows; ++i) { + SDL_WindowData *data = videodata->windowlist[i]; + if (data && data->pending_focus != PENDING_FOCUS_NONE) { + Uint32 now = SDL_GetTicks(); + if ( (int)(data->pending_focus_time-now) <= 0 ) { + if ( data->pending_focus == PENDING_FOCUS_IN ) { + X11_DispatchFocusIn(data); + } else { + X11_DispatchFocusOut(data); + } + data->pending_focus = PENDING_FOCUS_NONE; + } + } + } + } +} /* Ack! XPending() actually performs a blocking read if no events available */ static int X11_Pending(Display * display) @@ -606,6 +650,10 @@ X11_PumpEvents(_THIS) while (X11_Pending(data->display)) { X11_DispatchEvent(_this); } + + /* FIXME: Only need to do this when there are pending focus changes */ + X11_HandleFocusChanges(_this); + /*Dont process evtouch events if XInput2 multitouch is supported*/ if(X11_Xinput2IsMultitouchSupported()) { return; diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h index 60c818459..8ff9a4dd7 100644 --- a/src/video/x11/SDL_x11window.h +++ b/src/video/x11/SDL_x11window.h @@ -23,6 +23,20 @@ #ifndef _SDL_x11window_h #define _SDL_x11window_h +/* We need to queue the focus in/out changes because they may occur during + video mode changes and we can respond to them by triggering more mode + changes. +*/ +#define PENDING_FOCUS_IN_TIME 200 +#define PENDING_FOCUS_OUT_TIME 200 + +typedef enum +{ + PENDING_FOCUS_NONE, + PENDING_FOCUS_IN, + PENDING_FOCUS_OUT +} PendingFocusEnum; + typedef struct { SDL_Window *window; @@ -39,6 +53,8 @@ typedef struct GC gc; XIC ic; SDL_bool created; + PendingFocusEnum pending_focus; + Uint32 pending_focus_time; struct SDL_VideoData *videodata; } SDL_WindowData; From 633433e0bf133706d6531550eb5f370dd31526ba Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 28 Sep 2012 14:21:15 -0700 Subject: [PATCH 6/7] Print the bounds of each display when showing mode information --- test/common.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/common.c b/test/common.c index fb6411c36..fbe256432 100644 --- a/test/common.c +++ b/test/common.c @@ -617,6 +617,7 @@ CommonInit(CommonState * state) } if (state->verbose & VERBOSE_MODES) { + SDL_Rect bounds; SDL_DisplayMode mode; int bpp; Uint32 Rmask, Gmask, Bmask, Amask; @@ -626,6 +627,10 @@ CommonInit(CommonState * state) for (i = 0; i < n; ++i) { fprintf(stderr, "Display %d:\n", i); + SDL_zero(bounds); + SDL_GetDisplayBounds(i, &bounds); + fprintf(stderr, "Bounds: %dx%d at %d,%d\n", bounds.w, bounds.h, bounds.x, bounds.y); + SDL_GetDesktopDisplayMode(i, &mode); SDL_PixelFormatEnumToMasks(mode.format, &bpp, &Rmask, &Gmask, &Bmask, &Amask); From bbbe1abd41de8a81c3bfdd323f4f95eae503d29c Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 28 Sep 2012 14:22:18 -0700 Subject: [PATCH 7/7] Get the correct screen bounds from xinerama --- src/video/x11/SDL_x11modes.c | 5 +++-- src/video/x11/SDL_x11modes.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/video/x11/SDL_x11modes.c b/src/video/x11/SDL_x11modes.c index 4c82c5dae..795fcc4f7 100644 --- a/src/video/x11/SDL_x11modes.c +++ b/src/video/x11/SDL_x11modes.c @@ -217,6 +217,7 @@ X11_InitModes(_THIS) displaydata->screen = 0; displaydata->use_xinerama = xinerama_major * 100 + xinerama_minor; displaydata->xinerama_info = xinerama[screen]; + displaydata->xinerama_screen = screen; } else displaydata->screen = screen; #else @@ -642,8 +643,8 @@ get_real_resolution(Display * display, SDL_DisplayData * data, int *w, int *h, /* Update the current screen layout information */ xinerama = XineramaQueryScreens(display, &screencount); - if (xinerama && data->screen < screencount) { - data->xinerama_info = xinerama[data->screen]; + if (xinerama && data->xinerama_screen < screencount) { + data->xinerama_info = xinerama[data->xinerama_screen]; } if (xinerama) XFree(xinerama); diff --git a/src/video/x11/SDL_x11modes.h b/src/video/x11/SDL_x11modes.h index 89d470d48..feb8b911d 100644 --- a/src/video/x11/SDL_x11modes.h +++ b/src/video/x11/SDL_x11modes.h @@ -36,6 +36,7 @@ typedef struct #if SDL_VIDEO_DRIVER_X11_XINERAMA XineramaScreenInfo xinerama_info; + int xinerama_screen; #endif #if SDL_VIDEO_DRIVER_X11_XRANDR XRRScreenConfiguration *screen_config;