Move to glib for getting desktop entries

Author Mitja Felicijan <mitja.felicijan@gmail.com> 2026-04-15 18:45:23 +0200
Committer Mitja Felicijan <mitja.felicijan@gmail.com> 2026-04-15 18:45:23 +0200
Commit 55f211a5a5217f67abec6dee50b1d7052bf28b59 (patch)
-rw-r--r-- Makefile 4
-rw-r--r-- launcher.c 111
2 files changed, 30 insertions, 85 deletions
diff --git a/Makefile b/Makefile
1
CC           ?= clang
1
CC           ?= clang
2
CFLAGS       := -std=c99 -pedantic -Wall -Wextra -Wunused -Wswitch-enum
2
CFLAGS       := -std=c99 -pedantic -Wall -Wextra -Wunused -Wswitch-enum
3
INCLUDES     := $(shell pkg-config --cflags xft libpulse)
3
INCLUDES     := $(shell pkg-config --cflags xft libpulse gio-2.0 gio-unix-2.0)
4
LDFLAGS      := $(shell pkg-config --libs x11 xft libpulse) -lpthread
4
LDFLAGS      := $(shell pkg-config --libs x11 xft libpulse gio-2.0 gio-unix-2.0) -lpthread
5
DESTDIR      ?= /usr/local
5
DESTDIR      ?= /usr/local
6
DISPLAY_NUM  := 69
6
DISPLAY_NUM  := 69
7
  
7
  
...
diff --git a/launcher.c b/launcher.c
...
10
#include <X11/Xutil.h>
10
#include <X11/Xutil.h>
11
#include <X11/keysym.h>
11
#include <X11/keysym.h>
12
  
12
  
  
13
#include <gio/gio.h>
  
14
  
13
#include "glitch.h"
15
#include "glitch.h"
14
#include "config.h"
16
#include "config.h"
15
  
17
  
...
17
  
19
  
18
static void launcher_filter(void);
20
static void launcher_filter(void);
19
  
21
  
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) {
22
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) {
23
	if (wm.launcher_items) {
43
		for (int i = 0; i < wm.launcher_items_count; i++) {
24
		for (int i = 0; i < wm.launcher_items_count; i++) {
44
			free(wm.launcher_items[i].name);
25
			free(wm.launcher_items[i].name);
...
49
		wm.launcher_items_count = 0;
30
		wm.launcher_items_count = 0;
50
	}
31
	}
51
  
32
  
52
	int capacity = 100;
33
	GList *apps = g_app_info_get_all();
53
	wm.launcher_items = malloc(sizeof(LauncherItem) * capacity);
34
	int total_apps = g_list_length(apps);
  
35
	wm.launcher_items = malloc(sizeof(LauncherItem) * total_apps);
54
  
36
  
55
	for (int d = -1; d < (int)LENGTH(system_dirs); d++) {
37
	for (GList *l = apps; l != NULL; l = l->next) {
56
		const char *path_to_open;
38
		GAppInfo *app = (GAppInfo *)l->data;
57
		if (d == -1) {
39
  
58
			if (!home) continue;
40
		if (!g_app_info_should_show(app)) {
59
			path_to_open = home_dir;
41
			g_object_unref(app);
60
		} else {
42
			continue;
61
			path_to_open = system_dirs[d];
  
62
		}
43
		}
63
  
44
  
64
		DIR *dir = opendir(path_to_open);
45
		const char *name = g_app_info_get_name(app);
65
		if (!dir) continue;
46
		const char *exec = g_app_info_get_commandline(app);
66
  
47
  
67
		struct dirent *entry;
48
		if (name && exec) {
68
		while ((entry = readdir(dir))) {
49
			wm.launcher_items[wm.launcher_items_count].name = strdup(name);
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
  
50
  
73
				FILE *f = fopen(desktop_path, "r");
51
			char *e = strdup(exec);
74
				if (!f) continue;
52
			char *percent = strchr(e, '%');
  
53
			if (percent) *percent = '\0';
75
  
54
  
76
				char line[1024];
55
			// Trim potential trailing space after removing %
77
				char *name = NULL;
56
			int len = strlen(e);
78
				char *exec = NULL;
57
			while (len > 0 && isspace((unsigned char)e[len-1])) {
79
				int no_display = 0;
58
				e[--len] = '\0';
80
				int in_desktop_entry = 0;
59
			}
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
  
60
  
92
					if (!in_desktop_entry) continue;
61
			wm.launcher_items[wm.launcher_items_count].exec = strdup(e);
  
62
			free(e);
93
  
63
  
94
					if (strncmp(trimmed, "Name=", 5) == 0 && !name) {
64
			wm.launcher_items_count++;
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
		}
65
		}
122
		closedir(dir);
66
		g_object_unref(app);
123
	}
67
	}
  
68
	g_list_free(apps);
124
}
69
}
125
  
70
  
126
void toggle_launcher(const Arg *arg) {
71
void toggle_launcher(const Arg *arg) {
...