Adding drag-n-drop patch
This commit is contained in:
parent
48f696499d
commit
137bb152b3
9 changed files with 292 additions and 0 deletions
|
|
@ -15,6 +15,8 @@ Refer to [https://st.suckless.org/](https://st.suckless.org/) for details on the
|
||||||
|
|
||||||
### Changelog:
|
### Changelog:
|
||||||
|
|
||||||
|
2025-02-20 - Added the drag-n-drop patch
|
||||||
|
|
||||||
2024-05-31 - Added the anygeometry patch
|
2024-05-31 - Added the anygeometry patch
|
||||||
|
|
||||||
2024-03-13 - Added the reflow patch and upgraded the netwmicon 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/)
|
- [disable-fonts](https://st.suckless.org/patches/disable_bold_italic_fonts/)
|
||||||
- this patch adds the option of disabling bold/italic/roman fonts globally
|
- 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/)
|
- [dynamic-cursor-color](https://st.suckless.org/patches/dynamic-cursor-color/)
|
||||||
- this patch makes the cursor color the inverse of the current cell color
|
- this patch makes the cursor color the inverse of the current cell color
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,15 @@ float alphaUnfocused = 0.6;
|
||||||
#endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
|
#endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
|
||||||
#endif // ALPHA_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) */
|
/* Terminal colors (16 first used in escape sequence) */
|
||||||
static char *colorname[] = {
|
static char *colorname[] = {
|
||||||
"#011627", /* hard contrast: #1d2021 / soft contrast: #32302f */
|
"#011627", /* hard contrast: #1d2021 / soft contrast: #32302f */
|
||||||
|
|
|
||||||
204
patch/drag-n-drop.c
Normal file
204
patch/drag-n-drop.c
Normal 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
5
patch/drag-n-drop.h
Normal 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 *);
|
||||||
|
|
@ -8,6 +8,9 @@
|
||||||
#if BOXDRAW_PATCH
|
#if BOXDRAW_PATCH
|
||||||
#include "boxdraw.c"
|
#include "boxdraw.c"
|
||||||
#endif
|
#endif
|
||||||
|
#if DRAG_AND_DROP_PATCH
|
||||||
|
#include "drag-n-drop.c"
|
||||||
|
#endif
|
||||||
#if OPENCOPIED_PATCH
|
#if OPENCOPIED_PATCH
|
||||||
#include "opencopied.c"
|
#include "opencopied.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,9 @@
|
||||||
#if BOXDRAW_PATCH
|
#if BOXDRAW_PATCH
|
||||||
#include "boxdraw.h"
|
#include "boxdraw.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if DRAG_AND_DROP_PATCH
|
||||||
|
#include "drag-n-drop.h"
|
||||||
|
#endif
|
||||||
#if OPENCOPIED_PATCH
|
#if OPENCOPIED_PATCH
|
||||||
#include "opencopied.h"
|
#include "opencopied.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,11 @@
|
||||||
*/
|
*/
|
||||||
#define DISABLE_ROMAN_FONTS_PATCH 0
|
#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.
|
/* This patch makes the cursor color the inverse of the current cell color.
|
||||||
* https://st.suckless.org/patches/dynamic-cursor-color/
|
* https://st.suckless.org/patches/dynamic-cursor-color/
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
14
st.h
14
st.h
|
|
@ -37,6 +37,12 @@
|
||||||
#define HISTSIZE 2000
|
#define HISTSIZE 2000
|
||||||
#endif // SCROLLBACK_PATCH | REFLOW_PATCH
|
#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 {
|
enum glyph_attribute {
|
||||||
ATTR_NULL = 0,
|
ATTR_NULL = 0,
|
||||||
ATTR_SET = 1 << 0,
|
ATTR_SET = 1 << 0,
|
||||||
|
|
@ -247,6 +253,14 @@ typedef struct {
|
||||||
GlyphFontSeq *specseq;
|
GlyphFontSeq *specseq;
|
||||||
#endif // LIGATURES_PATCH
|
#endif // LIGATURES_PATCH
|
||||||
Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid;
|
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
|
#if FULLSCREEN_PATCH
|
||||||
Atom netwmstate, netwmfullscreen;
|
Atom netwmstate, netwmfullscreen;
|
||||||
#endif // FULLSCREEN_PATCH
|
#endif // FULLSCREEN_PATCH
|
||||||
|
|
|
||||||
44
x.c
44
x.c
|
|
@ -603,6 +603,13 @@ selnotify(XEvent *e)
|
||||||
if (property == None)
|
if (property == None)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if DRAG_AND_DROP_PATCH
|
||||||
|
if (property == xw.XdndSelection) {
|
||||||
|
xdndsel(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif // DRAG_AND_DROP_PATCH
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (XGetWindowProperty(xw.dpy, xw.win, property, ofs,
|
if (XGetWindowProperty(xw.dpy, xw.win, property, ofs,
|
||||||
BUFSIZ/4, False, AnyPropertyType,
|
BUFSIZ/4, False, AnyPropertyType,
|
||||||
|
|
@ -1683,6 +1690,28 @@ xinit(int cols, int rows)
|
||||||
xw.netwmfullscreen = XInternAtom(xw.dpy, "_NET_WM_STATE_FULLSCREEN", False);
|
xw.netwmfullscreen = XInternAtom(xw.dpy, "_NET_WM_STATE_FULLSCREEN", False);
|
||||||
#endif // FULLSCREEN_PATCH
|
#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;
|
win.mode = MODE_NUMLOCK;
|
||||||
resettitle();
|
resettitle();
|
||||||
xhints();
|
xhints();
|
||||||
|
|
@ -3713,6 +3742,21 @@ cmessage(XEvent *e)
|
||||||
} else if (e->xclient.data.l[0] == xw.wmdeletewin) {
|
} else if (e->xclient.data.l[0] == xw.wmdeletewin) {
|
||||||
ttyhangup();
|
ttyhangup();
|
||||||
exit(0);
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue