2 * ion/ioncore/kbresize.c
4 * Copyright (c) Tuomo Valkonen 1999-2007.
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.
17 #include <libtu/minmax.h>
19 #include <libmainloop/signal.h>
30 /*{{{ Resize accelerator */
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;
41 static void accel_reset()
45 last_action_tv.tv_sec=-1;
46 last_action_tv.tv_usec=-1;
50 void ioncore_set_moveres_accel(ExtlTab tab)
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);
68 void ioncore_get_moveres_accel(ExtlTab tab)
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);
78 static int sign(int x)
80 return (x>0 ? 1 : (x<0 ? -1 : 0));
84 static long tvdiffmsec(struct timeval *tv1, struct timeval *tv2)
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;
92 #define SIGN_NZ(X) ((X) < 0 ? -1 : 1)
94 static double max(double a, double b)
99 void moveresmode_accel(WMoveresMode *mode, int *wu, int *hu, int accel_mode)
104 gettimeofday(&tv, NULL);
106 adiff=tvdiffmsec(&tv, &last_action_tv);
107 udiff=tvdiffmsec(&tv, &last_update_tv);
109 if(last_accel_mode==accel_mode && adiff<actmax){
121 last_accel_mode=accel_mode;
125 *wu=(*wu)*ceil(sqrt(accel)/abs(*wu));
127 *hu=(*hu)*ceil(sqrt(accel)/abs(*hu));
134 /*{{{ Keyboard resize handler */
137 static ExtlExportedFn *moveres_safe_fns[]={
138 (ExtlExportedFn*)&moveresmode_resize,
139 (ExtlExportedFn*)&moveresmode_move,
140 (ExtlExportedFn*)&moveresmode_rqgeom_extl,
141 (ExtlExportedFn*)&moveresmode_geom,
142 (ExtlExportedFn*)&moveresmode_finish,
143 (ExtlExportedFn*)&moveresmode_cancel,
147 static ExtlSafelist moveres_safelist=EXTL_SAFELIST_INIT(moveres_safe_fns);
150 static bool resize_handler(WRegion *reg, XEvent *xev)
152 XKeyEvent *ev=&xev->xkey;
153 WBinding *binding=NULL;
157 if(ev->type==KeyRelease)
163 mode=moveres_mode(reg);
168 binding=bindmap_lookup_binding(ioncore_moveres_bindmap,
170 ev->state, ev->keycode);
176 extl_protect(&moveres_safelist);
177 extl_call(binding->func, "oo", NULL, mode, reg);
178 extl_unprotect(&moveres_safelist);
181 return (moveres_mode(reg)==NULL);
188 /*{{{ Resize timer */
191 static WTimer *resize_timer=NULL;
194 static void tmr_end_resize(WTimer *unused, WMoveresMode *mode)
197 moveresmode_cancel(mode);
201 static bool setup_resize_timer(WMoveresMode *mode)
203 if(resize_timer==NULL){
204 resize_timer=create_timer();
205 if(resize_timer==NULL)
209 timer_set(resize_timer, resize_delay,
210 (WTimerHandler*)tmr_end_resize, (Obj*)mode);
216 static void reset_resize_timer()
218 if(resize_timer!=NULL){
219 timer_reset(resize_timer);
220 destroy_obj((Obj*)resize_timer);
232 static int limit_and_encode_mode(int *left, int *right,
233 int *top, int *bottom)
238 *bottom=sign(*bottom);
240 return (*left)+(*right)*3+(*top)*9+(*bottom)*27;
244 static void resize_units(WMoveresMode *mode, int *wret, int *hret)
246 WSizeHints *h=&(mode->hints);
249 if(h->inc_set && (h->width_inc>1 || h->height_inc>1)){
259 /*{{{ Keyboard resize interface */
263 * Shrink or grow resize mode target one step in each direction.
264 * Acceptable values for the parameters \var{left}, \var{right}, \var{top}
265 * and \var{bottom} are as follows: -1: shrink along,
266 * 0: do not change, 1: grow along corresponding border.
269 void moveresmode_resize(WMoveresMode *mode,
270 int left, int right, int top, int bottom)
275 if(!setup_resize_timer(mode))
278 accel_mode=3*limit_and_encode_mode(&left, &right, &top, &bottom);
279 resize_units(mode, &wu, &hu);
280 moveresmode_accel(mode, &wu, &hu, accel_mode);
282 moveresmode_delta_resize(mode, -left*wu, right*wu, -top*hu, bottom*hu,
288 * Move resize mode target one step:
290 * \begin{tabular}{rl}
292 * \var{horizmul}/\var{vertmul} & effect \\\hline
293 * -1 & Move left/up \\
295 * 1 & Move right/down \\
299 void moveresmode_move(WMoveresMode *mode, int horizmul, int vertmul)
301 int accel_mode=0, dummy=0;
303 if(!setup_resize_timer(mode))
306 accel_mode=1+3*limit_and_encode_mode(&horizmul, &vertmul, &dummy, &dummy);
307 moveresmode_accel(mode, &horizmul, &vertmul, accel_mode);
309 moveresmode_delta_resize(mode, horizmul, horizmul, vertmul, vertmul,
315 * Request exact geometry in move/resize mode. For details on parameters,
316 * see \fnref{WRegion.rqgeom}.
318 EXTL_EXPORT_AS(WMoveresMode, rqgeom)
319 ExtlTab moveresmode_rqgeom_extl(WMoveresMode *mode, ExtlTab g)
321 WRQGeomParams rq=RQGEOMPARAMS_INIT;
324 rqgeomparams_from_table(&rq, &mode->geom, g);
326 moveresmode_rqgeom(mode, &rq, &res);
328 return extl_table_from_rectangle(&res);
332 * Returns current geometry.
335 ExtlTab moveresmode_geom(WMoveresMode *mode)
337 return extl_table_from_rectangle(&mode->geom);
342 * Return from move/resize mode and apply changes unless opaque
343 * move/resize is enabled.
346 void moveresmode_finish(WMoveresMode *mode)
348 WRegion *reg=moveresmode_target(mode);
349 if(moveresmode_do_end(mode, TRUE)){
350 reset_resize_timer();
352 ioncore_grab_remove(resize_handler);
358 * Return from move/resize cancelling changes if opaque
359 * move/resize has not been enabled.
362 void moveresmode_cancel(WMoveresMode *mode)
364 WRegion *reg=moveresmode_target(mode);
365 if(moveresmode_do_end(mode, FALSE)){
366 reset_resize_timer();
368 ioncore_grab_remove(resize_handler);
373 static void cancel_moveres(WRegion *reg)
375 WMoveresMode *mode=moveres_mode(reg);
377 moveresmode_cancel(mode);
382 * Enter move/resize mode for \var{reg}. The bindings set with
383 * \fnref{ioncore.set_bindings} for \type{WMoveresMode} are used in
384 * this mode. Of the functions exported by the Ion C core, only
385 * \fnref{WMoveresMode.resize}, \fnref{WMoveresMode.move},
386 * \fnref{WMoveresMode.cancel} and \fnref{WMoveresMode.end} are
387 * allowed to be called while in this mode.
390 WMoveresMode *region_begin_kbresize(WRegion *reg)
392 WMoveresMode *mode=region_begin_resize(reg, NULL, FALSE);
397 if(!setup_resize_timer(mode))
402 ioncore_grab_establish(reg, resize_handler,
403 (GrabKilledHandler*)cancel_moveres, 0);