/*
* 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;
}