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

Provide a way to specify the window drag area on an undecorrated window #923

Open
adambrown opened this Issue Dec 21, 2016 · 12 comments

Comments

Projects
None yet
6 participants
@adambrown

adambrown commented Dec 21, 2016

I am doing exactly what @Andos is doing here: #902. Creating windows with completely re-purposed title bar area. The current trend on Windows 10, and possibly some other platforms as well given that @Andos is doing it on OSX, seems to be that the title bar is dead (Firefox, Chrome, Edge, Photoshop, Visual Studio, and a multitude of others, too numerous to name or remember off the top of my head, seem to agree). This space can be better used by moving up your menu, toolbar, tabs or whatever you have right below the title bar in order to maximize usable space.

All of these examples given above provide some portion of the former title bar as a drag area for moving the window. It would be nice if GLFW provided a way to specify a dynamically resizable area, probably a rectangle, within an un-decorated window to use as a drag handle, to provide native window dragging functionality without a title bar.

In #902 @Andos gives an example of how this can be hacked around OSX with performWindowDragWithEvent. In windows this is done with Window.DragMove. Combined with the native resizing functionality in #902 this will allow fully functional undecorated windows like those used by Firefox, Chrome, Photoshop etc...

@adambrown adambrown changed the title from Provide a way to spcify the window drag area on an undecorrated window to Provide a way to specify the window drag area on an undecorrated window Dec 21, 2016

@richtw1

This comment has been minimized.

Show comment
Hide comment
@richtw1

richtw1 Mar 14, 2017

In my opinion, this is better achieved in Windows by catching the WM_NCHITTEST message. I would love a callback which can return some kind of 'hit code' based on the screen coordinates relative to the upper-left of the client area. Not sure if X11/Cocoa have a similar kind of functionality.

As others have noted, the current vogue is to abandon the native title bar and/or window borders in favour of rendering them yourself, and a callback system like this would be far better than the alternative laggy method of calculating cursor pos deltas and moving the window accordingly in the event loop.

richtw1 commented Mar 14, 2017

In my opinion, this is better achieved in Windows by catching the WM_NCHITTEST message. I would love a callback which can return some kind of 'hit code' based on the screen coordinates relative to the upper-left of the client area. Not sure if X11/Cocoa have a similar kind of functionality.

As others have noted, the current vogue is to abandon the native title bar and/or window borders in favour of rendering them yourself, and a callback system like this would be far better than the alternative laggy method of calculating cursor pos deltas and moving the window accordingly in the event loop.

@elmindreda elmindreda added this to the 3.4 milestone Mar 27, 2017

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 5, 2017

Contributor

Instead of defining an area for dragging the window, it would be more flexible to just add a function to start the drag operation (example, glfwDragWindow).

X11 (and probably Wayland) has this functionality, too. Long ago I did this with X11, so I can implement for X11 if no one is working on this yet.

Contributor

felselva commented Apr 5, 2017

Instead of defining an area for dragging the window, it would be more flexible to just add a function to start the drag operation (example, glfwDragWindow).

X11 (and probably Wayland) has this functionality, too. Long ago I did this with X11, so I can implement for X11 if no one is working on this yet.

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 6, 2017

Contributor

I did a implementation on X11 (Here's my fork: https://github.com/felipefs/glfw/tree/window-drag).

It adds the function glfwDragWindow(glfwWindow *window). Here are the most important internal part of the implementation:

/* window.c */
GLFWAPI void glfwDragWindow(GLFWwindow* handle)
{
    _GLFWwindow* window = (_GLFWwindow*) handle;
    assert(window != NULL);

    _GLFW_REQUIRE_INIT();

    _glfwPlatformDragWindow(window);
}

/* x11_window.c */
void _glfwPlatformDragWindow(_GLFWwindow* window)
{
    XClientMessageEvent xclient;
    memset(&xclient, 0, sizeof(XClientMessageEvent));
    XUngrabPointer(_glfw.x11.display, 0);
    XFlush(_glfw.x11.display);
    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] = window->x11.xpos + window->x11.lastCursorPosX;
    xclient.data.l[1] = window->x11.ypos + window->x11.lastCursorPosY;
    xclient.data.l[2] = _NET_WM_MOVERESIZE_MOVE;
    xclient.data.l[3] = 0;
    xclient.data.l[4] = 0;
    XSendEvent(_glfw.x11.display, _glfw.x11.root, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient);
}

@elmindreda Since I didn't implement _glfwPlatformDragWindow for every platform, should I put that call between #ifdef/#endif or should I add at least an empty _glfwPlatformDragWindow for every platform (while the implementation for those aren't still done)? I found that I should put the _glfwPlatformDragWindow on null_window.c.

As for the implementation for other platforms:
I can make implementations for Windows and Wayland, too, but I'm having some problems trying to build for Wayland (I tried defining _GLFW_WAYLAND on glfw_config.h) and Windows (when targeting the mingw cross-compilation, I get that Vulkan libraries are missing).

Contributor

felselva commented Apr 6, 2017

I did a implementation on X11 (Here's my fork: https://github.com/felipefs/glfw/tree/window-drag).

It adds the function glfwDragWindow(glfwWindow *window). Here are the most important internal part of the implementation:

/* window.c */
GLFWAPI void glfwDragWindow(GLFWwindow* handle)
{
    _GLFWwindow* window = (_GLFWwindow*) handle;
    assert(window != NULL);

    _GLFW_REQUIRE_INIT();

    _glfwPlatformDragWindow(window);
}

/* x11_window.c */
void _glfwPlatformDragWindow(_GLFWwindow* window)
{
    XClientMessageEvent xclient;
    memset(&xclient, 0, sizeof(XClientMessageEvent));
    XUngrabPointer(_glfw.x11.display, 0);
    XFlush(_glfw.x11.display);
    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] = window->x11.xpos + window->x11.lastCursorPosX;
    xclient.data.l[1] = window->x11.ypos + window->x11.lastCursorPosY;
    xclient.data.l[2] = _NET_WM_MOVERESIZE_MOVE;
    xclient.data.l[3] = 0;
    xclient.data.l[4] = 0;
    XSendEvent(_glfw.x11.display, _glfw.x11.root, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient);
}

@elmindreda Since I didn't implement _glfwPlatformDragWindow for every platform, should I put that call between #ifdef/#endif or should I add at least an empty _glfwPlatformDragWindow for every platform (while the implementation for those aren't still done)? I found that I should put the _glfwPlatformDragWindow on null_window.c.

As for the implementation for other platforms:
I can make implementations for Windows and Wayland, too, but I'm having some problems trying to build for Wayland (I tried defining _GLFW_WAYLAND on glfw_config.h) and Windows (when targeting the mingw cross-compilation, I get that Vulkan libraries are missing).

@richtw1

This comment has been minimized.

Show comment
Hide comment
@richtw1

richtw1 Apr 6, 2017

@felipefs In Win32, I'm not aware of a similar functionality to force the window manager to initiate a window drag. So I think it's still necessary to hook into the WM_NCHITTEST message. Essentially glfwPlatformDragWindow would need to set a flag that the message handler could look at, reset on a mouse up event.

richtw1 commented Apr 6, 2017

@felipefs In Win32, I'm not aware of a similar functionality to force the window manager to initiate a window drag. So I think it's still necessary to hook into the WM_NCHITTEST message. Essentially glfwPlatformDragWindow would need to set a flag that the message handler could look at, reset on a mouse up event.

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 6, 2017

Contributor

@richtw1 yup, that's how it is done on Windows. I can blindly make a implementation for Windows and let someone else with a Windows machine to test.

Contributor

felselva commented Apr 6, 2017

@richtw1 yup, that's how it is done on Windows. I can blindly make a implementation for Windows and let someone else with a Windows machine to test.

@richtw1

This comment has been minimized.

Show comment
Hide comment
@richtw1

richtw1 Apr 6, 2017

@felipefs I'll be happy to test a Windows implementation. I'm wondering if we should also support a similar facility for resize, and maybe if the function name should be slightly changed (glfwStartDragWindow and glfwStartResizeWindow).

The last thing that I would change to make this really useful is to allow an undecorated window with a border (maybe specifying GLFW_DECORATED == GLFW_FALSE with GLFW_RESIZABLE == GLFW_TRUE, or a completely different window hint).

richtw1 commented Apr 6, 2017

@felipefs I'll be happy to test a Windows implementation. I'm wondering if we should also support a similar facility for resize, and maybe if the function name should be slightly changed (glfwStartDragWindow and glfwStartResizeWindow).

The last thing that I would change to make this really useful is to allow an undecorated window with a border (maybe specifying GLFW_DECORATED == GLFW_FALSE with GLFW_RESIZABLE == GLFW_TRUE, or a completely different window hint).

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 6, 2017

Contributor

Here's the branch with the X11 and Windows impementation:
https://github.com/felipefs/glfw/tree/window-drag

I think that is all that is needed for the Windows implementation:

void _glfwPlatformDragWindow(_GLFWwindow* window)
{
    ReleaseCapture();
    SendMessage(window->win32.handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
}

We just force to send a message of 'button down' and that the area is the title bar 'HTCAPTION'. I'm not sure if the last parameter should or not recieve the cursor's position (and whether it's the global position or the position inside the window). We will know if the window suddenly jump when clicked.

@richtw1 You can test using the example simple in /examples/simple, it already has the callback:

void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
    if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
        glfwDragWindow(window);
}

Let me know about any problem 😊

For the future implementation in other platforms: I've added an empty _glfwPlatformDragWindow in the null_window.c, which seems to be the place to add a function when it's not implemented for every platform.

Contributor

felselva commented Apr 6, 2017

Here's the branch with the X11 and Windows impementation:
https://github.com/felipefs/glfw/tree/window-drag

I think that is all that is needed for the Windows implementation:

void _glfwPlatformDragWindow(_GLFWwindow* window)
{
    ReleaseCapture();
    SendMessage(window->win32.handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
}

We just force to send a message of 'button down' and that the area is the title bar 'HTCAPTION'. I'm not sure if the last parameter should or not recieve the cursor's position (and whether it's the global position or the position inside the window). We will know if the window suddenly jump when clicked.

@richtw1 You can test using the example simple in /examples/simple, it already has the callback:

void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
    if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
        glfwDragWindow(window);
}

Let me know about any problem 😊

For the future implementation in other platforms: I've added an empty _glfwPlatformDragWindow in the null_window.c, which seems to be the place to add a function when it's not implemented for every platform.

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 6, 2017

Contributor

I'm wondering if we should also support a similar facility for resize, and maybe if the function name should be slightly changed (glfwStartDragWindow and glfwStartResizeWindow).

Yeah, I don't think supporting resize is too different compared with drag operation, so I will check it out later. I don't know, however, if Wayland and Cocoa allows it. But, I know that with X11 and Windows it is possible.

The last thing that I would change to make this really useful is to allow an undecorated window with a border (maybe specifying GLFW_DECORATED == GLFW_FALSE with GLFW_RESIZABLE == GLFW_TRUE, or a completely different window hint).

Probably won't need a new window hint, just letting GLFW_RESIZABLE as true will do.

Contributor

felselva commented Apr 6, 2017

I'm wondering if we should also support a similar facility for resize, and maybe if the function name should be slightly changed (glfwStartDragWindow and glfwStartResizeWindow).

Yeah, I don't think supporting resize is too different compared with drag operation, so I will check it out later. I don't know, however, if Wayland and Cocoa allows it. But, I know that with X11 and Windows it is possible.

The last thing that I would change to make this really useful is to allow an undecorated window with a border (maybe specifying GLFW_DECORATED == GLFW_FALSE with GLFW_RESIZABLE == GLFW_TRUE, or a completely different window hint).

Probably won't need a new window hint, just letting GLFW_RESIZABLE as true will do.

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 6, 2017

Contributor

I'm trying to get it to work on Wayland, but it's not moving at all. Here's what I have:

void _glfwPlatformDragWindow(_GLFWwindow* window)
{
    wl_shell_surface_move(window->wl.shellSurface, _glfw.wl.seat, _glfw.wl.pointerSerial);
}

Any ideas, anyone?

Edit 1:
oh, wait, maybe I have to release/ungrab first! Doesn't seems to be the case. Every example I found just uses wl_shell_surface_move.

Edit 2:
Weston examples use the function zxdg_toplevel_v6_move (https://github.com/wayland-project/weston/blob/master/clients/window.c). The example flower.c works ok with a borderless window and the drag operation. So, I'm not sure if this is a feature only available when using "zxdg_" or if using "wl_" also works and I'm doing it wrong.

Contributor

felselva commented Apr 6, 2017

I'm trying to get it to work on Wayland, but it's not moving at all. Here's what I have:

void _glfwPlatformDragWindow(_GLFWwindow* window)
{
    wl_shell_surface_move(window->wl.shellSurface, _glfw.wl.seat, _glfw.wl.pointerSerial);
}

Any ideas, anyone?

Edit 1:
oh, wait, maybe I have to release/ungrab first! Doesn't seems to be the case. Every example I found just uses wl_shell_surface_move.

Edit 2:
Weston examples use the function zxdg_toplevel_v6_move (https://github.com/wayland-project/weston/blob/master/clients/window.c). The example flower.c works ok with a borderless window and the drag operation. So, I'm not sure if this is a feature only available when using "zxdg_" or if using "wl_" also works and I'm doing it wrong.

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 6, 2017

Contributor

I tested the Windows implementation using Wine on Linux and worked just fine.

Contributor

felselva commented Apr 6, 2017

I tested the Windows implementation using Wine on Linux and worked just fine.

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 8, 2017

Contributor

Ok, Wayland implementation is solved with the pull request #992. 🎆

Contributor

felselva commented Apr 8, 2017

Ok, Wayland implementation is solved with the pull request #992. 🎆

@codeyash

This comment has been minimized.

Show comment
Hide comment
@codeyash

codeyash Feb 26, 2018

Any update please. Very nice features and much required.

codeyash commented Feb 26, 2018

Any update please. Very nice features and much required.

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