Add program name to the window switcher

Author Mitja Felicijan <mitja.felicijan@gmail.com> 2026-01-26 10:14:22 +0100
Committer Mitja Felicijan <mitja.felicijan@gmail.com> 2026-01-26 10:14:22 +0100
Commit 62591d967905d01333397722f8f18111f80047f3 (patch)
-rw-r--r-- manager.c 1
-rw-r--r-- switcher.c 62
2 files changed, 40 insertions, 23 deletions
diff --git a/manager.c b/manager.c
...
421
	deinit_audio();
421
	deinit_audio();
422
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_color);
422
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_color);
423
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_bg_color);
423
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_bg_color);
  
424
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_root_bg_color);
424
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_mic_active_bg);
425
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_mic_active_bg);
425
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_mic_muted_bg);
426
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_mic_muted_bg);
426
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_mic_active_fg);
427
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_mic_active_fg);
...
diff --git a/switcher.c b/switcher.c
...
3
  
3
  
4
#include <X11/Xatom.h>
4
#include <X11/Xatom.h>
5
#include <X11/Xproto.h>
5
#include <X11/Xproto.h>
  
6
#include <X11/Xutil.h>
6
  
7
  
7
#include "glitch.h"
8
#include "glitch.h"
8
#include "config.h"
  
9
  
9
  
10
extern WindowManager wm;
10
extern WindowManager wm;
11
  
11
  
...
27
  
27
  
28
		// Draw box background
28
		// Draw box background
29
		if (is_selected) {
29
		if (is_selected) {
30
			// Use blue color for active background (wm.xft_bg_color is usually blue from config)
  
31
			XSetForeground(wm.dpy, DefaultGC(wm.dpy, wm.screen), wm.xft_bg_color.pixel);
30
			XSetForeground(wm.dpy, DefaultGC(wm.dpy, wm.screen), wm.xft_bg_color.pixel);
32
			XFillRectangle(wm.dpy, wm.cycle_win, DefaultGC(wm.dpy, wm.screen), x_offset, y_offset, box_size, box_size);
31
			XFillRectangle(wm.dpy, wm.cycle_win, DefaultGC(wm.dpy, wm.screen), x_offset, y_offset, box_size, box_size);
33
		} else {
32
		} else {
...
35
			XFillRectangle(wm.dpy, wm.cycle_win, DefaultGC(wm.dpy, wm.screen), x_offset, y_offset, box_size, box_size);
34
			XFillRectangle(wm.dpy, wm.cycle_win, DefaultGC(wm.dpy, wm.screen), x_offset, y_offset, box_size, box_size);
36
		}
35
		}
37
  
36
  
38
		// Draw Window Name
37
		// Get Program Name
39
		char *name = NULL;
38
		char *prog_name = NULL;
40
		Atom utf8_string = XInternAtom(wm.dpy, "UTF8_STRING", False);
39
		XClassHint ch;
41
		if (XFetchName(wm.dpy, w, &name) || XGetWindowProperty(wm.dpy, w, XInternAtom(wm.dpy, "_NET_WM_NAME", False), 0, (~0L), False, utf8_string, &(Atom){0}, &(int){0}, &(unsigned long){0}, &(unsigned long){0}, (unsigned char **)&name) == Success) {
40
		if (XGetClassHint(wm.dpy, w, &ch)) {
42
			if (name) {
41
			prog_name = ch.res_class;
43
				// Selected: White text. Unselected: Black text.
42
			if (prog_name) {
44
				XftColor *color = is_selected ? &wm.xft_color : &wm.xft_root_bg_color;
43
				char *dash = strchr(prog_name, '-');
45
				// NOTE: wm.xft_color is "white" (indicator_fg_color), wm.xft_root_bg_color is "black".
44
				if (dash) *dash = '\0';
  
45
			}
  
46
			if (ch.res_name) XFree(ch.res_name);
  
47
		}
46
  
48
  
47
				XftDraw *draw = XftDrawCreate(wm.dpy, wm.cycle_win, DefaultVisual(wm.dpy, wm.screen), wm.cmap);
49
		// Get Window Title
48
				if (draw) {
50
		char *win_title = NULL;
49
					if (strlen(name) > 8) {
51
		if (!XFetchName(wm.dpy, w, &win_title)) {
50
						char truncated[9];
52
			Atom utf8_string = XInternAtom(wm.dpy, "UTF8_STRING", False);
51
						strncpy(truncated, name, 8);
53
			XGetWindowProperty(wm.dpy, w, XInternAtom(wm.dpy, "_NET_WM_NAME", False), 0, (~0L), False, utf8_string, &(Atom){0}, &(int){0}, &(unsigned long){0}, &(unsigned long){0}, (unsigned char **)&win_title);
52
						truncated[8] = '\0';
54
		}
53
						XftDrawStringUtf8(draw, color, wm.font, x_offset + 10, y_offset + 90, (const FcChar8 *)truncated, strlen(truncated));
55
  
54
					} else {
56
		XftDraw *draw = XftDrawCreate(wm.dpy, wm.cycle_win, DefaultVisual(wm.dpy, wm.screen), wm.cmap);
55
						XftDrawStringUtf8(draw, color, wm.font, x_offset + 10, y_offset + 90, (const FcChar8 *)name, strlen(name));
57
		if (draw) {
56
					}
58
			XftColor *color = is_selected ? &wm.xft_color : &wm.xft_root_bg_color;
57
					XftDrawDestroy(draw);
59
  
58
				}
60
			if (prog_name) {
59
				XFree(name);
61
				char truncated[9];
  
62
				strncpy(truncated, prog_name, 8);
  
63
				truncated[8] = '\0';
  
64
				XftDrawStringUtf8(draw, color, wm.font, x_offset + 10, y_offset + 70, (const FcChar8 *)truncated, strlen(truncated));
  
65
			}
  
66
  
  
67
			if (win_title) {
  
68
				char truncated[9];
  
69
				strncpy(truncated, win_title, 8);
  
70
				truncated[8] = '\0';
  
71
				XftDrawStringUtf8(draw, color, wm.font, x_offset + 10, y_offset + 90, (const FcChar8 *)truncated, strlen(truncated));
60
			}
72
			}
  
73
			XftDrawDestroy(draw);
61
		}
74
		}
  
75
  
  
76
		if (prog_name) XFree(prog_name);
  
77
		if (win_title) XFree(win_title);
62
  
78
  
63
		x_offset += box_size;
79
		x_offset += box_size;
64
	}
80
	}
...