Compare commits

...

38 commits

Author SHA1 Message Date
ant
b5498bad11 Revert "change colors for light theme"
This reverts commit 042af42400.
2025-11-30 15:20:10 +01:00
Antoine Vaure
33209c6746 change colors for light theme 2025-11-30 15:20:10 +01:00
Antoine Vaure
f8b47f894b add keybinnds to scroll 2025-11-30 15:19:37 +01:00
Antoine Vaure
ae3a9baf0d decrease default font size 2025-11-30 15:17:58 +01:00
ant
1cc56c4856 Enable alpha patch 2025-11-30 15:17:58 +01:00
ant
a9d0d20213 enable boxdraw 2025-11-30 15:17:58 +01:00
ant
7415d93cf2 Add a nix flake 2025-11-30 15:17:58 +01:00
ant
d0b32e19c6 enable patches I want 2025-11-30 15:17:58 +01:00
ant
1ea9ec607b change keys to keyboard select and zoom 2025-11-30 15:17:58 +01:00
ant
84a920d545 change default colors 2025-11-30 15:17:58 +01:00
ant
48defe07d2 Add darkman patch
a patch to choose between two color themes by executing a command
2025-11-30 15:17:58 +01:00
ant
d44ab2a9a2 font default to caskadia 2025-11-30 15:17:58 +01:00
Antoine Vaure
b8131450b0 config: increase scroll speed 2025-11-30 15:17:58 +01:00
ant
ec1b8b0ac0 fontfeature patch 2025-11-30 15:17:58 +01:00
Javier
37bc089f1d Add selectionbg-alpha patch (#188) 2025-10-28 10:18:15 +01:00
Bakkeby
e77d5e1b3b sync patch: add DECRQM 80 and 8452 for sixel patch ref. #179 2025-10-26 00:22:53 +02:00
Bakkeby
d12d2ad1c2 sync patch: remove redundant inner #if for DECRQM -- DEC Request Mode case statement ref. #179 2025-10-25 14:04:52 +02:00
Bakkeby
46a5982e9d Removing utils.h, leftover from the vim browse patch 2025-10-14 16:03:38 +02:00
Lady Alice
1d5c8a1595
reflow: enable keyboard scrolling by default (#187) 2025-10-14 14:26:45 +02:00
Bakkeby
bdb21ddb8b bump version to 0.9.3
https://git.suckless.org/st/commit/5a4666c19e3956069147aee43a06b326d998366e.html

add a few comments

https://git.suckless.org/st/commit/5a4666c19e3956069147aee43a06b326d998366e.html

Support OSC 110, 111, and 112 for resetting colors

This adds support for OSC 110, 111, and 112 escape sequences to reset
the foreground, background, and cursor colors in the terminal. The
changes include handling these sequences in the `strhandle` function of
`st.c`, allowing applications to reset colors to their default values.

The OSC sequences originated from Xterm control sequences and are now
widely used in terminal applications and supported by many terminal
emulators. For applications, this allows them to reset colors to
default values without needing to know the colors beforehand.

https://git.suckless.org/st/commit/d6c431859c6c0201e0668ed24a9f17cebf0a68f5.html
2025-08-10 15:44:48 +02:00
Bakkeby
9328548866 xresources: removing focus change ttywrite ref. #182 2025-08-03 22:19:37 +02:00
Bakkeby
92e6c003f7 Eat up "CSI 58" sequences
This is used in the wild by systemd systemctl for example and st
misinterpreted it as "blink", because it didn't know "58", then saw "5"
as "blink", and then didn't know "245".

This should print "foo" as normal text:

    printf '\e[58:5:245mfoo\n'
    printf '\e[58:2:50💯200mfoo\n'

Ref.
https://git.suckless.org/st/commit/f114bcedd113017d907aad32031db92c050f4bf3.html
2025-07-27 20:48:20 +02:00
Bakkeby
fba8d10417 Bump to 98610fc 2025-07-09 09:47:04 +02:00
Laurent Cheylus
f17e1dcf31
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-07-09 09:45:24 +02:00
Bakkeby
7c28c7868a sync: add support for DECRQM queries for synchronization ref. #179 2025-07-08 19:17:57 +02:00
Bakkeby
9edaa4c149 sync: mode 2026 correction ref. #179 2025-07-08 15:11:17 +02:00
Bakkeby
4000b47a10 sync: adding mode 2026 for the sync patch to allow syncing to be controlled by programs ref. #179 2025-07-08 10:42:24 +02:00
Bakkeby
dd9784883f boxdraw: fix for rendering errors following commit f8e451e ref. #180 2025-07-08 10:27:50 +02:00
Bakkeby
43d9be991b OpenBSD compatibility changes 2025-06-16 22:53:48 +02:00
Bakkeby
f8e451e26c Refactoring Xft clipping ref. #175 2025-05-06 14:41:20 +02:00
veltza
cb91e175ba
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-04-22 09:53:53 +02:00
Bakkeby
da81ae1704 dynamic padding - add explicit dependency on the ANYSIZE_PATCH ref. #168 2025-03-04 10:12:43 +01:00
Bakkeby
dc64384989 dynamic cursor color: visual bug on selection ref. #169 2025-02-27 21:57:48 +01:00
Bakkeby
d60f1b355f Adding dynamic padding patch - a variant of anysize that do not alter size hints ref. #168 2025-02-26 22:36:24 +01:00
Bakkeby
75da349fb3 selection colors vs dynamic cursor color patch compatibility issue ref. #167 2025-02-26 21:58:05 +01:00
Bakkeby
c4af76a9cc reflow: addressing selection clearing bug when selection includes the prompt ref. #166 2025-02-26 21:23:09 +01:00
Bakkeby
978e25f23b Adding open selected text patch 2025-02-20 22:36:51 +01:00
Bakkeby
08b53c4960 Adding drag-n-drop patch 2025-02-20 10:18:17 +01:00
21 changed files with 807 additions and 154 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.3 (6e97047, 2025-08-09) 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,10 @@ Refer to [https://st.suckless.org/](https://st.suckless.org/) for details on the
### Changelog:
2025-10-28 - Added the selectionbg-alpha patch
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 +166,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 +237,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
@ -252,6 +262,10 @@ Refer to [https://st.suckless.org/](https://st.suckless.org/) for details on the
- [right-click-to-plumb](https://st.suckless.org/patches/right_click_to_plumb/)
- allows you to right-click on some selected text to send it to the plumbing program of choice
- [selectionbg-alpha](https://st.suckless.org/patches/selectionbg-alpha/)
- allows for the selection to have a transparent background when combined with the alpha
and selection colors patches
- [scrollback](https://st.suckless.org/patches/scrollback/)
- allows you scroll back through terminal output using keyboard shortcuts or mousewheel

View file

@ -5,13 +5,10 @@
*
* 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
/* Spare fonts */
static char *font2[] = {
/* "Inconsolata for Powerline:pixelsize=12:antialias=true:autohint=true", */
/* "Hack Nerd Font Mono:pixelsize=11:antialias=true:autohint=true", */
};
static char *font2[] = { "CaskaydiaCove Nerd Font:pixelsize=13.5:antialias=true:autohint=true" };
#endif // FONT2_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.
* 0: disable (render all U25XX glyphs normally from the font).
*/
const int boxdraw = 0;
const int boxdraw_bold = 0;
const int boxdraw = 1;
const int boxdraw_bold = 1;
/* braille (U28XX): 1: render as adjacent "pixels", 0: use font */
const int boxdraw_braille = 0;
const int boxdraw_braille = 1;
#endif // BOXDRAW_PATCH
/*
@ -175,37 +172,79 @@ 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 const char *colorname[] = {
/* 8 normal colors */
"black",
"red3",
"green3",
"yellow3",
"blue2",
"magenta3",
"cyan3",
"gray90",
/* 8 bright colors */
"gray50",
"red",
"green",
"yellow",
"#5c5cff",
"magenta",
"cyan",
"white",
[255] = 0,
/* more colors can be added after 255 to use with DefaultXX */
"#add8e6", /* 256 -> cursor */
"#555555", /* 257 -> rev cursor*/
"#000000", /* 258 -> bg */
"#e5e5e5", /* 259 -> fg */
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",
[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 */
};
#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)
@ -362,14 +401,17 @@ 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
{ XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
#endif // CLIPBOARD_PATCH
#if SCROLLBACK_MOUSE_PATCH
{ ShiftMask, Button4, kscrollup, {.i = 1}, 0, S_PRI},
{ ShiftMask, Button5, kscrolldown, {.i = 1}, 0, S_PRI},
{ ShiftMask, Button4, kscrollup, {.i = 4}, 0, S_PRI},
{ ShiftMask, Button5, kscrolldown, {.i = 4}, 0, S_PRI},
#elif UNIVERSCROLL_PATCH
{ XK_ANY_MOD, Button4, ttysend, {.s = "\033[5;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~"} },
#endif // SCROLLBACK_MOUSE_PATCH
#if SCROLLBACK_MOUSE_ALTSCREEN_PATCH || REFLOW_PATCH
{ XK_ANY_MOD, Button4, kscrollup, {.i = 1}, 0, S_PRI },
{ XK_ANY_MOD, Button5, kscrolldown, {.i = 1}, 0, S_PRI },
{ XK_ANY_MOD, Button4, kscrollup, {.i = 4}, 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, Button5, ttysend, {.s = "\005"}, 0, S_ALT },
#else
@ -410,8 +452,8 @@ static Shortcut shortcuts[] = {
{ ControlMask, XK_Print, toggleprinter, {.i = 0} },
{ ShiftMask, XK_Print, printscreen, {.i = 0} },
{ XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
{ TERMMOD, XK_Prior, zoom, {.f = +1} },
{ TERMMOD, XK_Next, zoom, {.f = -1} },
{ MODKEY | ControlMask, XK_comma, zoom, {.f = +1} },
{ MODKEY | ControlMask, XK_semicolon, zoom, {.f = -1} },
{ TERMMOD, XK_Home, zoomreset, {.f = 0} },
{ TERMMOD, XK_C, clipcopy, {.i = 0} },
{ TERMMOD, XK_V, clippaste, {.i = 0} },
@ -427,10 +469,14 @@ static Shortcut shortcuts[] = {
{ XK_NO_MOD, XK_F11, fullscreen, {.i = 0} },
{ MODKEY, XK_Return, fullscreen, {.i = 0} },
#endif // FULLSCREEN_PATCH
#if SCROLLBACK_PATCH
#if SCROLLBACK_PATCH || REFLOW_PATCH
{ ShiftMask, XK_Page_Up, kscrollup, {.i = -1}, S_PRI },
{ ShiftMask, XK_Page_Down, kscrolldown, {.i = -1}, S_PRI },
#endif // SCROLLBACK_PATCH
{ 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 || REFLOW_PATCH
#if CLIPBOARD_PATCH
{ TERMMOD, XK_Y, clippaste, {.i = 0} },
{ ShiftMask, XK_Insert, clippaste, {.i = 0} },
@ -455,7 +501,7 @@ static Shortcut shortcuts[] = {
#endif // EXTERNALPIPEIN_PATCH
#endif // EXTERNALPIPE_PATCH
#if KEYBOARDSELECT_PATCH
{ TERMMOD, XK_Escape, keyboard_select, { 0 } },
{ TERMMOD, XK_space, keyboard_select, { 0 } },
#endif // KEYBOARDSELECT_PATCH
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
{ TERMMOD, XK_F, searchforward, { 0 } },

View file

@ -1,5 +1,5 @@
# st version
VERSION = 0.9.2
VERSION = 0.9.3
# Customize below to fit your system
@ -21,14 +21,14 @@ PKG_CONFIG = pkg-config
#XCURSOR = `$(PKG_CONFIG) --libs xcursor`
# Uncomment the lines below for the ligatures patch / LIGATURES_PATCH
#LIGATURES_C = hb.c
#LIGATURES_H = hb.h
#LIGATURES_INC = `$(PKG_CONFIG) --cflags harfbuzz`
#LIGATURES_LIBS = `$(PKG_CONFIG) --libs harfbuzz`
LIGATURES_C = hb.c
LIGATURES_H = hb.h
LIGATURES_INC = `$(PKG_CONFIG) --cflags harfbuzz`
LIGATURES_LIBS = `$(PKG_CONFIG) --libs harfbuzz`
# Uncomment this for the SIXEL patch / SIXEL_PATCH
#SIXEL_C = sixel.c sixel_hls.c
#SIXEL_LIBS = `$(PKG_CONFIG) --libs imlib2`
SIXEL_C = sixel.c sixel_hls.c
SIXEL_LIBS = `$(PKG_CONFIG) --libs imlib2`
# Uncomment for the netwmicon patch / NETWMICON_PATCH
#NETWMICON_LIBS = `$(PKG_CONFIG) --libs gdlib`
@ -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

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 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
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);
/* 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. */
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_position_t *positions;
unsigned int count;
#if FONTFEATURES_PATCH
hb_feature_t *features;
int features_count;
#endif // FONTFEATURES_PATCH
} HbTransformData;
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;
/* 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

@ -1,23 +0,0 @@
/// Dynamic memory-chunk, with (1) datatype size, (2/3) initialized / allocated chunk, (4) content
typedef struct { uint8_t const elSize; uint32_t init, alloc; char* content; } DynamicArray;
#define UTF8_ARRAY {4, 0, 0, NULL}
static inline int p_alloc(DynamicArray *s, uint32_t amount) {
uint32_t const diff=s->init+s->elSize*amount-s->alloc, nas=s->alloc+max(diff,15)*s->elSize;
if (s->alloc < s->init + s->elSize * amount) {
char* tmp = realloc(s->content, nas);
if (!tmp) return 0;
s->alloc = nas, s->content = tmp;
}
return 1;
}
static inline char *view(DynamicArray * s, uint32_t i) { return s->content + i*s->elSize; }
static inline char *end(DynamicArray *s, uint32_t i) { return s->content +s->init-(i+1)*s->elSize; }
static inline uint32_t getU32(DynamicArray* s, uint32_t i, int b) { return *((uint32_t*) (b ?view(s,i) :end(s,i))); }
static char *expand(DynamicArray *s) { if (!p_alloc(s, 1)) return NULL; s->init += s->elSize; return end(s, 0); }
static inline void pop(DynamicArray* s) { s->init -= s->elSize; }
static inline void empty(DynamicArray* s) { s->init = 0; }
static inline int size(DynamicArray const * s) { return s->init / s->elSize; }
static inline void assign(DynamicArray* s, DynamicArray const *o) {
if (p_alloc(s, size(o))) memcpy(s->content, o->content, (s->init=o->init));
}

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

@ -74,9 +74,5 @@ reload_config(int sig)
xhints();
XCloseDisplay(dpy);
/* from https://st.suckless.org/patches/xresources-with-reload-signal */
/* triggers re-render if we're visible */
ttywrite("\033[O", 3, 1);
}
#endif // XRESOURCES_RELOAD_PATCH

View file

@ -14,7 +14,7 @@
* when including this patch.
* 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
* 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.
* 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.
* https://st.suckless.org/patches/boxdraw/
*/
#define BOXDRAW_PATCH 0
#define BOXDRAW_PATCH 1
/* By default st only sets PRIMARY on selection.
* This patch makes st set CLIPBOARD on selection.
@ -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/
*/
@ -176,7 +192,7 @@
* that are available to GUI applications.
* 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
* 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.
* 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.
* 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/
*/
#define KEYBOARDSELECT_PATCH 0
#define KEYBOARDSELECT_PATCH 1
/* 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.
@ -233,7 +249,14 @@
* https://github.com/cog1to/st-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
* 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.
* 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
* respects it, will show the st window without window decorations.
@ -294,12 +317,17 @@
*/
#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.
*
* 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
* sequence emitted by shells. Must be used with newterm patch.
@ -321,7 +349,7 @@
* Text wraps when the terminal window is made smaller.
* 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
* in the terminal.
@ -338,19 +366,19 @@
/* Scroll back through terminal output using Shift+{PageUp, PageDown}.
* https://st.suckless.org/patches/scrollback/
*/
#define SCROLLBACK_PATCH 0
#define SCROLLBACK_PATCH 1
/* Scroll back through terminal output using Shift+MouseWheel.
* This variant depends on SCROLLBACK_PATCH being enabled.
* 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).
* This variant depends on SCROLLBACK_PATCH being enabled.
* 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.
* Those define the fore- and background colors which are used when text on the screen is selected
@ -359,6 +387,12 @@
*/
#define SELECTION_COLORS_PATCH 0
/* This patch works with selectioncolors and alpha patches to make selection
* background color transparent.
* https://st.suckless.org/patches/selectionbg-alpha/
*/
#define SELECTIONBG_ALPHA_PATCH 0
/* This is the single drawable buffer patch as outlined in the FAQ to get images
* in w3m to display. While this patch does not break the alpha patch it images
* are not shown in w3m if the alpha patch is applied.
@ -378,7 +412,7 @@
*
* 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
* start X applications from the terminal. For example:
@ -438,7 +472,7 @@
*
* 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
* scroll program.

86
st.c
View file

@ -1837,7 +1837,7 @@ tsetattr(const int *attr, int l)
term.c.attr.fg = idx;
#endif // MONOCHROME_PATCH
break;
case 39:
case 39: /* set foreground color to default */
term.c.attr.fg = defaultfg;
break;
case 48:
@ -1848,7 +1848,7 @@ tsetattr(const int *attr, int l)
term.c.attr.bg = idx;
#endif // MONOCHROME_PATCH
break;
case 49:
case 49: /* set background color to default */
term.c.attr.bg = defaultbg;
break;
#if UNDERCURL_PATCH
@ -1864,6 +1864,13 @@ tsetattr(const int *attr, int l)
term.c.attr.ucolor[2] = -1;
term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
break;
#else
case 58:
/* This starts a sequence to change the color of
* "underline" pixels. We don't support that and
* instead eat up a following "5;n" or "2;r;g;b". */
tdefcolor(attr, &i, l);
break;
#endif // UNDERCURL_PATCH
default:
if (BETWEEN(attr[i], 30, 37)) {
@ -1978,7 +1985,7 @@ tsetmode(int priv, int set, const int *args, int narg)
case 1006: /* 1006: extended reporting mode */
xsetmode(set, MODE_MOUSESGR);
break;
case 1034:
case 1034: /* 1034: enable 8-bit mode for keyboard input */
xsetmode(set, MODE_8BIT);
break;
case 1049: /* swap screen & set/restore cursor as xterm */
@ -1986,8 +1993,8 @@ tsetmode(int priv, int set, const int *args, int narg)
break;
tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
/* FALLTHROUGH */
case 47: /* swap screen */
case 1047:
case 47: /* swap screen buffer */
case 1047: /* swap screen buffer */
if (!allowaltscreen)
break;
#if REFLOW_PATCH
@ -2011,7 +2018,7 @@ tsetmode(int priv, int set, const int *args, int narg)
break;
/* FALLTHROUGH */
#endif // REFLOW_PATCH
case 1048:
case 1048: /* save/restore cursor (like DECSC/DECRC) */
#if REFLOW_PATCH
if (!allowaltscreen)
break;
@ -2039,6 +2046,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 +2451,35 @@ csihandle(void)
goto unknown;
}
break;
#if SYNC_PATCH || SIXEL_PATCH
case '$': /* DECRQM -- DEC Request Mode (private) */
if (csiescseq.mode[1] == 'p' && csiescseq.priv) {
switch (csiescseq.arg[0]) {
#if SIXEL_PATCH
case 80:
/* Sixel Display Mode */
ttywrite(IS_SET(MODE_SIXEL_SDM) ? "\033[?80;1$y"
: "\033[?80;2$y", 9, 0);
break;
case 8452:
/* Sixel scrolling leaves cursor to right of graphic */
ttywrite(IS_SET(MODE_SIXEL_CUR_RT) ? "\033[?8452;1$y"
: "\033[?8452;2$y", 11, 0);
break;
#endif // SIXEL_PATCH
#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 | SIXEL_PATCH
case 'r': /* DECSTBM -- Set Scrolling Region */
if (csiescseq.priv) {
goto unknown;
@ -2498,7 +2543,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]) {
@ -2619,7 +2668,7 @@ strhandle(void)
xsettitle(strescseq.args[1]);
#endif // CSI_22_23_PATCH
return;
case 52:
case 52: /* manipulate selection data */
if (narg > 2 && allowwindowops) {
dec = base64dec(strescseq.args[2]);
if (dec) {
@ -2637,9 +2686,9 @@ strhandle(void)
#endif // OSC7_PATCH
case 8: /* Clear Hyperlinks */
return;
case 10:
case 11:
case 12:
case 10: /* set dynamic VT100 text foreground color */
case 11: /* set dynamic VT100 text background color */
case 12: /* set dynamic text cursor color */
if (narg < 2)
break;
p = strescseq.args[1];
@ -2680,6 +2729,19 @@ strhandle(void)
tfulldirt();
}
return;
case 110: /* reset dynamic VT100 text foreground color */
case 111: /* reset dynamic VT100 text background color */
case 112: /* reset dynamic text cursor color */
if (narg != 1)
break;
if ((j = par - 110) < 0 || j >= LEN(osc_table))
break; /* shouldn't be possible */
if (xsetcolorname(osc_table[j].idx, NULL)) {
fprintf(stderr, "erresc: %s color not found\n", osc_table[j].str);
} else {
tfulldirt();
}
return;
#if OSC133_PATCH
case 133:
if (narg < 2)
@ -3434,7 +3496,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

181
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,
@ -795,10 +802,13 @@ setsel(char *str, Time t)
#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
sigusr1_reload(int sig)
{
#if DARKMAN_PATCH
xloadcols();
#endif // DARKMAN_PATCH
#if XRESOURCES_PATCH && XRESOURCES_RELOAD_PATCH
reload_config(sig);
#endif // XRESOURCES_RELOAD_PATCH
@ -973,9 +983,36 @@ xloadalpha(void)
dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * usedAlpha);
dc.col[defaultbg].pixel &= 0x00FFFFFF;
dc.col[defaultbg].pixel |= (unsigned char)(0xff * usedAlpha) << 24;
#if SELECTION_COLORS_PATCH && SELECTIONBG_ALPHA_PATCH
dc.col[selectionbg].color.alpha = (unsigned short)(0xffff * usedAlpha);
dc.col[selectionbg].pixel &= 0x00FFFFFF;
dc.col[selectionbg].pixel |= (unsigned char)(0xff * usedAlpha) << 24;
#endif // SELECTION_COLORS_PATCH && SELECTIONBG_ALPHA_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
void
xloadcols(void)
@ -1009,6 +1046,8 @@ xloadcols(void)
static int loaded;
Color *cp;
darkmanThemeChoose();
if (loaded) {
for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp)
XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
@ -1034,6 +1073,18 @@ xloadcols(void)
dc.col[defaultbg].color.red *= alpha;
dc.col[defaultbg].color.green *= alpha;
dc.col[defaultbg].color.blue *= alpha;
#if SELECTION_COLORS_PATCH && SELECTIONBG_ALPHA_PATCH
/* set alpha value of selbg color */
dc.col[selectionbg].color.alpha = (unsigned short)(0xffff * alpha);
dc.col[selectionbg].pixel &= 0x00FFFFFF;
dc.col[selectionbg].pixel |= (unsigned char)(0xff * alpha) << 24;
dc.col[selectionbg].color.red =
((unsigned short)(dc.col[selectionbg].color.red * alpha)) & 0xff00;
dc.col[selectionbg].color.green =
((unsigned short)(dc.col[selectionbg].color.green * alpha)) & 0xff00;
dc.col[selectionbg].color.blue =
((unsigned short)(dc.col[selectionbg].color.blue * alpha)) & 0xff00;
#endif // SELECTION_COLORS_PATCH && SELECTIONBG_ALPHA_PATCH
#endif // ALPHA_PATCH
loaded = 1;
}
@ -1130,7 +1181,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
@ -1656,6 +1707,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();
@ -1724,6 +1797,26 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
xp = winx, yp = winy + font->ascent;
#endif // VERTCENTER_PATCH
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. */
hbtransform(&shaped, font->match, glyphs, 0, len);
#endif // LIGATURES_PATCH
@ -2205,20 +2298,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
@ -2229,12 +2311,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. */
@ -2671,21 +2768,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
@ -2728,7 +2823,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];
@ -3666,6 +3761,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
}
}
@ -3762,8 +3872,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])
@ -3790,10 +3904,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;
}
@ -3958,9 +4072,12 @@ run:
setlocale(LC_CTYPE, "");
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);
#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 (!(xw.dpy = XOpenDisplay(NULL)))
die("Can't open display\n");