static void cb_keyboard(GLFWwindow* window, int k, int scancode, int action, int mods) { if(action != 1) return; if(k == '-') opt_levels--; if(k == '=') opt_levels++; if(k == '0') opt_levels = 4; if(k == GLFW_KEY_ESCAPE) exit(0); if(k == 'Q') exit(0); if(k == 'A') opt_apparent = !opt_apparent; if(k == 'C') opt_count = !opt_count; if(k == 'B') opt_bytes = !opt_bytes; if(k == 'F') fuzz = (fuzz == 0) ? opt_fuzz : 0; if(k == 'G') opt_gradient = !opt_gradient; if(k == ',') if(opt_ring_gap > 0) opt_ring_gap --; if(k == '.') opt_ring_gap ++; if(k == 'P') palette = (palette + 1) % 5; if(k == GLFW_KEY_BACKSPACE) { duc_dir *dir2 = duc_dir_openat(dir, ".."); if(dir2) { duc_dir_close(dir); dir = dir2; } } }
int gui_main(duc *duc, int argc, char *argv[]) { char *path = "."; if(argc > 0) path = argv[0]; fuzz = opt_fuzz; if(opt_palette) { char c = tolower(opt_palette[0]); if(c == 's') palette = DUC_GRAPH_PALETTE_SIZE; if(c == 'r') palette = DUC_GRAPH_PALETTE_RAINBOW; if(c == 'g') palette = DUC_GRAPH_PALETTE_GREYSCALE; if(c == 'm') palette = DUC_GRAPH_PALETTE_MONOCHROME; } int r = duc_open(duc, opt_database, DUC_OPEN_RO); if(r != DUC_OK) { duc_log(duc, DUC_LOG_FTL, "%s", duc_strerror(duc)); return -1; } dir = duc_dir_open(duc, path); if(dir == NULL) { duc_log(duc, DUC_LOG_FTL, "%s", duc_strerror(duc)); return -1; } dpy = XOpenDisplay(NULL); if(dpy == NULL) { duc_log(duc, DUC_LOG_FTL, "ERROR: Could not open display"); exit(1); } int scr = DefaultScreen(dpy); rootwin = RootWindow(dpy, scr); Window win = XCreateSimpleWindow( dpy, rootwin, 1, 1, win_w, win_h, 0, BlackPixel(dpy, scr), WhitePixel(dpy, scr)); XSelectInput(dpy, win, ExposureMask | ButtonPressMask | StructureNotifyMask | KeyPressMask | PointerMotionMask); XMapWindow(dpy, win); cs = cairo_xlib_surface_create(dpy, win, DefaultVisual(dpy, 0), win_w, win_h); cr = cairo_create(cs); graph = duc_graph_new_cairo(duc, cr); do_gui(duc, graph, dir); duc_dir_close(dir); return 0; }
void cb_mouse_button(GLFWwindow* window, int b, int action, int mods) { if(action != 1) return; double x, y; glfwGetCursorPos(window, &x, &y); sc2fb(window, &x, &y); if(b == 0) { duc_dir *dir2 = duc_graph_find_spot(graph, dir, x, y, NULL); if(dir2) { duc_dir_close(dir); dir = dir2; } } if(b == 3) { duc_dir *dir2 = duc_dir_openat(dir, ".."); if(dir2) { duc_dir_close(dir); dir = dir2; } } }
duc_dir *duc_dir_open(struct duc *duc, const char *path) { /* Canonicalized path */ char *path_canon = duc_canonicalize_path(path); if(!path_canon) { duc->err = DUC_E_PATH_NOT_FOUND; return NULL; } /* Find top path in database */ char *path_try = duc_strdup(path_canon); int l = strlen(path_try); struct duc_devino devino = { 0, 0 }; while(l > 0) { path_try[l] = '\0'; struct duc_index_report *report; report = db_read_report(duc, path_try); if(report) { devino = report->devino; free(report); break; } l--; } free(path_try); if(l == 0) { duc_log(duc, DUC_LOG_FTL, "Path %s not found in database", path_canon); duc->err = DUC_E_PATH_NOT_FOUND; free(path_canon); return NULL; } struct duc_dir *dir; dir = duc_dir_new(duc, &devino); if(dir == NULL) { duc->err = DUC_E_PATH_NOT_FOUND; free(path_canon); return NULL; } char rest[DUC_PATH_MAX]; strncpy(rest, path_canon+l, sizeof rest); char *name = strtok(rest, "/"); while(dir && name) { struct duc_dirent *ent = duc_dir_find_child(dir, name); struct duc_dir *dir_next = NULL; if(ent) { dir_next = duc_dir_openent(dir, ent); } duc_dir_close(dir); dir = dir_next; name = strtok(NULL, "/"); } if(dir) { dir->path = strdup(path_canon); } free(path_canon); return dir; }
duc_dir *duc_dir_open(struct duc *duc, const char *path) { /* Canonicalized path */ char *path_canon = stripdir(path); if(!path_canon) { duc->err = DUC_E_PATH_NOT_FOUND; return NULL; } /* Find top path in database */ int l = strlen(path_canon); dev_t dev = 0; ino_t ino = 0; while(l > 0) { struct duc_index_report *report; size_t report_len; report = db_get(duc->db, path_canon, l, &report_len); if(report && report_len == sizeof(*report)) { dev = report->dev; ino = report->ino; free(report); break; } l--; while(l > 1 && path_canon[l] != '/') l--; } if(l == 0) { duc_log(duc, DUC_LOG_WRN, "Path %s not found in database", path_canon); duc->err = DUC_E_PATH_NOT_FOUND; free(path_canon); return NULL; } struct duc_dir *dir; dir = db_read_dir(duc, dev, ino); if(dir == NULL) { duc->err = DUC_E_PATH_NOT_FOUND; free(path_canon); return NULL; } char rest[PATH_MAX]; strncpy(rest, path_canon+l, sizeof rest); char *name = strtok(rest, "/"); while(dir && name) { struct duc_dirent *ent = duc_dir_find_child(dir, name); struct duc_dir *dir_next = NULL; if(ent) { dir_next = duc_dir_openent(dir, ent); } duc_dir_close(dir); dir = dir_next; name = strtok(NULL, "/"); } if(dir) { dir->path = strdup(path_canon); } return dir; }
static int handle_event(XEvent e) { KeySym k; int x, y, b; switch(e.type) { case ConfigureNotify: win_w = e.xconfigure.width; win_h = e.xconfigure.height; cairo_xlib_surface_set_size(cs, win_w, win_h); redraw = 1; break; case Expose: if(e.xexpose.count < 1) redraw = 1; break; case KeyPress: k = XLookupKeysym(&e.xkey, 0); if(k == XK_minus) opt_levels--; if(k == XK_equal) opt_levels++; if(k == XK_0) opt_levels = 4; if(k == XK_Escape) return 1; if(k == XK_q) return 1; if(k == XK_a) opt_apparent = !opt_apparent; if(k == XK_b) opt_bytes = !opt_bytes; if(k == XK_f) fuzz = (fuzz == 0) ? opt_fuzz : 0; if(k == XK_comma) if(opt_ring_gap > 0) opt_ring_gap --; if(k == XK_period) opt_ring_gap ++; if(k == XK_p) { palette = (palette + 1) % 4; } if(k == XK_BackSpace) { duc_dir *dir2 = duc_dir_openat(dir, ".."); if(dir2) { duc_dir_close(dir); dir = dir2; } } redraw = 1; break; case ButtonPress: x = e.xbutton.x; y = e.xbutton.y; b = e.xbutton.button; if(b == 1) { duc_dir *dir2 = duc_graph_find_spot(graph, dir, x, y, NULL); if(dir2) { duc_dir_close(dir); dir = dir2; } } if(b == 3) { duc_dir *dir2 = duc_dir_openat(dir, ".."); if(dir2) { duc_dir_close(dir); dir = dir2; } } if(b == 4) opt_levels --; if(b == 5) opt_levels ++; redraw = 1; break; case MotionNotify: tooltip_x = e.xmotion.x; tooltip_y = e.xmotion.y; tooltip_moved = 1; break; default: break; } return 0; }
static duc_dir *do_dir(duc_dir *dir, int depth) { int top = 0; int cur = 0; for(;;) { int attr_size, attr_name, attr_class, attr_graph, attr_bar, attr_cursor; if(opt_color) { attr_size = COLOR_PAIR(PAIR_SIZE); attr_name = COLOR_PAIR(PAIR_NAME); attr_bar = COLOR_PAIR(PAIR_BAR); attr_cursor = COLOR_PAIR(PAIR_CURSOR); attr_graph = COLOR_PAIR(PAIR_GRAPH); attr_class = COLOR_PAIR(PAIR_CLASS); } else { attr_size = 0; attr_name = A_BOLD; attr_class = 0; attr_graph = 0; attr_bar = A_REVERSE; attr_cursor = A_REVERSE; use_default_colors(); } duc_size_type st = opt_apparent ? DUC_SIZE_TYPE_APPARENT : DUC_SIZE_TYPE_ACTUAL; /* Iterate all dirents to find largest size */ duc_dir_seek(dir, 0); off_t size_max = 1; struct duc_dirent *e; while( (e = duc_dir_read(dir, st)) != NULL) { off_t size = opt_apparent ? e->size.apparent : e->size.actual; if(size > size_max) size_max = size; } int count = duc_dir_get_count(dir); int pgsize = rows - 2; /* Check boundaries */ if(cur < 0) cur = 0; if(cur > count - 1) cur = count - 1; if(cur < top) top = cur; if(cur > top + pgsize - 1) top = cur - pgsize + 1; if(top < 0) top = 0; /* Draw header */ char *path = duc_dir_get_path(dir); attrset(attr_bar); mvhline(0, 0, ' ', cols); mvprintw(0, 1, " %s ", path); attrset(0); free(path); /* Draw footer */ struct duc_size size; duc_dir_get_size(dir, &size); char siz[32], cnt[32]; duc_human_size(&size, st, opt_bytes, siz, sizeof siz); duc_human_number(count, opt_bytes, cnt, sizeof cnt); attrset(attr_bar); mvhline(rows-1, 0, ' ', cols); mvprintw(rows-1, 0, " Total %sB in %s files/directories", siz, cnt); attrset(0); /* Draw dirents */ duc_dir_seek(dir, top); int i; int y = 1; for(i=top; i<top + pgsize; i++) { struct duc_dirent *e = duc_dir_read(dir, st); attrset(cur == i ? attr_cursor : 0); mvhline(y, 0, ' ', cols); if(e) { off_t size = opt_apparent ? e->size.apparent : e->size.actual; size_t max_size_len = opt_bytes ? 12 : 7; char class = duc_file_type_char(e->type); char siz[32]; duc_human_size(&e->size, st, opt_bytes, siz, sizeof siz); if(cur != i) attrset(attr_size); printw("%*s", max_size_len, siz); printw(" "); char *p = e->name; if(cur != i) attrset(attr_name); while(*p) { if(*(uint8_t *)p >= 32) { printw("%c", *p); } else { printw("^%c", *p+64); } p++; } if(cur != i) attrset(attr_class); printw("%c", class); int w = cols - 30; if(w > cols / 2) w = cols / 2; if(opt_graph && w > 2) { int j; off_t g = w * size / size_max; if(cur != i) attrset(attr_graph); mvprintw(y, cols - w - 4, " ["); for(j=0; j<w; j++) printw("%s", j < g ? "=" : " "); printw("] "); } } else { attrset(A_DIM); mvprintw(y, 0, "~"); } y++; } duc_dir *dir2 = NULL; /* Handle key */ int c = getch(); switch(c) { case 'k': case KEY_UP: cur--; break; case 'j': case KEY_DOWN: cur++; break; case 21: cur -= pgsize/2; break; case KEY_PPAGE: cur -= pgsize; break; case 4: cur += pgsize/2; break; case KEY_NPAGE: cur += pgsize; break; case KEY_RESIZE: getmaxyx(stdscr, rows, cols); break; case 'a': opt_apparent ^= 1; break; case 'b': opt_bytes ^= 1; break; case 'c': opt_color ^= 1; break; case 'g': opt_graph ^= 1; break; case 'h': help(); break; case 27: case 'q': exit(0); break; case KEY_BACKSPACE: case KEY_LEFT: if(depth > 0) { return NULL; } else { dir2 = duc_dir_openat(dir, ".."); if(dir2) { do_dir(dir2, 0); duc_dir_close(dir2); } } break; case KEY_RIGHT: case '\r': case '\n': duc_dir_seek(dir, cur); struct duc_dirent *e = duc_dir_read(dir, st); if(e->type == DUC_FILE_TYPE_DIR) { dir2 = duc_dir_openent(dir, e); if(dir2) { do_dir(dir2, depth + 1); duc_dir_close(dir2); } } break; default: break; } }