From 7af650abc98227da9869d8d8c4f84e4dba369d1b Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Tue, 28 Feb 2023 13:47:47 -0500
Subject: [PATCH] X11: Implement the popup window changes
---
src/video/x11/SDL_x11events.c | 21 ++++++-
src/video/x11/SDL_x11sym.h | 3 +
src/video/x11/SDL_x11window.c | 101 ++++++++++++++++++++++++++++++----
src/video/x11/SDL_x11window.h | 5 ++
4 files changed, 119 insertions(+), 11 deletions(-)
diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c
index 99014a863797..1a78a409223f 100644
--- a/src/video/x11/SDL_x11events.c
+++ b/src/video/x11/SDL_x11events.c
@@ -753,6 +753,14 @@ static int XLookupStringAsUTF8(XKeyEvent *event_struct, char *buffer_return, int
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 @@ static void X11_DispatchEvent(_THIS, XEvent *xevent)
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 d160eae034af..45630dd469e5 100644
--- a/src/video/x11/SDL_x11sym.h
+++ b/src/video/x11/SDL_x11sym.h
@@ -155,6 +155,9 @@ SDL_X11_SYM(void,XRefreshKeyboardMapping,(XMappingEvent *a),(a),)
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 ca94ae86065d..bc962a970e42 100644
--- a/src/video/x11/SDL_x11window.c
+++ b/src/video/x11/SDL_x11window.c
@@ -166,6 +166,36 @@ void X11_SetNetWMState(_THIS, Window xwindow, Uint32 flags)
}
}
+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 @@ static int SetupWindowData(_THIS, SDL_Window *window, Window w, BOOL created)
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 @@ int X11_CreateWindow(_THIS, SDL_Window *window)
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 @@ int X11_CreateWindow(_THIS, SDL_Window *window)
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 @@ int X11_CreateWindow(_THIS, SDL_Window *window)
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 @@ int X11_CreateWindow(_THIS, SDL_Window *window)
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 @@ int X11_CreateWindow(_THIS, SDL_Window *window)
}
#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 @@ int X11_SetWindowIcon(_THIS, SDL_Window *window, SDL_Surface *icon)
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 @@ void X11_SetWindowPosition(_THIS, SDL_Window *window)
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 @@ void X11_SetWindowPosition(_THIS, SDL_Window *window)
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 @@ void X11_SetWindowPosition(_THIS, SDL_Window *window)
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 fe1321849f55..f2c41a782063 100644
--- a/src/video/x11/SDL_x11window.h
+++ b/src/video/x11/SDL_x11window.h
@@ -59,6 +59,10 @@ struct SDL_WindowData
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 void X11_AcceptDragAndDrop(SDL_Window *window, SDL_bool accept);
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_ */