diff --git a/lib/awful/tooltip.lua b/lib/awful/tooltip.lua index 7907185c..9162efda 100644 --- a/lib/awful/tooltip.lua +++ b/lib/awful/tooltip.lua @@ -44,16 +44,19 @@ local mouse = mouse local timer = require("gears.timer") local util = require("awful.util") local object = require("gears.object") +local color = require("gears.color") local wibox = require("wibox") local a_placement = require("awful.placement") local abutton = require("awful.button") +local shape = require("gears.shape") local beautiful = require("beautiful") local textbox = require("wibox.widget.textbox") -local background = require("wibox.container.background") local dpi = require("beautiful").xresources.apply_dpi +local cairo = require("lgi").cairo local setmetatable = setmetatable +local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1) local ipairs = ipairs -local capi = {mouse=mouse} +local capi = {mouse=mouse, awesome=awesome} local tooltip = { mt = {} } @@ -83,7 +86,97 @@ local offset = { bottom = {x = 0, y = 1 }, } --- Place the tooltip under the mouse. +--- The tooltip border color. +-- @beautiful beautiful.tooltip_border_color + +--- The tooltip background color. +-- @beautiful beautiful.tooltip_bg + +--- The tooltip foregound (text) color. +-- @beautiful beautiful.tooltip_fg + +--- The tooltip font. +-- @beautiful beautiful.tooltip_font + +--- The tooltip border width. +-- @beautiful beautiful.tooltip_border_width + +--- The tooltip opacity. +-- @beautiful beautiful.tooltip_opacity + +--- The default tooltip shape. +-- By default, all tooltips are rectangles, however, by setting this variables, +-- they can default to rounded rectangle or stretched octogons. +-- @beautiful beautiful.tooltip_shape +-- @tparam[opt=gears.shape.rectangle] function shape A `gears.shape` compatible function +-- @see shape +-- @see gears.shape + +local function apply_shape(self) + local s = self._private.shape + + local wb = self.wibox + + if not s then + -- Clear the shape + if wb.shape_bounding then + wb.shape_bounding = nil + wb:set_bgimage(nil) + end + + return + end + + local w, h = wb.width, wb.height + + -- First, create a A1 mask for the shape bounding itself + local img = cairo.ImageSurface(cairo.Format.A1, w, h) + local cr = cairo.Context(img) + + cr:set_source_rgba(1,1,1,1) + + s(cr, w, h, unpack(self._private.shape_args or {})) + cr:fill() + wb.shape_bounding = img._native + + -- The wibox background uses ARGB32 border so tooltip anti-aliasing works + -- when an external compositor is used. This will look better than + -- the capi.drawin's own border support. + img = cairo.ImageSurface(cairo.Format.ARGB32, w, h) + cr = cairo.Context(img) + + -- Draw the border (multiply by 2, then mask the inner part to save a path) + local bw = (self._private.border_width + or beautiful.tooltip_border_width + or beautiful.border_width or 0) * 2 + + -- Fix anti-aliasing + if bw > 2 and awesome.composite_manager_running then + bw = bw - 1 + end + + local bc = self._private.border_color + or beautiful.tooltip_border_color + or beautiful.border_normal + or "#ffcb60" + + cr:translate(bw, bw) + s(cr, w-2*bw, h-2*bw, unpack(self._private.shape_args or {})) + cr:set_line_width(bw) + cr:set_source(color(bc)) + cr:stroke_preserve() + cr:clip() + + local bg = self._private.bg + or beautiful.tooltip_bg + or beautiful.bg_focus or "#ffcb60" + + cr:set_source(color(bg)) + cr:paint() + + wb:set_bgimage(img) +end + -- -- @tparam tooltip self A tooltip object. local function set_geometry(self) @@ -95,6 +188,10 @@ local function set_geometry(self) local w = self:get_wibox() w:geometry({ width = n_w, height = n_h }) + if self._private.shape then + apply_shape(self) + end + local align = self._private.align local real_placement = align_convert[align] @@ -216,6 +313,24 @@ function tooltip:set_align(value) self:emit_signal("property::align") end +--- The shape of the tooltip window. +-- If the shape require some parameters, use `set_shape`. +-- @property shape +-- @see gears.shape +-- @see set_shape +-- @see beautiful.tooltip_shape + +--- Set the tooltip shape. +-- All other arguments will be passed to the shape function. +-- @tparam gears.shape s The shape +-- @see shape +-- @see gears.shape +function tooltip:set_shape(s, ...) + self._private.shape = s + self._private.shape_args = {...} + apply_shape(self) +end + --- Change displayed text. -- -- @property text @@ -292,6 +407,7 @@ end -- seconds. -- @tparam[opt=apply_dpi(5)] integer args.margin_leftright The left/right margin for the text. -- @tparam[opt=apply_dpi(3)] integer args.margin_topbottom The top/bottom margin for the text. +-- @tparam[opt=nil] gears.shape args.shape The shape -- @treturn awful.tooltip The created tooltip. -- @see add_to_object -- @see timeout @@ -306,7 +422,9 @@ function tooltip.new(args) rawset(self,"_private", {}) self._private.visible = false - self._private.align = beautiful.tooltip_align or "right" + self._private.align = args.align or beautiful.tooltip_align or "right" + self._private.shape = args.shape or beautiful.tooltip_shape + or shape.rectangle -- private data if args.delay_show then @@ -350,27 +468,26 @@ function tooltip.new(args) self.timer:connect_signal("timeout", self.timer_function) end + local fg = beautiful.tooltip_fg or beautiful.fg_focus or "#000000" + local font = beautiful.tooltip_font or beautiful.font or "terminus 6" + -- Set default properties self.wibox_properties = { visible = false, ontop = true, - border_width = beautiful.tooltip_border_width or beautiful.border_width or 1, - border_color = beautiful.tooltip_border_color or beautiful.border_normal or "#ffcb60", + border_width = 0, + fg = fg, + bg = color.transparent, opacity = beautiful.tooltip_opacity or 1, - bg = beautiful.tooltip_bg_color or beautiful.bg_focus or "#ffcb60" } - local fg = beautiful.tooltip_fg_color or beautiful.fg_focus or "#000000" - local font = beautiful.tooltip_font or beautiful.font or "terminus 6" self.textbox = textbox() self.textbox:set_font(font) - self.background = background(self.textbox) - self.background:set_fg(fg) -- Add margin. local m_lr = args.margin_leftright or dpi(5) local m_tb = args.margin_topbottom or dpi(3) - self.marginbox = wibox.container.margin(self.background, m_lr, m_lr, m_tb, m_tb) + self.marginbox = wibox.container.margin(self.textbox, m_lr, m_lr, m_tb, m_tb) -- Add tooltip to objects if args.objects then