2 * ion/ioncore/frame-pointer.c
4 * Copyright (c) Tuomo Valkonen 1999-2006.
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.
14 #include <libtu/objp.h>
26 #include "frame-pointer.h"
27 #include "frame-draw.h"
30 #include "rectangle.h"
37 static int p_tab_x=0, p_tab_y=0, p_tabnum=-1;
38 static WInfoWin *tabdrag_infowin=NULL;
44 static WRegion *sub_at_tab(WFrame *frame)
46 return mplex_mx_nth((WMPlex*)frame, p_tabnum);
50 int frame_press(WFrame *frame, XButtonEvent *ev, WRegion **reg_ret)
57 window_p_resize_prepare((WWindow*)frame, ev);
61 frame_bar_geom(frame, &g);
63 /* Borders act like tabs at top of the parent region */
64 if(REGION_GEOM(frame).y==0){
69 if(rectangle_contains(&g, ev->x, ev->y)){
70 p_tabnum=frame_tab_at_x(frame, ev->x);
72 region_rootpos((WRegion*)frame, &p_tab_x, &p_tab_y);
73 p_tab_x+=frame_nth_tab_x(frame, p_tabnum);
76 sub=mplex_mx_nth(&(frame->mplex), p_tabnum);
81 return FRAME_AREA_TAB;
84 FRAME_MX_FOR_ALL(sub, frame, tmp){
86 if(sub==FRAME_CURRENT(frame))
91 p_tab_x=ev->x_root-frame_nth_tab_w(frame, p_tabnum)/2;
92 p_tab_y=ev->y_root-frame->bar_h/2;
101 frame_border_inner_geom(frame, &g);
103 if(rectangle_contains(&g, ev->x, ev->y))
104 return FRAME_AREA_CLIENT;
106 return FRAME_AREA_BORDER;
116 static ExtlExportedFn *tabdrag_safe_fns[]={
117 (ExtlExportedFn*)&mplex_switch_nth,
118 (ExtlExportedFn*)&mplex_switch_next,
119 (ExtlExportedFn*)&mplex_switch_prev,
123 static ExtlSafelist tabdrag_safelist=EXTL_SAFELIST_INIT(tabdrag_safe_fns);
126 #define BUTTONS_MASK \
127 (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)
130 static bool tabdrag_kbd_handler(WRegion *reg, XEvent *xev)
132 XKeyEvent *ev=&xev->xkey;
133 WBinding *binding=NULL;
136 if(ev->type==KeyRelease)
141 binding=bindmap_lookup_binding(ioncore_rootwin_bindmap, BINDING_KEYPRESS,
142 ev->state&~BUTTONS_MASK, ev->keycode);
144 if(binding!=NULL && binding->func!=extl_fn_none()){
145 extl_protect(&tabdrag_safelist);
146 extl_call(binding->func, "o", NULL, region_screen_of(reg));
147 extl_unprotect(&tabdrag_safelist);
154 static void setup_dragwin(WFrame *frame, uint tab)
159 const char *tab_style=framemode_get_tab_style(frame->mode);
161 assert(tabdrag_infowin==NULL);
163 rw=region_rootwin_of((WRegion*)frame);
165 fp.mode=REGION_FIT_EXACT;
168 fp.g.w=frame_nth_tab_w(frame, tab);
171 tabdrag_infowin=create_infowin((WWindow*)rw, &fp, tab_style);
173 if(tabdrag_infowin==NULL)
176 infowin_set_attr2(tabdrag_infowin, (REGION_IS_ACTIVE(frame)
177 ? "active" : "inactive"),
178 frame->titles[tab].attr);
180 if(frame->titles[tab].text!=NULL){
181 char *buf=INFOWIN_BUFFER(tabdrag_infowin);
182 strncpy(buf, frame->titles[tab].text, INFOWIN_BUFFER_LEN-1);
183 buf[INFOWIN_BUFFER_LEN-1]='\0';
188 static void p_tabdrag_motion(WFrame *frame, XMotionEvent *ev,
191 WRootWin *rootwin=region_rootwin_of((WRegion*)frame);
196 if(tabdrag_infowin!=NULL){
200 g.w=REGION_GEOM(tabdrag_infowin).w;
201 g.h=REGION_GEOM(tabdrag_infowin).h;
202 region_fit((WRegion*)tabdrag_infowin, &g, REGION_FIT_EXACT);
207 static void p_tabdrag_begin(WFrame *frame, XMotionEvent *ev,
210 WRootWin *rootwin=region_rootwin_of((WRegion*)frame);
215 ioncore_change_grab_cursor(IONCORE_CURSOR_DRAG);
217 setup_dragwin(frame, p_tabnum);
219 frame->tab_dragged_idx=p_tabnum;
220 frame_update_attr_nth(frame, p_tabnum);
222 frame_draw_bar(frame, FALSE);
224 p_tabdrag_motion(frame, ev, dx, dy);
226 if(tabdrag_infowin!=NULL)
227 window_map((WWindow*)tabdrag_infowin);
231 static WRegion *fnd(Window root, int x, int y)
239 FOR_ALL_SCREENS(scr){
240 if(region_root_of((WRegion*)scr)==root &&
241 rectangle_contains(®ION_GEOM(scr), x, y)){
249 if(HAS_DYN(w, region_handle_drop))
252 if(!XTranslateCoordinates(ioncore_g.dpy, root, w->win,
253 x, y, &dstx, &dsty, &win)){
257 w=XWINDOW_REGION_OF_T(win, WWindow);
266 static bool drop_ok(WRegion *mgr, WRegion *reg)
269 for(reg2=mgr; reg2!=NULL; reg2=region_manager(reg2)){
274 for(reg2=REGION_PARENT_REG(mgr); reg2!=NULL; reg2=REGION_PARENT_REG(reg2)){
282 warn(TR("Attempt to make region %s manage its ancestor %s."),
283 region_name(mgr), region_name(reg));
288 static void tabdrag_deinit(WFrame *frame)
290 int idx=frame->tab_dragged_idx;
291 frame->tab_dragged_idx=-1;
292 frame_update_attr_nth(frame, idx);
294 if(tabdrag_infowin!=NULL){
295 destroy_obj((Obj*)tabdrag_infowin);
296 tabdrag_infowin=NULL;
301 static void tabdrag_killed(WFrame *frame)
303 tabdrag_deinit(frame);
304 if(!OBJ_IS_BEING_DESTROYED(frame))
305 frame_draw_bar(frame, TRUE);
309 static void p_tabdrag_end(WFrame *frame, XButtonEvent *ev)
315 sub=sub_at_tab(frame);
317 tabdrag_deinit(frame);
319 /* Must be same root window */
320 if(sub==NULL || ev->root!=region_root_of(sub))
323 dropped_on=fnd(ev->root, ev->x_root, ev->y_root);
325 if(dropped_on==NULL || dropped_on==(WRegion*)frame ||
326 dropped_on==sub || !drop_ok(dropped_on, sub)){
327 frame_draw_bar(frame, TRUE);
331 if(region_handle_drop(dropped_on, p_tab_x, p_tab_y, sub))
332 region_goto(dropped_on);
334 frame_draw_bar(frame, TRUE);
339 * Start dragging the tab that the user pressed on with the pointing device.
340 * This function should only be used by binding it to \emph{mpress} or
341 * \emph{mdrag} action with area ''tab''.
344 void frame_p_tabdrag(WFrame *frame)
349 ioncore_set_drag_handlers((WRegion*)frame,
350 (WMotionHandler*)p_tabdrag_begin,
351 (WMotionHandler*)p_tabdrag_motion,
352 (WButtonHandler*)p_tabdrag_end,
354 (GrabKilledHandler*)tabdrag_killed);
365 * Display the region corresponding to the tab that the user pressed on.
366 * This function should only be used by binding it to a mouse action.
369 void frame_p_switch_tab(WFrame *frame)
373 if(ioncore_pointer_grab_region()!=(WRegion*)frame)
376 sub=sub_at_tab(frame);
379 bool mcf=region_may_control_focus((WRegion*)frame);
380 region_goto_flags(sub, (mcf
381 ? REGION_GOTO_FOCUS|REGION_GOTO_NOWARP