diff --git a/.gitignore b/.gitignore index 2fca53d..05bf491 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,123 @@ # IDE-specific .idea .vscode + +# PYTHON + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +!/lib +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..99782df --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include comfortable_swipe/res/comfortable-swipe.desktop diff --git a/README.md b/README.md index d1b85a0..a6e8ee3 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,10 @@ Comfortable, seamless, and fast 3-finger (and 4-finger) touchpad swipe gestures ## Installation -1. Install git, libinput, and g++ +1. Install Python3, libinput, and g++ ```bash - sudo apt-get install git libinput-tools libxdo-dev g++ + sudo apt-get install git python3-dev libinput-tools libxdo-dev ``` 2. Clone this repository diff --git a/comfortable-swipe.compile.sh b/comfortable-swipe.compile.sh deleted file mode 100755 index d839b64..0000000 --- a/comfortable-swipe.compile.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -g++ $(dirname $0)/comfortable-swipe.cpp -std=c++11 -O2 -lxdo -Wno-unused-result -o $1 diff --git a/comfortable-swipe.cpp b/comfortable-swipe.cpp deleted file mode 100644 index 65359b5..0000000 --- a/comfortable-swipe.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* -Comfortable Swipe -by Rico Tiongson - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include // std::ios -#include // std::cin, std::cout, std::cerr -#include // std::string -#include "lib/comfortable_swipe" - -/* MAIN DRIVER FUNCTION */ - -int main(int argc, char** args) -{ - // improve buffering by decoupling loggers from stdio - std::ios::sync_with_stdio(false); - std::cin.tie(0); - std::cout.tie(0); - std::cerr.tie(0); - - if (argc > 1) - { - std::string arg = args[1]; - - // select based on argument - if (arg == "start") - comfortable_swipe::service::start(); - - else if (arg == "stop") - comfortable_swipe::service::stop(); - - else if (arg == "restart") - comfortable_swipe::service::restart(); - - else if (arg == "buffer") - comfortable_swipe::service::buffer(); - - else if (arg == "autostart") - comfortable_swipe::service::autostart(); - - else if (arg == "config") - comfortable_swipe::service::config(); - - else if (arg == "debug") - comfortable_swipe::service::debug(); - - else if (arg == "status") - comfortable_swipe::service::status(); - - else /* if (arg == "help") */ - comfortable_swipe::service::help(); - } - else - comfortable_swipe::service::help(); - - return 0; -} diff --git a/comfortable_swipe/__init__.py b/comfortable_swipe/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/comfortable_swipe/__main__.py b/comfortable_swipe/__main__.py new file mode 100644 index 0000000..ef34de2 --- /dev/null +++ b/comfortable_swipe/__main__.py @@ -0,0 +1,28 @@ +from __future__ import print_function + +import sys + +from comfortable_swipe.autostart import toggle_status +from comfortable_swipe.constants import CONFIG +from comfortable_swipe.status import print_status + +from comfortable_swipe.cpp import service as cpp_service + +def main(): + if len(sys.argv) <= 1: + cpp_service.help() + else: + dict( + start=cpp_service.start, + stop=cpp_service.stop, + restart=cpp_service.restart, + buffer=cpp_service.buffer, + help=cpp_service.help, + debug=cpp_service.debug, + status=print_status, + autostart=lambda: print('Autostart switched', toggle_status()), + config=lambda: print(CONFIG), + )[sys.argv[1]]() + +if __name__ == '__main__': + main() diff --git a/comfortable_swipe/autostart.py b/comfortable_swipe/autostart.py new file mode 100644 index 0000000..164a335 --- /dev/null +++ b/comfortable_swipe/autostart.py @@ -0,0 +1,61 @@ +from __future__ import print_function + +import os +import sys + +from comfortable_swipe.constants import NAME, RES, exe + + +# status enums +OFF = 'off' +ON = 'on' + + +# the target path to the autostart desktop file +def target_path(): + return os.path.join( + os.getenv( + 'XDG_CONFIG_HOME', + os.path.join(os.getenv('HOME'), '.config') + ), + 'autostart', + '{}.desktop'.format(NAME) + ) + + +# path to the autostart template file to be copied +def template_path(): + return os.path.join(RES, '{}.desktop'.format(NAME)) + + +# parsed contents of the template file +def template(raw=False): + with open(template_path(), 'r') as file: + contents = file.read() + if raw: + return contents + return contents.replace('Exec=' + NAME, 'Exec={} {}'.format(sys.executable, exe())) + + +# gets the current autostart status +def get_status(): + return ON if os.path.exists(target_path()) else OFF + + +# sets the autostart status +def set_status(status=ON): + if status == ON: + with open(target_path(), 'w') as file: + file.write(template()) + elif status == OFF: + if os.path.exists(target_path()): + os.remove(target_path()) + else: + raise ValueError('invalid status for autostart') + + return status + + +# toggles autostart status +def toggle_status(): + return set_status(OFF if get_status() == ON else ON) diff --git a/comfortable_swipe/constants.py b/comfortable_swipe/constants.py new file mode 100644 index 0000000..f27af9e --- /dev/null +++ b/comfortable_swipe/constants.py @@ -0,0 +1,17 @@ +import os +import sys + +from distutils.spawn import find_executable + + +NAME = 'comfortable-swipe' +DESCRIPTION = 'Comfortable 3-finger and 4-finger swipe gestures' +BIN = os.path.dirname(sys.executable) +DIR = os.path.dirname(os.path.abspath(__file__)) +PYTHON_NAME = os.path.basename(DIR) +RES = os.path.join(DIR, 'res') +CONFIG = os.path.join(sys.prefix, 'local', 'share', NAME, '{}.conf'.format(NAME)) +DEFAULT_CONFIG = os.path.join(RES, 'defaults.conf') + +def exe(): + return find_executable(NAME) diff --git a/comfortable_swipe/cpp/__init__.py b/comfortable_swipe/cpp/__init__.py new file mode 100644 index 0000000..ded284d --- /dev/null +++ b/comfortable_swipe/cpp/__init__.py @@ -0,0 +1 @@ +# This is a placeholder module that will contain the C++ libraries. diff --git a/comfortable_swipe/res/comfortable-swipe.desktop b/comfortable_swipe/res/comfortable-swipe.desktop new file mode 100644 index 0000000..fc0cf02 --- /dev/null +++ b/comfortable_swipe/res/comfortable-swipe.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Type=Application +Exec=comfortable-swipe start +Hidden=false +NoDisplay=false +X-GNOME-Autostart-enabled=true +Name=Comfortable Swipe +Comment=3 or 4 finger swipe gestures diff --git a/defaults.conf b/comfortable_swipe/res/defaults.conf similarity index 99% rename from defaults.conf rename to comfortable_swipe/res/defaults.conf index 7d201e3..9bb095b 100644 --- a/defaults.conf +++ b/comfortable_swipe/res/defaults.conf @@ -5,59 +5,46 @@ # # Refer to https://www.linux.org/threads/xdotool-keyboard.10528/ for a list of # keycodes you can use. - ################# # MISCELLANEOUS # ################# - # Threshold # Tweak this value depending on the sensitivity of your mousepad to perform # gestures. A higher value means less sensitive. -# # (Note: Sky is the limit! Can be as large as 1000.0) -# # Default: threshold = 0.0 threshold = 0.0 - ############################# # THREE / FOUR FINGER SWIPE # ############################# - # 3-finger swipe left # The default shortcut is switching to the right workspace. # Default: left3 = ctrl+alt+Right left3 = ctrl+alt+Right - -# 4-finger swipe left -# The default shortcut is moving current window to the right workspace. -# Default: left4=ctrl+alt+shift+Right -left4 = ctrl+alt+shift+Right - # 3-finger swipe right # The default shortcut is switching to the left workspace. # Default: right3 = ctrl+alt+Left right3 = ctrl+alt+Left - +# 4-finger swipe left +# The default shortcut is moving current window to the right workspace. +# Default: left4=ctrl+alt+shift+Right +left4 = ctrl+alt+shift+Right # 4-finger swipe right # The default shortcut is moving current window to the left workspace. # Default: right4=ctrl+alt+shift+Left right4 = ctrl+alt+shift+Left - # 3-finger swipe up # The default shortcut is switching to the workspace below. # Default: up3 = ctrl+alt+Down up3 = ctrl+alt+Down - -# 4-finger swipe up -# The default shortcut is moving current window to the bottom workspace. -# Default: ctrl+alt+shift+Down -up4 = ctrl+alt+shift+Down - # 3-finger swipe down # The default shortcut is switching to the workspace above. # Default: down3 = ctrl+alt+Up down3 = ctrl+alt+Up - +# 4-finger swipe up +# The default shortcut is moving current window to the bottom workspace. +# Default: ctrl+alt+shift+Down +up4 = ctrl+alt+shift+Down # 4-finger swipe down # The default shortcut is moving current window to the above workspace. # Default: ctrl+alt+shift+Up diff --git a/comfortable_swipe/status.py b/comfortable_swipe/status.py new file mode 100644 index 0000000..6a51500 --- /dev/null +++ b/comfortable_swipe/status.py @@ -0,0 +1,22 @@ +from __future__ import print_function + +import os + +from comfortable_swipe import autostart +from comfortable_swipe.cpp import service +from comfortable_swipe.constants import NAME, exe + +def print_status(): + service.status() + print('autostart is', autostart.get_status().upper()) + print('{} program is {}'.format(NAME, 'RUNNING' if is_running() else 'STOPPED')) + + +def is_running(): + import psutil + for process in psutil.process_iter(): + process_args = [process.name()] + process.cmdline() + for index in range(len(process_args) - 1): + if process_args[index + 1] == 'start' and process_args[index].endswith(NAME): + return True + return False diff --git a/cpp/_index.cpp b/cpp/_index.cpp new file mode 100644 index 0000000..e274cfb --- /dev/null +++ b/cpp/_index.cpp @@ -0,0 +1,8 @@ +#ifndef __COMFORTABLE_SWIPE__index_cpp__ +#define __COMFORTABLE_SWIPE__index_cpp__ + +#include "gesture/_index.cpp" +#include "service/_index.cpp" +#include "util/_index.cpp" + +#endif /* __COMFORTABLE_SWIPE__index_cpp__ */ diff --git a/cpp/_index.hpp b/cpp/_index.hpp new file mode 100644 index 0000000..ce0849d --- /dev/null +++ b/cpp/_index.hpp @@ -0,0 +1,8 @@ +#ifndef __COMFORTABLE_SWIPE__index_hpp__ +#define __COMFORTABLE_SWIPE__index_hpp__ + +#include "gesture/_index.hpp" +#include "service/_index.hpp" +#include "util/_index.hpp" + +#endif /* __COMFORTABLE_SWIPE__index_hpp__ */ diff --git a/cpp/_macro.cpp b/cpp/_macro.cpp new file mode 100644 index 0000000..bffa78a --- /dev/null +++ b/cpp/_macro.cpp @@ -0,0 +1,12 @@ +#ifndef __COMFORTABLE_SWIPE__macro_hpp__ +#define __COMFORTABLE_SWIPE__macro_hpp__ + +#ifndef COMFORTABLE_SWIPE_CONFIG +#error "COMFORTABLE_SWIPE_CONFIG must be defined." +#endif /* COMFORTABLE_SWIPE_CONFIG */ + +#ifndef COMFORTABLE_SWIPE_VERSION +#warning "COMFORTABLE_SWIPE_VERSION is not defined." +#endif /* COMFORTABLE_SWIPE_VERSION */ + +#endif /* __COMFORTABLE_SWIPE__macro_hpp__ */ diff --git a/cpp/_python.cpp b/cpp/_python.cpp new file mode 100644 index 0000000..4f1cd9a --- /dev/null +++ b/cpp/_python.cpp @@ -0,0 +1,7 @@ +#ifndef __COMFORTABLE_SWIPE__python_cpp__ +#define __COMFORTABLE_SWIPE__python_cpp__ + +#include "service/_python.cpp" +#include "comfortable-swipe.cpp" + +#endif /* __COMFORTABLE_SWIPE__python_cpp__ */ diff --git a/cpp/comfortable-swipe b/cpp/comfortable-swipe new file mode 100644 index 0000000..6465c73 --- /dev/null +++ b/cpp/comfortable-swipe @@ -0,0 +1 @@ +#include "comfortable-swipe.cpp" diff --git a/lib/util/conf_filename.cpp b/cpp/comfortable-swipe.cpp similarity index 62% rename from lib/util/conf_filename.cpp rename to cpp/comfortable-swipe.cpp index 5de5ae9..1f10dd1 100644 --- a/lib/util/conf_filename.cpp +++ b/cpp/comfortable-swipe.cpp @@ -1,5 +1,5 @@ -#ifndef __COMFORTABLE_SWIPE__util_conf_filename__ -#define __COMFORTABLE_SWIPE__util_conf_filename__ +#ifndef __COMFORTABLE_SWIPE__ +#define __COMFORTABLE_SWIPE__ /* Comfortable Swipe @@ -19,17 +19,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "../index.hpp" +#include "_macro.cpp" +#include "_index.hpp" +#include "_index.cpp" -namespace comfortable_swipe::util -{ - /** - * The path where the configuration file is located. - */ - constexpr const char* conf_filename() - { - return __COMFORTABLE_SWIPE__CONFIG__; - } -} - -#endif /* __COMFORTABLE_SWIPE__util_conf_filename__ */ +#endif /* __COMFORTABLE_SWIPE__ */ diff --git a/cpp/gesture/_index.cpp b/cpp/gesture/_index.cpp new file mode 100644 index 0000000..5de8bb2 --- /dev/null +++ b/cpp/gesture/_index.cpp @@ -0,0 +1,9 @@ +#ifndef __COMFORTABLE_SWIPE__gesture_index_cpp__ +#define __COMFORTABLE_SWIPE__gesture_index_cpp__ + +#include "_index.hpp" +#include "xdo_gesture.cpp" +#include "swipe_gesture.cpp" +#include "swipe_gesture.regex.cpp" + +#endif /* __COMFORTABLE_SWIPE__gesture_index_cpp__ */ diff --git a/cpp/gesture/_index.hpp b/cpp/gesture/_index.hpp new file mode 100644 index 0000000..9c097c5 --- /dev/null +++ b/cpp/gesture/_index.hpp @@ -0,0 +1,7 @@ +#ifndef __COMFORTABLE_SWIPE__gesture_index_hpp__ +#define __COMFORTABLE_SWIPE__gesture_index_hpp__ + +#include "xdo_gesture.h" +#include "swipe_gesture.h" + +#endif /* __COMFORTABLE_SWIPE__gesture_index_hpp__ */ diff --git a/lib/gesture/swipe_gesture.cpp b/cpp/gesture/swipe_gesture.cpp similarity index 99% rename from lib/gesture/swipe_gesture.cpp rename to cpp/gesture/swipe_gesture.cpp index a8ba7c9..9056911 100644 --- a/lib/gesture/swipe_gesture.cpp +++ b/cpp/gesture/swipe_gesture.cpp @@ -22,6 +22,7 @@ along with this program. If not, see . #include // std::cout, std::endl #include // std::stoi, std::stof #include // std::regex, std::regex_match, std::cmatch +#include #include "swipe_gesture.h" extern "C" @@ -140,8 +141,6 @@ namespace comfortable_swipe::gesture */ bool swipe_gesture::parse_line(const char * line) { - - // prepare regex matchers (will only load at most once) static const std::regex gesture_swipe_begin(swipe_gesture::GESTURE_BEGIN_REGEX_PATTERN); static const std::regex gesture_swipe_update(swipe_gesture::GESTURE_UPDATE_REGEX_PATTERN); static const std::regex gesture_swipe_end(swipe_gesture::GESTURE_END_REGEX_PATTERN); diff --git a/lib/gesture/swipe_gesture.h b/cpp/gesture/swipe_gesture.h similarity index 100% rename from lib/gesture/swipe_gesture.h rename to cpp/gesture/swipe_gesture.h diff --git a/lib/gesture/swipe_gesture.regex.cpp b/cpp/gesture/swipe_gesture.regex.cpp similarity index 100% rename from lib/gesture/swipe_gesture.regex.cpp rename to cpp/gesture/swipe_gesture.regex.cpp diff --git a/lib/gesture/xdo_gesture.cpp b/cpp/gesture/xdo_gesture.cpp similarity index 100% rename from lib/gesture/xdo_gesture.cpp rename to cpp/gesture/xdo_gesture.cpp diff --git a/lib/gesture/xdo_gesture.h b/cpp/gesture/xdo_gesture.h similarity index 100% rename from lib/gesture/xdo_gesture.h rename to cpp/gesture/xdo_gesture.h diff --git a/cpp/service/_index.cpp b/cpp/service/_index.cpp new file mode 100644 index 0000000..3aeb559 --- /dev/null +++ b/cpp/service/_index.cpp @@ -0,0 +1,13 @@ +#ifndef __COMFORTABLE_SWIPE__service_index_cpp__ +#define __COMFORTABLE_SWIPE__service_index_cpp__ + +#include "_index.hpp" +#include "buffer.cpp" +#include "debug.cpp" +#include "help.cpp" +#include "restart.cpp" +#include "start.cpp" +#include "status.cpp" +#include "stop.cpp" + +#endif /* __COMFORTABLE_SWIPE__service_index_cpp__ */ diff --git a/cpp/service/_index.hpp b/cpp/service/_index.hpp new file mode 100644 index 0000000..25af404 --- /dev/null +++ b/cpp/service/_index.hpp @@ -0,0 +1,24 @@ +#ifndef __COMFORTABLE_SWIPE__service_index_hpp__ +#define __COMFORTABLE_SWIPE__service_index_hpp__ + +#include // std::map +#include // std::string + +extern "C" +{ + namespace comfortable_swipe + { + namespace service + { + void buffer(); + void debug(); + void help(); + void restart(); + void start(); + void stop(); + void status(); + } + } +} + +#endif /* __COMFORTABLE_SWIPE__service_index_hpp__ */ diff --git a/cpp/service/_python.cpp b/cpp/service/_python.cpp new file mode 100644 index 0000000..1316948 --- /dev/null +++ b/cpp/service/_python.cpp @@ -0,0 +1,82 @@ +#ifndef __COMFORTABLE_SWIPE__service_python__ +#define __COMFORTABLE_SWIPE__service_python__ + +#include "_index.hpp" +#include + +// export as python module +namespace comfortable_swipe::service::python +{ + #define __comfortable_swipe_void_method(method) \ + static PyObject * \ + method(PyObject * self, PyObject * args) \ + { \ + comfortable_swipe::service::method(); \ + Py_RETURN_NONE; \ + } + + // create the python method signatures + __comfortable_swipe_void_method(status); + __comfortable_swipe_void_method(start); + __comfortable_swipe_void_method(stop); + __comfortable_swipe_void_method(restart); + // __comfortable_swipe_void_method(autostart); + __comfortable_swipe_void_method(buffer); + __comfortable_swipe_void_method(help); + // __comfortable_swipe_void_method(config); + __comfortable_swipe_void_method(debug); + + #undef __comfortable_swipe_void_method + + // create the method list for C++ + static PyMethodDef methods[] = + { + { "status", &status, METH_VARARGS , "checks status of program, autostart, and config" }, + { "start", &start, METH_VARARGS , "starts 3/4-finger gesture service" }, + { "stop", &stop, METH_VARARGS , "stops 3/4-finger gesture service" }, + { "restart", &restart, METH_VARARGS , "stops then starts 3/4-finger gesture service" }, + // { "autostart", &autostart, METH_VARARGS , "automatically run on startup (toggleable)" }, + { "buffer", &buffer, METH_VARARGS , "parses output of libinput debug-events" }, + { "help", &help, METH_VARARGS , "shows the help dialog" }, + // { "config", &config, METH_VARARGS , "locates the config file " }, + { "debug", &debug, METH_VARARGS , "logs raw output from input events taken from libinput" }, + { NULL, NULL, 0, NULL } // sentinel + }; + + // create the module configuration + #if PY_MAJOR_VERSION >= 3 + static struct PyModuleDef module_def = + { + PyModuleDef_HEAD_INIT, + "service", + "Comfortable swipe service", + -1, + methods + }; + #endif + + PyObject * module; +} + +// initialize module +#if PY_MAJOR_VERSION >= 3 + PyMODINIT_FUNC + PyInit_service(void) + { + using comfortable_swipe::service::python::module_def; + using comfortable_swipe::service::python::module; + if (module != NULL) return module; + return module = PyModule_Create(&module_def); + } +#else /* PY_MAJOR_VERSION < 3 */ + PyMODINIT_FUNC + initservice(void) + { + using comfortable_swipe::service::python::methods; + using comfortable_swipe::service::python::module; + if (module != NULL) return; + module = Py_InitModule("service", methods); + } +#endif /* PY_MAJOR_VERSION */ + +#endif /* __COMFORTABLE_SWIPE__service_python__ */ diff --git a/lib/service/buffer.cpp b/cpp/service/buffer.cpp similarity index 88% rename from lib/service/buffer.cpp rename to cpp/service/buffer.cpp index 7edd7b6..082943e 100644 --- a/lib/service/buffer.cpp +++ b/cpp/service/buffer.cpp @@ -19,9 +19,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "../_macro.cpp" +#include "../util/_index.hpp" +#include "../gesture/_index.hpp" #include // fgets_unlocked, stdin -#include // std::ios, std::cout, std::cin -#include "../index.hpp" /** * Starts the comfortable-swipe service by buffering libinput debug-events. @@ -30,13 +31,8 @@ namespace comfortable_swipe::service { void buffer() { - std::ios::sync_with_stdio(false); - std::cin.tie(0); - std::cout.tie(0); - std::cout.flush(); - // read config file - auto config = comfortable_swipe::util::read_config_file(comfortable_swipe::util::conf_filename()); + auto config = comfortable_swipe::util::read_config_file(COMFORTABLE_SWIPE_CONFIG); // initialize swipe gesture handler comfortable_swipe::gesture::swipe_gesture swipe_gesture_handler diff --git a/lib/service/debug.cpp b/cpp/service/debug.cpp similarity index 100% rename from lib/service/debug.cpp rename to cpp/service/debug.cpp diff --git a/lib/service/help.cpp b/cpp/service/help.cpp similarity index 84% rename from lib/service/help.cpp rename to cpp/service/help.cpp index 80c2c85..68f9528 100644 --- a/lib/service/help.cpp +++ b/cpp/service/help.cpp @@ -20,7 +20,6 @@ along with this program. If not, see . */ #include // std::puts, std::printf -#include "../index.hpp" namespace comfortable_swipe::service { @@ -29,7 +28,6 @@ namespace comfortable_swipe::service */ void help() { - using comfortable_swipe::util::conf_filename; std::puts("comfortable-swipe [start|stop|restart|autostart|buffer|help|config|debug|status]"); std::puts(""); std::puts("start - starts 3/4-finger gesture service"); @@ -38,11 +36,9 @@ namespace comfortable_swipe::service std::puts("autostart - automatically run on startup (toggleable)"); std::puts("buffer - parses output of libinput debug-events"); std::puts("help - shows the help dialog"); - std::puts("config - locates the config file [/usr/share/comfortable-swipe/comfortable-swipe.conf]"); + std::puts("config - locates the config file"); std::puts("debug - logs raw output from input events taken from libinput"); std::puts("status - checks status of program and autostart"); - std::puts(""); - std::printf("Configuration file can be found in %s\n", conf_filename()); } } diff --git a/lib/service/restart.cpp b/cpp/service/restart.cpp similarity index 96% rename from lib/service/restart.cpp rename to cpp/service/restart.cpp index 28191c8..b66beb1 100644 --- a/lib/service/restart.cpp +++ b/cpp/service/restart.cpp @@ -19,7 +19,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "../index.hpp" +#include "../service/_index.hpp" namespace comfortable_swipe::service { diff --git a/lib/service/start.cpp b/cpp/service/start.cpp similarity index 58% rename from lib/service/start.cpp rename to cpp/service/start.cpp index 9ab566e..c7e0e50 100644 --- a/lib/service/start.cpp +++ b/cpp/service/start.cpp @@ -19,8 +19,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "../index.hpp" +#include "_index.hpp" +#include // std::cin, std::cout, std::ios #include // std::system +#include // pipe, fork, perror, exit namespace comfortable_swipe::service { @@ -31,7 +33,30 @@ namespace comfortable_swipe::service */ void start() { - (void) std::system(__COMFORTABLE_SWIPE__PROGRAM__ " debug | " __COMFORTABLE_SWIPE__PROGRAM__ " buffer"); + std::ios::sync_with_stdio(false); + std::cin.tie(0); + std::cout.tie(0); + std::cout.flush(); + + // redirect stdout to stdin + int fd[2]; + pipe(fd); // create the pipes + + int child; + if ((child = fork()) == -1) { + perror("fork"); + exit(EXIT_FAILURE); + } + if (child) { + dup2(fd[1], STDOUT_FILENO); + comfortable_swipe::service::debug(); + close(fd[0]); + } else { + dup2(fd[0], STDIN_FILENO); + comfortable_swipe::service::buffer(); + close(fd[1]); + } + comfortable_swipe::service::stop(); } } diff --git a/lib/service/status.cpp b/cpp/service/status.cpp similarity index 57% rename from lib/service/status.cpp rename to cpp/service/status.cpp index a084de4..0aae353 100644 --- a/lib/service/status.cpp +++ b/cpp/service/status.cpp @@ -19,7 +19,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "../index.hpp" +#include "../_macro.cpp" +#include "../util/_index.hpp" +#include "../gesture/_index.hpp" #include // std::runtime_error #include // popen, pclose, getpid, access, F_OK #include // std::unique_ptr @@ -35,45 +37,21 @@ namespace comfortable_swipe::service */ void status() { - // check if comfortable-swipe is running - bool running = false; - std::array buffer; - std::unique_ptr pipe(popen("pgrep -f comfortable-swipe", "r"), pclose); - if (pipe && !std::feof(pipe.get()) && std::fgets(buffer.data(), buffer.size(), pipe.get()) != NULL) - { - int pid = std::atoi(buffer.data()); - if (pid != getpid()) - running = true; - } - - // check if autostart is on - auto autostart_f = comfortable_swipe::util::autostart_filename(); - bool autostart_on = access(autostart_f, F_OK) != -1; - - // print status - std::printf("program is %s\n", running ? "ON" : "OFF"); - std::printf("autostart is %s\n", autostart_on ? "ON" : "OFF"); - std::printf("config file at %s\n", comfortable_swipe::util::conf_filename()); + // std::printf("autostart is %s\n", autostart_on ? "ON" : "OFF"); // check status of configuration file try { - auto config = comfortable_swipe::util::read_config_file(comfortable_swipe::util::conf_filename()); - - // print keys and values of config file - std::printf("\nConfigurations:\n"); - + std::puts(COMFORTABLE_SWIPE_CONFIG); + auto config = comfortable_swipe::util::read_config_file(COMFORTABLE_SWIPE_CONFIG); // print threshold if (config.count("threshold") > 0) { auto & threshold = config["threshold"]; - - // check if regex pattern matches threshold - std::cmatch matches; - bool ok = (std::regex_match(threshold.data(), matches, std::regex("^\\d+(?:\\.\\d+)??$")) != 0); - + // std::cmatch matches; + // bool ok = (std::regex_match(threshold.data(), matches, std::regex("^\\d+(?:\\.\\d+)??$")) != 0); // print status of threshold - std::printf(" %9s is %s (%s)\n", "threshold", ok ? "OK" : "INVALID", threshold.data()); + std::printf(" %9s = %s\n", "threshold", threshold.data()); // ok ? "VALID" : "INVALID" } else std::printf(" %9s is OFF\n", "threshold"); @@ -82,9 +60,9 @@ namespace comfortable_swipe::service for (auto &command : comfortable_swipe::gesture::swipe_gesture::command_map) { if (config.count(command) > 0) - std::printf(" %9s is OK (%s)\n", command, config[command].data()); + std::printf(" %9s = %s\n", command, config[command].data()); else - std::printf(" %9s is OFF\n", command); + std::printf(" %9s NOT SET\n", command); } } catch (const std::runtime_error& e) diff --git a/lib/service/stop.cpp b/cpp/service/stop.cpp similarity index 100% rename from lib/service/stop.cpp rename to cpp/service/stop.cpp diff --git a/cpp/util/_index.cpp b/cpp/util/_index.cpp new file mode 100644 index 0000000..6dc6d8c --- /dev/null +++ b/cpp/util/_index.cpp @@ -0,0 +1,7 @@ +#ifndef __COMFORTABLE_SWIPE__util_index_cpp__ +#define __COMFORTABLE_SWIPE__util_index_cpp__ + +#include "_index.hpp" +#include "read_config_file.cpp" + +#endif /* __COMFORTABLE_SWIPE__util_index_cpp__ */ diff --git a/cpp/util/_index.hpp b/cpp/util/_index.hpp new file mode 100644 index 0000000..2fbfe7b --- /dev/null +++ b/cpp/util/_index.hpp @@ -0,0 +1,18 @@ +#ifndef __COMFORTABLE_SWIPE__util_index_hpp__ +#define __COMFORTABLE_SWIPE__util_index_hpp__ + +#include // std::map +#include // std::string + +extern "C" +{ + namespace comfortable_swipe + { + namespace util + { + std::map read_config_file(const char*); + } + } +} + +#endif /* __COMFORTABLE_SWIPE__util_index_hpp__ */ diff --git a/lib/util/read_config_file.cpp b/cpp/util/read_config_file.cpp similarity index 100% rename from lib/util/read_config_file.cpp rename to cpp/util/read_config_file.cpp diff --git a/install b/install deleted file mode 100755 index 9de80c6..0000000 --- a/install +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/bash -# prefer running as root -DIR=$(dirname $0) -PROGRAM=/usr/local/bin/comfortable-swipe -COMPILE=$DIR/comfortable-swipe.compile.sh -CONF_PATH=/usr/local/share/comfortable-swipe/comfortable-swipe.conf -DCONF_PATH=$DIR/defaults.conf -OLD_CONF_PATH=${XDG_CONFIG_HOME:-$HOME/.config}/comfortable-swipe.conf - -if [ -x "$(command -v $PROGRAM)" ]; then - # stop any running comfortable-swipe if it exists - $PROGRAM stop -fi - -#copy config file -abort () { - exec echo "Installation aborted" -} -sudo mkdir -p $(dirname $CONF_PATH) || abort - -# check if "-y" or "--yes" is passed as an argument -YES=false -while test $# -gt 0 -do - case "$1" in - -y) YES=true - ;; - --yes) YES=true - ;; - esac - shift -done - -sudo chown $USER $(dirname $CONF_PATH) -if [ ! -f $CONF_PATH ]; then - if [ ! -f $OLD_CONF_PATH ]; then - # old config file not found, create from scratch - cat $DCONF_PATH > $CONF_PATH || abort - else - # old config file found, move to the new path - cat $OLD_CONF_PATH > $CONF_PATH || abort - echo "Configuration copied from $OLD_CONF_PATH to $CONF_PATH" - fi -else - # config file found, ask user if overwrite - echo "Old conf file found in $CONF_PATH" - if [ $YES == false ]; then - read -r -p "Keep the old conf file? (default: yes) [Y/n] " response - response=${response,,} # tolower - if [[ "$response" =~ ^(no|n)$ ]]; then - read -r -p "Conf file will be overwritten. Are you sure? [Y/n] " response - response=${response,,} - if [[ "$response" =~ ^(yes|y)$ ]]; then - cat $DCONF_PATH > $CONF_PATH || abort - else - abort - fi - fi - fi -fi - -echo "Installing..." - -# remove existing comfortable-swipe -if [ -x "$(command -v $PROGRAM)" ]; then - sudo rm -f $(which comfortable-swipe) -fi - -# compile library -sudo $COMPILE $PROGRAM || abort - -# add permissions to input group (defer) -# GROUP=$(ls -l /dev/input/event* | awk '{print $4}' | head --line=1) || abort - -# toggle autostart twice to refresh any changes -$PROGRAM autostart > /dev/null || abort -$PROGRAM autostart > /dev/null || abort - -echo "Successfully installed comfortable-swipe." -echo "Configuration file is located at $CONF_PATH" -echo "" -echo "Try running 'comfortable-swipe start' to test." diff --git a/lib/comfortable_swipe b/lib/comfortable_swipe deleted file mode 100644 index 3ee260a..0000000 --- a/lib/comfortable_swipe +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef __COMFORTABLE_SWIPE__ -#define __COMFORTABLE_SWIPE__ - -/* -Comfortable Swipe -by Rico Tiongson - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "index.hpp" - -/** - * Make sure to include all implementation (.cpp) files below to be ready for export. - */ - -#include "gesture/xdo_gesture.cpp" -#include "gesture/swipe_gesture.cpp" -#include "gesture/swipe_gesture.regex.cpp" -#include "service/autostart.cpp" -#include "service/buffer.cpp" -#include "service/config.cpp" -#include "service/debug.cpp" -#include "service/help.cpp" -#include "service/restart.cpp" -#include "service/start.cpp" -#include "service/status.cpp" -#include "service/stop.cpp" -#include "util/autostart_filename.cpp" -#include "util/conf_filename.cpp" -#include "util/read_config_file.cpp" - -#endif /* __COMFORTABLE_SWIPE__ */ diff --git a/lib/index.hpp b/lib/index.hpp deleted file mode 100644 index b54cc3e..0000000 --- a/lib/index.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef __COMFORTABLE_SWIPE__index_hpp__ -#define __COMFORTABLE_SWIPE__index_hpp__ - -/* -Comfortable Swipe -by Rico Tiongson - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -// global defines -#ifndef __COMFORTABLE_SWIPE__PROGRAM__ -#define __COMFORTABLE_SWIPE__PROGRAM__ "/usr/local/bin/comfortable-swipe" -#endif /* __COMFORTABLE_SWIPE__PROGRAM__ */ - -#ifndef __COMFORTABLE_SWIPE__CONFIG__ -#define __COMFORTABLE_SWIPE__CONFIG__ "/usr/local/share/comfortable-swipe/comfortable-swipe.conf" -#endif /* __COMFORTABLE_SWIPE__CONFIG__ */ - -#include // std::map -#include // std::string - -/** - * Make sure to include your header files here so that they can be imported by other modules. - */ -#include "gesture/xdo_gesture.h" -#include "gesture/swipe_gesture.h" -extern "C" -{ - namespace comfortable_swipe - { - namespace util - { - const char* autostart_filename(); - constexpr const char* conf_filename(); - std::map read_config_file(const char*); - } - namespace service - { - void autostart(); - void buffer(); - void config(); - void debug(); - void help(); - void restart(); - void start(); - void status(); - void stop(); - } - } -} - -#endif /* __COMFORTABLE_SWIPE__index_hpp__ */ diff --git a/lib/service/autostart.cpp b/lib/service/autostart.cpp deleted file mode 100644 index 1a4575f..0000000 --- a/lib/service/autostart.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef __COMFORTABLE_SWIPE__service_autostart__ -#define __COMFORTABLE_SWIPE__service_autostart__ - -/* -Comfortable Swipe -by Rico Tiongson - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include // std::cerr, std::cout, std::endl -#include // std::ifstream, std::ofstream -#include // std::string -#include // std::remove -#include // std::system -#include "../index.hpp" - -namespace comfortable_swipe::service -{ - /** - * Toggles automatic startup of comfortable swipe. - */ - void autostart() - { - using comfortable_swipe::util::autostart_filename; - - const std::string& path = autostart_filename(); - if (std::ifstream(path.data()).good()) - { - // file found, delete it - if (std::remove(path.data()) != 0) - std::cerr << "Error: failed to switch off autostart. " - << "Maybe the autostart file is in use?" - << std::endl; - else - std::cout << "Autostart switched off" << std::endl; - } - else { - // file not found, create it - int result = std::system(("mkdir -p $(dirname " + path + ")").data()); - std::ofstream fout(path.data()); - if (result != 0 || !fout.good()) - std::cerr << "Error: failed to switch on autostart. " - << "Are you sure you have the permissions?" - << std::endl; - else { - fout << - "[Desktop Entry]\n" - "Type=Application\n" - "Exec=bash -c \"" - __COMFORTABLE_SWIPE__PROGRAM__ - " start\"\n" - "Hidden=false\n" - "NoDisplay=false\n" - "X-GNOME-Autostart-enabled=true\n" - "Name=Comfortable Swipe\n" - "Comment=3 or 4 touchpad gestures\n"; - std::cout << "Autostart switched on" << std::endl; - } - } - } -} - -#endif /* __COMFORTABLE_SWIPE__service_autostart__ */ diff --git a/lib/service/config.cpp b/lib/service/config.cpp deleted file mode 100644 index 6bb02bd..0000000 --- a/lib/service/config.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef __COMFORTABLE_SWIPE__service_config__ -#define __COMFORTABLE_SWIPE__service_config__ - -/* -Comfortable Swipe -by Rico Tiongson - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "../index.hpp" -#include // std::puts - -namespace comfortable_swipe::service -{ - /** - * Prints where the config file of comfortable swipe is located. - * - * Usage: nano $(comfortable-swipe config) - */ - void config() - { - std::puts(comfortable_swipe::util::conf_filename()); - } -} - -#endif /* __COMFORTABLE_SWIPE__service_config__ */ diff --git a/lib/util/autostart_filename.cpp b/lib/util/autostart_filename.cpp deleted file mode 100644 index d3b0046..0000000 --- a/lib/util/autostart_filename.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef __COMFORTABLE_SWIPE__util_autostart_filename__ -#define __COMFORTABLE_SWIPE__util_autostart_filename__ - -/* -Comfortable Swipe -by Rico Tiongson - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include // std::string -#include // getenv - -namespace comfortable_swipe::util -{ - /** - * The path where the autostart configuration is located. - */ - const char* autostart_filename() - { - static std::string filename; - if (filename.empty()) { - const char* xdg_config = getenv("XDG_CONFIG_HOME"); - std::string config( - xdg_config == NULL - ? std::string(getenv("HOME")) + "/.config" - : xdg_config - ); - filename = config + "/autostart/comfortable-swipe.desktop"; - } - return filename.data(); - } -} - -#endif /* __COMFORTABLE_SWIPE__util_autostart_filename__ */ diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..e92b294 --- /dev/null +++ b/setup.py @@ -0,0 +1,158 @@ +from __future__ import print_function + +import os +import sys +import setuptools + +from shutil import copyfile +from setuptools import setup, find_packages +from setuptools.extension import Extension +from setuptools.command.develop import develop +from setuptools.command.install import install +from setuptools.command.easy_install import easy_install +from wheel.bdist_wheel import bdist_wheel + + +VERSION = '1.1.0-beta' +__CWD__ = os.getcwd() +__DIR__ = os.path.dirname(os.path.abspath(__file__)) +__URL__ = 'https://github.com/Hikari9/comfortable-swipe-ubuntu' + +extension_names = ['service'] + + + +try: + # make sure working directory is here + os.chdir(__DIR__) + + + # save README as long_description + with open('README.md', 'r') as README_file: + README = README_file.read() + + + # match constants with source + from comfortable_swipe.constants import * + + # include old conf paths to list from previous versions + conf_paths = [ + DEFAULT_CONFIG, + os.path.join(os.getenv('HOME', ''), '.config', 'comfortable-swipe', 'comfortable-swipe.conf'), + os.path.join('/usr/local/share', 'comfortable-swipe', 'comfortable-swipe.conf'), + CONFIG + ] + + # for C++ library + cpp_macros = dict( + COMFORTABLE_SWIPE_VERSION='"{}"'.format(VERSION), + COMFORTABLE_SWIPE_CONFIG='"{}"'.format(CONFIG) + ) + + # read C++ libraries for comfortable swipe + extensions = [Extension( + name='{}.cpp.{}'.format(PYTHON_NAME, extension_name), + define_macros=list(cpp_macros.items()), + sources=[os.path.join('cpp', '_python.cpp')], + extra_compile_args=['-O2', '-Wno-unused-result'], + libraries=['xdo'] + ) for extension_name in extension_names] + + + class Command: + outer_installer = None + outer_uninstaller = None + + def pre_install(self): + # make sure only outer install script will run post_install + if self.__class__.outer_installer is not None: return + self.__class__.outer_installer = self + print('running pre_install') + + def post_install(self): + # make sure post_install will only run when command is outer installer + if self.__class__.outer_installer is not self: return + print('running post_install') + + # create program/config directories + if not os.path.exists(os.path.dirname(CONFIG)): + os.makedirs(os.path.dirname(CONFIG)) + + # copy any of the old config files + conf_files = [path for path in conf_paths if os.path.exists(path) and os.path.isfile(path)] + print('Using configuration file at', conf_files[-1]) + + if conf_files[-1] != CONFIG: + # new installation or upgrading from old version, copy to new location + copyfile(conf_files[-1], CONFIG) + if conf_files[-1] == DEFAULT_CONFIG: + # new installation - copy default configuration + print('Copying configuration file to', CONFIG) + else: + # upgrading - delete the deprecated config file (failsafe) + print('warning: depcrecated configuration file at', conf_files[-1]) + print(' you have to remove this manually') + + # enable autostart by default + from comfortable_swipe import autostart + autostart.set_status(autostart.ON) + print('Autostart created at', autostart.target_path()) + print('\nInstallation successful\nTry running: {} start'.format(NAME)) + + def pre_uninstall(self): + # make sure only outer uninstall script will run post_uninstall + if self.__class__.outer_uninstaller is not None: return + self.__class__.outer_uninstaller = self + print('running pre_uninstall') + + + def post_uninstall(self): + # make sure post_uninstall will only run when command is outer uninstaller + if self.__class__.outer_uninstaller is not self: return + print('running post_uninstall') + from comfortable_swipe import autostart + if autostart.get_status() is autostart.ON: + print('Removing autostart at', autostart.target_path()) + autostart.set_status(autostart.OFF) + + # add post_install script to install method + def wrap_command(base_cls, uninstall=False): + class InstallCommand(Command, base_cls): + def run(self): + self.pre_uninstall() if uninstall and self.uninstall else self.pre_install() + base_cls.run(self) + self.post_uninstall() if uninstall and self.uninstall else self.post_install() + + InstallCommand.__name__ = base_cls.__name__ + return InstallCommand + + # Override command classes here + cmdclass = dict( + install=wrap_command(install), + easy_install=wrap_command(easy_install), + develop=wrap_command(develop, uninstall=True), + bdist_wheel=wrap_command(bdist_wheel) + ) + + # setup python script + setup_script = setup( + name=NAME, + version=VERSION, + description=DESCRIPTION, + long_description=README, + license='MIT', + author='Rico Tiongson', + author_email='thericotiongson@gmail.com', + url=__URL__, + zip_safe=False, + packages=find_packages(), + include_package_data=True, + entry_points=dict(console_scripts=['{}={}.__main__:main'.format(NAME, PYTHON_NAME)]), + ext_modules=extensions, + cmdclass=cmdclass, + install_requires=['psutil'] + ) + +finally: + # move working directory back to where it was before + os.chdir(__CWD__) diff --git a/uninstall b/uninstall deleted file mode 100644 index 900c2f5..0000000 --- a/uninstall +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -echo "Uninstalling..." -rm ${XDG_CONFIG_HOME:-$HOME/.config}/autostart/comfortable-swipe.desktop 2> /dev/null -comfortable-swipe stop 2> /dev/null -rm $HOME/.local/bin/comfortable-swipe 2> /dev/null # compat -sudo rm /usr/local/bin/comfortable-swipe 2> /dev/null -echo "Successfully uninstalled comfortable-swipe"