Sunday, March 23, 2025
Window in X11
X11, also known as the X Window System, is a graphical display management system for Unix and Linux operating systems. It allows users to run graphical applications and manage windows on the screen. X11 provides basic functionality for displaying graphics, managing input devices such as the keyboard and mouse, and supporting multiple windows and multiple displays. This system is essential for the operation of many graphical environments on Linux, such as GNOME, KDE, and others.
The trick we're going to perform today involves rendering a ttf font
but without known development frameworks (Gnome, KDE).
So, we are faced with creating an application in the C programming language.
Prerequisites
We need development libraries:
sudo apt-get install build-essential
sudo apt-get install libx11-dev
Andheader lib
stb_truetype.h
Application
//main.c
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define STB_TRUETYPE_IMPLEMENTATION
#include "./stb_truetype.h"
Display *display;
Window window;
XEvent event;
int screen;
GC gc;
int main() {
// Open a connection to the X server
display = XOpenDisplay(NULL);
if (display == NULL) {
fprintf(stderr, "Cannot open display\n");
exit(1);
}
screen = DefaultScreen(display);
// Create a window
window = XCreateSimpleWindow(display, RootWindow(display, screen),
10, 10, 400, 300, 1,
BlackPixel(display, screen),
WhitePixel(display, screen));
XStoreName(display, window, "My X11 Window");
gc = XCreateGC(display, window, 0, NULL);
XSelectInput(display, window, ExposureMask | KeyPressMask | StructureNotifyMask);
XMapWindow(display, window);
// Load the font
unsigned char font_data[1 << 20];
FILE *font_file = fopen("./fantasquesansmono-regular.otf", "rb"); //ovdje učitajte bilo koji .ttf font
if (font_file == NULL) {
fprintf(stderr, "Cannot open font file\n");
exit(1);
}
fread(font_data, 1, sizeof(font_data), font_file);
fclose(font_file);
stbtt_fontinfo font;
if (!stbtt_InitFont(&font, font_data, stbtt_GetFontOffsetForIndex(font_data, 0))) {
fprintf(stderr, "Cannot initialize font\n");
exit(1);
}
float scale = stbtt_ScaleForPixelHeight(&font, 24.0f);
// Event loop
while (1) {
XNextEvent(display, &event);
if (event.type == Expose) {
XClearWindow(display, window);
int x = 10;
int y = 40; // Adjust vertical position for better visibility
const char *text = "Hello, world!";
int text_len = strlen(text);
for (int i = 0; i < text_len; i++) {
int codepoint = text[i];
int w, h;
int x_offset = 0, y_offset = 0;
// Get bitmap box info for proper positioning
if (codepoint == ',' || codepoint == '.' || codepoint == ';' || codepoint == ':') {
// Special handling for punctuation
stbtt_GetCodepointBitmapBox(&font, codepoint, scale, scale,
&x_offset, &y_offset, NULL, NULL);
}
// Get the actual bitmap
unsigned char *bitmap = stbtt_GetCodepointBitmap(&font, 0, scale, codepoint, &w, &h, &x_offset, &y_offset);
if (bitmap != NULL) {
// Create an XImage
XImage *image = XCreateImage(display, DefaultVisual(display, screen),
DefaultDepth(display, screen), ZPixmap, 0, NULL, w, h, 32, 0);
image->data = (char *)malloc(image->bytes_per_line * h);
// Fill the image data
for (int j = 0; j < h; j++) {
for (int k = 0; k < w; k++) {
int index = j * w + k;
unsigned char alpha = bitmap[index];
// Calculate color (black text on white background)
unsigned char r = 255 - alpha;
unsigned char g = 255 - alpha;
unsigned char b = 255 - alpha;
// Pack the color into the image
XPutPixel(image, k, j, (r << 16) | (g << 8) | b);
}
}
// Adjust y position for punctuation
int render_y = y;
if (codepoint == ',' || codepoint == ';') {
// Lower commas and semicolons slightly
render_y += 4;
}
XPutImage(display, window, gc, image, 0, 0, x, render_y + y_offset, w, h);
XDestroyImage(image);
stbtt_FreeBitmap(bitmap, NULL);
}
// Advance to next character position
int advance, lsb;
stbtt_GetCodepointHMetrics(&font, codepoint, &advance, &lsb);
// Adjust kerning between characters
if (i < text_len - 1) {
int kern = stbtt_GetCodepointKernAdvance(&font, codepoint, text[i+1]);
x += (int)((advance + kern) * scale);
} else {
x += (int)(advance * scale);
}
}
}
if (event.type == ConfigureNotify) {
printf("Window resized to %dx%d\n", event.xconfigure.width, event.xconfigure.height);
}
if (event.type == KeyPress) {
// break;
}
}
XFreeGC(display, gc);
XDestroyWindow(display, window);
XCloseDisplay(display);
return 0;
}
Compiling
gcc -o main main.c -lX11 -lm
>