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