commit 993b2c6eef89253717974d588075f5b3aa423ca4
parent 6ea7deca34cb64f852d7096497ab7184c8e12125
Author: steve <3337990267@qq.com>
Date: Tue, 9 Jul 2024 23:07:44 +0800
[dwm][patch][preview-all-windows] dwm patch for preview all windows
Diffstat:
3 files changed, 307 insertions(+), 0 deletions(-)
diff --git a/dwm.suckless.org/patches/preview-all-win/dwm-preview-all-windows-6.5.diff b/dwm.suckless.org/patches/preview-all-win/dwm-preview-all-windows-6.5.diff
@@ -0,0 +1,280 @@
+diff --git a/config.def.h b/config.def.h
+index 9efa774..2992668 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -95,6 +95,7 @@ static const Key keys[] = {
+ TAGKEYS( XK_8, 7)
+ TAGKEYS( XK_9, 8)
+ { MODKEY|ShiftMask, XK_q, quit, {0} },
++ { MODKEY, XK_r, previewallwin, {0} },
+ };
+
+ /* button definitions */
+diff --git a/config.mk b/config.mk
+index 8efca9a..8d7c303 100644
+--- a/config.mk
++++ b/config.mk
+@@ -23,7 +23,7 @@ FREETYPEINC = /usr/include/freetype2
+
+ # includes and libs
+ INCS = -I${X11INC} -I${FREETYPEINC}
+-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
++LIBS = -L${X11LIB} -lX11 -lXrender -lXcomposite ${XINERAMALIBS} ${FREETYPELIBS}
+
+ # flags
+ CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
+diff --git a/dwm.c b/dwm.c
+index 67c6b2b..bf30141 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -40,6 +40,8 @@
+ #include <X11/extensions/Xinerama.h>
+ #endif /* XINERAMA */
+ #include <X11/Xft/Xft.h>
++#include <X11/extensions/Xcomposite.h>
++#include <X11/extensions/Xrender.h>
+
+ #include "drw.h"
+ #include "util.h"
+@@ -84,6 +86,16 @@ typedef struct {
+
+ typedef struct Monitor Monitor;
+ typedef struct Client Client;
++
++typedef struct Preview Preview;
++struct Preview {
++ XImage *orig_image;
++ XImage *scaled_image;
++ Window win;
++ unsigned int x, y;
++ Preview *next;
++};
++
+ struct Client {
+ char name[256];
+ float mina, maxa;
+@@ -97,6 +109,7 @@ struct Client {
+ Client *snext;
+ Monitor *mon;
+ Window win;
++ Preview pre;
+ };
+
+ typedef struct {
+@@ -233,6 +246,10 @@ static int xerror(Display *dpy, XErrorEvent *ee);
+ static int xerrordummy(Display *dpy, XErrorEvent *ee);
+ static int xerrorstart(Display *dpy, XErrorEvent *ee);
+ static void zoom(const Arg *arg);
++static void previewallwin();
++static void setpreviewwindowsizepositions(unsigned int n, Monitor *m, unsigned int gappo, unsigned int gappi);
++static XImage *getwindowximage(Client *c);
++static XImage *scaledownimage(XImage *orig_image, unsigned int cw, unsigned int ch);
+
+ /* variables */
+ static const char broken[] = "broken";
+@@ -2140,6 +2157,205 @@ zoom(const Arg *arg)
+ pop(c);
+ }
+
++void previewallwin(){
++ int composite_event_base, composite_error_base;
++ if (!XCompositeQueryExtension(dpy, &composite_event_base, &composite_error_base)) {
++ fprintf(stderr, "Error: XComposite extension not available.\n");
++ return;
++ }
++ Monitor *m = selmon;
++ Client *c;
++ unsigned int n;
++ for (n = 0, c = m->clients; c; c = c->next, n++){
++ /* If you hit actualfullscreen patch Unlock the notes below */
++ // if (c->isfullscreen)
++ // togglefullscr(&(Arg){0});
++ /* If you hit awesomebar patch Unlock the notes below */
++ // if (HIDDEN(c))
++ // continue;
++ c->pre.orig_image = getwindowximage(c);
++ }
++ if (n == 0)
++ return;
++ setpreviewwindowsizepositions(n, m, 60, 15);
++ XEvent event;
++ for(c = m->clients; c; c = c->next){
++ if (!c->pre.win)
++ c->pre.win = XCreateSimpleWindow(dpy, root, c->pre.x, c->pre.y, c->pre.scaled_image->width, c->pre.scaled_image->height, 1, BlackPixel(dpy, screen), WhitePixel(dpy, screen));
++ else
++ XMoveResizeWindow(dpy, c->pre.win, c->pre.x, c->pre.y, c->pre.scaled_image->width, c->pre.scaled_image->height);
++ XSetWindowBorder(dpy, c->pre.win, scheme[SchemeNorm][ColBorder].pixel);
++ XUnmapWindow(dpy, c->win);
++ if (c->pre.win){
++ XSelectInput(dpy, c->pre.win, ButtonPress | EnterWindowMask | LeaveWindowMask );
++ XMapWindow(dpy, c->pre.win);
++ XPutImage(dpy, c->pre.win, drw->gc, c->pre.scaled_image, 0, 0, 0, 0, c->pre.scaled_image->width, c->pre.scaled_image->height);
++ }
++ }
++ while (1) {
++ XNextEvent(dpy, &event);
++ if (event.type == ButtonPress)
++ if (event.xbutton.button == Button1){
++ for(c = m->clients; c; c = c->next){
++ XUnmapWindow(dpy, c->pre.win);
++ if (event.xbutton.window == c->pre.win){
++ selmon->seltags ^= 1; /* toggle sel tagset */
++ m->tagset[selmon->seltags] = c->tags;
++ focus(c);
++ /* If you hit awesomebar patch Unlock the notes below */
++ // if (HIDDEN(c)){
++ // showwin(c);
++ // continue;
++ // }
++ }
++ /* If you hit awesomebar patch Unlock the notes below;
++ * And you should add the following line to "hidewin" Function
++ * c->pre.orig_image = getwindowximage(c);
++ * */
++ // if (HIDDEN(c)){
++ // continue;
++ // }
++ XMapWindow(dpy, c->win);
++ XDestroyImage(c->pre.orig_image);
++ XDestroyImage(c->pre.scaled_image);
++ }
++ break;
++ }
++ if (event.type == EnterNotify)
++ for(c = m->clients; c; c = c->next)
++ if (event.xcrossing.window == c->pre.win){
++ XSetWindowBorder(dpy, c->pre.win, scheme[SchemeSel][ColBorder].pixel);
++ break;
++ }
++ if (event.type == LeaveNotify)
++ for(c = m->clients; c; c = c->next)
++ if (event.xcrossing.window == c->pre.win){
++ XSetWindowBorder(dpy, c->pre.win, scheme[SchemeNorm][ColBorder].pixel);
++ break;
++ }
++ }
++ arrange(m);
++}
++
++void setpreviewwindowsizepositions(unsigned int n, Monitor *m, unsigned int gappo, unsigned int gappi){
++ unsigned int i, j;
++ unsigned int cx, cy, cw, ch, cmaxh;
++ unsigned int cols, rows;
++ Client *c, *tmpc;
++
++ if (n == 1) {
++ c = m->clients;
++ cw = (m->ww - 2 * gappo) * 0.8;
++ ch = (m->wh - 2 * gappo) * 0.9;
++ c->pre.scaled_image = scaledownimage(c->pre.orig_image, cw, ch);
++ c->pre.x = m->mx + (m->mw - c->pre.scaled_image->width) / 2;
++ c->pre.y = m->my + (m->mh - c->pre.scaled_image->height) / 2;
++ return;
++ }
++ if (n == 2) {
++ c = m->clients;
++ cw = (m->ww - 2 * gappo - gappi) / 2;
++ ch = (m->wh - 2 * gappo) * 0.7;
++ c->pre.scaled_image = scaledownimage(c->pre.orig_image, cw, ch);
++ c->next->pre.scaled_image = scaledownimage(c->next->pre.orig_image, cw, ch);
++ c->pre.x = m->mx + (m->mw - c->pre.scaled_image->width - gappi - c->next->pre.scaled_image->width) / 2;
++ c->pre.y = m->my + (m->mh - c->pre.scaled_image->height) / 2;
++ c->next->pre.x = c->pre.x + c->pre.scaled_image->width + gappi;
++ c->next->pre.y = m->my + (m->mh - c->next->pre.scaled_image->height) / 2;
++ return;
++ }
++ for (cols = 0; cols <= n / 2; cols++)
++ if (cols * cols >= n)
++ break;
++ rows = (cols && (cols - 1) * cols >= n) ? cols - 1 : cols;
++ ch = (m->wh - 2 * gappo) / rows;
++ cw = (m->ww - 2 * gappo) / cols;
++ c = m->clients;
++ cy = 0;
++ for (i = 0; i < rows; i++) {
++ cx = 0;
++ cmaxh = 0;
++ tmpc = c;
++ for (int j = 0; j < cols; j++) {
++ if (!c)
++ break;
++ c->pre.scaled_image = scaledownimage(c->pre.orig_image, cw, ch);
++ c->pre.x = cx;
++ cmaxh = c->pre.scaled_image->height > cmaxh ? c->pre.scaled_image->height : cmaxh;
++ cx += c->pre.scaled_image->width + gappi;
++ c = c->next;
++ }
++ c = tmpc;
++ cx = m->wx + (m->ww - cx) / 2;
++ for (j = 0; j < cols; j++) {
++ if (!c)
++ break;
++ c->pre.x += cx;
++ c->pre.y = cy + (cmaxh - c->pre.scaled_image->height) / 2;
++ c = c->next;
++ }
++ cy += cmaxh + gappi;
++ }
++ cy = m->wy + (m->wh - cy) / 2;
++ for (c = m->clients; c; c = c->next)
++ c->pre.y += cy;
++}
++
++XImage *getwindowximage(Client *c) {
++ XCompositeRedirectWindow(dpy, c->win, CompositeRedirectAutomatic);
++ XWindowAttributes attr;
++ XGetWindowAttributes( dpy, c->win, &attr );
++ XRenderPictFormat *format = XRenderFindVisualFormat( dpy, attr.visual );
++ int hasAlpha = ( format->type == PictTypeDirect && format->direct.alphaMask );
++ XRenderPictureAttributes pa;
++ pa.subwindow_mode = IncludeInferiors;
++ Picture picture = XRenderCreatePicture( dpy, c->win, format, CPSubwindowMode, &pa );
++ Pixmap pixmap = XCreatePixmap(dpy, root, c->w, c->h, 32);
++ XRenderPictureAttributes pa2;
++ XRenderPictFormat *format2 = XRenderFindStandardFormat(dpy, PictStandardARGB32);
++ Picture pixmapPicture = XRenderCreatePicture( dpy, pixmap, format2, 0, &pa2 );
++ XRenderColor color;
++ color.red = 0x0000;
++ color.green = 0x0000;
++ color.blue = 0x0000;
++ color.alpha = 0x0000;
++ XRenderFillRectangle (dpy, PictOpSrc, pixmapPicture, &color, 0, 0, c->w, c->h);
++ XRenderComposite(dpy, hasAlpha ? PictOpOver : PictOpSrc, picture, 0,
++ pixmapPicture, 0, 0, 0, 0, 0, 0,
++ c->w, c->h);
++ XImage* temp = XGetImage( dpy, pixmap, 0, 0, c->w, c->h, AllPlanes, ZPixmap );
++ temp->red_mask = format2->direct.redMask << format2->direct.red;
++ temp->green_mask = format2->direct.greenMask << format2->direct.green;
++ temp->blue_mask = format2->direct.blueMask << format2->direct.blue;
++ temp->depth = DefaultDepth(dpy, screen);
++ XCompositeUnredirectWindow(dpy, c->win, CompositeRedirectAutomatic);
++ return temp;
++}
++
++XImage *scaledownimage(XImage *orig_image, unsigned int cw, unsigned int ch) {
++ int factor_w = orig_image->width / cw + 1;
++ int factor_h = orig_image->height / ch + 1;
++ int scale_factor = factor_w > factor_h ? factor_w : factor_h;
++ int scaled_width = orig_image->width / scale_factor;
++ int scaled_height = orig_image->height / scale_factor;
++ XImage *scaled_image = XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)),
++ orig_image->depth,
++ ZPixmap, 0, NULL,
++ scaled_width, scaled_height,
++ 32, 0);
++ scaled_image->data = malloc(scaled_image->height * scaled_image->bytes_per_line);
++ for (int y = 0; y < scaled_height; y++) {
++ for (int x = 0; x < scaled_width; x++) {
++ int orig_x = x * scale_factor;
++ int orig_y = y * scale_factor;
++ unsigned long pixel = XGetPixel(orig_image, orig_x, orig_y);
++ XPutPixel(scaled_image, x, y, pixel);
++ }
++ }
++ scaled_image->depth = orig_image->depth;
++ return scaled_image;
++}
++
+ int
+ main(int argc, char *argv[])
+ {
diff --git a/dwm.suckless.org/patches/preview-all-win/index.md b/dwm.suckless.org/patches/preview-all-win/index.md
@@ -0,0 +1,27 @@
+preview all windows
+================
+
+Description
+-----------
+Allows you to preview all window image thumbnails under the current display, and when clicked, it will jump to the corresponding application window
+
+![preview all windows](./preview-all-windows.png)
+
+I used two x11 extensions, xcomposite's off-screen storage feature and xrender to get the window image
+
+
+> [!WARNING]
+
+> If you're using patches for fullscreen and hidewin, please follow the comments in my patches and adjust the code to suit the effects of other patches
+
+> The project is still in the development stage, and there are still many problems, such as: without using a renderer like picom, the window image will not be available, but fortunately there is no crash
+
+> (I'm sorry because I've been using picom and this issue didn't come to me until I was making diff)
+
+Download
+--------
+* [dwm-preview-all-windows-6.5.diff](./dwm-preview-all-windows-6.5.diff)
+
+Author
+------
+* HJ-Zhang - <hjzhang216@gmail.com>
diff --git a/dwm.suckless.org/patches/preview-all-win/preview-all-windows.png b/dwm.suckless.org/patches/preview-all-win/preview-all-windows.png
Binary files differ.