tabbed-icon-20200905-2da4e96.diff - sites - public wiki contents of suckless.org
 (HTM) git clone git://git.suckless.org/sites
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       tabbed-icon-20200905-2da4e96.diff (9398B)
       ---
            1 diff --git a/Makefile b/Makefile
            2 index 1b95d15..e571818 100644
            3 --- a/Makefile
            4 +++ b/Makefile
            5 @@ -37,7 +37,7 @@ dist: clean
            6          @echo creating dist tarball
            7          @mkdir -p tabbed-${VERSION}
            8          @cp -R LICENSE Makefile README config.def.h config.mk \
            9 -                tabbed.1 arg.h ${SRC} tabbed-${VERSION}
           10 +                tabbed.1 arg.h icon.h ${SRC} tabbed-${VERSION}
           11          @tar -cf tabbed-${VERSION}.tar tabbed-${VERSION}
           12          @gzip tabbed-${VERSION}.tar
           13          @rm -rf tabbed-${VERSION}
           14 diff --git a/TODO b/TODO
           15 index 8e1986d..dbcb930 100644
           16 --- a/TODO
           17 +++ b/TODO
           18 @@ -1,4 +1,3 @@
           19  # TODO
           20  * add some way to detach windows
           21  * add some way to attach windows
           22 -
           23 diff --git a/icon.h b/icon.h
           24 new file mode 100644
           25 index 0000000..e2ef631
           26 --- /dev/null
           27 +++ b/icon.h
           28 @@ -0,0 +1,41 @@
           29 +/* GIMP RGBA C-Source image dump (icon.c) */
           30 +
           31 +#define ICON_WIDTH (16)
           32 +#define ICON_HEIGHT (16)
           33 +#define ICON_BYTES_PER_PIXEL (4) /* 2:RGB16, 3:RGB, 4:RGBA */
           34 +#define ICON_COMMENT \
           35 +  "GIMP -> Export -> C-Source -> Prefixed name = ICON, Use macros, Save alpha"
           36 +#define ICON_PIXEL_DATA ((unsigned char*) ICON_pixel_data)
           37 +static const unsigned char ICON_pixel_data[16 * 16 * 4 + 1] =
           38 +("\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\000\000\000\000\000\000\000"
           39 + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000"
           40 + "\000\377\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
           41 + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000"
           42 + "\000\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
           43 + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000"
           44 + "\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377"
           45 + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000"
           46 + "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377"
           47 + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000"
           48 + "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377"
           49 + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000"
           50 + "\000\377\000\000\000\377\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\000\000\000"
           51 + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000"
           52 + "\000\377\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
           53 + "\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377"
           54 + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377"
           55 + "\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
           56 + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\000"
           57 + "\000\000\377\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377"
           58 + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000"
           59 + "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377"
           60 + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000"
           61 + "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377"
           62 + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000"
           63 + "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\000"
           64 + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
           65 + "\000\000\377\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\001\000"
           66 + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000"
           67 + "\000\000\377\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
           68 + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\000\000\000\000"
           69 + "\000\000\000\000\000\000\000\000\377\000\000\000\377");
           70 diff --git a/tabbed.c b/tabbed.c
           71 index eafe28a..ec6212e 100644
           72 --- a/tabbed.c
           73 +++ b/tabbed.c
           74 @@ -18,6 +18,7 @@
           75  #include <X11/Xft/Xft.h>
           76  
           77  #include "arg.h"
           78 +#include "icon.h"
           79  
           80  /* XEMBED messages */
           81  #define XEMBED_EMBEDDED_NOTIFY          0
           82 @@ -49,7 +50,7 @@
           83  
           84  enum { ColFG, ColBG, ColLast };       /* color */
           85  enum { WMProtocols, WMDelete, WMName, WMState, WMFullscreen,
           86 -       XEmbed, WMSelectTab, WMLast }; /* default atoms */
           87 +       XEmbed, WMSelectTab, WMIcon, WMLast }; /* default atoms */
           88  
           89  typedef union {
           90          int i;
           91 @@ -135,6 +136,7 @@ static void updatenumlockmask(void);
           92  static void updatetitle(int c);
           93  static int xerror(Display *dpy, XErrorEvent *ee);
           94  static void xsettitle(Window w, const char *str);
           95 +static void xseticon(void);
           96  
           97  /* variables */
           98  static int screen;
           99 @@ -169,6 +171,7 @@ static char winid[64];
          100  static char **cmd;
          101  static char *wmname = "tabbed";
          102  static const char *geometry;
          103 +static unsigned long icon[ICON_WIDTH * ICON_HEIGHT + 2];
          104  
          105  char *argv0;
          106  
          107 @@ -455,6 +458,8 @@ focus(int c)
          108                          n += snprintf(&buf[n], sizeof(buf) - n, " %s", cmd[i]);
          109  
          110                  xsettitle(win, buf);
          111 +                XChangeProperty(dpy, win, wmatom[WMIcon], XA_CARDINAL, 32,
          112 +                                PropModeReplace, (unsigned char *) icon, ICON_WIDTH * ICON_HEIGHT + 2);
          113                  XRaiseWindow(dpy, win);
          114  
          115                  return;
          116 @@ -474,6 +479,7 @@ focus(int c)
          117                  lastsel = sel;
          118                  sel = c;
          119          }
          120 +        xseticon();
          121  
          122          if (clients[c]->urgent && (wmh = XGetWMHints(dpy, clients[c]->win))) {
          123                  wmh->flags &= ~XUrgencyHint;
          124 @@ -868,9 +874,13 @@ propertynotify(const XEvent *e)
          125                          }
          126                  }
          127                  XFree(wmh);
          128 +                if (c == sel)
          129 +                        xseticon();
          130          } else if (ev->state != PropertyDelete && ev->atom == XA_WM_NAME &&
          131                     (c = getclient(ev->window)) > -1) {
          132                  updatetitle(c);
          133 +        } else if (ev->atom == wmatom[WMIcon] && (c = getclient(ev->window)) > -1 && c == sel) {
          134 +                xseticon();
          135          }
          136  }
          137  
          138 @@ -995,6 +1005,7 @@ setup(void)
          139          wmatom[WMSelectTab] = XInternAtom(dpy, "_TABBED_SELECT_TAB", False);
          140          wmatom[WMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
          141          wmatom[XEmbed] = XInternAtom(dpy, "_XEMBED", False);
          142 +        wmatom[WMIcon] = XInternAtom(dpy, "_NET_WM_ICON", False);
          143  
          144          /* init appearance */
          145          wx = 0;
          146 @@ -1074,6 +1085,17 @@ setup(void)
          147          snprintf(winid, sizeof(winid), "%lu", win);
          148          setenv("XEMBED", winid, 1);
          149  
          150 +        /* change icon from RGBA to ARGB */
          151 +        icon[0] = ICON_WIDTH;
          152 +        icon[1] =  ICON_HEIGHT;
          153 +        for (int i = 0; i < ICON_WIDTH * ICON_HEIGHT; ++i) {
          154 +                icon[i + 2] =
          155 +                    ICON_PIXEL_DATA[i * 4 + 3] << 24 |
          156 +                    ICON_PIXEL_DATA[i * 4 + 0] <<  0 |
          157 +                    ICON_PIXEL_DATA[i * 4 + 1] <<  8 |
          158 +                    ICON_PIXEL_DATA[i * 4 + 2] << 16 ;
          159 +        }
          160 +
          161          nextfocus = foreground;
          162          focus(-1);
          163  }
          164 @@ -1265,6 +1287,46 @@ xsettitle(Window w, const char *str)
          165          }
          166  }
          167  
          168 +void
          169 +xseticon(void)
          170 +{
          171 +        Atom ret_type;
          172 +        XWMHints *wmh, *cwmh;
          173 +        int ret_format;
          174 +        unsigned long ret_nitems, ret_nleft;
          175 +        long offset = 0L;
          176 +        unsigned char *data;
          177 +
          178 +        wmh = XGetWMHints(dpy, win);
          179 +        wmh->flags &= ~(IconPixmapHint | IconMaskHint);
          180 +        wmh->icon_pixmap = wmh->icon_mask = None;
          181 +
          182 +
          183 +        if (XGetWindowProperty(dpy, clients[sel]->win, wmatom[WMIcon], offset, LONG_MAX, False,
          184 +                               XA_CARDINAL, &ret_type, &ret_format, &ret_nitems,
          185 +                               &ret_nleft, &data) == Success &&
          186 +            ret_type == XA_CARDINAL && ret_format == 32)
          187 +        {
          188 +                XChangeProperty(dpy, win, wmatom[WMIcon], XA_CARDINAL, 32,
          189 +                                PropModeReplace, data, ret_nitems);
          190 +        } else if ((cwmh = XGetWMHints(dpy, clients[sel]->win)) && cwmh->flags & IconPixmapHint) {
          191 +                XDeleteProperty(dpy, win, wmatom[WMIcon]);
          192 +                wmh->flags |= IconPixmapHint;
          193 +                wmh->icon_pixmap = cwmh->icon_pixmap;
          194 +                if (cwmh->flags & IconMaskHint) {
          195 +                        wmh->flags |= IconMaskHint;
          196 +                        wmh->icon_mask = cwmh->icon_mask;
          197 +                }
          198 +                XFree(cwmh);
          199 +        } else {
          200 +                XChangeProperty(dpy, win, wmatom[WMIcon], XA_CARDINAL, 32,
          201 +                                PropModeReplace, (unsigned char *) icon, ICON_WIDTH * ICON_HEIGHT + 2);
          202 +        }
          203 +        XSetWMHints(dpy, win, wmh);
          204 +        XFree(wmh);
          205 +        XFree(data);
          206 +}
          207 +
          208  void
          209  usage(void)
          210  {