diff --git a/README.md b/README.md index 3710d13..ec590cb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Similar to [dwm-flexipatch](https://github.com/bakkeby/dwm-flexipatch) this st 0.9.2 (6009e6e, 2024-11-25) project has a different take on st patching. It uses preprocessor directives to decide whether or not to include a patch during build time. Essentially this means that this build, for better or worse, contains both the patched _and_ the original code. The aim being that you can select which patches to include and the build will contain that code and nothing more. +Similar to [dwm-flexipatch](https://github.com/bakkeby/dwm-flexipatch) this st 0.9.2 (98610fc, 2025-01-26) project has a different take on st patching. It uses preprocessor directives to decide whether or not to include a patch during build time. Essentially this means that this build, for better or worse, contains both the patched _and_ the original code. The aim being that you can select which patches to include and the build will contain that code and nothing more. For example to include the `alpha` patch then you would only need to flip this setting from 0 to 1 in [patches.h](https://github.com/bakkeby/st-flexipatch/blob/master/patches.def.h): ```c @@ -15,6 +15,8 @@ Refer to [https://st.suckless.org/](https://st.suckless.org/) for details on the ### Changelog: +2025-02-20 - Added the drag-n-drop and open-selected-text patches + 2024-05-31 - Added the anygeometry patch 2024-03-13 - Added the reflow patch and upgraded the netwmicon patch @@ -162,6 +164,9 @@ Refer to [https://st.suckless.org/](https://st.suckless.org/) for details on the - [disable-fonts](https://st.suckless.org/patches/disable_bold_italic_fonts/) - this patch adds the option of disabling bold/italic/roman fonts globally + - [drag-n-drop](https://st.suckless.org/patches/drag-n-drop) + - allows dragging a file into the terminal and have the path printed + - [dynamic-cursor-color](https://st.suckless.org/patches/dynamic-cursor-color/) - this patch makes the cursor color the inverse of the current cell color @@ -230,6 +235,9 @@ Refer to [https://st.suckless.org/](https://st.suckless.org/) for details on the - [open-copied-url](https://st.suckless.org/patches/open_copied_url/) - open contents of the clipboard in a user-defined browser + - [open-selected-text](https://st.suckless.org/patches/open_selected_text) + - open the selected text using `xdg-open` + - [openurlonclick](https://www.reddit.com/r/suckless/comments/cc83om/st_open_url/) - allows for URLs to be opened directly when you click on them diff --git a/config.def.h b/config.def.h index 163e042..426a496 100644 --- a/config.def.h +++ b/config.def.h @@ -162,7 +162,7 @@ unsigned int tabspaces = 8; #if ALPHA_PATCH /* bg opacity */ -float alpha = 0.8; +float alpha = 0.9; #if ALPHA_GRADIENT_PATCH float grad_alpha = 0.54; //alpha value that'll change float stat_alpha = 0.46; //constant alpha value that'll get added to grad_alpha @@ -172,30 +172,39 @@ float alphaUnfocused = 0.6; #endif // ALPHA_FOCUS_HIGHLIGHT_PATCH #endif // ALPHA_PATCH +#if DRAG_AND_DROP_PATCH +/* + * drag and drop escape characters + * + * this will add a '\' before any characters specified in the string. + */ +char *xdndescchar = " !\"#$&'()*;<>?[\\]^`{|}~"; +#endif // DRAG_AND_DROP_PATCH + /* Terminal colors (16 first used in escape sequence) */ static char *colorname[] = { - "#011627", /* hard contrast: #1d2021 / soft contrast: #32302f */ - "#d3423e", - "#2aa298", - "#daaa01", - "#4876d6", - "#403f53", - "#08916a", - "#7a8181", - "#7a8181", - "#f76e6e", - "#49d0c5", - "#dac26b", - "#5ca7e4", - "#697098", - "#00c990", - "#989fb1", + "#000000", + "#ff3333", + "#86b200", + "#f19618", + "#41a6d9", + "#f07078", + "#4cbe99", + "#ffffff", + "#323232", + "#ff6565", + "#b8e532", + "#ffc849", + "#73d7ff", + "#ffa3aa", + "#7ff0cb", + "#ffffff", [255] = 0, /* more colors can be added after 255 to use with DefaultXX */ - "#403f53", /* 256 -> cursor */ - "#f2f2f2", /* 257 -> rev cursor*/ - "#ffffff", /* 258 -> bg */ - "#403f53", /* 259 -> fg */ + "#ff6900", /* 256 -> cursor */ + "#f0ede4", /* 257 -> rev cursor*/ + "#fafafa", /* 258 -> bg */ + "#5b6673", /* 259 -> fg */ }; #if DARKMAN_PATCH @@ -392,6 +401,9 @@ static uint forcemousemod = ShiftMask; */ static MouseShortcut mshortcuts[] = { /* mask button function argument release screen */ + #if OPEN_SELECTED_TEXT_PATCH + { ControlMask, Button2, selopen, {.i = 0}, 1 }, + #endif // OPEN_SELECTED_TEXT_PATCH #if CLIPBOARD_PATCH { XK_ANY_MOD, Button2, clippaste, {.i = 0}, 1 }, #else diff --git a/config.mk b/config.mk index 832bcff..260fff0 100644 --- a/config.mk +++ b/config.mk @@ -38,7 +38,7 @@ INCS = -I$(X11INC) \ `$(PKG_CONFIG) --cflags fontconfig` \ `$(PKG_CONFIG) --cflags freetype2` \ $(LIGATURES_INC) -LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft ${SIXEL_LIBS} ${XRENDER} ${XCURSOR}\ +LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft ${SIXEL_LIBS} ${XRENDER} ${XCURSOR}\ `$(PKG_CONFIG) --libs fontconfig` \ `$(PKG_CONFIG) --libs freetype2` \ $(LIGATURES_LIBS) \ @@ -50,10 +50,7 @@ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) STLDFLAGS = $(LIBS) $(LDFLAGS) # OpenBSD: -#CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -#LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ -# `pkg-config --libs fontconfig` \ -# `pkg-config --libs freetype2` +#CPPFLAGS = $(STCPPFLAGS) -D_XOPEN_SOURCE=600 #MANPREFIX = ${PREFIX}/man # compiler and linker diff --git a/patch/drag-n-drop.c b/patch/drag-n-drop.c new file mode 100644 index 0000000..917a9aa --- /dev/null +++ b/patch/drag-n-drop.c @@ -0,0 +1,204 @@ +const char XdndVersion = 5; + +void +xdndsel(XEvent *e) +{ + char* data; + unsigned long result; + + Atom actualType; + int32_t actualFormat; + unsigned long bytesAfter; + XEvent reply = { ClientMessage }; + + reply.xclient.window = xw.XdndSourceWin; + reply.xclient.format = 32; + reply.xclient.data.l[0] = (long) xw.win; + reply.xclient.data.l[2] = 0; + reply.xclient.data.l[3] = 0; + + XGetWindowProperty((Display*) xw.dpy, e->xselection.requestor, + e->xselection.property, 0, LONG_MAX, False, + e->xselection.target, &actualType, &actualFormat, &result, + &bytesAfter, (unsigned char**) &data); + + if (result == 0) + return; + + if (data) { + xdndpastedata(data); + XFree(data); + } + + if (xw.XdndSourceVersion >= 2) { + reply.xclient.message_type = xw.XdndFinished; + reply.xclient.data.l[1] = result; + reply.xclient.data.l[2] = xw.XdndActionCopy; + + XSendEvent((Display*) xw.dpy, xw.XdndSourceWin, False, NoEventMask, + &reply); + XFlush((Display*) xw.dpy); + } +} + +int +xdndurldecode(char *src, char *dest) +{ + char c; + int i = 0; + + while (*src) { + if (*src == '%' && HEX_TO_INT(src[1]) != -1 && HEX_TO_INT(src[2]) != -1) { + /* handle %xx escape sequences in url e.g. %20 == ' ' */ + c = (char)((HEX_TO_INT(src[1]) << 4) | HEX_TO_INT(src[2])); + src += 3; + } else { + c = *src++; + } + if (strchr(xdndescchar, c) != NULL) { + *dest++ = '\\'; + i++; + } + *dest++ = c; + i++; + } + *dest++ = ' '; + *dest = '\0'; + return i + 1; +} + +void +xdndpastedata(char *data) +{ + char *pastedata, *t; + int i = 0; + + pastedata = (char *)malloc(strlen(data) * 2 + 1); + *pastedata = '\0'; + + t = strtok(data, "\n\r"); + while(t != NULL) { + /* Remove 'file://' prefix if it exists */ + if (strncmp(data, "file://", 7) == 0) { + t += 7; + } + i += xdndurldecode(t, pastedata + i); + t = strtok(NULL, "\n\r"); + } + + xsetsel(pastedata); + selpaste(0); +} + +void +xdndenter(XEvent *e) +{ + unsigned long count; + Atom* formats; + Atom real_formats[6]; + Bool list; + Atom actualType; + int32_t actualFormat; + unsigned long bytesAfter; + unsigned long i; + + list = e->xclient.data.l[1] & 1; + + if (list) { + XGetWindowProperty((Display*) xw.dpy, + xw.XdndSourceWin, + xw.XdndTypeList, + 0, + LONG_MAX, + False, + 4, + &actualType, + &actualFormat, + &count, + &bytesAfter, + (unsigned char**) &formats); + } else { + count = 0; + + if (e->xclient.data.l[2] != None) + real_formats[count++] = e->xclient.data.l[2]; + if (e->xclient.data.l[3] != None) + real_formats[count++] = e->xclient.data.l[3]; + if (e->xclient.data.l[4] != None) + real_formats[count++] = e->xclient.data.l[4]; + + formats = real_formats; + } + + for (i = 0; i < count; i++) { + if (formats[i] == xw.XtextUriList || formats[i] == xw.XtextPlain) { + xw.XdndSourceFormat = formats[i]; + break; + } + } + + if (list) + XFree(formats); +} + +void +xdndpos(XEvent *e) +{ + const int32_t xabs = (e->xclient.data.l[2] >> 16) & 0xffff; + const int32_t yabs = (e->xclient.data.l[2]) & 0xffff; + Window dummy; + int32_t xpos, ypos; + XEvent reply = { ClientMessage }; + + reply.xclient.window = xw.XdndSourceWin; + reply.xclient.format = 32; + reply.xclient.data.l[0] = (long) xw.win; + reply.xclient.data.l[2] = 0; + reply.xclient.data.l[3] = 0; + + XTranslateCoordinates((Display*) xw.dpy, + XDefaultRootWindow((Display*) xw.dpy), + (Window) xw.win, + xabs, yabs, + &xpos, &ypos, + &dummy); + + reply.xclient.message_type = xw.XdndStatus; + + if (xw.XdndSourceFormat) { + reply.xclient.data.l[1] = 1; + if (xw.XdndSourceVersion >= 2) + reply.xclient.data.l[4] = xw.XdndActionCopy; + } + + XSendEvent((Display*) xw.dpy, xw.XdndSourceWin, False, NoEventMask, + &reply); + XFlush((Display*) xw.dpy); +} + +void +xdnddrop(XEvent *e) +{ + Time time = CurrentTime; + XEvent reply = { ClientMessage }; + + reply.xclient.window = xw.XdndSourceWin; + reply.xclient.format = 32; + reply.xclient.data.l[0] = (long) xw.win; + reply.xclient.data.l[2] = 0; + reply.xclient.data.l[3] = 0; + + if (xw.XdndSourceFormat) { + if (xw.XdndSourceVersion >= 1) + time = e->xclient.data.l[2]; + + XConvertSelection((Display*) xw.dpy, xw.XdndSelection, + xw.XdndSourceFormat, xw.XdndSelection, (Window) xw.win, time); + } else if (xw.XdndSourceVersion >= 2) { + reply.xclient.message_type = xw.XdndFinished; + + XSendEvent((Display*) xw.dpy, xw.XdndSourceWin, + False, NoEventMask, &reply); + XFlush((Display*) xw.dpy); + } +} diff --git a/patch/drag-n-drop.h b/patch/drag-n-drop.h new file mode 100644 index 0000000..ee8e82b --- /dev/null +++ b/patch/drag-n-drop.h @@ -0,0 +1,5 @@ +static void xdndenter(XEvent *); +static void xdndpos(XEvent *); +static void xdnddrop(XEvent *); +static void xdndsel(XEvent *); +static void xdndpastedata(char *); diff --git a/patch/openselectedtext.c b/patch/openselectedtext.c new file mode 100644 index 0000000..42d40e2 --- /dev/null +++ b/patch/openselectedtext.c @@ -0,0 +1,13 @@ +void +selopen(const Arg *dummy) +{ + pid_t chpid; + + if ((chpid = fork()) == 0) { + if (fork() == 0) + execlp("xdg-open", "xdg-open", getsel(), NULL); + exit(1); + } + if (chpid > 0) + waitpid(chpid, NULL, 0); +} diff --git a/patch/openselectedtext.h b/patch/openselectedtext.h new file mode 100644 index 0000000..3dccbc6 --- /dev/null +++ b/patch/openselectedtext.h @@ -0,0 +1,3 @@ +#include + +static void selopen(const Arg *); diff --git a/patch/reflow.c b/patch/reflow.c index bf145a6..dac7b9d 100644 --- a/patch/reflow.c +++ b/patch/reflow.c @@ -619,8 +619,8 @@ tclearregion(int x1, int y1, int x2, int y2, int usecurattr) int x, y; /* regionselected() takes relative coordinates */ - if (regionselected(x1+term.scr, y1+term.scr, x2+term.scr, y2+term.scr)) - selremove(); + if (regionselected(x1, y1+term.scr, x2, y2+term.scr)) + selclear(); for (y = y1; y <= y2; y++) { term.dirty[y] = 1; diff --git a/patch/x_include.c b/patch/x_include.c index 30b77da..5a0ba58 100644 --- a/patch/x_include.c +++ b/patch/x_include.c @@ -8,6 +8,9 @@ #if BOXDRAW_PATCH #include "boxdraw.c" #endif +#if DRAG_AND_DROP_PATCH +#include "drag-n-drop.c" +#endif #if OPENCOPIED_PATCH #include "opencopied.c" #endif @@ -35,6 +38,9 @@ #elif NETWMICON_LEGACY_PATCH #include "netwmicon_legacy.c" #endif +#if OPEN_SELECTED_TEXT_PATCH +#include "openselectedtext.c" +#endif #if OPENURLONCLICK_PATCH #include "openurlonclick.c" #endif diff --git a/patch/x_include.h b/patch/x_include.h index 78290e1..ed10e8c 100644 --- a/patch/x_include.h +++ b/patch/x_include.h @@ -8,6 +8,9 @@ #if BOXDRAW_PATCH #include "boxdraw.h" #endif +#if DRAG_AND_DROP_PATCH +#include "drag-n-drop.h" +#endif #if OPENCOPIED_PATCH #include "opencopied.h" #endif @@ -32,6 +35,9 @@ #if NETWMICON_PATCH || NETWMICON_FF_PATCH || NETWMICON_LEGACY_PATCH #include "netwmicon.h" #endif +#if OPEN_SELECTED_TEXT_PATCH +#include "openselectedtext.h" +#endif #if RIGHTCLICKTOPLUMB_PATCH #include "rightclicktoplumb_x.h" #endif diff --git a/patches.def.h b/patches.def.h index 46834e8..1e92a9f 100644 --- a/patches.def.h +++ b/patches.def.h @@ -144,11 +144,27 @@ */ #define DISABLE_ROMAN_FONTS_PATCH 0 +/* Allows dragging a file into the terminal and have the path printed. + * https://st.suckless.org/patches/drag-n-drop + */ +#define DRAG_AND_DROP_PATCH 0 + /* This patch makes the cursor color the inverse of the current cell color. * https://st.suckless.org/patches/dynamic-cursor-color/ */ #define DYNAMIC_CURSOR_COLOR_PATCH 0 +/* This is a variant of the anysize patch that explicitly do not change the size increment hints, + * i.e. only keeping the dynamic padding which is the main thing the anysize patch introduces. + * In practice this means that the dynamic padding / anysize functionality only ever comes into + * effect when the size hints are intentionally ignored. + * An example of this would be dwm respecting the size hints of floating windows, but disrespecting + * the size hints when the window is tiled (provided that resizehints config is set to 0). + * + * Note that this patch depends on ANYSIZE_PATCH being enabled to have an effect. + */ +#define DYNAMIC_PADDING_PATCH 0 + /* Reading and writing st's screen through a pipe, e.g. pass info to dmenu. * https://st.suckless.org/patches/externalpipe/ */ @@ -301,6 +317,11 @@ */ #define OPENCOPIED_PATCH 0 +/* Open the selected text using xdg-open. + * https://st.suckless.org/patches/open_selected_text/ + */ +#define OPEN_SELECTED_TEXT_PATCH 0 + /* This patch allows for URLs to be opened directly when you click on them. This may not work with * all terminal applications. * diff --git a/st.c b/st.c index 5efe122..1be93f2 100644 --- a/st.c +++ b/st.c @@ -2039,6 +2039,15 @@ tsetmode(int priv, int set, const int *args, int narg) MODBIT(term.mode, set, MODE_SIXEL_CUR_RT); break; #endif // SIXEL_PATCH + #if SYNC_PATCH + case 2026: + if (set) { + tsync_begin(); + } else { + tsync_end(); + } + break; + #endif // SYNC_PATCH default: fprintf(stderr, "erresc: unknown private set/reset mode %d\n", @@ -2435,6 +2444,23 @@ csihandle(void) goto unknown; } break; + #if SYNC_PATCH + case '$': /* DECRQM -- DEC Request Mode (private) */ + if (csiescseq.mode[1] == 'p' && csiescseq.priv) { + switch (csiescseq.arg[0]) { + #if SYNC_PATCH + case 2026: + /* https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036 */ + ttywrite(su ? "\033[?2026;1$y" : "\033[?2026;2$y", 11, 0); + break; + #endif // SYNC_PATCH + default: + goto unknown; + } + break; + } + goto unknown; + #endif // SYNC_PATCH case 'r': /* DECSTBM -- Set Scrolling Region */ if (csiescseq.priv) { goto unknown; @@ -2498,7 +2524,11 @@ csihandle(void) break; #endif // CSI_22_23_PATCH | SIXEL_PATCH case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */ - tcursor(CURSOR_LOAD); + if (csiescseq.priv) { + goto unknown; + } else { + tcursor(CURSOR_LOAD); + } break; case ' ': switch (csiescseq.mode[1]) { @@ -3434,7 +3464,7 @@ check_control_code: #if REFLOW_PATCH /* selected() takes relative coordinates */ - if (selected(term.c.x + term.scr, term.c.y + term.scr)) + if (selected(term.c.x, term.c.y + term.scr)) selclear(); #else if (selected(term.c.x, term.c.y)) diff --git a/st.h b/st.h index 0682a0e..0464f24 100644 --- a/st.h +++ b/st.h @@ -37,6 +37,12 @@ #define HISTSIZE 2000 #endif // SCROLLBACK_PATCH | REFLOW_PATCH +#if DRAG_AND_DROP_PATCH +#define HEX_TO_INT(c) ((c) >= '0' && (c) <= '9' ? (c) - '0' : \ + (c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \ + (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : -1) +#endif // DRAG_AND_DROP_PATCH + enum glyph_attribute { ATTR_NULL = 0, ATTR_SET = 1 << 0, @@ -247,6 +253,14 @@ typedef struct { GlyphFontSeq *specseq; #endif // LIGATURES_PATCH Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid; + #if DRAG_AND_DROP_PATCH + Atom XdndTypeList, XdndSelection, XdndEnter, XdndPosition, XdndStatus, + XdndLeave, XdndDrop, XdndFinished, XdndActionCopy, XdndActionMove, + XdndActionLink, XdndActionAsk, XdndActionPrivate, XtextUriList, + XtextPlain, XdndAware; + int64_t XdndSourceWin, XdndSourceVersion; + int32_t XdndSourceFormat; + #endif // DRAG_AND_DROP_PATCH #if FULLSCREEN_PATCH Atom netwmstate, netwmfullscreen; #endif // FULLSCREEN_PATCH diff --git a/x.c b/x.c index 7bf72e9..0de0ac7 100644 --- a/x.c +++ b/x.c @@ -603,6 +603,13 @@ selnotify(XEvent *e) if (property == None) return; + #if DRAG_AND_DROP_PATCH + if (property == xw.XdndSelection) { + xdndsel(e); + return; + } + #endif // DRAG_AND_DROP_PATCH + do { if (XGetWindowProperty(xw.dpy, xw.win, property, ofs, BUFSIZ/4, False, AnyPropertyType, @@ -1157,7 +1164,7 @@ xhints(void) sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize; sizeh->height = win.h; sizeh->width = win.w; - #if ANYSIZE_PATCH || ANYSIZE_SIMPLE_PATCH + #if ANYSIZE_PATCH && !DYNAMIC_PADDING_PATCH || ANYSIZE_SIMPLE_PATCH sizeh->height_inc = 1; sizeh->width_inc = 1; #else @@ -1683,6 +1690,28 @@ xinit(int cols, int rows) xw.netwmfullscreen = XInternAtom(xw.dpy, "_NET_WM_STATE_FULLSCREEN", False); #endif // FULLSCREEN_PATCH + #if DRAG_AND_DROP_PATCH + /* Xdnd setup */ + xw.XdndTypeList = XInternAtom(xw.dpy, "XdndTypeList", 0); + xw.XdndSelection = XInternAtom(xw.dpy, "XdndSelection", 0); + xw.XdndEnter = XInternAtom(xw.dpy, "XdndEnter", 0); + xw.XdndPosition = XInternAtom(xw.dpy, "XdndPosition", 0); + xw.XdndStatus = XInternAtom(xw.dpy, "XdndStatus", 0); + xw.XdndLeave = XInternAtom(xw.dpy, "XdndLeave", 0); + xw.XdndDrop = XInternAtom(xw.dpy, "XdndDrop", 0); + xw.XdndFinished = XInternAtom(xw.dpy, "XdndFinished", 0); + xw.XdndActionCopy = XInternAtom(xw.dpy, "XdndActionCopy", 0); + xw.XdndActionMove = XInternAtom(xw.dpy, "XdndActionMove", 0); + xw.XdndActionLink = XInternAtom(xw.dpy, "XdndActionLink", 0); + xw.XdndActionAsk = XInternAtom(xw.dpy, "XdndActionAsk", 0); + xw.XdndActionPrivate = XInternAtom(xw.dpy, "XdndActionPrivate", 0); + xw.XtextUriList = XInternAtom((Display*) xw.dpy, "text/uri-list", 0); + xw.XtextPlain = XInternAtom((Display*) xw.dpy, "text/plain", 0); + xw.XdndAware = XInternAtom(xw.dpy, "XdndAware", 0); + XChangeProperty(xw.dpy, xw.win, xw.XdndAware, 4, 32, PropModeReplace, + &XdndVersion, 1); + #endif // DRAG_AND_DROP_PATCH + win.mode = MODE_NUMLOCK; resettitle(); xhints(); @@ -2252,20 +2281,9 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i else #endif // BACKGROUND_IMAGE_PATCH - #if !WIDE_GLYPHS_PATCH - XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); - #endif // WIDE_GLYPHS_PATCH - - /* Set the clip region because Xft is sometimes dirty. */ - r.x = 0; - r.y = 0; - r.height = win.ch; - r.width = width; - XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); - - #if WIDE_GLYPHS_PATCH /* Fill the background */ XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); + #if WIDE_GLYPHS_PATCH } #endif // WIDE_GLYPHS_PATCH @@ -2276,12 +2294,27 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i if (base.mode & ATTR_BOXDRAW) { drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); } else { - /* Render the glyphs. */ - XftDrawGlyphFontSpec(xw.draw, fg, specs, len); - } + #endif // BOXDRAW_PATCH + /* Set the clip region because Xft is sometimes dirty. */ + #if WIDE_GLYPHS_PATCH + r.x = 0; + r.y = 0; + r.height = win.ch; + r.width = win.w; + XftDrawSetClipRectangles(xw.draw, 0, winy, &r, 1); #else + r.x = 0; + r.y = 0; + r.height = win.ch; + r.width = width; + XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); + #endif // WIDE_GLYPHS_PATCH + /* Render the glyphs. */ XftDrawGlyphFontSpec(xw.draw, fg, specs, len); + + #if BOXDRAW_PATCH + } #endif // BOXDRAW_PATCH /* Render underline and strikethrough. */ @@ -2718,21 +2751,19 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) XRenderColor colbg; #endif // DYNAMIC_CURSOR_COLOR_PATCH - #if !DYNAMIC_CURSOR_COLOR_PATCH - /* remove the old cursor */ + #if LIGATURES_PATCH + /* Redraw the line where cursor was previously. + * It will restore the ligatures broken by the cursor. */ + xdrawline(line, 0, oy, len); + #else + /* Remove the old cursor */ if (selected(ox, oy)) #if SELECTION_COLORS_PATCH og.mode |= ATTR_SELECTED; #else og.mode ^= ATTR_REVERSE; #endif // SELECTION_COLORS_PATCH - #endif // DYNAMIC_CURSOR_COLOR_PATCH - #if LIGATURES_PATCH - /* Redraw the line where cursor was previously. - * It will restore the ligatures broken by the cursor. */ - xdrawline(line, 0, oy, len); - #else xdrawglyph(og, ox, oy); #endif // LIGATURES_PATCH @@ -2775,7 +2806,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) } #endif // SELECTION_COLORS_PATCH } else { - #if SELECTION_COLORS_PATCH + #if SELECTION_COLORS_PATCH && !DYNAMIC_CURSOR_COLOR_PATCH g.fg = defaultbg; g.bg = defaultcs; drawcol = dc.col[defaultcs]; @@ -3713,6 +3744,21 @@ cmessage(XEvent *e) } else if (e->xclient.data.l[0] == xw.wmdeletewin) { ttyhangup(); exit(0); + #if DRAG_AND_DROP_PATCH + } else if (e->xclient.message_type == xw.XdndEnter) { + xw.XdndSourceWin = e->xclient.data.l[0]; + xw.XdndSourceVersion = e->xclient.data.l[1] >> 24; + xw.XdndSourceFormat = None; + if (xw.XdndSourceVersion > 5) + return; + xdndenter(e); + } else if (e->xclient.message_type == xw.XdndPosition + && xw.XdndSourceVersion <= 5) { + xdndpos(e); + } else if (e->xclient.message_type == xw.XdndDrop + && xw.XdndSourceVersion <= 5) { + xdnddrop(e); + #endif // DRAG_AND_DROP_PATCH } } @@ -3809,8 +3855,12 @@ run(void) xev = 0; while (XPending(xw.dpy)) { - xev = 1; XNextEvent(xw.dpy, &ev); + #if BLINKING_CURSOR_PATCH + xev = (!xev || xev == SelectionRequest) ? ev.type : xev; + #else + xev = 1; + #endif // BLINKING_CURSOR_PATCH if (XFilterEvent(&ev, None)) continue; if (handler[ev.type]) @@ -3837,10 +3887,10 @@ run(void) if (!drawing) { trigger = now; #if BLINKING_CURSOR_PATCH - if (IS_SET(MODE_BLINK)) { - win.mode ^= MODE_BLINK; + if (xev != SelectionRequest) { + win.mode &= ~MODE_BLINK; + lastblink = now; } - lastblink = now; #endif // BLINKING_CURSOR_PATCH drawing = 1; }