/* * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors * Copyright (C) 2004-2021 Kim Woelders * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies of the Software, its documentation and marketing & publicity * materials, and acknowledgment shall be given in the documentation, materials * and software packages that this Software was used. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "E.h" #include "eimage.h" #include "ewins.h" #include "iclass.h" #include "icons.h" #include "timers.h" #include "windowmatch.h" #include "xwin.h" #define EWIN_ICON_TYPE_NONE 0 #define EWIN_ICON_TYPE_APP 1 #define EWIN_ICON_TYPE_IMG 2 #define EWIN_ICON_TYPE_SNAP 3 #define EWIN_ICON_TYPE_FB 4 static int NetwmIconFindBestSize(unsigned int *val, unsigned int len, int size) { unsigned int i, j, sj, sbest, sz; int k = -1; sz = (unsigned int)size; sbest = 0; for (i = 0; i < len;) { j = i; i += 2 + val[i] * val[i + 1]; if (i > len) break; /* Valid */ sj = val[j]; if (sj == sz) { k = j; break; /* First exact match */ } if (sj > sz) { if (sbest > sz && sj >= sbest) continue; } else { if (sj <= sbest) continue; } k = j; sbest = sj; } return k; } static void IB_IconGetSize(int ww, int hh, int size, int scale, int *pw, int *ph) { int w, h; w = h = size; w *= scale; h *= scale; if (ww > hh) h = (w * hh) / ww; else w = (h * ww) / hh; if (w < 4) w = 4; if (h < 4) h = 4; if (w > ww || h > hh) { w = ww; h = hh; } *pw = w; *ph = h; } static EImage * IB_SnapEWin(EWin *ewin, int size) { /* Make snapshot of window */ int w, h, ww, hh; int was_shaded; EImage *im; EX_Drawable draw; if (!EoIsShown(ewin)) return NULL; was_shaded = ewin->state.shaded; if (ewin->state.shaded) EwinInstantUnShade(ewin); EwinRaise(ewin); IdlersRun(); ww = EoGetW(ewin); hh = EoGetH(ewin); if (ww <= 0 || hh <= 0) return NULL; /* Oversample for nicer snapshots */ IB_IconGetSize(ww, hh, size, 4, &w, &h); draw = EoGetPixmap(ewin); if (draw != NoXID) { EX_Pixmap mask; mask = EWindowGetShapePixmap(EoGetWin(ewin)); im = EImageGrabDrawableScaled(EoGetWin(ewin), draw, mask, 0, 0, ww, hh, w, h, !EServerIsGrabbed(), 0); if (mask) EFreePixmap(mask); } else { draw = EoGetXwin(ewin); im = EImageGrabDrawableScaled(EoGetWin(ewin), draw, NoXID, 0, 0, ww, hh, w, h, !EServerIsGrabbed(), 1); } EImageSetHasAlpha(im, 1); if (was_shaded != ewin->state.shaded) EwinInstantShade(ewin, 0); return im; } static EImage * IB_GetAppIcon(EWin *ewin, int size) { /* Get the applications icon pixmap/mask */ int w, h; EImage *im; if (ewin->ewmh.wm_icon) { int x; x = NetwmIconFindBestSize(ewin->ewmh.wm_icon, ewin->ewmh.wm_icon_len, size); if (x >= 0) { im = EImageCreateFromData(ewin->ewmh.wm_icon[x], ewin->ewmh.wm_icon[x + 1], ewin->ewmh.wm_icon + x + 2); EImageSetHasAlpha(im, 1); return im; } } if (!ewin->icccm.icon_pmap) return NULL; EXGetSize(ewin->icccm.icon_pmap, &w, &h); if (w <= 0 || h <= 0) return NULL; im = EImageGrabDrawable(ewin->icccm.icon_pmap, ewin->icccm.icon_mask, 0, 0, w, h, !EServerIsGrabbed()); EImageSetHasAlpha(im, 1); return im; } static EImage * IB_GetEIcon(EWin *ewin) { /* get the icon defined for this window in E's iconf match file */ const char *file; EImage *im; file = WindowMatchEwinIcon(ewin); if (!file) return NULL; im = ThemeImageLoad(file); return im; } static EImage * IB_GetFallbackIcon(EWin *ewin, int size) { int w, h, ww, hh; ImageClass *ic; EImage *im; im = ThemeImageLoad("icons/default.png"); if (im) return im; ww = EoGetW(ewin); hh = EoGetH(ewin); if (ww <= 0) ww = 1; if (hh <= 0) hh = 1; IB_IconGetSize(ww, hh, size, 1, &w, &h); ic = ImageclassFind("ICONBOX_HORIZONTAL", 1); im = ImageclassGetImageBlended(ic, EoGetWin(ewin), w, h, 0, 0, STATE_NORMAL); return im; } #define N_MODES 5 #define N_TYPES 3 static const char ewin_icon_modes[N_MODES][N_TYPES] = { { EWIN_ICON_TYPE_SNAP, EWIN_ICON_TYPE_FB, EWIN_ICON_TYPE_NONE }, { EWIN_ICON_TYPE_APP, EWIN_ICON_TYPE_IMG, EWIN_ICON_TYPE_SNAP }, { EWIN_ICON_TYPE_IMG, EWIN_ICON_TYPE_APP, EWIN_ICON_TYPE_SNAP }, { EWIN_ICON_TYPE_APP, EWIN_ICON_TYPE_IMG, EWIN_ICON_TYPE_FB }, { EWIN_ICON_TYPE_IMG, EWIN_ICON_TYPE_APP, EWIN_ICON_TYPE_FB }, }; EImage * EwinIconImageGet(EWin *ewin, int size, int mode) { EImage *im = NULL; int i, type; if (mode < 0 || mode >= N_MODES) mode = 1; for (i = 0; i < N_TYPES; i++) { type = ewin_icon_modes[mode][i]; switch (type) { default: goto done; case EWIN_ICON_TYPE_SNAP: im = IB_SnapEWin(ewin, size); break; case EWIN_ICON_TYPE_APP: im = IB_GetAppIcon(ewin, size); break; case EWIN_ICON_TYPE_IMG: im = IB_GetEIcon(ewin); break; case EWIN_ICON_TYPE_FB: im = IB_GetFallbackIcon(ewin, size); break; } if (im) goto done; } done: return im; }