2 * ion/ioncore/kbresize.c
4 * Copyright (c) Tuomo Valkonen 1999-2007.
6 * See the included file LICENSE for details.
14 #include <libtu/minmax.h>
16 #include <libmainloop/signal.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;
38 static void accel_reset()
42 last_action_tv.tv_sec=-1;
43 last_action_tv.tv_usec=-1;
47 void ioncore_set_moveres_accel(ExtlTab tab)
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);
65 void ioncore_get_moveres_accel(ExtlTab tab)
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);
75 static int sign(int x)
77 return (x>0 ? 1 : (x<0 ? -1 : 0));
81 static long tvdiffmsec(struct timeval *tv1, struct timeval *tv2)
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;
89 #define SIGN_NZ(X) ((X) < 0 ? -1 : 1)
91 static double max(double a, double b)
96 void moveresmode_accel(WMoveresMode *mode, int *wu, int *hu, int accel_mode)
101 if(mainloop_gettime(&tv)!=0)
104 adiff=tvdiffmsec(&tv, &last_action_tv);
105 udiff=tvdiffmsec(&tv, &last_update_tv);
107 if(last_accel_mode==accel_mode && adiff<actmax){
119 last_accel_mode=accel_mode;
123 *wu=(*wu)*ceil(sqrt(accel)/abs(*wu));
125 *hu=(*hu)*ceil(sqrt(accel)/abs(*hu));
132 /*{{{ Keyboard resize handler */
135 static ExtlExportedFn *moveres_safe_fns[]={
136 (ExtlExportedFn*)&moveresmode_resize,
137 (ExtlExportedFn*)&moveresmode_move,
138 (ExtlExportedFn*)&moveresmode_rqgeom_extl,
139 (ExtlExportedFn*)&moveresmode_geom,
140 (ExtlExportedFn*)&moveresmode_finish,
141 (ExtlExportedFn*)&moveresmode_cancel,
145 static ExtlSafelist moveres_safelist=EXTL_SAFELIST_INIT(moveres_safe_fns);
148 static bool resize_handler(WRegion *reg, XEvent *xev)
150 XKeyEvent *ev=&xev->xkey;
151 WBinding *binding=NULL;
155 if(ev->type==KeyRelease)
161 mode=moveres_mode(reg);
166 binding=bindmap_lookup_binding(ioncore_moveres_bindmap,
168 ev->state, ev->keycode);
174 extl_protect(&moveres_safelist);
175 extl_call(binding->func, "oo", NULL, mode, reg);
176 extl_unprotect(&moveres_safelist);
179 return (moveres_mode(reg)==NULL);
186 /*{{{ Resize timer */
189 static WTimer *resize_timer=NULL;
192 static void tmr_end_resize(WTimer *unused, WMoveresMode *mode)
195 moveresmode_cancel(mode);
199 static bool setup_resize_timer(WMoveresMode *mode)
201 if(resize_timer==NULL){
202 resize_timer=create_timer();
203 if(resize_timer==NULL)
207 timer_set(resize_timer, resize_delay,
208 (WTimerHandler*)tmr_end_resize, (Obj*)mode);
214 static void reset_resize_timer()
216 if(resize_timer!=NULL){
217 timer_reset(resize_timer);
218 destroy_obj((Obj*)resize_timer);
230 static int limit_and_encode_mode(int *left, int *right,
231 int *top, int *bottom)
236 *bottom=sign(*bottom);
238 return (*left)+(*right)*3+(*top)*9+(*bottom)*27;
242 static void resize_units(WMoveresMode *mode, int *wret, int *hret)
244 WSizeHints *h=&(mode->hints);
247 if(h->inc_set && (h->width_inc>1 || h->height_inc>1)){
257 /*{{{ Keyboard resize interface */
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.
267 void moveresmode_resize(WMoveresMode *mode,
268 int left, int right, int top, int bottom)
273 if(!setup_resize_timer(mode))
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);
280 moveresmode_delta_resize(mode, -left*wu, right*wu, -top*hu, bottom*hu,
286 * Move resize mode target one step:
288 * \begin{tabular}{rl}
290 * \var{horizmul}/\var{vertmul} & effect \\\hline
291 * -1 & Move left/up \\
293 * 1 & Move right/down \\
297 void moveresmode_move(WMoveresMode *mode, int horizmul, int vertmul)
299 int accel_mode=0, dummy=0;
301 if(!setup_resize_timer(mode))
304 accel_mode=1+3*limit_and_encode_mode(&horizmul, &vertmul, &dummy, &dummy);
305 moveresmode_accel(mode, &horizmul, &vertmul, accel_mode);
307 moveresmode_delta_resize(mode, horizmul, horizmul, vertmul, vertmul,
313 * Request exact geometry in move/resize mode. For details on parameters,
314 * see \fnref{WRegion.rqgeom}.
316 EXTL_EXPORT_AS(WMoveresMode, rqgeom)
317 ExtlTab moveresmode_rqgeom_extl(WMoveresMode *mode, ExtlTab g)
319 WRQGeomParams rq=RQGEOMPARAMS_INIT;
322 rqgeomparams_from_table(&rq, &mode->geom, g);
324 moveresmode_rqgeom(mode, &rq, &res);
326 return extl_table_from_rectangle(&res);
330 * Returns current geometry.
333 ExtlTab moveresmode_geom(WMoveresMode *mode)
335 return extl_table_from_rectangle(&mode->geom);
340 * Return from move/resize mode and apply changes unless opaque
341 * move/resize is enabled.
344 void moveresmode_finish(WMoveresMode *mode)
346 WRegion *reg=moveresmode_target(mode);
347 if(moveresmode_do_end(mode, TRUE)){
348 reset_resize_timer();
350 ioncore_grab_remove(resize_handler);
356 * Return from move/resize cancelling changes if opaque
357 * move/resize has not been enabled.
360 void moveresmode_cancel(WMoveresMode *mode)
362 WRegion *reg=moveresmode_target(mode);
363 if(moveresmode_do_end(mode, FALSE)){
364 reset_resize_timer();
366 ioncore_grab_remove(resize_handler);
371 static void cancel_moveres(WRegion *reg)
373 WMoveresMode *mode=moveres_mode(reg);
375 moveresmode_cancel(mode);
380 * Enter move/resize mode for \var{reg}. The bindings set with
381 * \fnref{ioncore.set_bindings} for \type{WMoveresMode} are used in
382 * this mode. Of the functions exported by the Ion C core, only
383 * \fnref{WMoveresMode.resize}, \fnref{WMoveresMode.move},
384 * \fnref{WMoveresMode.cancel} and \fnref{WMoveresMode.end} are
385 * allowed to be called while in this mode.
388 WMoveresMode *region_begin_kbresize(WRegion *reg)
390 WMoveresMode *mode=region_begin_resize(reg, NULL, FALSE);
395 if(!setup_resize_timer(mode))
400 ioncore_grab_establish(reg, resize_handler,
401 (GrabKilledHandler*)cancel_moveres, 0);