Merged rofi launcher alternative

Author Mitja Felicijan <mitja.felicijan@gmail.com> 2026-04-15 18:35:41 +0200
Committer Mitja Felicijan <mitja.felicijan@gmail.com> 2026-04-15 18:35:41 +0200
Commit 6330c2827935a67ee03f18baf9cf4a7a77684760 (patch)
-rw-r--r-- Makefile 2
-rw-r--r-- config.def.h 15
-rw-r--r-- glitch.h 26
-rw-r--r-- launcher.c 262
-rw-r--r-- manager.c 50
5 files changed, 351 insertions, 4 deletions
diff --git a/Makefile b/Makefile
...
15
  
15
  
16
all: glitch
16
all: glitch
17
  
17
  
18
glitch: main.c logging.c manager.c widgets.c switcher.c audio.c
18
glitch: main.c logging.c manager.c widgets.c switcher.c audio.c launcher.c
19
	$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ $(LDFLAGS)
19
	$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ $(LDFLAGS)
20
  
20
  
21
config.h:
21
config.h:
...
diff --git a/config.def.h b/config.def.h
...
21
static const char *on_top_inactive_border_color = "darkorange";
21
static const char *on_top_inactive_border_color = "darkorange";
22
  
22
  
23
static const char *widget_font = "Berkeley Mono:size=7:bold";
23
static const char *widget_font = "Berkeley Mono:size=7:bold";
  
24
static const char *launcher_font_name = "Berkeley Mono:size=9:bold";
24
static const char *time_format = "%A %d.%m.%Y %H:%M:%S";
25
static const char *time_format = "%A %d.%m.%Y %H:%M:%S";
25
static const char *indicator_fg_color = "white";
26
static const char *indicator_fg_color = "white";
26
static const char *indicator_bg_color = "blue";
27
static const char *indicator_bg_color = "blue";
...
33
static const char *layout_tile_fg_color = "white";
34
static const char *layout_tile_fg_color = "white";
34
static const char *layout_float_fg_color = "white";
35
static const char *layout_float_fg_color = "white";
35
  
36
  
  
37
static const char *launcher_bg_color = "black";
  
38
static const char *launcher_border_color = "khaki";
  
39
static const char *launcher_fg_color = "white";
  
40
static const char *launcher_hl_bg_color = "khaki";
  
41
static const char *launcher_hl_fg_color = "black";
  
42
static int launcher_width = 800;
  
43
static int launcher_height = 600;
  
44
  
36
static Shortcut shortcuts[] = {
45
static Shortcut shortcuts[] = {
37
	/* Mask                 KeySym                    Shell command */
46
	/* Mask                 KeySym                    Shell command */
38
	{ MODKEY,               XK_Return,                "st -f \"Berkeley Mono:style=Bold:size=10\" -g 80x40" },
47
	{ MODKEY,               XK_Return,                "alacritty" },
39
	{ MODKEY,               XK_p,                     "rofi -show drun -theme ~/.black.rasi" },
  
40
	{ ControlMask,          XK_Escape,                "sh -c 'maim -s | xclip -selection clipboard -t image/png'" },
48
	{ ControlMask,          XK_Escape,                "sh -c 'maim -s | xclip -selection clipboard -t image/png'" },
41
	{ MODKEY,               XK_w,                     "/home/m/Applications/brave --new-window" },
49
	{ MODKEY,               XK_w,                     "brave --new-window" },
42
	{ MODKEY,               XK_e,                     "thunar" },
50
	{ MODKEY,               XK_e,                     "thunar" },
43
	{ MODKEY,               XK_s,                     "xmagnify -s 1000 -z 3" },
51
	{ MODKEY,               XK_s,                     "xmagnify -s 1000 -z 3" },
44
	{ MODKEY,               XK_r,                     "simplescreenrecorder" },
52
	{ MODKEY,               XK_r,                     "simplescreenrecorder" },
...
92
	{ MODKEY,               XK_c,       center_window,       { 0 }        },
100
	{ MODKEY,               XK_c,       center_window,       { 0 }        },
93
	{ MODKEY,               XK_m,       toggle_mic_mute,     { 0 }        },
101
	{ MODKEY,               XK_m,       toggle_mic_mute,     { 0 }        },
94
	{ MODKEY,               XK_space,   toggle_layout,       { 0 }        },
102
	{ MODKEY,               XK_space,   toggle_layout,       { 0 }        },
  
103
	{ MODKEY,               XK_p,       toggle_launcher,     { 0 }        },
95
	{ MODKEY | ShiftMask,   XK_q,       quit,                { 0 }        },
104
	{ MODKEY | ShiftMask,   XK_q,       quit,                { 0 }        },
96
	{ MODKEY,               XK_q,       close_window,        { 0 }        },
105
	{ MODKEY,               XK_q,       close_window,        { 0 }        },
97
};
106
};
...
diff --git a/glitch.h b/glitch.h
...
56
} Client;
56
} Client;
57
  
57
  
58
typedef struct {
58
typedef struct {
  
59
	char *name;
  
60
	char *exec;
  
61
} LauncherItem;
  
62
  
  
63
typedef struct {
59
	Display *dpy;
64
	Display *dpy;
60
	Window root;
65
	Window root;
61
	Window active;
66
	Window active;
...
76
  
81
  
77
	unsigned int current_desktop;
82
	unsigned int current_desktop;
78
	XftFont *font;
83
	XftFont *font;
  
84
	XftFont *launcher_font;
79
	XftDraw *xft_draw;
85
	XftDraw *xft_draw;
80
	XftColor xft_color;
86
	XftColor xft_color;
81
	XftColor xft_bg_color;
87
	XftColor xft_bg_color;
...
90
	XftColor xft_layout_tile_fg;
96
	XftColor xft_layout_tile_fg;
91
	XftColor xft_layout_float_fg;
97
	XftColor xft_layout_float_fg;
92
  
98
  
  
99
	XftColor xft_launcher_bg;
  
100
	XftColor xft_launcher_border;
  
101
	XftColor xft_launcher_fg;
  
102
	XftColor xft_launcher_hl_bg;
  
103
	XftColor xft_launcher_hl_fg;
  
104
  
93
	unsigned long last_widget_update;
105
	unsigned long last_widget_update;
94
	Client *clients;
106
	Client *clients;
95
  
107
  
...
106
	pa_threaded_mainloop *pa_mainloop;
118
	pa_threaded_mainloop *pa_mainloop;
107
	pa_context *pa_ctx;
119
	pa_context *pa_ctx;
108
	int mic_muted;
120
	int mic_muted;
  
121
  
  
122
	// Launcher
  
123
	int launcher_active;
  
124
	Window launcher_win;
  
125
	LauncherItem *launcher_items;
  
126
	int launcher_items_count;
  
127
	LauncherItem **launcher_filtered;
  
128
	int launcher_filtered_count;
  
129
	char launcher_search[256];
  
130
	int launcher_selected;
109
} WindowManager;
131
} WindowManager;
110
  
132
  
111
typedef struct {
133
typedef struct {
...
196
  
218
  
197
void apply_tiling_layout(void);
219
void apply_tiling_layout(void);
198
void toggle_layout(const Arg *arg);
220
void toggle_layout(const Arg *arg);
  
221
  
  
222
void toggle_launcher(const Arg *arg);
  
223
void launcher_handle_key(void);
  
224
void launcher_draw(void);
199
  
225
  
200
#endif // GLITCH_H
226
#endif // GLITCH_H
diff --git a/launcher.c b/launcher.c
  
1
#define _GNU_SOURCE
  
2
#define _POSIX_C_SOURCE 200809L
  
3
#include <stdio.h>
  
4
#include <stdlib.h>
  
5
#include <string.h>
  
6
#include <dirent.h>
  
7
#include <ctype.h>
  
8
  
  
9
#include <X11/Xlib.h>
  
10
#include <X11/Xutil.h>
  
11
#include <X11/keysym.h>
  
12
  
  
13
#include "glitch.h"
  
14
#include "config.h"
  
15
  
  
16
extern WindowManager wm;
  
17
  
  
18
static void launcher_filter(void);
  
19
  
  
20
static char *trim_whitespace(char *str) {
  
21
	char *end;
  
22
	while (isspace((unsigned char)*str)) str++;
  
23
	if (*str == 0) return str;
  
24
	end = str + strlen(str) - 1;
  
25
	while (end > str && isspace((unsigned char)*end)) end--;
  
26
	end[1] = '\0';
  
27
	return str;
  
28
}
  
29
  
  
30
static void load_applications(void) {
  
31
	const char *system_dirs[] = {
  
32
		"/usr/share/applications",
  
33
		"/usr/local/share/applications"
  
34
	};
  
35
  
  
36
	char home_dir[1024];
  
37
	char *home = getenv("HOME");
  
38
	if (home) {
  
39
		snprintf(home_dir, sizeof(home_dir), "%s/.local/share/applications", home);
  
40
	}
  
41
  
  
42
	if (wm.launcher_items) {
  
43
		for (int i = 0; i < wm.launcher_items_count; i++) {
  
44
			free(wm.launcher_items[i].name);
  
45
			free(wm.launcher_items[i].exec);
  
46
		}
  
47
		free(wm.launcher_items);
  
48
		wm.launcher_items = NULL;
  
49
		wm.launcher_items_count = 0;
  
50
	}
  
51
  
  
52
	int capacity = 100;
  
53
	wm.launcher_items = malloc(sizeof(LauncherItem) * capacity);
  
54
  
  
55
	for (int d = -1; d < (int)LENGTH(system_dirs); d++) {
  
56
		const char *path_to_open;
  
57
		if (d == -1) {
  
58
			if (!home) continue;
  
59
			path_to_open = home_dir;
  
60
		} else {
  
61
			path_to_open = system_dirs[d];
  
62
		}
  
63
  
  
64
		DIR *dir = opendir(path_to_open);
  
65
		if (!dir) continue;
  
66
  
  
67
		struct dirent *entry;
  
68
		while ((entry = readdir(dir))) {
  
69
			if (strstr(entry->d_name, ".desktop")) {
  
70
				char desktop_path[2048];
  
71
				snprintf(desktop_path, sizeof(desktop_path), "%s/%s", path_to_open, entry->d_name);
  
72
  
  
73
				FILE *f = fopen(desktop_path, "r");
  
74
				if (!f) continue;
  
75
  
  
76
				char line[1024];
  
77
				char *name = NULL;
  
78
				char *exec = NULL;
  
79
				int no_display = 0;
  
80
				int in_desktop_entry = 0;
  
81
  
  
82
				while (fgets(line, sizeof(line), f)) {
  
83
					char *trimmed = trim_whitespace(line);
  
84
					if (trimmed[0] == '[' && strstr(trimmed, "[Desktop Entry]")) {
  
85
						in_desktop_entry = 1;
  
86
						continue;
  
87
					}
  
88
					if (trimmed[0] == '[' && !strstr(trimmed, "[Desktop Entry]")) {
  
89
						in_desktop_entry = 0;
  
90
					}
  
91
  
  
92
					if (!in_desktop_entry) continue;
  
93
  
  
94
					if (strncmp(trimmed, "Name=", 5) == 0 && !name) {
  
95
						name = strdup(trim_whitespace(trimmed + 5));
  
96
					} else if (strncmp(trimmed, "Exec=", 5) == 0 && !exec) {
  
97
						char *e = strdup(trimmed + 5);
  
98
						char *percent = strchr(e, '%');
  
99
						if (percent) *percent = '\0';
  
100
						exec = strdup(trim_whitespace(e));
  
101
						free(e);
  
102
					} else if (strncmp(trimmed, "NoDisplay=true", 14) == 0) {
  
103
						no_display = 1;
  
104
					}
  
105
				}
  
106
				fclose(f);
  
107
  
  
108
				if (name && exec && !no_display) {
  
109
					if (wm.launcher_items_count >= capacity) {
  
110
						capacity *= 2;
  
111
						wm.launcher_items = realloc(wm.launcher_items, sizeof(LauncherItem) * capacity);
  
112
					}
  
113
					wm.launcher_items[wm.launcher_items_count].name = name;
  
114
					wm.launcher_items[wm.launcher_items_count].exec = exec;
  
115
					wm.launcher_items_count++;
  
116
				} else {
  
117
					if (name) free(name);
  
118
					if (exec) free(exec);
  
119
				}
  
120
			}
  
121
		}
  
122
		closedir(dir);
  
123
	}
  
124
}
  
125
  
  
126
void toggle_launcher(const Arg *arg) {
  
127
	(void)arg;
  
128
	if (wm.launcher_active) {
  
129
		wm.launcher_active = 0;
  
130
		XUnmapWindow(wm.dpy, wm.launcher_win);
  
131
		XUngrabKeyboard(wm.dpy, CurrentTime);
  
132
		return;
  
133
	}
  
134
  
  
135
	if (!wm.launcher_items) {
  
136
		load_applications();
  
137
	}
  
138
  
  
139
	wm.launcher_active = 1;
  
140
	wm.launcher_search[0] = '\0';
  
141
	wm.launcher_selected = 0;
  
142
	launcher_filter();
  
143
  
  
144
	int screen_width = DisplayWidth(wm.dpy, wm.screen);
  
145
	int screen_height = DisplayHeight(wm.dpy, wm.screen);
  
146
	int win_width = launcher_width;
  
147
	int win_height = launcher_height;
  
148
	int x = (screen_width - win_width) / 2;
  
149
	int y = (screen_height - win_height) / 2;
  
150
  
  
151
	if (!wm.launcher_win) {
  
152
		XSetWindowAttributes wa;
  
153
		wa.override_redirect = True;
  
154
		wa.background_pixel = wm.xft_launcher_bg.pixel;
  
155
		wa.border_pixel = wm.xft_launcher_border.pixel;
  
156
		wm.launcher_win = XCreateWindow(wm.dpy, wm.root, x, y, win_width, win_height, 2,
  
157
				DefaultDepth(wm.dpy, wm.screen), CopyFromParent,
  
158
				DefaultVisual(wm.dpy, wm.screen),
  
159
				CWOverrideRedirect | CWBackPixel | CWBorderPixel, &wa);
  
160
	} else {
  
161
		XMoveWindow(wm.dpy, wm.launcher_win, x, y);
  
162
	}
  
163
  
  
164
	XMapRaised(wm.dpy, wm.launcher_win);
  
165
	XGrabKeyboard(wm.dpy, wm.launcher_win, True, GrabModeAsync, GrabModeAsync, CurrentTime);
  
166
	launcher_draw();
  
167
}
  
168
  
  
169
static void launcher_filter(void) {
  
170
	if (wm.launcher_filtered) free(wm.launcher_filtered);
  
171
	wm.launcher_filtered = malloc(sizeof(LauncherItem *) * wm.launcher_items_count);
  
172
	wm.launcher_filtered_count = 0;
  
173
  
  
174
	for (int i = 0; i < wm.launcher_items_count; i++) {
  
175
		if (wm.launcher_search[0] == '\0' || 
  
176
				strcasestr(wm.launcher_items[i].name, wm.launcher_search)) {
  
177
			wm.launcher_filtered[wm.launcher_filtered_count++] = &wm.launcher_items[i];
  
178
		}
  
179
	}
  
180
  
  
181
	if (wm.launcher_selected >= wm.launcher_filtered_count) {
  
182
		wm.launcher_selected = wm.launcher_filtered_count > 0 ? wm.launcher_filtered_count - 1 : 0;
  
183
	}
  
184
}
  
185
  
  
186
void launcher_handle_key(void) {
  
187
	KeySym keysym = XLookupKeysym(&wm.ev.xkey, 0);
  
188
	int len = strlen(wm.launcher_search);
  
189
  
  
190
	if (keysym == XK_Escape) {
  
191
		toggle_launcher(NULL);
  
192
		return;
  
193
	} else if (keysym == XK_BackSpace) {
  
194
		if (len > 0) {
  
195
			wm.launcher_search[len - 1] = '\0';
  
196
			wm.launcher_selected = 0;
  
197
			launcher_filter();
  
198
		}
  
199
	} else if (keysym == XK_Return) {
  
200
		if (wm.launcher_filtered_count > 0 && wm.launcher_selected < wm.launcher_filtered_count) {
  
201
			execute_shortcut(wm.launcher_filtered[wm.launcher_selected]->exec);
  
202
			toggle_launcher(NULL);
  
203
			return;
  
204
		}
  
205
	} else if (keysym == XK_Up) {
  
206
		if (wm.launcher_selected > 0) wm.launcher_selected--;
  
207
	} else if (keysym == XK_Down) {
  
208
		if (wm.launcher_selected < wm.launcher_filtered_count - 1) wm.launcher_selected++;
  
209
	} else {
  
210
		char buf[32];
  
211
		int n = XLookupString(&wm.ev.xkey, buf, sizeof(buf), NULL, NULL);
  
212
		if (n > 0 && len + n < (int)sizeof(wm.launcher_search)) {
  
213
			memcpy(wm.launcher_search + len, buf, n);
  
214
			wm.launcher_search[len + n] = '\0';
  
215
			wm.launcher_selected = 0;
  
216
			launcher_filter();
  
217
		}
  
218
	}
  
219
  
  
220
	launcher_draw();
  
221
}
  
222
  
  
223
void launcher_draw(void) {
  
224
	if (!wm.launcher_win) return;
  
225
  
  
226
	XftDraw *draw = XftDrawCreate(wm.dpy, wm.launcher_win, DefaultVisual(wm.dpy, wm.screen), wm.cmap);
  
227
	XWindowAttributes wa;
  
228
	XGetWindowAttributes(wm.dpy, wm.launcher_win, &wa);
  
229
  
  
230
	// Clear background
  
231
	XftDrawRect(draw, &wm.xft_launcher_bg, 0, 0, wa.width, wa.height);
  
232
  
  
233
	int x = 20;
  
234
	int y = 30;
  
235
	int row_height = wm.launcher_font->height + 10;
  
236
  
  
237
	// Draw search bar
  
238
	char search_display[300];
  
239
	snprintf(search_display, sizeof(search_display), "> %s", wm.launcher_search);
  
240
	XftDrawStringUtf8(draw, &wm.xft_launcher_fg, wm.launcher_font, x, y, (FcChar8 *)search_display, strlen(search_display));
  
241
  
  
242
	y += row_height + 10; // Extra padding below input
  
243
  
  
244
	// Draw items
  
245
	int start_idx = 0;
  
246
	if (wm.launcher_selected >= 10) {
  
247
		start_idx = wm.launcher_selected - 9;
  
248
	}
  
249
  
  
250
	for (int i = start_idx; i < wm.launcher_filtered_count && i < start_idx + 15; i++) {
  
251
		if (i == wm.launcher_selected) {
  
252
			XftDrawRect(draw, &wm.xft_launcher_hl_bg, 0, y - wm.launcher_font->ascent - 5, wa.width, row_height);
  
253
			XftDrawStringUtf8(draw, &wm.xft_launcher_hl_fg, wm.launcher_font, x, y, (FcChar8 *)wm.launcher_filtered[i]->name, strlen(wm.launcher_filtered[i]->name));
  
254
		} else {
  
255
			XftDrawStringUtf8(draw, &wm.xft_launcher_fg, wm.launcher_font, x, y, (FcChar8 *)wm.launcher_filtered[i]->name, strlen(wm.launcher_filtered[i]->name));
  
256
		}
  
257
		y += row_height;
  
258
	}
  
259
  
  
260
	XftDrawDestroy(draw);
  
261
	XFlush(wm.dpy);
  
262
}
diff --git a/manager.c b/manager.c
...
317
		wm.font = XftFontOpenName(wm.dpy, wm.screen, "fixed");
317
		wm.font = XftFontOpenName(wm.dpy, wm.screen, "fixed");
318
	}
318
	}
319
  
319
  
  
320
	wm.launcher_font = XftFontOpenName(wm.dpy, wm.screen, launcher_font_name);
  
321
	if (!wm.launcher_font) {
  
322
		log_message(stdout, LOG_WARNING, "Failed to load launcher font %s, falling back to fixed", launcher_font_name);
  
323
		wm.launcher_font = XftFontOpenName(wm.dpy, wm.screen, "fixed");
  
324
	}
  
325
  
320
	Visual *visual = DefaultVisual(wm.dpy, wm.screen);
326
	Visual *visual = DefaultVisual(wm.dpy, wm.screen);
321
  
327
  
322
	// Create XftDraw for the root window.
328
	// Create XftDraw for the root window.
...
386
		XftColorAllocValue(wm.dpy, visual, wm.cmap, &render_color, &wm.xft_layout_float_fg);
392
		XftColorAllocValue(wm.dpy, visual, wm.cmap, &render_color, &wm.xft_layout_float_fg);
387
	}
393
	}
388
  
394
  
  
395
	if (!XftColorAllocName(wm.dpy, visual, wm.cmap, launcher_bg_color, &wm.xft_launcher_bg)) {
  
396
		XRenderColor render_color = {0x0000, 0x0000, 0x0000, 0xFFFF};
  
397
		XftColorAllocValue(wm.dpy, visual, wm.cmap, &render_color, &wm.xft_launcher_bg);
  
398
	}
  
399
	if (!XftColorAllocName(wm.dpy, visual, wm.cmap, launcher_border_color, &wm.xft_launcher_border)) {
  
400
		XRenderColor render_color = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
  
401
		XftColorAllocValue(wm.dpy, visual, wm.cmap, &render_color, &wm.xft_launcher_border);
  
402
	}
  
403
	if (!XftColorAllocName(wm.dpy, visual, wm.cmap, launcher_fg_color, &wm.xft_launcher_fg)) {
  
404
		XRenderColor render_color = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
  
405
		XftColorAllocValue(wm.dpy, visual, wm.cmap, &render_color, &wm.xft_launcher_fg);
  
406
	}
  
407
	if (!XftColorAllocName(wm.dpy, visual, wm.cmap, launcher_hl_bg_color, &wm.xft_launcher_hl_bg)) {
  
408
		XRenderColor render_color = {0x8000, 0x8000, 0x0000, 0xFFFF};
  
409
		XftColorAllocValue(wm.dpy, visual, wm.cmap, &render_color, &wm.xft_launcher_hl_bg);
  
410
	}
  
411
	if (!XftColorAllocName(wm.dpy, visual, wm.cmap, launcher_hl_fg_color, &wm.xft_launcher_hl_fg)) {
  
412
		XRenderColor render_color = {0x0000, 0x0000, 0x0000, 0xFFFF};
  
413
		XftColorAllocValue(wm.dpy, visual, wm.cmap, &render_color, &wm.xft_launcher_hl_fg);
  
414
	}
  
415
  
389
	wm.running = 1;
416
	wm.running = 1;
390
  
417
  
391
	// Grab keys for keybinds.
418
	// Grab keys for keybinds.
...
488
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_mic_muted_bg);
515
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_mic_muted_bg);
489
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_mic_active_fg);
516
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_mic_active_fg);
490
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_mic_muted_fg);
517
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_mic_muted_fg);
  
518
  
  
519
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_launcher_bg);
  
520
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_launcher_border);
  
521
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_launcher_fg);
  
522
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_launcher_hl_bg);
  
523
	XftColorFree(wm.dpy, DefaultVisual(wm.dpy, wm.screen), wm.cmap, &wm.xft_launcher_hl_fg);
  
524
  
491
	XftDrawDestroy(wm.xft_draw);
525
	XftDrawDestroy(wm.xft_draw);
492
  
526
  
  
527
	if (wm.launcher_win) XDestroyWindow(wm.dpy, wm.launcher_win);
  
528
	if (wm.launcher_items) {
  
529
		for (int i = 0; i < wm.launcher_items_count; i++) {
  
530
			free(wm.launcher_items[i].name);
  
531
			free(wm.launcher_items[i].exec);
  
532
		}
  
533
		free(wm.launcher_items);
  
534
	}
  
535
	if (wm.launcher_filtered) free(wm.launcher_filtered);
  
536
  
493
	XftFontClose(wm.dpy, wm.font);
537
	XftFontClose(wm.dpy, wm.font);
  
538
	XftFontClose(wm.dpy, wm.launcher_font);
494
	XFreeCursor(wm.dpy, wm.cursor_default);
539
	XFreeCursor(wm.dpy, wm.cursor_default);
495
	XFreeCursor(wm.dpy, wm.cursor_move);
540
	XFreeCursor(wm.dpy, wm.cursor_move);
496
	XFreeCursor(wm.dpy, wm.cursor_resize);
541
	XFreeCursor(wm.dpy, wm.cursor_resize);
...
1062
  
1107
  
1063
// https://tronche.com/gui/x/xlib/events/keyboard-pointer/keyboard-pointer.html
1108
// https://tronche.com/gui/x/xlib/events/keyboard-pointer/keyboard-pointer.html
1064
void handle_key_press(void) {
1109
void handle_key_press(void) {
  
1110
	if (wm.launcher_active) {
  
1111
		launcher_handle_key();
  
1112
		return;
  
1113
	}
  
1114
  
1065
	log_message(stdout, LOG_DEBUG, ">> Key pressed > active window 0x%lx", wm.ev.xkey.subwindow);
1115
	log_message(stdout, LOG_DEBUG, ">> Key pressed > active window 0x%lx", wm.ev.xkey.subwindow);
1066
	if (wm.ev.type != KeyPress) return;
1116
	if (wm.ev.type != KeyPress) return;
1067
  
1117
  
...