diff --git a/js/ui/boxpointer.js b/js/ui/boxpointer.js index 68cea44eb..916005a9f 100644 --- a/js/ui/boxpointer.js +++ b/js/ui/boxpointer.js @@ -264,6 +264,92 @@ BoxPointer.prototype = { cr.stroke(); }, + setPosition: function(sourceActor, gap, alignment) { + let primary = global.get_primary_monitor(); + + // We need to show it now to force an allocation, + // so that we can query the correct size. + this.actor.show(); + + // Position correctly relative to the sourceActor + let [sourceX, sourceY] = sourceActor.get_transformed_position(); + let [sourceWidth, sourceHeight] = sourceActor.get_transformed_size(); + + let [minWidth, minHeight, natWidth, natHeight] = this.actor.get_preferred_size(); + + let resX, resY; + + switch (this._arrowSide) { + case St.Side.TOP: + resY = sourceY + sourceHeight + gap; + break; + case St.Side.BOTTOM: + resY = sourceY - natHeight - gap; + break; + case St.Side.LEFT: + resX = sourceX + sourceWidth + gap; + break; + case St.Side.RIGHT: + resX = sourceX - natWidth - gap; + break; + } + + // Now align and position the pointing axis, making sure + // it fits on screen + switch (this._arrowSide) { + case St.Side.TOP: + case St.Side.BOTTOM: + switch (alignment) { + case St.Align.START: + resX = sourceX; + break; + case St.Align.MIDDLE: + resX = sourceX - Math.floor((natWidth - sourceWidth) / 2); + break; + case St.Align.END: + resX = sourceX - (natWidth - sourceWidth); + break; + } + + resX = Math.min(resX, primary.x + primary.width - natWidth); + resX = Math.max(resX, primary.x); + + this.setArrowOrigin((sourceX - resX) + Math.floor(sourceWidth / 2)); + break; + + case St.Side.LEFT: + case St.Side.RIGHT: + switch (alignment) { + case St.Align.START: + resY = sourceY; + break; + case St.Align.MIDDLE: + resY = sourceY - Math.floor((natHeight - sourceHeight) / 2); + break; + case St.Align.END: + resY = sourceY - (natHeight - sourceHeight); + break; + } + + resY = Math.min(resY, primary.y + primary.height - natHeight); + resY = Math.max(resY, primary.y); + + this.setArrowOrigin((sourceY - resY) + Math.floor(sourceHeight / 2)); + break; + } + + let parent = this.actor.get_parent(); + let success, x, y; + while (!success) { + [success, x, y] = parent.transform_stage_point(resX, resY); + parent = parent.get_parent(); + } + + // Actually set the position + this.actor.x = Math.floor(x); + this.actor.y = Math.floor(y); + }, + // @origin: Coordinate specifying middle of the arrow, along // the Y axis for St.Side.LEFT, St.Side.RIGHT from the top and X axis from // the left for St.Side.TOP and St.Side.BOTTOM. diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js index 60f9011b1..889f29622 100644 --- a/js/ui/popupMenu.js +++ b/js/ui/popupMenu.js @@ -550,7 +550,6 @@ PopupMenu.prototype = { let [minWidth, minHeight, natWidth, natHeight] = this.actor.get_preferred_size(); - let menuX, menuY; let menuWidth = natWidth, menuHeight = natHeight; // Position the non-pointing axis @@ -573,68 +572,8 @@ PopupMenu.prototype = { this._boxPointer._arrowSide = this._arrowSide = St.Side.LEFT; } } - switch (this._arrowSide) { - case St.Side.TOP: - menuY = sourceY + sourceHeight + this._gap; - break; - case St.Side.BOTTOM: - menuY = sourceY - menuHeight - this._gap; - break; - case St.Side.LEFT: - menuX = sourceX + sourceWidth + this._gap; - break; - case St.Side.RIGHT: - menuX = sourceX - menuWidth - this._gap; - break; - } - // Now align and position the pointing axis, making sure - // it fits on screen - switch (this._arrowSide) { - case St.Side.TOP: - case St.Side.BOTTOM: - switch (this._alignment) { - case St.Align.START: - menuX = sourceX; - break; - case St.Align.MIDDLE: - menuX = sourceX - Math.floor((menuWidth - sourceWidth) / 2); - break; - case St.Align.END: - menuX = sourceX - (menuWidth - sourceWidth); - break; - } - - menuX = Math.min(menuX, primary.x + primary.width - menuWidth); - menuX = Math.max(menuX, primary.x); - - this._boxPointer.setArrowOrigin((sourceX - menuX) + Math.floor(sourceWidth / 2)); - break; - - case St.Side.LEFT: - case St.Side.RIGHT: - switch (this._alignment) { - case St.Align.START: - menuY = sourceY; - break; - case St.Align.MIDDLE: - menuY = sourceY - Math.floor((menuHeight - sourceHeight) / 2); - break; - case St.Align.END: - menuY = sourceY - (menuHeight - sourceHeight); - break; - } - - menuY = Math.min(menuY, primary.y + primary.height - menuHeight); - menuY = Math.max(menuY, primary.y); - - this._boxPointer.setArrowOrigin((sourceY - menuY) + Math.floor(sourceHeight / 2)); - break; - } - - // Actually set the position - this.actor.x = Math.floor(menuX); - this.actor.y = Math.floor(menuY); + this._boxPointer.setPosition(this.sourceActor, this._gap, this._alignment); // Now show it this.actor.reactive = true;