Created
May 17, 2024 21:58
-
-
Save 8dcc/4cc80d9960c43245b0e108c55aebf61c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Compile with: | |
* gcc -Wall -Wextra -ggdb3 -o xwindow.out xwindow.c -lX11 -lXext -lXfixes -lm | |
*/ | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <limits.h> | |
#include <X11/Xos.h> | |
#include <X11/Xlib.h> | |
#include <X11/Xutil.h> | |
#include <X11/Xatom.h> | |
#include <X11/extensions/shape.h> | |
#include <X11/extensions/Xcomposite.h> | |
#include <X11/extensions/Xfixes.h> | |
#include <math.h> | |
#define WINDOW_W 640 | |
#define WINDOW_H 480 | |
#define BASIC_EVENT_MASK \ | |
(StructureNotifyMask | ExposureMask | PropertyChangeMask | \ | |
EnterWindowMask | LeaveWindowMask | KeyPressMask | KeyReleaseMask | \ | |
KeymapStateMask) | |
#define NOT_PROPAGATE_MASK \ | |
(KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \ | |
PointerMotionMask | ButtonMotionMask) | |
/*----------------------------------------------------------------------------*/ | |
typedef struct { | |
Display* d; | |
Window win; | |
int screen_num; | |
int disp_w, disp_h; | |
} Context; | |
static Context ctx; | |
/*----------------------------------------------------------------------------*/ | |
static inline XColor createXColorFromRGB(uint16_t r, uint16_t g, uint16_t b) { | |
XColor color; | |
color.red = r; | |
color.green = g; | |
color.blue = b; | |
color.flags = DoRed | DoGreen | DoBlue; | |
if (!XAllocColor(ctx.d, DefaultColormap(ctx.d, ctx.screen_num), &color)) { | |
fprintf(stderr, "createXColorFromRGB: Cannot create color\n"); | |
exit(1); | |
} | |
return color; | |
} | |
static inline XColor createXColorFromRGBA(uint16_t r, uint16_t g, uint16_t b, | |
uint16_t a) { | |
XColor color; | |
color.red = r; | |
color.green = g; | |
color.blue = b; | |
color.flags = DoRed | DoGreen | DoBlue; | |
if (!XAllocColor(ctx.d, DefaultColormap(ctx.d, ctx.screen_num), &color)) { | |
fprintf(stderr, "createXColorFromRGBA: Cannot create color\n"); | |
exit(1); | |
} | |
/* Add alpha in bits 24..31 */ | |
uint64_t pixel = (uint64_t)color.pixel; | |
pixel &= 0x00FFFFFF; | |
pixel |= (a & 0xFF) << 24; | |
color.pixel = pixel; | |
return color; | |
} | |
/*----------------------------------------------------------------------------*/ | |
static void displayInit() { | |
ctx.d = XOpenDisplay(0); | |
if (!ctx.d) { | |
fprintf(stderr, "Failed to open X display\n"); | |
exit(1); | |
} | |
ctx.screen_num = DefaultScreen(ctx.d); | |
ctx.disp_w = DisplayWidth(ctx.d, ctx.screen_num); | |
ctx.disp_h = DisplayHeight(ctx.d, ctx.screen_num); | |
int shape_event_base; | |
int shape_error_base; | |
if (!XShapeQueryExtension(ctx.d, &shape_event_base, &shape_error_base)) { | |
fprintf(stderr, "No shape extension in your system\n"); | |
exit(1); | |
} | |
} | |
static inline void allow_input_passthrough(Window w) { | |
XserverRegion region = XFixesCreateRegion(ctx.d, NULL, 0); | |
XFixesSetWindowShapeRegion(ctx.d, w, ShapeInput, 0, 0, region); | |
XFixesDestroyRegion(ctx.d, region); | |
} | |
static void windowInit() { | |
Window root = DefaultRootWindow(ctx.d); | |
XVisualInfo vinfo; | |
XMatchVisualInfo(ctx.d, DefaultScreen(ctx.d), 32, TrueColor, &vinfo); | |
Colormap colormap = | |
XCreateColormap(ctx.d, DefaultRootWindow(ctx.d), vinfo.visual, AllocNone); | |
XSetWindowAttributes attr; | |
attr.background_pixmap = None; | |
attr.background_pixel = 0; | |
attr.border_pixel = 0; | |
attr.win_gravity = NorthWestGravity; | |
attr.bit_gravity = ForgetGravity; | |
attr.save_under = 1; | |
attr.event_mask = BASIC_EVENT_MASK; | |
attr.do_not_propagate_mask = NOT_PROPAGATE_MASK; | |
attr.override_redirect = 1; // OpenGL > 0 | |
attr.colormap = colormap; | |
uint64_t mask = CWColormap | CWBorderPixel | CWBackPixel | CWEventMask | | |
CWWinGravity | CWBitGravity | CWSaveUnder | | |
CWDontPropagate | CWOverrideRedirect; | |
/* TODO: Change possition */ | |
ctx.win = | |
XCreateWindow(ctx.d, root, 400, 400, WINDOW_W, WINDOW_H, 0, vinfo.depth, | |
InputOutput, vinfo.visual, mask, &attr); | |
if (!ctx.win) { | |
fprintf(stderr, "Failed to create X window.\n"); | |
exit(1); | |
} | |
XShapeCombineMask(ctx.d, ctx.win, ShapeInput, 0, 0, None, ShapeSet); | |
XShapeSelectInput(ctx.d, ctx.win, ShapeNotifyMask); | |
/* Tell the Window Manager not to draw window borders (frame) or title */ | |
XSetWindowAttributes wattr; | |
wattr.override_redirect = 1; | |
XChangeWindowAttributes(ctx.d, ctx.win, CWOverrideRedirect, &wattr); | |
/* Defined above */ | |
allow_input_passthrough(ctx.win); | |
/* Show the window */ | |
XMapWindow(ctx.d, ctx.win); | |
} | |
static void draw() { | |
GC gc = XCreateGC(ctx.d, ctx.win, 0, 0); | |
/* TODO: This could be moved out if we only used this font */ | |
XFontStruct* font = XLoadQueryFont(ctx.d, "fixed"); | |
if (!font) { | |
fprintf(stderr, "Could not find \"fixed\" font\n"); | |
exit(1); | |
} | |
XSetFont(ctx.d, gc, font->fid); | |
XSetBackground(ctx.d, gc, 0x00000000); | |
XSetForeground(ctx.d, gc, 0xFF555555); | |
XFillRectangle(ctx.d, ctx.win, gc, 30, 30, 100, 18); /* x, y, w, h */ | |
XSetForeground(ctx.d, gc, 0xFFFFFFFF); | |
const char* str = "Hello, world."; | |
XDrawString(ctx.d, ctx.win, gc, 42, 42, str, strlen(str)); | |
XFreeFont(ctx.d, font); | |
XFreeGC(ctx.d, gc); | |
} | |
/*----------------------------------------------------------------------------*/ | |
/* Use if needed */ | |
void list_fonts() { | |
char** fontlist; | |
int num_fonts; | |
fontlist = XListFonts(ctx.d, "*", 1000, &num_fonts); | |
for (int i = 0; i < num_fonts; ++i) | |
fprintf(stderr, "> %s\n", fontlist[i]); | |
} | |
int main() { | |
displayInit(); | |
windowInit(); | |
for (;;) { | |
draw(); | |
usleep(1000); | |
} | |
return 0; | |
} |
You could try taking a look at XInternAtom
and _NET_WM_STATE_ABOVE
, but I have never used those.
I tried, but did not work :(
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@8dcc Hi! Do you think that is possible to make a overlay that will be always on the top of everything? The GNOME panel, for example, will open over the overlay.