ion->notion
[notion/jeffpc.git] / ioncore / frame-pointer.c
blob6340dd0d2ccfebdd692bcf999bce243f46565ab6
1 /*
2 * ion/ioncore/frame-pointer.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <string.h>
11 #include <libtu/objp.h>
13 #include "common.h"
14 #include "global.h"
15 #include "pointer.h"
16 #include "cursor.h"
17 #include "focus.h"
18 #include "attach.h"
19 #include "resize.h"
20 #include "grab.h"
21 #include "frame.h"
22 #include "framep.h"
23 #include "frame-pointer.h"
24 #include "frame-draw.h"
25 #include "bindmaps.h"
26 #include "infowin.h"
27 #include "rectangle.h"
28 #include "xwindow.h"
29 #include "names.h"
30 #include "presize.h"
31 #include "llist.h"
34 static int p_tab_x=0, p_tab_y=0, p_tabnum=-1;
35 static WInfoWin *tabdrag_infowin=NULL;
38 /*{{{ Frame press */
41 static WRegion *sub_at_tab(WFrame *frame)
43 return mplex_mx_nth((WMPlex*)frame, p_tabnum);
47 int frame_press(WFrame *frame, XButtonEvent *ev, WRegion **reg_ret)
49 WRegion *sub=NULL;
50 WRectangle g;
52 p_tabnum=-1;
54 window_p_resize_prepare((WWindow*)frame, ev);
56 /* Check tab */
58 frame_bar_geom(frame, &g);
60 /* Borders act like tabs at top of the parent region */
61 if(REGION_GEOM(frame).y==0){
62 g.h+=g.y;
63 g.y=0;
66 if(frame->barmode!=FRAME_BAR_NONE &&
67 rectangle_contains(&g, ev->x, ev->y)){
68 p_tabnum=frame_tab_at_x(frame, ev->x);
70 region_rootpos((WRegion*)frame, &p_tab_x, &p_tab_y);
71 p_tab_x+=frame_nth_tab_x(frame, p_tabnum);
72 p_tab_y+=g.y;
74 sub=mplex_mx_nth(&(frame->mplex), p_tabnum);
76 if(reg_ret!=NULL)
77 *reg_ret=sub;
79 return FRAME_AREA_TAB;
80 }else{
81 WLListIterTmp tmp;
82 FRAME_MX_FOR_ALL(sub, frame, tmp){
83 p_tabnum++;
84 if(sub==FRAME_CURRENT(frame))
85 break;
88 if(sub!=NULL){
89 p_tab_x=ev->x_root-frame_nth_tab_w(frame, p_tabnum)/2;
90 p_tab_y=ev->y_root-frame->bar_h/2;
91 }else{
92 p_tabnum=-1;
97 /* Check border */
99 frame_border_inner_geom(frame, &g);
101 if(rectangle_contains(&g, ev->x, ev->y))
102 return FRAME_AREA_CLIENT;
104 return FRAME_AREA_BORDER;
108 /*}}}*/
111 /*{{{ Tab drag */
114 static ExtlExportedFn *tabdrag_safe_fns[]={
115 (ExtlExportedFn*)&mplex_switch_nth,
116 (ExtlExportedFn*)&mplex_switch_next,
117 (ExtlExportedFn*)&mplex_switch_prev,
118 NULL
121 static ExtlSafelist tabdrag_safelist=EXTL_SAFELIST_INIT(tabdrag_safe_fns);
124 #define BUTTONS_MASK \
125 (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)
128 static bool tabdrag_kbd_handler(WRegion *reg, XEvent *xev)
130 XKeyEvent *ev=&xev->xkey;
131 WBinding *binding=NULL;
132 WBindmap **bindptr;
134 if(ev->type==KeyRelease)
135 return FALSE;
137 assert(reg!=NULL);
139 binding=bindmap_lookup_binding(ioncore_screen_bindmap, BINDING_KEYPRESS,
140 ev->state&~BUTTONS_MASK, ev->keycode);
142 if(binding!=NULL && binding->func!=extl_fn_none()){
143 extl_protect(&tabdrag_safelist);
144 extl_call(binding->func, "o", NULL, region_screen_of(reg));
145 extl_unprotect(&tabdrag_safelist);
148 return FALSE;
152 static void setup_dragwin(WFrame *frame, uint tab)
154 WRectangle g;
155 WRootWin *rw;
156 WFitParams fp;
157 const char *tab_style=framemode_get_tab_style(frame->mode);
159 assert(tabdrag_infowin==NULL);
161 rw=region_rootwin_of((WRegion*)frame);
163 fp.mode=REGION_FIT_EXACT;
164 fp.g.x=p_tab_x;
165 fp.g.y=p_tab_y;
166 fp.g.w=frame_nth_tab_w(frame, tab);
167 fp.g.h=frame->bar_h;
169 tabdrag_infowin=create_infowin((WWindow*)rw, &fp, tab_style);
171 if(tabdrag_infowin==NULL)
172 return;
174 frame_setup_dragwin_style(frame, infowin_stylespec(tabdrag_infowin), tab);
176 if(frame->titles[tab].text!=NULL){
177 char *buf=INFOWIN_BUFFER(tabdrag_infowin);
178 strncpy(buf, frame->titles[tab].text, INFOWIN_BUFFER_LEN-1);
179 buf[INFOWIN_BUFFER_LEN-1]='\0';
184 static void p_tabdrag_motion(WFrame *frame, XMotionEvent *ev,
185 int dx, int dy)
187 WRootWin *rootwin=region_rootwin_of((WRegion*)frame);
189 p_tab_x+=dx;
190 p_tab_y+=dy;
192 if(tabdrag_infowin!=NULL){
193 WRectangle g;
194 g.x=p_tab_x;
195 g.y=p_tab_y;
196 g.w=REGION_GEOM(tabdrag_infowin).w;
197 g.h=REGION_GEOM(tabdrag_infowin).h;
198 region_fit((WRegion*)tabdrag_infowin, &g, REGION_FIT_EXACT);
203 static void p_tabdrag_begin(WFrame *frame, XMotionEvent *ev,
204 int dx, int dy)
206 WRootWin *rootwin=region_rootwin_of((WRegion*)frame);
208 if(p_tabnum<0)
209 return;
211 ioncore_change_grab_cursor(IONCORE_CURSOR_DRAG);
213 setup_dragwin(frame, p_tabnum);
215 frame->tab_dragged_idx=p_tabnum;
216 frame_update_attr_nth(frame, p_tabnum);
218 frame_draw_bar(frame, FALSE);
220 p_tabdrag_motion(frame, ev, dx, dy);
222 if(tabdrag_infowin!=NULL)
223 window_map((WWindow*)tabdrag_infowin);
227 static WRegion *fnd(Window root, int x, int y)
229 Window win=root;
230 int dstx, dsty;
231 WRegion *reg=NULL;
232 WWindow *w=NULL;
233 WScreen *scr;
235 FOR_ALL_SCREENS(scr){
236 if(region_root_of((WRegion*)scr)==root &&
237 rectangle_contains(&REGION_GEOM(scr), x, y)){
238 break;
242 w=(WWindow*)scr;
244 while(w!=NULL){
245 if(HAS_DYN(w, region_handle_drop))
246 reg=(WRegion*)w;
248 if(!XTranslateCoordinates(ioncore_g.dpy, root, w->win,
249 x, y, &dstx, &dsty, &win)){
250 break;
253 w=XWINDOW_REGION_OF_T(win, WWindow);
254 /*x=dstx;
255 y=dsty;*/
258 return reg;
262 static bool drop_ok(WRegion *mgr, WRegion *reg)
264 WRegion *reg2=mgr;
265 for(reg2=mgr; reg2!=NULL; reg2=region_manager(reg2)){
266 if(reg2==reg)
267 goto err;
270 for(reg2=REGION_PARENT_REG(mgr); reg2!=NULL; reg2=REGION_PARENT_REG(reg2)){
271 if(reg2==reg)
272 goto err;
275 return TRUE;
277 err:
278 warn(TR("Attempt to make region %s manage its ancestor %s."),
279 region_name(mgr), region_name(reg));
280 return FALSE;
284 static void tabdrag_deinit(WFrame *frame)
286 int idx=frame->tab_dragged_idx;
287 frame->tab_dragged_idx=-1;
288 frame_update_attr_nth(frame, idx);
290 if(tabdrag_infowin!=NULL){
291 destroy_obj((Obj*)tabdrag_infowin);
292 tabdrag_infowin=NULL;
297 static void tabdrag_killed(WFrame *frame)
299 tabdrag_deinit(frame);
300 if(!OBJ_IS_BEING_DESTROYED(frame))
301 frame_draw_bar(frame, TRUE);
305 static void p_tabdrag_end(WFrame *frame, XButtonEvent *ev)
307 WRegion *sub=NULL;
308 WRegion *dropped_on;
309 Window win=None;
311 sub=sub_at_tab(frame);
313 tabdrag_deinit(frame);
315 /* Must be same root window */
316 if(sub==NULL || ev->root!=region_root_of(sub))
317 return;
319 dropped_on=fnd(ev->root, ev->x_root, ev->y_root);
321 if(dropped_on==NULL || dropped_on==(WRegion*)frame ||
322 dropped_on==sub || !drop_ok(dropped_on, sub)){
323 frame_draw_bar(frame, TRUE);
324 return;
327 if(region_handle_drop(dropped_on, p_tab_x, p_tab_y, sub))
328 region_goto(dropped_on);
329 else
330 frame_draw_bar(frame, TRUE);
334 /*EXTL_DOC
335 * Start dragging the tab that the user pressed on with the pointing device.
336 * This function should only be used by binding it to \emph{mpress} or
337 * \emph{mdrag} action with area \codestr{tab}.
339 EXTL_EXPORT_MEMBER
340 void frame_p_tabdrag(WFrame *frame)
342 if(p_tabnum<0)
343 return;
345 ioncore_set_drag_handlers((WRegion*)frame,
346 (WMotionHandler*)p_tabdrag_begin,
347 (WMotionHandler*)p_tabdrag_motion,
348 (WButtonHandler*)p_tabdrag_end,
349 tabdrag_kbd_handler,
350 (GrabKilledHandler*)tabdrag_killed);
354 /*}}}*/
357 /*{{{ switch_tab */
360 /*EXTL_DOC
361 * Display the region corresponding to the tab that the user pressed on.
362 * This function should only be used by binding it to a mouse action.
364 EXTL_EXPORT_MEMBER
365 void frame_p_switch_tab(WFrame *frame)
367 /*WRegion *sub;*/
369 if(ioncore_pointer_grab_region()!=(WRegion*)frame)
370 return;
373 sub=sub_at_tab(frame);
374 if(sub!=NULL){
375 bool mcf=region_may_control_focus((WRegion*)frame);
376 region_goto_flags(sub, (mcf
377 ? REGION_GOTO_FOCUS|REGION_GOTO_NOWARP
378 : 0));
382 mplex_switch_nth((WMPlex*)frame, p_tabnum);
386 /*}}}*/