1 /*
2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2004-2021 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 "timers.h"
30 #include "windowmatch.h"
31 #include "xwin.h"
32
33 #define EWIN_ICON_TYPE_NONE 0
34 #define EWIN_ICON_TYPE_APP 1
35 #define EWIN_ICON_TYPE_IMG 2
36 #define EWIN_ICON_TYPE_SNAP 3
37 #define EWIN_ICON_TYPE_FB 4
38
39 static int
NetwmIconFindBestSize(unsigned int * val,unsigned int len,int size)40 NetwmIconFindBestSize(unsigned int *val, unsigned int len, int size)
41 {
42 unsigned int i, j, sj, sbest, sz;
43 int k = -1;
44
45 sz = (unsigned int)size;
46 sbest = 0;
47 for (i = 0; i < len;)
48 {
49 j = i;
50 i += 2 + val[i] * val[i + 1];
51 if (i > len)
52 break;
53 /* Valid */
54 sj = val[j];
55 if (sj == sz)
56 {
57 k = j;
58 break; /* First exact match */
59 }
60 if (sj > sz)
61 {
62 if (sbest > sz && sj >= sbest)
63 continue;
64 }
65 else
66 {
67 if (sj <= sbest)
68 continue;
69 }
70 k = j;
71 sbest = sj;
72 }
73
74 return k;
75 }
76
77 static void
IB_IconGetSize(int ww,int hh,int size,int scale,int * pw,int * ph)78 IB_IconGetSize(int ww, int hh, int size, int scale, int *pw, int *ph)
79 {
80 int w, h;
81
82 w = h = size;
83 w *= scale;
84 h *= scale;
85
86 if (ww > hh)
87 h = (w * hh) / ww;
88 else
89 w = (h * ww) / hh;
90 if (w < 4)
91 w = 4;
92 if (h < 4)
93 h = 4;
94 if (w > ww || h > hh)
95 {
96 w = ww;
97 h = hh;
98 }
99
100 *pw = w;
101 *ph = h;
102 }
103
104 static EImage *
IB_SnapEWin(EWin * ewin,int size)105 IB_SnapEWin(EWin * ewin, int size)
106 {
107 /* Make snapshot of window */
108 int w, h, ww, hh;
109 int was_shaded;
110 EImage *im;
111 EX_Drawable draw;
112
113 if (!EoIsShown(ewin))
114 return NULL;
115
116 was_shaded = ewin->state.shaded;
117
118 if (ewin->state.shaded)
119 EwinInstantUnShade(ewin);
120 EwinRaise(ewin);
121 IdlersRun();
122
123 ww = EoGetW(ewin);
124 hh = EoGetH(ewin);
125 if (ww <= 0 || hh <= 0)
126 return NULL;
127
128 /* Oversample for nicer snapshots */
129 IB_IconGetSize(ww, hh, size, 4, &w, &h);
130
131 draw = EoGetPixmap(ewin);
132 if (draw != NoXID)
133 {
134 EX_Pixmap mask;
135
136 mask = EWindowGetShapePixmap(EoGetWin(ewin));
137 im = EImageGrabDrawableScaled(EoGetWin(ewin), draw, mask, 0, 0, ww, hh,
138 w, h, !EServerIsGrabbed(), 0);
139 if (mask)
140 EFreePixmap(mask);
141 }
142 else
143 {
144 draw = EoGetXwin(ewin);
145 im = EImageGrabDrawableScaled(EoGetWin(ewin), draw, NoXID, 0, 0, ww, hh,
146 w, h, !EServerIsGrabbed(), 1);
147 }
148 EImageSetHasAlpha(im, 1);
149
150 if (was_shaded != ewin->state.shaded)
151 EwinInstantShade(ewin, 0);
152
153 return im;
154 }
155
156 static EImage *
IB_GetAppIcon(EWin * ewin,int size)157 IB_GetAppIcon(EWin * ewin, int size)
158 {
159 /* Get the applications icon pixmap/mask */
160 int w, h;
161 EImage *im;
162
163 if (ewin->ewmh.wm_icon)
164 {
165 int x;
166
167 x = NetwmIconFindBestSize(ewin->ewmh.wm_icon, ewin->ewmh.wm_icon_len,
168 size);
169 if (x >= 0)
170 {
171 im = EImageCreateFromData(ewin->ewmh.wm_icon[x],
172 ewin->ewmh.wm_icon[x + 1],
173 ewin->ewmh.wm_icon + x + 2);
174 EImageSetHasAlpha(im, 1);
175 return im;
176 }
177 }
178
179 if (!ewin->icccm.icon_pmap)
180 return NULL;
181
182 EXGetSize(ewin->icccm.icon_pmap, &w, &h);
183 if (w <= 0 || h <= 0)
184 return NULL;
185
186 im = EImageGrabDrawable(ewin->icccm.icon_pmap, ewin->icccm.icon_mask,
187 0, 0, w, h, !EServerIsGrabbed());
188 EImageSetHasAlpha(im, 1);
189
190 return im;
191 }
192
193 static EImage *
IB_GetEIcon(EWin * ewin)194 IB_GetEIcon(EWin * ewin)
195 {
196 /* get the icon defined for this window in E's iconf match file */
197 const char *file;
198 EImage *im;
199
200 file = WindowMatchEwinIcon(ewin);
201 if (!file)
202 return NULL;
203
204 im = ThemeImageLoad(file);
205
206 return im;
207 }
208
209 static EImage *
IB_GetFallbackIcon(EWin * ewin,int size)210 IB_GetFallbackIcon(EWin * ewin, int size)
211 {
212 int w, h, ww, hh;
213 ImageClass *ic;
214 EImage *im;
215
216 im = ThemeImageLoad("icons/default.png");
217 if (im)
218 return im;
219
220 ww = EoGetW(ewin);
221 hh = EoGetH(ewin);
222 if (ww <= 0)
223 ww = 1;
224 if (hh <= 0)
225 hh = 1;
226
227 IB_IconGetSize(ww, hh, size, 1, &w, &h);
228
229 ic = ImageclassFind("ICONBOX_HORIZONTAL", 1);
230 im = ImageclassGetImageBlended(ic, EoGetWin(ewin), w, h, 0, 0, STATE_NORMAL);
231
232 return im;
233 }
234
235 #define N_MODES 5
236 #define N_TYPES 3
237 static const char ewin_icon_modes[N_MODES][N_TYPES] = {
238 {EWIN_ICON_TYPE_SNAP, EWIN_ICON_TYPE_FB, EWIN_ICON_TYPE_NONE},
239 {EWIN_ICON_TYPE_APP, EWIN_ICON_TYPE_IMG, EWIN_ICON_TYPE_SNAP},
240 {EWIN_ICON_TYPE_IMG, EWIN_ICON_TYPE_APP, EWIN_ICON_TYPE_SNAP},
241 {EWIN_ICON_TYPE_APP, EWIN_ICON_TYPE_IMG, EWIN_ICON_TYPE_FB},
242 {EWIN_ICON_TYPE_IMG, EWIN_ICON_TYPE_APP, EWIN_ICON_TYPE_FB},
243 };
244
245 EImage *
EwinIconImageGet(EWin * ewin,int size,int mode)246 EwinIconImageGet(EWin * ewin, int size, int mode)
247 {
248 EImage *im = NULL;
249 int i, type;
250
251 if (mode < 0 || mode >= N_MODES)
252 mode = 1;
253
254 for (i = 0; i < N_TYPES; i++)
255 {
256 type = ewin_icon_modes[mode][i];
257
258 switch (type)
259 {
260 default:
261 goto done;
262
263 case EWIN_ICON_TYPE_SNAP:
264 im = IB_SnapEWin(ewin, size);
265 break;
266
267 case EWIN_ICON_TYPE_APP:
268 im = IB_GetAppIcon(ewin, size);
269 break;
270
271 case EWIN_ICON_TYPE_IMG:
272 im = IB_GetEIcon(ewin);
273 break;
274
275 case EWIN_ICON_TYPE_FB:
276 im = IB_GetFallbackIcon(ewin, size);
277 break;
278 }
279 if (im)
280 goto done;
281 }
282
283 done:
284 return im;
285 }
286