rofi 1.7.5
filebrowser.c
Go to the documentation of this file.
1
26#include <errno.h>
27#include <gio/gio.h>
28#include <gmodule.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <unistd.h>
33
34#include <dirent.h>
35#include <glib/gstdio.h>
36#include <sys/stat.h>
37#include <sys/types.h>
38
39#include "helper.h"
40#include "history.h"
41#include "mode-private.h"
42#include "mode.h"
43#include "modes/filebrowser.h"
44#include "rofi.h"
45#include "theme.h"
46
47#include <stdint.h>
48
49#include "rofi-icon-fetcher.h"
50
51#define FILEBROWSER_CACHE_FILE "rofi3.filebrowsercache"
52
53#if defined(__APPLE__)
54#define st_atim st_atimespec
55#define st_ctim st_ctimespec
56#define st_mtim st_mtimespec
57#endif
58
68
76
85
87const char *icon_name[NUM_FILE_TYPES] = {"go-up", "folder", "gtk-file"};
88typedef struct {
89 char *name;
90 char *path;
94 gboolean link;
95 time_t time;
96} FBFile;
97
98typedef struct {
101 unsigned int array_length;
102 unsigned int array_length_real;
104
108struct {
116 .sorting_method = FB_SORT_NAME,
117 .sorting_time = FB_MTIME,
118 .directories_first = TRUE,
120
122 for (unsigned int i = 0; i < pd->array_length; i++) {
123 FBFile *fb = &(pd->array[i]);
124 g_free(fb->name);
125 g_free(fb->path);
126 }
127 g_free(pd->array);
128 pd->array = NULL;
129 pd->array_length = 0;
130 pd->array_length_real = 0;
131}
132#include <dirent.h>
133#include <sys/types.h>
134
135static gint compare_name(gconstpointer a, gconstpointer b,
136 G_GNUC_UNUSED gpointer data) {
137 FBFile *fa = (FBFile *)a;
138 FBFile *fb = (FBFile *)b;
139
140 if (file_browser_config.directories_first && fa->type != fb->type) {
141 return fa->type - fb->type;
142 }
143
144 return g_strcmp0(fa->name, fb->name);
145}
146
147static gint compare_time(gconstpointer a, gconstpointer b,
148 G_GNUC_UNUSED gpointer data) {
149 FBFile *fa = (FBFile *)a;
150 FBFile *fb = (FBFile *)b;
151
152 if (file_browser_config.directories_first && fa->type != fb->type) {
153 return fa->type - fb->type;
154 }
155
156 if (fa->time < 0) {
157 return -1;
158 }
159
160 if (fb->time < 0) {
161 return 1;
162 }
163
164 return fb->time - fa->time;
165}
166
167static gint compare(gconstpointer a, gconstpointer b, gpointer data) {
168 GCompareDataFunc comparator = NULL;
169
170 switch (file_browser_config.sorting_method) {
171 case FB_SORT_NAME:
172 comparator = compare_name;
173 break;
174 case FB_SORT_TIME:
175 comparator = compare_time;
176 break;
177 default:
178 comparator = compare_name;
179 break;
180 }
181
182 return comparator(a, b, data);
183}
184
185static time_t get_time(const GStatBuf *statbuf) {
186 switch (file_browser_config.sorting_time) {
187 case FB_MTIME:
188 return statbuf->st_mtim.tv_sec;
189 case FB_ATIME:
190 return statbuf->st_atim.tv_sec;
191 case FB_CTIME:
192 return statbuf->st_ctim.tv_sec;
193 default:
194 return 0;
195 }
196}
197
198static void set_time(FBFile *file) {
199 // GError *error = NULL;
200 // gchar *path = g_filename_from_utf8(file->path, -1, NULL, NULL, &error);
201 // if (error) {
202 // g_warning("Failed to convert filename: %s: %s", file->path,
203 // error->message); g_error_free(error); return;
204 // }
205
206 GStatBuf statbuf;
207
208 if (g_lstat(file->path, &statbuf) == 0) {
209 file->time = get_time(&statbuf);
210 } else {
211 g_warning("Failed to stat file: %s, %s", file->path, strerror(errno));
212 }
213
214 // g_free(path);
215}
216
218 if ((pd->array_length + 1) > pd->array_length_real) {
219 pd->array_length_real += 256;
220 pd->array =
221 g_realloc(pd->array, (pd->array_length_real + 1) * sizeof(FBFile));
222 }
223}
224
225static void get_file_browser(Mode *sw) {
232 char *cdir = g_file_get_path(pd->current_dir);
233 DIR *dir = opendir(cdir);
234 if (dir) {
235 struct dirent *rd = NULL;
236 while ((rd = readdir(dir)) != NULL) {
237 if (g_strcmp0(rd->d_name, "..") == 0) {
238 fb_resize_array(pd);
239 // Rofi expects utf-8, so lets convert the filename.
240 pd->array[pd->array_length].name = g_strdup("..");
241 pd->array[pd->array_length].path = NULL;
242 pd->array[pd->array_length].type = UP;
243 pd->array[pd->array_length].icon_fetch_uid = 0;
245 pd->array[pd->array_length].link = FALSE;
246 pd->array[pd->array_length].time = -1;
247 pd->array_length++;
248 continue;
249 }
250 if (rd->d_name[0] == '.') {
251 continue;
252 }
253
254 switch (rd->d_type) {
255 case DT_BLK:
256 case DT_CHR:
257 case DT_FIFO:
258 case DT_UNKNOWN:
259 case DT_SOCK:
260 default:
261 break;
262 case DT_REG:
263 case DT_DIR:
264 fb_resize_array(pd);
265 // Rofi expects utf-8, so lets convert the filename.
266 pd->array[pd->array_length].name =
267 g_filename_to_utf8(rd->d_name, -1, NULL, NULL, NULL);
268 if (pd->array[pd->array_length].name == NULL) {
269 pd->array[pd->array_length].name = rofi_force_utf8(rd->d_name, -1);
270 }
271 pd->array[pd->array_length].path =
272 g_build_filename(cdir, rd->d_name, NULL);
273 pd->array[pd->array_length].type =
274 (rd->d_type == DT_DIR) ? DIRECTORY : RFILE;
275 pd->array[pd->array_length].icon_fetch_uid = 0;
277 pd->array[pd->array_length].link = FALSE;
278
279 if (file_browser_config.sorting_method == FB_SORT_TIME) {
280 set_time(&pd->array[pd->array_length]);
281 }
282
283 pd->array_length++;
284 break;
285 case DT_LNK:
286 fb_resize_array(pd);
287 // Rofi expects utf-8, so lets convert the filename.
288 pd->array[pd->array_length].name =
289 g_filename_to_utf8(rd->d_name, -1, NULL, NULL, NULL);
290 if (pd->array[pd->array_length].name == NULL) {
291 pd->array[pd->array_length].name = rofi_force_utf8(rd->d_name, -1);
292 }
293 pd->array[pd->array_length].path =
294 g_build_filename(cdir, rd->d_name, NULL);
295 pd->array[pd->array_length].icon_fetch_uid = 0;
297 pd->array[pd->array_length].link = TRUE;
298 // Default to file.
299 pd->array[pd->array_length].type = RFILE;
300 {
301 // If we have link, use a stat to fine out what it is, if we fail, we
302 // mark it as file.
303 // TODO have a 'broken link' mode?
304 // Convert full path to right encoding.
305 // DD: Path should be in file encoding, not utf-8
306 // char *file =
307 // g_filename_from_utf8(pd->array[pd->array_length].path,
308 // -1, NULL, NULL, NULL);
309 if (pd->array[pd->array_length].path) {
310 GStatBuf statbuf;
311 if (g_stat(pd->array[pd->array_length].path, &statbuf) == 0) {
312 if (S_ISDIR(statbuf.st_mode)) {
313 pd->array[pd->array_length].type = DIRECTORY;
314 } else if (S_ISREG(statbuf.st_mode)) {
315 pd->array[pd->array_length].type = RFILE;
316 }
317
318 if (file_browser_config.sorting_method == FB_SORT_TIME) {
319 pd->array[pd->array_length].time = get_time(&statbuf);
320 }
321 } else {
322 g_warning("Failed to stat file: %s, %s",
323 pd->array[pd->array_length].path, strerror(errno));
324 }
325
326 // g_free(file);
327 }
328 }
329 pd->array_length++;
330 break;
331 }
332 }
333 closedir(dir);
334 }
335 g_free(cdir);
336 g_qsort_with_data(pd->array, pd->array_length, sizeof(FBFile), compare, NULL);
337}
338
340 char *msg = NULL;
341 gboolean found_error = FALSE;
342
343 ThemeWidget *wid = rofi_config_find_widget(sw->name, NULL, TRUE);
344
345 Property *p = rofi_theme_find_property(wid, P_STRING, "sorting-method", TRUE);
346 if (p != NULL && p->type == P_STRING) {
347 if (g_strcmp0(p->value.s, "name") == 0) {
348 file_browser_config.sorting_method = FB_SORT_NAME;
349 } else if (g_strcmp0(p->value.s, "mtime") == 0) {
350 file_browser_config.sorting_method = FB_SORT_TIME;
351 file_browser_config.sorting_time = FB_MTIME;
352 } else if (g_strcmp0(p->value.s, "atime") == 0) {
353 file_browser_config.sorting_method = FB_SORT_TIME;
354 file_browser_config.sorting_time = FB_ATIME;
355 } else if (g_strcmp0(p->value.s, "ctime") == 0) {
356 file_browser_config.sorting_method = FB_SORT_TIME;
357 file_browser_config.sorting_time = FB_CTIME;
358 } else {
359 found_error = TRUE;
360
361 msg = g_strdup_printf("\"%s\" is not a valid filebrowser sorting method",
362 p->value.s);
363 }
364 }
365
366 p = rofi_theme_find_property(wid, P_BOOLEAN, "directories-first", TRUE);
367 if (p != NULL && p->type == P_BOOLEAN) {
368 file_browser_config.directories_first = p->value.b;
369 }
370
371 if (found_error) {
372 rofi_view_error_dialog(msg, FALSE);
373
374 g_free(msg);
375 }
376}
377
381
382 ThemeWidget *wid = rofi_config_find_widget(sw->name, NULL, TRUE);
383
384 Property *p = rofi_theme_find_property(wid, P_STRING, "directory", TRUE);
385
386 gboolean config_has_valid_dir = p != NULL && p->type == P_STRING &&
387 g_file_test(p->value.s, G_FILE_TEST_IS_DIR);
388
389 if (config_has_valid_dir) {
390 pd->current_dir = g_file_new_for_path(p->value.s);
391 } else {
392 char *current_dir = NULL;
393 char *cache_file =
394 g_build_filename(cache_dir, FILEBROWSER_CACHE_FILE, NULL);
395
396 if (g_file_get_contents(cache_file, &current_dir, NULL, NULL)) {
397 if (g_file_test(current_dir, G_FILE_TEST_IS_DIR)) {
398 pd->current_dir = g_file_new_for_path(current_dir);
399 }
400
401 g_free(current_dir);
402 }
403
404 // Store it based on the unique identifiers (desktop_id).
405 g_free(cache_file);
406 }
407
408 if (pd->current_dir == NULL) {
409 pd->current_dir = g_file_new_for_path(g_get_home_dir());
410 }
411}
412
417 if (mode_get_private_data(sw) == NULL) {
418 FileBrowserModePrivateData *pd = g_malloc0(sizeof(*pd));
419 mode_set_private_data(sw, (void *)pd);
420
423
424 // Load content.
426 }
427 return TRUE;
428}
429static unsigned int file_browser_mode_get_num_entries(const Mode *sw) {
432 return pd->array_length;
433}
434
435static ModeMode file_browser_mode_result(Mode *sw, int mretv, char **input,
436 unsigned int selected_line) {
437 ModeMode retv = MODE_EXIT;
440
441 gboolean special_command =
443 if (mretv & MENU_NEXT) {
444 retv = NEXT_DIALOG;
445 } else if (mretv & MENU_PREVIOUS) {
446 retv = PREVIOUS_DIALOG;
447 } else if (mretv & MENU_QUICK_SWITCH) {
448 retv = (mretv & MENU_LOWER_MASK);
449 } else if (mretv & MENU_CUSTOM_COMMAND) {
450 retv = (mretv & MENU_LOWER_MASK);
451 } else if ((mretv & MENU_OK)) {
452 if (selected_line < pd->array_length) {
453 if (pd->array[selected_line].type == UP) {
454 GFile *new = g_file_get_parent(pd->current_dir);
455 if (new) {
456 g_object_unref(pd->current_dir);
457 pd->current_dir = new;
458 free_list(pd);
460 return RESET_DIALOG;
461 }
462 } else if ((pd->array[selected_line].type == RFILE) ||
463 (pd->array[selected_line].type == DIRECTORY &&
464 special_command)) {
465 char *d_esc = g_shell_quote(pd->array[selected_line].path);
466 char *cmd = g_strdup_printf("xdg-open %s", d_esc);
467 g_free(d_esc);
468 char *cdir = g_file_get_path(pd->current_dir);
469 helper_execute_command(cdir, cmd, FALSE, NULL);
470 g_free(cdir);
471 g_free(cmd);
472 return MODE_EXIT;
473 } else if (pd->array[selected_line].type == DIRECTORY) {
474 char *path = g_build_filename(cache_dir, FILEBROWSER_CACHE_FILE, NULL);
475 g_file_set_contents(path, pd->array[selected_line].path, -1, NULL);
476 g_free(path);
477 GFile *new = g_file_new_for_path(pd->array[selected_line].path);
478 g_object_unref(pd->current_dir);
479 pd->current_dir = new;
480 free_list(pd);
482 return RESET_DIALOG;
483 }
484 }
485 retv = RELOAD_DIALOG;
486 } else if ((mretv & MENU_CUSTOM_INPUT)) {
487 if (special_command) {
488 GFile *new = g_file_get_parent(pd->current_dir);
489 if (new) {
490 g_object_unref(pd->current_dir);
491 pd->current_dir = new;
492 free_list(pd);
494 }
495 return RESET_DIALOG;
496 }
497 if (*input) {
498 char *p = rofi_expand_path(*input);
499 char *dir = g_filename_from_utf8(p, -1, NULL, NULL, NULL);
500 g_free(p);
501 if (g_file_test(dir, G_FILE_TEST_EXISTS)) {
502 if (g_file_test(dir, G_FILE_TEST_IS_DIR)) {
503 g_object_unref(pd->current_dir);
504 pd->current_dir = g_file_new_for_path(dir);
505 g_free(dir);
506 free_list(pd);
508 return RESET_DIALOG;
509 }
510 }
511 g_free(dir);
512 retv = RELOAD_DIALOG;
513 }
514 } else if ((mretv & MENU_ENTRY_DELETE) == MENU_ENTRY_DELETE) {
515 retv = RELOAD_DIALOG;
516 }
517 return retv;
518}
519
523 if (pd != NULL) {
524 g_object_unref(pd->current_dir);
525 free_list(pd);
526 g_free(pd);
527 mode_set_private_data(sw, NULL);
528 }
529}
530
531static char *_get_display_value(const Mode *sw, unsigned int selected_line,
532 G_GNUC_UNUSED int *state,
533 G_GNUC_UNUSED GList **attr_list,
534 int get_entry) {
537
538 // Only return the string if requested, otherwise only set state.
539 if (!get_entry) {
540 return NULL;
541 }
542 if (pd->array[selected_line].type == UP) {
543 return g_strdup(" ..");
544 }
545 if (pd->array[selected_line].link) {
546 return g_strconcat("@", pd->array[selected_line].name, NULL);
547 }
548 return g_strdup(pd->array[selected_line].name);
549}
550
560static int file_browser_token_match(const Mode *sw, rofi_int_matcher **tokens,
561 unsigned int index) {
564
565 // Call default matching function.
566 return helper_token_match(tokens, pd->array[index].name);
567}
568
569static cairo_surface_t *_get_icon(const Mode *sw, unsigned int selected_line,
570 unsigned int height) {
573 g_return_val_if_fail(pd->array != NULL, NULL);
574 FBFile *dr = &(pd->array[selected_line]);
575 if (dr->icon_fetch_uid > 0 && dr->icon_fetch_size == height) {
577 }
580 } else {
582 }
583 dr->icon_fetch_size = height;
585}
586
587static char *_get_message(const Mode *sw) {
590 if (pd->current_dir) {
591 char *dirname = g_file_get_parse_name(pd->current_dir);
592 char *str =
593 g_markup_printf_escaped("<b>Current directory:</b> %s", dirname);
594 g_free(dirname);
595 return str;
596 }
597 return "n/a";
598}
599
600static char *_get_completion(const Mode *sw, unsigned int index) {
603
604 char *d = g_strescape(pd->array[index].path, NULL);
605 return d;
606}
607
609 Mode *sw = g_malloc0(sizeof(Mode));
610
611 *sw = file_browser_mode;
612
613 sw->private_data = NULL;
614 return sw;
615}
616
617#if 1
618ModeMode file_browser_mode_completer(Mode *sw, int mretv, char **input,
619 unsigned int selected_line, char **path) {
620 ModeMode retv = MODE_EXIT;
623 if (mretv & MENU_NEXT) {
624 retv = NEXT_DIALOG;
625 } else if (mretv & MENU_PREVIOUS) {
626 retv = PREVIOUS_DIALOG;
627 } else if (mretv & MENU_QUICK_SWITCH) {
628 retv = (mretv & MENU_LOWER_MASK);
629 } else if ((mretv & MENU_OK)) {
630 if (selected_line < pd->array_length) {
631 if (pd->array[selected_line].type == UP) {
632 GFile *new = g_file_get_parent(pd->current_dir);
633 if (new) {
634 g_object_unref(pd->current_dir);
635 pd->current_dir = new;
636 free_list(pd);
638 return RESET_DIALOG;
639 }
640 } else if (pd->array[selected_line].type == DIRECTORY) {
641 GFile *new = g_file_new_for_path(pd->array[selected_line].path);
642 g_object_unref(pd->current_dir);
643 pd->current_dir = new;
644 free_list(pd);
646 return RESET_DIALOG;
647 } else if (pd->array[selected_line].type == RFILE) {
648 *path = g_strescape(pd->array[selected_line].path, NULL);
649 return MODE_EXIT;
650 }
651 }
652 retv = RELOAD_DIALOG;
653 } else if ((mretv & MENU_CUSTOM_INPUT) && *input) {
654 char *p = rofi_expand_path(*input);
655 char *dir = g_filename_from_utf8(p, -1, NULL, NULL, NULL);
656 g_free(p);
657 if (g_file_test(dir, G_FILE_TEST_EXISTS)) {
658 if (g_file_test(dir, G_FILE_TEST_IS_DIR)) {
659 g_object_unref(pd->current_dir);
660 pd->current_dir = g_file_new_for_path(dir);
661 g_free(dir);
662 free_list(pd);
664 return RESET_DIALOG;
665 }
666 }
667 g_free(dir);
668 retv = RELOAD_DIALOG;
669 } else if ((mretv & MENU_ENTRY_DELETE) == MENU_ENTRY_DELETE) {
670 retv = RELOAD_DIALOG;
671 }
672 return retv;
673}
674#endif
675
677 .display_name = NULL,
678 .abi_version = ABI_VERSION,
679 .name = "filebrowser",
680 .cfg_name_key = "display-filebrowser",
681 ._init = file_browser_mode_init,
682 ._get_num_entries = file_browser_mode_get_num_entries,
683 ._result = file_browser_mode_result,
684 ._destroy = file_browser_mode_destroy,
685 ._token_match = file_browser_token_match,
686 ._get_display_value = _get_display_value,
687 ._get_icon = _get_icon,
688 ._get_message = _get_message,
689 ._get_completion = _get_completion,
690 ._preprocess_input = NULL,
691 .private_data = NULL,
692 .free = NULL,
693};
static int file_browser_token_match(const Mode *sw, rofi_int_matcher **tokens, unsigned int index)
static char * _get_message(const Mode *sw)
static void free_list(FileBrowserModePrivateData *pd)
struct @0 file_browser_config
static char * _get_completion(const Mode *sw, unsigned int index)
static unsigned int file_browser_mode_get_num_entries(const Mode *sw)
FBFileType
Definition filebrowser.c:62
@ NUM_FILE_TYPES
Definition filebrowser.c:66
@ DIRECTORY
Definition filebrowser.c:64
@ UP
Definition filebrowser.c:63
@ RFILE
Definition filebrowser.c:65
static cairo_surface_t * _get_icon(const Mode *sw, unsigned int selected_line, unsigned int height)
static void file_browser_mode_init_current_dir(Mode *sw)
static void fb_resize_array(FileBrowserModePrivateData *pd)
static void set_time(FBFile *file)
#define FILEBROWSER_CACHE_FILE
Definition filebrowser.c:51
static gint compare_time(gconstpointer a, gconstpointer b, G_GNUC_UNUSED gpointer data)
static void file_browser_mode_destroy(Mode *sw)
enum FBSortingMethod sorting_method
enum FBSortingTime sorting_time
static gint compare_name(gconstpointer a, gconstpointer b, G_GNUC_UNUSED gpointer data)
FBSortingMethod
Definition filebrowser.c:72
@ FB_SORT_NAME
Definition filebrowser.c:73
@ FB_SORT_TIME
Definition filebrowser.c:74
static char * _get_display_value(const Mode *sw, unsigned int selected_line, G_GNUC_UNUSED int *state, G_GNUC_UNUSED GList **attr_list, int get_entry)
static void get_file_browser(Mode *sw)
FBSortingTime
Definition filebrowser.c:80
@ FB_CTIME
Definition filebrowser.c:83
@ FB_MTIME
Definition filebrowser.c:81
@ FB_ATIME
Definition filebrowser.c:82
static int file_browser_mode_init(Mode *sw)
static ModeMode file_browser_mode_result(Mode *sw, int mretv, char **input, unsigned int selected_line)
static void file_browser_mode_init_config(Mode *sw)
const char * icon_name[NUM_FILE_TYPES]
Definition filebrowser.c:87
gboolean directories_first
static time_t get_time(const GStatBuf *statbuf)
static gint compare(gconstpointer a, gconstpointer b, gpointer data)
Mode file_browser_mode
Mode * create_new_file_browser(void)
ModeMode file_browser_mode_completer(Mode *sw, int mretv, char **input, unsigned int selected_line, char **path)
gboolean helper_execute_command(const char *wd, const char *cmd, gboolean run_in_term, RofiHelperExecuteContext *context)
Definition helper.c:1030
char * rofi_expand_path(const char *input)
Definition helper.c:740
int helper_token_match(rofi_int_matcher *const *tokens, const char *input)
Definition helper.c:518
char * rofi_force_utf8(const gchar *data, ssize_t length)
Definition helper.c:814
gboolean rofi_icon_fetcher_file_is_image(const char *const path)
cairo_surface_t * rofi_icon_fetcher_get(const uint32_t uid)
uint32_t rofi_icon_fetcher_query(const char *name, const int size)
void * mode_get_private_data(const Mode *mode)
Definition mode.c:159
void mode_set_private_data(Mode *mode, void *pd)
Definition mode.c:164
ModeMode
Definition mode.h:49
@ MENU_CUSTOM_COMMAND
Definition mode.h:79
@ MENU_LOWER_MASK
Definition mode.h:87
@ MENU_PREVIOUS
Definition mode.h:81
@ MENU_QUICK_SWITCH
Definition mode.h:77
@ MENU_ENTRY_DELETE
Definition mode.h:75
@ MENU_NEXT
Definition mode.h:71
@ MENU_CUSTOM_ACTION
Definition mode.h:85
@ MENU_OK
Definition mode.h:67
@ MENU_CUSTOM_INPUT
Definition mode.h:73
@ MODE_EXIT
Definition mode.h:51
@ NEXT_DIALOG
Definition mode.h:53
@ RELOAD_DIALOG
Definition mode.h:55
@ PREVIOUS_DIALOG
Definition mode.h:57
@ RESET_DIALOG
Definition mode.h:59
const char * cache_dir
Definition rofi.c:83
int rofi_view_error_dialog(const char *msg, int markup)
Definition view.c:2191
#define ABI_VERSION
@ P_BOOLEAN
Definition rofi-types.h:20
@ P_STRING
Definition rofi-types.h:16
enum FBFileType type
Definition filebrowser.c:91
gboolean link
Definition filebrowser.c:94
uint32_t icon_fetch_size
Definition filebrowser.c:93
char * path
Definition filebrowser.c:90
char * name
Definition filebrowser.c:89
uint32_t icon_fetch_uid
Definition filebrowser.c:92
time_t time
Definition filebrowser.c:95
PropertyValue value
Definition rofi-types.h:297
PropertyType type
Definition rofi-types.h:295
char * display_name
char * name
void * private_data
Property * rofi_theme_find_property(ThemeWidget *widget, PropertyType type, const char *property, gboolean exact)
Definition theme.c:740
ThemeWidget * rofi_config_find_widget(const char *name, const char *state, gboolean exact)
Definition theme.c:778