From 8d017ceaf1dffd3c35c15fea3dba810c6e36744a Mon Sep 17 00:00:00 2001 From: Rui Matos Date: Thu, 14 Jun 2012 19:43:15 +0200 Subject: [PATCH] boxpointer: Flip side if we would end outside the monitor This flips the BoxPointer if it ends outside the monitor and we have enough space to fit it inside, on the opposite side of the source actor. https://bugzilla.gnome.org/show_bug.cgi?id=678164 --- js/ui/boxpointer.js | 68 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/js/ui/boxpointer.js b/js/ui/boxpointer.js index 05356516c..d09c8bf77 100644 --- a/js/ui/boxpointer.js +++ b/js/ui/boxpointer.js @@ -18,7 +18,10 @@ const POPUP_ANIMATION_TIME = 0.15; * * An actor which displays a triangle "arrow" pointing to a given * side. The .bin property is a container in which content can be - * placed. The arrow position may be controlled via setArrowOrigin(). + * placed. The arrow position may be controlled via + * setArrowOrigin(). The arrow side might be temporarily flipped + * depending on the box size and source position to keep the box + * totally inside the monitor if possible. * */ const BoxPointer = new Lang.Class({ @@ -26,6 +29,7 @@ const BoxPointer = new Lang.Class({ _init: function(arrowSide, binProperties) { this._arrowSide = arrowSide; + this._userArrowSide = arrowSide; this._arrowOrigin = 0; this.actor = new St.Bin({ x_fill: true, y_fill: true }); @@ -199,8 +203,27 @@ const BoxPointer = new Lang.Class({ } this.bin.allocate(childBox, flags); - if (this._sourceActor && this._sourceActor.mapped) + if (this._sourceActor && this._sourceActor.mapped) { this._reposition(this._sourceActor, this._arrowAlignment); + + if (this._shouldFlip()) { + switch (this._arrowSide) { + case St.Side.TOP: + this._arrowSide = St.Side.BOTTOM; + break; + case St.Side.BOTTOM: + this._arrowSide = St.Side.TOP; + break; + case St.Side.LEFT: + this._arrowSide = St.Side.RIGHT; + break; + case St.Side.RIGHT: + this._arrowSide = St.Side.LEFT; + break; + } + this._reposition(this._sourceActor, this._arrowAlignment); + } + } }, _drawBorder: function(area) { @@ -327,6 +350,8 @@ const BoxPointer = new Lang.Class({ }, setPosition: function(sourceActor, alignment) { + this._arrowSide = this._userArrowSide; + // We need to show it now to force an allocation, // so that we can query the correct size. this.actor.show(); @@ -343,11 +368,7 @@ const BoxPointer = new Lang.Class({ if (!this._sourceActor) return; - // We need to show it now to force an allocation, - // so that we can query the correct size. - this.actor.show(); - - this._reposition(this._sourceActor, this._arrowAlignment); + this.setPosition(this._sourceActor, this._arrowAlignment); }, _reposition: function(sourceActor, alignment) { @@ -446,6 +467,39 @@ const BoxPointer = new Lang.Class({ -(this._yPosition + this._yOffset)); }, + _shouldFlip: function() { + let sourceAllocation = Shell.util_get_transformed_allocation(this._sourceActor); + let boxAllocation = Shell.util_get_transformed_allocation(this.actor); + let boxWidth = boxAllocation.x2 - boxAllocation.x1; + let boxHeight = boxAllocation.y2 - boxAllocation.y1; + let monitor = Main.layoutManager.findMonitorForActor(this.actor); + + switch (this._arrowSide) { + case St.Side.TOP: + if (boxAllocation.y2 > monitor.y + monitor.height && + boxHeight < sourceAllocation.y1 - monitor.y) + return true; + break; + case St.Side.BOTTOM: + if (boxAllocation.y1 < monitor.y && + boxHeight < monitor.y + monitor.height - sourceAllocation.y2) + return true; + break; + case St.Side.LEFT: + if (boxAllocation.x2 > monitor.x + monitor.width && + boxWidth < sourceAllocation.x1 - monitor.x) + return true; + break; + case St.Side.RIGHT: + if (boxAllocation.x1 < monitor.x && + boxWidth < monitor.x + monitor.width - sourceAllocation.x2) + return true; + break; + } + + return false; + }, + set xOffset(offset) { this._xOffset = offset; this._shiftActor();