diff --git a/js/misc/util.js b/js/misc/util.js index 072dbce91..9e8dfa4ef 100644 --- a/js/misc/util.js +++ b/js/misc/util.js @@ -2,6 +2,7 @@ const Clutter = imports.gi.Clutter; const GLib = imports.gi.GLib; +const Lang = imports.lang; const St = imports.gi.St; const Main = imports.ui.main; @@ -189,28 +190,57 @@ function insertSorted(array, val, cmp) { return pos; } -function makeCloseButton() { - let closeButton = new St.Button({ style_class: 'notification-close'}); +const CloseButton = new Lang.Class({ + Name: 'CloseButton', + Extends: St.Button, - // This is a bit tricky. St.Bin has its own x-align/y-align properties - // that compete with Clutter's properties. This should be fixed for - // Clutter 2.0. Since St.Bin doesn't define its own setters, the - // setters are a workaround to get Clutter's version. - closeButton.set_x_align(Clutter.ActorAlign.END); - closeButton.set_y_align(Clutter.ActorAlign.START); + _init: function(boxpointer) { + this.parent({ style_class: 'notification-close'}); - // XXX Clutter 2.0 workaround: ClutterBinLayout needs expand - // to respect the alignments. - closeButton.set_x_expand(true); - closeButton.set_y_expand(true); + // This is a bit tricky. St.Bin has its own x-align/y-align properties + // that compete with Clutter's properties. This should be fixed for + // Clutter 2.0. Since St.Bin doesn't define its own setters, the + // setters are a workaround to get Clutter's version. + this.set_x_align(Clutter.ActorAlign.END); + this.set_y_align(Clutter.ActorAlign.START); - closeButton.connect('style-changed', function() { - let themeNode = closeButton.get_theme_node(); - closeButton.translation_x = themeNode.get_length('-shell-close-overlap-x'); - closeButton.translation_y = themeNode.get_length('-shell-close-overlap-y'); - }); + // XXX Clutter 2.0 workaround: ClutterBinLayout needs expand + // to respect the alignments. + this.set_x_expand(true); + this.set_y_expand(true); - return closeButton; + this._boxPointer = boxpointer; + if (boxpointer) + this._boxPointer.connect('arrow-side-changed', Lang.bind(this, this._sync)); + }, + + _computeBoxPointerOffset: function() { + if (!this._boxPointer || !this._boxPointer.actor.get_stage()) + return 0; + + let side = this._boxPointer.arrowSide; + if (side == St.Side.TOP) + return this._boxPointer.getArrowHeight(); + else + return 0; + }, + + _sync: function() { + let themeNode = this.get_theme_node(); + + let offY = this._computeBoxPointerOffset(); + this.translation_x = themeNode.get_length('-shell-close-overlap-x') + this.translation_y = themeNode.get_length('-shell-close-overlap-y') + offY; + }, + + vfunc_style_changed: function() { + this._sync(); + this.parent(); + }, +}); + +function makeCloseButton(boxpointer) { + return new CloseButton(boxpointer); } function ensureActorVisibleInScrollView(scrollView, actor) { diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js index 6d4586e08..0d9c5958f 100644 --- a/js/ui/appDisplay.js +++ b/js/ui/appDisplay.js @@ -1157,7 +1157,7 @@ const AppFolderPopup = new Lang.Class({ this.actor.add_actor(this._boxPointer.actor); this._boxPointer.bin.set_child(this._view.actor); - this.closeButton = Util.makeCloseButton(); + this.closeButton = Util.makeCloseButton(this._boxPointer); this.closeButton.connect('clicked', Lang.bind(this, this.popdown)); this.actor.add_actor(this.closeButton); diff --git a/js/ui/boxpointer.js b/js/ui/boxpointer.js index 272444f35..80dd11de9 100644 --- a/js/ui/boxpointer.js +++ b/js/ui/boxpointer.js @@ -3,8 +3,9 @@ const Clutter = imports.gi.Clutter; const Lang = imports.lang; const Meta = imports.gi.Meta; -const St = imports.gi.St; const Shell = imports.gi.Shell; +const Signals = imports.signals; +const St = imports.gi.St; const Main = imports.ui.main; const Tweener = imports.ui.tweener; @@ -61,6 +62,10 @@ const BoxPointer = new Lang.Class({ this._muteInput(); }, + get arrowSide() { + return this._arrowSide; + }, + _muteInput: function() { if (this._capturedEventId == 0) this._capturedEventId = this.actor.connect('captured-event', @@ -612,6 +617,8 @@ const BoxPointer = new Lang.Class({ this._container.queue_relayout(); return false; })); + + this.emit('arrow-side-changed'); } }, @@ -644,6 +651,8 @@ const BoxPointer = new Lang.Class({ updateArrowSide: function(side) { this._arrowSide = side; this._border.queue_repaint(); + + this.emit('arrow-side-changed'); }, getPadding: function(side) { @@ -654,3 +663,4 @@ const BoxPointer = new Lang.Class({ return this.actor.get_theme_node().get_length('-arrow-rise'); } }); +Signals.addSignalMethods(BoxPointer.prototype);