]> git.decadent.org.uk Git - ion3.git/blob - ioncore/kbresize.c
[svn-upgrade] Integrating new upstream version, ion3 (20070506)
[ion3.git] / ioncore / kbresize.c
1 /*
2  * ion/ioncore/kbresize.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2007. 
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <math.h>
10 #include <sys/time.h>
11 #include <time.h>
12 #include <limits.h>
13
14 #include <libtu/minmax.h>
15
16 #include <libmainloop/signal.h>
17
18 #include "global.h"
19 #include "resize.h"
20 #include "kbresize.h"
21 #include "grab.h"
22 #include "binding.h"
23 #include "focus.h"
24 #include "bindmaps.h"
25
26
27 /*{{{ Resize accelerator */
28
29
30 static struct timeval last_action_tv={-1, 0};
31 static struct timeval last_update_tv={-1, 0};
32 static int last_accel_mode=0;
33 static double accel=1, accelinc=30, accelmax=100*100;
34 static long actmax=200, uptmin=50;
35 static int resize_delay=CF_RESIZE_DELAY;
36
37
38 static void accel_reset()
39 {
40     last_accel_mode=0;
41     accel=1.0;
42     last_action_tv.tv_sec=-1;
43     last_action_tv.tv_usec=-1;
44 }
45
46
47 void ioncore_set_moveres_accel(ExtlTab tab)
48 {
49     int t_max, t_min, rd;
50     double step, maxacc;
51     
52     if(extl_table_gets_i(tab, "kbresize_t_max", &t_max))
53        actmax=(t_max>0 ? t_max : INT_MAX);
54     if(extl_table_gets_i(tab, "kbresize_t_min", &t_min))
55        uptmin=(t_min>0 ? t_min : INT_MAX);
56     if(extl_table_gets_d(tab, "kbresize_step", &step))
57        accelinc=(step>0 ? step : 1);
58     if(extl_table_gets_d(tab, "kbresize_maxacc", &maxacc))
59        accelmax=(maxacc>0 ? maxacc*maxacc : 1);
60     if(extl_table_gets_i(tab, "kbresize_delay", &rd))
61         resize_delay=maxof(0, rd);
62 }
63
64
65 void ioncore_get_moveres_accel(ExtlTab tab)
66 {
67     extl_table_sets_i(tab, "kbresize_t_max", actmax),
68     extl_table_sets_i(tab, "kbresize_t_min", uptmin);
69     extl_table_sets_d(tab, "kbresize_step", accelinc);
70     extl_table_sets_d(tab, "kbresize_maxacc", accelmax);
71     extl_table_sets_d(tab, "kbresize_delay", resize_delay);
72 }
73
74
75 static int sign(int x)
76 {
77     return (x>0 ? 1 : (x<0 ? -1 : 0));
78 }
79
80
81 static long tvdiffmsec(struct timeval *tv1, struct timeval *tv2)
82 {
83     double t1=1000*(double)tv1->tv_sec+(double)tv1->tv_usec/1000;
84     double t2=1000*(double)tv2->tv_sec+(double)tv2->tv_usec/1000;
85     
86     return (int)(t1-t2);
87 }
88
89 #define SIGN_NZ(X) ((X) < 0 ? -1 : 1)
90
91 static double max(double a, double b)
92 {
93     return (a<b ? b : a);
94 }
95
96 void moveresmode_accel(WMoveresMode *mode, int *wu, int *hu, int accel_mode)
97 {
98     struct timeval tv;
99     long adiff, udiff;
100     
101     gettimeofday(&tv, NULL);
102     
103     adiff=tvdiffmsec(&tv, &last_action_tv);
104     udiff=tvdiffmsec(&tv, &last_update_tv);
105     
106     if(last_accel_mode==accel_mode && adiff<actmax){
107         if(udiff>uptmin){
108             accel+=accelinc;
109             if(accel>accelmax)
110                 accel=accelmax;
111             last_update_tv=tv;
112         }
113     }else{
114         accel=1.0;
115         last_update_tv=tv;
116     }
117     
118     last_accel_mode=accel_mode;
119     last_action_tv=tv;
120     
121     if(*wu!=0)
122         *wu=(*wu)*ceil(sqrt(accel)/abs(*wu));
123     if(*hu!=0)
124         *hu=(*hu)*ceil(sqrt(accel)/abs(*hu));
125 }
126
127
128 /*}}}*/
129
130
131 /*{{{ Keyboard resize handler */
132
133
134 static ExtlExportedFn *moveres_safe_fns[]={
135     (ExtlExportedFn*)&moveresmode_resize,
136     (ExtlExportedFn*)&moveresmode_move,
137     (ExtlExportedFn*)&moveresmode_rqgeom_extl,
138     (ExtlExportedFn*)&moveresmode_geom,
139     (ExtlExportedFn*)&moveresmode_finish,
140     (ExtlExportedFn*)&moveresmode_cancel,
141     NULL
142 };
143
144 static ExtlSafelist moveres_safelist=EXTL_SAFELIST_INIT(moveres_safe_fns);
145
146
147 static bool resize_handler(WRegion *reg, XEvent *xev)
148 {
149     XKeyEvent *ev=&xev->xkey;
150     WBinding *binding=NULL;
151     WBindmap **bindptr;
152     WMoveresMode *mode;
153     
154     if(ev->type==KeyRelease)
155         return FALSE;
156     
157     if(reg==NULL)
158         return FALSE;
159     
160     mode=moveres_mode(reg);
161     
162     if(mode==NULL)
163         return FALSE;
164     
165     binding=bindmap_lookup_binding(ioncore_moveres_bindmap, 
166                                    BINDING_KEYPRESS,
167                                    ev->state, ev->keycode);
168     
169     if(!binding)
170         return FALSE;
171     
172     if(binding!=NULL){
173         extl_protect(&moveres_safelist);
174         extl_call(binding->func, "oo", NULL, mode, reg);
175         extl_unprotect(&moveres_safelist);
176     }
177     
178     return (moveres_mode(reg)==NULL);
179 }
180
181
182 /*}}}*/
183
184
185 /*{{{ Resize timer */
186
187
188 static WTimer *resize_timer=NULL;
189
190
191 static void tmr_end_resize(WTimer *unused, WMoveresMode *mode)
192 {
193     if(mode!=NULL)
194         moveresmode_cancel(mode);
195 }
196
197
198 static bool setup_resize_timer(WMoveresMode *mode)
199 {
200     if(resize_timer==NULL){
201         resize_timer=create_timer();
202         if(resize_timer==NULL)
203             return FALSE;
204     }
205     
206     timer_set(resize_timer, resize_delay, 
207               (WTimerHandler*)tmr_end_resize, (Obj*)mode);
208     
209     return TRUE;
210 }
211
212
213 static void reset_resize_timer()
214 {
215     if(resize_timer!=NULL){
216         timer_reset(resize_timer);
217         destroy_obj((Obj*)resize_timer);
218         resize_timer=NULL;
219     }
220 }
221
222
223 /*}}}*/
224
225
226 /*{{{ Misc. */
227
228
229 static int limit_and_encode_mode(int *left, int *right, 
230                                  int *top, int *bottom)
231 {
232     *left=sign(*left);
233     *right=sign(*right);
234     *top=sign(*top);
235     *bottom=sign(*bottom);
236
237     return (*left)+(*right)*3+(*top)*9+(*bottom)*27;
238 }
239
240
241 static void resize_units(WMoveresMode *mode, int *wret, int *hret)
242 {
243     WSizeHints *h=&(mode->hints);
244     *wret=1;
245     *hret=1;
246     if(h->inc_set && (h->width_inc>1 || h->height_inc>1)){
247         *wret=h->width_inc;
248         *hret=h->height_inc;
249     }
250 }
251
252
253 /*}}}*/
254
255
256 /*{{{ Keyboard resize interface */
257
258
259 /*EXTL_DOC
260  * Shrink or grow resize mode target one step in each direction.
261  * Acceptable values for the parameters \var{left}, \var{right}, \var{top}
262  * and \var{bottom} are as follows: -1: shrink along,
263  * 0: do not change, 1: grow along corresponding border.
264  */
265 EXTL_EXPORT_MEMBER
266 void moveresmode_resize(WMoveresMode *mode, 
267                         int left, int right, int top, int bottom)
268 {
269     int wu=0, hu=0;
270     int accel_mode=0;
271     
272     if(!setup_resize_timer(mode))
273         return;
274     
275     accel_mode=3*limit_and_encode_mode(&left, &right, &top, &bottom);
276     resize_units(mode, &wu, &hu);
277     moveresmode_accel(mode, &wu, &hu, accel_mode);
278
279     moveresmode_delta_resize(mode, -left*wu, right*wu, -top*hu, bottom*hu, 
280                              NULL);
281 }
282
283
284 /*EXTL_DOC
285  * Move resize mode target one step:
286  *
287  * \begin{tabular}{rl}
288  * \hline
289  * \var{horizmul}/\var{vertmul} & effect \\\hline
290  * -1 & Move left/up \\
291  * 0 & No effect \\
292  * 1 & Move right/down \\
293  * \end{tabular}
294  */
295 EXTL_EXPORT_MEMBER
296 void moveresmode_move(WMoveresMode *mode, int horizmul, int vertmul)
297 {
298     int accel_mode=0, dummy=0;
299
300     if(!setup_resize_timer(mode))
301         return;
302     
303     accel_mode=1+3*limit_and_encode_mode(&horizmul, &vertmul, &dummy, &dummy);
304     moveresmode_accel(mode, &horizmul, &vertmul, accel_mode);
305
306     moveresmode_delta_resize(mode, horizmul, horizmul, vertmul, vertmul, 
307                              NULL);
308 }
309
310
311 /*EXTL_DOC
312  * Request exact geometry in move/resize mode. For details on parameters,
313  * see \fnref{WRegion.rqgeom}.
314  */
315 EXTL_EXPORT_AS(WMoveresMode, rqgeom)
316 ExtlTab moveresmode_rqgeom_extl(WMoveresMode *mode, ExtlTab g)
317 {
318     WRQGeomParams rq=RQGEOMPARAMS_INIT;
319     WRectangle res;
320     
321     rqgeomparams_from_table(&rq, &mode->geom, g);
322     
323     moveresmode_rqgeom(mode, &rq, &res);
324     
325     return extl_table_from_rectangle(&res);
326 }
327
328 /*EXTL_DOC
329  * Returns current geometry.
330  */
331 EXTL_EXPORT_MEMBER
332 ExtlTab moveresmode_geom(WMoveresMode *mode)
333 {
334     return extl_table_from_rectangle(&mode->geom);
335 }
336
337
338 /*EXTL_DOC
339  * Return from move/resize mode and apply changes unless opaque
340  * move/resize is enabled.
341  */
342 EXTL_EXPORT_MEMBER
343 void moveresmode_finish(WMoveresMode *mode)
344 {
345     WRegion *reg=moveresmode_target(mode);
346     if(moveresmode_do_end(mode, TRUE)){
347         reset_resize_timer();
348         region_warp(reg);
349         ioncore_grab_remove(resize_handler);
350     }
351 }
352
353
354 /*EXTL_DOC
355  * Return from move/resize cancelling changes if opaque
356  * move/resize has not been enabled.
357  */
358 EXTL_EXPORT_MEMBER
359 void moveresmode_cancel(WMoveresMode *mode)
360 {
361     WRegion *reg=moveresmode_target(mode);
362     if(moveresmode_do_end(mode, FALSE)){
363         reset_resize_timer();
364         region_warp(reg);
365         ioncore_grab_remove(resize_handler);
366     }
367 }
368
369
370 static void cancel_moveres(WRegion *reg)
371 {
372     WMoveresMode *mode=moveres_mode(reg);
373     if(mode!=NULL)
374         moveresmode_cancel(mode);
375 }
376
377     
378 /*EXTL_DOC
379  * Enter move/resize mode for \var{reg}. The bindings set with
380  * \fnref{ioncore.set_bindings} for \type{WMoveresMode} are used in 
381  * this mode. Of the functions exported by the Ion C core, only
382  * \fnref{WMoveresMode.resize}, \fnref{WMoveresMode.move}, 
383  * \fnref{WMoveresMode.cancel} and \fnref{WMoveresMode.end} are
384  * allowed to be called while in this mode.
385  */
386 EXTL_EXPORT_MEMBER
387 WMoveresMode *region_begin_kbresize(WRegion *reg)
388 {
389     WMoveresMode *mode=region_begin_resize(reg, NULL, FALSE);
390
391     if(mode==NULL)
392         return NULL;
393     
394     if(!setup_resize_timer(mode))
395         return NULL;
396
397     accel_reset();
398     
399     ioncore_grab_establish(reg, resize_handler,
400                            (GrabKilledHandler*)cancel_moveres, 0);
401     
402     return mode;
403 }
404
405
406 /*}}}*/