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

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

Open
luisfpg opened this Issue Jan 4, 2017 · 10 comments

Comments

Projects
None yet
7 participants
@luisfpg

luisfpg commented Jan 4, 2017

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

This comment has been minimized.

Owner

kotelnik commented Feb 7, 2017

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

@kupiqu

This comment has been minimized.

kupiqu commented Feb 13, 2017

That would certainly be a nice add :)

@cognifloyd

This comment has been minimized.

cognifloyd commented Feb 20, 2017

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

@Snuggle

This comment has been minimized.

Snuggle commented Sep 15, 2017

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

@nmabhinandan

This comment has been minimized.

nmabhinandan commented Oct 22, 2017

Any updates? 😋

@Zren

This comment has been minimized.

Zren commented Feb 8, 2018

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

This comment has been minimized.

Zren commented Feb 9, 2018

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:

  • onClicked (aka mouse button is up) will:
    • the mouse will move the mouse to the center when requestMove is called
    • the window will follow the mouse
    • let me move the mouse with keyboard arrow keys (which moves the window)
    • If you press Esc the window resets to it's original position
    • If you press Alt+Space, it opens KRunner and you can type into it. Esc will close Krunner and cancel the drag.
    • If you click, it will finish the move
  • onPressed (aka mouse button is still down) will:
    • move the mouse to the center when requestMove is called
    • the window does not follow the mouse
    • while the button is still down, you can use the keyboard arrow keys to control the mouse
    • when the button is released, the window will move to where the mouse is
    • after it's released, you can still control the mouse with the keyboard arrow keys. The window does not follow the mouse.
    • after it's released, you can move the mouse, but clicking does nothing
    • If you press Esc the window resets to it's original position
    • If you press Meta the Menu will appear, but you can't type anything or click it.
    • If you press Alt+Space to open KRunner, while KRunner doesn't show, you will regain control and mouse clicks start working again. Eg: If you do Alt+Space a second time, it will open KRunner.
@kotelnik

This comment has been minimized.

Owner

kotelnik commented Feb 13, 2018

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

@Zren

This comment has been minimized.

Zren commented Apr 6, 2018

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

This comment has been minimized.

Zren commented Apr 26, 2018

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment