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

[Request] Detection of window grabbing #2

Closed
ivnvitx opened this issue Mar 29, 2020 · 15 comments
Closed

[Request] Detection of window grabbing #2

ivnvitx opened this issue Mar 29, 2020 · 15 comments

Comments

@ivnvitx
Copy link

ivnvitx commented Mar 29, 2020

Basically, somehow making the menu buttons behave as if they were not there when I click and drag, and so just move the window around.
I do not know if this is possible, as there may be issues with the window manager or something (I really do not know much about this), but it would certainly take it to the next level, to the point where I could see this system become the standard. It is just too space-efficient. I love it.


Thanks for the work you are doing here. I hope it brings many people in to work it all out.

@ripefig
Copy link

ripefig commented Jun 13, 2020

Yes, this also how GTK does it client side. If you have lots of widgets in the decorations, dragging can become a huge problem unless you allow the user to drag from the widget.

Is this possible @Zren ?

@Zren
Copy link
Owner

Zren commented Jun 17, 2020

First I'll need to get rid of the mousePressEvent code that triggers mouseReleaseEvent which is easy enough.

I don't think we can tell KDecoration to ignore the "press button", letting it fall through to the titlebar "move" unfortunately. There doesn't seem to be a "move" function anywhere in KDecoration either. So KWin is probably handling it.

There's a mouseMoveEvent, which I think is only triggered when a mouse button is pressed.

    virtual void hoverEnterEvent(QHoverEvent *event);
    virtual void hoverLeaveEvent(QHoverEvent *event);
    virtual void hoverMoveEvent(QHoverEvent *event);
    virtual void mouseMoveEvent(QMouseEvent *event);
    virtual void mousePressEvent(QMouseEvent *event);
    virtual void mouseReleaseEvent(QMouseEvent *event);
    virtual void wheelEvent(QWheelEvent *event);

We can use that with mousePressEvent to get the distrance dragged, and if it goes over the threshold to somehow trigger the "move window" event.

https://doc.qt.io/qt-5/qstylehints.html#startDragDistance-prop

Breeze has a "SizeGrip" in the bottom right which manually sends a MoveResize event to the xorg server. It sends direction=4 or _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT

        clientMessageEvent.response_type = XCB_CLIENT_MESSAGE;
        clientMessageEvent.type = m_moveResizeAtom;
        clientMessageEvent.format = 32;
        clientMessageEvent.window = c->windowId();
        clientMessageEvent.data.data32[0] = rootPosition.x();
        clientMessageEvent.data.data32[1] = rootPosition.y();
        clientMessageEvent.data.data32[2] = 4; // bottom right
        clientMessageEvent.data.data32[3] = Qt::LeftButton;
        clientMessageEvent.data.data32[4] = 0;

        xcb_send_event( connection, false, QX11Info::appRootWindow(),
            XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
            XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
            reinterpret_cast<const char*>(&clientMessageEvent) );

We can probably try _NET_WM_MOVERESIZE_MOVE to send a Move only event. We can also look at what event the taskmanager widget sends when you right click a window > More Actions > Move.

#define _NET_WM_MOVERESIZE_MOVE              8   /* movement only */

@Zren
Copy link
Owner

Zren commented Jun 18, 2020

DecorationButton::mouseMoveEvent doesn't seem to be triggered, event when isPressed() == true. DecorationButton::hoverMoveEvent is sent when it's true and false, so that's weird. I didn't check Decoration::mouseMoveEvent. I'll probably need to use Decoration::mouseMoveEvent in the long term so that:

Click the very edge of a AppMenu button then dragging. It should trigger the move event.

DecorationButton::hoverMoveEvent may not detect this as each button has it's own pressedPoint atm. I'll need to store pressedPoint in the Decoration object.

Zren added a commit that referenced this issue Jun 18, 2020
DecorationButton::isPressed() remains true however, even after
releasing the mouse. Not only is there a visual bug, but due to how
KDecoration mouse events work, this means that clicking an AppMenu
button after the currently "pressed" button will not open it's menu on
the first click. Instead it will "reset" the pressed state of the
previously pressed button.
@Zren
Copy link
Owner

Zren commented Jun 18, 2020

I've gotten it working, however I'm not able to reset the "pressed" state of the button, so there a visual and functional bug. The first button press to open a menu item will be gobbled up to set "pressed = false" of the previously dragged button.

@Zren
Copy link
Owner

Zren commented Jun 18, 2020

Try the buttonmove branch.

master...buttonmove

I've found a workaround for button->setPressed(false) by toggling button->setEnabled twice.

@trmdi
Copy link

trmdi commented Jun 19, 2020

Just tried this and it works just fine. Should we also apply this to other buttons like Close/Min/Max... ?

@trmdi
Copy link

trmdi commented Jun 19, 2020

One issue could be improved is that the grabbing window should become the active one.

@Zren
Copy link
Owner

Zren commented Jun 19, 2020

I deliberately limited the effect to just the appmenu with m_menuButtons->geometry().contains(event->pos()) to limit edge cases.

https://github.com/Zren/material-decoration/blob/master/src/Decoration.cc#L177

You can remove the if check if you want to try applying the affect to all buttons.

@ripefig
Copy link

ripefig commented Jun 28, 2020

@Zren what about scroll and right-click events. I could see right-click-anywhere to maximize being useful here. As an added bonus, you can configure the same behavior in gtk CSD system-wide, so you could even get consistent wm behavior between CSD and SSD.

I personally think scroll up/down anywhere to maximize/restore is more natural though, so there is value in that as well, esp for people who don't care about gtk CSD.

@Zren
Copy link
Owner

Zren commented Jul 10, 2020

The default Application Menu accepts Left and Right click to activate. I can definitely pass through Middle Button and wheel events though.

  • Gtk apps activate the menu on right click.
  • Qt apps do not activate the menu on right click... well usually.
  • On a few KDE Qt apps, it shows a "view > toggle" like menu for toggling dock widgets and toolbars.

Tbh, I don't really care about enforcing a standard atm, I'll just pass through RightClick events too.

Zren added a commit that referenced this issue Jul 10, 2020
We can also setAccepted(false) of LeftButton. Unfortunately I don't
think there's a way to detect when the titlebar starts the drag, so
we can't run unPressAllButtons to fix the sticky button underneath the
drag. It causes the (possibly) wrong menu to open on next click.

So we're stuck with manually sending a move event to X11.
@Zren Zren closed this as completed Jul 27, 2020
@emvaized
Copy link

@Zren
I have also a small question regarding this topic.

On Ubuntu, it is possible to call the menu item by pressing left mouse button (mouse-down event), select the entry by moving the cursor, and then select it by releasing the button (mouse-up action). The same behavior also applies in some KDE apps - for example context menus in Dolphin or on desktop behave this way, so it is possible to select some submenu entry within only one whole click event.

However, this trick doesn't work with material-decoration menu - if you press mouse button over one of the menu buttons, and then move cursor down (while keeping mouse button pressed), whole window is getting moved.
Maybe it is possible somehow to make continuous selection work with material-decoration ? For example, open the menu on 'mouse-down' event instead of 'click' or 'mouse-up' can help in theory (just a thought).

Thanks.

@Zren
Copy link
Owner

Zren commented Mar 24, 2021

How did unity differentiate a "mousedown+drag" to open a menu from a "mousedown+drag" to move a window?

@emvaized
Copy link

emvaized commented Mar 24, 2021

I guess it works the way that when initial click was over empty space - "move window" action gets triggered on cursor move, and when it was over the menu button - then, the menu dropdown behavior I described above.

So basically menu bar should somehow consume mouse events to make it all work. Maybe event consuming will be handled by system itself, if the menu dropdown is opened immediately after 'mouse-down' event, instead of being opened only on releasing the mouse button (as it is in the current version)?

@Zren
Copy link
Owner

Zren commented Mar 24, 2021

So you want it to never move the window when you press a menu item?

So you want an option that will:

@emvaized
Copy link

emvaized commented Mar 24, 2021

Yes, sounds about right!
But need to check somehow if these changes allow the behavior I was talking about. Just wanted to test it, but the last 2 links point to the Plasma sources?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants