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