]> git.decadent.org.uk Git - ion3.git/blob - ioncore/screen-notify.c
ecb280702aac96b863b5b40c69dca38c0eca73ff
[ion3.git] / ioncore / screen-notify.c
1 /*
2  * ion/ioncore/screen-notify.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2008. 
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <string.h>
10
11 #include <libtu/minmax.h>
12 #include <libmainloop/defer.h>
13
14 #include "common.h"
15 #include "global.h"
16 #include "infowin.h"
17 #include "activity.h"
18 #include "tags.h"
19 #include "gr.h"
20 #include "gr-util.h"
21 #include "stacking.h"
22 #include "names.h"
23 #include "screen.h"
24 #include "screen-notify.h"
25 #include "strings.h"
26
27
28 /*{{{ Generic stuff */
29
30
31 static WInfoWin *do_get_notifywin(WScreen *scr, Watch *watch, uint pos,
32                                   char *style)
33 {
34
35     WInfoWin *iw=(WInfoWin*)(watch->obj);
36     WFitParams fp;
37     
38     if(iw==NULL){
39         WMPlexAttachParams param=MPLEXATTACHPARAMS_INIT;
40         
41         param.flags=(MPLEX_ATTACH_UNNUMBERED|
42                      MPLEX_ATTACH_SIZEPOLICY|
43                      MPLEX_ATTACH_GEOM|
44                      MPLEX_ATTACH_LEVEL|
45                      MPLEX_ATTACH_PASSIVE);
46         param.level=STACKING_LEVEL_ON_TOP;
47         
48         param.geom.x=0;
49         param.geom.y=0;
50         param.geom.w=1;
51         param.geom.h=1;
52         
53         switch(pos){
54         case MPLEX_STDISP_TL:
55             param.szplcy=SIZEPOLICY_GRAVITY_NORTHWEST;
56             param.geom.x=0;
57             break;
58             
59         case MPLEX_STDISP_TR:
60             param.szplcy=SIZEPOLICY_GRAVITY_NORTHEAST;
61             param.geom.x=REGION_GEOM(scr).w-1;
62             break;
63             
64         case MPLEX_STDISP_BL:
65             param.szplcy=SIZEPOLICY_GRAVITY_SOUTHWEST;
66             param.geom.x=0;
67             param.geom.y=REGION_GEOM(scr).h-1;
68             break;
69             
70         case MPLEX_STDISP_BR:
71             param.szplcy=SIZEPOLICY_GRAVITY_SOUTHEAST;
72             param.geom.x=REGION_GEOM(scr).w-1;
73             param.geom.y=REGION_GEOM(scr).h-1;
74             break;
75         }
76         
77
78         iw=(WInfoWin*)mplex_do_attach_new(&scr->mplex, &param,
79                                           (WRegionCreateFn*)create_infowin, 
80                                           style);
81         
82         if(iw!=NULL)
83             watch_setup(watch, (Obj*)iw, NULL);
84     }
85     
86     return iw;
87 }
88
89
90 static void do_unnotify(Watch *watch)
91 {    
92     Obj *iw=watch->obj;
93     if(iw!=NULL){
94         watch_reset(watch);
95         mainloop_defer_destroy((Obj*)iw);
96     }
97 }
98
99
100 /*}}}*/
101
102
103 /*{{{ Notifywin */
104
105
106 static WInfoWin *get_notifywin(WScreen *scr)
107 {
108     WRegion *stdisp=NULL;
109     WMPlexSTDispInfo info;
110     uint pos=MPLEX_STDISP_TL;
111     
112     mplex_get_stdisp(&scr->mplex, &stdisp, &info);
113     if(stdisp!=NULL)
114         pos=info.pos;
115     
116     return do_get_notifywin(scr, &scr->notifywin_watch, pos, "actnotify");
117 }
118
119
120 void screen_notify(WScreen *scr, const char *str)
121 {
122     WInfoWin *iw=get_notifywin(scr);
123     
124     if(iw!=NULL){
125         int maxw=REGION_GEOM(scr).w/3;
126         infowin_set_text(iw, str, maxw);
127     }
128 }
129
130
131 void screen_unnotify(WScreen *scr)
132 {
133     do_unnotify(&scr->notifywin_watch);
134 }
135
136
137 static bool ws_mapped(WScreen *scr, WRegion *reg)
138 {
139     while(1){
140         WRegion *mgr=REGION_MANAGER(reg);
141         
142         if(mgr==NULL)
143             return FALSE;
144         
145         if(mgr==(WRegion*)scr)
146             return REGION_IS_MAPPED(reg);
147         
148         reg=mgr;
149     }
150 }
151
152
153 static void screen_managed_activity(WScreen *scr)
154 {
155     char *notstr=NULL;
156     WRegion *reg;
157     ObjListIterTmp tmp;
158     PtrListIterTmp tmp2;
159     ObjList *actlist=ioncore_activity_list();
160     WInfoWin *iw=NULL;
161     PtrList *found=NULL;
162     int nfound=0, nadded=0;
163     int w=0, maxw=REGION_GEOM(scr).w/4;
164     
165     /* Lisäksi minimipituus (10ex tms.), ja sen yli menevät jätetään
166      * pois (+ n) 
167      */
168     FOR_ALL_ON_OBJLIST(WRegion*, reg, actlist, tmp){
169         if(region_screen_of(reg)!=scr || ws_mapped(scr, reg))
170             continue;
171         if(region_name(reg)==NULL)
172             continue;
173         if(ptrlist_insert_last(&found, reg))
174             nfound++;
175     }
176     
177     if(found==NULL)
178         goto unnotify;
179     
180     iw=get_notifywin(scr);
181     
182     if(iw==NULL)
183         return;
184         
185     if(iw->brush==NULL)
186         goto unnotify;
187     
188     notstr=scopy(TR("act: "));
189     
190     if(notstr==NULL)
191         goto unnotify;
192     
193     FOR_ALL_ON_PTRLIST(WRegion*, reg, found, tmp2){
194         const char *nm=region_name(reg);
195         char *nstr=NULL, *label=NULL;
196         
197         w=grbrush_get_text_width(iw->brush, notstr, strlen(notstr));
198
199         if(w>=maxw)
200             break;
201         
202         label=grbrush_make_label(iw->brush, nm, maxw-w);
203         if(label!=NULL){
204             nstr=(nadded>0
205                   ? scat3(notstr, ", ", label)
206                   : scat(notstr, label));
207             
208             if(nstr!=NULL){
209                 free(notstr);
210                 notstr=nstr;
211                 nadded++;
212             }
213             free(label);
214         }
215     }
216     
217     if(nfound > nadded){
218         char *nstr=NULL;
219         
220         libtu_asprintf(&nstr, "%s  +%d", notstr, nfound-nadded);
221         
222         if(nstr!=NULL){
223             free(notstr);
224             notstr=nstr;
225         }
226     }
227     
228     ptrlist_clear(&found);
229     
230     infowin_set_text(iw, notstr, 0);
231     
232     free(notstr);
233     
234     return;
235
236 unnotify:    
237     screen_unnotify(scr);
238 }
239
240
241 static void screen_do_update_notifywin(WScreen *scr)
242 {
243     if(ioncore_g.screen_notify)
244         screen_managed_activity(scr);
245     else
246         screen_unnotify(scr);
247 }
248
249
250 /*}}}*/
251
252
253 /*{{{ Infowin */
254
255
256 static WInfoWin *get_infowin(WScreen *scr)
257 {
258     WRegion *stdisp=NULL;
259     WMPlexSTDispInfo info;
260     uint pos=MPLEX_STDISP_TR;
261     
262     mplex_get_stdisp(&scr->mplex, &stdisp, &info);
263     if(stdisp!=NULL && info.pos==MPLEX_STDISP_TR)
264         pos=MPLEX_STDISP_BR;
265     
266     return do_get_notifywin(scr, &scr->infowin_watch, pos, "tab-info");
267 }
268
269
270 void screen_windowinfo(WScreen *scr, const char *str)
271 {
272     WInfoWin *iw=get_infowin(scr);
273     
274     if(iw!=NULL){
275         int maxw=REGION_GEOM(scr).w/3;
276         infowin_set_text(iw, str, maxw);
277     }
278 }
279
280
281 void screen_nowindowinfo(WScreen *scr)
282 {
283     do_unnotify(&scr->infowin_watch);
284 }
285
286
287 GR_DEFATTR(active);
288 GR_DEFATTR(inactive);
289 GR_DEFATTR(selected);
290 GR_DEFATTR(tagged);
291 GR_DEFATTR(not_tagged);
292 GR_DEFATTR(not_dragged);
293 GR_DEFATTR(activity);
294 GR_DEFATTR(no_activity);
295
296
297 static void init_attr()
298 {
299     GR_ALLOCATTR_BEGIN;
300     GR_ALLOCATTR(active);
301     GR_ALLOCATTR(inactive);
302     GR_ALLOCATTR(selected);
303     GR_ALLOCATTR(tagged);
304     GR_ALLOCATTR(not_tagged);
305     GR_ALLOCATTR(not_dragged);
306     GR_ALLOCATTR(no_activity);
307     GR_ALLOCATTR(activity);
308     GR_ALLOCATTR_END;
309 }
310
311
312 static void screen_do_update_infowin(WScreen *scr)
313 {
314     WRegion *reg=mplex_mx_current(&(scr->mplex));
315     bool tag=(reg!=NULL && region_is_tagged(reg));
316     bool act=(reg!=NULL && region_is_activity_r(reg) && !REGION_IS_ACTIVE(scr));
317     bool sac=REGION_IS_ACTIVE(scr);
318     
319     if(tag || act){
320         const char *n=region_displayname(reg);
321         WInfoWin *iw;
322                 
323         screen_windowinfo(scr, n);
324         
325         iw=(WInfoWin*)scr->infowin_watch.obj;
326         
327         if(iw!=NULL){
328             GrStyleSpec *spec=infowin_stylespec(iw);
329             
330             init_attr();
331             
332             gr_stylespec_unalloc(spec);
333             
334             gr_stylespec_set(spec, GR_ATTR(selected));
335             gr_stylespec_set(spec, GR_ATTR(not_dragged));
336             gr_stylespec_set(spec, sac ? GR_ATTR(active) : GR_ATTR(inactive));
337             gr_stylespec_set(spec, tag ? GR_ATTR(tagged) : GR_ATTR(not_tagged));
338             gr_stylespec_set(spec, act ? GR_ATTR(activity) : GR_ATTR(no_activity));
339         }
340             
341     }else{
342         screen_nowindowinfo(scr);
343     }
344 }
345
346
347
348 /*}}}*/
349
350
351 /*{{{ Notification callbacks and deferred updates*/
352
353
354 void screen_update_infowin(WScreen *scr)
355 {
356     mainloop_defer_action((Obj*)scr, 
357                           (WDeferredAction*)screen_do_update_infowin);
358 }
359
360
361 void screen_update_notifywin(WScreen *scr)
362 {
363     mainloop_defer_action((Obj*)scr, 
364                           (WDeferredAction*)screen_do_update_notifywin);
365 }
366
367
368 void screen_managed_notify(WScreen *scr, WRegion *reg, WRegionNotify how)
369 {
370     if(how==ioncore_g.notifies.tag)
371         screen_update_infowin(scr);
372 }
373
374
375 void ioncore_screen_activity_notify(WRegion *reg, WRegionNotify how)
376 {
377     if(how==ioncore_g.notifies.activity){
378         screen_update_notifywin(region_screen_of(reg));
379     }else if(how==ioncore_g.notifies.name){
380         WScreen *scr=region_screen_of(reg);
381         if(region_is_activity(reg))
382             screen_update_notifywin(scr);
383         if((WRegion*)scr==REGION_MANAGER(reg))
384             screen_do_update_infowin(scr);
385     }
386 }
387
388
389 /*}}}*/
390