From 45ff4a033d676887d31a48c69cebd19dc5c95220 Mon Sep 17 00:00:00 2001 From: Benoit Clennett-Sirois Date: Sat, 22 Jan 2022 11:41:10 -0500 Subject: [PATCH] some fixes --- .gitignore | 4 -- .gitmodules | 3 ++ README.md | 8 +++- config.h | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++ dwm_src | 1 + extra/push.c | 58 +++++++++++++++++++++++ install.sh | 8 ++++ setup.py | 71 ++-------------------------- 8 files changed, 209 insertions(+), 72 deletions(-) create mode 100644 .gitmodules create mode 100644 config.h create mode 160000 dwm_src create mode 100644 extra/push.c create mode 100755 install.sh diff --git a/.gitignore b/.gitignore index 1502f02..ed9f012 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ # Created by https://www.gitignore.io/api/emacs,python -dwm_src/dwm* - ### Emacs ### # -*- mode: gitignore; -*- *~ @@ -61,5 +59,3 @@ ENV/ env.bak/ venv.bak/ dist/ - -dwm_src \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..3ce300f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "dwm_src"] + path = dwm_src + url = https://git.suckless.org/dwm#6.3 diff --git a/README.md b/README.md index 56e8f11..51f0247 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,14 @@ With this, you can start `dwm` from a python script, and spawn sub-processes / t To build this, you'll need the source code for some libraries DWM requires. On Ubuntu: -```bash +``` sudo apt-get install build-essential libx11-dev libxft-dev libxinerama-dev ``` +## Run tests + +``` +python -m pytest +``` + ## Install diff --git a/config.h b/config.h new file mode 100644 index 0000000..c2649cd --- /dev/null +++ b/config.h @@ -0,0 +1,128 @@ +/* See LICENSE file for copyright and license details. */ + +/* appearance */ +static const char normbordercolor[] = "#49483E"; +static const char normbgcolor[] = "#272822"; +static const char normfgcolor[] = "#F8F8F2"; +static const char selbordercolor[] = "#f92672"; +static const char selbgcolor[] = "#49483E"; +static const char selfgcolor[] = "#F8F8F2"; +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const unsigned int snap = 32; /* snap pixel */ +static const int showbar = 1; /* 0 means no bar */ +static const int topbar = 1; /* 0 means bottom bar */ +static const char *fonts[] = { "monospace:size=10" }; +static const char dmenufont[] = "monospace:size=10"; +static const char col_gray1[] = "#222222"; +static const char col_gray2[] = "#444444"; +static const char col_gray3[] = "#bbbbbb"; +static const char col_gray4[] = "#eeeeee"; +static const char col_cyan[] = "#005577"; +static const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, +}; + +/* tagging */ +static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, +}; + +/* layout(s) */ +static const float mfact = 0.55; /* 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 */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, +}; + +/* key definitions */ +#define MODKEY Mod4Mask +#define TAGKEYS(KEY,TAG) \ + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ + { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.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", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL }; +static const char *langcyclecmd[] = { "langcycle", "us", "ca:fr", NULL }; +static const char *termcmd[] = { "alacritty", NULL }; + +#include "push.c" + +static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY|ControlMask, XK_space, spawn, {.v = langcyclecmd } }, + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY|ShiftMask, XK_j, pushdown, {.i = +1 } }, + { MODKEY|ShiftMask, XK_k, pushup, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, + { MODKEY, XK_d, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY, XK_Return, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY|ShiftMask, XK_c, killclient, {0} }, + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, + { MODKEY, XK_comma, focusmon, {.i = -1 } }, + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) + TAGKEYS( XK_4, 3) + TAGKEYS( XK_5, 4) + TAGKEYS( XK_6, 5) + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + { MODKEY|ShiftMask, XK_q, quit, {0} }, +}; + +/* button definitions */ +/* click can be ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ +static Button buttons[] = { + /* click event mask button function argument */ + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, +}; + diff --git a/dwm_src b/dwm_src new file mode 160000 index 0000000..d39e2f3 --- /dev/null +++ b/dwm_src @@ -0,0 +1 @@ +Subproject commit d39e2f3441fe18aba8d1a62c08918a411ec6f237 diff --git a/extra/push.c b/extra/push.c new file mode 100644 index 0000000..493613c --- /dev/null +++ b/extra/push.c @@ -0,0 +1,58 @@ +static Client * +prevtiled(Client *c) { + Client *p, *r; + + for(p = selmon->clients, r = NULL; p && p != c; p = p->next) + if(!p->isfloating && ISVISIBLE(p)) + r = p; + return r; +} + +static void +pushup(const Arg *arg) { + Client *sel = selmon->sel; + Client *c; + + if(!sel || sel->isfloating) + return; + if((c = prevtiled(sel))) { + /* attach before c */ + detach(sel); + sel->next = c; + if(selmon->clients == c) + selmon->clients = sel; + else { + for(c = selmon->clients; c->next != sel->next; c = c->next); + c->next = sel; + } + } else { + /* move to the end */ + for(c = sel; c->next; c = c->next); + detach(sel); + sel->next = NULL; + c->next = sel; + } + focus(sel); + arrange(selmon); +} + +static void +pushdown(const Arg *arg) { + Client *sel = selmon->sel; + Client *c; + + if(!sel || sel->isfloating) + return; + if((c = nexttiled(sel->next))) { + /* attach after c */ + detach(sel); + sel->next = c->next; + c->next = sel; + } else { + /* move to the front */ + detach(sel); + attach(sel); + } + focus(sel); + arrange(selmon); +} diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..437c643 --- /dev/null +++ b/install.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +git submodule update +cp extra/push.c dwm_src/ +pip uninstall pydwm +rm -rf build/ dist/ pydwm.egg-info/ +python setup.py build +python setup.py install diff --git a/setup.py b/setup.py index d17f7ad..650534a 100644 --- a/setup.py +++ b/setup.py @@ -1,34 +1,16 @@ import os import distutils.ccompiler as cc -import logging -import tempfile -import hashlib -import tarfile -import shutil from setuptools.command.build_ext import build_ext -from setuptools.command.install import install from setuptools import (Extension, setup) -try: - from urllib.request import urlopen -except ImportError: - from urllib2 import urlopen - def relative_path(*parts): return os.path.join('.', *parts) DWM_VERSION = '6.3' -DWM_SRC_ROOT_DIR= relative_path('dwm_src') -DWM_REMOTE_SOURCE = ( - 'https://dl.suckless.org/dwm/dwm-{version}.tar.gz'.format( - version=DWM_VERSION - ) -) -DWM_MD5 = '9929845ccdec4d2cc191f16210dd7f3d' - +DWM_SRC_ROOT_DIR = relative_path('dwm_src') dwm = Extension( 'dwm', @@ -71,49 +53,13 @@ class BuildDwm(build_ext, object): ] def initialize_options(self): - self.dwm_source = None super(BuildDwm, self).initialize_options() - def download_dwm(self): - if not os.path.exists(relative_path(DWM_SRC_ROOT_DIR)): - logger = logging.getLogger() - logger.warn('Downloading {file}...'.format(file=DWM_SRC_ROOT_DIR)) - response = urlopen(DWM_REMOTE_SOURCE) - data = response.read() - - os.mkdir(relative_path(DWM_SRC_ROOT_DIR)) - - logger.warn('Validating MD5...') - assert(hashlib.md5(data).hexdigest() == DWM_MD5) - - logger.warn('Extracting...') - with tempfile.TemporaryFile() as destination_file: - destination_file.write(data) - destination_file.seek(0) - with tarfile.open( - fileobj=destination_file, - mode='r:gz' - ) as archive: - archive.extractall(DWM_SRC_ROOT_DIR) - destination_file.close() - unpacked_dest = 'dwm-{version}'.format(version=DWM_VERSION) - unpacked_dest = relative_path( - DWM_SRC_ROOT_DIR, - unpacked_dest - ) - for file in os.listdir(unpacked_dest): - shutil.move( - relative_path(unpacked_dest, file), - relative_path(DWM_SRC_ROOT_DIR), - ) - def copy_default_config(self): dest_file_path = relative_path(DWM_SRC_ROOT_DIR, 'config.h') if not os.path.exists(dest_file_path): source_file = open( - relative_path( - DWM_SRC_ROOT_DIR, 'config.def.h' - ), + relative_path('config.h'), 'r' ) dest_file = open(dest_file_path, 'w') @@ -121,21 +67,11 @@ def copy_default_config(self): source_file.close() dest_file.close() - def copy_dwm_source(self): - if not os.path.exists(relative_path(DWM_SRC_ROOT_DIR)): - shutil.copytree(self.dwm_source, DWM_SRC_ROOT_DIR) - def build_extension(self, ext): if ext.name == 'dwm': self.compiler = cc.new_compiler() + self.copy_default_config() - if self.dwm_source is None: - self.download_dwm() - self.copy_default_config() - else: - self.copy_dwm_source() - - del(self.dwm_source) return super(BuildDwm, self).build_extension(ext) def get_export_symbols(self, ext): @@ -144,6 +80,7 @@ def get_export_symbols(self, ext): def get_ext_filename(self, ext_name): return ext_name + '.so' + setup( name='pydwm', url='https://github.com/benwah/pydwm',