dwm-preview-all-windows-20250407-e381933.diff - sites - public wiki contents of suckless.org
 (HTM) git clone git://git.suckless.org/sites
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       dwm-preview-all-windows-20250407-e381933.diff (12466B)
       ---
            1 From e381933255718c6ed30e1b930d8fd76d62ccda75 Mon Sep 17 00:00:00 2001
            2 From: elbachir-one <bachiralfa@gmail.com>
            3 Date: Mon, 7 Apr 2025 06:02:14 +0100
            4 Subject: [PATCH] Added some keys to move/select around windows in the preview
            5 
            6 ---
            7  config.def.h |   4 +
            8  config.mk    |   2 +-
            9  dwm.c        | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++
           10  3 files changed, 312 insertions(+), 1 deletion(-)
           11 
           12 diff --git a/config.def.h b/config.def.h
           13 index 4412cb1..37feaf7 100644
           14 --- a/config.def.h
           15 +++ b/config.def.h
           16 @@ -1,5 +1,8 @@
           17  /* See LICENSE file for copyright and license details. */
           18  
           19 +//#define ACTUALFULLSCREEN /* Uncomment if the actualfullscreen patch is added */
           20 +//#define AWESOMEBAR /* Uncommnet if the awesomebar patch is used */
           21 +
           22  /* appearance */
           23  static const unsigned int borderpx  = 1;        /* border pixel of windows */
           24  static const unsigned int snap      = 32;       /* snap pixel */
           25 @@ -95,6 +98,7 @@ static const Key keys[] = {
           26          TAGKEYS(                        XK_8,                      7)
           27          TAGKEYS(                        XK_9,                      8)
           28          { MODKEY|ShiftMask,             XK_q,      quit,           {0} },
           29 +        { MODKEY,                       XK_r,      togglepreviewallwin,  {0} },
           30  };
           31  
           32  /* button definitions */
           33 diff --git a/config.mk b/config.mk
           34 index 8efca9a..8df2978 100644
           35 --- a/config.mk
           36 +++ b/config.mk
           37 @@ -23,7 +23,7 @@ FREETYPEINC = /usr/include/freetype2
           38  
           39  # includes and libs
           40  INCS = -I${X11INC} -I${FREETYPEINC}
           41 -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
           42 +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lXrender
           43  
           44  # flags
           45  CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
           46 diff --git a/dwm.c b/dwm.c
           47 index 1443802..6d38874 100644
           48 --- a/dwm.c
           49 +++ b/dwm.c
           50 @@ -40,6 +40,7 @@
           51  #include <X11/extensions/Xinerama.h>
           52  #endif /* XINERAMA */
           53  #include <X11/Xft/Xft.h>
           54 +#include <X11/extensions/Xrender.h>
           55  
           56  #include "drw.h"
           57  #include "util.h"
           58 @@ -83,6 +84,16 @@ typedef struct {
           59  
           60  typedef struct Monitor Monitor;
           61  typedef struct Client Client;
           62 +
           63 +typedef struct Preview Preview;
           64 +struct Preview {
           65 +        XImage *orig_image;
           66 +        XImage *scaled_image;
           67 +        Window win;
           68 +        unsigned int x, y;
           69 +        Preview *next;
           70 +};
           71 +
           72  struct Client {
           73          char name[256];
           74          float mina, maxa;
           75 @@ -96,6 +107,7 @@ struct Client {
           76          Client *snext;
           77          Monitor *mon;
           78          Window win;
           79 +        Preview pre;
           80  };
           81  
           82  typedef struct {
           83 @@ -232,8 +244,14 @@ static int xerror(Display *dpy, XErrorEvent *ee);
           84  static int xerrordummy(Display *dpy, XErrorEvent *ee);
           85  static int xerrorstart(Display *dpy, XErrorEvent *ee);
           86  static void zoom(const Arg *arg);
           87 +static void togglepreviewallwin();
           88 +static void highlightwindow(int idx, Monitor *m);
           89 +static void setpreviewwindowsizepositions(unsigned int n, Monitor *m, unsigned int gappo, unsigned int gappi);
           90 +static XImage *getwindowximage(Client *c);
           91 +static XImage *scaledownimage(XImage *orig_image, unsigned int cw, unsigned int ch);
           92  
           93  /* variables */
           94 +
           95  static const char broken[] = "broken";
           96  static char stext[256];
           97  static int screen;
           98 @@ -266,6 +284,7 @@ static Display *dpy;
           99  static Drw *drw;
          100  static Monitor *mons, *selmon;
          101  static Window root, wmcheckwin;
          102 +static int previewallwin = 0;
          103  
          104  /* configuration, allows nested code to access above variables */
          105  #include "config.h"
          106 @@ -2139,6 +2158,294 @@ zoom(const Arg *arg)
          107          pop(c);
          108  }
          109  
          110 +void
          111 +togglepreviewallwin() {
          112 +        if (previewallwin) {  /* If already active, disable preview */
          113 +                previewallwin = 0;
          114 +                for (Client *c = selmon->clients; c; c = c->next) {
          115 +                        XUnmapWindow(dpy, c->pre.win);
          116 +                        XMapWindow(dpy, c->win);
          117 +                        if (c->pre.orig_image)
          118 +                                XDestroyImage(c->pre.orig_image);
          119 +                        if (c->pre.scaled_image)
          120 +                                XDestroyImage(c->pre.scaled_image);
          121 +                }
          122 +                arrange(selmon);
          123 +                focus(NULL);
          124 +                return;  /* Exit function early to prevent running again */
          125 +        }
          126 +
          127 +        previewallwin = 1;  /* Enable preview mode */
          128 +        Monitor *m = selmon;
          129 +        Client *c, *focus_c = NULL;
          130 +        unsigned int n = 0;
          131 +
          132 +        for (c = m->clients; c; c = c->next, n++) {
          133 +#ifdef ACTUALFULLSCREEN
          134 +                if (c->isfullscreen)
          135 +                        togglefullscr(&(Arg){0});
          136 +#endif
          137 +#ifdef AWESOMEBAR
          138 +                if (HIDDEN(c))
          139 +                        continue;
          140 +#endif
          141 +                c->pre.orig_image = getwindowximage(c);
          142 +        }
          143 +
          144 +        if (n == 0) return;
          145 +
          146 +        setpreviewwindowsizepositions(n, m, 60, 15);
          147 +        XEvent event;
          148 +
          149 +        for (c = m->clients; c; c = c->next) {
          150 +                if (!c->pre.win)
          151 +                        c->pre.win = XCreateSimpleWindow(dpy, root, c->pre.x, c->pre.y,
          152 +                                        c->pre.scaled_image->width, c->pre.scaled_image->height,
          153 +                                        1, BlackPixel(dpy, screen), WhitePixel(dpy, screen));
          154 +                else
          155 +                        XMoveResizeWindow(dpy, c->pre.win, c->pre.x, c->pre.y,
          156 +                                        c->pre.scaled_image->width, c->pre.scaled_image->height);
          157 +
          158 +                XSetWindowBorder(dpy, c->pre.win, scheme[SchemeNorm][ColBorder].pixel);
          159 +                XUnmapWindow(dpy, c->win);
          160 +
          161 +                if (c->pre.win) {
          162 +                        XSelectInput(dpy, c->pre.win, ButtonPress | EnterWindowMask | LeaveWindowMask);
          163 +                        XMapWindow(dpy, c->pre.win);
          164 +                        GC gc = XCreateGC(dpy, c->pre.win, 0, NULL);
          165 +                        XPutImage(dpy, c->pre.win, gc, c->pre.scaled_image, 0, 0, 0, 0,
          166 +                                        c->pre.scaled_image->width, c->pre.scaled_image->height);
          167 +                }
          168 +        }
          169 +
          170 +        int selected_idx = 0;
          171 +
          172 +        while (previewallwin) {
          173 +                XNextEvent(dpy, &event);
          174 +                if (event.type == ButtonPress) {
          175 +                        if (event.xbutton.button == Button1) { /* Left-click to select a window */
          176 +                                for (c = selmon->clients; c; c = c->next) {
          177 +                                        if (event.xbutton.window == c->pre.win) {
          178 +                                                previewallwin = 0;
          179 +                                                selmon->tagset[selmon->seltags] = c->tags;
          180 +                                                focus(c);
          181 +                                                arrange(selmon); /* Ensure layout updates correctly */
          182 +                                                break;
          183 +                                        }
          184 +                                }
          185 +                        }
          186 +                }
          187 +                if (event.type == KeyPress) {
          188 +                        if (event.xkey.keycode == XKeysymToKeycode(dpy, XK_j)) {
          189 +                                if (selected_idx < n - 1) {
          190 +                                        selected_idx++;
          191 +                                }
          192 +                                highlightwindow(selected_idx, m);
          193 +                        }
          194 +                        if (event.xkey.keycode == XKeysymToKeycode(dpy, XK_k)) {
          195 +                                if (selected_idx > 0) {
          196 +                                        selected_idx--;
          197 +                                }
          198 +                                highlightwindow(selected_idx, m);
          199 +                        }
          200 +                        if (event.xkey.keycode == XKeysymToKeycode(dpy, XK_Return)) {
          201 +                                previewallwin = 0;
          202 +                                Client *selected_client = NULL;
          203 +                                int idx = 0;
          204 +
          205 +                                for (c = m->clients; c; c = c->next, idx++) {
          206 +                                        if (idx == selected_idx) {
          207 +                                                selected_client = c;
          208 +                                                break;
          209 +                                        }
          210 +                                }
          211 +                                if (selected_client) {
          212 +                                        selmon->tagset[selmon->seltags] = selected_client->tags;
          213 +                                        focus(selected_client);
          214 +                                        arrange(selmon);
          215 +                                }
          216 +                        }
          217 +                        if (event.xkey.keycode == XKeysymToKeycode(dpy, XK_r)) {
          218 +                                previewallwin = 0;
          219 +                                Client *selected_client = NULL;
          220 +                                int idx = 0;
          221 +
          222 +                                for (c = m->clients; c; c = c->next, idx++) {
          223 +                                        if (idx == selected_idx) {
          224 +                                                selected_client = c;
          225 +                                                break;
          226 +                                        }
          227 +                                }
          228 +                                if (selected_client) {
          229 +                                        selmon->tagset[selmon->seltags] = selected_client->tags;
          230 +                                        focus(selected_client);
          231 +                                        arrange(selmon);
          232 +                                }
          233 +                        }
          234 +                }
          235 +
          236 +                if (event.type == EnterNotify) {
          237 +                        for (c = m->clients; c; c = c->next) {
          238 +                                if (event.xcrossing.window == c->pre.win) {
          239 +                                        XSetWindowBorder(dpy, c->pre.win, scheme[SchemeSel][ColBorder].pixel);
          240 +                                        break;
          241 +                                }
          242 +                        }
          243 +                }
          244 +                if (event.type == LeaveNotify) {
          245 +                        for (c = m->clients; c; c = c->next) {
          246 +                                if (event.xcrossing.window == c->pre.win) {
          247 +                                        XSetWindowBorder(dpy, c->pre.win, scheme[SchemeNorm][ColBorder].pixel);
          248 +                                        break;
          249 +                                }
          250 +                        }
          251 +                }
          252 +        }
          253 +        for (c = selmon->clients; c; c = c->next) { /* Restore all windows when exiting */
          254 +                XUnmapWindow(dpy, c->pre.win);
          255 +                XMapWindow(dpy, c->win);
          256 +                if (c->pre.orig_image)
          257 +                        XDestroyImage(c->pre.orig_image);
          258 +                if (c->pre.scaled_image)
          259 +                        XDestroyImage(c->pre.scaled_image);
          260 +        }
          261 +        arrange(m);
          262 +        focus(focus_c);
          263 +}
          264 +
          265 +void
          266 +highlightwindow(int idx, Monitor *m) {
          267 +        int i = 0;
          268 +        Client *c;
          269 +        for (c = m->clients; c; c = c->next, i++) {
          270 +                if (i == idx) {
          271 +                        XSetWindowBorder(dpy, c->pre.win, scheme[SchemeSel][ColBorder].pixel); /* Highlight selected window */
          272 +                } else {
          273 +                        XSetWindowBorder(dpy, c->pre.win, scheme[SchemeNorm][ColBorder].pixel); /* Reset border for other windows */
          274 +                }
          275 +        }
          276 +}
          277 +
          278 +void
          279 +setpreviewwindowsizepositions(unsigned int n, Monitor *m, unsigned int gappo, unsigned int gappi){
          280 +        unsigned int i, j;
          281 +        unsigned int cx, cy, cw, ch, cmaxh;
          282 +        unsigned int cols, rows;
          283 +        Client *c, *tmpc;
          284 +
          285 +        if (n == 1) {
          286 +                c = m->clients;
          287 +                cw = (m->ww - 2 * gappo) * 0.8;
          288 +                ch = (m->wh - 2 * gappo) * 0.9;
          289 +                c->pre.scaled_image = scaledownimage(c->pre.orig_image, cw, ch);
          290 +                c->pre.x = m->mx + (m->mw - c->pre.scaled_image->width) / 2;
          291 +                c->pre.y = m->my + (m->mh - c->pre.scaled_image->height) / 2;
          292 +                return;
          293 +        }
          294 +        if (n == 2) {
          295 +                c = m->clients;
          296 +                cw = (m->ww - 2 * gappo - gappi) / 2;
          297 +                ch = (m->wh - 2 * gappo) * 0.7;
          298 +                c->pre.scaled_image = scaledownimage(c->pre.orig_image, cw, ch);
          299 +                c->next->pre.scaled_image = scaledownimage(c->next->pre.orig_image, cw, ch);
          300 +                c->pre.x = m->mx + (m->mw - c->pre.scaled_image->width - gappi - c->next->pre.scaled_image->width) / 2;
          301 +                c->pre.y = m->my + (m->mh - c->pre.scaled_image->height) / 2;
          302 +                c->next->pre.x = c->pre.x + c->pre.scaled_image->width + gappi;
          303 +                c->next->pre.y = m->my + (m->mh - c->next->pre.scaled_image->height) / 2;
          304 +                return;
          305 +        }
          306 +        for (cols = 0; cols <= n / 2; cols++)
          307 +                if (cols * cols >= n)
          308 +                        break;
          309 +        rows = (cols && (cols - 1) * cols >= n) ? cols - 1 : cols;
          310 +        ch = (m->wh - 2 * gappo) / rows;
          311 +        cw = (m->ww - 2 * gappo) / cols;
          312 +        c = m->clients;
          313 +        cy = 0;
          314 +        for (i = 0; i < rows; i++) {
          315 +                cx = 0;
          316 +                cmaxh = 0;
          317 +                tmpc = c;
          318 +                for (int j = 0; j < cols; j++) {
          319 +                        if (!c)
          320 +                                break;
          321 +                        c->pre.scaled_image = scaledownimage(c->pre.orig_image, cw, ch);
          322 +                        c->pre.x = cx;
          323 +                        cmaxh = c->pre.scaled_image->height > cmaxh ? c->pre.scaled_image->height : cmaxh;
          324 +                        cx += c->pre.scaled_image->width + gappi;
          325 +                        c = c->next;
          326 +                }
          327 +                c = tmpc;
          328 +                cx = m->wx + (m->ww - cx) / 2;
          329 +                for (j = 0; j < cols; j++) {
          330 +                        if (!c)
          331 +                                break;
          332 +                        c->pre.x += cx;
          333 +                        c->pre.y = cy + (cmaxh - c->pre.scaled_image->height) / 2;
          334 +                        c = c->next;
          335 +                }
          336 +                cy += cmaxh + gappi;
          337 +        }
          338 +        cy = m->wy + (m->wh - cy) / 2;
          339 +        for (c = m->clients; c; c = c->next)
          340 +                c->pre.y += cy;
          341 +}
          342 +
          343 +XImage*
          344 +getwindowximage(Client *c) {
          345 +        XWindowAttributes attr;
          346 +        XGetWindowAttributes( dpy, c->win, &attr );
          347 +        XRenderPictFormat *format = XRenderFindVisualFormat( dpy, attr.visual );
          348 +        int hasAlpha = ( format->type == PictTypeDirect && format->direct.alphaMask );
          349 +        XRenderPictureAttributes pa;
          350 +        pa.subwindow_mode = IncludeInferiors;
          351 +        Picture picture = XRenderCreatePicture( dpy, c->win, format, CPSubwindowMode, &pa );
          352 +        Pixmap pixmap = XCreatePixmap(dpy, root, c->w, c->h, 32);
          353 +        XRenderPictureAttributes pa2;
          354 +        XRenderPictFormat *format2 = XRenderFindStandardFormat(dpy, PictStandardARGB32);
          355 +        Picture pixmapPicture = XRenderCreatePicture( dpy, pixmap, format2, 0, &pa2 );
          356 +        XRenderColor color;
          357 +        color.red = 0x0000;
          358 +        color.green = 0x0000;
          359 +        color.blue = 0x0000;
          360 +        color.alpha = 0x0000;
          361 +        XRenderFillRectangle (dpy, PictOpSrc, pixmapPicture, &color, 0, 0, c->w, c->h);
          362 +        XRenderComposite(dpy, hasAlpha ? PictOpOver : PictOpSrc, picture, 0,
          363 +                        pixmapPicture, 0, 0, 0, 0, 0, 0,
          364 +                        c->w, c->h);
          365 +        XImage* temp = XGetImage( dpy, pixmap, 0, 0, c->w, c->h, AllPlanes, ZPixmap );
          366 +        temp->red_mask = format2->direct.redMask << format2->direct.red;
          367 +        temp->green_mask = format2->direct.greenMask << format2->direct.green;
          368 +        temp->blue_mask = format2->direct.blueMask << format2->direct.blue;
          369 +        temp->depth = DefaultDepth(dpy, screen);
          370 +        return temp;
          371 +}
          372 +
          373 +XImage*
          374 +scaledownimage(XImage *orig_image, unsigned int cw, unsigned int ch) {
          375 +        int factor_w = orig_image->width / cw + 1;
          376 +        int factor_h = orig_image->height / ch + 1;
          377 +        int scale_factor = factor_w > factor_h ? factor_w : factor_h;
          378 +        int scaled_width = orig_image->width / scale_factor;
          379 +        int scaled_height = orig_image->height / scale_factor;
          380 +        XImage *scaled_image = XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)),
          381 +                        orig_image->depth,
          382 +                        ZPixmap, 0, NULL,
          383 +                        scaled_width, scaled_height,
          384 +                        32, 0);
          385 +        scaled_image->data = malloc(scaled_image->height * scaled_image->bytes_per_line);
          386 +        for (int y = 0; y < scaled_height; y++) {
          387 +                for (int x = 0; x < scaled_width; x++) {
          388 +                        int orig_x = x * scale_factor;
          389 +                        int orig_y = y * scale_factor;
          390 +                        unsigned long pixel = XGetPixel(orig_image, orig_x, orig_y);
          391 +                        XPutPixel(scaled_image, x, y, pixel);
          392 +                }
          393 +        }
          394 +        scaled_image->depth = orig_image->depth;
          395 +        return scaled_image;
          396 +}
          397 +
          398  int
          399  main(int argc, char *argv[])
          400  {
          401 -- 
          402 2.48.1
          403