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