--------------------------------------------------------------------------- -- @author Uli Schlachter -- @copyright 2015 Uli Schlachter --------------------------------------------------------------------------- local hierarchy = require("wibox.hierarchy") local Region = require("lgi").cairo.Region local matrix = require("gears.matrix") local utils = require("wibox.test_utils") local function make_widget(children) local result = utils.widget_stub() result.layout = function() return children end return result end local function make_child(widget, width, height, mat) return { _widget = widget, _width = width, _height = height, _matrix = mat } end describe("wibox.hierarchy", function() describe("Accessor functions", function() local widget, instance before_each(function() local function nop() end local context = {} widget = make_widget(nil) instance = hierarchy.new(context, widget, 10, 20, nop, nop) end) it("get_widget", function() assert.is.equal(instance:get_widget(), widget) end) it("get_matrix_to_parent", function() assert.is.equal(matrix.identity, instance:get_matrix_to_parent()) end) it("get_matrix_to_device", function() assert.is.equal(matrix.identity, instance:get_matrix_to_device()) end) it("get_matrix_from_parent", function() assert.is.equal(matrix.identity, instance:get_matrix_from_parent()) end) it("get_matrix_from_device", function() assert.is.equal(matrix.identity, instance:get_matrix_from_device()) end) it("get_draw_extents", function() assert.is.same({ instance:get_draw_extents() }, { 0, 0, 10, 20 }) end) it("get_size", function() assert.is.same({ instance:get_size() }, { 10, 20 }) end) it("get_children", function() assert.is.same(instance:get_children(), {}) end) end) it("disconnect works", function() local child = make_widget(nil) local parent = make_widget({ make_child(child, 2, 5, matrix.create_translate(10, 0)) }) local extra_arg = {} local child_redraws, child_layouts = 0, 0 local parent_redraws, parent_layouts = 0, 0 local function redraw(arg, extra) assert.is.equal(extra_arg, extra) if arg:get_widget() == child then child_redraws = child_redraws + 1 elseif arg:get_widget() == parent then parent_redraws = parent_redraws + 1 else error("Unknown widget") end end local function layout(arg, extra) assert.is.equal(extra_arg, extra) if arg:get_widget() == child then child_layouts = child_layouts + 1 elseif arg:get_widget() == parent then parent_layouts = parent_layouts + 1 else error("Unknown widget") end end local context = {} local instance = hierarchy.new(context, parent, 15, 20, redraw, layout, extra_arg) -- luacheck: no unused -- There should be a connection parent:emit_signal("widget::redraw_needed") assert.is.same({ 0, 0, 1, 0 }, { child_redraws, child_layouts, parent_redraws, parent_layouts }) child:emit_signal("widget::redraw_needed") assert.is.same({ 1, 0, 1, 0 }, { child_redraws, child_layouts, parent_redraws, parent_layouts }) child:emit_signal("widget::layout_changed") assert.is.same({ 1, 1, 1, 0 }, { child_redraws, child_layouts, parent_redraws, parent_layouts }) parent:emit_signal("widget::layout_changed") assert.is.same({ 1, 1, 1, 1 }, { child_redraws, child_layouts, parent_redraws, parent_layouts }) -- Garbage-collect the hierarchy instance = nil collectgarbage("collect") -- No connections should be left parent:emit_signal("widget::redraw_needed") child:emit_signal("widget::redraw_needed") child:emit_signal("widget::layout_changed") parent:emit_signal("widget::layout_changed") assert.is.same({ 1, 1, 1, 1 }, { child_redraws, child_layouts, parent_redraws, parent_layouts }) end) describe("children", function() local child, intermediate, parent local hierarchy_child, hierarchy_intermediate, hierarchy_parent before_each(function() child = make_widget(nil) intermediate = make_widget({ make_child(child, 10, 20, matrix.create_translate(0, 5):scale(2, 2)) }) parent = make_widget({ make_child(intermediate, 5, 2, matrix.create_translate(4, 0)) }) local function nop() end local context = {} hierarchy_parent = hierarchy.new(context, parent, 15, 16, nop, nop) -- This also tests get_children local children = hierarchy_parent:get_children() assert.is.equal(#children, 1) hierarchy_intermediate = children[1] children = hierarchy_intermediate:get_children() assert.is.equal(#children, 1) hierarchy_child = children[1] end) it("get_widget", function() assert.is.equal(hierarchy_child:get_widget(), child) assert.is.equal(hierarchy_intermediate:get_widget(), intermediate) assert.is.equal(hierarchy_parent:get_widget(), parent) end) it("get_matrix_to_parent", function() assert.is.equal(hierarchy_child:get_matrix_to_parent(), matrix.create(2, 0, 0, 2, 0, 5)) assert.is.equal(hierarchy_intermediate:get_matrix_to_parent(), matrix.create_translate(4, 0)) assert.is.equal(hierarchy_parent:get_matrix_to_parent(), matrix.identity) end) it("get_matrix_to_device", function() assert.is.equal(hierarchy_child:get_matrix_to_device(), matrix.create(2, 0, 0, 2, 4, 5)) assert.is.equal(hierarchy_intermediate:get_matrix_to_device(), matrix.create_translate(4, 0)) assert.is.equal(hierarchy_parent:get_matrix_to_device(), matrix.identity) end) it("get_matrix_from_parent", function() assert.is.equal(hierarchy_child:get_matrix_from_parent(), matrix.create(0.5, 0, 0, 0.5, 0, -2.5)) assert.is.equal(hierarchy_intermediate:get_matrix_from_parent(), matrix.create_translate(-4, 0)) assert.is.equal(hierarchy_parent:get_matrix_from_parent(), matrix.identity) end) it("get_matrix_from_device", function() assert.is.equal(hierarchy_child:get_matrix_from_device(), matrix.create(0.5, 0, 0, 0.5, -2, -2.5)) assert.is.equal(hierarchy_intermediate:get_matrix_from_device(), matrix.create_translate(-4, 0)) assert.is.equal(hierarchy_parent:get_matrix_from_device(), matrix.identity) end) it("get_draw_extents", function() assert.is.same({ hierarchy_child:get_draw_extents() }, { 0, 0, 10, 20 }) assert.is.same({ hierarchy_intermediate:get_draw_extents() }, { 0, 0, 20, 45 }) assert.is.same({ hierarchy_parent:get_draw_extents() }, { 0, 0, 24, 45 }) end) it("get_size", function() assert.is.same({ hierarchy_child:get_size() }, { 10, 20 }) assert.is.same({ hierarchy_intermediate:get_size() }, { 5, 2 }) assert.is.same({ hierarchy_parent:get_size() }, { 15, 16 }) end) end) describe("update", function() local child, intermediate, parent local instance local function nop() end before_each(function() child = make_widget(nil) intermediate = make_widget({ make_child(child, 10, 20, matrix.create_translate(0, 5)) }) parent = make_widget({ make_child(intermediate, 5, 2, matrix.create_translate(4, 0)) }) local context = {} instance = hierarchy.new(context, parent, 15, 16, nop, nop) end) it("No difference 1", function() local region = instance:update(context, parent, 15, 16) assert.is.equal(region:num_rectangles(), 0) end) it("No difference 2", function() local region1 = Region.create() local region2 = instance:update(context, parent, 15, 16, region1) assert.is.equal(region1, region2) assert.is.equal(region2:num_rectangles(), 0) end) it("child moved", function() -- Clear caches and change result of intermediate intermediate.layout = function() return { make_child(child, 10, 20, matrix.create_translate(0, 4)) } end intermediate:emit_signal("widget::layout_changed") local region = instance:update(context, parent, 15, 16) assert.is.equal(region:num_rectangles(), 1) local rect = region:get_rectangle(0) -- The widget drew to 4, 5, 10, 20 before and 4, 4, 10, 20 after assert.is.same({ rect.x, rect.y, rect.width, rect.height }, { 4, 4, 10, 21 }) end) it("child disappears", function() -- Clear caches and change result of intermediate intermediate.layout = function() end intermediate:emit_signal("widget::layout_changed") local region = instance:update(context, parent, 15, 16) assert.is.equal(region:num_rectangles(), 1) local rect = region:get_rectangle(0) -- The child was drawn to 4, 5, 10, 20 assert.is.same({ rect.x, rect.y, rect.width, rect.height }, { 4, 5, 10, 20 }) end) it("widget changed", function() -- Clear caches and change result of parent local new_intermediate = make_widget({ make_child(child, 10, 20, matrix.create_translate(0, 5)) }) parent.layout = function() return { make_child(new_intermediate, 5, 2, matrix.create_translate(4, 0)) } end parent:emit_signal("widget::layout_changed") local region = instance:update(context, parent, 15, 16) assert.is.equal(region:num_rectangles(), 1) local rect = region:get_rectangle(0) -- Intermediate drew to 4, 0, 5, 2 (and so does new_intermediate) assert.is.same({ rect.x, rect.y, rect.width, rect.height }, { 4, 0, 5, 2 }) end) end) describe("widget counts", function() local child, intermediate, parent local unrelated local context, instance before_each(function() local function nop() end context = {} child = make_widget(nil) intermediate = make_widget({ make_child(child, 10, 20, matrix.identity) }) parent = make_widget({ make_child(intermediate, 10, 20, matrix.identity), make_child(child, 0, 20, matrix.identity) }) unrelated = make_widget(nil) hierarchy.count_widget(child) hierarchy.count_widget(parent) hierarchy.count_widget(unrelated) instance = hierarchy.new(context, parent, 10, 20, nop, nop) end) it("basic counts", function() local unrelated_other = make_widget(nil) assert.is.equal(1, instance:get_count(child)) -- intermediate was not passed to hierarchy.count_widget()! assert.is.equal(0, instance:get_count(intermediate)) assert.is.equal(1, instance:get_count(parent)) assert.is.equal(0, instance:get_count(unrelated)) assert.is.equal(0, instance:get_count(unrelated_other)) end) it("after update", function() -- Replace child and intermediate by just a new_child local new_child = make_widget(nil) parent.layout = function() return { make_child(new_child, 10, 20, matrix.identity) } end parent:emit_signal("widget::layout_changed") instance:update(context, parent, 10, 20) assert.is.equal(0, instance:get_count(child)) -- new_child was not passed to hierarchy.count_widget()! assert.is.equal(0, instance:get_count(new_child)) assert.is.equal(1, instance:get_count(parent)) assert.is.equal(0, instance:get_count(unrelated)) end) it("collectible", function() -- This test that hierarchy.count_widget() does not prevent garbage collection of the widget. local weak = setmetatable({}, { __mode = "v"}) weak[1], weak[2], weak[3], weak[4] = child, intermediate, parent, instance child, intermediate, parent, instance = nil, nil, nil, nil assert.is.equal(4, #weak) collectgarbage("collect") assert.is.equal(0, #weak) end) end) end) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80