Advertisement
Guest User

Sample extension.js demonstrating problem.

a guest
Sep 6th, 2012
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2. The setup:
  3.  
  4. An indicator in the panel (Shell.GenericContainer), containing
  5. - workspaces (St.Bin containing a St.Group/St.Widget (depending on GNOME 3.2 or 3.4))
  6.   containing:
  7.   - windows (St.Bin)
  8.  
  9. The window St.Bins adjust their size/position with their actual windows, and although this works, I **do not see the St.Bins move accordingly unless I call queue_relayout() on the Shell.GenericContainer**. Calling .queue_relayout() on anything else has no effect, and ommitting any .queue_relayout() call also has no effect (i.e. St.Bin doesn't move).
  10.  
  11. To demonstrate this I've called .queue_relayout() on the size-changed signal and not called it in the position-changed signal, so when you move windows around you will not see the St.Bins move, but when you change their size the St.Bins will be updated. (in the WindowClone class)
  12.  
  13. How can I fix this? I shouldn't have to store a pointer to the SHell.GenericContainer *within* the lowest-level St.Bin simply to call .queue_relayout?
  14.  
  15. */
  16.  
  17. /////     CODE     ////
  18. const Lang = imports.lang;
  19. const Mainloop = imports.mainloop;
  20. const Shell = imports.gi.Shell;
  21. const St = imports.gi.St;
  22.  
  23. const Main = imports.ui.main;
  24. const PanelMenu = imports.ui.panelMenu;
  25.  
  26. /* Compatibility for dev version (remove later) */
  27. const StGroup = St.Group || St.Widget;
  28.  
  29. /* Extension variables */
  30. let indicator;
  31.  
  32. // the indicator in the top panel
  33. function WorkspaceApplet() {
  34.     this._init.apply(this, arguments);
  35. }
  36.  
  37. WorkspaceApplet.prototype = {
  38.     __proto__: PanelMenu.Button.prototype,
  39.  
  40.     _init: function () {
  41.         PanelMenu.Button.prototype._init.call(this,
  42.                 St.Align.START,       // menu alignment
  43.                 'workspace-inicator'  // text
  44.         );
  45.  
  46.         this._container = new Shell.GenericContainer({
  47.             reactive: true
  48.         });
  49.         this._container.connect('get-preferred-width',
  50.                 Lang.bind(this, this._getPreferredWidth));
  51.         this._container.connect('get-preferred-height',
  52.                 Lang.bind(this, this._getPreferredHeight));
  53.         this._container.connect('allocate', Lang.bind(this, this._allocate));
  54.  
  55.         this.actor.add_actor(this._container);
  56.  
  57.  
  58.         // add a "workspace" actor.
  59.         let workspace = new WorkspaceThumbnail(0);
  60.         this._container.add_actor(workspace.actor);
  61.     },
  62.  
  63.     //// allocation ////
  64.  
  65.     _getPreferredHeight: function (actor, forWidth, alloc) {
  66.         alloc.min_size = alloc.natural_size = Main.panel.actor.height;
  67.     },
  68.  
  69.     _getPreferredWidth: function (actor, forHeight, alloc) {
  70.         alloc.min_size = alloc.natural_size = Main.panel.actor.height * global.stage.width / global.stage.height;
  71.     },
  72.  
  73.     _allocate: function (actor, box, flags) {
  74.         let children = this._container.get_children();
  75.  
  76.         // just allocate the whole space
  77.         children[0].allocate(box, flags);
  78.     }
  79. };
  80.  
  81. // represents a workspace, contains up-to-date snapshot of window.
  82. function WorkspaceThumbnail() {
  83.     this._init.apply(this, arguments);
  84. }
  85.  
  86. WorkspaceThumbnail.prototype = {
  87.     _init: function (index) {
  88.         this._index = index;
  89.         this.workspace = global.screen.get_workspace_by_index(index);
  90.  
  91.         this.actor = new St.Bin({
  92.             track_hover: true,
  93.             reactive: true
  94.         });
  95.         this.actor.style = 'border: 1px solid white; background: #888888'; // so we can see
  96.         this.actor._delegate = this;
  97.  
  98.         // need to hold many windows
  99.         this._workspace = new  StGroup({
  100.             clip_to_allocation: true
  101.         });
  102.         this.actor.child = this._workspace;
  103.  
  104.         this.workspace.connect('window-added', Lang.bind(this, this._onWindowAdded));
  105.     },
  106.  
  107.     _onWindowAdded: function (ws, win) {
  108.         let winActor = win.get_compositor_private();
  109.         if (!winActor) {
  110.             Mainloop.idle_add(Lang.bind(this, function () {
  111.                 this._onWindowAdded(ws, win);
  112.             }));
  113.         } else {
  114.             // window has an actor, make a clone for it.
  115.             log('making clone of window ' + win.get_title());
  116.             let clone = new WindowClone(winActor);
  117.             this._workspace.add_actor(clone.actor);
  118.         }
  119.     },
  120. };
  121.  
  122. // one per window
  123. function WindowClone() {
  124.     this._init.apply(this, arguments);
  125. }
  126.  
  127. WindowClone.prototype = {
  128.     _init: function (winActor) {
  129.         this.actor = new St.Bin({
  130.             x_fill: false,
  131.             y_fill: false,
  132.             x_align: St.Align.MIDDLE,
  133.             y_align: St.Align.MIDDLE
  134.         });
  135.         this.actor._delegate = this;
  136.         this.actor.style = 'border: 1px solid white; background: #cecece'; // so we can see
  137.  
  138.         this.winActor = winActor;
  139.         this.metaWindow = winActor.meta_window;
  140.  
  141.         // we could use .set_scale but that makes it not as easy to
  142.         // style the St.Bin (e.g. if border width is 1 and we use a scale
  143.         // factor on the actor, we won't see the border at all)
  144.         // hard code scale for now; in reality it is based off the WorkspaceThumbnail's
  145.         // width/height.
  146.         this._scale = Main.panel.actor.height / global.stage.height;
  147.  
  148.         if (!this.actor.realized) {
  149.             let onetime = this.actor.connect('notify::realized',
  150.                 Lang.bind(this, function () {
  151.                 if (this.actor.realized) {
  152.                     this.actor.disconnect(onetime);
  153.                     this.init();
  154.                 }
  155.             }));
  156.         } else {
  157.             this.init();
  158.         }
  159.     },
  160.  
  161.     init: function () {
  162.         this.winActor.connect('position-changed', Lang.bind(this, this._onPositionChanged));
  163.         this.winActor.connect('size-changed', Lang.bind(this, this._onSizeChanged));
  164.  
  165.         this._grandaddy = indicator.actor;
  166.        
  167.         this._onPositionChanged();
  168.         this._onSizeChanged();
  169.     },
  170.  
  171.     _onPositionChanged: function () {
  172.         // update our position
  173.         let rect = this.metaWindow.get_outer_rect(),
  174.             newx = Math.round(rect.x * this._scale),
  175.             newy = Math.round(rect.y * this._scale);
  176.         if (this.actor.x === newx && this.actor.y === newy) {
  177.             return;
  178.         }
  179.         // log('new position %d, %d'.format(newx, newy));
  180.         this.actor.x = newx;
  181.         this.actor.y = newy;
  182.  
  183.         // NOTE !! If I don't include the following line, the thumbnail
  184.         // will not update !! why is this?
  185.         // this.actor.queue_relayout, this.parent.queue_relayout all do
  186.         // *not* cause the thumbnail to update.
  187.         /* // uncomment the following to make it work
  188.         if (this._grandaddy) {
  189.             this._grandaddy.queue_relayout();
  190.         }
  191.         */
  192.     },
  193.  
  194.     _onSizeChanged: function () {
  195.         let rect = this.metaWindow.get_outer_rect(),
  196.             newwid = Math.round(rect.width * this._scale),
  197.             newh   = Math.round(rect.height * this._scale);
  198.         if (this.actor.width === newwid && this.actor.height === newh) {
  199.             return;
  200.         }
  201.         // log('new size %dx%d'.format(newwid, newh));
  202.         this.actor.width = newwid;
  203.         this.actor.height = newh;
  204.  
  205.         // NOTE !! If I don't include the following line, the thumbnail
  206.         // will not update !! why is this?
  207.         // this.actor.queue_relayout, this.parent.queue_relayout all do
  208.         // *not* cause the thumbnail to update.
  209.         if (this._grandaddy) {
  210.             this._grandaddy.queue_relayout();
  211.         }
  212.     }
  213. };
  214.  
  215. /** Extension code **/
  216. function init(metadata) {
  217. }
  218.  
  219. function enable() {
  220.     indicator = new WorkspaceApplet();
  221.     Main.panel.addToStatusArea('graphical-workspace-indicator', indicator);
  222. }
  223.  
  224. function disable() {
  225.     indicator = null;
  226. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement