From 8f469fdf2bf6a446f78a3b76c8b2092fbc70ba19 Mon Sep 17 00:00:00 2001 From: Benoit Clennett-Sirois Date: Fri, 15 Dec 2017 16:21:42 -0500 Subject: [PATCH] First commit --- .gitignore | 62 +++++++++++++++++++ LICENSE | 32 ++++++++++ dwm_src/.keep | 0 pydwm/__init__.py | 31 ++++++++++ setup.py | 154 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 279 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 dwm_src/.keep create mode 100644 pydwm/__init__.py create mode 100644 setup.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ddfd678 --- /dev/null +++ b/.gitignore @@ -0,0 +1,62 @@ +# Created by https://www.gitignore.io/api/emacs,python + +dwm_src/dwm* + +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# flymake-mode +*_flymake.* + +# Flycheck +flycheck_*.el + +# projectiles files +.projectile +projectile-bookmarks.eld + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# pyenv +.python-version + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2e53d0a --- /dev/null +++ b/LICENSE @@ -0,0 +1,32 @@ +MIT/X Consortium License + +© 2006-2012 Anselm R Garbe +© 2007-2011 Peter Hartlich +© 2010-2011 Connor Lane Smith +© 2006-2009 Jukka Salmi +© 2007-2009 Premysl Hruby +© 2007-2009 Szabolcs Nagy +© 2007-2009 Christof Musik +© 2009 Mate Nagy +© 2007-2008 Enno Gottox Boland +© 2008 Martin Hurton +© 2008 Neale Pickett +© 2006-2007 Sander van Dijk + +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. diff --git a/dwm_src/.keep b/dwm_src/.keep new file mode 100644 index 0000000..e69de29 diff --git a/pydwm/__init__.py b/pydwm/__init__.py new file mode 100644 index 0000000..d71d04f --- /dev/null +++ b/pydwm/__init__.py @@ -0,0 +1,31 @@ +import os +import ctypes + + +SO_PATH = os.path.join( + os.path.dirname(__file__), + '..', + 'dwm.so' +) + + +def init_dwm(*args): + args = ['dwm'] + list(args) + lib = ctypes.CDLL(SO_PATH) + + LP_c_char = ctypes.POINTER(ctypes.c_char) + LP_LP_c_char = ctypes.POINTER(LP_c_char) + + lib.main.argtypes = ( + ctypes.c_int, + LP_LP_c_char + ) + + argc = len(args) + argv = (LP_c_char * (argc + 1))() + + for i, arg in enumerate(args): + enc_arg = arg.encode('utf-8') + argv[i] = ctypes.create_string_buffer(enc_arg) + + lib.main(argc, argv) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..af5c910 --- /dev/null +++ b/setup.py @@ -0,0 +1,154 @@ +import os +import distutils.ccompiler as cc +import logging +import tempfile +import hashlib +import tarfile + +from distutils.command.build_ext import build_ext +from setuptools import Extension +from setuptools import setup + +try: + from urllib.request import urlopen +except ImportError: + from urllib2 import urlopen + + +DWM_VERSION = '6.1' +DWM_SRC_ROOT_DIR = 'dwm_src' +DWM_SRC_DIR = os.path.join('dwm_src', 'dwm-{version}').format( + version=DWM_VERSION +) +DWM_SOURCE = ( + 'https://dl.suckless.org/dwm/dwm-{version}.tar.gz'.format( + version=DWM_VERSION + ) +) +DWM_MD5 = 'f0b6b1093b7207f89c2a90b848c008ec' + + +dwm = Extension( + 'dwm', + libraries=['X11', 'Xinerama', 'fontconfig', 'Xft'], + library_dirs=['/usr/X11R6/lib'], + include_dirs=[ + '/usr/X11R6/include', + '/usr/include/freetype2', + DWM_SRC_DIR, + ], + define_macros=[ + ('_DEFAULT_SOURCE',), + ('_BSD_SOURCE',), + ('_POSIX_C_SOURCE', 2), + ('VERSION', '"{version}"'.format(version=DWM_VERSION)), + ('XINERAMA',), + ], + sources=[ + os.path.join(DWM_SRC_DIR, 'drw.c'), + os.path.join(DWM_SRC_DIR, 'dwm.c'), + os.path.join(DWM_SRC_DIR, 'util.c'), + ], + extra_compile_args=[ + '-c', + '-fPIC', + '-std=c99', + '-pedantic', + '-Wno-deprecated-declarations', + '-Os', + ], + extra_link_args=[ + '-fPIC', + ] +) + + +class BuildDwm(build_ext, object): + def relative_path(self, *dirs): + return os.path.join(os.path.dirname(__file__), *dirs) + + def download_dwm(self): + if not os.path.exists(self.relative_path(DWM_SRC_DIR)): + logger = logging.getLogger() + logger.warn('Downloading {file}...'.format(file=DWM_SRC_DIR)) + response = urlopen(DWM_SOURCE) + data = response.read() + + os.mkdir(self.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() + + def copy_default_config(self): + dest_file_path = self.relative_path(DWM_SRC_DIR, 'config.h') + if not os.path.exists(dest_file_path): + source_file = open( + self.relative_path( + DWM_SRC_DIR, 'config.def.h' + ), + 'r' + ) + dest_file = open(dest_file_path, 'w') + dest_file.write(source_file.read()) + source_file.close() + dest_file.close() + + def build_extension(self, ext): + self.download_dwm() + self.copy_default_config() + self.compiler = cc.new_compiler() + return super(BuildDwm, self).build_extension(ext) + + def get_export_symbols(self, ext): + return ext.export_symbols + + def get_ext_filename(self, ext_name): + return ext_name + '.so' + +setup( + name='pydwm', + url='', + author='Benoit', + author_email='benoitcsirois@gmail.com', + version='0.1', + description='A simple python wrapper around DWM.', + long_description=( + 'This is a very simple python wrapper around DWM. It downloads DWM, ' + 'compiles it as a shared object and exposes DWM\'s main function as ' + 'pydwm:init_dwm. Installing this via pip will give you a pydwm ' + 'executable, which just runs dwm.' + ), + packages=['pydwm'], + include_package_data=True, + license='MIT License', + classifiers=[ + 'Development Status :: 4 - Beta', + 'Environment :: X11 Applications', + 'Intended Audience :: Developers', + 'Intended Audience :: End Users/Desktop', + 'License :: OSI Approved :: MIT License', + 'Operating System :: POSIX', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: Implementation :: CPython', + 'Topic :: Desktop Environment :: Window Managers', + ], + cmdclass={'build_ext': BuildDwm}, + ext_modules=[dwm], + entry_points={ + 'console_scripts': [ + 'pydwn = pydwm:init_dwm', + ] + } +)