~ubuntu-branches/ubuntu/karmic/parti-all/karmic

« back to all changes in this revision

Viewing changes to wimpiggy/test_lowlevel.py

  • Committer: Bazaar Package Importer
  • Author(s): Evan Dandrea
  • Date: 2009-06-02 12:44:00 UTC
  • Revision ID: james.westby@ubuntu.com-20090602124400-xbkgh9vxjciey732
Tags: upstream-0.0.6
ImportĀ upstreamĀ versionĀ 0.0.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# This file is part of Parti.
 
2
# Copyright (C) 2008, 2009 Nathaniel Smith <njs@pobox.com>
 
3
# Parti is released under the terms of the GNU GPL v2, or, at your option, any
 
4
# later version. See the file COPYING for details.
 
5
 
 
6
from wimpiggy.test import *
 
7
import wimpiggy.lowlevel as l
 
8
import gtk
 
9
from wimpiggy.error import *
 
10
 
 
11
class TestLowlevel(TestWithSession):
 
12
    def root(self, disp=None):
 
13
        if disp is None:
 
14
            disp = self.display
 
15
        return disp.get_default_screen().get_root_window()
 
16
 
 
17
    def window(self, disp=None):
 
18
        if disp is None:
 
19
            disp = self.display
 
20
        win = gtk.gdk.Window(self.root(disp), width=10, height=10,
 
21
                             # WINDOW_CHILD is sort of bogus, but it reduces
 
22
                             # the amount of magic that GDK will do (e.g.,
 
23
                             # WINDOW_TOPLEVELs automatically get a child
 
24
                             # window to be used in focus management).
 
25
                             window_type=gtk.gdk.WINDOW_CHILD,
 
26
                             wclass=gtk.gdk.INPUT_OUTPUT,
 
27
                             event_mask=0)
 
28
        return win
 
29
 
 
30
class TestLowlevelMisc(TestLowlevel):
 
31
    def test_get_xwindow_pywindow(self):
 
32
        d2 = self.clone_display()
 
33
        r1 = self.root()
 
34
        r2 = self.root(d2)
 
35
        assert r1 is not r2
 
36
        assert l.get_xwindow(r1) == l.get_xwindow(r2)
 
37
        win = self.window()
 
38
        assert l.get_xwindow(r1) != l.get_xwindow(win)
 
39
        assert l.get_pywindow(r2, l.get_xwindow(r1)) is r2
 
40
 
 
41
        assert_raises(l.XError, l.get_pywindow, self.display, 0)
 
42
 
 
43
        # This is necessary to stop some mysterious failure (perhaps d2 being
 
44
        # garbage collected before r2):
 
45
        del r2
 
46
 
 
47
    def test_get_display_for(self):
 
48
        assert l.get_display_for(self.display) is self.display
 
49
        win = self.window()
 
50
        assert l.get_display_for(win) is self.display
 
51
        assert_raises(TypeError, l.get_display_for, None)
 
52
        widg = gtk.Window()
 
53
        assert l.get_display_for(widg) is self.display
 
54
        clipboard = gtk.Clipboard(self.display, "PRIMARY")
 
55
        assert l.get_display_for(clipboard) is self.display
 
56
 
 
57
    def test_get_xatom_pyatom(self):
 
58
        d2 = self.clone_display()
 
59
        asdf1 = l.get_xatom(self.display, "ASDF")
 
60
        asdf2 = l.get_xatom(d2, "ASDF")
 
61
        ghjk1 = l.get_xatom(self.display, "GHJK")
 
62
        ghjk2 = l.get_xatom(d2, "GHJK")
 
63
        assert asdf1 == asdf2
 
64
        assert ghjk1 == ghjk2
 
65
        assert l.get_pyatom(self.display, asdf2) == "ASDF"
 
66
        assert l.get_pyatom(d2, ghjk1) == "GHJK"
 
67
        
 
68
    def test_property(self):
 
69
        r = self.root()
 
70
        data = "\x01\x02\x03\x04\x05\x06\x07\x08"
 
71
        assert_raises(l.NoSuchProperty,
 
72
                      l.XGetWindowProperty, r, "ASDF", "ASDF")
 
73
        l.XChangeProperty(r, "ASDF", ("GHJK", 32, data))
 
74
        assert_raises(l.BadPropertyType,
 
75
                      l.XGetWindowProperty, r, "ASDF", "ASDF")
 
76
 
 
77
        for n in (8, 16, 32):
 
78
            print n
 
79
            l.XChangeProperty(r, "ASDF", ("GHJK", n, data))
 
80
            assert l.XGetWindowProperty(r, "ASDF", "GHJK") == data
 
81
        
 
82
        l.XDeleteProperty(r, "ASDF")
 
83
        assert_raises(l.NoSuchProperty,
 
84
                      l.XGetWindowProperty, r, "ASDF", "GHJK")
 
85
 
 
86
        badwin = self.window()
 
87
        badwin.destroy()
 
88
        assert_raises((l.PropertyError, XError),
 
89
                      trap.call, l.XGetWindowProperty, badwin, "ASDF", "ASDF")
 
90
 
 
91
        # Giant massive property
 
92
        l.XChangeProperty(r, "ASDF",
 
93
                          ("GHJK", 32, "\x00" * 512 * (2 ** 10)))
 
94
        assert_raises(l.PropertyOverflow,
 
95
                      l.XGetWindowProperty, r, "ASDF", "GHJK")
 
96
 
 
97
    def test_BadProperty_on_empty(self):
 
98
        win = self.window()
 
99
        l.XChangeProperty(win, "ASDF", ("GHJK", 32, ""))
 
100
        assert l.XGetWindowProperty(win, "ASDF", "GHJK") == ""
 
101
        assert_raises(l.BadPropertyType,
 
102
                      l.XGetWindowProperty, win, "ASDF", "ASDF")
 
103
 
 
104
    def test_get_children_and_get_parent_and_reparent(self):
 
105
        d2 = self.clone_display()
 
106
        w1 = self.window(self.display)
 
107
        w2 = self.window(d2)
 
108
        gtk.gdk.flush()
 
109
 
 
110
        assert not l.get_children(w1)
 
111
        children = l.get_children(self.root())
 
112
        xchildren = map(l.get_xwindow, children)
 
113
        xwins = map(l.get_xwindow, [w1, w2])
 
114
        # GDK creates an invisible child of the root window on each
 
115
        # connection, so there are some windows we don't know about:
 
116
        for known in xwins:
 
117
            assert known in xchildren
 
118
        assert l.get_parent(w1) == w1.get_parent()
 
119
 
 
120
        w1.reparent(l.get_pywindow(w1, l.get_xwindow(w2)), 0, 0)
 
121
        gtk.gdk.flush()
 
122
        assert map(l.get_xwindow, l.get_children(w2)) == [l.get_xwindow(w1)]
 
123
        assert l.get_parent(w1).xid == w2.xid
 
124
 
 
125
    def test_get_parent_of_root(self):
 
126
        assert l.get_parent(self.root()) is None
 
127
 
 
128
    def test_save_set(self):
 
129
        w1 = self.window(self.display)
 
130
        w2 = self.window(self.display)
 
131
        w3 = self.window(self.display)
 
132
        gtk.gdk.flush()
 
133
        
 
134
        import os
 
135
        def do_child(disp_name, xwindow1, xwindow2, xwindow3):
 
136
            print "child: in do_child"
 
137
            d2 = gtk.gdk.Display(disp_name)
 
138
            w1on2 = l.get_pywindow(d2, xwindow1)
 
139
            w2on2 = l.get_pywindow(d2, xwindow2)
 
140
            w3on2 = l.get_pywindow(d2, xwindow3)
 
141
            mywin = self.window(d2)
 
142
            print "child: mywin == %s" % l.get_xwindow(mywin)
 
143
            w1on2.reparent(mywin, 0, 0)
 
144
            w2on2.reparent(mywin, 0, 0)
 
145
            w3on2.reparent(mywin, 0, 0)
 
146
            gtk.gdk.flush()
 
147
            # w1 gets saved:
 
148
            l.XAddToSaveSet(w1on2)
 
149
            # w2 does not
 
150
            # w3 is saved, but then unsaved (to test RemoveFromSaveSet):
 
151
            l.XAddToSaveSet(w3on2)
 
152
            l.XRemoveFromSaveSet(w3on2)
 
153
            gtk.gdk.flush()
 
154
            print "child: finished"
 
155
        print "prefork: ", os.getpid()
 
156
        pid = os.fork()
 
157
        if not pid:
 
158
            # Child
 
159
            try:
 
160
                print "child: pid ", os.getpid()
 
161
                name = self.display.get_name()
 
162
                # This is very important, though I don't know why.  If we
 
163
                # don't close this display then something inside
 
164
                # xcb_wait_for_reply gets Very Confused and the *parent*
 
165
                # process gets a spurious IO error with nonsense errno
 
166
                # (because errno is not actually being set, because there is
 
167
                # no IO error, just something going weird inside xcb).  I'm
 
168
                # not even sure that this actually fixes the underlying
 
169
                # problem, but it makes the test pass, so...
 
170
                self.display.close()
 
171
                do_child(name,
 
172
                         l.get_xwindow(w1),
 
173
                         l.get_xwindow(w2),
 
174
                         l.get_xwindow(w3))
 
175
            finally:
 
176
                os._exit(0)
 
177
        # Parent
 
178
        print "parent: ", os.getpid()
 
179
        print "parent: child is ", pid
 
180
        print "parent: waiting for child"
 
181
        os.waitpid(pid, 0)
 
182
        print "parent: child exited"
 
183
        # Is there a race condition here, where the child exits but the X
 
184
        # server doesn't notice until after we send our commands?
 
185
        print map(l.get_xwindow, [w1, w2, w3])
 
186
        print map(l.get_xwindow, l.get_children(self.root()))
 
187
        assert w1 in l.get_children(self.root())
 
188
        assert w2 not in l.get_children(self.root())
 
189
        assert w3 not in l.get_children(self.root())
 
190
 
 
191
    def test_is_mapped(self):
 
192
        win = self.window()
 
193
        gtk.gdk.flush()
 
194
        assert not l.is_mapped(win)
 
195
        win.show()
 
196
        gtk.gdk.flush()
 
197
        assert l.is_mapped(win)
 
198
 
 
199
    def test_show_unraised_without_extra_stupid_stuff(self):
 
200
        win = self.window()
 
201
        gtk.gdk.flush()
 
202
        assert not l.is_mapped(win)
 
203
        l.show_unraised_without_extra_stupid_stuff(win)
 
204
        gtk.gdk.flush()
 
205
        assert l.is_mapped(win)
 
206
 
 
207
    def test_is_override_redirect(self):
 
208
        win = self.window()
 
209
        gtk.gdk.flush()
 
210
        assert not l.is_override_redirect(win)
 
211
        win.set_override_redirect(True)
 
212
        gtk.gdk.flush()
 
213
        assert l.is_override_redirect(win)
 
214
 
 
215
class _EventRoutingReceiver(MockEventReceiver):
 
216
    def __init__(self, tag, store_in):
 
217
        MockEventReceiver.__init__(self)
 
218
        self.tag = tag
 
219
        self.store_in = store_in
 
220
    def do_wimpiggy_map_event(self, event):
 
221
        print "map_event in %s" % self.tag
 
222
        self.store_in.add(("map", self.tag))
 
223
        gtk.main_quit()
 
224
    def do_wimpiggy_child_map_event(self, event):
 
225
        print "child_map_event in %s" % self.tag
 
226
        self.store_in.add(("child-map", self.tag))
 
227
        gtk.main_quit()
 
228
 
 
229
class TestEventRouting(TestLowlevel):
 
230
    def test_event_routing(self):
 
231
        w1 = self.window()
 
232
        w2 = self.window()
 
233
        w2.reparent(w1, 0, 0)
 
234
        results = set()
 
235
        r1 = _EventRoutingReceiver(1, results)
 
236
        r2 = _EventRoutingReceiver(2, results)
 
237
        r3 = _EventRoutingReceiver(3, results)
 
238
        r4 = _EventRoutingReceiver(4, results)
 
239
        l.add_event_receiver(w1, r1)
 
240
        l.add_event_receiver(w1, r2)
 
241
        l.add_event_receiver(w2, r3)
 
242
        l.add_event_receiver(w2, r4)
 
243
 
 
244
        w1.set_events(gtk.gdk.SUBSTRUCTURE_MASK)
 
245
        w2.set_events(gtk.gdk.STRUCTURE_MASK)
 
246
        w2.show()
 
247
        while len(results) != 4:
 
248
            gtk.main()
 
249
        w2.hide()
 
250
        assert results == set([("child-map", 1), ("child-map", 2),
 
251
                                    ("map", 3), ("map", 4)])
 
252
        l.remove_event_receiver(w1, r2)
 
253
        l.remove_event_receiver(w2, r4)
 
254
        results.clear()
 
255
        w2.show()
 
256
        while len(results) != 2:
 
257
            gtk.main()
 
258
        assert results == set([("child-map", 1), ("map", 3)])
 
259
 
 
260
class TestUnmapWithSerial(TestLowlevel, MockEventReceiver):
 
261
    def do_wimpiggy_map_event(self, event):
 
262
        pass
 
263
 
 
264
    def do_wimpiggy_unmap_event(self, event):
 
265
        print "hi!"
 
266
        self._event = event
 
267
        gtk.main_quit()
 
268
 
 
269
    def test_unmap_with_serial(self):
 
270
        w = self.window()
 
271
        w.show()
 
272
        self._event = None
 
273
        l.add_event_receiver(w, self)
 
274
        serial = l.unmap_with_serial(w)
 
275
        print serial
 
276
        gtk.main()
 
277
        assert self._event is not None
 
278
        assert self._event.serial == serial
 
279
 
 
280
class TestFocusStuff(TestLowlevel, MockEventReceiver):
 
281
    def do_wimpiggy_focus_in_event(self, event):
 
282
        if event.window is self.w1:
 
283
            assert self.w1_got is None
 
284
            self.w1_got = event
 
285
        else:
 
286
            assert self.w2_got is None
 
287
            self.w2_got = event
 
288
        gtk.main_quit()
 
289
    def do_wimpiggy_focus_out_event(self, event):
 
290
        if event.window is self.w1:
 
291
            assert self.w1_lost is None
 
292
            self.w1_lost = event
 
293
        else:
 
294
            assert self.w2_lost is None
 
295
            self.w2_lost = event
 
296
        gtk.main_quit()
 
297
    def test_focus_stuff(self):
 
298
        self.w1 = self.window()
 
299
        self.w1.show()
 
300
        self.w2 = self.window()
 
301
        self.w2.show()
 
302
        gtk.gdk.flush()
 
303
        self.w1_got, self.w2_got = None, None
 
304
        self.w1_lost, self.w2_lost = None, None
 
305
        l.selectFocusChange(self.w1)
 
306
        l.selectFocusChange(self.w2)
 
307
        l.add_event_receiver(self.w1, self)
 
308
        l.add_event_receiver(self.w2, self)
 
309
 
 
310
        gtk.gdk.flush()
 
311
        l.XSetInputFocus(self.w1)
 
312
        gtk.gdk.flush()
 
313
        gtk.main()
 
314
        assert self.w1_got is not None
 
315
        assert self.w1_got.window is self.w1
 
316
        assert self.w1_got.mode == l.const["NotifyNormal"]
 
317
        assert self.w1_got.detail == l.const["NotifyNonlinear"]
 
318
        self.w1_got = None
 
319
        assert self.w2_got is None
 
320
        assert self.w1_lost is None
 
321
        assert self.w2_lost is None
 
322
 
 
323
        l.XSetInputFocus(self.w2)
 
324
        gtk.gdk.flush()
 
325
        gtk.main()
 
326
        gtk.main()
 
327
        assert self.w1_got is None
 
328
        assert self.w2_got is not None
 
329
        assert self.w2_got.window is self.w2
 
330
        assert self.w2_got.mode == l.const["NotifyNormal"]
 
331
        assert self.w2_got.detail == l.const["NotifyNonlinear"]
 
332
        self.w2_got = None
 
333
        assert self.w1_lost is not None
 
334
        assert self.w1_lost.window is self.w1
 
335
        assert self.w1_lost.mode == l.const["NotifyNormal"]
 
336
        assert self.w1_lost.detail == l.const["NotifyNonlinear"]
 
337
        self.w1_lost = None
 
338
        assert self.w2_lost is None
 
339
 
 
340
        l.XSetInputFocus(self.root())
 
341
        gtk.gdk.flush()
 
342
        gtk.main()
 
343
        assert self.w1_got is None
 
344
        assert self.w2_got is None
 
345
        assert self.w1_lost is None
 
346
        assert self.w2_lost is not None
 
347
        assert self.w2_lost.window is self.w2
 
348
        assert self.w2_lost.mode == l.const["NotifyNormal"]
 
349
        assert self.w2_lost.detail == l.const["NotifyAncestor"]
 
350
        self.w2_lost = None
 
351
        
 
352
class TestClientMessageAndXSelectInputStuff(TestLowlevel, MockEventReceiver):
 
353
    def do_wimpiggy_client_message_event(self, event):
 
354
        print "got clientmessage"
 
355
        self.evs.append(event)
 
356
        gtk.main_quit()
 
357
 
 
358
    def test_select_clientmessage_and_xselectinput(self):
 
359
        self.evs = []
 
360
        self.w = self.window()
 
361
        gtk.gdk.flush()
 
362
 
 
363
        l.add_event_receiver(self.w, self)
 
364
        l.add_event_receiver(self.root(), self)
 
365
 
 
366
        data = (0x01020304, 0x05060708, 0x090a0b0c, 0x0d0e0f10, 0x11121314)
 
367
        l.sendClientMessage(self.root(), False, 0, "NOMASK", *data)
 
368
        l.sendClientMessage(self.w, False, 0, "NOMASK", *data)
 
369
        gtk.main()
 
370
        # Should have gotten message to w, not to root
 
371
        assert len(self.evs) == 1
 
372
        ev = self.evs[0]
 
373
        assert ev.window is self.w
 
374
        assert ev.message_type == "NOMASK"
 
375
        assert ev.format == 32
 
376
        assert ev.data == data
 
377
 
 
378
        self.evs = []
 
379
        l.sendClientMessage(self.root(), False, l.const["Button1MotionMask"],
 
380
                            "BAD", *data)
 
381
        l.addXSelectInput(self.root(), l.const["Button1MotionMask"])
 
382
        l.sendClientMessage(self.root(), False, l.const["Button1MotionMask"],
 
383
                            "GOOD", *data)
 
384
        gtk.main()
 
385
        assert len(self.evs) == 1
 
386
        ev = self.evs[0]
 
387
        assert ev.window is self.root()
 
388
        assert ev.message_type == "GOOD"
 
389
        assert ev.format == 32
 
390
        assert ev.data == data
 
391
 
 
392
    def test_send_wm_take_focus(self):
 
393
        self.evs = []
 
394
        win = self.window()
 
395
        l.add_event_receiver(win, self)
 
396
        gtk.gdk.flush()
 
397
 
 
398
        l.send_wm_take_focus(win, 1234)
 
399
        gtk.main()
 
400
        assert len(self.evs) == 1
 
401
        event = self.evs[0]
 
402
        assert event is not None
 
403
        assert event.window is win
 
404
        assert event.message_type == "WM_PROTOCOLS"
 
405
        assert event.format == 32
 
406
        assert event.data == (l.get_xatom(win, "WM_TAKE_FOCUS"),
 
407
                              1234, 0, 0, 0)
 
408
 
 
409
# myGetSelectionOwner gets tested in test_selection.py
 
410
 
 
411
class TestSendConfigureNotify(TestLowlevel):
 
412
    # This test stomps on Wimpiggy's global event handler, so make sure not to
 
413
    # try receiving wimpiggy events in it.
 
414
    def test_sendConfigureNotify(self):
 
415
        # GDK discards ConfigureNotify's sent to child windows, so we can't
 
416
        # use self.window():
 
417
        w1 = gtk.gdk.Window(self.root(), width=10, height=10,
 
418
                            window_type=gtk.gdk.WINDOW_TOPLEVEL,
 
419
                            wclass=gtk.gdk.INPUT_OUTPUT,
 
420
                            event_mask=gtk.gdk.ALL_EVENTS_MASK)
 
421
        self.ev = None
 
422
        def myfilter(ev, data=None):
 
423
            print "ev %s" % (ev.type,)
 
424
            if ev.type == gtk.gdk.CONFIGURE:
 
425
                self.ev = ev
 
426
                gtk.main_quit()
 
427
            gtk.main_do_event(ev)
 
428
        gtk.gdk.event_handler_set(myfilter)
 
429
 
 
430
        w1.show()
 
431
        gtk.gdk.flush()
 
432
        l.sendConfigureNotify(w1)
 
433
        gtk.main()
 
434
        
 
435
        assert self.ev is not None
 
436
        assert self.ev.type == gtk.gdk.CONFIGURE
 
437
        assert self.ev.window == w1
 
438
        assert self.ev.send_event
 
439
        assert self.ev.x == 0
 
440
        assert self.ev.y == 0
 
441
        assert self.ev.width == 10
 
442
        assert self.ev.height == 10
 
443
        
 
444
        # We have to create w2 on a separate connection, because if we just
 
445
        # did w1.reparent(w2, ...), then GDK would magically convert w1 from a
 
446
        # TOPLEVEL window into a CHILD window.
 
447
        # Have to hold onto a reference to d2, so it doesn't get garbage
 
448
        # collected and kill the connection:
 
449
        d2 = self.clone_display()
 
450
        w2 = self.window(d2)
 
451
        gtk.gdk.flush()
 
452
        w2on1 = l.get_pywindow(w1, l.get_xwindow(w2))
 
453
        # Doesn't generate an event, because event mask is zeroed out.
 
454
        w2.move(11, 12)
 
455
        # Reparenting doesn't trigger a ConfigureNotify.
 
456
        w1.reparent(w2on1, 13, 14)
 
457
        # To double-check that it's still a TOPLEVEL:
 
458
        print w1.get_window_type()
 
459
        w1.resize(15, 16)
 
460
        gtk.main()
 
461
 
 
462
        # w1 in root coordinates is now at (24, 26)
 
463
        self.ev = None
 
464
        l.sendConfigureNotify(w1)
 
465
        gtk.main()
 
466
 
 
467
        assert self.ev is not None
 
468
        assert self.ev.type == gtk.gdk.CONFIGURE
 
469
        assert self.ev.window == w1
 
470
        assert self.ev.send_event
 
471
        assert self.ev.x == 24
 
472
        assert self.ev.y == 26
 
473
        assert self.ev.width == 15
 
474
        assert self.ev.height == 16
 
475
 
 
476
class TestSubstructureRedirect(TestLowlevel, MockEventReceiver):
 
477
    def do_child_map_request_event(self, event):
 
478
        print "do_child_map_request_event"
 
479
        self.map_ev = event
 
480
        gtk.main_quit()
 
481
    def do_child_configure_request_event(self, event):
 
482
        print "do_child_configure_request_event"
 
483
        self.conf_ev = event
 
484
        gtk.main_quit()
 
485
 
 
486
    def test_substructure_redirect(self):
 
487
        self.map_ev = None
 
488
        self.conf_ev = None
 
489
        root = self.root()
 
490
        d2 = self.clone_display()
 
491
        w2 = self.window(d2)
 
492
        gtk.gdk.flush()
 
493
        w1 = l.get_pywindow(self.display, l.get_xwindow(w2))
 
494
 
 
495
        l.add_event_receiver(root, self)
 
496
        l.substructureRedirect(root)
 
497
        gtk.gdk.flush()
 
498
 
 
499
        # gdk_window_show does both a map and a configure (to raise the
 
500
        # window)
 
501
        print "showing w2"
 
502
        w2.show()
 
503
        # Can't just call gtk.main() twice, the two events may be delivered
 
504
        # together and processed in a single mainloop iteration.
 
505
        while None in (self.map_ev, self.conf_ev):
 
506
            gtk.main()
 
507
        assert self.map_ev.delivered_to is root
 
508
        assert self.map_ev.window is w1
 
509
 
 
510
        assert self.conf_ev.delivered_to is root
 
511
        assert self.conf_ev.window is w1
 
512
        for field in ("x", "y", "width", "height",
 
513
                      "border_width", "above", "detail", "value_mask"):
 
514
            print field
 
515
            assert hasattr(self.conf_ev, field)
 
516
 
 
517
        self.map_ev = None
 
518
        self.conf_ev = None
 
519
 
 
520
        w2.move_resize(1, 2, 3, 4)
 
521
        gtk.main()
 
522
        assert self.map_ev is None
 
523
        assert self.conf_ev is not None
 
524
        assert self.conf_ev.delivered_to is root
 
525
        assert self.conf_ev.window is w1
 
526
        assert self.conf_ev.x == 1
 
527
        assert self.conf_ev.y == 2
 
528
        assert self.conf_ev.width == 3
 
529
        assert self.conf_ev.height == 4
 
530
        assert self.conf_ev.value_mask == (l.const["CWX"]
 
531
                                           | l.const["CWY"]
 
532
                                           | l.const["CWWidth"]
 
533
                                           | l.const["CWHeight"])
 
534
 
 
535
        self.map_ev = None
 
536
        self.conf_ev = None
 
537
        w2.move(5, 6)
 
538
        gtk.main()
 
539
        assert self.map_ev is None
 
540
        assert self.conf_ev.x == 5
 
541
        assert self.conf_ev.y == 6
 
542
        assert self.conf_ev.value_mask == (l.const["CWX"] | l.const["CWY"])
 
543
        
 
544
        self.map_ev = None
 
545
        self.conf_ev = None
 
546
        w2.raise_()
 
547
        gtk.main()
 
548
        assert self.map_ev is None
 
549
        assert self.conf_ev.detail == l.const["Above"]
 
550
        assert self.conf_ev.value_mask == l.const["CWStackMode"]
 
551
        
 
552
    def test_configureAndNotify(self):
 
553
        self.conf_ev = None
 
554
        l.substructureRedirect(self.root())
 
555
        l.add_event_receiver(self.root(), self)
 
556
        # Need to hold onto a handle to this, so connection doesn't get
 
557
        # dropped:
 
558
        client = self.clone_display()
 
559
        w1_client = self.window(client)
 
560
        gtk.gdk.flush()
 
561
        w1_wm = l.get_pywindow(self.display, l.get_xwindow(w1_client))
 
562
 
 
563
        l.configureAndNotify(w1_client, 11, 12, 13, 14)
 
564
        gtk.main()
 
565
 
 
566
        assert self.conf_ev is not None
 
567
        assert self.conf_ev.delivered_to is self.root()
 
568
        assert self.conf_ev.window is w1_wm
 
569
        assert self.conf_ev.x == 11
 
570
        assert self.conf_ev.y == 12
 
571
        assert self.conf_ev.width == 13
 
572
        assert self.conf_ev.height == 14
 
573
        assert self.conf_ev.border_width == 0
 
574
        assert self.conf_ev.value_mask == (l.const["CWX"]
 
575
                                           | l.const["CWY"]
 
576
                                           | l.const["CWWidth"]
 
577
                                           | l.const["CWHeight"]
 
578
                                           | l.const["CWBorderWidth"])
 
579
        
 
580
        partial_mask = l.const["CWWidth"] | l.const["CWStackMode"]
 
581
        l.configureAndNotify(w1_client, 11, 12, 13, 14, partial_mask)
 
582
        gtk.main()
 
583
        
 
584
        assert self.conf_ev is not None
 
585
        assert self.conf_ev.delivered_to is self.root()
 
586
        assert self.conf_ev.window is w1_wm
 
587
        assert self.conf_ev.width == 13
 
588
        assert self.conf_ev.border_width == 0
 
589
        assert self.conf_ev.value_mask == (l.const["CWWidth"]
 
590
                                           | l.const["CWBorderWidth"])
 
591
        
 
592
 
 
593
 
 
594
class TestGeometryConstraints(object):
 
595
    # This doesn't actually need a session to play with...
 
596
    def test_calc_constrained_size(self):
 
597
        class Foo:
 
598
            def __repr__(self):
 
599
                return repr(self.__dict__)
 
600
        def hints(**args):
 
601
            f = Foo()
 
602
            for k in ("max_size", "min_size", "base_size", "resize_inc",
 
603
                      "min_aspect", "max_aspect"):
 
604
                setattr(f, k, None)
 
605
            for k, v in args.iteritems():
 
606
                setattr(f, k, v)
 
607
            return f
 
608
        def t(w, h, hints, exp_w, exp_h, exp_vw, exp_vh):
 
609
            got = l.calc_constrained_size(w, h, hints)
 
610
            print repr(hints)
 
611
            assert got == (exp_w, exp_h, exp_vw, exp_vh)
 
612
        t(150, 100, None, 150, 100, 150, 100)
 
613
        t(150, 100, hints(), 150, 100, 150, 100)
 
614
        t(150, 100, hints(max_size=(90, 150)), 90, 100, 90, 100)
 
615
        t(150, 100, hints(max_size=(200, 90)), 150, 90, 150, 90)
 
616
        t(150, 100, hints(min_size=(90, 150)), 150, 150, 150, 150)
 
617
        t(150, 100, hints(min_size=(200, 90)), 200, 100, 200, 100)
 
618
        t(150, 100, hints(min_size=(182, 17), max_size=(182, 17)),
 
619
          182, 17, 182, 17)
 
620
 
 
621
        t(150, 100, hints(base_size=(3, 4), resize_inc=(10, 10)),
 
622
          143, 94, 14, 9)
 
623
        try:
 
624
            t(150, 100, hints(base_size=(3, 4), resize_inc=(10, 10),
 
625
                              max_size=(100, 150), min_size=(0, 140)),
 
626
              93, 144, 9, 14)
 
627
        except AssertionError:
 
628
            print ("Assertion Failed!  But *cough* *cough* actually gdk "
 
629
                   + "(and apparently every wm ever) has a bug here. "
 
630
                   + "and it's trivial and I'm ignoring it for now. "
 
631
                   + "(see http://bugzilla.gnome.org/show_bug.cgi?id=492961)")
 
632
        else:
 
633
            raise AssertionError, "Dude look at this, gtk+ fixed bug#492961"
 
634
        # FIXME: this is wrong (see above), but it is what it actually
 
635
        # returns, and is not so bad as all that:
 
636
        t(150, 100, hints(base_size=(3, 4), resize_inc=(10, 10),
 
637
                          max_size=(100, 150), min_size=(0, 140)),
 
638
          93, 134, 9, 13)
 
639
        
 
640
        # Behavior in this case is basically undefined, so *shrug*:
 
641
        t(150, 100, hints(base_size=(3, 4), resize_inc=(10, 10),
 
642
                          max_size=(100, 100), min_size=(100, 100)),
 
643
          93, 94, 9, 9)
 
644
        
 
645
        t(150, 100, hints(min_aspect=1, max_aspect=1), 100, 100, 100, 100)
 
646
        t(100, 150, hints(min_aspect=1, max_aspect=1), 100, 100, 100, 100)
 
647
 
 
648
        t(100, 150, hints(min_aspect=1, max_aspect=1,
 
649
                          base_size=(3, 3), resize_inc=(10, 10)),
 
650
          93, 93, 9, 9)
 
651
 
 
652
        # Also undefined, but (93, 94) is good enough:
 
653
        t(100, 150, hints(min_aspect=1, max_aspect=1,
 
654
                          base_size=(3, 4), resize_inc=(10, 10)),
 
655
          93, 94, 9, 9)
 
656
 
 
657
 
 
658
class TestRegion(object):
 
659
    def test_get_rectangle_from_region(self):
 
660
        print 1
 
661
        region = gtk.gdk.Region()
 
662
        assert_raises(ValueError, l.get_rectangle_from_region, region)
 
663
        print 2
 
664
        rect1 = gtk.gdk.Rectangle(1, 2, 3, 4)
 
665
        region = gtk.gdk.region_rectangle(rect1)
 
666
        (x, y, w, h) = l.get_rectangle_from_region(region)
 
667
        assert (x, y, w, h) == (1, 2, 3, 4)
 
668
        print 3
 
669
        region.union_with_rect(gtk.gdk.Rectangle(10, 11, 12, 13))
 
670
        (x, y, w, h) = l.get_rectangle_from_region(region)
 
671
        assert (x, y, w, h) in [(1, 2, 3, 4), (10, 11, 12, 13)]
 
672
        print 4
 
673
        region.subtract(gtk.gdk.region_rectangle(rect1))
 
674
        (x, y, w, h) = l.get_rectangle_from_region(region)
 
675
        assert (x, y, w, h) == (10, 11, 12, 13)
 
676
        print 5
 
677
 
 
678
class TestImageOptimizations(object):
 
679
    def test_premultiply_argb_in_place(self):
 
680
        import array
 
681
        ar = array.array("I", [0x80ffffff, 0x306090b0])
 
682
        l.premultiply_argb_in_place(ar)
 
683
        # Got each byte by calculating e.g.:
 
684
        #   hex(int(0xb0 * (0x30 / 255.))) == 0x21
 
685
        assert ar[0] == 0x80808080
 
686
        assert ar[1] == 0x30121b21