[gnome-shell-extensions/wip/fmuellner/fix-auto-move: 5/5] auto-move-windows: Track apps' windows instead of window creation



commit 282fb9e271c15da1db70758ac94d522c3271cb93
Author: Florian Müllner <fmuellner gnome org>
Date:   Thu Dec 21 21:01:53 2017 +0100

    auto-move-windows: Track apps' windows instead of window creation
    
    We currently track window creation to decide whether the new window
    should be moved or not. In order for this to work, the window must
    already have been matched to the correct application, which is only
    the case when the properties used for app matching were supplied
    during window creation.
    
    This is usually the case on X11, but never on wayland. To avoid this
    issue altogether, stop listening for raw window creations, and instead
    track when a window is added to an application we are interested in.
    
    https://gitlab.gnome.org/GNOME/gnome-shell-extensions/issues/33

 extensions/auto-move-windows/extension.js | 93 ++++++++++++++++++++-----------
 1 file changed, 61 insertions(+), 32 deletions(-)
---
diff --git a/extensions/auto-move-windows/extension.js b/extensions/auto-move-windows/extension.js
index 92ce7b1..5e4bd6d 100644
--- a/extensions/auto-move-windows/extension.js
+++ b/extensions/auto-move-windows/extension.js
@@ -1,7 +1,6 @@
 // -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
 // Start apps on custom workspaces
 
-const Mainloop = imports.mainloop;
 const Shell = imports.gi.Shell;
 
 const Main = imports.ui.main;
@@ -13,12 +12,13 @@ const Convenience = Me.imports.convenience;
 class WindowMover {
     constructor() {
         this._settings = Convenience.getSettings();
-        this._windowTracker = Shell.WindowTracker.get_default();
+        this._appSystem = Shell.AppSystem.get_default();
         this._appConfigs = new Map();
+        this._appData = new Map();
 
-        let display = global.screen.get_display();
-        // Connect after so the handler from ShellWindowTracker has already run
-        this._windowCreatedId = display.connect_after('window-created', this._findAndMove.bind(this));
+        this._appsChangedId =
+            this._appSystem.connect('installed-changed',
+                                    this._updateAppData.bind(this));
 
         this._settings.connect('changed', this._updateAppConfigs.bind(this));
         this._updateAppConfigs();
@@ -31,50 +31,79 @@ class WindowMover {
             let [appId, num] = v.split(':');
             this._appConfigs.set(appId, parseInt(num) - 1);
         });
+
+        this._updateAppData();
+    }
+
+    _updateAppData() {
+        let ids = [...this._appConfigs.keys()];
+        let removedApps = [...this._appData.keys()].filter(
+            a => !ids.includes(a.id)
+        );
+        removedApps.forEach(app => {
+            app.disconnect(this._appData.get(app).windowsChangedId);
+            this._appData.delete(app);
+        });
+
+        let addedApps = ids.map(id => this._appSystem.lookup_app(id)).filter(
+            app => app != null && !this._appData.has(app)
+        );
+        addedApps.forEach(app => {
+            let data = {
+                windowsChangedId: app.connect('windows-changed',
+                                              this._appWindowsChanged.bind(this)),
+                moveWindowsId: 0,
+                windows: app.get_windows()
+            }
+            this._appData.set(app, data);
+        });
     }
 
     destroy() {
-        if (this._windowCreatedId) {
-            global.screen.get_display().disconnect(this._windowCreatedId);
-            this._windowCreatedId = 0;
+        if (this._appsChangedId) {
+            this._appSystem.disconnect(this._appsChangedId);
+            this._appsChangedId = 0;
         }
 
         if (this._settings) {
             this._settings.run_dispose();
             this._settings = null;
         }
-    }
 
-    _ensureAtLeastWorkspaces(num, window) {
-        for (let i = global.screen.n_workspaces; i <= num; i++) {
-            window.change_workspace_by_index(i - 1, false);
-            global.screen.append_new_workspace(false, 0);
-        }
+        this._appConfigs.clear();
+        this._updateAppData();
     }
 
-    _findAndMove(display, window, noRecurse) {
+    _moveWindow(window, workspaceNum) {
         if (window.skip_taskbar)
             return;
 
-        let app = this._windowTracker.get_window_app(window);
-        if (!app) {
-            if (!noRecurse) {
-                // window is not tracked yet
-                Mainloop.idle_add(() => {
-                    this._findAndMove(display, window, true);
-                    return false;
-                });
-            } else
-                log ('Cannot find application for window');
-            return;
+        // ensure we have the required number of workspaces
+        for (let i = global.screen.n_workspaces; i <= workspaceNum; i++) {
+            window.change_workspace_by_index(i - 1, false);
+            global.screen.append_new_workspace(false, 0);
         }
-        let workspaceNum = this._appConfigs.get(app.get_id());
-        if (workspaceNum !== undefined) {
-            if (workspaceNum >= global.screen.n_workspaces)
-                this._ensureAtLeastWorkspaces(workspaceNum, window);
 
-            window.change_workspace_by_index(workspaceNum, false);
-        }
+        window.change_workspace_by_index(workspaceNum, false);
+    }
+
+    _appWindowsChanged(app) {
+        let data = this._appData.get(app);
+        let windows = app.get_windows();
+
+        // If get_compositor_private() returns non-NULL on a removed windows,
+        // the window still exists and is just moved to a different workspace
+        // or something; assume it'll be added back immediately, so keep it
+        // to avoid moving it again
+        windows.push(...data.windows.filter(
+            w => !windows.includes(w) && w.get_compositor_private() != null
+        ));
+
+        let workspaceNum = this._appConfigs.get(app.id);
+        windows.filter(w => !data.windows.includes(w)).forEach(window => {
+            this._moveWindow(window, workspaceNum);
+        });
+        data.windows = windows;
     }
 };
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]