2 * ion/ioncore/kbresize.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
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
;
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()
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
;
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;
94 #define SIGN_NZ(X) ((X) < 0 ? -1 : 1)
96 static double max(double a
, double b
)
101 void moveresmode_accel(WMoveresMode
*mode
, int *wu
, int *hu
, int accel_mode
)
106 if(mainloop_gettime(&tv
)!=0)
109 adiff
=tvdiffmsec(&tv
, &last_action_tv
);
110 udiff
=tvdiffmsec(&tv
, &last_update_tv
);
112 if(last_accel_mode
==accel_mode
&& adiff
<actmax
){
124 last_accel_mode
=accel_mode
;
128 *wu
=(*wu
)*ceil(sqrt(accel
)/abs(*wu
));
130 *hu
=(*hu
)*ceil(sqrt(accel
)/abs(*hu
));
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
,
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
;
160 if(ev
->type
==KeyRelease
)
166 mode
=moveres_mode(reg
);
171 binding
=bindmap_lookup_binding(ioncore_moveres_bindmap
,
173 ev
->state
, ev
->keycode
);
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
);
191 /*{{{ Resize timer */
194 static WTimer
*resize_timer
=NULL
;
197 static void tmr_end_resize(WTimer
*unused
, WMoveresMode
*mode
)
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
)
212 timer_set(resize_timer
, resize_delay
,
213 (WTimerHandler
*)tmr_end_resize
, (Obj
*)mode
);
219 static void reset_resize_timer()
221 if(resize_timer
!=NULL
){
222 timer_reset(resize_timer
);
223 destroy_obj((Obj
*)resize_timer
);
235 static int limit_and_encode_mode(int *left
, int *right
,
236 int *top
, int *bottom
)
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
);
252 if(h
->inc_set
&& (h
->width_inc
>1 || h
->height_inc
>1)){
262 /*{{{ Keyboard resize interface */
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.
272 void moveresmode_resize(WMoveresMode
*mode
,
273 int left
, int right
, int top
, int bottom
)
278 if(!setup_resize_timer(mode
))
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
,
291 * Move resize mode target one step:
293 * \begin{tabular}{rl}
295 * \var{horizmul}/\var{vertmul} & effect \\\hline
296 * -1 & Move left/up \\
298 * 1 & Move right/down \\
302 void moveresmode_move(WMoveresMode
*mode
, int horizmul
, int vertmul
)
304 int accel_mode
=0, dummy
=0;
306 if(!setup_resize_timer(mode
))
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
,
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
;
327 rqgeomparams_from_table(&rq
, &mode
->geom
, g
);
329 moveresmode_rqgeom(mode
, &rq
, &res
);
331 return extl_table_from_rectangle(&res
);
335 * Returns current geometry.
338 ExtlTab
moveresmode_geom(WMoveresMode
*mode
)
340 return extl_table_from_rectangle(&mode
->geom
);
345 * Return from move/resize mode and apply changes unless opaque
346 * move/resize is enabled.
349 void moveresmode_finish(WMoveresMode
*mode
)
351 WRegion
*reg
=moveresmode_target(mode
);
352 if(moveresmode_do_end(mode
, TRUE
)){
353 reset_resize_timer();
355 ioncore_grab_remove(resize_handler
);
361 * Return from move/resize cancelling changes if opaque
362 * move/resize has not been enabled.
365 void moveresmode_cancel(WMoveresMode
*mode
)
367 WRegion
*reg
=moveresmode_target(mode
);
368 if(moveresmode_do_end(mode
, FALSE
)){
369 reset_resize_timer();
371 ioncore_grab_remove(resize_handler
);
376 static void cancel_moveres(WRegion
*reg
)
378 WMoveresMode
*mode
=moveres_mode(reg
);
380 moveresmode_cancel(mode
);
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.
393 WMoveresMode
*region_begin_kbresize(WRegion
*reg
)
395 WMoveresMode
*mode
=region_begin_resize(reg
, NULL
, FALSE
);
400 if(!setup_resize_timer(mode
))
405 ioncore_grab_establish(reg
, resize_handler
,
406 (GrabKilledHandler
*)cancel_moveres
, 0);