diff options
author | nirav <nirav@teisuu.com> | 2018-09-09 12:13:13 +0530 |
---|---|---|
committer | Dandelion <nirav@teisuu.com> | 2018-09-09 12:46:57 +0530 |
commit | e54d8327819e310b7b148e45c15fca197be845c7 (patch) | |
tree | 04e513d52ed2191364e6b9472cd0f3882a60da4a /src | |
parent | 661756c9237a26562cae102f53b12aa0b403fde1 (diff) | |
download | im-e54d8327819e310b7b148e45c15fca197be845c7.tar.gz im-e54d8327819e310b7b148e45c15fca197be845c7.zip |
Moved source files to src dir, updated makefile
Diffstat (limited to 'src')
-rw-r--r-- | src/file.c | 131 | ||||
-rw-r--r-- | src/file.h | 15 | ||||
-rw-r--r-- | src/image.c | 97 | ||||
-rw-r--r-- | src/image.h | 25 | ||||
-rw-r--r-- | src/input.c | 206 | ||||
-rw-r--r-- | src/input.h | 13 | ||||
-rw-r--r-- | src/main.c | 51 | ||||
-rw-r--r-- | src/window.c | 105 | ||||
-rw-r--r-- | src/window.h | 12 |
9 files changed, 655 insertions, 0 deletions
diff --git a/src/file.c b/src/file.c new file mode 100644 index 0000000..dcbcbf0 --- /dev/null +++ b/src/file.c @@ -0,0 +1,131 @@ +#define _DEFAULT_SOURCE +#include "file.h" +#include "image.h" +#include <dirent.h> +#include <gtk-3.0/gtk/gtk.h> +#include <libgen.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +static char **extensions = NULL; + +char *get_filename_ext(const char *file_name) +{ + char *dot = strrchr(file_name, '.'); + if (!dot || dot == file_name) + return ""; + return dot + 1; +} + +int is_file_format_supported(const char *file_name) +{ + char *file_ext = get_filename_ext(file_name); + char **it = extensions; + while (*it != NULL) { + if (!strcmp(*it++, file_ext)) { + return 1; + } + } + return 0; +} + +void scan_supported_formats() +{ + GSList *list, *it; + GdkPixbufFormat *format; + gchar **exts, **ex_it; + int i = 0; + + list = gdk_pixbuf_get_formats(); + if (list != NULL) { + for (it = list; it->next != NULL; it = it->next) { + format = (GdkPixbufFormat *)it->data; + exts = gdk_pixbuf_format_get_extensions(format); + if (exts != NULL) { + ex_it = exts; + while (*ex_it != NULL) { + extensions = realloc(extensions, sizeof(char *) * (i + 1)); + extensions[i++] = strdup(*ex_it); + g_free(*ex_it); + ex_it++; + } + g_free(exts); + } + } + g_slist_free(list); + extensions[i] = NULL; + } +} + +int image_filter(const struct dirent *dir) +{ + if (dir->d_type == DT_REG && is_file_format_supported(dir->d_name)) { + return 1; + } + return 0; +} + +int scan(const char *file_name) +{ + scan_supported_formats(); + struct dirent **name_list; + char *dir_name = dirname(strdup(file_name)); + file_list_count = scandir(dir_name, &name_list, image_filter, alphasort); + if (file_list_count < 0) { + return -1; + } + + file_list = malloc(file_list_count * sizeof(char *)); + char *file_basename = basename(strdup(file_name)); + int i = 0; + while (i < file_list_count) { + if (!strcmp(file_basename, name_list[i]->d_name)) + curr_file_index = i; + file_list[i] = g_build_filename(dir_name, name_list[i]->d_name, NULL); + free(name_list[i]); + i++; + } + free(name_list); + + return 0; +} + +char *get_next_file() +{ + if (curr_file_index >= file_list_count - 1) + return NULL; + return file_list[++curr_file_index]; +} + +char *get_prev_file() +{ + if (curr_file_index <= 0) + return NULL; + return file_list[--curr_file_index]; +} + +char *get_first_file() +{ + if (curr_file_index == 0) + return NULL; + curr_file_index = 0; + return file_list[curr_file_index]; +} + +char *get_last_file() +{ + if (curr_file_index == file_list_count - 1) + return NULL; + curr_file_index = file_list_count - 1; + return file_list[curr_file_index]; +} + +void clean() +{ + for (int i = 0; i < file_list_count; ++i) { + g_free(file_list[i]); + } + g_free(file_list); +} diff --git a/src/file.h b/src/file.h new file mode 100644 index 0000000..7e8c167 --- /dev/null +++ b/src/file.h @@ -0,0 +1,15 @@ +#ifndef __FILE_H +#define __FILE_H + +char **file_list; +char *curr_file_name; +int curr_file_index, file_list_count; + +int scan(const char *file_name); +char *get_next_file(); +char *get_prev_file(); +char *get_first_file(); +char *get_last_file(); +void clean(); + +#endif diff --git a/src/image.c b/src/image.c new file mode 100644 index 0000000..d4765fd --- /dev/null +++ b/src/image.c @@ -0,0 +1,97 @@ +#include "image.h" +#include "window.h" +#include <gtk-3.0/gtk/gtk.h> + +GtkWidget *new_image() +{ + image = gtk_image_new(); + return image; +} + +int load_image(char *file_name) +{ + GError *error = NULL; + if (pixbuf != NULL) + g_object_unref(pixbuf); + pixbuf = gdk_pixbuf_new_from_file(file_name, &error); + if (error) + return -1; + curr_pixbuf_width = pixbuf_width = gdk_pixbuf_get_width(GDK_PIXBUF(pixbuf)); + curr_pixbuf_height = pixbuf_height = + gdk_pixbuf_get_height(GDK_PIXBUF(pixbuf)); + aspect_ratio = (double)pixbuf_width / (double)pixbuf_height; + curr_zoom = 1.0; + fit_image(); + set_window_title(g_path_get_basename(file_name)); + return 1; +} + +void update_pixbuf() +{ + if (curr_pixbuf != NULL) + g_object_unref(curr_pixbuf); + if (pixbuf == NULL) + return; + curr_pixbuf = + gdk_pixbuf_scale_simple(GDK_PIXBUF(pixbuf), curr_pixbuf_width, + curr_pixbuf_height, GDK_INTERP_BILINEAR); + gtk_image_set_from_pixbuf(GTK_IMAGE(image), GDK_PIXBUF(curr_pixbuf)); +} + +void fit_image() +{ + gint win_width, win_height; + get_curr_win_size(&win_width, &win_height); + curr_scale_mod = fit; + if (pixbuf == NULL || win_width < 1 || win_height < 1) + return; + if (win_width < pixbuf_width && win_height > pixbuf_height) { + curr_pixbuf_width = win_width; + curr_pixbuf_height = (double)curr_pixbuf_width / aspect_ratio; + } else if (win_width > pixbuf_width && win_height < pixbuf_height) { + curr_pixbuf_height = win_height; + curr_pixbuf_width = (double)curr_pixbuf_height * aspect_ratio; + } else if (win_width < pixbuf_width && win_height < pixbuf_height) { + if (((double)win_width / (double)win_height) > aspect_ratio) { + curr_pixbuf_height = win_height; + curr_pixbuf_width = ((double)curr_pixbuf_height * aspect_ratio); + } else { + curr_pixbuf_width = win_width; + curr_pixbuf_height = (double)curr_pixbuf_width / aspect_ratio; + } + } else { + curr_pixbuf_width = pixbuf_width; + curr_pixbuf_height = pixbuf_height; + } + + curr_zoom = (double)curr_pixbuf_width / (double)pixbuf_width; + if (curr_pixbuf_width < 1 || curr_pixbuf_height < 1) + return; + + update_pixbuf(); +} + +void zoom(int type) +{ + curr_scale_mod = zoomed; + if (pixbuf == NULL) + return; + if (type == 0) { + if (curr_zoom == 1.0) + return; + curr_zoom = 1.0; + } else if (type < 0) { + if (curr_zoom < 0.2) + return; + curr_zoom -= 0.1; + } else if (type > 0) { + if (curr_zoom > 2) + return; + curr_zoom += 0.1; + } + + curr_pixbuf_width = curr_zoom * (double)pixbuf_width; + curr_pixbuf_height = curr_zoom * (double)pixbuf_height; + + update_pixbuf(); +} diff --git a/src/image.h b/src/image.h new file mode 100644 index 0000000..dfbd9ff --- /dev/null +++ b/src/image.h @@ -0,0 +1,25 @@ +#ifndef __IMAGE_H +#define __IMAGE_H + +#include <gtk-3.0/gtk/gtk.h> + +#define ZOOM_FACTOR 0.1 + +enum scale_mode { + fit = 0, + zoomed = 1, +} curr_scale_mod; + +GtkWidget *image; +GdkPixbuf *pixbuf; +GdkPixbuf *curr_pixbuf; +int pixbuf_width, pixbuf_height, curr_pixbuf_width, curr_pixbuf_height; +double aspect_ratio; +double curr_zoom; + +GtkWidget *new_image(); +int load_image(char *file_name); +void fit_image(); +void zoom(int type); + +#endif diff --git a/src/input.c b/src/input.c new file mode 100644 index 0000000..1d21ef2 --- /dev/null +++ b/src/input.c @@ -0,0 +1,206 @@ +#include "input.h" +#include "file.h" +#include "image.h" +#include "window.h" +#include <gtk-3.0/gtk/gtk.h> + +#define TIMEOUT 20 +#define SCROLLAMMOUNT 30 + +int grabbed = 0; +gdouble start_x, start_y; + +void next() +{ + char *name; + if ((name = get_next_file()) != NULL) + load_image(name); +} + +void prev() +{ + char *name; + if ((name = get_prev_file()) != NULL) + load_image(name); +} + +void first() +{ + char *name; + if ((name = get_first_file()) != NULL) + load_image(name); +} + +void last() +{ + char *name; + if ((name = get_last_file()) != NULL) + load_image(name); +} + +void handle_key_press(GdkEvent *event) +{ + GdkModifierType state; + gdk_event_get_state(event, &state); + + switch (event->key.keyval) { + case GDK_KEY_q: + quit(); + case GDK_KEY_w: + fit_image(); + break; + case GDK_KEY_plus: + case GDK_KEY_KP_Add: + zoom(1); + break; + case GDK_KEY_minus: + case GDK_KEY_KP_Subtract: + zoom(-1); + break; + case GDK_KEY_equal: + zoom(0); + break; + case GDK_KEY_n: + next(); + break; + case GDK_KEY_p: + prev(); + break; + case GDK_KEY_Up: + if (curr_scale_mod == fit || state & GDK_SHIFT_MASK) + prev(); + else + scroll_window(0, -SCROLLAMMOUNT); + break; + case GDK_KEY_Down: + if (curr_scale_mod == fit || state & GDK_SHIFT_MASK) + next(); + else + scroll_window(0, SCROLLAMMOUNT); + break; + case GDK_KEY_Right: + if (curr_scale_mod == fit || state & GDK_SHIFT_MASK) + next(); + else + scroll_window(SCROLLAMMOUNT, 0); + break; + case GDK_KEY_Left: + if (curr_scale_mod == fit || state & GDK_SHIFT_MASK) + prev(); + else + scroll_window(-SCROLLAMMOUNT, 0); + break; + case GDK_KEY_j: + if (curr_scale_mod == fit) + next(); + else + scroll_window(0, SCROLLAMMOUNT); + break; + case GDK_KEY_J: + next(); + break; + case GDK_KEY_k: + if (curr_scale_mod == fit) + prev(); + else + scroll_window(0, -SCROLLAMMOUNT); + break; + case GDK_KEY_K: + prev(); + break; + case GDK_KEY_l: + if (curr_scale_mod == fit) + next(); + else + scroll_window(SCROLLAMMOUNT, 0); + break; + case GDK_KEY_L: + next(); + break; + case GDK_KEY_h: + if (curr_scale_mod == fit) + prev(); + else + scroll_window(-SCROLLAMMOUNT, 0); + break; + case GDK_KEY_H: + prev(); + break; + case GDK_KEY_g: + case GDK_KEY_Home: + first(); + break; + case GDK_KEY_G: + case GDK_KEY_End: + last(); + break; + default: + break; + } +} + +void handle_button_press(GdkEvent *event) +{ + grabbed = 1; + start_x = event->motion.x; + start_y = event->motion.y; +} + +void handle_button_release() +{ + grabbed = 0; +} + +void handle_mouse_move(gdouble x, gdouble y) +{ + if (grabbed) { + gdouble diff_x = start_x - x; + gdouble diff_y = start_y - y; + start_x = x; + start_y = y; + scroll_window(diff_x, diff_y); + } +} + +void handle_scroll(GdkEvent *event) +{ + GdkModifierType state; + gdk_event_get_state(event, &state); + + switch (event->scroll.direction) { + case GDK_SCROLL_UP: + if (state & GDK_CONTROL_MASK) { + zoom(1); + } else { + prev(); + } + break; + case GDK_SCROLL_DOWN: + if (state & GDK_CONTROL_MASK) { + zoom(-1); + } else { + next(); + } + break; + default: + break; + } +} + +gboolean resize_done(gpointer data) +{ + guint *id = data; + *id = 0; + fit_image(); + return FALSE; +} + +void handle_resize() +{ + if (curr_scale_mod != fit) + return; + static guint id = 0; + if (id) + g_source_remove(id); + id = g_timeout_add(TIMEOUT, resize_done, &id); +} diff --git a/src/input.h b/src/input.h new file mode 100644 index 0000000..ff50b0c --- /dev/null +++ b/src/input.h @@ -0,0 +1,13 @@ +#ifndef __INPUT_H +#define __INPUT_H + +#include <gtk-3.0/gtk/gtk.h> + +void handle_key_press(GdkEvent *event); +void handle_button_press(GdkEvent *event); +void handle_button_release(); +void handle_mouse_move(gdouble x, gdouble y); +void handle_scroll(GdkEvent *event); +void handle_resize(); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..b5eb616 --- /dev/null +++ b/src/main.c @@ -0,0 +1,51 @@ +#include "file.h" +#include "image.h" +#include "input.h" +#include "window.h" +#include <gtk-3.0/gtk/gtk.h> + +void print_help() +{ + printf("usage: qwe [filename]\n"); +} + +static void activate(GtkApplication *app, gpointer user_data) +{ + print_help(); +} + +static void open(GApplication *app, GFile **files, gint n_files, + const gchar *hint) +{ + if (n_files != 1) { + print_help(); + return; + } + + create_main_window(app); + + char *curr_filename = g_file_get_path(files[0]); + int i = scan(curr_filename); + if (i < 0) { + printf("failed to load file\n"); + return; + } + + i = load_image(curr_filename); + if (i < 0) { + printf("failed to load file\n"); + quit(); + } +} + +int main(int argc, char *argv[]) +{ + GtkApplication *app; + int status; + app = gtk_application_new("org.gtk.qwe", G_APPLICATION_HANDLES_OPEN); + g_signal_connect(app, "activate", G_CALLBACK(activate), NULL); + g_signal_connect(app, "open", G_CALLBACK(open), NULL); + status = g_application_run(G_APPLICATION(app), argc, argv); + g_object_unref(app); + return status; +} diff --git a/src/window.c b/src/window.c new file mode 100644 index 0000000..c659114 --- /dev/null +++ b/src/window.c @@ -0,0 +1,105 @@ +#include "window.h" +#include "file.h" +#include "image.h" +#include "input.h" +#include <gtk-3.0/gtk/gtk.h> + +GtkWidget *window; +GtkWidget *scrolled_window; + +static gboolean key_press(GtkWindow *window, GdkEvent *event, gpointer data) +{ + handle_key_press(event); + return FALSE; +} + +static gboolean button_press(GtkWindow *window, GdkEvent *event, gpointer data) +{ + handle_button_press(event); + return TRUE; +} + +static gboolean button_release(GtkWindow *window, GdkEvent *event, + gpointer data) +{ + handle_button_release(); + return TRUE; +} + +static gboolean motion_notify(GtkWindow *window, GdkEvent *event, gpointer data) +{ + handle_mouse_move(event->motion.x, event->motion.y); + return TRUE; +} + +static gboolean scroll_callback(GtkWindow *window, GdkEvent *event, + gpointer data) +{ + handle_scroll(event); + return TRUE; +} + +static gboolean configure_callback(GtkWindow *window, GdkEvent *event, + gpointer data) +{ + handle_resize(); + return TRUE; +} + +void create_main_window(GApplication *app) +{ + window = gtk_application_window_new(GTK_APPLICATION(app)); + gtk_window_set_title(GTK_WINDOW(window), "qwe"); + gtk_window_set_default_size(GTK_WINDOW(window), 800, 600); + g_signal_connect(G_OBJECT(window), "configure-event", + G_CALLBACK(configure_callback), NULL); + g_signal_connect(G_OBJECT(window), "key-press-event", G_CALLBACK(key_press), + NULL); + g_signal_connect(G_OBJECT(window), "button-press-event", + G_CALLBACK(button_press), NULL); + g_signal_connect(G_OBJECT(window), "button-release-event", + G_CALLBACK(button_release), NULL); + g_signal_connect(G_OBJECT(window), "motion-notify-event", + G_CALLBACK(motion_notify), NULL); + gtk_widget_add_events(GTK_WIDGET(window), GDK_SCROLL_MASK); + g_signal_connect(G_OBJECT(window), "scroll-event", + G_CALLBACK(scroll_callback), NULL); + + scrolled_window = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(new_image())); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(scrolled_window)); + gtk_widget_show_all(GTK_WIDGET(window)); +} + +void scroll_window(gdouble x, gdouble y) +{ + GtkAdjustment *h_adj = gtk_scrolled_window_get_hadjustment( + GTK_SCROLLED_WINDOW(scrolled_window)); + GtkAdjustment *v_adj = gtk_scrolled_window_get_vadjustment( + GTK_SCROLLED_WINDOW(scrolled_window)); + gtk_adjustment_set_value(h_adj, gtk_adjustment_get_value(h_adj) + x); + gtk_adjustment_set_value(v_adj, gtk_adjustment_get_value(v_adj) + y); + gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolled_window), + h_adj); + gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolled_window), + v_adj); +} + +void set_window_title(const char *title) +{ + gtk_window_set_title(GTK_WINDOW(window), title); +} + +void get_curr_win_size(gint *width, gint *height) +{ + gtk_window_get_size(GTK_WINDOW(window), width, height); +} + +void quit() +{ + clean(); + g_application_quit( + G_APPLICATION(gtk_window_get_application(GTK_WINDOW(window)))); +} diff --git a/src/window.h b/src/window.h new file mode 100644 index 0000000..8b8a7fe --- /dev/null +++ b/src/window.h @@ -0,0 +1,12 @@ +#ifndef __WINDOW_H +#define __WINDOW_H + +#include <gtk-3.0/gtk/gtk.h> + +void create_main_window(GApplication *app); +void get_curr_win_size(gint *width, gint *height); +void scroll_window(gdouble x, gdouble y); +void set_window_title(const char *title); +void quit(); + +#endif |