Skip to content

Commit 4ca2424

Browse files
committed
Add integration tests for _NET_WM_MOVERESIZE behaviour
1 parent 2b7fabb commit 4ca2424

File tree

2 files changed

+296
-3
lines changed

2 files changed

+296
-3
lines changed

tests/_client.lua

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,21 @@ local function open_window(class, title, options)
2424
default_height = options.default_height or 100,
2525
title = title
2626
}
27+
if options.resize_increment or options.custom_titlebar then
28+
-- These require Gtk3, but may fail with an obscure message with Gtk2.
29+
-- Produce a better error message instead.
30+
assert(tonumber(require("lgi").Gtk._version) >= 3, "Gtk 3 required, but not found")
31+
end
2732
if options.gravity then
2833
window:set_gravity(tonumber(options.gravity))
2934
end
3035
if options.snid and options.snid ~= "" then
3136
window:set_startup_id(options.snid)
3237
end
38+
if options.custom_titlebar then
39+
window:set_titlebar(Gtk.Label { label = title })
40+
end
3341
if options.resize_increment then
34-
-- This requires Gtk3, but fails with an obscure message with Gtk2.
35-
-- Produce a better error message instead.
36-
assert(tonumber(require("lgi").Gtk._version) >= 3, "Gtk 3 required, but not found")
3742
local geom = Gdk.Geometry {
3843
width_inc = 200,
3944
height_inc = 200,
@@ -194,6 +199,9 @@ local function new(_, class, title, sn_rules, callback, resize_increment, args)
194199
if args.minimize_after then
195200
options = options .. "minimize_after,"
196201
end
202+
if args.custom_titlebar then
203+
options = options .. "custom_titlebar,"
204+
end
197205

198206
if args.size then
199207
options = table.concat {

tests/test-ewmh-wm_moveresize.lua

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
local test_client = require("_client")
2+
local placement = require("awful.placement")
3+
local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
4+
5+
-- Testing utils
6+
local signals_of_interest = {
7+
"request::mouse_move",
8+
"request::mouse_resize",
9+
"request::mouse_cancel"
10+
}
11+
local signal_buffer = {}
12+
13+
local function assert_signal(sig_name, asserts)
14+
local sig_data = signal_buffer[sig_name]
15+
assert(sig_data ~= nil, "expected signal: " .. sig_name)
16+
if asserts then
17+
asserts(unpack(sig_data))
18+
end
19+
signal_buffer = {}
20+
end
21+
22+
local function assert_geometry(c, x, y, width, height)
23+
local geo = c:geometry()
24+
assert(geo.x == x, "expected x coord " .. x ..
25+
", but it was " .. geo.x)
26+
assert(geo.y == y, "expected y coord " .. y ..
27+
", but it was " .. geo.y)
28+
assert(geo.width == width, "expected width " .. width ..
29+
", but it was " .. geo.width)
30+
assert(geo.height == height, "expected height " .. height ..
31+
", but it was " .. geo.height)
32+
end
33+
34+
local function drag(x, y)
35+
mouse.coords {x = x, y = y}
36+
end
37+
38+
local function click(x, y)
39+
drag(x, y)
40+
root.fake_input("button_press", 1)
41+
end
42+
43+
local function unclick()
44+
root.fake_input("button_release", 1)
45+
end
46+
47+
local resize_corners = {
48+
{corner = "right", bx = -1, by = 0, dx = 0, dy = 0, dw = 1, dh = 0},
49+
{corner = "bottom_right", bx = -1, by = -1, dx = 0, dy = 0, dw = 1, dh = 1},
50+
{corner = "bottom", bx = 0, by = -1, dx = 0, dy = 0, dw = 0, dh = 1},
51+
{corner = "bottom_left", bx = 1, by = -1, dx = 1, dy = 0, dw = -1, dh = 1},
52+
{corner = "left", bx = 1, by = 0, dx = 1, dy = 0, dw = -1, dh = 0},
53+
{corner = "top_left", bx = 1, by = 1, dx = 1, dy = 1, dw = -1, dh = -1},
54+
{corner = "top", bx = 0, by = 1, dx = 0, dy = 1, dw = 0, dh = -1},
55+
{corner = "top_right", bx = -1, by = 1, dx = 0, dy = 1, dw = 1, dh = -1},
56+
}
57+
local steps = {}
58+
59+
-- Mouse movement tests
60+
61+
table.insert(steps, function(count)
62+
if count == 1 then -- Setup.
63+
test_client("foobar", "foobar", nil, nil, nil, {
64+
custom_titlebar = true
65+
})
66+
elseif #client.get() > 0 then
67+
local c = client.get()[1]
68+
69+
c : geometry {
70+
x = 200,
71+
y = 200,
72+
width = 400,
73+
height = 400,
74+
}
75+
76+
-- Attach signal handlers so that we can see which signals have been fired
77+
for _,sig_name in ipairs(signals_of_interest) do
78+
c:connect_signal(sig_name, function(_, ...)
79+
signal_buffer[sig_name] = {...}
80+
local _, args = ...
81+
if args and args.mouse_pos then
82+
print("got signal " .. sig_name ..
83+
" at (" .. args.mouse_pos.x .. ", " .. args.mouse_pos.y .. ")")
84+
else
85+
print("got signal " .. sig_name)
86+
end
87+
end)
88+
end
89+
90+
return true
91+
end
92+
end)
93+
94+
table.insert(steps, function()
95+
local c = client.get()[1]
96+
97+
-- GTK window may take some time to finish setting up
98+
-- Just repeat until the drag works
99+
if signal_buffer["request::mouse_move"] then return true end
100+
101+
-- Just in case there is an accidental delayed geometry callback
102+
assert_geometry(c, 200, 200, 400, 400)
103+
104+
-- Click the title bar and drag to start a mouse movement transaction
105+
-- This doesn't necessarily move the window yet!
106+
unclick()
107+
click(400, 220)
108+
drag(420, 220)
109+
end)
110+
111+
table.insert(steps, function()
112+
assert_signal("request::mouse_move", function(context, args)
113+
assert(context == "ewmh")
114+
assert(args.button == 1)
115+
assert(args.mouse_pos.x == 400)
116+
assert(args.mouse_pos.y == 220)
117+
end)
118+
119+
-- Actually move the window
120+
drag(500, 120)
121+
122+
return true
123+
end)
124+
125+
table.insert(steps, function()
126+
local c = client.get()[1]
127+
128+
assert_geometry(c, 300, 100, 400, 400)
129+
130+
-- Release the mouse to end the movement
131+
unclick()
132+
133+
return true
134+
end)
135+
136+
table.insert(steps, function()
137+
local c = client.get()[1]
138+
139+
if mousegrabber.isrunning() then return end
140+
141+
assert_geometry(c, 300, 100, 400, 400)
142+
143+
-- Window should no longer follow mouse
144+
drag(300, 200)
145+
146+
return true
147+
end)
148+
149+
table.insert(steps, function()
150+
local c = client.get()[1]
151+
152+
assert_geometry(c, 300, 100, 400, 400)
153+
154+
-- Start another mouse movement transaction
155+
click(500, 120)
156+
drag(520, 120)
157+
158+
return true
159+
end)
160+
161+
table.insert(steps, function()
162+
local c = client.get()[1]
163+
164+
if not signal_buffer["request::mouse_move"] then return end
165+
166+
assert_geometry(c, 300, 100, 400, 400)
167+
168+
-- Move the window somewhere else
169+
drag(600, 170)
170+
171+
return true
172+
end)
173+
174+
table.insert(steps, function()
175+
local c = client.get()[1]
176+
177+
assert_geometry(c, 400, 150, 400, 400)
178+
179+
-- Cancel the mouse movement with a signal
180+
c:emit_signal("request::mouse_cancel", "test")
181+
182+
return true
183+
end)
184+
185+
table.insert(steps, function()
186+
local c = client.get()[1]
187+
188+
assert_signal("request::mouse_cancel")
189+
assert_geometry(c, 400, 150, 400, 400)
190+
191+
-- Window should no longer follow mouse
192+
drag(300, 200)
193+
194+
return true
195+
end)
196+
197+
table.insert(steps, function()
198+
local c = client.get()[1]
199+
200+
assert_geometry(c, 400, 150, 400, 400)
201+
202+
unclick()
203+
204+
return true
205+
end)
206+
207+
-- Mouse resizing tests
208+
209+
local exp_x = 400
210+
local exp_y = 150
211+
local exp_w = 400
212+
local exp_h = 400
213+
214+
local function assert_expected_geometry(c)
215+
assert_geometry(c, exp_x, exp_y, exp_w, exp_h)
216+
end
217+
218+
local drag_amount = 50
219+
local exp_mouse_x
220+
local exp_mouse_y
221+
222+
for _,rc in ipairs(resize_corners) do
223+
table.insert(steps, function()
224+
local c = client.get()[1]
225+
226+
assert_expected_geometry(c)
227+
228+
local corner_pos = placement[rc.corner](mouse, {parent = c, pretend = true})
229+
exp_mouse_x = corner_pos.x + rc.bx * 3
230+
exp_mouse_y = corner_pos.y + rc.by * 3
231+
232+
-- Click the edge of the window to start a mouse resizing transaction
233+
click(exp_mouse_x, exp_mouse_y)
234+
235+
return true
236+
end)
237+
238+
table.insert(steps, function()
239+
if not signal_buffer["request::mouse_resize"] then return end
240+
241+
assert_signal("request::mouse_resize", function(context, args)
242+
assert(context == "ewmh")
243+
assert(args.button == 1)
244+
assert(args.mouse_pos.x == exp_mouse_x)
245+
assert(args.mouse_pos.y == exp_mouse_y)
246+
end)
247+
248+
-- Resize the window
249+
drag(exp_mouse_x + drag_amount, exp_mouse_y + drag_amount)
250+
exp_x = exp_x + rc.dx * drag_amount
251+
exp_y = exp_y + rc.dy * drag_amount
252+
exp_w = exp_w + rc.dw * drag_amount
253+
exp_h = exp_h + rc.dh * drag_amount
254+
255+
return true
256+
end)
257+
258+
table.insert(steps, function()
259+
local c = client.get()[1]
260+
261+
assert_expected_geometry(c)
262+
263+
-- Release the mouse to end the resizing
264+
unclick()
265+
266+
return true
267+
end)
268+
269+
table.insert(steps, function()
270+
local c = client.get()[1]
271+
272+
if mousegrabber.isrunning() then return end
273+
274+
assert_expected_geometry(c)
275+
276+
-- Window should no longer follow mouse
277+
drag(exp_mouse_x + 30, exp_mouse_y - 20)
278+
279+
return true
280+
end)
281+
end
282+
283+
require("_runner").run_steps(steps)
284+
285+
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

0 commit comments

Comments
 (0)