Compare commits

...

29 commits

Author SHA1 Message Date
Antoine Vaure
042af42400 change colors for light theme 2025-10-03 13:21:56 +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
Antoine Vaure
48f696499d add keybinnds to scroll 2025-07-18 00:25:00 +02:00
Antoine Vaure
cae36041b4 decrease default font size 2025-06-02 09:17:07 +02:00
ant
304293d4e1 Enable alpha patch 2025-05-21 20:50:08 +02:00
ant
5a65d4a512 enable boxdraw 2025-05-21 20:50:08 +02:00
ant
0f0f929022 Add a nix flake 2025-01-12 16:30:56 +01:00
ant
2a20129a48 enable patches I want 2025-01-12 16:30:51 +01:00
ant
f2c7f80738 change keys to keyboard select and zoom 2025-01-12 16:09:02 +01:00
ant
0b4c1084f0 change default colors 2025-01-12 16:07:50 +01:00
ant
816061be47 Add darkman patch
a patch to choose between two color themes by executing a command
2025-01-12 16:07:23 +01:00
ant
292f3ae44d font default to caskadia 2025-01-12 16:07:23 +01:00
Antoine Vaure
c87ded477c config: increase scroll speed 2025-01-12 16:07:23 +01:00
ant
4397a1814f fontfeature patch 2025-01-12 16:07:18 +01:00
19 changed files with 734 additions and 115 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): 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 ```c
@ -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 and open-selected-text patches
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
@ -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-copied-url](https://st.suckless.org/patches/open_copied_url/)
- open contents of the clipboard in a user-defined browser - 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/) - [openurlonclick](https://www.reddit.com/r/suckless/comments/cc83om/st_open_url/)
- allows for URLs to be opened directly when you click on them - allows for URLs to be opened directly when you click on them

View file

@ -5,13 +5,10 @@
* *
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/ */
static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; static char *font = "Cascadia Code NF:regular:pixelsize=13.5:fontfeatures=calt,ss01:antialias=true:autohint=true";
#if FONT2_PATCH #if FONT2_PATCH
/* Spare fonts */ /* Spare fonts */
static char *font2[] = { static char *font2[] = { "CaskaydiaCove Nerd Font:pixelsize=13.5:antialias=true:autohint=true" };
/* "Inconsolata for Powerline:pixelsize=12:antialias=true:autohint=true", */
/* "Hack Nerd Font Mono:pixelsize=11:antialias=true:autohint=true", */
};
#endif // FONT2_PATCH #endif // FONT2_PATCH
#if BACKGROUND_IMAGE_PATCH #if BACKGROUND_IMAGE_PATCH
@ -130,11 +127,11 @@ int hidecursor = 1;
* Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored. * Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored.
* 0: disable (render all U25XX glyphs normally from the font). * 0: disable (render all U25XX glyphs normally from the font).
*/ */
const int boxdraw = 0; const int boxdraw = 1;
const int boxdraw_bold = 0; const int boxdraw_bold = 1;
/* braille (U28XX): 1: render as adjacent "pixels", 0: use font */ /* braille (U28XX): 1: render as adjacent "pixels", 0: use font */
const int boxdraw_braille = 0; const int boxdraw_braille = 1;
#endif // BOXDRAW_PATCH #endif // BOXDRAW_PATCH
/* /*
@ -165,7 +162,7 @@ unsigned int tabspaces = 8;
#if ALPHA_PATCH #if ALPHA_PATCH
/* bg opacity */ /* bg opacity */
float alpha = 0.8; float alpha = 0.9;
#if ALPHA_GRADIENT_PATCH #if ALPHA_GRADIENT_PATCH
float grad_alpha = 0.54; //alpha value that'll change 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 float stat_alpha = 0.46; //constant alpha value that'll get added to grad_alpha
@ -175,37 +172,79 @@ 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 const char *colorname[] = { static char *colorname[] = {
/* 8 normal colors */ "#000000",
"black", "#ff3333",
"red3", "#86b200",
"green3", "#f19618",
"yellow3", "#41a6d9",
"blue2", "#f07078",
"magenta3", "#4cbe99",
"cyan3", "#ffffff",
"gray90", "#323232",
"#ff6565",
/* 8 bright colors */ "#b8e532",
"gray50", "#ffc849",
"red", "#73d7ff",
"green", "#ffa3aa",
"yellow", "#7ff0cb",
"#5c5cff", "#ffffff",
"magenta", [255] = 0,
"cyan", /* more colors can be added after 255 to use with DefaultXX */
"white", "#403f53", /* 256 -> cursor */
"#f0ede4", /* 257 -> rev cursor*/
[255] = 0, "#fafafa", /* 258 -> bg */
"#5b6673", /* 259 -> fg */
/* more colors can be added after 255 to use with DefaultXX */
"#add8e6", /* 256 -> cursor */
"#555555", /* 257 -> rev cursor*/
"#000000", /* 258 -> bg */
"#e5e5e5", /* 259 -> fg */
}; };
#if DARKMAN_PATCH
#define colorname_len (sizeof(colorname) / sizeof(char *))
enum theme {
THEME_LIGHT,
THEME_DARK,
THEME_NUM,
};
/* Terminal colors (16 first used in escape sequence) */
static const char *colornames[THEME_NUM][colorname_len] = {
{ }, {
"#1a1a1a", /* hard contrast: #1d2021 / soft contrast: #32302f */
"#f4005f",
"#98e024",
"#fa8419",
"#9d65ff",
"#f4005f",
"#58d1eb",
"#c4c5b5",
"#625e4c",
"#f4005f",
"#98e024",
"#e0d561",
"#9d65ff",
"#f4005f",
"#58d1eb",
"#f6f6ef",
[255] = 0,
/* more colors can be added after 255 to use with DefaultXX */
"#aaaaaa", /* 256 -> cursor */
"#555555", /* 257 -> rev cursor*/
"#000000", /* 258 -> bg */
"#ffffff", /* 259 -> fg */
}};
#endif // DARKMAN_PATCH
/* /*
* Default colors (colorname index) * Default colors (colorname index)
@ -362,14 +401,17 @@ static uint forcemousemod = ShiftMask;
*/ */
static MouseShortcut mshortcuts[] = { static MouseShortcut mshortcuts[] = {
/* mask button function argument release screen */ /* 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 #if CLIPBOARD_PATCH
{ XK_ANY_MOD, Button2, clippaste, {.i = 0}, 1 }, { XK_ANY_MOD, Button2, clippaste, {.i = 0}, 1 },
#else #else
{ XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
#endif // CLIPBOARD_PATCH #endif // CLIPBOARD_PATCH
#if SCROLLBACK_MOUSE_PATCH #if SCROLLBACK_MOUSE_PATCH
{ ShiftMask, Button4, kscrollup, {.i = 1}, 0, S_PRI}, { ShiftMask, Button4, kscrollup, {.i = 4}, 0, S_PRI},
{ ShiftMask, Button5, kscrolldown, {.i = 1}, 0, S_PRI}, { ShiftMask, Button5, kscrolldown, {.i = 4}, 0, S_PRI},
#elif UNIVERSCROLL_PATCH #elif UNIVERSCROLL_PATCH
{ XK_ANY_MOD, Button4, ttysend, {.s = "\033[5;2~"}, 0, S_PRI }, { XK_ANY_MOD, Button4, ttysend, {.s = "\033[5;2~"}, 0, S_PRI },
{ XK_ANY_MOD, Button5, ttysend, {.s = "\033[6;2~"}, 0, S_PRI }, { XK_ANY_MOD, Button5, ttysend, {.s = "\033[6;2~"}, 0, S_PRI },
@ -378,8 +420,8 @@ static MouseShortcut mshortcuts[] = {
{ ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} }, { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} },
#endif // SCROLLBACK_MOUSE_PATCH #endif // SCROLLBACK_MOUSE_PATCH
#if SCROLLBACK_MOUSE_ALTSCREEN_PATCH || REFLOW_PATCH #if SCROLLBACK_MOUSE_ALTSCREEN_PATCH || REFLOW_PATCH
{ XK_ANY_MOD, Button4, kscrollup, {.i = 1}, 0, S_PRI }, { XK_ANY_MOD, Button4, kscrollup, {.i = 4}, 0, S_PRI },
{ XK_ANY_MOD, Button5, kscrolldown, {.i = 1}, 0, S_PRI }, { XK_ANY_MOD, Button5, kscrolldown, {.i = 4}, 0, S_PRI },
{ XK_ANY_MOD, Button4, ttysend, {.s = "\031"}, 0, S_ALT }, { XK_ANY_MOD, Button4, ttysend, {.s = "\031"}, 0, S_ALT },
{ XK_ANY_MOD, Button5, ttysend, {.s = "\005"}, 0, S_ALT }, { XK_ANY_MOD, Button5, ttysend, {.s = "\005"}, 0, S_ALT },
#else #else
@ -410,8 +452,8 @@ static Shortcut shortcuts[] = {
{ ControlMask, XK_Print, toggleprinter, {.i = 0} }, { ControlMask, XK_Print, toggleprinter, {.i = 0} },
{ ShiftMask, XK_Print, printscreen, {.i = 0} }, { ShiftMask, XK_Print, printscreen, {.i = 0} },
{ XK_ANY_MOD, XK_Print, printsel, {.i = 0} }, { XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
{ TERMMOD, XK_Prior, zoom, {.f = +1} }, { MODKEY | ControlMask, XK_comma, zoom, {.f = +1} },
{ TERMMOD, XK_Next, zoom, {.f = -1} }, { MODKEY | ControlMask, XK_semicolon, zoom, {.f = -1} },
{ TERMMOD, XK_Home, zoomreset, {.f = 0} }, { TERMMOD, XK_Home, zoomreset, {.f = 0} },
{ TERMMOD, XK_C, clipcopy, {.i = 0} }, { TERMMOD, XK_C, clipcopy, {.i = 0} },
{ TERMMOD, XK_V, clippaste, {.i = 0} }, { TERMMOD, XK_V, clippaste, {.i = 0} },
@ -430,6 +472,10 @@ static Shortcut shortcuts[] = {
#if SCROLLBACK_PATCH #if SCROLLBACK_PATCH
{ ShiftMask, XK_Page_Up, kscrollup, {.i = -1}, S_PRI }, { ShiftMask, XK_Page_Up, kscrollup, {.i = -1}, S_PRI },
{ ShiftMask, XK_Page_Down, kscrolldown, {.i = -1}, S_PRI }, { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1}, S_PRI },
{ TERMMOD, XK_U, kscrollup, {.i = -1}, S_PRI },
{ TERMMOD, XK_D, kscrolldown, {.i = -1}, S_PRI },
{ TERMMOD, XK_K, kscrollup, {.i = 4}, S_PRI },
{ TERMMOD, XK_J, kscrolldown, {.i = 4}, S_PRI },
#endif // SCROLLBACK_PATCH #endif // SCROLLBACK_PATCH
#if CLIPBOARD_PATCH #if CLIPBOARD_PATCH
{ TERMMOD, XK_Y, clippaste, {.i = 0} }, { TERMMOD, XK_Y, clippaste, {.i = 0} },
@ -455,7 +501,7 @@ static Shortcut shortcuts[] = {
#endif // EXTERNALPIPEIN_PATCH #endif // EXTERNALPIPEIN_PATCH
#endif // EXTERNALPIPE_PATCH #endif // EXTERNALPIPE_PATCH
#if KEYBOARDSELECT_PATCH #if KEYBOARDSELECT_PATCH
{ TERMMOD, XK_Escape, keyboard_select, { 0 } }, { TERMMOD, XK_space, keyboard_select, { 0 } },
#endif // KEYBOARDSELECT_PATCH #endif // KEYBOARDSELECT_PATCH
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
{ TERMMOD, XK_F, searchforward, { 0 } }, { TERMMOD, XK_F, searchforward, { 0 } },

View file

@ -21,14 +21,14 @@ PKG_CONFIG = pkg-config
#XCURSOR = `$(PKG_CONFIG) --libs xcursor` #XCURSOR = `$(PKG_CONFIG) --libs xcursor`
# Uncomment the lines below for the ligatures patch / LIGATURES_PATCH # Uncomment the lines below for the ligatures patch / LIGATURES_PATCH
#LIGATURES_C = hb.c LIGATURES_C = hb.c
#LIGATURES_H = hb.h LIGATURES_H = hb.h
#LIGATURES_INC = `$(PKG_CONFIG) --cflags harfbuzz` LIGATURES_INC = `$(PKG_CONFIG) --cflags harfbuzz`
#LIGATURES_LIBS = `$(PKG_CONFIG) --libs harfbuzz` LIGATURES_LIBS = `$(PKG_CONFIG) --libs harfbuzz`
# Uncomment this for the SIXEL patch / SIXEL_PATCH # Uncomment this for the SIXEL patch / SIXEL_PATCH
#SIXEL_C = sixel.c sixel_hls.c SIXEL_C = sixel.c sixel_hls.c
#SIXEL_LIBS = `$(PKG_CONFIG) --libs imlib2` SIXEL_LIBS = `$(PKG_CONFIG) --libs imlib2`
# Uncomment for the netwmicon patch / NETWMICON_PATCH # Uncomment for the netwmicon patch / NETWMICON_PATCH
#NETWMICON_LIBS = `$(PKG_CONFIG) --libs gdlib` #NETWMICON_LIBS = `$(PKG_CONFIG) --libs gdlib`
@ -38,7 +38,7 @@ INCS = -I$(X11INC) \
`$(PKG_CONFIG) --cflags fontconfig` \ `$(PKG_CONFIG) --cflags fontconfig` \
`$(PKG_CONFIG) --cflags freetype2` \ `$(PKG_CONFIG) --cflags freetype2` \
$(LIGATURES_INC) $(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 fontconfig` \
`$(PKG_CONFIG) --libs freetype2` \ `$(PKG_CONFIG) --libs freetype2` \
$(LIGATURES_LIBS) \ $(LIGATURES_LIBS) \
@ -50,10 +50,7 @@ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
STLDFLAGS = $(LIBS) $(LDFLAGS) STLDFLAGS = $(LIBS) $(LDFLAGS)
# OpenBSD: # OpenBSD:
#CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE #CPPFLAGS = $(STCPPFLAGS) -D_XOPEN_SOURCE=600
#LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
# `pkg-config --libs fontconfig` \
# `pkg-config --libs freetype2`
#MANPREFIX = ${PREFIX}/man #MANPREFIX = ${PREFIX}/man
# compiler and linker # compiler and linker

56
default.nix Normal file
View file

@ -0,0 +1,56 @@
{ lib
, stdenv
, pkg-config
, fontconfig
, freetype
, libX11
, libXft
, harfbuzz
, gd
, glib
, ncurses
, writeText
, conf ? null
, patches ? []
, extraLibs ? []
, nixosTests
, imlib2
}:
stdenv.mkDerivation rec {
pname = "st";
version = "0.8.5";
src = ./.;
inherit patches;
configFile =
lib.optionalString (conf != null) (writeText "config.def.h" conf);
postPatch = lib.optionalString (conf != null) "cp ${configFile} config.def.h"
+ lib.optionalString stdenv.isDarwin ''
substituteInPlace config.mk --replace "-lrt" ""
'';
strictDeps = true;
makeFlags = [ "PKG_CONFIG=${stdenv.cc.targetPrefix}pkg-config" ];
nativeBuildInputs = [ pkg-config ncurses fontconfig freetype ];
buildInputs = [ libX11 libXft harfbuzz gd glib imlib2 ] ++ extraLibs;
preInstall = ''
export TERMINFO=$out/share/terminfo
'';
installFlags = [ "PREFIX=$(out)" ];
passthru.tests.test = nixosTests.terminal-emulators.st;
meta = with lib; {
description = "st terminal";
license = licenses.mit;
maintainers = with maintainers; [ sioodmy ];
platforms = platforms.unix;
};
}

61
flake.lock generated Normal file
View file

@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1736549401,
"narHash": "sha256-ibkQrMHxF/7TqAYcQE+tOnIsSEzXmMegzyBWza6uHKM=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "1dab772dd4a68a7bba5d9460685547ff8e17d899",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-24.11",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

41
flake.nix Normal file
View file

@ -0,0 +1,41 @@
{
description = "st terminal";
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11";
inputs.flake-utils.url = "github:numtide/flake-utils";
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let pkgs = nixpkgs.legacyPackages.${system};
in rec {
packages = flake-utils.lib.flattenTree {
st = pkgs.callPackage ./default.nix { };
};
defaultPackage = packages.st;
apps.st = flake-utils.lib.mkApp {
drv = packages.st;
exePath = "/bin/st";
};
apps.default = apps.st;
defaultApp = apps.st;
devShell = pkgs.mkShell rec {
name = "st";
packages = with pkgs; [
pkg-config
xorg.libX11
xorg.libXft
fontconfig
harfbuzz.dev
imlib2
gd
glib
# ccls
# bear
# lldb
# gdb
# valgrind
];
};
});
}

13
hb.c
View file

@ -35,13 +35,6 @@ typedef struct {
static RuneBuffer hbrunebuffer = { 0, NULL }; static RuneBuffer hbrunebuffer = { 0, NULL };
static hb_buffer_t *hbbuffer; static hb_buffer_t *hbbuffer;
/*
* Poplulate the array with a list of font features, wrapped in FEATURE macro,
* e. g.
* FEATURE('c', 'a', 'l', 't'), FEATURE('d', 'l', 'i', 'g')
*/
hb_feature_t features[] = { };
void void
hbcreatebuffer(void) hbcreatebuffer(void)
{ {
@ -125,7 +118,11 @@ hbtransform(HbTransformData *data, XftFont *xfont, const Glyph *glyphs, int star
hb_buffer_add_codepoints(buffer, hbrunebuffer.runes, length, 0, length); hb_buffer_add_codepoints(buffer, hbrunebuffer.runes, length, 0, length);
/* Shape the segment. */ /* Shape the segment. */
hb_shape(font, buffer, features, sizeof(features)/sizeof(hb_feature_t)); #if FONTFEATURES_PATCH
hb_shape(font, buffer, data->features, data->features_count);
#else
hb_shape(font, buffer, NULL, 0);
#endif
/* Get new glyph info. */ /* Get new glyph info. */
hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, &glyph_count); hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, &glyph_count);

4
hb.h
View file

@ -7,6 +7,10 @@ typedef struct {
hb_glyph_info_t *glyphs; hb_glyph_info_t *glyphs;
hb_glyph_position_t *positions; hb_glyph_position_t *positions;
unsigned int count; unsigned int count;
#if FONTFEATURES_PATCH
hb_feature_t *features;
int features_count;
#endif // FONTFEATURES_PATCH
} HbTransformData; } HbTransformData;
void hbcreatebuffer(void); void hbcreatebuffer(void);

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; int x, y;
/* regionselected() takes relative coordinates */ /* regionselected() takes relative coordinates */
if (regionselected(x1+term.scr, y1+term.scr, x2+term.scr, y2+term.scr)) if (regionselected(x1, y1+term.scr, x2, y2+term.scr))
selremove(); selclear();
for (y = y1; y <= y2; y++) { for (y = y1; y <= y2; y++) {
term.dirty[y] = 1; term.dirty[y] = 1;

View file

@ -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
@ -35,6 +38,9 @@
#elif NETWMICON_LEGACY_PATCH #elif NETWMICON_LEGACY_PATCH
#include "netwmicon_legacy.c" #include "netwmicon_legacy.c"
#endif #endif
#if OPEN_SELECTED_TEXT_PATCH
#include "openselectedtext.c"
#endif
#if OPENURLONCLICK_PATCH #if OPENURLONCLICK_PATCH
#include "openurlonclick.c" #include "openurlonclick.c"
#endif #endif

View file

@ -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
@ -32,6 +35,9 @@
#if NETWMICON_PATCH || NETWMICON_FF_PATCH || NETWMICON_LEGACY_PATCH #if NETWMICON_PATCH || NETWMICON_FF_PATCH || NETWMICON_LEGACY_PATCH
#include "netwmicon.h" #include "netwmicon.h"
#endif #endif
#if OPEN_SELECTED_TEXT_PATCH
#include "openselectedtext.h"
#endif
#if RIGHTCLICKTOPLUMB_PATCH #if RIGHTCLICKTOPLUMB_PATCH
#include "rightclicktoplumb_x.h" #include "rightclicktoplumb_x.h"
#endif #endif

View file

@ -14,7 +14,7 @@
* when including this patch. * when including this patch.
* https://st.suckless.org/patches/alpha/ * https://st.suckless.org/patches/alpha/
*/ */
#define ALPHA_PATCH 0 #define ALPHA_PATCH 1
/* The alpha focus highlight patch allows the user to specify two distinct opacity values or /* The alpha focus highlight patch allows the user to specify two distinct opacity values or
* background colors in order to easily differentiate between focused and unfocused terminal * background colors in order to easily differentiate between focused and unfocused terminal
@ -70,12 +70,12 @@
* This patch makes bold text rendered simply as bold, leaving the color unaffected. * This patch makes bold text rendered simply as bold, leaving the color unaffected.
* https://st.suckless.org/patches/bold-is-not-bright/ * https://st.suckless.org/patches/bold-is-not-bright/
*/ */
#define BOLD_IS_NOT_BRIGHT_PATCH 0 #define BOLD_IS_NOT_BRIGHT_PATCH 1
/* This patch adds custom rendering of lines/blocks/braille characters for gapless alignment. /* This patch adds custom rendering of lines/blocks/braille characters for gapless alignment.
* https://st.suckless.org/patches/boxdraw/ * https://st.suckless.org/patches/boxdraw/
*/ */
#define BOXDRAW_PATCH 0 #define BOXDRAW_PATCH 1
/* By default st only sets PRIMARY on selection. /* By default st only sets PRIMARY on selection.
* This patch makes st set CLIPBOARD on selection. * This patch makes st set CLIPBOARD on selection.
@ -144,11 +144,27 @@
*/ */
#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/
*/ */
#define DYNAMIC_CURSOR_COLOR_PATCH 0 #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. /* Reading and writing st's screen through a pipe, e.g. pass info to dmenu.
* https://st.suckless.org/patches/externalpipe/ * https://st.suckless.org/patches/externalpipe/
*/ */
@ -176,7 +192,7 @@
* that are available to GUI applications. * that are available to GUI applications.
* https://st.suckless.org/patches/fix_keyboard_input/ * https://st.suckless.org/patches/fix_keyboard_input/
*/ */
#define FIXKEYBOARDINPUT_PATCH 0 #define FIXKEYBOARDINPUT_PATCH 1
/* This patch allows you to add spare font besides the default. Some glyphs can be not present in /* This patch allows you to add spare font besides the default. Some glyphs can be not present in
* the default font. For this glyphs st uses font-config and try to find them in font cache first. * the default font. For this glyphs st uses font-config and try to find them in font cache first.
@ -184,7 +200,7 @@
* So they will be used first for glyphs that are absent in the default font. * So they will be used first for glyphs that are absent in the default font.
* https://st.suckless.org/patches/font2/ * https://st.suckless.org/patches/font2/
*/ */
#define FONT2_PATCH 0 #define FONT2_PATCH 1
/* This patch adds the ability to toggle st into fullscreen mode. /* This patch adds the ability to toggle st into fullscreen mode.
* Two key bindings are defined: F11 which is typical with other applications and Alt+Enter * Two key bindings are defined: F11 which is typical with other applications and Alt+Enter
@ -223,7 +239,7 @@
* *
* https://st.suckless.org/patches/keyboard_select/ * https://st.suckless.org/patches/keyboard_select/
*/ */
#define KEYBOARDSELECT_PATCH 0 #define KEYBOARDSELECT_PATCH 1
/* This patch adds support for drawing ligatures using the Harfbuzz library to transform /* This patch adds support for drawing ligatures using the Harfbuzz library to transform
* original text of a single line to a list of glyphs with ligatures included. * original text of a single line to a list of glyphs with ligatures included.
@ -233,7 +249,14 @@
* https://github.com/cog1to/st-ligatures * https://github.com/cog1to/st-ligatures
* https://st.suckless.org/patches/ligatures/ * https://st.suckless.org/patches/ligatures/
*/ */
#define LIGATURES_PATCH 0 #define LIGATURES_PATCH 1
/* This patch add support for custom font features. It depends on the LIGATURES_PATCH patch
*/
#define FONTFEATURES_PATCH 1
#define DARKMAN_PATCH 1
/* This patch makes st ignore terminal color attributes by forcing display of the default /* This patch makes st ignore terminal color attributes by forcing display of the default
* foreground and background colors only - making for a monochrome look. Idea ref. * foreground and background colors only - making for a monochrome look. Idea ref.
@ -279,7 +302,7 @@
* same CWD (current working directory) as the original st instance. * same CWD (current working directory) as the original st instance.
* https://st.suckless.org/patches/newterm/ * https://st.suckless.org/patches/newterm/
*/ */
#define NEWTERM_PATCH 0 #define NEWTERM_PATCH 1
/* This patch will set the _MOTIF_WM_HINTS property for the st window which, if the window manager /* This patch will set the _MOTIF_WM_HINTS property for the st window which, if the window manager
* respects it, will show the st window without window decorations. * respects it, will show the st window without window decorations.
@ -294,12 +317,17 @@
*/ */
#define OPENCOPIED_PATCH 0 #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 /* This patch allows for URLs to be opened directly when you click on them. This may not work with
* all terminal applications. * all terminal applications.
* *
* https://www.reddit.com/r/suckless/comments/cc83om/st_open_url/ * https://www.reddit.com/r/suckless/comments/cc83om/st_open_url/
*/ */
#define OPENURLONCLICK_PATCH 0 #define OPENURLONCLICK_PATCH 1
/* This patch allows st to fetch the current working directory through the OSC 7 escape /* This patch allows st to fetch the current working directory through the OSC 7 escape
* sequence emitted by shells. Must be used with newterm patch. * sequence emitted by shells. Must be used with newterm patch.
@ -321,7 +349,7 @@
* Text wraps when the terminal window is made smaller. * Text wraps when the terminal window is made smaller.
* Comes with scrollback. * Comes with scrollback.
*/ */
#define REFLOW_PATCH 0 #define REFLOW_PATCH 1
/* This patch allows you to specify a border that is relative in size to the width of a cell /* This patch allows you to specify a border that is relative in size to the width of a cell
* in the terminal. * in the terminal.
@ -338,19 +366,19 @@
/* Scroll back through terminal output using Shift+{PageUp, PageDown}. /* Scroll back through terminal output using Shift+{PageUp, PageDown}.
* https://st.suckless.org/patches/scrollback/ * https://st.suckless.org/patches/scrollback/
*/ */
#define SCROLLBACK_PATCH 0 #define SCROLLBACK_PATCH 1
/* Scroll back through terminal output using Shift+MouseWheel. /* Scroll back through terminal output using Shift+MouseWheel.
* This variant depends on SCROLLBACK_PATCH being enabled. * This variant depends on SCROLLBACK_PATCH being enabled.
* https://st.suckless.org/patches/scrollback/ * https://st.suckless.org/patches/scrollback/
*/ */
#define SCROLLBACK_MOUSE_PATCH 0 #define SCROLLBACK_MOUSE_PATCH 1
/* Scroll back through terminal output using mouse wheel (when not in MODE_ALTSCREEN). /* Scroll back through terminal output using mouse wheel (when not in MODE_ALTSCREEN).
* This variant depends on SCROLLBACK_PATCH being enabled. * This variant depends on SCROLLBACK_PATCH being enabled.
* https://st.suckless.org/patches/scrollback/ * https://st.suckless.org/patches/scrollback/
*/ */
#define SCROLLBACK_MOUSE_ALTSCREEN_PATCH 0 #define SCROLLBACK_MOUSE_ALTSCREEN_PATCH 1
/* This patch adds the two color-settings selectionfg and selectionbg to config.def.h. /* This patch adds the two color-settings selectionfg and selectionbg to config.def.h.
* Those define the fore- and background colors which are used when text on the screen is selected * Those define the fore- and background colors which are used when text on the screen is selected
@ -378,7 +406,7 @@
* *
* https://gist.github.com/saitoha/70e0fdf22e3e8f63ce937c7f7da71809 * https://gist.github.com/saitoha/70e0fdf22e3e8f63ce937c7f7da71809
*/ */
#define SIXEL_PATCH 0 #define SIXEL_PATCH 1
/* This patch allows clients to embed into the st window and is useful if you tend to /* This patch allows clients to embed into the st window and is useful if you tend to
* start X applications from the terminal. For example: * start X applications from the terminal. For example:
@ -438,7 +466,7 @@
* *
* https://st.suckless.org/patches/undercurl/ * https://st.suckless.org/patches/undercurl/
*/ */
#define UNDERCURL_PATCH 0 #define UNDERCURL_PATCH 1
/* Allows mouse scroll without modifier keys for regardless of alt screen using the external /* Allows mouse scroll without modifier keys for regardless of alt screen using the external
* scroll program. * scroll program.

34
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); MODBIT(term.mode, set, MODE_SIXEL_CUR_RT);
break; break;
#endif // SIXEL_PATCH #endif // SIXEL_PATCH
#if SYNC_PATCH
case 2026:
if (set) {
tsync_begin();
} else {
tsync_end();
}
break;
#endif // SYNC_PATCH
default: default:
fprintf(stderr, fprintf(stderr,
"erresc: unknown private set/reset mode %d\n", "erresc: unknown private set/reset mode %d\n",
@ -2435,6 +2444,23 @@ csihandle(void)
goto unknown; goto unknown;
} }
break; 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 */ case 'r': /* DECSTBM -- Set Scrolling Region */
if (csiescseq.priv) { if (csiescseq.priv) {
goto unknown; goto unknown;
@ -2498,7 +2524,11 @@ csihandle(void)
break; break;
#endif // CSI_22_23_PATCH | SIXEL_PATCH #endif // CSI_22_23_PATCH | SIXEL_PATCH
case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */ case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
tcursor(CURSOR_LOAD); if (csiescseq.priv) {
goto unknown;
} else {
tcursor(CURSOR_LOAD);
}
break; break;
case ' ': case ' ':
switch (csiescseq.mode[1]) { switch (csiescseq.mode[1]) {
@ -3434,7 +3464,7 @@ check_control_code:
#if REFLOW_PATCH #if REFLOW_PATCH
/* selected() takes relative coordinates */ /* 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(); selclear();
#else #else
if (selected(term.c.x, term.c.y)) if (selected(term.c.x, term.c.y))

14
st.h
View file

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

164
x.c
View file

@ -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,
@ -795,10 +802,13 @@ setsel(char *str, Time t)
#endif // CLIPBOARD_PATCH #endif // CLIPBOARD_PATCH
} }
#if XRESOURCES_PATCH && XRESOURCES_RELOAD_PATCH || BACKGROUND_IMAGE_PATCH && BACKGROUND_IMAGE_RELOAD_PATCH #if XRESOURCES_PATCH && XRESOURCES_RELOAD_PATCH || BACKGROUND_IMAGE_PATCH && BACKGROUND_IMAGE_RELOAD_PATCH || DARKMAN_PATCH
void void
sigusr1_reload(int sig) sigusr1_reload(int sig)
{ {
#if DARKMAN_PATCH
xloadcols();
#endif // DARKMAN_PATCH
#if XRESOURCES_PATCH && XRESOURCES_RELOAD_PATCH #if XRESOURCES_PATCH && XRESOURCES_RELOAD_PATCH
reload_config(sig); reload_config(sig);
#endif // XRESOURCES_RELOAD_PATCH #endif // XRESOURCES_RELOAD_PATCH
@ -976,6 +986,28 @@ xloadalpha(void)
} }
#endif // ALPHA_FOCUS_HIGHLIGHT_PATCH #endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
#if DARKMAN_PATCH
void
darkmanThemeChoose() {
FILE *fp;
char path[128];
fp = popen("darkman get", "r");
if (fp == NULL) {
memcpy(colorname, colornames[0], sizeof(colorname));
} else {
/* match the stdout with the theme */
while (fgets(path, sizeof(path)-1, fp) != NULL) {
if (strcmp(path, "light\n") == 0) {
memcpy(colorname, colornames[0], sizeof(colorname));
} else if (strcmp(path, "dark\n") == 0) {
memcpy(colorname, colornames[1], sizeof(colorname));
}
}
}
}
#endif // DARKMAN_PATCH
#if ALPHA_PATCH && ALPHA_FOCUS_HIGHLIGHT_PATCH #if ALPHA_PATCH && ALPHA_FOCUS_HIGHLIGHT_PATCH
void void
xloadcols(void) xloadcols(void)
@ -1009,6 +1041,8 @@ xloadcols(void)
static int loaded; static int loaded;
Color *cp; Color *cp;
darkmanThemeChoose();
if (loaded) { if (loaded) {
for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp) for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp)
XftColorFree(xw.dpy, xw.vis, xw.cmap, cp); XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
@ -1130,7 +1164,7 @@ xhints(void)
sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize; sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize;
sizeh->height = win.h; sizeh->height = win.h;
sizeh->width = win.w; sizeh->width = win.w;
#if ANYSIZE_PATCH || ANYSIZE_SIMPLE_PATCH #if ANYSIZE_PATCH && !DYNAMIC_PADDING_PATCH || ANYSIZE_SIMPLE_PATCH
sizeh->height_inc = 1; sizeh->height_inc = 1;
sizeh->width_inc = 1; sizeh->width_inc = 1;
#else #else
@ -1656,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();
@ -1724,6 +1780,26 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
xp = winx, yp = winy + font->ascent; xp = winx, yp = winy + font->ascent;
#endif // VERTCENTER_PATCH #endif // VERTCENTER_PATCH
cluster_xp = xp; cluster_yp = yp; cluster_xp = xp; cluster_yp = yp;
#if FONTFEATURES_PATCH
{ // Get font features
shaped.features = (hb_feature_t *) malloc(sizeof(hb_feature_t) * 128);
FcChar8 *s;
int feature_idx = 0;
while (FcPatternGetString(font->pattern, FC_FONT_FEATURES, feature_idx, &s) == FcResultMatch) {
if (strlen(s) != 4)
die("Invalid font feature tag");
if (feature_idx >= 128)
die("Too many font features");
shaped.features[feature_idx].tag = HB_TAG(s[0], s[1], s[2], s[3]);
shaped.features[feature_idx].value = 1;
shaped.features[feature_idx].start = HB_FEATURE_GLOBAL_START;
shaped.features[feature_idx].end = HB_FEATURE_GLOBAL_END;
feature_idx++;
}
shaped.features_count = feature_idx;
}
#endif // FONTFEATURES_PATCH
/* Shape the segment. */ /* Shape the segment. */
hbtransform(&shaped, font->match, glyphs, 0, len); hbtransform(&shaped, font->match, glyphs, 0, len);
#endif // LIGATURES_PATCH #endif // LIGATURES_PATCH
@ -2205,20 +2281,9 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
else else
#endif // BACKGROUND_IMAGE_PATCH #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 */ /* Fill the background */
XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
#if WIDE_GLYPHS_PATCH
} }
#endif // WIDE_GLYPHS_PATCH #endif // WIDE_GLYPHS_PATCH
@ -2229,12 +2294,27 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
if (base.mode & ATTR_BOXDRAW) { if (base.mode & ATTR_BOXDRAW) {
drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len);
} else { } else {
/* Render the glyphs. */ #endif // BOXDRAW_PATCH
XftDrawGlyphFontSpec(xw.draw, fg, specs, len); /* 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 #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. */ /* Render the glyphs. */
XftDrawGlyphFontSpec(xw.draw, fg, specs, len); XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
#if BOXDRAW_PATCH
}
#endif // BOXDRAW_PATCH #endif // BOXDRAW_PATCH
/* Render underline and strikethrough. */ /* Render underline and strikethrough. */
@ -2671,21 +2751,19 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
XRenderColor colbg; XRenderColor colbg;
#endif // DYNAMIC_CURSOR_COLOR_PATCH #endif // DYNAMIC_CURSOR_COLOR_PATCH
#if !DYNAMIC_CURSOR_COLOR_PATCH #if LIGATURES_PATCH
/* remove the old cursor */ /* 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 (selected(ox, oy))
#if SELECTION_COLORS_PATCH #if SELECTION_COLORS_PATCH
og.mode |= ATTR_SELECTED; og.mode |= ATTR_SELECTED;
#else #else
og.mode ^= ATTR_REVERSE; og.mode ^= ATTR_REVERSE;
#endif // SELECTION_COLORS_PATCH #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); xdrawglyph(og, ox, oy);
#endif // LIGATURES_PATCH #endif // LIGATURES_PATCH
@ -2728,7 +2806,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
} }
#endif // SELECTION_COLORS_PATCH #endif // SELECTION_COLORS_PATCH
} else { } else {
#if SELECTION_COLORS_PATCH #if SELECTION_COLORS_PATCH && !DYNAMIC_CURSOR_COLOR_PATCH
g.fg = defaultbg; g.fg = defaultbg;
g.bg = defaultcs; g.bg = defaultcs;
drawcol = dc.col[defaultcs]; drawcol = dc.col[defaultcs];
@ -3666,6 +3744,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
} }
} }
@ -3762,8 +3855,12 @@ run(void)
xev = 0; xev = 0;
while (XPending(xw.dpy)) { while (XPending(xw.dpy)) {
xev = 1;
XNextEvent(xw.dpy, &ev); 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)) if (XFilterEvent(&ev, None))
continue; continue;
if (handler[ev.type]) if (handler[ev.type])
@ -3790,10 +3887,10 @@ run(void)
if (!drawing) { if (!drawing) {
trigger = now; trigger = now;
#if BLINKING_CURSOR_PATCH #if BLINKING_CURSOR_PATCH
if (IS_SET(MODE_BLINK)) { if (xev != SelectionRequest) {
win.mode ^= MODE_BLINK; win.mode &= ~MODE_BLINK;
lastblink = now;
} }
lastblink = now;
#endif // BLINKING_CURSOR_PATCH #endif // BLINKING_CURSOR_PATCH
drawing = 1; drawing = 1;
} }
@ -3958,9 +4055,12 @@ run:
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");
XSetLocaleModifiers(""); XSetLocaleModifiers("");
#if XRESOURCES_PATCH && XRESOURCES_RELOAD_PATCH || BACKGROUND_IMAGE_PATCH && BACKGROUND_IMAGE_RELOAD_PATCH #if XRESOURCES_PATCH && XRESOURCES_RELOAD_PATCH || BACKGROUND_IMAGE_PATCH && BACKGROUND_IMAGE_RELOAD_PATCH || DARKMAN_PATCH
signal(SIGUSR1, sigusr1_reload); signal(SIGUSR1, sigusr1_reload);
#endif // XRESOURCES_RELOAD_PATCH | BACKGROUND_IMAGE_RELOAD_PATCH #endif // XRESOURCES_RELOAD_PATCH | BACKGROUND_IMAGE_RELOAD_PATCH | DARKMAN_PATCH
#if DARKMAN_PATCH
memcpy(colornames[0], colorname, sizeof(colorname));
#endif // DARKMAN_PATCH
#if XRESOURCES_PATCH #if XRESOURCES_PATCH
if (!(xw.dpy = XOpenDisplay(NULL))) if (!(xw.dpy = XOpenDisplay(NULL)))
die("Can't open display\n"); die("Can't open display\n");