]> icculus.org git repositories - mikachu/openbox.git/blob - scripts/motion.py
dont snap back, properly
[mikachu/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 - the amount of resistance to provide to moving a       ###
10 ###                 window past a screen boundary. Specify a value of 0   ###
11 ###                 to disable edge resistance.                           ###
12 edge_resistance = 10                                                      ###
13 ###                                                                       ###
14 # move_popup - display a coordinates popup when moving windows.           ###
15 move_popup = 1                                                            ###
16 ###                                                                       ###
17 # NOT IMPLEMENTED (yet?)                                                  ###
18 # move_rubberband - display an outline while moving instead of moving the ###
19 ###                 actual window, until the move is completed. Good for  ###
20 ###                 slower systems.                                       ###
21 move_rubberband = 0                                                       ###
22 ###                                                                       ###
23 # resize_popup - display a size popup when resizing windows.              ###
24 resize_popup = 1                                                          ###
25 ###                                                                       ###
26 # NOT IMPLEMENTED (yet?)                                                  ###
27 # resize_rubberband - display an outline while resizing instead of        ###
28 ###                   resizing the actual window, until the resize is     ###
29 ###                   completed. Good for slower systems.                 ###
30 resize_rubberband = 0                                                     ###
31 ###                                                                       ###
32 # resize_nearest - 1 to resize from the corner nearest where the mouse    ###
33 ###                is, 0 to resize always from the bottom right corner.   ###
34 resize_nearest = 1                                                        ###
35 ###                                                                       ###
36 ###                                                                       ###
37 # Provides:                                                               ###
38 # def move(data):                                                         ###
39 #     """Moves the window interactively. This should only be used with    ###
40 #        MouseMotion events. If move_popup or move_rubberband is enabled, ###
41 #        then the end_move function needs to be bound as well."""         ###
42 # def end_move(data):                                                     ###
43 #     """Complete the interactive move of a window."""                    ###
44 # def resize(data):                                                       ###
45 #     """Resizes the window interactively. This should only be used with  ###
46 #        MouseMotion events"""                                            ###
47 # def end_resize(data):                                                   ###
48 #     """Complete the interactive resize of a window."""                  ###
49 ###                                                                       ###
50 #############################################################################
51
52 import ob
53 import otk
54
55 _popwidget = 0
56 _poplabel = 0
57
58 # motion state
59 _inmove = 0
60 _inresize = 0
61
62 # last motion data
63 _cx = 0
64 _cy = 0
65 _cw = 0
66 _ch = 0
67 _px = 0
68 _py = 0
69 _dx = 0
70 _dy = 0
71 _client = 0
72 _screen = 0
73
74 _motion_mask = 0
75
76 def _motion_grab(data):
77     global _motion_mask, _inmove, _inresize;
78
79     if data.action == ob.KeyAction.Release:
80         # have all the modifiers this started with been released?
81         if not _motion_mask & data.state:
82             if _inmove:
83                 end_move(data)
84             elif _inresize:
85                 end_resize(data)
86             else:
87                 raise RuntimeError
88
89 _last_x = 0
90 _last_y = 0
91
92 def _do_move():
93     global _screen, _client, _cx, _cy, _dx, _dy
94
95     x = _cx + _dx
96     y = _cy + _dy
97
98     global edge_resistance
99     global _last_x, _last_y
100     if edge_resistance:
101         fs = _client.frame.size()
102         w = _client.area().width() + fs.left + fs.right
103         h = _client.area().height() + fs.top + fs.bottom
104         # use the area based on the struts
105         area = ob.openbox.screen(_screen).area()
106         l = area.left()
107         r = area.right() - w + 1
108         t = area.top()
109         b = area.bottom() - h + 1
110         # left screen edge
111         if _last_x > x and x < l and x >= l - edge_resistance:
112             x = l
113         # right screen edge
114         if _last_x < x and x > r and x <= r + edge_resistance:
115             x = r
116         # top screen edge
117         if _last_y > y and y < t and y >= t - edge_resistance:
118             y = t
119         # right screen edge
120         if _last_y < y and y > b and y <= b + edge_resistance:
121             y = b
122
123     global _inmove
124     if not _inmove:
125         _last_x = 0
126         _last_y = 0
127     else:
128         _last_x = x
129         _last_y = y
130
131     global move_rubberband
132     if move_rubberband:
133         # draw the outline ...
134         f=0
135     else:
136         _client.move(x, y)
137
138     global move_popup
139     if move_popup:
140         global _popwidget, _poplabel
141         style = ob.openbox.screen(_screen).style()
142         font = style.labelFont()
143         text = "X: " + str(x) + " Y: " + str(y)
144         length = font.measureString(text)
145         if not _popwidget:
146             _popwidget = otk.Widget(ob.openbox, style,
147                                     otk.Widget.Horizontal, 0,
148                                     style.bevelWidth(), 1)
149             _popwidget.setTexture(style.titlebarFocusBackground())
150             _poplabel = otk.Label(_popwidget)
151             _poplabel.setTexture(style.labelFocusBackground())
152         _poplabel.fitString(text)
153         _poplabel.setText(text)
154         _popwidget.update() 
155         area = otk.display.screenInfo(_screen).rect()
156         _popwidget.move(area.x() + (area.width() -
157                                     _popwidget.width()) / 2,
158                         area.y() + (area.height() -
159                                     _popwidget.height()) / 2)
160         _popwidget.show(1)
161
162 def move(data):
163     """Moves the window interactively. This should only be used with
164        MouseMotion events. If move_popup or move_rubberband is enabled, then
165        the end_move function needs to be bound as well."""
166     if not data.client: return
167
168     # not-normal windows dont get moved
169     if not data.client.normal(): return
170
171     global _screen, _client, _cx, _cy, _dx, _dy
172     _screen = data.screen
173     _client = data.client
174     _cx = data.press_clientx
175     _cy = data.press_clienty
176     _dx = data.xroot - data.pressx
177     _dy = data.yroot - data.pressy
178     _do_move()
179     global _inmove
180     if not _inmove:
181         ob.kgrab(_screen, _motion_grab)
182         _inmove = 1
183
184 def end_move(data):
185     """Complete the interactive move of a window."""
186     global move_rubberband, _inmove
187     global _popwidget, _poplabel
188     if _inmove:
189         r = move_rubberband
190         move_rubberband = 0
191         _do_move()
192         move_rubberband = r
193         _inmove = 0
194     _poplabel = 0
195     _popwidget = 0
196     ob.kungrab()
197
198 def _do_resize():
199     global _screen, _client, _cx, _cy, _cw, _ch, _px, _py, _dx, _dy
200
201     dx = _dx
202     dy = _dy
203     
204     # pick a corner to anchor
205     if not (resize_nearest or _context == ob.MouseContext.Grip):
206         corner = ob.Client.TopLeft
207     else:
208         x = _px - _cx
209         y = _py - _cy
210         if y < _ch / 2:
211             if x < _cw / 2:
212                 corner = ob.Client.BottomRight
213                 dx *= -1
214             else:
215                 corner = ob.Client.BottomLeft
216             dy *= -1
217         else:
218             if x < _cw / 2:
219                 corner = ob.Client.TopRight
220                 dx *= -1
221             else:
222                 corner = ob.Client.TopLeft
223
224     w = _cw + dx
225     h = _ch + dy
226
227     global resize_popup
228     if resize_rubberband:
229         # draw the outline ...
230         f=0
231     else:
232         _client.resize(corner, w, h)
233
234     global resize_popup
235     if resize_popup:
236         global _popwidget, _poplabel
237         style = ob.openbox.screen(_screen).style()
238         ls = _client.logicalSize()
239         text = "W: " + str(ls.x()) + " H: " + str(ls.y())
240         if not _popwidget:
241             _popwidget = otk.Widget(ob.openbox, style,
242                                     otk.Widget.Horizontal, 0,
243                                     style.bevelWidth(), 1)
244             _popwidget.setTexture(style.titlebarFocusBackground())
245             _poplabel = otk.Label(_popwidget)
246             _poplabel.setTexture(style.labelFocusBackground())
247         _poplabel.fitString(text)
248         _poplabel.setText(text)
249         area = otk.display.screenInfo(_screen).rect()
250         _popwidget.update() 
251         _popwidget.move(area.x() + (area.width() -
252                                     _popwidget.width()) / 2,
253                         area.y() + (area.height() -
254                                     _popwidget.height()) / 2)
255         _popwidget.show(1)
256
257 def resize(data):
258     """Resizes the window interactively. This should only be used with
259        MouseMotion events"""
260     if not data.client: return
261
262     # not-normal windows dont get resized
263     if not data.client.normal(): return
264
265     global _screen, _client, _cx, _cy, _cw, _ch, _px, _py, _dx, _dy
266     _screen = data.screen
267     _client = data.client
268     _cx = data.press_clientx
269     _cy = data.press_clienty
270     _cw = data.press_clientwidth
271     _ch = data.press_clientheight
272     _px = data.pressx
273     _py = data.pressy
274     _dx = data.xroot - _px
275     _dy = data.yroot - _py
276     _do_resize()
277     global _inresize
278     if not _inresize:
279         ob.kgrab(_screen, _motion_grab)
280         _inresize = 1
281
282 def end_resize(data):
283     """Complete the interactive resize of a window."""
284     global resize_rubberband, _inresize
285     global _popwidget, _poplabel
286     if _inresize:
287         r = resize_rubberband
288         resize_rubberband = 0
289         _do_resize()
290         resize_rubberband = r
291         _inresize = 0
292     _poplabel = 0
293     _popwidget = 0
294     ob.kungrab()