feat(x11): migrate to pure Xlibre + dwm/dmenu/st stack, fix fcitx5-t9 bottom bar, PM8909 PON shutdown, and remove Wayland

This commit is contained in:
Luxferre
2026-10-20 21:15:16 +03:00
parent ad012360c3
commit 7bab7b7a11
422 changed files with 63226 additions and 2342 deletions
+133 -127
View File
@@ -5,64 +5,18 @@
#include <fcitx/inputpanel.h>
#include <fcitx/text.h>
#include <algorithm>
#include <cctype>
#include <cstdint>
#include <dlfcn.h>
#include <cstdio>
#include <cstdlib>
#include <string_view>
#include <typeinfo>
#include <sys/stat.h>
namespace {
struct wl_proxy;
struct wl_interface;
using WlProxyGetVersionFn = uint32_t (*)(struct wl_proxy*);
using WlProxyMarshalFlagsFn = struct wl_proxy* (*)(
struct wl_proxy*, uint32_t, const struct wl_interface*, uint32_t, uint32_t,
...);
void sendWaylandVkModifiers(fcitx::InputContext* ic, uint32_t modsDepressed) {
if (!ic || ic->frontendName() != std::string_view("wayland_v2")) {
return;
}
static void* wlHandle = dlopen("libwayland-client.so.0", RTLD_LAZY);
static auto getVer =
wlHandle ? reinterpret_cast<WlProxyGetVersionFn>(
dlsym(wlHandle, "wl_proxy_get_version"))
: nullptr;
static auto marshalFlags =
wlHandle ? reinterpret_cast<WlProxyMarshalFlagsFn>(
dlsym(wlHandle, "wl_proxy_marshal_flags"))
: nullptr;
if (!getVer || !marshalFlags) {
return;
}
auto* raw = reinterpret_cast<uint8_t*>(ic);
std::string_view typeName(typeid(*ic).name());
if (typeName.find("VirtualInputContext") != std::string_view::npos) {
raw = *reinterpret_cast<uint8_t**>(raw + 3 * sizeof(void*));
if (!raw) {
return;
}
}
if (!raw[54]) {
return;
}
void* vkObj = *reinterpret_cast<void**>(raw + 40);
if (!vkObj) {
return;
}
auto* proxy = *reinterpret_cast<struct wl_proxy**>(
reinterpret_cast<uint8_t*>(vkObj) + 2 * sizeof(void*));
if (!proxy) {
return;
}
constexpr uint32_t kZwpVirtualKeyboardV1ModifiersOpcode = 2;
uint32_t ver = getVer(proxy);
marshalFlags(proxy, kZwpVirtualKeyboardV1ModifiersOpcode, nullptr, ver, 0,
modsDepressed, 0u, 0u, 0u);
}
const fcitx::Rect kFixedPopupRect(1, 289, 2, 290);
constexpr size_t kFixedPreeditChars = 28;
constexpr int kKey1 = 1;
constexpr int kKey2 = 2;
@@ -237,24 +191,50 @@ bool charToCtrlKey(char ch, fcitx::KeySym* symOut, uint32_t* xkbCodeOut) {
}
int mapHardwareKey(const fcitx::Key& key) {
if (key.states().testAny(fcitx::KeyState::Ctrl_Alt) ||
key.states().test(fcitx::KeyState::Super)) {
return -1;
}
uint32_t code = key.code();
// XKB keycodes: KEY_1..KEY_9 = 10..18, KEY_0 = 19
if (code >= 10 && code <= 19) {
return static_cast<int>(code - 9);
}
// KEY_NUMERIC_STAR (evdev 522 -> XKB 530)
if (code == 530 || key.sym() == FcitxKey_asterisk ||
// KEY_NUMERIC_STAR (evdev 522 -> XKB 530, or remapped KEY_KPASTERISK -> XKB 63)
if (code == 530 || code == 63 || key.sym() == FcitxKey_asterisk ||
key.sym() == FcitxKey_KP_Multiply ||
static_cast<uint32_t>(key.sym()) == 0x1008ffaa) {
return kKeyStar;
}
// KEY_NUMERIC_POUND (evdev 523 -> XKB 531)
if (code == 531 || key.sym() == FcitxKey_numbersign ||
// KEY_NUMERIC_POUND (evdev 523 -> XKB 531, or remapped KEY_KPSLASH -> XKB 106)
if (code == 531 || code == 106 || key.sym() == FcitxKey_numbersign ||
key.sym() == FcitxKey_KP_Divide ||
static_cast<uint32_t>(key.sym()) == 0x1008ffab) {
return kKeyPound;
}
return -1;
}
void writeStatusIndicator(const std::string& badge) {
const char* runtimeDir = std::getenv("XDG_RUNTIME_DIR");
std::string base = (runtimeDir && runtimeDir[0]) ? runtimeDir : "/run/user/10000";
std::string statusDir = base + "/sxmo_status/default";
::mkdir((base + "/sxmo_status").c_str(), 0700);
::mkdir(statusDir.c_str(), 0700);
std::string modeFile = base + "/sxmo_t9_mode";
if (FILE* fp = std::fopen(modeFile.c_str(), "w")) {
std::fprintf(fp, "%s\n", badge.c_str());
std::fclose(fp);
}
std::string barFile = statusDir + "/005-input-method";
if (FILE* fp = std::fopen(barFile.c_str(), "w")) {
std::fprintf(fp, "%s\n", badge.c_str());
std::fclose(fp);
}
}
} // namespace
T9Engine::T9Engine(fcitx::Instance* instance)
@@ -262,6 +242,17 @@ T9Engine::T9Engine(fcitx::Instance* instance)
return new T9State(this, &ic);
}) {
instance->inputContextManager().registerProperty("t9State", &factory);
cursorWatcher = instance->watchEvent(
fcitx::EventType::InputContextCursorRectChanged,
fcitx::EventWatcherPhase::PreInputMethod,
[](fcitx::Event& event) {
auto& icEvent = static_cast<fcitx::InputContextEvent&>(event);
auto* ic = icEvent.inputContext();
if (ic && ic->cursorRect() != kFixedPopupRect) {
ic->setCursorRect(kFixedPopupRect);
}
});
writeStatusIndicator("[abc]");
}
std::vector<fcitx::InputMethodEntry> T9Engine::listInputMethods() {
@@ -273,6 +264,14 @@ std::vector<fcitx::InputMethodEntry> T9Engine::listInputMethods() {
return result;
}
void T9Engine::activate(const fcitx::InputMethodEntry& entry,
fcitx::InputContextEvent& event) {
FCITX_UNUSED(entry);
auto* ic = event.inputContext();
auto* state = ic->propertyFor(&factory);
state->reset();
}
void T9Engine::keyEvent(const fcitx::InputMethodEntry& entry,
fcitx::KeyEvent& keyEvent) {
FCITX_UNUSED(entry);
@@ -296,6 +295,10 @@ void T9Engine::reset(const fcitx::InputMethodEntry& entry,
FCITX_ADDON_FACTORY(T9EngineFactory);
void T9State::updateStatusBar() const {
writeStatusIndicator("[" + modePrefix() + "]");
}
std::string T9State::modePrefix() const {
std::string p;
switch (mode) {
@@ -520,6 +523,8 @@ void T9State::cycleMode() {
mode = T9Mode::Lower;
break;
}
engine->sharedMode = mode;
updateStatusBar();
showStatusBanner("[Mode: " + modePrefix() + "]");
}
@@ -560,6 +565,7 @@ void T9State::stepCandidate(int delta) {
}
bool T9State::handleKeyEvent(fcitx::KeyEvent& keyEvent) {
mode = engine->sharedMode;
fcitx::Key key = keyEvent.key();
uint32_t code = key.code();
fcitx::KeySym sym = key.sym();
@@ -654,45 +660,52 @@ bool T9State::handleKeyEvent(fcitx::KeyEvent& keyEvent) {
if (releasedId != keyId && releasedId != -1) {
return true;
}
if (keyId == kKeyPound) {
if (!activeItems.empty()) {
toggleCurrentCase();
} else {
cycleMode();
}
return true;
if (!activeItems.empty()) {
uint64_t delayUs = (activeItems.size() > 10) ? 1800000 : 1500000;
scheduleCommit(delayUs);
}
if (mode == T9Mode::Num) {
if (bannerTimer) {
bannerTimer.reset();
resetUI();
}
if (keyId >= kKey1 && keyId <= kKey9) {
sendItem(makeChar(static_cast<char>('0' + keyId)));
} else if (keyId == kKey0) {
sendItem(makeChar('0'));
} else if (keyId == kKeyStar) {
sendItem(makeChar('*'));
}
return true;
}
handleMultiTap(keyId);
return true;
}
// Key press event
if (pressedKeyId != keyId) {
pressedKeyId = keyId;
isLongPressHandled = false;
startLongPressTimer(keyId);
if (pressedKeyId == keyId) {
// Ignore X11 auto-repeat key presses while holding the same key
return true;
}
pressedKeyId = keyId;
isLongPressHandled = false;
startLongPressTimer(keyId);
if (keyId == kKeyPound) {
if (!activeItems.empty()) {
toggleCurrentCase();
} else {
cycleMode();
}
return true;
}
if (mode == T9Mode::Num) {
if (bannerTimer) {
bannerTimer.reset();
resetUI();
}
if (keyId >= kKey1 && keyId <= kKey9) {
sendItem(makeChar(static_cast<char>('0' + keyId)));
} else if (keyId == kKey0) {
sendItem(makeChar('0'));
} else if (keyId == kKeyStar) {
sendItem(makeChar('*'));
}
return true;
}
handleMultiTap(keyId);
return true;
}
void T9State::startLongPressTimer(int keyId) {
cancelLongPressTimer();
longPressTimer = engine->instance->eventLoop().addTimeEvent(
CLOCK_MONOTONIC, fcitx::now(CLOCK_MONOTONIC) + 450000, 0,
CLOCK_MONOTONIC, fcitx::now(CLOCK_MONOTONIC) + 550000, 0,
[this, keyId](fcitx::EventSourceTime*, uint64_t) {
onLongPress(keyId);
return true;
@@ -707,9 +720,11 @@ void T9State::cancelLongPressTimer() {
void T9State::onLongPress(int keyId) {
isLongPressHandled = true;
if (!activeItems.empty()) {
commit();
}
// Discard current key's uncommitted multi-tap candidate and commit long-press action
cancelCommit();
activeItems.clear();
lastKeyId = -1;
currentIndex = 0;
if (keyId >= kKey1 && keyId <= kKey9) {
sendItem(makeChar(static_cast<char>('0' + keyId)));
resetUI();
@@ -722,6 +737,7 @@ void T9State::onLongPress(int keyId) {
resetUI();
} else {
ctrlLatch = !ctrlLatch;
updateStatusBar();
showStatusBanner(ctrlLatch ? "[Ctrl+ LATCH ON]" : "[Ctrl+ LATCH OFF]");
}
} else if (keyId == kKeyPound) {
@@ -747,7 +763,7 @@ void T9State::handleMultiTap(int keyId) {
if (activeItems.empty()) {
return;
}
uint64_t delayUs = (activeItems.size() > 10) ? 750000 : 600000;
uint64_t delayUs = (activeItems.size() > 10) ? 1800000 : 1500000;
scheduleCommit(delayUs);
showPreview(activeItems, currentIndex);
}
@@ -758,21 +774,20 @@ void T9State::reset() {
if (bannerTimer) {
bannerTimer.reset();
}
mode = engine->sharedMode;
lastKeyId = -1;
pressedKeyId = -1;
currentIndex = 0;
activeItems.clear();
isLongPressHandled = false;
ctrlLatch = false;
updateStatusBar();
}
void T9State::forwardKeyTap(fcitx::KeySym sym, fcitx::KeyStates states,
uint32_t xkbCode) {
if (states.test(fcitx::KeyState::Ctrl)) {
constexpr uint32_t kXkbModCtrl = (1u << 2);
sendWaylandVkModifiers(ic, kXkbModCtrl);
ic->forwardKey(fcitx::Key(sym, fcitx::KeyState::Ctrl, xkbCode), false);
sendWaylandVkModifiers(ic, 0u);
} else {
ic->forwardKey(fcitx::Key(sym, states, xkbCode), false);
}
@@ -783,12 +798,16 @@ void T9State::sendItem(const T9Item& item) {
fcitx::KeySym cSym = FcitxKey_None;
uint32_t cCode = 0;
ctrlLatch = false;
updateStatusBar();
if (charToCtrlKey(item.commitText[0], &cSym, &cCode)) {
forwardKeyTap(cSym, fcitx::KeyState::Ctrl, cCode);
return;
}
}
ctrlLatch = false;
if (ctrlLatch) {
ctrlLatch = false;
updateStatusBar();
}
if (item.sym != FcitxKey_None) {
forwardKeyTap(item.sym, item.states, item.xkbCode);
} else if (!item.commitText.empty()) {
@@ -796,6 +815,8 @@ void T9State::sendItem(const T9Item& item) {
if (mode == T9Mode::Shift &&
std::isalpha(static_cast<unsigned char>(item.commitText[0]))) {
mode = T9Mode::Lower;
engine->sharedMode = mode;
updateStatusBar();
}
}
}
@@ -849,19 +870,19 @@ void T9State::showStatusBanner(const std::string& msg) {
if (bannerTimer) {
bannerTimer.reset();
}
std::string padded = msg;
if (padded.size() < kFixedPreeditChars) {
padded.append(kFixedPreeditChars - padded.size(), ' ');
}
ic->setCursorRect(kFixedPopupRect);
auto& inputPanel = ic->inputPanel();
inputPanel.reset();
fcitx::Text text;
text.append(msg);
if (ic->capabilityFlags().test(fcitx::CapabilityFlag::Preedit)) {
inputPanel.setClientPreedit(text);
ic->updatePreedit();
} else {
inputPanel.setPreedit(text);
}
text.append(padded);
inputPanel.setPreedit(text);
ic->updateUserInterface(fcitx::UserInterfaceComponent::InputPanel);
bannerTimer = engine->instance->eventLoop().addTimeEvent(
CLOCK_MONOTONIC, fcitx::now(CLOCK_MONOTONIC) + 900000, 0,
CLOCK_MONOTONIC, fcitx::now(CLOCK_MONOTONIC) + 1500000, 0,
[this](fcitx::EventSourceTime*, uint64_t) {
resetUI();
return true;
@@ -873,50 +894,35 @@ void T9State::showPreview(const std::vector<T9Item>& items, int index) {
if (total == 0) {
return;
}
constexpr int kMaxVisible = 7;
int start = 0;
int end = total;
if (total > kMaxVisible) {
start = index - (kMaxVisible / 2);
if (start < 0) {
start = 0;
}
end = start + kMaxVisible;
if (end > total) {
end = total;
start = end - kMaxVisible;
}
}
constexpr int kPageSize = 7;
int page = index / kPageSize;
int start = page * kPageSize;
int end = std::min(start + kPageSize, total);
std::string preedit = modePrefix() + ": ";
if (start > 0) {
preedit += "< ";
}
std::string preedit = modePrefix() + ":";
for (int i = start; i < end; ++i) {
if (i == index) {
preedit += "[";
preedit += items[i].label;
preedit += "]";
} else {
preedit += " ";
preedit += items[i].label;
}
if (i < end - 1) {
preedit += " ";
}
}
if (end < total) {
preedit += " >";
if (total > kPageSize) {
preedit += (end < total) ? ">" : "<";
}
if (preedit.size() < kFixedPreeditChars) {
preedit.append(kFixedPreeditChars - preedit.size(), ' ');
}
ic->setCursorRect(kFixedPopupRect);
auto& inputPanel = ic->inputPanel();
inputPanel.reset();
fcitx::Text text;
text.append(preedit);
if (ic->capabilityFlags().test(fcitx::CapabilityFlag::Preedit)) {
inputPanel.setClientPreedit(text);
ic->updatePreedit();
} else {
inputPanel.setPreedit(text);
}
inputPanel.setPreedit(text);
ic->updateUserInterface(fcitx::UserInterfaceComponent::InputPanel);
}
+6 -1
View File
@@ -46,13 +46,14 @@ class T9State : public fcitx::InputContextProperty {
private:
std::vector<T9Item> getItemsForKey(int keyId) const;
std::string modePrefix() const;
void updateStatusBar() const;
void cycleMode();
void toggleCurrentCase();
void stepCandidate(int delta);
void startLongPressTimer(int keyId);
void cancelLongPressTimer();
void onLongPress(int keyId);
void scheduleCommit(uint64_t delayUs = 600000);
void scheduleCommit(uint64_t delayUs = 1500000);
void commit();
void sendItem(const T9Item& item);
void forwardKeyTap(fcitx::KeySym sym, fcitx::KeyStates states,
@@ -80,14 +81,18 @@ class T9Engine : public fcitx::InputMethodEngineV2 {
public:
explicit T9Engine(fcitx::Instance* instance);
std::vector<fcitx::InputMethodEntry> listInputMethods() override;
void activate(const fcitx::InputMethodEntry& entry,
fcitx::InputContextEvent& event) override;
void keyEvent(const fcitx::InputMethodEntry& entry,
fcitx::KeyEvent& keyEvent) override;
void reset(const fcitx::InputMethodEntry& entry,
fcitx::InputContextEvent& event) override;
fcitx::Instance* instance;
T9Mode sharedMode = T9Mode::Lower;
private:
fcitx::FactoryFor<T9State> factory;
std::unique_ptr<fcitx::HandlerTableEntry<fcitx::EventHandler>> cursorWatcher;
};
class T9EngineFactory : public fcitx::AddonFactory {
+66 -35
View File
@@ -42,7 +42,8 @@
#define RCGR_D_TORCH_50PCT 0xff7fU
#define RCGR_CMD_ENABLE_UPDATE 0x0003U /* ROOT_EN | CMD_UPDATE */
/* PM8909 PON registers for PS_HOLD shutdown vs warm reset configuration */
/* PM8909 PON registers for PS_HOLD shutdown vs hard reset configuration */
#define QPNP_PON_REVISION2 0x0801U
#define QPNP_PON_PS_HOLD_RST_CTL 0x085aU
#define QPNP_PON_PS_HOLD_RST_CTL2 0x085bU
#define QPNP_PON_S2_CNTL_EN 0x80U
@@ -54,6 +55,8 @@
static void __iomem *tlmm_gpio32_base;
static void __iomem *gcc_camss_base;
static struct regmap *pon_regmap;
static struct sys_off_handler *pon_poweroff_handler;
static struct sys_off_handler *pon_restart_handler;
static DEFINE_SPINLOCK(torch_lock);
static enum led_brightness current_brightness = LED_OFF;
@@ -131,51 +134,66 @@ static struct led_classdev msm8905_torch_led = {
.flags = LED_CORE_SUSPENDRESUME,
};
static void msm8905_pon_config_reset(unsigned int rst_type)
{
unsigned int rev2 = 0;
unsigned int ctl_reg = QPNP_PON_PS_HOLD_RST_CTL2;
if (!pon_regmap)
return;
if (regmap_read(pon_regmap, QPNP_PON_REVISION2, &rev2) == 0 && rev2 == 0)
ctl_reg = QPNP_PON_PS_HOLD_RST_CTL;
/*
* Match Qualcomm qpnp_pon_system_pwr_off():
* 1. Disable S2_CNTL_EN (bit 7 of 0x085b on Gen2 / 0x085a on Gen1)
* 2. Wait >10 sleep clock cycles (~350 us)
* 3. Program PS_HOLD_RST_CTL (0x085a) to SHUTDOWN (0x04) or HARD_RESET (0x07)
* 4. Re-enable S2_CNTL_EN (bit 7) and wait ~350 us
*/
regmap_update_bits(pon_regmap, ctl_reg, QPNP_PON_S2_CNTL_EN, 0);
udelay(350);
regmap_update_bits(pon_regmap, QPNP_PON_PS_HOLD_RST_CTL,
QPNP_PON_RST_TYPE_MASK, rst_type);
udelay(350);
regmap_update_bits(pon_regmap, ctl_reg,
QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN);
udelay(350);
pr_info("leds-msm8905-torch: configured PM8909 PON PS_HOLD_RST_CTL=0x%02x (%s)\n",
rst_type, (rst_type == PON_POWER_OFF_SHUTDOWN) ? "shutdown" : "hard-reset");
}
static int msm8905_pon_sys_poweroff(struct sys_off_data *data)
{
msm8905_torch_hw_disable();
msm8905_pon_config_reset(PON_POWER_OFF_SHUTDOWN);
return NOTIFY_DONE;
}
static int msm8905_pon_sys_restart(struct sys_off_data *data)
{
msm8905_torch_hw_disable();
msm8905_pon_config_reset(PON_POWER_OFF_HARD_RESET);
return NOTIFY_DONE;
}
static int msm8905_pon_reboot_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
unsigned int ctl1 = 0;
unsigned int ctl2 = 0;
unsigned int rst_type;
msm8905_torch_hw_disable();
if (!pon_regmap)
return NOTIFY_DONE;
if (action == SYS_POWER_OFF || action == SYS_HALT)
rst_type = PON_POWER_OFF_SHUTDOWN;
else
rst_type = PON_POWER_OFF_WARM_RESET;
rst_type = PON_POWER_OFF_HARD_RESET;
/*
* Match Qualcomm qpnp_pon_system_pwr_off():
* 1. Disable S2_CNTL_EN (bit 7 of 0x085b)
* 2. Wait >10 sleep clock cycles (~500 us)
* 3. Program PS_HOLD_RST_CTL (0x085a) to SHUTDOWN (0x04) or WARM_RESET (0x01)
* 4. Re-enable S2_CNTL_EN (bit 7 of 0x085b) and wait ~500 us
*/
if (regmap_read(pon_regmap, QPNP_PON_PS_HOLD_RST_CTL2, &ctl2) == 0)
regmap_write(pon_regmap, QPNP_PON_PS_HOLD_RST_CTL2, ctl2 & ~QPNP_PON_S2_CNTL_EN);
else
regmap_write(pon_regmap, QPNP_PON_PS_HOLD_RST_CTL2, 0x00U);
udelay(500);
if (regmap_read(pon_regmap, QPNP_PON_PS_HOLD_RST_CTL, &ctl1) == 0)
ctl1 = (ctl1 & ~QPNP_PON_RST_TYPE_MASK) | rst_type;
else
ctl1 = rst_type;
regmap_write(pon_regmap, QPNP_PON_PS_HOLD_RST_CTL, ctl1);
udelay(500);
regmap_write(pon_regmap, QPNP_PON_PS_HOLD_RST_CTL2,
(ctl2 & ~QPNP_PON_S2_CNTL_EN) | QPNP_PON_S2_CNTL_EN);
udelay(500);
pr_info("leds-msm8905-torch: configured PM8909 PON PS_HOLD_RST_CTL=0x%02x for %s\n",
ctl1, (rst_type == PON_POWER_OFF_SHUTDOWN) ? "shutdown" : "reboot");
msm8905_pon_config_reset(rst_type);
return NOTIFY_OK;
}
@@ -253,7 +271,16 @@ static int __init msm8905_torch_init(void)
}
msm8905_pon_lookup_regmap();
msm8905_pon_config_reset(PON_POWER_OFF_HARD_RESET);
register_reboot_notifier(&msm8905_pon_reboot_nb);
pon_poweroff_handler = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
SYS_OFF_PRIO_HIGH,
msm8905_pon_sys_poweroff,
NULL);
pon_restart_handler = register_sys_off_handler(SYS_OFF_MODE_RESTART,
SYS_OFF_PRIO_HIGH,
msm8905_pon_sys_restart,
NULL);
pr_info("leds-msm8905-torch: registered white:torch on GPIO_32 (cci_timer1 150kHz PWM), pon_regmap=%s\n",
pon_regmap ? "ready" : "none");
@@ -262,6 +289,10 @@ static int __init msm8905_torch_init(void)
static void __exit msm8905_torch_exit(void)
{
if (!IS_ERR_OR_NULL(pon_restart_handler))
unregister_sys_off_handler(pon_restart_handler);
if (!IS_ERR_OR_NULL(pon_poweroff_handler))
unregister_sys_off_handler(pon_poweroff_handler);
unregister_reboot_notifier(&msm8905_pon_reboot_nb);
led_classdev_unregister(&msm8905_torch_led);
msm8905_torch_hw_disable();
+15
View File
@@ -0,0 +1,15 @@
image: alpine/edge
packages:
- editorconfig-checker
- libxft-dev
- libx11-dev
- libxinerama-dev
sources:
- https://git.sr.ht/~mil/sxmo-dmenu
tasks:
- editorconfig-check: |
cd sxmo-dmenu
ec
- make: |
cd sxmo-dmenu
make
+14
View File
@@ -0,0 +1,14 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*.{sh|c}]
end_of_line = lf
insert_final_newline = true
indent_style = tab
#max_line_length = 80
spaces_around_operators = true
charset = utf-8
trim_trailing_whitespace = true
+30
View File
@@ -0,0 +1,30 @@
MIT/X Consortium License
© 2006-2019 Anselm R Garbe <anselm@garbe.ca>
© 2006-2008 Sander van Dijk <a.h.vandijk@gmail.com>
© 2006-2007 Michał Janeczek <janeczek@gmail.com>
© 2007 Kris Maglione <jg@suckless.org>
© 2009 Gottox <gottox@s01.de>
© 2009 Markus Schnalke <meillo@marmaro.de>
© 2009 Evan Gates <evan.gates@gmail.com>
© 2010-2012 Connor Lane Smith <cls@lubutu.com>
© 2014-2020 Hiltjo Posthuma <hiltjo@codemadness.org>
© 2015-2019 Quentin Rameau <quinq@fifth.space>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
+64
View File
@@ -0,0 +1,64 @@
# dmenu - dynamic menu
# See LICENSE file for copyright and license details.
include config.mk
SRC = drw.c dmenu.c stest.c util.c
OBJ = $(SRC:.c=.o)
all: options dmenu stest
options:
@echo dmenu build options:
@echo "CFLAGS = $(CFLAGS)"
@echo "LDFLAGS = $(LDFLAGS)"
@echo "CC = $(CC)"
.c.o:
$(CC) -c $(CFLAGS) $<
config.h:
cp config.def.h $@
$(OBJ): arg.h config.h config.mk drw.h
dmenu: dmenu.o drw.o util.o
$(CC) -o $@ dmenu.o drw.o util.o $(LDFLAGS)
stest: stest.o
$(CC) -o $@ stest.o $(LDFLAGS)
clean:
rm -f dmenu stest $(OBJ) dmenu-$(VERSION).tar.gz
dist: clean
mkdir -p dmenu-$(VERSION)
cp LICENSE Makefile README arg.h config.def.h config.mk dmenu.1\
drw.h util.h dmenu_path dmenu_run stest.1 $(SRC)\
dmenu-$(VERSION)
tar -cf dmenu-$(VERSION).tar dmenu-$(VERSION)
gzip dmenu-$(VERSION).tar
rm -rf dmenu-$(VERSION)
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
cp -f dmenu dmenu_path dmenu_run stest $(DESTDIR)$(PREFIX)/bin
chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu
chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu_path
chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu_run
chmod 755 $(DESTDIR)$(PREFIX)/bin/stest
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
sed "s/VERSION/$(VERSION)/g" < dmenu.1 > $(DESTDIR)$(MANPREFIX)/man1/dmenu.1
sed "s/VERSION/$(VERSION)/g" < stest.1 > $(DESTDIR)$(MANPREFIX)/man1/stest.1
chmod 644 $(DESTDIR)$(MANPREFIX)/man1/dmenu.1
chmod 644 $(DESTDIR)$(MANPREFIX)/man1/stest.1
uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/dmenu\
$(DESTDIR)$(PREFIX)/bin/dmenu_path\
$(DESTDIR)$(PREFIX)/bin/dmenu_run\
$(DESTDIR)$(PREFIX)/bin/stest\
$(DESTDIR)$(MANPREFIX)/man1/dmenu.1\
$(DESTDIR)$(MANPREFIX)/man1/stest.1
.PHONY: all options clean dist install uninstall
+27
View File
@@ -0,0 +1,27 @@
dmenu - dynamic menu
====================
[![builds.sr.ht status](https://builds.sr.ht/~mil/sxmo-dmenu.svg)](https://builds.sr.ht/~mil/sxmo-dmenu?)
dmenu is an efficient dynamic menu for X.
Requirements
------------
In order to build dmenu you need the Xlib header files.
Installation
------------
Edit config.mk to match your local setup (dmenu is installed into
the /usr/local namespace by default).
Afterwards enter the following command to build and install dmenu
(if necessary as root):
make clean install
Running dmenu
-------------
See the man page for details.
+49
View File
@@ -0,0 +1,49 @@
/*
* Copy me if you can.
* by 20h
*/
#ifndef ARG_H__
#define ARG_H__
extern char *argv0;
/* use main(int argc, char *argv[]) */
#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
argv[0] && argv[0][0] == '-'\
&& argv[0][1];\
argc--, argv++) {\
char argc_;\
char **argv_;\
int brk_;\
if (argv[0][1] == '-' && argv[0][2] == '\0') {\
argv++;\
argc--;\
break;\
}\
for (brk_ = 0, argv[0]++, argv_ = argv;\
argv[0][0] && !brk_;\
argv[0]++) {\
if (argv_ != argv)\
break;\
argc_ = argv[0][0];\
switch (argc_)
#define ARGEND }\
}
#define ARGC() argc_
#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\
((x), abort(), (char *)0) :\
(brk_ = 1, (argv[0][1] != '\0')?\
(&argv[0][1]) :\
(argc--, argv++, argv[0])))
#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\
(char *)0 :\
(brk_ = 1, (argv[0][1] != '\0')?\
(&argv[0][1]) :\
(argc--, argv++, argv[0])))
#endif
+41
View File
@@ -0,0 +1,41 @@
/* See LICENSE file for copyright and license details. */
/* Default settings; can be overriden by command line. */
static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
static int colorprompt = 1; /* -p option; if 1, prompt uses SchemeSel, otherwise SchemeNorm */
static int centered = 0; /* -c option; centers dmenu on screen */
static int min_width = 240; /* minimum width when centered */
static unsigned int lineheight = 26;
static unsigned int min_lineheight = 24;
/* -fn option overrides fonts[0]; default X11 font or font set */
static const char *defaultfonts[] = {
"Fira Code:pixelsize=18:style=Regular:antialias=true:autohint=true",
"DejaVuSansM Nerd Font:pixelsize=18:style=Regular:antialias=true:autohint=true"
};
static const char *prompt = NULL; /* -p option; prompt to the left of input field */
static const char *defaultcolors[SchemeLast][2] = {
/* fg bg */
[SchemeNorm] = { "#ffffff", "#1c1c1c" },
[SchemeSel] = { "#ffffff", "#005577" },
[SchemeSelHighlight] = { "#ffc978", "#005577" },
[SchemeNormHighlight] = { "#ffc978", "#1c1c1c" },
[SchemeOut] = { "#ffffff", "#383838" },
};
/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
static unsigned int lines = 9;
/*
* Characters not considered part of a word while deleting words
* for example: " /?\"&[]"
*/
static const char worddelimiters[] = " ";
/* Size of the window border */
static const unsigned int border_width = 0;
/* Whether to wrap around to the top and bottom of the menu */
static int wrap_around = 1;
/* height of each scroll region above and below the menu, in units of menu items */
static int scrollregion = 4;
+41
View File
@@ -0,0 +1,41 @@
/* See LICENSE file for copyright and license details. */
/* Default settings; can be overriden by command line. */
static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
static int colorprompt = 1; /* -p option; if 1, prompt uses SchemeSel, otherwise SchemeNorm */
static int centered = 0; /* -c option; centers dmenu on screen */
static int min_width = 240; /* minimum width when centered */
static unsigned int lineheight = 26;
static unsigned int min_lineheight = 24;
/* -fn option overrides fonts[0]; default X11 font or font set */
static const char *defaultfonts[] = {
"Fira Code:pixelsize=18:style=Regular:antialias=true:autohint=true",
"DejaVuSansM Nerd Font:pixelsize=18:style=Regular:antialias=true:autohint=true"
};
static const char *prompt = NULL; /* -p option; prompt to the left of input field */
static const char *defaultcolors[SchemeLast][2] = {
/* fg bg */
[SchemeNorm] = { "#ffffff", "#1c1c1c" },
[SchemeSel] = { "#ffffff", "#005577" },
[SchemeSelHighlight] = { "#ffc978", "#005577" },
[SchemeNormHighlight] = { "#ffc978", "#1c1c1c" },
[SchemeOut] = { "#ffffff", "#383838" },
};
/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
static unsigned int lines = 9;
/*
* Characters not considered part of a word while deleting words
* for example: " /?\"&[]"
*/
static const char worddelimiters[] = " ";
/* Size of the window border */
static const unsigned int border_width = 0;
/* Whether to wrap around to the top and bottom of the menu */
static int wrap_around = 1;
/* height of each scroll region above and below the menu, in units of menu items */
static int scrollregion = 4;
+31
View File
@@ -0,0 +1,31 @@
# dmenu version
VERSION = 5.0.12
# paths
PREFIX = /usr/local
MANPREFIX = $(PREFIX)/share/man
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
# Xinerama, comment if you don't want it
XINERAMALIBS = -lXinerama
XINERAMAFLAGS = -DXINERAMA
# freetype
FREETYPELIBS = -lfontconfig -lXft
FREETYPEINC = /usr/include/freetype2
# OpenBSD (uncomment)
#FREETYPEINC = $(X11INC)/freetype2
# includes and libs
INCS = -I$(X11INC) -I$(FREETYPEINC)
LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS)
# flags
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS)
CFLAGS = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS)
LDFLAGS = $(LIBS)
# compiler and linker
CC = cc
+252
View File
@@ -0,0 +1,252 @@
.TH DMENU 1 dmenu\-VERSION
.SH NAME
dmenu \- dynamic menu
.SH SYNOPSIS
.B dmenu
.RB [ \-bfitv ]
.RB [ \-l
.IR lines ]
.RB [ \-m
.IR monitor ]
.RB [ \-p
.IR prompt ]
.RB [ \-fn
.IR font ]
.RB [ \-nb
.IR color ]
.RB [ \-nf
.IR color ]
.RB [ \-sb
.IR color ]
.RB [ \-sf
.IR color ]
.RB [ \-H
.IR height ]
.RB [ \-w
.IR windowid ]
.RB [ \-idx
.IR index ]
.RB [ \-wm ]
.P
.BR dmenu_run " ..."
.SH DESCRIPTION
.B dmenu
is a dynamic menu for X, which reads a list of newline\-separated items from
stdin. When the user selects an item and presses Return, their choice is printed
to stdout and dmenu terminates. Entering text will narrow the items to those
matching the tokens in the input.
.P
.B dmenu_run
is a script used by
.IR dwm (1)
which lists programs in the user's $PATH and runs the result in their $SHELL.
.SH OPTIONS
.TP
.B \-b
dmenu appears at the bottom of the screen.
.TP
.B \-nc
dmenu appears not centered on the screen.
.TP
.B \-f
dmenu grabs the keyboard before reading stdin if not reading from a tty. This
is faster, but will lock up X until stdin reaches end\-of\-file.
.TP
.B \-i
dmenu matches menu items case insensitively.
.TP
.BI \-l " lines"
dmenu lists items vertically, with the given number of lines.
.TP
.BI \-H " height"
dmenu uses a menu line of at least 'height' pixels tall, but no less than 8
.TP
.BI \-m " monitor"
dmenu is displayed on the monitor number supplied. Monitor numbers are starting
from 0.
.TP
.BI \-p " prompt"
defines the prompt to be displayed to the left of the input field.
.TP
.BI \-fn " font"
defines the font or font set used.
.TP
.BI \-nb " color"
defines the normal background color.
.IR #RGB ,
.IR #RRGGBB ,
and X color names are supported.
.TP
.BI \-nf " color"
defines the normal foreground color.
.TP
.BI \-sb " color"
defines the selected background color.
.TP
.BI \-sf " color"
defines the selected foreground color.
.TP
.B \-t
Return key prints input text instead of selection.
.TP
.B \-v
prints version information to stdout, then exits.
.TP
.BI \-w " windowid"
embed into windowid.
.TP
.BI \-idx " index"
specify the initial selection index number.
.TP
.BI \-wm
Display as a managed WM window (e.g. don't set overide_redirect flag)
.SH USAGE
dmenu is completely controlled by the keyboard. Items are selected using the
arrow keys, page up, page down, home, and end.
.TP
.B Tab
Copy the selected item to the input field.
.TP
.B Return
Confirm selection. Prints the selected item to stdout and exits, returning
success. If \-t option is given it confirms input instead of selection.
.TP
.B Ctrl-Return
Confirm selection. Prints the selected item to stdout and continues.
.TP
.B Shift\-Return
Confirm input. Prints the input text to stdout and exits, returning success.
If \-t option is given it confirms selection instead of input.
.TP
.B Escape
Exit without selecting an item, returning failure.
.TP
.B Ctrl-Left
Move cursor to the start of the current word
.TP
.B Ctrl-Right
Move cursor to the end of the current word
.TP
.B C\-a
Home
.TP
.B C\-b
Left
.TP
.B C\-nc
Escape
.TP
.B C\-d
Delete
.TP
.B C\-e
End
.TP
.B C\-f
Right
.TP
.B C\-g
Escape
.TP
.B C\-h
Backspace
.TP
.B C\-i
Tab
.TP
.B C\-j
Return
.TP
.B C\-J
Shift-Return
.TP
.B C\-k
Delete line right
.TP
.B C\-m
Return
.TP
.B C\-M
Shift-Return
.TP
.B C\-n
Down
.TP
.B C\-p
Up
.TP
.B C\-u
Delete line left
.TP
.B C\-w
Delete word left
.TP
.B C\-y
Paste from primary X selection
.TP
.B C\-Y
Paste from X clipboard
.TP
.B M\-b
Move cursor to the start of the current word
.TP
.B M\-f
Move cursor to the end of the current word
.TP
.B M\-g
Home
.TP
.B M\-G
End
.TP
.B M\-h
Up
.TP
.B M\-j
Page down
.TP
.B M\-k
Page up
.TP
.B M\-l
Down
.SH X Resources
.TP
.BI dmenu.font
defines the font or font set used.
.TP
.BI dmenu.background
defines the normal background color.
.IR #RGB ,
.IR #RRGGBB ,
and X color names are supported.
.TP
.BI dmenu.foreground
defines the normal foreground color.
.TP
.BI dmenu.selbackground
defines the selected background color.
.TP
.BI dmenu.selforeground
defines the selected foreground color.
.TP
.BI dmenu.selhighlightbackground
defines the highlighted selected background color.
.TP
.BI dmenu.selhighlightforeground
defines the highlighted selected foreground color.
.TP
.BI dmenu.highlightbackground
defines the highlighted background color.
.TP
.BI dmenu.highlightforeground
defines the highlighted foreground color.
.TP
.BI dmenu.outbackground
defines the out background color.
.TP
.BI dmenu.outforeground
defines the out foreground color.
.SH SEE ALSO
.IR dwm (1),
.IR stest (1)
File diff suppressed because it is too large Load Diff
+13
View File
@@ -0,0 +1,13 @@
#!/bin/sh
cachedir="${XDG_CACHE_HOME:-"$HOME/.cache"}"
cache="$cachedir/dmenu_run"
[ ! -e "$cachedir" ] && mkdir -p "$cachedir"
IFS=:
if stest -dqr -n "$cache" $PATH; then
stest -flx $PATH | sort -u | tee "$cache"
else
cat "$cache"
fi
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &
+605
View File
@@ -0,0 +1,605 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
#include "drw.h"
#include "util.h"
#define UTF_INVALID 0xFFFD
#define UTF_SIZ 4
static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
static long
utf8decodebyte(const char c, size_t *i)
{
for (*i = 0; *i < (UTF_SIZ + 1); ++(*i))
if (((unsigned char)c & utfmask[*i]) == utfbyte[*i])
return (unsigned char)c & ~utfmask[*i];
return 0;
}
static size_t
utf8validate(long *u, size_t i)
{
if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
*u = UTF_INVALID;
for (i = 1; *u > utfmax[i]; ++i)
;
return i;
}
static size_t
utf8decode(const char *c, long *u, size_t clen)
{
size_t i, j, len, type;
long udecoded;
*u = UTF_INVALID;
if (!clen)
return 0;
udecoded = utf8decodebyte(c[0], &len);
if (!BETWEEN(len, 1, UTF_SIZ))
return 1;
for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
if (type)
return j;
}
if (j < len)
return 0;
*u = udecoded;
utf8validate(u, len);
return len;
}
Drw *
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
{
Drw *drw = ecalloc(1, sizeof(Drw));
drw->dpy = dpy;
drw->screen = screen;
drw->root = root;
drw->w = w;
drw->h = h;
drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
drw->gc = XCreateGC(dpy, root, 0, NULL);
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
return drw;
}
void
drw_resize(Drw *drw, unsigned int w, unsigned int h)
{
if (!drw)
return;
drw->w = w;
drw->h = h;
if (drw->drawable)
XFreePixmap(drw->dpy, drw->drawable);
drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
}
void
drw_free(Drw *drw)
{
XFreePixmap(drw->dpy, drw->drawable);
XFreeGC(drw->dpy, drw->gc);
drw_fontset_free(drw->fonts);
free(drw);
}
/* This function is an implementation detail. Library users should use
* drw_fontset_create instead.
*/
static Fnt *
xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
{
Fnt *font;
XftFont *xfont = NULL;
FcPattern *pattern = NULL;
if (fontname) {
/* Using the pattern found at font->xfont->pattern does not yield the
* same substitution results as using the pattern returned by
* FcNameParse; using the latter results in the desired fallback
* behaviour whereas the former just results in missing-character
* rectangles being drawn, at least with some fonts. */
if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
return NULL;
}
if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname);
XftFontClose(drw->dpy, xfont);
return NULL;
}
} else if (fontpattern) {
if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
fprintf(stderr, "error, cannot load font from pattern.\n");
return NULL;
}
} else {
die("no font specified.");
}
/* Do not allow using color fonts. This is a workaround for a BadLength
* error from Xft with color glyphs. Modelled on the Xterm workaround. See
* https://bugzilla.redhat.com/show_bug.cgi?id=1498269
* https://lists.suckless.org/dev/1701/30932.html
* https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349
* and lots more all over the internet.
*/
FcBool iscol;
if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) {
XftFontClose(drw->dpy, xfont);
return NULL;
}
font = ecalloc(1, sizeof(Fnt));
font->xfont = xfont;
font->pattern = pattern;
font->h = xfont->ascent + xfont->descent;
font->dpy = drw->dpy;
return font;
}
static void
xfont_free(Fnt *font)
{
if (!font)
return;
if (font->pattern)
FcPatternDestroy(font->pattern);
XftFontClose(font->dpy, font->xfont);
free(font);
}
Fnt*
drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
{
Fnt *cur, *ret = NULL;
size_t i;
if (!drw || !fonts)
return NULL;
for (i = 1; i <= fontcount; i++) {
if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) {
cur->next = ret;
ret = cur;
}
}
return (drw->fonts = ret);
}
void
drw_fontset_free(Fnt *font)
{
if (font) {
drw_fontset_free(font->next);
xfont_free(font);
}
}
void
drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
{
if (!drw || !dest || !clrname)
return;
if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen),
clrname, dest))
die("error, cannot allocate color '%s'", clrname);
}
/* Wrapper to create color schemes. The caller has to call free(3) on the
* returned color scheme when done using it. */
Clr *
drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
{
size_t i;
Clr *ret;
/* need at least two colors for a scheme */
if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
return NULL;
for (i = 0; i < clrcount; i++)
drw_clr_create(drw, &ret[i], clrnames[i]);
return ret;
}
void
drw_setfontset(Drw *drw, Fnt *set)
{
if (drw)
drw->fonts = set;
}
void
drw_setscheme(Drw *drw, Clr *scm)
{
if (drw)
drw->scheme = scm;
}
void
drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
{
if (!drw || !drw->scheme)
return;
XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
if (filled)
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
else
XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
}
int
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
{
char buf[1024];
int ty;
unsigned int ew;
XftDraw *d = NULL;
Fnt *usedfont, *curfont, *nextfont;
size_t i, len;
int utf8strlen, utf8charlen, render = x || y || w || h;
long utf8codepoint = 0;
const char *utf8str;
FcCharSet *fccharset;
FcPattern *fcpattern;
FcPattern *match;
XftResult result;
int charexists = 0;
if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
return 0;
if (!render) {
w = ~w;
} else {
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
d = XftDrawCreate(drw->dpy, drw->drawable,
DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen));
x += lpad;
w -= lpad;
}
usedfont = drw->fonts;
while (1) {
utf8strlen = 0;
utf8str = text;
nextfont = NULL;
while (*text) {
utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ);
for (curfont = drw->fonts; curfont; curfont = curfont->next) {
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
if (charexists) {
if (curfont == usedfont) {
utf8strlen += utf8charlen;
text += utf8charlen;
} else {
nextfont = curfont;
}
break;
}
}
if (!charexists || nextfont)
break;
else
charexists = 0;
}
if (utf8strlen) {
drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
/* shorten text if necessary */
for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--)
drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
if (len) {
memcpy(buf, utf8str, len);
buf[len] = '\0';
if (len < utf8strlen)
for (i = len; i && i > len - 3; buf[--i] = '.')
; /* NOP */
if (render) {
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
usedfont->xfont, x, ty, (XftChar8 *)buf, len);
}
x += ew;
w -= ew;
}
}
if (!*text) {
break;
} else if (nextfont) {
charexists = 0;
usedfont = nextfont;
} else {
/* Regardless of whether or not a fallback font is found, the
* character must be drawn. */
charexists = 1;
fccharset = FcCharSetCreate();
FcCharSetAddChar(fccharset, utf8codepoint);
if (!drw->fonts->pattern) {
/* Refer to the comment in xfont_create for more information. */
die("the first font in the cache must be loaded from a font string.");
}
fcpattern = FcPatternDuplicate(drw->fonts->pattern);
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
FcDefaultSubstitute(fcpattern);
match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
FcCharSetDestroy(fccharset);
FcPatternDestroy(fcpattern);
if (match) {
usedfont = xfont_create(drw, NULL, match);
if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
; /* NOP */
curfont->next = usedfont;
} else {
xfont_free(usedfont);
usedfont = drw->fonts;
}
}
}
}
if (d)
XftDrawDestroy(d);
return x + (render ? w : 0);
}
int
utf8nextchar(const char *str, int len, int i, int inc)
{
int n;
for (n = i + inc; n + inc >= 0 && n + inc <= len
&& (str[n] & 0xc0) == 0x80; n += inc)
;
return n;
}
int
drw_text_align(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int textlen, int align)
{
int ty;
unsigned int ew;
XftDraw *d = NULL;
Fnt *usedfont, *curfont, *nextfont;
size_t len;
int utf8strlen, utf8charlen, render = x || y || w || h;
long utf8codepoint = 0;
const char *utf8str;
FcCharSet *fccharset;
FcPattern *fcpattern;
FcPattern *match;
XftResult result;
int charexists = 0;
int i, n;
if (!drw || (render && !drw->scheme) || !text || !drw->fonts || textlen <= 0
|| (align != AlignL && align != AlignR))
return 0;
if (!render) {
w = ~w;
} else {
XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel);
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
d = XftDrawCreate(drw->dpy, drw->drawable,
DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen));
}
usedfont = drw->fonts;
i = align == AlignL ? 0 : textlen;
x = align == AlignL ? x : x + w;
while (1) {
utf8strlen = 0;
nextfont = NULL;
/* if (align == AlignL) */
utf8str = text + i;
while ((align == AlignL && i < textlen) || (align == AlignR && i > 0)) {
if (align == AlignL) {
utf8charlen = utf8decode(text + i, &utf8codepoint, MIN(textlen - i, UTF_SIZ));
if (!utf8charlen) {
textlen = i;
break;
}
} else {
n = utf8nextchar(text, textlen, i, -1);
utf8charlen = utf8decode(text + n, &utf8codepoint, MIN(textlen - n, UTF_SIZ));
if (!utf8charlen) {
textlen -= i;
text += i;
i = 0;
break;
}
}
for (curfont = drw->fonts; curfont; curfont = curfont->next) {
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
if (charexists) {
if (curfont == usedfont) {
utf8strlen += utf8charlen;
i += align == AlignL ? utf8charlen : -utf8charlen;
} else {
nextfont = curfont;
}
break;
}
}
if (!charexists || nextfont)
break;
else
charexists = 0;
}
if (align == AlignR)
utf8str = text + i;
if (utf8strlen) {
drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
/* shorten text if necessary */
if (align == AlignL) {
for (len = utf8strlen; len && ew > w; ) {
len = utf8nextchar(utf8str, len, len, -1);
drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
}
} else {
for (len = utf8strlen; len && ew > w; ) {
n = utf8nextchar(utf8str, len, 0, +1);
utf8str += n;
len -= n;
drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
}
}
if (len) {
if (render) {
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
XftDrawStringUtf8(d, &drw->scheme[ColFg],
usedfont->xfont, align == AlignL ? x : x - ew, ty, (XftChar8 *)utf8str, len);
}
x += align == AlignL ? ew : -ew;
w -= ew;
}
if (len < utf8strlen)
break;
}
if ((align == AlignR && i <= 0) || (align == AlignL && i >= textlen)) {
break;
} else if (nextfont) {
charexists = 0;
usedfont = nextfont;
} else {
/* Regardless of whether or not a fallback font is found, the
* character must be drawn. */
charexists = 1;
fccharset = FcCharSetCreate();
FcCharSetAddChar(fccharset, utf8codepoint);
if (!drw->fonts->pattern) {
/* Refer to the comment in xfont_create for more information. */
die("the first font in the cache must be loaded from a font string.");
}
fcpattern = FcPatternDuplicate(drw->fonts->pattern);
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
FcDefaultSubstitute(fcpattern);
match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
FcCharSetDestroy(fccharset);
FcPatternDestroy(fcpattern);
if (match) {
usedfont = xfont_create(drw, NULL, match);
if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
; /* NOP */
curfont->next = usedfont;
} else {
xfont_free(usedfont);
usedfont = drw->fonts;
}
}
}
}
if (d)
XftDrawDestroy(d);
return x;
}
void
drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
{
if (!drw)
return;
XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
XSync(drw->dpy, False);
}
unsigned int
drw_fontset_getwidth(Drw *drw, const char *text)
{
if (!drw || !drw->fonts || !text)
return 0;
return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
}
void
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
{
XGlyphInfo ext;
if (!font || !text)
return;
XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
if (w)
*w = ext.xOff;
if (h)
*h = font->h;
}
Cur *
drw_cur_create(Drw *drw, int shape)
{
Cur *cur;
if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
return NULL;
cur->cursor = XCreateFontCursor(drw->dpy, shape);
return cur;
}
void
drw_cur_free(Drw *drw, Cur *cursor)
{
if (!cursor)
return;
XFreeCursor(drw->dpy, cursor->cursor);
free(cursor);
}
+59
View File
@@ -0,0 +1,59 @@
/* See LICENSE file for copyright and license details. */
typedef struct {
Cursor cursor;
} Cur;
typedef struct Fnt {
Display *dpy;
unsigned int h;
XftFont *xfont;
FcPattern *pattern;
struct Fnt *next;
} Fnt;
enum { ColFg, ColBg }; /* Clr scheme index */
enum { AlignL, AlignR };
typedef XftColor Clr;
typedef struct {
unsigned int w, h;
Display *dpy;
int screen;
Window root;
Drawable drawable;
GC gc;
Clr *scheme;
Fnt *fonts;
} Drw;
/* Drawable abstraction */
Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
void drw_resize(Drw *drw, unsigned int w, unsigned int h);
void drw_free(Drw *drw);
/* Fnt abstraction */
Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount);
void drw_fontset_free(Fnt* set);
unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
/* Colorscheme abstraction */
void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
/* Cursor abstraction */
Cur *drw_cur_create(Drw *drw, int shape);
void drw_cur_free(Drw *drw, Cur *cursor);
/* Drawing context manipulation */
void drw_setfontset(Drw *drw, Fnt *set);
void drw_setscheme(Drw *drw, Clr *scm);
/* Drawing functions */
void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert);
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert);
int drw_text_align(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int textlen, int align);
/* Map functions */
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
+90
View File
@@ -0,0 +1,90 @@
.TH STEST 1 dmenu\-VERSION
.SH NAME
stest \- filter a list of files by properties
.SH SYNOPSIS
.B stest
.RB [ -abcdefghlpqrsuwx ]
.RB [ -n
.IR file ]
.RB [ -o
.IR file ]
.RI [ file ...]
.SH DESCRIPTION
.B stest
takes a list of files and filters by the files' properties, analogous to
.IR test (1).
Files which pass all tests are printed to stdout. If no files are given, stest
reads files from stdin.
.SH OPTIONS
.TP
.B \-a
Test hidden files.
.TP
.B \-b
Test that files are block specials.
.TP
.B \-c
Test that files are character specials.
.TP
.B \-d
Test that files are directories.
.TP
.B \-e
Test that files exist.
.TP
.B \-f
Test that files are regular files.
.TP
.B \-g
Test that files have their set-group-ID flag set.
.TP
.B \-h
Test that files are symbolic links.
.TP
.B \-l
Test the contents of a directory given as an argument.
.TP
.BI \-n " file"
Test that files are newer than
.IR file .
.TP
.BI \-o " file"
Test that files are older than
.IR file .
.TP
.B \-p
Test that files are named pipes.
.TP
.B \-q
No files are printed, only the exit status is returned.
.TP
.B \-r
Test that files are readable.
.TP
.B \-s
Test that files are not empty.
.TP
.B \-u
Test that files have their set-user-ID flag set.
.TP
.B \-v
Invert the sense of tests, only failing files pass.
.TP
.B \-w
Test that files are writable.
.TP
.B \-x
Test that files are executable.
.SH EXIT STATUS
.TP
.B 0
At least one file passed all tests.
.TP
.B 1
No files passed all tests.
.TP
.B 2
An error occurred.
.SH SEE ALSO
.IR dmenu (1),
.IR test (1)
+109
View File
@@ -0,0 +1,109 @@
/* See LICENSE file for copyright and license details. */
#include <sys/stat.h>
#include <dirent.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "arg.h"
char *argv0;
#define FLAG(x) (flag[(x)-'a'])
static void test(const char *, const char *);
static void usage(void);
static int match = 0;
static int flag[26];
static struct stat old, new;
static void
test(const char *path, const char *name)
{
struct stat st, ln;
if ((!stat(path, &st) && (FLAG('a') || name[0] != '.') /* hidden files */
&& (!FLAG('b') || S_ISBLK(st.st_mode)) /* block special */
&& (!FLAG('c') || S_ISCHR(st.st_mode)) /* character special */
&& (!FLAG('d') || S_ISDIR(st.st_mode)) /* directory */
&& (!FLAG('e') || access(path, F_OK) == 0) /* exists */
&& (!FLAG('f') || S_ISREG(st.st_mode)) /* regular file */
&& (!FLAG('g') || st.st_mode & S_ISGID) /* set-group-id flag */
&& (!FLAG('h') || (!lstat(path, &ln) && S_ISLNK(ln.st_mode))) /* symbolic link */
&& (!FLAG('n') || st.st_mtime > new.st_mtime) /* newer than file */
&& (!FLAG('o') || st.st_mtime < old.st_mtime) /* older than file */
&& (!FLAG('p') || S_ISFIFO(st.st_mode)) /* named pipe */
&& (!FLAG('r') || access(path, R_OK) == 0) /* readable */
&& (!FLAG('s') || st.st_size > 0) /* not empty */
&& (!FLAG('u') || st.st_mode & S_ISUID) /* set-user-id flag */
&& (!FLAG('w') || access(path, W_OK) == 0) /* writable */
&& (!FLAG('x') || access(path, X_OK) == 0)) != FLAG('v')) { /* executable */
if (FLAG('q'))
exit(0);
match = 1;
puts(name);
}
}
static void
usage(void)
{
fprintf(stderr, "usage: %s [-abcdefghlpqrsuvwx] "
"[-n file] [-o file] [file...]\n", argv0);
exit(2); /* like test(1) return > 1 on error */
}
int
main(int argc, char *argv[])
{
struct dirent *d;
char path[PATH_MAX], *line = NULL, *file;
size_t linesiz = 0;
ssize_t n;
DIR *dir;
int r;
ARGBEGIN {
case 'n': /* newer than file */
case 'o': /* older than file */
file = EARGF(usage());
if (!(FLAG(ARGC()) = !stat(file, (ARGC() == 'n' ? &new : &old))))
perror(file);
break;
default:
/* miscellaneous operators */
if (strchr("abcdefghlpqrsuvwx", ARGC()))
FLAG(ARGC()) = 1;
else
usage(); /* unknown flag */
} ARGEND;
if (!argc) {
/* read list from stdin */
while ((n = getline(&line, &linesiz, stdin)) > 0) {
if (n && line[n - 1] == '\n')
line[n - 1] = '\0';
test(line, line);
}
free(line);
} else {
for (; argc; argc--, argv++) {
if (FLAG('l') && (dir = opendir(*argv))) {
/* test directory contents */
while ((d = readdir(dir))) {
r = snprintf(path, sizeof path, "%s/%s",
*argv, d->d_name);
if (r >= 0 && (size_t)r < sizeof path)
test(path, d->d_name);
}
closedir(dir);
} else {
test(*argv, *argv);
}
}
}
return match ? 0 : 1;
}
+35
View File
@@ -0,0 +1,35 @@
/* See LICENSE file for copyright and license details. */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
void *
ecalloc(size_t nmemb, size_t size)
{
void *p;
if (!(p = calloc(nmemb, size)))
die("calloc:");
return p;
}
void
die(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
fputc(' ', stderr);
perror(NULL);
} else {
fputc('\n', stderr);
}
exit(1);
}
+8
View File
@@ -0,0 +1,8 @@
/* See LICENSE file for copyright and license details. */
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
void die(const char *fmt, ...);
void *ecalloc(size_t nmemb, size_t size);
+16
View File
@@ -0,0 +1,16 @@
image: alpine/edge
packages:
- editorconfig-checker
- libxft-dev
- libx11-dev
- libxinerama-dev
- pango-dev
sources:
- https://git.sr.ht/~mil/sxmo-dwm
tasks:
- editorconfig-check: |
cd sxmo-dwm
ec
- make: |
cd sxmo-dwm
make
+14
View File
@@ -0,0 +1,14 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*.{sh|c}]
end_of_line = lf
insert_final_newline = true
indent_style = tab
#max_line_length = 80
spaces_around_operators = true
charset = utf-8
trim_trailing_whitespace = true
+37
View File
@@ -0,0 +1,37 @@
MIT/X Consortium License
© 2006-2019 Anselm R Garbe <anselm@garbe.ca>
© 2006-2009 Jukka Salmi <jukka at salmi dot ch>
© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
© 2007-2011 Peter Hartlich <sgkkr at hartlich dot com>
© 2007-2009 Szabolcs Nagy <nszabolcs at gmail dot com>
© 2007-2009 Christof Musik <christof at sendfax dot de>
© 2007-2009 Premysl Hruby <dfenze at gmail dot com>
© 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
© 2008 Martin Hurton <martin dot hurton at gmail dot com>
© 2008 Neale Pickett <neale dot woozle dot org>
© 2009 Mate Nagy <mnagy at port70 dot net>
© 2010-2016 Hiltjo Posthuma <hiltjo@codemadness.org>
© 2010-2012 Connor Lane Smith <cls@lubutu.com>
© 2011 Christoph Lohmann <20h@r-36.net>
© 2015-2016 Quentin Rameau <quinq@fifth.space>
© 2015-2016 Eric Pruitt <eric.pruitt@gmail.com>
© 2016-2017 Markus Teich <markus.teich@stusta.mhn.de>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
+51
View File
@@ -0,0 +1,51 @@
# dwm - dynamic window manager
# See LICENSE file for copyright and license details.
include config.mk
SRC = drw.c dwm.c util.c
OBJ = ${SRC:.c=.o}
all: options dwm
options:
@echo dwm build options:
@echo "CFLAGS = ${CFLAGS}"
@echo "LDFLAGS = ${LDFLAGS}"
@echo "CC = ${CC}"
.c.o:
${CC} -c ${CFLAGS} $<
${OBJ}: config.h config.mk
config.h:
cp config.def.h $@
dwm: ${OBJ}
${CC} -o $@ ${OBJ} ${LDFLAGS}
clean:
rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz
dist: clean
mkdir -p dwm-${VERSION}
cp -R LICENSE Makefile README config.def.h config.mk\
dwm.1 drw.h util.h ${SRC} dwm.png transient.c dwm-${VERSION}
tar -cf dwm-${VERSION}.tar dwm-${VERSION}
gzip dwm-${VERSION}.tar
rm -rf dwm-${VERSION}
install: all
mkdir -p ${DESTDIR}${PREFIX}/bin
cp -f dwm ${DESTDIR}${PREFIX}/bin
chmod 755 ${DESTDIR}${PREFIX}/bin/dwm
mkdir -p ${DESTDIR}${MANPREFIX}/man1
sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1
chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
uninstall:
rm -f ${DESTDIR}${PREFIX}/bin/dwm\
${DESTDIR}${MANPREFIX}/man1/dwm.1
.PHONY: all options clean dist install uninstall
+50
View File
@@ -0,0 +1,50 @@
dwm - dynamic window manager
============================
[![builds.sr.ht status](https://builds.sr.ht/~mil/sxmo-dwm.svg)](https://builds.sr.ht/~mil/sxmo-dwm?)
dwm is an extremely fast, small, and dynamic window manager for X.
Requirements
------------
In order to build dwm you need the Xlib header files.
Installation
------------
Edit config.mk to match your local setup (dwm is installed into
the /usr/local namespace by default).
Afterwards enter the following command to build and install dwm (if
necessary as root):
make clean install
Running dwm
-----------
Add the following line to your .xinitrc to start dwm using startx:
exec dwm
In order to connect dwm to a specific display, make sure that
the DISPLAY environment variable is set correctly, e.g.:
DISPLAY=foo.bar:1 exec dwm
(This will start dwm on display :1 of the host foo.bar.)
In order to display status info in the bar, you can do something
like this in your .xinitrc:
while xsetroot -name "`date` `uptime | sed 's/.*,//'`"
do
sleep 1
done &
exec dwm
Configuration
-------------
The configuration of dwm is done by creating a custom config.h
and (re)compiling the source code.
+171
View File
@@ -0,0 +1,171 @@
/* See LICENSE file for copyright and license details. */
/* appearance */
static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 16; /* snap pixel */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
static const char font[] = "Fira Code, DejaVuSansM Nerd Font 15px";
static const char dmenufont[] = "Fira Code:pixelsize=18:style=Regular:antialias=true:autohint=true";
static const char col_gray1[] = "#323232";
static const char col_gray2[] = "#444444";
static const char col_gray3[] = "#dddddd";
static const char col_gray4[] = "#ffffff";
static const char col_cyan[] = "#005577";
static const char *defaultcolors[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
[SchemeTabActive] = { col_gray2, col_gray3, col_gray2 },
[SchemeTabInactive] = { col_gray1, col_gray3, col_gray1 }
};
/* 1 means attach after the currently active window */
static const int attachbelow = 1;
/* tagging */
static const char *tags[] = { "1", "2", "3", "4" };
static const Rule rules[] = {
/* class instance title tags mask isfloating isterminal noswallow monitor */
{ "st", NULL, NULL, 0, 0, 1, 1, -1, 0},
{ "St", NULL, NULL, 0, 0, 1, 1, -1, 0},
{ "svkbd", NULL, NULL, TAGMASK, 1, 1, 0, -1, 1},
};
/* layout(s) */
static const float mfact = 0.50; /* factor of master area size [0.05..0.95] */
static const int nmaster = 1; /* number of clients in master area */
static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */
/* Bartabgroups properties */
#define BARTAB_BORDERS 1 // 0 = off, 1 = on
#define BARTAB_BOTTOMBORDER 1 // 0 = off, 1 = on
#define BARTAB_TAGSINDICATOR 1 // 0 = off, 1 = on if >1 client/view tag, 2 = always on
#define BARTAB_TAGSPX 4 // # pixels for tag grid boxes
#define BARTAB_TAGSROWS 2 // # rows in tag grid (9 tags, e.g. 3x3)
static void (*bartabmonfns[])(Monitor *) = { monocle, bstack };
static void (*bartabfloatfns[])(Monitor *) = { NULL };
static const Layout ppcyclelayouts[] = {
/* symbol arrange function */
{ "", bstack }, /* first entry is default (vertical stack for 240x320) */
{ "", monocle },
{ "", tile },
};
static const Layout layouts[] = {
/* symbol arrange function */
{ "", bstack }, /* first entry is default */
{ "", tile },
{ "F", NULL },
{ "", monocle },
{ "DD", deckdouble },
{ "D", deck },
};
/* key definitions */
#define MODKEY Mod4Mask
#define ALTKEY Mod1Mask
#define TAGKEYS(KEY,TAG) \
{ KeyPress, MODKEY, KEY, view, {.ui = 1 << TAG} }, \
{ KeyPress, MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
{ KeyPress, MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} },
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
/* commands */
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
#include <X11/XF86keysym.h>
#ifndef _EVDEVK
#define _EVDEVK(_v) (0x10081000 + (_v))
#endif
static Key keys[] = {
/* Nokia 8110 4G / MSM8909 Physical Keypad & Action Keys */
{ KeyPress, 0, XK_Menu, spawn, { .v = (const char*[]){ "sxmo_appmenu.sh", "sys", NULL } } },
{ KeyPress, 0, XF86XK_KbdLcdMenu1, spawn, { .v = (const char*[]){ "sxmo_appmenu.sh", "sys", NULL } } },
{ KeyPress, 0, XF86XK_Back, spawn, { .v = (const char*[]){ "sxmo_appmenu.sh", NULL } } },
{ KeyPress, 0, XF86XK_KbdLcdMenu2, spawn, { .v = (const char*[]){ "sxmo_appmenu.sh", NULL } } },
{ KeyPress, 0, XF86XK_Phone, spawn, { .v = (const char*[]){ "sxmo_hook_inputhandler.sh", "enter_one", NULL } } },
{ KeyPress, 0, XF86XK_PickupPhone, spawn, { .v = (const char*[]){ "sxmo_hook_inputhandler.sh", "enter_one", NULL } } },
{ KeyPress, 0, XF86XK_PowerOff, spawn, { .v = (const char*[]){ "sxmo_multikey.sh", "powerbutton", "powerbutton_one", "powerbutton_two", "powerbutton_three", NULL } } },
{ KeyPress, 0, XF86XK_AudioRaiseVolume, spawn, { .v = (const char*[]){ "sxmo_audio.sh", "vol", "up", "5", NULL } } },
{ KeyPress, 0, XF86XK_AudioLowerVolume, spawn, { .v = (const char*[]){ "sxmo_audio.sh", "vol", "down", "5", NULL } } },
/* Used by scripts via xdotool */
{ KeyPress, MODKEY|ShiftMask, XK_e, shiftview, {.i = -1} },
{ KeyPress, MODKEY|ShiftMask, XK_r, shiftview, {.i = +1} },
{ KeyPress, MODKEY, XK_e, clienttagpush, {.i = -1} },
{ KeyPress, MODKEY, XK_r, clienttagpush, {.i = +1} },
/* Quick Navigation */
{ KeyPress, MODKEY, XK_p, spawn, SHCMD("sxmo_appmenu.sh") },
{ KeyPress, MODKEY, XK_d, spawn, SHCMD("sxmo_files.sh") },
{ KeyPress, MODKEY|ShiftMask, XK_Return, spawn, SHCMD("st") },
{ KeyPress, MODKEY, XK_b, togglebar, {0} },
{ KeyPress, MODKEY, XK_j, focusstack, {.i = +1 } },
{ KeyPress, MODKEY, XK_k, focusstack, {.i = -1 } },
{ KeyPress, MODKEY, XK_Down, focusstack, {.i = +1 } },
{ KeyPress, MODKEY, XK_Up, focusstack, {.i = -1 } },
{ KeyPress, MODKEY|ShiftMask, XK_j, pushdown, {.i = +1 } },
{ KeyPress, MODKEY|ShiftMask, XK_k, pushup, {.i = -1 } },
{ KeyPress, MODKEY, XK_x, focusstack, {.i = +1 } },
{ KeyPress, 0, XF86XK_MonBrightnessUp, spawn, SHCMD("sxmo_brightness.sh up") },
{ KeyPress, 0, XF86XK_MonBrightnessDown, spawn, SHCMD("sxmo_brightness.sh down") },
{ KeyPress, MODKEY|ShiftMask, XK_Down, spawn, SHCMD("sxmo_audio.sh vol down") },
{ KeyPress, MODKEY|ShiftMask, XK_Up, spawn, SHCMD("sxmo_audio.sh vol up") },
{ KeyPress, MODKEY, XK_i, incnmaster, {.i = +1 } },
{ KeyPress, MODKEY, XK_o, incnmaster, {.i = -1 } },
{ KeyPress, MODKEY, XK_h, setmfact, {.f = -0.05} },
{ KeyPress, MODKEY, XK_l, setmfact, {.f = +0.05} },
{ KeyPress, MODKEY, XK_Return, zoom, {0} },
{ KeyPress, MODKEY, XK_Tab, view, {0} },
{ KeyPress, MODKEY|ShiftMask, XK_c, killclient, {0} },
{ KeyPress, MODKEY|ShiftMask, XK_q, killclient, {0} },
{ KeyPress, MODKEY, XK_semicolon, switchcol, {0} },
{ KeyPress, MODKEY, XK_s, transfer, {0} },
/* monocle */
{ KeyPress, MODKEY, XK_m, setlayout, {.v = &layouts[3]} },
/* tile */
{ KeyPress, MODKEY, XK_slash, setlayout, {.v = &layouts[1]} },
/* bstack */
{ KeyPress, MODKEY|ShiftMask, XK_slash, setlayout, {.v = &layouts[0]} },
{ KeyPress, MODKEY, XK_f, togglefloating, {0} },
{ KeyPress, MODKEY|ShiftMask, XK_f, unfloatvisible, {0} },
/* cycle through the layouts in ppcyclelayouts */
{ KeyPress, MODKEY, XK_space, cyclelayout, {.i = +1} },
{ KeyPress, MODKEY|ShiftMask, XK_space, togglefloating, {0} },
{ KeyPress, MODKEY, XK_0, view, {.ui = ~0 } },
{ KeyPress, MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
{ KeyPress, MODKEY, XK_comma, focusmon, {.i = -1 } },
{ KeyPress, MODKEY, XK_period, focusmon, {.i = +1 } },
{ KeyPress, MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
{ KeyPress, MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
TAGKEYS( XK_1, 0)
TAGKEYS( XK_2, 1)
TAGKEYS( XK_3, 2)
TAGKEYS( XK_4, 3)
};
/* button definitions */
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
static Button buttons[] = {
/* click event mask button function argument */
{ ClkTagBar, 0, Button1, view, {0} },
{ ClkLtSymbol, 0, Button1, cyclelayout, {.i = +1} },
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
};
+171
View File
@@ -0,0 +1,171 @@
/* See LICENSE file for copyright and license details. */
/* appearance */
static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 16; /* snap pixel */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
static const char font[] = "Fira Code, DejaVuSansM Nerd Font 15px";
static const char dmenufont[] = "Fira Code:pixelsize=18:style=Regular:antialias=true:autohint=true";
static const char col_gray1[] = "#323232";
static const char col_gray2[] = "#444444";
static const char col_gray3[] = "#dddddd";
static const char col_gray4[] = "#ffffff";
static const char col_cyan[] = "#005577";
static const char *defaultcolors[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
[SchemeTabActive] = { col_gray2, col_gray3, col_gray2 },
[SchemeTabInactive] = { col_gray1, col_gray3, col_gray1 }
};
/* 1 means attach after the currently active window */
static const int attachbelow = 1;
/* tagging */
static const char *tags[] = { "1", "2", "3", "4" };
static const Rule rules[] = {
/* class instance title tags mask isfloating isterminal noswallow monitor */
{ "st", NULL, NULL, 0, 0, 1, 1, -1, 0},
{ "St", NULL, NULL, 0, 0, 1, 1, -1, 0},
{ "svkbd", NULL, NULL, TAGMASK, 1, 1, 0, -1, 1},
};
/* layout(s) */
static const float mfact = 0.50; /* factor of master area size [0.05..0.95] */
static const int nmaster = 1; /* number of clients in master area */
static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */
/* Bartabgroups properties */
#define BARTAB_BORDERS 1 // 0 = off, 1 = on
#define BARTAB_BOTTOMBORDER 1 // 0 = off, 1 = on
#define BARTAB_TAGSINDICATOR 1 // 0 = off, 1 = on if >1 client/view tag, 2 = always on
#define BARTAB_TAGSPX 4 // # pixels for tag grid boxes
#define BARTAB_TAGSROWS 2 // # rows in tag grid (9 tags, e.g. 3x3)
static void (*bartabmonfns[])(Monitor *) = { monocle, bstack };
static void (*bartabfloatfns[])(Monitor *) = { NULL };
static const Layout ppcyclelayouts[] = {
/* symbol arrange function */
{ "", bstack }, /* first entry is default (vertical stack for 240x320) */
{ "", monocle },
{ "", tile },
};
static const Layout layouts[] = {
/* symbol arrange function */
{ "", bstack }, /* first entry is default */
{ "", tile },
{ "F", NULL },
{ "", monocle },
{ "DD", deckdouble },
{ "D", deck },
};
/* key definitions */
#define MODKEY Mod4Mask
#define ALTKEY Mod1Mask
#define TAGKEYS(KEY,TAG) \
{ KeyPress, MODKEY, KEY, view, {.ui = 1 << TAG} }, \
{ KeyPress, MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
{ KeyPress, MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} },
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
/* commands */
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
#include <X11/XF86keysym.h>
#ifndef _EVDEVK
#define _EVDEVK(_v) (0x10081000 + (_v))
#endif
static Key keys[] = {
/* Nokia 8110 4G / MSM8909 Physical Keypad & Action Keys */
{ KeyPress, 0, XK_Menu, spawn, { .v = (const char*[]){ "sxmo_appmenu.sh", "sys", NULL } } },
{ KeyPress, 0, XF86XK_KbdLcdMenu1, spawn, { .v = (const char*[]){ "sxmo_appmenu.sh", "sys", NULL } } },
{ KeyPress, 0, XF86XK_Back, spawn, { .v = (const char*[]){ "sxmo_appmenu.sh", NULL } } },
{ KeyPress, 0, XF86XK_KbdLcdMenu2, spawn, { .v = (const char*[]){ "sxmo_appmenu.sh", NULL } } },
{ KeyPress, 0, XF86XK_Phone, spawn, { .v = (const char*[]){ "sxmo_hook_inputhandler.sh", "enter_one", NULL } } },
{ KeyPress, 0, XF86XK_PickupPhone, spawn, { .v = (const char*[]){ "sxmo_hook_inputhandler.sh", "enter_one", NULL } } },
{ KeyPress, 0, XF86XK_PowerOff, spawn, { .v = (const char*[]){ "sxmo_multikey.sh", "powerbutton", "powerbutton_one", "powerbutton_two", "powerbutton_three", NULL } } },
{ KeyPress, 0, XF86XK_AudioRaiseVolume, spawn, { .v = (const char*[]){ "sxmo_audio.sh", "vol", "up", "5", NULL } } },
{ KeyPress, 0, XF86XK_AudioLowerVolume, spawn, { .v = (const char*[]){ "sxmo_audio.sh", "vol", "down", "5", NULL } } },
/* Used by scripts via xdotool */
{ KeyPress, MODKEY|ShiftMask, XK_e, shiftview, {.i = -1} },
{ KeyPress, MODKEY|ShiftMask, XK_r, shiftview, {.i = +1} },
{ KeyPress, MODKEY, XK_e, clienttagpush, {.i = -1} },
{ KeyPress, MODKEY, XK_r, clienttagpush, {.i = +1} },
/* Quick Navigation */
{ KeyPress, MODKEY, XK_p, spawn, SHCMD("sxmo_appmenu.sh") },
{ KeyPress, MODKEY, XK_d, spawn, SHCMD("sxmo_files.sh") },
{ KeyPress, MODKEY|ShiftMask, XK_Return, spawn, SHCMD("st") },
{ KeyPress, MODKEY, XK_b, togglebar, {0} },
{ KeyPress, MODKEY, XK_j, focusstack, {.i = +1 } },
{ KeyPress, MODKEY, XK_k, focusstack, {.i = -1 } },
{ KeyPress, MODKEY, XK_Down, focusstack, {.i = +1 } },
{ KeyPress, MODKEY, XK_Up, focusstack, {.i = -1 } },
{ KeyPress, MODKEY|ShiftMask, XK_j, pushdown, {.i = +1 } },
{ KeyPress, MODKEY|ShiftMask, XK_k, pushup, {.i = -1 } },
{ KeyPress, MODKEY, XK_x, focusstack, {.i = +1 } },
{ KeyPress, 0, XF86XK_MonBrightnessUp, spawn, SHCMD("sxmo_brightness.sh up") },
{ KeyPress, 0, XF86XK_MonBrightnessDown, spawn, SHCMD("sxmo_brightness.sh down") },
{ KeyPress, MODKEY|ShiftMask, XK_Down, spawn, SHCMD("sxmo_audio.sh vol down") },
{ KeyPress, MODKEY|ShiftMask, XK_Up, spawn, SHCMD("sxmo_audio.sh vol up") },
{ KeyPress, MODKEY, XK_i, incnmaster, {.i = +1 } },
{ KeyPress, MODKEY, XK_o, incnmaster, {.i = -1 } },
{ KeyPress, MODKEY, XK_h, setmfact, {.f = -0.05} },
{ KeyPress, MODKEY, XK_l, setmfact, {.f = +0.05} },
{ KeyPress, MODKEY, XK_Return, zoom, {0} },
{ KeyPress, MODKEY, XK_Tab, view, {0} },
{ KeyPress, MODKEY|ShiftMask, XK_c, killclient, {0} },
{ KeyPress, MODKEY|ShiftMask, XK_q, killclient, {0} },
{ KeyPress, MODKEY, XK_semicolon, switchcol, {0} },
{ KeyPress, MODKEY, XK_s, transfer, {0} },
/* monocle */
{ KeyPress, MODKEY, XK_m, setlayout, {.v = &layouts[3]} },
/* tile */
{ KeyPress, MODKEY, XK_slash, setlayout, {.v = &layouts[1]} },
/* bstack */
{ KeyPress, MODKEY|ShiftMask, XK_slash, setlayout, {.v = &layouts[0]} },
{ KeyPress, MODKEY, XK_f, togglefloating, {0} },
{ KeyPress, MODKEY|ShiftMask, XK_f, unfloatvisible, {0} },
/* cycle through the layouts in ppcyclelayouts */
{ KeyPress, MODKEY, XK_space, cyclelayout, {.i = +1} },
{ KeyPress, MODKEY|ShiftMask, XK_space, togglefloating, {0} },
{ KeyPress, MODKEY, XK_0, view, {.ui = ~0 } },
{ KeyPress, MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
{ KeyPress, MODKEY, XK_comma, focusmon, {.i = -1 } },
{ KeyPress, MODKEY, XK_period, focusmon, {.i = +1 } },
{ KeyPress, MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
{ KeyPress, MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
TAGKEYS( XK_1, 0)
TAGKEYS( XK_2, 1)
TAGKEYS( XK_3, 2)
TAGKEYS( XK_4, 3)
};
/* button definitions */
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
static Button buttons[] = {
/* click event mask button function argument */
{ ClkTagBar, 0, Button1, view, {0} },
{ ClkLtSymbol, 0, Button1, cyclelayout, {.i = +1} },
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
};
+41
View File
@@ -0,0 +1,41 @@
# dwm version
VERSION = 6.3.1-sxmo
# Customize below to fit your system
# paths
PREFIX = /usr/local
MANPREFIX = ${PREFIX}/share/man
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
# Xinerama, comment if you don't want it
XINERAMALIBS = -lXinerama
XINERAMAFLAGS = -DXINERAMA
# freetype
FREETYPELIBS = -lfontconfig -lXft
FREETYPEINC = /usr/include/freetype2
# OpenBSD (uncomment)
#FREETYPEINC = ${X11INC}/freetype2
# Disable bonsai by uncommenting this
#NOBONSAIFLAGS = -DNOBONSAI
# includes and libs
INCS = -I${X11INC} -I${FREETYPEINC} `pkg-config --cflags xft pango pangoxft`
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res -lrt `pkg-config --libs xft pango pangoxft`
# flags
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} ${NOBONSAIFLAGS}
#CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS}
LDFLAGS = ${LIBS}
# Solaris
#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\"
#LDFLAGS = ${LIBS}
# compiler and linker
CC = cc
+298
View File
@@ -0,0 +1,298 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
#include <pango/pango.h>
#include <pango/pangoxft.h>
#include "drw.h"
#include "util.h"
Drw *
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
{
Drw *drw = ecalloc(1, sizeof(Drw));
drw->dpy = dpy;
drw->screen = screen;
drw->root = root;
drw->w = w;
drw->h = h;
drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
drw->gc = XCreateGC(dpy, root, 0, NULL);
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
return drw;
}
void
drw_resize(Drw *drw, unsigned int w, unsigned int h)
{
if (!drw)
return;
drw->w = w;
drw->h = h;
if (drw->drawable)
XFreePixmap(drw->dpy, drw->drawable);
drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
}
void
drw_free(Drw *drw)
{
XFreePixmap(drw->dpy, drw->drawable);
XFreeGC(drw->dpy, drw->gc);
drw_font_free(drw->font);
free(drw);
}
/* This function is an implementation detail. Library users should use
* drw_font_create instead.
*/
static Fnt *
xfont_create(Drw *drw, const char *fontname)
{
Fnt *font;
PangoFontMap *fontmap;
PangoContext *context;
PangoFontDescription *desc;
PangoFontMetrics *metrics;
if (!fontname) {
die("no font specified.");
}
font = ecalloc(1, sizeof(Fnt));
font->dpy = drw->dpy;
fontmap = pango_xft_get_font_map(drw->dpy, drw->screen);
context = pango_font_map_create_context(fontmap);
desc = pango_font_description_from_string(fontname);
font->layout = pango_layout_new(context);
pango_layout_set_font_description(font->layout, desc);
metrics = pango_context_get_metrics(context, desc, NULL);
font->h = pango_font_metrics_get_height(metrics) / PANGO_SCALE;
pango_font_metrics_unref(metrics);
g_object_unref(context);
return font;
}
static void
xfont_free(Fnt *font)
{
if (!font)
return;
if (font->layout)
g_object_unref(font->layout);
free(font);
}
Fnt*
drw_font_create(Drw* drw, const char font[])
{
Fnt *fnt = NULL;
if (!drw || !font)
return NULL;
fnt = xfont_create(drw, font);
return (drw->font = fnt);
}
void
drw_font_free(Fnt *font)
{
if (font) {
xfont_free(font);
}
}
void
drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
{
if (!drw || !dest || !clrname)
return;
if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen),
clrname, dest))
die("error, cannot allocate color '%s'", clrname);
}
/* Wrapper to create color schemes. The caller has to call free(3) on the
* returned color scheme when done using it. */
Clr *
drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
{
size_t i;
Clr *ret;
/* need at least two colors for a scheme */
if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
return NULL;
for (i = 0; i < clrcount; i++)
drw_clr_create(drw, &ret[i], clrnames[i]);
return ret;
}
void
drw_setscheme(Drw *drw, Clr *scm)
{
if (drw)
drw->scheme = scm;
}
void
drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
{
if (!drw || !drw->scheme)
return;
XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
if (filled)
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
else
XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
}
int
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup)
{
char buf[1024];
int ty, th;
unsigned int ew, eh;
XftDraw *d = NULL;
size_t i, len;
int render = x || y || w || h;
if (!drw || (render && !drw->scheme) || !text || !drw->font)
return 0;
if (!render) {
w = ~w;
} else {
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
d = XftDrawCreate(drw->dpy, drw->drawable,
DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen));
x += lpad;
w -= lpad;
}
len = strlen(text);
if (len) {
drw_font_getexts(drw->font, text, len, &ew, &eh, markup);
th = eh;
/* shorten text if necessary */
for (len = MIN(len, sizeof(buf) - 1); len && ew > w; len--) {
drw_font_getexts(drw->font, text, len, &ew, &eh, markup);
if (eh > th)
th = eh;
}
if (len) {
memcpy(buf, text, len);
buf[len] = '\0';
if (len < strlen(text))
for (i = len; i && i > len - 3; buf[--i] = '.')
; /* NOP */
if (render) {
ty = y + (h - th) / 2;
if(markup)
pango_layout_set_markup(drw->font->layout, buf, len);
else
pango_layout_set_text(drw->font->layout, buf, len);
pango_xft_render_layout(d, &drw->scheme[invert ? ColBg : ColFg],
drw->font->layout, x * PANGO_SCALE, ty * PANGO_SCALE);
if(markup) /* clear markup attributes */
pango_layout_set_attributes(drw->font->layout, NULL);
}
x += ew;
w -= ew;
}
}
if (d)
XftDrawDestroy(d);
return x + (render ? w : 0);
}
void
drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
{
if (!drw)
return;
XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
XSync(drw->dpy, False);
}
unsigned int
drw_font_getwidth(Drw *drw, const char *text, Bool markup)
{
if (!drw || !drw->font || !text)
return 0;
return drw_text(drw, 0, 0, 0, 0, 0, text, 0, markup);
}
void
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup)
{
if (!font || !text)
return;
PangoRectangle r;
if(markup)
pango_layout_set_markup(font->layout, text, len);
else
pango_layout_set_text(font->layout, text, len);
pango_layout_get_extents(font->layout, 0, &r);
if(markup) /* clear markup attributes */
pango_layout_set_attributes(font->layout, NULL);
if (w)
*w = r.width / PANGO_SCALE;
if (h)
*h = r.height / PANGO_SCALE;
}
Cur *
drw_cur_create(Drw *drw, int shape)
{
Cur *cur;
Pixmap blank;
XColor dummy;
static const char data[1] = {0};
(void)shape;
if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
return NULL;
memset(&dummy, 0, sizeof(dummy));
blank = XCreateBitmapFromData(drw->dpy, drw->root, data, 1, 1);
cur->cursor = XCreatePixmapCursor(drw->dpy, blank, blank, &dummy, &dummy, 0, 0);
XFreePixmap(drw->dpy, blank);
return cur;
}
void
drw_cur_free(Drw *drw, Cur *cursor)
{
if (!cursor)
return;
XFreeCursor(drw->dpy, cursor->cursor);
free(cursor);
}
+54
View File
@@ -0,0 +1,54 @@
/* See LICENSE file for copyright and license details. */
typedef struct {
Cursor cursor;
} Cur;
typedef struct Fnt {
Display *dpy;
unsigned int h;
PangoLayout *layout;
} Fnt;
enum { ColFg, ColBg, ColBorder }; /* Clr scheme index */
typedef XftColor Clr;
typedef struct {
unsigned int w, h;
Display *dpy;
int screen;
Window root;
Drawable drawable;
GC gc;
Clr *scheme;
Fnt *font;
} Drw;
/* Drawable abstraction */
Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
void drw_resize(Drw *drw, unsigned int w, unsigned int h);
void drw_free(Drw *drw);
/* Fnt abstraction */
Fnt *drw_font_create(Drw* drw, const char font[]);
void drw_font_free(Fnt* set);
unsigned int drw_font_getwidth(Drw *drw, const char *text, Bool markup);
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup);
/* Colorscheme abstraction */
void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
/* Cursor abstraction */
Cur *drw_cur_create(Drw *drw, int shape);
void drw_cur_free(Drw *drw, Cur *cursor);
/* Drawing context manipulation */
void drw_setscheme(Drw *drw, Clr *scm);
/* Drawing functions */
void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert);
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup);
/* Map functions */
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
+226
View File
@@ -0,0 +1,226 @@
.TH DWM 1 dwm\-VERSION
.SH NAME
dwm \- dynamic window manager
.SH SYNOPSIS
.B dwm
.RB [ \-v ]
.SH DESCRIPTION
dwm is a dynamic window manager for X. It manages windows in tiled, monocle
and floating layouts. Either layout can be applied dynamically, optimising the
environment for the application in use and the task performed.
.P
In tiled layouts windows are managed in a master and stacking area. The master
area on the left contains one window by default, and the stacking area on the
right contains all other windows. The number of master area windows can be
adjusted from zero to an arbitrary number. In monocle layout all windows are
maximised to the screen size. In floating layout windows can be resized and
moved freely. Dialog windows are always managed floating, regardless of the
layout applied.
.P
Windows are grouped by tags. Each window can be tagged with one or multiple
tags. Selecting certain tags displays all windows with these tags.
.P
Each screen contains a small status bar which displays all available tags, the
layout, the title of the focused window, and the text read from the root window
name property, if the screen is focused. A floating window is indicated with an
empty square and a maximised floating window is indicated with a filled square
before the windows title. The selected tags are indicated with a different
color. The tags of the focused window are indicated with a filled square in the
top left corner. The tags which are applied to one or more windows are
indicated with an empty square in the top left corner.
.P
The attach below patch makes newly spawned windows attach after the currently
selected window
.P
dwm draws a small border around windows to indicate the focus state.
.SH OPTIONS
.TP
.B \-v
prints version information to standard output, then exits.
.SH USAGE
.SS Status bar
.TP
.B X root window name
is read and displayed in the status text area. It can be set with the
.BR xsetroot (1)
command.
.TP
.B Button1
click on a tag label to display all windows with that tag, click on the layout
label toggles between tiled and floating layout.
.TP
.B Button3
click on a tag label adds/removes all windows with that tag to/from the view.
.TP
.B Mod4\-Button1
click on a tag label applies that tag to the focused window.
.TP
.B Mod4\-Button3
click on a tag label adds/removes that tag to/from the focused window.
.SS Keyboard commands
.TP
.B Mod4\-Shift\-Return
Start
.BR st(1).
.TP
.B Mod4\-p
Spawn
.BR dmenu(1)
for launching other programs.
.TP
.B Mod4\-,
Focus previous screen, if any.
.TP
.B Mod4\-.
Focus next screen, if any.
.TP
.B Mod4\-Shift\-,
Send focused window to previous screen, if any.
.TP
.B Mod4\-Shift\-.
Send focused window to next screen, if any.
.TP
.B Mod4\-b
Toggles bar on and off.
.TP
.B Mod4\-t
Sets tiled layout.
.TP
.B Mod4\-f
Sets floating layout.
.TP
.B Mod4\-m
Sets monocle layout.
.TP
.B Mod4\-space
Toggles between current and previous layout.
.TP
.B Mod4\-Control\-,
Cycles backwards in layout list.
.TP
.B Mod4\-Control\-.
Cycles forwards in layout list.
.TP
.B Mod4\-j
Focus next window.
.TP
.B Mod4\-k
Focus previous window.
.TP
.B Mod4\-i
Increase number of windows in master area.
.TP
.B Mod4\-d
Decrease number of windows in master area.
.TP
.B Mod4\-l
Increase master area size.
.TP
.B Mod4\-h
Decrease master area size.
.TP
.B Mod4\-Return
Zooms/cycles focused window to/from master area (tiled layouts only).
.TP
.B Mod4\-Shift\-c
Close focused window.
.TP
.B Mod4\-Shift\-space
Toggle focused window between tiled and floating state.
.TP
.B Mod4\-Tab
Toggles to the previously selected tags.
.TP
.B Mod4\-Shift\-[1..n]
Apply nth tag to focused window.
.TP
.B Mod4\-Shift\-0
Apply all tags to focused window.
.TP
.B Mod4\-Control\-Shift\-[1..n]
Add/remove nth tag to/from focused window.
.TP
.B Mod4\-[1..n]
View all windows with nth tag.
.TP
.B Mod4\-0
View all windows with any tag.
.TP
.B Mod4\-Control\-[1..n]
Add/remove all windows with nth tag to/from the view.
.TP
.B Mod4\-Shift\-q
Quit dwm.
.SS Mouse commands
.TP
.B Mod4\-Button1
Move focused window while dragging. Tiled windows will be toggled to the floating state.
.TP
.B Mod4\-Button2
Toggles focused window between floating and tiled state.
.TP
.B Mod4\-Button3
Resize focused window while dragging. Tiled windows will be toggled to the floating state.
.SH CUSTOMIZATION
dwm is customized by creating a custom config.h and (re)compiling the source
code, or by setting X resources.
.P
The following X resource settings can be set:
.TP
.BI dwm.font
defines the font or font set used.
.TP
.BI dwm.background
defines the normal background color.
.IR #RGB ,
.IR #RRGGBB ,
and X color names are supported.
.TP
.BI dwm.border
defines the normal border color
.TP
.BI dwm.selbackground
defines the selected background color
.TP
.BI dwm.selforeground
defines the selected foreground color
.TP
.BI dwm.selborder
defines the selected border color
.TP
.BI dwm.tabactivebackground
defines the background color for active tabs
.TP
.BI dwm.tabactiveforeground
defines the foreground color for active tabs
.TP
.BI dwm.tabactiveborder
defines the border color for active tabs
.TP
.BI dwm.tabinactivebackground
defines the background color for inactive tabs
.TP
.BI dwm.tabinactiveforeground
defines the foreground color for inactive tabs
.TP
.BI dwm.tabinactiveborder
defines the border color for inactive tabs
.SH SEE ALSO
.BR dmenu (1),
.BR st (1)
.SH ISSUES
Java applications which use the XToolkit/XAWT backend may draw grey windows
only. The XToolkit/XAWT backend breaks ICCCM-compliance in recent JDK 1.5 and early
JDK 1.6 versions, because it assumes a reparenting window manager. Possible workarounds
are using JDK 1.4 (which doesn't contain the XToolkit/XAWT backend) or setting the
environment variable
.BR AWT_TOOLKIT=MToolkit
(to use the older Motif backend instead) or running
.B xprop -root -f _NET_WM_NAME 32a -set _NET_WM_NAME LG3D
or
.B wmname LG3D
(to pretend that a non-reparenting window manager is running that the
XToolkit/XAWT backend can recognize) or when using OpenJDK setting the environment variable
.BR _JAVA_AWT_WM_NONREPARENTING=1 .
.SH BUGS
Send all bug reports with a patch to hackers@suckless.org.
+3259
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 373 B

+42
View File
@@ -0,0 +1,42 @@
/* cc transient.c -o transient -lX11 */
#include <stdlib.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
int main(void) {
Display *d;
Window r, f, t = None;
XSizeHints h;
XEvent e;
d = XOpenDisplay(NULL);
if (!d)
exit(1);
r = DefaultRootWindow(d);
f = XCreateSimpleWindow(d, r, 100, 100, 400, 400, 0, 0, 0);
h.min_width = h.max_width = h.min_height = h.max_height = 400;
h.flags = PMinSize | PMaxSize;
XSetWMNormalHints(d, f, &h);
XStoreName(d, f, "floating");
XMapWindow(d, f);
XSelectInput(d, f, ExposureMask);
while (1) {
XNextEvent(d, &e);
if (t == None) {
sleep(5);
t = XCreateSimpleWindow(d, r, 50, 50, 100, 100, 0, 0, 0);
XSetTransientForHint(d, t, f);
XStoreName(d, t, "transient");
XMapWindow(d, t);
XSelectInput(d, t, ExposureMask);
}
}
XCloseDisplay(d);
exit(0);
}
+35
View File
@@ -0,0 +1,35 @@
/* See LICENSE file for copyright and license details. */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
void *
ecalloc(size_t nmemb, size_t size)
{
void *p;
if (!(p = calloc(nmemb, size)))
die("calloc:");
return p;
}
void
die(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
fputc(' ', stderr);
perror(NULL);
} else {
fputc('\n', stderr);
}
exit(1);
}
+12
View File
@@ -0,0 +1,12 @@
/* See LICENSE file for copyright and license details. */
#ifndef MAX
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#endif
#ifndef MIN
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#endif
#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
void die(const char *fmt, ...);
void *ecalloc(size_t nmemb, size_t size);
+17
View File
@@ -0,0 +1,17 @@
image: alpine/edge
packages:
- editorconfig-checker
- fontconfig-dev
- freetype-dev
- libx11-dev
- libxext-dev
- libxft-dev
sources:
- https://git.sr.ht/~mil/sxmo-st
tasks:
- editorconfig-check: |
cd sxmo-st
ec
- make: |
cd sxmo-st
make
+14
View File
@@ -0,0 +1,14 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*.{sh|c}]
end_of_line = lf
insert_final_newline = true
indent_style = tab
#max_line_length = 80
spaces_around_operators = true
charset = utf-8
trim_trailing_whitespace = true
+250
View File
@@ -0,0 +1,250 @@
## Why does st not handle utmp entries?
Use the excellent tool of [utmp](https://git.suckless.org/utmp/) for this task.
## Some _random program_ complains that st is unknown/not recognised/unsupported/whatever!
It means that st doesn’t have any terminfo entry on your system. Chances are
you did not `make install`. If you just want to test it without installing it,
you can manually run `tic -sx st.info`.
## Nothing works, and nothing is said about an unknown terminal!
* Some programs just assume they’re running in xterm i.e. they don’t rely on
terminfo. What you see is the current state of the “xterm compliance”.
* Some programs don’t complain about the lacking st description and default to
another terminal. In that case see the question about terminfo.
## How do I scroll back up?
* Using a terminal multiplexer.
* `st -e tmux` using C-b [
* `st -e screen` using C-a ESC
* Using the excellent tool of [scroll](https://git.suckless.org/scroll/).
* Using the scrollback [patch](https://st.suckless.org/patches/scrollback/).
## I would like to have utmp and/or scroll functionality by default
You can add the absolute patch of both programs in your config.h
file. You only have to modify the value of utmp and scroll variables.
## Why doesn't the Del key work in some programs?
Taken from the terminfo manpage:
If the terminal has a keypad that transmits codes when the keys
are pressed, this information can be given. Note that it is not
possible to handle terminals where the keypad only works in
local (this applies, for example, to the unshifted HP 2621 keys).
If the keypad can be set to transmit or not transmit, give these
codes as smkx and rmkx. Otherwise the keypad is assumed to
always transmit.
In the st case smkx=E[?1hE= and rmkx=E[?1lE>, so it is mandatory that
applications which want to test against keypad keys send these
sequences.
But buggy applications (like bash and irssi, for example) don't do this. A fast
solution for them is to use the following command:
$ printf '\033[?1h\033=' >/dev/tty
or
$ tput smkx
In the case of bash, readline is used. Readline has a different note in its
manpage about this issue:
enable-keypad (Off)
When set to On, readline will try to enable the
application keypad when it is called. Some systems
need this to enable arrow keys.
Adding this option to your .inputrc will fix the keypad problem for all
applications using readline.
If you are using zsh, then read the zsh FAQ
<http://zsh.sourceforge.net/FAQ/zshfaq03.html#l25>:
It should be noted that the O / [ confusion can occur with other keys
such as Home and End. Some systems let you query the key sequences
sent by these keys from the system's terminal database, terminfo.
Unfortunately, the key sequences given there typically apply to the
mode that is not the one zsh uses by default (it's the "application"
mode rather than the "raw" mode). Explaining the use of terminfo is
outside of the scope of this FAQ, but if you wish to use the key
sequences given there you can tell the line editor to turn on
"application" mode when it starts and turn it off when it stops:
function zle-line-init () { echoti smkx }
function zle-line-finish () { echoti rmkx }
zle -N zle-line-init
zle -N zle-line-finish
Putting these lines into your .zshrc will fix the problems.
## How can I use meta in 8bit mode?
St supports meta in 8bit mode, but the default terminfo entry doesn't
use this capability. If you want it, you have to use the 'st-meta' value
in TERM.
## I cannot compile st in OpenBSD
OpenBSD lacks librt, despite it being mandatory in POSIX
<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html#tag_20_11_13>.
If you want to compile st for OpenBSD you have to remove -lrt from config.mk, and
st will compile without any loss of functionality, because all the functions are
included in libc on this platform.
## The Backspace Case
St is emulating the Linux way of handling backspace being delete and delete being
backspace.
This is an issue that was discussed in suckless mailing list
<https://lists.suckless.org/dev/1404/20697.html>. Here is why some old grumpy
terminal users wants its backspace to be how he feels it:
Well, I am going to comment why I want to change the behaviour
of this key. When ASCII was defined in 1968, communication
with computers was done using punched cards, or hardcopy
terminals (basically a typewriter machine connected with the
computer using a serial port). ASCII defines DELETE as 7F,
because, in punched-card terms, it means all the holes of the
card punched; it is thus a kind of 'physical delete'. In the
same way, the BACKSPACE key was a non-destructive backspace,
as on a typewriter. So, if you wanted to delete a character,
you had to BACKSPACE and then DELETE. Another use of BACKSPACE
was to type accented characters, for example 'a BACKSPACE `'.
The VT100 had no BACKSPACE key; it was generated using the
CONTROL key as another control character (CONTROL key sets to
0 b7 b6 b5, so it converts H (code 0x48) into BACKSPACE (code
0x08)), but it had a DELETE key in a similar position where
the BACKSPACE key is located today on common PC keyboards.
All the terminal emulators emulated the difference between
these keys correctly: the backspace key generated a BACKSPACE
(^H) and delete key generated a DELETE (^?).
But a problem arose when Linus Torvalds wrote Linux. Unlike
earlier terminals, the Linux virtual terminal (the terminal
emulator integrated in the kernel) returned a DELETE when
backspace was pressed, due to the VT100 having a DELETE key in
the same position. This created a lot of problems (see [1]
and [2]). Since Linux has become the king, a lot of terminal
emulators today generate a DELETE when the backspace key is
pressed in order to avoid problems with Linux. The result is
that the only way of generating a BACKSPACE on these systems
is by using CONTROL + H. (I also think that emacs had an
important point here because the CONTROL + H prefix is used
in emacs in some commands (help commands).)
From point of view of the kernel, you can change the key
for deleting a previous character with stty erase. When you
connect a real terminal into a machine you describe the type
of terminal, so getty configures the correct value of stty
erase for this terminal. In the case of terminal emulators,
however, you don't have any getty that can set the correct
value of stty erase, so you always get the default value.
For this reason, it is necessary to add 'stty erase ^H' to your
profile if you have changed the value of the backspace key.
Of course, another solution is for st itself to modify the
value of stty erase. I usually have the inverse problem:
when I connect to non-Unix machines, I have to press CONTROL +
h to get a BACKSPACE. The inverse problem occurs when a user
connects to my Unix machines from a different system with a
correct backspace key.
[1] http://www.ibb.net/~anne/keyboard.html
[2] http://www.tldp.org/HOWTO/Keyboard-and-Console-HOWTO-5.html
## But I really want the old grumpy behaviour of my terminal
Apply [1].
[1] https://st.suckless.org/patches/delkey
## Why do images not work in st using the w3m image hack?
w3mimg uses a hack that draws an image on top of the terminal emulator Drawable
window. The hack relies on the terminal to use a single buffer to draw its
contents directly.
st uses double-buffered drawing so the image is quickly replaced and may show a
short flicker effect.
Below is a patch example to change st double-buffering to a single Drawable
buffer.
diff --git a/x.c b/x.c
--- a/x.c
+++ b/x.c
@@ -732,10 +732,6 @@ xresize(int col, int row)
win.tw = col * win.cw;
win.th = row * win.ch;
- XFreePixmap(xw.dpy, xw.buf);
- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
- DefaultDepth(xw.dpy, xw.scr));
- XftDrawChange(xw.draw, xw.buf);
xclear(0, 0, win.w, win.h);
/* resize to new width */
@@ -1148,8 +1144,7 @@ xinit(int cols, int rows)
gcvalues.graphics_exposures = False;
dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
&gcvalues);
- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
- DefaultDepth(xw.dpy, xw.scr));
+ xw.buf = xw.win;
XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
@@ -1632,8 +1627,6 @@ xdrawline(Line line, int x1, int y1, int x2)
void
xfinishdraw(void)
{
- XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w,
- win.h, 0, 0);
XSetForeground(xw.dpy, dc.gc,
dc.col[IS_SET(MODE_REVERSE)?
defaultfg : defaultbg].pixel);
## BadLength X error in Xft when trying to render emoji
Xft makes st crash when rendering color emojis with the following error:
"X Error of failed request: BadLength (poly request too large or internal Xlib length error)"
Major opcode of failed request: 139 (RENDER)
Minor opcode of failed request: 20 (RenderAddGlyphs)
Serial number of failed request: 1595
Current serial number in output stream: 1818"
This is a known bug in Xft (not st) which happens on some platforms and
combination of particular fonts and fontconfig settings.
See also:
https://gitlab.freedesktop.org/xorg/lib/libxft/issues/6
https://bugs.freedesktop.org/show_bug.cgi?id=107534
https://bugzilla.redhat.com/show_bug.cgi?id=1498269
The solution is to remove color emoji fonts or disable this in the fontconfig
XML configuration. As an ugly workaround (which may work only on newer
fontconfig versions (FC_COLOR)), the following code can be used to mask color
fonts:
FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
Please don't bother reporting this bug to st, but notify the upstream Xft
developers about fixing this bug.
+17
View File
@@ -0,0 +1,17 @@
A STATEMENT ON LEGACY SUPPORT
In the terminal world there is much cruft that comes from old and unsup‐
ported terminals that inherit incompatible modes and escape sequences
which noone is able to know, except when he/she comes from that time and
developed a graphical vt100 emulator at that time.
One goal of st is to only support what is really needed. When you en‐
counter a sequence which you really need, implement it. But while you
are at it, do not add the other cruft you might encounter while sneek‐
ing at other terminal emulators. History has bloated them and there is
no real evidence that most of the sequences are used today.
Christoph Lohmann <20h@r-36.net>
2012-09-13T07:00:36.081271045+02:00
+34
View File
@@ -0,0 +1,34 @@
MIT/X Consortium License
© 2014-2020 Hiltjo Posthuma <hiltjo at codemadness dot org>
© 2018 Devin J. Pohly <djpohly at gmail dot com>
© 2014-2017 Quentin Rameau <quinq at fifth dot space>
© 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com>
© 2008-2017 Anselm R Garbe <garbeam at gmail dot com>
© 2012-2017 Roberto E. Vargas Caballero <k0ga at shike2 dot com>
© 2012-2016 Christoph Lohmann <20h at r-36 dot net>
© 2013 Eon S. Jeon <esjeon at hyunmu dot am>
© 2013 Alexander Sedov <alex0player at gmail dot com>
© 2013 Mark Edgar <medgar123 at gmail dot com>
© 2013-2014 Eric Pruitt <eric.pruitt at gmail dot com>
© 2013 Michael Forney <mforney at mforney dot org>
© 2013-2014 Markus Teich <markus dot teich at stusta dot mhn dot de>
© 2014-2015 Laslo Hunhold <dev at frign dot de>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
+58
View File
@@ -0,0 +1,58 @@
# st - simple terminal
# See LICENSE file for copyright and license details.
.POSIX:
include config.mk
SRC = st.c x.c hb.c
OBJ = $(SRC:.c=.o)
all: options st
options:
@echo st build options:
@echo "CFLAGS = $(STCFLAGS)"
@echo "LDFLAGS = $(STLDFLAGS)"
@echo "CC = $(CC)"
config.h:
cp config.def.h config.h
.c.o:
$(CC) $(STCFLAGS) -c $<
st.o: config.h st.h win.h
x.o: arg.h config.h st.h win.h hb.h
hb.o: st.h hb.h
$(OBJ): config.h config.mk
st: $(OBJ)
$(CC) -o $@ $(OBJ) $(STLDFLAGS)
clean:
rm -f st $(OBJ) st-$(VERSION).tar.gz
dist: clean
mkdir -p st-$(VERSION)
cp -R FAQ LEGACY TODO LICENSE Makefile README config.mk\
config.def.h st.info st.1 arg.h st.h win.h $(SRC)\
st-$(VERSION)
tar -cf - st-$(VERSION) | gzip > st-$(VERSION).tar.gz
rm -rf st-$(VERSION)
install: st
mkdir -p $(DESTDIR)$(PREFIX)/bin
cp -f st $(DESTDIR)$(PREFIX)/bin
chmod 755 $(DESTDIR)$(PREFIX)/bin/st
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1
chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1
tic -sx st.info
@echo Please see the README file regarding the terminfo entry of st.
uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/st
rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
.PHONY: all options clean dist install uninstall
+37
View File
@@ -0,0 +1,37 @@
st - simple terminal
--------------------
[![builds.sr.ht status](https://builds.sr.ht/~mil/sxmo-st.svg)](https://builds.sr.ht/~mil/sxmo-st?)
st is a simple terminal emulator for X which sucks less.
Requirements
------------
In order to build st you need the Xlib header files.
Installation
------------
Edit config.mk to match your local setup (st is installed into
the /usr/local namespace by default).
Afterwards enter the following command to build and install st (if
necessary as root):
make clean install
Running st
----------
If you did not install st with make clean install, you must compile
the st terminfo entry with the following command:
tic -sx st.info
See the man page for additional details.
Credits
-------
Based on Aurélien APTEL <aurelien dot aptel at gmail dot com> bt source code.
+28
View File
@@ -0,0 +1,28 @@
vt emulation
------------
* double-height support
code & interface
----------------
* add a simple way to do multiplexing
drawing
-------
* add diacritics support to xdraws()
* switch to a suckless font drawing library
* make the font cache simpler
* add better support for brightening of the upper colors
bugs
----
* fix shift up/down (shift selection in emacs)
* remove DEC test sequence when appropriate
misc
----
$ grep -nE 'XXX|TODO' st.c
+50
View File
@@ -0,0 +1,50 @@
/*
* Copy me if you can.
* by 20h
*/
#ifndef ARG_H__
#define ARG_H__
extern char *argv0;
/* use main(int argc, char *argv[]) */
#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
argv[0] && argv[0][0] == '-'\
&& argv[0][1];\
argc--, argv++) {\
char argc_;\
char **argv_;\
int brk_;\
if (argv[0][1] == '-' && argv[0][2] == '\0') {\
argv++;\
argc--;\
break;\
}\
int i_;\
for (i_ = 1, brk_ = 0, argv_ = argv;\
argv[0][i_] && !brk_;\
i_++) {\
if (argv_ != argv)\
break;\
argc_ = argv[0][i_];\
switch (argc_)
#define ARGEND }\
}
#define ARGC() argc_
#define EARGF(x) ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\
((x), abort(), (char *)0) :\
(brk_ = 1, (argv[0][i_+1] != '\0')?\
(&argv[0][i_+1]) :\
(argc--, argv++, argv[0])))
#define ARGF() ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\
(char *)0 :\
(brk_ = 1, (argv[0][i_+1] != '\0')?\
(&argv[0][i_+1]) :\
(argc--, argv++, argv[0])))
#endif
+520
View File
@@ -0,0 +1,520 @@
/* See LICENSE file for copyright and license details. */
/*
* appearance
*
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/
static char *font = "Fira Code:pixelsize=15:style=Regular:antialias=true:autohint=true";
static int borderpx = 2;
/*
* What program is execed by st depends of these precedence rules:
* 1: program passed with -e
* 2: scroll and/or utmp
* 3: SHELL environment variable
* 4: value of shell in /etc/passwd
* 5: value of shell in config.h
*/
static char *shell = "/bin/sh";
char *utmp = NULL;
/* scroll program: to enable use a string like "scroll" */
char *scroll = NULL;
char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
/* identification sequence returned in DA and DECID */
char *vtiden = "\033[?6c";
/* Kerning / character bounding-box multipliers */
static float cwscale = 1.0;
static float chscale = 1.0;
/*
* word delimiter string
*
* More advanced example: L" `'\"()[]{}"
*/
wchar_t *worddelimiters = L" ";
/* selection timeouts (in milliseconds) */
static unsigned int doubleclicktimeout = 1000;
static unsigned int tripleclicktimeout = 2000;
/* alt screens */
int allowaltscreen = 1;
/* allow certain non-interactive (insecure) window operations such as:
setting the clipboard text */
int allowwindowops = 0;
/*
* draw latency range in ms - from new content/keypress/etc until drawing.
* within this range, st draws when content stops arriving (idle). mostly it's
* near minlatency, but it waits longer for slow updates to avoid partial draw.
* low minlatency will tear/flicker more, as it can "detect" idle too early.
*/
static double minlatency = 8;
static double maxlatency = 33;
/*
* blinking timeout (set to 0 to disable blinking) for the terminal blinking
* attribute.
*/
static unsigned int blinktimeout = 800;
/*
* thickness of underline and bar cursors
*/
static unsigned int cursorthickness = 2;
/*
* bell volume. It must be a value between -100 and 100. Use 0 for disabling
* it
*/
static int bellvolume = 0;
/* default TERM value */
char *termname = "st-256color";
/*
* spaces per tab
*
* When you are changing this value, don't forget to adapt the »it« value in
* the st.info and appropriately install the st.info in the environment where
* you use this st version.
*
* it#$tabspaces,
*
* Secondly make sure your kernel is not expanding tabs. When running `stty
* -a` »tab0« should appear. You can tell the terminal to not expand tabs by
* running following command:
*
* stty tabs
*/
unsigned int tabspaces = 8;
/* 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 */
"#cccccc",
"#555555",
};
/*
* Default colors (colorname index)
* foreground, background, cursor, reverse cursor
*/
unsigned int defaultfg = 7;
unsigned int defaultbg = 0;
static unsigned int defaultcs = 256;
static unsigned int defaultrcs = 257;
/*
* Default shape of cursor
* 2: Block ("█")
* 4: Underline ("_")
* 6: Bar ("|")
* 7: Snowman ("☃")
*/
static unsigned int cursorshape = 2;
/*
* Default columns and rows numbers
*/
static unsigned int cols = 80;
static unsigned int rows = 24;
/*
* Default colour and shape of the mouse cursor
*/
static unsigned int mouseshape = XC_xterm;
static unsigned int mousefg = 7;
static unsigned int mousebg = 0;
/*
* Color used to display font attributes when fontconfig selected a font which
* doesn't match the ones requested.
*/
static unsigned int defaultattr = 11;
/*
* Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set).
* Note that if you want to use ShiftMask with selmasks, set this to an other
* modifier, set to 0 to not use it.
*/
static uint forcemousemod = ShiftMask;
/*
* Xresources preferences to load at startup
*/
ResourcePref resources[] = {
{ "font", STRING, &font },
{ "color0", STRING, &colorname[0] },
{ "color1", STRING, &colorname[1] },
{ "color2", STRING, &colorname[2] },
{ "color3", STRING, &colorname[3] },
{ "color4", STRING, &colorname[4] },
{ "color5", STRING, &colorname[5] },
{ "color6", STRING, &colorname[6] },
{ "color7", STRING, &colorname[7] },
{ "color8", STRING, &colorname[8] },
{ "color9", STRING, &colorname[9] },
{ "color10", STRING, &colorname[10] },
{ "color11", STRING, &colorname[11] },
{ "color12", STRING, &colorname[12] },
{ "color13", STRING, &colorname[13] },
{ "color14", STRING, &colorname[14] },
{ "color15", STRING, &colorname[15] },
{ "background", STRING, &colorname[256] },
{ "foreground", STRING, &colorname[257] },
{ "cursorColor", STRING, &colorname[258] },
{ "termname", STRING, &termname },
{ "shell", STRING, &shell },
{ "blinktimeout", INTEGER, &blinktimeout },
{ "bellvolume", INTEGER, &bellvolume },
{ "tabspaces", INTEGER, &tabspaces },
{ "borderpx", INTEGER, &borderpx },
{ "cwscale", FLOAT, &cwscale },
{ "chscale", FLOAT, &chscale },
};
/*
* Internal mouse shortcuts.
* Beware that overloading Button1 will disable the selection.
*/
static MouseShortcut mshortcuts[] = {
/* mask button function argument release */
{ XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
{ ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
{ XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
{ ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} },
{ XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
};
/* Internal keyboard shortcuts. */
#define MODKEY Mod1Mask
#define TERMMOD (ControlMask|ShiftMask)
static char *externalpipe_typecomplete[] = { "/bin/sh", "-c", "sxmo_pipecomplete.sh type $0", NULL };
static char *externalpipe_copycomplete[] = { "/bin/sh", "-c", "sxmo_pipecomplete.sh copy $0", NULL };
static Shortcut shortcuts[] = {
/* mask keysym function argument */
{ XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} },
{ 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} },
{ TERMMOD, XK_Home, zoomreset, {.f = 0} },
{ TERMMOD, XK_C, clipcopy, {.i = 0} },
{ TERMMOD, XK_V, clippaste, {.i = 0} },
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
{ TERMMOD, XK_S, toggleselectionmode, {.i = 0} },
{ TERMMOD, XK_B, kscrollup, {.i = -1} },
{ TERMMOD, XK_F, kscrolldown, {.i = -1} },
{ TERMMOD, XK_X, invert, { } },
{ TERMMOD, XK_plus, zoom, {.f = +1} },
{ TERMMOD, XK_underscore, zoom, {.f = -1} },
{ TERMMOD, XK_U, externalpipe, { .v = externalpipe_typecomplete } },
{ TERMMOD, XK_I, externalpipe, { .v = externalpipe_copycomplete } },
};
/*
* Special keys (change & recompile st.info accordingly)
*
* Mask value:
* * Use XK_ANY_MOD to match the key no matter modifiers state
* * Use XK_NO_MOD to match the key alone (no modifiers)
* appkey value:
* * 0: no value
* * > 0: keypad application mode enabled
* * = 2: term.numlock = 1
* * < 0: keypad application mode disabled
* appcursor value:
* * 0: no value
* * > 0: cursor application mode enabled
* * < 0: cursor application mode disabled
*
* Be careful with the order of the definitions because st searches in
* this table sequentially, so any XK_ANY_MOD must be in the last
* position for a key.
*/
/*
* If you want keys other than the X11 function keys (0xFD00 - 0xFFFF)
* to be mapped below, add them to this array.
*/
static KeySym mappedkeys[] = { -1 };
/*
* State bits to ignore when matching key or button events. By default,
* numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored.
*/
static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
/*
* This is the huge key array which defines all compatibility to the Linux
* world. Please decide about changes wisely.
*/
static Key key[] = {
/* keysym mask string appkey appcursor */
{ XK_KP_Home, ShiftMask, "\033[2J", 0, -1},
{ XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1},
{ XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1},
{ XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1},
{ XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0},
{ XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1},
{ XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1},
{ XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0},
{ XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1},
{ XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1},
{ XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0},
{ XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1},
{ XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1},
{ XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0},
{ XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1},
{ XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1},
{ XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0},
{ XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
{ XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0},
{ XK_KP_End, ControlMask, "\033[J", -1, 0},
{ XK_KP_End, ControlMask, "\033[1;5F", +1, 0},
{ XK_KP_End, ShiftMask, "\033[K", -1, 0},
{ XK_KP_End, ShiftMask, "\033[1;2F", +1, 0},
{ XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0},
{ XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0},
{ XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0},
{ XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0},
{ XK_KP_Insert, ShiftMask, "\033[4l", -1, 0},
{ XK_KP_Insert, ControlMask, "\033[L", -1, 0},
{ XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0},
{ XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
{ XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
{ XK_KP_Delete, ControlMask, "\033[M", -1, 0},
{ XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0},
{ XK_KP_Delete, ShiftMask, "\033[2K", -1, 0},
{ XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0},
{ XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0},
{ XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
{ XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0},
{ XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0},
{ XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0},
{ XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0},
{ XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0},
{ XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0},
{ XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0},
{ XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0},
{ XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0},
{ XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0},
{ XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0},
{ XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0},
{ XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0},
{ XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0},
{ XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0},
{ XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0},
{ XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0},
{ XK_Up, ShiftMask, "\033[1;2A", 0, 0},
{ XK_Up, Mod1Mask, "\033[1;3A", 0, 0},
{ XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0},
{ XK_Up, ControlMask, "\033[1;5A", 0, 0},
{ XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0},
{ XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0},
{ XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0},
{ XK_Up, XK_ANY_MOD, "\033[A", 0, -1},
{ XK_Up, XK_ANY_MOD, "\033OA", 0, +1},
{ XK_Down, ShiftMask, "\033[1;2B", 0, 0},
{ XK_Down, Mod1Mask, "\033[1;3B", 0, 0},
{ XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0},
{ XK_Down, ControlMask, "\033[1;5B", 0, 0},
{ XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0},
{ XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0},
{ XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0},
{ XK_Down, XK_ANY_MOD, "\033[B", 0, -1},
{ XK_Down, XK_ANY_MOD, "\033OB", 0, +1},
{ XK_Left, ShiftMask, "\033[1;2D", 0, 0},
{ XK_Left, Mod1Mask, "\033[1;3D", 0, 0},
{ XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0},
{ XK_Left, ControlMask, "\033[1;5D", 0, 0},
{ XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0},
{ XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0},
{ XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0},
{ XK_Left, XK_ANY_MOD, "\033[D", 0, -1},
{ XK_Left, XK_ANY_MOD, "\033OD", 0, +1},
{ XK_Right, ShiftMask, "\033[1;2C", 0, 0},
{ XK_Right, Mod1Mask, "\033[1;3C", 0, 0},
{ XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0},
{ XK_Right, ControlMask, "\033[1;5C", 0, 0},
{ XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0},
{ XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0},
{ XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0},
{ XK_Right, XK_ANY_MOD, "\033[C", 0, -1},
{ XK_Right, XK_ANY_MOD, "\033OC", 0, +1},
{ XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0},
{ XK_Return, Mod1Mask, "\033\r", 0, 0},
{ XK_Return, XK_ANY_MOD, "\r", 0, 0},
{ XK_Insert, ShiftMask, "\033[4l", -1, 0},
{ XK_Insert, ShiftMask, "\033[2;2~", +1, 0},
{ XK_Insert, ControlMask, "\033[L", -1, 0},
{ XK_Insert, ControlMask, "\033[2;5~", +1, 0},
{ XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
{ XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
{ XK_Delete, ControlMask, "\033[M", -1, 0},
{ XK_Delete, ControlMask, "\033[3;5~", +1, 0},
{ XK_Delete, ShiftMask, "\033[2K", -1, 0},
{ XK_Delete, ShiftMask, "\033[3;2~", +1, 0},
{ XK_Delete, XK_ANY_MOD, "\033[P", -1, 0},
{ XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
{ XK_BackSpace, XK_NO_MOD, "\177", 0, 0},
{ XK_BackSpace, Mod1Mask, "\033\177", 0, 0},
{ XK_Home, ShiftMask, "\033[2J", 0, -1},
{ XK_Home, ShiftMask, "\033[1;2H", 0, +1},
{ XK_Home, XK_ANY_MOD, "\033[H", 0, -1},
{ XK_Home, XK_ANY_MOD, "\033[1~", 0, +1},
{ XK_End, ControlMask, "\033[J", -1, 0},
{ XK_End, ControlMask, "\033[1;5F", +1, 0},
{ XK_End, ShiftMask, "\033[K", -1, 0},
{ XK_End, ShiftMask, "\033[1;2F", +1, 0},
{ XK_End, XK_ANY_MOD, "\033[4~", 0, 0},
{ XK_Prior, ControlMask, "\033[5;5~", 0, 0},
{ XK_Prior, ShiftMask, "\033[5;2~", 0, 0},
{ XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
{ XK_Next, ControlMask, "\033[6;5~", 0, 0},
{ XK_Next, ShiftMask, "\033[6;2~", 0, 0},
{ XK_Next, XK_ANY_MOD, "\033[6~", 0, 0},
{ XK_F1, XK_NO_MOD, "\033OP" , 0, 0},
{ XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0},
{ XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0},
{ XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0},
{ XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0},
{ XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0},
{ XK_F2, XK_NO_MOD, "\033OQ" , 0, 0},
{ XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0},
{ XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0},
{ XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0},
{ XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0},
{ XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0},
{ XK_F3, XK_NO_MOD, "\033OR" , 0, 0},
{ XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0},
{ XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0},
{ XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0},
{ XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0},
{ XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0},
{ XK_F4, XK_NO_MOD, "\033OS" , 0, 0},
{ XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0},
{ XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0},
{ XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0},
{ XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0},
{ XK_F5, XK_NO_MOD, "\033[15~", 0, 0},
{ XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0},
{ XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0},
{ XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0},
{ XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0},
{ XK_F6, XK_NO_MOD, "\033[17~", 0, 0},
{ XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0},
{ XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0},
{ XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0},
{ XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0},
{ XK_F7, XK_NO_MOD, "\033[18~", 0, 0},
{ XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0},
{ XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0},
{ XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0},
{ XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0},
{ XK_F8, XK_NO_MOD, "\033[19~", 0, 0},
{ XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0},
{ XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0},
{ XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0},
{ XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0},
{ XK_F9, XK_NO_MOD, "\033[20~", 0, 0},
{ XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0},
{ XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0},
{ XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0},
{ XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0},
{ XK_F10, XK_NO_MOD, "\033[21~", 0, 0},
{ XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0},
{ XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0},
{ XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0},
{ XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0},
{ XK_F11, XK_NO_MOD, "\033[23~", 0, 0},
{ XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0},
{ XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0},
{ XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0},
{ XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0},
{ XK_F12, XK_NO_MOD, "\033[24~", 0, 0},
{ XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0},
{ XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0},
{ XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0},
{ XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0},
{ XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0},
{ XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0},
{ XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0},
{ XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0},
{ XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0},
{ XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0},
{ XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0},
{ XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0},
{ XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0},
{ XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0},
{ XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0},
{ XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0},
{ XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0},
{ XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0},
{ XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0},
{ XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0},
{ XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0},
{ XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0},
{ XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0},
{ XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0},
{ XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0},
{ XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0},
{ XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0},
};
/*
* Selection types' masks.
* Use the same masks as usual.
* Button1Mask is always unset, to make masks match between ButtonPress.
* ButtonRelease and MotionNotify.
* If no match is found, regular selection is used.
*/
static uint selmasks[] = {
[SEL_RECTANGULAR] = Mod1Mask,
};
/*
* Printable characters in ASCII, used to estimate the advance width
* of single wide characters.
*/
static char ascii_printable[] =
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~";
+520
View File
@@ -0,0 +1,520 @@
/* See LICENSE file for copyright and license details. */
/*
* appearance
*
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/
static char *font = "Fira Code:pixelsize=15:style=Regular:antialias=true:autohint=true";
static int borderpx = 2;
/*
* What program is execed by st depends of these precedence rules:
* 1: program passed with -e
* 2: scroll and/or utmp
* 3: SHELL environment variable
* 4: value of shell in /etc/passwd
* 5: value of shell in config.h
*/
static char *shell = "/bin/sh";
char *utmp = NULL;
/* scroll program: to enable use a string like "scroll" */
char *scroll = NULL;
char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
/* identification sequence returned in DA and DECID */
char *vtiden = "\033[?6c";
/* Kerning / character bounding-box multipliers */
static float cwscale = 1.0;
static float chscale = 1.0;
/*
* word delimiter string
*
* More advanced example: L" `'\"()[]{}"
*/
wchar_t *worddelimiters = L" ";
/* selection timeouts (in milliseconds) */
static unsigned int doubleclicktimeout = 1000;
static unsigned int tripleclicktimeout = 2000;
/* alt screens */
int allowaltscreen = 1;
/* allow certain non-interactive (insecure) window operations such as:
setting the clipboard text */
int allowwindowops = 0;
/*
* draw latency range in ms - from new content/keypress/etc until drawing.
* within this range, st draws when content stops arriving (idle). mostly it's
* near minlatency, but it waits longer for slow updates to avoid partial draw.
* low minlatency will tear/flicker more, as it can "detect" idle too early.
*/
static double minlatency = 8;
static double maxlatency = 33;
/*
* blinking timeout (set to 0 to disable blinking) for the terminal blinking
* attribute.
*/
static unsigned int blinktimeout = 800;
/*
* thickness of underline and bar cursors
*/
static unsigned int cursorthickness = 2;
/*
* bell volume. It must be a value between -100 and 100. Use 0 for disabling
* it
*/
static int bellvolume = 0;
/* default TERM value */
char *termname = "st-256color";
/*
* spaces per tab
*
* When you are changing this value, don't forget to adapt the »it« value in
* the st.info and appropriately install the st.info in the environment where
* you use this st version.
*
* it#$tabspaces,
*
* Secondly make sure your kernel is not expanding tabs. When running `stty
* -a` »tab0« should appear. You can tell the terminal to not expand tabs by
* running following command:
*
* stty tabs
*/
unsigned int tabspaces = 8;
/* 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 */
"#cccccc",
"#555555",
};
/*
* Default colors (colorname index)
* foreground, background, cursor, reverse cursor
*/
unsigned int defaultfg = 7;
unsigned int defaultbg = 0;
static unsigned int defaultcs = 256;
static unsigned int defaultrcs = 257;
/*
* Default shape of cursor
* 2: Block ("█")
* 4: Underline ("_")
* 6: Bar ("|")
* 7: Snowman ("☃")
*/
static unsigned int cursorshape = 2;
/*
* Default columns and rows numbers
*/
static unsigned int cols = 80;
static unsigned int rows = 24;
/*
* Default colour and shape of the mouse cursor
*/
static unsigned int mouseshape = XC_xterm;
static unsigned int mousefg = 7;
static unsigned int mousebg = 0;
/*
* Color used to display font attributes when fontconfig selected a font which
* doesn't match the ones requested.
*/
static unsigned int defaultattr = 11;
/*
* Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set).
* Note that if you want to use ShiftMask with selmasks, set this to an other
* modifier, set to 0 to not use it.
*/
static uint forcemousemod = ShiftMask;
/*
* Xresources preferences to load at startup
*/
ResourcePref resources[] = {
{ "font", STRING, &font },
{ "color0", STRING, &colorname[0] },
{ "color1", STRING, &colorname[1] },
{ "color2", STRING, &colorname[2] },
{ "color3", STRING, &colorname[3] },
{ "color4", STRING, &colorname[4] },
{ "color5", STRING, &colorname[5] },
{ "color6", STRING, &colorname[6] },
{ "color7", STRING, &colorname[7] },
{ "color8", STRING, &colorname[8] },
{ "color9", STRING, &colorname[9] },
{ "color10", STRING, &colorname[10] },
{ "color11", STRING, &colorname[11] },
{ "color12", STRING, &colorname[12] },
{ "color13", STRING, &colorname[13] },
{ "color14", STRING, &colorname[14] },
{ "color15", STRING, &colorname[15] },
{ "background", STRING, &colorname[256] },
{ "foreground", STRING, &colorname[257] },
{ "cursorColor", STRING, &colorname[258] },
{ "termname", STRING, &termname },
{ "shell", STRING, &shell },
{ "blinktimeout", INTEGER, &blinktimeout },
{ "bellvolume", INTEGER, &bellvolume },
{ "tabspaces", INTEGER, &tabspaces },
{ "borderpx", INTEGER, &borderpx },
{ "cwscale", FLOAT, &cwscale },
{ "chscale", FLOAT, &chscale },
};
/*
* Internal mouse shortcuts.
* Beware that overloading Button1 will disable the selection.
*/
static MouseShortcut mshortcuts[] = {
/* mask button function argument release */
{ XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
{ ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
{ XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
{ ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} },
{ XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
};
/* Internal keyboard shortcuts. */
#define MODKEY Mod1Mask
#define TERMMOD (ControlMask|ShiftMask)
static char *externalpipe_typecomplete[] = { "/bin/sh", "-c", "sxmo_pipecomplete.sh type $0", NULL };
static char *externalpipe_copycomplete[] = { "/bin/sh", "-c", "sxmo_pipecomplete.sh copy $0", NULL };
static Shortcut shortcuts[] = {
/* mask keysym function argument */
{ XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} },
{ 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} },
{ TERMMOD, XK_Home, zoomreset, {.f = 0} },
{ TERMMOD, XK_C, clipcopy, {.i = 0} },
{ TERMMOD, XK_V, clippaste, {.i = 0} },
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
{ TERMMOD, XK_S, toggleselectionmode, {.i = 0} },
{ TERMMOD, XK_B, kscrollup, {.i = -1} },
{ TERMMOD, XK_F, kscrolldown, {.i = -1} },
{ TERMMOD, XK_X, invert, { } },
{ TERMMOD, XK_plus, zoom, {.f = +1} },
{ TERMMOD, XK_underscore, zoom, {.f = -1} },
{ TERMMOD, XK_U, externalpipe, { .v = externalpipe_typecomplete } },
{ TERMMOD, XK_I, externalpipe, { .v = externalpipe_copycomplete } },
};
/*
* Special keys (change & recompile st.info accordingly)
*
* Mask value:
* * Use XK_ANY_MOD to match the key no matter modifiers state
* * Use XK_NO_MOD to match the key alone (no modifiers)
* appkey value:
* * 0: no value
* * > 0: keypad application mode enabled
* * = 2: term.numlock = 1
* * < 0: keypad application mode disabled
* appcursor value:
* * 0: no value
* * > 0: cursor application mode enabled
* * < 0: cursor application mode disabled
*
* Be careful with the order of the definitions because st searches in
* this table sequentially, so any XK_ANY_MOD must be in the last
* position for a key.
*/
/*
* If you want keys other than the X11 function keys (0xFD00 - 0xFFFF)
* to be mapped below, add them to this array.
*/
static KeySym mappedkeys[] = { -1 };
/*
* State bits to ignore when matching key or button events. By default,
* numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored.
*/
static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
/*
* This is the huge key array which defines all compatibility to the Linux
* world. Please decide about changes wisely.
*/
static Key key[] = {
/* keysym mask string appkey appcursor */
{ XK_KP_Home, ShiftMask, "\033[2J", 0, -1},
{ XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1},
{ XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1},
{ XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1},
{ XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0},
{ XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1},
{ XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1},
{ XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0},
{ XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1},
{ XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1},
{ XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0},
{ XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1},
{ XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1},
{ XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0},
{ XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1},
{ XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1},
{ XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0},
{ XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
{ XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0},
{ XK_KP_End, ControlMask, "\033[J", -1, 0},
{ XK_KP_End, ControlMask, "\033[1;5F", +1, 0},
{ XK_KP_End, ShiftMask, "\033[K", -1, 0},
{ XK_KP_End, ShiftMask, "\033[1;2F", +1, 0},
{ XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0},
{ XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0},
{ XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0},
{ XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0},
{ XK_KP_Insert, ShiftMask, "\033[4l", -1, 0},
{ XK_KP_Insert, ControlMask, "\033[L", -1, 0},
{ XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0},
{ XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
{ XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
{ XK_KP_Delete, ControlMask, "\033[M", -1, 0},
{ XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0},
{ XK_KP_Delete, ShiftMask, "\033[2K", -1, 0},
{ XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0},
{ XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0},
{ XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
{ XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0},
{ XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0},
{ XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0},
{ XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0},
{ XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0},
{ XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0},
{ XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0},
{ XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0},
{ XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0},
{ XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0},
{ XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0},
{ XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0},
{ XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0},
{ XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0},
{ XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0},
{ XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0},
{ XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0},
{ XK_Up, ShiftMask, "\033[1;2A", 0, 0},
{ XK_Up, Mod1Mask, "\033[1;3A", 0, 0},
{ XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0},
{ XK_Up, ControlMask, "\033[1;5A", 0, 0},
{ XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0},
{ XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0},
{ XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0},
{ XK_Up, XK_ANY_MOD, "\033[A", 0, -1},
{ XK_Up, XK_ANY_MOD, "\033OA", 0, +1},
{ XK_Down, ShiftMask, "\033[1;2B", 0, 0},
{ XK_Down, Mod1Mask, "\033[1;3B", 0, 0},
{ XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0},
{ XK_Down, ControlMask, "\033[1;5B", 0, 0},
{ XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0},
{ XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0},
{ XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0},
{ XK_Down, XK_ANY_MOD, "\033[B", 0, -1},
{ XK_Down, XK_ANY_MOD, "\033OB", 0, +1},
{ XK_Left, ShiftMask, "\033[1;2D", 0, 0},
{ XK_Left, Mod1Mask, "\033[1;3D", 0, 0},
{ XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0},
{ XK_Left, ControlMask, "\033[1;5D", 0, 0},
{ XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0},
{ XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0},
{ XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0},
{ XK_Left, XK_ANY_MOD, "\033[D", 0, -1},
{ XK_Left, XK_ANY_MOD, "\033OD", 0, +1},
{ XK_Right, ShiftMask, "\033[1;2C", 0, 0},
{ XK_Right, Mod1Mask, "\033[1;3C", 0, 0},
{ XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0},
{ XK_Right, ControlMask, "\033[1;5C", 0, 0},
{ XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0},
{ XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0},
{ XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0},
{ XK_Right, XK_ANY_MOD, "\033[C", 0, -1},
{ XK_Right, XK_ANY_MOD, "\033OC", 0, +1},
{ XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0},
{ XK_Return, Mod1Mask, "\033\r", 0, 0},
{ XK_Return, XK_ANY_MOD, "\r", 0, 0},
{ XK_Insert, ShiftMask, "\033[4l", -1, 0},
{ XK_Insert, ShiftMask, "\033[2;2~", +1, 0},
{ XK_Insert, ControlMask, "\033[L", -1, 0},
{ XK_Insert, ControlMask, "\033[2;5~", +1, 0},
{ XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
{ XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
{ XK_Delete, ControlMask, "\033[M", -1, 0},
{ XK_Delete, ControlMask, "\033[3;5~", +1, 0},
{ XK_Delete, ShiftMask, "\033[2K", -1, 0},
{ XK_Delete, ShiftMask, "\033[3;2~", +1, 0},
{ XK_Delete, XK_ANY_MOD, "\033[P", -1, 0},
{ XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
{ XK_BackSpace, XK_NO_MOD, "\177", 0, 0},
{ XK_BackSpace, Mod1Mask, "\033\177", 0, 0},
{ XK_Home, ShiftMask, "\033[2J", 0, -1},
{ XK_Home, ShiftMask, "\033[1;2H", 0, +1},
{ XK_Home, XK_ANY_MOD, "\033[H", 0, -1},
{ XK_Home, XK_ANY_MOD, "\033[1~", 0, +1},
{ XK_End, ControlMask, "\033[J", -1, 0},
{ XK_End, ControlMask, "\033[1;5F", +1, 0},
{ XK_End, ShiftMask, "\033[K", -1, 0},
{ XK_End, ShiftMask, "\033[1;2F", +1, 0},
{ XK_End, XK_ANY_MOD, "\033[4~", 0, 0},
{ XK_Prior, ControlMask, "\033[5;5~", 0, 0},
{ XK_Prior, ShiftMask, "\033[5;2~", 0, 0},
{ XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
{ XK_Next, ControlMask, "\033[6;5~", 0, 0},
{ XK_Next, ShiftMask, "\033[6;2~", 0, 0},
{ XK_Next, XK_ANY_MOD, "\033[6~", 0, 0},
{ XK_F1, XK_NO_MOD, "\033OP" , 0, 0},
{ XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0},
{ XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0},
{ XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0},
{ XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0},
{ XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0},
{ XK_F2, XK_NO_MOD, "\033OQ" , 0, 0},
{ XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0},
{ XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0},
{ XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0},
{ XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0},
{ XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0},
{ XK_F3, XK_NO_MOD, "\033OR" , 0, 0},
{ XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0},
{ XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0},
{ XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0},
{ XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0},
{ XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0},
{ XK_F4, XK_NO_MOD, "\033OS" , 0, 0},
{ XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0},
{ XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0},
{ XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0},
{ XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0},
{ XK_F5, XK_NO_MOD, "\033[15~", 0, 0},
{ XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0},
{ XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0},
{ XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0},
{ XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0},
{ XK_F6, XK_NO_MOD, "\033[17~", 0, 0},
{ XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0},
{ XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0},
{ XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0},
{ XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0},
{ XK_F7, XK_NO_MOD, "\033[18~", 0, 0},
{ XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0},
{ XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0},
{ XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0},
{ XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0},
{ XK_F8, XK_NO_MOD, "\033[19~", 0, 0},
{ XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0},
{ XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0},
{ XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0},
{ XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0},
{ XK_F9, XK_NO_MOD, "\033[20~", 0, 0},
{ XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0},
{ XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0},
{ XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0},
{ XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0},
{ XK_F10, XK_NO_MOD, "\033[21~", 0, 0},
{ XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0},
{ XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0},
{ XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0},
{ XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0},
{ XK_F11, XK_NO_MOD, "\033[23~", 0, 0},
{ XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0},
{ XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0},
{ XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0},
{ XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0},
{ XK_F12, XK_NO_MOD, "\033[24~", 0, 0},
{ XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0},
{ XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0},
{ XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0},
{ XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0},
{ XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0},
{ XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0},
{ XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0},
{ XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0},
{ XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0},
{ XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0},
{ XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0},
{ XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0},
{ XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0},
{ XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0},
{ XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0},
{ XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0},
{ XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0},
{ XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0},
{ XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0},
{ XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0},
{ XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0},
{ XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0},
{ XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0},
{ XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0},
{ XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0},
{ XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0},
{ XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0},
};
/*
* Selection types' masks.
* Use the same masks as usual.
* Button1Mask is always unset, to make masks match between ButtonPress.
* ButtonRelease and MotionNotify.
* If no match is found, regular selection is used.
*/
static uint selmasks[] = {
[SEL_RECTANGULAR] = Mod1Mask,
};
/*
* Printable characters in ASCII, used to estimate the advance width
* of single wide characters.
*/
static char ascii_printable[] =
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~";
+37
View File
@@ -0,0 +1,37 @@
# st version
VERSION = 0.8.4.1
# Customize below to fit your system
# paths
PREFIX = /usr/local
MANPREFIX = $(PREFIX)/share/man
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
PKG_CONFIG = pkg-config
# includes and libs
INCS = -I$(X11INC) \
`$(PKG_CONFIG) --cflags fontconfig` \
`$(PKG_CONFIG) --cflags freetype2` \
`$(PKG_CONFIG) --cflags harfbuzz`
LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \
`$(PKG_CONFIG) --libs fontconfig` \
`$(PKG_CONFIG) --libs freetype2` \
`$(PKG_CONFIG) --libs harfbuzz`
# flags
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
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`
# compiler and linker
# CC = c99
+140
View File
@@ -0,0 +1,140 @@
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <X11/Xft/Xft.h>
#include <hb.h>
#include <hb-ft.h>
#include "st.h"
#include "hb.h"
#define FEATURE(c1,c2,c3,c4) { .tag = HB_TAG(c1,c2,c3,c4), .value = 1, .start = HB_FEATURE_GLOBAL_START, .end = HB_FEATURE_GLOBAL_END }
typedef struct {
XftFont *match;
hb_font_t *font;
} HbFontMatch;
static int hbfontslen = 0;
static HbFontMatch *hbfontcache = NULL;
static hb_buffer_t *hbbuffer = NULL;
static hb_feature_t features[] = {
FEATURE('l','i','g','a'),
FEATURE('c','a','l','t'),
FEATURE('c','l','i','g'),
FEATURE('d','l','i','g'),
};
void
hbunloadfonts(void)
{
for (int i = 0; i < hbfontslen; i++) {
hb_font_destroy(hbfontcache[i].font);
XftUnlockFace(hbfontcache[i].match);
}
if (hbfontcache != NULL) {
free(hbfontcache);
hbfontcache = NULL;
}
hbfontslen = 0;
}
static hb_font_t *
hbfindfont(XftFont *match)
{
for (int i = 0; i < hbfontslen; i++) {
if (hbfontcache[i].match == match)
return hbfontcache[i].font;
}
hbfontcache = xrealloc(hbfontcache, sizeof(HbFontMatch) * (hbfontslen + 1));
FT_Face face = XftLockFace(match);
hb_font_t *font = hb_ft_font_create(face, NULL);
if (font == NULL)
die("Failed to load HarfBuzz font.");
hbfontcache[hbfontslen].match = match;
hbfontcache[hbfontslen].font = font;
hbfontslen += 1;
return font;
}
static void
hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length)
{
hb_font_t *font = hbfindfont(xfont);
if (font == NULL)
return;
if (hbbuffer == NULL)
hbbuffer = hb_buffer_create();
hb_buffer_reset(hbbuffer);
hb_buffer_set_direction(hbbuffer, HB_DIRECTION_LTR);
hb_buffer_set_script(hbbuffer, HB_SCRIPT_LATIN);
for (int i = start; i < (start + length); i++) {
Rune rune = string[i].u;
if (string[i].mode & ATTR_WDUMMY)
rune = 0x0020;
hb_buffer_add_codepoints(hbbuffer, &rune, 1, 0, 1);
}
hb_shape(font, hbbuffer, features, sizeof(features) / sizeof(hb_feature_t));
unsigned int glyph_count = 0;
hb_glyph_info_t *info = hb_buffer_get_glyph_infos(hbbuffer, &glyph_count);
if ((int)glyph_count == length) {
for (int i = 0; i < length; i++)
codepoints[start + i] = info[i].codepoint;
} else if (glyph_count > 0 && (int)glyph_count < length) {
for (int i = 0; i < length; i++)
codepoints[start + i] = 0;
for (unsigned int g = 0; g < glyph_count; g++) {
uint32_t c = info[g].cluster;
if ((int)c < length)
codepoints[start + c] = info[g].codepoint;
}
}
}
void
hbtransform(XftGlyphFontSpec *specs, const Glyph *glyphs, size_t len, int x, int y)
{
int start = 0, length = 1, gstart = 0;
hb_codepoint_t *codepoints = calloc(len, sizeof(hb_codepoint_t));
if (!codepoints)
return;
for (int idx = 1, specidx = 1; idx < (int)len; idx++) {
if (glyphs[idx].mode & ATTR_WDUMMY) {
length += 1;
continue;
}
if (specs[specidx].font != specs[start].font || ATTRCMP(glyphs[gstart], glyphs[idx])) {
hbtransformsegment(specs[start].font, glyphs, codepoints, gstart, length);
length = 1;
start = specidx;
gstart = idx;
} else {
length += 1;
}
specidx++;
}
hbtransformsegment(specs[start].font, glyphs, codepoints, gstart, length);
for (int i = 0, specidx = 0; i < (int)len; i++) {
if (glyphs[i].mode & ATTR_WDUMMY)
continue;
if (codepoints[i] != 0 && codepoints[i] != specs[specidx].glyph)
specs[specidx].glyph = codepoints[i];
specidx++;
}
free(codepoints);
}
+6
View File
@@ -0,0 +1,6 @@
#include <X11/Xft/Xft.h>
#include <hb.h>
#include <hb-ft.h>
void hbunloadfonts(void);
void hbtransform(XftGlyphFontSpec *, const Glyph *, size_t, int, int);
+177
View File
@@ -0,0 +1,177 @@
.TH ST 1 st\-VERSION
.SH NAME
st \- simple terminal
.SH SYNOPSIS
.B st
.RB [ \-aiv ]
.RB [ \-c
.IR class ]
.RB [ \-f
.IR font ]
.RB [ \-g
.IR geometry ]
.RB [ \-n
.IR name ]
.RB [ \-o
.IR iofile ]
.RB [ \-T
.IR title ]
.RB [ \-t
.IR title ]
.RB [ \-l
.IR line ]
.RB [ \-w
.IR windowid ]
.RB [[ \-e ]
.IR command
.RI [ arguments ...]]
.PP
.B st
.RB [ \-aiv ]
.RB [ \-c
.IR class ]
.RB [ \-f
.IR font ]
.RB [ \-g
.IR geometry ]
.RB [ \-n
.IR name ]
.RB [ \-o
.IR iofile ]
.RB [ \-T
.IR title ]
.RB [ \-t
.IR title ]
.RB [ \-w
.IR windowid ]
.RB \-l
.IR line
.RI [ stty_args ...]
.SH DESCRIPTION
.B st
is a simple terminal emulator.
.SH OPTIONS
.TP
.B \-a
disable alternate screens in terminal
.TP
.BI \-c " class"
defines the window class (default $TERM).
.TP
.BI \-f " font"
defines the
.I font
to use when st is run.
.TP
.BI \-g " geometry"
defines the X11 geometry string.
The form is [=][<cols>{xX}<rows>][{+-}<xoffset>{+-}<yoffset>]. See
.BR XParseGeometry (3)
for further details.
.TP
.B \-i
will fixate the position given with the -g option.
.TP
.BI \-n " name"
defines the window instance name (default $TERM).
.TP
.BI \-o " iofile"
writes all the I/O to
.I iofile.
This feature is useful when recording st sessions. A value of "-" means
standard output.
.TP
.BI \-T " title"
defines the window title (default 'st').
.TP
.BI \-t " title"
defines the window title (default 'st').
.TP
.BI \-w " windowid"
embeds st within the window identified by
.I windowid
.TP
.BI \-l " line"
use a tty
.I line
instead of a pseudo terminal.
.I line
should be a (pseudo-)serial device (e.g. /dev/ttyS0 on Linux for serial port
0).
When this flag is given
remaining arguments are used as flags for
.BR stty(1).
By default st initializes the serial line to 8 bits, no parity, 1 stop bit
and a 38400 baud rate. The speed is set by appending it as last argument
(e.g. 'st -l /dev/ttyS0 115200'). Arguments before the last one are
.BR stty(1)
flags. If you want to set odd parity on 115200 baud use for example 'st -l
/dev/ttyS0 parenb parodd 115200'. Set the number of bits by using for
example 'st -l /dev/ttyS0 cs7 115200'. See
.BR stty(1)
for more arguments and cases.
.TP
.B \-v
prints version information to stderr, then exits.
.TP
.BI \-e " command " [ " arguments " "... ]"
st executes
.I command
instead of the shell. If this is used it
.B must be the last option
on the command line, as in xterm / rxvt.
This option is only intended for compatibility,
and all the remaining arguments are used as a command
even without it.
.SH SHORTCUTS
.TP
.B Break
Send a break in the serial line.
Break key is obtained in PC keyboards
pressing at the same time control and pause.
.TP
.B Ctrl-Print Screen
Toggle if st should print to the
.I iofile.
.TP
.B Shift-Print Screen
Print the full screen to the
.I iofile.
.TP
.B Print Screen
Print the selection to the
.I iofile.
.TP
.B Ctrl-Shift-Page Up
Increase font size.
.TP
.B Ctrl-Shift-Page Down
Decrease font size.
.TP
.B Ctrl-Shift-Home
Reset to default font size.
.TP
.B Ctrl-Shift-y
Paste from primary selection (middle mouse button).
.TP
.B Ctrl-Shift-c
Copy the selected text to the clipboard selection.
.TP
.B Ctrl-Shift-v
Paste from the clipboard selection.
.SH CUSTOMIZATION
.B st
can be customized by creating a custom config.h and (re)compiling the source
code. This keeps it fast, secure and simple.
.SH AUTHORS
See the LICENSE file for the authors.
.SH LICENSE
See the LICENSE file for the terms of redistribution.
.SH SEE ALSO
.BR tabbed (1),
.BR utmp (1),
.BR stty (1),
.BR scroll (1)
.SH BUGS
See the TODO file in the distribution.
+2728
View File
File diff suppressed because it is too large Load Diff
+128
View File
@@ -0,0 +1,128 @@
/* See LICENSE for license details. */
#include <stdint.h>
#include <sys/types.h>
/* macros */
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) < (b) ? (b) : (a))
#define LEN(a) (sizeof(a) / sizeof(a)[0])
#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d))
#define DEFAULT(a, b) (a) = (a) ? (a) : (b)
#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \
(a).bg != (b).bg)
#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \
(t1.tv_nsec-t2.tv_nsec)/1E6)
#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
#define IS_TRUECOL(x) (1 << 24 & (x))
enum glyph_attribute {
ATTR_NULL = 0,
ATTR_BOLD = 1 << 0,
ATTR_FAINT = 1 << 1,
ATTR_ITALIC = 1 << 2,
ATTR_UNDERLINE = 1 << 3,
ATTR_BLINK = 1 << 4,
ATTR_REVERSE = 1 << 5,
ATTR_INVISIBLE = 1 << 6,
ATTR_STRUCK = 1 << 7,
ATTR_WRAP = 1 << 8,
ATTR_WIDE = 1 << 9,
ATTR_WDUMMY = 1 << 10,
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
};
enum selection_mode {
SEL_IDLE = 0,
SEL_EMPTY = 1,
SEL_READY = 2
};
enum selection_type {
SEL_REGULAR = 1,
SEL_RECTANGULAR = 2
};
enum selection_snap {
SNAP_WORD = 1,
SNAP_LINE = 2
};
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned short ushort;
typedef uint_least32_t Rune;
#define Glyph Glyph_
typedef struct {
Rune u; /* character code */
ushort mode; /* attribute flags */
uint32_t fg; /* foreground */
uint32_t bg; /* background */
} Glyph;
typedef Glyph *Line;
typedef union {
int i;
uint ui;
float f;
const void *v;
const char *s;
} Arg;
void die(const char *, ...);
void redraw(void);
void draw(void);
void kscrolldown(const Arg *);
void kscrollup(const Arg *);
void printscreen(const Arg *);
void printsel(const Arg *);
void sendbreak(const Arg *);
void toggleprinter(const Arg *);
void externalpipe(const Arg *);
int tattrset(int);
void tnew(int, int);
void tresize(int, int);
void tsetdirtattr(int);
void ttyhangup(void);
int ttynew(char *, char *, char *, char **);
size_t ttyread(void);
void ttyresize(int, int);
void ttywrite(const char *, size_t, int);
void resettitle(void);
void selclear(void);
void selinit(void);
void selstart(int, int, int);
void selextend(int, int, int, int);
int selected(int, int);
char *getsel(void);
size_t utf8encode(Rune, char *);
void *xmalloc(size_t);
void *xrealloc(void *, size_t);
char *xstrdup(char *);
/* config.h globals */
extern char *utmp;
extern char *scroll;
extern char *stty_args;
extern char *vtiden;
extern wchar_t *worddelimiters;
extern int allowaltscreen;
extern int allowwindowops;
extern char *termname;
extern unsigned int tabspaces;
extern unsigned int defaultfg;
extern unsigned int defaultbg;
+239
View File
@@ -0,0 +1,239 @@
st-mono| simpleterm monocolor,
acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
am,
bce,
bel=^G,
blink=\E[5m,
bold=\E[1m,
cbt=\E[Z,
cvvis=\E[?25h,
civis=\E[?25l,
clear=\E[H\E[2J,
cnorm=\E[?12l\E[?25h,
colors#2,
cols#80,
cr=^M,
csr=\E[%i%p1%d;%p2%dr,
cub=\E[%p1%dD,
cub1=^H,
cud1=^J,
cud=\E[%p1%dB,
cuf1=\E[C,
cuf=\E[%p1%dC,
cup=\E[%i%p1%d;%p2%dH,
cuu1=\E[A,
cuu=\E[%p1%dA,
dch=\E[%p1%dP,
dch1=\E[P,
dim=\E[2m,
dl=\E[%p1%dM,
dl1=\E[M,
ech=\E[%p1%dX,
ed=\E[J,
el=\E[K,
el1=\E[1K,
enacs=\E)0,
flash=\E[?5h$<80/>\E[?5l,
fsl=^G,
home=\E[H,
hpa=\E[%i%p1%dG,
hs,
ht=^I,
hts=\EH,
ich=\E[%p1%d@,
il1=\E[L,
il=\E[%p1%dL,
ind=^J,
indn=\E[%p1%dS,
invis=\E[8m,
is2=\E[4l\E>\E[?1034l,
it#8,
kel=\E[1;2F,
ked=\E[1;5F,
ka1=\E[1~,
ka3=\E[5~,
kc1=\E[4~,
kc3=\E[6~,
kbs=\177,
kcbt=\E[Z,
kb2=\EOu,
kcub1=\EOD,
kcud1=\EOB,
kcuf1=\EOC,
kcuu1=\EOA,
kDC=\E[3;2~,
kent=\EOM,
kEND=\E[1;2F,
kIC=\E[2;2~,
kNXT=\E[6;2~,
kPRV=\E[5;2~,
kHOM=\E[1;2H,
kLFT=\E[1;2D,
kRIT=\E[1;2C,
kind=\E[1;2B,
kri=\E[1;2A,
kclr=\E[3;5~,
kdl1=\E[3;2~,
kdch1=\E[3~,
kich1=\E[2~,
kend=\E[4~,
kf1=\EOP,
kf2=\EOQ,
kf3=\EOR,
kf4=\EOS,
kf5=\E[15~,
kf6=\E[17~,
kf7=\E[18~,
kf8=\E[19~,
kf9=\E[20~,
kf10=\E[21~,
kf11=\E[23~,
kf12=\E[24~,
kf13=\E[1;2P,
kf14=\E[1;2Q,
kf15=\E[1;2R,
kf16=\E[1;2S,
kf17=\E[15;2~,
kf18=\E[17;2~,
kf19=\E[18;2~,
kf20=\E[19;2~,
kf21=\E[20;2~,
kf22=\E[21;2~,
kf23=\E[23;2~,
kf24=\E[24;2~,
kf25=\E[1;5P,
kf26=\E[1;5Q,
kf27=\E[1;5R,
kf28=\E[1;5S,
kf29=\E[15;5~,
kf30=\E[17;5~,
kf31=\E[18;5~,
kf32=\E[19;5~,
kf33=\E[20;5~,
kf34=\E[21;5~,
kf35=\E[23;5~,
kf36=\E[24;5~,
kf37=\E[1;6P,
kf38=\E[1;6Q,
kf39=\E[1;6R,
kf40=\E[1;6S,
kf41=\E[15;6~,
kf42=\E[17;6~,
kf43=\E[18;6~,
kf44=\E[19;6~,
kf45=\E[20;6~,
kf46=\E[21;6~,
kf47=\E[23;6~,
kf48=\E[24;6~,
kf49=\E[1;3P,
kf50=\E[1;3Q,
kf51=\E[1;3R,
kf52=\E[1;3S,
kf53=\E[15;3~,
kf54=\E[17;3~,
kf55=\E[18;3~,
kf56=\E[19;3~,
kf57=\E[20;3~,
kf58=\E[21;3~,
kf59=\E[23;3~,
kf60=\E[24;3~,
kf61=\E[1;4P,
kf62=\E[1;4Q,
kf63=\E[1;4R,
khome=\E[1~,
kil1=\E[2;5~,
krmir=\E[2;2~,
knp=\E[6~,
kmous=\E[M,
kpp=\E[5~,
lines#24,
mir,
msgr,
npc,
op=\E[39;49m,
pairs#64,
mc0=\E[i,
mc4=\E[4i,
mc5=\E[5i,
rc=\E8,
rev=\E[7m,
ri=\EM,
rin=\E[%p1%dT,
ritm=\E[23m,
rmacs=\E(B,
rmcup=\E[?1049l,
rmir=\E[4l,
rmkx=\E[?1l\E>,
rmso=\E[27m,
rmul=\E[24m,
rs1=\Ec,
rs2=\E[4l\E>\E[?1034l,
sc=\E7,
sitm=\E[3m,
sgr0=\E[0m,
smacs=\E(0,
smcup=\E[?1049h,
smir=\E[4h,
smkx=\E[?1h\E=,
smso=\E[7m,
smul=\E[4m,
tbc=\E[3g,
tsl=\E]0;,
xenl,
vpa=\E[%i%p1%dd,
# XTerm extensions
rmxx=\E[29m,
smxx=\E[9m,
# disabled rep for now: causes some issues with older ncurses versions.
# rep=%p1%c\E[%p2%{1}%-%db,
# tmux extensions, see TERMINFO EXTENSIONS in tmux(1)
Tc,
Ms=\E]52;%p1%s;%p2%s\007,
Se=\E[2 q,
Ss=\E[%p1%d q,
st| simpleterm,
use=st-mono,
colors#8,
setab=\E[4%p1%dm,
setaf=\E[3%p1%dm,
setb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m,
st-256color| simpleterm with 256 colors,
use=st,
ccc,
colors#256,
oc=\E]104\007,
pairs#32767,
# Nicked from xterm-256color
initc=\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\,
setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m,
setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m,
st-meta| simpleterm with meta key,
use=st,
km,
rmm=\E[?1034l,
smm=\E[?1034h,
rs2=\E[4l\E>\E[?1034h,
is2=\E[4l\E>\E[?1034h,
st-meta-256color| simpleterm with meta key and 256 colors,
use=st-256color,
km,
rmm=\E[?1034l,
smm=\E[?1034h,
rs2=\E[4l\E>\E[?1034h,
is2=\E[4l\E>\E[?1034h,
st-bs| simpleterm with backspace as backspace,
use=st,
kbs=\010,
kdch1=\177,
st-bs-256color| simpleterm with backspace as backspace and 256colors,
use=st-256color,
kbs=\010,
kdch1=\177,
+39
View File
@@ -0,0 +1,39 @@
/* See LICENSE for license details. */
enum win_mode {
MODE_VISIBLE = 1 << 0,
MODE_FOCUSED = 1 << 1,
MODE_APPKEYPAD = 1 << 2,
MODE_MOUSEBTN = 1 << 3,
MODE_MOUSEMOTION = 1 << 4,
MODE_REVERSE = 1 << 5,
MODE_KBDLOCK = 1 << 6,
MODE_HIDE = 1 << 7,
MODE_APPCURSOR = 1 << 8,
MODE_MOUSESGR = 1 << 9,
MODE_8BIT = 1 << 10,
MODE_BLINK = 1 << 11,
MODE_FBLINK = 1 << 12,
MODE_FOCUS = 1 << 13,
MODE_MOUSEX10 = 1 << 14,
MODE_MOUSEMANY = 1 << 15,
MODE_BRCKTPASTE = 1 << 16,
MODE_NUMLOCK = 1 << 17,
MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
|MODE_MOUSEMANY,
};
void xbell(void);
void xclipcopy(void);
void xdrawcursor(int, int, Glyph, int, int, Glyph);
void xdrawline(Line, int, int, int);
void xfinishdraw(void);
void xloadcols(void);
int xsetcolorname(int, const char *);
void xsettitle(char *);
int xsetcursor(int);
void xsetmode(int, unsigned int);
void xsetpointermotion(int);
void xsetsel(char *);
int xstartdraw(void);
void xximspot(int, int);
+2188
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,65 @@
name: 🐞 Bug report
description: Create a report to help us improve
labels: [bug, needs-triage]
body:
- type: markdown
attributes:
value: |
Please fill out the sections below to help everyone identify and fix the bug. If you have a general idea or question then please use the [discussions](https://github.com/orgs/X11Libre/discussions).
- type: dropdown
id: affected-version
attributes:
label: Select the version
options:
- 1.5.0.1
- Git master branch
- other or don't know
default: 1
validations:
required: true
- type: textarea
id: description
attributes:
label: Describe your issue
placeholder: When I did X then Y happened.
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
placeholder: |
1. Start ...
2. Do this
3. Do that
validations:
required: true
- type: textarea
id: expected
attributes:
label: What did you expect?
placeholder: I expected this to happen.
- type: textarea
id: environment
attributes:
label: Additional Information
description: |
Additional information you want to provide such as logs, system info, environment, screenshots, etc.
placeholder: |
Add any other context about the bug here.
- type: checkboxes
id: checks
attributes:
label: Extra fields
options:
- label: I have checked the existing [issues](https://github.com/X11Libre/xf86-input-libinput/issues)
required: true
- label: I have read the [Contributing Guidelines](https://github.com/X11Libre/xserver/blob/master/CONTRIBUTING.md)
required: true
- label: I'd like to work on this issue
- type: markdown
attributes:
value: |
Thanks for reporting this issue! We will get back to you as soon as possible.
@@ -0,0 +1,49 @@
name: ✨ Feature request
description: Suggest a feature for this software
labels: [enhancement, needs-triage]
body:
- type: markdown
attributes:
value: |
Please fill out the sections below to properly describe the new software feature you are suggesting. If you have a general idea or question then please use the [discussions](https://github.com/orgs/X11Libre/discussions).
- type: textarea
id: description
attributes:
label: "Describe the feature"
placeholder: A thing in X that allows to do Y.
validations:
required: true
- type: textarea
id: rationale
attributes:
label: "It should be done because"
placeholder: Doing Y is needed for Z.
validations:
required: true
- type: textarea
id: alternative
attributes:
label: "What are the alternatives?"
placeholder: We could do A or B instead.
- type: textarea
id: context
attributes:
label: Additional context
description: Additional information you want to provide such as references to related issues or protocols, the implications on existing use cases, etc.
placeholder: |
Add any other context about the feature request here.
- type: checkboxes
id: checks
attributes:
label: Extra fields
options:
- label: I have checked the existing [issues](https://github.com/X11Libre/xf86-input-libinput/issues)
required: true
- label: I have read the [Contributing Guidelines](https://github.com/X11Libre/xserver/blob/master/CONTRIBUTING.md)
required: true
- label: I'd like to work on this issue
- type: markdown
attributes:
value: |
Thanks for your suggestion! Let's see together if it can be done.
@@ -0,0 +1,49 @@
name: 🔧 Code cleanup
description: Level up the source code
labels: [code-cleanup, needs-triage]
body:
- type: markdown
attributes:
value: |
Please fill out the sections below to properly describe the code cleanup you are suggesting. If you have a general idea or question then please use the [discussions](https://github.com/orgs/X11Libre/discussions).
- type: textarea
id: description
attributes:
label: "Describe the cleanup"
placeholder: C in X needs to be changed into D.
validations:
required: true
- type: textarea
id: rationale
attributes:
label: "It should be done because"
placeholder: Having D is needed for E.
validations:
required: true
- type: textarea
id: alternative
attributes:
label: "What are the alternatives?"
placeholder: We could do A or B instead.
- type: textarea
id: context
attributes:
label: Additional context
description: Additional information you want to provide such as implications on existing code, how to ensure API/ABI stability, which tests are needed or to be run, related issues, etc.
placeholder: |
Add any other context about the cleanup here.
- type: checkboxes
id: checks
attributes:
label: Extra fields
options:
- label: I have checked the existing [issues](https://github.com/X11Libre/xf86-input-libinput/issues)
required: true
- label: I have read the [Contributing Guidelines](https://github.com/X11Libre/xserver/blob/master/CONTRIBUTING.md)
required: true
- label: I'd like to work on this issue
- type: markdown
attributes:
value: |
Thanks for looking at the source code! Let's see together how it can be improved.
@@ -0,0 +1,38 @@
name: 🔖 Documentation update
description: Make your mark for better documentation
labels: [documentation, needs-triage]
body:
- type: markdown
attributes:
value: |
Please fill out the sections below to help others understand our software. If you have a general idea or question then please use the [discussions](https://github.com/orgs/X11Libre/discussions).
- type: textarea
id: description
attributes:
label: Describe the update
placeholder: These things need to be better documented.
validations:
required: true
- type: textarea
id: environment
attributes:
label: Additional Information
description: Additional information you want to provide such as tickets related to changes in the software, affected files, screenshots, etc.
placeholder: |
Add any other context about the update here.
- type: checkboxes
id: checks
attributes:
label: Extra fields
options:
- label: I have checked the existing [issues](https://github.com/X11Libre/xf86-input-libinput/issues)
required: true
- label: I have read the [Contributing Guidelines](https://github.com/X11Libre/xserver/blob/master/CONTRIBUTING.md)
required: true
- label: I'd like to work on this issue
- type: markdown
attributes:
value: |
Thanks for requesting this update! We will get back to you as soon as possible.
@@ -0,0 +1,43 @@
name: ✅ Organizational task
description: Create a task for project organization
labels: [needs-triage, organization]
body:
- type: markdown
attributes:
value: |
Please fill out the sections below to get organizational things done. If you have a general idea or question then please use the [discussions](https://github.com/orgs/X11Libre/discussions).
- type: textarea
id: description
attributes:
label: Describe the task
placeholder: These things need to be done.
validations:
required: true
- type: textarea
id: rationale
attributes:
label: "It should be done because"
placeholder: Doing Y is needed for Z.
- type: textarea
id: environment
attributes:
label: Additional Information
description: Additional information you want to provide such as the context for bigger tasks, the implicatons on existing workflows, related issues, etc.
placeholder: |
Add any other context about the task here.
- type: checkboxes
id: checks
attributes:
label: Extra fields
options:
- label: I have checked the existing [issues](https://github.com/X11Libre/xf86-input-libinput/issues)
required: true
- label: I have read the [Contributing Guidelines](https://github.com/X11Libre/xserver/blob/master/CONTRIBUTING.md)
required: true
- label: I'd like to work on this issue
- type: markdown
attributes:
value: |
Thanks for adding this task! We will get back to you as soon as possible.
@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: XLibre Community Support
url: https://github.com/orgs/X11Libre/discussions
about: Please ask and answer questions here.
- name: Mailing List
url: https://www.freelists.org/list/xlibre
about: You can join the discussions on our mailing list.
+50
View File
@@ -0,0 +1,50 @@
permissions:
contents: write
on:
push:
pull_request:
jobs:
ubuntu:
strategy:
matrix:
xserver-version: [ master, xlibre-xserver-25.1.0, xlibre-xserver-25.0.0.18 ]
runs-on: ubuntu-latest
steps:
- uses: X11Libre/action-build-driver/target/ubuntu@v0.4.0
with:
xserver-version: ${{ matrix.xserver-version }}
freebsd:
strategy:
matrix:
xserver-version: [ master, xlibre-xserver-25.1.0, xlibre-xserver-25.0.0.18 ]
runs-on: ubuntu-latest
steps:
- uses: X11Libre/action-build-driver/target/freebsd@v0.4.0
with:
xserver-version: ${{ matrix.xserver-version }}
dragonfly:
strategy:
matrix:
# xlibre-xserver-25.0.x not compiling on dragonfly yet
xserver-version: [ master, xlibre-xserver-25.1.0 ]
runs-on: ubuntu-latest
steps:
- uses: X11Libre/action-build-driver/target/dragonfly@v0.4.0
with:
xserver-version: ${{ matrix.xserver-version }}
# not supported on NetBSD
release-notes:
name: Release pushed tag
runs-on: ubuntu-latest
if: ${{ startsWith(github.ref, 'refs/tags/xlibre-') }}
needs: [ ubuntu, freebsd, dragonfly ]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: X11Libre/action-build-driver/release@v0.4.0
+87
View File
@@ -0,0 +1,87 @@
#
# X.Org module default exclusion patterns
# The next section if for module specific patterns
#
# Do not edit the following section
# GNU Build System (Autotools)
aclocal.m4
autom4te.cache/
autoscan.log
ChangeLog
compile
config.guess
config.h
config.h.in
config.log
config-ml.in
config.py
config.status
config.status.lineno
config.sub
configure
configure.scan
depcomp
.deps/
INSTALL
install-sh
.libs/
libtool
libtool.m4
ltmain.sh
lt~obsolete.m4
ltoptions.m4
ltsugar.m4
ltversion.m4
Makefile
Makefile.in
mdate-sh
missing
mkinstalldirs
*.pc
py-compile
stamp-h?
symlink-tree
texinfo.tex
ylwrap
# Do not edit the following section
# Edit Compile Debug Document Distribute
*~
*.[0-9]
*.[0-9]x
*.bak
*.bin
core
*.dll
*.exe
*-ISO*.bdf
*-JIS*.bdf
*-KOI8*.bdf
*.kld
*.ko
*.ko.cmd
*.lai
*.l[oa]
*.[oa]
*.obj
*.patch
*.so
*.pcf.gz
*.pdb
*.tar.bz2
*.tar.gz
#
# Add & Override patterns for xf86-input-libinput
#
# Edit the following section as needed
# For example, !report.pc overrides *.pc. See 'man gitignore'
#
*.log
*.trs
*.swp
*.announce
*.sig
test-driver
tags
.vimdir
test/test-bezier
+20
View File
@@ -0,0 +1,20 @@
SPDX-License-Identifier: MIT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
+45
View File
@@ -0,0 +1,45 @@
# Copyright 2005 Adam Jackson.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# on the rights to use, copy, modify, merge, publish, distribute, sub
# license, and/or sell copies of the Software, and to permit persons to whom
# the Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
# ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# During distcheck, system locations (as provided by pkg-config) may
# not be writable; provide instead relative locations.
DISTCHECK_CONFIGURE_FLAGS = --with-xorg-module-dir='$${libdir}/xorg/modules' \
--with-sdkdir='$${includedir}/xorg'
SUBDIRS = src include man test
MAINTAINERCLEANFILES = ChangeLog INSTALL
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = xorg-libinput.pc
dist_xorgconf_DATA = conf/40-libinput.conf
.PHONY: ChangeLog INSTALL
INSTALL:
$(INSTALL_CMD)
ChangeLog:
$(CHANGELOG_CMD)
dist-hook: ChangeLog INSTALL
EXTRA_DIST = README.md
+33
View File
@@ -0,0 +1,33 @@
xf86-input-libinput - a libinput-based X driver
===============================================
The official repository for this driver is
https://github.com/X11Libre/xf86-input-evdev
This is an X driver based on libinput. It is a thin wrapper around libinput,
so while it does provide all features that libinput supports it does little
beyond.
***WARNING: misconfiguration of an X input driver may leave you without
usable input devices in your X session. Use with caution.***
Building
--------
To build this driver:
autoreconf -vif
./configure --prefix=$HOME/build
make && make install
Note that this assumes the same prefix as used in "Building the X Window
System" above, adjust as required. If you want a system install, use a
prefix of */usr*.
Install the default configuration file:
cp conf/99-libinput.conf /etc/X11/xorg.conf.d/
This will assign this driver to *all* devices. Use with caution.
+17
View File
@@ -0,0 +1,17 @@
#! /bin/sh
srcdir=`dirname "$0"`
test -z "$srcdir" && srcdir=.
ORIGDIR=`pwd`
cd "$srcdir"
autoreconf -v --install || exit 1
cd "$ORIGDIR" || exit $?
git config --local --get format.subjectPrefix >/dev/null 2>&1 ||
git config --local format.subjectPrefix "PATCH xf86-input-libinput"
if test -z "$NOCONFIGURE"; then
exec "$srcdir"/configure "$@"
fi
@@ -0,0 +1,52 @@
# Match on all types of devices but joysticks
#
# If you want to configure your devices, do not copy this file.
# Instead, use a config snippet that contains something like this:
#
# Section "InputClass"
# Identifier "something or other"
# MatchDriver "libinput"
#
# MatchIsTouchpad "on"
# ... other Match directives ...
# Option "someoption" "value"
# EndSection
#
# This applies the option any libinput device also matched by the other
# directives. See the xorg.conf(5) man page for more info on
# matching devices.
Section "InputClass"
Identifier "libinput pointer catchall"
MatchIsPointer "on"
MatchDevicePath "/dev/input/event*"
Driver "libinput"
EndSection
Section "InputClass"
Identifier "libinput keyboard catchall"
MatchIsKeyboard "on"
MatchDevicePath "/dev/input/event*"
Driver "libinput"
EndSection
Section "InputClass"
Identifier "libinput touchpad catchall"
MatchIsTouchpad "on"
MatchDevicePath "/dev/input/event*"
Driver "libinput"
EndSection
Section "InputClass"
Identifier "libinput touchscreen catchall"
MatchIsTouchscreen "on"
MatchDevicePath "/dev/input/event*"
Driver "libinput"
EndSection
Section "InputClass"
Identifier "libinput tablet catchall"
MatchIsTablet "on"
MatchDevicePath "/dev/input/event*"
Driver "libinput"
EndSection
+157
View File
@@ -0,0 +1,157 @@
# Copyright 2005 Adam Jackson.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# on the rights to use, copy, modify, merge, publish, distribute, sub
# license, and/or sell copies of the Software, and to permit persons to whom
# the Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
# ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Process this file with autoconf to produce a configure script
# Initialize Autoconf
AC_PREREQ([2.60])
AC_INIT([xlibre-xf86-input-libinput],
[25.0.1],
[https://github.com/X11Libre/xf86-input-libinput/issues],
[xlibre-xf86-input-libinput])
AC_CONFIG_SRCDIR([Makefile.am])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_AUX_DIR(.)
# Initialize Automake
AM_INIT_AUTOMAKE([foreign dist-xz])
# Initialize libtool
AC_DISABLE_STATIC
LT_INIT
# Initialize X.Org macros 1.8 or later for MAN_SUBSTS set by XORG_MANPAGE_SECTIONS
m4_ifndef([XORG_MACROS_VERSION],
[m4_fatal([must install xorg-macros 1.8 or later before running autoconf/autogen])])
XORG_MACROS_VERSION(1.8)
XORG_DEFAULT_OPTIONS
CFLAGS="$CFLAGS -Wno-declaration-after-statement"
# Obtain compiler/linker options from server and required extensions
PKG_CHECK_MODULES(XORG, [xorg-server >= 25.0.0] xproto [inputproto >= 2.3.99.1])
PKG_CHECK_MODULES(LIBINPUT, [libinput >= 1.11.0])
OLD_LIBS=$LIBS
OLD_CFLAGS=$CFLAGS
LIBS="$LIBS $LIBINPUT_LIBS"
CFLAGS="$CFLAGS $LIBINPUT_CFLAGS"
AC_MSG_CHECKING([if libinput_device_config_scroll_get_button_lock is available])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <libinput.h>]],
[[libinput_device_config_scroll_get_button_lock(NULL)]])],
[AC_MSG_RESULT([yes])
AC_DEFINE(HAVE_LIBINPUT_SCROLL_BUTTON_LOCK, [1],
[libinput_device_config_scroll_get_button_lock() is available])
[libinput_have_scroll_button_lock=yes]],
[AC_MSG_RESULT([no])
[libinput_have_scroll_button_lock=no]])
AC_MSG_CHECKING([if libinput_event_pointer_get_scroll_value_v120 is available])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <libinput.h>]],
[[libinput_event_pointer_get_scroll_value_v120(NULL, 0)]])],
[AC_MSG_RESULT([yes])
AC_DEFINE(HAVE_LIBINPUT_AXIS_VALUE_V120, [1],
[libinput_event_pointer_get_scroll_value_v120() is available])
[libinput_have_axis_value_v120=yes]],
[AC_MSG_RESULT([no])
[libinput_have_axis_value_v120=no]])
AC_MSG_CHECKING([if libinput_config_accel_create is available])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <libinput.h>]],
[[libinput_config_accel_create(0)]])],
[AC_MSG_RESULT([yes])
AC_DEFINE(HAVE_LIBINPUT_CUSTOM_ACCEL, [1],
[libinput_config_accel_create() is available])
[libinput_have_custom_accel=yes]],
[AC_MSG_RESULT([no])
[libinput_have_custom_accel=no]])
AC_MSG_CHECKING([if libinput_tablet_tool_config_pressure_range_set is available])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <libinput.h>]],
[[libinput_tablet_tool_config_pressure_range_set(0)]])],
[AC_MSG_RESULT([yes])
AC_DEFINE(HAVE_LIBINPUT_PRESURE_RANGE, [1],
[libinput_tablet_tool_config_pressure_range_set() is available])
[libinput_have_pressure_range=yes]],
[AC_MSG_RESULT([no])
[libinput_have_pressure_range=no]])
AC_MSG_CHECKING([if libinput_device_config_click_set_clickfinger_button_map is available])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <libinput.h>]],
[[libinput_device_config_click_set_clickfinger_button_map(NULL, 0)]])],
[AC_MSG_RESULT([yes])
AC_DEFINE(HAVE_LIBINPUT_CLICKFINGER_BUTTON_MAP, [1],
[libinput_device_config_click_set_clickfinger_button_map() is available])
[libinput_have_clickfinger_button_map=yes]],
[AC_MSG_RESULT([no])
[libinput_have_clickfinger_button_map=no]])
AC_MSG_CHECKING([if libinput_plugin_system_load is available])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <libinput.h>]],
[[libinput_plugin_system_load_plugins(NULL, 0)]])],
[AC_MSG_RESULT([yes])
AC_DEFINE(HAVE_LIBINPUT_PLUGINS, [1],
[libinput_plugin_system_load_plugins() is available])
[libinput_have_plugin_system=yes]],
[AC_MSG_RESULT([no])
[libinput_have_plugin_system=no]])
LIBS=$OLD_LIBS
CFLAGS=$OLD_CFLAGS
# Define a configure option for an alternate input module directory
PKG_PROG_PKG_CONFIG([0.25])
AC_ARG_WITH(xorg-module-dir,
AS_HELP_STRING([--with-xorg-module-dir=DIR],
[Default xorg module directory]),
[moduledir="$withval"],
[moduledir=`$PKG_CONFIG --variable=moduledir xorg-server`])
inputdir=${moduledir}/input
AC_SUBST(inputdir)
AC_ARG_WITH(xorg-conf-dir,
AC_HELP_STRING([--with-xorg-conf-dir=DIR],
[Default xorg.conf.d directory [[default=${prefix}/share/X11/xorg.conf.d]]]),
[xorgconfdir="$withval"],
[xorgconfdir='${prefix}/share/X11/xorg.conf.d'])
AC_SUBST(xorgconfdir)
# X Server SDK location is required to install header files
sdkdir=`$PKG_CONFIG --variable=sdkdir xorg-server`
# Workaround overriding sdkdir to be able to create a tarball when user has no
# write permission in sdkdir. See DISTCHECK_CONFIGURE_FLAGS in Makefile.am
AC_ARG_WITH([sdkdir], [], [sdkdir="$withval"])
AC_SUBST([sdkdir])
AC_CONFIG_FILES([Makefile
include/Makefile
src/Makefile
man/Makefile
test/Makefile
xorg-libinput.pc])
AC_OUTPUT
@@ -0,0 +1 @@
sdk_HEADERS = libinput-properties.h
@@ -0,0 +1,269 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright © 2015 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef _LIBINPUT_PROPERTIES_H_
#define _LIBINPUT_PROPERTIES_H_
/* Tapping enabled/disabled: BOOL, 1 value */
#define LIBINPUT_PROP_TAP "libinput Tapping Enabled"
/* Tapping default enabled/disabled: BOOL, 1 value, read-only */
#define LIBINPUT_PROP_TAP_DEFAULT "libinput Tapping Enabled Default"
/* Tap drag enabled/disabled: BOOL, 1 value */
#define LIBINPUT_PROP_TAP_DRAG "libinput Tapping Drag Enabled"
/* Tap drag default enabled/disabled: BOOL, 1 value, read-only */
#define LIBINPUT_PROP_TAP_DRAG_DEFAULT "libinput Tapping Drag Enabled Default"
/* Tap drag lock enabled/disabled: BOOL, 1 value */
#define LIBINPUT_PROP_TAP_DRAG_LOCK "libinput Tapping Drag Lock Enabled"
/* Tap drag lock default enabled/disabled: BOOL, 1 value, read-only */
#define LIBINPUT_PROP_TAP_DRAG_LOCK_DEFAULT "libinput Tapping Drag Lock Enabled Default"
/* Tap button order: BOOL, 2 values in order LRM, LMR, only one may be set
at any time */
#define LIBINPUT_PROP_TAP_BUTTONMAP "libinput Tapping Button Mapping Enabled"
/* Tap button default order: BOOL, 2 values in order LRM, LMR, read-only */
#define LIBINPUT_PROP_TAP_BUTTONMAP_DEFAULT "libinput Tapping Button Mapping Default"
/* Clickfinger button order: BOOL, 2 values in order LRM, LMR, only one may be set
at any time */
#define LIBINPUT_PROP_CLICKFINGER_BUTTONMAP "libinput Clickfinger Button Mapping Enabled"
/* Clickfinger button default order: BOOL, 2 values in order LRM, LMR, read-only */
#define LIBINPUT_PROP_CLICKFINGER_BUTTONMAP_DEFAULT "libinput Clickfinger Button Mapping Default"
/* Calibration matrix: FLOAT, 9 values of a 3x3 matrix, in rows */
#define LIBINPUT_PROP_CALIBRATION "libinput Calibration Matrix"
/* Calibration matrix: FLOAT, 9 values of a 3x3 matrix, in rows, read-only*/
#define LIBINPUT_PROP_CALIBRATION_DEFAULT "libinput Calibration Matrix Default"
/* Pointer accel speed: FLOAT, 1 value, 32 bit */
#define LIBINPUT_PROP_ACCEL "libinput Accel Speed"
/* Pointer accel speed: FLOAT, 1 value, 32 bit, read-only*/
#define LIBINPUT_PROP_ACCEL_DEFAULT "libinput Accel Speed Default"
/* Pointer accel profile: BOOL, 3 values in order adaptive, flat, custom
* only one is enabled at a time at max, read-only */
#define LIBINPUT_PROP_ACCEL_PROFILES_AVAILABLE "libinput Accel Profiles Available"
/* Pointer accel profile: BOOL, 3 values in order adaptive, flat, custom
only one is enabled at a time at max, read-only */
#define LIBINPUT_PROP_ACCEL_PROFILE_ENABLED_DEFAULT "libinput Accel Profile Enabled Default"
/* Pointer accel profile: BOOL, 3 values in order adaptive, flat, custom
only one is enabled at a time at max */
#define LIBINPUT_PROP_ACCEL_PROFILE_ENABLED "libinput Accel Profile Enabled"
/* Points for the custom accel profile: FLOAT, N values */
#define LIBINPUT_PROP_ACCEL_CUSTOM_POINTS_FALLBACK "libinput Accel Custom Fallback Points"
/* Steps for the custom accel profile: FLOAT, 1 value */
#define LIBINPUT_PROP_ACCEL_CUSTOM_STEP_FALLBACK "libinput Accel Custom Fallback Step"
/* Points for the custom accel profile: FLOAT, N values */
#define LIBINPUT_PROP_ACCEL_CUSTOM_POINTS_MOTION "libinput Accel Custom Motion Points"
/* Steps for the custom accel profile: FLOAT, 1 value */
#define LIBINPUT_PROP_ACCEL_CUSTOM_STEP_MOTION "libinput Accel Custom Motion Step"
/* Points for the custom accel profile: FLOAT, N values */
#define LIBINPUT_PROP_ACCEL_CUSTOM_POINTS_SCROLL "libinput Accel Custom Scroll Points"
/* Steps for the custom accel profile: FLOAT, 1 value */
#define LIBINPUT_PROP_ACCEL_CUSTOM_STEP_SCROLL "libinput Accel Custom Scroll Step"
/* Natural scrolling: BOOL, 1 value */
#define LIBINPUT_PROP_NATURAL_SCROLL "libinput Natural Scrolling Enabled"
/* Natural scrolling: BOOL, 1 value, read-only */
#define LIBINPUT_PROP_NATURAL_SCROLL_DEFAULT "libinput Natural Scrolling Enabled Default"
/* Send-events mode: BOOL read-only, 2 values in order disabled,
disabled-on-external-mouse */
#define LIBINPUT_PROP_SENDEVENTS_AVAILABLE "libinput Send Events Modes Available"
/* Send-events mode: BOOL, 2 values in order disabled,
disabled-on-external-mouse */
#define LIBINPUT_PROP_SENDEVENTS_ENABLED "libinput Send Events Mode Enabled"
/* Send-events mode: BOOL, 2 values in order disabled,
disabled-on-external-mouse, read-only */
#define LIBINPUT_PROP_SENDEVENTS_ENABLED_DEFAULT "libinput Send Events Mode Enabled Default"
/* Left-handed enabled/disabled: BOOL, 1 value */
#define LIBINPUT_PROP_LEFT_HANDED "libinput Left Handed Enabled"
/* Left-handed enabled/disabled: BOOL, 1 value, read-only */
#define LIBINPUT_PROP_LEFT_HANDED_DEFAULT "libinput Left Handed Enabled Default"
/* Scroll method: BOOL read-only, 3 values in order 2fg, edge, button.
shows available scroll methods */
#define LIBINPUT_PROP_SCROLL_METHODS_AVAILABLE "libinput Scroll Methods Available"
/* Scroll method: BOOL, 3 values in order 2fg, edge, button
only one is enabled at a time at max */
#define LIBINPUT_PROP_SCROLL_METHOD_ENABLED "libinput Scroll Method Enabled"
/* Scroll method: BOOL, 3 values in order 2fg, edge, button
only one is enabled at a time at max, read-only */
#define LIBINPUT_PROP_SCROLL_METHOD_ENABLED_DEFAULT "libinput Scroll Method Enabled Default"
/* Scroll button for button scrolling: 32-bit int, 1 value */
#define LIBINPUT_PROP_SCROLL_BUTTON "libinput Button Scrolling Button"
/* Scroll button for button scrolling: 32-bit int, 1 value, read-only */
#define LIBINPUT_PROP_SCROLL_BUTTON_DEFAULT "libinput Button Scrolling Button Default"
/* Scroll button lock: BOOL, 1 value, TRUE for enabled, FALSE otherwise */
#define LIBINPUT_PROP_SCROLL_BUTTON_LOCK "libinput Button Scrolling Button Lock Enabled"
/* Scroll button lock: BOOL, 1 value, TRUE for enabled, FALSE otherwise, read-only*/
#define LIBINPUT_PROP_SCROLL_BUTTON_LOCK_DEFAULT "libinput Button Scrolling Button Lock Enabled Default"
/* Scroll pixel distance: CARD32, 1 value (with implementation-defined limits) */
#define LIBINPUT_PROP_SCROLL_PIXEL_DISTANCE "libinput Scrolling Pixel Distance"
/* Scroll pixel distance: CARD32, 1 value, read-only */
#define LIBINPUT_PROP_SCROLL_PIXEL_DISTANCE_DEFAULT "libinput Scrolling Pixel Distance Default"
/* Scroll factor: FLOAT, 1 value, 32 bit */
#define LIBINPUT_PROP_SCROLL_FACTOR "libinput Scrolling Factor"
/* Scroll factor: FLOAT, 1 value, 32 bit, read-only */
#define LIBINPUT_PROP_SCROLL_FACTOR_DEFAULT "libinput Scrolling Factor Default"
/* Click method: BOOL read-only, 2 values in order buttonareas, clickfinger
shows available click methods */
#define LIBINPUT_PROP_CLICK_METHODS_AVAILABLE "libinput Click Methods Available"
/* Click method: BOOL, 2 values in order buttonareas, clickfinger
only one enabled at a time at max */
#define LIBINPUT_PROP_CLICK_METHOD_ENABLED "libinput Click Method Enabled"
/* Click method: BOOL, 2 values in order buttonareas, clickfinger
only one enabled at a time at max, read-only */
#define LIBINPUT_PROP_CLICK_METHOD_ENABLED_DEFAULT "libinput Click Method Enabled Default"
/* Middle button emulation: BOOL, 1 value */
#define LIBINPUT_PROP_MIDDLE_EMULATION_ENABLED "libinput Middle Emulation Enabled"
/* Middle button emulation: BOOL, 1 value, read-only */
#define LIBINPUT_PROP_MIDDLE_EMULATION_ENABLED_DEFAULT "libinput Middle Emulation Enabled Default"
/* Disable while typing: BOOL, 1 value */
#define LIBINPUT_PROP_DISABLE_WHILE_TYPING "libinput Disable While Typing Enabled"
/* Disable while typing: BOOL, 1 value, read-only */
#define LIBINPUT_PROP_DISABLE_WHILE_TYPING_DEFAULT "libinput Disable While Typing Enabled Default"
/* Drag lock buttons, either:
CARD8, one value, the meta lock button, or
CARD8, n * 2 values, the drag lock pairs with n being the button and n+1
the target button number */
#define LIBINPUT_PROP_DRAG_LOCK_BUTTONS "libinput Drag Lock Buttons"
/* Horizontal scroll events enabled: BOOL, 1 value (0 or 1).
* If disabled, horizontal scroll events are discarded */
#define LIBINPUT_PROP_HORIZ_SCROLL_ENABLED "libinput Horizontal Scroll Enabled"
/* Number of modes each pad mode group has available: CARD8, one for each
* pad mode group, read-only.
*/
#define LIBINPUT_PROP_TABLET_PAD_MODE_GROUPS_AVAILABLE "libinput Pad Mode Groups Modes Available"
/* Mode each pad mode group is currently in: CARD8, one for each pad mode
* group, read-only.
*/
#define LIBINPUT_PROP_TABLET_PAD_MODE_GROUPS "libinput Pad Mode Groups Modes"
/* The association of each logical button with the pad mode group: INT8,
* one for each logical button. If set to -1 the button cannot be associated
* with a mode group. read-only
*/
#define LIBINPUT_PROP_TABLET_PAD_MODE_GROUP_BUTTONS "libinput Pad Mode Group Buttons"
/* The association of each logical strip with the pad mode group: INT8,
* one for each logical strip. If set to -1 the strip cannot be associated
* with a mode group. read-only
*/
#define LIBINPUT_PROP_TABLET_PAD_MODE_GROUP_STRIPS "libinput Pad Mode Group Strips"
/* The association of each logical ring with the pad mode group: INT8,
* one for each logical ring. If set to -1 the ring cannot be associated
* with a mode group. read-only
*/
#define LIBINPUT_PROP_TABLET_PAD_MODE_GROUP_RINGS "libinput Pad Mode Group Rings"
/* Device rotation: FLOAT, 1 value, 32 bit */
#define LIBINPUT_PROP_ROTATION_ANGLE "libinput Rotation Angle"
/* Device rotation: FLOAT, 1 value, 32 bit, read-only */
#define LIBINPUT_PROP_ROTATION_ANGLE_DEFAULT "libinput Rotation Angle Default"
/* Tablet tool pressure curve: float, 8 values, 32 bit
* Value range is [0.0, 1.0], the values specify the x/y of the four
* control points for a cubic bezier curve.
* Default value: 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0
*/
#define LIBINPUT_PROP_TABLET_TOOL_PRESSURECURVE "libinput Tablet Tool Pressurecurve"
/* Tablet tool pressure range: float, 2 values, 32 bit
* Value range is [0.0, 1.0] for min and max physical pressure to map to the logical range
* Default value: 0.0 1.0
*/
#define LIBINPUT_PROP_TABLET_TOOL_PRESSURE_RANGE "libinput Tablet Tool Pressure Range"
/* Tablet tool pressure range: float, 2 values, 32 bit, read-only */
#define LIBINPUT_PROP_TABLET_TOOL_PRESSURE_RANGE_DEFAULT "libinput Tablet Tool Pressure Range Default"
/* Tablet tool area ratio: CARD32, 2 values, w and h */
#define LIBINPUT_PROP_TABLET_TOOL_AREA_RATIO "libinput Tablet Tool Area Ratio"
/* High-resolution wheel scroll events enabled: BOOL, 1 value (0 or 1).
* If disabled, high-resolution wheel scroll events are discarded */
#define LIBINPUT_PROP_HIRES_WHEEL_SCROLL_ENABLED "libinput High Resolution Wheel Scroll Enabled"
/* The tablet tool unique serial number: CARD32, 1 value, constant for the
* lifetime of the device.
*
* If this property exists and is zero, the tool does not have a unique serial
* number.
*/
#define LIBINPUT_PROP_TABLET_TOOL_SERIAL "libinput Tablet Tool Serial"
/* The tablet tool hardware ID: CARD32, 1 value, constant for the lifetime of the device.
*
* This property only exists if the device has a known tool ID.
* See libinput_tablet_tool_get_tool_id() in the libinput documentation for details.
*/
#define LIBINPUT_PROP_TABLET_TOOL_ID "libinput Tablet Tool ID"
#endif /* _LIBINPUT_PROPERTIES_H_ */
+40
View File
@@ -0,0 +1,40 @@
# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
drivermandir = $(DRIVER_MAN_DIR)
driverman_PRE = libinput.man
driverman_DATA = $(driverman_PRE:man=$(DRIVER_MAN_SUFFIX))
EXTRA_DIST = libinput.man
CLEANFILES = $(driverman_DATA)
SUFFIXES = .$(DRIVER_MAN_SUFFIX) .man
MAN_SUBSTS += \
-e 's|\@VERSION\@|$(PACKAGE_NAME) $(PACKAGE_VERSION)|g'
# String replacements in MAN_SUBSTS now come from xorg-macros.m4 via configure
.man.$(DRIVER_MAN_SUFFIX):
$(AM_V_GEN)$(SED) $(MAN_SUBSTS) < $< > $@
+612
View File
@@ -0,0 +1,612 @@
'\" t
.\" shorthand for double quote that works everywhere.
.ds q \N'34'
.TH LIBINPUT 4 2025-06-01 "@VERSION@"
.SH NAME
libinput \- libinput-based X.Org input driver
.SH SYNOPSIS
.nf
.B "Section \*qInputDevice\*q"
.BI " Identifier \*q" devname \*q
.B " Driver \*qlibinput\*q"
.BI " Option \*qDevice\*q \*q" devpath \*q
\ \ ...
.B EndSection
.fi
.SH NOTE
This is the man page for the X input driver.
If you are looking for the library documentation, go to
.B http://wayland.freedesktop.org/libinput/doc/
.SH DESCRIPTION
.B libinput
is an XLibre input driver based on libinput.
It therefore supports all input devices that libinput can handle, including
most mice, keyboards, tablets and touchscreens.
.PP
It is recommended that
.B libinput
devices are configured through the
.B InputClass
directive (refer to
.BR xorg.conf (5))
instead of manual per-device configuration.
Devices configured using the
.B InputDevice
directive in the
.BR xorg.conf (5)
file are not hot-plug capable.
.SH CONFIGURATION DETAILS
Please refer to
.BR xorg.conf (5)
for general configuration details
and for options that can be used with all input drivers.
This section only covers configuration details specific to this driver.
.PP
The following driver
.B Options
are supported:
.TP 7
.BI "Option \*qAccelProfile\*q \*q" string \*q
Sets the pointer acceleration profile to the given profile.
Permitted values are
.BR adaptive ,
.BR flat ,
.BR custom .
Not all devices support this option or all profiles.
If a profile is unsupported, the default profile for this device is used.
For a description on the profiles and their behavior,
see the libinput documentation.
.TP 7
.BI "Option \*qAccelSpeed\*q \*q" float \*q
Sets the pointer acceleration speed within the range [-1, 1].
This only applies to the flat or adaptive profile.
.TP 7
.BI "Option \*qAccelPointsFallback\*q \*q" string \*q
.TQ
.BI "Option \*qAccelPointsMotion\*q \*q" string \*q
.TQ
.BI "Option \*qAccelPointsScroll\*q \*q" string \*q
Sets the points of the Fallback/Motion/Scroll acceleration functions.
The string must be a space-separated list of
floating point non-negative numbers, e.g.,
"0.0 1.0 2.4 2.5".
This only applies to the custom profile.
See section
.B CUSTOM ACCELERATION PROFILE
.TP 7
.BI "Option \*qAccelStepFallback\*q \*q" float \*q
.TQ
.BI "Option \*qAccelStepMotion\*q \*q" float \*q
.TQ
.BI "Option \*qAccelStepScroll\*q \*q" float \*q
Sets the step between the points of the Fallback/Motion/Scroll
acceleration functions.
When a step of 0.0 is provided,
libinput's Fallback acceleration function is used.
This only applies to the custom profile.
See section
.B CUSTOM ACCELERATION PROFILE
.TP 7
.BI "Option \*qButtonMapping\*q \*q" string \*q
Sets the logical button mapping for this device, see
.BR XSetPointerMapping (3).
The string must be a space-separated list of button mappings in the order of the
logical buttons on the device, starting with button 1.
The default mapping is "1 2 3 ... 32".
A mapping of 0 deactivates the button.
Multiple buttons can have the same mapping.
Invalid mapping strings are discarded and the default mapping
is used for all buttons.
Buttons not specified in the user's mapping use the default mapping.
See section
.B BUTTON MAPPING
for more details.
.TP 7
.BI "Option \*qCalibrationMatrix\*q \*q" string \*q
A string of 9 space-separated floating point numbers, in the order
\*qa b c d e f g h i\*q.
Sets the calibration matrix to the 3x3 matrix where the first row is (abc),
the second row is (def) and the third row is (ghi).
.TP 7
.BI "Option \*qClickMethod\*q \*q" string \*q
Enables a click method.
Permitted values are
.BR none ,
.BR buttonareas ,
.BR clickfinger .
Not all devices support all methods.
If an option is unsupported, the default click method for this device is used.
.TP 7
.BI "Option \*qDisableWhileTyping\*q \*q" bool \*q
Indicates if the touchpad should be disabled while typing on the keyboard
(this does not apply to modifier keys such as Ctrl or Alt).
.TP 7
.BI "Option \*qDevice\*q \*q" string \*q
Specifies the device through which the device can be accessed.
This will generally be of the form \*q/dev/input/eventX\*q,
where X is some integer.
When using
.B InputClass
directives, this option is set by the server.
The mapping from device node to hardware is system-dependent.
Property: "Device Node" (read-only).
.TP 7
.BI "Option \*qDragLockButtons\*q \*q" "L1 B1 L2 B2 ..." \*q
Sets "drag lock buttons" that simulate a button logically down even when it has
been physically released.
To logically release a locked button,
a second click of the same button is required.
.IP
If the option is a single button number, that button acts as the
"meta" locking button for the next button number.
See section
.B BUTTON DRAG LOCK
for details.
.IP
If the option is a list of button number pairs, the first number of each
number pair is the lock button, the second number the logical button number
to be locked.
See section
.B BUTTON DRAG LOCK
for details.
.IP
For both meta and button pair configuration,
the button numbers are device button numbers, i.e. the
.B ButtonMapping
applies after drag lock.
.TP 7
.BI "Option \*qHighResolutionWheelScrolling\*q \*q" bool \*q
Disables high-resolution wheel scroll events, enabled by default. When enabled,
the driver forwards only high-resolution wheel scroll events from libinput.
When disabled, the driver forwards legacy wheel scroll events instead.
.TP 7
.BI "Option \*qHorizontalScrolling\*q \*q" bool \*q
Enables or disables horizontal scrolling.
When disabled,
this driver will discard any horizontal scroll events from libinput.
This does not disable horizontal scroll events from libinput;
it merely discards the horizontal axis from any scroll events.
Default is enabled.
.TP 7
.BI "Option \*qLeftHanded\*q \*q" bool \*q
Enables left-handed button orientation, i.e. swapping left and right buttons.
.TP 7
.BI "Option \*qMiddleEmulation\*q \*q" bool \*q
Enables middle button emulation.
When enabled, pressing the left and right
buttons simultaneously produces a middle mouse button click.
A synonym
.IP
.BI "Option \*qEmulate3Buttons\*q \*q" bool \*q
.IP
is preserved for compatibility with
.B evdev
driver, with
.BI "\*qMiddleEmulation\*q
having preference if both are set.
.TP 7
.BI "Option \*qNaturalScrolling\*q \*q" bool \*q
Enables or disables natural scrolling behavior.
.TP 7
.BI "Option \*qRotationAngle\*q \*q" float \*q
Sets the rotation angle of the device to the given angle, in degrees clockwise.
The angle must be between 0.0 (inclusive) and 360.0 (exclusive).
.TP 7
.BI "Option \*qScrollButton\*q \*q" int \*q
Designates a button as scroll button.
If the
.B ScrollMethod
is
.B button
and the button is logically down, x/y axis movement is converted into
scroll events.
.TP 7
.BI "Option \*qScrollButtonLock\*q \*q" bool \*q
Enables or disables the scroll button lock.
If enabled, the
.B ScrollButton
is considered logically down after the first click and remains down until
the second click of that button.
If disabled (the default), the
.B ScrollButton
button is considered logically down while held down and up once physically
released.
.TP 7
.BI "Option \*qScrollFactor\*q \*q" float \*q
Sets the scroll factor for scroll events. A value higher than 1.0 means faster scrolling.
Applications that don't support xi2 input will instead receive scroll button events
less or more frequently depending on the scroll factor value, instead of scrolling "smoother".
.TP 7
.BI "Option \*qScrollMethod\*q \*q" string \*q
Enables a scroll method. Permitted values are
.BR none ,
.BR twofinger ,
.BR edge ,
.BR button .
Not all devices support all options.
If an option is unsupported, the default scroll option for this device is used.
.TP 7
.BI "Option \*qScrollPixelDistance\*q \*q" int \*q
Sets the movement distance, in "pixels", required to trigger one logical
wheel click.
This option only applies to the scroll methods
.BR twofinger ,
.BR edge ,
.BR button .
See section
.B SCROLL PIXEL DISTANCE
for more details.
.TP 7
.BI "Option \*qSendEventsMode\*q \*q" (disabled|enabled|disabled-on-external-mouse) \*q
Sets the send events mode to disabled, enabled,
or "disable when an external mouse is connected".
.TP 7
.BI "Option \*qTabletToolPressureCurve\*q \*q" "x0/y0 x1/y1 x2/y2 x3/y3" \*q
Set the pressure curve for a tablet stylus to the bezier formed by the four
points.
The respective x/y coordinate must be in the [0.0, 1.0] range.
For more information see section
.B TABLET TOOL PRESSURE CURVE.
.TP 7
.BI "Option \*qTabletToolPressureRange\*q \*q" "min max" \*q
Set the pressure range for a tablet stylus to the given subset of the physical
range.
The min/max values must be in the [0.0, 1.0] range.
For example, a min of 0.3 means the tablet will send 0 pressure for anything
equal or below 30% of the physical pressure range and a max of 0.7 means
the tablet sends its maximum pressure value for any pressure equal or higher to
70% of the physical pressure range.
.TP 7
.BI "Option \*qTabletToolAreaRatio\*q \*q" "w:h" \*q
Sets the area ratio for a tablet tool.
The area always starts at the origin (0/0) and
expands to the largest available area with the specified aspect ratio.
Events outside this area are cropped to the area.
The special value "default" is used for the default mapping
(i.e. the device-native mapping).
For more information see section
.B TABLET TOOL AREA RATIO.
.TP 7
.BI "Option \*qTapping\*q \*q" bool \*q
Enables or disables tap-to-click behavior.
.TP 7
.BI "Option \*qTappingButtonMap\*q \*q" (lrm|lmr) \*q
Set the button mapping for 1/2/3-finger taps to left/right/middle or
left/middle/right, respectively.
.TP 7
.BI "Option \*qTappingDrag\*q \*q" bool \*q
Enables or disables drag during tapping behavior ("tap-and-drag").
When enabled, a tap followed by a finger held down causes a single button down
only, all motions of that finger thus translate into dragging motion.
Tap-and-drag requires option
.B Tapping
to be enabled.
.TP 7
.BI "Option \*qTappingDragLock\*q \*q" bool \*q
Enables or disables drag lock during tapping behavior.
When enabled,
a finger up during tap-and-drag will not immediately release the button.
If the finger is set down again within the timeout,
the dragging process continues.
.PP
For all options, the options are only parsed if the device supports that
configuration option.
For all options, the default value is the one used by libinput.
On configuration failure, the default value is applied.
.SH SUPPORTED PROPERTIES
.B libinput
exports runtime-configurable options as properties.
If a property listed below is not available,
the matching configuration option is not available on the device.
This however does not imply that the feature is not available on the device.
The following properties are provided by the
.B libinput
driver.
.TP 7
.B "libinput Accel Profiles Available"
3 boolean values (8 bit, 0 or 1), in order "adaptive", "flat", "custom".
Indicates which acceleration profiles are available on this device.
.TP 7
.B "libinput Accel Profile Enabled"
3 boolean values (8 bit, 0 or 1), in order "adaptive", "flat", "custom".
Indicates which acceleration profile is currently enabled on this device.
.TP 7
.B "libinput Accel Speed"
1 32-bit float value, defines the pointer speed.
Value range -1, 1.
This only applies to the flat or adaptive profile.
.TP 7
.B "libinput Accel Custom Fallback Points"
.TQ
.B "libinput Accel Custom Motion Points"
.TQ
.B "libinput Accel Custom Scroll Points"
A space-separated list of 32-bit floating point non-negative numbers, e.g.
"0.0 1.0 2.4 2.5".
Sets the points of the Fallback/Motion/Scroll acceleration functions.
This only applies to the custom profile.
See section
.B CUSTOM ACCELERATION PROFILE
.TP 7
.B "libinput Accel Custom Fallback Step"
.TQ
.B "libinput Accel Custom Motion Step"
.TQ
.B "libinput Accel Custom Scroll Step"
1 32-bit float value, sets the step between the points of the
Fallback/Motion/Scroll acceleration functions.
When a step of 0.0 is provided, libinput's Fallback acceleration
function is used.
This only applies to the custom profile.
See section
.B CUSTOM ACCELERATION PROFILE
.TP 7
.B "libinput Button Scrolling Button"
1 32-bit value. Sets the button number to use for button scrolling.
This setting is independent of the scroll method, to enable button scrolling the
method must be set to button-scrolling and a valid button must be set.
.TP 7
.B "libinput Button Scrolling Button Lock Enabled"
1 boolean value. If true, the scroll button lock is enabled.
This setting is independent of the scroll method or the scroll button, to enable
button scrolling the method must be set to button-scrolling and a valid
button must be set.
.TP 7
.B "libinput Calibration Matrix"
9 32-bit float values, representing a 3x3 calibration matrix, order is row
1, row 2, row 3
.TP 7
.B "libinput Click Methods Available"
2 boolean values (8 bit, 0 or 1), in order "buttonareas", "clickfinger".
Indicates which click methods are available on this device.
.TP 7
.B "libinput Click Methods Enabled"
2 boolean values (8 bit, 0 or 1), in order "buttonareas", "clickfinger".
Indicates which click methods are enabled on this device.
.TP 7
.B "libinput Drag Lock Buttons"
Either one 8-bit value specifying the meta drag lock button, or a list of
button pairs.
See section
.B BUTTON DRAG LOCK
for details.
.TP 7
.B "libinput High Resolution Wheel Scroll Enabled"
1 boolean value (8 bit, 0 or 1).
Indicates whether high-resolution wheel scroll events are enabled or not.
.TP 7
.B "libinput Horizontal Scroll Enabled"
1 boolean value (8 bit, 0 or 1).
Indicates whether horizontal scrolling events are enabled or not.
.TP 7
.B "libinput Left Handed Enabled"
1 boolean value (8 bit, 0 or 1).
Indicates if left-handed mode is enabled or disabled.
.TP 7
.B "libinput Middle Emulation Enabled"
1 boolean value (8 bit, 0 or 1).
Indicates if middle emulation is enabled or disabled.
.TP 7
.B "libinput Natural Scrolling Enabled"
1 boolean value (8 bit, 0 or 1).
1 enables natural scrolling.
.TP 7
.B "libinput Rotation Angle"
1 32-bit float value [0.0 to 360.0).
Sets the rotation angle of the device,
clockwise of its natural neutral position.
.TP 7
.B "libinput Scrolling Factor"
1 32-bit float value.
Sets the scroll factor for scroll events. A value higher than 1.0 means faster scrolling.
Applications that don't support xi2 input will instead receive scroll button events
less or more frequently depending on the scroll factor value, instead of scrolling "smoother".
.TP 7
.B "libinput Scroll Methods Available"
3 boolean values (8 bit, 0 or 1), in order "two-finger", "edge", "button".
Indicates which scroll methods are available on this device.
.TP 7
.B "libinput Scroll Method Enabled"
3 boolean values (8 bit, 0 or 1), in order "two-finger", "edge", "button".
Indicates which scroll method is currently enabled on this device.
.TP 7
.B "libinput Scrolling Pixel Distance"
1 32-bit value (nonzero, with additional implementation-defined range checks).
Changes the movement distance required to trigger one logical wheel click.
.TP 7
.B "libinput Send Events Modes Available"
2 boolean values (8 bit, 0 or 1), in order "disabled" and
"disabled-on-external-mouse".
Indicates which send-event modes are available on this device.
.TP 7
.B "libinput Send Events Mode Enabled"
2 boolean values (8 bit, 0 or 1), in order "disabled" and
"disabled-on-external-mouse".
Indicates which send-event mode is currently enabled on this device.
.TP 7
.B "libinput Tablet Tool Pressurecurve"
4 32-bit float values [0.0 to 1.0].
See section
.B TABLET TOOL PRESSURE CURVE
.TP 7
.B "libinput Tablet Tool Area Ratio"
2 32-bit values, corresponding to width and height.
Special value 0, 0 resets to the default ratio.
See section
.B TABLET TOOL AREA RATIO
for more information.
.TP 7
.B "libinput Tapping Enabled"
1 boolean value (8 bit, 0 or 1).
1 enables tapping.
.TP 7.
.B "libinput Tapping Button Mapping Enabled"
2 boolean value (8 bit, 0 or 1), in order "lrm" and "lmr".
Indicates which button mapping is currently enabled on this device.
.TP 7
.B "libinput Tapping Drag Lock Enabled"
1 boolean value (8 bit, 0 or 1).
1 enables drag lock during tapping.
.TP 7
.B "libinput Disable While Typing Enabled"
1 boolean value (8 bit, 0 or 1).
Indicates if disable while typing is enabled or disabled.
.PP
Most properties have a
.B "libinput <property name> Default"
equivalent that indicates the default value for this setting on this device.
.SH BUTTON MAPPING
X clients receive events with logical button numbers,
where 1, 2, 3 are usually interpreted as left, middle, right;
and logical buttons 4, 5, 6, 7 are usually interpreted
as scroll up, down, left, right.
The fourth and fifth physical buttons on a device
will thus send logical buttons 8 and 9.
The
.B ButtonMapping
option adjusts the logical button mapping, it does not affect how a physical
button is mapped to a logical button.
.PP
Traditionally, a device was set to left-handed button mode by applying a
button mapping of
.B "\*q3 2 1 ...\*q"
On systems using the
.B libinput
XLibre input driver it is recommended to use the
.B LeftHanded
option instead.
.PP
The
.B libinput
XLibre input driver does not use the button mapping after setup.
Use
.BR XSetPointerMapping (3)
to modify the button mapping at runtime.
.SH BUTTON DRAG LOCK
Button drag lock holds a button logically down even when the button itself
has been physically released since.
Button drag lock comes in two modes.
.PP
If in "meta" mode, a meta button click activates drag lock for the next
button press of any other button.
A button click in the future will keep that button held logically down
until a subsequent click of that same button.
The meta button events themselves are discarded.
A separate meta button click is required each time a drag lock should be
activated for a button in the future.
.PP
If in "pairs" mode, each button can be assigned a target locking button.
On button click, the target lock button is held logically down until the
next click of the same button.
The button events themselves are discarded
and only the target button events are sent.
.PP
This feature is provided by this driver, not by libinput.
.SH TABLET TOOL PRESSURE CURVE
The pressure curve affects how stylus pressure is reported.
By default, the hardware pressure is reported as-is.
By setting a pressure curve, the feel of the stylus can be adjusted
to be more like e.g. a pencil or a brush.
.PP
The pressure curve is a cubic Bezier curve, drawn within a normalized range
of 0.0 to 1.0 between the four points provided.
This normalized range is applied to the tablet's pressure input
so that the highest pressure maps to 1.0.
The points must have increasing x coordinates, if x0 is larger than 0.0
all pressure values lower than x0 are equivalent to y0.
If x3 is less than 1.0,
all pressure values higher than x3 are equivalent to y3.
.PP
The input for a linear curve (default) is "0.0/0.0 0.0/0.0 1.0/1.0 1.0/1.0";
a slightly depressed curve (firmer) might be
"0.0/0.0 0.05/0.0 1.0/0.95 1.0/1.0";
a slightly raised curve (softer) might be "0.0/0.0 0.0/0.05 0.95/1.0 1.0/1.0".
.PP
This feature is provided by this driver, not by libinput.
.SH TABLET TOOL AREA RATIO
By default, a tablet tool can access the whole sensor area and the tablet
area is mapped to the available screen area.
For external tablets like the Wacom Intuos series,
the height:width ratio of the tablet may be different to that of the monitor,
causing the skew of input data.
.PP
To avoid this skew of input data, an area ratio may be set to match the
ratio of the screen device.
For example, a ratio of 4:3 will reduce the available area of the tablet
to the largest available area with a ratio of 4:3.
Events within this area will scale to the tablet's announced axis range,
the area ratio is thus transparent to the X server.
Any events outside this area will send events equal to the maximum value of
that axis.
The area always starts at the device's origin in it's current rotation, i.e.,
it takes left-handed-ness into account.
.PP
This feature is provided by this driver, not by libinput.
.SH SCROLL PIXEL DISTANCE
The X server does not support per-pixel scrolling but it does support
smooth scrolling.
All scroll events however are based around a logical unit of scrolling
(traditionally corresponding to a wheel click).
It is thus not possible to scroll by 10 pixels, but it is possible for a
driver to scroll by 1/10th of a logical wheel click.
.PP
libinput provides scroll data in pixels.
The \fBScrollPixelDistance\fR option defines the amount of movement equivalent
to one wheel click.
For example, a value of 50 means the user has to move a finger by 50 pixels to
generate one logical click event and each pixel is 1/50th of a wheel click.
.SH CUSTOM ACCELERATION PROFILE
The custom pointer acceleration profile gives users full control over the
acceleration behavior at different speeds.
libinput exposes an acceleration function \fIf(x)\fP
where the x-axis is the device speed in device units per millisecond
and the y-axis is the pointer speed.
.PP
The custom acceleration function is defined using n points which are spaced
uniformly along the x-axis, starting from 0 and continuing in constant steps.
Thus the points defining the custom function are:
.EX
(0 * step, f[0]), (1 * step, f[1]), ..., ((n-1) * step, f[n-1])
.EE
When a velocity value does not lie exactly on those points,
a linear interpolation/extrapolation of the two closest points
will be calculated.
.PP
There are 3 custom acceleration functions,
which are used for different movement types:
.TS
tab(;) allbox;
l l l.
Movement type; Uses; supported by
Fallback; Catch-all default movement type; All devices
Motion; Used for pointer motion; All devices
Scroll; Used for scroll movement; Mouse, Touchpad
.TE
.PP
See libinput library documentation for more details:
https://wayland.freedesktop.org/libinput/doc/latest/pointer-acceleration.html#the-custom-acceleration-profile
.SH BUGS
This driver does not work with \fBOption \*qDevice\*q\fR set to an event
node in \fI/dev/input/by-id\fR and \fI/dev/input/by-path\fR.
This can be usually be worked by using \fBSection \*qInputClass\*q\fR with an
appropriate \fBMatch*\fR statement in the
.BR xorg.conf (5).
.SH AUTHORS
Peter Hutterer
.SH "SEE ALSO"
.BR XLibre (1),
.BR xorg.conf (5),
.BR Xserver (1),
.BR X (7)
+154
View File
@@ -0,0 +1,154 @@
project('xf86-input-libinput', 'c',
version: '25.0.1',
default_options: ['warning_level=2'],
meson_version: '>= 0.50.0')
driver_version = meson.project_version().split('.')
dir_pkgconf = get_option('prefix') / get_option('libdir') / 'pkgconfig'
dir_man4 = get_option('prefix') / get_option('mandir') / 'man4'
cc = meson.get_compiler('c')
cflags = [
'-Wno-unused-parameter',
'-Wno-sign-compare', # lots of work to get rid of this
'-Wmissing-prototypes',
'-Wstrict-prototypes',
'-Wlogical-op',
'-Wpointer-arith',
'-Wuninitialized',
'-Winit-self',
'-Wstrict-prototypes',
'-Wimplicit-fallthrough',
'-Wredundant-decls',
'-Wincompatible-pointer-types',
'-Wformat=2',
'-Wno-missing-field-initializers',
'-Wmissing-declarations',
'-fvisibility=hidden',
]
add_project_arguments(cc.get_supported_arguments(cflags), language: 'c')
pkgconfig = import('pkgconfig')
dep_xserver = dependency('xorg-server', version: '>= 1.19')
dep_xproto = dependency('xproto')
dep_inputproto = dependency('inputproto', version: '>= 2.3.99.1')
dep_libinput = dependency('libinput', version: '>= 1.11.0')
config_h = configuration_data()
config_h.set('PACKAGE_VERSION_MAJOR', driver_version[0])
config_h.set('PACKAGE_VERSION_MINOR', driver_version[1])
config_h.set('PACKAGE_VERSION_PATCHLEVEL', driver_version[2])
if cc.has_function('libinput_device_config_scroll_get_button_lock',
dependencies: dep_libinput)
config_h.set('HAVE_LIBINPUT_SCROLL_BUTTON_LOCK', 1)
endif
if cc.has_function('libinput_event_pointer_get_scroll_value_v120',
dependencies: dep_libinput)
config_h.set('HAVE_LIBINPUT_AXIS_VALUE_V120', 1)
endif
if cc.has_function('libinput_config_accel_create',
dependencies: dep_libinput)
config_h.set('HAVE_LIBINPUT_CUSTOM_ACCEL', 1)
endif
if cc.has_function('libinput_tablet_tool_config_pressure_range_set',
dependencies: dep_libinput)
config_h.set('HAVE_LIBINPUT_PRESSURE_RANGE', 1)
endif
if cc.has_function('libinput_device_config_click_set_clickfinger_button_map',
dependencies: dep_libinput)
config_h.set('HAVE_LIBINPUT_CLICKFINGER_BUTTON_MAP', 1)
endif
if cc.has_header_symbol('libinput.h', 'LIBINPUT_LED_COMPOSE',
dependencies: dep_libinput)
config_h.set('HAVE_LIBINPUT_COMPOSE_AND_KANA', 1)
endif
if cc.has_function('libinput_plugin_system_load_plugins', dependencies: dep_libinput)
config_h.set('HAVE_LIBINPUT_PLUGINS', 1)
endif
dir_headers = get_option('sdkdir')
if dir_headers == ''
dir_headers = dep_xserver.get_pkgconfig_variable('sdkdir')
endif
dir_xorg_module = get_option('xorg-module-dir')
if dir_xorg_module == ''
dir_xorg_module = dep_xserver.get_pkgconfig_variable('moduledir') / 'input'
endif
dir_xorg_conf = get_option('xorg-conf-dir')
if dir_xorg_conf == ''
dir_xorg_conf = dep_xserver.get_pkgconfig_variable('sysconfigdir')
endif
libbezier = static_library('bezier', ['src/bezier.c', 'src/bezier.h'])
dep_libbezier = declare_dependency(link_with: libbezier)
libdraglock = static_library('draglock', ['src/draglock.c', 'src/draglock.h'])
dep_libdraglock = declare_dependency(link_with: libdraglock)
dep_drivers = [
dep_xserver,
dep_xproto,
dep_inputproto,
dep_libinput,
dep_libbezier,
dep_libdraglock,
]
driver_src = ['src/xf86libinput.c', 'src/util-strings.c']
driver_lib = shared_module(
'libinput_drv',
driver_src,
name_prefix: '', # we want libinput_drv.so, not liblibinput_drv.so
include_directories: include_directories('include'),
dependencies: dep_drivers,
install: true,
install_dir: dir_xorg_module,
)
test_bezier = executable('test-bezier',
['test/test-bezier.c'],
dependencies: dep_libbezier,
include_directories: include_directories('src'),
install: false)
test('test-bezier', test_bezier)
test_draglock = executable('test-draglock',
['test/test-draglock.c'],
dependencies: dep_libdraglock,
include_directories: include_directories('src'),
install: false)
test('test-draglock', test_draglock)
conf_pkgconf = configuration_data()
conf_pkgconf.set('PACKAGE_VERSION', meson.project_version())
conf_pkgconf.set('sdkdir', dir_headers)
configure_file(
input: 'xorg-libinput.pc.in',
output: 'xorg-libinput.pc',
configuration: conf_pkgconf,
install_dir: dir_pkgconf,
)
config_man = configuration_data()
config_man.set('VERSION', '@0@ @1@'.format(meson.project_name(), meson.project_version()))
configure_file(
input: 'man/libinput.man',
output: 'libinput.4',
configuration: config_man,
install_dir: dir_man4
)
install_headers('include/libinput-properties.h', install_dir: dir_headers)
install_data('conf/40-libinput.conf', install_dir: dir_xorg_conf)
# Now generate config.h
configure_file(output: 'config.h', configuration: config_h)
+15
View File
@@ -0,0 +1,15 @@
option('sdkdir',
type: 'string',
value: '',
description: 'Directory to install header files in [default=from xorg-server pkgconf]',
)
option('xorg-module-dir',
type : 'string',
value : '',
description : 'Default xorg module directory [default=from xorg-server pkgconf]',
)
option('xorg-conf-dir',
type : 'string',
value : '',
description : 'Default xorg.conf.d directory [default=from xorg-server pkgconfig]'
)
+45
View File
@@ -0,0 +1,45 @@
# Copyright 2005 Adam Jackson.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# on the rights to use, copy, modify, merge, publish, distribute, sub
# license, and/or sell copies of the Software, and to permit persons to whom
# the Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
# ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# this is obnoxious:
# -module lets us name the module exactly how we want
# -avoid-version prevents gratuitous .0.0.0 version numbers on the end
# _ladir passes a dummy rpath to libtool so the thing will actually link
# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
AM_CFLAGS = $(XORG_CFLAGS) $(CWARNFLAGS)
AM_CPPFLAGS =-I$(top_srcdir)/include $(LIBINPUT_CFLAGS)
libinput_drv_la_LTLIBRARIES = libinput_drv.la
libinput_drv_la_LDFLAGS = -module -avoid-version
libinput_drv_la_LIBADD = $(LIBINPUT_LIBS) libdraglock.la libbezier.la -lm
libinput_drv_ladir = @inputdir@
libinput_drv_la_SOURCES = \
xf86libinput.c \
util-macros.h \
util-strings.h \
util-strings.c \
$(NULL)
noinst_LTLIBRARIES = libdraglock.la libbezier.la
libdraglock_la_SOURCES = draglock.c draglock.h
libbezier_la_SOURCES = bezier.c bezier.h
+176
View File
@@ -0,0 +1,176 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright © 2016 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "config.h"
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include "bezier.h"
const struct bezier_control_point bezier_defaults[4] = {
{ 0.0, 0.0 },
{ 0.0, 0.0 },
{ 1.0, 1.0 },
{ 1.0, 1.0 },
};
struct point {
int x, y;
};
/**
* de Casteljau's algorithm. See this page here
* https://pomax.github.io/bezierinfo/#extended
*
* To play with bezier curve shapes, I used
* http://cubic-bezier.com/
*/
static struct point
decasteljau(const struct point *controls,
size_t ncontrols,
double t)
{
struct point new_controls[ncontrols];
if (ncontrols == 1)
return controls[0];
for (int i = 0; i < ncontrols - 1; i++) {
new_controls[i].x = (1.0 - t) * controls[i].x + t * controls[i + 1].x;
new_controls[i].y = (1.0 - t) * controls[i].y + t * controls[i + 1].y;
}
return decasteljau(new_controls, ncontrols - 1, t);
}
/**
* Given a Bézier curve defined by the control points, reduce the curve to
* one with ncurve_points.
*/
static void
flatten_curve(const struct point *controls,
size_t ncontrols,
struct point *curve,
size_t ncurve_points)
{
ncurve_points--; /* make sure we end up with 100/100 as last point */
for (int i = 0; i <= ncurve_points; i++) {
double t = 1.0 * i/ncurve_points;
struct point p;
p = decasteljau(controls, ncontrols, t);
curve[i] = p;
}
}
/**
* Calculate line through a and b, set curve[x] for each x between
* [a.x, b.x].
*
* Note: pcurve must be at least b.x size.
*/
static void
line_between(struct point a, struct point b,
struct point *curve, size_t curve_sz)
{
double slope;
double offset;
assert(b.x < curve_sz);
if (a.x == b.x) {
curve[a.x].x = a.x;
curve[a.x].y = a.y;
return;
}
slope = (double)(b.y - a.y)/(b.x - a.x);
offset = a.y - slope * a.x;
for (int x = a.x; x <= b.x; x++) {
struct point p;
p.x = x;
p.y = slope * x + offset;
curve[x] = p;
}
}
bool
cubic_bezier(const struct bezier_control_point controls[4],
int *bezier_out,
size_t bezier_sz)
{
const int nsegments = 50;
const int range = bezier_sz - 1;
struct point curve[nsegments];
struct point bezier[bezier_sz];
struct point zero = { 0, 0 },
max = { range, range};
/* Scale control points into the [0, bezier_sz) range */
struct point ctrls[4];
for (int i = 0; i < 4; i++) {
if (controls[i].x < 0.0 || controls[i].x > 1.0 ||
controls[i].y < 0.0 || controls[i].y > 1.0)
return false;
ctrls[i].x = controls[i].x * range;
ctrls[i].y = controls[i].y * range;
}
for (int i = 0; i < 3; i++) {
if (ctrls[i].x > ctrls[i+1].x)
return false;
}
/* Reduce curve to nsegments, because this isn't a drawing program */
flatten_curve(ctrls, 4, curve, nsegments);
/* we now have nsegments points in curve that represent the bezier
curve (already in the [0, bezier_sz) range). Run through the
points and draw a straight line between each point and voila, we
have our curve.
If the first control points (x0/y0) is not at x == 0 or the last
control point (x3/y3) is not at the max value, draw a line
between from 0/0 to x0/y0 and from x3/y3 to xmax/y3.
*/
line_between(zero, curve[0], bezier, bezier_sz);
for (int i = 0; i < nsegments - 1; i++)
line_between(curve[i], curve[i+1], bezier, bezier_sz);
if (curve[nsegments - 1].x < max.x)
line_between(curve[nsegments - 1], max, bezier, bezier_sz);
for (int i = 0; i < bezier_sz; i++)
bezier_out[i] = bezier[i].y;
return true;
}
+68
View File
@@ -0,0 +1,68 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright © 2016 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "config.h"
#ifndef BEZIER_H
#define BEZIER_H
#include <stdlib.h>
#include <stdbool.h>
struct bezier_control_point {
double x, y;
};
extern const struct bezier_control_point bezier_defaults[4];
/**
* Given four control points in the range [(0.0/0.0), (1.0/1.0)]
* construct a Bézier curve.
*
* ^
*1.0 | c2 ______ c3
* | _/
* | /
* |c1 /
* | /
* | /
* |/_________________>
* c0 1.0
*
* This function requires that c[i].x <= c[i+1].x
*
* The curve is mapped into a canvas size [0, bezier_sz)². For each x
* coordinate in [0, bezier_sz), the matching y coordinate is thus
* bezier[x].
*
* In other words, if you have a range [0,2048) input possible values,
* the output is a list of 2048 points in a [0, 2048) range.
*
* @return true on success, false otherwise
*/
bool
cubic_bezier(const struct bezier_control_point controls[4],
int *bezier,
size_t bezier_sz);
#endif
+281
View File
@@ -0,0 +1,281 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright © 2015 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "config.h"
#include "draglock.h"
#include <string.h>
#include <stdlib.h>
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
static int
draglock_parse_config(struct draglock *dl, const char *config)
{
int button = 0, target = 0;
const char *str = NULL;
char *end_str = NULL;
int pairs[DRAGLOCK_MAX_BUTTONS] = {0};
if (!config)
return 0;
/* empty string disables drag lock */
if (*config == '\0') {
dl->mode = DRAGLOCK_DISABLED;
return 0;
}
/* check for a single-number string first, config is "<int>" */
button = strtol(config, &end_str, 10);
if (*end_str == '\0') {
if (button < 0 || button >= DRAGLOCK_MAX_BUTTONS)
return 1;
/* we allow for button 0 so stacked xorg.conf.d snippets can
* disable the config again */
if (button == 0) {
dl->mode = DRAGLOCK_DISABLED;
return 0;
}
return draglock_set_meta(dl, button);
}
dl->mode = DRAGLOCK_DISABLED;
/* check for a set of button pairs, config is
* "<int> <int> <int> <int>..." */
str = config;
while (*str != '\0') {
button = strtol(str, &end_str, 10);
if (*end_str == '\0')
return 1;
str = end_str;
target = strtol(str, &end_str, 10);
if (end_str == str)
return 1;
if (button <= 0 || button >= DRAGLOCK_MAX_BUTTONS || target >= DRAGLOCK_MAX_BUTTONS)
return 1;
pairs[button] = target;
str = end_str;
}
return draglock_set_pairs(dl, pairs, ARRAY_SIZE(pairs));
}
int
draglock_init_from_string(struct draglock *dl, const char *config)
{
dl->mode = DRAGLOCK_DISABLED;
dl->meta_button = 0;
dl->meta_state = false;
memset(dl->lock_pair, 0, sizeof(dl->lock_pair));
memset(dl->lock_state, 0, sizeof(dl->lock_state));
return draglock_parse_config(dl, config);
}
enum draglock_mode
draglock_get_mode(const struct draglock *dl)
{
return dl->mode;
}
int
draglock_get_meta(const struct draglock *dl)
{
if (dl->mode == DRAGLOCK_META)
return dl->meta_button;
return 0;
}
size_t
draglock_get_pairs(const struct draglock *dl, int *array, size_t nelem)
{
unsigned int i;
size_t last = 0;
if (dl->mode != DRAGLOCK_PAIRS)
return 0;
/* size 1 array with the meta button */
if (dl->meta_button) {
*array = dl->meta_button;
return 1;
}
/* size N array with a[0] == 0, the rest ordered by button number */
memset(array, 0, nelem * sizeof(array[0]));
for (i = 0; i < nelem && i < ARRAY_SIZE(dl->lock_pair); i++) {
array[i] = dl->lock_pair[i];
if (array[i] != 0 && i > last)
last = i;
}
return last;
}
int
draglock_set_meta(struct draglock *dl, int meta_button)
{
if (meta_button < 0 || meta_button >= DRAGLOCK_MAX_BUTTONS)
return 1;
dl->meta_button = meta_button;
dl->mode = meta_button ? DRAGLOCK_META : DRAGLOCK_DISABLED;
return 0;
}
int
draglock_set_pairs(struct draglock *dl, const int *array, size_t nelem)
{
unsigned int i;
if (nelem == 0 || array[0] != 0)
return 1;
for (i = 0; i < nelem; i++) {
if (array[i] < 0 || array[i] >= DRAGLOCK_MAX_BUTTONS)
return 1;
}
dl->mode = DRAGLOCK_DISABLED;
for (i = 0; i < nelem; i++) {
dl->lock_pair[i] = array[i];
if (dl->lock_pair[i])
dl->mode = DRAGLOCK_PAIRS;
}
return 0;
}
static int
draglock_filter_meta(struct draglock *dl, int *button, int *press)
{
int b = *button,
is_press = *press;
if (b == dl->meta_button) {
if (is_press)
dl->meta_state = true;
*button = 0;
return 0;
}
switch (dl->lock_state[b]) {
case DRAGLOCK_BUTTON_STATE_NONE:
if (dl->meta_state && is_press) {
dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_DOWN_1;
dl->meta_state = false;
}
break;
case DRAGLOCK_BUTTON_STATE_DOWN_1:
if (!is_press) {
dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_UP_1;
b = 0;
}
break;
case DRAGLOCK_BUTTON_STATE_UP_1:
if (is_press) {
dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_DOWN_2;
b = 0;
}
break;
case DRAGLOCK_BUTTON_STATE_DOWN_2:
if (!is_press) {
dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_NONE;
}
break;
}
*button = b;
return 0;
}
static int
draglock_filter_pair(struct draglock *dl, int *button, int *press)
{
int b = *button,
is_press = *press;
if (dl->lock_pair[b] == 0)
return 0;
switch (dl->lock_state[b]) {
case DRAGLOCK_BUTTON_STATE_NONE:
if (is_press) {
dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_DOWN_1;
b = dl->lock_pair[b];
}
break;
case DRAGLOCK_BUTTON_STATE_DOWN_1:
if (!is_press) {
dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_UP_1;
b = 0;
}
break;
case DRAGLOCK_BUTTON_STATE_UP_1:
if (is_press) {
dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_DOWN_2;
b = 0;
}
break;
case DRAGLOCK_BUTTON_STATE_DOWN_2:
if (!is_press) {
dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_NONE;
b = dl->lock_pair[b];
}
break;
}
*button = b;
return 0;
}
int
draglock_filter_button(struct draglock *dl, int *button, int *is_press)
{
if (*button == 0)
return 0;
switch(dl->mode) {
case DRAGLOCK_DISABLED:
return 0;
case DRAGLOCK_META:
return draglock_filter_meta(dl, button, is_press);
case DRAGLOCK_PAIRS:
return draglock_filter_pair(dl, button, is_press);
default:
abort();
break;
}
return 0;
}
+158
View File
@@ -0,0 +1,158 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright © 2015 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "config.h"
#ifndef DRAGLOCK_H
#define DRAGLOCK_H 1
#include <stdbool.h>
#include <stdlib.h>
/* 32 buttons are enough for everybody™
* Note that this is the limit of physical buttons as well as the highest
* allowed target button.
*/
#define DRAGLOCK_MAX_BUTTONS 32
enum draglock_mode
{
DRAGLOCK_DISABLED,
DRAGLOCK_META,
DRAGLOCK_PAIRS
};
enum draglock_button_state
{
DRAGLOCK_BUTTON_STATE_NONE,
DRAGLOCK_BUTTON_STATE_DOWN_1,
DRAGLOCK_BUTTON_STATE_UP_1,
DRAGLOCK_BUTTON_STATE_DOWN_2,
};
struct draglock
{
enum draglock_mode mode;
int meta_button; /* meta key to lock any button */
bool meta_state; /* meta_button state */
unsigned int lock_pair[DRAGLOCK_MAX_BUTTONS + 1];/* specify a meta/lock pair */
enum draglock_button_state lock_state[DRAGLOCK_MAX_BUTTONS + 1]; /* state of any locked buttons */
};
/**
* Initialize the draglock struct based on the config string. The string is
* either a single number to configure DRAGLOCK_META mode or a list of
* number pairs, with pair[0] as button and pair[1] as target lock number to
* configure DRAGLOCK_PAIRS mode.
*
* If config is NULL, the empty string, "0" or an even-numbered list of 0,
* the drag lock mode is DRAGLOCK_DISABLED.
*
* @return 0 on success or nonzero on error
*/
int
draglock_init_from_string(struct draglock *dl, const char *config);
/**
* Get the current drag lock mode.
*
* If the mode is DRAGLOCK_META, a meta button click will cause the next
* subsequent button click to be held logically down until the release of
* the second button click of that same button. Events from the meta button
* are always discarded.
*
* If the mode is DRAGLOCK_PAIRS, any button may be configured with a
* 'target' button number. A click of that button causes the target button
* to be held logically down until the release of the second button click.
*/
enum draglock_mode
draglock_get_mode(const struct draglock *dl);
/**
* @return the meta button number or 0 if the current mode is not
* DRAGLOCK_META.
*/
int
draglock_get_meta(const struct draglock *dl);
/**
* Get the drag lock button mapping pairs. The array is filled with the
* button number as index and the mapped target button number as value, i.e.
* array[3] == 8 means button 3 will draglock button 8.
*
* A value of 0 indicates draglock is disabled for that button.
*
* @note Button numbers start at 1, array[0] is always 0.
*
* @param[in|out] array Caller-allocated array to hold the button mappings.
* @param[in] nelem Maximum number of elements in array
*
* @return The number of valid elements in array or 0 if the current mode is
* not DRAGLOCK_PAIRS
*/
size_t
draglock_get_pairs(const struct draglock *dl, int *array, size_t nelem);
/**
* Set the drag lock config to the DRAGLOCK_META mode, with the given
* button as meta button.
*
* If the button is 0 the mode becomes DRAGLOCK_DISABLED.
*
* @return 0 on success, nonzero otherwise
*/
int
draglock_set_meta(struct draglock *dl, int meta_button);
/**
* Set the drag lock config to the DRAGLOCK_PAIRS mode. The array
* must be filled with the button number as index and the mapped target
* button number as value, i.e.
* array[3] == 8 means button 3 will draglock button 8.
*
* A value of 0 indicates draglock is disabled for that button. If all
* buttons are 0, the mode becomes DRAGLOCK_DISABLED.
*
* @note Button numbers start at 1, array[0] is always 0.
*
* @return 0 on successor nonzero otherwise
*/
int
draglock_set_pairs(struct draglock *dl, const int *array, size_t nelem);
/**
* Process the given button event through the drag lock state machine.
* If the event is to be discarded by the caller, button is set to 0.
* Otherwise, button is set to the button event to process and is_press is
* set to the button state to process.
*
* @param[in|out] button The button number to process
* @param[in|out] is_press nonzero for press, zero for release
*
* @return 0 on success or 1 on error
*/
int
draglock_filter_button(struct draglock *dl, int *button, int *is_press);
#endif /* DRAGLOCK_H */
+65
View File
@@ -0,0 +1,65 @@
/*
* Copyright © 2008-2011 Kristian Høgsberg
* Copyright © 2011 Intel Corporation
* Copyright © 2013-2015 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include "config.h"
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
/**
* Iterate through the array _arr, assigning the variable elem to each
* element. elem only exists within the loop.
*/
#define ARRAY_FOR_EACH(_arr, _elem) \
for (__typeof__((_arr)[0]) *_elem = _arr; \
_elem < (_arr) + ARRAY_LENGTH(_arr); \
_elem++)
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define ANSI_HIGHLIGHT "\x1B[0;1;39m"
#define ANSI_RED "\x1B[0;31m"
#define ANSI_GREEN "\x1B[0;32m"
#define ANSI_YELLOW "\x1B[0;33m"
#define ANSI_BLUE "\x1B[0;34m"
#define ANSI_MAGENTA "\x1B[0;35m"
#define ANSI_CYAN "\x1B[0;36m"
#define ANSI_BRIGHT_RED "\x1B[0;31;1m"
#define ANSI_BRIGHT_GREEN "\x1B[0;32;1m"
#define ANSI_BRIGHT_YELLOW "\x1B[0;33;1m"
#define ANSI_BRIGHT_BLUE "\x1B[0;34;1m"
#define ANSI_BRIGHT_MAGENTA "\x1B[0;35;1m"
#define ANSI_BRIGHT_CYAN "\x1B[0;36;1m"
#define ANSI_NORMAL "\x1B[0m"
#define ANSI_UP "\x1B[%dA"
#define ANSI_DOWN "\x1B[%dB"
#define ANSI_RIGHT "\x1B[%dC"
#define ANSI_LEFT "\x1B[%dD"
#define CASE_RETURN_STRING(a) case a: return #a
#define _fallthrough_ __attribute__((fallthrough))
+246
View File
@@ -0,0 +1,246 @@
/*
* Copyright © 2008 Kristian Høgsberg
* Copyright © 2013-2015 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#define _GNU_SOURCE
#include "util-strings.h"
/**
* Return the next word in a string pointed to by state before the first
* separator character. Call repeatedly to tokenize a whole string.
*
* @param state Current state
* @param len String length of the word returned
* @param separators List of separator characters
*
* @return The first word in *state, NOT null-terminated
*/
static const char *
next_word(const char **state, size_t *len, const char *separators)
{
const char *next = *state;
size_t l;
if (!*next)
return NULL;
next += strspn(next, separators);
if (!*next) {
*state = next;
return NULL;
}
l = strcspn(next, separators);
*state = next + l;
*len = l;
return next;
}
/**
* Return a null-terminated string array with the contents of argv
* duplicated.
*
* Use strv_free() to free the array.
*
* @return A null-terminated string array or NULL on errors
*/
char**
strv_from_argv(int argc, char **argv)
{
char **strv = NULL;
assert(argc >= 0);
if (argc == 0)
return NULL;
strv = zalloc((argc + 1) * sizeof *strv);
for (int i = 0; i < argc; i++) {
char *copy = safe_strdup(argv[i]);
if (!copy) {
strv_free(strv);
return NULL;
}
strv[i] = copy;
}
return strv;
}
/**
* Return a null-terminated string array with the tokens in the input
* string, e.g. "one two\tthree" with a separator list of " \t" will return
* an array [ "one", "two", "three", NULL ] and num elements 3.
*
* Use strv_free() to free the array.
*
* Another example:
* result = strv_from_string("+1-2++3--4++-+5-+-", "+-", &nelem)
* result == [ "1", "2", "3", "4", "5", NULL ] and nelem == 5
*
* @param in Input string
* @param separators List of separator characters
* @param num_elements Number of elements found in the input string
*
* @return A null-terminated string array or NULL on errors
*/
char **
strv_from_string(const char *in, const char *separators, size_t *num_elements)
{
assert(in != NULL);
const char *s = in;
size_t l, nelems = 0;
while (next_word(&s, &l, separators) != NULL)
nelems++;
if (nelems == 0) {
*num_elements = 0;
return NULL;
}
size_t strv_len = nelems + 1; /* NULL-terminated */
char **strv = calloc(strv_len, sizeof(*strv));
if (!strv)
return NULL;
size_t idx = 0;
const char *word;
s = in;
while ((word = next_word(&s, &l, separators)) != NULL) {
char *copy = strndup(word, l);
if (!copy) {
strv_free(strv);
*num_elements = 0;
return NULL;
}
strv[idx++] = copy;
}
*num_elements = nelems;
return strv;
}
/**
* Return a newly allocated string with all elements joined by the
* joiner, same as Python's string.join() basically.
* A strv of ["one", "two", "three", NULL] with a joiner of ", " results
* in "one, two, three".
*
* An empty strv ([NULL]) returns NULL, same for passing NULL as either
* argument.
*
* @param strv Input string array
* @param joiner Joiner between the elements in the final string
*
* @return A null-terminated string joining all elements
*/
char *
strv_join(char **strv, const char *joiner)
{
char **s;
char *str;
size_t slen = 0;
size_t count = 0;
if (!strv || !joiner)
return NULL;
if (strv[0] == NULL)
return NULL;
for (s = strv, count = 0; *s; s++, count++) {
slen += strlen(*s);
}
assert(slen < 1000);
assert(strlen(joiner) < 1000);
assert(count > 0);
assert(count < 100);
slen += (count - 1) * strlen(joiner);
str = zalloc(slen + 1); /* trailing \0 */
for (s = strv; *s; s++) {
strcat(str, *s);
--count;
if (count > 0)
strcat(str, joiner);
}
return str;
}
/**
* Return a pointer to the basename within filename.
* If the filename the empty string or a directory (i.e. the last char of
* filename is '/') NULL is returned.
*/
const char *
safe_basename(const char *filename)
{
const char *basename;
if (*filename == '\0')
return NULL;
basename = strrchr(filename, '/');
if (basename == NULL)
return filename;
if (*(basename + 1) == '\0')
return NULL;
return basename + 1;
}
/**
* Similar to basename() but returns the trunk only without the (last)
* trailing suffix, so that:
*
* - foo.c returns foo
* - foo.a.b returns foo.a
* - foo returns foo
* - foo/ returns ""
*
* @return an allocated string representing the trunk name of the file
*/
char *
trunkname(const char *filename)
{
const char *base = safe_basename(filename);
char *suffix;
if (base == NULL)
return safe_strdup("");
suffix = rindex(base, '.');
if (suffix == NULL)
return safe_strdup(base);
else
return strndup(base, suffix-base);
}
+395
View File
@@ -0,0 +1,395 @@
/*
* Copyright © 2008 Kristian Høgsberg
* Copyright © 2013-2015 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdarg.h>
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#ifdef HAVE_XLOCALE_H
#include <xlocale.h>
#endif
#include "util-macros.h"
static inline bool
streq(const char *str1, const char *str2)
{
/* one NULL, one not NULL is always false */
if (str1 && str2)
return strcmp(str1, str2) == 0;
return str1 == str2;
}
static inline bool
strneq(const char *str1, const char *str2, int n)
{
/* one NULL, one not NULL is always false */
if (str1 && str2)
return strncmp(str1, str2, n) == 0;
return str1 == str2;
}
static inline void *
zalloc(size_t size)
{
void *p;
/* We never need to alloc anything more than 1,5 MB so we can assume
* if we ever get above that something's going wrong */
if (size > 1536 * 1024)
assert(!"bug: internal malloc size limit exceeded");
p = calloc(1, size);
if (!p)
abort();
return p;
}
/**
* strdup guaranteed to succeed. If the input string is NULL, the output
* string is NULL. If the input string is a string pointer, we strdup or
* abort on failure.
*/
static inline char*
safe_strdup(const char *str)
{
char *s;
if (!str)
return NULL;
s = strdup(str);
if (!s)
abort();
return s;
}
static inline bool
safe_atoi_base(const char *str, int *val, int base)
{
char *endptr;
long v;
assert(base == 10 || base == 16 || base == 8);
errno = 0;
v = strtol(str, &endptr, base);
if (errno > 0)
return false;
if (str == endptr)
return false;
if (*str != '\0' && *endptr != '\0')
return false;
if (v > INT_MAX || v < INT_MIN)
return false;
*val = v;
return true;
}
static inline bool
safe_atoi(const char *str, int *val)
{
return safe_atoi_base(str, val, 10);
}
static inline bool
safe_atou_base(const char *str, unsigned int *val, int base)
{
char *endptr;
unsigned long v;
assert(base == 10 || base == 16 || base == 8);
errno = 0;
v = strtoul(str, &endptr, base);
if (errno > 0)
return false;
if (str == endptr)
return false;
if (*str != '\0' && *endptr != '\0')
return false;
if ((long)v < 0)
return false;
*val = v;
return true;
}
static inline bool
safe_atou(const char *str, unsigned int *val)
{
return safe_atou_base(str, val, 10);
}
static inline bool
safe_atod(const char *str, double *val)
{
char *endptr;
double v;
#ifdef HAVE_LOCALE_H
locale_t c_locale;
#endif
size_t slen = strlen(str);
/* We don't have a use-case where we want to accept hex for a double
* or any of the other values strtod can parse */
for (size_t i = 0; i < slen; i++) {
char c = str[i];
if (isdigit(c))
continue;
switch(c) {
case '+':
case '-':
case '.':
break;
default:
return false;
}
}
#ifdef HAVE_LOCALE_H
/* Create a "C" locale to force strtod to use '.' as separator */
c_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
if (c_locale == (locale_t)0)
return false;
errno = 0;
v = strtod_l(str, &endptr, c_locale);
freelocale(c_locale);
#else
/* No locale support in provided libc, assume it already uses '.' */
errno = 0;
v = strtod(str, &endptr);
#endif
if (errno > 0)
return false;
if (str == endptr)
return false;
if (*str != '\0' && *endptr != '\0')
return false;
if (v != 0.0 && !isnormal(v))
return false;
*val = v;
return true;
}
char **strv_from_argv(int argc, char **argv);
char **strv_from_string(const char *in, const char *separator, size_t *num_elements);
char *strv_join(char **strv, const char *joiner);
static inline void
strv_free(char **strv) {
char **s = strv;
if (!strv)
return;
while (*s != NULL) {
free(*s);
*s = (char*)0x1; /* detect use-after-free */
s++;
}
free (strv);
}
/**
* parse a string containing a list of doubles into a double array.
*
* @param in string to parse
* @param separator string used to separate double in list e.g. ","
* @param result double array
* @param length length of double array
* @return true when parsed successfully otherwise false
*/
static inline double *
double_array_from_string(const char *in,
const char *separator,
size_t *length)
{
double *result = NULL;
*length = 0;
size_t nelem;
char **strv = strv_from_string(in, separator, &nelem);
if(!strv)
return result;
double *numv = calloc(nelem, sizeof(double));
if (!numv)
goto out;
for (size_t idx = 0; idx < nelem; idx++) {
double val;
if (!safe_atod(strv[idx], &val))
goto out;
numv[idx] = val;
}
result = numv;
numv = NULL;
*length = nelem;
out:
strv_free(strv);
free(numv);
return result;
}
struct key_value_str{
char *key;
char *value;
};
struct key_value_double {
double key;
double value;
};
static inline ssize_t
kv_double_from_string(const char *string,
const char *pair_separator,
const char *kv_separator,
struct key_value_double **result_out)
{
struct key_value_double *result = NULL;
if (!pair_separator || pair_separator[0] == '\0' ||
!kv_separator || kv_separator[0] == '\0')
return -1;
size_t npairs;
char **pairs = strv_from_string(string, pair_separator, &npairs);
if (!pairs || npairs == 0)
goto error;
result = zalloc(npairs * sizeof *result);
for (size_t idx = 0; idx < npairs; idx++) {
char *pair = pairs[idx];
size_t nelem;
char **kv = strv_from_string(pair, kv_separator, &nelem);
double k, v;
if (!kv || nelem != 2 ||
!safe_atod(kv[0], &k) ||
!safe_atod(kv[1], &v)) {
strv_free(kv);
goto error;
}
result[idx].key = k;
result[idx].value = v;
strv_free(kv);
}
strv_free(pairs);
*result_out = result;
return npairs;
error:
strv_free(pairs);
free(result);
return -1;
}
/**
* Strip any of the characters in what from the beginning and end of the
* input string.
*
* @return a newly allocated string with none of "what" at the beginning or
* end of string
*/
static inline char *
strstrip(const char *input, const char *what)
{
char *str, *last;
str = safe_strdup(&input[strspn(input, what)]);
last = str;
for (char *c = str; *c != '\0'; c++) {
if (!strchr(what, *c))
last = c + 1;
}
*last = '\0';
return str;
}
/**
* Return true if str ends in suffix, false otherwise. If the suffix is the
* empty string, strendswith() always returns false.
*/
static inline bool
strendswith(const char *str, const char *suffix)
{
size_t slen = strlen(str);
size_t suffixlen = strlen(suffix);
size_t offset;
if (slen == 0 || suffixlen == 0 || suffixlen > slen)
return false;
offset = slen - suffixlen;
return strneq(&str[offset], suffix, suffixlen);
}
static inline bool
strstartswith(const char *str, const char *prefix)
{
size_t prefixlen = strlen(prefix);
return prefixlen > 0 ? strneq(str, prefix, strlen(prefix)) : false;
}
const char *
safe_basename(const char *filename);
char *
trunkname(const char *filename);
File diff suppressed because it is too large Load Diff
+1
View File
@@ -0,0 +1 @@
test-draglock
+16
View File
@@ -0,0 +1,16 @@
AM_CPPFLAGS = $(XORG_CFLAGS) \
$(CWARNFLAGS) \
-I$(top_srcdir)/include \
-I$(top_srcdir)/src
tests = test-draglock test-bezier
noinst_PROGRAMS = $(tests)
test_draglock_SOURCES = test-draglock.c
test_draglock_LDADD = ../src/libdraglock.la
test_bezier_SOURCES = test-bezier.c
test_bezier_LDADD = ../src/libbezier.la -lm
TESTS = $(tests)
+208
View File
@@ -0,0 +1,208 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright © 2016 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "bezier.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>
static inline void
print_curve(int *bezier, size_t size)
{
/* look at it with gnuplot, "plot 'output-file.txt'" */
for (int i = 0; i < size; i++)
printf("%d %d\n", i, bezier[i]);
}
static void
test_linear(void)
{
const int size = 2048;
int bezier[size];
struct bezier_control_point controls[] = {
{ 0.0, 0.0 },
{ 0.0, 0.0 },
{ 1.0, 1.0 },
{ 1.0, 1.0 }
};
cubic_bezier(controls, bezier, size);
assert(bezier[0] == 0);
assert(bezier[size - 1] == size - 1);
for (int x = 1; x < size; x++)
assert(bezier[x] == x);
}
/* Center point pulled down towards X axis */
static void
test_flattened(void)
{
const int size = 2048;
int bezier[size];
struct bezier_control_point controls[] = {
{ 0.0, 0.0 },
{ 0.1, 0.0 },
{ 1.0, 0.9 },
{ 1.0, 1.0 }
};
cubic_bezier(controls, bezier, size);
assert(bezier[0] == 0);
assert(bezier[size - 1] == size - 1);
for (int x = 1; x < size - 1; x++) {
assert(bezier[x] < x);
}
}
/* Center point pulled up from X axis */
static void
test_raised(void)
{
const int size = 2048;
int bezier[size];
struct bezier_control_point controls[] = {
{ 0.0, 0.0 },
{ 0.1, 0.4 },
{ 0.4, 1.0 },
{ 1.0, 1.0 }
};
cubic_bezier(controls, bezier, size);
assert(bezier[0] == 0);
assert(bezier[size - 1] == size - 1);
for (int x = 1; x < size; x++)
assert(bezier[x] >= x);
for (int x = 10; x < size - 10; x++)
assert(bezier[x] > x);
}
static void
test_windy(void)
{
const int size = 2048;
int bezier[size];
struct bezier_control_point controls[] = {
{ 0.0, 0.0 },
{ 0.0, 0.3 },
{ 1.0, 0.7 },
{ 1.0, 1.0 }
};
cubic_bezier(controls, bezier, size);
assert(bezier[0] == 0);
assert(bezier[size - 1] == size - 1);
for (int x = 1; x < size/2 - 20; x++)
assert(bezier[x] > x);
for (int x = size/2 + 20; x < size - 1; x++)
assert(bezier[x] < x);
}
static void
test_nonzero_x_linear(void)
{
const int size = 2048;
int bezier[size];
int x;
struct bezier_control_point controls[] = {
{ 0.2, 0.0 },
{ 0.2, 0.0 },
{ 0.8, 1.0 },
{ 0.8, 1.0 }
};
cubic_bezier(controls, bezier, size);
x = 0;
do {
assert(bezier[x] == 0);
} while (++x < size * 0.2 - 1);
/* ppc64le, ppc64, aarch64 have different math results at -O2,
resulting in one extra zero at the beginning of the array.
some other numbers are different too but within the error
margin (#99992) */
if (bezier[x] == 0)
x++;
do {
assert(bezier[x] > bezier[x-1]);
} while (++x < size * 0.8 - 1);
do {
assert(bezier[x] == size - 1);
} while (++x < size);
}
static void
test_nonzero_y_linear(void)
{
const int size = 2048;
int bezier[size];
struct bezier_control_point controls[] = {
{ 0.0, 0.2 },
{ 0.0, 0.2 },
{ 1.0, 0.8 },
{ 1.0, 0.8 }
};
cubic_bezier(controls, bezier, size);
assert(bezier[0] == (int)(size * 0.2));
for (int x = 1; x < size; x++) {
assert(bezier[x - 1] <= bezier[x]);
assert(bezier[x] >= (int)(size * 0.2));
}
}
int
main(int argc, char **argv)
{
test_linear();
test_flattened();
test_raised();
test_windy();
test_nonzero_x_linear();
test_nonzero_y_linear();
return 0;
}
@@ -0,0 +1,548 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright © 2013-2015 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "draglock.h"
#include <assert.h>
#include <string.h>
static void
test_config_empty(void)
{
struct draglock dl;
int rc;
rc = draglock_init_from_string(&dl, NULL);
assert(dl.mode == DRAGLOCK_DISABLED);
assert(rc == 0);
}
static void
test_config_invalid(void)
{
struct draglock dl;
int rc;
/* no trailing space */
rc = draglock_init_from_string(&dl, "1 ");
assert(rc != 0);
assert(dl.mode == DRAGLOCK_DISABLED);
rc = draglock_init_from_string(&dl, "256");
assert(rc != 0);
assert(dl.mode == DRAGLOCK_DISABLED);
rc = draglock_init_from_string(&dl, "-1");
assert(rc != 0);
assert(dl.mode == DRAGLOCK_DISABLED);
rc = draglock_init_from_string(&dl, "1 2 3");
assert(rc != 0);
assert(dl.mode == DRAGLOCK_DISABLED);
rc = draglock_init_from_string(&dl, "0 2");
assert(rc != 0);
assert(dl.mode == DRAGLOCK_DISABLED);
rc = draglock_init_from_string(&dl, "0 0");
assert(rc != 0);
assert(dl.mode == DRAGLOCK_DISABLED);
}
static void
test_config_disable(void)
{
struct draglock dl;
int rc;
rc = draglock_init_from_string(&dl, "");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_DISABLED);
rc = draglock_init_from_string(&dl, "0");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_DISABLED);
}
static void
test_config_meta_button(void)
{
struct draglock dl;
int rc;
rc = draglock_init_from_string(&dl, "1");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_META);
assert(dl.meta_button == 1);
rc = draglock_init_from_string(&dl, "2");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_META);
assert(dl.meta_button == 2);
rc = draglock_init_from_string(&dl, "10");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_META);
assert(dl.meta_button == 10);
}
static void
test_config_button_pairs(void)
{
struct draglock dl;
int rc;
rc = draglock_init_from_string(&dl, "1 1");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_PAIRS);
rc = draglock_init_from_string(&dl, "1 2 3 4 5 6 7 8");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_PAIRS);
rc = draglock_init_from_string(&dl, "1 2 3 4 5 0 7 8");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_PAIRS);
/* all disabled */
rc = draglock_init_from_string(&dl, "1 0 3 0 5 0 7 0");
assert(rc == 0);
assert(dl.mode == DRAGLOCK_DISABLED);
}
static void
test_config_get(void)
{
struct draglock dl;
int rc;
const int sz = 32;
int map[sz];
draglock_init_from_string(&dl, "");
rc = draglock_get_meta(&dl);
assert(rc == 0);
rc = draglock_get_pairs(&dl, map, sz);
assert(rc == 0);
draglock_init_from_string(&dl, "8");
rc = draglock_get_meta(&dl);
assert(rc == 8);
rc = draglock_get_pairs(&dl, map, sz);
assert(rc == 0);
draglock_init_from_string(&dl, "1 2 3 4 5 6");
rc = draglock_get_meta(&dl);
assert(rc == 0);
rc = draglock_get_pairs(&dl, map, sz);
assert(rc == 5);
assert(map[0] == 0);
assert(map[1] == 2);
assert(map[2] == 0);
assert(map[3] == 4);
assert(map[4] == 0);
assert(map[5] == 6);
}
static void
test_set_meta(void)
{
struct draglock dl;
int rc;
draglock_init_from_string(&dl, "");
rc = draglock_set_meta(&dl, 0);
assert(rc == 0);
assert(dl.mode == DRAGLOCK_DISABLED);
rc = draglock_set_meta(&dl, 1);
assert(rc == 0);
assert(dl.mode == DRAGLOCK_META);
rc = draglock_set_meta(&dl, -1);
assert(rc == 1);
rc = draglock_set_meta(&dl, 32);
assert(rc == 1);
}
static void
test_set_pairs(void)
{
struct draglock dl;
int rc;
const int sz = 32;
int map[sz];
draglock_init_from_string(&dl, "");
memset(map, 0, sizeof(map));
rc = draglock_set_pairs(&dl, map, sz);
assert(rc == 0);
assert(dl.mode == DRAGLOCK_DISABLED);
rc = draglock_set_pairs(&dl, map, 1);
assert(rc == 0);
assert(dl.mode == DRAGLOCK_DISABLED);
map[0] = 1;
rc = draglock_set_pairs(&dl, map, 1);
assert(rc == 1);
map[0] = 0;
map[1] = 2;
rc = draglock_set_pairs(&dl, map, sz);
assert(rc == 0);
assert(dl.mode == DRAGLOCK_PAIRS);
map[0] = 0;
map[1] = 0;
map[10] = 8;
rc = draglock_set_pairs(&dl, map, sz);
assert(rc == 0);
assert(dl.mode == DRAGLOCK_PAIRS);
}
static void
test_filter_meta_passthrough(void)
{
struct draglock dl;
int rc;
int button, press;
int i;
rc = draglock_init_from_string(&dl, "10");
assert(rc == 0);
for (i = 0; i < 10; i++) {
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == i);
assert(press == 1);
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == i);
assert(press == 1);
}
}
static void
test_filter_meta_click_meta_only(void)
{
struct draglock dl;
int rc;
int button, press;
rc = draglock_init_from_string(&dl, "10");
assert(rc == 0);
button = 10;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
button = 10;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
}
static void
test_filter_meta(void)
{
struct draglock dl;
int rc;
int button, press;
int i;
rc = draglock_init_from_string(&dl, "10");
assert(rc == 0);
for (i = 1; i < 10; i++) {
/* meta down */
button = 10;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* meta up */
button = 10;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* button down -> passthrough */
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == i);
/* button up -> eaten */
button = i;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* button down -> eaten */
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* button up -> passthrough */
button = i;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == i);
assert(press == 0);
}
}
static void
test_filter_meta_extra_click(void)
{
struct draglock dl;
int rc;
int button, press;
int i;
rc = draglock_init_from_string(&dl, "10");
assert(rc == 0);
for (i = 1; i < 10; i++) {
/* meta down */
button = 10;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* meta up */
button = 10;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* button down -> passthrough */
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == i);
/* button up -> eaten */
button = i;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* meta down */
button = 10;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* meta up */
button = 10;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* button down -> eaten */
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* button up -> passthrough */
button = i;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == i);
assert(press == 0);
}
}
static void
test_filter_meta_interleaved(void)
{
struct draglock dl;
int rc;
int button, press;
int i;
rc = draglock_init_from_string(&dl, "10");
assert(rc == 0);
for (i = 1; i < 10; i++) {
/* meta down */
button = 10;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* meta up */
button = 10;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* button down -> passthrough */
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == i);
/* button up -> eaten */
button = i;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
}
for (i = 0; i < 10; i++) {
/* button down -> eaten */
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == 0);
/* button up -> passthrough */
button = i;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
assert(button == i);
assert(press == 0);
}
}
static void
test_filter_pairs(void)
{
struct draglock dl;
int rc;
int button, press;
int i;
rc = draglock_init_from_string(&dl, "1 11 2 0 3 13 4 0 5 15 6 0 7 17 8 0 9 19");
assert(rc == 0);
for (i = 1; i < 10; i++) {
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
if (i % 2)
assert(button == i + 10);
else
assert(button == i);
assert(press == 1);
button = i;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
if (i % 2) {
assert(button == 0);
} else {
assert(button == i);
assert(press == 0);
}
}
for (i = 1; i < 10; i++) {
button = i;
press = 1;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
if (i % 2) {
assert(button == 0);
} else {
assert(button == i);
assert(press == 1);
}
button = i;
press = 0;
rc = draglock_filter_button(&dl, &button, &press);
assert(rc == 0);
if (i % 2)
assert(button == i + 10);
else
assert(button == i);
assert(press == 0);
}
}
int
main(int argc, char **argv)
{
test_config_empty();
test_config_invalid();
test_config_disable();
test_config_meta_button();
test_config_button_pairs();
test_config_get();
test_set_meta();
test_set_pairs();
test_filter_meta_passthrough();
test_filter_meta_click_meta_only();
test_filter_meta();
test_filter_meta_extra_click();
test_filter_meta_interleaved();
test_filter_pairs();
return 0;
}
@@ -0,0 +1,6 @@
sdkdir=@sdkdir@
Name: xorg-libinput
Description: X.Org libinput input driver.
Version: @PACKAGE_VERSION@
Cflags: -I${sdkdir}
@@ -0,0 +1,65 @@
name: 🐞 Bug report
description: Create a report to help us improve
labels: [bug, needs-triage]
body:
- type: markdown
attributes:
value: |
Please fill out the sections below to help everyone identify and fix the bug. If you have a general idea or question then please use the [discussions](https://github.com/orgs/X11Libre/discussions).
- type: dropdown
id: affected-version
attributes:
label: Select the version
options:
- 0.5.1.1
- Git master branch
- other or don't know
default: 1
validations:
required: true
- type: textarea
id: description
attributes:
label: Describe your issue
placeholder: When I did X then Y happened.
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
placeholder: |
1. Start ...
2. Do this
3. Do that
validations:
required: true
- type: textarea
id: expected
attributes:
label: What did you expect?
placeholder: I expected this to happen.
- type: textarea
id: environment
attributes:
label: Additional Information
description: |
Additional information you want to provide such as logs, system info, environment, screenshots, etc.
placeholder: |
Add any other context about the bug here.
- type: checkboxes
id: checks
attributes:
label: Extra fields
options:
- label: I have checked the existing [issues](https://github.com/X11Libre/xf86-video-fbdev/issues)
required: true
- label: I have read the [Contributing Guidelines](https://github.com/X11Libre/xserver/blob/master/CONTRIBUTING.md)
required: true
- label: I'd like to work on this issue
- type: markdown
attributes:
value: |
Thanks for reporting this issue! We will get back to you as soon as possible.
@@ -0,0 +1,49 @@
name: ✨ Feature request
description: Suggest a feature for this software
labels: [enhancement, needs-triage]
body:
- type: markdown
attributes:
value: |
Please fill out the sections below to properly describe the new software feature you are suggesting. If you have a general idea or question then please use the [discussions](https://github.com/orgs/X11Libre/discussions).
- type: textarea
id: description
attributes:
label: "Describe the feature"
placeholder: A thing in X that allows to do Y.
validations:
required: true
- type: textarea
id: rationale
attributes:
label: "It should be done because"
placeholder: Doing Y is needed for Z.
validations:
required: true
- type: textarea
id: alternative
attributes:
label: "What are the alternatives?"
placeholder: We could do A or B instead.
- type: textarea
id: context
attributes:
label: Additional context
description: Additional information you want to provide such as references to related issues or protocols, the implications on existing use cases, etc.
placeholder: |
Add any other context about the feature request here.
- type: checkboxes
id: checks
attributes:
label: Extra fields
options:
- label: I have checked the existing [issues](https://github.com/X11Libre/xf86-video-fbdev/issues)
required: true
- label: I have read the [Contributing Guidelines](https://github.com/X11Libre/xserver/blob/master/CONTRIBUTING.md)
required: true
- label: I'd like to work on this issue
- type: markdown
attributes:
value: |
Thanks for your suggestion! Let's see together if it can be done.
@@ -0,0 +1,49 @@
name: 🔧 Code cleanup
description: Level up the source code
labels: [code-cleanup, needs-triage]
body:
- type: markdown
attributes:
value: |
Please fill out the sections below to properly describe the code cleanup you are suggesting. If you have a general idea or question then please use the [discussions](https://github.com/orgs/X11Libre/discussions).
- type: textarea
id: description
attributes:
label: "Describe the cleanup"
placeholder: C in X needs to be changed into D.
validations:
required: true
- type: textarea
id: rationale
attributes:
label: "It should be done because"
placeholder: Having D is needed for E.
validations:
required: true
- type: textarea
id: alternative
attributes:
label: "What are the alternatives?"
placeholder: We could do A or B instead.
- type: textarea
id: context
attributes:
label: Additional context
description: Additional information you want to provide such as implications on existing code, how to ensure API/ABI stability, which tests are needed or to be run, related issues, etc.
placeholder: |
Add any other context about the cleanup here.
- type: checkboxes
id: checks
attributes:
label: Extra fields
options:
- label: I have checked the existing [issues](https://github.com/X11Libre/xf86-video-fbdev/issues)
required: true
- label: I have read the [Contributing Guidelines](https://github.com/X11Libre/xserver/blob/master/CONTRIBUTING.md)
required: true
- label: I'd like to work on this issue
- type: markdown
attributes:
value: |
Thanks for looking at the source code! Let's see together how it can be improved.
@@ -0,0 +1,38 @@
name: 🔖 Documentation update
description: Make your mark for better documentation
labels: [documentation, needs-triage]
body:
- type: markdown
attributes:
value: |
Please fill out the sections below to help others understand our software. If you have a general idea or question then please use the [discussions](https://github.com/orgs/X11Libre/discussions).
- type: textarea
id: description
attributes:
label: Describe the update
placeholder: These things need to be better documented.
validations:
required: true
- type: textarea
id: environment
attributes:
label: Additional Information
description: Additional information you want to provide such as tickets related to changes in the software, affected files, screenshots, etc.
placeholder: |
Add any other context about the update here.
- type: checkboxes
id: checks
attributes:
label: Extra fields
options:
- label: I have checked the existing [issues](https://github.com/X11Libre/xf86-video-fbdev/issues)
required: true
- label: I have read the [Contributing Guidelines](https://github.com/X11Libre/xserver/blob/master/CONTRIBUTING.md)
required: true
- label: I'd like to work on this issue
- type: markdown
attributes:
value: |
Thanks for requesting this update! We will get back to you as soon as possible.
@@ -0,0 +1,43 @@
name: ✅ Organizational task
description: Create a task for project organization
labels: [needs-triage, organization]
body:
- type: markdown
attributes:
value: |
Please fill out the sections below to get organizational things done. If you have a general idea or question then please use the [discussions](https://github.com/orgs/X11Libre/discussions).
- type: textarea
id: description
attributes:
label: Describe the task
placeholder: These things need to be done.
validations:
required: true
- type: textarea
id: rationale
attributes:
label: "It should be done because"
placeholder: Doing Y is needed for Z.
- type: textarea
id: environment
attributes:
label: Additional Information
description: Additional information you want to provide such as the context for bigger tasks, the implicatons on existing workflows, related issues, etc.
placeholder: |
Add any other context about the task here.
- type: checkboxes
id: checks
attributes:
label: Extra fields
options:
- label: I have checked the existing [issues](https://github.com/X11Libre/xf86-video-fbdev/issues)
required: true
- label: I have read the [Contributing Guidelines](https://github.com/X11Libre/xserver/blob/master/CONTRIBUTING.md)
required: true
- label: I'd like to work on this issue
- type: markdown
attributes:
value: |
Thanks for adding this task! We will get back to you as soon as possible.
@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: XLibre Community Support
url: https://github.com/orgs/X11Libre/discussions
about: Please ask and answer questions here.
- name: Mailing List
url: https://www.freelists.org/list/xlibre
about: You can join the discussions on our mailing list.
+58
View File
@@ -0,0 +1,58 @@
permissions:
contents: write
on:
push:
pull_request:
jobs:
ubuntu:
strategy:
matrix:
xserver-version: [ master, xlibre-xserver-25.1.0, xlibre-xserver-25.0.0.18 ]
runs-on: ubuntu-latest
steps:
- uses: X11Libre/action-build-driver/target/ubuntu@v0.4.0
with:
xserver-version: ${{ matrix.xserver-version }}
freebsd:
strategy:
matrix:
xserver-version: [ master, xlibre-xserver-25.1.0, xlibre-xserver-25.0.0.18 ]
runs-on: ubuntu-latest
steps:
- uses: X11Libre/action-build-driver/target/freebsd@v0.4.0
with:
xserver-version: ${{ matrix.xserver-version }}
dragonfly:
strategy:
matrix:
# xlibre-xserver-25.0.x not compiling on dragonfly yet
xserver-version: [ master, xlibre-xserver-25.1.0 ]
runs-on: ubuntu-latest
steps:
- uses: X11Libre/action-build-driver/target/dragonfly@v0.4.0
with:
xserver-version: ${{ matrix.xserver-version }}
netbsd:
strategy:
matrix:
xserver-version: [ master, xlibre-xserver-25.1.0 ]
runs-on: ubuntu-latest
steps:
- uses: X11Libre/action-build-driver/target/netbsd@v0.4.0
with:
xserver-version: ${{ matrix.xserver-version }}
release-notes:
name: Release pushed tag
runs-on: ubuntu-latest
if: ${{ startsWith(github.ref, 'refs/tags/xlibre-') }}
needs: [ ubuntu, freebsd, dragonfly, netbsd ]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: X11Libre/action-build-driver/release@v0.4.0
+78
View File
@@ -0,0 +1,78 @@
#
# X.Org module default exclusion patterns
# The next section if for module specific patterns
#
# Do not edit the following section
# GNU Build System (Autotools)
aclocal.m4
autom4te.cache/
autoscan.log
ChangeLog
compile
config.guess
config.h
config.h.in
config.log
config-ml.in
config.py
config.status
config.status.lineno
config.sub
configure
configure.scan
depcomp
.deps/
INSTALL
install-sh
.libs/
libtool
libtool.m4
ltmain.sh
lt~obsolete.m4
ltoptions.m4
ltsugar.m4
ltversion.m4
Makefile
Makefile.in
mdate-sh
missing
mkinstalldirs
*.pc
py-compile
stamp-h?
symlink-tree
texinfo.tex
ylwrap
# Do not edit the following section
# Edit Compile Debug Document Distribute
*~
*.[0-9]
*.[0-9]x
*.bak
*.bin
core
*.dll
*.exe
*-ISO*.bdf
*-JIS*.bdf
*-KOI8*.bdf
*.kld
*.ko
*.ko.cmd
*.lai
*.l[oa]
*.[oa]
*.obj
*.patch
*.so
*.pcf.gz
*.pdb
*.tar.bz2
*.tar.gz
#
# Add & Override patterns for xf86-video-fbdev
#
# Edit the following section as needed
# For example, !report.pc overrides *.pc. See 'man gitignore'
#

Some files were not shown because too many files have changed in this diff Show More