Merge pull request #2407 from Elv13/fix_next_to

Fix awful.placement.next_to
This commit is contained in:
Emmanuel Lepage Vallée 2018-12-31 00:15:55 -05:00 committed by GitHub
commit 289cfcaaed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 946 additions and 119 deletions

View File

@ -262,16 +262,19 @@ local resize_to_point_map = {
} }
-- Outer position matrix -- Outer position matrix
-- 1=best case, 2=fallback
local outer_positions = { local outer_positions = {
left1 = function(r, w, _) return {x=r.x-w , y=r.y }, "down" end, left_front = function(r, w, _) return {x=r.x-w , y=r.y }, "front" end,
left2 = function(r, w, h) return {x=r.x-w , y=r.y-h+r.height }, "up" end, left_back = function(r, w, h) return {x=r.x-w , y=r.y-h+r.height }, "back" end,
right1 = function(r, _, _) return {x=r.x , y=r.y }, "down" end, left_middle = function(r, w, h) return {x=r.x-w , y=r.y-h/2+r.height/2 }, "middle" end,
right2 = function(r, _, h) return {x=r.x , y=r.y-h+r.height }, "up" end, right_front = function(r, _, _) return {x=r.x , y=r.y }, "front" end,
top1 = function(r, _, h) return {x=r.x , y=r.y-h }, "right" end, right_back = function(r, _, h) return {x=r.x , y=r.y-h+r.height }, "back" end,
top2 = function(r, w, h) return {x=r.x-w+r.width, y=r.y-h }, "left" end, right_middle = function(r, _, h) return {x=r.x , y=r.y-h/2+r.height/2 }, "middle" end,
bottom1 = function(r, _, _) return {x=r.x , y=r.y }, "right" end, top_front = function(r, _, h) return {x=r.x , y=r.y-h }, "front" end,
bottom2 = function(r, w, _) return {x=r.x-w+r.width, y=r.y }, "left" end, top_back = function(r, w, h) return {x=r.x-w+r.width , y=r.y-h }, "back" end,
top_middle = function(r, w, h) return {x=r.x-w/2+r.width/2, y=r.y-h }, "middle" end,
bottom_front = function(r, _, _) return {x=r.x , y=r.y }, "front" end,
bottom_back = function(r, w, _) return {x=r.x-w+r.width , y=r.y }, "back" end,
bottom_middle = function(r, w, _) return {x=r.x-w/2+r.width/2, y=r.y }, "middle" end,
} }
--- Add a context to the arguments. --- Add a context to the arguments.
@ -644,7 +647,6 @@ local function get_cross_sections(abs_geo, mode)
} }
elseif mode == "geometry" then elseif mode == "geometry" then
-- The widget geometry extended to reach the end of the drawable -- The widget geometry extended to reach the end of the drawable
return { return {
h = { h = {
x = abs_geo.drawable_geo.x , x = abs_geo.drawable_geo.x ,
@ -702,23 +704,39 @@ local function get_relative_regions(geo, mode, is_absolute)
end end
end end
-- Get the drawable geometry -- Get the parent geometry using one way or another depending on the object
local dpos = geo.drawable and ( -- Type
geo.drawable.drawable and local bw, dgeo = 0, {x=0, y=0, width=1, height=1}
geo.drawable.drawable:geometry()
or geo.drawable:geometry() -- Detect various types of geometry table and (try) to get rid of the
) or {x=0, y=0} -- differences so the code below don't have to care anymore.
if geo.drawin then
bw, dgeo = geo.drawin.border_width, geo.drawin:geometry()
elseif geo.drawable and geo.drawable.get_wibox then
bw = geo.drawable.get_wibox().border_width
dgeo = geo.drawable.get_wibox():geometry()
elseif geo.drawable and geo.drawable.drawable then
bw, dgeo = 0, geo.drawable.drawable:geometry()
else
-- The placement isn't done on an object at all, having no border is
-- normal.
assert(mode == "geometry")
end
-- Add the infamous border size
dgeo.width = dgeo.width + 2*bw
dgeo.height = dgeo.height + 2*bw
-- Compute the absolute widget geometry -- Compute the absolute widget geometry
local abs_widget_geo = is_absolute and geo or { local abs_widget_geo = is_absolute and dgeo or {
x = dpos.x + geo.x , x = dgeo.x + geo.x + bw,
y = dpos.y + geo.y , y = dgeo.y + geo.y + bw,
width = geo.width , width = geo.width ,
height = geo.height , height = geo.height ,
drawable = geo.drawable , drawable = geo.drawable ,
} }
abs_widget_geo.drawable_geo = geo.drawable and dpos or geo abs_widget_geo.drawable_geo = geo.drawable and dgeo or geo
-- Get the point for comparison. -- Get the point for comparison.
local center_point = mode:match("cursor") and capi.mouse.coords() or { local center_point = mode:match("cursor") and capi.mouse.coords() or {
@ -1342,28 +1360,66 @@ end
--- Move a drawable to a relative position next to another one. --- Move a drawable to a relative position next to another one.
-- --
-- This placement function offers two additional settings to align the drawable
-- alongside the parent geometry. The first one, the position, sets the side
-- relative to the parent. The second one, the anchor, set the alignment within
-- the side selected by the `preferred_positions`. Both settings are tables of
-- priorities. The first available slot will be used. If there isn't enough
-- space, then it will fallback to the next until it is possible to fit the
-- drawable. This is meant to avoid going offscreen.
--
-- The `args.preferred_positions` look like this: -- The `args.preferred_positions` look like this:
-- --
-- {"top", "right", "left", "bottom"} -- {"top", "right", "left", "bottom"}
-- --
-- The `args.preferred_anchors` are:
--
-- * "front": The closest to the origin (0,0)
-- * "middle": Centered aligned with the parent
-- * "back": The opposite side compared to `front`
--
-- In that case, if there is room on the top of the geometry, then it will have -- In that case, if there is room on the top of the geometry, then it will have
-- priority, followed by all the others, in order. -- priority, followed by all the others, in order.
-- --
--@DOC_awful_placement_next_to_EXAMPLE@
--
-- The `args.mode` parameters allows to control from which `next_to` takes its
-- source object from. The valid values are:
--
-- * geometry: Next to this geometry, `args.geometry` has to be set.
-- * cursor: Next to the mouse.
-- * cursor_inside
-- * geometry_inside
--
-- @tparam drawable d A wibox or client -- @tparam drawable d A wibox or client
-- @tparam table args -- @tparam table args
-- @tparam string args.mode The mode -- @tparam string args.mode The mode
-- @tparam string args.preferred_positions The preferred positions (in order) -- @tparam string|table args.preferred_positions The preferred positions (in order)
-- @tparam string|table args.preferred_anchors The preferred anchor(s) (in order)
-- @tparam string args.geometry A geometry inside the other drawable -- @tparam string args.geometry A geometry inside the other drawable
-- @treturn table The new geometry -- @treturn table The new geometry
-- @treturn string The choosen position -- @treturn string The choosen position ("left", "right", "top" or "bottom")
-- @treturn string The choosen direction -- @treturn string The choosen anchor ("front", "middle" or "back")
function placement.next_to(d, args) function placement.next_to(d, args)
args = add_context(args, "next_to") args = add_context(args, "next_to")
d = d or capi.client.focus d = d or capi.client.focus
local preferred_positions = {} local osize = type(d.geometry) == "function" and d:geometry() or nil
local original_pos, original_anchors = args.preferred_positions, args.preferred_anchors
for k, v in ipairs(args.preferred_positions or {}) do if type(original_pos) == "string" then
original_pos = {original_pos}
end
if type(original_anchors) == "string" then
original_anchors = {original_anchors}
end
local preferred_positions = {}
local preferred_anchors = #(original_anchors or {}) > 0 and
original_anchors or {"front", "back", "middle"}
for k, v in ipairs(original_pos or {}) do
preferred_positions[v] = k preferred_positions[v] = k
end end
@ -1391,40 +1447,72 @@ function placement.next_to(d, args)
local regions = get_relative_regions(wgeo, mode, is_absolute) local regions = get_relative_regions(wgeo, mode, is_absolute)
-- Order the regions with the preferred_positions, then the defaults
local sorted_regions, default_positions = {}, {"left", "right", "bottom", "top"}
for _, pos in ipairs(original_pos or {}) do
for idx, def in ipairs(default_positions) do
if def == pos then
table.remove(default_positions, idx)
break
end
end
table.insert(sorted_regions, {name = pos, region = regions[pos]})
end
for _, pos in ipairs(default_positions) do
table.insert(sorted_regions, {name = pos, region = regions[pos]})
end
-- Check each possible slot around the drawable (8 total), see what fits -- Check each possible slot around the drawable (8 total), see what fits
-- and order them by preferred_positions -- and order them by preferred_positions
local does_fit = {} local does_fit = {}
for k,v in pairs(regions) do for _, pos in ipairs(sorted_regions) do
local geo, dir = outer_positions[k.."1"](v, dgeo.width, dgeo.height) local geo, dir, fit
geo.width, geo.height = dgeo.width, dgeo.height
local fit = fit_in_bounding(v.screen, geo, args) -- Try each anchor until one that fits is found
for _, anchor in ipairs(preferred_anchors) do
geo, dir = outer_positions[pos.name.."_"..anchor](pos.region, dgeo.width, dgeo.height)
-- Try the other compatible geometry
if not fit then
geo, dir = outer_positions[k.."2"](v, dgeo.width, dgeo.height)
geo.width, geo.height = dgeo.width, dgeo.height geo.width, geo.height = dgeo.width, dgeo.height
fit = fit_in_bounding(v.screen, geo, args)
fit = fit_in_bounding(pos.region.screen, geo, args)
if fit then break end
end end
does_fit[k] = fit and {geo, dir} or nil does_fit[pos.name] = fit and {geo, dir} or nil
if fit and preferred_positions[k] and preferred_positions[k] < pref_idx then if fit and preferred_positions[pos.name] and preferred_positions[pos.name] < pref_idx then
pref_idx = preferred_positions[k] pref_idx = preferred_positions[pos.name]
pref_name = k pref_name = pos.name
end end
-- No need to continue -- No need to continue
if fit and preferred_positions[k] == 1 then break end if fit then break end
end end
local pos_name = pref_name or next(does_fit) local ngeo, dir = unpack(does_fit[pref_name] or {}) --FIXME why does this happen
local ngeo, dir = unpack(does_fit[pos_name] or {}) --FIXME why does this happen
-- The requested placement isn't possible due to the lack of space, better
-- do nothing an try random things
if not ngeo then return end
remove_border(d, args, ngeo)
geometry_common(d, args, ngeo) geometry_common(d, args, ngeo)
attach(d, placement.next_to, args) attach(d, placement.next_to, args)
return fix_new_geometry(ngeo, args, true), pos_name, dir local ret = fix_new_geometry(ngeo, args, true)
-- Make sure the geometry didn't change, it would indicate an
-- "off by border" issue.
assert((not osize.width) or ret.width == d.width)
assert((not osize.height) or ret.height == d.height)
return ret, pref_name, dir
end end
--- Restore the geometry. --- Restore the geometry.

View File

@ -10,13 +10,16 @@
-- How to create a tooltip? -- How to create a tooltip?
-- --- -- ---
-- --
-- myclock = wibox.widget.textclock("%T", 1) -- @DOC_awful_tooltip_textclock_EXAMPLE@
-- myclock_t = awful.tooltip({ --
-- objects = { myclock }, -- Alternatively, you can use `mouse::enter` signal:
-- timer_function = function() --
-- return os.date("Today is %A %B %d %Y\nThe time is %T") -- @DOC_awful_tooltip_textclock2_EXAMPLE@
-- end, --
-- }) -- How to create a tooltip without objects?
-- ---
--
-- @DOC_awful_tooltip_mouse_EXAMPLE@
-- --
-- How to add the same tooltip to multiple objects? -- How to add the same tooltip to multiple objects?
-- --- -- ---
@ -124,6 +127,7 @@ local function apply_outside_mode(self)
local _, position = a_placement.next_to(w, { local _, position = a_placement.next_to(w, {
geometry = self._private.widget_geometry, geometry = self._private.widget_geometry,
preferred_positions = self.preferred_positions, preferred_positions = self.preferred_positions,
preferred_anchors = self.preferred_alignments,
honor_workarea = true, honor_workarea = true,
}) })
@ -228,6 +232,13 @@ end
--- The horizontal alignment. --- The horizontal alignment.
-- --
-- This is valid for the mouse mode only. For the outside mode, use
-- `preferred_positions`.
--
-- @DOC_awful_tooltip_align_EXAMPLE@
--
-- @DOC_awful_tooltip_align2_EXAMPLE@
--
-- The following values are valid: -- The following values are valid:
-- --
-- * top_left -- * top_left
@ -241,6 +252,8 @@ end
-- --
-- @property align -- @property align
-- @see beautiful.tooltip_align -- @see beautiful.tooltip_align
-- @see mode
-- @see preferred_positions
--- The default tooltip alignment. --- The default tooltip alignment.
-- @beautiful beautiful.tooltip_align -- @beautiful beautiful.tooltip_align
@ -264,6 +277,9 @@ end
--- The shape of the tooltip window. --- The shape of the tooltip window.
-- If the shape require some parameters, use `set_shape`. -- If the shape require some parameters, use `set_shape`.
--
-- @DOC_awful_tooltip_shape_EXAMPLE@
--
-- @property shape -- @property shape
-- @see gears.shape -- @see gears.shape
-- @see set_shape -- @see set_shape
@ -274,7 +290,6 @@ end
-- @tparam gears.shape s The shape -- @tparam gears.shape s The shape
-- @see shape -- @see shape
-- @see gears.shape -- @see gears.shape
function tooltip:set_shape(s) function tooltip:set_shape(s)
self.backgroundbox:set_shape(s) self.backgroundbox:set_shape(s)
end end
@ -284,6 +299,14 @@ end
-- close to the mouse cursor. It is also possible to place the tooltip relative -- close to the mouse cursor. It is also possible to place the tooltip relative
-- to the widget geometry. -- to the widget geometry.
-- --
-- **mouse:**
--
-- @DOC_awful_tooltip_mode_EXAMPLE@
--
-- **outside:**
--
-- @DOC_awful_tooltip_mode2_EXAMPLE@
--
-- Valid modes are: -- Valid modes are:
-- --
-- * "mouse": Next to the mouse cursor -- * "mouse": Next to the mouse cursor
@ -305,8 +328,17 @@ end
--- The preferred positions when in `outside` mode. --- The preferred positions when in `outside` mode.
-- --
-- @DOC_awful_tooltip_preferred_positions_EXAMPLE@
--
-- If the tooltip fits on multiple sides of the drawable, then this defines the -- If the tooltip fits on multiple sides of the drawable, then this defines the
-- priority -- priority.
--
-- The valid table values are:
--
-- * "top"
-- * "right"
-- * "left"
-- * "bottom"
-- --
-- The default is: -- The default is:
-- --
@ -314,6 +346,9 @@ end
-- --
-- @property preferred_positions -- @property preferred_positions
-- @tparam table preferred_positions The position, ordered by priorities -- @tparam table preferred_positions The position, ordered by priorities
-- @see align
-- @see mode
-- @see preferred_alignments
function tooltip:get_preferred_positions() function tooltip:get_preferred_positions()
return self._private.preferred_positions or return self._private.preferred_positions or
@ -326,6 +361,48 @@ function tooltip:set_preferred_positions(value)
set_geometry(self) set_geometry(self)
end end
--- The preferred alignment when using the `outside` mode.
--
-- The values of the table are ordered by priority, the first one that fits
-- will be used.
--
-- **front:**
--
-- @DOC_awful_tooltip_preferred_alignment_EXAMPLE@
--
-- **middle:**
--
-- @DOC_awful_tooltip_preferred_alignment2_EXAMPLE@
--
-- **back:**
--
-- @DOC_awful_tooltip_preferred_alignment3_EXAMPLE@
--
-- The valid table values are:
--
-- * front
-- * middle
-- * back
--
-- The default is:
--
-- {"front", "back", "middle"}
--
-- @property preferred_alignments
-- @param string
-- @see preferred_positions
function tooltip:get_preferred_alignments()
return self._private.preferred_alignments or
{"front", "back", "middle"}
end
function tooltip:set_preferred_alignments(value)
self._private.preferred_alignments = value
set_geometry(self)
end
--- Change displayed text. --- Change displayed text.
-- --
-- @property text -- @property text
@ -370,6 +447,8 @@ end
--- Set all margins around the tooltip textbox --- Set all margins around the tooltip textbox
-- --
-- @DOC_awful_tooltip_margins_EXAMPLE@
--
-- @property margins -- @property margins
-- @tparam tooltip self A tooltip object -- @tparam tooltip self A tooltip object
-- @tparam number New margins value -- @tparam number New margins value
@ -378,26 +457,62 @@ function tooltip:set_margins(val)
self.marginbox:set_margins(val) self.marginbox:set_margins(val)
end end
--- The border width.
--
-- @DOC_awful_tooltip_border_width_EXAMPLE@
--
-- @property border_width
-- @param number
function tooltip:set_border_width(val)
self.widget.shape_border_width = val
end
--- The border color.
--
-- @DOC_awful_tooltip_border_color_EXAMPLE@
--
-- @property border_color
-- @param gears.color
function tooltip:set_border_color(val)
self.widget.shape_border_color = val
end
--- Set the margins around the left and right of the tooltip textbox --- Set the margins around the left and right of the tooltip textbox
-- --
-- @DOC_awful_tooltip_margins_leftright_EXAMPLE@
--
-- @property margins_leftright -- @property margins_leftright
-- @tparam tooltip self A tooltip object -- @tparam tooltip self A tooltip object
-- @tparam number New margins value -- @tparam number New margins value
function tooltip:set_margin_leftright(val) function tooltip:set_margin_leftright(val)
self.marginbox.left = val self.marginbox:set_left(val)
self.marginbox.right = val self.marginbox:set_right(val)
end
--TODO v5 deprecate this
function tooltip:set_margins_leftright(val)
self:set_margin_leftright(val)
end end
--- Set the margins around the top and bottom of the tooltip textbox --- Set the margins around the top and bottom of the tooltip textbox
-- --
-- @DOC_awful_tooltip_margins_topbottom_EXAMPLE@
--
-- @property margins_topbottom -- @property margins_topbottom
-- @tparam tooltip self A tooltip object -- @tparam tooltip self A tooltip object
-- @tparam number New margins value -- @tparam number New margins value
function tooltip:set_margin_topbottom(val) function tooltip:set_margin_topbottom(val)
self.marginbox.top = val self.marginbox:set_top(val)
self.marginbox.bottom = val self.marginbox:set_bottom(val)
end
--TODO v5 deprecate this
function tooltip:set_margins_topbottom(val)
self:set_margin_topbottom(val)
end end
--- Add tooltip to an object. --- Add tooltip to an object.
@ -509,7 +624,7 @@ function tooltip.new(args)
function self.show(other, geo) function self.show(other, geo)
-- Auto detect clients and wiboxes -- Auto detect clients and wiboxes
if other.drawable or other.pid then if other.drawable or other.pid then
geo = other:geometry() geo = other
end end
-- Cache the geometry in case it is needed later -- Cache the geometry in case it is needed later

View File

@ -253,6 +253,10 @@ local function new(args)
ret._drawable = wibox.drawable(w.drawable, { wibox = ret }, ret._drawable = wibox.drawable(w.drawable, { wibox = ret },
"wibox drawable (" .. object.modulename(3) .. ")") "wibox drawable (" .. object.modulename(3) .. ")")
function ret._drawable.get_wibox()
return ret
end
ret._drawable:_inform_visible(w.visible) ret._drawable:_inform_visible(w.visible)
w:connect_signal("property::visible", function() w:connect_signal("property::visible", function()
ret._drawable:_inform_visible(w.visible) ret._drawable:_inform_visible(w.visible)

View File

@ -0,0 +1,61 @@
--DOC_GEN_IMAGE --DOC_HIDE
local awful = { placement = require("awful.placement") }--DOC_HIDE
screen[1]._resize {x= 0, width = 640, height=200} --DOC_HIDE
local parent_client = client.gen_fake {x = 0, y = 0, width=350, height=70} --DOC_HIDE
parent_client:_hide() --DOC_HIDE
awful.placement.centered(client.focus) --DOC_HIDE
parent_client:set_label("Parent client") --DOC_HIDE
for _, pos in ipairs{"left", "right", "top", "bottom"} do
for _, anchor in ipairs{"front", "middle", "back"} do
local c1 = client.gen_fake {x = 0, y = 0, width=80, height=20} --DOC_HIDE
c1:_hide() --DOC_HIDE
local _,p,a = --DOC_HIDE
awful.placement.next_to(
client.focus,
{
preferred_positions = pos,
preferred_anchors = anchor,
geometry = parent_client,
}
)
c1:set_label(pos.."+"..anchor) --DOC_HIDE
assert(pos == p) --DOC_HIDE
assert(anchor == a) --DOC_HIDE
--DOC_HIDE Make sure the border are correctly applied
if pos == "left" then --DOC_HIDE
assert(c1.x + c1.width + 2*c1.border_width == parent_client.x) --DOC_HIDE
end --DOC_HIDE
if pos == "right" then --DOC_HIDE
assert(c1.x == parent_client.x+parent_client.width+2*parent_client.border_width) --DOC_HIDE
end --DOC_HIDE
if pos == "top" then --DOC_HIDE
assert(c1.y + c1.height + 2*c1.border_width == parent_client.y) --DOC_HIDE
end --DOC_HIDE
if pos == "bottom" then --DOC_HIDE
assert(c1.y == parent_client.y+parent_client.height+2*parent_client.border_width)--DOC_HIDE
end --DOC_HIDE
--DOC_HIDE Make sure the "children" don't overshoot the parent geometry
if pos ~= "right" then --DOC_HIDE
assert(c1.x+c1.width+2*c1.border_width--DOC_HIDE
<= parent_client.x+parent_client.width+2*parent_client.border_width) --DOC_HIDE
end --DOC_HIDE
if pos ~= "bottom" then --DOC_HIDE
assert(c1.y+c1.height+2*c1.border_width --DOC_HIDE
<= parent_client.y+parent_client.height+2*parent_client.border_width) --DOC_HIDE
end --DOC_HIDE
if pos ~= "left" then --DOC_HIDE
assert(c1.x >= parent_client.x) --DOC_HIDE
end --DOC_HIDE
if pos ~= "top" then --DOC_HIDE
assert(c1.y >= parent_client.y) --DOC_HIDE
end --DOC_HIDE
end
end
return {hide_lines=true} --DOC_HIDE
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -11,6 +11,11 @@ local wibox = require( "wibox" )
-- Run the test -- Run the test
local args = loadfile(file_path)() or {} local args = loadfile(file_path)() or {}
-- Emulate the event loop for 5 iterations
for _ = 1, 5 do
awesome.emit_signal("refresh")
end
-- Draw the result -- Draw the result
local img = cairo.SvgSurface.create(image_path..".svg", screen._get_extents() ) local img = cairo.SvgSurface.create(image_path..".svg", screen._get_extents() )
@ -30,6 +35,7 @@ local function draw_mouse(x, y)
end end
-- Print an outline for the screens -- Print an outline for the screens
if not screen.no_outline then
for _, s in ipairs(screen) do for _, s in ipairs(screen) do
cr:save() cr:save()
-- Draw the screen outline -- Draw the screen outline
@ -48,8 +54,9 @@ for _, s in ipairs(screen) do
--TODO --TODO
cr:restore() cr:restore()
end end
end
cr:set_line_width(beautiful.border_width) cr:set_line_width(beautiful.border_width/2)
cr:set_source(color(beautiful.border_color)) cr:set_source(color(beautiful.border_color))
@ -124,12 +131,8 @@ local function client_widget(c, col, label)
l.forced_height = c.height l.forced_height = c.height
return wibox.widget { return wibox.widget {
{
{ {
l, l,
margins = bw + 1, -- +1 because the the SVG AA
layout = wibox.container.margin
},
{ {
text = label or "", text = label or "",
align = "center", align = "center",
@ -138,22 +141,40 @@ local function client_widget(c, col, label)
}, },
layout = wibox.layout.stack layout = wibox.layout.stack
}, },
shape_border_width = bw*2, shape_border_width = bw,
shape_border_color = beautiful.border_color, shape_border_color = beautiful.border_color,
shape_clip = true, shape_clip = true,
fg = beautiful.fg_normal or "#000000", fg = beautiful.fg_normal or "#000000",
bg = col, bg = col,
forced_width = geo.width + 2*bw,
forced_height = geo.height + 2*bw,
shape = function(cr2, w, h) shape = function(cr2, w, h)
return shape.rounded_rect(cr2, w, h, args.radius or 5) return shape.rounded_rect(cr2, w, h, args.radius or 5)
end, end,
forced_width = geo.width + 2*bw,
forced_height = geo.height + 2*bw,
widget = wibox.container.background, widget = wibox.container.background,
} }
end end
-- Add all wiboxes -- Add all wiboxes
-- Fix the wibox geometries that have a dependency on their content
for _, d in ipairs(drawin.get()) do
local w = d.get_wibox and d:get_wibox() or nil
if w then
-- Force a full layout first as widgets with as the awful.popup have
-- interdependencies between the content and the container
if w._apply_size_now then
w:_apply_size_now()
end
end
end
-- Emulate the event loop for another 5 iterations
for _ = 1, 5 do
awesome.emit_signal("refresh")
end
for _, d in ipairs(drawin.get()) do for _, d in ipairs(drawin.get()) do
local w = d.get_wibox and d:get_wibox() or nil local w = d.get_wibox and d:get_wibox() or nil
if w then if w then
@ -164,6 +185,7 @@ end
-- Loop each clients geometry history and paint it -- Loop each clients geometry history and paint it
for _, c in ipairs(client.get()) do for _, c in ipairs(client.get()) do
if not c.minimized then
local pgeo = nil local pgeo = nil
for _, geo in ipairs(c._old_geo) do for _, geo in ipairs(c._old_geo) do
if not geo._hide then if not geo._hide then
@ -203,6 +225,7 @@ for _, c in ipairs(client.get()) do
pgeo = geo pgeo = geo
end end
end end
end
-- Draw the wiboxes/clients on top of the screen -- Draw the wiboxes/clients on top of the screen
wibox.widget.draw_to_cairo_context( wibox.widget.draw_to_cairo_context(

View File

@ -0,0 +1,30 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
--DOC_HIDE_ALL
screen[1]._resize {width = 300, height = 75}
screen.no_outline = true
local awful = {tooltip = require("awful.tooltip")}
local beautiful = require("beautiful")
local wibox = require("wibox")
-- mouse.coords{x=50, y= 10}
local wb = wibox {
width = 100, height = 44, x = 100, y = 10, visible = true, bg = "#00000000"
}
awesome.emit_signal("refresh")
for _, side in ipairs{ "top_left", "bottom_left", "top_right", "bottom_right"} do
local tt = awful.tooltip {
text = side,
objects = {wb},
mode = "mouse",
align = side,
}
tt.bg = beautiful.bg_normal
end
mouse.coords{x=125, y= 35}
mouse.push_history()
awesome.emit_signal("refresh")

View File

@ -0,0 +1,30 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
--DOC_HIDE_ALL
screen[1]._resize {width = 300, height = 75}
screen.no_outline = true
local awful = {tooltip = require("awful.tooltip")}
local beautiful = require("beautiful")
local wibox = require("wibox")
-- mouse.coords{x=50, y= 10}
local wb = wibox {
width = 100, height = 44, x = 100, y = 10, visible = true, bg = "#00000000"
}
awesome.emit_signal("refresh")
for _, side in ipairs{ "left", "right", "bottom", "top" } do
local tt = awful.tooltip {
text = side,
objects = {wb},
mode = "mouse",
align = side,
}
tt.bg = beautiful.bg_normal
end
mouse.coords{x=125, y= 35}
mouse.push_history()
awesome.emit_signal("refresh")

View File

@ -0,0 +1,32 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
--DOC_HIDE_ALL
screen[1]._resize {width = 640, height = 55}
screen.no_outline = true
local awful = {tooltip = require("awful.tooltip")}
local beautiful = require("beautiful")
-- mouse.coords{x=50, y= 10}
awesome.emit_signal("refresh")
local x_offset = 0
for _, color in ipairs{ "#ff0000", "#00ff00", "#0000ff", "#00ffff" } do
local tt = awful.tooltip {
text = color,
mode = "mouse",
border_width = 2,
border_color = color,
}
tt.bg = beautiful.bg_normal
awesome.emit_signal("refresh")
tt:show()
awesome.emit_signal("refresh")
tt.wibox.x = x_offset
x_offset = x_offset + 640/5
end
mouse.coords{x=125, y= 0}
-- mouse.push_history()
awesome.emit_signal("refresh")

View File

@ -0,0 +1,32 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
--DOC_HIDE_ALL
screen[1]._resize {width = 640, height = 55}
screen.no_outline = true
local awful = {tooltip = require("awful.tooltip")}
local beautiful = require("beautiful")
-- mouse.coords{x=50, y= 10}
awesome.emit_signal("refresh")
local x_offset = 0
for _, width in ipairs{ 1,2,4,6 } do
local tt = awful.tooltip {
text = "width: "..width,
mode = "mouse",
border_width = width,
border_color = beautiful.border_color,
}
tt.bg = beautiful.bg_normal
awesome.emit_signal("refresh")
tt:show()
awesome.emit_signal("refresh")
tt.wibox.x = x_offset
x_offset = x_offset + 640/5
end
mouse.coords{x=125, y= 0}
-- mouse.push_history()
awesome.emit_signal("refresh")

View File

@ -0,0 +1,32 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
--DOC_HIDE_ALL
screen[1]._resize {width = 640, height = 55}
screen.no_outline = true
local awful = {tooltip = require("awful.tooltip")}
local beautiful = require("beautiful")
-- mouse.coords{x=50, y= 10}
awesome.emit_signal("refresh")
local x_offset = 0
for _, width in ipairs{ 1,2,4,6 } do
local tt = awful.tooltip {
text = "margins: "..width,
mode = "mouse",
margins = width,
border_color = beautiful.border_color,
}
tt.bg = beautiful.bg_normal
awesome.emit_signal("refresh")
tt:show()
awesome.emit_signal("refresh")
tt.wibox.x = x_offset
x_offset = x_offset + 640/5
end
mouse.coords{x=125, y= 0}
-- mouse.push_history()
awesome.emit_signal("refresh")

View File

@ -0,0 +1,32 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
--DOC_HIDE_ALL
screen[1]._resize {width = 640, height = 55}
screen.no_outline = true
local awful = {tooltip = require("awful.tooltip")}
local beautiful = require("beautiful")
-- mouse.coords{x=50, y= 10}
awesome.emit_signal("refresh")
local x_offset = 0
for _, width in ipairs{ 1,2,4,6 } do
local tt = awful.tooltip {
text = "margins: "..width,
mode = "mouse",
margins_leftright = width,
border_color = beautiful.border_color,
}
tt.bg = beautiful.bg_normal
awesome.emit_signal("refresh")
tt:show()
awesome.emit_signal("refresh")
tt.wibox.x = x_offset
x_offset = x_offset + 640/5
end
mouse.coords{x=125, y= 0}
-- mouse.push_history()
awesome.emit_signal("refresh")

View File

@ -0,0 +1,32 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
--DOC_HIDE_ALL
screen[1]._resize {width = 640, height = 55}
screen.no_outline = true
local awful = {tooltip = require("awful.tooltip")}
local beautiful = require("beautiful")
-- mouse.coords{x=50, y= 10}
awesome.emit_signal("refresh")
local x_offset = 0
for _, width in ipairs{ 1,2,4,6 } do
local tt = awful.tooltip {
text = "margins: "..width,
mode = "mouse",
margins_topbottom = width,
border_color = beautiful.border_color,
}
tt.bg = beautiful.bg_normal
awesome.emit_signal("refresh")
tt:show()
awesome.emit_signal("refresh")
tt.wibox.x = x_offset
x_offset = x_offset + 640/5
end
mouse.coords{x=125, y= 0}
-- mouse.push_history()
awesome.emit_signal("refresh")

View File

@ -0,0 +1,23 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
--DOC_HIDE_ALL
screen[1]._resize {width = 200, height = 100}
screen.no_outline = true
local awful = {tooltip = require("awful.tooltip")}
local beautiful = require("beautiful")
local wibox = require("wibox")
mouse.coords{x=50, y= 10}
local wb = wibox {width = 100, height = 44, x = 50, y = 25, visible = true}
awesome.emit_signal("refresh")
local tt = awful.tooltip {
text = "A tooltip!",
objects = {wb},
}
tt.bg = beautiful.bg_normal
mouse.coords{x=75, y= 35}
mouse.push_history()
awesome.emit_signal("refresh")

View File

@ -0,0 +1,24 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
--DOC_HIDE_ALL
screen[1]._resize {width = 200, height = 100}
screen.no_outline = true
local awful = {tooltip = require("awful.tooltip")}
local beautiful = require("beautiful")
local wibox = require("wibox")
mouse.coords{x=50, y= 10}
local wb = wibox {width = 100, height = 44, x = 50, y = 25, visible = true}
awesome.emit_signal("refresh")
local tt = awful.tooltip {
text = "A tooltip!",
objects = {wb},
mode = "outside",
}
tt.bg = beautiful.bg_normal
mouse.coords{x=75, y= 35}
mouse.push_history()
awesome.emit_signal("refresh")

View File

@ -0,0 +1,20 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
screen[1]._resize {width = 200, height = 50} --DOC_HIDE
screen.no_outline = true --DOC_HIDE
local awful = {tooltip = require("awful.tooltip")} --DOC_HIDE
local beautiful = require("beautiful") --DOC_HIDE
mouse.coords{x=50, y= 10} --DOC_HIDE
mouse.push_history() --DOC_HIDE
local tt = awful.tooltip {
text = "A tooltip!",
visible = true,
}
--DOC_NEWLINE
tt.bg = beautiful.bg_normal
--DOC_NEWLINE

View File

@ -0,0 +1,29 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
--DOC_HIDE_ALL
screen[1]._resize {width = 300, height = 150}
screen.no_outline = true
local awful = {tooltip = require("awful.tooltip")}
local beautiful = require("beautiful")
local wibox = require("wibox")
-- mouse.coords{x=50, y= 10}
local wb = wibox {width = 100, height = 44, x = 100, y = 50, visible = true}
awesome.emit_signal("refresh")
for _, side in ipairs{ "left", "right", "bottom", "top" } do
local tt = awful.tooltip {
text = side,
objects = {wb},
mode = "outside",
preferred_positions = {side},
preferred_alignments = {"front"},
}
tt.bg = beautiful.bg_normal
end
mouse.coords{x=125, y= 75}
mouse.push_history()
awesome.emit_signal("refresh")

View File

@ -0,0 +1,29 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
--DOC_HIDE_ALL
screen[1]._resize {width = 300, height = 150}
screen.no_outline = true
local awful = {tooltip = require("awful.tooltip")}
local beautiful = require("beautiful")
local wibox = require("wibox")
-- mouse.coords{x=50, y= 10}
local wb = wibox {width = 100, height = 44, x = 100, y = 50, visible = true}
awesome.emit_signal("refresh")
for _, side in ipairs{ "left", "right", "bottom", "top" } do
local tt = awful.tooltip {
text = side,
objects = {wb},
mode = "outside",
preferred_positions = {side},
preferred_alignments = {"middle"},
}
tt.bg = beautiful.bg_normal
end
mouse.coords{x=125, y= 75}
mouse.push_history()
awesome.emit_signal("refresh")

View File

@ -0,0 +1,29 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
--DOC_HIDE_ALL
screen[1]._resize {width = 300, height = 150}
screen.no_outline = true
local awful = {tooltip = require("awful.tooltip")}
local beautiful = require("beautiful")
local wibox = require("wibox")
-- mouse.coords{x=50, y= 10}
local wb = wibox {width = 100, height = 44, x = 100, y = 50, visible = true}
awesome.emit_signal("refresh")
for _, side in ipairs{ "left", "right", "bottom", "top" } do
local tt = awful.tooltip {
text = side,
objects = {wb},
mode = "outside",
preferred_positions = {side},
preferred_alignments = {"back"},
}
tt.bg = beautiful.bg_normal
end
mouse.coords{x=125, y= 75}
mouse.push_history()
awesome.emit_signal("refresh")

View File

@ -0,0 +1,28 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
--DOC_HIDE_ALL
screen[1]._resize {width = 300, height = 150}
screen.no_outline = true
local awful = {tooltip = require("awful.tooltip")}
local beautiful = require("beautiful")
local wibox = require("wibox")
-- mouse.coords{x=50, y= 10}
local wb = wibox {width = 100, height = 44, x = 100, y = 50, visible = true}
awesome.emit_signal("refresh")
for _, side in ipairs{ "left", "right", "bottom", "top" } do
local tt = awful.tooltip {
text = side,
objects = {wb},
mode = "outside",
preferred_positions = {side},
}
tt.bg = beautiful.bg_normal
end
mouse.coords{x=125, y= 75}
mouse.push_history()
awesome.emit_signal("refresh")

View File

@ -0,0 +1,34 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
--DOC_HIDE_ALL
screen[1]._resize {width = 640, height = 55}
screen.no_outline = true
local awful = {tooltip = require("awful.tooltip")}
local beautiful = require("beautiful")
local gears = {shape = require("gears.shape")}
-- mouse.coords{x=50, y= 10}
awesome.emit_signal("refresh")
local x_offset = 0
for _, shape in ipairs{ "rounded_rect", "rounded_bar", "octogon", "infobubble"} do
local tt = awful.tooltip {
text = shape,
mode = "mouse",
border_width = 2,
shape = gears.shape[shape],
border_color = beautiful.border_color,
}
tt.bg = beautiful.bg_normal
awesome.emit_signal("refresh")
tt:show()
awesome.emit_signal("refresh")
tt.wibox.x = x_offset
x_offset = x_offset + 640/5
end
mouse.coords{x=125, y= 0}
-- mouse.push_history()
awesome.emit_signal("refresh")

View File

@ -0,0 +1,31 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
screen[1]._resize {width = 300, height = 75} --DOC_HIDE
local awful = {tooltip = require("awful.tooltip"), wibar = require("awful.wibar")} --DOC_HIDE
local wibox = { widget = { textclock = require("wibox.widget.textclock") }, --DOC_HIDE
layout = { align = require("wibox.layout.align") } } --DOC_HIDE
local mytextclock = wibox.widget.textclock()
--DOC_NEWLINE
local wb = awful.wibar { position = "top" } --DOC_HIDE
wb:setup { layout = wibox.layout.align.horizontal, --DOC_HIDE
nil, nil, mytextclock} --DOC_HIDE
awesome.emit_signal("refresh") --DOC_HIDE the hierarchy is async
local myclock_t = awful.tooltip {
objects = { mytextclock },
timer_function = function()
return os.date("Today is %A %B %d %Y\nThe time is %T")
end,
}
awesome.emit_signal("refresh") --DOC_HIDE
mouse.coords{x=250, y= 10} --DOC_HIDE
mouse.push_history() --DOC_HIDE
assert(myclock_t.wibox and myclock_t.wibox.visible) --DOC_HIDE

View File

@ -0,0 +1,32 @@
--DOC_GEN_IMAGE
--DOC_NO_USAGE
screen[1]._resize {width = 300, height = 75} --DOC_HIDE
local awful = {tooltip = require("awful.tooltip"), wibar = require("awful.wibar")} --DOC_HIDE
local wibox = { widget = { textclock = require("wibox.widget.textclock") }, --DOC_HIDE
layout = { align = require("wibox.layout.align") } } --DOC_HIDE
local mytextclock = wibox.widget.textclock()
--DOC_NEWLINE
local wb = awful.wibar { position = "top" } --DOC_HIDE
wb:setup { layout = wibox.layout.align.horizontal, --DOC_HIDE
nil, nil, mytextclock} --DOC_HIDE
awesome.emit_signal("refresh") --DOC_HIDE the hierarchy is async
local myclock_t = awful.tooltip { }
--DOC_NEWLINE
myclock_t:add_to_object(mytextclock)
--DOC_NEWLINE
mytextclock:connect_signal("mouse::enter", function()
myclock_t.text = os.date("Today is %A %B %d %Y\nThe time is %T")
end)
awesome.emit_signal("refresh") --DOC_HIDE
mouse.coords{x=250, y= 10} --DOC_HIDE
mouse.push_history() --DOC_HIDE
assert(myclock_t.wibox and myclock_t.wibox.visible) --DOC_HIDE

View File

@ -63,6 +63,9 @@ end
-- Always show deprecated messages -- Always show deprecated messages
awesome.version = "v9999" awesome.version = "v9999"
-- SVG are composited. Without it we need a root surface
awesome.composite_manager_running = true
return awesome return awesome
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -2,6 +2,7 @@ local gears_obj = require("gears.object")
local drawin, meta = awesome._shim_fake_class() local drawin, meta = awesome._shim_fake_class()
local drawins = setmetatable({}, {__mode="v"}) local drawins = setmetatable({}, {__mode="v"})
local cairo = require("lgi").cairo
local function new_drawin(_, args) local function new_drawin(_, args)
local ret = gears_obj() local ret = gears_obj()
@ -11,6 +12,10 @@ local function new_drawin(_, args)
ret.y=0 ret.y=0
ret.width=1 ret.width=1
ret.height=1 ret.height=1
ret.border_width=0
ret.ontop = false
ret.below = false
ret.above = false
ret.geometry = function(_, new) ret.geometry = function(_, new)
new = new or {} new = new or {}
@ -26,6 +31,11 @@ local function new_drawin(_, args)
} }
end end
ret.data.drawable.valid = true
ret.data.drawable.surface = cairo.ImageSurface(cairo.Format.ARGB32, 0, 0)
ret.data.drawable.geometry = ret.geometry
ret.data.drawable.refresh = function() end
for _, k in pairs{ "buttons", "struts", "get_xproperty", "set_xproperty" } do for _, k in pairs{ "buttons", "struts", "get_xproperty", "set_xproperty" } do
ret[k] = function() end ret[k] = function() end
end end

View File

@ -7,10 +7,34 @@ local mouse = {
history = {}, history = {},
} }
-- Avoid gears when possible
local function contains(rect, point)
return point.x >= rect.x and point.x < rect.x+rect.width and
point.y >= rect.y and point.y < rect.y+rect.height
end
function mouse.coords(args) function mouse.coords(args)
if args then if args then
local old = {x = coords.x, y = coords.y}
coords.x, coords.y = args.x, args.y coords.x, coords.y = args.x, args.y
table.insert(mouse.history, {x=coords.x, y=coords.y}) table.insert(mouse.history, {x=coords.x, y=coords.y})
for _, d in ipairs(drawin.get()) do
local geo = d.geometry()
local was_in, is_in = contains(geo, old), contains(geo, coords)
local sig = {(is_in and not was_in) and "mouse::enter" or
(was_in and not is_in) and "mouse::leave" or "mouse::move"}
-- Enter is also a move, otherwise drawable.handle_motion isn't called
if sig[1] == "mouse::enter" then
table.insert(sig, "mouse::move")
end
for _, s in ipairs(sig) do
d:emit_signal(s, coords.x - geo.x, coords.y - geo.y)
d.drawable:emit_signal(s, coords.x - geo.x, coords.y - geo.y)
end
end
end end
return coords return coords