15

I have dual display configuration, and want all new and old applications start on primary display, which is on the right. But some apps start on second screen, regardless where focus/mouse pointer is. I think this is because top:left corner 0:0 is on second monitor. And its bigger then primary, can this be a cause?

Secondary is a TV where I run kodi, which have a setting to choose display.

May be there are some app what remember for every app position and display, and also take care when second is turned off - mean remember position until monitor is on again. In earlier versions of ubuntu compiz do that, but no more.

Update: Changed DE to cinnamon

11
  • I'm also looking for this, have you had any luck?
    – Felipe
    Apr 8, 2019 at 22:21
  • @Felipe No luck
    – LeonidMew
    Apr 9, 2019 at 8:21
  • In applications list in cinnamon, I have menu option to move app to different monitor, its useful especially when secondary is turned off. But this not solution to a question.
    – LeonidMew
    Apr 9, 2019 at 9:24
  • 1
    A solution could be a little deamon-like process, to watch out for new windows, move them to your primary screen. Would that be an acceptable solution? You'd probably even not see it being moved. Apr 9, 2019 at 10:17
  • @JacobVlijm Yes, this can be solution. But I don't known how to write it, can you please give two code pieces - how to determine new window and how to move
    – LeonidMew
    Apr 9, 2019 at 10:26

2 Answers 2

15
+150

Be prepared to get your hands dirty
On the edge of what I feel we could ask users to do, but on the other hand, when instructions are clear, why not? So here we go...


Background process to set on which monitor new windows should appear

The Vala snippet

using Wnck;
using Gdk;
using Gtk;

// compile:
// valac --pkg gtk+-3.0 --pkg gio-2.0 --pkg libwnck-3.0 -X "-D WNCK_I_KNOW_THIS_IS_UNSTABLE" 'file.vala'

namespace move_newwins {

    private int[] monitor_geo_x;
    private int[] monitor_geo_y;
    private int monitorindex;
    private string currmon;

    private void getwins() {
        var dsp = Gdk.Display.get_default();
        unowned Wnck.Screen scr = Wnck.Screen.get_default();
        scr.force_update();
        get_monitors(dsp);
        scr.window_opened.connect(newwin);
    }

    private void newwin (Wnck.Window newwin) {
        newwin.unmaximize();
        int winx;
        int winy;
        int winwidth;
        int winheight;
        newwin.get_geometry(out winx, out winy, out winwidth, out winheight);
        Wnck.WindowType type = newwin.get_window_type();
        if (type == Wnck.WindowType.NORMAL) {
            newwin.set_geometry(
                Wnck.WindowGravity.NORTHWEST,
                Wnck.WindowMoveResizeMask.X |
                Wnck.WindowMoveResizeMask.Y |
                Wnck.WindowMoveResizeMask.WIDTH |
                Wnck.WindowMoveResizeMask.HEIGHT,
                monitor_geo_x[monitorindex] + 100,
                monitor_geo_y[monitorindex] + 100,
                winwidth, winheight
            );
        }
    }

    private int get_stringindex (string s, string[] arr) {
        for (int i=0; i < arr.length; i++) {
            if(s == arr[i]) return i;
        } return -1;
    }

    private void get_monitors(Gdk.Display dsp) {
        int nmons = dsp.get_n_monitors();
        string[] monitornames = {};
        for (int i=0; i < nmons; i++) {
            Gdk.Monitor newmon = dsp.get_monitor(i);
            monitornames += newmon.get_model();
            Rectangle geo = newmon.get_geometry();
            monitor_geo_x += geo.x;
            monitor_geo_y += geo.y;
            monitorindex = get_stringindex(
                currmon, monitornames
            );
        }
    }

    public static void main (string[] args) {
        currmon = args[1];
        Gtk.init(ref args);
        getwins();
        Gtk.main();
    }
}
  1. The Vala snippet needs to be compiled. To do so you need to install a few things:

    sudo apt install valac libwnck-3-dev libgtk-3-dev
    
  2. Copy the snippet below, save it as win_tomonitor.vala

  3. Compile the snippet with the command:

    valac --pkg gtk+-3.0 --pkg gio-2.0 --pkg libwnck-3.0 -X "-D WNCK_I_KNOW_THIS_IS_UNSTABLE" '/path/to/win_tomonitor.vala' 
    

    (I know, the wnck argument is silly, but needed), an executable will be produced in the working directory.

  4. Find out the name of your primary monitor by running the command xrandrin terminal.
  5. Run the executable with the targeted monitor as argument, e.g.

    /path/to/win_tomonitor HDMI-1
    

New ("normal") windows will appear on 100px (x + y) from topleft of the targeted monitor.

N.B.

When adding this as a startup item, you might need to add a break of a few seconds before running it. If you run into issues on login/startup, please mention.


EDIT

Below an edited version (on request). Differences:

  • This version skips action on windows which already are on the targeted monitor.
  • This version allows to set excluded WM_CLASS -es. To exclude one or more classes: add extra arguments after the targeted monitor- argument. An example:

    /path/to/win_tomonitor HDMI-1 Tilix Gedit
    

    to exclude both Tilix and gedit windows from moving.

Setup is exactly the same as the first version. Have fun!

Find out a window's WM_CLASS

  • Open a terminal window
  • Type xprop, Press Return
  • click on the targeted window, The WM_CLASS appears in terminal

The code

using Wnck;
using Gdk;
using Gtk;

// compile:
// valac --pkg gtk+-3.0 --pkg gio-2.0 --pkg libwnck-3.0 -X "-D WNCK_I_KNOW_THIS_IS_UNSTABLE" 'file.vala'

namespace move_newwins {

    private int[] monitor_geo_x;
    private int[] monitor_geo_y;
    private int monitorindex;
    private string currmon;
    Gdk.Display dsp;
    string[] blacklist;

    private void getwins() {
        dsp = Gdk.Display.get_default();
        unowned Wnck.Screen scr = Wnck.Screen.get_default();
        scr.force_update();
        get_monitors(dsp);
        scr.window_opened.connect(newwin);
    }

    private void newwin (Wnck.Window newwin) {
        newwin.unmaximize();
        int winx;
        int winy;
        int winwidth;
        int winheight;
        newwin.get_geometry(out winx, out winy, out winwidth, out winheight);
        string wins_monitor = dsp.get_monitor_at_point(winx, winy).get_model();
        Wnck.WindowType type = newwin.get_window_type();
        string wm_class = newwin.get_class_group_name();
        bool blacklisted = get_stringindex(wm_class, blacklist) != -1;

        if (
            type == Wnck.WindowType.NORMAL &&
            wins_monitor != currmon &&
            !blacklisted
        ) {
            newwin.set_geometry(
                Wnck.WindowGravity.NORTHWEST,
                Wnck.WindowMoveResizeMask.X |
                Wnck.WindowMoveResizeMask.Y |
                Wnck.WindowMoveResizeMask.WIDTH |
                Wnck.WindowMoveResizeMask.HEIGHT,
                monitor_geo_x[monitorindex] + 100,
                monitor_geo_y[monitorindex] + 100,
                winwidth, winheight
            );
        }
    }

    private int get_stringindex (string s, string[] arr) {
        for (int i=0; i < arr.length; i++) {
            if(s == arr[i]) return i;
        } return -1;
    }

    private void get_monitors(Gdk.Display dsp) {
        int nmons = dsp.get_n_monitors();
        string[] monitornames = {};
        for (int i=0; i < nmons; i++) {
            Gdk.Monitor newmon = dsp.get_monitor(i);
            monitornames += newmon.get_model();
            Rectangle geo = newmon.get_geometry();
            monitor_geo_x += geo.x;
            monitor_geo_y += geo.y;
            monitorindex = get_stringindex(
                currmon, monitornames
            );
        }
    }

    public static void main (string[] args) {
        currmon = args[1];
        blacklist = args[1:args.length];
        Gtk.init(ref args);
        getwins();
        Gtk.main();
    }
}
2
  • Command valac not found. When I try to install it with apt install valac, script isn't finding some IPs Jan 28, 2020 at 14:08
  • Working correctly on Ubuntu 22.0.4. +1 (didn't test the edit) Thanks a lot Jacob! (making our life easier) PS : There were a few case were the application (window) was opened on the wrong monitor but in most of the cases the solution works. May 3 at 7:35
0

you want the simple answer? open the app, go to the screen its opened on. maximise, then restore (window it). drag it to the screen you want it to open on, maximise then close it. next and every time you open the app it will be on the correct screen

1
  • Thanks. I can't try it right now. You forgot to specify what version of Ubuntu this behaviour belongs. This was not working this way at 2019.
    – LeonidMew
    Sep 17 at 3:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .