chiark / gitweb /
Imported Upstream version 1.0.0
[e16] / src / icons.c
1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2004-2008 Kim Woelders
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies of the Software, its documentation and marketing & publicity
14  * materials, and acknowledgment shall be given in the documentation, materials
15  * and software packages that this Software was used.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include "E.h"
25 #include "eimage.h"
26 #include "ewins.h"
27 #include "iclass.h"
28 #include "icons.h"
29 #include "windowmatch.h"
30 #include "xwin.h"
31
32 static int
33 NetwmIconFindBestSize(unsigned int *val, unsigned int len, int size)
34 {
35    unsigned int        i, j, sj, sbest, sz;
36    int                 k = -1;
37
38    sz = (unsigned int)size;
39    sj = sbest = 0;
40    for (i = 0; i < len;)
41      {
42         j = i;
43         i += 2 + val[i] * val[i + 1];
44         if (i > len)
45            break;
46         /* Valid */
47         sj = val[j];
48         if (sj == sz)
49           {
50              k = j;
51              break;             /* First exact match */
52           }
53         if (sj > sz)
54           {
55              if (sbest > sz && sj >= sbest)
56                 continue;
57           }
58         else
59           {
60              if (sj <= sbest)
61                 continue;
62           }
63         k = j;
64         sbest = sj;
65      }
66
67    return k;
68 }
69
70 static void
71 IB_IconGetSize(int ww, int hh, int size, int scale, int *pw, int *ph)
72 {
73    int                 w, h;
74
75    w = h = size;
76    w *= scale;
77    h *= scale;
78
79    if (ww > hh)
80       h = (w * hh) / ww;
81    else
82       w = (h * ww) / hh;
83    if (w < 4)
84       w = 4;
85    if (h < 4)
86       h = 4;
87    if (w > ww || h > hh)
88      {
89         w = ww;
90         h = hh;
91      }
92
93    *pw = w;
94    *ph = h;
95 }
96
97 static EImage      *
98 IB_SnapEWin(EWin * ewin, int size)
99 {
100    /* Make snapshot of window */
101    int                 w, h, ww, hh;
102    EImage             *im;
103    Drawable            draw;
104
105    if (!EoIsShown(ewin))
106       return NULL;
107
108    ww = EoGetW(ewin);
109    hh = EoGetH(ewin);
110    if (ww <= 0 || hh <= 0)
111       return NULL;
112
113    if (ewin->state.shaded)
114       EwinInstantUnShade(ewin);
115    EwinRaise(ewin);
116
117    /* Oversample for nicer snapshots */
118    IB_IconGetSize(ww, hh, size, 4, &w, &h);
119
120    draw = EoGetPixmap(ewin);
121    if (draw != None)
122      {
123         Pixmap              mask;
124
125         mask = EWindowGetShapePixmap(EoGetWin(ewin));
126         im = EImageGrabDrawableScaled(EoGetWin(ewin), draw, mask, 0, 0, ww, hh,
127                                       w, h, !EServerIsGrabbed(), 0);
128         if (mask)
129            EFreePixmap(mask);
130      }
131    else
132      {
133         draw = EoGetXwin(ewin);
134         im = EImageGrabDrawableScaled(EoGetWin(ewin), draw, None, 0, 0, ww, hh,
135                                       w, h, !EServerIsGrabbed(), 1);
136      }
137    EImageSetHasAlpha(im, 1);
138
139    return im;
140 }
141
142 static EImage      *
143 IB_GetAppIcon(EWin * ewin, int size)
144 {
145    /* Get the applications icon pixmap/mask */
146    int                 w, h;
147    EImage             *im;
148
149    if (ewin->ewmh.wm_icon)
150      {
151         int                 x;
152
153         x = NetwmIconFindBestSize(ewin->ewmh.wm_icon, ewin->ewmh.wm_icon_len,
154                                   size);
155         if (x >= 0)
156           {
157              im = EImageCreateFromData(ewin->ewmh.wm_icon[x],
158                                        ewin->ewmh.wm_icon[x + 1],
159                                        ewin->ewmh.wm_icon + x + 2);
160              EImageSetHasAlpha(im, 1);
161              return im;
162           }
163      }
164
165    if (!ewin->icccm.icon_pmap)
166       return NULL;
167
168    w = 0;
169    h = 0;
170    EXGetGeometry(ewin->icccm.icon_pmap, NULL, NULL, NULL, &w, &h, NULL, NULL);
171
172    if (w < 1 || h < 1)
173       return NULL;
174
175    im = EImageGrabDrawable(ewin->icccm.icon_pmap, ewin->icccm.icon_mask,
176                            0, 0, w, h, !EServerIsGrabbed());
177    EImageSetHasAlpha(im, 1);
178
179    return im;
180 }
181
182 static EImage      *
183 IB_GetEIcon(EWin * ewin)
184 {
185    /* get the icon defined for this window in E's iconf match file */
186    const char         *file;
187    EImage             *im;
188
189    file = WindowMatchEwinIcon(ewin);
190    if (!file)
191       return NULL;
192
193    im = ThemeImageLoad(file);
194
195    return im;
196 }
197
198 static EImage      *
199 IB_GetFallbackIcon(EWin * ewin, int size)
200 {
201    int                 w, h, ww, hh;
202    ImageClass         *ic;
203    EImage             *im;
204
205    ww = EoGetW(ewin);
206    hh = EoGetH(ewin);
207    if (ww <= 0)
208       ww = 1;
209    if (hh <= 0)
210       hh = 1;
211
212    IB_IconGetSize(ww, hh, size, 1, &w, &h);
213
214    ic = ImageclassFind("ICONBOX_HORIZONTAL", 1);
215    im = ImageclassGetImageBlended(ic, EoGetWin(ewin), w, h, 0, 0,
216                                   STATE_NORMAL, ST_SOLID);
217
218    return im;
219 }
220
221 #define N_MODES 5
222 #define N_TYPES 4
223 static const char   ewin_icon_modes[N_MODES][N_TYPES] = {
224    {EWIN_ICON_TYPE_SNAP, EWIN_ICON_TYPE_APP, EWIN_ICON_TYPE_IMG,
225     EWIN_ICON_TYPE_FB},
226    {EWIN_ICON_TYPE_APP, EWIN_ICON_TYPE_IMG, EWIN_ICON_TYPE_SNAP,
227     EWIN_ICON_TYPE_FB},
228    {EWIN_ICON_TYPE_IMG, EWIN_ICON_TYPE_SNAP, EWIN_ICON_TYPE_APP,
229     EWIN_ICON_TYPE_FB},
230    {EWIN_ICON_TYPE_IMG, EWIN_ICON_TYPE_APP, EWIN_ICON_TYPE_NONE,
231     EWIN_ICON_TYPE_NONE},
232    {EWIN_ICON_TYPE_APP, EWIN_ICON_TYPE_IMG, EWIN_ICON_TYPE_NONE,
233     EWIN_ICON_TYPE_NONE},
234 };
235
236 EImage             *
237 EwinIconImageGet(EWin * ewin, int size, int mode)
238 {
239    EImage             *im = NULL;
240    int                 i, type;
241
242    if (mode < 0 || mode >= N_MODES)
243       mode = 4;
244
245    for (i = 0; i < N_TYPES; i++)
246      {
247         type = ewin_icon_modes[mode][i];
248
249         switch (type)
250           {
251           default:
252              goto done;
253
254           case EWIN_ICON_TYPE_SNAP:
255              im = IB_SnapEWin(ewin, size);
256              break;
257
258           case EWIN_ICON_TYPE_APP:
259              im = IB_GetAppIcon(ewin, size);
260              break;
261
262           case EWIN_ICON_TYPE_IMG:
263              im = IB_GetEIcon(ewin);
264              break;
265
266           case EWIN_ICON_TYPE_FB:
267              im = IB_GetFallbackIcon(ewin, size);
268              break;
269           }
270         if (im)
271            goto done;
272      }
273
274  done:
275    return im;
276 }