e16/src/icons.c

287 lines
7.0 KiB
C

/*
* 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;
}