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

Dragging on the TitleBar to move the window does not always work #368

Open
hvisser opened this issue Apr 26, 2024 · 16 comments
Open

Dragging on the TitleBar to move the window does not always work #368

hvisser opened this issue Apr 26, 2024 · 16 comments
Assignees
Labels
bug Something isn't working

Comments

@hvisser
Copy link

hvisser commented Apr 26, 2024

Dragging the TitleBar doesn't always work, at least on macOS with jbr-17 and jbr-21. When I use a normal Window the window can be dragged normally. Since TitleBar is delegating the hit test to the JetBrains runtime, this might also be a runtime bug.

titlebar.mov
@rock3r
Copy link
Collaborator

rock3r commented Apr 27, 2024

Hugo, can you confirm this isn't by any chance happening when clicking clickable/focusable components? This doesn't seem to be the case in the video, but just to be sure.

@rock3r rock3r added the bug Something isn't working label Apr 27, 2024
@hvisser
Copy link
Author

hvisser commented Apr 27, 2024

I've also tested this with an completely empty window, so it doesn't seem to be related to focus I think.

@rock3r
Copy link
Collaborator

rock3r commented Apr 27, 2024

Thanks :) @devkanro have you ever seen this?

@devkanro
Copy link
Collaborator

This is a known issue, and I have no idea currently, will look into this, but I think it is a JBR issue.

@hvisser
Copy link
Author

hvisser commented Apr 29, 2024

The pointer is handled here https://github.com/JetBrains/jewel/blob/main/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/TitleBar.Windows.kt#L43 and it looks OK, but maybe the actual pointer event does not always get delivered to the window decoration correctly?

FWIW I assume that Intellij and other products do something similar but using Swing API's and I'm not observing that issue with those products.

@hmy65
Copy link

hmy65 commented Oct 25, 2024

pretty sure this issue existed on windows as well, using latest 243 with jbr21, still sadly existed :(

@rock3r
Copy link
Collaborator

rock3r commented Oct 25, 2024

@devkanro any chance you could look into this?

@yaroslavkulinich
Copy link

This issue significantly impacts usability, and I hope this gets prioritized for a fix soon.

@rock3r
Copy link
Collaborator

rock3r commented Dec 2, 2024

I hope @devkanro will come back to help with this; they're the only person who's got knowledge on the topic

@hmy65
Copy link

hmy65 commented Dec 3, 2024

@rock3r @devkanro
It's weird Intellij does not have this issue at all. So part of the implementation must be close source.

@MFlisar
Copy link

MFlisar commented Dec 13, 2024

Here's my input to this issue:

The TitleBar is on top of it's content inside the composable tree - events are propagated from top to bottom. titleBar.forceHitTest does only have an effect on the next event as far as I can see in my tests.... I think, that you can't intercept the events of child from somewhere above in the hierarchy without a fully custom event handling if the implementation of the title bar does not work with the consumed flags but by calling a function after the event has reached the TitleBar already...

Suggestion

In my first tests I can fix everything if I make it simple: just enable drag&drop and double click resize in the region of the title text and not on the full title bar - this means I apply

internal fun Modifier.customTitleBarMouseEventHandler(titleBar: CustomTitleBar): Modifier =
to the title region only. In this case, I don't have to enable and disable the forceHitTest at all...

If this is something that would be an acceptable solution for all, I can beautify my quick work around and make a pull request. It's not perfect though, but for me, it's good enough (at least better than what is not)

@rock3r
Copy link
Collaborator

rock3r commented Dec 15, 2024

Thanks for the investigation @MFlisar — any chance you can do a quick PR with the change?

We're in the process of moving everything into the JetBrains/intellij-community repo, but we'll cherry pick all approved PRs from here in the meantime

@MFlisar
Copy link

MFlisar commented Dec 15, 2024

I will do that. I even have good news - when I remove the hierarchy and place a background Spacer behind the title bar the event propagation of compose does solve everything for us automatically. Nothing special to do in this case.

The PR is here: #731

@rock3r
Copy link
Collaborator

rock3r commented Dec 15, 2024

Awesome news, thanks a lot! We appreciate it 🙏

@rock3r
Copy link
Collaborator

rock3r commented Dec 15, 2024

I'll review the PR tomorrow, I'm AFK until then

@rock3r
Copy link
Collaborator

rock3r commented Dec 19, 2024

The PR was related to another bug, not this one. There was some confusion on my side. Sorry everyone.

I have looked into this issue a bit with folks from the Compose Multiplatform team and we (they!) have identified a root cause:

[the issue is] that Compose filters out move events with the same coordinates as the previous move event, but this [JBR] title bar [API] expects the forceHitTest call on every event. When it doesn’t receive the call on some mouse event, it reverts to its default behavior until the next press.

Given we don't want to change how Compose handles events due to obvious compatibility reasons, we need a workaround for this problem. Luckily, we found this should work:

  1. Fix the isUserInControl logic in the customTitleBarMouseEventHandler code (it'll never set the flag to true)

  2. Add both an AWT mouse listener that looks like the one IJ uses, and the Compose pointerInput code, to the DecoratedWindow:

    DisposableEffect(window, titleBar) {
        val listener = object : java.awt.event.MouseAdapter() {
            override fun mousePressed(e: java.awt.event.MouseEvent?) {
                onMouseEvent(e)
            }
            override fun mouseReleased(e: java.awt.event.MouseEvent?) = onMouseEvent(e)
            override fun mouseEntered(e: java.awt.event.MouseEvent?) = onMouseEvent(e)
            override fun mouseDragged(e: java.awt.event.MouseEvent?) = onMouseEvent(e)
            override fun mouseMoved(e: java.awt.event.MouseEvent?) = onMouseEvent(e)
    
            private fun onMouseEvent(e: java.awt.event.MouseEvent?) {
                titleBar.forceHitTest(false)
            }
        }
        window.addMouseListener(listener)
        window.addMouseMotionListener(listener)
    
        onDispose {
            window.removeMouseListener(listener)
            window.removeMouseMotionListener(listener)
        }
    }
  3. Remove calls to forceHitTest from the pointerInput logic, only leaving the isUserInControl logic (possibly renaming it to isTitleBarClientEvent)

  4. Call the titleBar.forceHitTest(isTitleBarClientEvent) function from the AWT listener as above

We'll get to doing this as soon as possible — but that may be "at some point in Q1 2025" as we're both overloaded and about to go on vacation :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants