diff --git a/include/SDL_video.h b/include/SDL_video.h index 7d52e6a51..4a2fb0458 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -800,7 +800,14 @@ typedef enum { SDL_HITTEST_NORMAL, /**< Region is normal. No special properties. */ SDL_HITTEST_DRAGGABLE, /**< Region can drag entire window. */ - /* !!! FIXME: resize enums here. */ + SDL_HITTEST_RESIZE_TOPLEFT, + SDL_HITTEST_RESIZE_TOP, + SDL_HITTEST_RESIZE_TOPRIGHT, + SDL_HITTEST_RESIZE_RIGHT, + SDL_HITTEST_RESIZE_BOTTOMRIGHT, + SDL_HITTEST_RESIZE_BOTTOM, + SDL_HITTEST_RESIZE_BOTTOMLEFT, + SDL_HITTEST_RESIZE_LEFT } SDL_HitTestResult; /** diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 45b6083c1..0e788b523 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -40,8 +40,40 @@ #include +#ifndef _NET_WM_MOVERESIZE_SIZE_TOPLEFT +#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 +#endif + +#ifndef _NET_WM_MOVERESIZE_SIZE_TOP +#define _NET_WM_MOVERESIZE_SIZE_TOP 1 +#endif + +#ifndef _NET_WM_MOVERESIZE_SIZE_TOPRIGHT +#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 +#endif + +#ifndef _NET_WM_MOVERESIZE_SIZE_RIGHT +#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 +#endif + +#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 +#endif + +#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOM +#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 +#endif + +#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 +#endif + +#ifndef _NET_WM_MOVERESIZE_SIZE_LEFT +#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 +#endif + #ifndef _NET_WM_MOVERESIZE_MOVE -#define _NET_WM_MOVERESIZE_MOVE 8 +#define _NET_WM_MOVERESIZE_MOVE 8 #endif typedef struct { @@ -290,7 +322,7 @@ InitiateWindowMove(_THIS, const SDL_WindowData *data, const SDL_Point *point) XEvent evt; evt.xclient.type = ClientMessage; evt.xclient.window = data->xwindow; - evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", False); + evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True); evt.xclient.format = 32; evt.xclient.data.l[0] = window->x + point->x; evt.xclient.data.l[1] = window->y + point->y; @@ -302,21 +334,96 @@ InitiateWindowMove(_THIS, const SDL_WindowData *data, const SDL_Point *point) X11_XSync(display, 0); } +static void +InitiateWindowResize(_THIS, const SDL_WindowData *data, const SDL_Point *point, int direction) +{ + SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + SDL_Window* window = data->window; + Display *display = viddata->display; + + if (direction < _NET_WM_MOVERESIZE_SIZE_TOPLEFT || direction > _NET_WM_MOVERESIZE_SIZE_LEFT) + return; + + /* !!! FIXME: we need to regrab this if necessary when the drag is done. */ + X11_XUngrabPointer(display, 0L); + X11_XFlush(display); + + XEvent evt; + evt.xclient.type = ClientMessage; + evt.xclient.window = data->xwindow; + evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True); + evt.xclient.format = 32; + evt.xclient.data.l[0] = window->x + point->x; + evt.xclient.data.l[1] = window->y + point->y; + evt.xclient.data.l[2] = direction; + evt.xclient.data.l[3] = Button1; + evt.xclient.data.l[4] = 0; + X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt); + + X11_XSync(display, 0); +} + static SDL_bool ProcessHitTest(_THIS, const SDL_WindowData *data, const XEvent *xev) { SDL_Window *window = data->window; + SDL_bool ret = SDL_FALSE; if (window->hit_test) { const SDL_Point point = { xev->xbutton.x, xev->xbutton.y }; const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data); - if (rc == SDL_HITTEST_DRAGGABLE) { - InitiateWindowMove(_this, data, &point); - return SDL_TRUE; /* dragging, drop this event. */ + switch (rc) { + case SDL_HITTEST_DRAGGABLE: { + InitiateWindowMove(_this, data, &point); + ret = SDL_TRUE; + } + break; + case SDL_HITTEST_RESIZE_TOPLEFT: { + InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOPLEFT); + ret = SDL_TRUE; + } + break; + case SDL_HITTEST_RESIZE_TOP: { + InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOP); + ret = SDL_TRUE; + } + break; + case SDL_HITTEST_RESIZE_TOPRIGHT: { + InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOPRIGHT); + ret = SDL_TRUE; + } + break; + case SDL_HITTEST_RESIZE_RIGHT: { + InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_RIGHT); + ret = SDL_TRUE; + } + break; + case SDL_HITTEST_RESIZE_BOTTOMRIGHT: { + InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT); + ret = SDL_TRUE; + } + break; + case SDL_HITTEST_RESIZE_BOTTOM: { + InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOM); + ret = SDL_TRUE; + } + break; + case SDL_HITTEST_RESIZE_BOTTOMLEFT: { + InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT); + ret = SDL_TRUE; + } + break; + case SDL_HITTEST_RESIZE_LEFT: { + InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_LEFT); + ret = SDL_TRUE; + } + break; + default: + break; } } - return SDL_FALSE; /* not a drag area. */ + return ret; } static void diff --git a/test/testhittesting.c b/test/testhittesting.c index f6ae4ee70..5f2f274d4 100644 --- a/test/testhittesting.c +++ b/test/testhittesting.c @@ -3,6 +3,8 @@ /* !!! FIXME: rewrite this to be wired in to test framework. */ +#define RESIZE_BORDER 20 + const SDL_Rect drag_areas[] = { { 20, 20, 100, 100 }, { 200, 70, 100, 100 }, @@ -16,6 +18,8 @@ static SDL_HitTestResult hitTest(SDL_Window *window, const SDL_Point *pt, void *data) { int i; + int w, h; + for (i = 0; i < numareas; i++) { if (SDL_PointInRect(pt, &areas[i])) { SDL_Log("HIT-TEST: DRAGGABLE\n"); @@ -23,6 +27,24 @@ hitTest(SDL_Window *window, const SDL_Point *pt, void *data) } } + SDL_GetWindowSize(window, &w, &h); + if (pt->x < RESIZE_BORDER && pt->y < RESIZE_BORDER) + return SDL_HITTEST_RESIZE_TOPLEFT; + if (pt->x > RESIZE_BORDER && pt->x < w - RESIZE_BORDER && pt->y < RESIZE_BORDER) + return SDL_HITTEST_RESIZE_TOP; + if (pt->x > w - RESIZE_BORDER && pt->y < RESIZE_BORDER) + return SDL_HITTEST_RESIZE_TOPRIGHT; + if (pt->x > w - RESIZE_BORDER && pt->y > RESIZE_BORDER && pt->y < h - RESIZE_BORDER) + return SDL_HITTEST_RESIZE_RIGHT; + if (pt->x > w - RESIZE_BORDER && pt->y > h - RESIZE_BORDER) + return SDL_HITTEST_RESIZE_BOTTOMRIGHT; + if (pt->x < w - RESIZE_BORDER && pt->x > RESIZE_BORDER && pt->y > h - RESIZE_BORDER) + return SDL_HITTEST_RESIZE_BOTTOM; + if (pt->x < RESIZE_BORDER && pt->y > h - RESIZE_BORDER) + return SDL_HITTEST_RESIZE_BOTTOMLEFT; + if (pt->x < RESIZE_BORDER && pt->y < h - RESIZE_BORDER && pt->y > RESIZE_BORDER) + return SDL_HITTEST_RESIZE_LEFT; + SDL_Log("HIT-TEST: NORMAL\n"); return SDL_HITTEST_NORMAL; } @@ -36,7 +58,7 @@ int main(int argc, char **argv) /* !!! FIXME: check for errors. */ SDL_Init(SDL_INIT_VIDEO); - window = SDL_CreateWindow("Drag the red boxes", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_BORDERLESS); + window = SDL_CreateWindow("Drag the red boxes", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE); renderer = SDL_CreateRenderer(window, -1, 0); if (SDL_SetWindowHitTest(window, hitTest, NULL) == -1) {