Zren / material-decoration

Material-ish window decoration theme for KWin, with LIM, based on zzag's original design.
GNU General Public License v2.0
200 stars 17 forks source link

[Request] Detection of window grabbing #2

Closed ivnvitx closed 4 years ago

ivnvitx commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

Try the buttonmove branch.

https://github.com/Zren/material-decoration/compare/master...buttonmove

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

trmdi commented 4 years ago

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

trmdi commented 4 years ago

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

Zren commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

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

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

emvaized commented 3 years ago

@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 commented 3 years ago

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

emvaized commented 3 years ago

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 commented 3 years ago

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

So you want an option that will:

emvaized commented 3 years ago

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?