/* * This file is part of firk's window manager for x11 (fwm) * Copyright (C) 2022 firk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "fwm-menu.h" #include "xdg_parser.h" #include "dirscan.h" char const *dirs[MAX_MENU_DIRS]; size_t ND; t_menu_list menus[MAX_MENU_NESTING]; size_t NM; int debug_dirscan = 0; static void printpath(size_t JM, size_t JD) { size_t jm; assert(JMisdir>b->isdir) return -1; if(a->isdirisdir) return 1; return strcasecmp(a->xdg.title?a->xdg.title:a->name, b->xdg.title?b->xdg.title:b->name); #undef a #undef b } static void fill_entries(void) { size_t j; t_menu_entry ee[MAX_MENU_ENTRIES]; size_t ne, je, jj; int dupfd, isdir; DIR *dp; struct dirent *de; char const *name; struct stat sb; int *fds; t_menu_list *ml; assert(NMe.n && !ml->e.sel && !ml->e.list); ne = 0; if(fds = ml->fds) for(j=0; j=0) { if((dupfd = dup(fds[j]))<0) { logprint_path(NM, j, "dup() error %d (%s)", errno, strerror(errno)); continue; } if(!(dp = fdopendir(dupfd))) { logprint_path(NM, j, "fdopendir() error %d (%s)", errno, strerror(errno)); close(dupfd); continue; } while(errno=0,de=readdir(dp)) { if(!*de->d_name || *de->d_name=='.') continue; while(fstatat(dupfd, de->d_name, &sb, 0)<0) if(errno!=EINTR) { logprint_path(NM, j, "stat(%s) error %d (%s)", de->d_name, errno, strerror(errno)); goto cont; } if(S_ISDIR(sb.st_mode)) { if(debug_dirscan) fprintf(stderr, "(%u) directory: %s\n", (unsigned)NM, de->d_name); isdir = 1; } else if(S_ISREG(sb.st_mode)) { if(debug_dirscan) fprintf(stderr, "(%u) file: %s\n", (unsigned)NM, de->d_name); isdir = 0; } else { if(debug_dirscan) fprintf(stderr, "(%u) wrong type: %s\n", (unsigned)NM, de->d_name); continue; } for(je=0; jed_name)) break; if(jed_name))) { logprint_path(NM, j, "out of memory"); continue; } ee[je].isdir = isdir; if(!isdir) { if(debug_dirscan) fprintf(stderr, "(%u) checking: %s\n", (unsigned)NM, ee[je].name); jj = strlen(ee[je].name); if(jj>8 && !strcmp(ee[je].name+(jj-8),".desktop")) { if(parse_desktop_file(&ee[je].xdg, dupfd, ee[je].name)<0) { if(debug_dirscan) fprintf(stderr, "(%u) bad .desktop, skipping: %s\n", (unsigned)NM, ee[je].name); free((void*)ee[je].name); continue; } if(debug_dirscan) fprintf(stderr, "(%u) parsed .desktop: %s | %s | %s\n", (unsigned)NM, ee[je].name, ee[je].xdg.title, ee[je].xdg.command); } else if(!(sb.st_mode & 0111)) { if(debug_dirscan) fprintf(stderr, "(%u) bad non-exec, skipping: %s\n", (unsigned)NM, ee[je].name); free((void*)ee[je].name); continue; } else { if(debug_dirscan) fprintf(stderr, "(%u) executable: %s\n", (unsigned)NM, ee[je].name); } } ee[je].fd_idx = j; ne++; cont: ; } if(errno) logprint_path(NM, j, "readdir() error %d (%s)", errno, strerror(errno)); closedir(dp); } if(!ne) return; if(!(ml->e.list = malloc(sizeof(t_menu_entry)*ne))) { logprint_path(NM, ND, "out of memory"); while(ne) { ne--; free((void*)ee[ne].name); } return; } qsort(ee, ne, sizeof(t_menu_entry), &menu_cmp); bcopy(ee, ml->e.list, sizeof(t_menu_entry)*ne); ml->e.n = ml->e.sel = ml->e.sel_stable = ne; } extern void menu_list_open(char const *name) { t_menu_list *ml; if(!name) { assert(NM==0); } else { assert(NM>=1 && NMmyname = name; open_fds(); fill_entries(); NM++; } extern void menu_list_close(void) { int *fds; size_t j, n; t_menu_entry *e; t_menu_list *ml; assert(NM>=1 && NM<=MAX_MENU_NESTING); NM--; ml = menus+NM; fds = ml->fds; e = ml->e.list; n = ml->e.n; if(n) { assert(fds); assert(e); for(j=0; j=0) close(fds[j]); free(fds); } bzero(ml, sizeof(*ml)); }