diff options
Diffstat (limited to 'src')
46 files changed, 1757 insertions, 2491 deletions
diff --git a/src/Makefile b/src/Makefile index 10e33eb..2968671 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,8 +4,6 @@ TARGETS = \ events.c \ feh_png.c \ filelist.c \ - getopt.c \ - getopt1.c \ gib_hash.c \ gib_imlib.c \ gib_list.c \ diff --git a/src/debug.h b/src/debug.h index 569637e..0ff1447 100644 --- a/src/debug.h +++ b/src/debug.h @@ -1,7 +1,7 @@ /* debug.h Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to diff --git a/src/events.c b/src/events.c index c44ebf4..de9e7b3 100644 --- a/src/events.c +++ b/src/events.c @@ -1,7 +1,7 @@ /* events.c Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -85,6 +85,15 @@ static void feh_set_parse_bb_partial(fehkey *button, char *binding) button->button = atoi(cur); button->state = mod; + + if (button->button == 0) { + /* + * Mod3 is unused on today's keyboards. If Mod3 is unset and button==0, + * we are dealing with an uninitialized or unset binding. If Mod3 is set + * and button==0, it refers to mouse movement. + */ + button->state |= Mod3Mask; + } } /* @@ -255,7 +264,7 @@ static void feh_event_handle_ButtonPress(XEvent * ev) - winwid->im_y) / winwid->old_zoom; /* copied from zoom_in, keyevents.c */ - winwid->zoom = winwid->zoom * 1.25; + winwid->zoom = winwid->zoom * opt.zoom_rate; if (winwid->zoom > ZOOM_MAX) winwid->zoom = ZOOM_MAX; @@ -283,7 +292,7 @@ static void feh_event_handle_ButtonPress(XEvent * ev) - winwid->im_y) / winwid->old_zoom; /* copied from zoom_out, keyevents.c */ - winwid->zoom = winwid->zoom * 0.80; + winwid->zoom = winwid->zoom / opt.zoom_rate; if (winwid->zoom < ZOOM_MIN) winwid->zoom = ZOOM_MIN; @@ -672,14 +681,18 @@ static void feh_event_handle_MotionNotify(XEvent * ev) } else { while (XCheckTypedWindowEvent(disp, ev->xmotion.window, MotionNotify, ev)); winwid = winwidget_get_from_window(ev->xmotion.window); - if ((winwid != NULL) && (winwid->type == WIN_TYPE_THUMBNAIL)) { - feh_thumbnail *thumbnail; - int x, y; - - x = (ev->xbutton.x - winwid->im_x) / winwid->zoom; - y = (ev->xbutton.y - winwid->im_y) / winwid->zoom; - thumbnail = feh_thumbnail_get_thumbnail_from_coords(x, y); - feh_thumbnail_select(winwid, thumbnail); + if (winwid != NULL) { + if (winwid->type == WIN_TYPE_THUMBNAIL) { + feh_thumbnail *thumbnail; + int x, y; + + x = (ev->xbutton.x - winwid->im_x) / winwid->zoom; + y = (ev->xbutton.y - winwid->im_y) / winwid->zoom; + thumbnail = feh_thumbnail_get_thumbnail_from_coords(x, y); + feh_thumbnail_select(winwid, thumbnail); + } else { + feh_event_handle_generic(winwid, ev->xmotion.state | Mod3Mask, NoSymbol, 0); + } } } return; @@ -1,6 +1,7 @@ /* exif.c Copyright (C) 2012 Dennis Real. +Copyright (C) 2021 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -42,199 +43,302 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* remove all spaces on the right end of a string */ void exif_trim_spaces(char *str) { - char *end; - - for (end = str; *str!='\0'; str++) - { - if (*str != ' ') - { - end = str + 1; - } - } - *end = '\0'; + char *end; + + for (end = str; *str != '\0'; str++) { + if (*str != ' ') { + end = str + 1; + } + } + *end = '\0'; } /* show given exif tag content with tag name */ -void exif_get_tag(ExifData *d, ExifIfd ifd, ExifTag tag, char* buffer, unsigned int maxsize) +void exif_get_tag(ExifData * d, ExifIfd ifd, ExifTag tag, char *buffer, + unsigned int maxsize) { - char s[EXIF_MAX_DATA]; - ExifEntry *entry = NULL; - - if ( (d != NULL) && (buffer != NULL) && (maxsize > 0) ) - { - entry = exif_content_get_entry(d->ifd[ifd], tag); - if (entry != NULL) - { - /* Get the contents of the tag in human-readable form */ - exif_entry_get_value(entry, s, EXIF_MAX_DATA); - - /* Don't bother printing it if it's entirely blank */ - exif_trim_spaces(s); - if (*s != '\0') - { - D(("%s: %s\n", exif_tag_get_name_in_ifd(tag,ifd), s)); - snprintf(buffer, (size_t)maxsize, "%s: %s\n", exif_tag_get_name_in_ifd(tag,ifd), s); - } - } - } + char s[EXIF_MAX_DATA]; + ExifEntry *entry = NULL; + + if ((d != NULL) && (buffer != NULL) && (maxsize > 0)) { + entry = exif_content_get_entry(d->ifd[ifd], tag); + if (entry != NULL) { + /* Get the contents of the tag in human-readable form */ + exif_entry_get_value(entry, s, EXIF_MAX_DATA); + + /* Don't bother printing it if it's entirely blank */ + exif_trim_spaces(s); + if (*s != '\0') { + D(("%s: %s\n", + exif_tag_get_name_in_ifd(tag, ifd), s)); + snprintf(buffer, (size_t) maxsize, + "%s: %s\n", + exif_tag_get_name_in_ifd(tag, + ifd), s); + } + } + } } /* show given exif tag content without tag name */ -void exif_get_tag_content(ExifData *d, ExifIfd ifd, ExifTag tag, char* buffer, unsigned int maxsize) +void exif_get_tag_content(ExifData * d, ExifIfd ifd, ExifTag tag, + char *buffer, unsigned int maxsize) { - char s[EXIF_MAX_DATA]; - ExifEntry *entry = NULL; - - if ( (d != NULL) && (buffer != NULL) && (maxsize > 0) ) - { - entry = exif_content_get_entry(d->ifd[ifd], tag); - if (entry != NULL) - { - /* Get the contents of the tag in human-readable form */ - exif_entry_get_value(entry, s, EXIF_MAX_DATA); - - /* Don't bother printing it if it's entirely blank */ - exif_trim_spaces(s); - if (*s != '\0') - { - D(("%s - %s\n", exif_tag_get_name_in_ifd(tag,ifd), s)); - snprintf(buffer, (size_t)maxsize, "%s", s); - } - } - } + char s[EXIF_MAX_DATA]; + ExifEntry *entry = NULL; + + if ((d != NULL) && (buffer != NULL) && (maxsize > 0)) { + entry = exif_content_get_entry(d->ifd[ifd], tag); + if (entry != NULL) { + /* Get the contents of the tag in human-readable form */ + exif_entry_get_value(entry, s, EXIF_MAX_DATA); + + /* Don't bother printing it if it's entirely blank */ + exif_trim_spaces(s); + if (*s != '\0') { + D(("%s - %s\n", + exif_tag_get_name_in_ifd(tag, ifd), s)); + snprintf(buffer, (size_t) maxsize, "%s", + s); + } + } + } } /* Show the given MakerNote tag if it exists */ -void exif_get_mnote_tag(ExifData *d, unsigned int tag, char* buffer, unsigned int maxsize) +void exif_get_mnote_tag(ExifData * d, unsigned int tag, char *buffer, + unsigned int maxsize) { - ExifMnoteData *mn = NULL; - int i, num; - char buf[1024]; - - if ( (d!=NULL) && (buffer!=NULL) && (maxsize > 0) ) - { - mn = exif_data_get_mnote_data(d); - } - else - { - return; - } - - if ( mn != NULL ) - { - num = exif_mnote_data_count(mn); - - /* Loop through all MakerNote tags, searching for the desired one */ - for (i=0; i < num; ++i) - { - D(("%d/%d %d 0x%2x %s; %s\n", i, num, exif_mnote_data_get_id(mn, i), - exif_mnote_data_get_id(mn, i), - exif_mnote_data_get_name(mn,i), - exif_mnote_data_get_title(mn, i) )); - - if (exif_mnote_data_get_id(mn, i) == tag) - { - if (exif_mnote_data_get_value(mn, i, buf, sizeof(buf))) - { - /* Don't bother printing it if it's entirely blank */ - exif_trim_spaces(buf); - if (*buf != '\0') - { - D(("%s\n", buf)); - snprintf(buffer, (size_t)maxsize, "%s: %s\n", exif_mnote_data_get_title(mn, i), buf); - } - } - } - } - } + ExifMnoteData *mn = NULL; + int i, num; + char buf[1024]; + + if ((d != NULL) && (buffer != NULL) && (maxsize > 0)) { + mn = exif_data_get_mnote_data(d); + } else { + return; + } + + if (mn != NULL) { + num = exif_mnote_data_count(mn); + + /* Loop through all MakerNote tags, searching for the desired one */ + for (i = 0; i < num; ++i) { + D(("%d/%d %d 0x%2x %s; %s\n", i, num, + exif_mnote_data_get_id(mn, i), + exif_mnote_data_get_id(mn, i), + exif_mnote_data_get_name(mn, i), + exif_mnote_data_get_title(mn, i))); + + if (exif_mnote_data_get_id(mn, i) == tag) { + if (exif_mnote_data_get_value + (mn, i, buf, sizeof(buf))) { + /* Don't bother printing it if it's entirely blank */ + exif_trim_spaces(buf); + if (*buf != '\0') { + D(("%s\n", buf)); + snprintf(buffer, + (size_t) maxsize, + "%s: %s\n", + exif_mnote_data_get_title + (mn, i), buf); + } + } + } + } + } } +void exif_get_make_model_lens(ExifData * ed, char *buffer, unsigned int maxsize) +{ + char make[EXIF_STD_BUF_LEN]; + char model[EXIF_STD_BUF_LEN]; + char lens[EXIF_STD_BUF_LEN]; + unsigned int offset = 0; + + make[0] = model[0] = lens[0] = '\0'; + + exif_get_tag_content(ed, EXIF_IFD_0, EXIF_TAG_MAKE, make, sizeof(make)); + exif_get_tag_content(ed, EXIF_IFD_0, EXIF_TAG_MODEL, model, sizeof(model)); + exif_get_tag_content(ed, EXIF_IFD_EXIF, 0xa434, lens, sizeof(lens)); + + if (make[0] && strncmp(make, model, strlen(make)) != 0) { + offset += snprintf(buffer, maxsize, "%s ", make); + } + if (model[0]) { + offset += snprintf(buffer + offset, maxsize - offset, "%s", model); + } + if (lens[0]) { + offset += snprintf(buffer + offset, maxsize - offset, " + %s", lens); + } + snprintf(buffer + offset, maxsize - offset, "\n"); +} + +void exif_get_exposure(ExifData * ed, char *buffer, unsigned int maxsize) +{ + char fnumber[EXIF_STD_BUF_LEN]; + char exposure[EXIF_STD_BUF_LEN]; + char iso[EXIF_STD_BUF_LEN]; + char focus[EXIF_STD_BUF_LEN]; + char focus35[EXIF_STD_BUF_LEN]; + unsigned int offset = 0; + + fnumber[0] = exposure[0] = iso[0] = '\0'; + focus[0] = focus35[0] = '\0'; + + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_FNUMBER, fnumber, sizeof(fnumber)); + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME, exposure, sizeof(exposure)); + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, iso, sizeof(iso)); + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, focus, sizeof(focus)); + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM, focus35, sizeof(focus35)); + + if (fnumber[0] || exposure[0]) { + offset += snprintf(buffer, maxsize, "%s %s ", fnumber, exposure); + } + if (iso[0]) { + offset += snprintf(buffer + offset, maxsize - offset, "ISO%s ", iso); + } + if (focus[0] && focus35[0]) { + snprintf(buffer + offset, maxsize - offset, "%s (%s mm)\n", focus, focus35); + } else if (focus[0]) { + snprintf(buffer + offset, maxsize - offset, "%s\n", focus); + } +} + +void exif_get_flash(ExifData * ed, char *buffer, unsigned int maxsize) +{ + char flash[EXIF_STD_BUF_LEN]; + + flash[0] = '\0'; + + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_FLASH, flash, sizeof(flash)); + + if (flash[0]) { + snprintf(buffer, maxsize, "%s\n", flash); + } +} + +void exif_get_mode(ExifData * ed, char *buffer, unsigned int maxsize) +{ + char mode[EXIF_STD_BUF_LEN]; + char program[EXIF_STD_BUF_LEN]; + + mode[0] = program[0] = '\0'; + + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_MODE, mode, sizeof(mode)); + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_PROGRAM, program, sizeof(program)); + + if (mode[0] || program[0]) { + snprintf(buffer, maxsize, "%s (%s)\n", mode, program); + } +} + +void exif_get_datetime(ExifData * ed, char *buffer, unsigned int maxsize) +{ + char datetime[EXIF_STD_BUF_LEN]; + + datetime[0] = '\0'; + + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, datetime, sizeof(datetime)); + + if (datetime[0]) { + snprintf(buffer, maxsize, "%s\n", datetime); + } +} + +void exif_get_description(ExifData * ed, char *buffer, unsigned int maxsize) +{ + char description[EXIF_STD_BUF_LEN]; + + description[0] = '\0'; + + exif_get_tag_content(ed, EXIF_IFD_0, EXIF_TAG_IMAGE_DESCRIPTION, description, sizeof(description)); + + if (description[0]) { + snprintf(buffer, maxsize, "\"%s\"\n", description); + } +} /* get gps coordinates if available */ void exif_get_gps_coords(ExifData * ed, char *buffer, unsigned int maxsize) { - char buf[EXIF_STD_BUF_LEN]; - - buf[0] = '\0'; - exif_get_tag_content(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE_REF, buf, sizeof(buf)); - if ( buf[0] != '\0' ) - { - snprintf(buffer + strlen(buffer), maxsize - strlen(buffer), "GPS: %s ", buf); - } - else - { - return; - } - - buf[0] = '\0'; - exif_get_tag_content(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE, buf, sizeof(buf)); - if ( buf[0] != '\0' ) - { - snprintf(buffer + strlen(buffer), maxsize - strlen(buffer), "%s ", buf); - } - else - { - return; - } - - buf[0] = '\0'; - exif_get_tag_content(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE_REF, buf, sizeof(buf)); - if ( buf[0] != '\0' ) - { - snprintf(buffer + strlen(buffer), maxsize - strlen(buffer), ", %s ", buf); - } - else - { - return; - } - - buf[0] = '\0'; - exif_get_tag_content(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE, buf, sizeof(buf)); - if ( buf[0] != '\0' ) - { - snprintf(buffer + strlen(buffer), maxsize - strlen(buffer), "%s ", buf); - } - else - { - return; - } - - buf[0] = '\0'; - exif_get_tag_content(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_MAP_DATUM, buf, sizeof(buf)); - if ( buf[0] != '\0' ) - { - snprintf(buffer + strlen(buffer), maxsize - strlen(buffer), "(%s)\n", buf); - } - else - { - return; - } + char buf[EXIF_STD_BUF_LEN]; + + buf[0] = '\0'; + exif_get_tag_content(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE_REF, + buf, sizeof(buf)); + if (buf[0] != '\0') { + snprintf(buffer + strlen(buffer), maxsize - strlen(buffer), + "GPS: %s ", buf); + } else { + return; + } + + buf[0] = '\0'; + exif_get_tag_content(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE, buf, + sizeof(buf)); + if (buf[0] != '\0') { + snprintf(buffer + strlen(buffer), maxsize - strlen(buffer), + "%s ", buf); + } else { + return; + } + + buf[0] = '\0'; + exif_get_tag_content(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE_REF, + buf, sizeof(buf)); + if (buf[0] != '\0') { + snprintf(buffer + strlen(buffer), maxsize - strlen(buffer), + ", %s ", buf); + } else { + return; + } + + buf[0] = '\0'; + exif_get_tag_content(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE, buf, + sizeof(buf)); + if (buf[0] != '\0') { + snprintf(buffer + strlen(buffer), maxsize - strlen(buffer), + "%s ", buf); + } else { + return; + } + + buf[0] = '\0'; + exif_get_tag_content(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_MAP_DATUM, buf, + sizeof(buf)); + if (buf[0] != '\0') { + snprintf(buffer + strlen(buffer), maxsize - strlen(buffer), + "(%s)\n", buf); + } else { + return; + } } /* return data structure with exif data if available */ -ExifData * exif_get_data(char *path) +ExifData *exif_get_data(char *path) { - ExifData *ed = NULL; + ExifData *ed = NULL; - /* Load an ExifData object from an EXIF file */ - ed = exif_data_new_from_file(path); - if (ed == NULL) - { - D(("File not readable or no Exif data present in %s\n", path)); - } + /* Load an ExifData object from an EXIF file */ + ed = exif_data_new_from_file(path); + if (ed == NULL) { + D(("File not readable or no Exif data present in %s\n", + path)); + } - return(ed); + return (ed); } @@ -243,76 +347,93 @@ ExifData * exif_get_data(char *path) /* get all exif data in readable form */ void exif_get_info(ExifData * ed, char *buffer, unsigned int maxsize) { - ExifEntry *entry = NULL; - char buf[EXIF_STD_BUF_LEN]; - unsigned short int i = 0; - - if ( (buffer == NULL) || (maxsize == 0) ) - { - return; - } - else if (ed == NULL) - { - snprintf(buffer, (size_t)maxsize, "%s\n", "No Exif data in file."); - return; - } - else - { - /* show normal exif tags. list must be defined in exif_cfg.h */ - while ( (i < USHRT_MAX) && (Exif_tag_list[i].ifd != EXIF_IFD_COUNT) ) - { - exif_get_tag(ed, Exif_tag_list[i].ifd, Exif_tag_list[i].tag, buffer + strlen(buffer), maxsize - strlen(buffer)); - i++; - } - - /* show vendor specific makernote tags */ - entry = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_MAKE); - if (entry != NULL) - { - - if (exif_entry_get_value(entry, buf, sizeof(buf))) - { - exif_trim_spaces(buf); - - if ( (strcmp(buf, "NIKON CORPORATION") == 0) - || (strcmp(buf, "Nikon") == 0) - || (strcmp(buf, "NIKON") == 0) - ) - { - /* show nikon makernote exif tags. list must be defined in exif_cfg.h */ - i=0; - while ( (i < USHRT_MAX) && (Exif_makernote_nikon_tag_list[i] != EXIF_NIKON_MAKERNOTE_END) ) - { - exn_get_mnote_nikon_tags(ed, Exif_makernote_nikon_tag_list[i], - buffer + strlen(buffer), maxsize - strlen(buffer)); - i++; - } - - } - else if ( (strcmp(buf, "Canon") == 0) ) - { - /* show canon makernote exif tags. list must be defined in exif_cfg.h */ - i=0; - while ( (i < USHRT_MAX) && (Exif_makernote_canon_tag_list[i] != EXIF_CANON_MAKERNOTE_END) ) - { - exc_get_mnote_canon_tags(ed, Exif_makernote_canon_tag_list[i], - buffer + strlen(buffer), maxsize - strlen(buffer)); - i++; - } - - } - else - { - } - } - - } - - /* show gps coordinates */ - exif_get_gps_coords(ed, buffer + strlen(buffer), maxsize - strlen(buffer)); - - } - + ExifEntry *entry = NULL; + char buf[EXIF_STD_BUF_LEN]; + unsigned short int i = 0; + + if ((buffer == NULL) || (maxsize == 0)) { + return; + } else if (ed == NULL) { + snprintf(buffer, (size_t) maxsize, "%s\n", + "No Exif data in file."); + return; + } + + exif_get_description(ed, buffer + strlen(buffer), + maxsize - strlen(buffer)); + exif_get_make_model_lens(ed, buffer + strlen(buffer), + maxsize - strlen(buffer)); + exif_get_exposure(ed, buffer + strlen(buffer), + maxsize - strlen(buffer)); + exif_get_mode(ed, buffer + strlen(buffer), + maxsize - strlen(buffer)); + exif_get_flash(ed, buffer + strlen(buffer), + maxsize - strlen(buffer)); + exif_get_datetime(ed, buffer + strlen(buffer), + maxsize - strlen(buffer)); + + /* show vendor specific makernote tags */ + entry = + exif_content_get_entry(ed->ifd[EXIF_IFD_0], + EXIF_TAG_MAKE); + if (entry != NULL) { + + if (exif_entry_get_value(entry, buf, sizeof(buf))) { + exif_trim_spaces(buf); + + if ((strcmp(buf, "NIKON CORPORATION") == 0) + || (strcmp(buf, "Nikon") == 0) + || (strcmp(buf, "NIKON") == 0) + ) { + /* show nikon makernote exif tags. list must be defined in exif_cfg.h */ + i = 0; + while ((i < USHRT_MAX) + && + (Exif_makernote_nikon_tag_list + [i] != + EXIF_NIKON_MAKERNOTE_END)) + { + exn_get_mnote_nikon_tags + (ed, + Exif_makernote_nikon_tag_list + [i], + buffer + + strlen(buffer), + maxsize - + strlen(buffer)); + i++; + } + + } else if ((strcmp(buf, "Canon") == 0)) { + /* show canon makernote exif tags. list must be defined in exif_cfg.h */ + i = 0; + while ((i < USHRT_MAX) + && + (Exif_makernote_canon_tag_list + [i] != + EXIF_CANON_MAKERNOTE_END)) + { + exc_get_mnote_canon_tags + (ed, + Exif_makernote_canon_tag_list + [i], + buffer + + strlen(buffer), + maxsize - + strlen(buffer)); + i++; + } + + } else { + } + } + + } + + /* show gps coordinates */ + exif_get_gps_coords(ed, buffer + strlen(buffer), + maxsize - strlen(buffer)); + } #endif @@ -32,11 +32,16 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define EXIF_STD_BUF_LEN 128 extern void exif_trim_spaces(char *str); -extern void exif_get_tag(ExifData *d, ExifIfd ifd, ExifTag tag, char* buffer, unsigned int maxsize); -extern void exif_get_tag_content(ExifData *d, ExifIfd ifd, ExifTag tag, char* buffer, unsigned int maxsize); -extern void exif_get_mnote_tag(ExifData *d, unsigned int tag, char* buffer, unsigned int maxsize); -extern void exif_get_gps_coords(ExifData * ed, char *buffer, unsigned int maxsize); -extern ExifData * exif_get_data(char *path); -extern void exif_get_info(ExifData * ed, char *buffer, unsigned int maxsize); +extern void exif_get_tag(ExifData * d, ExifIfd ifd, ExifTag tag, + char *buffer, unsigned int maxsize); +extern void exif_get_tag_content(ExifData * d, ExifIfd ifd, ExifTag tag, + char *buffer, unsigned int maxsize); +extern void exif_get_mnote_tag(ExifData * d, unsigned int tag, + char *buffer, unsigned int maxsize); +extern void exif_get_gps_coords(ExifData * ed, char *buffer, + unsigned int maxsize); +extern ExifData *exif_get_data(char *path); +extern void exif_get_info(ExifData * ed, char *buffer, + unsigned int maxsize); #endif diff --git a/src/exif_canon.c b/src/exif_canon.c index 8801899..ee72164 100644 --- a/src/exif_canon.c +++ b/src/exif_canon.c @@ -36,26 +36,26 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* get interesting canon maker note tags in readable form */ -void exc_get_mnote_canon_tags(ExifData *ed, unsigned int tag, char * buffer, unsigned int maxsize) +void exc_get_mnote_canon_tags(ExifData * ed, unsigned int tag, + char *buffer, unsigned int maxsize) { - /* char buf[EXIF_STD_BUF_LEN]; + /* char buf[EXIF_STD_BUF_LEN]; - buf[0] = '\0'; - exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_FLASH, buf, sizeof(buf)); - exif_trim_spaces(buf); */ + buf[0] = '\0'; + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_FLASH, buf, sizeof(buf)); + exif_trim_spaces(buf); */ - switch(tag) - { - default: - { - /* normal makernote tags without special treatment */ - exif_get_mnote_tag(ed, tag, buffer, maxsize); - } - break; - } + switch (tag) { + default: + { + /* normal makernote tags without special treatment */ + exif_get_mnote_tag(ed, tag, buffer, maxsize); + } + break; + } - return; + return; } #endif diff --git a/src/exif_canon.h b/src/exif_canon.h index d8682c3..58ecc0e 100644 --- a/src/exif_canon.h +++ b/src/exif_canon.h @@ -28,6 +28,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <libexif/exif-data.h> -extern void exc_get_mnote_canon_tags(ExifData *ed, unsigned int tag, char * buffer, unsigned int maxsize); +extern void exc_get_mnote_canon_tags(ExifData * ed, unsigned int tag, + char *buffer, unsigned int maxsize); #endif diff --git a/src/exif_cfg.h b/src/exif_cfg.h index a961147..0a13fa3 100644 --- a/src/exif_cfg.h +++ b/src/exif_cfg.h @@ -28,78 +28,43 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <libexif/exif-data.h> -typedef struct -{ - ExifIfd ifd; /* section */ - ExifTag tag; /* tag */ -} t_EXIF_INFO; - - -/* show these standard tags. section must be given first, than the tag itself */ -/* definition: http://libexif.sourceforge.net/api/exif-tag_8h.html */ -const t_EXIF_INFO Exif_tag_list [] = -{ - {EXIF_IFD_0, EXIF_TAG_MAKE}, - {EXIF_IFD_0, EXIF_TAG_MODEL}, - {EXIF_IFD_0, EXIF_TAG_IMAGE_DESCRIPTION}, - {EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL}, - {EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME}, - {EXIF_IFD_EXIF, EXIF_TAG_SHUTTER_SPEED_VALUE}, - {EXIF_IFD_EXIF, EXIF_TAG_FNUMBER}, - {EXIF_IFD_EXIF, EXIF_TAG_APERTURE_VALUE}, - {EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_BIAS_VALUE}, - {EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS}, - {EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH}, - {EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM}, - {EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_MODE}, - {EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_PROGRAM}, - {EXIF_IFD_EXIF, EXIF_TAG_SCENE_CAPTURE_TYPE}, - {EXIF_IFD_EXIF, EXIF_TAG_FLASH}, - - {EXIF_IFD_COUNT, 0} /* end marker */ -}; +/* Nikon */ +#define EXIF_NIKON_MAKERNOTE_END 0 /* end marker: if 0 used as a tag we must find something else */ +/* show these nikon makernote tags */ +const unsigned int Exif_makernote_nikon_tag_list[] = { -/* Nikon */ + 6, + 8, /* Flash Setting */ + 9, /* Flash Mode */ + 135, /* Flash used */ + 18, /* Flash Exposure Comp */ + 168, /* Flash info: control mode */ -#define EXIF_NIKON_MAKERNOTE_END 0 /* end marker: if 0 used as a tag we must find something else */ + 2, /* ISO. Has some more info than EXIF_TAG_ISO_SPEED_RATINGS but also fails on Lo.1 */ + 5, /* White Balance */ + 132, /* Lens */ + 171, /* Digital Vari-Program */ + 34, /* Active D-Lighting */ -/* show these nikon makernote tags */ -const unsigned int Exif_makernote_nikon_tag_list [] = -{ - - 6, - 8, /* Flash Setting */ - 9, /* Flash Mode */ - 135, /* Flash used */ - 18, /* Flash Exposure Comp */ - 168, /* Flash info: control mode */ - - 2, /* ISO. Has some more info than EXIF_TAG_ISO_SPEED_RATINGS but also fails on Lo.1 */ - 5, /* White Balance */ - 132, /* Lens */ - 171, /* Digital Vari-Program */ - 34, /* Active D-Lighting */ - - 35, /* PictureControlData */ - 183, /* AFInfo2 */ - - EXIF_NIKON_MAKERNOTE_END /* end marker */ + 35, /* PictureControlData */ + 183, /* AFInfo2 */ + + EXIF_NIKON_MAKERNOTE_END /* end marker */ }; /* Canon */ -#define EXIF_CANON_MAKERNOTE_END 0xFFFF /* end marker: if this is used as a tag we must find something else */ +#define EXIF_CANON_MAKERNOTE_END 0xFFFF /* end marker: if this is used as a tag we must find something else */ /* show these canon makernote tags */ -const unsigned int Exif_makernote_canon_tag_list [] = -{ - 8, /* Image Number */ - 9, /* Owner Name */ - - EXIF_CANON_MAKERNOTE_END /* end marker */ +const unsigned int Exif_makernote_canon_tag_list[] = { + 8, /* Image Number */ + 9, /* Owner Name */ + + EXIF_CANON_MAKERNOTE_END /* end marker */ }; diff --git a/src/exif_nikon.c b/src/exif_nikon.c index c058d8c..a81f290 100644 --- a/src/exif_nikon.c +++ b/src/exif_nikon.c @@ -37,12 +37,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* Flash control mode */ /* http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#FlashControlMode */ #define EXN_FLASH_CONTROL_MODES_MAX 9 -char *EXN_NikonFlashControlModeValues[EXN_FLASH_CONTROL_MODES_MAX] = {"Off", - "iTTL-BL", "iTTL", "Auto Aperture", - "Automatic", "GN (distance priority)", - "Manual", "Repeating Flash", - "N/A" /* "N/A" is not a nikon setting */ - }; +char *EXN_NikonFlashControlModeValues[EXN_FLASH_CONTROL_MODES_MAX] = + { "Off", + "iTTL-BL", "iTTL", "Auto Aperture", + "Automatic", "GN (distance priority)", + "Manual", "Repeating Flash", + "N/A" /* "N/A" is not a nikon setting */ +}; #define EXN_FLASH_CONTROL_MODE_MASK 0x7F @@ -50,280 +51,302 @@ char *EXN_NikonFlashControlModeValues[EXN_FLASH_CONTROL_MODES_MAX] = {"Off", /* AFInfo2 */ /* http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#AFInfo2 */ #define EXN_CONTRAST_DETECT_AF_MAX 2 -char *EXN_NikonContrastDetectAF[EXN_CONTRAST_DETECT_AF_MAX] = {"Off", "On"}; +char *EXN_NikonContrastDetectAF[EXN_CONTRAST_DETECT_AF_MAX] = + { "Off", "On" }; /* AFArea Mode for ContrastDetectAF Off */ #define EXN_AF_AREA_MODE_P_MAX 13 char *EXN_NikonAFAreaModePhase[EXN_AF_AREA_MODE_P_MAX] = { - "Single Area", "Dynamic Area", "Dynamic Area (closest subject)", - "Group Dynamic ", "Dynamic Area (9 points) ", "Dynamic Area (21 points)", - "Dynamic Area (51 points) ", "Dynamic Area (51 points, 3D-tracking)", - "Auto-area", "Dynamic Area (3D-tracking)", "Single Area (wide)", - "Dynamic Area (wide)", "Dynamic Area (wide, 3D-tracking)"}; + "Single Area", "Dynamic Area", "Dynamic Area (closest subject)", + "Group Dynamic ", "Dynamic Area (9 points) ", + "Dynamic Area (21 points)", + "Dynamic Area (51 points) ", + "Dynamic Area (51 points, 3D-tracking)", + "Auto-area", "Dynamic Area (3D-tracking)", "Single Area (wide)", + "Dynamic Area (wide)", "Dynamic Area (wide, 3D-tracking)" +}; /* AFArea Mode for ContrastDetectAF On */ #define EXN_AF_AREA_MODE_C_MAX 5 char *EXN_NikonAFAreaModeContr[EXN_AF_AREA_MODE_C_MAX] = { - "Contrast-detect", - "Contrast-detect (normal area)", - "Contrast-detect (wide area)", - "Contrast-detect (face priority)", - "Contrast-detect (subject tracking)"}; + "Contrast-detect", + "Contrast-detect (normal area)", + "Contrast-detect (wide area)", + "Contrast-detect (face priority)", + "Contrast-detect (subject tracking)" +}; #define EXN_PHASE_DETECT_AF_MAX 4 -char *EXN_NikonPhaseDetectAF[EXN_PHASE_DETECT_AF_MAX] = {"Off", "On (51-point)", - "On (11-point)", "On (39-point)"}; +char *EXN_NikonPhaseDetectAF[EXN_PHASE_DETECT_AF_MAX] = + { "Off", "On (51-point)", + "On (11-point)", "On (39-point)" +}; /* PrimaryAFPoint and AFPointsUsed only valid with PhaseDetectAF == On */ #define EXN_PRIM_AF_PT_51_MAX 52 -char * EXN_Prim_AF_Pt_51[EXN_PRIM_AF_PT_51_MAX] = {"(none)", "C6 (Center)", "B6", "A5", - "D6", "E5", "C7", "B7", "A6", "D7", "E6", "C5", "B5", "A4", "D5", "E4", "C8", "B8", - "A7", "D8", "E7", "C9", "B9", "A8", "D9", "E8", "C10", "B10", "A9", "D10", "E9", - "C11", "B11", "D11", "C4", "B4", "A3", "D4", "E3", "C3", "B3", "A2", "D3", "E2", - "C2", "B2", "A1", "D2", "E1", "C1", "B1", "D1"}; - +char *EXN_Prim_AF_Pt_51[EXN_PRIM_AF_PT_51_MAX] = + { "(none)", "C6 (Center)", "B6", "A5", + "D6", "E5", "C7", "B7", "A6", "D7", "E6", "C5", "B5", "A4", "D5", + "E4", "C8", "B8", + "A7", "D8", "E7", "C9", "B9", "A8", "D9", "E8", "C10", "B10", "A9", + "D10", "E9", + "C11", "B11", "D11", "C4", "B4", "A3", "D4", "E3", "C3", "B3", + "A2", "D3", "E2", + "C2", "B2", "A1", "D2", "E1", "C1", "B1", "D1" +}; + #define EXN_PRIM_AF_PT_11_MAX 12 -char * EXN_Prim_AF_Pt_11[EXN_PRIM_AF_PT_11_MAX] = {"(none)", "Center", "Top", "Bottom", - "Mid-left", "Upper-left", "Lower-left", "Far Left", "Mid-right", "Upper-right", - "Lower-right", "Far Right"}; +char *EXN_Prim_AF_Pt_11[EXN_PRIM_AF_PT_11_MAX] = + { "(none)", "Center", "Top", "Bottom", + "Mid-left", "Upper-left", "Lower-left", "Far Left", "Mid-right", + "Upper-right", + "Lower-right", "Far Right" +}; #define EXN_PRIM_AF_PT_39_MAX 40 -char * EXN_Prim_AF_Pt_39[EXN_PRIM_AF_PT_39_MAX] = {"(none)", "C6 (Center)", "B6", "A2", - "D6", "E2", "C7", "B7", "A3", "D7", "E3", "C5", "B5", "A1", "D5", "E1", "C8", "B8", - "D8", "C9", "B9", "D9", "C10", "B10", "D10", "C11", "B11", "D11", "C4", "B4", "D4", - "C3", "B3", "D3", "C2", "B2", "D2", "C1", "B1", "D1"}; +char *EXN_Prim_AF_Pt_39[EXN_PRIM_AF_PT_39_MAX] = + { "(none)", "C6 (Center)", "B6", "A2", + "D6", "E2", "C7", "B7", "A3", "D7", "E3", "C5", "B5", "A1", "D5", + "E1", "C8", "B8", + "D8", "C9", "B9", "D9", "C10", "B10", "D10", "C11", "B11", "D11", + "C4", "B4", "D4", + "C3", "B3", "D3", "C2", "B2", "D2", "C1", "B1", "D1" +}; #define EXN_PIC_CTRL_ADJ_MAX 3 -char * EXN_Pic_Ctrl_Adj[EXN_PIC_CTRL_ADJ_MAX] = {"Default Settings", - "Quick Adjust", - "Full Control"}; +char *EXN_Pic_Ctrl_Adj[EXN_PIC_CTRL_ADJ_MAX] = { "Default Settings", + "Quick Adjust", + "Full Control" +}; static void exn_get_prim_af_pt(unsigned int phasedetectaf, - unsigned int primafpt, - char * buffer, - unsigned int maxsize); -static void exn_get_flash_output(unsigned int flashoutput, char * buffer, unsigned int maxsize); -static void exn_get_mnote_nikon_18(ExifData *ed, char * buffer, unsigned int maxsize); -static void exn_get_mnote_nikon_34(ExifData *ed, char * buffer, unsigned int maxsize); -static void exn_get_mnote_nikon_35(ExifData *ed, char * buffer, unsigned int maxsize); -static void exn_get_mnote_nikon_168(ExifData *ed, char * buffer, unsigned int maxsize); -static void exn_get_mnote_nikon_183(ExifData *ed, char * buffer, unsigned int maxsize); + unsigned int primafpt, + char *buffer, unsigned int maxsize); +static void exn_get_flash_output(unsigned int flashoutput, char *buffer, + unsigned int maxsize); +static void exn_get_mnote_nikon_18(ExifData * ed, char *buffer, + unsigned int maxsize); +static void exn_get_mnote_nikon_34(ExifData * ed, char *buffer, + unsigned int maxsize); +static void exn_get_mnote_nikon_35(ExifData * ed, char *buffer, + unsigned int maxsize); +static void exn_get_mnote_nikon_168(ExifData * ed, char *buffer, + unsigned int maxsize); +static void exn_get_mnote_nikon_183(ExifData * ed, char *buffer, + unsigned int maxsize); /* get primary AF point */ static void exn_get_prim_af_pt(unsigned int phasedetectaf, - unsigned int primafpt, - char * buffer, - unsigned int maxsize) + unsigned int primafpt, + char *buffer, unsigned int maxsize) { - - switch(phasedetectaf) - { - case 0: - { - /* phasedetect not used. should not happen */ - snprintf(buffer, maxsize, "FAIL"); - return; - } - break; - case 1: - { - /* 51 pt */ - if ( primafpt < EXN_PRIM_AF_PT_51_MAX ) - { - snprintf(buffer, maxsize, "%s", EXN_Prim_AF_Pt_51[primafpt]); - } - return; - } - break; - case 2: - { - /* 11 pt */ - if ( primafpt < EXN_PRIM_AF_PT_11_MAX ) - { - snprintf(buffer, maxsize, "%s", EXN_Prim_AF_Pt_11[primafpt]); - } - return; - } - break; - case 3: - { - /* 39 pt */ - if ( primafpt < EXN_PRIM_AF_PT_39_MAX ) - { - snprintf(buffer, maxsize, "%s", EXN_Prim_AF_Pt_39[primafpt]); - } - return; - } - break; - default: - { - snprintf(buffer, maxsize, "?"); - return; - } - break; - - } - + + switch (phasedetectaf) { + case 0: + { + /* phasedetect not used. should not happen */ + snprintf(buffer, maxsize, "FAIL"); + return; + } + break; + case 1: + { + /* 51 pt */ + if (primafpt < EXN_PRIM_AF_PT_51_MAX) { + snprintf(buffer, maxsize, "%s", + EXN_Prim_AF_Pt_51[primafpt]); + } + return; + } + break; + case 2: + { + /* 11 pt */ + if (primafpt < EXN_PRIM_AF_PT_11_MAX) { + snprintf(buffer, maxsize, "%s", + EXN_Prim_AF_Pt_11[primafpt]); + } + return; + } + break; + case 3: + { + /* 39 pt */ + if (primafpt < EXN_PRIM_AF_PT_39_MAX) { + snprintf(buffer, maxsize, "%s", + EXN_Prim_AF_Pt_39[primafpt]); + } + return; + } + break; + default: + { + snprintf(buffer, maxsize, "?"); + return; + } + break; + + } + } /* get flash output power (for FlashInfo010x) */ -static void exn_get_flash_output(unsigned int flashoutput, char * buffer, unsigned int maxsize) +static void exn_get_flash_output(unsigned int flashoutput, char *buffer, + unsigned int maxsize) { - - if ( flashoutput == 0 ) - { - /* full power */ - snprintf(buffer, maxsize, "Full"); - } - else - { - if ( (flashoutput % 6) == 0 ) - { - /* value is a power of 2 */ - snprintf(buffer, maxsize, "1/%d", 1<<(flashoutput/6)); - } - else - { - /* something uneven...ugly. maybe introduce pow() function from libm later */ - snprintf(buffer, maxsize, "1/2^(%f)", ((float)flashoutput)/6.0); - } - } + + if (flashoutput == 0) { + /* full power */ + snprintf(buffer, maxsize, "Full"); + } else { + if ((flashoutput % 6) == 0) { + /* value is a power of 2 */ + snprintf(buffer, maxsize, "1/%d", + 1 << (flashoutput / 6)); + } else { + /* something uneven...ugly. maybe introduce pow() function from libm later */ + snprintf(buffer, maxsize, "1/2^(%f)", + ((float) flashoutput) / 6.0); + } + } } /* get ActiveD-Lighting (18) info */ -static void exn_get_mnote_nikon_18(ExifData *ed, char * buffer, unsigned int maxsize) +static void exn_get_mnote_nikon_18(ExifData * ed, char *buffer, + unsigned int maxsize) { - char buf[EXIF_STD_BUF_LEN]; - float data = 0; + char buf[EXIF_STD_BUF_LEN]; + float data = 0; - buf[0] = '\0'; - exif_get_mnote_tag(ed, 18, buf, sizeof(buf)); + buf[0] = '\0'; + exif_get_mnote_tag(ed, 18, buf, sizeof(buf)); - sscanf(buf, "Flash Exposure Compensation: %f", &data); /* libexif buggy here. fix conversion */ + sscanf(buf, "Flash Exposure Compensation: %f", &data); /* libexif buggy here. fix conversion */ - snprintf(buffer, maxsize, "FlashExposureCompensation: %+.1f EV\n", ((float)((signed char)round(data*6.0))) / 6.0 ); + snprintf(buffer, maxsize, "FlashExposureCompensation: %+.1f EV\n", + ((float) ((signed char) round(data * 6.0))) / 6.0); } /* get ActiveD-Lighting (34) info */ -static void exn_get_mnote_nikon_34(ExifData *ed, char * buffer, unsigned int maxsize) +static void exn_get_mnote_nikon_34(ExifData * ed, char *buffer, + unsigned int maxsize) { - char buf[EXIF_STD_BUF_LEN]; - unsigned int data = 0; - char *answer; - - buf[0] = '\0'; - exif_get_mnote_tag(ed, 34, buf, sizeof(buf)); - sscanf(buf, "(null): %u", &data); /* not directly supported by libexif yet */ - - switch(data) - { - case 0: - { - answer = "Off"; - } - break; - case 1: - { - answer = "Low"; - } - break; - case 3: - { - answer = "Normal"; - } - break; - case 5: - { - answer = "High"; - } - break; - case 7: - { - answer = "Extra High"; - } - break; - case 65535: - { - answer = "Auto"; - } - break; - default: - { - answer = "N/A"; /* this is not a nikon value */ - } - - } - - snprintf(buffer, maxsize, "Active D-Lightning: %s\n", answer); - + char buf[EXIF_STD_BUF_LEN]; + unsigned int data = 0; + char *answer; + + buf[0] = '\0'; + exif_get_mnote_tag(ed, 34, buf, sizeof(buf)); + sscanf(buf, "(null): %u", &data); /* not directly supported by libexif yet */ + + switch (data) { + case 0: + { + answer = "Off"; + } + break; + case 1: + { + answer = "Low"; + } + break; + case 3: + { + answer = "Normal"; + } + break; + case 5: + { + answer = "High"; + } + break; + case 7: + { + answer = "Extra High"; + } + break; + case 65535: + { + answer = "Auto"; + } + break; + default: + { + answer = "N/A"; /* this is not a nikon value */ + } + + } + + snprintf(buffer, maxsize, "Active D-Lightning: %s\n", answer); + } /* get nikon PictureControlData (35) info */ -static void exn_get_mnote_nikon_35(ExifData *ed, char * buffer, unsigned int maxsize) +static void exn_get_mnote_nikon_35(ExifData * ed, char *buffer, + unsigned int maxsize) { - char buf[EXIF_STD_BUF_LEN]; - char picturecontrolname[EXIF_STD_BUF_LEN]; - char picturecontrolbase[EXIF_STD_BUF_LEN]; - unsigned int version = 0; - unsigned int length = 0; - unsigned int piccontroladj = 0; - unsigned int piccontrolquickadj = 0; - unsigned int sharpness = 0; - unsigned int contrast = 0; - unsigned int brightness = 0; - unsigned int saturation = 0; - unsigned int hueadjustment = 0; - unsigned int i, j; - - /* libexif does not support PictureControlData 35 yet. so we have to parse the debug data :-( */ - buf[0] = '\0'; - exif_get_mnote_tag(ed, 35, buf, sizeof(buf)); - - sscanf(buf, "(null): %u bytes unknown data: 303130%02X%40s%40s%*8s%02X%02X%02X%02X%02X%02X%02X", - &length, &version, &picturecontrolname[0], &picturecontrolbase[0], - &piccontroladj, &piccontrolquickadj, - &sharpness, &contrast, &brightness, &saturation, &hueadjustment - ); - - /* printf("--%s %d-%d-\n", buf, version, piccontroladj); */ - - for ( i=0; i<40; i++ ) - { - sscanf(&picturecontrolname[2*i], "%2X", &j); - picturecontrolname[i] = j; - sscanf(&picturecontrolbase[2*i], "%2X", &j); - picturecontrolbase[i] = j; - - } - exif_trim_spaces(picturecontrolname); - exif_trim_spaces(picturecontrolbase); - - if ( ((length == 58) && (version == '0')) - && (piccontroladj < EXN_PIC_CTRL_ADJ_MAX) - - ) - { - snprintf(buffer, maxsize, - "PictCtrlData: Name: %s; Base: %s; CtrlAdj: %s; Quick: %d; Shrp: %d; Contr: %d; Brght: %d; Sat: %d; Hue: %d\n", - picturecontrolname, picturecontrolbase, - EXN_Pic_Ctrl_Adj[piccontroladj], piccontrolquickadj, - sharpness, contrast, brightness, saturation, hueadjustment); - } + char buf[EXIF_STD_BUF_LEN]; + char picturecontrolname[EXIF_STD_BUF_LEN]; + char picturecontrolbase[EXIF_STD_BUF_LEN]; + unsigned int version = 0; + unsigned int length = 0; + unsigned int piccontroladj = 0; + unsigned int piccontrolquickadj = 0; + unsigned int sharpness = 0; + unsigned int contrast = 0; + unsigned int brightness = 0; + unsigned int saturation = 0; + unsigned int hueadjustment = 0; + unsigned int i, j; + + /* libexif does not support PictureControlData 35 yet. so we have to parse the debug data :-( */ + buf[0] = '\0'; + exif_get_mnote_tag(ed, 35, buf, sizeof(buf)); + + sscanf(buf, + "(null): %u bytes unknown data: 303130%02X%40s%40s%*8s%02X%02X%02X%02X%02X%02X%02X", + &length, &version, &picturecontrolname[0], + &picturecontrolbase[0], &piccontroladj, &piccontrolquickadj, + &sharpness, &contrast, &brightness, &saturation, + &hueadjustment); + + /* printf("--%s %d-%d-\n", buf, version, piccontroladj); */ + + for (i = 0; i < 40; i++) { + sscanf(&picturecontrolname[2 * i], "%2X", &j); + picturecontrolname[i] = j; + sscanf(&picturecontrolbase[2 * i], "%2X", &j); + picturecontrolbase[i] = j; + + } + exif_trim_spaces(picturecontrolname); + exif_trim_spaces(picturecontrolbase); + + if (((length == 58) && (version == '0')) + && (piccontroladj < EXN_PIC_CTRL_ADJ_MAX) + ) { + snprintf(buffer, maxsize, + "PictCtrlData: Name: %s; Base: %s; CtrlAdj: %s; Quick: %d; Shrp: %d; Contr: %d; Brght: %d; Sat: %d; Hue: %d\n", + picturecontrolname, picturecontrolbase, + EXN_Pic_Ctrl_Adj[piccontroladj], + piccontrolquickadj, sharpness, contrast, + brightness, saturation, hueadjustment); + } } @@ -331,180 +354,189 @@ static void exn_get_mnote_nikon_35(ExifData *ed, char * buffer, unsigned int max /* get nikon Flash info: control mode (168) info */ -static void exn_get_mnote_nikon_168(ExifData *ed, char * buffer, unsigned int maxsize) +static void exn_get_mnote_nikon_168(ExifData * ed, char *buffer, + unsigned int maxsize) { - char buf[EXIF_STD_BUF_LEN]; - unsigned int version = 0; - unsigned int length = 0; - unsigned int exn_fcm = (EXN_FLASH_CONTROL_MODES_MAX-1); /* default to N/A */ - unsigned int flashoutput = 0; - unsigned int externalflashflags = 0; - unsigned int flashcompensation = 0; - - /* libexif does not support flash info 168 yet. so we have to parse the debug data :-( */ - buf[0] = '\0'; - exif_get_mnote_tag(ed, 168, buf, sizeof(buf)); - sscanf(buf, "(null): %u bytes unknown data: 303130%02X%*8s%02X%02X%02X%02X", &length, &version, &externalflashflags, &exn_fcm, &flashoutput, &flashcompensation); - exn_fcm = exn_fcm & EXN_FLASH_CONTROL_MODE_MASK; - - /* printf("%s - %d %d %d %d\n", buf, externalflashflags, exn_fcm, flashoutput, (signed char)flashcompensation); */ - - if ( (exn_fcm < EXN_FLASH_CONTROL_MODES_MAX) - && ( ((length == 22) && (version == '3')) /* Nikon FlashInfo0103 */ - || ((length == 22) && (version == '4')) /* Nikon FlashInfo0104 */ - || ((length == 21) && (version == '2')) /* Nikon FlashInfo0102 */ - || ((length == 19) && (version == '0')) /* Nikon FlashInfo0100 */ - ) - ) - { - - buf[0] = '\0'; - exn_get_flash_output(flashoutput, buf, EXIF_STD_BUF_LEN); - snprintf(buffer, maxsize, "NikonFlashControlMode: %s (Power: %s)\n", EXN_NikonFlashControlModeValues[exn_fcm], buf); - - /* External Flash Flags. Not as useful as expected. Not used (yet). */ - /* if ( (externalflashflags & (1<<2)) ) -> Bounce Flash */ - /* if ( (externalflashflags & (1<<4)) ) -> Wide Flash Adapter */ - /* if ( (externalflashflags & (1<<5)) ) -> Dome Diffusor */ - - } + char buf[EXIF_STD_BUF_LEN]; + unsigned int version = 0; + unsigned int length = 0; + unsigned int exn_fcm = (EXN_FLASH_CONTROL_MODES_MAX - 1); /* default to N/A */ + unsigned int flashoutput = 0; + unsigned int externalflashflags = 0; + unsigned int flashcompensation = 0; + + /* libexif does not support flash info 168 yet. so we have to parse the debug data :-( */ + buf[0] = '\0'; + exif_get_mnote_tag(ed, 168, buf, sizeof(buf)); + sscanf(buf, + "(null): %u bytes unknown data: 303130%02X%*8s%02X%02X%02X%02X", + &length, &version, &externalflashflags, &exn_fcm, + &flashoutput, &flashcompensation); + exn_fcm = exn_fcm & EXN_FLASH_CONTROL_MODE_MASK; + + /* printf("%s - %d %d %d %d\n", buf, externalflashflags, exn_fcm, flashoutput, (signed char)flashcompensation); */ + + if ((exn_fcm < EXN_FLASH_CONTROL_MODES_MAX) + && (((length == 22) && (version == '3')) /* Nikon FlashInfo0103 */ + ||((length == 22) && (version == '4')) /* Nikon FlashInfo0104 */ + ||((length == 21) && (version == '2')) /* Nikon FlashInfo0102 */ + ||((length == 19) && (version == '0')) /* Nikon FlashInfo0100 */ + ) + ) { + + buf[0] = '\0'; + exn_get_flash_output(flashoutput, buf, EXIF_STD_BUF_LEN); + snprintf(buffer, maxsize, + "NikonFlashControlMode: %s (Power: %s)\n", + EXN_NikonFlashControlModeValues[exn_fcm], buf); + + /* External Flash Flags. Not as useful as expected. Not used (yet). */ + /* if ( (externalflashflags & (1<<2)) ) -> Bounce Flash */ + /* if ( (externalflashflags & (1<<4)) ) -> Wide Flash Adapter */ + /* if ( (externalflashflags & (1<<5)) ) -> Dome Diffusor */ + + } } /* get nikon AFInfo2 (183) info */ -static void exn_get_mnote_nikon_183(ExifData *ed, char * buffer, unsigned int maxsize) +static void exn_get_mnote_nikon_183(ExifData * ed, char *buffer, + unsigned int maxsize) { - char buf[EXIF_STD_BUF_LEN]; - unsigned int contrastdetectaf = 0; - unsigned int afareamode = 0; - unsigned int phasedetectaf = 0; - unsigned int primaryafpoint = 0; - unsigned int version = 0; - unsigned int length = 0; - - /* AFInfo2 */ - /* libexif does not support AFInfo2 183 yet. so we have to parse the debug data :-( */ - buf[0] = '\0'; - exif_get_mnote_tag(ed, 183, buf, sizeof(buf)); - sscanf(buf, "(null): %u bytes unknown data: 303130%02X%02X%02X%02X%02X", &length, &version, - &contrastdetectaf, - &afareamode, - &phasedetectaf, - &primaryafpoint - ); - - - if ( ((length == 30) && (version == '0')) - && (contrastdetectaf < EXN_CONTRAST_DETECT_AF_MAX) - && (phasedetectaf < EXN_PHASE_DETECT_AF_MAX) - ) - { - if ( (contrastdetectaf != 0) && (afareamode < EXN_AF_AREA_MODE_C_MAX) ) - { - /* Contrast AF (live view) */ - snprintf(buffer, maxsize, - "ContrastDetectAF: %s; AFAreaMode: %s\n", - EXN_NikonContrastDetectAF[contrastdetectaf], - EXN_NikonAFAreaModeContr[afareamode]); - - } - else if ( (phasedetectaf != 0) && (afareamode < EXN_AF_AREA_MODE_P_MAX) ) - { - /* Phase AF */ - buf[0] = '\0'; - exn_get_prim_af_pt(phasedetectaf, primaryafpoint, buf, EXIF_STD_BUF_LEN); - - snprintf(buffer, maxsize, - "PhaseDetectAF: %s; AreaMode: %s; PrimaryAFPoint: %s\n", - EXN_NikonPhaseDetectAF[phasedetectaf], - EXN_NikonAFAreaModePhase[afareamode], - buf - ); - } - - } + char buf[EXIF_STD_BUF_LEN]; + unsigned int contrastdetectaf = 0; + unsigned int afareamode = 0; + unsigned int phasedetectaf = 0; + unsigned int primaryafpoint = 0; + unsigned int version = 0; + unsigned int length = 0; + + /* AFInfo2 */ + /* libexif does not support AFInfo2 183 yet. so we have to parse the debug data :-( */ + buf[0] = '\0'; + exif_get_mnote_tag(ed, 183, buf, sizeof(buf)); + sscanf(buf, + "(null): %u bytes unknown data: 303130%02X%02X%02X%02X%02X", + &length, &version, &contrastdetectaf, &afareamode, + &phasedetectaf, &primaryafpoint); + + + if (((length == 30) && (version == '0')) + && (contrastdetectaf < EXN_CONTRAST_DETECT_AF_MAX) + && (phasedetectaf < EXN_PHASE_DETECT_AF_MAX) + ) { + if ((contrastdetectaf != 0) + && (afareamode < EXN_AF_AREA_MODE_C_MAX)) { + /* Contrast AF (live view) */ + snprintf(buffer, maxsize, + "ContrastDetectAF: %s; AFAreaMode: %s\n", + EXN_NikonContrastDetectAF + [contrastdetectaf], + EXN_NikonAFAreaModeContr[afareamode]); + + } else if ((phasedetectaf != 0) + && (afareamode < EXN_AF_AREA_MODE_P_MAX)) { + /* Phase AF */ + buf[0] = '\0'; + exn_get_prim_af_pt(phasedetectaf, primaryafpoint, + buf, EXIF_STD_BUF_LEN); + + snprintf(buffer, maxsize, + "PhaseDetectAF: %s; AreaMode: %s; PrimaryAFPoint: %s\n", + EXN_NikonPhaseDetectAF[phasedetectaf], + EXN_NikonAFAreaModePhase[afareamode], + buf); + } + + } } /* get interesting nikon maker note tags in readable form */ -void exn_get_mnote_nikon_tags(ExifData *ed, unsigned int tag, char * buffer, unsigned int maxsize) +void exn_get_mnote_nikon_tags(ExifData * ed, unsigned int tag, + char *buffer, unsigned int maxsize) { - char buf[EXIF_STD_BUF_LEN]; - - buf[0] = '\0'; - exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_FLASH, buf, sizeof(buf)); - exif_trim_spaces(buf); - - switch(tag) - { - /* show only if flash was used */ - case 8: /* Flash Setting */ - case 9: /* Flash Mode */ - case 135: /* Flash used */ - { - if ( !(strcmp("Flash: Flash did not fire\n", buf) == 0) ) - { - /* show extended flash info only if flash was fired */ - exif_get_mnote_tag(ed, tag, buffer, maxsize); - } - } - break; - - case 18: /* FlashExposureComp */ - { - if ( !(strcmp("Flash: Flash did not fire\n", buf) == 0) ) - { - /* show only if flash was fired */ - exn_get_mnote_nikon_18(ed, buffer, maxsize); - } - } - break; - - case 34: - { - /* ActiveD-Lighting */ - exn_get_mnote_nikon_34(ed, buffer, maxsize); - } - break; - - case 35: - { - /* PictureControlData */ - exn_get_mnote_nikon_35(ed, buffer, maxsize); - } - break; - - case 168: - { - /* Flash info: control mode */ - if ( !(strcmp("Flash: Flash did not fire\n", buf) == 0) ) - { - /* show extended flash info only if flash was fired */ - exn_get_mnote_nikon_168(ed, buffer, maxsize); - } - } - break; - - case 183: - { - /* AFInfo 2 */ - exn_get_mnote_nikon_183(ed, buffer, maxsize); - } - break; - - default: - { - /* normal makernote tags without special treatment */ - exif_get_mnote_tag(ed, tag, buffer, maxsize); - } - break; - } - - - return; + char buf[EXIF_STD_BUF_LEN]; + + buf[0] = '\0'; + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_FLASH, buf, sizeof(buf)); + exif_trim_spaces(buf); + + switch (tag) { + /* show only if flash was used */ + case 8: /* Flash Setting */ + case 9: /* Flash Mode */ + case 135: /* Flash used */ + { + if (! + (strcmp("Flash: Flash did not fire\n", buf) == + 0)) { + /* show extended flash info only if flash was fired */ + exif_get_mnote_tag(ed, tag, buffer, + maxsize); + } + } + break; + + case 18: /* FlashExposureComp */ + { + if (! + (strcmp("Flash: Flash did not fire\n", buf) == + 0)) { + /* show only if flash was fired */ + exn_get_mnote_nikon_18(ed, buffer, + maxsize); + } + } + break; + + case 34: + { + /* ActiveD-Lighting */ + exn_get_mnote_nikon_34(ed, buffer, maxsize); + } + break; + + case 35: + { + /* PictureControlData */ + exn_get_mnote_nikon_35(ed, buffer, maxsize); + } + break; + + case 168: + { + /* Flash info: control mode */ + if (! + (strcmp("Flash: Flash did not fire\n", buf) == + 0)) { + /* show extended flash info only if flash was fired */ + exn_get_mnote_nikon_168(ed, buffer, + maxsize); + } + } + break; + + case 183: + { + /* AFInfo 2 */ + exn_get_mnote_nikon_183(ed, buffer, maxsize); + } + break; + + default: + { + /* normal makernote tags without special treatment */ + exif_get_mnote_tag(ed, tag, buffer, maxsize); + } + break; + } + + + return; } #endif diff --git a/src/exif_nikon.h b/src/exif_nikon.h index 16e8fb9..49d14b6 100644 --- a/src/exif_nikon.h +++ b/src/exif_nikon.h @@ -28,6 +28,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <libexif/exif-data.h> -extern void exn_get_mnote_nikon_tags(ExifData *ed, unsigned int tag, char * buffer, unsigned int maxsize); +extern void exn_get_mnote_nikon_tags(ExifData * ed, unsigned int tag, + char *buffer, unsigned int maxsize); #endif @@ -1,7 +1,7 @@ /* feh.h Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -63,6 +63,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <signal.h> #include <sys/wait.h> #include <math.h> +#include <getopt.h> #include <Imlib2.h> #include "gib_hash.h" @@ -74,7 +75,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "menu.h" #include "utils.h" -#include "getopt.h" #include "debug.h" @@ -115,6 +115,14 @@ enum slide_change { SLIDE_NEXT, SLIDE_PREV, SLIDE_RAND, SLIDE_FIRST, SLIDE_LAST, SLIDE_JUMP_PREV_DIR }; +enum feh_load_error { + LOAD_ERROR_IMLIB = 0, + LOAD_ERROR_IMAGEMAGICK, + LOAD_ERROR_CURL, + LOAD_ERROR_DCRAW, + LOAD_ERROR_MAGICBYTES +}; + #define INPLACE_EDIT_FLIP -1 #define INPLACE_EDIT_MIRROR -2 @@ -137,6 +145,10 @@ void init_slideshow_mode(void); void init_list_mode(void); void init_loadables_mode(void); void init_unloadables_mode(void); +#ifdef HAVE_LIBMAGIC +void uninit_magic(void); +void init_magic(void); +#endif void feh_clean_exit(void); int feh_should_ignore_image(Imlib_Image * im); int feh_load_image(Imlib_Image * im, feh_file * file); @@ -148,7 +160,7 @@ void init_buttonbindings(void); void setup_stdin(void); void restore_stdin(void); void feh_event_handle_keypress(XEvent * ev); -void feh_event_handle_stdin(); +void feh_event_handle_stdin(void); void feh_event_handle_generic(winwidget winwid, unsigned int state, KeySym keysym, unsigned int button); fehkey *feh_str_to_kb(char * action); void feh_action_run(feh_file * file, char *action, winwidget winwid); @@ -172,7 +184,7 @@ void feh_display_status(char stat); void real_loadables_mode(int loadable); void feh_reload_image(winwidget w, int resize, int force_new); void feh_filelist_image_remove(winwidget winwid, char do_delete); -void feh_imlib_print_load_error(char *file, winwidget w, Imlib_Load_Error err); +void feh_print_load_error(char *file, winwidget w, Imlib_Load_Error err, enum feh_load_error feh_err); void slideshow_save_image(winwidget win); void feh_edit_inplace(winwidget w, int orientation); void feh_edit_inplace_lossless(winwidget w, int orientation); diff --git a/src/feh_png.c b/src/feh_png.c index d0c1c8a..8f5b94d 100644 --- a/src/feh_png.c +++ b/src/feh_png.c @@ -197,7 +197,10 @@ int feh_png_file_is_png(FILE * fp) { unsigned char buf[8]; - fread(buf, 1, 8, fp); + if (fread(buf, 1, 8, fp) != 8) { + return 0; + } + if (png_sig_cmp(buf, 0, 8)) { return 0; } diff --git a/src/filelist.c b/src/filelist.c index 361ac19..f1e820c 100644 --- a/src/filelist.c +++ b/src/filelist.c @@ -1,7 +1,7 @@ /* filelist.c Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -24,20 +24,19 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifdef HAVE_LIBEXIF -#include <libexif/exif-data.h> -#endif - #include "feh.h" #include "filelist.h" #include "signals.h" #include "options.h" +#ifdef HAVE_LIBCURL +#include <curl/curl.h> +#endif + gib_list *filelist = NULL; gib_list *original_file_items = NULL; /* original file items from argv */ int filelist_len = 0; gib_list *current_file = NULL; -extern int errno; static gib_list *rm_filelist = NULL; @@ -156,7 +155,7 @@ static void feh_print_stat_error(char *path) } } -static void add_stdin_to_filelist() +static void add_stdin_to_filelist(void) { char buf[1024]; size_t readsize; @@ -181,6 +180,7 @@ static void add_stdin_to_filelist() while ((readsize = fread(buf, sizeof(char), sizeof(buf), stdin)) > 0) { if (fwrite(buf, sizeof(char), readsize, outfile) < readsize) { free(sfn); + fclose(outfile); return; } } @@ -198,7 +198,7 @@ void add_file_to_filelist_recursively(char *origpath, unsigned char level) struct stat st; char *path; - if (!origpath) + if (!origpath || *origpath == '\0') return; path = estrdup(origpath); @@ -398,7 +398,7 @@ void feh_file_dirname(char *dst, feh_file * f, int maxlen) return; } - strncpy(dst, f->filename, n); + memcpy(dst, f->filename, n); dst[n] = '\0'; } @@ -641,12 +641,13 @@ char *feh_absolute_path(char *path) filelist file can be saved anywhere and feh will still find the images */ D(("Need to convert %s to an absolute form\n", path)); - /* I SHOULD be able to just use a simple realpath() here, but dumb * + /* I SHOULD be able to just use a simple realpath() here, but dumb * old Solaris's realpath doesn't return an absolute path if the path you give it is relative. Linux and BSD get this right... */ if (getcwd(cwd, sizeof(cwd)) == NULL) eprintf("Cannot determine working directory:"); - snprintf(temp, sizeof(temp), "%s/%s", cwd, path); + if ((size_t) snprintf(temp, sizeof(temp), "%s/%s", cwd, path) >= sizeof(temp)) + eprintf("Absolute path for working directory was truncated"); if (realpath(temp, fullpath) != NULL) { ret = estrdup(fullpath); } else { @@ -656,11 +657,20 @@ char *feh_absolute_path(char *path) return(ret); } -void feh_save_filelist() +void feh_save_filelist(void) { char *tmpname; + char *base_dir = ""; - tmpname = feh_unique_filename("", "filelist"); + if (opt.output_dir) { + base_dir = estrjoin("", opt.output_dir, "/", NULL); + } + + tmpname = feh_unique_filename(base_dir, "filelist"); + + if (opt.output_dir) { + free(base_dir); + } if (opt.verbose) fprintf(stderr, "saving filelist to filename '%s'\n", tmpname); @@ -669,3 +679,27 @@ void feh_save_filelist() free(tmpname); return; } + +#ifdef HAVE_LIBCURL + +char *feh_http_unescape(char *url) +{ + CURL *curl = curl_easy_init(); + if (!curl) { + return NULL; + } + char *tmp_url = curl_easy_unescape(curl, url, 0, NULL); + char *new_url = estrdup(tmp_url); + curl_free(tmp_url); + curl_easy_cleanup(curl); + return new_url; +} + +#else + +char *feh_http_unescape(char *url) +{ + return NULL; +} + +#endif diff --git a/src/filelist.h b/src/filelist.h index e24a6a6..7f263dc 100644 --- a/src/filelist.h +++ b/src/filelist.h @@ -96,7 +96,8 @@ int feh_write_filelist(gib_list * list, char *filename); gib_list *feh_read_filelist(char *filename); char *feh_absolute_path(char *path); gib_list *feh_file_remove_from_list(gib_list * list, gib_list * l); -void feh_save_filelist(); +void feh_save_filelist(void); +char *feh_http_unescape(char * url); int feh_cmp_name(void *file1, void *file2); int feh_cmp_dirname(void *file1, void *file2); diff --git a/src/getopt.c b/src/getopt.c deleted file mode 100644 index d212b3a..0000000 --- a/src/getopt.c +++ /dev/null @@ -1,949 +0,0 @@ -/* Getopt for GNU. - NOTE: getopt is now part of the C library, so if you don't know what - "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu - before changing it! - - Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97 - Free Software Foundation, Inc. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. - Ditto for AIX 3.2 and <stdlib.h>. */ -#ifndef _NO_PROTO -#define _NO_PROTO -#endif - -#if !defined (__STDC__) || !__STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -#ifndef const -#define const -#endif -#endif - -#include <stdio.h> - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#define GETOPT_INTERFACE_VERSION 2 -#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 -#include <gnu-versions.h> -#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION -#define ELIDE_CODE -#endif -#endif - -#ifndef ELIDE_CODE - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -/* Don't include stdlib.h for non-GNU C libraries because some of them - contain conflicting prototypes for getopt. */ -#include <stdlib.h> -#include <unistd.h> -#endif /* GNU C library. */ - -#ifdef VMS -#include <unixlib.h> -#if HAVE_STRING_H - 0 -#include <string.h> -#endif -#endif - -#ifndef _ -/* This is for other GNU distributions with internationalized messages. - When compiling libc, the _ macro is predefined. */ -#ifdef HAVE_LIBINTL_H -# include <libintl.h> -# define _(msgid) gettext (msgid) -#else -# define _(msgid) (msgid) -#endif -#endif - -/* This version of `getopt' appears to the caller like standard Unix `getopt' - but it behaves differently for the user, since it allows the user - to intersperse the options with the other arguments. - - As `getopt' works, it permutes the elements of ARGV so that, - when it is done, all the options precede everything else. Thus - all application programs are extended to handle flexible argument order. - - Setting the environment variable POSIXLY_CORRECT disables permutation. - Then the behavior is completely standard. - - GNU application programs can use a third alternative mode in which - they can distinguish the relative order of options and other arguments. */ - -#include "getopt.h" - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -char *optarg = NULL; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -/* 1003.2 says this must be 1 before any call. */ -int optind = 1; - -/* Formerly, initialization of getopt depended on optind==0, which - causes problems with re-calling getopt as programs generally don't - know that. */ - -int __getopt_initialized = 0; - -/* The next char to be scanned in the option-element - in which the last option character we returned was found. - This allows us to pick up the scan where we left off. - - If this is zero, or a null string, it means resume the scan - by advancing to the next ARGV-element. */ - -static char *nextchar; - -/* Callers store zero here to inhibit the error message - for unrecognized options. */ - -int opterr = 1; - -/* Set to an option character which was unrecognized. - This must be initialized on some systems to avoid linking in the - system's own getopt implementation. */ - -int optopt = '?'; - -/* Describe how to deal with options that follow non-option ARGV-elements. - - If the caller did not specify anything, - the default is REQUIRE_ORDER if the environment variable - POSIXLY_CORRECT is defined, PERMUTE otherwise. - - REQUIRE_ORDER means don't recognize them as options; - stop option processing when the first non-option is seen. - This is what Unix does. - This mode of operation is selected by either setting the environment - variable POSIXLY_CORRECT, or using `+' as the first character - of the list of option characters. - - PERMUTE is the default. We permute the contents of ARGV as we scan, - so that eventually all the non-options are at the end. This allows options - to be given in any order, even with programs that were not written to - expect this. - - RETURN_IN_ORDER is an option available to programs that were written - to expect options and other ARGV-elements in any order and that care about - the ordering of the two. We describe each non-option ARGV-element - as if it were the argument of an option with character code 1. - Using `-' as the first character of the list of option characters - selects this mode of operation. - - The special argument `--' forces an end of option-scanning regardless - of the value of `ordering'. In the case of RETURN_IN_ORDER, only - `--' can cause `getopt' to return -1 with `optind' != ARGC. */ - -static enum { - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER -} ordering; - -/* Value of POSIXLY_CORRECT environment variable. */ -static char *posixly_correct; - -#ifdef __GNU_LIBRARY__ -/* We want to avoid inclusion of string.h with non-GNU libraries - because there are many ways it can cause trouble. - On some systems, it contains special magic macros that don't work - in GCC. */ -#include <string.h> -#define my_index strchr -#else - -/* Avoid depending on library functions or files - whose names are inconsistent. */ - -char *getenv(); - -static char *my_index(str, chr) -const char *str; -int chr; -{ - while (*str) { - if (*str == chr) - return (char *) str; - str++; - } - return 0; -} - -/* If using GCC, we can safely declare strlen this way. - If not using GCC, it is ok not to declare it. */ -#ifdef __GNUC__ -/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. - That was relevant to code that was here before. */ -#if !defined (__STDC__) || !__STDC__ -/* gcc with -traditional declares the built-in strlen to return int, - and has done so at least since version 2.4.5. -- rms. */ -extern int strlen(const char *); -#endif /* not __STDC__ */ -#endif /* __GNUC__ */ - -#endif /* not __GNU_LIBRARY__ */ - -/* Handle permutation of arguments. */ - -/* Describe the part of ARGV that contains non-options that have - been skipped. `first_nonopt' is the index in ARGV of the first of them; - `last_nonopt' is the index after the last of them. */ - -static int first_nonopt; -static int last_nonopt; - -#ifdef _LIBC -/* Bash 2.0 gives us an environment variable containing flags - indicating ARGV elements that should not be considered arguments. */ - -/* Defined in getopt_init.c */ -extern char *__getopt_nonoption_flags; - -static int nonoption_flags_max_len; -static int nonoption_flags_len; - -static int original_argc; -static char *const *original_argv; - -/* Make sure the environment variable bash 2.0 puts in the environment - is valid for the getopt call we must make sure that the ARGV passed - to getopt is that one passed to the process. */ -static void - __attribute__ ((unused)) store_args_and_env(int argc, char *const *argv) -{ - /* XXX This is no good solution. We should rather copy the args so that - we can compare them later. But we must not use malloc(3). */ - original_argc = argc; - original_argv = argv; -} - -# ifdef text_set_element -text_set_element(__libc_subinit, store_args_and_env); -# endif /* text_set_element */ - -# define SWAP_FLAGS(ch1, ch2) \ - if (nonoption_flags_len > 0) \ - { \ - char __tmp = __getopt_nonoption_flags[ch1]; \ - __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ - __getopt_nonoption_flags[ch2] = __tmp; \ - } -#else /* !_LIBC */ -# define SWAP_FLAGS(ch1, ch2) -#endif /* _LIBC */ - -/* Exchange two adjacent subsequences of ARGV. - One subsequence is elements [first_nonopt,last_nonopt) - which contains all the non-options that have been skipped so far. - The other is elements [last_nonopt,optind), which contains all - the options processed since those non-options were skipped. - - `first_nonopt' and `last_nonopt' are relocated so that they describe - the new indices of the non-options in ARGV after they are moved. */ - -#if defined (__STDC__) && __STDC__ -static void exchange(char **); -#endif - -static void exchange(argv) -char **argv; -{ - int bottom = first_nonopt; - int middle = last_nonopt; - int top = optind; - char *tem; - - /* Exchange the shorter segment with the far end of the longer segment. - That puts the shorter segment into the right place. It leaves the - longer segment in the right place overall, but it consists of two parts - that need to be swapped next. */ - -#ifdef _LIBC - /* First make sure the handling of the `__getopt_nonoption_flags' string - can work normally. Our top argument must be in the range of the - string. */ - if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { - /* We must extend the array. The user plays games with us and presents - new arguments. */ - char *new_str = malloc(top + 1); - - if (new_str == NULL) - nonoption_flags_len = nonoption_flags_max_len = 0; - else { - memset(__mempcpy - (new_str, __getopt_nonoption_flags, - nonoption_flags_max_len), '\0', top + 1 - nonoption_flags_max_len); - nonoption_flags_max_len = top + 1; - __getopt_nonoption_flags = new_str; - } - } -#endif - - while (top > middle && middle > bottom) { - if (top - middle > middle - bottom) { - /* Bottom segment is the short one. */ - int len = middle - bottom; - register int i; - - /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) { - tem = argv[bottom + i]; - argv[bottom + i] = argv[top - (middle - bottom) + i]; - argv[top - (middle - bottom) + i] = tem; - SWAP_FLAGS(bottom + i, top - (middle - bottom) + i); - } - /* Exclude the moved bottom segment from further swapping. */ - top -= len; - } else { - /* Top segment is the short one. */ - int len = top - middle; - register int i; - - /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) { - tem = argv[bottom + i]; - argv[bottom + i] = argv[middle + i]; - argv[middle + i] = tem; - SWAP_FLAGS(bottom + i, middle + i); - } - /* Exclude the moved top segment from further swapping. */ - bottom += len; - } - } - - /* Update records for the slots the non-options now occupy. */ - - first_nonopt += (optind - last_nonopt); - last_nonopt = optind; -} - -/* Initialize the internal data when the first call is made. */ - -#if defined (__STDC__) && __STDC__ -static const char *_getopt_initialize(int, char *const *, const char *); -#endif -static const char *_getopt_initialize(argc, argv, optstring) -int argc; -char *const *argv; -const char *optstring; -{ - /* Start processing options with ARGV-element 1 (since ARGV-element 0 is - the program name); the sequence of previously skipped non-option - ARGV-elements is empty. */ - - first_nonopt = last_nonopt = optind; - - nextchar = NULL; - - posixly_correct = getenv("POSIXLY_CORRECT"); - - /* Determine how to handle the ordering of options and nonoptions. */ - - if (optstring[0] == '-') { - ordering = RETURN_IN_ORDER; - ++optstring; - } else if (optstring[0] == '+') { - ordering = REQUIRE_ORDER; - ++optstring; - } else if (posixly_correct != NULL) - ordering = REQUIRE_ORDER; - else - ordering = PERMUTE; - -#ifdef _LIBC - if (posixly_correct == NULL && argc == original_argc && argv == original_argv) { - if (nonoption_flags_max_len == 0) { - if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') - nonoption_flags_max_len = -1; - else { - const char *orig_str = __getopt_nonoption_flags; - int len = nonoption_flags_max_len = strlen(orig_str); - - if (nonoption_flags_max_len < argc) - nonoption_flags_max_len = argc; - __getopt_nonoption_flags = (char *) - malloc(nonoption_flags_max_len); - if (__getopt_nonoption_flags == NULL) - nonoption_flags_max_len = -1; - else - memset(__mempcpy - (__getopt_nonoption_flags, - orig_str, len), '\0', nonoption_flags_max_len - len); - } - } - nonoption_flags_len = nonoption_flags_max_len; - } else - nonoption_flags_len = 0; -#endif - - return optstring; -} - -/* Scan elements of ARGV (whose length is ARGC) for option characters - given in OPTSTRING. - - If an element of ARGV starts with '-', and is not exactly "-" or "--", - then it is an option element. The characters of this element - (aside from the initial '-') are option characters. If `getopt' - is called repeatedly, it returns successively each of the option characters - from each of the option elements. - - If `getopt' finds another option character, it returns that character, - updating `optind' and `nextchar' so that the next call to `getopt' can - resume the scan with the following option character or ARGV-element. - - If there are no more option characters, `getopt' returns -1. - Then `optind' is the index in ARGV of the first ARGV-element - that is not an option. (The ARGV-elements have been permuted - so that those that are not options now come last.) - - OPTSTRING is a string containing the legitimate option characters. - If an option character is seen that is not listed in OPTSTRING, - return '?' after printing an error message. If you set `opterr' to - zero, the error message is suppressed but we still return '?'. - - If a char in OPTSTRING is followed by a colon, that means it wants an arg, - so the following text in the same ARGV-element, or the text of the following - ARGV-element, is returned in `optarg'. Two colons mean an option that - wants an optional arg; if there is text in the current ARGV-element, - it is returned in `optarg', otherwise `optarg' is set to zero. - - If OPTSTRING starts with `-' or `+', it requests different methods of - handling the non-option ARGV-elements. - See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. - - Long-named options begin with `--' instead of `-'. - Their names may be abbreviated as long as the abbreviation is unique - or is an exact match for some defined option. If they have an - argument, it follows the option name in the same ARGV-element, separated - from the option name by a `=', or else the in next ARGV-element. - When `getopt' finds a long-named option, it returns 0 if that option's - `flag' field is nonzero, the value of the option's `val' field - if the `flag' field is zero. - - The elements of ARGV aren't really const, because we permute them. - But we pretend they're const in the prototype to be compatible - with other systems. - - LONGOPTS is a vector of `struct option' terminated by an - element containing a name which is zero. - - LONGIND returns the index in LONGOPT of the long-named option found. - It is only valid when a long-named option has been found by the most - recent call. - - If LONG_ONLY is nonzero, '-' as well as '--' can introduce - long-named options. */ - -int _getopt_internal(argc, argv, optstring, longopts, longind, long_only) -int argc; -char *const *argv; -const char *optstring; -const struct option *longopts; -int *longind; -int long_only; -{ - optarg = NULL; - - if (optind == 0 || !__getopt_initialized) { - if (optind == 0) - optind = 1; /* Don't scan ARGV[0], the - program name. */ - optstring = _getopt_initialize(argc, argv, optstring); - __getopt_initialized = 1; - } - - /* Test whether ARGV[optind] points to a non-option argument. Either it - does not have option syntax, or there is an environment flag from the - shell indicating it is not an option. The later information is only - used when the used in the GNU libc. */ -#ifdef _LIBC -#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ - || (optind < nonoption_flags_len \ - && __getopt_nonoption_flags[optind] == '1')) -#else -#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') -#endif - - if (nextchar == NULL || *nextchar == '\0') { - /* Advance to the next ARGV-element. */ - - /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been - moved back by the user (who may also have changed the arguments). */ - if (last_nonopt > optind) - last_nonopt = optind; - if (first_nonopt > optind) - first_nonopt = optind; - - if (ordering == PERMUTE) { - /* If we have just processed some options following some - non-options, exchange them so that the options come first. */ - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange((char **) argv); - else if (last_nonopt != optind) - first_nonopt = optind; - - /* Skip any additional non-options and extend the range of - non-options previously skipped. */ - - while (optind < argc && NONOPTION_P) - optind++; - last_nonopt = optind; - } - - /* The special ARGV-element `--' means premature end of options. Skip - it like a null option, then exchange with previous non-options as if - it were an option, then skip everything else like a non-option. */ - - if (optind != argc && !strcmp(argv[optind], "--")) { - optind++; - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange((char **) argv); - else if (first_nonopt == last_nonopt) - first_nonopt = optind; - last_nonopt = argc; - - optind = argc; - } - - /* If we have done all the ARGV-elements, stop the scan and back over - any non-options that we skipped and permuted. */ - - if (optind == argc) { - /* Set the next-arg-index to point at the non-options that we - previously skipped, so the caller will digest them. */ - if (first_nonopt != last_nonopt) - optind = first_nonopt; - return -1; - } - - /* If we have come to a non-option and did not permute it, either stop - the scan or describe it to the caller and pass it by. */ - - if (NONOPTION_P) { - if (ordering == REQUIRE_ORDER) - return -1; - optarg = argv[optind++]; - return 1; - } - - /* We have found another option-ARGV-element. Skip the initial - punctuation. */ - - nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); - } - - /* Decode the current option-ARGV-element. */ - - /* Check whether the ARGV-element is a long option. - - If long_only and the ARGV-element has the form "-f", where f is a valid - short option, don't consider it an abbreviated form of a long option - that starts with f. Otherwise there would be no way to give the -f - short option. - - On the other hand, if there's a long option "fubar" and the - ARGV-element is "-fu", do consider that an abbreviation of the long - option, just like "--fu", and not "-f" with arg "u". - - This distinction seems to be the most useful approach. */ - - if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] - || !my_index(optstring, argv[optind] - [1]))))) { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = -1; - int option_index; - - for (nameend = nextchar; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match or abbreviated matches. - */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp(p->name, nextchar, nameend - nextchar)) { - if ((unsigned int) (nameend - nextchar) == (unsigned int) strlen(p->name)) { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } else if (pfound == NULL) { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } else - /* Second or later nonexact match found. */ - ambig = 1; - } - - if (ambig && !exact) { - if (opterr) - fprintf(stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); - nextchar += strlen(nextchar); - optind++; - optopt = 0; - return '?'; - } - - if (pfound != NULL) { - option_index = indfound; - optind++; - if (*nameend) { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else { - if (opterr) { - if (argv[optind - 1][1] == '-') - /* --option */ - fprintf(stderr, - _ - ("%s: option `--%s' doesn't allow an argument\n"), - argv[0], pfound->name); - else - /* +option or -option */ - fprintf(stderr, - _ - ("%s: option `%c%s' doesn't allow an argument\n"), - argv[0], argv[optind - 1][0], pfound->name); - } - - nextchar += strlen(nextchar); - - optopt = pfound->val; - return '?'; - } - } else if (pfound->has_arg == 1) { - if (optind < argc) - optarg = argv[optind++]; - else { - if (opterr) - fprintf(stderr, - _ - ("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - nextchar += strlen(nextchar); - optopt = pfound->val; - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen(nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - - /* Can't find it as a long option. If this is not getopt_long_only, or - the option starts with '--' or is not a valid short option, then - it's an error. Otherwise interpret it as a short option. */ - if (!long_only || argv[optind][1] == '-' || my_index(optstring, *nextchar) == NULL) { - if (opterr) { - if (argv[optind][1] == '-') - /* --option */ - fprintf(stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); - else - /* +option or -option */ - fprintf(stderr, - _ - ("%s: unrecognized option `%c%s'\n"), - argv[0], argv[optind][0], nextchar); - } - nextchar = (char *) ""; - optind++; - optopt = 0; - return '?'; - } - } - - /* Look at and handle the next short option-character. */ - - { - char c = *nextchar++; - char *temp = my_index(optstring, c); - - /* Increment `optind' when we start to process its last character. */ - if (*nextchar == '\0') - ++optind; - - if (temp == NULL || c == ':') { - if (opterr) { - if (posixly_correct) - /* 1003.2 specifies the format of this message. */ - fprintf(stderr, _("%s: illegal option -- %c\n"), argv[0], c); - else - fprintf(stderr, _("%s: invalid option -- %c\n"), argv[0], c); - } - optopt = c; - return '?'; - } - /* Convenience. Treat POSIX -W foo same as long option --foo */ - if (temp[0] == 'W' && temp[1] == ';') { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = 0; - int option_index; - - /* This is an option that requires an argument. */ - if (*nextchar != '\0') { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, we - must advance to the next element now. */ - optind++; - } else if (optind == argc) { - if (opterr) { - /* 1003.2 specifies the format of this message. */ - fprintf(stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - return c; - } else - /* We already incremented `optind' once; increment it again when - taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - - /* optarg is now the argument, see if it's in the table of longopts. - */ - - for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match or abbreviated - matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp(p->name, nextchar, nameend - nextchar)) { - if ((unsigned int) (nameend - nextchar) == strlen(p->name)) { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } else if (pfound == NULL) { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } else - /* Second or later nonexact match found. */ - ambig = 1; - } - if (ambig && !exact) { - if (opterr) - fprintf(stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); - nextchar += strlen(nextchar); - optind++; - return '?'; - } - if (pfound != NULL) { - option_index = indfound; - if (*nameend) { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else { - if (opterr) - fprintf(stderr, _("\ -%s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); - - nextchar += strlen(nextchar); - return '?'; - } - } else if (pfound->has_arg == 1) { - if (optind < argc) - optarg = argv[optind++]; - else { - if (opterr) - fprintf(stderr, - _ - ("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - nextchar += strlen(nextchar); - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen(nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - nextchar = NULL; - return 'W'; /* Let the application handle it. - */ - } - if (temp[1] == ':') { - if (temp[2] == ':') { - /* This is an option that accepts an argument optionally. */ - if (*nextchar != '\0') { - optarg = nextchar; - optind++; - } else - optarg = NULL; - nextchar = NULL; - } else { - /* This is an option that requires an argument. */ - if (*nextchar != '\0') { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } else if (optind == argc) { - if (opterr) { - /* 1003.2 specifies the format of this message. */ - fprintf(stderr, - _("%s: option requires an argument -- %c\n"), argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - } else - /* We already incremented `optind' once; increment it again - when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - nextchar = NULL; - } - } - return c; - } -} - -int getopt(argc, argv, optstring) -int argc; -char *const *argv; -const char *optstring; -{ - return _getopt_internal(argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); -} - -#endif /* Not ELIDE_CODE. */ - -#ifdef TEST - -/* Compile with -DTEST to make an executable for use in testing - the above definition of `getopt'. */ - -int main(argc, argv) -int argc; -char **argv; -{ - int c; - int digit_optind = 0; - - while (1) { - int this_option_optind = optind ? optind : 1; - - c = getopt(argc, argv, "abc:d:0123456789"); - if (c == -1) - break; - - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf("option %c\n", c); - break; - - case 'a': - printf("option a\n"); - break; - - case 'b': - printf("option b\n"); - break; - - case 'c': - printf("option c with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) { - printf("non-option ARGV-elements: "); - while (optind < argc) - printf("%s ", argv[optind++]); - printf("\n"); - } - - exit(0); -} - -#endif /* TEST */ diff --git a/src/getopt.h b/src/getopt.h deleted file mode 100644 index 0a985b0..0000000 --- a/src/getopt.h +++ /dev/null @@ -1,130 +0,0 @@ -/* Declarations for getopt. - Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -#ifndef _GETOPT_H -#define _GETOPT_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - - extern char *optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - - extern int optind; - -/* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ - - extern int opterr; - -/* Set to an option character which was unrecognized. */ - - extern int optopt; - -/* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. - - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. - - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - - struct option { -#if defined (__STDC__) && __STDC__ - const char *name; -#else - char *name; -#endif - /* has_arg can't be an enum because some compilers complain about type - mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; - }; - -/* Names for the values of the `has_arg' field of `struct option'. */ - -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 - -#if defined (__STDC__) && __STDC__ -#ifdef __GNU_LIBRARY__ -/* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ - extern int getopt(int argc, char *const *argv, const char *shortopts); -#else /* not __GNU_LIBRARY__ */ -#ifndef __cplusplus -/* C++ is more pedantic, and demands a full prototype, not this. - Hope that stdlib.h has a prototype for `getopt'. */ - extern int getopt(); -#endif /* __cplusplus */ -#endif /* __GNU_LIBRARY__ */ - extern int getopt_long(int argc, char *const *argv, - const char *shortopts, const struct option *longopts, int *longind); - extern int getopt_long_only(int argc, char *const *argv, - const char *shortopts, const struct option *longopts, int *longind); - -/* Internal only. Users should not call this directly. */ - extern int _getopt_internal(int argc, char *const *argv, - const char *shortopts, const struct option *longopts, int *longind, int long_only); -#else /* not __STDC__ */ - extern int getopt(); - extern int getopt_long(); - extern int getopt_long_only(); - - extern int _getopt_internal(); -#endif /* __STDC__ */ - -#ifdef __cplusplus -} -#endif -#endif /* getopt.h */ diff --git a/src/getopt1.c b/src/getopt1.c deleted file mode 100644 index 5a5c483..0000000 --- a/src/getopt1.c +++ /dev/null @@ -1,173 +0,0 @@ -/* getopt_long and getopt_long_only entry points for GNU getopt. - Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#include "getopt.h" - -#if !defined (__STDC__) || !__STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -#ifndef const -#define const -#endif -#endif - -#include <stdio.h> - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#define GETOPT_INTERFACE_VERSION 2 -#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 -#include <gnu-versions.h> -#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION -#define ELIDE_CODE -#endif -#endif - -#ifndef ELIDE_CODE - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -#include <stdlib.h> -#endif - -#ifndef NULL -#define NULL 0 -#endif - -int getopt_long(argc, argv, options, long_options, opt_index) -int argc; -char *const *argv; -const char *options; -const struct option *long_options; -int *opt_index; -{ - return _getopt_internal(argc, argv, options, long_options, opt_index, 0); -} - -/* Like getopt_long, but '-' as well as '--' can indicate a long option. - If an option that starts with '-' (not '--') doesn't match a long option, - but does match a short option, it is parsed as a short option - instead. */ - -int getopt_long_only(argc, argv, options, long_options, opt_index) -int argc; -char *const *argv; -const char *options; -const struct option *long_options; -int *opt_index; -{ - return _getopt_internal(argc, argv, options, long_options, opt_index, 1); -} - -#endif /* Not ELIDE_CODE. */ - -#ifdef TEST - -#include <stdio.h> - -int main(argc, argv) -int argc; -char **argv; -{ - int c; - int digit_optind = 0; - - while (1) { - int this_option_optind = optind ? optind : 1; - int option_index = 0; - static struct option long_options[] = { - {"add", 1, 0, 0}, - {"append", 0, 0, 0}, - {"delete", 1, 0, 0}, - {"verbose", 0, 0, 0}, - {"create", 0, 0, 0}, - {"file", 1, 0, 0}, - {0, 0, 0, 0} - }; - - c = getopt_long(argc, argv, "abc:d:0123456789", long_options, &option_index); - if (c == -1) - break; - - switch (c) { - case 0: - printf("option %s", long_options[option_index].name); - if (optarg) - printf(" with arg %s", optarg); - printf("\n"); - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf("option %c\n", c); - break; - - case 'a': - printf("option a\n"); - break; - - case 'b': - printf("option b\n"); - break; - - case 'c': - printf("option c with value `%s'\n", optarg); - break; - - case 'd': - printf("option d with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) { - printf("non-option ARGV-elements: "); - while (optind < argc) - printf("%s ", argv[optind++]); - printf("\n"); - } - - exit(0); -} - -#endif /* TEST */ diff --git a/src/gib_hash.c b/src/gib_hash.c index 0d6a226..9497d04 100644 --- a/src/gib_hash.c +++ b/src/gib_hash.c @@ -53,7 +53,7 @@ void gib_hash_node_free_and_data(gib_hash_node *node) return; } -gib_hash *gib_hash_new() +gib_hash *gib_hash_new(void) { gib_hash *hash = emalloc(sizeof(gib_hash)); hash->base = gib_hash_node_new("__gib_hash_new",NULL); @@ -89,7 +89,7 @@ static unsigned char gib_hash_find_callback(gib_list *list, void *data) gib_hash_node *node = GIB_HASH_NODE(list); char *key = (char*) data; - /* strncasecmp causes simliar keys like key1 and key11 clobber eachother */ + /* strncasecmp causes similar keys like key1 and key11 clobber each other */ return !strcasecmp(node->key, key); } diff --git a/src/gib_hash.h b/src/gib_hash.h index 58506c8..125e280 100644 --- a/src/gib_hash.h +++ b/src/gib_hash.h @@ -55,7 +55,7 @@ gib_hash_node *gib_hash_node_new(char *key, void *data); void gib_hash_node_free(gib_hash_node *node); void gib_hash_node_free_and_data(gib_hash_node *node); -gib_hash *gib_hash_new(); +gib_hash *gib_hash_new(void); void gib_hash_free(gib_hash *hash); void gib_hash_free_and_data(gib_hash *hash); diff --git a/src/gib_imlib.c b/src/gib_imlib.c index 7858cb7..39d0081 100644 --- a/src/gib_imlib.c +++ b/src/gib_imlib.c @@ -27,6 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "utils.h" #include "debug.h" +/* int gib_imlib_load_image(Imlib_Image * im, char *filename) { @@ -38,7 +39,6 @@ gib_imlib_load_image(Imlib_Image * im, char *filename) *im = imlib_load_image_with_error_return(filename, &err); if ((err) || (!im)) { - /* Check error code */ switch (err) { case IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST: @@ -91,6 +91,7 @@ gib_imlib_load_image(Imlib_Image * im, char *filename) } return (1); } +*/ int gib_imlib_image_get_width(Imlib_Image im) @@ -322,7 +323,7 @@ gib_imlib_text_draw(Imlib_Image im, Imlib_Font fn, gib_style * s, int x, gib_style_bit *bb; gib_list *l; - /* here we shift the draw to accomodate bits with negative offsets, + /* here we shift the draw to accommodate bits with negative offsets, * which would be drawn at negative coords otherwise */ l = s->bits; while (l) diff --git a/src/gib_imlib.h b/src/gib_imlib.h index 07daabe..6a35e7e 100644 --- a/src/gib_imlib.h +++ b/src/gib_imlib.h @@ -47,7 +47,9 @@ extern "C" { #endif +/* int gib_imlib_load_image(Imlib_Image * im, char *filename); +*/ int gib_imlib_image_get_width(Imlib_Image im); int gib_imlib_image_get_height(Imlib_Image im); int gib_imlib_image_has_alpha(Imlib_Image im); diff --git a/src/gib_list.c b/src/gib_list.c index a8ba1dd..e7710bc 100644 --- a/src/gib_list.c +++ b/src/gib_list.c @@ -520,7 +520,7 @@ gib_list_find(gib_list *root, unsigned char (*find_func)(gib_list *node, void *d for (i=root; i; i=i->next) if (find_func(i,data)) return i; - + return NULL; } diff --git a/src/help.raw b/src/help.raw index e0fb62a..e218e78 100644 --- a/src/help.raw +++ b/src/help.raw @@ -29,6 +29,8 @@ OPTIONS mode or when window geometry is fixed. If combined with --auto-zoom, zooming will be limited to the the size. Also support \"max\" and \"fill\" + --zoom-step PERCENT Zoom images in and out by PERCENT (default: 25) + when using the zoom keys / buttons --keep-zoom-vp Keep viewport zoom and settings while changing images -w, --multiwindow Open all files at once, one window per image -x, --borderless Create borderless windows @@ -39,7 +41,7 @@ OPTIONS --auto-rotate Rotate images according to Exif info (if compiled with exif=1) -^, --title TITLE Set window title (see FORMAT SPECIFIERS) -D, --slideshow-delay NUM Set delay between automatically changing slides - --on-last-slide quit Exit after one loop through the slide show + --on-last-slide quit Exit after one loop through the slide show (old --cycle-once) --on-last-slide hold Stop at both ends of the filelist -R, --reload NUM Reload images after NUM seconds -k, --keep-http Keep local copies when viewing HTTP/FTP files @@ -100,6 +102,7 @@ OPTIONS --scroll-step COUNT scroll COUNT pixels when movement key is pressed --cache-size NUM imlib cache size in mebibytes (0 .. 2048) --auto-reload automatically reload shown image if file was changed + --window-id ID Draw to an existing X11 window by its ID MONTAGE MODE OPTIONS -X, --ignore-aspect Set thumbnail to specified width/height without @@ -201,7 +204,7 @@ DEFAULT KEYS This program is free software, see the file COPYING for licensing info. Copyright Tom Gilbert (and various contributors) 1999-2003. -Copyright Daniel Friesel (and various contributors) 2010-2020. +Copyright Birte Kristina Friesel (and various contributors) 2010-2020. Homepage: http://feh.finalrewind.org Report bugs to <derf+feh@finalrewind.org> or #feh on irc.oftc.net. diff --git a/src/imlib.c b/src/imlib.c index 4e8e790..143807d 100644 --- a/src/imlib.c +++ b/src/imlib.c @@ -1,7 +1,7 @@ /* imlib.c Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -44,6 +44,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "exif.h" #endif +#ifdef HAVE_LIBMAGIC +#include <magic.h> + +magic_t magic = NULL; +#endif + Display *disp = NULL; Visual *vis = NULL; Screen *scr = NULL; @@ -164,11 +170,31 @@ int feh_load_image_char(Imlib_Image * im, char *filename) return(i); } -void feh_imlib_print_load_error(char *file, winwidget w, Imlib_Load_Error err) +void feh_print_load_error(char *file, winwidget w, Imlib_Load_Error err, enum feh_load_error feh_err) { if (err == IMLIB_LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS) eprintf("%s - Out of file descriptors while loading", file); else if (!opt.quiet || w) { + switch (feh_err) { + case LOAD_ERROR_IMLIB: + // handled in the next switch/case statement + break; + case LOAD_ERROR_IMAGEMAGICK: + im_weprintf(w, "%s - No ImageMagick loader for that file format", file); + break; + case LOAD_ERROR_CURL: + im_weprintf(w, "%s - libcurl was unable to retrieve the file", file); + break; + case LOAD_ERROR_DCRAW: + im_weprintf(w, "%s - Unable to open preview via dcraw", file); + break; + case LOAD_ERROR_MAGICBYTES: + im_weprintf(w, "%s - Does not look like an image (magic bytes missing)", file); + break; + } + if (feh_err != LOAD_ERROR_IMLIB) { + return; + } switch (err) { case IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST: im_weprintf(w, "%s - File does not exist", file); @@ -181,11 +207,7 @@ void feh_imlib_print_load_error(char *file, winwidget w, Imlib_Load_Error err) break; case IMLIB_LOAD_ERROR_UNKNOWN: case IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT: - if (getenv("FEH_SKIP_MAGIC")) { - im_weprintf(w, "%s - No Imlib2 loader for that file format", file); - } else { - im_weprintf(w, "%s - Does not look like an image (magic bytes missing)", file); - } + im_weprintf(w, "%s - No Imlib2 loader for that file format", file); break; case IMLIB_LOAD_ERROR_PATH_TOO_LONG: im_weprintf(w, "%s - Path specified is too long", file); @@ -211,6 +233,14 @@ void feh_imlib_print_load_error(char *file, winwidget w, Imlib_Load_Error err) case IMLIB_LOAD_ERROR_OUT_OF_DISK_SPACE: im_weprintf(w, "%s - Cannot write - out of disk space", file); break; +#if defined(IMLIB2_VERSION_MAJOR) && defined(IMLIB2_VERSION_MINOR) && (IMLIB2_VERSION_MAJOR > 1 || IMLIB2_VERSION_MINOR > 7) + case IMLIB_LOAD_ERROR_IMAGE_READ: + im_weprintf(w, "%s - Invalid image file", file); + break; + case IMLIB_LOAD_ERROR_IMAGE_FRAME: + im_weprintf(w, "%s - Requested frame not in image", file); + break; +#endif default: im_weprintf(w, "While loading %s - Unknown error (%d)", file, err); @@ -219,6 +249,33 @@ void feh_imlib_print_load_error(char *file, winwidget w, Imlib_Load_Error err) } } +#ifdef HAVE_LIBMAGIC +void uninit_magic(void) +{ + if (!magic) { + return; + } + + magic_close(magic); + magic = NULL; +} +void init_magic(void) +{ + if (getenv("FEH_SKIP_MAGIC")) { + return; + } + + if (!(magic = magic_open(MAGIC_NONE))) { + weprintf("unable to initialize magic library\n"); + return; + } + + if (magic_load(magic, NULL) != 0) { + weprintf("cannot load magic database: %s\n", magic_error(magic)); + uninit_magic(); + } +} + /* * This is a workaround for an Imlib2 regression, causing unloadable image * detection to be excessively slow (and, thus, causing feh to hang for a while @@ -226,90 +283,53 @@ void feh_imlib_print_load_error(char *file, winwidget w, Imlib_Load_Error err) * avoid calling Imlib2 for files it probably cannot handle. See * <https://phab.enlightenment.org/T8739> and * <https://github.com/derf/feh/issues/505>. - * - * Note that this drops support for bz2-compressed files, unless - * FEH_SKIP_MAGIC is set */ -int feh_is_image(feh_file * file) +int feh_is_image(feh_file * file, int magic_flags) { - unsigned char buf[16]; - FILE *fh = fopen(file->filename, "r"); - if (!fh) { - return 0; - } - if (fread(buf, 1, 16, fh) != 16) { - return 0; - } - fclose(fh); + const char * mime_type = NULL; - if (buf[0] == 0xff && buf[1] == 0xd8) { - // JPEG - return 1; - } - if (!memcmp(buf, "\x89PNG\x0d\x0a\x1a\x0a", 8)) { - // PNG - return 1; - } - if (buf[0] == 'A' && buf[1] == 'R' && buf[2] == 'G' && buf[3] == 'B') { - // ARGB - return 1; - } - if (buf[0] == 'B' && buf[1] == 'M') { - // BMP - return 1; - } - if (!memcmp(buf, "farbfeld", 8)) { - // farbfeld - return 1; - } - if (buf[0] == 'G' && buf[1] == 'I' && buf[2] == 'F') { - // GIF + if (!magic) { return 1; } - if (buf[0] == 0x00 && buf[1] == 0x00 && buf[2] <= 0x02 && buf[3] == 0x00) { - // ICO - return 1; - } - if (!memcmp(buf, "FORM", 4)) { - // Amiga IFF ILBM - return 1; - } - if (buf[0] == 'P' && buf[1] >= '1' && buf[1] <= '7') { - // PNM et al. - return 1; - } - if (strstr(file->filename, ".tga")) { - // TGA - return 1; - } - if (!memcmp(buf, "II\x2a\x00", 4) || !memcmp(buf, "MM\x00\x2a", 4)) { - // TIFF - return 1; - } - if (!memcmp(buf, "RIFF", 4)) { - // might be webp - return 1; + + magic_setflags(magic, MAGIC_MIME_TYPE | MAGIC_SYMLINK | magic_flags); + mime_type = magic_file(magic, file->filename); + + if (!mime_type) { + return 0; } - buf[15] = 0; - if (strstr((char *)buf, "XPM")) { - // XPM + + D(("file %s has mime type: %s\n", file->filename, mime_type)); + + if (strncmp(mime_type, "image/", 6) == 0) { return 1; } - if (strstr(file->filename, ".bz2") || strstr(file->filename, ".gz")) { - // Imlib2 supports compressed images. It relies on the filename to - // determine the appropriate loader and does not use magic bytes here. - return 1; + + /* no infinite loop on compressed content, please */ + if (magic_flags) { + return 0; } - // moved to the end as this variable won't be set in most cases - if (getenv("FEH_SKIP_MAGIC")) { - return 1; + + /* imlib2 supports loading compressed images, let's have a look inside */ + if (strcmp(mime_type, "application/gzip") == 0 || + strcmp(mime_type, "application/x-bzip2") == 0 || + strcmp(mime_type, "application/x-xz") == 0) { + return feh_is_image(file, MAGIC_COMPRESS); } + return 0; } +#else +int feh_is_image(__attribute__((unused)) feh_file * file, __attribute__((unused)) int magic_flags) +{ + return 1; +} +#endif int feh_load_image(Imlib_Image * im, feh_file * file) { Imlib_Load_Error err = IMLIB_LOAD_ERROR_NONE; + enum feh_load_error feh_err = LOAD_ERROR_IMLIB; enum { SRC_IMLIB, SRC_HTTP, SRC_MAGICK, SRC_DCRAW } image_source = SRC_IMLIB; char *tmpname = NULL; char *real_filename = NULL; @@ -322,19 +342,16 @@ int feh_load_image(Imlib_Image * im, feh_file * file) if (path_is_url(file->filename)) { image_source = SRC_HTTP; - if ((tmpname = feh_http_load_image(file->filename)) == NULL) + if ((tmpname = feh_http_load_image(file->filename)) == NULL) { + feh_err = LOAD_ERROR_CURL; err = IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST; - } - else if (opt.conversion_timeout >= 0 && feh_file_is_raw(file->filename)) { - image_source = SRC_DCRAW; - tmpname = feh_dcraw_load_image(file->filename); - if (!tmpname) - err = IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT; + } } else { - if (feh_is_image(file)) { + if (feh_is_image(file, 0)) { *im = imlib_load_image_with_error_return(file->filename, &err); } else { + feh_err = LOAD_ERROR_MAGICBYTES; err = IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT; } } @@ -342,8 +359,20 @@ int feh_load_image(Imlib_Image * im, feh_file * file) if (opt.conversion_timeout >= 0 && ( (err == IMLIB_LOAD_ERROR_UNKNOWN) || (err == IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT))) { - image_source = SRC_MAGICK; - tmpname = feh_magick_load_image(file->filename); + if (feh_file_is_raw(file->filename)) { + image_source = SRC_DCRAW; + tmpname = feh_dcraw_load_image(file->filename); + if (!tmpname) { + feh_err = LOAD_ERROR_DCRAW; + } + } else { + image_source = SRC_MAGICK; + feh_err = LOAD_ERROR_IMLIB; + tmpname = feh_magick_load_image(file->filename); + if (!tmpname) { + feh_err = LOAD_ERROR_IMAGEMAGICK; + } + } } if (tmpname) { @@ -366,7 +395,14 @@ int feh_load_image(Imlib_Image * im, feh_file * file) file->filename = real_filename; #ifdef HAVE_LIBEXIF - file->ed = exif_get_data(tmpname); + /* + * if we're called from within feh_reload_image, file->ed is already + * populated. + */ + if (file->ed) { + exif_data_unref(file->ed); + } + file->ed = exif_data_new_from_file(tmpname); #endif } if (!opt.use_conversion_cache && ((image_source != SRC_HTTP) || !opt.keep_http)) @@ -376,8 +412,19 @@ int feh_load_image(Imlib_Image * im, feh_file * file) // add_file_to_rm_filelist duplicates tmpname add_file_to_rm_filelist(tmpname); - if (image_source != SRC_HTTP && !opt.use_conversion_cache) + if (!opt.use_conversion_cache) free(tmpname); + } else if (im) { +#ifdef HAVE_LIBEXIF + /* + * if we're called from within feh_reload_image, file->ed is already + * populated. + */ + if (file->ed) { + exif_data_unref(file->ed); + } + file->ed = exif_data_new_from_file(file->filename); +#endif } if ((err) || (!im)) { @@ -385,7 +432,7 @@ int feh_load_image(Imlib_Image * im, feh_file * file) fputs("\n", stderr); reset_output = 1; } - feh_imlib_print_load_error(file->filename, NULL, err); + feh_print_load_error(file->filename, NULL, err, feh_err); D(("Load *failed*\n")); return(0); } @@ -402,14 +449,13 @@ int feh_load_image(Imlib_Image * im, feh_file * file) #ifdef HAVE_LIBEXIF int orientation = 0; - ExifData *exifData = exif_data_new_from_file(file->filename); - if (exifData) { - ExifByteOrder byteOrder = exif_data_get_byte_order(exifData); - ExifEntry *exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION); - if (exifEntry && opt.auto_rotate) + if (file->ed) { + ExifByteOrder byteOrder = exif_data_get_byte_order(file->ed); + ExifEntry *exifEntry = exif_data_get_entry(file->ed, EXIF_TAG_ORIENTATION); + if (exifEntry && opt.auto_rotate) { orientation = exif_get_short(exifEntry->data, byteOrder); + } } - file->ed = exifData; if (orientation == 2) gib_imlib_image_flip_horizontal(*im); @@ -527,11 +573,9 @@ static int feh_file_is_raw(char *filename) } if (childpid == 0) { - if (opt.quiet) { - int devnull = open("/dev/null", O_WRONLY); - dup2(devnull, 1); - dup2(devnull, 2); - } + int devnull = open("/dev/null", O_WRONLY); + dup2(devnull, 1); + dup2(devnull, 2); execlp("dcraw", "dcraw", "-i", filename, NULL); _exit(1); } else { @@ -591,9 +635,7 @@ static char *feh_dcraw_load_image(char *filename) close(fd); return NULL; } else if (childpid == 0) { - - close(1); - dup(fd); + dup2(fd, STDOUT_FILENO); close(fd); alarm(opt.conversion_timeout); @@ -818,15 +860,32 @@ static char *feh_http_load_image(char *url) } basename = strrchr(url, '/') + 1; - tmpname = feh_unique_filename(path, basename); - if (strlen(tmpname) > (NAME_MAX-6)) - tmpname[NAME_MAX-7] = '\0'; +#ifdef HAVE_MKSTEMPS + tmpname = estrjoin("_", "feh_curl_XXXXXX", basename, NULL); - sfn = estrjoin("_", tmpname, "XXXXXX", NULL); + if (strlen(tmpname) > NAME_MAX) { + tmpname[NAME_MAX] = '\0'; + } +#else + if (strlen(basename) > NAME_MAX-7) { + tmpname = estrdup("feh_curl_XXXXXX"); + } else { + tmpname = estrjoin("_", "feh_curl", basename, "XXXXXX", NULL); + } +#endif + + sfn = estrjoin("", path, tmpname, NULL); free(tmpname); + D(("sfn is %s\n", sfn)) + +#ifdef HAVE_MKSTEMPS + fd = mkstemps(sfn, strlen(basename) + 1); +#else fd = mkstemp(sfn); +#endif + if (fd != -1) { sfp = fdopen(fd, "w+"); if (sfp != NULL) { @@ -835,8 +894,8 @@ static char *feh_http_load_image(char *url) #endif /* * Do not allow requests to take longer than 30 minutes. - * This should be sufficiently high to accomodate use cases with - * unusually high latencies, while at the sime time avoiding + * This should be sufficiently high to accommodate use cases with + * unusually high latencies, while at the same time avoiding * feh hanging indefinitely in unattended slideshows. */ curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1800); @@ -844,6 +903,7 @@ static char *feh_http_load_image(char *url) curl_easy_setopt(curl, CURLOPT_WRITEDATA, sfp); ebuff = emalloc(CURL_ERROR_SIZE); curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, ebuff); + curl_easy_setopt(curl, CURLOPT_USERAGENT, PACKAGE "/" VERSION); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); #if LIBCURL_VERSION_NUM >= 0x072000 /* 07.32.0 */ @@ -885,7 +945,11 @@ static char *feh_http_load_image(char *url) close(fd); } } else { +#ifdef HAVE_MKSTEMPS + weprintf("open url: mkstemps failed:"); +#else weprintf("open url: mkstemp failed:"); +#endif free(sfn); } curl_easy_cleanup(curl); @@ -1115,7 +1179,7 @@ void feh_draw_exif(winwidget w) if (buffer[0] == '\0') { - snprintf(buffer, EXIF_MAX_DATA, "%s", estrdup("Failed to run exif command")); + snprintf(buffer, EXIF_MAX_DATA, "%s", "Failed to run exif command"); gib_imlib_get_text_size(fn, buffer, NULL, &width, &height, IMLIB_TEXT_TO_RIGHT); info_buf[no_lines] = estrdup(buffer); no_lines++; @@ -1127,29 +1191,28 @@ void feh_draw_exif(winwidget w) { /* max 128 lines */ pos2 = 0; - while ( pos2 < 256 ) /* max 256 chars per line */ + while ( pos2 < 255 ) /* max 255 chars + 1 null byte per line */ { if ( (buffer[pos] != '\n') && (buffer[pos] != '\0') ) { - info_line[pos2] = buffer[pos]; - } - else if ( buffer[pos] == '\0' ) - { - pos = EXIF_MAX_DATA; /* all data seen */ - info_line[pos2] = '\0'; + info_line[pos2] = buffer[pos]; + } + else if ( buffer[pos] == '\0' ) + { + pos = EXIF_MAX_DATA; /* all data seen */ + break; + } + else + { + pos++; /* line finished, continue with next line*/ + break; } - else - { - info_line[pos2] = '\0'; /* line finished, continue with next line*/ - - pos++; - break; - } - pos++; - pos2++; + pos++; + pos2++; } + info_line[pos2] = '\0'; gib_imlib_get_text_size(fn, info_line, NULL, &line_width, &line_height, IMLIB_TEXT_TO_RIGHT); @@ -1184,6 +1247,7 @@ void feh_draw_exif(winwidget w) info_buf[i], IMLIB_TEXT_TO_RIGHT, 0, 0, 0, 255); gib_imlib_text_draw(im, fn, NULL, 1, (i * line_height) + 1, info_buf[i], IMLIB_TEXT_TO_RIGHT, 255, 255, 255, 255); + free(info_buf[i]); } @@ -1514,8 +1578,8 @@ void feh_edit_inplace(winwidget w, int op) FEH_FILE(w->file->data)->filename, &err); gib_imlib_free_image(old); if (err) - feh_imlib_print_load_error(FEH_FILE(w->file->data)->filename, - w, err); + feh_print_load_error(FEH_FILE(w->file->data)->filename, + w, err, LOAD_ERROR_IMLIB); feh_reload_image(w, 1, 1); } else { /* diff --git a/src/index.c b/src/index.c index 3633c96..b0b6923 100644 --- a/src/index.c +++ b/src/index.c @@ -1,7 +1,7 @@ /* index.c Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -131,7 +131,7 @@ void init_index_mode(void) weprintf( "The image size you specified (%dx%d) is not large\n" "enough to hold all %d thumbnails. To fit all the thumbnails,\n" - "either decrease their size, choos e asmaller font,\n" + "either decrease their size, choose a smaller font,\n" "or use a larger image (like %dx%d)", opt.limit_w, opt.limit_h, filelist_len, w, h); h = opt.limit_h; @@ -332,7 +332,7 @@ void init_index_mode(void) gib_imlib_save_image_with_error_return(im_main, output_buf, &err); if (err) { - feh_imlib_print_load_error(output_buf, im_main, err); + feh_print_load_error(output_buf, im_main, err, LOAD_ERROR_IMLIB); } else if (opt.verbose) { int tw, th; diff --git a/src/index.h b/src/index.h index b022f1a..b805cc0 100644 --- a/src/index.h +++ b/src/index.h @@ -1,6 +1,6 @@ /* index.h -Copyright (C) 2018 Daniel Friesel. +Copyright (C) 2018 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to diff --git a/src/keyevents.c b/src/keyevents.c index a5526a2..2f9b1d6 100644 --- a/src/keyevents.c +++ b/src/keyevents.c @@ -1,7 +1,7 @@ /* keyevents.c Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -35,7 +35,7 @@ struct __fehkey keys[EVENT_LIST_END]; struct termios old_term_settings; unsigned char control_via_stdin = 0; -void setup_stdin() { +void setup_stdin(void) { struct termios ctrl; control_via_stdin = 1; @@ -55,7 +55,7 @@ void setup_stdin() { eprintf("tcsetattr failed"); } -void restore_stdin() { +void restore_stdin(void) { if (tcsetattr(STDIN_FILENO, TCSANOW, &old_term_settings) == -1) eprintf("tcsetattr failed"); } @@ -314,12 +314,12 @@ void feh_event_invoke_action(winwidget winwid, unsigned char action) return; } -void feh_event_handle_stdin() +void feh_event_handle_stdin(void) { char stdin_buf[2]; static char is_esc = 0; KeySym keysym = NoSymbol; - if (read(STDIN_FILENO, &stdin_buf, 1) == -1) { + if (read(STDIN_FILENO, &stdin_buf, 1) <= 0) { control_via_stdin = 0; if (isatty(STDIN_FILENO) && getpgrp() == (tcgetpgrp(STDIN_FILENO))) { weprintf("reading a command from stdin failed - disabling control via stdin"); @@ -359,7 +359,7 @@ void feh_event_handle_stdin() else keysym = XStringToKeysym(stdin_buf); - if (window_num) + if (window_num && keysym) feh_event_handle_generic(windows[0], is_esc * Mod1Mask, keysym, 0); is_esc = 0; @@ -603,7 +603,7 @@ void feh_event_handle_generic(winwidget winwid, unsigned int state, KeySym keysy } else if (feh_is_kp(EVENT_zoom_in, state, keysym, button)) { winwid->old_zoom = winwid->zoom; - winwid->zoom = winwid->zoom * 1.25; + winwid->zoom = winwid->zoom * opt.zoom_rate; if (winwid->zoom > ZOOM_MAX) winwid->zoom = ZOOM_MAX; @@ -617,7 +617,7 @@ void feh_event_handle_generic(winwidget winwid, unsigned int state, KeySym keysy } else if (feh_is_kp(EVENT_zoom_out, state, keysym, button)) { winwid->old_zoom = winwid->zoom; - winwid->zoom = winwid->zoom * 0.80; + winwid->zoom = winwid->zoom / opt.zoom_rate; if (winwid->zoom < ZOOM_MIN) winwid->zoom = ZOOM_MIN; @@ -1,7 +1,7 @@ /* list.c Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -1,7 +1,7 @@ /* main.c Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -49,6 +49,11 @@ int main(int argc, char **argv) srandom(getpid() * time(NULL) % ((unsigned int) -1)); setup_signal_handlers(); + +#ifdef HAVE_LIBMAGIC + init_magic(); +#endif + init_parse_options(argc, argv); init_imlib_fonts(); @@ -102,6 +107,28 @@ int main(int argc, char **argv) return(sig_exit); } +static void feh_process_signal(void) +{ + winwidget winwid = winwidget_get_first_window_of_type(WIN_TYPE_SLIDESHOW); + int i; + int signo = sig_received; + sig_received = 0; + + if (winwid) { + if (filelist_len > 1) { + if (signo == SIGUSR1) + slideshow_change_image(winwid, SLIDE_NEXT, 1); + else if (signo == SIGUSR2) + slideshow_change_image(winwid, SLIDE_PREV, 1); + } else { + feh_reload_image(winwid, 0, 0); + } + } else if (opt.multiwindow) { + for (i = window_num - 1; i >= 0; i--) + feh_reload_image(windows[i], 0, 0); + } +} + /* Return 0 to stop iterating, 1 if ok to continue. */ int feh_main_iteration(int block) { @@ -119,6 +146,10 @@ int feh_main_iteration(int block) if (window_num == 0 || sig_exit != 0) return(0); + if (sig_received) { + feh_process_signal(); + } + if (first) { /* Only need to set these up the first time */ xfd = ConnectionNumber(disp); @@ -151,6 +182,10 @@ int feh_main_iteration(int block) if (window_num == 0 || sig_exit != 0) return(0); + + if (sig_received) { + feh_process_signal(); + } } XFlush(disp); @@ -158,8 +193,9 @@ int feh_main_iteration(int block) FD_ZERO(&fdset); FD_SET(xfd, &fdset); - if (control_via_stdin) + if (control_via_stdin) { FD_SET(STDIN_FILENO, &fdset); + } #ifdef HAVE_INOTIFY if (opt.auto_reload) { FD_SET(opt.inotify_fd, &fdset); @@ -210,7 +246,12 @@ int feh_main_iteration(int block) in that */ feh_handle_timer(); } - else if ((count > 0) && (FD_ISSET(0, &fdset))) + /* + * Beware: If stdin is not connected, we may end up with xfd == 0. + * However, STDIN_FILENO == 0 holds as well in most cases. So we must + * check control_via_stdin to avoid mistaking an X11 event for stdin. + */ + else if ((count > 0) && control_via_stdin && (FD_ISSET(STDIN_FILENO, &fdset))) feh_event_handle_stdin(); #ifdef HAVE_INOTIFY else if ((count > 0) && (FD_ISSET(opt.inotify_fd, &fdset))) @@ -227,7 +268,7 @@ int feh_main_iteration(int block) && ((errno == ENOMEM) || (errno == EINVAL) || (errno == EBADF))) eprintf("Connection to X display lost"); - else if ((count > 0) && (FD_ISSET(0, &fdset))) + else if ((count > 0) && control_via_stdin && (FD_ISSET(STDIN_FILENO, &fdset))) feh_event_handle_stdin(); #ifdef HAVE_INOTIFY else if ((count > 0) && (FD_ISSET(opt.inotify_fd, &fdset))) @@ -237,7 +278,11 @@ int feh_main_iteration(int block) } if (window_num == 0 || sig_exit != 0) return(0); - + + if (sig_received) { + feh_process_signal(); + } + return(1); } @@ -256,6 +301,10 @@ void feh_clean_exit(void) if(disp) XCloseDisplay(disp); +#ifdef HAVE_LIBMAGIC + uninit_magic(); +#endif + /* * Only restore the old terminal settings if * - we changed them in the first place @@ -1,7 +1,7 @@ /* menu.c Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -825,21 +825,17 @@ void feh_menu_draw_toggle_at(int x, int y, int w, int h, Imlib_Image dst, int ox void feh_menu_draw_submenu_at(int x, int y, Imlib_Image dst, int ox, int oy) { - ImlibPolygon poly; - - x -= ox; + // Draw filled triangle + x -= ox; y -= oy; imlib_context_set_image(dst); - - poly = imlib_polygon_new(); - imlib_polygon_add_point(poly, x, y + 3); - imlib_polygon_add_point(poly, x + 3, y + 6); - imlib_polygon_add_point(poly, x, y + 9); imlib_context_set_color(0, 0, 0, 255); - imlib_image_fill_polygon(poly); - imlib_polygon_free(poly); + for (int i= 0; i <= 3; i++) { + imlib_image_draw_line(x+i, y+3+i, x+i, y+9-i, 0); + } + return; } @@ -936,7 +932,7 @@ void feh_menu_init_main(void) return; } -void feh_menu_init_common() +void feh_menu_init_common(void) { int num_desks, i; char buf[30]; @@ -1,7 +1,7 @@ /* menu.h Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to diff --git a/src/options.c b/src/options.c index 04f02c5..0fc656d 100644 --- a/src/options.c +++ b/src/options.c @@ -1,7 +1,7 @@ /* options.c Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -63,6 +63,8 @@ void init_parse_options(int argc, char **argv) opt.font = NULL; opt.max_height = opt.max_width = UINT_MAX; + opt.zoom_rate = 1.25; + opt.start_list_at = NULL; opt.jump_on_resort = 1; @@ -330,109 +332,111 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) /* (*name, has_arg, *flag, val) See: struct option in getopts.h */ static struct option lopts[] = { - {"debug" , 0, 0, '+'}, - {"scale-down" , 0, 0, '.'}, - {"max-dimension" , 1, 0, '<'}, - {"min-dimension" , 1, 0, '>'}, - {"title-font" , 1, 0, '@'}, - {"action" , 1, 0, 'A'}, - {"image-bg" , 1, 0, 'B'}, - {"fontpath" , 1, 0, 'C'}, - {"slideshow-delay",1, 0, 'D'}, - {"thumb-height" , 1, 0, 'E'}, - {"full-screen" , 0, 0, 'F'}, /* deprecated */ - {"fullscreen" , 0, 0, 'F'}, - {"draw-actions" , 0, 0, 'G'}, - {"limit-height" , 1, 0, 'H'}, - {"fullindex" , 0, 0, 'I'}, - {"thumb-redraw" , 1, 0, 'J'}, - {"caption-path" , 1, 0, 'K'}, - {"customlist" , 1, 0, 'L'}, - {"menu-font" , 1, 0, 'M'}, - {"no-menus" , 0, 0, 'N'}, - {"output-only" , 1, 0, 'O'}, - {"cache-thumbnails", 0, 0, 'P'}, - {"reload" , 1, 0, 'R'}, - {"sort" , 1, 0, 'S'}, - {"theme" , 1, 0, 'T'}, - {"loadable" , 0, 0, 'U'}, - {"verbose" , 0, 0, 'V'}, - {"limit-width" , 1, 0, 'W'}, - {"ignore-aspect" , 0, 0, 'X'}, - {"hide-pointer" , 0, 0, 'Y'}, - {"auto-zoom" , 0, 0, 'Z'}, - {"title" , 1, 0, '^'}, - {"alpha" , 1, 0, 'a'}, - {"bg" , 1, 0, 'b'}, - {"draw-filename" , 0, 0, 'd'}, - {"font" , 1, 0, 'e'}, - {"filelist" , 1, 0, 'f'}, - {"geometry" , 1, 0, 'g'}, - {"help" , 0, 0, 'h'}, - {"index" , 0, 0, 'i'}, - {"output-dir" , 1, 0, 'j'}, - {"keep-http" , 0, 0, 'k'}, - {"list" , 0, 0, 'l'}, - {"montage" , 0, 0, 'm'}, - {"reverse" , 0, 0, 'n'}, - {"output" , 1, 0, 'o'}, - {"preload" , 0, 0, 'p'}, - {"quiet" , 0, 0, 'q'}, - {"recursive" , 0, 0, 'r'}, - {"stretch" , 0, 0, 's'}, - {"thumbnails" , 0, 0, 't'}, - {"unloadable" , 0, 0, 'u'}, - {"version" , 0, 0, 'v'}, - {"multiwindow" , 0, 0, 'w'}, - {"borderless" , 0, 0, 'x'}, - {"thumb-width" , 1, 0, 'y'}, - {"randomize" , 0, 0, 'z'}, - {"start-at" , 1, 0, '|'}, - {"thumb-title" , 1, 0, '~'}, - {"bg-tile" , 0, 0, 200}, - {"bg-center" , 0, 0, 201}, - {"bg-scale" , 0, 0, 202}, - {"zoom" , 1, 0, 205}, - {"no-screen-clip", 0, 0, 206}, - {"index-info" , 1, 0, 207}, - {"magick-timeout", 1, 0, 208}, - {"action1" , 1, 0, 209}, - {"action2" , 1, 0, 210}, - {"action3" , 1, 0, 211}, - {"action4" , 1, 0, 212}, - {"action5" , 1, 0, 213}, - {"action6" , 1, 0, 214}, - {"action7" , 1, 0, 215}, - {"action8" , 1, 0, 216}, - {"action9" , 1, 0, 217}, - {"bg-fill" , 0, 0, 218}, - {"bg-max" , 0, 0, 219}, - {"no-jump-on-resort", 0, 0, 220}, - {"edit" , 0, 0, 221}, + {"debug" , 0, 0, OPTION_debug}, + {"scale-down" , 0, 0, OPTION_scale_down}, + {"max-dimension" , 1, 0, OPTION_max_dimension}, + {"min-dimension" , 1, 0, OPTION_min_dimension}, + {"title-font" , 1, 0, OPTION_title_font}, + {"action" , 1, 0, OPTION_action}, + {"image-bg" , 1, 0, OPTION_image_bg}, + {"fontpath" , 1, 0, OPTION_fontpath}, + {"slideshow-delay",1, 0, OPTION_slideshow_delay}, + {"thumb-height" , 1, 0, OPTION_thumb_height}, + {"full-screen" , 0, 0, OPTION_fullscreen}, /* deprecated */ + {"fullscreen" , 0, 0, OPTION_fullscreen}, + {"draw-actions" , 0, 0, OPTION_draw_actions}, + {"limit-height" , 1, 0, OPTION_limit_height}, + {"fullindex" , 0, 0, OPTION_fullindex}, + {"thumb-redraw" , 1, 0, OPTION_thumb_redraw}, + {"caption-path" , 1, 0, OPTION_caption_path}, + {"customlist" , 1, 0, OPTION_customlist}, + {"menu-font" , 1, 0, OPTION_menu_font}, + {"no-menus" , 0, 0, OPTION_no_menus}, + {"output-only" , 1, 0, OPTION_output_only}, + {"cache-thumbnails", 0, 0, OPTION_cache_thumbnails}, + {"reload" , 1, 0, OPTION_reload}, + {"sort" , 1, 0, OPTION_sort}, + {"theme" , 1, 0, OPTION_theme}, + {"loadable" , 0, 0, OPTION_loadable}, + {"verbose" , 0, 0, OPTION_verbose}, + {"limit-width" , 1, 0, OPTION_limit_width}, + {"ignore-aspect" , 0, 0, OPTION_ignore_aspect}, + {"hide-pointer" , 0, 0, OPTION_hide_pointer}, + {"auto-zoom" , 0, 0, OPTION_auto_zoom}, + {"title" , 1, 0, OPTION_title}, + {"alpha" , 1, 0, OPTION_alpha}, + {"bg" , 1, 0, OPTION_bg}, + {"draw-filename" , 0, 0, OPTION_draw_filename}, + {"font" , 1, 0, OPTION_font}, + {"filelist" , 1, 0, OPTION_filelist}, + {"geometry" , 1, 0, OPTION_geometry}, + {"help" , 0, 0, OPTION_help}, + {"index" , 0, 0, OPTION_index}, + {"output-dir" , 1, 0, OPTION_output_dir}, + {"keep-http" , 0, 0, OPTION_keep_http}, + {"list" , 0, 0, OPTION_list}, + {"montage" , 0, 0, OPTION_montage}, + {"reverse" , 0, 0, OPTION_reverse}, + {"output" , 1, 0, OPTION_output}, + {"preload" , 0, 0, OPTION_preload}, + {"quiet" , 0, 0, OPTION_quiet}, + {"recursive" , 0, 0, OPTION_recursive}, + {"stretch" , 0, 0, OPTION_stretch}, + {"thumbnails" , 0, 0, OPTION_thumbnails}, + {"unloadable" , 0, 0, OPTION_unloadable}, + {"version" , 0, 0, OPTION_version}, + {"multiwindow" , 0, 0, OPTION_multiwindow}, + {"borderless" , 0, 0, OPTION_borderless}, + {"thumb-width" , 1, 0, OPTION_thumb_width}, + {"randomize" , 0, 0, OPTION_randomize}, + {"start-at" , 1, 0, OPTION_start_at}, + {"thumb-title" , 1, 0, OPTION_thumb_title}, + {"bg-tile" , 0, 0, OPTION_bg_title}, + {"bg-center" , 0, 0, OPTION_bg_center}, + {"bg-scale" , 0, 0, OPTION_bg_scale}, + {"zoom" , 1, 0, OPTION_zoom}, + {"zoom-step" , 1, 0, OPTION_zoom_step}, + {"no-screen-clip", 0, 0, OPTION_no_screen_clip}, + {"index-info" , 1, 0, OPTION_index_info}, + {"magick-timeout", 1, 0, OPTION_magick_timeout}, + {"action1" , 1, 0, OPTION_action1}, + {"action2" , 1, 0, OPTION_action2}, + {"action3" , 1, 0, OPTION_action3}, + {"action4" , 1, 0, OPTION_action4}, + {"action5" , 1, 0, OPTION_action5}, + {"action6" , 1, 0, OPTION_action6}, + {"action7" , 1, 0, OPTION_action7}, + {"action8" , 1, 0, OPTION_action8}, + {"action9" , 1, 0, OPTION_action9}, + {"bg-fill" , 0, 0, OPTION_bg_fill}, + {"bg-max" , 0, 0, OPTION_bg_max}, + {"no-jump-on-resort", 0, 0, OPTION_no_jump_on_resort}, + {"edit" , 0, 0, OPTION_edit}, #ifdef HAVE_LIBEXIF - {"draw-exif" , 0, 0, 223}, - {"auto-rotate" , 0, 0, 242}, + {"draw-exif" , 0, 0, OPTION_draw_exif}, + {"auto-rotate" , 0, 0, OPTION_auto_rotate}, #endif - {"no-xinerama" , 0, 0, 225}, - {"draw-tinted" , 0, 0, 229}, - {"info" , 1, 0, 234}, - {"force-aliasing", 0, 0, 235}, - {"no-fehbg" , 0, 0, 236}, - {"keep-zoom-vp" , 0, 0, 237}, - {"scroll-step" , 1, 0, 238}, - {"xinerama-index", 1, 0, 239}, - {"insecure" , 0, 0, 240}, - {"no-recursive" , 0, 0, 241}, - {"cache-size" , 1, 0, 243}, - {"on-last-slide" , 1, 0, 244}, - {"conversion-timeout" , 1, 0, 245}, - {"version-sort" , 0, 0, 246}, - {"offset" , 1, 0, 247}, + {"no-xinerama" , 0, 0, OPTION_no_xinerama}, + {"draw-tinted" , 0, 0, OPTION_draw_tinted}, + {"info" , 1, 0, OPTION_info}, + {"force-aliasing", 0, 0, OPTION_force_aliasing}, + {"no-fehbg" , 0, 0, OPTION_no_fehbg}, + {"keep-zoom-vp" , 0, 0, OPTION_keep_zoom_vp}, + {"scroll-step" , 1, 0, OPTION_scroll_step}, + {"xinerama-index", 1, 0, OPTION_xinerama_index}, + {"insecure" , 0, 0, OPTION_insecure}, + {"no-recursive" , 0, 0, OPTION_recursive}, + {"cache-size" , 1, 0, OPTION_cache_size}, + {"on-last-slide" , 1, 0, OPTION_on_last_slide}, + {"conversion-timeout" , 1, 0, OPTION_conversion_timeout}, + {"version-sort" , 0, 0, OPTION_version_sort}, + {"offset" , 1, 0, OPTION_offset}, #ifdef HAVE_INOTIFY - {"auto-reload" , 0, 0, 248}, + {"auto-reload" , 0, 0, OPTION_auto_reload}, #endif - {"class" , 1, 0, 249}, - {"no-conversion-cache", 0, 0, 250}, + {"class" , 1, 0, OPTION_class}, + {"no-conversion-cache", 0, 0, OPTION_no_conversion_cache}, + {"window-id", 1, 0, OPTION_window_id}, {0, 0, 0, 0} }; int optch = 0, cmdx = 0; @@ -442,10 +446,10 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) switch (optch) { case 0: break; - case '+': + case OPTION_debug: opt.debug = 1; break; - case '<': + case OPTION_max_dimension: opt.filter_by_dimensions = 1; XParseGeometry(optarg, &discard, &discard, &opt.max_width, &opt.max_height); if (opt.max_width == 0) @@ -453,27 +457,27 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) if (opt.max_height == 0) opt.max_height = UINT_MAX; break; - case '>': + case OPTION_min_dimension: opt.filter_by_dimensions = 1; XParseGeometry(optarg, &discard, &discard, &opt.min_width, &opt.min_height); break; - case '.': + case OPTION_scale_down: opt.scale_down = 1; break; - case '@': + case OPTION_title_font: opt.title_font = estrdup(optarg); break; - case 'A': + case OPTION_action: opt.actions[0] = estrdup(optarg); break; - case 'B': + case OPTION_image_bg: opt.image_bg = estrdup(optarg); break; - case 'C': + case OPTION_fontpath: D(("adding fontpath %s\n", optarg)); imlib_add_path_to_font_path(optarg); break; - case 'D': + case OPTION_slideshow_delay: opt.slideshow_delay = atof(optarg); if (opt.slideshow_delay < 0.0) { opt.slideshow_delay *= (-1); @@ -482,57 +486,59 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) opt.paused = 0; } break; - case 'E': + case OPTION_thumb_height: opt.thumb_h = atoi(optarg); break; - case 'F': + case OPTION_fullscreen: opt.full_screen = 1; break; - case 'G': + case OPTION_draw_actions: opt.draw_actions = 1; break; - case 'H': + case OPTION_limit_height: opt.limit_h = atoi(optarg); break; - case 'I': + case OPTION_fullindex: opt.index = 1; opt.index_info = estrdup("%n\n%S\n%wx%h"); break; - case 'J': + case OPTION_thumb_redraw: opt.thumb_redraw = atoi(optarg); break; - case 'K': + case OPTION_caption_path: opt.caption_path = estrdup(optarg); break; - case 'L': + case OPTION_customlist: opt.customlist = estrdup(optarg); opt.display = 0; break; - case 'M': + case OPTION_menu_font: free(opt.menu_font); opt.menu_font = estrdup(optarg); break; - case 'N': + case OPTION_no_menus: opt.no_menus = 1; break; - case 'O': + case OPTION_output_only: opt.output = 1; opt.output_file = estrdup(optarg); opt.display = 0; break; - case 'P': + case OPTION_cache_thumbnails: opt.cache_thumbnails = 1; break; - case 'R': + case OPTION_reload: opt.reload = atof(optarg); opt.use_conversion_cache = 0; #ifdef HAVE_INOTIFY opt.auto_reload = 0; #endif break; - case 'S': + case OPTION_sort: if (!strcasecmp(optarg, "name")) opt.sort = SORT_NAME; + else if (!strcasecmp(optarg, "none")) + opt.sort = SORT_NONE; else if (!strcasecmp(optarg, "filename")) opt.sort = SORT_FILENAME; else if (!strcasecmp(optarg, "dirname")) @@ -560,116 +566,116 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) opt.randomize = 0; } break; - case 'T': + case OPTION_theme: theme = estrdup(optarg); break; - case 'U': + case OPTION_loadable: opt.loadables = 1; opt.display = 0; break; - case 'V': + case OPTION_verbose: opt.verbose = 1; break; - case 'W': + case OPTION_limit_width: opt.limit_w = atoi(optarg); break; - case 'X': + case OPTION_ignore_aspect: opt.aspect = 0; break; - case 'Y': + case OPTION_hide_pointer: opt.hide_pointer = 1; break; - case 'Z': + case OPTION_auto_zoom: opt.zoom_mode = ZOOM_MODE_MAX; break; - case '^': + case OPTION_title: opt.title = estrdup(optarg); break; - case 'a': + case OPTION_alpha: opt.alpha = 1; opt.alpha_level = 255 - atoi(optarg); break; - case 'b': + case OPTION_bg: opt.bg = 1; opt.bg_file = estrdup(optarg); break; - case 'd': + case OPTION_draw_filename: opt.draw_filename = 1; break; - case 'e': + case OPTION_font: opt.font = estrdup(optarg); break; - case 'f': + case OPTION_filelist: if (!strcmp(optarg, "-")) opt.filelistfile = estrdup("/dev/stdin"); else opt.filelistfile = estrdup(optarg); break; - case 'g': + case OPTION_geometry: opt.geom_enabled = 1; opt.geom_flags = XParseGeometry(optarg, &opt.geom_x, &opt.geom_y, &opt.geom_w, &opt.geom_h); break; - case 'h': + case OPTION_help: show_usage(); break; - case 'i': + case OPTION_index: opt.index = 1; opt.index_info = estrdup("%n"); break; - case 'j': + case OPTION_output_dir: opt.output_dir = estrdup(optarg); break; - case 'k': + case OPTION_keep_http: opt.keep_http = 1; break; - case 'l': + case OPTION_list: opt.list = 1; opt.display = 0; break; - case 'm': + case OPTION_montage: opt.index = 1; break; - case 'n': + case OPTION_reverse: opt.reverse = 1; break; - case 'o': + case OPTION_output: opt.output = 1; opt.output_file = estrdup(optarg); break; - case 'p': + case OPTION_preload: opt.preload = 1; break; - case 'q': + case OPTION_quiet: opt.quiet = 1; break; - case 'r': + case OPTION_recursive: opt.recursive = 1; break; - case 's': + case OPTION_stretch: opt.stretch = 1; break; - case 't': + case OPTION_thumbnails: opt.thumbs = 1; opt.index_info = estrdup("%n"); break; - case 'u': + case OPTION_unloadable: opt.unloadables = 1; opt.display = 0; break; - case 'v': + case OPTION_version: show_version(); break; - case 'w': + case OPTION_multiwindow: opt.multiwindow = 1; break; - case 'x': + case OPTION_borderless: opt.borderless = 1; break; - case 'y': + case OPTION_thumb_width: opt.thumb_w = atoi(optarg); break; - case 'z': + case OPTION_randomize: opt.randomize = 1; if (opt.sort != SORT_NONE) { weprintf("commandline contains --sort and --randomize. " @@ -677,22 +683,22 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) opt.sort = SORT_NONE; } break; - case '|': + case OPTION_start_at: opt.start_list_at = estrdup(optarg); break; - case '~': + case OPTION_thumb_title: opt.thumb_title = estrdup(optarg); break; - case 200: + case OPTION_bg_title: opt.bgmode = BG_MODE_TILE; break; - case 201: + case OPTION_bg_center: opt.bgmode = BG_MODE_CENTER; break; - case 202: + case OPTION_bg_scale: opt.bgmode = BG_MODE_SCALE; break; - case 205: + case OPTION_zoom: if (!strcmp("fill", optarg)) opt.zoom_mode = ZOOM_MODE_FILL; else if (!strcmp("max", optarg)) @@ -700,70 +706,75 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) else opt.default_zoom = atoi(optarg); break; - case 206: + case OPTION_no_screen_clip: opt.screen_clip = 0; break; - case 207: + case OPTION_index_info: opt.index_info = estrdup(optarg); break; - case 208: + case OPTION_magick_timeout: weprintf("--magick-timeout is deprecated, please use --conversion-timeout instead"); opt.conversion_timeout = atoi(optarg); break; - case 209: + case OPTION_action1: opt.actions[1] = estrdup(optarg); break; - case 210: + case OPTION_action2: opt.actions[2] = estrdup(optarg); break; - case 211: + case OPTION_action3: opt.actions[3] = estrdup(optarg); break; - case 212: + case OPTION_action4: opt.actions[4] = estrdup(optarg); break; - case 213: + case OPTION_action5: opt.actions[5] = estrdup(optarg); break; - case 214: + case OPTION_action6: opt.actions[6] = estrdup(optarg); break; - case 215: + case OPTION_action7: opt.actions[7] = estrdup(optarg); break; - case 216: + case OPTION_action8: opt.actions[8] = estrdup(optarg); break; - case 217: + case OPTION_action9: opt.actions[9] = estrdup(optarg); break; - case 218: + case OPTION_bg_fill: opt.bgmode = BG_MODE_FILL; break; - case 219: + case OPTION_bg_max: opt.bgmode = BG_MODE_MAX; break; - case 220: + case OPTION_no_jump_on_resort: opt.jump_on_resort = 0; break; - case 221: + case OPTION_edit: opt.edit = 1; break; #ifdef HAVE_LIBEXIF - case 223: + case OPTION_draw_exif: opt.draw_exif = 1; break; - case 242: + case OPTION_auto_rotate: +#if defined(IMLIB2_VERSION_MAJOR) && defined(IMLIB2_VERSION_MINOR) && defined(IMLIB2_VERSION_MICRO) && (IMLIB2_VERSION_MAJOR > 1 || IMLIB2_VERSION_MINOR > 7 || IMLIB2_VERSION_MICRO >= 5) + weprintf("This feh release was built with Imlib2 version %d.%d.%d, which transparently adjusts for image orientation according to EXIF data.", IMLIB2_VERSION_MAJOR, IMLIB2_VERSION_MINOR, IMLIB2_VERSION_MICRO); + weprintf("--auto-rotate would rotate an already correctly oriented image, resulting in incorrect orientation. It has been disabled in this build. Rebuild feh with Imlib2 <1.7.5 to enable --auto-rotate."); +#else opt.auto_rotate = 1; +#endif break; #endif - case 225: + case OPTION_no_xinerama: opt.xinerama = 0; break; - case 229: + case OPTION_draw_tinted: opt.text_bg = TEXT_BG_TINTED; break; - case 234: + case OPTION_info: opt.info_cmd = estrdup(optarg); if (opt.info_cmd[0] == ';') { opt.draw_info = 0; @@ -772,35 +783,35 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) opt.draw_info = 1; } break; - case 235: + case OPTION_force_aliasing: opt.force_aliasing = 1; break; - case 236: + case OPTION_no_fehbg: opt.no_fehbg = 1; break; - case 237: + case OPTION_keep_zoom_vp: opt.keep_zoom_vp = 1; break; - case 238: + case OPTION_scroll_step: opt.scroll_step = atoi(optarg); break; - case 239: + case OPTION_xinerama_index: opt.xinerama_index = atoi(optarg); break; - case 240: + case OPTION_insecure: opt.insecure_ssl = 1; break; - case 241: + case OPTION_no_recursive: opt.recursive = 0; break; - case 243: + case OPTION_cache_size: opt.cache_size = atoi(optarg); if (opt.cache_size < 0) opt.cache_size = 0; if (opt.cache_size > 2048) opt.cache_size = 2048; break; - case 244: + case OPTION_on_last_slide: if (!strcmp(optarg, "quit")) { opt.on_last_slide = ON_LAST_SLIDE_QUIT; } else if (!strcmp(optarg, "hold")) { @@ -812,27 +823,39 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) "Supported actions: hold, resume, quit\n", optarg); } break; - case 245: + case OPTION_conversion_timeout: opt.conversion_timeout = atoi(optarg); break; - case 246: + case OPTION_version_sort: opt.version_sort = 1; break; - case 247: + case OPTION_offset: opt.offset_flags = XParseGeometry(optarg, &opt.offset_x, &opt.offset_y, (unsigned int *)&discard, (unsigned int *)&discard); break; #ifdef HAVE_INOTIFY - case 248: + case OPTION_auto_reload: opt.auto_reload = 1; break; #endif - case 249: + case OPTION_class: opt.x11_class = estrdup(optarg); break; - case 250: + case OPTION_no_conversion_cache: opt.use_conversion_cache = 0; break; + case OPTION_window_id: + opt.x11_windowid = strtol(optarg, NULL, 0); + break; + case OPTION_zoom_step: + opt.zoom_rate = atof(optarg); + if ((opt.zoom_rate <= 0)) { + weprintf("Zooming disabled due to --zoom-step=%f", opt.zoom_rate); + opt.zoom_rate = 1.0; + } else { + opt.zoom_rate = 1 + ((float)opt.zoom_rate / 100); + } + break; default: break; } @@ -855,11 +878,26 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) */ if (opt.start_list_at && path_is_url(opt.start_list_at) && (strlen(opt.start_list_at) <= 8 || strncmp(opt.start_list_at, "file:///", 8) != 0)) { add_file_to_filelist_recursively(opt.start_list_at, FILELIST_FIRST); + /* + * Otherwise, make "feh --start-at dir/file.jpg" behave like + * "feh --start-at dir/file.jpg dir". + */ } else if (opt.start_list_at && strrchr(opt.start_list_at, '/')) { + /* + * feh can't candle urlencoded path components ("some%20dir" etc). + * Use libcurl to unescape them if --start-at is file://... + */ if (strlen(opt.start_list_at) > 8 && strncmp(opt.start_list_at, "file:///", 8) == 0) { - char *start_at_path = estrdup(opt.start_list_at + 7); - free(opt.start_list_at); - opt.start_list_at = start_at_path; + char *unescaped_path = feh_http_unescape(opt.start_list_at); + if (unescaped_path != NULL) { + free(opt.start_list_at); + opt.start_list_at = estrdup(unescaped_path + 7); + free(unescaped_path); + } else { + char *new_path = estrdup(opt.start_list_at + 7); + free(opt.start_list_at); + opt.start_list_at = new_path; + } } char *target_directory = estrdup(opt.start_list_at); char *filename_start = strrchr(target_directory, '/'); @@ -867,6 +905,7 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) *filename_start = '\0'; } add_file_to_filelist_recursively(target_directory, FILELIST_FIRST); + original_file_items = gib_list_add_front(original_file_items, estrdup(target_directory)); free(target_directory); } else { add_file_to_filelist_recursively(".", FILELIST_FIRST); @@ -939,6 +978,10 @@ static void show_version(void) "help " #endif +#ifdef HAVE_LIBMAGIC + "magic " +#endif + #if _FILE_OFFSET_BITS == 64 "stat64 " #endif diff --git a/src/options.h b/src/options.h index 4906004..aa3cd91 100644 --- a/src/options.h +++ b/src/options.h @@ -1,7 +1,7 @@ /* options.h Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -127,9 +127,11 @@ struct __fehoptions { int offset_y; int default_zoom; int zoom_mode; + double zoom_rate; unsigned char adjust_reload; int xinerama_index; char *x11_class; + unsigned long int x11_windowid; /* signed in case someone wants to invert scrolling real quick */ int scroll_step; @@ -149,6 +151,113 @@ struct __fehoptions { Imlib_Font menu_fn; }; +enum __feh_option { +OPTION_debug = '+', +OPTION_scale_down = '.', +OPTION_max_dimension = '<', +OPTION_min_dimension = '>', +OPTION_title_font = '@', +OPTION_action = 'A', +OPTION_image_bg = 'B', +OPTION_fontpath = 'C', +OPTION_slideshow_delay = 'D', +OPTION_thumb_height = 'E', +OPTION_fullscreen = 'F', +OPTION_draw_actions = 'G', +OPTION_limit_height = 'H', +OPTION_fullindex = 'I', +OPTION_thumb_redraw = 'J', +OPTION_caption_path = 'K', +OPTION_customlist = 'L', +OPTION_menu_font = 'M', +OPTION_no_menus = 'N', +OPTION_output_only = 'O', +OPTION_cache_thumbnails = 'P', +OPTION_reload = 'R', +OPTION_sort = 'S', +OPTION_theme = 'T', +OPTION_loadable = 'U', +OPTION_verbose = 'V', +OPTION_limit_width = 'W', +OPTION_ignore_aspect = 'X', +OPTION_hide_pointer = 'Y', +OPTION_auto_zoom = 'Z', +OPTION_title = '^', +OPTION_alpha = 'a', +OPTION_bg = 'b', +OPTION_draw_filename = 'd', +OPTION_font = 'e', +OPTION_filelist = 'f', +OPTION_geometry = 'g', +OPTION_help = 'h', +OPTION_index = 'i', +OPTION_output_dir = 'j', +OPTION_keep_http = 'k', +OPTION_list = 'l', +OPTION_montage = 'm', +OPTION_reverse = 'n', +OPTION_output = 'o', +OPTION_preload = 'p', +OPTION_quiet = 'q', +OPTION_recursive = 'r', +OPTION_stretch = 's', +OPTION_thumbnails = 't', +OPTION_unloadable = 'u', +OPTION_version = 'v', +OPTION_multiwindow = 'w', +OPTION_borderless = 'x', +OPTION_thumb_width = 'y', +OPTION_randomize = 'z', +OPTION_start_at = '|', +OPTION_thumb_title = '~', +OPTION_bg_title, +OPTION_bg_center, +OPTION_bg_scale, +OPTION_bg_fill, +OPTION_bg_max, +OPTION_zoom, +OPTION_zoom_step, +OPTION_zoom_in_rate, +OPTION_zoom_out_rate, +OPTION_keep_zoom_vp, +OPTION_no_screen_clip, +OPTION_index_info, +OPTION_magick_timeout, +OPTION_action1, +OPTION_action2, +OPTION_action3, +OPTION_action4, +OPTION_action5, +OPTION_action6, +OPTION_action7, +OPTION_action8, +OPTION_action9, +OPTION_no_jump_on_resort, +OPTION_edit, +OPTION_draw_exif, +OPTION_auto_rotate, +OPTION_no_xinerama, +OPTION_draw_tinted, +OPTION_info, +OPTION_force_aliasing, +OPTION_no_fehbg, +OPTION_scroll_step, +OPTION_xinerama_index, +OPTION_insecure, +OPTION_no_recursive, +OPTION_cache_size, +OPTION_on_last_slide, +OPTION_conversion_timeout, +OPTION_version_sort, +OPTION_offset, +OPTION_auto_reload, +OPTION_class, +OPTION_no_conversion_cache, +OPTION_window_id, +}; + +//typedef enum __fehoption fehoption; + struct __fehkey { unsigned int keysyms[3]; unsigned int keystates[3]; diff --git a/src/signals.c b/src/signals.c index a64f935..5a64883 100644 --- a/src/signals.c +++ b/src/signals.c @@ -1,6 +1,6 @@ /* signals.c -Copyright (C) 2010-2020 by Daniel Friesel +Copyright (C) 2010-2020 by Birte Kristina Friesel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -29,9 +29,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "options.h" void feh_handle_signal(int); +volatile int sig_received = 0; volatile int sig_exit = 0; -void setup_signal_handlers() +void setup_signal_handlers(void) { struct sigaction feh_sh; sigset_t feh_ss; @@ -71,9 +72,6 @@ void setup_signal_handlers() void feh_handle_signal(int signo) { - winwidget winwid; - int i; - switch (signo) { case SIGALRM: if (childpid) @@ -92,21 +90,5 @@ void feh_handle_signal(int signo) return; } - winwid = winwidget_get_first_window_of_type(WIN_TYPE_SLIDESHOW); - - if (winwid) { - if (filelist_len > 1) { - if (signo == SIGUSR1) - slideshow_change_image(winwid, SLIDE_NEXT, 1); - else if (signo == SIGUSR2) - slideshow_change_image(winwid, SLIDE_PREV, 1); - } else { - feh_reload_image(winwid, 0, 0); - } - } else if (opt.multiwindow) { - for (i = window_num - 1; i >= 0; i--) - feh_reload_image(windows[i], 0, 0); - } - - return; + sig_received = signo; } diff --git a/src/signals.h b/src/signals.h index bff737e..505a071 100644 --- a/src/signals.h +++ b/src/signals.h @@ -1,6 +1,6 @@ /* signals.h -Copyright (C) 2010 by Daniel Friesel +Copyright (C) 2010 by Birte Kristina Friesel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -26,6 +26,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #ifndef SIGNALS_H #define SIGNALS_H -void setup_signal_handlers(); +void setup_signal_handlers(void); extern volatile int sig_exit; +extern volatile int sig_received; #endif diff --git a/src/slideshow.c b/src/slideshow.c index 07a1e94..a53749e 100644 --- a/src/slideshow.c +++ b/src/slideshow.c @@ -1,7 +1,7 @@ /* slideshow.c Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -57,6 +57,7 @@ void init_slideshow_mode(void) // Try finding an exact filename match first for (; l && opt.start_list_at; l = l->next) { if (!strcmp(opt.start_list_at, FEH_FILE(l->data)->filename)) { + free(opt.start_list_at); opt.start_list_at = NULL; break; } @@ -83,6 +84,7 @@ void init_slideshow_mode(void) current_filename = FEH_FILE(l->data)->filename; } if (!strcmp(start_at_filename, current_filename)) { + free(opt.start_list_at); opt.start_list_at = NULL; break; } @@ -163,7 +165,7 @@ void cb_reload_timer(void *data) if (opt.filelistfile) { filelist = gib_list_cat(filelist, feh_read_filelist(opt.filelistfile)); } - + if (!(filelist_len = gib_list_length(filelist))) { eprintf("No files found to reload."); } @@ -225,6 +227,18 @@ void slideshow_change_image(winwidget winwid, int change, int render) /* The for loop prevents us looping infinitely */ for (i = 0; i < our_filelist_len; i++) { winwidget_free_image(winwid); +#ifdef HAVE_LIBEXIF + /* + * An EXIF data chunk requires up to 50 kB of space. For large and + * long-running slideshows, this would acculumate gigabytes of + * EXIF data after a few days. We therefore do not cache EXIF data + * in slideshows. + */ + if (FEH_FILE(winwid->file->data)->ed) { + exif_data_unref(FEH_FILE(winwid->file->data)->ed); + FEH_FILE(winwid->file->data)->ed = NULL; + } +#endif switch (change) { case SLIDE_NEXT: current_file = feh_list_jump(filelist, current_file, FORWARD, 1); @@ -371,7 +385,8 @@ void feh_action_run(feh_file * file, char *action, winwidget winwid) if (opt.verbose && !opt.list && !opt.customlist) fprintf(stderr, "Running action -->%s<--\n", sys); - system(sys); + if (system(sys) == -1) + perror("running action via system() failed"); } return; } @@ -514,6 +529,12 @@ char *feh_printf(char *str, feh_file * file, winwidget winwid) strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); } break; + case 'W': + if (winwid) { + snprintf(buf, sizeof(buf), "%dx%d+%d+%d", winwid->w, winwid->h, winwid->x, winwid->y); + strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); + } + break; case 'z': if (winwid) { snprintf(buf, sizeof(buf), "%.2f", winwid->zoom); @@ -626,7 +647,7 @@ void slideshow_save_image(winwidget win) gib_imlib_save_image_with_error_return(win->im, tmpname, &err); if (err) - feh_imlib_print_load_error(tmpname, win, err); + feh_print_load_error(tmpname, win, err, LOAD_ERROR_IMLIB); free(tmpname); return; diff --git a/src/structs.h b/src/structs.h index 3e2a1aa..8438930 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1,7 +1,7 @@ /* structs.h Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to diff --git a/src/strverscmp.c b/src/strverscmp.c index 92cd877..ddc6b6d 100644 --- a/src/strverscmp.c +++ b/src/strverscmp.c @@ -41,9 +41,9 @@ int strverscmp(const char *l0, const char *r0) else if (c!='0') z=0; } - if (l[dp]!='0' && r[dp]!='0') { - /* If we're not looking at a digit sequence that began - * with a zero, longest digit string is greater. */ + if (l[dp]-'1'<9U && r[dp]-'1'<9U) { + /* If we're looking at non-degenerate digit sequences starting + * with nonzero digits, longest digit string is greater. */ for (j=i; isdigit(l[j]); j++) if (!isdigit(r[j])) return 1; if (isdigit(r[j])) return -1; diff --git a/src/thumbnail.c b/src/thumbnail.c index 41bd1a0..77c0acd 100644 --- a/src/thumbnail.c +++ b/src/thumbnail.c @@ -1,7 +1,7 @@ /* thumbnail.c Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -392,7 +392,7 @@ void init_thumbnail_mode(void) } gib_imlib_save_image_with_error_return(td.im_main, output_buf, &err); if (err) { - feh_imlib_print_load_error(output_buf, td.im_main, err); + feh_print_load_error(output_buf, td.im_main, err, LOAD_ERROR_IMLIB); } else if (opt.verbose) { int tw, th; @@ -411,6 +411,7 @@ void init_thumbnail_mode(void) else if (opt.start_list_at) { for (l = thumbnails; l; l = l->next) { if (!strcmp(opt.start_list_at, FEH_THUMB(l->data)->file->filename)) { + free(opt.start_list_at); opt.start_list_at = NULL; feh_thumbnail_select(winwid, FEH_THUMB(l->data)); break; @@ -592,7 +593,7 @@ int feh_thumbnail_get_thumbnail(Imlib_Image * image, feh_file * file, return status; } -static char *feh_thumbnail_get_prefix() +static char *feh_thumbnail_get_prefix(void) { char *dir = NULL, *home, *xdg_cache_home; @@ -635,9 +636,9 @@ char *feh_thumbnail_get_name_uri(char *name) /* FIXME: what happens with http, https, and ftp? MTime etc */ if (!path_is_url(name)) { - /* make sure it's an absoulte path */ + /* make sure it's an absolute path */ /* FIXME: add support for ~, need to investigate if it's expanded - somewhere else before adding (unecessary) code */ + somewhere else before adding (unnecessary) code */ if (name[0] != '/') { /* work around /some/path/./image.ext */ if ((strncmp(name, "./", 2)) == 0) @@ -881,13 +882,13 @@ void feh_thumbnail_select_prev(winwidget winwid, int jump) } } -void feh_thumbnail_show_selected() +void feh_thumbnail_show_selected(void) { if (td.selected && td.selected->file) feh_thumbnail_show_fullsize(td.selected->file); } -feh_file* feh_thumbnail_get_selected_file() +feh_file* feh_thumbnail_get_selected_file(void) { if (td.selected) return td.selected->file; diff --git a/src/thumbnail.h b/src/thumbnail.h index 61d3053..e69759f 100644 --- a/src/thumbnail.h +++ b/src/thumbnail.h @@ -1,7 +1,7 @@ /* thumbnail.h Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -83,8 +83,8 @@ void feh_thumbnail_show_fullsize(feh_file *thumbfile); void feh_thumbnail_select(winwidget winwid, feh_thumbnail *thumbnail); void feh_thumbnail_select_next(winwidget winwid, int jump); void feh_thumbnail_select_prev(winwidget winwid, int jump); -void feh_thumbnail_show_selected(); -feh_file *feh_thumbnail_get_selected_file(); +void feh_thumbnail_show_selected(void); +feh_file *feh_thumbnail_get_selected_file(void); int feh_thumbnail_setup_thumbnail_dir(void); diff --git a/src/timers.c b/src/timers.c index b2cdbc7..8e42050 100644 --- a/src/timers.c +++ b/src/timers.c @@ -1,7 +1,7 @@ /* timers.c Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to diff --git a/src/utils.c b/src/utils.c index 087e7f6..eb128a2 100644 --- a/src/utils.c +++ b/src/utils.c @@ -146,6 +146,8 @@ char *estrjoin(const char *separator, ...) char path_is_url(char *path) { if ((!strncmp(path, "http://", 7)) || (!strncmp(path, "https://", 8)) + || (!strncmp(path, "gopher://", 9)) + || (!strncmp(path, "gophers://", 10)) || (!strncmp(path, "ftp://", 6)) || (!strncmp(path, "file://", 7))) return 1; diff --git a/src/wallpaper.c b/src/wallpaper.c index 37b5a1d..e2fa67e 100644 --- a/src/wallpaper.c +++ b/src/wallpaper.c @@ -1,7 +1,7 @@ /* wallpaper.c Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -245,6 +245,106 @@ static void feh_wm_set_bg_maxed(Pixmap pmap, Imlib_Image im, int use_filelist, return; } +/* +** Creates a script that can be used to create the same background +** as the last time the program was called. +*/ +void feh_wm_gen_bg_script(char* fil, int centered, int scaled, int filled, int use_filelist) { + char * home = getenv("HOME"); + + if (!home) + return; + + FILE *fp; + int fd; + char *path; + char *exec_method; + char *absolute_path; + struct stat s; + gib_list *filelist_pos = filelist; + + if (strchr(cmdargv[0], '/')) + exec_method = feh_absolute_path(cmdargv[0]); + else + exec_method = cmdargv[0]; + + path = estrjoin("/", home, ".fehbg", NULL); + + if ((fp = fopen(path, "w")) == NULL) { + weprintf("Can't write to %s", path); + } else { + fputs("#!/bin/sh\n", fp); + fputs(exec_method, fp); + fputs(" --no-fehbg --bg-", fp); + if (centered) + fputs("center", fp); + else if (scaled) + fputs("scale", fp); + else if (filled == 1) + fputs("fill", fp); + else if (filled == 2) + fputs("max", fp); + else + fputs("tile", fp); + if (opt.image_bg) { + fputs(" --image-bg ", fp); + fputs(shell_escape(opt.image_bg), fp); + } +#ifdef HAVE_LIBXINERAMA + if (opt.xinerama) { + if (opt.xinerama_index >= 0) { + fprintf(fp, " --xinerama-index %d", opt.xinerama_index); + } + } + else { + fputs(" --no-xinerama", fp); + } +#endif /* HAVE_LIBXINERAMA */ + if (opt.geom_flags & XValue) { + fprintf(fp, " --geometry %c%d", + opt.geom_flags & XNegative ? '-' : '+', + opt.geom_flags & XNegative ? abs(opt.geom_x) : opt.geom_x); + if (opt.geom_flags & YValue) { + fprintf(fp, "%c%d", + opt.geom_flags & YNegative ? '-' : '+', + opt.geom_flags & YNegative ? abs(opt.geom_y) : opt.geom_y); + } + } + if (opt.force_aliasing) { + fputs(" --force-aliasing", fp); + } + fputc(' ', fp); + if (use_filelist) { +#ifdef HAVE_LIBXINERAMA + for (int i = 0; (i < opt.xinerama ? num_xinerama_screens : 1) && filelist_pos; i++) +#else + for (int i = 0; (i < 1 ) && filelist_pos; i++) +#endif + { + absolute_path = feh_absolute_path(FEH_FILE(filelist_pos->data)->filename); + fputs(shell_escape(absolute_path), fp); + filelist_pos = filelist_pos->next; + free(absolute_path); + fputc(' ', fp); + } + } else if (fil) { + absolute_path = feh_absolute_path(fil); + fputs(shell_escape(absolute_path), fp); + free(absolute_path); + } + fputc('\n', fp); + fd = fileno(fp); + if (fstat(fd, &s) != 0 || fchmod(fd, s.st_mode | S_IXUSR | S_IXGRP) != 0) { + weprintf("Can't set %s as executable", path); + } + fclose(fp); + } + free(path); + + if(exec_method != cmdargv[0]) + free(exec_method); +} + void feh_wm_set_bg(char *fil, Imlib_Image im, int centered, int scaled, int filled, int desktop, int use_filelist) { @@ -282,7 +382,10 @@ void feh_wm_set_bg(char *fil, Imlib_Image im, int centered, int scaled, feh_wm_load_next(&im); fil = FEH_FILE(filelist->data)->filename; } - snprintf(sendbuf, sizeof(sendbuf), "background %s bg.file %s", bgname, fil); + if ((size_t) snprintf(sendbuf, sizeof(sendbuf), "background %s bg.file %s", bgname, fil) >= sizeof(sendbuf)) { + weprintf("Writing to IPC send buffer was truncated"); + return; + } enl_ipc_send(sendbuf); if (scaled) { @@ -322,8 +425,6 @@ void feh_wm_set_bg(char *fil, Imlib_Image im, int centered, int scaled, unsigned char *data_root = NULL, *data_esetroot = NULL; Pixmap pmap_d1, pmap_d2; - char *home; - /* local display to set closedownmode on */ Display *disp2; Window root2; @@ -448,87 +549,8 @@ void feh_wm_set_bg(char *fil, Imlib_Image im, int centered, int scaled, gib_imlib_render_image_on_drawable(pmap_d1, im, 0, 0, 1, 1, 0); } - if (!opt.no_fehbg) { - home = getenv("HOME"); - if (home) { - FILE *fp; - int fd; - char *path; - char *absolute_path; - struct stat s; - gib_list *filelist_pos = filelist; - path = estrjoin("/", home, ".fehbg", NULL); - if ((fp = fopen(path, "w")) == NULL) { - weprintf("Can't write to %s", path); - } else { - fputs("#!/bin/sh\n", fp); - fputs(cmdargv[0], fp); - fputs(" --no-fehbg --bg-", fp); - if (centered) - fputs("center", fp); - else if (scaled) - fputs("scale", fp); - else if (filled == 1) - fputs("fill", fp); - else if (filled == 2) - fputs("max", fp); - else - fputs("tile", fp); - if (opt.image_bg) { - fputs(" --image-bg ", fp); - fputs(shell_escape(opt.image_bg), fp); - } -#ifdef HAVE_LIBXINERAMA - if (opt.xinerama) { - if (opt.xinerama_index >= 0) { - fprintf(fp, " --xinerama-index %d", opt.xinerama_index); - } - } - else { - fputs(" --no-xinerama", fp); - } -#endif /* HAVE_LIBXINERAMA */ - if (opt.geom_flags & XValue) { - fprintf(fp, " --geometry %c%d", - opt.geom_flags & XNegative ? '-' : '+', - opt.geom_flags & XNegative ? abs(opt.geom_x) : opt.geom_x); - if (opt.geom_flags & YValue) { - fprintf(fp, "%c%d", - opt.geom_flags & YNegative ? '-' : '+', - opt.geom_flags & YNegative ? abs(opt.geom_y) : opt.geom_y); - } - } - if (opt.force_aliasing) { - fputs(" --force-aliasing", fp); - } - fputc(' ', fp); - if (use_filelist) { -#ifdef HAVE_LIBXINERAMA - for (int i = 0; (i < opt.xinerama ? num_xinerama_screens : 1) && filelist_pos; i++) { -#else - for (int i = 0; (i < 1 ) && filelist_pos; i++) { -#endif - absolute_path = feh_absolute_path(FEH_FILE(filelist_pos->data)->filename); - fputs(shell_escape(absolute_path), fp); - filelist_pos = filelist_pos->next; - free(absolute_path); - fputc(' ', fp); - } - } else if (fil) { - absolute_path = feh_absolute_path(fil); - fputs(shell_escape(absolute_path), fp); - free(absolute_path); - } - fputc('\n', fp); - fd = fileno(fp); - if (fstat(fd, &s) != 0 || fchmod(fd, s.st_mode | S_IXUSR | S_IXGRP) != 0) { - weprintf("Can't set %s as executable", path); - } - fclose(fp); - } - free(path); - } - } + if (!opt.no_fehbg) + feh_wm_gen_bg_script(fil, centered, scaled, filled, use_filelist); /* create new display, copy pixmap to new display */ disp2 = XOpenDisplay(NULL); @@ -569,7 +591,7 @@ void feh_wm_set_bg(char *fil, Imlib_Image im, int centered, int scaled, if (data_root) XFree(data_root); - + if (data_esetroot) XFree(data_esetroot); diff --git a/src/wallpaper.h b/src/wallpaper.h index cf52d2d..c836c0f 100644 --- a/src/wallpaper.h +++ b/src/wallpaper.h @@ -1,7 +1,7 @@ /* wallpaper.h Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -42,7 +42,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. extern Window ipc_win; extern Atom ipc_atom; -_XFUNCPROTOBEGIN extern Window enl_ipc_get_win(void); +extern Window enl_ipc_get_win(void); extern void enl_ipc_send(char *); extern char *enl_wait_for_reply(void); extern char *enl_ipc_get(const char *); @@ -53,5 +53,4 @@ extern int feh_wm_get_num_desks(void); extern signed char feh_wm_get_wm_is_e(void); void feh_wm_set_bg_filelist(unsigned char bgmode); -_XFUNCPROTOEND #endif diff --git a/src/winwidget.c b/src/winwidget.c index bfd987d..b98cbef 100644 --- a/src/winwidget.c +++ b/src/winwidget.c @@ -1,7 +1,7 @@ /* winwidget.c Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -104,8 +104,13 @@ winwidget winwidget_create_from_image(Imlib_Image im, char type) ret->w = ret->im_w = gib_imlib_image_get_width(ret->im); ret->h = ret->im_h = gib_imlib_image_get_height(ret->im); - if (opt.full_screen && (type != WIN_TYPE_THUMBNAIL)) + if (opt.full_screen && (type != WIN_TYPE_THUMBNAIL)) { ret->full_screen = True; + } else if (opt.default_zoom) { + ret->zoom = 0.01 * opt.default_zoom; + ret->w *= ret->zoom; + ret->h *= ret->zoom; + } winwidget_create_window(ret, ret->w, ret->h); winwidget_render_image(ret, 1, 0); @@ -133,8 +138,13 @@ winwidget winwidget_create_from_file(gib_list * list, char type) ret->w = ret->im_w = gib_imlib_image_get_width(ret->im); ret->h = ret->im_h = gib_imlib_image_get_height(ret->im); D(("image is %dx%d pixels, format %s\n", ret->w, ret->h, gib_imlib_image_format(ret->im))); - if (opt.full_screen) + if (opt.full_screen) { ret->full_screen = True; + } else if (opt.default_zoom) { + ret->zoom = 0.01 * opt.default_zoom; + ret->w *= ret->zoom; + ret->h *= ret->zoom; + } winwidget_create_window(ret, ret->w, ret->h); winwidget_render_image(ret, 1, 0); } @@ -144,6 +154,7 @@ winwidget winwidget_create_from_file(gib_list * list, char type) void winwidget_create_window(winwidget ret, int w, int h) { + XWindowAttributes window_attr; XSetWindowAttributes attr; XEvent ev; XClassHint *xch; @@ -250,11 +261,31 @@ void winwidget_create_window(winwidget ret, int w, int h) } } - ret->win = - XCreateWindow(disp, DefaultRootWindow(disp), x, y, w, h, 0, - depth, InputOutput, vis, - CWOverrideRedirect | CWSaveUnder | CWBackingStore - | CWColormap | CWBackPixel | CWBorderPixel | CWEventMask, &attr); + if (opt.x11_windowid == 0) { + ret->win = + XCreateWindow(disp, DefaultRootWindow(disp), x, y, w, h, 0, + depth, InputOutput, vis, + CWOverrideRedirect | CWSaveUnder | CWBackingStore + | CWColormap | CWBackPixel | CWBorderPixel | CWEventMask, + &attr); + } else { + /* x11_windowid is a pointer to the window */ + ret->win = (Window) opt.x11_windowid; + + /* set our attributes on the window */ + XChangeWindowAttributes(disp, ret->win, + CWOverrideRedirect | CWSaveUnder | CWBackingStore + | CWColormap | CWBackPixel | CWBorderPixel + | CWEventMask, &attr); + + /* determine the size and visibility of the window */ + XGetWindowAttributes(disp, ret->win, &window_attr); + ret->visible = (window_attr.map_state == IsViewable); + ret->x = window_attr.x; + ret->y = window_attr.y; + ret->w = window_attr.width; + ret->h = window_attr.height; + } if (mwmhints.flags) { XChangeProperty(disp, ret->win, prop, prop, 32, @@ -433,7 +464,12 @@ void winwidget_render_image(winwidget winwid, int resize, int force_alias) int antialias = 0; if (!winwid->full_screen && resize) { - winwidget_resize(winwid, winwid->im_w, winwid->im_h, 0); + if (opt.default_zoom) { + winwid->zoom = 0.01 * opt.default_zoom; + winwidget_resize(winwid, winwid->im_w * winwid->zoom, winwid->im_h * winwid->zoom, 0); + } else { + winwidget_resize(winwid, winwid->im_w, winwid->im_h, 0); + } winwidget_reset_image(winwid); } @@ -703,7 +739,7 @@ void winwidget_inotify_remove(winwidget winwid) #ifdef HAVE_INOTIFY void winwidget_inotify_add(winwidget winwid, feh_file * file) { - if (opt.auto_reload) { + if (opt.auto_reload && !path_is_url(file->filename)) { D(("Adding inotify watch for %s\n", file->filename)); char dir[PATH_MAX]; feh_file_dirname(dir, file, PATH_MAX); @@ -742,7 +778,7 @@ void feh_event_handle_inotify(void) for (int j = 0; j < window_num; j++) { if(windows[j]->inotify_wd == event->wd) { if (event->mask & IN_IGNORED) { - D(("inotify watch was implicitely removed\n")); + D(("inotify watch was implicitly removed\n")); windows[j]->inotify_wd = -1; } else if (event->mask & (IN_CLOSE_WRITE | IN_MOVED_TO)) { if (strcmp(event->name, FEH_FILE(windows[j]->file->data)->name) == 0) { @@ -1014,8 +1050,9 @@ void winwidget_rename(winwidget winwid, char *newname) void winwidget_free_image(winwidget w) { - if (w->im) + if (w->im) { gib_imlib_free_image(w->im); + } w->im = NULL; w->im_w = 0; w->im_h = 0; diff --git a/src/winwidget.h b/src/winwidget.h index 9d74286..0894b5a 100644 --- a/src/winwidget.h +++ b/src/winwidget.h @@ -1,7 +1,7 @@ /* winwidget.h Copyright (C) 1999-2003 Tom Gilbert. -Copyright (C) 2010-2020 Daniel Friesel. +Copyright (C) 2010-2020 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to |