New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for resizing undecorated window #990

Open
felselva opened this Issue Apr 7, 2017 · 4 comments

Comments

Projects
None yet
2 participants
@felselva
Contributor

felselva commented Apr 7, 2017

I'm opening this issue for myself, related to #923.

The same way it's possible to start a drag operation of an undecorated window, it's also possible to start a resize operation. This feature might have some particularities in some platforms, as Wayland is still in development and Cocoa doesn't allow some of these operations (or they are slightly different).

I have in mind something like this:

glfwResizeWindow(GLFWwindow *window, int border);

where border could be any of the values bellow:

GLFW_WINDOW_LEFT
GLFW_WINDOW_TOP
GLFW_WINDOW_RIGHT
GLFW_WINDOW_BOTTOM
GLFW_WINDOW_LEFT_TOP
GLFW_WINDOW_RIGHT_TOP
GLFW_WINDOW_LEFT_BOTTOM
GLFW_WINDOW_RIGHT_BOTTOM

Opinions?

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 8, 2017

Contributor

I made the X11 implementation on my fork: https://github.com/felipefs/glfw/tree/window-resize

Here's the internal X11 implementation:

void _glfwPlatformResizeWindow(_GLFWwindow* window, int border)
{
    int winXpos, winYpos;
    double curXpos, curYpos;
    XClientMessageEvent xclient;
    memset(&xclient, 0, sizeof(XClientMessageEvent));
    XUngrabPointer(_glfw.x11.display, 0);
    XFlush(_glfw.x11.display);
    _glfwPlatformGetCursorPos(window, &curXpos, &curYpos);
    _glfwPlatformGetWindowPos(window, &winXpos, &winYpos);
    xclient.type = ClientMessage;
    xclient.window = window->x11.handle;
    xclient.message_type = XInternAtom(_glfw.x11.display, "_NET_WM_MOVERESIZE", False);
    xclient.format = 32;
    xclient.data.l[0] = winXpos + curXpos;
    xclient.data.l[1] = winYpos + curYpos;
    switch (border)
    {
        case GLFW_WINDOW_LEFT:
            xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_LEFT;
            break;
        case GLFW_WINDOW_TOP:
            xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_TOP;
            break;
        case GLFW_WINDOW_RIGHT:
            xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_RIGHT;
            break;
        case GLFW_WINDOW_BOTTOM:
            xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
            break;
        case GLFW_WINDOW_TOPLEFT:
            xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
            break;
        case GLFW_WINDOW_TOPRIGHT:
            xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
            break;
        case GLFW_WINDOW_BOTTOMLEFT:
            xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
            break;
        case GLFW_WINDOW_BOTTOMRIGHT:
            xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
    }
    xclient.data.l[3] = 0;
    xclient.data.l[4] = 0;
    XSendEvent(_glfw.x11.display, _glfw.x11.root, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient);
}
Contributor

felselva commented Apr 8, 2017

I made the X11 implementation on my fork: https://github.com/felipefs/glfw/tree/window-resize

Here's the internal X11 implementation:

void _glfwPlatformResizeWindow(_GLFWwindow* window, int border)
{
    int winXpos, winYpos;
    double curXpos, curYpos;
    XClientMessageEvent xclient;
    memset(&xclient, 0, sizeof(XClientMessageEvent));
    XUngrabPointer(_glfw.x11.display, 0);
    XFlush(_glfw.x11.display);
    _glfwPlatformGetCursorPos(window, &curXpos, &curYpos);
    _glfwPlatformGetWindowPos(window, &winXpos, &winYpos);
    xclient.type = ClientMessage;
    xclient.window = window->x11.handle;
    xclient.message_type = XInternAtom(_glfw.x11.display, "_NET_WM_MOVERESIZE", False);
    xclient.format = 32;
    xclient.data.l[0] = winXpos + curXpos;
    xclient.data.l[1] = winYpos + curYpos;
    switch (border)
    {
        case GLFW_WINDOW_LEFT:
            xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_LEFT;
            break;
        case GLFW_WINDOW_TOP:
            xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_TOP;
            break;
        case GLFW_WINDOW_RIGHT:
            xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_RIGHT;
            break;
        case GLFW_WINDOW_BOTTOM:
            xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
            break;
        case GLFW_WINDOW_TOPLEFT:
            xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
            break;
        case GLFW_WINDOW_TOPRIGHT:
            xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
            break;
        case GLFW_WINDOW_BOTTOMLEFT:
            xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
            break;
        case GLFW_WINDOW_BOTTOMRIGHT:
            xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
    }
    xclient.data.l[3] = 0;
    xclient.data.l[4] = 0;
    XSendEvent(_glfw.x11.display, _glfw.x11.root, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient);
}
@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 8, 2017

Contributor

The implementation for Windows is finished:

void _glfwPlatformResizeWindow(_GLFWwindow* window, int border)
{
    WPARAM wBorder;
    switch (border)
    {
        case GLFW_WINDOW_LEFT:
            wBorder = HTLEFT;
            break;
        case GLFW_WINDOW_TOP:
            wBorder = HTTOP;
            break;
        case GLFW_WINDOW_RIGHT:
            wBorder = HTRIGHT;
            break;
        case GLFW_WINDOW_BOTTOM:
            wBorder = HTBOTTOM;
            break;
        case GLFW_WINDOW_TOPLEFT:
            wBorder = HTTOPLEFT;
            break;
        case GLFW_WINDOW_TOPRIGHT:
            wBorder = HTTOPRIGHT;
            break;
        case GLFW_WINDOW_BOTTOMLEFT:
            wBorder = HTBOTTOMLEFT;
            break;
        case GLFW_WINDOW_BOTTOMRIGHT:
            wBorder = HTBOTTOMRIGHT;
    }
    ReleaseCapture();
    SendMessage(window->win32.handle, WM_NCLBUTTONDOWN, wBorder, 0);
}

Tested on Linux, using Wine.

Contributor

felselva commented Apr 8, 2017

The implementation for Windows is finished:

void _glfwPlatformResizeWindow(_GLFWwindow* window, int border)
{
    WPARAM wBorder;
    switch (border)
    {
        case GLFW_WINDOW_LEFT:
            wBorder = HTLEFT;
            break;
        case GLFW_WINDOW_TOP:
            wBorder = HTTOP;
            break;
        case GLFW_WINDOW_RIGHT:
            wBorder = HTRIGHT;
            break;
        case GLFW_WINDOW_BOTTOM:
            wBorder = HTBOTTOM;
            break;
        case GLFW_WINDOW_TOPLEFT:
            wBorder = HTTOPLEFT;
            break;
        case GLFW_WINDOW_TOPRIGHT:
            wBorder = HTTOPRIGHT;
            break;
        case GLFW_WINDOW_BOTTOMLEFT:
            wBorder = HTBOTTOMLEFT;
            break;
        case GLFW_WINDOW_BOTTOMRIGHT:
            wBorder = HTBOTTOMRIGHT;
    }
    ReleaseCapture();
    SendMessage(window->win32.handle, WM_NCLBUTTONDOWN, wBorder, 0);
}

Tested on Linux, using Wine.

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 8, 2017

Contributor

I've made the Wayland implementation, but for some reason (just like wl_shell_surface_move on #923), wl_shell_surface_resize function doesn't work (Solved):

void _glfwPlatformResizeWindow(_GLFWwindow* window, int border)
{
    int wlBorder;
    switch (border)
    {
        case GLFW_WINDOW_LEFT:
            wlBorder = WL_SHELL_SURFACE_RESIZE_LEFT;
            break;
        case GLFW_WINDOW_TOP:
            wlBorder = WL_SHELL_SURFACE_RESIZE_TOP;
            break;
        case GLFW_WINDOW_RIGHT:
            wlBorder = WL_SHELL_SURFACE_RESIZE_RIGHT;
            break;
        case GLFW_WINDOW_BOTTOM:
            wlBorder = WL_SHELL_SURFACE_RESIZE_BOTTOM;
            break;
        case GLFW_WINDOW_TOPLEFT:
            wlBorder = WL_SHELL_SURFACE_RESIZE_TOP_LEFT;
            break;
        case GLFW_WINDOW_TOPRIGHT:
            wlBorder = WL_SHELL_SURFACE_RESIZE_TOP_RIGHT;
            break;
        case GLFW_WINDOW_BOTTOMLEFT:
            wlBorder = WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT;
            break;
        case GLFW_WINDOW_BOTTOMRIGHT:
            wlBorder = WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT;
    }
    wl_shell_surface_resize(window->wl.shellSurface,
                            _glfw.wl.seat,
                            _glfw.wl.pointerSerial,
                            wlBorder);
}

Maybe one of those struct wl_seat seat or uint32_t serial should be grabbed from somewhere else?

Update:
By the heavens full of penguins, it works!!!
I found that on wl_init.c, the callback pointerHandleButton wasn't updating the pointerSerial, so I added:

    _glfw.wl.pointerSerial = serial;

🐧

Contributor

felselva commented Apr 8, 2017

I've made the Wayland implementation, but for some reason (just like wl_shell_surface_move on #923), wl_shell_surface_resize function doesn't work (Solved):

void _glfwPlatformResizeWindow(_GLFWwindow* window, int border)
{
    int wlBorder;
    switch (border)
    {
        case GLFW_WINDOW_LEFT:
            wlBorder = WL_SHELL_SURFACE_RESIZE_LEFT;
            break;
        case GLFW_WINDOW_TOP:
            wlBorder = WL_SHELL_SURFACE_RESIZE_TOP;
            break;
        case GLFW_WINDOW_RIGHT:
            wlBorder = WL_SHELL_SURFACE_RESIZE_RIGHT;
            break;
        case GLFW_WINDOW_BOTTOM:
            wlBorder = WL_SHELL_SURFACE_RESIZE_BOTTOM;
            break;
        case GLFW_WINDOW_TOPLEFT:
            wlBorder = WL_SHELL_SURFACE_RESIZE_TOP_LEFT;
            break;
        case GLFW_WINDOW_TOPRIGHT:
            wlBorder = WL_SHELL_SURFACE_RESIZE_TOP_RIGHT;
            break;
        case GLFW_WINDOW_BOTTOMLEFT:
            wlBorder = WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT;
            break;
        case GLFW_WINDOW_BOTTOMRIGHT:
            wlBorder = WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT;
    }
    wl_shell_surface_resize(window->wl.shellSurface,
                            _glfw.wl.seat,
                            _glfw.wl.pointerSerial,
                            wlBorder);
}

Maybe one of those struct wl_seat seat or uint32_t serial should be grabbed from somewhere else?

Update:
By the heavens full of penguins, it works!!!
I found that on wl_init.c, the callback pointerHandleButton wasn't updating the pointerSerial, so I added:

    _glfw.wl.pointerSerial = serial;

🐧

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 8, 2017

Contributor

I don't think Cocoa support this.

@elmindreda X11, Wayland and Windows implementations are done, and Cocoa doesn't allow and Mir doesn't support yet, I can close this if there's nothing else to add.

Contributor

felselva commented Apr 8, 2017

I don't think Cocoa support this.

@elmindreda X11, Wayland and Windows implementations are done, and Cocoa doesn't allow and Mir doesn't support yet, I can close this if there's nothing else to add.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment