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.
12 #include <libmainloop/hooks.h>
27 WHook *region_do_warp_alt=NULL;
28 WHook *region_activated_hook=NULL;
29 WHook *region_inactivated_hook=NULL;
38 void region_focuslist_remove(WRegion *reg)
40 UNLINK_ITEM(ioncore_g.focus_current, reg, active_next, active_prev);
44 void region_focuslist_push(WRegion *reg)
46 region_focuslist_remove(reg);
47 LINK_ITEM_FIRST(ioncore_g.focus_current, reg, active_next, active_prev);
51 void region_focuslist_move_after(WRegion *reg, WRegion *after)
53 region_focuslist_remove(reg);
54 LINK_ITEM_AFTER(ioncore_g.focus_current, after, reg,
55 active_next, active_prev);
59 void region_focuslist_deinit(WRegion *reg)
61 WRegion *replace=region_manager_or_parent(reg);
64 region_focuslist_move_after(replace, reg);
66 region_focuslist_remove(reg);
71 * Go to and return to a previously active region (if any).
73 * Note that this function is asynchronous; the region will not
74 * actually have received the focus when this function returns.
77 WRegion *ioncore_goto_previous()
81 if(ioncore_g.focus_current==NULL)
84 /* Find the first region on focus history list that isn't currently
87 for(next=ioncore_g.focus_current->active_next;
89 next=next->active_next){
91 if(!REGION_IS_ACTIVE(next))
108 static Watch await_watch=WATCH_INIT;
111 static void await_watch_handler(Watch *watch, WRegion *prev)
115 r=REGION_PARENT_REG(prev);
119 if(watch_setup(&await_watch, (Obj*)r,
120 (WatchHandler*)await_watch_handler))
127 void region_set_await_focus(WRegion *reg)
130 watch_reset(&await_watch);
132 watch_setup(&await_watch, (Obj*)reg,
133 (WatchHandler*)await_watch_handler);
138 static bool region_is_await(WRegion *reg)
140 WRegion *aw=(WRegion*)await_watch.obj;
145 aw=REGION_PARENT_REG(aw);
152 /* Only keep await status if focus event is to an ancestor of the await
155 static void check_clear_await(WRegion *reg)
157 if(region_is_await(reg) && reg!=(WRegion*)await_watch.obj)
160 watch_reset(&await_watch);
164 bool ioncore_await_focus()
166 return (await_watch.obj!=NULL);
176 void region_got_focus(WRegion *reg)
178 WRegion *par, *mgr, *tmp;
180 check_clear_await(reg);
182 region_set_activity(reg, SETPARAM_UNSET);
184 if(reg->active_sub==NULL){
185 region_focuslist_push(reg);
186 /*ioncore_g.focus_current=reg;*/
189 if(!REGION_IS_ACTIVE(reg)){
190 D(fprintf(stderr, "got focus (inact) %s [%p]\n", OBJ_TYPESTR(reg), reg);)
191 reg->flags|=REGION_ACTIVE;
193 par=REGION_PARENT_REG(reg);
196 region_update_owned_grabs(par);
199 region_activated(reg);
201 mgr=REGION_MANAGER(reg);
204 /* We need to loop over managing non-windows (workspaces) here to
205 * signal their managers.
207 region_managed_activated(mgr, tmp);
209 if(REGION_PARENT_REG(reg)==mgr)
213 mgr=REGION_MANAGER(mgr);
216 D(fprintf(stderr, "got focus (act) %s [%p]\n", OBJ_TYPESTR(reg), reg);)
219 /* Install default colour map only if there is no active subregion;
220 * their maps should come first. WClientWins will install their maps
221 * in region_activated. Other regions are supposed to use the same
224 if(reg->active_sub==NULL && !OBJ_IS(reg, WClientWin))
225 rootwin_install_colormap(region_rootwin_of(reg), None);
228 hook_call_o(region_activated_hook, (Obj*)reg);
229 extl_unprotect(NULL);
233 void region_lost_focus(WRegion *reg)
237 if(!REGION_IS_ACTIVE(reg)){
238 D(fprintf(stderr, "lost focus (inact) %s [%p:]\n", OBJ_TYPESTR(reg), reg);)
242 par=REGION_PARENT_REG(reg);
243 if(par!=NULL && par->active_sub==reg){
244 par->active_sub=NULL;
245 region_update_owned_grabs(par);
250 if(ioncore_g.focus_current==reg){
251 /* Find the closest active parent, or if none is found, stop at the
252 * screen and mark it "currently focused".
254 while(par!=NULL && !REGION_IS_ACTIVE(par) && !OBJ_IS(par, WScreen))
255 par=REGION_PARENT_REG(par);
256 ioncore_g.focus_current=par;
260 D(fprintf(stderr, "lost focus (act) %s [%p:]\n", OBJ_TYPESTR(reg), reg);)
262 reg->flags&=~REGION_ACTIVE;
263 region_inactivated(reg);
264 r=REGION_MANAGER(reg);
266 region_managed_inactivated(r, reg);
269 hook_call_o(region_inactivated_hook, (Obj*)reg);
270 extl_unprotect(NULL);
277 /*{{{ Focus status requests */
281 * Is \var{reg} active/does it or one of it's children of focus?
285 bool region_is_active(WRegion *reg)
287 return REGION_IS_ACTIVE(reg);
291 bool region_may_control_focus(WRegion *reg)
295 if(OBJ_IS_BEING_DESTROYED(reg))
298 if(REGION_IS_ACTIVE(reg))
301 if(region_is_await(reg))
304 par=REGION_PARENT_REG(reg);
306 if(par==NULL || !REGION_IS_ACTIVE(par))
310 while(r2!=NULL && r2!=par){
313 r2=REGION_MANAGER(r2);
323 /*{{{ set_focus, warp */
326 /*Time ioncore_focus_time=CurrentTime;*/
329 void region_finalise_focusing(WRegion* reg, Window win, bool warp)
334 region_set_await_focus(reg);
335 /*xwindow_do_set_focus(win);*/
336 XSetInputFocus(ioncore_g.dpy, win, RevertToParent,
337 CurrentTime/*ioncore_focus_time*/);
338 /*ioncore_focus_time=CurrentTime;*/
343 static WRegion *find_warp_to_reg(WRegion *reg)
347 if(reg->flags®ION_PLEASE_WARP)
349 return find_warp_to_reg(region_manager_or_parent(reg));
353 bool region_do_warp_default(WRegion *reg)
355 int x, y, w, h, px=0, py=0;
358 reg=find_warp_to_reg(reg);
363 D(fprintf(stderr, "region_do_warp %p %s\n", reg, OBJ_TYPESTR(reg)));
365 root=region_root_of(reg);
367 region_rootpos(reg, &x, &y);
368 w=REGION_GEOM(reg).w;
369 h=REGION_GEOM(reg).h;
371 if(xwindow_pointer_pos(root, &px, &py)){
372 if(px>=x && py>=y && px<x+w && py<y+h)
376 XWarpPointer(ioncore_g.dpy, None, root, 0, 0, 0, 0,
383 void region_do_warp(WRegion *reg)
386 hook_call_alt_o(region_do_warp_alt, (Obj*)reg);
387 extl_unprotect(NULL);
391 void region_maybewarp(WRegion *reg, bool warp)
393 ioncore_g.focus_next=reg;
394 ioncore_g.warp_next=(warp && ioncore_g.warp_enabled);
398 void region_set_focus(WRegion *reg)
400 region_maybewarp(reg, FALSE);
404 void region_warp(WRegion *reg)
406 region_maybewarp(reg, TRUE);
416 bool region_skip_focus(WRegion *reg)
419 if(reg->flags®ION_SKIP_FOCUS)
421 reg=REGION_PARENT_REG(reg);
427 * Returns the currently focused region, if any.
430 WRegion *ioncore_current()
432 return ioncore_g.focus_current;