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 gettimeofday(&tv, NULL);
103 adiff=tvdiffmsec(&tv, &last_action_tv);
104 udiff=tvdiffmsec(&tv, &last_update_tv);
106 if(last_accel_mode==accel_mode && adiff<actmax){
118 last_accel_mode=accel_mode;
122 *wu=(*wu)*ceil(sqrt(accel)/abs(*wu));
124 *hu=(*hu)*ceil(sqrt(accel)/abs(*hu));
131 /*{{{ Keyboard resize handler */
134 static ExtlExportedFn *moveres_safe_fns[]={
135 (ExtlExportedFn*)&moveresmode_resize,
136 (ExtlExportedFn*)&moveresmode_move,
137 (ExtlExportedFn*)&moveresmode_rqgeom_extl,
138 (ExtlExportedFn*)&moveresmode_geom,
139 (ExtlExportedFn*)&moveresmode_finish,
140 (ExtlExportedFn*)&moveresmode_cancel,
144 static ExtlSafelist moveres_safelist=EXTL_SAFELIST_INIT(moveres_safe_fns);
147 static bool resize_handler(WRegion *reg, XEvent *xev)
149 XKeyEvent *ev=&xev->xkey;
150 WBinding *binding=NULL;
154 if(ev->type==KeyRelease)
160 mode=moveres_mode(reg);
165 binding=bindmap_lookup_binding(ioncore_moveres_bindmap,
167 ev->state, ev->keycode);
173 extl_protect(&moveres_safelist);
174 extl_call(binding->func, "oo", NULL, mode, reg);
175 extl_unprotect(&moveres_safelist);
178 return (moveres_mode(reg)==NULL);
185 /*{{{ Resize timer */
188 static WTimer *resize_timer=NULL;
191 static void tmr_end_resize(WTimer *unused, WMoveresMode *mode)
194 moveresmode_cancel(mode);
198 static bool setup_resize_timer(WMoveresMode *mode)
200 if(resize_timer==NULL){
201 resize_timer=create_timer();
202 if(resize_timer==NULL)
206 timer_set(resize_timer, resize_delay,
207 (WTimerHandler*)tmr_end_resize, (Obj*)mode);
213 static void reset_resize_timer()
215 if(resize_timer!=NULL){
216 timer_reset(resize_timer);
217 destroy_obj((Obj*)resize_timer);
229 static int limit_and_encode_mode(int *left, int *right,
230 int *top, int *bottom)
235 *bottom=sign(*bottom);
237 return (*left)+(*right)*3+(*top)*9+(*bottom)*27;
241 static void resize_units(WMoveresMode *mode, int *wret, int *hret)
243 WSizeHints *h=&(mode->hints);
246 if(h->inc_set && (h->width_inc>1 || h->height_inc>1)){
256 /*{{{ Keyboard resize interface */
260 * Shrink or grow resize mode target one step in each direction.
261 * Acceptable values for the parameters \var{left}, \var{right}, \var{top}
262 * and \var{bottom} are as follows: -1: shrink along,
263 * 0: do not change, 1: grow along corresponding border.
266 void moveresmode_resize(WMoveresMode *mode,
267 int left, int right, int top, int bottom)
272 if(!setup_resize_timer(mode))
275 accel_mode=3*limit_and_encode_mode(&left, &right, &top, &bottom);
276 resize_units(mode, &wu, &hu);
277 moveresmode_accel(mode, &wu, &hu, accel_mode);
279 moveresmode_delta_resize(mode, -left*wu, right*wu, -top*hu, bottom*hu,
285 * Move resize mode target one step:
287 * \begin{tabular}{rl}
289 * \var{horizmul}/\var{vertmul} & effect \\\hline
290 * -1 & Move left/up \\
292 * 1 & Move right/down \\
296 void moveresmode_move(WMoveresMode *mode, int horizmul, int vertmul)
298 int accel_mode=0, dummy=0;
300 if(!setup_resize_timer(mode))
303 accel_mode=1+3*limit_and_encode_mode(&horizmul, &vertmul, &dummy, &dummy);
304 moveresmode_accel(mode, &horizmul, &vertmul, accel_mode);
306 moveresmode_delta_resize(mode, horizmul, horizmul, vertmul, vertmul,
312 * Request exact geometry in move/resize mode. For details on parameters,
313 * see \fnref{WRegion.rqgeom}.
315 EXTL_EXPORT_AS(WMoveresMode, rqgeom)
316 ExtlTab moveresmode_rqgeom_extl(WMoveresMode *mode, ExtlTab g)
318 WRQGeomParams rq=RQGEOMPARAMS_INIT;
321 rqgeomparams_from_table(&rq, &mode->geom, g);
323 moveresmode_rqgeom(mode, &rq, &res);
325 return extl_table_from_rectangle(&res);
329 * Returns current geometry.
332 ExtlTab moveresmode_geom(WMoveresMode *mode)
334 return extl_table_from_rectangle(&mode->geom);
339 * Return from move/resize mode and apply changes unless opaque
340 * move/resize is enabled.
343 void moveresmode_finish(WMoveresMode *mode)
345 WRegion *reg=moveresmode_target(mode);
346 if(moveresmode_do_end(mode, TRUE)){
347 reset_resize_timer();
349 ioncore_grab_remove(resize_handler);
355 * Return from move/resize cancelling changes if opaque
356 * move/resize has not been enabled.
359 void moveresmode_cancel(WMoveresMode *mode)
361 WRegion *reg=moveresmode_target(mode);
362 if(moveresmode_do_end(mode, FALSE)){
363 reset_resize_timer();
365 ioncore_grab_remove(resize_handler);
370 static void cancel_moveres(WRegion *reg)
372 WMoveresMode *mode=moveres_mode(reg);
374 moveresmode_cancel(mode);
379 * Enter move/resize mode for \var{reg}. The bindings set with
380 * \fnref{ioncore.set_bindings} for \type{WMoveresMode} are used in
381 * this mode. Of the functions exported by the Ion C core, only
382 * \fnref{WMoveresMode.resize}, \fnref{WMoveresMode.move},
383 * \fnref{WMoveresMode.cancel} and \fnref{WMoveresMode.end} are
384 * allowed to be called while in this mode.
387 WMoveresMode *region_begin_kbresize(WRegion *reg)
389 WMoveresMode *mode=region_begin_resize(reg, NULL, FALSE);
394 if(!setup_resize_timer(mode))
399 ioncore_grab_establish(reg, resize_handler,
400 (GrabKilledHandler*)cancel_moveres, 0);