2 * ion/ioncore/screen-notify.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
11 #include <libtu/minmax.h>
12 #include <libmainloop/defer.h>
13 #include <libmainloop/signal.h>
25 #include "screen-notify.h"
29 /*{{{ Generic stuff */
32 static WInfoWin
*do_get_popup_win(WScreen
*scr
, Watch
*watch
, uint pos
,
36 WInfoWin
*iw
=(WInfoWin
*)(watch
->obj
);
39 WMPlexAttachParams param
=MPLEXATTACHPARAMS_INIT
;
41 param
.flags
=(MPLEX_ATTACH_UNNUMBERED
|
42 MPLEX_ATTACH_SIZEPOLICY
|
45 MPLEX_ATTACH_PASSIVE
);
46 param
.level
=STACKING_LEVEL_ON_TOP
;
55 param
.szplcy
=SIZEPOLICY_GRAVITY_NORTHWEST
;
60 param
.szplcy
=SIZEPOLICY_GRAVITY_NORTHEAST
;
61 param
.geom
.x
=REGION_GEOM(scr
).w
-1;
65 param
.szplcy
=SIZEPOLICY_GRAVITY_SOUTHWEST
;
67 param
.geom
.y
=REGION_GEOM(scr
).h
-1;
71 param
.szplcy
=SIZEPOLICY_GRAVITY_SOUTHEAST
;
72 param
.geom
.x
=REGION_GEOM(scr
).w
-1;
73 param
.geom
.y
=REGION_GEOM(scr
).h
-1;
78 iw
=(WInfoWin
*)mplex_do_attach_new(&scr
->mplex
, ¶m
,
79 (WRegionCreateFn
*)create_infowin
,
83 watch_setup(watch
, (Obj
*)iw
, NULL
);
90 static void do_unnotify(Watch
*watch
)
95 mainloop_defer_destroy((Obj
*)iw
);
99 // returns the position or the stdisp, or -1 if there isn't one
100 static int get_stdisp_pos(WScreen
*scr
)
102 WRegion
* stdisp
=NULL
;
103 WMPlexSTDispInfo info
;
105 mplex_get_stdisp(&scr
->mplex
, &stdisp
, &info
);
107 return (stdisp
!=NULL
) ? info
.pos
: -1;
116 static WInfoWin
*get_notifywin(WScreen
*scr
)
118 int stdisp_pos
= get_stdisp_pos(scr
);
119 return do_get_popup_win(scr
,
120 &scr
->notifywin_watch
,
121 (stdisp_pos
>= 0) ? stdisp_pos
: MPLEX_STDISP_TL
,
126 void screen_notify(WScreen
*scr
, const char *str
)
128 WInfoWin
*iw
=get_notifywin(scr
);
131 int maxw
=REGION_GEOM(scr
).w
/3;
132 infowin_set_text(iw
, str
, maxw
);
137 void screen_unnotify_notifywin(WScreen
*scr
)
139 do_unnotify(&scr
->notifywin_watch
);
143 static bool ws_mapped(WScreen
*scr
, WRegion
*reg
)
146 WRegion
*mgr
=REGION_MANAGER(reg
);
151 if(mgr
==(WRegion
*)scr
)
152 return REGION_IS_MAPPED(reg
);
159 static void screen_managed_activity(WScreen
*scr
)
165 ObjList
*actlist
=ioncore_activity_list();
168 int nfound
=0, nadded
=0;
169 int w
=0, maxw
=REGION_GEOM(scr
).w
/4;
171 /* Lisäksi minimipituus (10ex tms.), ja sen yli menevät jätetään
174 FOR_ALL_ON_OBJLIST(WRegion
*, reg
, actlist
, tmp
){
175 if(!ioncore_g
.activity_notification_on_all_screens
&&
176 (region_screen_of(reg
)!=scr
|| ws_mapped(scr
, reg
)))
178 if(region_name(reg
)==NULL
)
180 if(ptrlist_insert_last(&found
, reg
))
187 iw
=get_notifywin(scr
);
195 notstr
=scopy(TR("act: "));
200 FOR_ALL_ON_PTRLIST(WRegion
*, reg
, found
, tmp2
){
201 const char *nm
=region_name(reg
);
202 char *nstr
=NULL
, *label
=NULL
;
204 w
=grbrush_get_text_width(iw
->brush
, notstr
, strlen(notstr
));
209 label
=grbrush_make_label(iw
->brush
, nm
, maxw
-w
);
212 ? scat3(notstr
, ", ", label
)
213 : scat(notstr
, label
));
227 libtu_asprintf(&nstr
, "%s +%d", notstr
, nfound
-nadded
);
235 ptrlist_clear(&found
);
237 infowin_set_text(iw
, notstr
, 0);
244 screen_unnotify_notifywin(scr
);
248 static void _screen_do_update_notifywin(WScreen
*scr
)
250 if(ioncore_g
.screen_notify
)
251 screen_managed_activity(scr
);
253 screen_unnotify_notifywin(scr
);
256 static void screen_do_update_notifywin(WScreen
*scr
)
258 if( ioncore_g
.activity_notification_on_all_screens
)
260 WScreen
* scr_iterated
;
261 FOR_ALL_SCREENS(scr_iterated
)
263 _screen_do_update_notifywin(scr_iterated
);
267 _screen_do_update_notifywin(scr
);
276 static WInfoWin
*get_infowin(WScreen
*scr
)
278 int stdisp_pos
= get_stdisp_pos(scr
);
279 return do_get_popup_win(scr
,
281 (stdisp_pos
== MPLEX_STDISP_TR
) ? MPLEX_STDISP_BR
: MPLEX_STDISP_TR
,
286 void screen_unnotify_infowin(WScreen
*scr
)
288 do_unnotify(&scr
->infowin_watch
);
293 GR_DEFATTR(inactive
);
294 GR_DEFATTR(selected
);
296 GR_DEFATTR(not_tagged
);
297 GR_DEFATTR(not_dragged
);
298 GR_DEFATTR(activity
);
299 GR_DEFATTR(no_activity
);
302 static void init_attr()
305 GR_ALLOCATTR(active
);
306 GR_ALLOCATTR(inactive
);
307 GR_ALLOCATTR(selected
);
308 GR_ALLOCATTR(tagged
);
309 GR_ALLOCATTR(not_tagged
);
310 GR_ALLOCATTR(not_dragged
);
311 GR_ALLOCATTR(no_activity
);
312 GR_ALLOCATTR(activity
);
317 static void screen_do_update_infowin(WScreen
*scr
)
319 WRegion
*reg
=mplex_mx_current(&(scr
->mplex
));
320 bool tag
=(reg
!=NULL
&& region_is_tagged(reg
));
321 bool act
=(reg
!=NULL
&& region_is_activity_r(reg
) && !REGION_IS_ACTIVE(scr
));
322 bool sac
=REGION_IS_ACTIVE(scr
);
325 const char *n
=region_displayname(reg
);
326 WInfoWin
*iw
=get_infowin(scr
);
329 int maxw
=REGION_GEOM(scr
).w
/3;
330 infowin_set_text(iw
, n
, maxw
);
332 GrStyleSpec
*spec
=infowin_stylespec(iw
);
336 gr_stylespec_unalloc(spec
);
338 gr_stylespec_set(spec
, GR_ATTR(selected
));
339 gr_stylespec_set(spec
, GR_ATTR(not_dragged
));
340 gr_stylespec_set(spec
, sac
? GR_ATTR(active
) : GR_ATTR(inactive
));
341 gr_stylespec_set(spec
, tag
? GR_ATTR(tagged
) : GR_ATTR(not_tagged
));
342 gr_stylespec_set(spec
, act
? GR_ATTR(activity
) : GR_ATTR(no_activity
));
346 screen_unnotify_infowin(scr
);
355 /*{{{ workspace indicator win */
357 // A single timer for ALL the screens
358 static WTimer
* workspace_indicator_remove_timer
= NULL
;
359 static WScreen
* workspace_indicator_active_screen
= NULL
;
360 static WGroupWS
* workspace_indicator_last_workspace
= NULL
;
362 static WInfoWin
*get_workspace_indicatorwin(WScreen
*scr
)
364 return do_get_popup_win(scr
,
365 &scr
->workspace_indicatorwin_watch
,
371 void screen_unnotify_workspace_indicatorwin(void)
373 if( workspace_indicator_active_screen
!= NULL
)
375 do_unnotify(&workspace_indicator_active_screen
->workspace_indicatorwin_watch
);
376 workspace_indicator_active_screen
= NULL
;
379 if( workspace_indicator_remove_timer
)
380 timer_reset( workspace_indicator_remove_timer
);
383 static void timer_expired__workspace_indicator_remove(WTimer
* UNUSED(dummy1
), Obj
* UNUSED(dummy2
))
385 if( workspace_indicator_active_screen
!= NULL
)
386 screen_unnotify_workspace_indicatorwin();
389 // Called when a region is focused. In response this function may either put up
390 // a new workspace-indicator or remove an existing one
391 void screen_update_workspace_indicatorwin(WRegion
* reg_focused
)
393 if( ioncore_g
.workspace_indicator_timeout
<= 0 )
396 WScreen
* scr
= region_screen_of(reg_focused
);
399 (mplex
= mplex_mx_current(&(scr
->mplex
))) == NULL
||
400 !OBJ_IS(mplex
, WGroupWS
) ||
401 mplex
->ni
.name
== NULL
)
406 // remove the indicator from the other screen that it is on (if it IS on
408 if( workspace_indicator_active_screen
!= NULL
&&
409 workspace_indicator_active_screen
!= scr
)
411 screen_unnotify_workspace_indicatorwin();
413 else if( (WGroupWS
*)mplex
== workspace_indicator_last_workspace
)
414 // If I'm already on this workspace, do nothing
417 const char* name
= mplex
->ni
.name
;
419 WInfoWin
*iw
=get_workspace_indicatorwin(scr
);
422 int maxw
=REGION_GEOM(scr
).w
/3;
423 infowin_set_text(iw
, name
, maxw
);
425 GrStyleSpec
*spec
=infowin_stylespec(iw
);
427 gr_stylespec_unalloc(spec
);
429 gr_stylespec_set(spec
, GR_ATTR(selected
));
430 gr_stylespec_set(spec
, GR_ATTR(not_dragged
));
431 gr_stylespec_set(spec
, GR_ATTR(active
));
434 // set up the indicator on THIS screen
435 workspace_indicator_active_screen
= scr
;
436 workspace_indicator_last_workspace
= (WGroupWS
*)mplex
;
438 // create and set the timer
439 if( workspace_indicator_remove_timer
== NULL
)
440 workspace_indicator_remove_timer
= create_timer();
441 if( workspace_indicator_remove_timer
== NULL
)
444 timer_set(workspace_indicator_remove_timer
, ioncore_g
.workspace_indicator_timeout
,
445 (WTimerHandler
*)timer_expired__workspace_indicator_remove
, NULL
);
448 void screen_unnotify_if_screen( WScreen
* reg
)
450 if( reg
== workspace_indicator_active_screen
)
451 screen_unnotify_workspace_indicatorwin();
454 void screen_unnotify_if_workspace( WGroupWS
* reg
)
456 if( reg
== workspace_indicator_last_workspace
)
458 screen_unnotify_workspace_indicatorwin();
459 workspace_indicator_last_workspace
= NULL
;
466 /*{{{ Notification callbacks and deferred updates*/
469 void screen_update_infowin(WScreen
*scr
)
471 mainloop_defer_action((Obj
*)scr
,
472 (WDeferredAction
*)screen_do_update_infowin
);
476 void screen_update_notifywin(WScreen
*scr
)
478 mainloop_defer_action((Obj
*)scr
,
479 (WDeferredAction
*)screen_do_update_notifywin
);
483 void screen_managed_notify(WScreen
*scr
, WRegion
*UNUSED(reg
), WRegionNotify how
)
485 if(how
==ioncore_g
.notifies
.tag
)
486 screen_update_infowin(scr
);
490 void ioncore_screen_activity_notify(WRegion
*reg
, WRegionNotify how
)
492 WScreen
*scr
=region_screen_of(reg
);
494 if(how
==ioncore_g
.notifies
.activity
){
495 screen_update_notifywin(region_screen_of(reg
));
496 }else if(how
==ioncore_g
.notifies
.name
){
497 if(region_is_activity(reg
))
498 screen_update_notifywin(scr
);
499 if((WRegion
*)scr
==REGION_MANAGER(reg
))
500 screen_do_update_infowin(scr
);