Skip to content

Commit 2a70b86

Browse files
Merge pull request #139 from mgarg1/damage-ext-example
Damage ext example
2 parents 64fc9a5 + 865f26f commit 2a70b86

File tree

3 files changed

+317
-0
lines changed

3 files changed

+317
-0
lines changed

Xlib/ext/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
('SECURITY', 'security'),
3838
('XInputExtension', 'xinput'),
3939
('NV-CONTROL', 'nvcontrol'),
40+
('DAMAGE', 'damage'),
4041
]
4142

4243
__all__ = map(lambda x: x[1], __extensions__)

Xlib/ext/damage.py

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
# Xlib.ext.damage -- DAMAGE extension module
2+
#
3+
# Copyright (C) 2018 Joseph Kogut <joseph.kogut@gmail.com>
4+
#
5+
# This library is free software; you can redistribute it and/or
6+
# modify it under the terms of the GNU Lesser General Public License
7+
# as published by the Free Software Foundation; either version 2.1
8+
# of the License, or (at your option) any later version.
9+
#
10+
# This library is distributed in the hope that it will be useful,
11+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13+
# See the GNU Lesser General Public License for more details.
14+
#
15+
# You should have received a copy of the GNU Lesser General Public
16+
# License along with this library; if not, write to the
17+
# Free Software Foundation, Inc.,
18+
# 59 Temple Place,
19+
# Suite 330,
20+
# Boston, MA 02111-1307 USA
21+
22+
23+
from Xlib import X
24+
from Xlib.protocol import rq, structs
25+
from Xlib.xobject import resource
26+
from Xlib.error import XError
27+
28+
extname = 'DAMAGE'
29+
30+
# Event codes #
31+
DamageNotifyCode = 0
32+
33+
# Error codes #
34+
BadDamageCode = 0
35+
36+
class BadDamageError(XError):
37+
pass
38+
39+
# DamageReportLevel options
40+
DamageReportRawRectangles = 0
41+
DamageReportDeltaRectangles = 1
42+
DamageReportBoundingBox = 2
43+
DamageReportNonEmpty = 3
44+
45+
DamageReportLevel = (
46+
DamageReportRawRectangles,
47+
DamageReportDeltaRectangles,
48+
DamageReportBoundingBox,
49+
DamageReportNonEmpty,
50+
)
51+
52+
DAMAGE = rq.Card32
53+
54+
# Methods
55+
56+
class QueryVersion(rq.ReplyRequest):
57+
_request = rq.Struct(rq.Card8('opcode'),
58+
rq.Opcode(0),
59+
rq.RequestLength(),
60+
rq.Card32('major_version'),
61+
rq.Card32('minor_version'),
62+
)
63+
64+
_reply = rq.Struct(rq.ReplyCode(),
65+
rq.Pad(1),
66+
rq.Card16('sequence_number'),
67+
rq.ReplyLength(),
68+
rq.Card32('major_version'),
69+
rq.Card32('minor_version'),
70+
rq.Pad(16),
71+
)
72+
73+
def query_version(self):
74+
return QueryVersion(display=self.display,
75+
opcode=self.display.get_extension_major(extname),
76+
major_version=1,
77+
minor_version=1)
78+
79+
class DamageCreate(rq.Request):
80+
_request = rq.Struct(rq.Card8('opcode'),
81+
rq.Opcode(1),
82+
rq.RequestLength(),
83+
DAMAGE('damage'),
84+
rq.Drawable('drawable'),
85+
rq.Set('level', 1, DamageReportLevel),
86+
rq.Pad(3),
87+
)
88+
89+
def damage_create(self, level):
90+
did = self.display.allocate_resource_id()
91+
DamageCreate(display=self.display,
92+
opcode=self.display.get_extension_major(extname),
93+
damage=did,
94+
drawable=self.id,
95+
level=level,
96+
)
97+
return did
98+
99+
class DamageDestroy(rq.Request):
100+
_request = rq.Struct(rq.Card8('opcode'),
101+
rq.Opcode(2),
102+
rq.RequestLength(),
103+
DAMAGE('damage')
104+
)
105+
106+
def damage_destroy(self, damage):
107+
DamageDestroy(display=self.display,
108+
opcode=self.display.get_extension_major(extname),
109+
damage=damage,
110+
)
111+
112+
self.display.free_resource_id(damage)
113+
114+
class DamageSubtract(rq.Request):
115+
_request = rq.Struct(rq.Card8('opcode'),
116+
rq.Opcode(3),
117+
rq.RequestLength(),
118+
DAMAGE('damage'),
119+
rq.Card32('repair'),
120+
rq.Card32('parts')
121+
)
122+
123+
def damage_subtract(self, damage, repair=X.NONE, parts=X.NONE):
124+
DamageSubtract(display=self.display,
125+
opcode=self.display.get_extension_major(extname),
126+
damage=damage,
127+
repair=repair,
128+
parts=parts)
129+
130+
class DamageAdd(rq.Request):
131+
_request = rq.Struct(rq.Card8('opcode'),
132+
rq.Opcode(4),
133+
rq.RequestLength(),
134+
rq.Card32('repair'),
135+
rq.Card32('parts'),
136+
)
137+
138+
def damage_add(self, repair, parts):
139+
DamageAdd(display=self.display,
140+
opcode=self.display.get_extension_major(extname),
141+
repair=repair,
142+
parts=parts)
143+
144+
# Events #
145+
146+
class DamageNotify(rq.Event):
147+
_code = None
148+
_fields = rq.Struct(
149+
rq.Card8('type'),
150+
rq.Card8('level'),
151+
rq.Card16('sequence_number'),
152+
rq.Drawable('drawable'),
153+
DAMAGE('damage'),
154+
rq.Card32('timestamp'),
155+
rq.Object('area', structs.Rectangle),
156+
rq.Object('drawable_geometry', structs.Rectangle)
157+
)
158+
159+
def init(disp, info):
160+
disp.extension_add_method('display',
161+
'damage_query_version',
162+
query_version)
163+
164+
disp.extension_add_method('drawable',
165+
'damage_create',
166+
damage_create)
167+
168+
disp.extension_add_method('display',
169+
'damage_destroy',
170+
damage_destroy)
171+
172+
disp.extension_add_method('display',
173+
'damage_subtract',
174+
damage_subtract)
175+
176+
disp.extension_add_method('drawable',
177+
'damage_add',
178+
damage_add)
179+
180+
disp.extension_add_event(info.first_event + DamageNotifyCode, DamageNotify)
181+
182+
disp.add_extension_error(code=BadDamageCode, err=BadDamageError)

examples/xdamage.py

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#!/usr/bin/python
2+
#
3+
# examples/xdamage.py -- demonstrate damage extension
4+
#
5+
# Copyright (C) 2019 Mohit Garg <mrmohitgarg1990@gmail.com>
6+
#
7+
# This library is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU Lesser General Public License
9+
# as published by the Free Software Foundation; either version 2.1
10+
# of the License, or (at your option) any later version.
11+
#
12+
# This library is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15+
# See the GNU Lesser General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU Lesser General Public
18+
# License along with this library; if not, write to the
19+
# Free Software Foundation, Inc.,
20+
# 59 Temple Place,
21+
# Suite 330,
22+
# Boston, MA 02111-1307 USA
23+
24+
25+
# Python 2/3 compatibility.
26+
from __future__ import print_function
27+
28+
import sys
29+
import os
30+
31+
# Change path so we find Xlib
32+
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
33+
34+
from Xlib import display, X, threaded,Xutil
35+
import time
36+
import thread
37+
from Xlib.ext import damage
38+
from PIL import Image, ImageTk
39+
import traceback
40+
41+
def redraw(win, gc):
42+
# win.clear_area()
43+
win.fill_rectangle(gc, 0, 0, 60, 60)
44+
45+
def blink(display, win, gc, cols):
46+
while 1:
47+
time.sleep(2)
48+
print('Changing color', cols[0])
49+
gc.change(foreground = cols[0])
50+
cols = (cols[1], cols[0])
51+
redraw(win, gc)
52+
display.flush()
53+
54+
def get_image_from_win(win, pt_w, pt_h, pt_x=0, pt_y=0):
55+
try:
56+
raw = win.get_image(ptX,ptY, ptW,ptH, X.ZPixmap, 0xffffffff)
57+
image = Image.frombytes("RGB", (ptW, ptH), raw.data, "raw", "BGRX")
58+
return image
59+
60+
except Exception:
61+
traceback.print_exc()
62+
63+
def check_ext(disp):
64+
# Check for extension
65+
if not disp.has_extension('DAMAGE'):
66+
sys.stderr.write('server does not have the DAMAGE extension\n')
67+
sys.stderr.write("\n".join(disp.list_extensions()))
68+
69+
if disp.query_extension('DAMAGE') is None:
70+
sys.exit(1)
71+
else:
72+
r = disp.damage_query_version()
73+
print('DAMAGE version {}.{}'.format(r.major_version, r.minor_version))
74+
75+
def main():
76+
d = display.Display()
77+
root = d.screen().root
78+
79+
check_ext(d)
80+
colormap = d.screen().default_colormap
81+
82+
red = colormap.alloc_named_color("red").pixel
83+
blue = colormap.alloc_named_color("blue").pixel
84+
background = colormap.alloc_named_color("white").pixel
85+
86+
window1 = root.create_window(100, 100, 250, 100, 1,
87+
X.CopyFromParent, X.InputOutput,
88+
X.CopyFromParent,
89+
background_pixel = background,
90+
event_mask = X.StructureNotifyMask | X.ExposureMask)
91+
window1.set_wm_name('Changing Window')
92+
window1.map()
93+
gc = window1.create_gc(foreground = red)
94+
95+
thread.start_new_thread(blink, (d, window1, gc, (blue, red)))
96+
97+
window1.damage_create(damage.DamageReportRawRectangles)
98+
window1.set_wm_normal_hints(
99+
flags=(Xutil.PPosition | Xutil.PSize | Xutil.PMinSize),
100+
min_width=50,
101+
min_height=50
102+
)
103+
104+
window2 = root.create_window(100, 250, 250, 100, 1,
105+
X.CopyFromParent, X.InputOutput,
106+
X.CopyFromParent,
107+
background_pixel = background,
108+
event_mask = X.StructureNotifyMask | X.ExposureMask)
109+
window2.set_wm_normal_hints(
110+
flags=(Xutil.PPosition | Xutil.PSize | Xutil.PMinSize),
111+
min_width=50,
112+
min_height=50
113+
)
114+
115+
window2.set_wm_name('Tracking Window')
116+
window2.map()
117+
118+
while 1:
119+
event = d.next_event()
120+
if event.type == X.Expose:
121+
if event.count == 0:
122+
redraw(window1, gc)
123+
elif event.type == d.extension_event.DamageNotify:
124+
image = get_image_from_win(window1, event.area.width, event.area.height, event.area.x, event.area.y)
125+
bgpm = window2.create_pixmap(image.width, image.height, d.screen().root_depth)
126+
bggc = window2.create_gc(foreground=0, background=0)
127+
bgpm.put_pil_image(bggc, 0, 0, image)
128+
window2.copy_area(bggc, bgpm, 0, 0, image.width, image.height, 0, 0)
129+
# bggc.free()
130+
elif event.type == X.DestroyNotify:
131+
sys.exit(0)
132+
133+
if __name__ == "__main__":
134+
main()

0 commit comments

Comments
 (0)