diff --git a/lib/awful/placement.lua b/lib/awful/placement.lua index 3cc2ceb0..cc77d7ce 100644 --- a/lib/awful/placement.lua +++ b/lib/awful/placement.lua @@ -262,16 +262,19 @@ local resize_to_point_map = { } -- Outer position matrix --- 1=best case, 2=fallback local outer_positions = { - left1 = function(r, w, _) return {x=r.x-w , y=r.y }, "down" end, - left2 = function(r, w, h) return {x=r.x-w , y=r.y-h+r.height }, "up" end, - right1 = function(r, _, _) return {x=r.x , y=r.y }, "down" end, - right2 = function(r, _, h) return {x=r.x , y=r.y-h+r.height }, "up" end, - top1 = function(r, _, h) return {x=r.x , y=r.y-h }, "right" end, - top2 = function(r, w, h) return {x=r.x-w+r.width, y=r.y-h }, "left" end, - bottom1 = function(r, _, _) return {x=r.x , y=r.y }, "right" end, - bottom2 = function(r, w, _) return {x=r.x-w+r.width, y=r.y }, "left" end, + left_front = function(r, w, _) return {x=r.x-w , y=r.y }, "front" end, + left_back = function(r, w, h) return {x=r.x-w , y=r.y-h+r.height }, "back" end, + left_middle = function(r, w, h) return {x=r.x-w , y=r.y-h/2+r.height/2 }, "middle" end, + right_front = function(r, _, _) return {x=r.x , y=r.y }, "front" end, + right_back = function(r, _, h) return {x=r.x , y=r.y-h+r.height }, "back" end, + right_middle = function(r, _, h) return {x=r.x , y=r.y-h/2+r.height/2 }, "middle" end, + top_front = function(r, _, h) return {x=r.x , y=r.y-h }, "front" 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. @@ -644,7 +647,6 @@ local function get_cross_sections(abs_geo, mode) } elseif mode == "geometry" then -- The widget geometry extended to reach the end of the drawable - return { h = { x = abs_geo.drawable_geo.x , @@ -702,23 +704,39 @@ local function get_relative_regions(geo, mode, is_absolute) end end - -- Get the drawable geometry - local dpos = geo.drawable and ( - geo.drawable.drawable and - geo.drawable.drawable:geometry() - or geo.drawable:geometry() - ) or {x=0, y=0} + -- Get the parent geometry using one way or another depending on the object + -- Type + local bw, dgeo = 0, {x=0, y=0, width=1, height=1} + + -- Detect various types of geometry table and (try) to get rid of the + -- 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 - local abs_widget_geo = is_absolute and geo or { - x = dpos.x + geo.x , - y = dpos.y + geo.y , - width = geo.width , - height = geo.height , - drawable = geo.drawable , + local abs_widget_geo = is_absolute and dgeo or { + x = dgeo.x + geo.x + bw, + y = dgeo.y + geo.y + bw, + width = geo.width , + height = geo.height , + 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. 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. -- +-- 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: -- -- {"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 -- 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 table args -- @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 -- @treturn table The new geometry --- @treturn string The choosen position --- @treturn string The choosen direction +-- @treturn string The choosen position ("left", "right", "top" or "bottom") +-- @treturn string The choosen anchor ("front", "middle" or "back") function placement.next_to(d, args) args = add_context(args, "next_to") 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 end @@ -1391,40 +1447,72 @@ function placement.next_to(d, args) 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 -- and order them by preferred_positions local does_fit = {} - for k,v in pairs(regions) do - local geo, dir = outer_positions[k.."1"](v, dgeo.width, dgeo.height) - geo.width, geo.height = dgeo.width, dgeo.height - local fit = fit_in_bounding(v.screen, geo, args) + for _, pos in ipairs(sorted_regions) do + local geo, dir, fit + + -- 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 - fit = fit_in_bounding(v.screen, geo, args) + + fit = fit_in_bounding(pos.region.screen, geo, args) + + if fit then break 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 - pref_idx = preferred_positions[k] - pref_name = k + if fit and preferred_positions[pos.name] and preferred_positions[pos.name] < pref_idx then + pref_idx = preferred_positions[pos.name] + pref_name = pos.name end -- No need to continue - if fit and preferred_positions[k] == 1 then break end + if fit then break end end - local pos_name = pref_name or next(does_fit) - local ngeo, dir = unpack(does_fit[pos_name] or {}) --FIXME why does this happen + local ngeo, dir = unpack(does_fit[pref_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) 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 --- Restore the geometry. diff --git a/lib/awful/tooltip.lua b/lib/awful/tooltip.lua index 39aa0910..62970d96 100644 --- a/lib/awful/tooltip.lua +++ b/lib/awful/tooltip.lua @@ -10,13 +10,16 @@ -- How to create a tooltip? -- --- -- --- myclock = wibox.widget.textclock("%T", 1) --- myclock_t = awful.tooltip({ --- objects = { myclock }, --- timer_function = function() --- return os.date("Today is %A %B %d %Y\nThe time is %T") --- end, --- }) +-- @DOC_awful_tooltip_textclock_EXAMPLE@ +-- +-- Alternatively, you can use `mouse::enter` signal: +-- +-- @DOC_awful_tooltip_textclock2_EXAMPLE@ +-- +-- How to create a tooltip without objects? +-- --- +-- +-- @DOC_awful_tooltip_mouse_EXAMPLE@ -- -- 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, { geometry = self._private.widget_geometry, preferred_positions = self.preferred_positions, + preferred_anchors = self.preferred_alignments, honor_workarea = true, }) @@ -228,6 +232,13 @@ end --- 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: -- -- * top_left @@ -241,6 +252,8 @@ end -- -- @property align -- @see beautiful.tooltip_align +-- @see mode +-- @see preferred_positions --- The default tooltip alignment. -- @beautiful beautiful.tooltip_align @@ -264,6 +277,9 @@ end --- The shape of the tooltip window. -- If the shape require some parameters, use `set_shape`. +-- +-- @DOC_awful_tooltip_shape_EXAMPLE@ +-- -- @property shape -- @see gears.shape -- @see set_shape @@ -274,7 +290,6 @@ end -- @tparam gears.shape s The shape -- @see shape -- @see gears.shape - function tooltip:set_shape(s) self.backgroundbox:set_shape(s) end @@ -284,6 +299,14 @@ end -- close to the mouse cursor. It is also possible to place the tooltip relative -- to the widget geometry. -- +-- **mouse:** +-- +-- @DOC_awful_tooltip_mode_EXAMPLE@ +-- +-- **outside:** +-- +-- @DOC_awful_tooltip_mode2_EXAMPLE@ +-- -- Valid modes are: -- -- * "mouse": Next to the mouse cursor @@ -305,8 +328,17 @@ end --- 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 --- priority +-- priority. +-- +-- The valid table values are: +-- +-- * "top" +-- * "right" +-- * "left" +-- * "bottom" -- -- The default is: -- @@ -314,6 +346,9 @@ end -- -- @property preferred_positions -- @tparam table preferred_positions The position, ordered by priorities +-- @see align +-- @see mode +-- @see preferred_alignments function tooltip:get_preferred_positions() return self._private.preferred_positions or @@ -326,6 +361,48 @@ function tooltip:set_preferred_positions(value) set_geometry(self) 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. -- -- @property text @@ -370,6 +447,8 @@ end --- Set all margins around the tooltip textbox -- +-- @DOC_awful_tooltip_margins_EXAMPLE@ +-- -- @property margins -- @tparam tooltip self A tooltip object -- @tparam number New margins value @@ -378,26 +457,62 @@ function tooltip:set_margins(val) self.marginbox:set_margins(val) 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 -- +-- @DOC_awful_tooltip_margins_leftright_EXAMPLE@ +-- -- @property margins_leftright -- @tparam tooltip self A tooltip object -- @tparam number New margins value function tooltip:set_margin_leftright(val) - self.marginbox.left = val - self.marginbox.right = val + self.marginbox:set_left(val) + self.marginbox:set_right(val) +end + +--TODO v5 deprecate this +function tooltip:set_margins_leftright(val) + self:set_margin_leftright(val) end --- Set the margins around the top and bottom of the tooltip textbox -- +-- @DOC_awful_tooltip_margins_topbottom_EXAMPLE@ +-- -- @property margins_topbottom -- @tparam tooltip self A tooltip object -- @tparam number New margins value function tooltip:set_margin_topbottom(val) - self.marginbox.top = val - self.marginbox.bottom = val + self.marginbox:set_top(val) + self.marginbox:set_bottom(val) +end + +--TODO v5 deprecate this +function tooltip:set_margins_topbottom(val) + self:set_margin_topbottom(val) end --- Add tooltip to an object. @@ -509,7 +624,7 @@ function tooltip.new(args) function self.show(other, geo) -- Auto detect clients and wiboxes if other.drawable or other.pid then - geo = other:geometry() + geo = other end -- Cache the geometry in case it is needed later diff --git a/lib/wibox/init.lua b/lib/wibox/init.lua index a8037954..00840560 100644 --- a/lib/wibox/init.lua +++ b/lib/wibox/init.lua @@ -253,6 +253,10 @@ local function new(args) ret._drawable = wibox.drawable(w.drawable, { wibox = ret }, "wibox drawable (" .. object.modulename(3) .. ")") + function ret._drawable.get_wibox() + return ret + end + ret._drawable:_inform_visible(w.visible) w:connect_signal("property::visible", function() ret._drawable:_inform_visible(w.visible) diff --git a/tests/examples/awful/placement/next_to.lua b/tests/examples/awful/placement/next_to.lua new file mode 100644 index 00000000..ae355728 --- /dev/null +++ b/tests/examples/awful/placement/next_to.lua @@ -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 diff --git a/tests/examples/awful/template.lua b/tests/examples/awful/template.lua index 9f84404f..a6a824b3 100644 --- a/tests/examples/awful/template.lua +++ b/tests/examples/awful/template.lua @@ -11,6 +11,11 @@ local wibox = require( "wibox" ) -- Run the test 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 local img = cairo.SvgSurface.create(image_path..".svg", screen._get_extents() ) @@ -30,26 +35,28 @@ local function draw_mouse(x, y) end -- Print an outline for the screens -for _, s in ipairs(screen) do - cr:save() - -- Draw the screen outline - cr:set_source(color("#00000044")) - cr:set_line_width(1.5) - cr:set_dash({10,4},1) - cr:rectangle(s.geometry.x+0.75,s.geometry.y+0.75,s.geometry.width-1.5,s.geometry.height-1.5) - cr:stroke() +if not screen.no_outline then + for _, s in ipairs(screen) do + cr:save() + -- Draw the screen outline + cr:set_source(color("#00000044")) + cr:set_line_width(1.5) + cr:set_dash({10,4},1) + cr:rectangle(s.geometry.x+0.75,s.geometry.y+0.75,s.geometry.width-1.5,s.geometry.height-1.5) + cr:stroke() - -- Draw the workarea outline - cr:set_source(color("#00000033")) - cr:rectangle(s.workarea.x,s.workarea.y,s.workarea.width,s.workarea.height) - cr:stroke() + -- Draw the workarea outline + cr:set_source(color("#00000033")) + cr:rectangle(s.workarea.x,s.workarea.y,s.workarea.width,s.workarea.height) + cr:stroke() - -- Draw the padding outline - --TODO - cr:restore() + -- Draw the padding outline + --TODO + cr:restore() + end end -cr:set_line_width(beautiful.border_width) +cr:set_line_width(beautiful.border_width/2) cr:set_source(color(beautiful.border_color)) @@ -125,11 +132,7 @@ local function client_widget(c, col, label) return wibox.widget { { - { - l, - margins = bw + 1, -- +1 because the the SVG AA - layout = wibox.container.margin - }, + l, { text = label or "", align = "center", @@ -138,22 +141,40 @@ local function client_widget(c, col, label) }, layout = wibox.layout.stack }, - shape_border_width = bw*2, + shape_border_width = bw, shape_border_color = beautiful.border_color, shape_clip = true, fg = beautiful.fg_normal or "#000000", bg = col, - forced_width = geo.width + 2*bw, - forced_height = geo.height + 2*bw, shape = function(cr2, w, h) return shape.rounded_rect(cr2, w, h, args.radius or 5) end, - widget = wibox.container.background, + forced_width = geo.width + 2*bw, + forced_height = geo.height + 2*bw, + widget = wibox.container.background, } end -- 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 local w = d.get_wibox and d:get_wibox() or nil if w then @@ -164,43 +185,45 @@ end -- Loop each clients geometry history and paint it for _, c in ipairs(client.get()) do - local pgeo = nil - for _, geo in ipairs(c._old_geo) do - if not geo._hide then - total_area:add_at( - client_widget(c, c.color or geo._color or beautiful.bg_normal, geo._label), - {x=geo.x, y=geo.y} - ) + if not c.minimized then + local pgeo = nil + for _, geo in ipairs(c._old_geo) do + if not geo._hide then + total_area:add_at( + client_widget(c, c.color or geo._color or beautiful.bg_normal, geo._label), + {x=geo.x, y=geo.y} + ) + end + + -- Draw lines between the old and new corners + if pgeo and not args.hide_lines then + cr:save() + cr:set_source_rgba(0,0,0,.1) + + -- Top left + cr:move_to(pgeo.x, pgeo.y) + cr:line_to(geo.x, geo.y) + cr:stroke() + + -- Top right + cr:move_to(pgeo.x+pgeo.width, pgeo.y) + cr:line_to(geo.x+pgeo.width, geo.y) + + -- Bottom left + cr:move_to(pgeo.x, pgeo.y+pgeo.height) + cr:line_to(geo.x, geo.y+geo.height) + cr:stroke() + + -- Bottom right + cr:move_to(pgeo.x+pgeo.width, pgeo.y+pgeo.height) + cr:line_to(geo.x+pgeo.width, geo.y+geo.height) + cr:stroke() + + cr:restore() + end + + pgeo = geo end - - -- Draw lines between the old and new corners - if pgeo and not args.hide_lines then - cr:save() - cr:set_source_rgba(0,0,0,.1) - - -- Top left - cr:move_to(pgeo.x, pgeo.y) - cr:line_to(geo.x, geo.y) - cr:stroke() - - -- Top right - cr:move_to(pgeo.x+pgeo.width, pgeo.y) - cr:line_to(geo.x+pgeo.width, geo.y) - - -- Bottom left - cr:move_to(pgeo.x, pgeo.y+pgeo.height) - cr:line_to(geo.x, geo.y+geo.height) - cr:stroke() - - -- Bottom right - cr:move_to(pgeo.x+pgeo.width, pgeo.y+pgeo.height) - cr:line_to(geo.x+pgeo.width, geo.y+geo.height) - cr:stroke() - - cr:restore() - end - - pgeo = geo end end diff --git a/tests/examples/awful/tooltip/align.lua b/tests/examples/awful/tooltip/align.lua new file mode 100644 index 00000000..da6b5e86 --- /dev/null +++ b/tests/examples/awful/tooltip/align.lua @@ -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") diff --git a/tests/examples/awful/tooltip/align2.lua b/tests/examples/awful/tooltip/align2.lua new file mode 100644 index 00000000..a0540f52 --- /dev/null +++ b/tests/examples/awful/tooltip/align2.lua @@ -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") diff --git a/tests/examples/awful/tooltip/border_color.lua b/tests/examples/awful/tooltip/border_color.lua new file mode 100644 index 00000000..452eec13 --- /dev/null +++ b/tests/examples/awful/tooltip/border_color.lua @@ -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") diff --git a/tests/examples/awful/tooltip/border_width.lua b/tests/examples/awful/tooltip/border_width.lua new file mode 100644 index 00000000..633f27f8 --- /dev/null +++ b/tests/examples/awful/tooltip/border_width.lua @@ -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") diff --git a/tests/examples/awful/tooltip/margins.lua b/tests/examples/awful/tooltip/margins.lua new file mode 100644 index 00000000..65fd743a --- /dev/null +++ b/tests/examples/awful/tooltip/margins.lua @@ -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") diff --git a/tests/examples/awful/tooltip/margins_leftright.lua b/tests/examples/awful/tooltip/margins_leftright.lua new file mode 100644 index 00000000..21ef3aeb --- /dev/null +++ b/tests/examples/awful/tooltip/margins_leftright.lua @@ -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") diff --git a/tests/examples/awful/tooltip/margins_topbottom.lua b/tests/examples/awful/tooltip/margins_topbottom.lua new file mode 100644 index 00000000..c815c955 --- /dev/null +++ b/tests/examples/awful/tooltip/margins_topbottom.lua @@ -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") diff --git a/tests/examples/awful/tooltip/mode.lua b/tests/examples/awful/tooltip/mode.lua new file mode 100644 index 00000000..9102e37a --- /dev/null +++ b/tests/examples/awful/tooltip/mode.lua @@ -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") diff --git a/tests/examples/awful/tooltip/mode2.lua b/tests/examples/awful/tooltip/mode2.lua new file mode 100644 index 00000000..ec1736a7 --- /dev/null +++ b/tests/examples/awful/tooltip/mode2.lua @@ -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") diff --git a/tests/examples/awful/tooltip/mouse.lua b/tests/examples/awful/tooltip/mouse.lua new file mode 100644 index 00000000..348d2e40 --- /dev/null +++ b/tests/examples/awful/tooltip/mouse.lua @@ -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 diff --git a/tests/examples/awful/tooltip/preferred_alignment.lua b/tests/examples/awful/tooltip/preferred_alignment.lua new file mode 100644 index 00000000..dca897f2 --- /dev/null +++ b/tests/examples/awful/tooltip/preferred_alignment.lua @@ -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") diff --git a/tests/examples/awful/tooltip/preferred_alignment2.lua b/tests/examples/awful/tooltip/preferred_alignment2.lua new file mode 100644 index 00000000..1040c00a --- /dev/null +++ b/tests/examples/awful/tooltip/preferred_alignment2.lua @@ -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") diff --git a/tests/examples/awful/tooltip/preferred_alignment3.lua b/tests/examples/awful/tooltip/preferred_alignment3.lua new file mode 100644 index 00000000..288e963e --- /dev/null +++ b/tests/examples/awful/tooltip/preferred_alignment3.lua @@ -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") diff --git a/tests/examples/awful/tooltip/preferred_positions.lua b/tests/examples/awful/tooltip/preferred_positions.lua new file mode 100644 index 00000000..1000d387 --- /dev/null +++ b/tests/examples/awful/tooltip/preferred_positions.lua @@ -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") diff --git a/tests/examples/awful/tooltip/shape.lua b/tests/examples/awful/tooltip/shape.lua new file mode 100644 index 00000000..b83a3893 --- /dev/null +++ b/tests/examples/awful/tooltip/shape.lua @@ -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") diff --git a/tests/examples/awful/tooltip/textclock.lua b/tests/examples/awful/tooltip/textclock.lua new file mode 100644 index 00000000..00f32dcc --- /dev/null +++ b/tests/examples/awful/tooltip/textclock.lua @@ -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 diff --git a/tests/examples/awful/tooltip/textclock2.lua b/tests/examples/awful/tooltip/textclock2.lua new file mode 100644 index 00000000..6aeec3fb --- /dev/null +++ b/tests/examples/awful/tooltip/textclock2.lua @@ -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 diff --git a/tests/examples/shims/awesome.lua b/tests/examples/shims/awesome.lua index 6af6f0e9..d162fd06 100644 --- a/tests/examples/shims/awesome.lua +++ b/tests/examples/shims/awesome.lua @@ -63,6 +63,9 @@ end -- Always show deprecated messages awesome.version = "v9999" +-- SVG are composited. Without it we need a root surface +awesome.composite_manager_running = true + return awesome -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/tests/examples/shims/drawin.lua b/tests/examples/shims/drawin.lua index 121a7a8d..1f1e8436 100644 --- a/tests/examples/shims/drawin.lua +++ b/tests/examples/shims/drawin.lua @@ -2,6 +2,7 @@ local gears_obj = require("gears.object") local drawin, meta = awesome._shim_fake_class() local drawins = setmetatable({}, {__mode="v"}) +local cairo = require("lgi").cairo local function new_drawin(_, args) local ret = gears_obj() @@ -11,6 +12,10 @@ local function new_drawin(_, args) ret.y=0 ret.width=1 ret.height=1 + ret.border_width=0 + ret.ontop = false + ret.below = false + ret.above = false ret.geometry = function(_, new) new = new or {} @@ -26,6 +31,11 @@ local function new_drawin(_, args) } 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 ret[k] = function() end end diff --git a/tests/examples/shims/mouse.lua b/tests/examples/shims/mouse.lua index c4766f3b..20c35f0d 100644 --- a/tests/examples/shims/mouse.lua +++ b/tests/examples/shims/mouse.lua @@ -7,10 +7,34 @@ local mouse = { 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) if args then + local old = {x = coords.x, y = coords.y} coords.x, coords.y = args.x, args.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 return coords