Advertisement
Guest User

AppFocusWrapper.js

a guest
Oct 16th, 2018
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // It would be nice if a "focused" prop was
  2. // provided by default by ShellApps...
  3. //
  4. // Things also get a little weird when there are more
  5. // than one instance of a player running at the same time.
  6. // As far as ShellApp is concerned they are the same app.
  7. // So we have to jump though a bunch of hoops to keep track
  8. // of and differentiate the windows.
  9. var AppFocusWrapper = GObject.registerClass({
  10.     GTypeName: "AppFocusWrapper",
  11.     Properties: {
  12.         "focused": GObject.ParamSpec.boolean(
  13.             "focused",                                          // property name
  14.             "focused-prop",                                     // nickname
  15.             "If any window that belongs to the app is focused", // description
  16.             GObject.ParamFlags.READABLE,                        // flags READABLE/READWRITE/CONSTRUCT/etc
  17.             false                                               // default value
  18.         )
  19.     }
  20. }, class AppFocusWrapper extends GObject.Object {
  21.     _init(shellApp, busName) {
  22.         super._init();
  23.         this._app = shellApp;
  24.         this._busName = busName;
  25.         this._focused = false;
  26.         this._onWindowsChanged();
  27.         this._onAppearsFocusedChanged();
  28.         this._windowsChangedId = this._app.connect(
  29.             "windows-changed",
  30.             this._onWindowsChanged.bind(this)
  31.         );
  32.     }
  33.  
  34.     get focused() {
  35.         return this._focused;
  36.     }
  37.  
  38.     _getNewAppWindow() {
  39.         // We want an "unclaimed" "Normal" window.
  40.         // Windows of all kinds, from all instances
  41.         // of an app will show up in "get_windows".
  42.         for (let window of this._app.get_windows()) {
  43.             if (!window.skip_taskbar &&
  44.                 window.window_type === Meta.WindowType.NORMAL &&
  45.                 !window.hasOwnProperty("_busName")) {
  46.                 return window;
  47.             }
  48.         }
  49.         return null;
  50.     }
  51.  
  52.     _getCurrentAppWindow() {
  53.         // We only want the window that matches this instance if any.
  54.         for (let window of this._app.get_windows()) {
  55.             if (window.hasOwnProperty("_busName") && window._busName === this._busName) {
  56.                 return window;
  57.             }
  58.         }
  59.         return null;
  60.     }
  61.  
  62.     _getNumOfInstances() {
  63.         // Count the number of "claimed" windows.
  64.         return Array.from(this._app.get_windows()).filter(w => w.hasOwnProperty("_busName")).length;
  65.     }
  66.  
  67.     _onWindowsChanged() {
  68.         // We get this signal when windows appear and disappear.
  69.         // We only really care about them appearing.
  70.         // We handle the disappear in _onUnmanaged.
  71.         let currentAppWindow = this._getCurrentAppWindow();
  72.         if (!currentAppWindow) {
  73.             let appWindow = this._getNewAppWindow();
  74.             if (appWindow) {
  75.                 appWindow._busName = this._busName;
  76.                 appWindow._unmanagedId = appWindow.connect(
  77.                     "unmanaged",
  78.                     this._onUnmanaged.bind(this)
  79.                 );
  80.                 appWindow._appearsFocusedId = appWindow.connect(
  81.                     "notify::appears-focused",
  82.                     this._onAppearsFocusedChanged.bind(this)
  83.                 );
  84.             }
  85.         }
  86.     }
  87.  
  88.     _onAppearsFocusedChanged() {
  89.         // Pretty self explanatory...
  90.         let currentAppWindow = this._getCurrentAppWindow();
  91.         let focused = currentAppWindow && currentAppWindow.has_focus();
  92.         if (this._focused != focused) {
  93.             this._focused = focused;
  94.             this.notify("focused");
  95.         }
  96.     }
  97.  
  98.     _onUnmanaged() {
  99.         // Basically for our purposes an "unmanaged" window is
  100.         // one that has been hidden and is about to be destroyed.
  101.         // So we disconnect our signals.
  102.         let currentAppWindow = this._getCurrentAppWindow();
  103.         if (currentAppWindow) {
  104.             if (currentAppWindow.hasOwnProperty("_unmanagedId") && currentAppWindow._unmanagedId) {
  105.                 currentAppWindow.disconnect(appWindow._unmanagedId);
  106.                 currentAppWindow._unmanagedId = null;
  107.             }
  108.             if (currentAppWindow.hasOwnProperty("_appearsFocusedId") && currentAppWindow._appearsFocusedId) {
  109.                 currentAppWindow.disconnect(appWindow._appearsFocusedId);
  110.                 currentAppWindow._appearsFocusedId = null;
  111.             }
  112.         }
  113.     }
  114.  
  115.     toggleWindow(minimize) {
  116.         if (!this._focused) {
  117.             // This is important. If we just called "activate" on an
  118.             // app with more than one instance we'd just raise the
  119.             // last active window regardless of which instance
  120.             // we actually wanted to raise.
  121.             // Multiple instance apps that have their window hidden
  122.             // will get the last active window.  
  123.             if (this._getNumOfInstances() > 1) {
  124.                 let currentAppWindow = this._getCurrentAppWindow();
  125.                 let eventTimeStamp = Gtk.get_current_event_time();
  126.                 this._app.activate_window(
  127.                     currentAppWindow,
  128.                     eventTimeStamp
  129.                 );
  130.             } else {
  131.                 this._app.activate();
  132.             }
  133.             return true;
  134.         } else if (minimize) {
  135.             let currentAppWindow = this._getCurrentAppWindow();
  136.             if (currentAppWindow && currentAppWindow.can_minimize()) {
  137.                 currentAppWindow.minimize();
  138.                 return true;
  139.             }
  140.         }
  141.         return false;
  142.     }
  143.  
  144.     destroy() {
  145.         if (this._app && this._windowsChangedId) {
  146.             this._app.disconnect(this._windowsChangedId);
  147.         }
  148.         this._windowsChangedId = null;
  149.         this._onUnmanaged();
  150.         this._app = null;
  151.         this._focused = null;
  152.         this._busName = null;
  153.         super.run_dispose();
  154.     }
  155. });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement