gnome-shellgnome-shell-extensions

Gnome Shell Extension: Resize and position a window on creation


I am trying to write a Gnome Shell extension that resizes and positions a window when it is created. I am using the move_resize_frame method provided by the Meta.Window object to set the window's size and position, and I've also tried move and move_resize_frame. However, while the window is sized correctly, it is not being positioned correctly, and it seems that the window manager is applying some constraints on the window position. The window is not maximized.

Here is the code I am using:

let windowCreatedId, sizeChangedId;

function init() {
}

function enable() {
    windowCreatedId = global.display.connect('window-created', onWindowCreated);
}

function disable() {
    global.display.disconnect(windowCreatedId);
    if (sizeChangedId)
        global.display.disconnect(sizeChangedId);
}

function onWindowCreated(display, win) {
    sizeChangedId = win.connect('size-changed', onSizeChanged);
    resizeWindow(win);
}

function onSizeChanged(win) {
    resizeWindow(win);
}

function resizeWindow(win) {
    win.move_resize_frame(false, 20, 20, 2000, 2000);
}

What am I missing or what should I change to make this extension work properly?


Solution

  • Instead of the size-changed signal, you need to connect to the first-frame signal, which is triggered when the frame is first drawn on the screen.

    Here's a full implementation:

    const Meta = imports.gi.Meta;
    
    let windowCreatedId;
    
    function init() {
    }
    
    function enable() {
        windowCreatedId = global.display.connect('window-created', onWindowCreated);
    }
    
    function disable() {
        global.display.disconnect(windowCreatedId);
    }
    
    function onWindowCreated(display, win) {
        const act = win.get_compositor_private();
        const id = act.connect('first-frame', _ => {
            resizeWindow(win);
            act.disconnect(id);
        });
    }
    
    function resizeWindow(win) {
        win.move_resize_frame(false, 20, 20, 2000, 2000);
    }
    

    It uses the window's get_compositor_private() method, which feels a little iffy, but it works (and Material Shell uses it too...)