Skip to content
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

Consider options for redefining locations where the user can drag, resize, close, etc. a window #221

Closed
LaylBongers opened this issue Jul 11, 2017 · 14 comments · Fixed by #1840
Labels
D - average Likely as difficult as most tasks here DS - windows H - help wanted Someone please save us P - low Nice to have S - api Design and usability S - enhancement Wouldn't this be the coolest?

Comments

@LaylBongers
Copy link

This is most likely low priority but a nice-to-have for making custom styled windows using borderless windows, and still allowing the user to drag a custom rendered title bar. On windows this is implemented using WM_NCHITTEST, which allows the application to define custom areas that can do these operations.

@tomaka tomaka added the S - enhancement Wouldn't this be the coolest? label Jul 12, 2017
@francesca64 francesca64 added H - help wanted Someone please save us DS - windows S - api Design and usability D - average Likely as difficult as most tasks here P - low Nice to have labels May 6, 2018
@Shookbelf
Copy link

I think a more flexible solution would be to let the application start an interactive move. Wayland clients can do this.

Unfortunately it looks like Windows does only support defining an area where drag and drop is possible.

@Shookbelf
Copy link

Shookbelf commented Jul 2, 2018

On X11 it seems like this is done with the wm-spec (also called ewmh) protocol, would it be possible to use it somehow?

@francesca64
Copy link
Member

Do you just need an EWMH hint, or do you really mean a protocol?

@Shookbelf
Copy link

I see it's only a spec and not a protocol, so excuse my error. For allowing window movement this message is probably needed. So I think it's a hint.

Please note that I just searched for this and have no prior experience in this regard. But I want to learn more about things like these and work with them.

Do you think I could work on this a little? I do not think it's only relevant for Windows and since it has low priority there would not be too much pressure.

@francesca64
Copy link
Member

It's a client message sent to the root window; a hint is just a window property. I can't say whether or not this qualifies as a protocol without getting needlessly pedantic, but my main reason for mentioning it was because protocols can be a big pain. That's not an issue here, though.

Do you think I could work on this a little?

Feel free! Reviewing/advising other people's PRs is more fun than making my own, to be honest.

Fortunately, winit's X11 util module (authored by yours truly) contains a bunch of convenience/safety wrappers for various Xlib functions. send_client_msg is the one you want for this.

I'd say winit itself is pretty good reference material for learning how to program X11 clients, since I've generally tried to do things in maintainable ways. You can also just ask me things, since what you'll discover is that almost nobody in the past decade and a half has directly touched this stuff, and thus learning resources are super scarce.

@Shookbelf
Copy link

Wow, i got great consistency with my initial implementation!

On KWin the window jumps once (not continuous) but as soon as you cancel the move it jumps back.
On Gnome X11 it doesn't do anything at all.
On Gnome via XWayland it works very well except that I don't get release events for secondary mouse buttons.

This is so strange. I guess this message is used for e.g. GTK CSD so it has to work somehow.

@francesca64
Copy link
Member

francesca64 commented Jul 3, 2018

It's hard for me to say much without seeing the code. You can also use hint_is_supported to check if the WM advertises support for that atom (I know the function contains the word "hint", and that I said this isn't a hint, but that doesn't really matter).

I guess this message is used for e.g. GTK CSD so it has to work somehow.

If you ctrl+F for _NET_WM_MOVERESIZE in this file, you'll find some results: https://github.com/GNOME/gtk/blob/d13843ee2a5e2afabe6418cc7e9e744258a3fc5d/gdk/x11/gdksurface-x11.c

@Shookbelf
Copy link

Shookbelf commented Jul 3, 2018

Yes, I have looked at some other implementations and can't really spot a relevant difference.
This is what I implemented. I'm calling this function every time I want to start or end a move (e.g. on button and cursor events). I've tried different values for button and mask but haven't got satisfying results.

pub fn start_move(&self, logical_position: LogicalPosition, stop: bool){
    self.grab_cursor(false);
    let (x, y): (i32, i32) = logical_position.to_physical(self.get_hidpi_factor()).into();
    let (root_x, root_y): (i32, i32) = {
        let pos = self.get_inner_position_physical().unwrap();
        (pos.0 + x, pos.1 + y)
    };
    let move_resize_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_MOVERESIZE\0") };

    let button = 0; //ffi::Button1;
    let test= self.xconn.send_client_msg(
        self.xwindow,
        self.root,
        move_resize_atom,
        Some(ffi::SubstructureRedirectMask | ffi::SubstructureNotifyMask),
        [
            root_x as c_long,
            root_y as c_long,
            if stop {11} else {8} as c_long, // _NET_WM_MOVERESIZE_MOVE or _NET_WM_MOVERESIZE_CANCEL
            button as c_long,
            0,
        ],
    ).flush();
}

@francesca64
Copy link
Member

I got it to grab once (though not in a way that was good), but since then, I don't remember what example code I used to do it, and nothing else I've tried has worked... I suspect the problem is in the usage of the messages rather than the messages themselves.

@Osspial
Copy link
Contributor

Osspial commented Apr 24, 2019

Reviving this - I'm okay in principle with this getting added, but I'd like to see an API design and/or PR that works across platforms.

@Shookbelf
Copy link

In principle I am open to continue my initial attempt at getting this to work on Linux (X11). Unfortunately I am stuck. I would appreciate if anyone can tell me what I am doing wrong.
After your comment, I wanted to look at it again. I looked at this spec page and my implementation again and tried a few things on KWin.

Apparently moving the window with the keyboard works fine after sending the according message. Moving with the mouse produces strange results. I suspect I am supplying the wrong mouse position or button but it should be correct. Maybe someone else can take a look at it.

Resizing from the respective window edges is analogous and should be very easy to implement after the error is found.

@daxpedda
Copy link
Member

I started working on this. To explain the issue I found in @Shookbelf's code, self.grab_cursor(false); doesn't execute XUngrabPointer unless the cursor has been grabbed before, but _NET_WM_MOVERESIZE requires the use of XUngrabPointer.

So replacing self.grab_cursor(false); with:

unsafe {
    (self.xconn.xlib.XUngrabPointer)(self.xconn.display, ffi::CurrentTime);
}
self.xconn.flush_requests().unwrap();

fixes this.

@Osspial I would really love to make a PR for this, I'm working on implementing this for Wayland, MacOS and Windows too, but I can't find a way to expose a neat cross-platform API.

The following summary is for an API that only supports moving the window (no resizing) with holding down a mouse button (no keyboard input), and only tested on X11 (testing on Windows incoming, MacOS and Wayland testing has to be done by others):

Wayland
Uses wl_shell_surface::move.

  • can be started on when a mouse button is pressed
  • automatically stops when the mouse button is released

X11
Uses _NET_WM_MOVERESIZE_MOVE to tell X11 that the last mouse button pressed should start moving the window until it is released again. _NET_WM_MOVERESIZE_CANCEL should be moved to cancel it, because some buttons don't cancel automatically.

  • can be started while a mouse button is being pressed
  • can be stopped at an arbitrary point, but automaticallly stops when the mouse button is released
  • removes Window::set_cursor_grab, we could potentially track it and reset it when dragging is done

MacOS
Uses NSWindow::performWindowDragWithEvent.

  • can be started on when a mouse button is pressed
  • automatically stops when the mouse button is released
  • may stop the corresponding mouse button release event to fire (unconfirmed)

Windows
Uses WM_NCHITTEST or WM_NCLBUTTONDOWN.

  • can be started when the left mouse button is pressed
  • automatically stops when the left mouse button is released

Limitations

Feature Wayland X11 MacOS Windows
only left button
only immediately after button press
only stops when released
may prevent button release event
undos cursor grab

So my current approach is to just document all these caveats and let users deal with it, as I don't see an easy way to force this to be used correctly.

PR incoming.

@daxpedda
Copy link
Member

See #1840.

@maroider
Copy link
Member

maroider commented Mar 7, 2021

There is one thing here that #1840 doesn't address, and that's user-defined resizing.
Users could arguably implement something like it by abusing set_cursor_icon and set_outer_position, but I doubt it would be as smooth as a solution which leverages the WM.

madsmtm added a commit to madsmtm/winit that referenced this issue Jun 11, 2022
* refactor(windows): `begin_resize_drag` now similar to gtk's (rust-windowing#200)

* refactor(windows): `begin_resize_drag` now similart to gtk's

* fix

* feat(linux): skipping taskbar will now also skip pager (rust-windowing#198)

* refactor(linux): clean dummy device_id (rust-windowing#195)

* refactor(linux): clean dummy device_id

* fmt

* feat(linux): allow resizing undecorated window using touch (rust-windowing#199)

* refactor(windows): only skip taskbar if needed when `set_visible` is called (rust-windowing#196)

* fix: increase borderless resizing inset (rust-windowing#202)

* fix: increase borderless resizing inset

* update some comments

* Replace winapi with windows crate bindings shared with WRY (rust-windowing#206)

* fix(deps): update rust crate libayatana-appindicator to 0.1.6 (rust-windowing#190)

Co-authored-by: Renovate Bot <[email protected]>

* Add Windows crate and webview2-com-sys bindings

* Initial port to webview2-com-sys

* Finish conversion and remove winapi

* Fix renamed lint warning

* Fix all match arms referencing const variables

* Put back the assert instead of expect

* Point to the published version of webview2-com-sys

* Cleanup slightly weird BOOL handling

* Replace mem::zeroed with Default::default

* Add a summary in .changes

* Remove extra projects not in config.json

* Fix clippy warnings

* Update to 32-bit compatible webview2-com-sys

* Better fix for merge conflict

* Fix clippy errors on Windows

* Use path prefix to prevent variable shadowing

* Fix Windows clippy warnings with nightly toolchain

* Fix Linux nightly/stable clippy warnings

* Fix macOS nightly/stable clippy warnings

* Put back public *mut libc::c_void for consistency

* Re-run cargo fmt

* Move call_default_window_proc to util mod

* Remove unnecessary util::to_wstring calls

* Don't repeat LRESULT expression in match arms

* Replace bitwise operations with util functions

* Cleanup more bit mask & shift with util fns

* Prefer from conversions instead of as cast

* Implement get_xbutton_wparam

* Use *mut libc::c_void for return types

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Renovate Bot <[email protected]>

* fix(keyboard): add mapping for space key on Windows (rust-windowing#209)

* fix(keyboard): add mapping for space key on Windows

* change file

* feat: impl Clone for EventLoopWindowTarget (rust-windowing#211)

* chore: add `on_issue_closed.yml` (rust-windowing#214)

* Update tray dependency version (rust-windowing#217)

* Delete on_issue_closed.yml (rust-windowing#221)

* refactor(linux): event loop (rust-windowing#233)

* Use crossbeam::channel

* Fix crossbeam channel import

* Add check on poll event

* Fix deadlock when unregistering shortcut on Linux (rust-windowing#230)

* Add fullscreen monitor selection support on Linux (rust-windowing#235)

* Add fullscreen monitor support on Linux

* Add change file

* Remove todo on videomode

* Fix clippy

* Update to 2021 edition (rust-windowing#236)

* Update to 2021 edition

* Fix clippy

* Add run_return on Linux (rust-windowing#237)

* Add run_return on Linux

* Add main context

* Add run_return trait on Linux (rust-windowing#238)

* Fix: rust-windowing#239 Update webview2-com and windows crates (rust-windowing#240)

* Replace webivew2-com-sys with prebuilt windows

* Use windows utility instead of direct GetLastError

* Bump windows version and add changelog

* Run cargo fmt

* Restore inverted matches macro

* Scope constants in match arms

* Fix inverted null check

* Update src/platform_impl/windows/util.rs

Co-authored-by: Amr Bashir <[email protected]>

* Use env_logger instead of simple_logger (rust-windowing#241)

* Use env_logger instead of simple_logger

* Make clippy happy

* Cherry pick commits to next (rust-windowing#244)

* feat(macos): Add `unhide_application` method, closes rust-windowing#182 (rust-windowing#231)

* feat(macos): Add `unhide_application` method

* Update src/platform/macos.rs

Co-authored-by: Amr Bashir <[email protected]>

* Reanme to `show_application()`

* Remove broken doc link

Co-authored-by: Amr Bashir <[email protected]>

* feat: Allow more strings to parse to keycode (rust-windowing#229)

* feat: support accelerator key strings `,` `-` `.` `Space` `Tab` and `F13`-`F24` (rust-windowing#228)

* feat(macOS): support more accelerator key strings

* Move function keys together

* Add `,` `-` `.` `Space` `F20-F24` for Windows

* Remove support for accelerators not found in `winapi`

* Add `,` `-` `.` `Space` `F13-F24` for Linux

* Update .changes

* Add the rest for Windows

* Add the rest for Linux

* Add the rest on macOS

* Update accelerator-strings.md

* Fix git comments

Co-authored-by: Kasper <[email protected]>
Co-authored-by: Amr Bashir <[email protected]>

* Add redraw events on Linux (rust-windowing#245)

* Add redraw events on Linux

* Update doc of RequestRedraw Event

* Add change file

* Fix missing menu bar on borderless window (rust-windowing#247)

Credit goes to irh's work on winit commit f2de847

* refactor: improve `set_skip_taskbar` impl on Windows (rust-windowing#250)

* fix: emit errors on parsing an invalid accelerator for string, closes rust-windowing#135 (rust-windowing#252)

* chore: update comment

* fix(linux): fix focus events not firing properly (rust-windowing#253)

* fix(linux): fix focus events not firing properly

* add changelog

* chore: update focus events error message

* chore: fmt

* fix: revert windows-rs 0.28 version bump

* fix(linux): fix native menu items (rust-windowing#256)

* chore: remove examples commited by accident

* Update `ReceivedImeText` (rust-windowing#251)

* Allow receiving text without Ime on Windows

* Avoid panic todo

* Receive text without ime on mac

* Fix CursorMoved event on Linux

* Add ReceivedImeText on Linux

This only add Simple IME from GTK for now. We should add the actual IME
from system in the future.

* Fix redraw event that causes inifinite loop (rust-windowing#260)

* Fix redraw event that causes inifinite loop

* Refactor event loop

* Remove unused function

* Add doc comment on linux's run_return

* Ignore doc test on run_return

* Add non blocking iteration on Linux (rust-windowing#261)

* Docs: SystemTrayExtWindows::remove() is gone (rust-windowing#262)

Fix docs following rust-windowing#153

* Fix busy loop on Linux (rust-windowing#265)

* Update windows crate to 0.29.0 (rust-windowing#266)

* Update to windows 0.29.0

* Add change description

* Remove clippy check (rust-windowing#267)

* refactor(windows): align util function with win32 names

* chore: update PR template

* fix(linux): fire resized & moved events on min/maximize, closes rust-windowing#219 (rust-windowing#254)

* feat(linux): implement `raw_window_handle()` (rust-windowing#269)

* chore(deps): update to raw-window-handle 0.4

* add linux raw-window-handle support

* update macos/ios/android

* fix ios

* Fix core-video-sys dependency (rust-windowing#274)

* The `cocoa` crate links to AppKit, which made the symbol `CGDisplayCreateUUIDFromDisplayID` from ApplicationServices/ColorSync (which AppKit uses internally) available to us on macOS 10.8 to 10.13. (rust-windowing#275)

However, this does not work on macOS 10.7 (where AppKit does not link to ColorSync internally). Instead of relying on this, we should just link to ApplicationServices directly.

* Fix some invalid msg_send! usage (rust-windowing#276)

* Revert "Fix some invalid msg_send! usage (rust-windowing#276)" (rust-windowing#277)

This reverts commit a3a2e0cfc49ddfa8cdf65cf9870fb8e3d45b4bc0.

* Revert "The `cocoa` crate links to AppKit, which made the symbol `CGDisplayCreateUUIDFromDisplayID` from ApplicationServices/ColorSync (which AppKit uses internally) available to us on macOS 10.8 to 10.13. (rust-windowing#275)" (rust-windowing#279)

This reverts commit 6f9c468f26ddb60e29be2139397bfaf3b30eab1e.

* The `cocoa` crate links to AppKit, which made the symbol `CGDisplayCreateUUIDFromDisplayID` from ApplicationServices/ColorSync (which AppKit uses internally) available to us on macOS 10.8 to 10.13. (rust-windowing#280)

However, this does not work on macOS 10.7 (where AppKit does not link to ColorSync internally). Instead of relying on this, we should just link to ApplicationServices directly.

Co-authored-by: madsmtm <[email protected]>

* Fix some invalid msg_send! usage (rust-windowing#278)

Co-authored-by: madsmtm <[email protected]>

* Add exit code to ControlFlow::Exit (rust-windowing#281)

* Add exit code to ControlFlow::Exit

* Cargo fmt

* Add change files

Co-authored-by:  multisn8 <[email protected]>

* Add new_any_thread to Unix event loop (rust-windowing#282)

* Update windows crate to 0.30.0 (rust-windowing#283)

* Update windows crate to 0.30.0

* Simplify new-type usage

* Fix boxing in GWL_USERDATA

* Make sure everyone is using Get/SetWindowLongPtrW

* build the system_tray module when "ayatana" feature is enabled (rust-windowing#285)

Without those cfg feature checks, the "ayatana" feature does
actually not enable anything.

* Fix click events missing whe tray has menu (rust-windowing#291)

* Fix click events missing whe tray has menu

* Add change file

* Fix crash when tray has no menu (rust-windowing#294)

* chore: update pull request commit exmple

* fix(windows): send correct position for system tray events, closes rust-windowing#295 (rust-windowing#300)

* fix(windows): revert maximized state handling to winit impl, closes rust-windowing#193 (rust-windowing#299)

* fix(windows): revet maximized state handling to winit impl, closes rust-windowing#193

* add chanefile [skip ci]

* fix: `MenuItem::Quit` on Windows (rust-windowing#303)

* fix: `MenuItem::Close` on Windows

* use `PostQuitMessage` instead

Co-authored-by: amrbashir <[email protected]>

* feat: v1 audit by Radically Open Security (rust-windowing#304)

* Update to gtk 0.15 (rust-windowing#288)

* Update to gtk 0.15

* Fix picky none on set_geometry_hint

* Fix CursorMoved position

Co-authored-by: Amr Bashir <[email protected]>
Co-authored-by: Bill Avery <[email protected]>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Renovate Bot <[email protected]>
Co-authored-by: Lucas Fernandes Nogueira <[email protected]>
Co-authored-by: Kasper <[email protected]>
Co-authored-by: amrbashir <[email protected]>
Co-authored-by: Jay Oster <[email protected]>
Co-authored-by: madsmtm <[email protected]>
Co-authored-by: multisn8 <[email protected]>
Co-authored-by: Aurélien Jacobs <[email protected]>
Co-authored-by: Lucas Fernandes Nogueira <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
D - average Likely as difficult as most tasks here DS - windows H - help wanted Someone please save us P - low Nice to have S - api Design and usability S - enhancement Wouldn't this be the coolest?
Development

Successfully merging a pull request may close this issue.

8 participants