Compare commits

..

17 commits

Author SHA1 Message Date
Antoine Vaure
0eeee01496 change default colors for light 2025-10-03 13:19:00 +02:00
Bakkeby
02627756f1 Bump to 98610fc 2025-08-20 16:27:46 +02:00
Laurent Cheylus
51d32a9a77 Do not interpret CSI ? u as DECRC (#181)
The kitty keyboard protocol docs recommend CSI ? u to query support for
that protocol, see https://sw.kovidgoyal.net/kitty/keyboard-protocol/

For better or worse, fish shell uses this query to work around bugs
in other terminals triggered by requesting that protocol via CSI = 5 u.

Unfortunately, st interprets CSI ? u as DECRC (restore cursor
position). reproduce with 'printf "\x1b[?u"; cat'.

fish could work around this by switching to the alternate screen
before running this query; but that might cause tearing on terminals
that don't support Synchronized Output. I'm not sure.

In the meantime, let's correct our parser.

This adds a redundant else-after-return, for consistency with the
surrounding code.

ref. https://git.suckless.org/st/commit/98610fcd37f655d44586323dc86c1d013c2798ce.html

Signed-off-by: Laurent Cheylus <foxy@free.fr>
2025-08-20 16:27:46 +02:00
Bakkeby
ad3c3e774c sync: add support for DECRQM queries for synchronization ref. #179 2025-08-20 16:27:46 +02:00
Bakkeby
9be6da0370 sync: mode 2026 correction ref. #179 2025-08-20 16:27:46 +02:00
Bakkeby
f7354190f7 sync: adding mode 2026 for the sync patch to allow syncing to be controlled by programs ref. #179 2025-08-20 16:27:46 +02:00
Bakkeby
4da3d6d87c boxdraw: fix for rendering errors following commit f8e451e ref. #180 2025-08-20 16:27:46 +02:00
Bakkeby
821244c2ae OpenBSD compatibility changes 2025-08-20 16:27:46 +02:00
Bakkeby
a12b73a36f Refactoring Xft clipping ref. #175 2025-08-20 16:27:46 +02:00
veltza
49ac4d1e14 Prevent SelectionRequests from interfering with blinking cursor (#173)
Some old clipboard managers, such as greenclip and parcellite,
constantly poll applications with SelectionRequest events, which breaks
the internal timer and blinking cursor. This fix prevents these events
from causing any disruption.

Fixes #172
2025-08-20 16:27:46 +02:00
Bakkeby
0aad70af58 dynamic padding - add explicit dependency on the ANYSIZE_PATCH ref. #168 2025-08-20 16:27:46 +02:00
Bakkeby
5d5fe76795 dynamic cursor color: visual bug on selection ref. #169 2025-08-20 16:27:46 +02:00
Bakkeby
9860867e10 Adding dynamic padding patch - a variant of anysize that do not alter size hints ref. #168 2025-08-20 16:27:46 +02:00
Bakkeby
3c7bcf616d selection colors vs dynamic cursor color patch compatibility issue ref. #167 2025-08-20 16:27:46 +02:00
Bakkeby
50286bb861 reflow: addressing selection clearing bug when selection includes the prompt ref. #166 2025-08-20 16:27:46 +02:00
Bakkeby
c7503f5737 Adding open selected text patch 2025-08-20 16:27:46 +02:00
Bakkeby
137bb152b3 Adding drag-n-drop patch 2025-08-20 16:27:46 +02:00
14 changed files with 429 additions and 60 deletions

View file

@ -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

View file

@ -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

View file

@ -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

204
patch/drag-n-drop.c Normal file
View file

@ -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);
}
}

5
patch/drag-n-drop.h Normal file
View file

@ -0,0 +1,5 @@
static void xdndenter(XEvent *);
static void xdndpos(XEvent *);
static void xdnddrop(XEvent *);
static void xdndsel(XEvent *);
static void xdndpastedata(char *);

13
patch/openselectedtext.c Normal file
View file

@ -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);
}

3
patch/openselectedtext.h Normal file
View file

@ -0,0 +1,3 @@
#include <sys/wait.h>
static void selopen(const Arg *);

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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.
*

32
st.c
View file

@ -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) */
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))

14
st.h
View file

@ -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

108
x.c
View file

@ -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;
}
#endif // BLINKING_CURSOR_PATCH
drawing = 1;
}