From 1ce11b6307b1c0cc1ab75547fcb5ea63daf72bfe Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Wed, 12 Apr 2017 21:20:34 +0100 Subject: Add generic list container --- src/list.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/list.h | 48 ++++++++++++++++++++++++++ src/util.c | 1 - 3 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 src/list.c create mode 100644 src/list.h (limited to 'src') diff --git a/src/list.c b/src/list.c new file mode 100644 index 0000000..03195e0 --- /dev/null +++ b/src/list.c @@ -0,0 +1,111 @@ +/* Copyright (c) 2017 imv authors + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "list.h" + +struct imv_list *imv_list_create(void) +{ + struct imv_list *list = malloc(sizeof(struct imv_list)); + list->len = 0; + list->cap = 64; + list->items = malloc(sizeof(void*) * list->cap); + return list; +} + +void imv_list_free(struct imv_list *list) +{ + free(list->items); +} + +void imv_list_deep_free(struct imv_list *list) +{ + for(size_t i = 0; i < list->len; ++i) { + free(list->items[i]); + } + imv_list_free(list); +} + +void imv_list_append(struct imv_list *list, void *item) +{ + imv_list_grow(list, list->len + 1); + list->items[list->len++] = item; +} + +void imv_list_grow(struct imv_list *list, size_t min_size) +{ + if(list->cap >= min_size) { + return; + } + + while(list->cap < min_size) { + list->cap *= 2; + } + + list->items = realloc(list->items, sizeof(void*) * list->cap); +} + +void imv_list_remove(struct imv_list *list, size_t index) +{ + if(index >= list->len) { + return; + } + + memmove(&list->items[index], &list->items[index + 1], list->len - index); + + list->len -= 1; +} + +void imv_list_insert(struct imv_list *list, size_t index, void *item) +{ + imv_list_grow(list, list->len + 1); + + if(index > list->len) { + index = list->len; + } + + memmove(&list->items[index + 1], &list->items[index], list->len - index); + list->items[index] = item; + list->len += 1; +} + +struct imv_list *imv_split_string(const char *string, char delim) +{ + struct imv_list *list = imv_list_create(); + + const char *base = string; + + while(*base) { + while(*base && *base == delim) { + ++base; + } + + const char *end = base; + while(*end && *end != delim) { + ++end; + } + + if(*base && base != end) { + char *item = strndup(base, end - base); + imv_list_append(list, item); + base = end; + } + } + + return list; +} + +/* vim:set ts=2 sts=2 sw=2 et: */ diff --git a/src/list.h b/src/list.h new file mode 100644 index 0000000..a329e6d --- /dev/null +++ b/src/list.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2017 imv authors + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef LIST_H +#define LIST_H + +#include +#include + +struct imv_list { + size_t len; + size_t cap; + void **items; +}; + +struct imv_list *imv_list_create(void); + +void imv_list_free(struct imv_list *list); + +void imv_list_deep_free(struct imv_list *list); + +void imv_list_append(struct imv_list *list, void *item); + +void imv_list_grow(struct imv_list *list, size_t min_size); + +void imv_list_remove(struct imv_list *list, size_t index); + +void imv_list_insert(struct imv_list *list, size_t index, void *item); + +struct imv_list *imv_split_string(const char *string, char delim); + +#endif + +/* vim:set ts=2 sts=2 sw=2 et: */ diff --git a/src/util.c b/src/util.c index 75d6910..9b2b867 100644 --- a/src/util.c +++ b/src/util.c @@ -153,5 +153,4 @@ void imv_printf(SDL_Renderer *renderer, TTF_Font *font, int x, int y, va_end(args); } - /* vim:set ts=2 sts=2 sw=2 et: */ -- cgit v1.2.3 From ad33be42c0192a491cce10c1771ed8e2ac1d0196 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Wed, 12 Apr 2017 22:16:41 +0100 Subject: Add basic command system --- src/commands.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/commands.h | 26 ++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 src/commands.c create mode 100644 src/commands.h (limited to 'src') diff --git a/src/commands.c b/src/commands.c new file mode 100644 index 0000000..9b93933 --- /dev/null +++ b/src/commands.c @@ -0,0 +1,64 @@ +/* Copyright (c) 2017 imv authors + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "commands.h" +#include "list.h" + +struct imv_command { + const char* command; + void (*handler)(struct imv_list *args); +}; + +struct imv_list *g_commands = NULL; + +void imv_command_register(const char *command, void (*handler)()) +{ + if(!g_commands) { + g_commands = imv_list_create(); + } + + struct imv_command *cmd = malloc(sizeof(struct imv_command)); + cmd->command = strdup(command); + cmd->handler = handler; + imv_list_append(g_commands, cmd); +} + +int imv_command_exec(const char *command) +{ + if(!g_commands) { + return 1; + } + + struct imv_list *args = imv_split_string(command, ' '); + int ret = 1; + + if(args->len > 0) { + for(size_t i = 0; i < g_commands->len; ++i) { + struct imv_command *cmd = g_commands->items[i]; + if(!strcmp(cmd->command, args->items[0])) { + cmd->handler(args); + ret = 0; + break; + } + } + } + + imv_list_deep_free(args); + return ret; +} + +/* vim:set ts=2 sts=2 sw=2 et: */ diff --git a/src/commands.h b/src/commands.h new file mode 100644 index 0000000..1dfa3bf --- /dev/null +++ b/src/commands.h @@ -0,0 +1,26 @@ +/* Copyright (c) 2017 imv authors + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef COMMANDS_H +#define COMMANDS_H + +void imv_command_register(const char *command, void (*handler)()); +int imv_command_exec(const char *command); + +#endif + +/* vim:set ts=2 sts=2 sw=2 et: */ -- cgit v1.2.3 From 66e6f2edc4abe7ef1ac33e0707b860568f59296b Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Wed, 12 Apr 2017 22:00:49 +0100 Subject: Move basic functionality into commands --- src/main.c | 322 ++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 200 insertions(+), 122 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 1e3df67..8a5ba78 100644 --- a/src/main.c +++ b/src/main.c @@ -28,6 +28,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include +#include "commands.h" +#include "list.h" #include "loader.h" #include "texture.h" #include "navigator.h" @@ -170,10 +172,44 @@ static void parse_args(int argc, char** argv) } } +struct { + struct imv_navigator nav; + struct imv_loader ldr; + struct imv_texture tex; + struct imv_viewport view; + SDL_Window *window; + SDL_Renderer *renderer; + int quit; + + /* used to calculate when to skip to the next image in slideshow mode */ + unsigned long delay_msec; + + /* do we need to redraw the window? */ + int need_redraw; + int need_rescale; +} g_state; + +void cmd_quit(struct imv_list *args); +void cmd_pan(struct imv_list *args); +void cmd_select_rel(struct imv_list *args); +void cmd_select_abs(struct imv_list *args); +void cmd_zoom(struct imv_list *args); +void cmd_remove(struct imv_list *args); +void cmd_fullscreen(struct imv_list *args); +void cmd_overlay(struct imv_list *args); + int main(int argc, char** argv) { - struct imv_navigator nav; - imv_navigator_init(&nav); + imv_command_register("quit", &cmd_quit); + imv_command_register("pan", &cmd_pan); + imv_command_register("select_rel", &cmd_select_rel); + imv_command_register("select_abs", &cmd_select_abs); + imv_command_register("zoom", &cmd_zoom); + imv_command_register("remove", &cmd_remove); + imv_command_register("fullscreen", &cmd_fullscreen); + imv_command_register("overlay", &cmd_overlay); + + imv_navigator_init(&g_state.nav); /* parse any command line options given */ parse_args(argc, argv); @@ -202,8 +238,8 @@ int main(int argc, char** argv) buf[--len] = 0; } if(len > 0) { - if(imv_navigator_add(&nav, buf, g_options.recursive) != 0) { - imv_navigator_destroy(&nav); + if(imv_navigator_add(&g_state.nav, buf, g_options.recursive) != 0) { + imv_navigator_destroy(&g_state.nav); exit(1); } break; @@ -237,25 +273,25 @@ int main(int argc, char** argv) errno = 0; /* clear errno */ } /* add the given path to the list to load */ - if(imv_navigator_add(&nav, argv[i], g_options.recursive) != 0) { - imv_navigator_destroy(&nav); + if(imv_navigator_add(&g_state.nav, argv[i], g_options.recursive) != 0) { + imv_navigator_destroy(&g_state.nav); exit(1); } } /* if we weren't given any paths we have nothing to view. exit */ - if(!imv_navigator_selection(&nav)) { + if(!imv_navigator_selection(&g_state.nav)) { fprintf(stderr, "No input files. Exiting.\n"); exit(1); } /* go to the chosen starting image if possible */ if(g_options.start_at) { - int start_index = imv_navigator_find_path(&nav, g_options.start_at); + int start_index = imv_navigator_find_path(&g_state.nav, g_options.start_at); if(start_index < 0) { start_index = strtol(g_options.start_at,NULL,10) - 1; } - imv_navigator_select_str(&nav, start_index); + imv_navigator_select_str(&g_state.nav, start_index); } /* we've got something to display, so create an SDL window */ @@ -269,23 +305,23 @@ int main(int argc, char** argv) const int width = 1280; const int height = 720; - SDL_Window *window = SDL_CreateWindow( + g_state.window = SDL_CreateWindow( "imv", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_RESIZABLE); - if(!window) { + if(!g_state.window) { fprintf(stderr, "SDL Failed to create window: %s\n", SDL_GetError()); SDL_Quit(); exit(1); } /* we'll use SDL's built-in renderer, hardware accelerated if possible */ - SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0); - if(!renderer) { + g_state.renderer = SDL_CreateRenderer(g_state.window, -1, 0); + if(!g_state.renderer) { fprintf(stderr, "SDL Failed to create renderer: %s\n", SDL_GetError()); - SDL_DestroyWindow(window); + SDL_DestroyWindow(g_state.window); SDL_Quit(); exit(1); } @@ -297,7 +333,7 @@ int main(int argc, char** argv) /* construct a chequered background texture */ SDL_Texture *chequered_tex = NULL; if(!g_options.solid_bg) { - chequered_tex = create_chequered(renderer); + chequered_tex = create_chequered(g_state.renderer); } /* set up the required fonts and surfaces for displaying the overlay */ @@ -308,18 +344,15 @@ int main(int argc, char** argv) } /* create our main classes on the stack*/ - struct imv_loader ldr; - imv_init_loader(&ldr); + imv_init_loader(&g_state.ldr); - struct imv_texture tex; - imv_init_texture(&tex, renderer); + imv_init_texture(&g_state.tex, g_state.renderer); - struct imv_viewport view; - imv_init_viewport(&view, window); + imv_init_viewport(&g_state.view, g_state.window); /* put us in fullscren mode to begin with if requested */ if(g_options.fullscreen) { - imv_viewport_toggle_fullscreen(&view); + imv_viewport_toggle_fullscreen(&g_state.view); } /* help keeping track of time */ @@ -329,56 +362,50 @@ int main(int argc, char** argv) /* keep file change polling rate under control */ static uint8_t poll_countdown = UINT8_MAX; - /* do we need to redraw the window? */ - int need_redraw = 1; - int need_rescale = 0; + g_state.need_redraw = 1; + g_state.need_rescale = 0; /* keep title buffer around for reuse */ char title[256]; - /* used to calculate when to skip to the next image in slideshow mode */ - unsigned long delay_msec = 0; + g_state.delay_msec = 0; /* initialize variables holding image dimentions */ int iw = 0, ih = 0; - int quit = 0; - while(!quit) { + g_state.quit = 0; + while(!g_state.quit) { /* handle any input/window events sent by SDL */ SDL_Event e; - while(!quit && SDL_PollEvent(&e)) { + while(!g_state.quit && SDL_PollEvent(&e)) { switch(e.type) { case SDL_QUIT: - quit = 1; + imv_command_exec("quit"); break; case SDL_KEYDOWN: SDL_ShowCursor(SDL_DISABLE); switch (e.key.keysym.sym) { case SDLK_q: - quit = 1; + imv_command_exec("quit"); break; case SDLK_LEFTBRACKET: case SDLK_LEFT: - imv_navigator_select_rel(&nav, -1); - /* reset slideshow delay */ - delay_msec = 0; + imv_command_exec("select_rel -1"); break; case SDLK_RIGHTBRACKET: case SDLK_RIGHT: - imv_navigator_select_rel(&nav, 1); - /* reset slideshow delay */ - delay_msec = 0; + imv_command_exec("select_rel 1"); break; case SDLK_EQUALS: case SDLK_PLUS: case SDLK_i: case SDLK_UP: - imv_viewport_zoom(&view, &tex, IMV_ZOOM_KEYBOARD, 1); + imv_viewport_zoom(&g_state.view, &g_state.tex, IMV_ZOOM_KEYBOARD, 1); break; case SDLK_MINUS: case SDLK_o: case SDLK_DOWN: - imv_viewport_zoom(&view, &tex, IMV_ZOOM_KEYBOARD, -1); + imv_viewport_zoom(&g_state.view, &g_state.tex, IMV_ZOOM_KEYBOARD, -1); break; case SDLK_s: if(!e.key.repeat) { @@ -389,71 +416,58 @@ int main(int argc, char** argv) /* FALLTHROUGH */ case SDLK_r: if(!e.key.repeat) { - need_rescale = 1; - need_redraw = 1; + g_state.need_rescale = 1; + g_state.need_redraw = 1; } break; case SDLK_a: if(!e.key.repeat) { - imv_viewport_scale_to_actual(&view, &tex); + imv_viewport_scale_to_actual(&g_state.view, &g_state.tex); } break; case SDLK_c: if(!e.key.repeat) { - imv_viewport_center(&view, &tex); + imv_viewport_center(&g_state.view, &g_state.tex); } break; case SDLK_j: - imv_viewport_move(&view, 0, -50); + imv_command_exec("pan 0 -50"); break; case SDLK_k: - imv_viewport_move(&view, 0, 50); + imv_command_exec("pan 0 50"); break; case SDLK_h: - imv_viewport_move(&view, 50, 0); + imv_command_exec("pan 50 0"); break; case SDLK_l: - imv_viewport_move(&view, -50, 0); + imv_command_exec("pan -50 0"); break; case SDLK_x: if(!e.key.repeat) { - char* path = strdup(imv_navigator_selection(&nav)); - imv_navigator_remove(&nav, path); - - if (SDL_GetModState() & KMOD_SHIFT) { - if (remove(path)) { - fprintf(stderr, "Warning: can't remove %s from disk.\n", path); - } - } - - free(path); - - /* reset slideshow delay */ - delay_msec = 0; + imv_command_exec("remove"); } break; case SDLK_f: if(!e.key.repeat) { - imv_viewport_toggle_fullscreen(&view); + imv_command_exec("fullscreen"); } break; case SDLK_PERIOD: - imv_loader_load_next_frame(&ldr); + imv_loader_load_next_frame(&g_state.ldr); break; case SDLK_SPACE: if(!e.key.repeat) { - imv_viewport_toggle_playing(&view); + imv_viewport_toggle_playing(&g_state.view); } break; case SDLK_p: if(!e.key.repeat) { - puts(imv_navigator_selection(&nav)); + puts(imv_navigator_selection(&g_state.nav)); } break; case SDLK_d: if(!e.key.repeat) { - g_options.overlay = !g_options.overlay; - need_redraw = 1; + imv_command_exec("overlay"); } break; case SDLK_t: @@ -464,35 +478,35 @@ int main(int argc, char** argv) } else { g_options.delay += 1000; } - need_redraw = 1; + g_state.need_redraw = 1; break; } break; case SDL_MOUSEWHEEL: - imv_viewport_zoom(&view, &tex, IMV_ZOOM_MOUSE, e.wheel.y); + imv_viewport_zoom(&g_state.view, &g_state.tex, IMV_ZOOM_MOUSE, e.wheel.y); SDL_ShowCursor(SDL_ENABLE); break; case SDL_MOUSEMOTION: if(e.motion.state & SDL_BUTTON_LMASK) { - imv_viewport_move(&view, e.motion.xrel, e.motion.yrel); + imv_viewport_move(&g_state.view, e.motion.xrel, e.motion.yrel); } SDL_ShowCursor(SDL_ENABLE); break; case SDL_WINDOWEVENT: - imv_viewport_update(&view, &tex); + imv_viewport_update(&g_state.view, &g_state.tex); break; } } /* if we're quitting, don't bother drawing any more images */ - if(quit) { + if(g_state.quit) { break; } /* check if an image failed to load, if so, remove it from our image list */ - char *err_path = imv_loader_get_error(&ldr); + char *err_path = imv_loader_get_error(&g_state.ldr); if(err_path) { - imv_navigator_remove(&nav, err_path); + imv_navigator_remove(&g_state.nav, err_path); if (strncmp(err_path, "-", 2) == 0) { free(stdin_buffer); stdin_buffer_size = 0; @@ -506,13 +520,13 @@ int main(int argc, char** argv) } /* Check if navigator wrapped around paths lists */ - if(!g_options.cycle && imv_navigator_wrapped(&nav)) { + if(!g_options.cycle && imv_navigator_wrapped(&g_state.nav)) { break; } /* if the user has changed image, start loading the new one */ - if(imv_navigator_poll_changed(&nav, poll_countdown--)) { - const char *current_path = imv_navigator_selection(&nav); + if(imv_navigator_poll_changed(&g_state.nav, poll_countdown--)) { + const char *current_path = imv_navigator_selection(&g_state.nav); if(!current_path) { if(g_options.stdin_list) { continue; @@ -522,37 +536,37 @@ int main(int argc, char** argv) } snprintf(title, sizeof(title), "imv - [%i/%i] [LOADING] %s [%s]", - nav.cur_path + 1, nav.num_paths, current_path, + g_state.nav.cur_path + 1, g_state.nav.num_paths, current_path, scaling_label[g_options.scaling]); - imv_viewport_set_title(&view, title); + imv_viewport_set_title(&g_state.view, title); - imv_loader_load(&ldr, current_path, stdin_buffer, stdin_buffer_size); - view.playing = 1; + imv_loader_load(&g_state.ldr, current_path, stdin_buffer, stdin_buffer_size); + g_state.view.playing = 1; } /* get window height and width */ int ww, wh; - SDL_GetWindowSize(window, &ww, &wh); + SDL_GetWindowSize(g_state.window, &ww, &wh); /* check if a new image is available to display */ FIBITMAP *bmp; int is_new_image; - if(imv_loader_get_image(&ldr, &bmp, &is_new_image)) { - imv_texture_set_image(&tex, bmp); + if(imv_loader_get_image(&g_state.ldr, &bmp, &is_new_image)) { + imv_texture_set_image(&g_state.tex, bmp); iw = FreeImage_GetWidth(bmp); ih = FreeImage_GetHeight(bmp); FreeImage_Unload(bmp); - need_redraw = 1; - need_rescale += is_new_image; + g_state.need_redraw = 1; + g_state.need_rescale += is_new_image; } - if(need_rescale) { - need_rescale = 0; + if(g_state.need_rescale) { + g_state.need_rescale = 0; if(g_options.scaling == NONE || (g_options.scaling == DOWN && ww > iw && wh > ih)) { - imv_viewport_scale_to_actual(&view, &tex); + imv_viewport_scale_to_actual(&g_state.view, &g_state.tex); } else { - imv_viewport_scale_to_window(&view, &tex); + imv_viewport_scale_to_window(&g_state.view, &g_state.tex); } } @@ -560,7 +574,7 @@ int main(int argc, char** argv) /* if we're playing an animated gif, tell the loader how much time has * passed */ - if(view.playing) { + if(g_state.view.playing) { unsigned int dt = current_time - last_time; /* We cap the delta-time to 100 ms so that if imv is asleep for several * seconds or more (e.g. suspended), upon waking up it doesn't try to @@ -568,49 +582,49 @@ int main(int argc, char** argv) if(dt > 100) { dt = 100; } - imv_loader_time_passed(&ldr, dt / 1000.0); + imv_loader_time_passed(&g_state.ldr, dt / 1000.0); } /* handle slideshow */ if(g_options.delay) { unsigned int dt = current_time - last_time; - delay_msec += dt; - need_redraw = 1; - if(delay_msec >= g_options.delay) { - imv_navigator_select_rel(&nav, 1); - delay_msec = 0; + g_state.delay_msec += dt; + g_state.need_redraw = 1; + if(g_state.delay_msec >= g_options.delay) { + imv_navigator_select_rel(&g_state.nav, 1); + g_state.delay_msec = 0; } } last_time = current_time; /* check if the viewport needs a redraw */ - if(imv_viewport_needs_redraw(&view)) { - need_redraw = 1; + if(imv_viewport_needs_redraw(&g_state.view)) { + g_state.need_redraw = 1; } /* only redraw when something's changed */ - if(need_redraw) { + if(g_state.need_redraw) { /* update window title */ int len; - const char *current_path = imv_navigator_selection(&nav); + const char *current_path = imv_navigator_selection(&g_state.nav); len = snprintf(title, sizeof(title), "imv - [%i/%i] [%ix%i] [%.2f%%] %s [%s]", - nav.cur_path + 1, nav.num_paths, tex.width, tex.height, - 100.0 * view.scale, + g_state.nav.cur_path + 1, g_state.nav.num_paths, g_state.tex.width, g_state.tex.height, + 100.0 * g_state.view.scale, current_path, scaling_label[g_options.scaling]); if(g_options.delay >= 1000) { len += snprintf(title + len, sizeof(title) - len, "[%lu/%lus]", - delay_msec / 1000 + 1, g_options.delay / 1000); + g_state.delay_msec / 1000 + 1, g_options.delay / 1000); } - imv_viewport_set_title(&view, title); + imv_viewport_set_title(&g_state.view, title); /* first we draw the background */ if(g_options.solid_bg) { /* solid background */ - SDL_SetRenderDrawColor(renderer, + SDL_SetRenderDrawColor(g_state.renderer, g_options.bg_r, g_options.bg_g, g_options.bg_b, 255); - SDL_RenderClear(renderer); + SDL_RenderClear(g_state.renderer); } else { /* chequered background */ int img_w, img_h; @@ -619,30 +633,30 @@ int main(int argc, char** argv) for(int y = 0; y < wh; y += img_h) { for(int x = 0; x < ww; x += img_w) { SDL_Rect dst_rect = {x,y,img_w,img_h}; - SDL_RenderCopy(renderer, chequered_tex, NULL, &dst_rect); + SDL_RenderCopy(g_state.renderer, chequered_tex, NULL, &dst_rect); } } } /* draw our actual texture */ - imv_texture_draw(&tex, view.x, view.y, view.scale); + imv_texture_draw(&g_state.tex, g_state.view.x, g_state.view.y, g_state.view.scale); /* if the overlay needs to be drawn, draw that too */ if(g_options.overlay && font) { SDL_Color fg = {255,255,255,255}; SDL_Color bg = {0,0,0,160}; - imv_printf(renderer, font, 0, 0, &fg, &bg, "%s", + imv_printf(g_state.renderer, font, 0, 0, &fg, &bg, "%s", title + strlen("imv - ")); } /* redraw complete, unset the flag */ - need_redraw = 0; + g_state.need_redraw = 0; /* reset poll countdown timer */ poll_countdown = UINT8_MAX; /* tell SDL to show the newly drawn frame */ - SDL_RenderPresent(renderer); + SDL_RenderPresent(g_state.renderer); } /* sleep a little bit so we don't waste CPU time */ @@ -668,10 +682,10 @@ int main(int argc, char** argv) buf[--len] = 0; } if(len > 0) { - if(imv_navigator_add(&nav, buf, g_options.recursive)) { + if(imv_navigator_add(&g_state.nav, buf, g_options.recursive)) { break; } - need_redraw = 1; + g_state.need_redraw = 1; } } } else { @@ -679,18 +693,18 @@ int main(int argc, char** argv) } } while(g_options.list) { - const char *path = imv_navigator_selection(&nav); + const char *path = imv_navigator_selection(&g_state.nav); if(!path) { break; } fprintf(stdout, "%s\n", path); - imv_navigator_remove(&nav, path); + imv_navigator_remove(&g_state.nav, path); } /* clean up our resources now that we're exiting */ - imv_destroy_loader(&ldr); - imv_destroy_texture(&tex); - imv_navigator_destroy(&nav); - imv_destroy_viewport(&view); + imv_destroy_loader(&g_state.ldr); + imv_destroy_texture(&g_state.tex); + imv_navigator_destroy(&g_state.nav); + imv_destroy_viewport(&g_state.view); if(font) { TTF_CloseFont(font); @@ -699,12 +713,76 @@ int main(int argc, char** argv) if(chequered_tex) { SDL_DestroyTexture(chequered_tex); } - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(window); + SDL_DestroyRenderer(g_state.renderer); + SDL_DestroyWindow(g_state.window); SDL_Quit(); return 0; } +void cmd_quit(struct imv_list *args) +{ + (void)args; + g_state.quit = 1; +} + +void cmd_pan(struct imv_list *args) +{ + if(args->len != 3) { + return; + } + + long int x = strtol(args->items[1], NULL, 10); + long int y = strtol(args->items[2], NULL, 10); + + imv_viewport_move(&g_state.view, x, y); +} + +void cmd_select_rel(struct imv_list *args) +{ + if(args->len != 2) { + return; + } + + long int index = strtol(args->items[1], NULL, 10); + imv_navigator_select_rel(&g_state.nav, index); + + /* reset slideshow delay */ + g_state.delay_msec = 0; +} + +void cmd_select_abs(struct imv_list *args) +{ + (void)args; +} + +void cmd_zoom(struct imv_list *args) +{ + (void)args; +} + +void cmd_remove(struct imv_list *args) +{ + (void)args; + char* path = strdup(imv_navigator_selection(&g_state.nav)); + imv_navigator_remove(&g_state.nav, path); + free(path); + + /* reset slideshow delay */ + g_state.delay_msec = 0; +} + +void cmd_fullscreen(struct imv_list *args) +{ + (void)args; + imv_viewport_toggle_fullscreen(&g_state.view); +} + +void cmd_overlay(struct imv_list *args) +{ + (void)args; + g_options.overlay = !g_options.overlay; + g_state.need_redraw = 1; +} /* vim:set ts=2 sts=2 sw=2 et: */ -- cgit v1.2.3 From 83959687adbd90303ee2ff630f659b8994000808 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Fri, 14 Apr 2017 16:17:21 +0100 Subject: Add a rough command mode --- src/main.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'src') diff --git a/src/main.c b/src/main.c index 8a5ba78..1318e8f 100644 --- a/src/main.c +++ b/src/main.c @@ -187,6 +187,9 @@ struct { /* do we need to redraw the window? */ int need_redraw; int need_rescale; + + /* buffer for command input - NULL when not in command mode */ + char *command_buffer; } g_state; void cmd_quit(struct imv_list *args); @@ -370,6 +373,9 @@ int main(int argc, char** argv) g_state.delay_msec = 0; + /* start outside of command mode */ + g_state.command_buffer = NULL; + /* initialize variables holding image dimentions */ int iw = 0, ih = 0; @@ -382,9 +388,48 @@ int main(int argc, char** argv) case SDL_QUIT: imv_command_exec("quit"); break; + case SDL_KEYDOWN: SDL_ShowCursor(SDL_DISABLE); + + if(g_state.command_buffer) { + /* in command mode, update the buffer */ + if(e.key.keysym.sym == SDLK_ESCAPE) { + free(g_state.command_buffer); + g_state.command_buffer = NULL; + g_state.need_redraw = 1; + } else if(e.key.keysym.sym == SDLK_RETURN) { + imv_command_exec(g_state.command_buffer); + free(g_state.command_buffer); + g_state.command_buffer = NULL; + g_state.need_redraw = 1; + } else if(e.key.keysym.sym == SDLK_BACKSPACE) { + const size_t len = strlen(g_state.command_buffer); + if(len > 0) { + g_state.command_buffer[len - 1] = '\0'; + g_state.need_redraw = 1; + } + } else if(e.key.keysym.sym >= ' ' && e.key.keysym.sym <= '~') { + const size_t len = strlen(g_state.command_buffer); + if(len + 1 < 1024) { + g_state.command_buffer[len] = e.key.keysym.sym; + g_state.command_buffer[len+1] = '\0'; + g_state.need_redraw = 1; + } + } + + /* input has been consumed by command input, move onto next event */ + continue; + } + switch (e.key.keysym.sym) { + case SDLK_SEMICOLON: + if(e.key.keysym.mod & KMOD_SHIFT) { + g_state.command_buffer = malloc(1024); + g_state.command_buffer[0] = '\0'; + g_state.need_redraw = 1; + } + break; case SDLK_q: imv_command_exec("quit"); break; @@ -649,6 +694,17 @@ int main(int argc, char** argv) title + strlen("imv - ")); } + /* draw command entry bar if needed */ + if(g_state.command_buffer && font) { + SDL_Color fg = {255,255,255,255}; + SDL_Color bg = {0,0,0,160}; + imv_printf(g_state.renderer, + font, + 0, wh - TTF_FontHeight(font), + &fg, &bg, + ":%s", g_state.command_buffer); + } + /* redraw complete, unset the flag */ g_state.need_redraw = 0; @@ -700,7 +756,12 @@ int main(int argc, char** argv) fprintf(stdout, "%s\n", path); imv_navigator_remove(&g_state.nav, path); } + /* clean up our resources now that we're exiting */ + if(g_state.command_buffer) { + free(g_state.command_buffer); + } + imv_destroy_loader(&g_state.ldr); imv_destroy_texture(&g_state.tex); imv_navigator_destroy(&g_state.nav); -- cgit v1.2.3 From b46385618eb6c2e6ee468c672c6824259d97add2 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Fri, 14 Apr 2017 16:23:50 +0100 Subject: Add basic alias support --- src/commands.c | 23 +++++++++++++++++++++-- src/commands.h | 1 + 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/commands.c b/src/commands.c index 9b93933..f9a4ff3 100644 --- a/src/commands.c +++ b/src/commands.c @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. struct imv_command { const char* command; void (*handler)(struct imv_list *args); + const char* alias; }; struct imv_list *g_commands = NULL; @@ -34,6 +35,20 @@ void imv_command_register(const char *command, void (*handler)()) struct imv_command *cmd = malloc(sizeof(struct imv_command)); cmd->command = strdup(command); cmd->handler = handler; + cmd->alias = NULL; + imv_list_append(g_commands, cmd); +} + +void imv_command_alias(const char *command, const char *alias) +{ + if(!g_commands) { + g_commands = imv_list_create(); + } + + struct imv_command *cmd = malloc(sizeof(struct imv_command)); + cmd->command = strdup(command); + cmd->handler = NULL; + cmd->alias = strdup(alias); imv_list_append(g_commands, cmd); } @@ -50,8 +65,12 @@ int imv_command_exec(const char *command) for(size_t i = 0; i < g_commands->len; ++i) { struct imv_command *cmd = g_commands->items[i]; if(!strcmp(cmd->command, args->items[0])) { - cmd->handler(args); - ret = 0; + if(cmd->handler) { + cmd->handler(args); + ret = 0; + } else if(cmd->alias) { + ret = imv_command_exec(cmd->alias); + } break; } } diff --git a/src/commands.h b/src/commands.h index 1dfa3bf..b3a78e6 100644 --- a/src/commands.h +++ b/src/commands.h @@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define COMMANDS_H void imv_command_register(const char *command, void (*handler)()); +void imv_command_alias(const char *command, const char *alias); int imv_command_exec(const char *command); #endif -- cgit v1.2.3 From 93f68f6b4c2212a80492274b9aea9a9fb43d7ec4 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Fri, 14 Apr 2017 16:23:58 +0100 Subject: Add some aliases --- src/main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/main.c b/src/main.c index 1318e8f..9ad0531 100644 --- a/src/main.c +++ b/src/main.c @@ -212,6 +212,12 @@ int main(int argc, char** argv) imv_command_register("fullscreen", &cmd_fullscreen); imv_command_register("overlay", &cmd_overlay); + imv_command_alias("q", "quit"); + imv_command_alias("next", "select_rel 1"); + imv_command_alias("previous", "select_rel -1"); + imv_command_alias("n", "select_rel 1"); + imv_command_alias("p", "select_rel -1"); + imv_navigator_init(&g_state.nav); /* parse any command line options given */ -- cgit v1.2.3 From 50759fb279b38c5db7cacf88206188b827f564b2 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Fri, 14 Apr 2017 16:44:07 +0100 Subject: Let's not have imv_commands use hidden globals --- src/commands.c | 55 +++++++++++++++++++++++++++++++------------------------ src/commands.h | 14 +++++++++++--- src/main.c | 55 +++++++++++++++++++++++++++++-------------------------- 3 files changed, 71 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/commands.c b/src/commands.c index f9a4ff3..a3a59b1 100644 --- a/src/commands.c +++ b/src/commands.c @@ -18,58 +18,65 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "commands.h" #include "list.h" -struct imv_command { - const char* command; +struct command { + char* command; void (*handler)(struct imv_list *args); - const char* alias; + char* alias; }; -struct imv_list *g_commands = NULL; +struct imv_commands *imv_commands_create(void) +{ + struct imv_commands *cmds = malloc(sizeof(struct imv_commands)); + cmds->command_list = imv_list_create(); + return cmds; +} -void imv_command_register(const char *command, void (*handler)()) +void imv_commands_free(struct imv_commands *cmds) { - if(!g_commands) { - g_commands = imv_list_create(); + for(size_t i = 0; i < cmds->command_list->len; ++i) { + struct command *cmd = cmds->command_list->items[i]; + free(cmd->command); + if(cmd->alias) { + free(cmd->alias); + } + free(cmd); } + imv_list_free(cmds->command_list); + free(cmds); +} - struct imv_command *cmd = malloc(sizeof(struct imv_command)); +void imv_command_register(struct imv_commands *cmds, const char *command, void (*handler)()) +{ + struct command *cmd = malloc(sizeof(struct command)); cmd->command = strdup(command); cmd->handler = handler; cmd->alias = NULL; - imv_list_append(g_commands, cmd); + imv_list_append(cmds->command_list, cmd); } -void imv_command_alias(const char *command, const char *alias) +void imv_command_alias(struct imv_commands *cmds, const char *command, const char *alias) { - if(!g_commands) { - g_commands = imv_list_create(); - } - - struct imv_command *cmd = malloc(sizeof(struct imv_command)); + struct command *cmd = malloc(sizeof(struct command)); cmd->command = strdup(command); cmd->handler = NULL; cmd->alias = strdup(alias); - imv_list_append(g_commands, cmd); + imv_list_append(cmds->command_list, cmd); } -int imv_command_exec(const char *command) +int imv_command_exec(struct imv_commands *cmds, const char *command) { - if(!g_commands) { - return 1; - } - struct imv_list *args = imv_split_string(command, ' '); int ret = 1; if(args->len > 0) { - for(size_t i = 0; i < g_commands->len; ++i) { - struct imv_command *cmd = g_commands->items[i]; + for(size_t i = 0; i < cmds->command_list->len; ++i) { + struct command *cmd = cmds->command_list->items[i]; if(!strcmp(cmd->command, args->items[0])) { if(cmd->handler) { cmd->handler(args); ret = 0; } else if(cmd->alias) { - ret = imv_command_exec(cmd->alias); + ret = imv_command_exec(cmds, cmd->alias); } break; } diff --git a/src/commands.h b/src/commands.h index b3a78e6..df8b43b 100644 --- a/src/commands.h +++ b/src/commands.h @@ -18,9 +18,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef COMMANDS_H #define COMMANDS_H -void imv_command_register(const char *command, void (*handler)()); -void imv_command_alias(const char *command, const char *alias); -int imv_command_exec(const char *command); +struct imv_list; + +struct imv_commands { + struct imv_list *command_list; +}; + +struct imv_commands *imv_commands_create(void); +void imv_commands_free(struct imv_commands *cmds); +void imv_command_register(struct imv_commands *cmds, const char *command, void (*handler)()); +void imv_command_alias(struct imv_commands *cmds, const char *command, const char *alias); +int imv_command_exec(struct imv_commands *cmds, const char *command); #endif diff --git a/src/main.c b/src/main.c index 9ad0531..56971c1 100644 --- a/src/main.c +++ b/src/main.c @@ -177,6 +177,7 @@ struct { struct imv_loader ldr; struct imv_texture tex; struct imv_viewport view; + struct imv_commands *cmds; SDL_Window *window; SDL_Renderer *renderer; int quit; @@ -203,20 +204,21 @@ void cmd_overlay(struct imv_list *args); int main(int argc, char** argv) { - imv_command_register("quit", &cmd_quit); - imv_command_register("pan", &cmd_pan); - imv_command_register("select_rel", &cmd_select_rel); - imv_command_register("select_abs", &cmd_select_abs); - imv_command_register("zoom", &cmd_zoom); - imv_command_register("remove", &cmd_remove); - imv_command_register("fullscreen", &cmd_fullscreen); - imv_command_register("overlay", &cmd_overlay); - - imv_command_alias("q", "quit"); - imv_command_alias("next", "select_rel 1"); - imv_command_alias("previous", "select_rel -1"); - imv_command_alias("n", "select_rel 1"); - imv_command_alias("p", "select_rel -1"); + g_state.cmds = imv_commands_create(); + imv_command_register(g_state.cmds, "quit", &cmd_quit); + imv_command_register(g_state.cmds, "pan", &cmd_pan); + imv_command_register(g_state.cmds, "select_rel", &cmd_select_rel); + imv_command_register(g_state.cmds, "select_abs", &cmd_select_abs); + imv_command_register(g_state.cmds, "zoom", &cmd_zoom); + imv_command_register(g_state.cmds, "remove", &cmd_remove); + imv_command_register(g_state.cmds, "fullscreen", &cmd_fullscreen); + imv_command_register(g_state.cmds, "overlay", &cmd_overlay); + + imv_command_alias(g_state.cmds, "q", "quit"); + imv_command_alias(g_state.cmds, "next", "select_rel 1"); + imv_command_alias(g_state.cmds, "previous", "select_rel -1"); + imv_command_alias(g_state.cmds, "n", "select_rel 1"); + imv_command_alias(g_state.cmds, "p", "select_rel -1"); imv_navigator_init(&g_state.nav); @@ -392,7 +394,7 @@ int main(int argc, char** argv) while(!g_state.quit && SDL_PollEvent(&e)) { switch(e.type) { case SDL_QUIT: - imv_command_exec("quit"); + imv_command_exec(g_state.cmds, "quit"); break; case SDL_KEYDOWN: @@ -405,7 +407,7 @@ int main(int argc, char** argv) g_state.command_buffer = NULL; g_state.need_redraw = 1; } else if(e.key.keysym.sym == SDLK_RETURN) { - imv_command_exec(g_state.command_buffer); + imv_command_exec(g_state.cmds, g_state.command_buffer); free(g_state.command_buffer); g_state.command_buffer = NULL; g_state.need_redraw = 1; @@ -437,15 +439,15 @@ int main(int argc, char** argv) } break; case SDLK_q: - imv_command_exec("quit"); + imv_command_exec(g_state.cmds, "quit"); break; case SDLK_LEFTBRACKET: case SDLK_LEFT: - imv_command_exec("select_rel -1"); + imv_command_exec(g_state.cmds, "select_rel -1"); break; case SDLK_RIGHTBRACKET: case SDLK_RIGHT: - imv_command_exec("select_rel 1"); + imv_command_exec(g_state.cmds, "select_rel 1"); break; case SDLK_EQUALS: case SDLK_PLUS: @@ -482,25 +484,25 @@ int main(int argc, char** argv) } break; case SDLK_j: - imv_command_exec("pan 0 -50"); + imv_command_exec(g_state.cmds, "pan 0 -50"); break; case SDLK_k: - imv_command_exec("pan 0 50"); + imv_command_exec(g_state.cmds, "pan 0 50"); break; case SDLK_h: - imv_command_exec("pan 50 0"); + imv_command_exec(g_state.cmds, "pan 50 0"); break; case SDLK_l: - imv_command_exec("pan -50 0"); + imv_command_exec(g_state.cmds, "pan -50 0"); break; case SDLK_x: if(!e.key.repeat) { - imv_command_exec("remove"); + imv_command_exec(g_state.cmds, "remove"); } break; case SDLK_f: if(!e.key.repeat) { - imv_command_exec("fullscreen"); + imv_command_exec(g_state.cmds, "fullscreen"); } break; case SDLK_PERIOD: @@ -518,7 +520,7 @@ int main(int argc, char** argv) break; case SDLK_d: if(!e.key.repeat) { - imv_command_exec("overlay"); + imv_command_exec(g_state.cmds, "overlay"); } break; case SDLK_t: @@ -772,6 +774,7 @@ int main(int argc, char** argv) imv_destroy_texture(&g_state.tex); imv_navigator_destroy(&g_state.nav); imv_destroy_viewport(&g_state.view); + imv_commands_free(g_state.cmds); if(font) { TTF_CloseFont(font); -- cgit v1.2.3 From 5a8932cb21f63af86dffa419ec5da5f4a5d29d70 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Fri, 14 Apr 2017 16:49:17 +0100 Subject: Refactor loader to new style --- src/loader.c | 7 +++++-- src/loader.h | 8 ++++---- src/main.c | 18 +++++++++--------- test/loader.c | 15 ++++++++------- 4 files changed, 26 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/loader.c b/src/loader.c index d70b66d..c5b64a6 100644 --- a/src/loader.c +++ b/src/loader.c @@ -44,15 +44,17 @@ static int is_thread_cancelled(void) return sigismember(&sigmask, SIGUSR1); } -void imv_init_loader(struct imv_loader *ldr) +struct imv_loader *imv_loader_create(void) { + struct imv_loader *ldr = malloc(sizeof(struct imv_loader)); memset(ldr, 0, sizeof(struct imv_loader)); pthread_mutex_init(&ldr->lock, NULL); /* ignore this signal in case we accidentally receive it */ block_usr1_signal(); + return ldr; } -void imv_destroy_loader(struct imv_loader *ldr) +void imv_loader_free(struct imv_loader *ldr) { /* wait for any existing bg thread to finish */ pthread_join(ldr->bg_thread, NULL); @@ -70,6 +72,7 @@ void imv_destroy_loader(struct imv_loader *ldr) if(ldr->path) { free(ldr->path); } + free(ldr); } void imv_loader_load(struct imv_loader *ldr, const char *path, diff --git a/src/loader.h b/src/loader.h index d2418a2..04dc640 100644 --- a/src/loader.h +++ b/src/loader.h @@ -44,11 +44,11 @@ struct imv_loader { double frame_time; }; -/* Initialises an instance of imv_loader */ -void imv_init_loader(struct imv_loader *img); +/* Creates an instance of imv_loader */ +struct imv_loader *imv_loader_create(void); -/* Cleans up all resources owned by a imv_loader instance */ -void imv_destroy_loader(struct imv_loader *img); +/* Cleans up an imv_loader instance */ +void imv_loader_free(struct imv_loader *ldr); /* Asynchronously load the given file */ void imv_loader_load(struct imv_loader *ldr, const char *path, diff --git a/src/main.c b/src/main.c index 56971c1..e2c0654 100644 --- a/src/main.c +++ b/src/main.c @@ -174,7 +174,7 @@ static void parse_args(int argc, char** argv) struct { struct imv_navigator nav; - struct imv_loader ldr; + struct imv_loader *ldr; struct imv_texture tex; struct imv_viewport view; struct imv_commands *cmds; @@ -354,8 +354,8 @@ int main(int argc, char** argv) fprintf(stderr, "Error loading font: %s\n", TTF_GetError()); } - /* create our main classes on the stack*/ - imv_init_loader(&g_state.ldr); + /* create our main classes */ + g_state.ldr = imv_loader_create(); imv_init_texture(&g_state.tex, g_state.renderer); @@ -506,7 +506,7 @@ int main(int argc, char** argv) } break; case SDLK_PERIOD: - imv_loader_load_next_frame(&g_state.ldr); + imv_loader_load_next_frame(g_state.ldr); break; case SDLK_SPACE: if(!e.key.repeat) { @@ -557,7 +557,7 @@ int main(int argc, char** argv) } /* check if an image failed to load, if so, remove it from our image list */ - char *err_path = imv_loader_get_error(&g_state.ldr); + char *err_path = imv_loader_get_error(g_state.ldr); if(err_path) { imv_navigator_remove(&g_state.nav, err_path); if (strncmp(err_path, "-", 2) == 0) { @@ -593,7 +593,7 @@ int main(int argc, char** argv) scaling_label[g_options.scaling]); imv_viewport_set_title(&g_state.view, title); - imv_loader_load(&g_state.ldr, current_path, stdin_buffer, stdin_buffer_size); + imv_loader_load(g_state.ldr, current_path, stdin_buffer, stdin_buffer_size); g_state.view.playing = 1; } @@ -604,7 +604,7 @@ int main(int argc, char** argv) /* check if a new image is available to display */ FIBITMAP *bmp; int is_new_image; - if(imv_loader_get_image(&g_state.ldr, &bmp, &is_new_image)) { + if(imv_loader_get_image(g_state.ldr, &bmp, &is_new_image)) { imv_texture_set_image(&g_state.tex, bmp); iw = FreeImage_GetWidth(bmp); ih = FreeImage_GetHeight(bmp); @@ -635,7 +635,7 @@ int main(int argc, char** argv) if(dt > 100) { dt = 100; } - imv_loader_time_passed(&g_state.ldr, dt / 1000.0); + imv_loader_time_passed(g_state.ldr, dt / 1000.0); } /* handle slideshow */ @@ -770,7 +770,7 @@ int main(int argc, char** argv) free(g_state.command_buffer); } - imv_destroy_loader(&g_state.ldr); + imv_loader_free(g_state.ldr); imv_destroy_texture(&g_state.tex); imv_navigator_destroy(&g_state.nav); imv_destroy_viewport(&g_state.view); diff --git a/test/loader.c b/test/loader.c index bbbb8d7..e8791c0 100644 --- a/test/loader.c +++ b/test/loader.c @@ -10,24 +10,25 @@ static void test_jpeg_rotation(void **state) { (void)state; - struct imv_loader ldr; + struct imv_loader *ldr = imv_loader_create(); void *retval; char *error; unsigned int width; - imv_init_loader(&ldr); - imv_loader_load(&ldr, "test/orientation.jpg", NULL, 0); - pthread_join(ldr.bg_thread, &retval); + imv_loader_load(ldr, "test/orientation.jpg", NULL, 0); + pthread_join(ldr->bg_thread, &retval); - error = imv_loader_get_error(&ldr); + error = imv_loader_get_error(ldr); assert_false(error); assert_false(retval == PTHREAD_CANCELED); - assert_false(ldr.out_bmp == NULL); + assert_false(ldr->out_bmp == NULL); - width = FreeImage_GetWidth(ldr.out_bmp); + width = FreeImage_GetWidth(ldr->out_bmp); assert_true(width == 1); + + imv_loader_free(ldr); } int main(void) -- cgit v1.2.3 From b9dd2cbc01bdd071fc44db771187d12860191d13 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Fri, 14 Apr 2017 16:56:06 +0100 Subject: Refactor texture to new style --- src/main.c | 29 ++++++++++++++--------------- src/texture.c | 7 +++++-- src/texture.h | 8 ++++---- 3 files changed, 23 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index e2c0654..2f13b33 100644 --- a/src/main.c +++ b/src/main.c @@ -175,7 +175,7 @@ static void parse_args(int argc, char** argv) struct { struct imv_navigator nav; struct imv_loader *ldr; - struct imv_texture tex; + struct imv_texture *tex; struct imv_viewport view; struct imv_commands *cmds; SDL_Window *window; @@ -356,8 +356,7 @@ int main(int argc, char** argv) /* create our main classes */ g_state.ldr = imv_loader_create(); - - imv_init_texture(&g_state.tex, g_state.renderer); + g_state.tex = imv_texture_create(g_state.renderer); imv_init_viewport(&g_state.view, g_state.window); @@ -453,12 +452,12 @@ int main(int argc, char** argv) case SDLK_PLUS: case SDLK_i: case SDLK_UP: - imv_viewport_zoom(&g_state.view, &g_state.tex, IMV_ZOOM_KEYBOARD, 1); + imv_viewport_zoom(&g_state.view, g_state.tex, IMV_ZOOM_KEYBOARD, 1); break; case SDLK_MINUS: case SDLK_o: case SDLK_DOWN: - imv_viewport_zoom(&g_state.view, &g_state.tex, IMV_ZOOM_KEYBOARD, -1); + imv_viewport_zoom(&g_state.view, g_state.tex, IMV_ZOOM_KEYBOARD, -1); break; case SDLK_s: if(!e.key.repeat) { @@ -475,12 +474,12 @@ int main(int argc, char** argv) break; case SDLK_a: if(!e.key.repeat) { - imv_viewport_scale_to_actual(&g_state.view, &g_state.tex); + imv_viewport_scale_to_actual(&g_state.view, g_state.tex); } break; case SDLK_c: if(!e.key.repeat) { - imv_viewport_center(&g_state.view, &g_state.tex); + imv_viewport_center(&g_state.view, g_state.tex); } break; case SDLK_j: @@ -536,7 +535,7 @@ int main(int argc, char** argv) } break; case SDL_MOUSEWHEEL: - imv_viewport_zoom(&g_state.view, &g_state.tex, IMV_ZOOM_MOUSE, e.wheel.y); + imv_viewport_zoom(&g_state.view, g_state.tex, IMV_ZOOM_MOUSE, e.wheel.y); SDL_ShowCursor(SDL_ENABLE); break; case SDL_MOUSEMOTION: @@ -546,7 +545,7 @@ int main(int argc, char** argv) SDL_ShowCursor(SDL_ENABLE); break; case SDL_WINDOWEVENT: - imv_viewport_update(&g_state.view, &g_state.tex); + imv_viewport_update(&g_state.view, g_state.tex); break; } } @@ -605,7 +604,7 @@ int main(int argc, char** argv) FIBITMAP *bmp; int is_new_image; if(imv_loader_get_image(g_state.ldr, &bmp, &is_new_image)) { - imv_texture_set_image(&g_state.tex, bmp); + imv_texture_set_image(g_state.tex, bmp); iw = FreeImage_GetWidth(bmp); ih = FreeImage_GetHeight(bmp); FreeImage_Unload(bmp); @@ -617,9 +616,9 @@ int main(int argc, char** argv) g_state.need_rescale = 0; if(g_options.scaling == NONE || (g_options.scaling == DOWN && ww > iw && wh > ih)) { - imv_viewport_scale_to_actual(&g_state.view, &g_state.tex); + imv_viewport_scale_to_actual(&g_state.view, g_state.tex); } else { - imv_viewport_scale_to_window(&g_state.view, &g_state.tex); + imv_viewport_scale_to_window(&g_state.view, g_state.tex); } } @@ -663,7 +662,7 @@ int main(int argc, char** argv) int len; const char *current_path = imv_navigator_selection(&g_state.nav); len = snprintf(title, sizeof(title), "imv - [%i/%i] [%ix%i] [%.2f%%] %s [%s]", - g_state.nav.cur_path + 1, g_state.nav.num_paths, g_state.tex.width, g_state.tex.height, + g_state.nav.cur_path + 1, g_state.nav.num_paths, g_state.tex->width, g_state.tex->height, 100.0 * g_state.view.scale, current_path, scaling_label[g_options.scaling]); if(g_options.delay >= 1000) { @@ -692,7 +691,7 @@ int main(int argc, char** argv) } /* draw our actual texture */ - imv_texture_draw(&g_state.tex, g_state.view.x, g_state.view.y, g_state.view.scale); + imv_texture_draw(g_state.tex, g_state.view.x, g_state.view.y, g_state.view.scale); /* if the overlay needs to be drawn, draw that too */ if(g_options.overlay && font) { @@ -771,7 +770,7 @@ int main(int argc, char** argv) } imv_loader_free(g_state.ldr); - imv_destroy_texture(&g_state.tex); + imv_texture_free(g_state.tex); imv_navigator_destroy(&g_state.nav); imv_destroy_viewport(&g_state.view); imv_commands_free(g_state.cmds); diff --git a/src/texture.c b/src/texture.c index 52ec521..bdfe91f 100644 --- a/src/texture.c +++ b/src/texture.c @@ -17,8 +17,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "texture.h" -void imv_init_texture(struct imv_texture *tex, SDL_Renderer *r) +struct imv_texture *imv_texture_create(SDL_Renderer *r) { + struct imv_texture *tex = malloc(sizeof(struct imv_texture)); memset(tex, 0, sizeof(struct imv_texture)); tex->renderer = r; @@ -26,9 +27,10 @@ void imv_init_texture(struct imv_texture *tex, SDL_Renderer *r) SDL_GetRendererInfo(r, &ri); tex->chunk_width = ri.max_texture_width != 0 ? ri.max_texture_width : 4096; tex->chunk_height = ri.max_texture_height != 0 ? ri.max_texture_height : 4096; + return tex; } -void imv_destroy_texture(struct imv_texture *tex) +void imv_texture_free(struct imv_texture *tex) { if(tex->num_chunks > 0) { for(int i = 0; i < tex->num_chunks; ++i) { @@ -39,6 +41,7 @@ void imv_destroy_texture(struct imv_texture *tex) tex->chunks = NULL; tex->renderer = NULL; } + free(tex); } int imv_texture_set_image(struct imv_texture *tex, FIBITMAP *image) diff --git a/src/texture.h b/src/texture.h index 4d2aea9..2931525 100644 --- a/src/texture.h +++ b/src/texture.h @@ -36,11 +36,11 @@ struct imv_texture { }; -/* Initialises an instance of imv_texture */ -void imv_init_texture(struct imv_texture *tex, SDL_Renderer *r); +/* Creates an instance of imv_texture */ +struct imv_texture *imv_texture_create(SDL_Renderer *r); -/* Cleans up all resources owned by a imv_texture instance */ -void imv_destroy_texture(struct imv_texture *tex); +/* Cleans up an imv_texture instance */ +void imv_texture_free(struct imv_texture *tex); /* Updates the texture to contain the data in the image parameter */ int imv_texture_set_image(struct imv_texture *tex, FIBITMAP *image); -- cgit v1.2.3 From e352474df09257342410e74e8fb686f424819b9a Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Fri, 14 Apr 2017 17:02:28 +0100 Subject: Refactor viewport to new style --- src/main.c | 47 +++++++++++++++++++++++------------------------ src/viewport.c | 9 +++++---- src/viewport.h | 8 ++++---- 3 files changed, 32 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 2f13b33..4006747 100644 --- a/src/main.c +++ b/src/main.c @@ -176,7 +176,7 @@ struct { struct imv_navigator nav; struct imv_loader *ldr; struct imv_texture *tex; - struct imv_viewport view; + struct imv_viewport *view; struct imv_commands *cmds; SDL_Window *window; SDL_Renderer *renderer; @@ -357,12 +357,11 @@ int main(int argc, char** argv) /* create our main classes */ g_state.ldr = imv_loader_create(); g_state.tex = imv_texture_create(g_state.renderer); - - imv_init_viewport(&g_state.view, g_state.window); + g_state.view = imv_viewport_create(g_state.window); /* put us in fullscren mode to begin with if requested */ if(g_options.fullscreen) { - imv_viewport_toggle_fullscreen(&g_state.view); + imv_viewport_toggle_fullscreen(g_state.view); } /* help keeping track of time */ @@ -452,12 +451,12 @@ int main(int argc, char** argv) case SDLK_PLUS: case SDLK_i: case SDLK_UP: - imv_viewport_zoom(&g_state.view, g_state.tex, IMV_ZOOM_KEYBOARD, 1); + imv_viewport_zoom(g_state.view, g_state.tex, IMV_ZOOM_KEYBOARD, 1); break; case SDLK_MINUS: case SDLK_o: case SDLK_DOWN: - imv_viewport_zoom(&g_state.view, g_state.tex, IMV_ZOOM_KEYBOARD, -1); + imv_viewport_zoom(g_state.view, g_state.tex, IMV_ZOOM_KEYBOARD, -1); break; case SDLK_s: if(!e.key.repeat) { @@ -474,12 +473,12 @@ int main(int argc, char** argv) break; case SDLK_a: if(!e.key.repeat) { - imv_viewport_scale_to_actual(&g_state.view, g_state.tex); + imv_viewport_scale_to_actual(g_state.view, g_state.tex); } break; case SDLK_c: if(!e.key.repeat) { - imv_viewport_center(&g_state.view, g_state.tex); + imv_viewport_center(g_state.view, g_state.tex); } break; case SDLK_j: @@ -509,7 +508,7 @@ int main(int argc, char** argv) break; case SDLK_SPACE: if(!e.key.repeat) { - imv_viewport_toggle_playing(&g_state.view); + imv_viewport_toggle_playing(g_state.view); } break; case SDLK_p: @@ -535,17 +534,17 @@ int main(int argc, char** argv) } break; case SDL_MOUSEWHEEL: - imv_viewport_zoom(&g_state.view, g_state.tex, IMV_ZOOM_MOUSE, e.wheel.y); + imv_viewport_zoom(g_state.view, g_state.tex, IMV_ZOOM_MOUSE, e.wheel.y); SDL_ShowCursor(SDL_ENABLE); break; case SDL_MOUSEMOTION: if(e.motion.state & SDL_BUTTON_LMASK) { - imv_viewport_move(&g_state.view, e.motion.xrel, e.motion.yrel); + imv_viewport_move(g_state.view, e.motion.xrel, e.motion.yrel); } SDL_ShowCursor(SDL_ENABLE); break; case SDL_WINDOWEVENT: - imv_viewport_update(&g_state.view, g_state.tex); + imv_viewport_update(g_state.view, g_state.tex); break; } } @@ -590,10 +589,10 @@ int main(int argc, char** argv) snprintf(title, sizeof(title), "imv - [%i/%i] [LOADING] %s [%s]", g_state.nav.cur_path + 1, g_state.nav.num_paths, current_path, scaling_label[g_options.scaling]); - imv_viewport_set_title(&g_state.view, title); + imv_viewport_set_title(g_state.view, title); imv_loader_load(g_state.ldr, current_path, stdin_buffer, stdin_buffer_size); - g_state.view.playing = 1; + g_state.view->playing = 1; } /* get window height and width */ @@ -616,9 +615,9 @@ int main(int argc, char** argv) g_state.need_rescale = 0; if(g_options.scaling == NONE || (g_options.scaling == DOWN && ww > iw && wh > ih)) { - imv_viewport_scale_to_actual(&g_state.view, g_state.tex); + imv_viewport_scale_to_actual(g_state.view, g_state.tex); } else { - imv_viewport_scale_to_window(&g_state.view, g_state.tex); + imv_viewport_scale_to_window(g_state.view, g_state.tex); } } @@ -626,7 +625,7 @@ int main(int argc, char** argv) /* if we're playing an animated gif, tell the loader how much time has * passed */ - if(g_state.view.playing) { + if(g_state.view->playing) { unsigned int dt = current_time - last_time; /* We cap the delta-time to 100 ms so that if imv is asleep for several * seconds or more (e.g. suspended), upon waking up it doesn't try to @@ -652,7 +651,7 @@ int main(int argc, char** argv) last_time = current_time; /* check if the viewport needs a redraw */ - if(imv_viewport_needs_redraw(&g_state.view)) { + if(imv_viewport_needs_redraw(g_state.view)) { g_state.need_redraw = 1; } @@ -663,13 +662,13 @@ int main(int argc, char** argv) const char *current_path = imv_navigator_selection(&g_state.nav); len = snprintf(title, sizeof(title), "imv - [%i/%i] [%ix%i] [%.2f%%] %s [%s]", g_state.nav.cur_path + 1, g_state.nav.num_paths, g_state.tex->width, g_state.tex->height, - 100.0 * g_state.view.scale, + 100.0 * g_state.view->scale, current_path, scaling_label[g_options.scaling]); if(g_options.delay >= 1000) { len += snprintf(title + len, sizeof(title) - len, "[%lu/%lus]", g_state.delay_msec / 1000 + 1, g_options.delay / 1000); } - imv_viewport_set_title(&g_state.view, title); + imv_viewport_set_title(g_state.view, title); /* first we draw the background */ if(g_options.solid_bg) { @@ -691,7 +690,7 @@ int main(int argc, char** argv) } /* draw our actual texture */ - imv_texture_draw(g_state.tex, g_state.view.x, g_state.view.y, g_state.view.scale); + imv_texture_draw(g_state.tex, g_state.view->x, g_state.view->y, g_state.view->scale); /* if the overlay needs to be drawn, draw that too */ if(g_options.overlay && font) { @@ -772,7 +771,7 @@ int main(int argc, char** argv) imv_loader_free(g_state.ldr); imv_texture_free(g_state.tex); imv_navigator_destroy(&g_state.nav); - imv_destroy_viewport(&g_state.view); + imv_viewport_free(g_state.view); imv_commands_free(g_state.cmds); if(font) { @@ -804,7 +803,7 @@ void cmd_pan(struct imv_list *args) long int x = strtol(args->items[1], NULL, 10); long int y = strtol(args->items[2], NULL, 10); - imv_viewport_move(&g_state.view, x, y); + imv_viewport_move(g_state.view, x, y); } void cmd_select_rel(struct imv_list *args) @@ -844,7 +843,7 @@ void cmd_remove(struct imv_list *args) void cmd_fullscreen(struct imv_list *args) { (void)args; - imv_viewport_toggle_fullscreen(&g_state.view); + imv_viewport_toggle_fullscreen(g_state.view); } void cmd_overlay(struct imv_list *args) diff --git a/src/viewport.c b/src/viewport.c index e706643..d096a45 100644 --- a/src/viewport.c +++ b/src/viewport.c @@ -17,19 +17,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "viewport.h" -void imv_init_viewport(struct imv_viewport *view, SDL_Window *window) +struct imv_viewport *imv_viewport_create(SDL_Window *window) { + struct imv_viewport *view = malloc(sizeof(struct imv_viewport)); view->window = window; view->scale = 1; view->x = view->y = view->fullscreen = view->redraw = 0; view->playing = 1; view->locked = 0; + return view; } -void imv_destroy_viewport(struct imv_viewport *view) +void imv_viewport_free(struct imv_viewport *view) { - view->window = NULL; - return; + free(view); } void imv_viewport_toggle_fullscreen(struct imv_viewport *view) diff --git a/src/viewport.h b/src/viewport.h index 0f19b85..d1803d4 100644 --- a/src/viewport.h +++ b/src/viewport.h @@ -37,11 +37,11 @@ enum imv_zoom_source { IMV_ZOOM_KEYBOARD }; -/* Initialises an instance of imv_viewport */ -void imv_init_viewport(struct imv_viewport *view, SDL_Window *window); +/* Creates an instance of imv_viewport */ +struct imv_viewport *imv_viewport_create(SDL_Window *window); -/* Cleans up all resources owned by a imv_viewport instance */ -void imv_destroy_viewport(struct imv_viewport *view); +/* Cleans up an imv_viewport instance */ +void imv_viewport_free(struct imv_viewport *view); /* Toggle their viewport's fullscreen mode. Triggers a redraw */ void imv_viewport_toggle_fullscreen(struct imv_viewport *view); -- cgit v1.2.3 From 4fde6ea289328b5f1668ceb69657e0c4a334b1fb Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Fri, 14 Apr 2017 17:10:23 +0100 Subject: Refactor navigator to new style --- src/main.c | 50 ++++++++++++++++++------------------- src/navigator.c | 8 +++--- src/navigator.h | 8 +++--- test/navigator.c | 76 +++++++++++++++++++++++++++----------------------------- 4 files changed, 71 insertions(+), 71 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 4006747..adee798 100644 --- a/src/main.c +++ b/src/main.c @@ -173,7 +173,7 @@ static void parse_args(int argc, char** argv) } struct { - struct imv_navigator nav; + struct imv_navigator *nav; struct imv_loader *ldr; struct imv_texture *tex; struct imv_viewport *view; @@ -220,7 +220,7 @@ int main(int argc, char** argv) imv_command_alias(g_state.cmds, "n", "select_rel 1"); imv_command_alias(g_state.cmds, "p", "select_rel -1"); - imv_navigator_init(&g_state.nav); + g_state.nav = imv_navigator_create(); /* parse any command line options given */ parse_args(argc, argv); @@ -249,8 +249,8 @@ int main(int argc, char** argv) buf[--len] = 0; } if(len > 0) { - if(imv_navigator_add(&g_state.nav, buf, g_options.recursive) != 0) { - imv_navigator_destroy(&g_state.nav); + if(imv_navigator_add(g_state.nav, buf, g_options.recursive) != 0) { + imv_navigator_free(g_state.nav); exit(1); } break; @@ -284,25 +284,25 @@ int main(int argc, char** argv) errno = 0; /* clear errno */ } /* add the given path to the list to load */ - if(imv_navigator_add(&g_state.nav, argv[i], g_options.recursive) != 0) { - imv_navigator_destroy(&g_state.nav); + if(imv_navigator_add(g_state.nav, argv[i], g_options.recursive) != 0) { + imv_navigator_free(g_state.nav); exit(1); } } /* if we weren't given any paths we have nothing to view. exit */ - if(!imv_navigator_selection(&g_state.nav)) { + if(!imv_navigator_selection(g_state.nav)) { fprintf(stderr, "No input files. Exiting.\n"); exit(1); } /* go to the chosen starting image if possible */ if(g_options.start_at) { - int start_index = imv_navigator_find_path(&g_state.nav, g_options.start_at); + int start_index = imv_navigator_find_path(g_state.nav, g_options.start_at); if(start_index < 0) { start_index = strtol(g_options.start_at,NULL,10) - 1; } - imv_navigator_select_str(&g_state.nav, start_index); + imv_navigator_select_str(g_state.nav, start_index); } /* we've got something to display, so create an SDL window */ @@ -513,7 +513,7 @@ int main(int argc, char** argv) break; case SDLK_p: if(!e.key.repeat) { - puts(imv_navigator_selection(&g_state.nav)); + puts(imv_navigator_selection(g_state.nav)); } break; case SDLK_d: @@ -557,7 +557,7 @@ int main(int argc, char** argv) /* check if an image failed to load, if so, remove it from our image list */ char *err_path = imv_loader_get_error(g_state.ldr); if(err_path) { - imv_navigator_remove(&g_state.nav, err_path); + imv_navigator_remove(g_state.nav, err_path); if (strncmp(err_path, "-", 2) == 0) { free(stdin_buffer); stdin_buffer_size = 0; @@ -571,13 +571,13 @@ int main(int argc, char** argv) } /* Check if navigator wrapped around paths lists */ - if(!g_options.cycle && imv_navigator_wrapped(&g_state.nav)) { + if(!g_options.cycle && imv_navigator_wrapped(g_state.nav)) { break; } /* if the user has changed image, start loading the new one */ - if(imv_navigator_poll_changed(&g_state.nav, poll_countdown--)) { - const char *current_path = imv_navigator_selection(&g_state.nav); + if(imv_navigator_poll_changed(g_state.nav, poll_countdown--)) { + const char *current_path = imv_navigator_selection(g_state.nav); if(!current_path) { if(g_options.stdin_list) { continue; @@ -587,7 +587,7 @@ int main(int argc, char** argv) } snprintf(title, sizeof(title), "imv - [%i/%i] [LOADING] %s [%s]", - g_state.nav.cur_path + 1, g_state.nav.num_paths, current_path, + g_state.nav->cur_path + 1, g_state.nav->num_paths, current_path, scaling_label[g_options.scaling]); imv_viewport_set_title(g_state.view, title); @@ -643,7 +643,7 @@ int main(int argc, char** argv) g_state.delay_msec += dt; g_state.need_redraw = 1; if(g_state.delay_msec >= g_options.delay) { - imv_navigator_select_rel(&g_state.nav, 1); + imv_navigator_select_rel(g_state.nav, 1); g_state.delay_msec = 0; } } @@ -659,9 +659,9 @@ int main(int argc, char** argv) if(g_state.need_redraw) { /* update window title */ int len; - const char *current_path = imv_navigator_selection(&g_state.nav); + const char *current_path = imv_navigator_selection(g_state.nav); len = snprintf(title, sizeof(title), "imv - [%i/%i] [%ix%i] [%.2f%%] %s [%s]", - g_state.nav.cur_path + 1, g_state.nav.num_paths, g_state.tex->width, g_state.tex->height, + g_state.nav->cur_path + 1, g_state.nav->num_paths, g_state.tex->width, g_state.tex->height, 100.0 * g_state.view->scale, current_path, scaling_label[g_options.scaling]); if(g_options.delay >= 1000) { @@ -744,7 +744,7 @@ int main(int argc, char** argv) buf[--len] = 0; } if(len > 0) { - if(imv_navigator_add(&g_state.nav, buf, g_options.recursive)) { + if(imv_navigator_add(g_state.nav, buf, g_options.recursive)) { break; } g_state.need_redraw = 1; @@ -755,12 +755,12 @@ int main(int argc, char** argv) } } while(g_options.list) { - const char *path = imv_navigator_selection(&g_state.nav); + const char *path = imv_navigator_selection(g_state.nav); if(!path) { break; } fprintf(stdout, "%s\n", path); - imv_navigator_remove(&g_state.nav, path); + imv_navigator_remove(g_state.nav, path); } /* clean up our resources now that we're exiting */ @@ -770,7 +770,7 @@ int main(int argc, char** argv) imv_loader_free(g_state.ldr); imv_texture_free(g_state.tex); - imv_navigator_destroy(&g_state.nav); + imv_navigator_free(g_state.nav); imv_viewport_free(g_state.view); imv_commands_free(g_state.cmds); @@ -813,7 +813,7 @@ void cmd_select_rel(struct imv_list *args) } long int index = strtol(args->items[1], NULL, 10); - imv_navigator_select_rel(&g_state.nav, index); + imv_navigator_select_rel(g_state.nav, index); /* reset slideshow delay */ g_state.delay_msec = 0; @@ -832,8 +832,8 @@ void cmd_zoom(struct imv_list *args) void cmd_remove(struct imv_list *args) { (void)args; - char* path = strdup(imv_navigator_selection(&g_state.nav)); - imv_navigator_remove(&g_state.nav, path); + char* path = strdup(imv_navigator_selection(g_state.nav)); + imv_navigator_remove(g_state.nav, path); free(path); /* reset slideshow delay */ diff --git a/src/navigator.c b/src/navigator.c index 97772cd..6abbfb1 100644 --- a/src/navigator.c +++ b/src/navigator.c @@ -24,13 +24,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include -void imv_navigator_init(struct imv_navigator *nav) +struct imv_navigator *imv_navigator_create(void) { + struct imv_navigator *nav = malloc(sizeof(struct imv_navigator)); memset(nav, 0, sizeof(struct imv_navigator)); nav->last_move_direction = 1; + return nav; } -void imv_navigator_destroy(struct imv_navigator *nav) +void imv_navigator_free(struct imv_navigator *nav) { if(nav->paths) { for(int i = 0; i < nav->num_paths; ++i) { @@ -45,7 +47,7 @@ void imv_navigator_destroy(struct imv_navigator *nav) free(nav->mtimes); } - memset(nav, 0, sizeof(struct imv_navigator)); + free(nav); } static int add_item(struct imv_navigator *nav, const char *path, diff --git a/src/navigator.h b/src/navigator.h index ac3cc59..7b7ccf8 100644 --- a/src/navigator.h +++ b/src/navigator.h @@ -32,11 +32,11 @@ struct imv_navigator { int wrapped; }; -/* Initialises an instance of imv_navigator */ -void imv_navigator_init(struct imv_navigator *nav); +/* Creates an instance of imv_navigator */ +struct imv_navigator *imv_navigator_create(void); -/* Cleans up all resources owned by a imv_navigator instance */ -void imv_navigator_destroy(struct imv_navigator *nav); +/* Cleans up an imv_navigator instance */ +void imv_navigator_free(struct imv_navigator *nav); /* Adds the given path to the navigator's internal list. * If a directory is given, all files within that directory are added. diff --git a/test/navigator.c b/test/navigator.c index 55ab392..2aba317 100644 --- a/test/navigator.c +++ b/test/navigator.c @@ -19,78 +19,76 @@ static void test_navigator_add_remove(void **state) { (void)state; - struct imv_navigator nav; - imv_navigator_init(&nav); + struct imv_navigator *nav = imv_navigator_create(); /* Check poll_changed */ - assert_false(imv_navigator_poll_changed(&nav, 0)); + assert_false(imv_navigator_poll_changed(nav, 0)); /* Add 6 paths, one non-existant should fail */ - assert_false(imv_navigator_add(&nav, FILENAME1, 0)); - assert_false(imv_navigator_add(&nav, FILENAME2, 0)); - assert_false(imv_navigator_add(&nav, FILENAME3, 0)); - assert_false(imv_navigator_add(&nav, FILENAME4, 0)); - assert_false(imv_navigator_add(&nav, FILENAME5, 0)); - assert_false(imv_navigator_add(&nav, FILENAME6, 0)); - assert_int_equal(nav.num_paths, 6); + assert_false(imv_navigator_add(nav, FILENAME1, 0)); + assert_false(imv_navigator_add(nav, FILENAME2, 0)); + assert_false(imv_navigator_add(nav, FILENAME3, 0)); + assert_false(imv_navigator_add(nav, FILENAME4, 0)); + assert_false(imv_navigator_add(nav, FILENAME5, 0)); + assert_false(imv_navigator_add(nav, FILENAME6, 0)); + assert_int_equal(nav->num_paths, 6); /* Check poll_changed */ - assert_true(imv_navigator_poll_changed(&nav, 0)); + assert_true(imv_navigator_poll_changed(nav, 0)); /* Make sure current selection is #1 */ - assert_string_equal(imv_navigator_selection(&nav), FILENAME1); + assert_string_equal(imv_navigator_selection(nav), FILENAME1); /* Move right and remove current file (#2); should get to #3 */ - imv_navigator_select_rel(&nav, 1); - assert_string_equal(imv_navigator_selection(&nav), FILENAME2); - imv_navigator_remove(&nav, FILENAME2); - assert_int_equal(nav.num_paths, 5); - assert_string_equal(imv_navigator_selection(&nav), FILENAME3); + imv_navigator_select_rel(nav, 1); + assert_string_equal(imv_navigator_selection(nav), FILENAME2); + imv_navigator_remove(nav, FILENAME2); + assert_int_equal(nav->num_paths, 5); + assert_string_equal(imv_navigator_selection(nav), FILENAME3); /* Move left and remove current file (#1); should get to #6 */ - imv_navigator_select_rel(&nav, -1); - assert_string_equal(imv_navigator_selection(&nav), FILENAME1); - imv_navigator_remove(&nav, FILENAME1); - assert_string_equal(imv_navigator_selection(&nav), FILENAME6); + imv_navigator_select_rel(nav, -1); + assert_string_equal(imv_navigator_selection(nav), FILENAME1); + imv_navigator_remove(nav, FILENAME1); + assert_string_equal(imv_navigator_selection(nav), FILENAME6); /* Move left, right, remove current file (#6); should get to #3 */ - imv_navigator_select_rel(&nav, -1); - imv_navigator_select_rel(&nav, 1); - assert_string_equal(imv_navigator_selection(&nav), FILENAME6); - imv_navigator_remove(&nav, FILENAME6); - assert_string_equal(imv_navigator_selection(&nav), FILENAME3); + imv_navigator_select_rel(nav, -1); + imv_navigator_select_rel(nav, 1); + assert_string_equal(imv_navigator_selection(nav), FILENAME6); + imv_navigator_remove(nav, FILENAME6); + assert_string_equal(imv_navigator_selection(nav), FILENAME3); /* Remove #4; should not move */ - imv_navigator_remove(&nav, FILENAME4); - assert_string_equal(imv_navigator_selection(&nav), FILENAME3); + imv_navigator_remove(nav, FILENAME4); + assert_string_equal(imv_navigator_selection(nav), FILENAME3); /* Verify that #4 is removed by moving left; should get to #5 */ - imv_navigator_select_rel(&nav, 1); - assert_string_equal(imv_navigator_selection(&nav), FILENAME5); + imv_navigator_select_rel(nav, 1); + assert_string_equal(imv_navigator_selection(nav), FILENAME5); - imv_navigator_destroy(&nav); + imv_navigator_free(nav); } static void test_navigator_file_changed(void **state) { int fd; - struct imv_navigator nav; + struct imv_navigator *nav = imv_navigator_create(); struct timespec times[2] = { {0, 0}, {0, 0} }; (void)state; - imv_navigator_init(&nav); fd = open(FILENAME1, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd == -1) { - imv_navigator_destroy(&nav); + imv_navigator_free(nav); (void)unlink(FILENAME1); skip(); } assert_false(futimens(fd, times) == -1); - assert_false(imv_navigator_add(&nav, FILENAME1, 0)); - assert_true(imv_navigator_poll_changed(&nav, 0)); - assert_false(imv_navigator_poll_changed(&nav, 0)); + assert_false(imv_navigator_add(nav, FILENAME1, 0)); + assert_true(imv_navigator_poll_changed(nav, 0)); + assert_false(imv_navigator_poll_changed(nav, 0)); assert_false(sleep(1)); @@ -103,11 +101,11 @@ static void test_navigator_file_changed(void **state) times[1].tv_sec = UTIME_NOW; assert_false(futimens(fd, times) == -1); - assert_true(imv_navigator_poll_changed(&nav, 0)); + assert_true(imv_navigator_poll_changed(nav, 0)); (void)close(fd); (void)unlink(FILENAME1); - imv_navigator_destroy(&nav); + imv_navigator_free(nav); } int main(void) -- cgit v1.2.3 From cccb00ec0fa28d58bcebad8e9c8ff054657b725c Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Fri, 14 Apr 2017 22:12:33 +0100 Subject: Move event handling into its own function --- src/main.c | 320 +++++++++++++++++++++++++++++++------------------------------ 1 file changed, 163 insertions(+), 157 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index adee798..0d7688e 100644 --- a/src/main.c +++ b/src/main.c @@ -202,6 +202,8 @@ void cmd_remove(struct imv_list *args); void cmd_fullscreen(struct imv_list *args); void cmd_overlay(struct imv_list *args); +void handle_event(SDL_Event *event); + int main(int argc, char** argv) { g_state.cmds = imv_commands_create(); @@ -390,163 +392,7 @@ int main(int argc, char** argv) /* handle any input/window events sent by SDL */ SDL_Event e; while(!g_state.quit && SDL_PollEvent(&e)) { - switch(e.type) { - case SDL_QUIT: - imv_command_exec(g_state.cmds, "quit"); - break; - - case SDL_KEYDOWN: - SDL_ShowCursor(SDL_DISABLE); - - if(g_state.command_buffer) { - /* in command mode, update the buffer */ - if(e.key.keysym.sym == SDLK_ESCAPE) { - free(g_state.command_buffer); - g_state.command_buffer = NULL; - g_state.need_redraw = 1; - } else if(e.key.keysym.sym == SDLK_RETURN) { - imv_command_exec(g_state.cmds, g_state.command_buffer); - free(g_state.command_buffer); - g_state.command_buffer = NULL; - g_state.need_redraw = 1; - } else if(e.key.keysym.sym == SDLK_BACKSPACE) { - const size_t len = strlen(g_state.command_buffer); - if(len > 0) { - g_state.command_buffer[len - 1] = '\0'; - g_state.need_redraw = 1; - } - } else if(e.key.keysym.sym >= ' ' && e.key.keysym.sym <= '~') { - const size_t len = strlen(g_state.command_buffer); - if(len + 1 < 1024) { - g_state.command_buffer[len] = e.key.keysym.sym; - g_state.command_buffer[len+1] = '\0'; - g_state.need_redraw = 1; - } - } - - /* input has been consumed by command input, move onto next event */ - continue; - } - - switch (e.key.keysym.sym) { - case SDLK_SEMICOLON: - if(e.key.keysym.mod & KMOD_SHIFT) { - g_state.command_buffer = malloc(1024); - g_state.command_buffer[0] = '\0'; - g_state.need_redraw = 1; - } - break; - case SDLK_q: - imv_command_exec(g_state.cmds, "quit"); - break; - case SDLK_LEFTBRACKET: - case SDLK_LEFT: - imv_command_exec(g_state.cmds, "select_rel -1"); - break; - case SDLK_RIGHTBRACKET: - case SDLK_RIGHT: - imv_command_exec(g_state.cmds, "select_rel 1"); - break; - case SDLK_EQUALS: - case SDLK_PLUS: - case SDLK_i: - case SDLK_UP: - imv_viewport_zoom(g_state.view, g_state.tex, IMV_ZOOM_KEYBOARD, 1); - break; - case SDLK_MINUS: - case SDLK_o: - case SDLK_DOWN: - imv_viewport_zoom(g_state.view, g_state.tex, IMV_ZOOM_KEYBOARD, -1); - break; - case SDLK_s: - if(!e.key.repeat) { - if((g_options.scaling += 1) > FULL) { - g_options.scaling = NONE; - } - } - /* FALLTHROUGH */ - case SDLK_r: - if(!e.key.repeat) { - g_state.need_rescale = 1; - g_state.need_redraw = 1; - } - break; - case SDLK_a: - if(!e.key.repeat) { - imv_viewport_scale_to_actual(g_state.view, g_state.tex); - } - break; - case SDLK_c: - if(!e.key.repeat) { - imv_viewport_center(g_state.view, g_state.tex); - } - break; - case SDLK_j: - imv_command_exec(g_state.cmds, "pan 0 -50"); - break; - case SDLK_k: - imv_command_exec(g_state.cmds, "pan 0 50"); - break; - case SDLK_h: - imv_command_exec(g_state.cmds, "pan 50 0"); - break; - case SDLK_l: - imv_command_exec(g_state.cmds, "pan -50 0"); - break; - case SDLK_x: - if(!e.key.repeat) { - imv_command_exec(g_state.cmds, "remove"); - } - break; - case SDLK_f: - if(!e.key.repeat) { - imv_command_exec(g_state.cmds, "fullscreen"); - } - break; - case SDLK_PERIOD: - imv_loader_load_next_frame(g_state.ldr); - break; - case SDLK_SPACE: - if(!e.key.repeat) { - imv_viewport_toggle_playing(g_state.view); - } - break; - case SDLK_p: - if(!e.key.repeat) { - puts(imv_navigator_selection(g_state.nav)); - } - break; - case SDLK_d: - if(!e.key.repeat) { - imv_command_exec(g_state.cmds, "overlay"); - } - break; - case SDLK_t: - if(e.key.keysym.mod & (KMOD_SHIFT|KMOD_CAPS)) { - if(g_options.delay >= 1000) { - g_options.delay -= 1000; - } - } else { - g_options.delay += 1000; - } - g_state.need_redraw = 1; - break; - } - break; - case SDL_MOUSEWHEEL: - imv_viewport_zoom(g_state.view, g_state.tex, IMV_ZOOM_MOUSE, e.wheel.y); - SDL_ShowCursor(SDL_ENABLE); - break; - case SDL_MOUSEMOTION: - if(e.motion.state & SDL_BUTTON_LMASK) { - imv_viewport_move(g_state.view, e.motion.xrel, e.motion.yrel); - } - SDL_ShowCursor(SDL_ENABLE); - break; - case SDL_WINDOWEVENT: - imv_viewport_update(g_state.view, g_state.tex); - break; - } + handle_event(&e); } /* if we're quitting, don't bother drawing any more images */ @@ -853,4 +699,164 @@ void cmd_overlay(struct imv_list *args) g_state.need_redraw = 1; } +void handle_event(SDL_Event *event) +{ + switch(event->type) { + case SDL_QUIT: + imv_command_exec(g_state.cmds, "quit"); + break; + + case SDL_KEYDOWN: + SDL_ShowCursor(SDL_DISABLE); + + if(g_state.command_buffer) { + /* in command mode, update the buffer */ + if(event->key.keysym.sym == SDLK_ESCAPE) { + free(g_state.command_buffer); + g_state.command_buffer = NULL; + g_state.need_redraw = 1; + } else if(event->key.keysym.sym == SDLK_RETURN) { + imv_command_exec(g_state.cmds, g_state.command_buffer); + free(g_state.command_buffer); + g_state.command_buffer = NULL; + g_state.need_redraw = 1; + } else if(event->key.keysym.sym == SDLK_BACKSPACE) { + const size_t len = strlen(g_state.command_buffer); + if(len > 0) { + g_state.command_buffer[len - 1] = '\0'; + g_state.need_redraw = 1; + } + } else if(event->key.keysym.sym >= ' ' && event->key.keysym.sym <= '~') { + const size_t len = strlen(g_state.command_buffer); + if(len + 1 < 1024) { + g_state.command_buffer[len] = event->key.keysym.sym; + g_state.command_buffer[len+1] = '\0'; + g_state.need_redraw = 1; + } + } + + return; + } + + switch (event->key.keysym.sym) { + case SDLK_SEMICOLON: + if(event->key.keysym.mod & KMOD_SHIFT) { + g_state.command_buffer = malloc(1024); + g_state.command_buffer[0] = '\0'; + g_state.need_redraw = 1; + } + break; + case SDLK_q: + imv_command_exec(g_state.cmds, "quit"); + break; + case SDLK_LEFTBRACKET: + case SDLK_LEFT: + imv_command_exec(g_state.cmds, "select_rel -1"); + break; + case SDLK_RIGHTBRACKET: + case SDLK_RIGHT: + imv_command_exec(g_state.cmds, "select_rel 1"); + break; + case SDLK_EQUALS: + case SDLK_PLUS: + case SDLK_i: + case SDLK_UP: + imv_viewport_zoom(g_state.view, g_state.tex, IMV_ZOOM_KEYBOARD, 1); + break; + case SDLK_MINUS: + case SDLK_o: + case SDLK_DOWN: + imv_viewport_zoom(g_state.view, g_state.tex, IMV_ZOOM_KEYBOARD, -1); + break; + case SDLK_s: + if(!event->key.repeat) { + if((g_options.scaling += 1) > FULL) { + g_options.scaling = NONE; + } + } + /* FALLTHROUGH */ + case SDLK_r: + if(!event->key.repeat) { + g_state.need_rescale = 1; + g_state.need_redraw = 1; + } + break; + case SDLK_a: + if(!event->key.repeat) { + imv_viewport_scale_to_actual(g_state.view, g_state.tex); + } + break; + case SDLK_c: + if(!event->key.repeat) { + imv_viewport_center(g_state.view, g_state.tex); + } + break; + case SDLK_j: + imv_command_exec(g_state.cmds, "pan 0 -50"); + break; + case SDLK_k: + imv_command_exec(g_state.cmds, "pan 0 50"); + break; + case SDLK_h: + imv_command_exec(g_state.cmds, "pan 50 0"); + break; + case SDLK_l: + imv_command_exec(g_state.cmds, "pan -50 0"); + break; + case SDLK_x: + if(!event->key.repeat) { + imv_command_exec(g_state.cmds, "remove"); + } + break; + case SDLK_f: + if(!event->key.repeat) { + imv_command_exec(g_state.cmds, "fullscreen"); + } + break; + case SDLK_PERIOD: + imv_loader_load_next_frame(g_state.ldr); + break; + case SDLK_SPACE: + if(!event->key.repeat) { + imv_viewport_toggle_playing(g_state.view); + } + break; + case SDLK_p: + if(!event->key.repeat) { + puts(imv_navigator_selection(g_state.nav)); + } + break; + case SDLK_d: + if(!event->key.repeat) { + imv_command_exec(g_state.cmds, "overlay"); + } + break; + case SDLK_t: + if(event->key.keysym.mod & (KMOD_SHIFT|KMOD_CAPS)) { + if(g_options.delay >= 1000) { + g_options.delay -= 1000; + } + } else { + g_options.delay += 1000; + } + g_state.need_redraw = 1; + break; + } + break; + case SDL_MOUSEWHEEL: + imv_viewport_zoom(g_state.view, g_state.tex, IMV_ZOOM_MOUSE, event->wheel.y); + SDL_ShowCursor(SDL_ENABLE); + break; + case SDL_MOUSEMOTION: + if(event->motion.state & SDL_BUTTON_LMASK) { + imv_viewport_move(g_state.view, event->motion.xrel, event->motion.yrel); + } + SDL_ShowCursor(SDL_ENABLE); + break; + case SDL_WINDOWEVENT: + imv_viewport_update(g_state.view, g_state.tex); + break; + } +} + /* vim:set ts=2 sts=2 sw=2 et: */ -- cgit v1.2.3 From f085f13f429d01a8f72e3b348a694124d5ba7533 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Fri, 14 Apr 2017 22:34:14 +0100 Subject: Refactor navigator poll rate limiting --- src/main.c | 8 +------- src/navigator.c | 18 +++++++++++++++--- src/navigator.h | 4 +++- test/navigator.c | 13 ++++++++----- 4 files changed, 27 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 0d7688e..4bdfe50 100644 --- a/src/main.c +++ b/src/main.c @@ -370,9 +370,6 @@ int main(int argc, char** argv) unsigned int last_time = SDL_GetTicks(); unsigned int current_time; - /* keep file change polling rate under control */ - static uint8_t poll_countdown = UINT8_MAX; - g_state.need_redraw = 1; g_state.need_rescale = 0; @@ -422,7 +419,7 @@ int main(int argc, char** argv) } /* if the user has changed image, start loading the new one */ - if(imv_navigator_poll_changed(g_state.nav, poll_countdown--)) { + if(imv_navigator_poll_changed(g_state.nav)) { const char *current_path = imv_navigator_selection(g_state.nav); if(!current_path) { if(g_options.stdin_list) { @@ -560,9 +557,6 @@ int main(int argc, char** argv) /* redraw complete, unset the flag */ g_state.need_redraw = 0; - /* reset poll countdown timer */ - poll_countdown = UINT8_MAX; - /* tell SDL to show the newly drawn frame */ SDL_RenderPresent(g_state.renderer); } diff --git a/src/navigator.c b/src/navigator.c index 6abbfb1..ae7bccd 100644 --- a/src/navigator.c +++ b/src/navigator.c @@ -47,6 +47,10 @@ void imv_navigator_free(struct imv_navigator *nav) free(nav->mtimes); } + if(nav->ctimes) { + free(nav->ctimes); + } + free(nav); } @@ -56,19 +60,23 @@ static int add_item(struct imv_navigator *nav, const char *path, if(nav->num_paths % BUFFER_SIZE == 0) { char **new_paths; time_t *new_mtimes; + time_t *new_ctimes; size_t new_size = nav->num_paths + BUFFER_SIZE; new_paths = realloc(nav->paths, sizeof(char*) * new_size); new_mtimes = realloc(nav->mtimes, sizeof(time_t) * new_size); - if (new_paths == NULL || new_mtimes == NULL) { + new_ctimes = realloc(nav->ctimes, sizeof(time_t) * new_size); + if (new_paths == NULL || new_mtimes == NULL || new_ctimes == NULL) { return 1; } nav->paths = new_paths; nav->mtimes = new_mtimes; + nav->ctimes = new_ctimes; } if((nav->paths[nav->num_paths] = strndup(path, PATH_MAX)) == NULL) { return 1; } nav->mtimes[nav->num_paths] = mtime; + nav->ctimes[nav->num_paths] = time(NULL); nav->num_paths += 1; if(nav->num_paths == 1) { nav->changed = 1; @@ -218,7 +226,7 @@ int imv_navigator_find_path(struct imv_navigator *nav, const char *path) return -1; } -int imv_navigator_poll_changed(struct imv_navigator *nav, const int nopoll) +int imv_navigator_poll_changed(struct imv_navigator *nav) { if(nav->changed) { nav->changed = 0; @@ -229,7 +237,11 @@ int imv_navigator_poll_changed(struct imv_navigator *nav, const int nopoll) return 0; }; - if(!nopoll) { + time_t cur_time = time(NULL); + /* limit polling to once per second */ + if(nav->ctimes[nav->cur_path] < cur_time - 1) { + nav->ctimes[nav->cur_path] = cur_time; + struct stat file_info; if(stat(nav->paths[nav->cur_path], &file_info) == -1) { return 0; diff --git a/src/navigator.h b/src/navigator.h index 7b7ccf8..0d56fa7 100644 --- a/src/navigator.h +++ b/src/navigator.h @@ -27,9 +27,11 @@ struct imv_navigator { int cur_path; char **paths; time_t *mtimes; + time_t *ctimes; int last_move_direction; int changed; int wrapped; + int poll_countdown; }; /* Creates an instance of imv_navigator */ @@ -65,7 +67,7 @@ int imv_navigator_find_path(struct imv_navigator *nav, const char *path); /* Returns 1 if either the currently selected path or underlying file has * changed since last called */ -int imv_navigator_poll_changed(struct imv_navigator *nav, const int nopoll); +int imv_navigator_poll_changed(struct imv_navigator *nav); /* Check whether navigator wrapped around paths list */ int imv_navigator_wrapped(struct imv_navigator *nav); diff --git a/test/navigator.c b/test/navigator.c index 2aba317..3f2c50f 100644 --- a/test/navigator.c +++ b/test/navigator.c @@ -22,7 +22,7 @@ static void test_navigator_add_remove(void **state) struct imv_navigator *nav = imv_navigator_create(); /* Check poll_changed */ - assert_false(imv_navigator_poll_changed(nav, 0)); + assert_false(imv_navigator_poll_changed(nav)); /* Add 6 paths, one non-existant should fail */ assert_false(imv_navigator_add(nav, FILENAME1, 0)); @@ -34,7 +34,7 @@ static void test_navigator_add_remove(void **state) assert_int_equal(nav->num_paths, 6); /* Check poll_changed */ - assert_true(imv_navigator_poll_changed(nav, 0)); + assert_true(imv_navigator_poll_changed(nav)); /* Make sure current selection is #1 */ assert_string_equal(imv_navigator_selection(nav), FILENAME1); @@ -87,8 +87,8 @@ static void test_navigator_file_changed(void **state) assert_false(futimens(fd, times) == -1); assert_false(imv_navigator_add(nav, FILENAME1, 0)); - assert_true(imv_navigator_poll_changed(nav, 0)); - assert_false(imv_navigator_poll_changed(nav, 0)); + assert_true(imv_navigator_poll_changed(nav)); + assert_false(imv_navigator_poll_changed(nav)); assert_false(sleep(1)); @@ -101,7 +101,10 @@ static void test_navigator_file_changed(void **state) times[1].tv_sec = UTIME_NOW; assert_false(futimens(fd, times) == -1); - assert_true(imv_navigator_poll_changed(nav, 0)); + /* sleep to ensure we don't hit the poll rate-limiting */ + sleep(1); + + assert_true(imv_navigator_poll_changed(nav)); (void)close(fd); (void)unlink(FILENAME1); -- cgit v1.2.3 From c5c40915248fbd45af8820138a81057400fbcb55 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Fri, 14 Apr 2017 22:42:38 +0100 Subject: Move rendering into its own function --- src/main.c | 129 +++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 69 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 4bdfe50..3a9c4e4 100644 --- a/src/main.c +++ b/src/main.c @@ -42,7 +42,7 @@ enum scaling_mode { FULL }; -static char *scaling_label[] = { +static const char *scaling_label[] = { "actual size", "best fit", "perfect fit" @@ -203,6 +203,7 @@ void cmd_fullscreen(struct imv_list *args); void cmd_overlay(struct imv_list *args); void handle_event(SDL_Event *event); +void render_window(TTF_Font *text_font, SDL_Texture *bg_texture); int main(int argc, char** argv) { @@ -500,65 +501,7 @@ int main(int argc, char** argv) /* only redraw when something's changed */ if(g_state.need_redraw) { - /* update window title */ - int len; - const char *current_path = imv_navigator_selection(g_state.nav); - len = snprintf(title, sizeof(title), "imv - [%i/%i] [%ix%i] [%.2f%%] %s [%s]", - g_state.nav->cur_path + 1, g_state.nav->num_paths, g_state.tex->width, g_state.tex->height, - 100.0 * g_state.view->scale, - current_path, scaling_label[g_options.scaling]); - if(g_options.delay >= 1000) { - len += snprintf(title + len, sizeof(title) - len, "[%lu/%lus]", - g_state.delay_msec / 1000 + 1, g_options.delay / 1000); - } - imv_viewport_set_title(g_state.view, title); - - /* first we draw the background */ - if(g_options.solid_bg) { - /* solid background */ - SDL_SetRenderDrawColor(g_state.renderer, - g_options.bg_r, g_options.bg_g, g_options.bg_b, 255); - SDL_RenderClear(g_state.renderer); - } else { - /* chequered background */ - int img_w, img_h; - SDL_QueryTexture(chequered_tex, NULL, NULL, &img_w, &img_h); - /* tile the texture so it fills the window */ - for(int y = 0; y < wh; y += img_h) { - for(int x = 0; x < ww; x += img_w) { - SDL_Rect dst_rect = {x,y,img_w,img_h}; - SDL_RenderCopy(g_state.renderer, chequered_tex, NULL, &dst_rect); - } - } - } - - /* draw our actual texture */ - imv_texture_draw(g_state.tex, g_state.view->x, g_state.view->y, g_state.view->scale); - - /* if the overlay needs to be drawn, draw that too */ - if(g_options.overlay && font) { - SDL_Color fg = {255,255,255,255}; - SDL_Color bg = {0,0,0,160}; - imv_printf(g_state.renderer, font, 0, 0, &fg, &bg, "%s", - title + strlen("imv - ")); - } - - /* draw command entry bar if needed */ - if(g_state.command_buffer && font) { - SDL_Color fg = {255,255,255,255}; - SDL_Color bg = {0,0,0,160}; - imv_printf(g_state.renderer, - font, - 0, wh - TTF_FontHeight(font), - &fg, &bg, - ":%s", g_state.command_buffer); - } - - /* redraw complete, unset the flag */ - g_state.need_redraw = 0; - - /* tell SDL to show the newly drawn frame */ - SDL_RenderPresent(g_state.renderer); + render_window(font, chequered_tex); } /* sleep a little bit so we don't waste CPU time */ @@ -853,4 +796,70 @@ void handle_event(SDL_Event *event) } } +void render_window(TTF_Font *text_font, SDL_Texture *bg_texture) +{ + char title[1024]; + int ww, wh; + SDL_GetWindowSize(g_state.window, &ww, &wh); + + /* update window title */ + const char *current_path = imv_navigator_selection(g_state.nav); + int len = snprintf(title, sizeof(title), "imv - [%i/%i] [%ix%i] [%.2f%%] %s [%s]", + g_state.nav->cur_path + 1, g_state.nav->num_paths, g_state.tex->width, g_state.tex->height, + 100.0 * g_state.view->scale, + current_path, scaling_label[g_options.scaling]); + if(g_options.delay >= 1000) { + len += snprintf(title + len, sizeof(title) - len, "[%lu/%lus]", + g_state.delay_msec / 1000 + 1, g_options.delay / 1000); + } + imv_viewport_set_title(g_state.view, title); + + /* first we draw the background */ + if(g_options.solid_bg) { + /* solid background */ + SDL_SetRenderDrawColor(g_state.renderer, + g_options.bg_r, g_options.bg_g, g_options.bg_b, 255); + SDL_RenderClear(g_state.renderer); + } else { + /* background */ + int img_w, img_h; + SDL_QueryTexture(bg_texture, NULL, NULL, &img_w, &img_h); + /* tile the texture so it fills the window */ + for(int y = 0; y < wh; y += img_h) { + for(int x = 0; x < ww; x += img_w) { + SDL_Rect dst_rect = {x,y,img_w,img_h}; + SDL_RenderCopy(g_state.renderer, bg_texture, NULL, &dst_rect); + } + } + } + + /* draw our actual texture */ + imv_texture_draw(g_state.tex, g_state.view->x, g_state.view->y, g_state.view->scale); + + /* if the overlay needs to be drawn, draw that too */ + if(g_options.overlay && text_font) { + SDL_Color fg = {255,255,255,255}; + SDL_Color bg = {0,0,0,160}; + imv_printf(g_state.renderer, text_font, 0, 0, &fg, &bg, "%s", + title + strlen("imv - ")); + } + + /* draw command entry bar if needed */ + if(g_state.command_buffer && text_font) { + SDL_Color fg = {255,255,255,255}; + SDL_Color bg = {0,0,0,160}; + imv_printf(g_state.renderer, + text_font, + 0, wh - TTF_FontHeight(text_font), + &fg, &bg, + ":%s", g_state.command_buffer); + } + + /* redraw complete, unset the flag */ + g_state.need_redraw = 0; + + /* tell SDL to show the newly drawn frame */ + SDL_RenderPresent(g_state.renderer); +} + /* vim:set ts=2 sts=2 sw=2 et: */ -- cgit v1.2.3 From a461d4f26fd2d62433ff553f0305de52b1f407aa Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Fri, 14 Apr 2017 22:55:54 +0100 Subject: Move some globals back to locals --- src/main.c | 55 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 3a9c4e4..dad28b1 100644 --- a/src/main.c +++ b/src/main.c @@ -178,8 +178,6 @@ struct { struct imv_texture *tex; struct imv_viewport *view; struct imv_commands *cmds; - SDL_Window *window; - SDL_Renderer *renderer; int quit; /* used to calculate when to skip to the next image in slideshow mode */ @@ -203,7 +201,11 @@ void cmd_fullscreen(struct imv_list *args); void cmd_overlay(struct imv_list *args); void handle_event(SDL_Event *event); -void render_window(TTF_Font *text_font, SDL_Texture *bg_texture); +void render_window( + SDL_Window *window, + SDL_Renderer *renderer, + TTF_Font *text_font, + SDL_Texture *bg_texture); int main(int argc, char** argv) { @@ -319,23 +321,23 @@ int main(int argc, char** argv) const int width = 1280; const int height = 720; - g_state.window = SDL_CreateWindow( + SDL_Window *window = SDL_CreateWindow( "imv", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_RESIZABLE); - if(!g_state.window) { + if(!window) { fprintf(stderr, "SDL Failed to create window: %s\n", SDL_GetError()); SDL_Quit(); exit(1); } /* we'll use SDL's built-in renderer, hardware accelerated if possible */ - g_state.renderer = SDL_CreateRenderer(g_state.window, -1, 0); - if(!g_state.renderer) { + SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0); + if(!renderer) { fprintf(stderr, "SDL Failed to create renderer: %s\n", SDL_GetError()); - SDL_DestroyWindow(g_state.window); + SDL_DestroyWindow(window); SDL_Quit(); exit(1); } @@ -347,7 +349,7 @@ int main(int argc, char** argv) /* construct a chequered background texture */ SDL_Texture *chequered_tex = NULL; if(!g_options.solid_bg) { - chequered_tex = create_chequered(g_state.renderer); + chequered_tex = create_chequered(renderer); } /* set up the required fonts and surfaces for displaying the overlay */ @@ -359,8 +361,8 @@ int main(int argc, char** argv) /* create our main classes */ g_state.ldr = imv_loader_create(); - g_state.tex = imv_texture_create(g_state.renderer); - g_state.view = imv_viewport_create(g_state.window); + g_state.tex = imv_texture_create(renderer); + g_state.view = imv_viewport_create(window); /* put us in fullscren mode to begin with if requested */ if(g_options.fullscreen) { @@ -441,7 +443,7 @@ int main(int argc, char** argv) /* get window height and width */ int ww, wh; - SDL_GetWindowSize(g_state.window, &ww, &wh); + SDL_GetWindowSize(window, &ww, &wh); /* check if a new image is available to display */ FIBITMAP *bmp; @@ -501,7 +503,9 @@ int main(int argc, char** argv) /* only redraw when something's changed */ if(g_state.need_redraw) { - render_window(font, chequered_tex); + render_window(window, renderer, font, chequered_tex); + /* tell SDL to show the newly drawn frame */ + SDL_RenderPresent(renderer); } /* sleep a little bit so we don't waste CPU time */ @@ -564,8 +568,8 @@ int main(int argc, char** argv) if(chequered_tex) { SDL_DestroyTexture(chequered_tex); } - SDL_DestroyRenderer(g_state.renderer); - SDL_DestroyWindow(g_state.window); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); SDL_Quit(); return 0; @@ -796,11 +800,15 @@ void handle_event(SDL_Event *event) } } -void render_window(TTF_Font *text_font, SDL_Texture *bg_texture) +void render_window( + SDL_Window *window, + SDL_Renderer *renderer, + TTF_Font *text_font, + SDL_Texture *bg_texture) { char title[1024]; int ww, wh; - SDL_GetWindowSize(g_state.window, &ww, &wh); + SDL_GetWindowSize(window, &ww, &wh); /* update window title */ const char *current_path = imv_navigator_selection(g_state.nav); @@ -817,9 +825,9 @@ void render_window(TTF_Font *text_font, SDL_Texture *bg_texture) /* first we draw the background */ if(g_options.solid_bg) { /* solid background */ - SDL_SetRenderDrawColor(g_state.renderer, + SDL_SetRenderDrawColor(renderer, g_options.bg_r, g_options.bg_g, g_options.bg_b, 255); - SDL_RenderClear(g_state.renderer); + SDL_RenderClear(renderer); } else { /* background */ int img_w, img_h; @@ -828,7 +836,7 @@ void render_window(TTF_Font *text_font, SDL_Texture *bg_texture) for(int y = 0; y < wh; y += img_h) { for(int x = 0; x < ww; x += img_w) { SDL_Rect dst_rect = {x,y,img_w,img_h}; - SDL_RenderCopy(g_state.renderer, bg_texture, NULL, &dst_rect); + SDL_RenderCopy(renderer, bg_texture, NULL, &dst_rect); } } } @@ -840,7 +848,7 @@ void render_window(TTF_Font *text_font, SDL_Texture *bg_texture) if(g_options.overlay && text_font) { SDL_Color fg = {255,255,255,255}; SDL_Color bg = {0,0,0,160}; - imv_printf(g_state.renderer, text_font, 0, 0, &fg, &bg, "%s", + imv_printf(renderer, text_font, 0, 0, &fg, &bg, "%s", title + strlen("imv - ")); } @@ -848,7 +856,7 @@ void render_window(TTF_Font *text_font, SDL_Texture *bg_texture) if(g_state.command_buffer && text_font) { SDL_Color fg = {255,255,255,255}; SDL_Color bg = {0,0,0,160}; - imv_printf(g_state.renderer, + imv_printf(renderer, text_font, 0, wh - TTF_FontHeight(text_font), &fg, &bg, @@ -857,9 +865,6 @@ void render_window(TTF_Font *text_font, SDL_Texture *bg_texture) /* redraw complete, unset the flag */ g_state.need_redraw = 0; - - /* tell SDL to show the newly drawn frame */ - SDL_RenderPresent(g_state.renderer); } /* vim:set ts=2 sts=2 sw=2 et: */ -- cgit v1.2.3 From 3900415f5bde879b11c43b7b1daa4ff5533b0794 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Fri, 14 Apr 2017 22:56:58 +0100 Subject: Move parse_args to end of main.c --- src/main.c | 182 +++++++++++++++++++++++++++++++------------------------------ 1 file changed, 92 insertions(+), 90 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index dad28b1..0406c04 100644 --- a/src/main.c +++ b/src/main.c @@ -82,96 +82,6 @@ struct { .font = "Monospace:24", }; -static void print_usage(void) -{ - fprintf(stdout, - "imv %s\n" - "See manual for usage information.\n" - "\n" - "Legal:\n" - "This program is free software; you can redistribute it and/or\n" - "modify it under the terms of the GNU General Public License\n" - "as published by the Free Software Foundation; either version 2\n" - "of the License, or (at your option) any later version.\n" - "\n" - "This software uses the FreeImage open source image library.\n" - "See http://freeimage.sourceforge.net for details.\n" - "FreeImage is used under the GNU GPLv2.\n" - , IMV_VERSION); -} - -static void parse_args(int argc, char** argv) -{ - /* Do not print getopt errors */ - opterr = 0; - - char *argp, *ep = *argv; - int o; - - while((o = getopt(argc, argv, "firasSudxhln:b:e:t:")) != -1) { - switch(o) { - case 'f': g_options.fullscreen = 1; break; - case 'i': - g_options.stdin_list = 1; - fprintf(stderr, "Warning: '-i' is deprecated. No flag is needed.\n"); - break; - case 'r': g_options.recursive = 1; break; - case 'a': g_options.scaling = NONE; break; - case 's': g_options.scaling = DOWN; break; - case 'S': g_options.scaling = FULL; break; - case 'u': g_options.nearest_neighbour = 1; break; - case 'd': g_options.overlay = 1; break; - case 'x': g_options.cycle = 0; break; - case 'h': print_usage(); exit(0); break; - case 'l': g_options.list = 1; break; - case 'n': - g_options.start_at = optarg; - break; - case 'b': - if(strcmp("checks", optarg) == 0) { - g_options.solid_bg = 0; - } else { - g_options.solid_bg = 1; - argp = (*optarg == '#') ? optarg + 1 : optarg; - uint32_t n = strtoul(argp, &ep, 16); - if(*ep != '\0' || ep - argp != 6 || n > 0xFFFFFF) { - fprintf(stderr, "Invalid hex color: '%s'\n", optarg); - exit(1); - } - g_options.bg_b = n & 0xFF; - g_options.bg_g = (n >> 8) & 0xFF; - g_options.bg_r = (n >> 16); - } - break; - case 'e': - g_options.font = optarg; - break; - case 't': - g_options.delay = strtoul(optarg, &argp, 10); - g_options.delay *= 1000; - if (*argp == '.') { - long delay = strtoul(++argp, &ep, 10); - for (int i = 3 - (ep - argp); i; i--) { - delay *= 10; - } - if (delay < 1000) { - g_options.delay += delay; - } else { - g_options.delay = ULONG_MAX; - } - } - if (g_options.delay == ULONG_MAX) { - fprintf(stderr, "Wrong slideshow delay '%s'. Aborting.\n", optarg); - exit(1); - } - break; - case '?': - fprintf(stderr, "Unknown argument '%c'. Aborting.\n", optopt); - exit(1); - } - } -} - struct { struct imv_navigator *nav; struct imv_loader *ldr; @@ -200,6 +110,7 @@ void cmd_remove(struct imv_list *args); void cmd_fullscreen(struct imv_list *args); void cmd_overlay(struct imv_list *args); +static void parse_args(int argc, char** argv); void handle_event(SDL_Event *event); void render_window( SDL_Window *window, @@ -640,6 +551,97 @@ void cmd_overlay(struct imv_list *args) g_state.need_redraw = 1; } +static void print_usage(void) +{ + fprintf(stdout, + "imv %s\n" + "See manual for usage information.\n" + "\n" + "Legal:\n" + "This program is free software; you can redistribute it and/or\n" + "modify it under the terms of the GNU General Public License\n" + "as published by the Free Software Foundation; either version 2\n" + "of the License, or (at your option) any later version.\n" + "\n" + "This software uses the FreeImage open source image library.\n" + "See http://freeimage.sourceforge.net for details.\n" + "FreeImage is used under the GNU GPLv2.\n" + , IMV_VERSION); +} + +static void parse_args(int argc, char** argv) +{ + /* Do not print getopt errors */ + opterr = 0; + + char *argp, *ep = *argv; + int o; + + while((o = getopt(argc, argv, "firasSudxhln:b:e:t:")) != -1) { + switch(o) { + case 'f': g_options.fullscreen = 1; break; + case 'i': + g_options.stdin_list = 1; + fprintf(stderr, "Warning: '-i' is deprecated. No flag is needed.\n"); + break; + case 'r': g_options.recursive = 1; break; + case 'a': g_options.scaling = NONE; break; + case 's': g_options.scaling = DOWN; break; + case 'S': g_options.scaling = FULL; break; + case 'u': g_options.nearest_neighbour = 1; break; + case 'd': g_options.overlay = 1; break; + case 'x': g_options.cycle = 0; break; + case 'h': print_usage(); exit(0); break; + case 'l': g_options.list = 1; break; + case 'n': + g_options.start_at = optarg; + break; + case 'b': + if(strcmp("checks", optarg) == 0) { + g_options.solid_bg = 0; + } else { + g_options.solid_bg = 1; + argp = (*optarg == '#') ? optarg + 1 : optarg; + uint32_t n = strtoul(argp, &ep, 16); + if(*ep != '\0' || ep - argp != 6 || n > 0xFFFFFF) { + fprintf(stderr, "Invalid hex color: '%s'\n", optarg); + exit(1); + } + g_options.bg_b = n & 0xFF; + g_options.bg_g = (n >> 8) & 0xFF; + g_options.bg_r = (n >> 16); + } + break; + case 'e': + g_options.font = optarg; + break; + case 't': + g_options.delay = strtoul(optarg, &argp, 10); + g_options.delay *= 1000; + if (*argp == '.') { + long delay = strtoul(++argp, &ep, 10); + for (int i = 3 - (ep - argp); i; i--) { + delay *= 10; + } + if (delay < 1000) { + g_options.delay += delay; + } else { + g_options.delay = ULONG_MAX; + } + } + if (g_options.delay == ULONG_MAX) { + fprintf(stderr, "Wrong slideshow delay '%s'. Aborting.\n", optarg); + exit(1); + } + break; + case '?': + fprintf(stderr, "Unknown argument '%c'. Aborting.\n", optopt); + exit(1); + } + } +} + + void handle_event(SDL_Event *event) { switch(event->type) { -- cgit v1.2.3 From b2fc7c3978d2da4d1f559b15ba36f36fafbf297d Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Fri, 14 Apr 2017 23:29:51 +0100 Subject: Minor clean up of main.c --- src/main.c | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 0406c04..09394c5 100644 --- a/src/main.c +++ b/src/main.c @@ -110,7 +110,7 @@ void cmd_remove(struct imv_list *args); void cmd_fullscreen(struct imv_list *args); void cmd_overlay(struct imv_list *args); -static void parse_args(int argc, char** argv); +static void parse_args(int *argc, char ***argv); void handle_event(SDL_Event *event); void render_window( SDL_Window *window, @@ -139,10 +139,7 @@ int main(int argc, char** argv) g_state.nav = imv_navigator_create(); /* parse any command line options given */ - parse_args(argc, argv); - - argc -= optind; - argv += optind; + parse_args(&argc, &argv); /* if no names are given, expect them on stdin */ if(argc == 0) { @@ -185,12 +182,16 @@ int main(int argc, char** argv) /* handle any image paths given as arguments */ for(int i = 0; i < argc; ++i) { - /* special case: '-' is actually an option */ + + /* special case: '-' means load raw image data from stdin */ if(!strcmp("-",argv[i])) { + /* did we already load data from stdin? */ if (stdin_buffer) { fprintf(stderr, "Can't read from stdin twice\n"); + imv_navigator_free(g_state.nav); exit(1); } + /* actually load the data from stdin */ stdin_buffer_size = read_from_stdin(&stdin_buffer); if (stdin_buffer_size == 0) { perror(NULL); @@ -209,6 +210,7 @@ int main(int argc, char** argv) /* if we weren't given any paths we have nothing to view. exit */ if(!imv_navigator_selection(g_state.nav)) { fprintf(stderr, "No input files. Exiting.\n"); + imv_navigator_free(g_state.nav); exit(1); } @@ -224,6 +226,7 @@ int main(int argc, char** argv) /* we've got something to display, so create an SDL window */ if(SDL_Init(SDL_INIT_VIDEO) != 0) { fprintf(stderr, "SDL Failed to Init: %s\n", SDL_GetError()); + imv_navigator_free(g_state.nav); exit(1); } @@ -240,6 +243,7 @@ int main(int argc, char** argv) SDL_WINDOW_RESIZABLE); if(!window) { fprintf(stderr, "SDL Failed to create window: %s\n", SDL_GetError()); + imv_navigator_free(g_state.nav); SDL_Quit(); exit(1); } @@ -248,6 +252,7 @@ int main(int argc, char** argv) SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0); if(!renderer) { fprintf(stderr, "SDL Failed to create renderer: %s\n", SDL_GetError()); + imv_navigator_free(g_state.nav); SDL_DestroyWindow(window); SDL_Quit(); exit(1); @@ -315,6 +320,8 @@ int main(int argc, char** argv) char *err_path = imv_loader_get_error(g_state.ldr); if(err_path) { imv_navigator_remove(g_state.nav, err_path); + + /* special case: the image came from stdin */ if (strncmp(err_path, "-", 2) == 0) { free(stdin_buffer); stdin_buffer_size = 0; @@ -336,11 +343,11 @@ int main(int argc, char** argv) if(imv_navigator_poll_changed(g_state.nav)) { const char *current_path = imv_navigator_selection(g_state.nav); if(!current_path) { - if(g_options.stdin_list) { - continue; + if(!g_options.stdin_list) { + fprintf(stderr, "No input files left. Exiting.\n"); + g_state.quit = 1; } - fprintf(stderr, "No input files left. Exiting.\n"); - exit(1); + continue; } snprintf(title, sizeof(title), "imv - [%i/%i] [LOADING] %s [%s]", @@ -352,9 +359,6 @@ int main(int argc, char** argv) g_state.view->playing = 1; } - /* get window height and width */ - int ww, wh; - SDL_GetWindowSize(window, &ww, &wh); /* check if a new image is available to display */ FIBITMAP *bmp; @@ -369,6 +373,9 @@ int main(int argc, char** argv) } if(g_state.need_rescale) { + int ww, wh; + SDL_GetWindowSize(window, &ww, &wh); + g_state.need_rescale = 0; if(g_options.scaling == NONE || (g_options.scaling == DOWN && ww > iw && wh > ih)) { @@ -419,7 +426,7 @@ int main(int argc, char** argv) SDL_RenderPresent(renderer); } - /* sleep a little bit so we don't waste CPU time */ + /* try to read some more paths from stdin */ if(g_options.stdin_list) { if(poll(rfds, 1, 10) != 1 || rfds[0].revents & (POLLERR|POLLNVAL)) { fprintf(stderr, "error polling stdin"); @@ -449,6 +456,7 @@ int main(int argc, char** argv) } } } else { + /* sleep a little bit so we don't waste CPU time */ SDL_Delay(10); } } @@ -569,15 +577,15 @@ static void print_usage(void) , IMV_VERSION); } -static void parse_args(int argc, char** argv) +static void parse_args(int *argc, char ***argv) { /* Do not print getopt errors */ opterr = 0; - char *argp, *ep = *argv; + char *argp, *ep = **argv; int o; - while((o = getopt(argc, argv, "firasSudxhln:b:e:t:")) != -1) { + while((o = getopt(*argc, *argv, "firasSudxhln:b:e:t:")) != -1) { switch(o) { case 'f': g_options.fullscreen = 1; break; case 'i': @@ -639,6 +647,9 @@ static void parse_args(int argc, char** argv) exit(1); } } + + *argc -= optind; + *argv += optind; } -- cgit v1.2.3 From ec0923e5cf9715943b198ea5c6f60e1037cef248 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Fri, 14 Apr 2017 23:49:43 +0100 Subject: Fix command text input --- src/main.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 09394c5..d0cfb78 100644 --- a/src/main.c +++ b/src/main.c @@ -299,6 +299,7 @@ int main(int argc, char** argv) /* start outside of command mode */ g_state.command_buffer = NULL; + SDL_StopTextInput(); /* initialize variables holding image dimentions */ int iw = 0, ih = 0; @@ -655,22 +656,30 @@ static void parse_args(int *argc, char ***argv) void handle_event(SDL_Event *event) { + const int command_buffer_len = 1024; switch(event->type) { case SDL_QUIT: imv_command_exec(g_state.cmds, "quit"); break; + case SDL_TEXTINPUT: + strncat(g_state.command_buffer, event->text.text, command_buffer_len - 1); + g_state.need_redraw = 1; + break; + case SDL_KEYDOWN: SDL_ShowCursor(SDL_DISABLE); if(g_state.command_buffer) { /* in command mode, update the buffer */ if(event->key.keysym.sym == SDLK_ESCAPE) { + SDL_StopTextInput(); free(g_state.command_buffer); g_state.command_buffer = NULL; g_state.need_redraw = 1; } else if(event->key.keysym.sym == SDLK_RETURN) { imv_command_exec(g_state.cmds, g_state.command_buffer); + SDL_StopTextInput(); free(g_state.command_buffer); g_state.command_buffer = NULL; g_state.need_redraw = 1; @@ -680,13 +689,6 @@ void handle_event(SDL_Event *event) g_state.command_buffer[len - 1] = '\0'; g_state.need_redraw = 1; } - } else if(event->key.keysym.sym >= ' ' && event->key.keysym.sym <= '~') { - const size_t len = strlen(g_state.command_buffer); - if(len + 1 < 1024) { - g_state.command_buffer[len] = event->key.keysym.sym; - g_state.command_buffer[len+1] = '\0'; - g_state.need_redraw = 1; - } } return; @@ -695,7 +697,8 @@ void handle_event(SDL_Event *event) switch (event->key.keysym.sym) { case SDLK_SEMICOLON: if(event->key.keysym.mod & KMOD_SHIFT) { - g_state.command_buffer = malloc(1024); + SDL_StartTextInput(); + g_state.command_buffer = malloc(command_buffer_len); g_state.command_buffer[0] = '\0'; g_state.need_redraw = 1; } -- cgit v1.2.3 From a6bb8ad100348693a39ea13ba6af361f2dab5101 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Sat, 15 Apr 2017 10:58:31 +0100 Subject: Let commands take an arbitrary pointer --- src/commands.c | 8 ++++---- src/commands.h | 4 ++-- src/main.c | 64 +++++++++++++++++++++++++++++++++------------------------- 3 files changed, 42 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/commands.c b/src/commands.c index a3a59b1..0f31bfc 100644 --- a/src/commands.c +++ b/src/commands.c @@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. struct command { char* command; - void (*handler)(struct imv_list *args); + void (*handler)(struct imv_list *args, void *data); char* alias; }; @@ -63,7 +63,7 @@ void imv_command_alias(struct imv_commands *cmds, const char *command, const cha imv_list_append(cmds->command_list, cmd); } -int imv_command_exec(struct imv_commands *cmds, const char *command) +int imv_command_exec(struct imv_commands *cmds, const char *command, void *data) { struct imv_list *args = imv_split_string(command, ' '); int ret = 1; @@ -73,10 +73,10 @@ int imv_command_exec(struct imv_commands *cmds, const char *command) struct command *cmd = cmds->command_list->items[i]; if(!strcmp(cmd->command, args->items[0])) { if(cmd->handler) { - cmd->handler(args); + cmd->handler(args, data); ret = 0; } else if(cmd->alias) { - ret = imv_command_exec(cmds, cmd->alias); + ret = imv_command_exec(cmds, cmd->alias, data); } break; } diff --git a/src/commands.h b/src/commands.h index df8b43b..89f94a2 100644 --- a/src/commands.h +++ b/src/commands.h @@ -24,11 +24,11 @@ struct imv_commands { struct imv_list *command_list; }; -struct imv_commands *imv_commands_create(void); +struct imv_commands *imv_commands_create(); void imv_commands_free(struct imv_commands *cmds); void imv_command_register(struct imv_commands *cmds, const char *command, void (*handler)()); void imv_command_alias(struct imv_commands *cmds, const char *command, const char *alias); -int imv_command_exec(struct imv_commands *cmds, const char *command); +int imv_command_exec(struct imv_commands *cmds, const char *command, void *data); #endif diff --git a/src/main.c b/src/main.c index d0cfb78..8cbd095 100644 --- a/src/main.c +++ b/src/main.c @@ -101,14 +101,14 @@ struct { char *command_buffer; } g_state; -void cmd_quit(struct imv_list *args); -void cmd_pan(struct imv_list *args); -void cmd_select_rel(struct imv_list *args); -void cmd_select_abs(struct imv_list *args); -void cmd_zoom(struct imv_list *args); -void cmd_remove(struct imv_list *args); -void cmd_fullscreen(struct imv_list *args); -void cmd_overlay(struct imv_list *args); +void cmd_quit(struct imv_list *args, void *data); +void cmd_pan(struct imv_list *args, void *data); +void cmd_select_rel(struct imv_list *args, void *data); +void cmd_select_abs(struct imv_list *args, void *data); +void cmd_zoom(struct imv_list *args, void *data); +void cmd_remove(struct imv_list *args, void *data); +void cmd_fullscreen(struct imv_list *args, void *data); +void cmd_overlay(struct imv_list *args, void *data); static void parse_args(int *argc, char ***argv); void handle_event(SDL_Event *event); @@ -495,14 +495,16 @@ int main(int argc, char** argv) return 0; } -void cmd_quit(struct imv_list *args) +void cmd_quit(struct imv_list *args, void *data) { (void)args; + (void)data; g_state.quit = 1; } -void cmd_pan(struct imv_list *args) +void cmd_pan(struct imv_list *args, void *data) { + (void)data; if(args->len != 3) { return; } @@ -513,8 +515,9 @@ void cmd_pan(struct imv_list *args) imv_viewport_move(g_state.view, x, y); } -void cmd_select_rel(struct imv_list *args) +void cmd_select_rel(struct imv_list *args, void *data) { + (void)data; if(args->len != 2) { return; } @@ -526,19 +529,22 @@ void cmd_select_rel(struct imv_list *args) g_state.delay_msec = 0; } -void cmd_select_abs(struct imv_list *args) +void cmd_select_abs(struct imv_list *args, void *data) { (void)args; + (void)data; } -void cmd_zoom(struct imv_list *args) +void cmd_zoom(struct imv_list *args, void *data) { (void)args; + (void)data; } -void cmd_remove(struct imv_list *args) +void cmd_remove(struct imv_list *args, void *data) { (void)args; + (void)data; char* path = strdup(imv_navigator_selection(g_state.nav)); imv_navigator_remove(g_state.nav, path); free(path); @@ -547,15 +553,17 @@ void cmd_remove(struct imv_list *args) g_state.delay_msec = 0; } -void cmd_fullscreen(struct imv_list *args) +void cmd_fullscreen(struct imv_list *args, void *data) { (void)args; + (void)data; imv_viewport_toggle_fullscreen(g_state.view); } -void cmd_overlay(struct imv_list *args) +void cmd_overlay(struct imv_list *args, void *data) { (void)args; + (void)data; g_options.overlay = !g_options.overlay; g_state.need_redraw = 1; } @@ -659,7 +667,7 @@ void handle_event(SDL_Event *event) const int command_buffer_len = 1024; switch(event->type) { case SDL_QUIT: - imv_command_exec(g_state.cmds, "quit"); + imv_command_exec(g_state.cmds, "quit", NULL); break; case SDL_TEXTINPUT: @@ -678,7 +686,7 @@ void handle_event(SDL_Event *event) g_state.command_buffer = NULL; g_state.need_redraw = 1; } else if(event->key.keysym.sym == SDLK_RETURN) { - imv_command_exec(g_state.cmds, g_state.command_buffer); + imv_command_exec(g_state.cmds, g_state.command_buffer, NULL); SDL_StopTextInput(); free(g_state.command_buffer); g_state.command_buffer = NULL; @@ -704,15 +712,15 @@ void handle_event(SDL_Event *event) } break; case SDLK_q: - imv_command_exec(g_state.cmds, "quit"); + imv_command_exec(g_state.cmds, "quit", NULL); break; case SDLK_LEFTBRACKET: case SDLK_LEFT: - imv_command_exec(g_state.cmds, "select_rel -1"); + imv_command_exec(g_state.cmds, "select_rel -1", NULL); break; case SDLK_RIGHTBRACKET: case SDLK_RIGHT: - imv_command_exec(g_state.cmds, "select_rel 1"); + imv_command_exec(g_state.cmds, "select_rel 1", NULL); break; case SDLK_EQUALS: case SDLK_PLUS: @@ -749,25 +757,25 @@ void handle_event(SDL_Event *event) } break; case SDLK_j: - imv_command_exec(g_state.cmds, "pan 0 -50"); + imv_command_exec(g_state.cmds, "pan 0 -50", NULL); break; case SDLK_k: - imv_command_exec(g_state.cmds, "pan 0 50"); + imv_command_exec(g_state.cmds, "pan 0 50", NULL); break; case SDLK_h: - imv_command_exec(g_state.cmds, "pan 50 0"); + imv_command_exec(g_state.cmds, "pan 50 0", NULL); break; case SDLK_l: - imv_command_exec(g_state.cmds, "pan -50 0"); + imv_command_exec(g_state.cmds, "pan -50 0", NULL); break; case SDLK_x: if(!event->key.repeat) { - imv_command_exec(g_state.cmds, "remove"); + imv_command_exec(g_state.cmds, "remove", NULL); } break; case SDLK_f: if(!event->key.repeat) { - imv_command_exec(g_state.cmds, "fullscreen"); + imv_command_exec(g_state.cmds, "fullscreen", NULL); } break; case SDLK_PERIOD: @@ -785,7 +793,7 @@ void handle_event(SDL_Event *event) break; case SDLK_d: if(!event->key.repeat) { - imv_command_exec(g_state.cmds, "overlay"); + imv_command_exec(g_state.cmds, "overlay", NULL); } break; case SDLK_t: -- cgit v1.2.3 From 0357d51086ffa79e964c4b22895e5d6d72771f37 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Sat, 15 Apr 2017 16:40:53 +0100 Subject: Fix compiler warning --- src/commands.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/commands.h b/src/commands.h index 89f94a2..2d106d9 100644 --- a/src/commands.h +++ b/src/commands.h @@ -24,7 +24,7 @@ struct imv_commands { struct imv_list *command_list; }; -struct imv_commands *imv_commands_create(); +struct imv_commands *imv_commands_create(void); void imv_commands_free(struct imv_commands *cmds); void imv_command_register(struct imv_commands *cmds, const char *command, void (*handler)()); void imv_command_alias(struct imv_commands *cmds, const char *command, const char *alias); -- cgit v1.2.3 From f16141f1846d507e02cc1f9ee940a41a07056a4e Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 18 Apr 2017 17:08:30 +0100 Subject: Start work on refactored imv --- src/imv.c | 470 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/imv.h | 36 +++++ 2 files changed, 506 insertions(+) create mode 100644 src/imv.c create mode 100644 src/imv.h (limited to 'src') diff --git a/src/imv.c b/src/imv.c new file mode 100644 index 0000000..c713dbc --- /dev/null +++ b/src/imv.c @@ -0,0 +1,470 @@ +/* Copyright (c) 2017 imv authors + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "imv.h" + +#include +#include +#include +#include +#include +#include + +#include "commands.h" +#include "list.h" +#include "loader.h" +#include "texture.h" +#include "navigator.h" +#include "viewport.h" +#include "util.h" + +enum scaling_mode { + SCALING_NONE, + SCALING_DOWN, + SCALING_FULL, + SCALING_MODE_COUNT +}; + +static const char *scaling_label[] = { + "actual size", + "best fit", + "perfect fit" +}; + +enum background_type { + BACKGROUND_SOLID, + BACKGROUND_CHEQUERED, + BACKGROUND_TYPE_COUNT +}; + +struct imv { + bool quit; + bool fullscreen; + bool overlay_enabled; + bool nearest_neighbour; + bool need_redraw; + bool need_rescale; + bool recursive_load; + bool cycle_input; + bool list_at_exit; + enum scaling_mode scaling_mode; + enum background_type background_type; + struct { unsigned char r, g, b; } background_color; + unsigned long slideshow_image_duration; + unsigned long slideshow_time_elapsed; + char *font_name; + struct imv_navigator *navigator; + struct imv_loader *loader; + struct imv_commands *commands; + struct imv_texture *texture; + struct imv_viewport *view; + char *input_buffer; + char *starting_path; + + SDL_Window *window; + SDL_Renderer *renderer; + TTF_Font *font; + SDL_Texture *background_texture; +}; + +static void handle_event(struct imv *imv, SDL_Event *event); +static void render_window(struct imv *imv); + +struct imv *imv_create(void) +{ + struct imv *imv = malloc(sizeof(struct imv)); + imv->quit = false; + imv->fullscreen = false; + imv->overlay_enabled = false; + imv->nearest_neighbour = false; + imv->need_redraw = true; + imv->need_rescale = true; + imv->recursive_load = false; + imv->scaling_mode = SCALING_NONE; + imv->cycle_input = true; + imv->list_at_exit = false; + imv->background_color.r = imv->background_color.g = imv->background_color.b = 0; + imv->slideshow_image_duration = 0; + imv->slideshow_time_elapsed = 0; + imv->font_name = "Monospace:24"; + imv->navigator = imv_navigator_create(); + imv->loader = imv_loader_create(); + imv->commands = imv_commands_create(); + imv->input_buffer = NULL; + imv->starting_path = NULL; + imv->window = NULL; + imv->renderer = NULL; + imv->font = NULL; + imv->background_texture = NULL; + return imv; +} + +void imv_free(struct imv *imv) +{ + free(imv->font_name); + imv_navigator_free(imv->navigator); + imv_loader_free(imv->loader); + imv_commands_free(imv->commands); + if(imv->input_buffer) { + free(imv->input_buffer); + } + free(imv); +} + +bool imv_parse_args(struct imv *imv, int argc, char **argv) +{ + /* Do not print getopt errors */ + opterr = 0; + + char *argp, *ep = *argv; + int o; + + while((o = getopt(argc, argv, "frasSudxhln:b:e:t:")) != -1) { + switch(o) { + case 'f': imv->fullscreen = true; break; + case 'r': imv->recursive_load = true; break; + case 'a': imv->scaling_mode = SCALING_NONE; break; + case 's': imv->scaling_mode = SCALING_DOWN; break; + case 'S': imv->scaling_mode = SCALING_FULL; break; + case 'u': imv->nearest_neighbour = true; break; + case 'd': imv->overlay_enabled = true; break; + case 'x': imv->cycle_input = false; break; + case 'l': imv->list_at_exit = true; break; + case 'n': imv->starting_path = optarg; break; + case 'e': imv->font_name = strdup(optarg); break; + case 'h': + fprintf(stdout, + "imv %s\n" + "See manual for usage information.\n" + "\n" + "Legal:\n" + "This program is free software; you can redistribute it and/or\n" + "modify it under the terms of the GNU General Public License\n" + "as published by the Free Software Foundation; either version 2\n" + "of the License, or (at your option) any later version.\n" + "\n" + "This software uses the FreeImage open source image library.\n" + "See http://freeimage.sourceforge.net for details.\n" + "FreeImage is used under the GNU GPLv2.\n" + , IMV_VERSION); + imv->quit = true; + return true; + case 'b': + if(strcmp("checks", optarg) == 0) { + imv->background_type = BACKGROUND_CHEQUERED; + } else { + imv->background_type = BACKGROUND_SOLID; + argp = (*optarg == '#') ? optarg + 1 : optarg; + uint32_t n = strtoul(argp, &ep, 16); + if(*ep != '\0' || ep - argp != 6 || n > 0xFFFFFF) { + fprintf(stderr, "Invalid hex color: '%s'\n", optarg); + return false; + } + imv->background_color.b = n & 0xFF; + imv->background_color.g = (n >> 8) & 0xFF; + imv->background_color.r = (n >> 16); + } + break; + case 't': + imv->slideshow_image_duration = strtoul(optarg, &argp, 10); + imv->slideshow_image_duration *= 1000; + if (*argp == '.') { + long delay = strtoul(++argp, &ep, 10); + for (int i = 3 - (ep - argp); i; i--) { + delay *= 10; + } + if (delay < 1000) { + imv->slideshow_image_duration += delay; + } else { + imv->slideshow_image_duration = ULONG_MAX; + } + } + if (imv->slideshow_image_duration == ULONG_MAX) { + fprintf(stderr, "Wrong slideshow delay '%s'. Aborting.\n", optarg); + return false; + } + break; + case '?': + fprintf(stderr, "Unknown argument '%c'. Aborting.\n", optopt); + return false; + } + } + + argc -= optind; + argv += optind; + + /* TODO parse paths ? */ + return true; +} + +void imv_add_path(struct imv *imv, const char *path) +{ + (void)imv; + (void)path; +} + +int imv_run(struct imv *imv) +{ + imv->quit = 0; + + while(!imv->quit) { + + SDL_Event e; + while(!imv->quit && SDL_PollEvent(&e)) { + handle_event(imv, &e); + } + + if(imv->need_redraw) { + render_window(imv); + SDL_RenderPresent(imv->renderer); + } + + /* sleep a little bit so we don't waste CPU time */ + SDL_Delay(10); + } + + return 0; +} + +static void handle_event(struct imv *imv, SDL_Event *event) +{ + const int command_buffer_len = 1024; + switch(event->type) { + case SDL_QUIT: + imv_command_exec(imv->commands, "quit", NULL); + break; + + case SDL_TEXTINPUT: + strncat(imv->input_buffer, event->text.text, command_buffer_len - 1); + imv->need_redraw = true; + break; + + case SDL_KEYDOWN: + SDL_ShowCursor(SDL_DISABLE); + + if(imv->input_buffer) { + /* in command mode, update the buffer */ + if(event->key.keysym.sym == SDLK_ESCAPE) { + SDL_StopTextInput(); + free(imv->input_buffer); + imv->input_buffer = NULL; + imv->need_redraw = true; + } else if(event->key.keysym.sym == SDLK_RETURN) { + imv_command_exec(imv->commands, imv->input_buffer, NULL); + SDL_StopTextInput(); + free(imv->input_buffer); + imv->input_buffer = NULL; + imv->need_redraw = true; + } else if(event->key.keysym.sym == SDLK_BACKSPACE) { + const size_t len = strlen(imv->input_buffer); + if(len > 0) { + imv->input_buffer[len - 1] = '\0'; + imv->need_redraw = true; + } + } + + return; + } + + switch (event->key.keysym.sym) { + case SDLK_SEMICOLON: + if(event->key.keysym.mod & KMOD_SHIFT) { + SDL_StartTextInput(); + imv->input_buffer = malloc(command_buffer_len); + imv->input_buffer[0] = '\0'; + imv->need_redraw = true; + } + break; + case SDLK_q: + imv_command_exec(imv->commands, "quit", NULL); + break; + case SDLK_LEFTBRACKET: + case SDLK_LEFT: + imv_command_exec(imv->commands, "select_rel -1", NULL); + break; + case SDLK_RIGHTBRACKET: + case SDLK_RIGHT: + imv_command_exec(imv->commands, "select_rel 1", NULL); + break; + case SDLK_EQUALS: + case SDLK_PLUS: + case SDLK_i: + case SDLK_UP: + imv_viewport_zoom(imv->view, imv->texture, IMV_ZOOM_KEYBOARD, 1); + break; + case SDLK_MINUS: + case SDLK_o: + case SDLK_DOWN: + imv_viewport_zoom(imv->view, imv->texture, IMV_ZOOM_KEYBOARD, -1); + break; + case SDLK_s: + if(!event->key.repeat) { + imv->scaling_mode++; + imv->scaling_mode %= SCALING_MODE_COUNT; + } + /* FALLTHROUGH */ + case SDLK_r: + if(!event->key.repeat) { + imv->need_rescale = true; + imv->need_redraw = true; + } + break; + case SDLK_a: + if(!event->key.repeat) { + imv_viewport_scale_to_actual(imv->view, imv->texture); + } + break; + case SDLK_c: + if(!event->key.repeat) { + imv_viewport_center(imv->view, imv->texture); + } + break; + case SDLK_j: + imv_command_exec(imv->commands, "pan 0 -50", NULL); + break; + case SDLK_k: + imv_command_exec(imv->commands, "pan 0 50", NULL); + break; + case SDLK_h: + imv_command_exec(imv->commands, "pan 50 0", NULL); + break; + case SDLK_l: + imv_command_exec(imv->commands, "pan -50 0", NULL); + break; + case SDLK_x: + if(!event->key.repeat) { + imv_command_exec(imv->commands, "remove", NULL); + } + break; + case SDLK_f: + if(!event->key.repeat) { + imv_command_exec(imv->commands, "fullscreen", NULL); + } + break; + case SDLK_PERIOD: + imv_loader_load_next_frame(imv->loader); + break; + case SDLK_SPACE: + if(!event->key.repeat) { + imv_viewport_toggle_playing(imv->view); + } + break; + case SDLK_p: + if(!event->key.repeat) { + puts(imv_navigator_selection(imv->navigator)); + } + break; + case SDLK_d: + if(!event->key.repeat) { + imv_command_exec(imv->commands, "overlay", NULL); + } + break; + case SDLK_t: + if(event->key.keysym.mod & (KMOD_SHIFT|KMOD_CAPS)) { + if(imv->slideshow_image_duration >= 1000) { + imv->slideshow_image_duration -= 1000; + } + } else { + imv->slideshow_image_duration += 1000; + } + imv->need_redraw = true; + break; + } + break; + case SDL_MOUSEWHEEL: + imv_viewport_zoom(imv->view, imv->texture, IMV_ZOOM_MOUSE, event->wheel.y); + SDL_ShowCursor(SDL_ENABLE); + break; + case SDL_MOUSEMOTION: + if(event->motion.state & SDL_BUTTON_LMASK) { + imv_viewport_move(imv->view, event->motion.xrel, event->motion.yrel); + } + SDL_ShowCursor(SDL_ENABLE); + break; + case SDL_WINDOWEVENT: + imv_viewport_update(imv->view, imv->texture); + break; + } +} + +static void render_window(struct imv *imv) +{ + char title[1024]; + int ww, wh; + SDL_GetWindowSize(imv->window, &ww, &wh); + + /* update window title */ + const char *current_path = imv_navigator_selection(imv->navigator); + int len = snprintf(title, sizeof(title), "imv - [%i/%i] [%ix%i] [%.2f%%] %s [%s]", + imv->navigator->cur_path + 1, imv->navigator->num_paths, imv->texture->width, imv->texture->height, + 100.0 * imv->view->scale, + current_path, scaling_label[imv->scaling_mode]); + if(imv->slideshow_image_duration >= 1000) { + len += snprintf(title + len, sizeof(title) - len, "[%lu/%lus]", + imv->slideshow_time_elapsed / 1000 + 1, imv->slideshow_image_duration / 1000); + } + imv_viewport_set_title(imv->view, title); + + /* first we draw the background */ + if(imv->background_type == BACKGROUND_SOLID) { + /* solid background */ + SDL_SetRenderDrawColor(imv->renderer, + imv->background_color.r, + imv->background_color.g, + imv->background_color.b, + 255); + SDL_RenderClear(imv->renderer); + } else { + /* chequered background */ + int img_w, img_h; + SDL_QueryTexture(imv->background_texture, NULL, NULL, &img_w, &img_h); + /* tile the texture so it fills the window */ + for(int y = 0; y < wh; y += img_h) { + for(int x = 0; x < ww; x += img_w) { + SDL_Rect dst_rect = {x,y,img_w,img_h}; + SDL_RenderCopy(imv->renderer, imv->background_texture, NULL, &dst_rect); + } + } + } + + /* draw our actual texture */ + imv_texture_draw(imv->texture, imv->view->x, imv->view->y, imv->view->scale); + + /* if the overlay needs to be drawn, draw that too */ + if(imv->overlay_enabled && imv->font) { + SDL_Color fg = {255,255,255,255}; + SDL_Color bg = {0,0,0,160}; + imv_printf(imv->renderer, imv->font, 0, 0, &fg, &bg, "%s", + title + strlen("imv - ")); + } + + /* draw command entry bar if needed */ + if(imv->input_buffer && imv->font) { + SDL_Color fg = {255,255,255,255}; + SDL_Color bg = {0,0,0,160}; + imv_printf(imv->renderer, + imv->font, + 0, wh - TTF_FontHeight(imv->font), + &fg, &bg, + ":%s", imv->input_buffer); + } + + /* redraw complete, unset the flag */ + imv->need_redraw = false; +} + +/* vim:set ts=2 sts=2 sw=2 et: */ diff --git a/src/imv.h b/src/imv.h new file mode 100644 index 0000000..7c00bb7 --- /dev/null +++ b/src/imv.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2017 imv authors + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef IMV_H +#define IMV_H + +#include + +struct imv; + +struct imv *imv_create(void); +void imv_free(struct imv *imv); + +bool imv_parse_args(struct imv *imv, int argc, char **argv); + +void imv_add_path(struct imv *imv, const char *path); + +int imv_run(struct imv *imv); + +#endif + +/* vim:set ts=2 sts=2 sw=2 et: */ -- cgit v1.2.3 From 8d5166d69ff1abf893409d847adc80a84dc688e8 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 18 Apr 2017 17:24:08 +0100 Subject: Add window set-up logic --- src/imv.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/imv.h | 2 +- 2 files changed, 92 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/imv.c b/src/imv.c index c713dbc..5240596 100644 --- a/src/imv.c +++ b/src/imv.c @@ -79,8 +79,11 @@ struct imv { SDL_Renderer *renderer; TTF_Font *font; SDL_Texture *background_texture; + bool sdl_init; + bool ttf_init; }; +static bool setup_window(struct imv *imv); static void handle_event(struct imv *imv, SDL_Event *event); static void render_window(struct imv *imv); @@ -110,6 +113,8 @@ struct imv *imv_create(void) imv->renderer = NULL; imv->font = NULL; imv->background_texture = NULL; + imv->sdl_init = false; + imv->ttf_init = false; return imv; } @@ -122,6 +127,24 @@ void imv_free(struct imv *imv) if(imv->input_buffer) { free(imv->input_buffer); } + if(imv->renderer) { + SDL_DestroyRenderer(imv->renderer); + } + if(imv->window) { + SDL_DestroyWindow(imv->window); + } + if(imv->background_texture) { + SDL_DestroyTexture(imv->background_texture); + } + if(imv->font) { + TTF_CloseFont(imv->font); + } + if(imv->ttf_init) { + TTF_Quit(); + } + if(imv->sdl_init) { + SDL_Quit(); + } free(imv); } @@ -217,8 +240,11 @@ void imv_add_path(struct imv *imv, const char *path) (void)path; } -int imv_run(struct imv *imv) +bool imv_run(struct imv *imv) { + if(!setup_window(imv)) + return false; + imv->quit = 0; while(!imv->quit) { @@ -240,6 +266,70 @@ int imv_run(struct imv *imv) return 0; } +static bool setup_window(struct imv *imv) +{ + if(SDL_Init(SDL_INIT_VIDEO) != 0) { + fprintf(stderr, "SDL Failed to Init: %s\n", SDL_GetError()); + return false; + } + imv->sdl_init = true; + + /* width and height arbitrarily chosen. Perhaps there's a smarter way to + * set this */ + const int width = 1280; + const int height = 720; + + imv->window = SDL_CreateWindow( + "imv", + SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, + width, height, + SDL_WINDOW_RESIZABLE); + + if(!imv->window) { + fprintf(stderr, "SDL Failed to create window: %s\n", SDL_GetError()); + return false; + } + + /* we'll use SDL's built-in renderer, hardware accelerated if possible */ + imv->renderer = SDL_CreateRenderer(imv->window, -1, 0); + if(!imv->renderer) { + fprintf(stderr, "SDL Failed to create renderer: %s\n", SDL_GetError()); + return false; + } + + /* use the appropriate resampling method */ + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, + imv->nearest_neighbour ? "0" : "1"); + + /* construct a chequered background texture */ + if(imv->background_type == BACKGROUND_CHEQUERED) { + imv->background_texture = create_chequered(imv->renderer); + } + + /* set up the required fonts and surfaces for displaying the overlay */ + TTF_Init(); + imv->ttf_init = true; + imv->font = load_font(imv->font_name); + if(!imv->font) { + fprintf(stderr, "Error loading font: %s\n", TTF_GetError()); + return false; + } + + imv->texture = imv_texture_create(imv->renderer); + imv->view = imv_viewport_create(imv->window); + + /* put us in fullscren mode to begin with if requested */ + if(imv->fullscreen) { + imv_viewport_toggle_fullscreen(imv->view); + } + + /* start outside of command mode */ + SDL_StopTextInput(); + + return true; +} + static void handle_event(struct imv *imv, SDL_Event *event) { const int command_buffer_len = 1024; diff --git a/src/imv.h b/src/imv.h index 7c00bb7..0945fe2 100644 --- a/src/imv.h +++ b/src/imv.h @@ -29,7 +29,7 @@ bool imv_parse_args(struct imv *imv, int argc, char **argv); void imv_add_path(struct imv *imv, const char *path); -int imv_run(struct imv *imv); +bool imv_run(struct imv *imv); #endif -- cgit v1.2.3 From c67d1b529cd7c1b1e95c30b2a34e6b53aa2e2bdb Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 18 Apr 2017 17:36:43 +0100 Subject: Fix crash in imv_loader_free --- src/loader.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/loader.c b/src/loader.c index c5b64a6..e85050b 100644 --- a/src/loader.c +++ b/src/loader.c @@ -57,7 +57,9 @@ struct imv_loader *imv_loader_create(void) void imv_loader_free(struct imv_loader *ldr) { /* wait for any existing bg thread to finish */ - pthread_join(ldr->bg_thread, NULL); + if(ldr->bg_thread) { + pthread_join(ldr->bg_thread, NULL); + } pthread_mutex_destroy(&ldr->lock); if(ldr->bmp) { -- cgit v1.2.3 From 202a2c8c8af2bc2f5f910042d134069142375b67 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 18 Apr 2017 17:53:12 +0100 Subject: Fix font_name crash --- src/imv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/imv.c b/src/imv.c index 5240596..516bfed 100644 --- a/src/imv.c +++ b/src/imv.c @@ -103,7 +103,7 @@ struct imv *imv_create(void) imv->background_color.r = imv->background_color.g = imv->background_color.b = 0; imv->slideshow_image_duration = 0; imv->slideshow_time_elapsed = 0; - imv->font_name = "Monospace:24"; + imv->font_name = strdup("Monospace:24"); imv->navigator = imv_navigator_create(); imv->loader = imv_loader_create(); imv->commands = imv_commands_create(); -- cgit v1.2.3 From 2df9da145a66d8551c940218fb5150151fc0864c Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 18 Apr 2017 17:53:20 +0100 Subject: Implement imv_add_path --- src/imv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/imv.c b/src/imv.c index 516bfed..a74f646 100644 --- a/src/imv.c +++ b/src/imv.c @@ -236,8 +236,7 @@ bool imv_parse_args(struct imv *imv, int argc, char **argv) void imv_add_path(struct imv *imv, const char *path) { - (void)imv; - (void)path; + imv_navigator_add(imv->navigator, path, imv->recursive_load); } bool imv_run(struct imv *imv) -- cgit v1.2.3 From 06b1620c1a60a2c02be3053424ec0c13dc7fa724 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 18 Apr 2017 17:54:06 +0100 Subject: Rough initial implementation of imv_run --- src/imv.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) (limited to 'src') diff --git a/src/imv.c b/src/imv.c index a74f646..e43aca7 100644 --- a/src/imv.c +++ b/src/imv.c @@ -246,6 +246,10 @@ bool imv_run(struct imv *imv) imv->quit = 0; + /* cache current image's dimensions */ + int iw = 0; + int ih = 0; + while(!imv->quit) { SDL_Event e; @@ -253,6 +257,81 @@ bool imv_run(struct imv *imv) handle_event(imv, &e); } + /* if we're quitting, don't bother drawing any more images */ + if(imv->quit) { + break; + } + + /* check if an image failed to load, if so, remove it from our image list */ + char *err_path = imv_loader_get_error(imv->loader); + if(err_path) { + imv_navigator_remove(imv->navigator, err_path); + + /* special case: the image came from stdin */ + /* if (strncmp(err_path, "-", 2) == 0) { */ + /* free(stdin_buffer); */ + /* stdin_buffer_size = 0; */ + /* if (stdin_error != 0) { */ + /* errno = stdin_error; */ + /* perror("Failed to load image from standard input"); */ + /* errno = 0; */ + /* } */ + /* } */ + free(err_path); + } + + /* Check if navigator wrapped around paths lists */ + if(!imv->cycle_input && imv_navigator_wrapped(imv->navigator)) { + break; + } + + /* if the user has changed image, start loading the new one */ + if(imv_navigator_poll_changed(imv->navigator)) { + const char *current_path = imv_navigator_selection(imv->navigator); + if(!current_path) { + /* if(!imv->stdin_list) { */ + fprintf(stderr, "No input files left. Exiting.\n"); + imv->quit = 1; + /* } */ + continue; + } + + char title[1024]; + snprintf(title, sizeof(title), "imv - [%i/%i] [LOADING] %s [%s]", + imv->navigator->cur_path + 1, imv->navigator->num_paths, current_path, + scaling_label[imv->scaling_mode]); + imv_viewport_set_title(imv->view, title); + + imv_loader_load(imv->loader, current_path, "", 0 /*stdin_buffer, stdin_buffer_size*/); + imv->view->playing = 1; + } + + + /* check if a new image is available to display */ + FIBITMAP *bmp; + int is_new_image; + if(imv_loader_get_image(imv->loader, &bmp, &is_new_image)) { + imv_texture_set_image(imv->texture, bmp); + iw = FreeImage_GetWidth(bmp); + ih = FreeImage_GetHeight(bmp); + FreeImage_Unload(bmp); + imv->need_redraw = 1; + imv->need_rescale += is_new_image; + } + + if(imv->need_rescale) { + int ww, wh; + SDL_GetWindowSize(imv->window, &ww, &wh); + + imv->need_rescale = 0; + if(imv->scaling_mode == SCALING_NONE || + (imv->scaling_mode == SCALING_DOWN && ww > iw && wh > ih)) { + imv_viewport_scale_to_actual(imv->view, imv->texture); + } else { + imv_viewport_scale_to_window(imv->view, imv->texture); + } + } + if(imv->need_redraw) { render_window(imv); SDL_RenderPresent(imv->renderer); -- cgit v1.2.3 From 625a1c14dbc0473cd50f96c536ead99f807776c2 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 18 Apr 2017 18:03:32 +0100 Subject: Add basic commands to refactor --- src/imv.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 109 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/imv.c b/src/imv.c index e43aca7..49ec82e 100644 --- a/src/imv.c +++ b/src/imv.c @@ -83,6 +83,15 @@ struct imv { bool ttf_init; }; +void command_quit(struct imv_list *args, void *data); +void command_pan(struct imv_list *args, void *data); +void command_select_rel(struct imv_list *args, void *data); +void command_select_abs(struct imv_list *args, void *data); +void command_zoom(struct imv_list *args, void *data); +void command_remove(struct imv_list *args, void *data); +void command_fullscreen(struct imv_list *args, void *data); +void command_overlay(struct imv_list *args, void *data); + static bool setup_window(struct imv *imv); static void handle_event(struct imv *imv, SDL_Event *event); static void render_window(struct imv *imv); @@ -115,6 +124,22 @@ struct imv *imv_create(void) imv->background_texture = NULL; imv->sdl_init = false; imv->ttf_init = false; + + imv_command_register(imv->commands, "quit", &command_quit); + imv_command_register(imv->commands, "pan", &command_pan); + imv_command_register(imv->commands, "select_rel", &command_select_rel); + imv_command_register(imv->commands, "select_abs", &command_select_abs); + imv_command_register(imv->commands, "zoom", &command_zoom); + imv_command_register(imv->commands, "remove", &command_remove); + imv_command_register(imv->commands, "fullscreen", &command_fullscreen); + imv_command_register(imv->commands, "overlay", &command_overlay); + + imv_command_alias(imv->commands, "q", "quit"); + imv_command_alias(imv->commands, "next", "select_rel 1"); + imv_command_alias(imv->commands, "previous", "select_rel -1"); + imv_command_alias(imv->commands, "n", "select_rel 1"); + imv_command_alias(imv->commands, "p", "select_rel -1"); + return imv; } @@ -413,7 +438,7 @@ static void handle_event(struct imv *imv, SDL_Event *event) const int command_buffer_len = 1024; switch(event->type) { case SDL_QUIT: - imv_command_exec(imv->commands, "quit", NULL); + imv_command_exec(imv->commands, "quit", imv); break; case SDL_TEXTINPUT: @@ -432,7 +457,7 @@ static void handle_event(struct imv *imv, SDL_Event *event) imv->input_buffer = NULL; imv->need_redraw = true; } else if(event->key.keysym.sym == SDLK_RETURN) { - imv_command_exec(imv->commands, imv->input_buffer, NULL); + imv_command_exec(imv->commands, imv->input_buffer, imv); SDL_StopTextInput(); free(imv->input_buffer); imv->input_buffer = NULL; @@ -458,15 +483,16 @@ static void handle_event(struct imv *imv, SDL_Event *event) } break; case SDLK_q: - imv_command_exec(imv->commands, "quit", NULL); + imv->quit = true; + imv_command_exec(imv->commands, "quit", imv); break; case SDLK_LEFTBRACKET: case SDLK_LEFT: - imv_command_exec(imv->commands, "select_rel -1", NULL); + imv_command_exec(imv->commands, "select_rel -1", imv); break; case SDLK_RIGHTBRACKET: case SDLK_RIGHT: - imv_command_exec(imv->commands, "select_rel 1", NULL); + imv_command_exec(imv->commands, "select_rel 1", imv); break; case SDLK_EQUALS: case SDLK_PLUS: @@ -502,25 +528,25 @@ static void handle_event(struct imv *imv, SDL_Event *event) } break; case SDLK_j: - imv_command_exec(imv->commands, "pan 0 -50", NULL); + imv_command_exec(imv->commands, "pan 0 -50", imv); break; case SDLK_k: - imv_command_exec(imv->commands, "pan 0 50", NULL); + imv_command_exec(imv->commands, "pan 0 50", imv); break; case SDLK_h: - imv_command_exec(imv->commands, "pan 50 0", NULL); + imv_command_exec(imv->commands, "pan 50 0", imv); break; case SDLK_l: - imv_command_exec(imv->commands, "pan -50 0", NULL); + imv_command_exec(imv->commands, "pan -50 0", imv); break; case SDLK_x: if(!event->key.repeat) { - imv_command_exec(imv->commands, "remove", NULL); + imv_command_exec(imv->commands, "remove", imv); } break; case SDLK_f: if(!event->key.repeat) { - imv_command_exec(imv->commands, "fullscreen", NULL); + imv_command_exec(imv->commands, "fullscreen", imv); } break; case SDLK_PERIOD: @@ -538,7 +564,7 @@ static void handle_event(struct imv *imv, SDL_Event *event) break; case SDLK_d: if(!event->key.repeat) { - imv_command_exec(imv->commands, "overlay", NULL); + imv_command_exec(imv->commands, "overlay", imv); } break; case SDLK_t: @@ -635,4 +661,75 @@ static void render_window(struct imv *imv) imv->need_redraw = false; } +void command_quit(struct imv_list *args, void *data) +{ + (void)args; + struct imv *imv = data; + imv->quit = 1; +} + +void command_pan(struct imv_list *args, void *data) +{ + struct imv *imv = data; + if(args->len != 3) { + return; + } + + long int x = strtol(args->items[1], NULL, 10); + long int y = strtol(args->items[2], NULL, 10); + + imv_viewport_move(imv->view, x, y); +} + +void command_select_rel(struct imv_list *args, void *data) +{ + struct imv *imv = data; + if(args->len != 2) { + return; + } + + long int index = strtol(args->items[1], NULL, 10); + imv_navigator_select_rel(imv->navigator, index); + + imv->slideshow_time_elapsed = 0; +} + +void command_select_abs(struct imv_list *args, void *data) +{ + (void)args; + (void)data; +} + +void command_zoom(struct imv_list *args, void *data) +{ + (void)args; + (void)data; +} + +void command_remove(struct imv_list *args, void *data) +{ + (void)args; + struct imv *imv = data; + char* path = strdup(imv_navigator_selection(imv->navigator)); + imv_navigator_remove(imv->navigator, path); + free(path); + + imv->slideshow_time_elapsed = 0; +} + +void command_fullscreen(struct imv_list *args, void *data) +{ + (void)args; + struct imv *imv = data; + imv_viewport_toggle_fullscreen(imv->view); +} + +void command_overlay(struct imv_list *args, void *data) +{ + (void)args; + struct imv *imv = data; + imv->overlay_enabled = !imv->overlay_enabled; + imv->need_redraw = true; +} + /* vim:set ts=2 sts=2 sw=2 et: */ -- cgit v1.2.3 From 6c7e4b9c032cd40674169c06561fe58f18f146cd Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 6 Jun 2017 19:52:20 +0100 Subject: Load paths from stdin --- src/imv.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- src/imv.h | 2 ++ 2 files changed, 77 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/imv.c b/src/imv.c index 49ec82e..6dbd777 100644 --- a/src/imv.c +++ b/src/imv.c @@ -19,10 +19,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include +#include #include #include #include #include +#include #include "commands.h" #include "list.h" @@ -61,6 +63,7 @@ struct imv { bool recursive_load; bool cycle_input; bool list_at_exit; + bool paths_from_stdin; enum scaling_mode scaling_mode; enum background_type background_type; struct { unsigned char r, g, b; } background_color; @@ -74,6 +77,7 @@ struct imv { struct imv_viewport *view; char *input_buffer; char *starting_path; + struct pollfd stdin_fd; SDL_Window *window; SDL_Renderer *renderer; @@ -109,6 +113,7 @@ struct imv *imv_create(void) imv->scaling_mode = SCALING_NONE; imv->cycle_input = true; imv->list_at_exit = false; + imv->paths_from_stdin = false; imv->background_color.r = imv->background_color.g = imv->background_color.b = 0; imv->slideshow_image_duration = 0; imv->slideshow_time_elapsed = 0; @@ -255,10 +260,69 @@ bool imv_parse_args(struct imv *imv, int argc, char **argv) argc -= optind; argv += optind; - /* TODO parse paths ? */ + /* if no paths are given as args, expect them from stdin */ + if(argc == 0) { + imv->paths_from_stdin = true; + } + + if(imv->paths_from_stdin) { + imv->stdin_fd.fd = STDIN_FILENO; + imv->stdin_fd.events = POLLIN; + fprintf(stderr, "Reading paths from stdin..."); + + char buf[PATH_MAX]; + char *stdin_ok; + while((stdin_ok = fgets(buf, sizeof(buf), stdin)) != NULL) { + size_t len = strlen(buf); + if(buf[len-1] == '\n') { + buf[--len] = 0; + } + if(len > 0) { + imv_add_path(imv, buf); + break; + } + } + if(!stdin_ok) { + fprintf(stderr, " no input!\n"); + return false; + } + fprintf(stderr, "\n"); + } return true; } +void imv_check_stdin_for_paths(struct imv *imv) +{ + /* check stdin to see if we've been given any new paths to load */ + if(poll(&imv->stdin_fd, 1, 10) != 1 || imv->stdin_fd.revents & (POLLERR|POLLNVAL)) { + fprintf(stderr, "error polling stdin"); + imv->quit = true; + return; + } + + if(imv->stdin_fd.revents & (POLLIN|POLLHUP)) { + char buf[PATH_MAX]; + if(fgets(buf, sizeof(buf), stdin) == NULL && ferror(stdin)) { + clearerr(stdin); + return; + } + if(feof(stdin)) { + imv->paths_from_stdin = false; + fprintf(stderr, "done with stdin\n"); + return; + } + + size_t len = strlen(buf); + if(buf[len-1] == '\n') { + buf[--len] = 0; + } + if(len > 0) { + imv_add_path(imv, buf); + imv->need_redraw = true; + } + } +} + void imv_add_path(struct imv *imv, const char *path) { imv_navigator_add(imv->navigator, path, imv->recursive_load); @@ -314,10 +378,10 @@ bool imv_run(struct imv *imv) if(imv_navigator_poll_changed(imv->navigator)) { const char *current_path = imv_navigator_selection(imv->navigator); if(!current_path) { - /* if(!imv->stdin_list) { */ + if(!imv->paths_from_stdin) { fprintf(stderr, "No input files left. Exiting.\n"); - imv->quit = 1; - /* } */ + imv->quit = true; + } continue; } @@ -362,8 +426,13 @@ bool imv_run(struct imv *imv) SDL_RenderPresent(imv->renderer); } - /* sleep a little bit so we don't waste CPU time */ - SDL_Delay(10); + if(imv->paths_from_stdin) { + /* check stdin for any more paths */ + imv_check_stdin_for_paths(imv); + } else { + /* sleep a little bit so we don't waste CPU time */ + SDL_Delay(10); + } } return 0; diff --git a/src/imv.h b/src/imv.h index 0945fe2..0538ca7 100644 --- a/src/imv.h +++ b/src/imv.h @@ -27,6 +27,8 @@ void imv_free(struct imv *imv); bool imv_parse_args(struct imv *imv, int argc, char **argv); +void imv_check_stdin_for_paths(struct imv *imv); + void imv_add_path(struct imv *imv, const char *path); bool imv_run(struct imv *imv); -- cgit v1.2.3 From 9dc4908ea44d15ba01fb2f66f3c39d4935195e3a Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 6 Jun 2017 20:00:42 +0100 Subject: Fix redraw on viewport update --- src/imv.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/imv.c b/src/imv.c index 6dbd777..9c6eded 100644 --- a/src/imv.c +++ b/src/imv.c @@ -421,6 +421,12 @@ bool imv_run(struct imv *imv) } } + + /* check if the viewport needs a redraw */ + if(imv_viewport_needs_redraw(imv->view)) { + imv->need_redraw = true; + } + if(imv->need_redraw) { render_window(imv); SDL_RenderPresent(imv->renderer); -- cgit v1.2.3 From 2fbe6678c2a1e8ecc8ed8835d7fa94a70196978a Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 6 Jun 2017 20:02:14 +0100 Subject: Don't mix ints and bools --- src/imv.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/imv.c b/src/imv.c index 9c6eded..578010d 100644 --- a/src/imv.c +++ b/src/imv.c @@ -333,7 +333,7 @@ bool imv_run(struct imv *imv) if(!setup_window(imv)) return false; - imv->quit = 0; + imv->quit = false; /* cache current image's dimensions */ int iw = 0; @@ -392,7 +392,7 @@ bool imv_run(struct imv *imv) imv_viewport_set_title(imv->view, title); imv_loader_load(imv->loader, current_path, "", 0 /*stdin_buffer, stdin_buffer_size*/); - imv->view->playing = 1; + imv->view->playing = true; } @@ -404,7 +404,7 @@ bool imv_run(struct imv *imv) iw = FreeImage_GetWidth(bmp); ih = FreeImage_GetHeight(bmp); FreeImage_Unload(bmp); - imv->need_redraw = 1; + imv->need_redraw = true; imv->need_rescale += is_new_image; } @@ -412,7 +412,7 @@ bool imv_run(struct imv *imv) int ww, wh; SDL_GetWindowSize(imv->window, &ww, &wh); - imv->need_rescale = 0; + imv->need_rescale = false; if(imv->scaling_mode == SCALING_NONE || (imv->scaling_mode == SCALING_DOWN && ww > iw && wh > ih)) { imv_viewport_scale_to_actual(imv->view, imv->texture); @@ -441,7 +441,7 @@ bool imv_run(struct imv *imv) } } - return 0; + return false; } static bool setup_window(struct imv *imv) @@ -740,7 +740,7 @@ void command_quit(struct imv_list *args, void *data) { (void)args; struct imv *imv = data; - imv->quit = 1; + imv->quit = true; } void command_pan(struct imv_list *args, void *data) -- cgit v1.2.3 From 973fe152b5e98ca4e75af41284b00193157043c4 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 6 Jun 2017 20:08:46 +0100 Subject: Fix animated gif / slideshow support --- src/imv.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'src') diff --git a/src/imv.c b/src/imv.c index 578010d..8a510ce 100644 --- a/src/imv.c +++ b/src/imv.c @@ -339,6 +339,10 @@ bool imv_run(struct imv *imv) int iw = 0; int ih = 0; + /* time keeping */ + unsigned int last_time = SDL_GetTicks(); + unsigned int current_time; + while(!imv->quit) { SDL_Event e; @@ -421,6 +425,36 @@ bool imv_run(struct imv *imv) } } + /* tell the loader time has passed (for gifs) */ + current_time = SDL_GetTicks(); + + /* if we're playing an animated gif, tell the loader how much time has + * passed */ + if(imv->view->playing) { + unsigned int dt = current_time - last_time; + /* We cap the delta-time to 100 ms so that if imv is asleep for several + * seconds or more (e.g. suspended), upon waking up it doesn't try to + * catch up all the time it missed by playing through the gif quickly. */ + if(dt > 100) { + dt = 100; + } + imv_loader_time_passed(imv->loader, dt / 1000.0); + } + + /* handle slideshow */ + if(imv->slideshow_image_duration != 0) { + unsigned int dt = current_time - last_time; + + imv->slideshow_time_elapsed += dt; + imv->need_redraw = true; /* need to update display */ + if(imv->slideshow_time_elapsed >= imv->slideshow_image_duration) { + imv_navigator_select_rel(imv->navigator, 1); + imv->slideshow_time_elapsed = 0; + } + } + + last_time = current_time; + /* check if the viewport needs a redraw */ if(imv_viewport_needs_redraw(imv->view)) { -- cgit v1.2.3 From 508e6344711bebc9193774bcb0a4ea3eeb2a8071 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 6 Jun 2017 20:14:59 +0100 Subject: Load paths from command line args --- src/imv.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/imv.c b/src/imv.c index 8a510ce..0e37e20 100644 --- a/src/imv.c +++ b/src/imv.c @@ -263,6 +263,11 @@ bool imv_parse_args(struct imv *imv, int argc, char **argv) /* if no paths are given as args, expect them from stdin */ if(argc == 0) { imv->paths_from_stdin = true; + } else { + /* otherwise, add the paths */ + for(int i = 0; i < argc; ++i) { + imv_add_path(imv, argv[i]); + } } if(imv->paths_from_stdin) { -- cgit v1.2.3 From eff4ee3fb359d747610ee706e904c8914841a6ba Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 6 Jun 2017 20:27:21 +0100 Subject: Switch to new implementation --- src/main.c | 876 +------------------------------------------------------------ 1 file changed, 11 insertions(+), 865 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 8cbd095..c2eb394 100644 --- a/src/main.c +++ b/src/main.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015 imv authors +/* Copyright (c) 2017 imv authors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -15,880 +15,26 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "commands.h" -#include "list.h" -#include "loader.h" -#include "texture.h" -#include "navigator.h" -#include "viewport.h" -#include "util.h" - -enum scaling_mode { - NONE, - DOWN, - FULL -}; - -static const char *scaling_label[] = { - "actual size", - "best fit", - "perfect fit" -}; - -struct { - int fullscreen; - int stdin_list; - int recursive; - int scaling; - int nearest_neighbour; - int solid_bg; - int list; - unsigned long delay; - int cycle; - unsigned char bg_r; - unsigned char bg_g; - unsigned char bg_b; - int overlay; - const char *start_at; - const char *font; -} g_options = { - .fullscreen = 0, - .stdin_list = 0, - .recursive = 0, - .scaling = FULL, - .nearest_neighbour = 0, - .solid_bg = 1, - .list = 0, - .delay = 0, - .cycle = 1, - .bg_r = 0, - .bg_g = 0, - .bg_b = 0, - .overlay = 0, - .start_at = NULL, - .font = "Monospace:24", -}; - -struct { - struct imv_navigator *nav; - struct imv_loader *ldr; - struct imv_texture *tex; - struct imv_viewport *view; - struct imv_commands *cmds; - int quit; - - /* used to calculate when to skip to the next image in slideshow mode */ - unsigned long delay_msec; - - /* do we need to redraw the window? */ - int need_redraw; - int need_rescale; - - /* buffer for command input - NULL when not in command mode */ - char *command_buffer; -} g_state; - -void cmd_quit(struct imv_list *args, void *data); -void cmd_pan(struct imv_list *args, void *data); -void cmd_select_rel(struct imv_list *args, void *data); -void cmd_select_abs(struct imv_list *args, void *data); -void cmd_zoom(struct imv_list *args, void *data); -void cmd_remove(struct imv_list *args, void *data); -void cmd_fullscreen(struct imv_list *args, void *data); -void cmd_overlay(struct imv_list *args, void *data); - -static void parse_args(int *argc, char ***argv); -void handle_event(SDL_Event *event); -void render_window( - SDL_Window *window, - SDL_Renderer *renderer, - TTF_Font *text_font, - SDL_Texture *bg_texture); +#include "imv.h" int main(int argc, char** argv) { - g_state.cmds = imv_commands_create(); - imv_command_register(g_state.cmds, "quit", &cmd_quit); - imv_command_register(g_state.cmds, "pan", &cmd_pan); - imv_command_register(g_state.cmds, "select_rel", &cmd_select_rel); - imv_command_register(g_state.cmds, "select_abs", &cmd_select_abs); - imv_command_register(g_state.cmds, "zoom", &cmd_zoom); - imv_command_register(g_state.cmds, "remove", &cmd_remove); - imv_command_register(g_state.cmds, "fullscreen", &cmd_fullscreen); - imv_command_register(g_state.cmds, "overlay", &cmd_overlay); - - imv_command_alias(g_state.cmds, "q", "quit"); - imv_command_alias(g_state.cmds, "next", "select_rel 1"); - imv_command_alias(g_state.cmds, "previous", "select_rel -1"); - imv_command_alias(g_state.cmds, "n", "select_rel 1"); - imv_command_alias(g_state.cmds, "p", "select_rel -1"); - - g_state.nav = imv_navigator_create(); - - /* parse any command line options given */ - parse_args(&argc, &argv); - - /* if no names are given, expect them on stdin */ - if(argc == 0) { - g_options.stdin_list = 1; - } - - /* if the user asked to load paths from stdin, set up poll(2)ing and read - the first path */ - struct pollfd rfds[1]; - if(g_options.stdin_list) { - rfds[0].fd = STDIN_FILENO; - rfds[0].events = POLLIN; - fprintf(stderr, "Reading paths from stdin..."); - - char buf[PATH_MAX]; - char *stdin_ok; - while((stdin_ok = fgets(buf, sizeof(buf), stdin)) != NULL) { - size_t len = strlen(buf); - if(buf[len-1] == '\n') { - buf[--len] = 0; - } - if(len > 0) { - if(imv_navigator_add(g_state.nav, buf, g_options.recursive) != 0) { - imv_navigator_free(g_state.nav); - exit(1); - } - break; - } - } - if(!stdin_ok) { - fprintf(stderr, " no input!\n"); - return -1; - } - fprintf(stderr, "\n"); - } - - void *stdin_buffer = NULL; - size_t stdin_buffer_size = 0; - int stdin_error = 0; - - /* handle any image paths given as arguments */ - for(int i = 0; i < argc; ++i) { - - /* special case: '-' means load raw image data from stdin */ - if(!strcmp("-",argv[i])) { - /* did we already load data from stdin? */ - if (stdin_buffer) { - fprintf(stderr, "Can't read from stdin twice\n"); - imv_navigator_free(g_state.nav); - exit(1); - } - /* actually load the data from stdin */ - stdin_buffer_size = read_from_stdin(&stdin_buffer); - if (stdin_buffer_size == 0) { - perror(NULL); - continue; /* we can't recover from the freed buffer, just ignore it */ - } - stdin_error = errno; - errno = 0; /* clear errno */ - } - /* add the given path to the list to load */ - if(imv_navigator_add(g_state.nav, argv[i], g_options.recursive) != 0) { - imv_navigator_free(g_state.nav); - exit(1); - } - } - - /* if we weren't given any paths we have nothing to view. exit */ - if(!imv_navigator_selection(g_state.nav)) { - fprintf(stderr, "No input files. Exiting.\n"); - imv_navigator_free(g_state.nav); - exit(1); - } - - /* go to the chosen starting image if possible */ - if(g_options.start_at) { - int start_index = imv_navigator_find_path(g_state.nav, g_options.start_at); - if(start_index < 0) { - start_index = strtol(g_options.start_at,NULL,10) - 1; - } - imv_navigator_select_str(g_state.nav, start_index); - } - - /* we've got something to display, so create an SDL window */ - if(SDL_Init(SDL_INIT_VIDEO) != 0) { - fprintf(stderr, "SDL Failed to Init: %s\n", SDL_GetError()); - imv_navigator_free(g_state.nav); - exit(1); - } - - /* width and height arbitrarily chosen. Perhaps there's a smarter way to - * set this */ - const int width = 1280; - const int height = 720; - - SDL_Window *window = SDL_CreateWindow( - "imv", - SDL_WINDOWPOS_CENTERED, - SDL_WINDOWPOS_CENTERED, - width, height, - SDL_WINDOW_RESIZABLE); - if(!window) { - fprintf(stderr, "SDL Failed to create window: %s\n", SDL_GetError()); - imv_navigator_free(g_state.nav); - SDL_Quit(); - exit(1); - } - - /* we'll use SDL's built-in renderer, hardware accelerated if possible */ - SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0); - if(!renderer) { - fprintf(stderr, "SDL Failed to create renderer: %s\n", SDL_GetError()); - imv_navigator_free(g_state.nav); - SDL_DestroyWindow(window); - SDL_Quit(); - exit(1); - } - - /* use the appropriate resampling method */ - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, - g_options.nearest_neighbour ? "0" : "1"); - - /* construct a chequered background texture */ - SDL_Texture *chequered_tex = NULL; - if(!g_options.solid_bg) { - chequered_tex = create_chequered(renderer); - } - - /* set up the required fonts and surfaces for displaying the overlay */ - TTF_Init(); - TTF_Font *font = load_font(g_options.font); - if(!font) { - fprintf(stderr, "Error loading font: %s\n", TTF_GetError()); - } - - /* create our main classes */ - g_state.ldr = imv_loader_create(); - g_state.tex = imv_texture_create(renderer); - g_state.view = imv_viewport_create(window); - - /* put us in fullscren mode to begin with if requested */ - if(g_options.fullscreen) { - imv_viewport_toggle_fullscreen(g_state.view); - } - - /* help keeping track of time */ - unsigned int last_time = SDL_GetTicks(); - unsigned int current_time; - - g_state.need_redraw = 1; - g_state.need_rescale = 0; - - /* keep title buffer around for reuse */ - char title[256]; - - g_state.delay_msec = 0; - - /* start outside of command mode */ - g_state.command_buffer = NULL; - SDL_StopTextInput(); - - /* initialize variables holding image dimentions */ - int iw = 0, ih = 0; - - g_state.quit = 0; - while(!g_state.quit) { - /* handle any input/window events sent by SDL */ - SDL_Event e; - while(!g_state.quit && SDL_PollEvent(&e)) { - handle_event(&e); - } - - /* if we're quitting, don't bother drawing any more images */ - if(g_state.quit) { - break; - } - - /* check if an image failed to load, if so, remove it from our image list */ - char *err_path = imv_loader_get_error(g_state.ldr); - if(err_path) { - imv_navigator_remove(g_state.nav, err_path); - - /* special case: the image came from stdin */ - if (strncmp(err_path, "-", 2) == 0) { - free(stdin_buffer); - stdin_buffer_size = 0; - if (stdin_error != 0) { - errno = stdin_error; - perror("Failed to load image from standard input"); - errno = 0; - } - } - free(err_path); - } - - /* Check if navigator wrapped around paths lists */ - if(!g_options.cycle && imv_navigator_wrapped(g_state.nav)) { - break; - } - - /* if the user has changed image, start loading the new one */ - if(imv_navigator_poll_changed(g_state.nav)) { - const char *current_path = imv_navigator_selection(g_state.nav); - if(!current_path) { - if(!g_options.stdin_list) { - fprintf(stderr, "No input files left. Exiting.\n"); - g_state.quit = 1; - } - continue; - } - - snprintf(title, sizeof(title), "imv - [%i/%i] [LOADING] %s [%s]", - g_state.nav->cur_path + 1, g_state.nav->num_paths, current_path, - scaling_label[g_options.scaling]); - imv_viewport_set_title(g_state.view, title); - - imv_loader_load(g_state.ldr, current_path, stdin_buffer, stdin_buffer_size); - g_state.view->playing = 1; - } - - - /* check if a new image is available to display */ - FIBITMAP *bmp; - int is_new_image; - if(imv_loader_get_image(g_state.ldr, &bmp, &is_new_image)) { - imv_texture_set_image(g_state.tex, bmp); - iw = FreeImage_GetWidth(bmp); - ih = FreeImage_GetHeight(bmp); - FreeImage_Unload(bmp); - g_state.need_redraw = 1; - g_state.need_rescale += is_new_image; - } - - if(g_state.need_rescale) { - int ww, wh; - SDL_GetWindowSize(window, &ww, &wh); - - g_state.need_rescale = 0; - if(g_options.scaling == NONE || - (g_options.scaling == DOWN && ww > iw && wh > ih)) { - imv_viewport_scale_to_actual(g_state.view, g_state.tex); - } else { - imv_viewport_scale_to_window(g_state.view, g_state.tex); - } - } - - current_time = SDL_GetTicks(); - - /* if we're playing an animated gif, tell the loader how much time has - * passed */ - if(g_state.view->playing) { - unsigned int dt = current_time - last_time; - /* We cap the delta-time to 100 ms so that if imv is asleep for several - * seconds or more (e.g. suspended), upon waking up it doesn't try to - * catch up all the time it missed by playing through the gif quickly. */ - if(dt > 100) { - dt = 100; - } - imv_loader_time_passed(g_state.ldr, dt / 1000.0); - } - - /* handle slideshow */ - if(g_options.delay) { - unsigned int dt = current_time - last_time; - - g_state.delay_msec += dt; - g_state.need_redraw = 1; - if(g_state.delay_msec >= g_options.delay) { - imv_navigator_select_rel(g_state.nav, 1); - g_state.delay_msec = 0; - } - } - - last_time = current_time; - - /* check if the viewport needs a redraw */ - if(imv_viewport_needs_redraw(g_state.view)) { - g_state.need_redraw = 1; - } - - /* only redraw when something's changed */ - if(g_state.need_redraw) { - render_window(window, renderer, font, chequered_tex); - /* tell SDL to show the newly drawn frame */ - SDL_RenderPresent(renderer); - } - - /* try to read some more paths from stdin */ - if(g_options.stdin_list) { - if(poll(rfds, 1, 10) != 1 || rfds[0].revents & (POLLERR|POLLNVAL)) { - fprintf(stderr, "error polling stdin"); - return 1; - } - if(rfds[0].revents & (POLLIN|POLLHUP)) { - char buf[PATH_MAX]; - if(fgets(buf, sizeof(buf), stdin) == NULL && ferror(stdin)) { - clearerr(stdin); - continue; - } - if(feof(stdin)) { - g_options.stdin_list = 0; - fprintf(stderr, "done with stdin\n"); - continue; - } - - size_t len = strlen(buf); - if(buf[len-1] == '\n') { - buf[--len] = 0; - } - if(len > 0) { - if(imv_navigator_add(g_state.nav, buf, g_options.recursive)) { - break; - } - g_state.need_redraw = 1; - } - } - } else { - /* sleep a little bit so we don't waste CPU time */ - SDL_Delay(10); - } - } - while(g_options.list) { - const char *path = imv_navigator_selection(g_state.nav); - if(!path) { - break; - } - fprintf(stdout, "%s\n", path); - imv_navigator_remove(g_state.nav, path); - } - - /* clean up our resources now that we're exiting */ - if(g_state.command_buffer) { - free(g_state.command_buffer); - } - - imv_loader_free(g_state.ldr); - imv_texture_free(g_state.tex); - imv_navigator_free(g_state.nav); - imv_viewport_free(g_state.view); - imv_commands_free(g_state.cmds); - - if(font) { - TTF_CloseFont(font); - } - TTF_Quit(); - if(chequered_tex) { - SDL_DestroyTexture(chequered_tex); - } - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(window); - SDL_Quit(); - - return 0; -} - -void cmd_quit(struct imv_list *args, void *data) -{ - (void)args; - (void)data; - g_state.quit = 1; -} + struct imv *imv = imv_create(); -void cmd_pan(struct imv_list *args, void *data) -{ - (void)data; - if(args->len != 3) { - return; + if(!imv) { + return 1; } - long int x = strtol(args->items[1], NULL, 10); - long int y = strtol(args->items[2], NULL, 10); - - imv_viewport_move(g_state.view, x, y); -} - -void cmd_select_rel(struct imv_list *args, void *data) -{ - (void)data; - if(args->len != 2) { - return; + if(!imv_parse_args(imv, argc, argv)) { + imv_free(imv); + return 1; } - long int index = strtol(args->items[1], NULL, 10); - imv_navigator_select_rel(g_state.nav, index); - - /* reset slideshow delay */ - g_state.delay_msec = 0; -} - -void cmd_select_abs(struct imv_list *args, void *data) -{ - (void)args; - (void)data; -} - -void cmd_zoom(struct imv_list *args, void *data) -{ - (void)args; - (void)data; -} - -void cmd_remove(struct imv_list *args, void *data) -{ - (void)args; - (void)data; - char* path = strdup(imv_navigator_selection(g_state.nav)); - imv_navigator_remove(g_state.nav, path); - free(path); - - /* reset slideshow delay */ - g_state.delay_msec = 0; -} - -void cmd_fullscreen(struct imv_list *args, void *data) -{ - (void)args; - (void)data; - imv_viewport_toggle_fullscreen(g_state.view); -} + int ret = imv_run(imv); -void cmd_overlay(struct imv_list *args, void *data) -{ - (void)args; - (void)data; - g_options.overlay = !g_options.overlay; - g_state.need_redraw = 1; -} - -static void print_usage(void) -{ - fprintf(stdout, - "imv %s\n" - "See manual for usage information.\n" - "\n" - "Legal:\n" - "This program is free software; you can redistribute it and/or\n" - "modify it under the terms of the GNU General Public License\n" - "as published by the Free Software Foundation; either version 2\n" - "of the License, or (at your option) any later version.\n" - "\n" - "This software uses the FreeImage open source image library.\n" - "See http://freeimage.sourceforge.net for details.\n" - "FreeImage is used under the GNU GPLv2.\n" - , IMV_VERSION); -} - -static void parse_args(int *argc, char ***argv) -{ - /* Do not print getopt errors */ - opterr = 0; - - char *argp, *ep = **argv; - int o; - - while((o = getopt(*argc, *argv, "firasSudxhln:b:e:t:")) != -1) { - switch(o) { - case 'f': g_options.fullscreen = 1; break; - case 'i': - g_options.stdin_list = 1; - fprintf(stderr, "Warning: '-i' is deprecated. No flag is needed.\n"); - break; - case 'r': g_options.recursive = 1; break; - case 'a': g_options.scaling = NONE; break; - case 's': g_options.scaling = DOWN; break; - case 'S': g_options.scaling = FULL; break; - case 'u': g_options.nearest_neighbour = 1; break; - case 'd': g_options.overlay = 1; break; - case 'x': g_options.cycle = 0; break; - case 'h': print_usage(); exit(0); break; - case 'l': g_options.list = 1; break; - case 'n': - g_options.start_at = optarg; - break; - case 'b': - if(strcmp("checks", optarg) == 0) { - g_options.solid_bg = 0; - } else { - g_options.solid_bg = 1; - argp = (*optarg == '#') ? optarg + 1 : optarg; - uint32_t n = strtoul(argp, &ep, 16); - if(*ep != '\0' || ep - argp != 6 || n > 0xFFFFFF) { - fprintf(stderr, "Invalid hex color: '%s'\n", optarg); - exit(1); - } - g_options.bg_b = n & 0xFF; - g_options.bg_g = (n >> 8) & 0xFF; - g_options.bg_r = (n >> 16); - } - break; - case 'e': - g_options.font = optarg; - break; - case 't': - g_options.delay = strtoul(optarg, &argp, 10); - g_options.delay *= 1000; - if (*argp == '.') { - long delay = strtoul(++argp, &ep, 10); - for (int i = 3 - (ep - argp); i; i--) { - delay *= 10; - } - if (delay < 1000) { - g_options.delay += delay; - } else { - g_options.delay = ULONG_MAX; - } - } - if (g_options.delay == ULONG_MAX) { - fprintf(stderr, "Wrong slideshow delay '%s'. Aborting.\n", optarg); - exit(1); - } - break; - case '?': - fprintf(stderr, "Unknown argument '%c'. Aborting.\n", optopt); - exit(1); - } - } - - *argc -= optind; - *argv += optind; -} - - -void handle_event(SDL_Event *event) -{ - const int command_buffer_len = 1024; - switch(event->type) { - case SDL_QUIT: - imv_command_exec(g_state.cmds, "quit", NULL); - break; - - case SDL_TEXTINPUT: - strncat(g_state.command_buffer, event->text.text, command_buffer_len - 1); - g_state.need_redraw = 1; - break; - - case SDL_KEYDOWN: - SDL_ShowCursor(SDL_DISABLE); - - if(g_state.command_buffer) { - /* in command mode, update the buffer */ - if(event->key.keysym.sym == SDLK_ESCAPE) { - SDL_StopTextInput(); - free(g_state.command_buffer); - g_state.command_buffer = NULL; - g_state.need_redraw = 1; - } else if(event->key.keysym.sym == SDLK_RETURN) { - imv_command_exec(g_state.cmds, g_state.command_buffer, NULL); - SDL_StopTextInput(); - free(g_state.command_buffer); - g_state.command_buffer = NULL; - g_state.need_redraw = 1; - } else if(event->key.keysym.sym == SDLK_BACKSPACE) { - const size_t len = strlen(g_state.command_buffer); - if(len > 0) { - g_state.command_buffer[len - 1] = '\0'; - g_state.need_redraw = 1; - } - } - - return; - } - - switch (event->key.keysym.sym) { - case SDLK_SEMICOLON: - if(event->key.keysym.mod & KMOD_SHIFT) { - SDL_StartTextInput(); - g_state.command_buffer = malloc(command_buffer_len); - g_state.command_buffer[0] = '\0'; - g_state.need_redraw = 1; - } - break; - case SDLK_q: - imv_command_exec(g_state.cmds, "quit", NULL); - break; - case SDLK_LEFTBRACKET: - case SDLK_LEFT: - imv_command_exec(g_state.cmds, "select_rel -1", NULL); - break; - case SDLK_RIGHTBRACKET: - case SDLK_RIGHT: - imv_command_exec(g_state.cmds, "select_rel 1", NULL); - break; - case SDLK_EQUALS: - case SDLK_PLUS: - case SDLK_i: - case SDLK_UP: - imv_viewport_zoom(g_state.view, g_state.tex, IMV_ZOOM_KEYBOARD, 1); - break; - case SDLK_MINUS: - case SDLK_o: - case SDLK_DOWN: - imv_viewport_zoom(g_state.view, g_state.tex, IMV_ZOOM_KEYBOARD, -1); - break; - case SDLK_s: - if(!event->key.repeat) { - if((g_options.scaling += 1) > FULL) { - g_options.scaling = NONE; - } - } - /* FALLTHROUGH */ - case SDLK_r: - if(!event->key.repeat) { - g_state.need_rescale = 1; - g_state.need_redraw = 1; - } - break; - case SDLK_a: - if(!event->key.repeat) { - imv_viewport_scale_to_actual(g_state.view, g_state.tex); - } - break; - case SDLK_c: - if(!event->key.repeat) { - imv_viewport_center(g_state.view, g_state.tex); - } - break; - case SDLK_j: - imv_command_exec(g_state.cmds, "pan 0 -50", NULL); - break; - case SDLK_k: - imv_command_exec(g_state.cmds, "pan 0 50", NULL); - break; - case SDLK_h: - imv_command_exec(g_state.cmds, "pan 50 0", NULL); - break; - case SDLK_l: - imv_command_exec(g_state.cmds, "pan -50 0", NULL); - break; - case SDLK_x: - if(!event->key.repeat) { - imv_command_exec(g_state.cmds, "remove", NULL); - } - break; - case SDLK_f: - if(!event->key.repeat) { - imv_command_exec(g_state.cmds, "fullscreen", NULL); - } - break; - case SDLK_PERIOD: - imv_loader_load_next_frame(g_state.ldr); - break; - case SDLK_SPACE: - if(!event->key.repeat) { - imv_viewport_toggle_playing(g_state.view); - } - break; - case SDLK_p: - if(!event->key.repeat) { - puts(imv_navigator_selection(g_state.nav)); - } - break; - case SDLK_d: - if(!event->key.repeat) { - imv_command_exec(g_state.cmds, "overlay", NULL); - } - break; - case SDLK_t: - if(event->key.keysym.mod & (KMOD_SHIFT|KMOD_CAPS)) { - if(g_options.delay >= 1000) { - g_options.delay -= 1000; - } - } else { - g_options.delay += 1000; - } - g_state.need_redraw = 1; - break; - } - break; - case SDL_MOUSEWHEEL: - imv_viewport_zoom(g_state.view, g_state.tex, IMV_ZOOM_MOUSE, event->wheel.y); - SDL_ShowCursor(SDL_ENABLE); - break; - case SDL_MOUSEMOTION: - if(event->motion.state & SDL_BUTTON_LMASK) { - imv_viewport_move(g_state.view, event->motion.xrel, event->motion.yrel); - } - SDL_ShowCursor(SDL_ENABLE); - break; - case SDL_WINDOWEVENT: - imv_viewport_update(g_state.view, g_state.tex); - break; - } -} - -void render_window( - SDL_Window *window, - SDL_Renderer *renderer, - TTF_Font *text_font, - SDL_Texture *bg_texture) -{ - char title[1024]; - int ww, wh; - SDL_GetWindowSize(window, &ww, &wh); - - /* update window title */ - const char *current_path = imv_navigator_selection(g_state.nav); - int len = snprintf(title, sizeof(title), "imv - [%i/%i] [%ix%i] [%.2f%%] %s [%s]", - g_state.nav->cur_path + 1, g_state.nav->num_paths, g_state.tex->width, g_state.tex->height, - 100.0 * g_state.view->scale, - current_path, scaling_label[g_options.scaling]); - if(g_options.delay >= 1000) { - len += snprintf(title + len, sizeof(title) - len, "[%lu/%lus]", - g_state.delay_msec / 1000 + 1, g_options.delay / 1000); - } - imv_viewport_set_title(g_state.view, title); - - /* first we draw the background */ - if(g_options.solid_bg) { - /* solid background */ - SDL_SetRenderDrawColor(renderer, - g_options.bg_r, g_options.bg_g, g_options.bg_b, 255); - SDL_RenderClear(renderer); - } else { - /* background */ - int img_w, img_h; - SDL_QueryTexture(bg_texture, NULL, NULL, &img_w, &img_h); - /* tile the texture so it fills the window */ - for(int y = 0; y < wh; y += img_h) { - for(int x = 0; x < ww; x += img_w) { - SDL_Rect dst_rect = {x,y,img_w,img_h}; - SDL_RenderCopy(renderer, bg_texture, NULL, &dst_rect); - } - } - } - - /* draw our actual texture */ - imv_texture_draw(g_state.tex, g_state.view->x, g_state.view->y, g_state.view->scale); - - /* if the overlay needs to be drawn, draw that too */ - if(g_options.overlay && text_font) { - SDL_Color fg = {255,255,255,255}; - SDL_Color bg = {0,0,0,160}; - imv_printf(renderer, text_font, 0, 0, &fg, &bg, "%s", - title + strlen("imv - ")); - } - - /* draw command entry bar if needed */ - if(g_state.command_buffer && text_font) { - SDL_Color fg = {255,255,255,255}; - SDL_Color bg = {0,0,0,160}; - imv_printf(renderer, - text_font, - 0, wh - TTF_FontHeight(text_font), - &fg, &bg, - ":%s", g_state.command_buffer); - } + imv_free(imv); - /* redraw complete, unset the flag */ - g_state.need_redraw = 0; + return ret; } /* vim:set ts=2 sts=2 sw=2 et: */ -- cgit v1.2.3 From eb0b93b8e28f8b885f60d53f011357324a3a4d94 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 6 Jun 2017 20:35:43 +0100 Subject: check_stdin_for_paths shouldn't be public --- src/imv.c | 4 ++-- src/imv.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/imv.c b/src/imv.c index 0e37e20..a0b23d7 100644 --- a/src/imv.c +++ b/src/imv.c @@ -296,7 +296,7 @@ bool imv_parse_args(struct imv *imv, int argc, char **argv) return true; } -void imv_check_stdin_for_paths(struct imv *imv) +static void check_stdin_for_paths(struct imv *imv) { /* check stdin to see if we've been given any new paths to load */ if(poll(&imv->stdin_fd, 1, 10) != 1 || imv->stdin_fd.revents & (POLLERR|POLLNVAL)) { @@ -473,7 +473,7 @@ bool imv_run(struct imv *imv) if(imv->paths_from_stdin) { /* check stdin for any more paths */ - imv_check_stdin_for_paths(imv); + check_stdin_for_paths(imv); } else { /* sleep a little bit so we don't waste CPU time */ SDL_Delay(10); diff --git a/src/imv.h b/src/imv.h index 0538ca7..0945fe2 100644 --- a/src/imv.h +++ b/src/imv.h @@ -27,8 +27,6 @@ void imv_free(struct imv *imv); bool imv_parse_args(struct imv *imv, int argc, char **argv); -void imv_check_stdin_for_paths(struct imv *imv); - void imv_add_path(struct imv *imv, const char *path); bool imv_run(struct imv *imv); -- cgit v1.2.3 From 29888f9f042e49a9b991ca2e6e790d808a3b74e9 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 6 Jun 2017 20:46:05 +0100 Subject: Tweak default scaling mode --- src/imv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/imv.c b/src/imv.c index a0b23d7..656b3a5 100644 --- a/src/imv.c +++ b/src/imv.c @@ -43,8 +43,8 @@ enum scaling_mode { static const char *scaling_label[] = { "actual size", - "best fit", - "perfect fit" + "shrink to fit", + "scale to fit" }; enum background_type { @@ -110,7 +110,7 @@ struct imv *imv_create(void) imv->need_redraw = true; imv->need_rescale = true; imv->recursive_load = false; - imv->scaling_mode = SCALING_NONE; + imv->scaling_mode = SCALING_FULL; imv->cycle_input = true; imv->list_at_exit = false; imv->paths_from_stdin = false; -- cgit v1.2.3 From 12450f38753699b0e606c3ad542892752da6aca8 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Sun, 18 Jun 2017 16:23:19 +0100 Subject: Support loading image data from stdin --- src/imv.c | 43 +++++++++++++++++++++++++++++++++---------- src/loader.c | 2 ++ src/util.c | 2 +- 3 files changed, 36 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/imv.c b/src/imv.c index 656b3a5..368973b 100644 --- a/src/imv.c +++ b/src/imv.c @@ -75,6 +75,8 @@ struct imv { struct imv_commands *commands; struct imv_texture *texture; struct imv_viewport *view; + void *stdin_image_data; + size_t stdin_image_data_len; char *input_buffer; char *starting_path; struct pollfd stdin_fd; @@ -121,6 +123,8 @@ struct imv *imv_create(void) imv->navigator = imv_navigator_create(); imv->loader = imv_loader_create(); imv->commands = imv_commands_create(); + imv->stdin_image_data = NULL; + imv->stdin_image_data_len = 0; imv->input_buffer = NULL; imv->starting_path = NULL; imv->window = NULL; @@ -154,6 +158,9 @@ void imv_free(struct imv *imv) imv_navigator_free(imv->navigator); imv_loader_free(imv->loader); imv_commands_free(imv->commands); + if(imv->stdin_image_data) { + free(imv->stdin_image_data); + } if(imv->input_buffer) { free(imv->input_buffer); } @@ -265,7 +272,23 @@ bool imv_parse_args(struct imv *imv, int argc, char **argv) imv->paths_from_stdin = true; } else { /* otherwise, add the paths */ + bool data_from_stdin = false; for(int i = 0; i < argc; ++i) { + + /* Special case: '-' denotes reading image data from stdin */ + if(!strcmp("-", argv[i])) { + if(imv->paths_from_stdin) { + fprintf(stderr, "Can't read paths AND image data from stdin. Aborting.\n"); + return false; + } else if(data_from_stdin) { + fprintf(stderr, "Can't read image data from stdin twice. Aborting.\n"); + return false; + } + data_from_stdin = true; + + imv->stdin_image_data_len = read_from_stdin(&imv->stdin_image_data); + } + imv_add_path(imv, argv[i]); } } @@ -366,15 +389,14 @@ bool imv_run(struct imv *imv) imv_navigator_remove(imv->navigator, err_path); /* special case: the image came from stdin */ - /* if (strncmp(err_path, "-", 2) == 0) { */ - /* free(stdin_buffer); */ - /* stdin_buffer_size = 0; */ - /* if (stdin_error != 0) { */ - /* errno = stdin_error; */ - /* perror("Failed to load image from standard input"); */ - /* errno = 0; */ - /* } */ - /* } */ + if(strncmp(err_path, "-", 2) == 0) { + if(imv->stdin_image_data) { + free(imv->stdin_image_data); + imv->stdin_image_data = NULL; + imv->stdin_image_data_len = 0; + } + fprintf(stderr, "Failed to load image from stdin.\n"); + } free(err_path); } @@ -400,7 +422,8 @@ bool imv_run(struct imv *imv) scaling_label[imv->scaling_mode]); imv_viewport_set_title(imv->view, title); - imv_loader_load(imv->loader, current_path, "", 0 /*stdin_buffer, stdin_buffer_size*/); + imv_loader_load(imv->loader, current_path, + imv->stdin_image_data, imv->stdin_image_data_len); imv->view->playing = true; } diff --git a/src/loader.c b/src/loader.c index e85050b..b21b140 100644 --- a/src/loader.c +++ b/src/loader.c @@ -98,6 +98,7 @@ void imv_loader_load(struct imv_loader *ldr, const char *path, ldr->buffer_size = buffer_size; } else if (ldr->fi_buffer != NULL) { FreeImage_CloseMemory(ldr->fi_buffer); + ldr->fi_buffer = NULL; } pthread_create(&ldr->bg_thread, NULL, &bg_new_img, ldr); pthread_mutex_unlock(&ldr->lock); @@ -191,6 +192,7 @@ static void *bg_new_img(void *data) if (from_stdin) { pthread_mutex_lock(&ldr->lock); FreeImage_CloseMemory(ldr->fi_buffer); + ldr->fi_buffer = NULL; pthread_mutex_unlock(&ldr->lock); } error_occurred(ldr); diff --git a/src/util.c b/src/util.c index 9b2b867..71d4c14 100644 --- a/src/util.c +++ b/src/util.c @@ -24,7 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. size_t read_from_stdin(void **buffer) { size_t len = 0; ssize_t r; - size_t step = 1024; /* Arbitrary value of 1 KiB */ + size_t step = 4096; /* Arbitrary value of 4 KiB */ void *p; errno = 0; /* clear errno */ -- cgit v1.2.3