]> icculus.org git repositories - dana/openbox.git/blob - scripts/motion.py
position is a function
[dana/openbox.git] / scripts / motion.py
1 ############################################################################
2 ###    Functions that provide callbacks for motion events to move and    ###
3 ###    resize windows.                                                   ###
4 ############################################################################
5
6 #############################################################################
7 ###   Options that can be modified to change the functions' behaviors.    ###
8 #############################################################################
9 EDGE_RESISTANCE = 10
10 """The amount of resistance to provide to moving a window past a screen
11    boundary. Specify a value of 0 to disable edge resistance."""
12 POPUP_IN_WINDOW = 0
13 """When this is non-zero, the coordinates popups will be placed relative to
14    the window being moved/resized. When zero, they will appear relative to the
15    entire screen."""
16 POPUP_CENTERED = 1
17 """When this is non-zero, the coordinates popups will be centered relative to
18    the window or screen (see POPUP_IN_WINDOW). When zero, they will be placed
19    at based upon POPUP_COORDS."""
20 POPUP_COORDS = 0, 0
21 """When POPUP_CENTERED is zero, these coordinates will be used to place the
22    coordinates popup. The popup will be placed relative to the window or the
23    screen (see POPUP_IN_WINDOW). A value of 0, 0 would place it in the top
24    left corner, while a value of -1, -1 would place it in the bottom right.
25    These values behave simmilarly to those passed to the -geometry flag of many
26    applications."""
27 MOVE_POPUP = 1
28 """Display a coordinates popup when moving windows."""
29 MOVE_RUBBERBAND = 0
30 """NOT IMPLEMENTED (yet?)
31    Display an outline while moving instead of moving the actual window,
32    until the move is completed. Good for slower systems."""
33 RESIZE_POPUP = 1
34 """Display a size popup when resizing windows."""
35 RESIZE_RUBBERBAND = 0
36 """NOT IMPLEMENTED (yet?)
37    Display an outline while resizing instead of resizing the actual
38    window, until the resize is completed. Good for slower systems."""
39 RESIZE_NEAREST = 1
40 """Non-zero to resize from the corner nearest where the mouse is, 0 to
41    resize always from the bottom right corner."""
42 #############################################################################
43
44 def move(data):
45     """Moves the window interactively. This should only be used with
46        MouseAction.Motion events. If MOVE_POPUP or MOVE_RUBBERBAND is enabled,
47        then the end_move function needs to be bound as well."""
48     _move(data)
49
50 def end_move(data):
51     """Complete the interactive move of a window."""
52     _end_move(data)
53
54 def resize(data):
55     """Resizes the window interactively. This should only be used with
56        MouseMotion events. If RESIZE_POPUP or RESIZE_RUBBERBAND is enabled,
57        then the end_resize function needs to be bound as well."""
58     _resize(data)
59
60 def end_resize(data):
61     """Complete the interactive resize of a window."""
62     _end_resize(data)
63
64 ###########################################################################
65 ###########################################################################
66
67 ###########################################################################
68 ###      Internal stuff, should not be accessed outside the module.     ###
69 ###########################################################################
70
71 import ob
72 import otk
73
74 _popwidget = 0
75
76 # motion state
77 _inmove = 0
78 _inresize = 0
79
80 # last motion data
81 _cx = 0
82 _cy = 0
83 _cw = 0
84 _ch = 0
85 _px = 0
86 _py = 0
87 _dx = 0
88 _dy = 0
89 _client = 0
90 _screen = 0
91
92 _motion_mask = 0
93
94 def _place_popup():
95     if POPUP_IN_WINDOW:
96         area = _client.frame.area()
97     else:
98         area = otk.Rect(otk.Point(0, 0), ob.openbox.screen(_screen).size())
99     size = _popwidget.minSize()
100     if POPUP_CENTERED:
101         x = area.position().x() + (area.size().width() - size.width()) / 2
102         y = area.position().y() + (area.size().height() - size.height()) / 2
103     else:
104         try: x, y = POPUP_COORDS
105         except: x = y = 0
106         if x < 0: x += area.right() - size.width() + 2
107         if y < 0: y += area.bottom() - size.height() + 2
108         x += area.position().x()
109         y += area.position().y()
110     _popwidget.moveresize(otk.Rect(x, y, size.width(), size.height()))
111
112 def _motion_grab(data):
113     global _motion_mask, _inmove, _inresize;
114
115     # are all the modifiers this started with still pressed?
116     if not _motion_mask & data.state:
117         if _inmove:
118             _end_move(data)
119         elif _inresize:
120             _end_resize(data)
121         else:
122             raise RuntimeError
123
124 _last_x = 0
125 _last_y = 0
126
127 def _do_move(final):
128     global _screen, _client, _cx, _cy, _dx, _dy
129
130     # get destination x/y for the *frame*
131     x = _cx + _dx + _client.frame.area().x() - _client.area().x()
132     y = _cy + _dy + _client.frame.area().y() - _client.area().y()
133
134     global _last_x, _last_y
135     if EDGE_RESISTANCE:
136         fs = _client.frame.size()
137         w = _client.area().width() + fs.left + fs.right
138         h = _client.area().height() + fs.top + fs.bottom
139         # use the area based on the struts
140         area = ob.openbox.screen(_screen).area(_client.desktop())
141         l = area.left()
142         r = area.right() - w + 1
143         t = area.top()
144         b = area.bottom() - h + 1
145         # left screen edge
146         if _last_x > x and x < l and x >= l - EDGE_RESISTANCE:
147             x = l
148         # right screen edge
149         if _last_x < x and x > r and x <= r + EDGE_RESISTANCE:
150             x = r
151         # top screen edge
152         if _last_y > y and y < t and y >= t - EDGE_RESISTANCE:
153             y = t
154         # right screen edge
155         if _last_y < y and y > b and y <= b + EDGE_RESISTANCE:
156             y = b
157
158     global _inmove
159     if not _inmove:
160         _last_x = 0
161         _last_y = 0
162     else:
163         _last_x = x
164         _last_y = y
165
166     if MOVE_RUBBERBAND:
167         # draw the outline ...
168         f=0
169     else:
170         _client.move(x, y, final)
171
172     if MOVE_POPUP:
173         global _popwidget
174         text = "X: " + str(x) + " Y: " + str(y)
175         if not _popwidget:
176             _popwidget = otk.Label(_screen, ob.openbox)
177             _popwidget.setHighlighted(1)
178         _popwidget.setText(text)
179         _place_popup()
180         _popwidget.show()
181
182 def _move(data):
183     if not data.client: return
184
185     # not-normal windows dont get moved
186     if not data.client.normal(): return
187
188     global _screen, _client, _cx, _cy, _dx, _dy, _motion_mask
189     _screen = data.screen
190     _client = data.client
191     _cx = data.press_clientx
192     _cy = data.press_clienty
193     _dx = data.xroot - data.pressx
194     _dy = data.yroot - data.pressy
195     _motion_mask = data.state
196     _do_move(0)
197     global _inmove
198     if not _inmove:
199         ob.kgrab(_screen, _motion_grab)
200         _inmove = 1
201
202 def _end_move(data):
203     global MOVE_RUBBERBAND
204     global _inmove, _popwidget
205     if _inmove:
206         r = MOVE_RUBBERBAND
207         MOVE_RUBBERBAND = 0
208         _do_move(1)
209         MOVE_RUBBERBAND = r
210         _inmove = 0
211     _popwidget = 0
212     ob.kungrab()
213
214 def _do_resize():
215     global _screen, _client, _cx, _cy, _cw, _ch, _px, _py, _dx, _dy
216
217     dx = _dx
218     dy = _dy
219     
220     # pick a corner to anchor
221     if not (RESIZE_NEAREST or _context == ob.MouseContext.Grip):
222         corner = ob.Client.TopLeft
223     else:
224         x = _px - _cx
225         y = _py - _cy
226         if y < _ch / 2:
227             if x < _cw / 2:
228                 corner = ob.Client.BottomRight
229                 dx *= -1
230             else:
231                 corner = ob.Client.BottomLeft
232             dy *= -1
233         else:
234             if x < _cw / 2:
235                 corner = ob.Client.TopRight
236                 dx *= -1
237             else:
238                 corner = ob.Client.TopLeft
239
240     w = _cw + dx
241     h = _ch + dy
242
243     if RESIZE_RUBBERBAND:
244         # draw the outline ...
245         f=0
246     else:
247         _client.resize(corner, w, h)
248
249     if RESIZE_POPUP:
250         global _popwidget
251         ls = _client.logicalSize()
252         text = "W: " + str(ls.width()) + " H: " + str(ls.height())
253         if not _popwidget:
254             _popwidget = otk.Label(_screen, ob.openbox)
255             _popwidget.setHighlighted(1)
256         _popwidget.setText(text)
257         _place_popup()
258         _popwidget.show()
259
260 def _resize(data):
261     if not data.client: return
262
263     # not-normal windows dont get resized
264     if not data.client.normal(): return
265
266     global _screen, _client, _cx, _cy, _cw, _ch, _px, _py, _dx, _dy
267     global _motion_mask
268     _screen = data.screen
269     _client = data.client
270     _cx = data.press_clientx
271     _cy = data.press_clienty
272     _cw = data.press_clientwidth
273     _ch = data.press_clientheight
274     _px = data.pressx
275     _py = data.pressy
276     _dx = data.xroot - _px
277     _dy = data.yroot - _py
278     _motion_mask = data.state
279     _do_resize()
280     global _inresize
281     if not _inresize:
282         ob.kgrab(_screen, _motion_grab)
283         _inresize = 1
284
285 def _end_resize(data):
286     global RESIZE_RUBBERBAND, _inresize
287     global _popwidget
288     if _inresize:
289         r = RESIZE_RUBBERBAND
290         RESIZE_RUBBERBAND = 0
291         _do_resize()
292         RESIZE_RUBBERBAND = r
293         _inresize = 0
294     _popwidget = 0
295     ob.kungrab()