static int has_dir(const char *home, const char *user, int i, char dir[PATH_MAX], char vis[PATH_MAX]) { const char *subdir = common_dirs[i].name; int icon = common_dirs[i].icon; if (subdir[0] == '~') { if (!home) return 0; if (subdir[1] == '/') { fz_snprintf(dir, PATH_MAX, "%s/%s", home, subdir+2); fz_snprintf(vis, PATH_MAX, "%C %s", icon, subdir+2); } else { fz_snprintf(dir, PATH_MAX, "%s", home); fz_snprintf(vis, PATH_MAX, "%C %s", icon, user ? user : "******"); } } else { fz_strlcpy(dir, subdir, PATH_MAX); fz_snprintf(vis, PATH_MAX, "%C %s", icon, subdir); } return fz_is_directory(ctx, dir); }
/* * Read and interleave split parts from a ZIP file. */ xps_part * xps_read_part(fz_context *ctx, xps_document *doc, char *partname) { fz_archive *zip = doc->zip; fz_buffer *buf, *tmp; char path[2048]; int count; char *name; int seen_last; name = partname; if (name[0] == '/') name ++; /* All in one piece */ if (fz_has_archive_entry(ctx, zip, name)) { buf = fz_read_archive_entry(ctx, zip, name); } /* Assemble all the pieces */ else { buf = fz_new_buffer(ctx, 512); seen_last = 0; for (count = 0; !seen_last; ++count) { fz_snprintf(path, sizeof path, "%s/[%d].piece", name, count); if (fz_has_archive_entry(ctx, zip, path)) { tmp = fz_read_archive_entry(ctx, zip, path); fz_append_buffer(ctx, buf, tmp); fz_drop_buffer(ctx, tmp); } else { fz_snprintf(path, sizeof path, "%s/[%d].last.piece", name, count); if (fz_has_archive_entry(ctx, zip, path)) { tmp = fz_read_archive_entry(ctx, zip, path); fz_append_buffer(ctx, buf, tmp); fz_drop_buffer(ctx, tmp); seen_last = 1; } else { fz_drop_buffer(ctx, buf); fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find all pieces for part '%s'", partname); } } } } return xps_new_part(ctx, doc, partname, buf); }
char * pdf_parse_file_spec(fz_context *ctx, pdf_document *doc, pdf_obj *file_spec, pdf_obj *dest) { pdf_obj *filename = NULL; const char *path; char *uri; char frag[256]; if (pdf_is_string(ctx, file_spec)) filename = file_spec; if (pdf_is_dict(ctx, file_spec)) { #ifdef _WIN32 filename = pdf_dict_get(ctx, file_spec, PDF_NAME(DOS)); #else filename = pdf_dict_get(ctx, file_spec, PDF_NAME(Unix)); #endif if (!filename) filename = pdf_dict_geta(ctx, file_spec, PDF_NAME(UF), PDF_NAME(F)); } if (!pdf_is_string(ctx, filename)) { fz_warn(ctx, "cannot parse file specification"); return NULL; } if (pdf_is_array(ctx, dest)) fz_snprintf(frag, sizeof frag, "#page=%d", pdf_array_get_int(ctx, dest, 0) + 1); else if (pdf_is_name(ctx, dest)) fz_snprintf(frag, sizeof frag, "#%s", pdf_to_name(ctx, dest)); else if (pdf_is_string(ctx, dest)) fz_snprintf(frag, sizeof frag, "#%s", pdf_to_str_buf(ctx, dest)); else frag[0] = 0; path = pdf_to_text_string(ctx, filename); uri = NULL; #ifdef _WIN32 if (!pdf_name_eq(ctx, pdf_dict_get(ctx, file_spec, PDF_NAME(FS)), PDF_NAME(URL))) { /* Fix up the drive letter (change "/C/Documents/Foo" to "C:/Documents/Foo") */ if (path[0] == '/' && (('A' <= path[1] && path[1] <= 'Z') || ('a' <= path[1] && path[1] <= 'z')) && path[2] == '/') uri = fz_asprintf(ctx, "file://%c:%s%s", path[1], path+2, frag); } #endif if (!uri) uri = fz_asprintf(ctx, "file://%s%s", path, frag); return uri; }
static void format_list_number(fz_context *ctx, int type, int x, char *buf, int size) { switch (type) { case LST_NONE: fz_strlcpy(buf, "", size); break; case LST_DISC: fz_strlcpy(buf, "\342\227\217 ", size); break; /* U+25CF BLACK CIRCLE */ case LST_CIRCLE: fz_strlcpy(buf, "\342\227\213 ", size); break; /* U+25CB WHITE CIRCLE */ case LST_SQUARE: fz_strlcpy(buf, "\342\226\240 ", size); break; /* U+25A0 BLACK SQUARE */ default: case LST_DECIMAL: fz_snprintf(buf, size, "%d. ", x); break; case LST_DECIMAL_ZERO: fz_snprintf(buf, size, "%02d. ", x); break; case LST_LC_ROMAN: format_roman_number(ctx, buf, size, x, roman_lc, "m"); break; case LST_UC_ROMAN: format_roman_number(ctx, buf, size, x, roman_uc, "M"); break; case LST_LC_ALPHA: format_alpha_number(ctx, buf, size, x, 'a', 'z'); break; case LST_UC_ALPHA: format_alpha_number(ctx, buf, size, x, 'A', 'Z'); break; case LST_LC_LATIN: format_alpha_number(ctx, buf, size, x, 'a', 'z'); break; case LST_UC_LATIN: format_alpha_number(ctx, buf, size, x, 'A', 'Z'); break; case LST_LC_GREEK: format_alpha_number(ctx, buf, size, x, 0x03B1, 0x03C9); break; case LST_UC_GREEK: format_alpha_number(ctx, buf, size, x, 0x0391, 0x03A9); break; } }
static void cbz_end_page(fz_context *ctx, fz_document_writer *wri_, fz_device *dev) { fz_cbz_writer *wri = (fz_cbz_writer*)wri_; fz_buffer *buffer; char name[40]; fz_try(ctx) fz_close_device(ctx, dev); fz_always(ctx) fz_drop_device(ctx, dev); fz_catch(ctx) fz_rethrow(ctx); wri->count += 1; fz_snprintf(name, sizeof name, "p%04d.png", wri->count); buffer = fz_new_buffer_from_pixmap_as_png(ctx, wri->pixmap, NULL); fz_try(ctx) fz_write_zip_entry(ctx, wri->zip, name, buffer, 0); fz_always(ctx) fz_drop_buffer(ctx, buffer); fz_catch(ctx) fz_rethrow(ctx); fz_drop_pixmap(ctx, wri->pixmap); wri->pixmap = NULL; }
int xps_has_part(fz_context *ctx, xps_document *doc, char *name) { char buf[2048]; if (name[0] == '/') name++; if (fz_has_archive_entry(ctx, doc->zip, name)) return 1; fz_snprintf(buf, sizeof buf, "%s/[0].piece", name); if (fz_has_archive_entry(ctx, doc->zip, buf)) return 1; fz_snprintf(buf, sizeof buf, "%s/[0].last.piece", name); if (fz_has_archive_entry(ctx, doc->zip, buf)) return 1; return 0; }
static void pdf_dev_alpha(fz_context *ctx, pdf_device *pdev, float alpha, int stroke) { int i; pdf_document *doc = pdev->doc; gstate *gs = CURRENT_GSTATE(pdev); /* If the alpha is unchanged, nothing to do */ if (gs->alpha[stroke] == alpha) return; /* Have we sent such an alpha before? */ for (i = 0; i < pdev->num_alphas; i++) if (pdev->alphas[i].alpha == alpha && pdev->alphas[i].stroke == stroke) break; if (i == pdev->num_alphas) { pdf_obj *o; pdf_obj *ref = NULL; fz_var(ref); /* No. Need to make a new one */ if (pdev->num_alphas == pdev->max_alphas) { int newmax = pdev->max_alphas * 2; if (newmax == 0) newmax = 4; pdev->alphas = fz_resize_array(ctx, pdev->alphas, newmax, sizeof(*pdev->alphas)); pdev->max_alphas = newmax; } pdev->alphas[i].alpha = alpha; pdev->alphas[i].stroke = stroke; o = pdf_new_dict(ctx, doc, 1); fz_try(ctx) { char text[32]; pdf_dict_put_drop(ctx, o, (stroke ? PDF_NAME_CA : PDF_NAME_ca), pdf_new_real(ctx, doc, alpha)); ref = pdf_add_object(ctx, doc, o); fz_snprintf(text, sizeof(text), "ExtGState/Alp%d", i); pdf_dict_putp(ctx, pdev->resources, text, ref); } fz_always(ctx) { pdf_drop_obj(ctx, o); pdf_drop_obj(ctx, ref); } fz_catch(ctx) { fz_rethrow(ctx); } pdev->num_alphas++; }
static void find_free_font_name(fz_context *ctx, pdf_obj *fdict, char *buf, int buf_size) { int i; /* Find a number X such that /FX doesn't occur as a key in fdict */ for (i = 0; 1; i++) { fz_snprintf(buf, buf_size, "F%d", i); if (!pdf_dict_gets(ctx, fdict, buf)) break; } }
void * fz_malloc_array_no_throw(fz_context *ctx, size_t count, size_t size) { if (count == 0 || size == 0) return 0; if (count > SIZE_MAX / size) { char buf[100]; fz_snprintf(buf, sizeof buf, "error: malloc of array (%zu x %zu bytes) failed (size_t overflow)", count, size); fprintf(stderr, "%s\n", buf); return NULL; } return do_scavenging_malloc(ctx, count * size); }
static void load_dir(const char *path) { char buf[PATH_MAX]; DIR *dir; struct dirent *dp; realpath(path, fc.curdir); if (!fz_is_directory(ctx, fc.curdir)) return; ui_input_init(&fc.input_dir, fc.curdir); fc.selected = -1; fc.count = 0; dir = opendir(fc.curdir); if (!dir) { fc.files[fc.count].is_dir = 1; fz_strlcpy(fc.files[fc.count].name, "..", FILENAME_MAX); ++fc.count; } else { while ((dp = readdir(dir)) && fc.count < nelem(fc.files)) { /* skip hidden files */ if (dp->d_name[0] == '.' && strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) continue; fz_snprintf(buf, sizeof buf, "%s/%s", fc.curdir, dp->d_name); fc.files[fc.count].is_dir = fz_is_directory(ctx, buf); if (fc.files[fc.count].is_dir || !fc.filter || fc.filter(buf)) { fz_strlcpy(fc.files[fc.count].name, dp->d_name, FILENAME_MAX); ++fc.count; } } closedir(dir); } qsort(fc.files, fc.count, sizeof fc.files[0], cmp_entry); }
static void bump_file_version(int dir) { char buf[PATH_MAX], *p, *n; char base[PATH_MAX], out[PATH_MAX]; int x; fz_strlcpy(buf, fc.input_file.text, sizeof buf); p = strrchr(buf, '.'); if (p) { n = p; while (n > buf && n[-1] >= '0' && n[-1] <= '9') --n; if (n != p) x = atoi(n) + dir; else x = dir; memcpy(base, buf, n-buf); base[n-buf] = 0; fz_snprintf(out, sizeof out, "%s%d%s", base, x, p); ui_input_init(&fc.input_file, out); } }
static void list_drives(void) { static struct list drive_list; DWORD drives; char dir[PATH_MAX], vis[PATH_MAX], buf[100]; const char *user, *home; char personal[MAX_PATH], desktop[MAX_PATH]; int i, n; drives = GetLogicalDrives(); n = 5; /* curdir + home + desktop + documents + downloads */ for (i=0; i < 26; ++i) if (drives & (1<<i)) ++n; ui_list_begin(&drive_list, n, 0, 10 * ui.lineheight + 4); user = getenv("USERNAME"); home = getenv("USERPROFILE"); if (user && home) { fz_snprintf(vis, sizeof vis, "%C %s", ICON_HOME, user); if (ui_list_item(&drive_list, "~", vis, 0)) load_dir(home); } if (SHGetFolderPathA(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, desktop) == S_OK) { fz_snprintf(vis, sizeof vis, "%C Desktop", ICON_PC); if (ui_list_item(&drive_list, "~/Desktop", vis, 0)) load_dir(desktop); } if (SHGetFolderPathA(NULL, CSIDL_PERSONAL, NULL, 0, personal) == S_OK) { fz_snprintf(vis, sizeof vis, "%C Documents", ICON_FOLDER); if (ui_list_item(&drive_list, "~/Documents", vis, 0)) load_dir(personal); } if (home) { fz_snprintf(vis, sizeof vis, "%C Downloads", ICON_FOLDER); fz_snprintf(dir, sizeof dir, "%s/Downloads", home); if (ui_list_item(&drive_list, "~/Downloads", vis, 0)) load_dir(dir); } for (i = 0; i < 26; ++i) { if (drives & (1<<i)) { fz_snprintf(dir, sizeof dir, "%c:\\", i+'A'); if (!GetVolumeInformationA(dir, buf, sizeof buf, NULL, NULL, NULL, NULL, 0)) buf[0] = 0; fz_snprintf(vis, sizeof vis, "%C %c: %s", ICON_DISK, i+'A', buf); if (ui_list_item(&drive_list, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"+i, vis, 0)) { load_dir(dir); } } } fz_snprintf(vis, sizeof vis, "%C .", ICON_PIN); if (ui_list_item(&drive_list, ".", vis, 0)) load_dir("."); ui_list_end(&drive_list); }
char * pdf_parse_link_dest(fz_context *ctx, pdf_document *doc, pdf_obj *dest) { pdf_obj *obj; char buf[256]; const char *ld; int page; int x, y; dest = resolve_dest(ctx, doc, dest); if (dest == NULL) { fz_warn(ctx, "undefined link destination"); return NULL; } if (pdf_is_name(ctx, dest)) { ld = pdf_to_name(ctx, dest); return fz_strdup(ctx, ld); } else if (pdf_is_string(ctx, dest)) { ld = pdf_to_str_buf(ctx, dest); return fz_strdup(ctx, ld); } obj = pdf_array_get(ctx, dest, 0); if (pdf_is_int(ctx, obj)) page = pdf_to_int(ctx, obj); else { fz_try(ctx) page = pdf_lookup_page_number(ctx, doc, obj); fz_catch(ctx) page = -1; } x = y = 0; obj = pdf_array_get(ctx, dest, 1); if (pdf_name_eq(ctx, obj, PDF_NAME_XYZ)) { x = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2)); y = pdf_to_int(ctx, pdf_array_get(ctx, dest, 3)); } else if (pdf_name_eq(ctx, obj, PDF_NAME_FitR)) { x = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2)); y = pdf_to_int(ctx, pdf_array_get(ctx, dest, 5)); } else if (pdf_name_eq(ctx, obj, PDF_NAME_FitH) || pdf_name_eq(ctx, obj, PDF_NAME_FitBH)) y = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2)); else if (pdf_name_eq(ctx, obj, PDF_NAME_FitV) || pdf_name_eq(ctx, obj, PDF_NAME_FitBV)) x = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2)); if (page >= 0) { if (x != 0 || y != 0) fz_snprintf(buf, sizeof buf, "#%d,%d,%d", page + 1, x, y); else fz_snprintf(buf, sizeof buf, "#%d", page + 1); return fz_strdup(ctx, buf); } return NULL; }
char * pdf_parse_file_spec(fz_context *ctx, pdf_document *doc, pdf_obj *file_spec, pdf_obj *dest) { pdf_obj *filename=NULL; char *path = NULL; char *uri = NULL; char buf[256]; size_t n; if (pdf_is_string(ctx, file_spec)) filename = file_spec; if (pdf_is_dict(ctx, file_spec)) { #if defined(_WIN32) || defined(_WIN64) filename = pdf_dict_get(ctx, file_spec, PDF_NAME_DOS); #else filename = pdf_dict_get(ctx, file_spec, PDF_NAME_Unix); #endif if (!filename) filename = pdf_dict_geta(ctx, file_spec, PDF_NAME_UF, PDF_NAME_F); } if (!pdf_is_string(ctx, filename)) { fz_warn(ctx, "cannot parse file specification"); return NULL; } path = pdf_to_utf8(ctx, filename); #if defined(_WIN32) || defined(_WIN64) if (strcmp(pdf_to_name(ctx, pdf_dict_gets(ctx, file_spec, "FS")), "URL") != 0) { /* move the file name into the expected place and use the expected path separator */ char *c; if (path[0] == '/' && (('A' <= path[1] && path[1] <= 'Z') || ('a' <= path[1] && path[1] <= 'z')) && path[2] == '/') { path[0] = path[1]; path[1] = ':'; } for (c = path; *c; c++) { if (*c == '/') *c = '\\'; } } #endif if (pdf_is_array(ctx, dest)) fz_snprintf(buf, sizeof buf, "#page=%d", pdf_to_int(ctx, pdf_array_get(ctx, dest, 0)) + 1); else if (pdf_is_name(ctx, dest)) fz_snprintf(buf, sizeof buf, "#%s", pdf_to_name(ctx, dest)); else if (pdf_is_string(ctx, dest)) fz_snprintf(buf, sizeof buf, "#%s", pdf_to_str_buf(ctx, dest)); else buf[0] = 0; n = 7 + strlen(path) + strlen(buf) + 1; uri = fz_malloc(ctx, n); fz_strlcpy(uri, "file://", n); fz_strlcat(uri, path, n); fz_strlcat(uri, buf, n); fz_free(ctx, path); return uri; }
int main(int argc, char *argv[]) { fz_context *ctx; FILE *script = NULL; int c; while ((c = fz_getopt(argc, argv, "o:p:v")) != -1) { switch(c) { case 'o': output = fz_optarg; break; case 'p': prefix = fz_optarg; break; case 'v': verbosity ^= 1; break; default: usage(); break; } } if (fz_optind == argc) usage(); ctx = fz_new_context(NULL, NULL, FZ_STORE_DEFAULT); if (!ctx) { fprintf(stderr, "cannot initialise context\n"); exit(1); } pdfapp_init(ctx, &gapp); gapp.scrw = 640; gapp.scrh = 480; gapp.colorspace = fz_device_rgb(ctx); fz_try(ctx) { while (fz_optind < argc) { scriptname = argv[fz_optind++]; script = fopen(scriptname, "rb"); if (script == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open script: %s", scriptname); do { char *line = my_getline(script); if (line == NULL) continue; if (verbosity) fprintf(stderr, "'%s'\n", line); if (match(&line, "%")) { /* Comment */ } else if (match(&line, "PASSWORD")) { strcpy(pd_password, line); } else if (match(&line, "OPEN")) { char path[LONGLINE]; if (file_open) pdfapp_close(&gapp); if (prefix) { sprintf(path, "%s%s", prefix, line); } else { strcpy(path, line); } pdfapp_open(&gapp, path, 0); file_open = 1; } else if (match(&line, "GOTO")) { pdfapp_gotopage(&gapp, atoi(line)-1); } else if (match(&line, "SCREENSHOT")) { char text[1024]; fz_snprintf(text, sizeof(text), output, ++shotcount); if (strstr(text, ".pgm") || strstr(text, ".ppm") || strstr(text, ".pnm")) fz_save_pixmap_as_pnm(ctx, gapp.image, text); else fz_save_pixmap_as_png(ctx, gapp.image, text); } else if (match(&line, "RESIZE")) { int w, h; sscanf(line, "%d %d", &w, &h); pdfapp_onresize(&gapp, w, h); } else if (match(&line, "CLICK")) { float x, y, b; int n; n = sscanf(line, "%f %f %f", &x, &y, &b); if (n < 1) x = 0.0f; if (n < 2) y = 0.0f; if (n < 3) b = 1; /* state = 1 = transition down */ pdfapp_onmouse(&gapp, (int)x, (int)y, b, 0, 1); /* state = -1 = transition up */ pdfapp_onmouse(&gapp, (int)x, (int)y, b, 0, -1); } else if (match(&line, "TEXT")) { unescape_string(td_textinput, line); } else { fprintf(stderr, "Ignoring line without script statement.\n"); } } while (!feof(script)); fclose(script); } } fz_catch(ctx) { fprintf(stderr, "error: cannot execute '%s'\n", scriptname); } if (file_open) pdfapp_close(&gapp); fz_drop_context(ctx); return 0; }
int ui_save_file(char filename[PATH_MAX], void (*extra_panel)(void)) { int i, rv = 0; ui_panel_begin(0, 0, 4, 4, 1); { ui_layout(L, Y, NW, 0, 0); ui_panel_begin(150, 0, 0, 0, 0); { ui_layout(T, X, NW, 2, 2); list_drives(); if (extra_panel) { ui_spacer(); extra_panel(); } ui_layout(B, X, NW, 2, 2); if (ui_button("Cancel") || (!ui.focus && ui.key == KEY_ESCAPE)) { filename[0] = 0; rv = 1; } } ui_panel_end(); ui_layout(T, X, NW, 2, 2); if (ui_input(&fc.input_dir, 0, 1) == UI_INPUT_ACCEPT) load_dir(fc.input_dir.text); ui_layout(T, X, NW, 2, 2); ui_panel_begin(0, ui.gridsize, 0, 0, 0); { ui_layout(R, NONE, CENTER, 0, 0); if (ui_button("Save")) { fz_snprintf(filename, PATH_MAX, "%s/%s", fc.curdir, fc.input_file.text); rv = 1; } ui_spacer(); if (ui_button("\xe2\x9e\x95")) /* U+2795 HEAVY PLUS */ bump_file_version(1); if (ui_button("\xe2\x9e\x96")) /* U+2796 HEAVY MINUS */ bump_file_version(-1); ui_spacer(); ui_layout(ALL, X, CENTER, 0, 0); ui_input(&fc.input_file, 0, 1); } ui_panel_end(); ui_layout(ALL, BOTH, NW, 2, 2); ui_list_begin(&fc.list_dir, fc.count, 0, 0); for (i = 0; i < fc.count; ++i) { const char *name = fc.files[i].name; char buf[PATH_MAX]; if (fc.files[i].is_dir) fz_snprintf(buf, sizeof buf, "\xf0\x9f\x93\x81 %s", name); else fz_snprintf(buf, sizeof buf, "\xf0\x9f\x93\x84 %s", name); if (ui_list_item(&fc.list_dir, &fc.files[i], buf, i==fc.selected)) { fc.selected = i; if (fc.files[i].is_dir) { fz_snprintf(buf, sizeof buf, "%s/%s", fc.curdir, name); load_dir(buf); ui.active = NULL; } else { ui_input_init(&fc.input_file, name); } } } ui_list_end(&fc.list_dir); } ui_panel_end(); return rv; }
int ui_open_file(char filename[PATH_MAX]) { static int last_click_time = 0; static int last_click_sel = -1; int i, rv = 0; ui_panel_begin(0, 0, 4, 4, 1); { ui_layout(L, Y, NW, 0, 0); ui_panel_begin(150, 0, 0, 0, 0); { ui_layout(T, X, NW, 2, 2); list_drives(); ui_layout(B, X, NW, 2, 2); if (ui_button("Cancel") || (!ui.focus && ui.key == KEY_ESCAPE)) { filename[0] = 0; rv = 1; } } ui_panel_end(); ui_layout(T, X, NW, 2, 2); ui_panel_begin(0, ui.gridsize, 0, 0, 0); { if (fc.selected >= 0) { ui_layout(R, NONE, CENTER, 0, 0); if (ui_button("Open") || (!ui.focus && ui.key == KEY_ENTER)) { fz_snprintf(filename, PATH_MAX, "%s/%s", fc.curdir, fc.files[fc.selected].name); rv = 1; } ui_spacer(); } ui_layout(ALL, X, CENTER, 0, 0); if (ui_input(&fc.input_dir, 0, 1) == UI_INPUT_ACCEPT) load_dir(fc.input_dir.text); } ui_panel_end(); ui_layout(ALL, BOTH, NW, 2, 2); ui_list_begin(&fc.list_dir, fc.count, 0, 0); for (i = 0; i < fc.count; ++i) { const char *name = fc.files[i].name; char buf[PATH_MAX]; if (fc.files[i].is_dir) fz_snprintf(buf, sizeof buf, "%C %s", ICON_FOLDER, name); else fz_snprintf(buf, sizeof buf, "%C %s", ICON_DOCUMENT, name); if (ui_list_item(&fc.list_dir, &fc.files[i], buf, i==fc.selected)) { fc.selected = i; if (fc.files[i].is_dir) { fz_snprintf(buf, sizeof buf, "%s/%s", fc.curdir, name); load_dir(buf); ui.active = NULL; last_click_sel = -1; } else { int click_time = glutGet(GLUT_ELAPSED_TIME); if (i == last_click_sel && click_time < last_click_time + 250) { fz_snprintf(filename, PATH_MAX, "%s/%s", fc.curdir, name); rv = 1; } last_click_time = click_time; last_click_sel = i; } } } ui_list_end(&fc.list_dir); } ui_panel_end(); return rv; }