X11: Implement the popup window changes
diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 99014a8..1a78a40 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c
@@ -753,6 +753,14 @@ return result; } +static void X11_TransformPosition(SDL_Window *window, int *pos_x, int *pos_y) +{ + if (SDL_WINDOW_IS_POPUP(window)) { + *pos_x -= window->parent->driverdata->abs_x; + *pos_y -= window->parent->driverdata->abs_y; + } +} + static void X11_DispatchEvent(_THIS, XEvent *xevent) { SDL_VideoData *videodata = _this->driverdata; @@ -1167,14 +1175,25 @@ if (xevent->xconfigure.x != data->last_xconfigure.x || xevent->xconfigure.y != data->last_xconfigure.y) { + SDL_Window *w; + int x = xevent->xconfigure.x; + int y = xevent->xconfigure.y; + + data->abs_x = x; + data->abs_y = y; + X11_TransformPosition(data->window, &x, &y); SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MOVED, - xevent->xconfigure.x, xevent->xconfigure.y); + x, y); + #ifdef SDL_USE_IME if (SDL_EventEnabled(SDL_EVENT_TEXT_INPUT)) { /* Update IME candidate list position */ SDL_IME_UpdateTextRect(NULL); } #endif + for (w = data->window->first_child; w != NULL; w = w->next_sibling) { + X11_UpdateWindowPosition(w); + } } if (xevent->xconfigure.width != data->last_xconfigure.width || xevent->xconfigure.height != data->last_xconfigure.height) {
diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h index d160eae..45630dd 100644 --- a/src/video/x11/SDL_x11sym.h +++ b/src/video/x11/SDL_x11sym.h
@@ -155,6 +155,9 @@ SDL_X11_SYM(int,XQueryTree,(Display* a,Window b,Window* c,Window* d,Window** e,unsigned int* f),(a,b,c,d,e,f),return) SDL_X11_SYM(Bool,XSupportsLocale,(void),(),return) SDL_X11_SYM(Status,XmbTextListToTextProperty,(Display* a,char** b,int c,XICCEncodingStyle d,XTextProperty* e),(a,b,c,d,e),return) +SDL_X11_SYM(Region,XCreateRegion,(void),(),return) +SDL_X11_SYM(void,XDestroyRegion,(Region),(a),) +SDL_X11_SYM(void,XShapeCombineRegion,(Display *a,Window b,int c,int d,int e,Region f,int g),(a,b,c,d,e,f,g),) #if SDL_VIDEO_DRIVER_X11_XFIXES SDL_X11_MODULE(XFIXES)
diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index ca94ae8..bc962a9 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c
@@ -166,6 +166,36 @@ } } +static void X11_ConstrainPopup(SDL_Window *window, int *offset_x, int *offset_y) +{ + if (SDL_WINDOW_IS_POPUP(window)) { + SDL_Rect bounds; + SDL_Window *w; + const int orig_offset_x = window->driverdata ? window->driverdata->offset_x : window->windowed.x; + const int orig_offset_y = window->driverdata ? window->driverdata->offset_y : window->windowed.y; + const int orig_popup_x = window->parent->driverdata->abs_x + orig_offset_x; + const int orig_popup_y = window->parent->driverdata->abs_y + orig_offset_y; + int popup_x = orig_popup_x; + int popup_y = orig_popup_y; + + /* Find the toplevel parent */ + for(w = window->parent; w->parent != NULL; w = w->parent); + + SDL_GetDisplayBounds(SDL_GetDisplayForWindow(w), &bounds); + if (popup_x + window->w > bounds.x + bounds.w) { + popup_x -= (popup_x + window->w) - (bounds.x + bounds.w); + } + if (popup_y + window->h > bounds.y + bounds.h) { + popup_y -= (popup_y + window->h) - (bounds.y + bounds.h); + } + popup_x = SDL_max(popup_x, bounds.x); + popup_y = SDL_max(popup_y, bounds.y); + + *offset_x = orig_offset_x + (popup_x - orig_popup_x); + *offset_y = orig_offset_y + (popup_y - orig_popup_y); + } +} + Uint32 X11_GetNetWMState(_THIS, SDL_Window *window, Window xwindow) { @@ -302,8 +332,10 @@ XWindowAttributes attrib; X11_XGetWindowAttributes(data->videodata->display, w, &attrib); - window->x = attrib.x; - window->y = attrib.y; + if (!SDL_WINDOW_IS_POPUP(window)) { + window->x = attrib.x; + window->y = attrib.y; + } window->w = attrib.width; window->h = attrib.height; if (attrib.map_state != IsUnmapped) { @@ -392,6 +424,8 @@ Atom _NET_WM_PID; long fevent = 0; const char *hint = NULL; + int x_pos, y_pos; + int popup_offset_x, popup_offset_y; #if SDL_VIDEO_OPENGL_GLX || SDL_VIDEO_OPENGL_EGL const char *forced_visual_id = SDL_GetHint(SDL_HINT_VIDEO_X11_WINDOW_VISUALID); @@ -527,6 +561,15 @@ visual, AllocNone); } + if (!SDL_WINDOW_IS_POPUP(window)) { + x_pos = window->windowed.x; + y_pos = window->windowed.y; + } else { + X11_ConstrainPopup(window, &popup_offset_x, &popup_offset_y); + x_pos = window->parent->driverdata->abs_x + popup_offset_x; + y_pos = window->parent->driverdata->abs_y + popup_offset_y; + } + /* Always create this with the window->windowed.* fields; if we're creating a windowed mode window, that's fine. If we're creating a fullscreen window, the window manager will want to know these values @@ -534,7 +577,7 @@ migration to fullscreen after CreateSDLWindow returns, which will put all the SDL_Window fields and system state as expected. */ w = X11_XCreateWindow(display, RootWindow(display, screen), - window->windowed.x, window->windowed.y, window->windowed.w, window->windowed.h, + x_pos, y_pos, window->windowed.w, window->windowed.h, 0, depth, InputOutput, visual, (CWOverrideRedirect | CWBackPixmap | CWBorderPixel | CWBackingStore | CWColormap), @@ -554,8 +597,8 @@ sizehints->min_height = sizehints->max_height = window->h; sizehints->flags |= (PMaxSize | PMinSize); } - sizehints->x = window->x; - sizehints->y = window->y; + sizehints->x = x_pos; + sizehints->y = y_pos; sizehints->flags |= USPosition; /* Setup the input hints so we get keyboard input */ @@ -667,6 +710,21 @@ } #endif + windowdata->abs_x = x_pos; + windowdata->abs_y = y_pos; + + if (SDL_WINDOW_IS_POPUP(window)) { + windowdata->offset_x = popup_offset_x; + windowdata->offset_y = popup_offset_y; + } + + /* Tooltips do not receive input */ + if (window->flags & SDL_WINDOW_TOOLTIP) { + Region region = X11_XCreateRegion(); + X11_XShapeCombineRegion(display, w, ShapeInput, 0, 0, region, ShapeSet); + X11_XDestroyRegion(region); + } + X11_Xinput2SelectTouch(_this, window); X11_XSelectInput(display, w, @@ -806,8 +864,9 @@ return rc; } -void X11_SetWindowPosition(_THIS, SDL_Window *window) +void X11_UpdateWindowPosition(SDL_Window *window) { + SDL_Window *w; SDL_WindowData *data = window->driverdata; Display *display = data->videodata->display; int (*prev_handler)(Display *, XErrorEvent *) = NULL; @@ -824,8 +883,16 @@ X11_XTranslateCoordinates(display, parent, DefaultRootWindow(display), attrs.x, attrs.y, &orig_x, &orig_y, &childReturn); + if (!SDL_WINDOW_IS_POPUP(window)) { + data->abs_x = window->x - data->border_left; + data->abs_y = window->y - data->border_top; + } else { + data->abs_x = window->parent->driverdata->abs_x + data->offset_x; + data->abs_y = window->parent->driverdata->abs_y + data->offset_y; + } + /*Attempt to move the window*/ - X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top); + X11_XMoveWindow(display, data->xwindow, data->abs_x, data->abs_y); /* Wait a brief time to see if the window manager decided to let this move happen. If the window changes at all, even to an unexpected value, we break out. */ @@ -844,10 +911,10 @@ if (!caught_x11_error) { if ((x != orig_x) || (y != orig_y)) { - window->x = x; - window->y = y; + data->abs_x = x; + data->abs_y = y; break; /* window moved, time to go. */ - } else if ((x == window->x) && (y == window->y)) { + } else if ((x == data->abs_x) && (y == data->abs_y)) { break; /* we're at the place we wanted to be anyhow, drop out. */ } } @@ -861,6 +928,20 @@ X11_XSetErrorHandler(prev_handler); caught_x11_error = SDL_FALSE; + + for (w = window->first_child; w != NULL; w = w->next_sibling) { + X11_UpdateWindowPosition(w); + } +} + +void X11_SetWindowPosition(_THIS, SDL_Window *window) +{ + if (SDL_WINDOW_IS_POPUP(window)) { + window->driverdata->offset_x = window->x; + window->driverdata->offset_y = window->y; + X11_ConstrainPopup(window, &window->driverdata->offset_x, &window->driverdata->offset_y); + } + X11_UpdateWindowPosition(window); } void X11_SetWindowMinimumSize(_THIS, SDL_Window *window)
diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h index fe13218..f2c41a7 100644 --- a/src/video/x11/SDL_x11window.h +++ b/src/video/x11/SDL_x11window.h
@@ -59,6 +59,10 @@ int border_right; int border_top; int border_bottom; + int offset_x; + int offset_y; + int abs_x; + int abs_y; SDL_bool mouse_grabbed; Uint64 last_focus_event_time; PendingFocusEnum pending_focus; @@ -116,5 +120,6 @@ extern int X11_FlashWindow(_THIS, SDL_Window *window, SDL_FlashOperation operation); int SDL_X11_SetWindowTitle(Display *display, Window xwindow, char *title); +void X11_UpdateWindowPosition(SDL_Window *window); #endif /* SDL_x11window_h_ */