From 0084d755618c8a5a55f36bbdd2c17952dfae68f0 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Fri, 8 Feb 2013 18:04:21 +0100 Subject: handle stdin when loading filelist so it also works with --list, rotation, etc. --- src/filelist.c | 38 ++++++++++++++++++++++++++++++++++++-- src/imlib.c | 39 +-------------------------------------- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/src/filelist.c b/src/filelist.c index 3ea0928..0aafa64 100644 --- a/src/filelist.c +++ b/src/filelist.c @@ -155,6 +155,40 @@ static void feh_print_stat_error(char *path) } } +static void add_stdin_to_filelist() +{ + char buf[1024]; + size_t readsize; + char *sfn = estrjoin("_", "/tmp/feh_stdin", "XXXXXX", NULL); + int fd = mkstemp(sfn); + FILE *outfile; + + if (fd == -1) { + free(sfn); + weprintf("cannot read from stdin: mktemp:"); + return; + } + + outfile = fdopen(fd, "w"); + + if (outfile == NULL) { + free(sfn); + weprintf("cannot read from stdin: fdopen:"); + return; + } + + while ((readsize = fread(buf, sizeof(char), sizeof(buf), stdin)) > 0) { + if (fwrite(buf, sizeof(char), readsize, outfile) < readsize) { + free(sfn); + return; + } + } + fclose(outfile); + + filelist = gib_list_add_front(filelist, feh_file_new(sfn)); + free(sfn); +} + /* Recursive */ void add_file_to_filelist_recursively(char *origpath, unsigned char level) @@ -186,8 +220,8 @@ void add_file_to_filelist_recursively(char *origpath, unsigned char level) free(path); return; } else if ((len == 1) && (path[0] == '-')) { - D(("Addig stdin (-) to filelist\n")); - filelist = gib_list_add_front(filelist, feh_file_new(path)); + D(("Adding temporary file for stdin (-) to filelist\n")); + add_stdin_to_filelist(); free(path); return; } else if (opt.filelistfile) { diff --git a/src/imlib.c b/src/imlib.c index bdf54ac..98a91be 100644 --- a/src/imlib.c +++ b/src/imlib.c @@ -61,7 +61,6 @@ int num_xinerama_screens; int childpid = 0; -static char *feh_stdin_load_image(); static char *feh_http_load_image(char *url); static char *feh_magick_load_image(char *filename); @@ -210,7 +209,7 @@ void feh_imlib_print_load_error(char *file, winwidget w, Imlib_Load_Error err) int feh_load_image(Imlib_Image * im, feh_file * file) { Imlib_Load_Error err; - enum { SRC_IMLIB, SRC_HTTP, SRC_MAGICK, SRC_STDIN } image_source = + enum { SRC_IMLIB, SRC_HTTP, SRC_MAGICK } image_source = SRC_IMLIB; char *tmpname = NULL; char *real_filename = NULL; @@ -227,10 +226,6 @@ int feh_load_image(Imlib_Image * im, feh_file * file) tmpname = feh_http_load_image(file->filename); } - if ((strlen(file->filename) == 1) && (file->filename[0] == '-')) { - image_source = SRC_STDIN; - tmpname = feh_stdin_load_image(); - } else *im = imlib_load_image_with_error_return(file->filename, &err); @@ -275,38 +270,6 @@ int feh_load_image(Imlib_Image * im, feh_file * file) return(1); } -static char *feh_stdin_load_image() -{ - char buf[1024]; - size_t readsize; - char *sfn = estrjoin("_", "/tmp/feh_stdin", "XXXXXX", NULL); - int fd = mkstemp(sfn); - FILE *outfile; - - if (fd == -1) { - free(sfn); - return NULL; - } - - outfile = fdopen(fd, "w"); - - if (outfile == NULL) { - free(sfn); - return NULL; - } - - while ((readsize = fread(buf, sizeof(char), sizeof(buf), stdin)) > 0) { - if (fwrite(buf, sizeof(char), readsize, outfile) < readsize) { - free(sfn); - return NULL; - } - } - - fclose(outfile); - - return sfn; -} - static char *feh_magick_load_image(char *filename) { char argv_fd[12]; -- cgit v1.2.3 From 71eb9b41250c907398ee8be426a9e5e450abe06c Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Fri, 8 Feb 2013 19:20:18 +0100 Subject: delete temporary stdin-files when exiting --- src/filelist.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/filelist.c b/src/filelist.c index 0aafa64..bbde98c 100644 --- a/src/filelist.c +++ b/src/filelist.c @@ -186,6 +186,7 @@ static void add_stdin_to_filelist() fclose(outfile); filelist = gib_list_add_front(filelist, feh_file_new(sfn)); + add_file_to_rm_filelist(sfn); free(sfn); } -- cgit v1.2.3 From a889a9f9a866f5dea241773f04d52fafd3ab0175 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Fri, 8 Feb 2013 22:31:29 +0100 Subject: fix imlib2 and x11 warnings when opening a URL that returned an HTTP error --- ChangeLog | 2 ++ src/imlib.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 561abfd..f4abf3c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,8 @@ git HEAD * Add --sort mtime option (patch by guns) * Add a desktop file (installed to share/applications/feh.desktop) * Use "feh -" to read image from stdin + * Fix Imlib2 and X11 warnings when opening a URL that returned an HTTP + error Mon, 24 Dec 2012 15:45:54 +0100 Daniel Friesel diff --git a/src/imlib.c b/src/imlib.c index 98a91be..2425050 100644 --- a/src/imlib.c +++ b/src/imlib.c @@ -224,7 +224,8 @@ int feh_load_image(Imlib_Image * im, feh_file * file) || (!strncmp(file->filename, "ftp://", 6))) { image_source = SRC_HTTP; - tmpname = feh_http_load_image(file->filename); + if ((tmpname = feh_http_load_image(file->filename)) == NULL) + err = IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST; } else *im = imlib_load_image_with_error_return(file->filename, &err); -- cgit v1.2.3 From acae8f069e69a7abd34910820c58570bf7b3d89f Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Sat, 9 Feb 2013 14:55:32 +0100 Subject: feh(1): stdin now behaves when used with other files / filelists --- man/feh.pre | 2 -- 1 file changed, 2 deletions(-) diff --git a/man/feh.pre b/man/feh.pre index a1df25a..706146f 100644 --- a/man/feh.pre +++ b/man/feh.pre @@ -74,8 +74,6 @@ disk, the new filelist can then be saved to the disk and reopened at a later time. An image can also be read from stdin via .Qq feh - . -However, you should not combine reading from stdin with normal file / filelist -usage. . .Pp . -- cgit v1.2.3 From 2bb1b9e35cd1984e8e5529873bcf0713058914b4 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Tue, 12 Feb 2013 20:24:30 +0100 Subject: patch by sdaau: button bindings for zoom in / out --- ChangeLog | 1 + examples/buttons | 4 ++++ man/feh.pre | 9 +++++++++ src/events.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/options.h | 2 ++ 5 files changed, 76 insertions(+) diff --git a/ChangeLog b/ChangeLog index f4abf3c..fbb1aac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,7 @@ git HEAD * Use "feh -" to read image from stdin * Fix Imlib2 and X11 warnings when opening a URL that returned an HTTP error + * Add button bindings to zoom in / out (patch by sdaau) Mon, 24 Dec 2012 15:45:54 +0100 Daniel Friesel diff --git a/examples/buttons b/examples/buttons index e625f9e..3c79413 100644 --- a/examples/buttons +++ b/examples/buttons @@ -11,3 +11,7 @@ # Switch menu and zoom keys, useful for two-button touchpads menu 2 zoom 3 + +# make scroll wheel (mousewheel up and down) zoom, instead of flipping images +zoom_in 4 +zoom_out 5 \ No newline at end of file diff --git a/man/feh.pre b/man/feh.pre index 706146f..14dfdc9 100644 --- a/man/feh.pre +++ b/man/feh.pre @@ -1376,6 +1376,15 @@ Blur current image . Rotate current image . +.It unbound Bq zoom_in +. +Zoom in +. +.It unbound Bq zoom_out +. +Zoom out +. +. .El . . diff --git a/src/events.c b/src/events.c index dcd1aa1..fadae9b 100644 --- a/src/events.c +++ b/src/events.c @@ -152,6 +152,10 @@ void init_buttonbindings(void) cur_bb = &buttons.blur; else if (!strcmp(action, "rotate")) cur_bb = &buttons.rotate; + else if (!strcmp(action, "zoom_in")) + cur_bb = &buttons.zoom_in; + else if (!strcmp(action, "zoom_out")) + cur_bb = &buttons.zoom_out; else weprintf("buttons: Invalid action: %s", action); @@ -246,6 +250,62 @@ static void feh_event_handle_ButtonPress(XEvent * ev) winwid->im_click_offset_y = (winwid->click_offset_y - winwid->im_y) / winwid->old_zoom; + } else if (feh_is_bb(&buttons.zoom_in, button, state)) { + D(("Zoom_In Button Press event\n")); + D(("click offset is %d,%d\n", ev->xbutton.x, ev->xbutton.y)); + winwid->click_offset_x = ev->xbutton.x; + winwid->click_offset_y = ev->xbutton.y; + winwid->old_zoom = winwid->zoom; + + /* required to adjust the image position in zoom mode */ + winwid->im_click_offset_x = (winwid->click_offset_x + - winwid->im_x) / winwid->old_zoom; + winwid->im_click_offset_y = (winwid->click_offset_y + - winwid->im_y) / winwid->old_zoom; + + /* copied from zoom_in, keyevents.c */ + winwid->zoom = winwid->zoom * 1.25; + + if (winwid->zoom > ZOOM_MAX) + winwid->zoom = ZOOM_MAX; + + /* copied from below (ZOOM, feh_event_handle_MotionNotify) */ + winwid->im_x = winwid->click_offset_x + - (winwid->im_click_offset_x * winwid->zoom); + winwid->im_y = winwid->click_offset_y + - (winwid->im_click_offset_y * winwid->zoom); + + winwidget_sanitise_offsets(winwid); + winwidget_render_image(winwid, 0, 0); + + } else if (feh_is_bb(&buttons.zoom_out, button, state)) { + D(("Zoom_Out Button Press event\n")); + D(("click offset is %d,%d\n", ev->xbutton.x, ev->xbutton.y)); + winwid->click_offset_x = ev->xbutton.x; + winwid->click_offset_y = ev->xbutton.y; + winwid->old_zoom = winwid->zoom; + + /* required to adjust the image position in zoom mode */ + winwid->im_click_offset_x = (winwid->click_offset_x + - winwid->im_x) / winwid->old_zoom; + winwid->im_click_offset_y = (winwid->click_offset_y + - winwid->im_y) / winwid->old_zoom; + + /* copied from zoom_out, keyevents.c */ + winwid->zoom = winwid->zoom * 0.80; + + if (winwid->zoom < ZOOM_MIN) + winwid->zoom = ZOOM_MIN; + + /* copied from below (ZOOM, feh_event_handle_MotionNotify) */ + winwid->im_x = winwid->click_offset_x + - (winwid->im_click_offset_x * winwid->zoom); + winwid->im_y = winwid->click_offset_y + - (winwid->im_click_offset_y * winwid->zoom); + + winwidget_sanitise_offsets(winwid); + winwidget_render_image(winwid, 0, 0); + } else if (feh_is_bb(&buttons.reload, button, state)) { D(("Reload Button Press event\n")); feh_reload_image(winwid, 0, 1); diff --git a/src/options.h b/src/options.h index f3f49eb..27d3d38 100644 --- a/src/options.h +++ b/src/options.h @@ -207,6 +207,8 @@ struct __fehbb { struct __fehbutton menu; struct __fehbutton blur; struct __fehbutton rotate; + struct __fehbutton zoom_in; + struct __fehbutton zoom_out; }; void init_parse_options(int argc, char **argv); -- cgit v1.2.3 From fc11253d85202e8733a709a5acbb8e09358d1054 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Wed, 13 Feb 2013 01:47:16 +0100 Subject: release v2.9 --- ChangeLog | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index fbb1aac..842c208 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,6 @@ -git HEAD +Wed, 13 Feb 2013 01:46:56 +0100 Daniel Friesel + +* Release v2.9 * Add --keep-zoom-vp option to keep zoom and offsets when switching images (patch by sdaau). Press 'k' to toggle it. * Add --sort mtime option (patch by guns) -- cgit v1.2.3 From 5dfdc0bc15e49f7c091aad123cf1b03f55d936cb Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Thu, 14 Feb 2013 12:12:56 +0100 Subject: Determine active Xinerama screen by pointer position --- ChangeLog | 5 +++++ src/imlib.c | 27 +++++++++++++++++++++++---- src/winwidget.c | 17 +++++++++++------ 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 842c208..bd69368 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +git HEAD + + * Set correct window dimensions on any Xinerama screen, not just the + first one (active screen is determined by current pointer location) + Wed, 13 Feb 2013 01:46:56 +0100 Daniel Friesel * Release v2.9 diff --git a/src/imlib.c b/src/imlib.c index 2425050..5514a34 100644 --- a/src/imlib.c +++ b/src/imlib.c @@ -68,13 +68,32 @@ static char *feh_magick_load_image(char *filename); void init_xinerama(void) { if (opt.xinerama && XineramaIsActive(disp)) { - int major, minor; + int major, minor, px, py, i; + + /* discarded */ + Window dw; + int di; + unsigned int du; + + XineramaQueryVersion(disp, &major, &minor); + xinerama_screens = XineramaQueryScreens(disp, &num_xinerama_screens); + if (getenv("XINERAMA_SCREEN")) xinerama_screen = atoi(getenv("XINERAMA_SCREEN")); - else + else { xinerama_screen = 0; - XineramaQueryVersion(disp, &major, &minor); - xinerama_screens = XineramaQueryScreens(disp, &num_xinerama_screens); + XQueryPointer(disp, root, &dw, &dw, &px, &py, &di, &di, &du); + for (i = 0; i < num_xinerama_screens; i++) { + if (XY_IN_RECT(px, py, + xinerama_screens[i].x_org, + xinerama_screens[i].y_org, + xinerama_screens[i].width, + xinerama_screens[i].height)) { + xinerama_screen = i; + break; + } + } + } } } #endif /* HAVE_LIBXINERAMA */ diff --git a/src/winwidget.c b/src/winwidget.c index 2f543df..ada4c02 100644 --- a/src/winwidget.c +++ b/src/winwidget.c @@ -780,23 +780,28 @@ void winwidget_move(winwidget winwid, int x, int y) void winwidget_resize(winwidget winwid, int w, int h) { - Window ignored_window; XWindowAttributes attributes; - int tc_x, tc_y; + int tc_x, tc_y, px, py; int scr_width = scr->width; int scr_height = scr->height; + /* discarded */ + Window dw; + int di, i; + unsigned int du; + XGetWindowAttributes(disp, winwid->win, &attributes); #ifdef HAVE_LIBXINERAMA if (opt.xinerama && xinerama_screens) { - int i; xinerama_screen = 0; + XQueryPointer(disp, root, &dw, &dw, &px, &py, &di, &di, &du); for (i = 0; i < num_xinerama_screens; i++) { - if (XY_IN_RECT(attributes.x, attributes.y, + if (XY_IN_RECT(px, py, xinerama_screens[i].x_org, xinerama_screens[i].y_org, - xinerama_screens[i].width, xinerama_screens[i].height)) { + xinerama_screens[i].width, + xinerama_screens[i].height)) { xinerama_screen = i; break; } @@ -828,7 +833,7 @@ void winwidget_resize(winwidget winwid, int w, int h) XTranslateCoordinates(disp, winwid->win, attributes.root, -attributes.border_width - attributes.x, - -attributes.border_width - attributes.y, &tc_x, &tc_y, &ignored_window); + -attributes.border_width - attributes.y, &tc_x, &tc_y, &dw); winwid->x = tc_x; winwid->y = tc_y; XMoveResizeWindow(disp, winwid->win, tc_x, tc_y, winwid->w, winwid->h); -- cgit v1.2.3 From 43a7d315ae6952e096ae3a0351273c5639377870 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Thu, 14 Feb 2013 12:52:23 +0100 Subject: release v2.9.1 --- ChangeLog | 3 +- TODO | 192 +----------------------------------------------------------- man/feh.pre | 4 -- 3 files changed, 3 insertions(+), 196 deletions(-) diff --git a/ChangeLog b/ChangeLog index bd69368..462a701 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ -git HEAD +Thu, 14 Feb 2013 12:52:02 +0100 Daniel Friesel +* Release v2.9.1 * Set correct window dimensions on any Xinerama screen, not just the first one (active screen is determined by current pointer location) diff --git a/TODO b/TODO index f7dbbac..27846ab 100644 --- a/TODO +++ b/TODO @@ -1,191 +1 @@ -# open issues on derf/feh -5. various Xinerama issues --------------------------- -From TODO: -On screen 1, it will work if fullscreen is turned off, the window is rendered -and moved so that its top corner is only on screen 1, and then fullscreen is -turned on (after that, it'll work for all images in the slideshow). - state: open - user: derf - votes: 0 - created: 2010/08/21 11:08:12 -0700 - updated: 2011/08/30 00:38:44 -0700 - comments: 3 - -9. feh fails for massive images -------------------------------- -At first I thought this was a single-band TIFF image problem but when I -starting playing with resizing things I noticed feh becoming happy.. so I -started twiddling until I was right between the edge of failing and working: - -By massive I mean the original image is: 30691x30661 - -Playing with resizing to various gets me: -23325x23302 fails (76%) -23018x22995 good (75%) - -Next phase was to make sure it wasn't just the TIFF libraries.. so converted -the TIFFs to PNG -tifftopnm | pnmtopng > - -Same behavior - the 76 fails, 75 works. Trying one more time this time -converting to JPG for a last sanity check. - -Feh blows up with No Imlib2 loader for that file format on the 76 but the 75 -works. Gimp opens both images (in any of the formats) fine (considering the -size of the images). XV opens all sizes fine. - -I can't distribute the raw (source TIFF) imagery (licensing issue) but I can -provide the JPG and PNG files for others to confirm the behavior. - -http://beef.gina.alaska.edu/pub/feh-testing/ - -I put the 75 and 76 as PNG and JPG there along with the original as a PNG. - -Running feh 1.9-21-gbeecfaf from github on a FC13 x86_64 machine. - state: open - user: dayne - votes: 1 - created: 2010/10/06 16:22:25 -0700 - updated: 2011/11/14 00:50:59 -0800 - comments: 4 - -12. "Reverse" --scale-down (zoom images to screen size) -------------------------------------------------------- -Requested by mail: - -Don't go fullscreen, but do make the window as big as possible (either max out -width or height) and zoom the image in to fit if necessary. -So, it's like --scale-down, but zooming in, not out. - -This can already partially be achieved by combining --auto-zoom and --geometry -/ the "Freeze Window Size" menu setting. - state: open - user: derf - votes: 0 - created: 2010/10/14 09:44:25 -0700 - updated: 2011/04/12 11:48:05 -0700 - comments: 0 - -24. maybe: include giblib directly into feh -------------------------------------------- -There are only three programs using giblib, one of them is feh. And feh only -uses a part of giblib. So including those parts into the source and removing -the dependency might be an idea - state: open - user: derf - votes: 0 - created: 2011/01/17 11:54:17 -0800 - updated: 2011/11/29 13:34:35 -0800 - comments: 2 - -67. receive commands from the terminal that started feh -------------------------------------------------------- -I am running feh on a remote machine by starting it from a ssh terminal. I -expected to be able to use the shortcuts in the terminal just as I would when -feh is running localy. Feh does output to the terminal (e.g. when a filetype -isn't supported) but it doesn't react to input from the terminal. Apparently I -can use SIGUSR1 and SIGUSR2 to go back and forth between images but it would be -much easier if feh would just react to keyboard input from the terminal. - state: open - user: tinus - votes: 0 - created: 2011/10/05 04:51:59 -0700 - updated: 2011/11/27 18:52:11 -0800 - comments: 5 - -72. --scale-down: account for window decorations ------------------------------------------------- -Reported by mail: Apparently, --scale-down does not take window decorations -into consideration when calculating the maximum -window size. Gotta fix that. - state: open - user: derf - votes: 0 - created: 2011/11/17 12:47:32 -0800 - updated: 2011/11/27 18:59:58 -0800 - comments: 1 - -75. image opened by thumbnail mode is in position 0 of the filelist -------------------------------------------------------------------- -1. -$ feh -tSsize /path/to/images/ - -2. -click on an image - -what i expected: -the image opens in slideshow mode, in filelist specified by command( -/path/to/images/ ), in order specified by command (-Ssize, sort by size) - -what happened: -the image opens in slideshow mode, -press d, that's what it draws: -/path/to/images/someimage.jpg -0 of number_of_file_in_filelist -press n -nothing happens -press p -nothing happens -press home/end/....etc -nothing - state: open - user: lolnameless - votes: 0 - created: 2011/12/07 11:34:11 -0800 - updated: 2011/12/08 14:35:24 -0800 - comments: 1 - -78. toggle_fullscreen action assigned to mouse button not working ------------------------------------------------------------------ -Is it possible to assign keys actions to mouse buttons? Installed newest -source, compiled on Fedora 14, tried toggle_fullscreen 1 in mouse -configuration, disables keyboard v key and no actions for mouse button. Urgent -feature for touchscreen implementations to configure all key actions for 1st -and 3rd mouse buttons. - state: open - user: rolandas - votes: 0 - created: 2012/01/25 07:45:04 -0800 - updated: 2012/01/27 00:53:05 -0800 - comments: 2 - -81. zoom, scale-down etc. are a huge mess ------------------------------------------ -* when using feh --scale-down, the middle button toggles between zoom 100% and -zoom to fit. It should only set zoom to 100% -* --scale-down: removing the zoom = 1.001 workaround from keyevents.c, zoom -100% -> zoom in / out breaks -* same for events.c, except there's no workaround in place - state: open - user: derf - votes: 0 - created: 2012/03/06 04:12:09 -0800 - comments: 0 - -82. feh loads movies with convert ---------------------------------- -feh loads movies with convert. That takes a very long time, because I only have -5 gigabytes of RAM. (pun intended) That is probably an unintended "feature" -introduced by commit ba08d4b25fcbcd4e16388673184cf4d179dbd420. - -For my needs it would be best if I could disable the call to convert by default -(maybe a new config file?), while providing a command line argument reenabling -the convert feature. (for the rare occasions when I use really obscure file -formats) - state: open - user: pyropeter - votes: 0 - created: 2012/03/07 13:25:32 -0800 - updated: 2012/03/10 06:49:16 -0800 - comments: 3 - -83. add keybindings for brightness / contrast adjustment --------------------------------------------------------- -Requested by mail: for example, b/B for brightness and k/K for contrast. - state: open - user: derf - votes: 0 - created: 2012/03/10 05:40:36 -0800 - comments: 0 - +See diff --git a/man/feh.pre b/man/feh.pre index 14dfdc9..23fdfce 100644 --- a/man/feh.pre +++ b/man/feh.pre @@ -1575,10 +1575,6 @@ section. . .Sh BUGS . -In a Xinerama setup, fullscreen mode only works properly on screen 0. Set -.Ev XINERAMA_SCREEN -to the correct screen number or toggle fullscreen off, then on as a workaround. -. .Pp . Thumbnail mode is somewhat inefficient, and because of that not nearly as fast -- cgit v1.2.3