2016-02-21 08:31:31 +01:00
|
|
|
---------------------------------------------------------------------------
|
|
|
|
--- An auto-resized, free floating or modal wibox built around a widget.
|
|
|
|
--
|
|
|
|
-- This type of widget box (wibox) is auto closed when being clicked on and is
|
|
|
|
-- automatically resized to the size of its main widget.
|
|
|
|
--
|
|
|
|
-- Note that the widget itself should have a finite size. If something like a
|
|
|
|
-- `wibox.layout.flex` is used, then the size would be unlimited and an error
|
|
|
|
-- will be printed. The `wibox.layout.fixed`, `wibox.container.constraint`,
|
|
|
|
-- `forced_width` and `forced_height` are recommended.
|
|
|
|
--
|
|
|
|
--@DOC_awful_popup_simple_EXAMPLE@
|
|
|
|
--
|
|
|
|
-- Here is an example of how to create an alt-tab like dialog by leveraging
|
|
|
|
-- the `awful.widget.tasklist`.
|
|
|
|
--
|
|
|
|
--@DOC_awful_popup_alttab_EXAMPLE@
|
|
|
|
--
|
|
|
|
-- @author Emmanuel Lepage Vallee
|
|
|
|
-- @copyright 2016 Emmanuel Lepage Vallee
|
2019-06-06 08:44:00 +02:00
|
|
|
-- @popupmod awful.popup
|
2021-03-29 09:39:46 +02:00
|
|
|
-- @supermodule wibox
|
2016-02-21 08:31:31 +01:00
|
|
|
---------------------------------------------------------------------------
|
|
|
|
local wibox = require( "wibox" )
|
2020-02-10 09:29:31 +01:00
|
|
|
local gtable = require( "gears.table" )
|
2016-02-21 08:31:31 +01:00
|
|
|
local placement = require( "awful.placement" )
|
|
|
|
local xresources= require("beautiful.xresources")
|
|
|
|
local timer = require( "gears.timer" )
|
|
|
|
local capi = {mouse = mouse}
|
|
|
|
|
|
|
|
|
|
|
|
local module = {}
|
|
|
|
|
|
|
|
local main_widget = {}
|
|
|
|
|
|
|
|
-- Get the optimal direction for the wibox
|
|
|
|
-- This (try to) avoid going offscreen
|
|
|
|
local function set_position(self)
|
|
|
|
-- First, if there is size to be applied, do it
|
|
|
|
if self._private.next_width then
|
|
|
|
self.width = self._private.next_width
|
|
|
|
self._private.next_width = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
if self._private.next_height then
|
|
|
|
self.height = self._private.next_height
|
|
|
|
self._private.next_height = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
local pf = self._private.placement
|
|
|
|
|
|
|
|
if pf == false then return end
|
|
|
|
|
|
|
|
if pf then
|
|
|
|
pf(self, {bounding_rect = self.screen.geometry})
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local geo = self._private.widget_geo
|
|
|
|
|
|
|
|
if not geo then return end
|
|
|
|
|
|
|
|
local _, pos_name, anchor_name = placement.next_to(self, {
|
|
|
|
preferred_positions = self._private.preferred_directions,
|
|
|
|
geometry = geo,
|
|
|
|
preferred_anchors = self._private.preferred_anchors,
|
|
|
|
offset = self._private.offset or { x = 0, y = 0},
|
|
|
|
})
|
|
|
|
|
|
|
|
if pos_name ~= self._private.current_position then
|
|
|
|
local old = self._private.current_position
|
|
|
|
self._private.current_position = pos_name
|
|
|
|
self:emit_signal("property::current_position", pos_name, old)
|
|
|
|
end
|
|
|
|
|
|
|
|
if anchor_name ~= self._private.current_anchor then
|
|
|
|
local old = self._private.current_anchor
|
|
|
|
self._private.current_anchor = anchor_name
|
|
|
|
self:emit_signal("property::current_anchor", anchor_name, old)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Set the wibox size taking into consideration the limits
|
|
|
|
local function apply_size(self, width, height, set_pos)
|
|
|
|
local prev_geo = self:geometry()
|
|
|
|
|
|
|
|
width = math.max(self._private.minimum_width or 1, math.ceil(width or 1))
|
|
|
|
height = math.max(self._private.minimum_height or 1, math.ceil(height or 1))
|
|
|
|
|
|
|
|
if self._private.maximum_width then
|
|
|
|
width = math.min(self._private.maximum_width, width)
|
|
|
|
end
|
|
|
|
|
|
|
|
if self._private.maximum_height then
|
|
|
|
height = math.min(self._private.maximum_height, height)
|
|
|
|
end
|
|
|
|
|
|
|
|
self._private.next_width, self._private.next_height = width, height
|
|
|
|
|
|
|
|
if set_pos or width ~= prev_geo.width or height ~= prev_geo.height then
|
|
|
|
set_position(self)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Layout this widget
|
|
|
|
function main_widget:layout(context, width, height)
|
|
|
|
if self._private.widget then
|
|
|
|
local w, h = wibox.widget.base.fit_widget(
|
|
|
|
self,
|
|
|
|
context,
|
|
|
|
self._private.widget,
|
|
|
|
self._wb._private.maximum_width or 9999,
|
|
|
|
self._wb._private.maximum_height or 9999
|
|
|
|
)
|
|
|
|
timer.delayed_call(function()
|
|
|
|
apply_size(self._wb, w, h, true)
|
|
|
|
end)
|
|
|
|
return { wibox.widget.base.place_widget_at(self._private.widget, 0, 0, width, height) }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Set the widget that is drawn on top of the background
|
|
|
|
function main_widget:set_widget(widget)
|
|
|
|
if widget then
|
|
|
|
wibox.widget.base.check_widget(widget)
|
|
|
|
end
|
|
|
|
self._private.widget = widget
|
|
|
|
self:emit_signal("widget::layout_changed")
|
2019-12-21 22:39:46 +01:00
|
|
|
self:emit_signal("property::widget")
|
2016-02-21 08:31:31 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
function main_widget:get_widget()
|
|
|
|
return self._private.widget
|
|
|
|
end
|
|
|
|
|
|
|
|
function main_widget:get_children_by_id(name)
|
|
|
|
return self._wb:get_children_by_id(name)
|
|
|
|
end
|
|
|
|
|
|
|
|
local popup = {}
|
|
|
|
|
|
|
|
--- Set the preferred popup position relative to its parent.
|
|
|
|
--
|
|
|
|
-- This allows, for example, to have a submenu that goes on the right of the
|
|
|
|
-- parent menu. If there is no space on the right, it tries on the left and so
|
|
|
|
-- on.
|
|
|
|
--
|
|
|
|
-- The basic use case for this method is to give it a parent wibox:
|
|
|
|
--
|
|
|
|
-- @DOC_awful_popup_position1_EXAMPLE@
|
|
|
|
--
|
|
|
|
-- As demonstrated by this second example, it is also possible to use a widget
|
|
|
|
-- as a parent object:
|
|
|
|
--
|
|
|
|
-- @DOC_awful_popup_position2_EXAMPLE@
|
|
|
|
--
|
|
|
|
-- @property preferred_positions
|
2022-08-22 08:02:26 +02:00
|
|
|
-- @tparam table|string preferred_positions
|
|
|
|
-- @propertydefault `{ "right", "left", "top", "bottom" }`
|
|
|
|
-- @propertytype string A single position with no fallback. It will be used
|
|
|
|
-- even if it doesn't fit.
|
|
|
|
-- @propertytype table A list of possible positions. The first one to fit will be
|
|
|
|
-- used.
|
|
|
|
-- @propertyvalue "left"
|
|
|
|
-- @propertyvalue "right"
|
|
|
|
-- @propertyvalue "top"
|
|
|
|
-- @propertyvalue "bottom"
|
2016-02-21 08:31:31 +01:00
|
|
|
-- @see awful.placement.next_to
|
|
|
|
-- @see awful.popup.preferred_anchors
|
2019-12-21 22:39:46 +01:00
|
|
|
-- @propemits true false
|
2016-02-21 08:31:31 +01:00
|
|
|
|
|
|
|
function popup:set_preferred_positions(pref_pos)
|
|
|
|
self._private.preferred_directions = pref_pos
|
|
|
|
set_position(self)
|
2019-12-21 22:39:46 +01:00
|
|
|
self:emit_signal("property::preferred_positions", pref_pos)
|
2016-02-21 08:31:31 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
--- Set the preferred popup anchors relative to the parent.
|
|
|
|
--
|
|
|
|
-- For details information, see the `awful.placement.next_to` documentation.
|
|
|
|
--
|
|
|
|
-- In this example, it is possible to see the effect of having a fallback
|
|
|
|
-- preferred anchors when the popup would otherwise not fit:
|
|
|
|
--
|
|
|
|
-- @DOC_awful_popup_anchors_EXAMPLE@
|
|
|
|
--
|
|
|
|
-- @property preferred_anchors
|
2022-08-22 08:02:26 +02:00
|
|
|
-- @tparam[opt="back"] table|string preferred_anchors
|
2016-02-21 08:31:31 +01:00
|
|
|
-- ordered by priority.
|
2022-08-22 08:02:26 +02:00
|
|
|
-- @propertytype string A single anchor value with no fallback.
|
|
|
|
-- @propertytype table A list of possible anchor, the first one has the higher
|
|
|
|
-- priority, but will fallback if it doesn't fit.
|
|
|
|
-- @propertyvalue "front"
|
|
|
|
-- @propertyvalue "middle"
|
|
|
|
-- @propertyvalue "back"
|
2019-12-21 22:39:46 +01:00
|
|
|
-- @propemits true false
|
2016-02-21 08:31:31 +01:00
|
|
|
-- @see awful.placement.next_to
|
|
|
|
-- @see awful.popup.preferred_positions
|
|
|
|
|
|
|
|
function popup:set_preferred_anchors(pref_anchors)
|
|
|
|
self._private.preferred_anchors = pref_anchors
|
|
|
|
set_position(self)
|
2019-12-21 22:39:46 +01:00
|
|
|
self:emit_signal("property::preferred_anchors", pref_anchors)
|
2016-02-21 08:31:31 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
--- The current position relative to the parent object.
|
|
|
|
--
|
|
|
|
-- If there is a parent object (widget, wibox, wibar, client or the mouse), then
|
|
|
|
-- this property returns the current position. This is determined using
|
|
|
|
-- `preferred_positions`. It is usually the preferred position, but when there
|
|
|
|
-- isn't enough space, it can also be one of the fallback.
|
|
|
|
--
|
|
|
|
-- @property current_position
|
2022-08-22 08:02:26 +02:00
|
|
|
-- @tparam string current_position
|
|
|
|
-- @propertydefault This depends on where the popup was displayed.
|
|
|
|
-- @propertyvalue "left"
|
|
|
|
-- @propertyvalue "right"
|
|
|
|
-- @propertyvalue "top"
|
|
|
|
-- @propertyvalue "bottom"
|
|
|
|
-- @readonly
|
|
|
|
-- @see awful.popup.preferred_positions
|
2016-02-21 08:31:31 +01:00
|
|
|
|
|
|
|
function popup:get_current_position()
|
|
|
|
return self._private.current_position
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Get the current anchor relative to the parent object.
|
|
|
|
--
|
|
|
|
-- If there is a parent object (widget, wibox, wibar, client or the mouse), then
|
|
|
|
-- this property returns the current anchor. The anchor is the "side" of the
|
|
|
|
-- parent object on which the popup is based on. It will "grow" in the
|
|
|
|
-- opposite direction from the anchor.
|
|
|
|
--
|
|
|
|
-- @property current_anchor
|
2022-08-22 08:02:26 +02:00
|
|
|
-- @tparam string current_anchor
|
|
|
|
-- @propertydefault This depends on where the popup was displayed.
|
|
|
|
-- @propertyvalue "front"
|
|
|
|
-- @propertyvalue "middle"
|
|
|
|
-- @propertyvalue "back"
|
|
|
|
-- @readonly
|
|
|
|
-- @see awful.popup.preferred_anchors
|
2016-02-21 08:31:31 +01:00
|
|
|
|
|
|
|
function popup:get_current_anchor()
|
|
|
|
return self._private.current_anchor
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Move the wibox to a position relative to `geo`.
|
|
|
|
-- This will try to avoid overlapping the source wibox and auto-detect the right
|
|
|
|
-- direction to avoid going off-screen.
|
|
|
|
--
|
|
|
|
-- @param[opt=mouse] obj An object such as a wibox, client or a table entry
|
|
|
|
-- returned by `wibox:find_widgets()`.
|
|
|
|
-- @see awful.placement.next_to
|
|
|
|
-- @see awful.popup.preferred_positions
|
|
|
|
-- @see awful.popup.preferred_anchors
|
|
|
|
-- @treturn table The new geometry
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @method move_next_to
|
2016-02-21 08:31:31 +01:00
|
|
|
function popup:move_next_to(obj)
|
|
|
|
if self._private.is_relative == false then return end
|
|
|
|
|
|
|
|
self._private.widget_geo = obj
|
|
|
|
|
|
|
|
obj = obj or capi.mouse
|
|
|
|
|
|
|
|
if obj._apply_size_now then
|
|
|
|
obj:_apply_size_now(false)
|
|
|
|
end
|
|
|
|
|
|
|
|
self.visible = true
|
|
|
|
|
|
|
|
self:_apply_size_now(true)
|
|
|
|
|
|
|
|
self._private.widget_geo = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Bind the popup to a widget button press.
|
|
|
|
--
|
|
|
|
-- @tparam widget widget The widget
|
|
|
|
-- @tparam[opt=1] number button The button index
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @method bind_to_widget
|
2022-07-05 10:37:14 +02:00
|
|
|
-- @noreturn
|
2016-02-21 08:31:31 +01:00
|
|
|
function popup:bind_to_widget(widget, button)
|
|
|
|
if not self._private.button_for_widget then
|
|
|
|
self._private.button_for_widget = {}
|
|
|
|
end
|
|
|
|
|
|
|
|
self._private.button_for_widget[widget] = button or 1
|
|
|
|
widget:connect_signal("button::press", self._private.show_fct)
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Unbind the popup from a widget button.
|
2022-08-22 08:02:26 +02:00
|
|
|
-- @tparam widget widget
|
|
|
|
-- @propertytype widget A widget or declarative widget construct.
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @method unbind_to_widget
|
2022-07-05 10:37:14 +02:00
|
|
|
-- @noreturn
|
2016-02-21 08:31:31 +01:00
|
|
|
function popup:unbind_to_widget(widget)
|
|
|
|
widget:disconnect_signal("button::press", self._private.show_fct)
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Hide the popup when right clicked.
|
|
|
|
--
|
|
|
|
-- @property hide_on_right_click
|
|
|
|
-- @tparam[opt=false] boolean hide_on_right_click
|
2019-12-21 22:39:46 +01:00
|
|
|
-- @propemits true false
|
2016-02-21 08:31:31 +01:00
|
|
|
|
|
|
|
function popup:set_hide_on_right_click(value)
|
|
|
|
self[value and "connect_signal" or "disconnect_signal"](
|
|
|
|
self, "button::press", self._private.hide_fct
|
|
|
|
)
|
2019-12-21 22:39:46 +01:00
|
|
|
self:emit_signal("property::hide_on_right_click", value)
|
2016-02-21 08:31:31 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
--- The popup minimum width.
|
2019-12-21 22:39:46 +01:00
|
|
|
--
|
2016-02-21 08:31:31 +01:00
|
|
|
-- @property minimum_width
|
2022-08-22 08:02:26 +02:00
|
|
|
-- @tparam[opt=1] integer minimum_width
|
|
|
|
-- @propertyunit pixel
|
|
|
|
-- @rangestart 1
|
2019-12-21 22:39:46 +01:00
|
|
|
-- @propemits true false
|
2016-02-21 08:31:31 +01:00
|
|
|
|
|
|
|
--- The popup minimum height.
|
2019-12-21 22:39:46 +01:00
|
|
|
--
|
2016-02-21 08:31:31 +01:00
|
|
|
-- @property minimum_height
|
2022-08-22 08:02:26 +02:00
|
|
|
-- @tparam[opt=1] integer minimum_height
|
|
|
|
-- @propertyunit pixel
|
|
|
|
-- @rangestart 1
|
2019-12-21 22:39:46 +01:00
|
|
|
-- @propemits true false
|
2016-02-21 08:31:31 +01:00
|
|
|
|
2019-10-08 03:45:41 +02:00
|
|
|
--- The popup maximum width.
|
2019-12-21 22:39:46 +01:00
|
|
|
--
|
2019-10-08 03:45:41 +02:00
|
|
|
-- @property maximum_width
|
2022-08-22 08:02:26 +02:00
|
|
|
-- @tparam[opt=1] integer maximum_width
|
|
|
|
-- @propertyunit pixel
|
|
|
|
-- @rangestart 1
|
2019-12-21 22:39:46 +01:00
|
|
|
-- @propemits true false
|
2016-02-21 08:31:31 +01:00
|
|
|
|
|
|
|
--- The popup maximum height.
|
2019-12-21 22:39:46 +01:00
|
|
|
--
|
2016-02-21 08:31:31 +01:00
|
|
|
-- @property maximum_height
|
2022-08-22 08:02:26 +02:00
|
|
|
-- @tparam[opt=1] integer maximum_height
|
|
|
|
-- @propertyunit pixel
|
|
|
|
-- @rangestart 1
|
2019-12-21 22:39:46 +01:00
|
|
|
-- @propemits true false
|
2016-02-21 08:31:31 +01:00
|
|
|
|
|
|
|
for _, orientation in ipairs {"_width", "_height"} do
|
|
|
|
for _, limit in ipairs {"minimum", "maximum"} do
|
2019-12-21 22:39:46 +01:00
|
|
|
local prop = limit..orientation
|
|
|
|
popup["set_"..prop] = function(self, value)
|
|
|
|
self._private[prop] = value
|
2016-02-21 08:31:31 +01:00
|
|
|
self._private.container:emit_signal("widget::layout_changed")
|
2019-12-21 22:39:46 +01:00
|
|
|
self:emit_signal("property::"..prop, value)
|
|
|
|
end
|
|
|
|
popup["get_"..prop] = function(self)
|
|
|
|
return self._private[prop]
|
2016-02-21 08:31:31 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
--- The distance between the popup and its parent (if any).
|
|
|
|
--
|
|
|
|
-- Here is an example of 5 popups stacked one below the other with an y axis
|
|
|
|
-- offset (spacing).
|
|
|
|
--
|
|
|
|
-- @DOC_awful_popup_position3_EXAMPLE@
|
|
|
|
-- @property offset
|
2022-08-22 08:02:26 +02:00
|
|
|
-- @tparam[opt=0] table|integer offset
|
|
|
|
-- @tparam[opt=0] integer offset.x The horizontal offset.
|
|
|
|
-- @tparam[opt=0] integer offset.y The vertical offset.
|
|
|
|
-- @propertytype integer A value for both `x` and `y` simultaneously.
|
|
|
|
-- @propertytype table Specify values for `x` and `y` individually.
|
|
|
|
-- @negativeallowed true
|
|
|
|
-- @propertyunit pixel
|
2019-12-21 22:39:46 +01:00
|
|
|
-- @propemits true false
|
2016-02-21 08:31:31 +01:00
|
|
|
|
|
|
|
function popup:set_offset(offset)
|
|
|
|
|
|
|
|
if type(offset) == "number" then
|
|
|
|
offset = {
|
|
|
|
x = offset or 0,
|
|
|
|
y = offset or 0,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
local oldoff = self._private.offset or {x=0, y=0}
|
|
|
|
|
|
|
|
if oldoff.x == offset.x and oldoff.y == offset.y then return end
|
|
|
|
|
|
|
|
offset.x, offset.y = offset.x or oldoff.x or 0, offset.y or oldoff.y or 0
|
|
|
|
|
|
|
|
self._private.offset = offset
|
|
|
|
|
|
|
|
self:_apply_size_now(false)
|
2019-12-21 22:39:46 +01:00
|
|
|
|
|
|
|
self:emit_signal("property::offset", offset)
|
2016-02-21 08:31:31 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
--- Set the placement function.
|
2019-12-21 22:39:46 +01:00
|
|
|
--
|
2016-02-21 08:31:31 +01:00
|
|
|
-- @property placement
|
2022-08-22 08:02:26 +02:00
|
|
|
-- @tparam[opt=awful.placement.next_to] placement|string|boolean placement
|
|
|
|
-- @propertytype boolean Use `false` to disable automatic placement.
|
|
|
|
-- @propertytype string The name of an `awful.placement` function, like `"next_to"`.
|
2019-12-21 22:39:46 +01:00
|
|
|
-- @propemits true false
|
|
|
|
-- @see awful.placement
|
2016-02-21 08:31:31 +01:00
|
|
|
|
|
|
|
function popup:set_placement(f)
|
|
|
|
if type(f) == "string" then
|
|
|
|
f = placement[f]
|
|
|
|
end
|
|
|
|
|
|
|
|
self._private.placement = f
|
|
|
|
self:_apply_size_now(false)
|
2019-12-21 22:39:46 +01:00
|
|
|
self:emit_signal("property::placement")
|
2016-02-21 08:31:31 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
-- For the tests and the race condition when 2 popups are placed next to each
|
|
|
|
-- other.
|
|
|
|
function popup:_apply_size_now(skip_set)
|
|
|
|
if not self.widget then return end
|
|
|
|
|
|
|
|
local w, h = wibox.widget.base.fit_widget(
|
|
|
|
self.widget,
|
|
|
|
{dpi= self.screen.dpi or xresources.get_dpi()},
|
|
|
|
self.widget,
|
|
|
|
self._private.maximum_width or 9999,
|
|
|
|
self._private.maximum_height or 9999
|
|
|
|
)
|
|
|
|
|
|
|
|
-- It is important to do it for the obscure reason that calling `w:geometry()`
|
|
|
|
-- is actually mutating the state due to quantum determinism thanks to XCB
|
|
|
|
-- async nature... It is only true the very first time `w:geometry()` is
|
|
|
|
-- called
|
|
|
|
self.width = math.max(1, math.ceil(w or 1))
|
|
|
|
self.height = math.max(1, math.ceil(h or 1))
|
|
|
|
|
|
|
|
apply_size(self, w, h, skip_set ~= false)
|
|
|
|
end
|
|
|
|
|
|
|
|
function popup:set_widget(wid)
|
|
|
|
self._private.widget = wid
|
|
|
|
self._private.container:set_widget(wid)
|
2019-12-21 22:39:46 +01:00
|
|
|
self:emit_signal("property::widget", wid)
|
2016-02-21 08:31:31 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
function popup:get_widget()
|
|
|
|
return self._private.widget
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Create a new popup build around a passed in widget.
|
|
|
|
-- @tparam[opt=nil] table args
|
|
|
|
--@DOC_wibox_constructor_COMMON@
|
|
|
|
-- @tparam function args.placement The `awful.placement` function
|
|
|
|
-- @tparam string|table args.preferred_positions
|
|
|
|
-- @tparam string|table args.preferred_anchors
|
|
|
|
-- @tparam table|number args.offset The X and Y offset compared to the parent object
|
|
|
|
-- @tparam boolean args.hide_on_right_click Whether or not to hide the popup on
|
|
|
|
-- right clicks.
|
2019-06-07 20:59:34 +02:00
|
|
|
-- @constructorfct awful.popup
|
2016-02-21 08:31:31 +01:00
|
|
|
local function create_popup(_, args)
|
|
|
|
assert(args)
|
|
|
|
|
|
|
|
-- Temporarily remove the widget
|
|
|
|
local original_widget = args.widget
|
|
|
|
args.widget = nil
|
|
|
|
|
|
|
|
assert(original_widget, "The `awful.popup` requires a `widget` constructor argument")
|
|
|
|
|
|
|
|
local child_widget = wibox.widget.base.make_widget_from_value(original_widget)
|
|
|
|
|
|
|
|
local ii = wibox.widget.base.make_widget(child_widget, "awful.popup", {
|
|
|
|
enable_properties = true
|
|
|
|
})
|
|
|
|
|
2020-02-10 09:29:31 +01:00
|
|
|
gtable.crush(ii, main_widget, true)
|
2016-02-21 08:31:31 +01:00
|
|
|
|
|
|
|
-- Create a wibox to host the widget
|
|
|
|
local w = wibox(args or {})
|
|
|
|
|
|
|
|
rawset(w, "_private", {
|
|
|
|
container = ii,
|
|
|
|
preferred_directions = { "right", "left", "top", "bottom" },
|
|
|
|
preferred_anchors = { "back", "front", "middle" },
|
|
|
|
widget = child_widget
|
|
|
|
})
|
|
|
|
|
2020-02-10 09:29:31 +01:00
|
|
|
gtable.crush(w, popup)
|
2016-02-21 08:31:31 +01:00
|
|
|
|
|
|
|
ii:set_widget(child_widget)
|
|
|
|
|
|
|
|
-- Create the signal handlers
|
|
|
|
function w._private.show_fct(wdg, _, _, button, _, geo)
|
|
|
|
if button == w._private.button_for_widget[wdg] then
|
|
|
|
w:move_next_to(geo)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
function w._private.hide_fct()
|
|
|
|
w.visible = false
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Restore
|
|
|
|
args.widget = original_widget
|
|
|
|
|
|
|
|
-- Cross-link the wibox and widget
|
|
|
|
ii._wb = w
|
|
|
|
wibox.set_widget(w, ii)
|
|
|
|
|
|
|
|
--WARNING The order is important
|
|
|
|
-- First, apply the limits to avoid a flicker with large width or height
|
|
|
|
-- when set_position is called before the limits
|
|
|
|
for _,v in ipairs{"minimum_width", "minimum_height", "maximum_height",
|
|
|
|
"maximum_width", "offset", "placement","preferred_positions",
|
|
|
|
"preferred_anchors", "hide_on_right_click"} do
|
|
|
|
if args[v] ~= nil then
|
|
|
|
w["set_"..v](w, args[v])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Default to visible
|
|
|
|
if args.visible ~= false then
|
|
|
|
w.visible = true
|
|
|
|
end
|
|
|
|
|
|
|
|
return w
|
|
|
|
end
|
|
|
|
|
|
|
|
return setmetatable(module, {__call = create_popup})
|