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