Simple lua repl for testing
[notion.git] / ioncore / kbresize.c
blob99f908d696ff769ddbd663444fbe3b30501b56e5
1 /*
2 * ion/ioncore/kbresize.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <math.h>
10 #include <sys/time.h>
11 #include <time.h>
12 #include <limits.h>
14 #include <libtu/minmax.h>
16 #include <libmainloop/signal.h>
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"
27 /*{{{ Resize accelerator */
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;
40 static void accel_reset()
42 last_accel_mode=0;
43 accel=1.0;
44 last_action_tv.tv_sec=-1;
45 last_action_tv.tv_usec=-1;
49 void ioncore_set_moveres_accel(ExtlTab tab)
51 int t_max, t_min, rd, er;
52 double step, maxacc;
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);
69 void ioncore_get_moveres_accel(ExtlTab tab)
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);
80 static int sign(int x)
82 return (x>0 ? 1 : (x<0 ? -1 : 0));
86 static long tvdiffmsec(struct timeval *tv1, struct timeval *tv2)
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;
91 return (int)(t1-t2);
94 #define SIGN_NZ(X) ((X) < 0 ? -1 : 1)
96 static double max(double a, double b)
98 return (a<b ? b : a);
101 void moveresmode_accel(WMoveresMode *mode, int *wu, int *hu, int accel_mode)
103 struct timeval tv;
104 long adiff, udiff;
106 if(mainloop_gettime(&tv)!=0)
107 return;
109 adiff=tvdiffmsec(&tv, &last_action_tv);
110 udiff=tvdiffmsec(&tv, &last_update_tv);
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;
119 }else{
120 accel=1.0;
121 last_update_tv=tv;
124 last_accel_mode=accel_mode;
125 last_action_tv=tv;
127 if(*wu!=0)
128 *wu=(*wu)*ceil(sqrt(accel)/abs(*wu));
129 if(*hu!=0)
130 *hu=(*hu)*ceil(sqrt(accel)/abs(*hu));
134 /*}}}*/
137 /*{{{ Keyboard resize handler */
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
150 static ExtlSafelist moveres_safelist=EXTL_SAFELIST_INIT(moveres_safe_fns);
153 static bool resize_handler(WRegion *reg, XEvent *xev)
155 XKeyEvent *ev=&xev->xkey;
156 WBinding *binding=NULL;
157 WBindmap **bindptr;
158 WMoveresMode *mode;
160 if(ev->type==KeyRelease)
161 return FALSE;
163 if(reg==NULL)
164 return FALSE;
166 mode=moveres_mode(reg);
168 if(mode==NULL)
169 return FALSE;
171 binding=bindmap_lookup_binding(ioncore_moveres_bindmap,
172 BINDING_KEYPRESS,
173 ev->state, ev->keycode);
175 if(!binding)
176 return FALSE;
178 if(binding!=NULL){
179 extl_protect(&moveres_safelist);
180 extl_call(binding->func, "oo", NULL, mode, reg);
181 extl_unprotect(&moveres_safelist);
184 return (moveres_mode(reg)==NULL);
188 /*}}}*/
191 /*{{{ Resize timer */
194 static WTimer *resize_timer=NULL;
197 static void tmr_end_resize(WTimer *unused, WMoveresMode *mode)
199 if(mode!=NULL)
200 moveresmode_cancel(mode);
204 static bool setup_resize_timer(WMoveresMode *mode)
206 if(resize_timer==NULL){
207 resize_timer=create_timer();
208 if(resize_timer==NULL)
209 return FALSE;
212 timer_set(resize_timer, resize_delay,
213 (WTimerHandler*)tmr_end_resize, (Obj*)mode);
215 return TRUE;
219 static void reset_resize_timer()
221 if(resize_timer!=NULL){
222 timer_reset(resize_timer);
223 destroy_obj((Obj*)resize_timer);
224 resize_timer=NULL;
229 /*}}}*/
232 /*{{{ Misc. */
235 static int limit_and_encode_mode(int *left, int *right,
236 int *top, int *bottom)
238 *left=sign(*left);
239 *right=sign(*right);
240 *top=sign(*top);
241 *bottom=sign(*bottom);
243 return (*left)+(*right)*3+(*top)*9+(*bottom)*27;
247 static void resize_units(WMoveresMode *mode, int *wret, int *hret)
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;
259 /*}}}*/
262 /*{{{ Keyboard resize interface */
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.
271 EXTL_EXPORT_MEMBER
272 void moveresmode_resize(WMoveresMode *mode,
273 int left, int right, int top, int bottom)
275 int wu=0, hu=0;
276 int accel_mode=0;
278 if(!setup_resize_timer(mode))
279 return;
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);
285 moveresmode_delta_resize(mode, -left*wu, right*wu, -top*hu, bottom*hu,
286 NULL);
290 /*EXTL_DOC
291 * Move resize mode target one step:
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}
301 EXTL_EXPORT_MEMBER
302 void moveresmode_move(WMoveresMode *mode, int horizmul, int vertmul)
304 int accel_mode=0, dummy=0;
306 if(!setup_resize_timer(mode))
307 return;
309 accel_mode=1+3*limit_and_encode_mode(&horizmul, &vertmul, &dummy, &dummy);
310 moveresmode_accel(mode, &horizmul, &vertmul, accel_mode);
312 moveresmode_delta_resize(mode, horizmul, horizmul, vertmul, vertmul,
313 NULL);
317 /*EXTL_DOC
318 * Request exact geometry in move/resize mode. For details on parameters,
319 * see \fnref{WRegion.rqgeom}.
321 EXTL_EXPORT_AS(WMoveresMode, rqgeom)
322 ExtlTab moveresmode_rqgeom_extl(WMoveresMode *mode, ExtlTab g)
324 WRQGeomParams rq=RQGEOMPARAMS_INIT;
325 WRectangle res;
327 rqgeomparams_from_table(&rq, &mode->geom, g);
329 moveresmode_rqgeom(mode, &rq, &res);
331 return extl_table_from_rectangle(&res);
334 /*EXTL_DOC
335 * Returns current geometry.
337 EXTL_EXPORT_MEMBER
338 ExtlTab moveresmode_geom(WMoveresMode *mode)
340 return extl_table_from_rectangle(&mode->geom);
344 /*EXTL_DOC
345 * Return from move/resize mode and apply changes unless opaque
346 * move/resize is enabled.
348 EXTL_EXPORT_MEMBER
349 void moveresmode_finish(WMoveresMode *mode)
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);
360 /*EXTL_DOC
361 * Return from move/resize cancelling changes if opaque
362 * move/resize has not been enabled.
364 EXTL_EXPORT_MEMBER
365 void moveresmode_cancel(WMoveresMode *mode)
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);
376 static void cancel_moveres(WRegion *reg)
378 WMoveresMode *mode=moveres_mode(reg);
379 if(mode!=NULL)
380 moveresmode_cancel(mode);
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.
392 EXTL_EXPORT_MEMBER
393 WMoveresMode *region_begin_kbresize(WRegion *reg)
395 WMoveresMode *mode=region_begin_resize(reg, NULL, FALSE);
397 if(mode==NULL)
398 return NULL;
400 if(!setup_resize_timer(mode))
401 return NULL;
403 accel_reset();
405 ioncore_grab_establish(reg, resize_handler,
406 (GrabKilledHandler*)cancel_moveres, 0);
408 return mode;
412 /*}}}*/