/* * Copyright (C) 2020 Christian Birchinger * * Version 0.1 * * 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 . * * Build: gcc borderless.c -Wall -o borderless `pkg-config --cflags --libs x11` `pkg-config --cflags --libs xmu` * * Usage: borderless [window-id] (No argument will use the current active window) * * This tool should work as a C replacement for the "borderless" python 2 script i found on various forums. * Because Python 2 is EOL i first did a Python 3 version but after finding enough C Xlib examples it was trivial * to do a plain C version. * * If something isn't working change DEBUG to 1 below. * * Frankenstein copy paste code with sources from: * * toggle-decorations.c: (C) 2017 Alberts Muktupāvels * https://gist.githubusercontent.com/muktupavels/d03bb14ea6042b779df89b4c87df975d/raw/5a0d4ce582c29e9538364ee0eb551cdf2dddb5e5/toggle-decorations.c * gistfile1.c (get the active window on X window system): (c) 2015 Keiichiro Ui * https://gist.githubusercontent.com/kui/2622504/raw/6e5378db5c4073ed8a39f527167c150509537e01/gistfile1.c * */ #include #include #include #include #include #include #include Bool xerror = False; #define DEBUG 0 #define debug_print(...) \ do { if (DEBUG) fprintf(stderr, __VA_ARGS__); } while (0) typedef struct { unsigned long flags; unsigned long functions; unsigned long decorations; long input_mode; unsigned long status; } MotifWmHints; static MotifWmHints *get_motif_wm_hints(Display *display, Window window) { Atom property; int result; Atom actual_type; int actual_format; unsigned long nitems; unsigned long bytes_after; unsigned char *data; property = XInternAtom (display, "_MOTIF_WM_HINTS", False); result = XGetWindowProperty (display, window, property, 0, LONG_MAX, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &data); if (result == Success && data != NULL) { size_t data_size; size_t max_size; MotifWmHints *hints; data_size = nitems * sizeof (long); max_size = sizeof (*hints); hints = calloc (1, max_size); memcpy (hints, data, data_size > max_size ? max_size : data_size); XFree (data); return hints; } return NULL; } static void toggle_window_decorations(Display *display, Window window) { MotifWmHints *hints; Atom property; int nelements; hints = get_motif_wm_hints (display, window); if (hints == NULL) { hints = calloc (1, sizeof (*hints)); hints->decorations = (1L << 0); } hints->flags |= (1L << 1); hints->decorations = hints->decorations == 0 ? (1L << 0) : 0; property = XInternAtom (display, "_MOTIF_WM_HINTS", False); nelements = sizeof (*hints) / sizeof (long); XChangeProperty (display, window, property, property, 32, PropModeReplace, (unsigned char *) hints, nelements); free (hints); } Display *open_display(){ debug_print("connecting X server ... "); Display* d = XOpenDisplay(NULL); if(d == NULL){ debug_print("fail\n"); exit(1); }else{ debug_print("success\n"); } return d; } int handle_error(Display *display, XErrorEvent *error){ debug_print("ERROR: X11 error\n"); xerror = True; return 1; } Window get_focus_window(Display *d){ Window w; int revert_to; debug_print("getting input focus window ... "); XGetInputFocus(d, &w, &revert_to); // see man if(xerror){ debug_print("fail\n"); exit(1); }else if(w == None){ debug_print("no focus window\n"); exit(1); }else{ debug_print("success (window: %d)\n", (int)w); } return w; } // get the top window. // a top window have the following specifications. // * the start window is contained the descendent windows. // * the parent window is the root window. Window get_top_window(Display *d, Window start){ Window w = start; Window parent = start; Window root = None; Window *children; unsigned int nchildren; Status s; debug_print("getting top window ... \n"); while (parent != root) { w = parent; s = XQueryTree(d, w, &root, &parent, &children, &nchildren); // see man if (s) XFree(children); if(xerror){ printf("X error, aborting\n"); exit(1); } debug_print(" get parent (window: %d)\n", (int)w); } debug_print("success (window: %d)\n", (int)w); return w; } // search a named window (that has a WM_STATE prop) // on the descendent windows of the argment Window. Window get_named_window(Display *d, Window start){ Window w; debug_print("getting named window ... "); w = XmuClientWindow(d, start); // see man if(w == start) debug_print("fail\n"); debug_print("success (window: %d)\n", (int) w); return w; } // (XFetchName cannot get a name with multi-byte chars) void print_window_name(Display *d, Window w){ XTextProperty prop; Status s; debug_print("window name:\n"); s = XGetWMName(d, w, &prop); // see man if(!xerror && s){ int count = 0, result; char **list = NULL; result = XmbTextPropertyToTextList(d, &prop, &list, &count); // see man if(result == Success){ debug_print("\t%s\n", list[0]); }else{ debug_print("ERROR: XmbTextPropertyToTextList\n"); } }else{ debug_print("ERROR: XGetWMName\n"); } } void print_window_class(Display *d, Window w){ Status s; XClassHint* class; debug_print("application: \n"); class = XAllocClassHint(); // see man if(xerror){ debug_print("ERROR: XAllocClassHint\n"); } s = XGetClassHint(d, w, class); // see man if(xerror || s){ debug_print("\tname: %s\n\tclass: %s\n", class->res_name, class->res_class); }else{ debug_print("ERROR: XGetClassHint\n"); } } void print_window_info(Display *d, Window w){ debug_print("--\n"); print_window_name(d, w); print_window_class(d, w); } int main(int argc, char *argv[]){ Display* d; Window w; Window wa = 0; // for XmbTextPropertyToTextList setlocale(LC_ALL, ""); // see man locale if (argc == 2){ sscanf (argv[1], "0x%lx", &wa); if (wa == 0) sscanf (argv[1], "%lu", &wa); if (wa == 0){ printf("Error: Invalid Window id\n"); return 1; } } d = open_display(); XSetErrorHandler(handle_error); if (wa){ w = wa; } else { // get active window w = get_focus_window(d); w = get_top_window(d, w); w = get_named_window(d, w); } print_window_info(d, w); toggle_window_decorations (d, w); XCloseDisplay(d); return 0; }