kotelnik / plasma-applet-active-window-control

Plasma 5 applet for controlling currently active window.
GNU General Public License v2.0
120 stars 18 forks source link

Feature request: Drag the application name to move (maximized) windows #30

Open luisfpg opened 7 years ago

luisfpg commented 7 years ago

This request is to be able to move the current window by dragging the applet. This is a nice complement for the option to hide the title bar for maximized windows. In such case there is no title bar to drag (and unmaximize) the window. Kwin has the option in the right click menu to move the window, so I assume it would be possible. Unity allows a similar behavior, where the top panel really feels like the "maximized window decoration". If you prefer this could be enabled with an option, and even the option could restrict to maximized windows only.

kotelnik commented 7 years ago

I know, I know, I want this feature, too. I'll look into it, thanks for suggestion :).

kupiqu commented 7 years ago

That would certainly be a nice add :)

cognifloyd commented 7 years ago

Or add a "Move" button/menu entry, like what is available in the taskbar's right click menu > More Actions.

Snuggle commented 7 years ago

I would love this so gosh darn much! Any updates, @kotelnik?

nmabhinandan commented 7 years ago

Any updates? 😋

Zren commented 6 years ago

The taskmanager widget can ask to "move the selected window".

https://github.com/KDE/plasma-desktop/blob/6ae9528c1ce91d72eabdb31fe5e623ad559f32cd/applets/taskmanager/package/contents/ui/ContextMenu.qml#L568

I've managed to get this sorta working with:

MouseArea {
    onClicked: {
        tasksModel.requestMove(tasksModel.activeTask)
    }
}

Video: https://streamable.com/vziac

However if I try triggering the requestMove in the middle of a drag, it foobars when the mouse is released. Mouse clicks are no longer registered.

I need to hit the global shortcut for KRunner to get input to work. I can also press Esc to fix it, but the window moves back to it's original location (which is a hint that it's KWin's state that's messed up instead of the plasmashell widget).

MouseArea {
    Item {
        id: dragTarget
        anchors.fill: parent
    }
    drag.target: dragTarget
    drag.onActiveChanged: console.log('drag.onActiveChanged', drag.active)
    onContainsMouseChanged: {
        console.log('onContainsMouseChanged', containsMouse)
        if (!containsMouse) {
            if (drag.active) {
                console.log('!containsMouse && drag.active')
                console.log('requestMove', tasksModel.activeTask)
                tasksModel.requestMove(tasksModel.activeTask)
                console.log('after tasksModel.requestMove')
            }
        }
    }
}

Video: https://streamable.com/weraq

Should it be possible to trigger it during a drag without breaking, we also need to make requestMouse not move the mouse to the center of the window.

The code for the X11 libtaskmanager is here:

https://github.com/KDE/plasma-workspace/blob/master/libtaskmanager/xwindowtasksmodel.cpp#L719

void XWindowTasksModel::requestMove(const QModelIndex &index)
{
    if (!index.isValid() || index.model() != this || index.row() < 0 || index.row() >= d->windows.count()) {
        return;
    }

    const WId window = d->windows.at(index.row());
    const KWindowInfo *info = d->windowInfo(window);

    bool onCurrent = info->isOnCurrentDesktop();

    if (!onCurrent) {
        KWindowSystem::setCurrentDesktop(info->desktop());
        KWindowSystem::forceActiveWindow(window);
    }

    if (info->isMinimized()) {
        KWindowSystem::unminimizeWindow(window);
    }

    const QRect &geom = info->geometry();

    NETRootInfo ri(QX11Info::connection(), NET::WMMoveResize);
    ri.moveResizeRequest(window, geom.center().x(), geom.center().y(), NET::Move);
}

Note the geom.center(). We'll need to ship our own C++ function that triggers the move at the current mouse coordinates so the mouse doesn't jump to the center.

Zren commented 6 years ago
if (direction == NET::Move) {
        // move cursor to the provided position to prevent the window jumping there on first movement
        // the expectation is that the cursor is already at the provided position,
        // thus it's more a safety measurement
        Cursor::setPos(QPoint(x_root, y_root));
        performMouseCommand(Options::MouseMove, QPoint(x_root, y_root));
case Options::MouseMove:
    case Options::MouseUnrestrictedMove: {
        if (!isMovableAcrossScreens())
            break;
        if (isMoveResize())
            finishMoveResize(false);
        setMoveResizePointerMode(PositionCenter);
        setMoveResizePointerButtonDown(true);
        setMoveOffset(QPoint(globalPos.x() - x(), globalPos.y() - y()));  // map from global
        setInvertedMoveOffset(rect().bottomRight() - moveOffset());
        setUnrestrictedMoveResize((cmd == Options::MouseActivateRaiseAndUnrestrictedMove
                                  || cmd == Options::MouseUnrestrictedMove));
        if (!startMoveResize())
            setMoveResizePointerButtonDown(false);
        updateCursor();
        break;
    }

Note:

kotelnik commented 6 years ago

Wonderful work @Zren, thanks for your interest, code and time spent on this! I'll dive in right away.

Zren commented 6 years ago

I can reproduce the bug with the "Window Move" global shortcut, so I think this might be a KWin bug.

https://bugs.kde.org/show_bug.cgi?id=392784

Zren commented 6 years ago

So according to the KWin maintainer, it seems we need to "ungrab" the mouse before calling tasksModel.requestMove(tasksModel.activeTask).

I recently found KDeclarative's EventGenerator class, but I can't seem to get any good results. It's still buggy.

import org.kde.kquickcontrolsaddons 2.0 // EventGenerator

MouseArea {
    EventGenerator {
        id: eventGenerator
    }

    onPressed: {
        eventGenerator.sendGrabEvent(mouseArea, EventGenerator.UngrabMouse)
        tasksModel.requestMove(tasksModel.activeTask)
    }
}

Wasn't able to get it working with kdeclariative's MouseEventListener either.

jidibinlin commented 5 years ago

Hi! I have the same problem. Some apps can be dragged from maximized status(firefox) but konsole, vscode ..... can`t dragged directorly.