Repository: mcpcpc/xwm Branch: main Commit: 8f79d3d69709 Files: 12 Total size: 23.3 KB Directory structure: gitextract_sdyjtq5f/ ├── .github/ │ ├── CONTRIBUTING │ ├── FUNDING.yml │ └── workflows/ │ └── codacy-analysis.yml ├── .gitignore ├── CHANGELOG ├── LICENSE ├── Makefile ├── README ├── config.h ├── xwm.1 ├── xwm.c └── xwm.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/CONTRIBUTING ================================================ CONTRIBUTING ============ Want to contribute? Great! First, read this page. Code reviews: * All submissions, including submissions by project members, require review. We use Github pull requests for this purpose. Some tips for good pull requests: * Use our code. When in doubt, try to stay true to the existing code of the project. * Write a descriptive commit message. What problem are you solving and what are the consequences? Where and what did you test? Some good tips: http://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message https://www.kernel.org/doc/Documentation/SubmittingPatches * If your PR consists of multiple commits which are successive improvements / fixes to your first commit, consider squashing them into a single commit (`git rebase -i`) such that your PR is a single commit on top of the current HEAD. This make reviewing the code so much easier, and our history more readable. ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: mcpcpc patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username custom: https://www.paypal.me/mcpcpc/usd5 ================================================ FILE: .github/workflows/codacy-analysis.yml ================================================ # This workflow checks out code, performs a Codacy security scan # and integrates the results with the # GitHub Advanced Security code scanning feature. For more information on # the Codacy security scan action usage and parameters, see # https://github.com/codacy/codacy-analysis-cli-action. # For more information on Codacy Analysis CLI in general, see # https://github.com/codacy/codacy-analysis-cli. name: Codacy Security Scan on: push: branches: [ main ] pull_request: branches: [ main ] jobs: codacy-security-scan: name: Codacy Security Scan runs-on: ubuntu-latest steps: # Checkout the repository to the GitHub Actions runner - name: Checkout code uses: actions/checkout@v2 # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis - name: Run Codacy Analysis CLI uses: codacy/codacy-analysis-cli-action@1.1.0 with: # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository # You can also omit the token and run the tools that support default configurations project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} verbose: true output: results.sarif format: sarif # Adjust severity of non-security issues gh-code-scanning-compat: true # Force 0 exit code to allow SARIF file generation # This will handover control about PR rejection to the GitHub side max-allowed-issues: 2147483647 # Upload the SARIF file generated in the previous step - name: Upload SARIF results file uses: github/codeql-action/upload-sarif@v1 with: sarif_file: results.sarif ================================================ FILE: .gitignore ================================================ xwm *.a *.o ================================================ FILE: CHANGELOG ================================================ # Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [0.1.9] - 2022-01-25 ### Added - New year to LICENSE file. ### Removed - "PATCHES" section from the README. ###Fixed - Typographic errors in the CHANGELOG. ## [0.1.8] - 2021-03-14 ### Fixed - free(ev), which is called erroneously when ev might equal NULL. ### Removed - xcb_destroy_window call in the spawn(), which is unnecessary and, furthermore, not recommended per the developer documentation. ## [0.1.7] - 2021-03-03 ### Fixed - Memory leak due to xcb_wait_for_event() not being freed. - Order of the CHANGELOG (i.e. latest on top). ## [0.1.6] - 2020-12-28 ### Added - Window fullscreen command alias (default: Win+f). ## [0.1.5] - 2020-12-23 ### Removed - Unused root padding definitions. - xcb_wait_for_event() not being freed. ## [0.1.4] - 2020-12-22 ### Added - Raise focus command keys to xwm.1 and README. ### Changed - The "Features" section of the README to indicate audience. ### Removed - Pointer warp on window resize/move as this appears to be default. ### Fixed - Spelling and grammar in man page. ## [0.1.3] - 2020-11-30 ### Added - Instructions in README for Arch Linux AUR installation. ### Changed - Default new window location from top-left to center. ### Removed - Global root variable. - Removed leave notify event. ## [0.1.2] - 2020-11-23 ### Changed - Default surf start page to startpage.com. ### Fixed - Zombie reaping. ## [0.1.1] - 2020-11-21 ### Added - Makefile warnings (e.g. -Wall, Wextra, etc.). ## [0.1.0] - 2020-11-20 ### Fixed - MISRA 10.4 non-compliance. - Fix operator dependence. ## [0.0.9] - 2020-11-17 ### Fixed - Window resize lag. - Bug where window border moves outside of root window. ## [0.0.8] - 2020-11-16 ### Fixed - Window focus/unfocus on new window creation. ## [0.0.7] - 2020-11-13 ### Fixed - Border focus/unfocus when leaving a window. ## [0.0.6] - 2020-11-12 ### Added - Window borders and color definitions. ## [0.0.5] - 2020-11-11 ### Added - Default key bindings in man page. - Disclaimer section in README. ## [0.0.4] - 2020-11-10 ### Added - Instructions for patches and the patching process. - Minimum window height and width parameters. ### Removed - Unused stdarg.h library dependency. ### Fixed - Crash when pointer x/y cords less than window origin. ## [0.0.3] - 2020-11-08 ### Added - Examples in the config.h file. - Window height and width parameters. ### Removed - string.h library dependency. ## [0.0.2] - 2020-11-07 ### Added - Close window command (default: Win+q). ### Fixed - Resize crash in root window. ## [0.0.1] - 2020-11-06 ### Added - Initial release. ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2021-2022 Michael Czigler 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. ================================================ FILE: Makefile ================================================ .POSIX: ALL_WARNING = -Wall -Wextra -pedantic ALL_LDFLAGS = -lxcb -lxcb-keysyms $(LDFLAGS) ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) -std=c99 $(ALL_WARNING) PREFIX = /usr/local LDLIBS = -lm BINDIR = $(PREFIX)/bin MANDIR = $(PREFIX)/share/man all: xwm install: all mkdir -p $(DESTDIR)$(BINDIR) mkdir -p $(DESTDIR)$(MANDIR)/man1 cp -f xwm $(DESTDIR)$(BINDIR) cp -f xwm.1 $(DESTDIR)$(MANDIR)/man1 chmod 755 $(DESTDIR)$(BINDIR)/xwm chmod 644 $(DESTDIR)$(MANDIR)/man1/xwm.1 xwm: xwm.o $(CC) -o xwm xwm.o $(ALL_LDFLAGS) $(LDLIBS) xwm.o: xwm.c xwm.h config.h clean: rm -f xwm *.o uninstall: rm -f $(DESTDIR)$(BINDIR)/xwm rm -f $(DESTDIR)$(MANDIR)/man1/xwm.1 .PHONY: all install uninstall clean ================================================ FILE: README ================================================ xwm - a tiny XCB floating window manager ======================================== A minimal viable solution that was developed with single-monitor workflows in mind. Despite the small footprint, xwm maintains extensibility and can be customized to enhance the user experience. REQUIREMENTS ------------ xcb-util-keysyms, along with any default or user defined utilities: application launcher https://git.suckless.org/dmenu terminal emulator https://git.suckless.org/st internet browser https://git.suckless.org/surf COMMANDS -------- Default keys and behavior can be customized via the config.h file: Win+Button1 raise focused window to top of stack Win+Button3 raise focused window to top of stack Win+Button1+[drag] interactive window move Win+Button3+[drag] interactive window resize Win+Space run launcher menu (default: dmenu_run) Win+Enter create new terminal window (default: st) Win+b create new browser window (default: surf) Win+q kill focused window Win+f full-screen focused window Win+Shift+q quit window manager INSTALL ------- Building and installing from source: $ git clone https://github.com/mcpcpc/xwm $ cd xwm $ make $ sudo make install EXAMPLES -------- Checking the installed version of xwm: $ xwm -v Using startx to run xwm: $ echo "exec xwm" > ~/.xinitrc $ startx Using imagemagick to set a wallpaper: $ display -window root background.png Patching xwm: $ patch -p0 < mypatch.patch DISCLAIMER ---------- xwm ("XCB Window Manager") is an homage to the original and now-defunct "X Window Manager". Both projects are unaffiliated and do not share any common source code. CONTACT ------- For questions or issues, please contact michaelczigler[at]mcpcpc[dot]com. ================================================ FILE: config.h ================================================ /* DEFAULT KEYS * The following are the possible mask definitions. Note * that these definitions may vary between X implementations * and keyboard models. * XCB_MOD_MASK_1 -> Alt_L Alt_R Meta_L * XCB_MOD_MASK_2 -> Num_Lock * XCB_MOD_MASK_3 -> ISO_Level3_Shift * XCB_MOD_MASK_4 -> Super_L Super_R SuperL Hyper_L * XCB_MOD_MASK_5 -> ISO_Level5_Shifta * XCB_MOD_MASK_SHIFT * XCB_MOD_MASK_CONTROL * XCB_MOD_MASK_LOCK * XCB_MOD_MASK_ANY */ #define MOD1 XCB_MOD_MASK_4 #define MOD2 XCB_MOD_MASK_SHIFT /* DEFAULT WINDOW PROPERTIES * The following parameters can be used to change existing and new * window behavior. */ #define WINDOW_WIDTH 600 /* pixels */ #define WINDOW_HEIGHT 400 /* pixels */ #define WINDOW_MIN_WIDTH 60 /* pixels */ #define WINDOW_MIN_HEIGHT 40 /* pixels */ #define BORDER_WIDTH 1 /* 0 = no border effect */ #define BORDER_COLOR_UNFOCUSED 0x696969 /* 0xRRGGBB */ #define BORDER_COLOR_FOCUSED 0xFFFFFF /* 0xRRGGBB */ /* ALIASED COMMANDS * Each space delimited argument should be passed as an additional * value to the character pointer array. For example, to run * "foo -a bar", the array would be "{ "foo", "-a", "bar", NULL }". * Since execvp() is a variadic functions, each argument pointer must * be terminated by a NULL pointer. */ static char *termcmd[] = { "st", NULL }; static char *menucmd[] = { "dmenu_run", NULL }; static char *browcmd[] = { "surf", "https://startpage.com", NULL }; /* KEY ALIASES * In general, one shortcut key should exist per alias. For more key * definitions, refer to the keysymdef.h and XF86keysym.h headers. */ static Key keys[] = { { MOD1, 0x0062, spawn, browcmd }, /* 0x0062 = XK_b */ { MOD1, 0xff0d, spawn, termcmd }, /* 0xff0d = XK_Enter */ { MOD1, 0x0020, spawn, menucmd }, /* 0x0020 = XK_space */ { MOD1, 0x0066, fullclient, NULL }, /* 0x0066 = XK_f */ { MOD1, 0x0071, killclient, NULL }, /* 0x0071 = XK_q */ { MOD1|MOD2, 0x0071, closewm, NULL } /* 0x0071 = XK_q */ }; ================================================ FILE: xwm.1 ================================================ .\"Manpage for xwm. .TH XWM 1 "NOVEMBER 2020" Linux "User Manuals" .SH NAME xwm \- a tiny XCB floating window manager .SH SYNOPSIS .B xwm [-v] .SH DESCRIPTION .B xwm is a tiny floating window manager implemented using the XCB protocol. Other than .BR xcb-util-keysyms (1), xwm relies on third-party tools, which can be configured or expanded to meet the user's preference. The default configuration provides support and command aliases for the .BR surf (1) web browser, .BR st (1) terminal emulator and .BR dmenu (1) application launcher. .SH OPTIONS .IP -v Prints the current xwm version. .SH DEFAULT KEY BINDINGS .B xwm may be controlled from an attached client using a key combination of a prefix key, the 'Super' (Win) key by default, followed by a command key. .PP The default command key bindings are: .TS tab(;); lb l l. _ Super;MouseButton1;T{ Raise focused window to top of stack. T} _ Super;MouseButton3;T{ Raise focused window to top of stack. T} _ Super-MouseButton1;[drag];T{ Interactive window move. T} _ Super-MouseButton3;[drag];T{ Interactive window resize. T} _ Super;Space;T{ Run launcher menu (default: dmenu_run). T} _ Super;Enter;T{ Create new terminal window (default: st). T} _ Super;b;T{ Create new browser window (default: surf). T} _ Super;f;T{ Full-screen focused window. T} _ Super;q;T{ Kill focused window. T} _ Super-Shift;q;T{ Quite window manager. T} _ .TE .SH BUGS No known bugs. .SH AUTHOR Michael Czigler .SH "SEE ALSO" .BR libxcb (1), .BR st (1), .BR surf (1), .BR dmenu (1) ================================================ FILE: xwm.c ================================================ /* See LICENSE file for license details. */ #include #include #include #include #include #include "xwm.h" #include "config.h" #define UNUSED(x) (void)(x) static xcb_connection_t * dpy; static xcb_screen_t * scre; static xcb_drawable_t win; static uint32_t values[3]; static void killclient(char **com) { UNUSED(com); xcb_kill_client(dpy, win); } static void closewm(char **com) { UNUSED(com); if (dpy != NULL) { xcb_disconnect(dpy); } } static void spawn(char **com) { if (fork() == 0) { setsid(); if (fork() != 0) { _exit(0); } execvp((char*)com[0], (char**)com); _exit(0); } wait(NULL); } static void fullclient(char **com) { UNUSED(com); uint32_t vals[4]; vals[0] = 0 - BORDER_WIDTH; vals[1] = 0 - BORDER_WIDTH; vals[2] = scre->width_in_pixels; vals[3] = scre->height_in_pixels; xcb_configure_window(dpy, win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, vals); xcb_flush(dpy); } static void handleButtonPress(xcb_generic_event_t *ev) { xcb_button_press_event_t *e = (xcb_button_press_event_t *) ev; win = e->child; values[0] = XCB_STACK_MODE_ABOVE; xcb_configure_window(dpy, win, XCB_CONFIG_WINDOW_STACK_MODE, values); values[2] = ((1 == e->detail) ? 1 : ((win != 0) ? 3 : 0 )); xcb_grab_pointer(dpy, 0, scre->root, XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_POINTER_MOTION_HINT, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, scre->root, XCB_NONE, XCB_CURRENT_TIME); } static void handleMotionNotify(xcb_generic_event_t *ev) { UNUSED(ev); xcb_query_pointer_cookie_t coord = xcb_query_pointer(dpy, scre->root); xcb_query_pointer_reply_t *poin = xcb_query_pointer_reply(dpy, coord, 0); if ((values[2] == (uint32_t)(1)) && (win != 0)) { xcb_get_geometry_cookie_t geom_now = xcb_get_geometry(dpy, win); xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(dpy, geom_now, NULL); uint16_t geom_x = geom->width + (2 * BORDER_WIDTH); uint16_t geom_y = geom->height + (2 * BORDER_WIDTH); values[0] = ((poin->root_x + geom_x) > scre->width_in_pixels) ? (scre->width_in_pixels - geom_x) : poin->root_x; values[1] = ((poin->root_y + geom_y) > scre->height_in_pixels) ? (scre->height_in_pixels - geom_y) : poin->root_y; xcb_configure_window(dpy, win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values); } else if ((values[2] == (uint32_t)(3)) && (win != 0)) { xcb_get_geometry_cookie_t geom_now = xcb_get_geometry(dpy, win); xcb_get_geometry_reply_t* geom = xcb_get_geometry_reply(dpy, geom_now, NULL); if (!((poin->root_x <= geom->x) || (poin->root_y <= geom->y))) { values[0] = poin->root_x - geom->x - BORDER_WIDTH; values[1] = poin->root_y - geom->y - BORDER_WIDTH; if ((values[0] >= (uint32_t)(WINDOW_MIN_WIDTH)) && (values[1] >= (uint32_t)(WINDOW_MIN_HEIGHT))) { xcb_configure_window(dpy, win, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); } } } else {} } static xcb_keycode_t *xcb_get_keycodes(xcb_keysym_t keysym) { xcb_key_symbols_t *keysyms = xcb_key_symbols_alloc(dpy); xcb_keycode_t *keycode; keycode = (!(keysyms) ? NULL : xcb_key_symbols_get_keycode(keysyms, keysym)); xcb_key_symbols_free(keysyms); return keycode; } static xcb_keysym_t xcb_get_keysym(xcb_keycode_t keycode) { xcb_key_symbols_t *keysyms = xcb_key_symbols_alloc(dpy); xcb_keysym_t keysym; keysym = (!(keysyms) ? 0 : xcb_key_symbols_get_keysym(keysyms, keycode, 0)); xcb_key_symbols_free(keysyms); return keysym; } static void setFocus(xcb_drawable_t window) { if ((window != 0) && (window != scre->root)) { xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, window, XCB_CURRENT_TIME); } } static void setFocusColor(xcb_window_t window, int focus) { if ((BORDER_WIDTH > 0) && (scre->root != window) && (0 != window)) { uint32_t vals[1]; vals[0] = focus ? BORDER_COLOR_FOCUSED : BORDER_COLOR_UNFOCUSED; xcb_change_window_attributes(dpy, window, XCB_CW_BORDER_PIXEL, vals); xcb_flush(dpy); } } static void handleKeyPress(xcb_generic_event_t *ev) { xcb_key_press_event_t *e = ( xcb_key_press_event_t *) ev; xcb_keysym_t keysym = xcb_get_keysym(e->detail); win = e->child; int key_table_size = sizeof(keys) / sizeof(*keys); for (int i = 0; i < key_table_size; ++i) { if ((keys[i].keysym == keysym) && (keys[i].mod == e->state)) { keys[i].func(keys[i].com); } } } static void handleEnterNotify(xcb_generic_event_t *ev) { xcb_enter_notify_event_t *e = ( xcb_enter_notify_event_t *) ev; setFocus(e->event); } static void handleButtonRelease(xcb_generic_event_t *ev) { UNUSED(ev); xcb_ungrab_pointer(dpy, XCB_CURRENT_TIME); } static void handleDestroyNotify(xcb_generic_event_t *ev) { xcb_destroy_notify_event_t *e = (xcb_destroy_notify_event_t *) ev; xcb_kill_client(dpy, e->window); } static void handleFocusIn(xcb_generic_event_t *ev) { xcb_focus_in_event_t *e = (xcb_focus_in_event_t *) ev; setFocusColor(e->event, 1); } static void handleFocusOut(xcb_generic_event_t *ev) { xcb_focus_out_event_t *e = (xcb_focus_out_event_t *) ev; setFocusColor(e->event, 0); } static void handleMapRequest(xcb_generic_event_t *ev) { xcb_map_request_event_t *e = (xcb_map_request_event_t *) ev; xcb_map_window(dpy, e->window); uint32_t vals[5]; vals[0] = (scre->width_in_pixels / 2) - (WINDOW_WIDTH / 2); vals[1] = (scre->height_in_pixels / 2) - (WINDOW_HEIGHT / 2); vals[2] = WINDOW_WIDTH; vals[3] = WINDOW_HEIGHT; vals[4] = BORDER_WIDTH; xcb_configure_window(dpy, e->window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_BORDER_WIDTH, vals); xcb_flush(dpy); values[0] = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE; xcb_change_window_attributes_checked(dpy, e->window, XCB_CW_EVENT_MASK, values); setFocus(e->window); } static int eventHandler(void) { int ret = xcb_connection_has_error(dpy); if (ret == 0) { xcb_generic_event_t *ev = xcb_wait_for_event(dpy); if (ev != NULL) { handler_func_t *handler; for (handler = handler_funs; handler->func != NULL; handler++) { if ((ev->response_type & ~0x80) == handler->request) { handler->func(ev); } } free(ev); } } xcb_flush(dpy); return ret; } static void setup(void) { values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE; xcb_change_window_attributes_checked(dpy, scre->root, XCB_CW_EVENT_MASK, values); xcb_ungrab_key(dpy, XCB_GRAB_ANY, scre->root, XCB_MOD_MASK_ANY); int key_table_size = sizeof(keys) / sizeof(*keys); for (int i = 0; i < key_table_size; ++i) { xcb_keycode_t *keycode = xcb_get_keycodes(keys[i].keysym); if (keycode != NULL) { xcb_grab_key(dpy, 1, scre->root, keys[i].mod, *keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC ); } } xcb_flush(dpy); xcb_grab_button(dpy, 0, scre->root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, scre->root, XCB_NONE, 1, MOD1); xcb_grab_button(dpy, 0, scre->root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, scre->root, XCB_NONE, 3, MOD1); xcb_flush(dpy); } static int die(char *errstr) { size_t n = 0; char *p = errstr; while ((* (p++)) != 0) { ++n; } ssize_t o = write(STDERR_FILENO, errstr, n); int ret = 1; if (o < 0) { ret = -1; } return ret; } static int strcmp_c(char *str1, char *str2) { char *c1 = str1; char *c2 = str2; while ((* c1) && ((* c1) == (* c2))) { ++c1; ++c2; } int n = (* c1) - (* c2); return n; } int main(int argc, char *argv[]) { int ret = 0; if ((argc == 2) && (strcmp_c("-v", argv[1]) == 0)) { ret = die("xwm-0.1.9, Copyright © 2021-2022 Michael Czigler, MIT License\n"); } if ((ret == 0) && (argc != 1)) { ret = die("usage: xwm [-v]\n"); } if (ret == 0) { dpy = xcb_connect(NULL, NULL); ret = xcb_connection_has_error(dpy); if (ret > 0) { ret = die("xcb_connection_has_error\n"); } } if (ret == 0) { scre = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data; setup(); } while (ret == 0) { ret = eventHandler(); } return ret; } ================================================ FILE: xwm.h ================================================ /* See LICENSE file for copyright and license details. */ /* typedefs */ typedef struct { unsigned int mod; xcb_keysym_t keysym; void (*func)(char **com); char **com; } Key; typedef struct { uint32_t request; void (*func)(xcb_generic_event_t *ev); } handler_func_t; /* convert keycode to keysym and back */ static xcb_keycode_t *xcb_get_keycodes(xcb_keysym_t keysym); static xcb_keysym_t xcb_get_keysym(xcb_keycode_t keycode); /* user defined command actions */ static void killclient(char **com); static void spawn(char **com); static void closewm(char **com); static void fullclient(char **com); /* window behavior */ static void setFocus(xcb_drawable_t window); static void setFocusColor(xcb_drawable_t window, int focus); /* event hander actions */ static int eventHandler(void); static void handleMotionNotify(xcb_generic_event_t *ev); static void handleEnterNotify(xcb_generic_event_t *ev); static void handleDestroyNotify(xcb_generic_event_t *ev); static void handleButtonPress(xcb_generic_event_t *ev); static void handleButtonRelease(xcb_generic_event_t *ev); static void handleKeyPress(xcb_generic_event_t *ev); static void handleMapRequest(xcb_generic_event_t *ev); static void handleFocusIn(xcb_generic_event_t *ev); static void handleFocusOut(xcb_generic_event_t *ev); static handler_func_t handler_funs[] = { { XCB_MOTION_NOTIFY, handleMotionNotify }, { XCB_ENTER_NOTIFY, handleEnterNotify }, { XCB_DESTROY_NOTIFY, handleDestroyNotify }, { XCB_BUTTON_PRESS, handleButtonPress }, { XCB_BUTTON_RELEASE, handleButtonRelease }, { XCB_KEY_PRESS, handleKeyPress }, { XCB_MAP_REQUEST, handleMapRequest }, { XCB_FOCUS_IN, handleFocusIn }, { XCB_FOCUS_OUT, handleFocusOut }, { XCB_NONE, NULL } }; /* intialize */ static void setup(void); /* error handling & misc. */ static int die(char *errstr); static int strcmp_c(char *str1, char *str2);