3
# examples/draw.py -- high-level xlib test application.
5
# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
7
# This program is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 2 of the License, or
10
# (at your option) any later version.
12
# This program 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. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with this program; if not, write to the Free Software
19
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
# Change path so we find Xlib
26
sys.path.insert(1, os.path.join(sys.path[0], '..'))
28
from Xlib import X, display, Xutil
30
# Application window (only one)
32
def __init__(self, display):
36
# Find which screen to open the window on
37
self.screen = self.d.screen()
39
self.window = self.screen.root.create_window(
41
self.screen.root_depth,
45
# special attribute values
46
background_pixel = self.screen.white_pixel,
47
event_mask = (X.ExposureMask |
48
X.StructureNotifyMask |
52
colormap = X.CopyFromParent,
55
self.gc = self.window.create_gc(
56
foreground = self.screen.black_pixel,
57
background = self.screen.white_pixel,
62
self.WM_DELETE_WINDOW = self.d.intern_atom('WM_DELETE_WINDOW')
63
self.WM_PROTOCOLS = self.d.intern_atom('WM_PROTOCOLS')
65
self.window.set_wm_name('Xlib example: draw.py')
66
self.window.set_wm_icon_name('draw.py')
67
self.window.set_wm_class('draw', 'XlibExample')
69
self.window.set_wm_protocols([self.WM_DELETE_WINDOW])
70
self.window.set_wm_hints(flags = Xutil.StateHint,
71
initial_state = Xutil.NormalState)
73
self.window.set_wm_normal_hints(flags = (Xutil.PPosition | Xutil.PSize
78
# Map the window, making it visible
81
# Main loop, handling events
85
e = self.d.next_event()
87
# Window has been destroyed, quit
88
if e.type == X.DestroyNotify:
91
# Some part of the window has been exposed,
92
# redraw all the objects.
93
if e.type == X.Expose:
94
for o in self.objects:
97
# Left button pressed, start to draw
98
if e.type == X.ButtonPress and e.detail == 1:
99
current = Movement(self, e)
100
self.objects.append(current)
102
# Left button released, finish drawing
103
if e.type == X.ButtonRelease and e.detail == 1 and current:
107
# Mouse movement with button pressed, draw
108
if e.type == X.MotionNotify and current:
111
if e.type == X.ClientMessage:
112
if e.client_type == self.WM_PROTOCOLS:
114
if fmt == 32 and data[0] == self.WM_DELETE_WINDOW:
117
# A drawed objects, consisting of either a single
118
# romboid, or two romboids connected by a winding line
121
def __init__(self, win, ev):
124
self.left = ev.event_x - 5
125
self.right = ev.event_x + 5
126
self.top = ev.event_y - 5
127
self.bottom = ev.event_y + 5
130
self.lines = [(ev.event_x, ev.event_y)]
132
self.first = Romboid(self.win, ev)
135
def motion(self, ev):
136
# Find all the mouse coordinates since the
137
# last event received
139
events = self.win.window.get_motion_events(self.time, ev.time)
142
# Record the previous last coordinate, and append
143
# the new coordinates
144
firstline = len(self.lines) - 1
147
# Discard the first coordinate if that is identical to
148
# the last recorded coordinate
151
if (pos.x, pos.y) == self.lines[-1]:
154
# Append all coordinates
169
self.lines.append((x, y))
171
# Append the event coordinate, if that is different from the
172
# last movement coordinate
173
if (ev.event_x, ev.event_y) != self.lines[-1]:
174
self.lines.append((ev.event_x, ev.event_y))
176
# Draw a line between the new coordinates
177
self.win.window.poly_line(self.win.gc,
179
self.lines[firstline:])
182
def finish(self, ev):
184
if len(self.lines) > 1:
185
self.last = Romboid(self.win, ev)
187
self.left = min(ev.event_x - 5, self.left)
188
self.right = max(ev.event_x + 5, self.right)
189
self.top = min(ev.event_y - 5, self.top)
190
self.bottom = max(ev.event_y + 5, self.bottom)
192
def expose(self, ev):
193
# We should check if this object is in the exposed
194
# area, but I can't be bothered right now, so just
195
# redraw on the last Expose in every batch
200
# Redraw all the lines
201
self.win.window.poly_line(self.win.gc,
207
# A romboid, drawed around the Movement endpoints
209
def __init__(self, win, ev):
216
# Draw the segments of the romboid
217
self.win.window.poly_line(self.win.gc, X.CoordModePrevious,
218
[(self.x, self.y - 5),
225
if __name__ == '__main__':
226
Window(display.Display()).loop()