2 * ion/ioncore/frame-pointer.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
11 #include <libtu/objp.h>
23 #include "frame-pointer.h"
24 #include "frame-draw.h"
27 #include "rectangle.h"
34 static int p_tab_x
=0, p_tab_y
=0, p_tabnum
=-1;
35 static WInfoWin
*tabdrag_infowin
=NULL
;
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
)
54 window_p_resize_prepare((WWindow
*)frame
, ev
);
58 frame_bar_geom(frame
, &g
);
60 /* Borders act like tabs at top of the parent region */
61 if(REGION_GEOM(frame
).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
);
74 sub
=mplex_mx_nth(&(frame
->mplex
), p_tabnum
);
79 return FRAME_AREA_TAB
;
82 FRAME_MX_FOR_ALL(sub
, frame
, tmp
){
84 if(sub
==FRAME_CURRENT(frame
))
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;
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
;
114 static ExtlExportedFn
*tabdrag_safe_fns
[]={
115 (ExtlExportedFn
*)&mplex_switch_nth
,
116 (ExtlExportedFn
*)&mplex_switch_next
,
117 (ExtlExportedFn
*)&mplex_switch_prev
,
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
;
134 if(ev
->type
==KeyRelease
)
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
);
152 static void setup_dragwin(WFrame
*frame
, uint tab
)
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
;
166 fp
.g
.w
=frame_nth_tab_w(frame
, tab
);
169 tabdrag_infowin
=create_infowin((WWindow
*)rw
, &fp
, tab_style
);
171 if(tabdrag_infowin
==NULL
)
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
,
187 WRootWin
*rootwin
=region_rootwin_of((WRegion
*)frame
);
192 if(tabdrag_infowin
!=NULL
){
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
,
206 WRootWin
*rootwin
=region_rootwin_of((WRegion
*)frame
);
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
)
235 FOR_ALL_SCREENS(scr
){
236 if(region_root_of((WRegion
*)scr
)==root
&&
237 rectangle_contains(®ION_GEOM(scr
), x
, y
)){
245 if(HAS_DYN(w
, region_handle_drop
))
248 if(!XTranslateCoordinates(ioncore_g
.dpy
, root
, w
->win
,
249 x
, y
, &dstx
, &dsty
, &win
)){
253 w
=XWINDOW_REGION_OF_T(win
, WWindow
);
262 static bool drop_ok(WRegion
*mgr
, WRegion
*reg
)
265 for(reg2
=mgr
; reg2
!=NULL
; reg2
=region_manager(reg2
)){
270 for(reg2
=REGION_PARENT_REG(mgr
); reg2
!=NULL
; reg2
=REGION_PARENT_REG(reg2
)){
278 warn(TR("Attempt to make region %s manage its ancestor %s."),
279 region_name(mgr
), region_name(reg
));
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
)
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
))
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
);
327 if(region_handle_drop(dropped_on
, p_tab_x
, p_tab_y
, sub
))
328 region_goto(dropped_on
);
330 frame_draw_bar(frame
, TRUE
);
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}.
340 void frame_p_tabdrag(WFrame
*frame
)
345 ioncore_set_drag_handlers((WRegion
*)frame
,
346 (WMotionHandler
*)p_tabdrag_begin
,
347 (WMotionHandler
*)p_tabdrag_motion
,
348 (WButtonHandler
*)p_tabdrag_end
,
350 (GrabKilledHandler
*)tabdrag_killed
);
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.
365 void frame_p_switch_tab(WFrame
*frame
)
369 if(ioncore_pointer_grab_region()!=(WRegion
*)frame
)
373 sub=sub_at_tab(frame);
375 bool mcf=region_may_control_focus((WRegion*)frame);
376 region_goto_flags(sub, (mcf
377 ? REGION_GOTO_FOCUS|REGION_GOTO_NOWARP
382 mplex_switch_nth((WMPlex
*)frame
, p_tabnum
);