diff --git a/tests/examples/screen/template.lua b/tests/examples/screen/template.lua
index b0f53f0dc..7a68725fe 100644
--- a/tests/examples/screen/template.lua
+++ b/tests/examples/screen/template.lua
@@ -76,12 +76,13 @@ local function stripe_pat(col, angle, line_width, spacing)
end
local colors = {
- geometry = "#000000",
- workarea = "#0000ff",
- tiling_area = "#ff0000",
- padding_area= "#ff0000",
- wibar = "#000000",
+ geometry = "#000000",
+ workarea = "#0000ff",
+ tiling_area = "#ff0000",
+ padding_area = "#ff0000",
+ wibar = "#000000",
tiling_client = "#ff0000",
+ gaps = "#9900ff",
}
local function draw_area(_, rect, name, offset, highlight)
@@ -142,6 +143,7 @@ local function write_on_area_middle(rect, text, offset)
cr:show_layout(playout)
end
+-- For clients/wibars with struts only.
local function draw_struct(_, struct, name, offset, label)
draw_solid_area(_, struct, name, offset)
if type(label) == 'string' then
@@ -149,6 +151,15 @@ local function draw_struct(_, struct, name, offset, label)
end
end
+-- For floating or tiled clients.
+local function draw_client(_, c, name, offset, label, alpha)
+ draw_solid_area(_, c, name, offset, alpha)
+ if type(label) == 'string' then
+ write_on_area_middle(c, label, offset)
+ end
+end
+
+
local function compute_ruler(_, rect, name)
table.insert(hrulers, {
label = name, x = rect.x, width = rect.width
@@ -176,7 +187,37 @@ end
local dx = 5
-local function show_ruler_label(offset, padding, ruler, playout)
+local playout, playout_height = nil, nil
+
+local function get_playout()
+ if playout then return playout end
+
+ local pctx = PangoCairo.font_map_get_default():create_context()
+ playout = Pango.Layout.new(pctx)
+ local pdesc = Pango.FontDescription()
+ pdesc:set_absolute_size(11 * Pango.SCALE)
+ playout:set_font_description(pdesc)
+
+ return playout
+end
+
+local function get_text_height()
+ if playout_height then return playout_height end
+
+ local l = get_playout()
+ local attr, parsed = Pango.parse_markup("GeometryWorkareaPaddingMargins", -1, 0)
+ l.attributes, l.text = attr, parsed
+
+ local _, logical = playout:get_pixel_extents()
+
+ playout_height = logical.height
+
+ return playout_height
+end
+
+local function show_ruler_label(offset, padding, ruler, playout2)
+ if not ruler.label then return end
+
local lbl
if ruler.x then
@@ -187,13 +228,85 @@ local function show_ruler_label(offset, padding, ruler, playout)
ruler.y.." height = "..ruler.height..""
end
+ local attr, parsed = Pango.parse_markup(lbl, -1, 0)
+ playout2.attributes, playout2.text = attr, parsed
+ local _, logical = playout2:get_pixel_extents()
+ cr:move_to((offset.x - logical.width) /2, offset.y+padding)
+ cr:show_layout(playout2)
+end
+
+local function show_aligned_label(dx2, offset, padding, ruler)
+ local lbl
+
+ if ruler.x then
+ lbl = ruler.width
+ else
+ lbl = ruler.height
+ end
+
local attr, parsed = Pango.parse_markup(lbl, -1, 0)
playout.attributes, playout.text = attr, parsed
local _, logical = playout:get_pixel_extents()
- cr:move_to((offset.x - logical.width) /2, offset.y+padding)
+
+ if ruler.x then
+ local off = (ruler.width*factor - logical.width)/2
+ cr:move_to(ruler.x*factor+off, offset.y+padding)
+ else
+ local off = (ruler.height*factor - logical.width)/2
+ cr:move_to(-ruler.y*factor-dx2*factor-off, padding)
+ end
+
cr:show_layout(playout)
end
+local function draw_vruler(s, dx2, sx, ruler, layer)
+ local pad = 5+(layer-1)*dx2
+ cr:set_source(color(ruler.color or (colors[ruler.label].."66")))
+ cr:move_to(sx+layer*dx2, ruler.y*factor)
+ cr:line_to(sx+layer*dx2, ruler.y*factor+ruler.height*factor)
+ cr:stroke()
+
+ cr:move_to(sx+layer*dx2-2.5,ruler.y*factor)
+ cr:line_to(sx+layer*dx2+2.5, ruler.y*factor)
+ cr:stroke()
+
+ cr:move_to(sx+layer*dx2-2.5,ruler.y*factor+ruler.height*factor)
+ cr:line_to(sx+layer*dx2+2.5, ruler.y*factor+ruler.height*factor)
+ cr:stroke()
+
+ cr:save()
+ cr:move_to(sx+layer*dx2-2.5,ruler.y*factor)
+ cr:rotate(-math.pi/2)
+ if ruler and ruler.label then
+ show_ruler_label({x=-s.geometry.height*factor, y=sx}, pad, ruler, get_playout())
+ elseif ruler and ruler.align then
+ show_aligned_label(dx2, {x=s.geometry.width*factor, y=0}, pad, ruler)
+ end
+ cr:restore()
+end
+
+local function draw_hruler(s, dx2, sy, ruler, layer)
+ local pad = 10+(layer-1)*(dx2 or 0)
+ cr:set_source(color(ruler.color or (colors[ruler.label].."66")))
+ cr:move_to(ruler.x*factor, sy+pad)
+ cr:line_to(ruler.x*factor+ruler.width*factor, sy+pad)
+ cr:stroke()
+
+ cr:move_to(ruler.x*factor, sy+pad-2.5)
+ cr:line_to(ruler.x*factor, sy+pad+2.5)
+ cr:stroke()
+
+ cr:move_to(ruler.x*factor+ruler.width*factor, sy+pad-2.5)
+ cr:line_to(ruler.x*factor+ruler.width*factor, sy+pad+2.5)
+ cr:stroke()
+
+ if ruler and ruler.label then
+ show_ruler_label({x=s.geometry.width*factor, y=sy}, pad, ruler, get_playout())
+ elseif ruler and ruler.align then
+ show_aligned_label(dx2, {x=s.geometry.width*factor, y=sy}, pad, ruler)
+ end
+end
+
local function draw_rulers(s)
-- The table has a maximum of 4 entries, the sort algorithm is irrelevant.
while not bubble_sort(hrulers, "x", "width" ) do end
@@ -205,67 +318,290 @@ local function draw_rulers(s)
local sx = (s.geometry.x+s.geometry.width )*factor
local sy = (s.geometry.y+s.geometry.height)*factor
-
- local pctx = PangoCairo.font_map_get_default():create_context()
- local playout = Pango.Layout.new(pctx)
- local pdesc = Pango.FontDescription()
- pdesc:set_absolute_size(11 * Pango.SCALE)
- playout:set_font_description(pdesc)
- local attr, parsed = Pango.parse_markup("GeometryWorkareaPaddingMargins", -1, 0)
- playout.attributes, playout.text = attr, parsed
- local _, logical = playout:get_pixel_extents()
- dx = logical.height + 10
+ dx = get_text_height() + 10
for k, ruler in ipairs(vrulers) do
- local pad = 5+(k-1)*dx
- cr:set_source(color(colors[ruler.label].."66"))
- cr:move_to(sx+k*dx, ruler.y*factor)
- cr:line_to(sx+k*dx, ruler.y*factor+ruler.height*factor)
- cr:stroke()
-
- cr:move_to(sx+k*dx-2.5,ruler.y*factor)
- cr:line_to(sx+k*dx+2.5, ruler.y*factor)
- cr:stroke()
-
- cr:move_to(sx+k*dx-2.5,ruler.y*factor+ruler.height*factor)
- cr:line_to(sx+k*dx+2.5, ruler.y*factor+ruler.height*factor)
- cr:stroke()
-
- cr:save()
- cr:move_to(sx+k*dx-2.5,ruler.y*factor)
- cr:rotate(-math.pi/2)
- show_ruler_label({x=-s.geometry.height*factor, y=sx}, pad, ruler, playout)
- cr:restore()
+ draw_vruler(s, dx, sx, ruler, k)
end
-
for k, ruler in ipairs(hrulers) do
- local pad = 10+(k-1)*dx
- cr:set_source(color(colors[ruler.label].."66"))
- cr:move_to(ruler.x*factor, sy+pad)
- cr:line_to(ruler.x*factor+ruler.width*factor, sy+pad)
- cr:stroke()
-
- cr:move_to(ruler.x*factor, sy+pad-2.5)
- cr:line_to(ruler.x*factor, sy+pad+2.5)
- cr:stroke()
-
- cr:move_to(ruler.x*factor+ruler.width*factor, sy+pad-2.5)
- cr:line_to(ruler.x*factor+ruler.width*factor, sy+pad+2.5)
- cr:stroke()
-
- show_ruler_label({x=s.geometry.width*factor, y=sy}, pad, ruler, playout)
+ draw_hruler(s, dx, sy, ruler, k)
end
end
+local tr_x, tr_y = 0, 0
+
+-- Not a very efficient way to do this, but at least it is simple.
+local function deduplicate_gaps(gaps)
+ for _, gap1 in ipairs(gaps) do
+ for k, gap2 in ipairs(gaps) do
+ if gap1[2] == gap2[1] then
+ gap1[2] = gap2[2]
+ table.remove(gaps, k)
+ return true
+ elseif gap2[1] >= gap1[1] and gap2[2] <= gap1[2] and gap1 ~= gap2 then
+ table.remove(gaps, k)
+ return true
+ elseif gap1[1] == gap2[1] and gap2[2] == gap2[2] and gap1 ~= gap2 then
+ table.remove(gaps, k)
+ return true
+ end
+ end
+ end
+
+
+ return false
+end
+
+local function get_gaps(s)
+ local ret = {vertical={gaps={}, content={}}, horizontal={gaps={}, content={}}}
+
+ local gap = s.selected_tag.gap
+
+ if gap == 0 then return ret end
+
+ if s.selected_tag.gap_single_client == false and #s.tiled_clients == 1 then
+ return ret
+ end
+
+ -- First, get all gaps.
+ for _, c in ipairs(s.tiled_clients) do
+ local bw = c.border_width
+ table.insert(ret.horizontal.gaps, {c.x-gap , c.x })
+ table.insert(ret.vertical.gaps , {c.y-gap , c.y })
+ table.insert(ret.horizontal.gaps, {c.x+c.width +2*bw, c.x+c.width+gap +2*bw})
+ table.insert(ret.vertical.gaps , {c.y+c.height+2*bw, c.y+c.height+gap+2*bw})
+ end
+
+ -- Merge continuous gaps.
+ while deduplicate_gaps(ret.vertical.gaps ) do end
+ while deduplicate_gaps(ret.horizontal.gaps) do end
+
+ return ret
+end
+
+local function evaluate_translation(draw_gaps, draw_struts, draw_mwfact, draw_client_snap)
+ for s in screen do
+ if (draw_gaps and s.selected_tag and s.selected_tag.gap > 0) then
+ local gaps = get_gaps(s)
+
+ -- Only add the space if there is something to display.
+ if #gaps.horizontal.gaps > 0 then
+ tr_y = math.max(tr_y, 3 * get_text_height())
+ end
+
+ if #gaps.vertical.gaps > 0 then
+ tr_x = math.max(tr_x, 2 * get_text_height())
+ end
+ end
+
+ if draw_client_snap or draw_struts then
+ tr_y = math.max(tr_y, 3 * get_text_height())
+ tr_x = math.max(tr_x, 2 * get_text_height())
+ end
+
+ if draw_mwfact then
+ tr_y = math.max(tr_y, 3 * get_text_height())
+ end
+ end
+end
+
+local function translate()
+ cr:translate(tr_x, tr_y * 0.66)
+end
+
+local function draw_gaps(s)
+ cr:translate(-tr_x, -tr_y)
+
+ local gaps = get_gaps(s)
+
+ local offset = s.tiling_area
+
+ for _, hgap in ipairs(gaps.horizontal.gaps) do
+ draw_hruler(
+ s,
+ offset.x,
+ get_text_height(),
+ {
+ x = offset.x+hgap[1]+tr_x,
+ width = math.ceil(hgap[2]-hgap[1]),
+ label = nil,
+ color = colors.gaps.."66",
+ align = true
+ },
+ 1
+ )
+ end
+
+ for _, vgap in ipairs(gaps.vertical.gaps) do
+ draw_vruler(
+ s,
+ get_text_height()*1.5,
+ 0,
+ {
+ y = offset.y+vgap[1]+tr_y,
+ height = math.ceil(vgap[2]-vgap[1]),
+ label = nil,
+ color = colors.gaps.."66",
+ align = true
+ },
+ 1
+ )
+ end
+
+ cr:translate(tr_x, tr_y)
+end
+
+local function has_struts(s)
+ for k, v in pairs(s.workarea) do
+ if s.geometry[k] ~= v then
+ return true
+ end
+ end
+
+ return false
+end
+
+local function draw_struts(s)
+ local left = s.workarea.x - s.geometry.x
+ local right = (s.geometry.x + s.geometry.width) - (s.workarea.x + s.workarea.width)
+ local top = s.workarea.y - s.geometry.y
+ local bottom = (s.geometry.y + s.geometry.height) - (s.workarea.y + s.workarea.height)
+
+ cr:translate(-tr_x, -tr_y)
+
+ if left > 0 then
+ draw_hruler(
+ s,
+ 0,
+ get_text_height(),
+ {x = s.geometry.x+tr_x*2, width = left, color = colors.gaps.."66", align = true},
+ 1
+ )
+ end
+
+ if top > 0 then
+ draw_vruler(
+ s,
+ get_text_height()*1.5,
+ 0,
+ {y=s.geometry.y+tr_y*(1/factor), height = top, color = colors.gaps.."66", align = true},
+ 1
+ )
+ end
+
+ if right > 0 then
+ draw_hruler(
+ s,
+ 0,
+ get_text_height(),
+ {x = s.geometry.x, width = left, color = colors.gaps.."66", align = true},
+ 1
+ )
+ end
+
+ if bottom > 0 then
+ draw_vruler(
+ s,
+ get_text_height()*1.5,
+ 0,
+ {
+ y = s.geometry.y+tr_y*(1/factor)+s.geometry.height - bottom,
+ height = bottom,
+ color = colors.gaps.."66",
+ align = true
+ },
+ 1
+ )
+ end
+
+ cr:translate(tr_x, tr_y)
+end
+
+local function draw_mwfact(s)
+ cr:translate(-tr_x, -tr_y)
+
+ local mwfact = s.selected_tag.master_width_factor
+
+ local offset = s.tiling_area.x
+ local width = s.tiling_area.width
+
+ local w1, w2 = math.ceil(width*mwfact), math.ceil(width*(1-mwfact))
+
+ draw_hruler(s, offset, get_text_height(), {x=offset,width=w1,color = colors.gaps.."66", align=true}, 1)
+ draw_hruler(s, offset, get_text_height(), {x=offset+w1,width=w2,color = colors.gaps.."66", align=true}, 1)
+
+ cr:translate(tr_x, tr_y)
+end
+
+local function draw_client_snap(s)
+ cr:translate(-tr_x, -tr_y)
+
+ local snap_areas = {
+ vertical ={},
+ horizontal={}
+ }
+
+ local d = require("awful.mouse.snap").default_distance
+
+ for _, c in ipairs(s.clients) do
+ if c.floating then
+ table.insert(snap_areas.horizontal, {c.x-d, c.x})
+ table.insert(snap_areas.horizontal, {c.x+c.width, c.x+c.width+d})
+ table.insert(snap_areas.vertical , {c.y-d, c.y})
+ table.insert(snap_areas.vertical , {c.y+c.height, c.y+c.height+d})
+ end
+ end
+
+ while deduplicate_gaps(snap_areas.horizontal) do end
+ while deduplicate_gaps(snap_areas.vertical ) do end
+
+ --FIXME
+ --[[for _, hgap in ipairs(snap_areas.horizontal) do
+ draw_hruler(
+ s,
+ 0,
+ get_text_height(),
+ {x=tr_x+s.workarea.x+hgap[1],width=hgap[2]-hgap[1],label="gaps"},
+ 1
+ )
+ end
+
+ for _, vgap in ipairs(snap_areas.vertical) do
+ draw_vruler(
+ s,
+ get_text_height()*1.5,
+ 0,
+ {y=tr_y+vgap[1],height=vgap[2]-vgap[1],label="gaps"},
+ 1
+ )
+ end]]--
+
+ cr:translate(tr_x, tr_y)
+end
+
+-- local function draw_screen_snap(s)
+-- local d = require("awful.mouse.snap").aerosnap_distance
+--
+--
+-- local proxy = {
+-- x = c.x - sd,
+-- y = c.y - sd,
+-- width = c.width + 2*sd,
+-- height = c.height + 2*sd,
+-- }
+--
+-- draw_client(s, proxy, 'gaps', (k-1)*10, nil, "11")
+-- end
+
local function draw_info(s)
cr:set_source_rgb(0, 0, 0)
- local pctx = PangoCairo.font_map_get_default():create_context()
- local playout = Pango.Layout.new(pctx)
- local pdesc = Pango.FontDescription()
+ local pctx = PangoCairo.font_map_get_default():create_context()
+ local playout2 = Pango.Layout.new(pctx)
+ local pdesc = Pango.FontDescription()
pdesc:set_absolute_size(11 * Pango.SCALE)
- playout:set_font_description(pdesc)
+ playout2:set_font_description(pdesc)
local rows = {
"primary", "index", "geometry", "dpi", "dpi range", "outputs"
@@ -298,13 +634,13 @@ local function draw_info(s)
-- Get the extents of the longest label.
for k, label in ipairs(rows) do
local attr, parsed = Pango.parse_markup(label..":", -1, 0)
- playout.attributes, playout.text = attr, parsed
- local _, logical = playout:get_pixel_extents()
+ playout2.attributes, playout2.text = attr, parsed
+ local _, logical = playout2:get_pixel_extents()
col1_width = math.max(col1_width, logical.width+10)
attr, parsed = Pango.parse_markup(values[k], -1, 0)
- playout.attributes, playout.text = attr, parsed
- _, logical = playout:get_pixel_extents()
+ playout2.attributes, playout2.text = attr, parsed
+ _, logical = playout2:get_pixel_extents()
col2_width = math.max(col2_width, logical.width+10)
height = math.max(height, logical.height)
@@ -316,15 +652,15 @@ local function draw_info(s)
-- Draw everything.
for k, label in ipairs(rows) do
local attr, parsed = Pango.parse_markup(label..":", -1, 0)
- playout.attributes, playout.text = attr, parsed
+ playout2.attributes, playout2.text = attr, parsed
cr:move_to(dx2, dy)
- cr:show_layout(playout)
+ cr:show_layout(playout2)
attr, parsed = Pango.parse_markup(values[k], -1, 0)
- playout.attributes, playout.text = attr, parsed
- local _, logical = playout:get_pixel_extents()
+ playout2.attributes, playout2.text = attr, parsed
+ local _, logical = playout2:get_pixel_extents()
cr:move_to( dx2+col1_width+5, dy)
- cr:show_layout(playout)
+ cr:show_layout(playout2)
dy = dy + 5 + logical.height
end
@@ -344,11 +680,21 @@ for _=1, screen.count() do
compute_ruler(s, s.geometry, "geometry")
end
+-- If there is some rulers on the left/top, add a global translation.
+evaluate_translation(
+ args.draw_gaps,
+ args.draw_struts,
+ args.draw_mwfact,
+ args.draw_client_snap
+)
+
-- Get the final size of the image.
local sew, seh = screen._get_extents()
sew, seh = sew/args.factor + (screen.count()-1)*10+2, seh/args.factor+2
-sew,seh=sew+100,seh+100
+sew, seh = sew + tr_x, seh + 0.66*tr_y
+
+sew, seh = sew + 5*get_text_height(), seh + 5*get_text_height()
img = cairo.SvgSurface.create(image_path..".svg", sew, seh)
cr = cairo.Context(img)
@@ -356,10 +702,14 @@ cr = cairo.Context(img)
cr:set_line_width(1.5)
cr:set_dash({10,4},1)
+-- Instead of adding origin offset everywhere, translate the viewport.
+translate()
+
-- Draw the various areas.
for k=1, screen.count() do
local s = screen[1]
+
-- The outer geometry.
draw_area(s, s.geometry, "geometry", (k-1)*10, args.highlight_geometry)
@@ -381,17 +731,68 @@ for k=1, screen.count() do
draw_struct(s, args.draw_wibar, 'wibar', (k-1)*10, 'Wibar')
end
+ local skip_gaps = s.selected_tag
+ and s.selected_tag.gap_single_client == false
+ and #s.tiled_clients == 1
+
+ local sd = require("awful.mouse.snap").default_distance
+
-- Draw clients.
if args.draw_clients then
for label,c in pairs(args.draw_clients) do
- draw_struct(s, c, 'tiling_client', (k-1)*10, label)
+ local gap = c:tags()[1].gap
+ if args.draw_gaps and gap > 0 and (not c.floating) and not skip_gaps then
+ local proxy = {
+ x = c.x - gap,
+ y = c.y - gap,
+ width = c.width + 2*gap,
+ height = c.height + 2*gap,
+ }
+
+ draw_client(s, proxy, 'gaps', (k-1)*10, nil, "11")
+ elseif args.draw_client_snap and c.floating then
+ local proxy = {
+ x = c.x - sd,
+ y = c.y - sd,
+ width = c.width + 2*sd,
+ height = c.height + 2*sd,
+ }
+
+ draw_client(s, proxy, 'gaps', (k-1)*10, nil, "11")
+ end
+
+ draw_client(s, c, 'tiling_client', (k-1)*10, label)
end
end
+ if args.draw_struts and has_struts(s) then
+ draw_struts(s)
+ end
+
-- Draw the informations.
if args.display_screen_info ~= false then
draw_info(s)
end
+
+ -- Draw the useless gaps.
+ if args.draw_gaps and not skip_gaps then
+ draw_gaps(s)
+ end
+
+ -- Draw the useless gaps.
+ if args.draw_mwfact then
+ draw_mwfact(s)
+ end
+
+ -- Draw the snapping areas of floating clients.
+ if args.draw_client_snap then
+ draw_client_snap(s)
+ end
+
+ -- Draw the screen edge areas.
+ --if args.draw_screen_snap then
+ -- draw_screen_snap(s)
+ --end
end
img:finish()