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_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 * Return from move/resize mode and apply changes unless opaque
314 * move/resize is enabled.
317 void moveresmode_finish(WMoveresMode *mode)
319 WRegion *reg=moveresmode_target(mode);
320 if(moveresmode_do_end(mode, TRUE)){
321 reset_resize_timer();
323 ioncore_grab_remove(resize_handler);
329 * Return from move/resize cancelling changes if opaque
330 * move/resize has not been enabled.
333 void moveresmode_cancel(WMoveresMode *mode)
335 WRegion *reg=moveresmode_target(mode);
336 if(moveresmode_do_end(mode, FALSE)){
337 reset_resize_timer();
339 ioncore_grab_remove(resize_handler);
344 static void cancel_moveres(WRegion *reg)
346 WMoveresMode *mode=moveres_mode(reg);
348 moveresmode_cancel(mode);
353 * Enter move/resize mode for \var{reg}. The bindings set with
354 * \fnref{ioncore.set_bindings} for \type{WMoveresMode} are used in
355 * this mode. Of the functions exported by the Ion C core, only
356 * \fnref{WMoveresMode.resize}, \fnref{WMoveresMode.move},
357 * \fnref{WMoveresMode.cancel} and \fnref{WMoveresMode.end} are
358 * allowed to be called while in this mode.
361 WMoveresMode *region_begin_kbresize(WRegion *reg)
363 WMoveresMode *mode=region_begin_resize(reg, NULL, FALSE);
368 if(!setup_resize_timer(mode))
373 ioncore_grab_establish(reg, resize_handler,
374 (GrabKilledHandler*)cancel_moveres, 0);