diff --git a/include/buffer.h b/include/buffer.h deleted file mode 100644 index 5e95fdc..0000000 --- a/include/buffer.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "swappy.h" - -bool buffer_init_from_file(struct swappy_state *state); -void buffer_resize_patterns(struct swappy_state *state); -void buffer_free_all(struct swappy_state *state); diff --git a/include/pixbuf.h b/include/pixbuf.h index 68a0cfa..4d439f7 100644 --- a/include/pixbuf.h +++ b/include/pixbuf.h @@ -2,8 +2,11 @@ #include "swappy.h" +GdkPixbuf *pixbuf_init_from_file(struct swappy_state *state); GdkPixbuf *pixbuf_get_from_state(struct swappy_state *state); void pixbuf_save_state_to_folder(GdkPixbuf *pixbuf, char *folder, char *filename_format); void pixbuf_save_to_file(GdkPixbuf *pixbuf, char *file); void pixbuf_save_to_stdout(GdkPixbuf *pixbuf); +void pixbuf_scale_surface_from_widget(struct swappy_state *state, + GtkWidget *widget); diff --git a/include/swappy.h b/include/swappy.h index 7818af0..1007b5f 100644 --- a/include/swappy.h +++ b/include/swappy.h @@ -148,6 +148,7 @@ struct swappy_state { struct swappy_state_ui *ui; struct swappy_config *config; + GdkPixbuf *original_image; cairo_surface_t *original_image_surface; cairo_surface_t *scaled_image_surface; cairo_surface_t *rendered_surface; @@ -165,8 +166,6 @@ struct swappy_state { struct swappy_box *window; struct swappy_box *geometry; - cairo_rectangle_int_t *drawing_area_rect; - GList *paints; GList *redo_paints; struct swappy_paint *temp_paint; diff --git a/meson.build b/meson.build index f78d93a..847f450 100644 --- a/meson.build +++ b/meson.build @@ -59,7 +59,6 @@ executable( 'src/main.c', 'src/algebra.c', 'src/application.c', - 'src/buffer.c', 'src/box.c', 'src/config.c', 'src/clipboard.c', diff --git a/src/application.c b/src/application.c index df9c562..923be68 100644 --- a/src/application.c +++ b/src/application.c @@ -5,7 +5,6 @@ #include #include -#include "buffer.h" #include "clipboard.h" #include "config.h" #include "file.h" @@ -231,8 +230,6 @@ void blur_clicked_handler(GtkWidget *widget, struct swappy_state *state) { void application_finish(struct swappy_state *state) { paint_free_all(state); - buffer_free_all(state); - g_free(state->drawing_area_rect); cairo_surface_destroy(state->rendered_surface); cairo_surface_destroy(state->original_image_surface); cairo_surface_destroy(state->scaled_image_surface); @@ -247,6 +244,7 @@ void application_finish(struct swappy_state *state) { g_free(state->geometry); g_free(state->window); g_free(state->ui); + g_object_unref(state->original_image); g_object_unref(state->app); config_free(state); @@ -394,27 +392,21 @@ gboolean draw_area_handler(GtkWidget *widget, cairo_t *cr, gboolean draw_area_configure_handler(GtkWidget *widget, GdkEventConfigure *event, struct swappy_state *state) { - g_debug("received configure_event handler"); + g_debug("received configure_event callback"); cairo_surface_destroy(state->rendered_surface); - g_free(state->drawing_area_rect); cairo_surface_t *surface = gdk_window_create_similar_surface( gtk_widget_get_window(widget), CAIRO_CONTENT_COLOR_ALPHA, gtk_widget_get_allocated_width(widget), gtk_widget_get_allocated_height(widget)); - state->rendered_surface = surface; + g_info("size of drawing area surface: %ux%u", + cairo_image_surface_get_width(surface), + cairo_image_surface_get_height(surface)); - GtkAllocation *alloc = g_new(GtkAllocation, 1); - gtk_widget_get_allocation(widget, alloc); - state->drawing_area_rect = alloc; - buffer_resize_patterns(state); + state->rendered_surface = surface; - g_info("size of cairo_surface: %ux%u with type: %d", - cairo_image_surface_get_width(surface), - cairo_image_surface_get_height(surface), - cairo_image_surface_get_format(surface)); - g_info("size of area to render: %ux%u", alloc->width, alloc->height); + pixbuf_scale_surface_from_widget(state, widget); render_state(state); @@ -562,18 +554,34 @@ static void compute_window_size(struct swappy_state *state) { state->window->y = workarea.y; double threshold = 0.75; - double scaling = 1.0; - if (state->geometry->width > workarea.width * threshold) { - scaling = workarea.width * threshold / state->geometry->width; - } else if (state->geometry->height > workarea.height * threshold) { - scaling = workarea.height * threshold / state->geometry->height; - } + int image_width = gdk_pixbuf_get_width(state->original_image); + int image_height = gdk_pixbuf_get_height(state->original_image); - state->window->width = state->geometry->width * scaling; - state->window->height = state->geometry->height * scaling; + int max_width = workarea.width * threshold; + int max_height = workarea.height * threshold; + g_info("size of image: %ux%u", image_width, image_height); g_info("size of monitor at window: %ux%u", workarea.width, workarea.height); + g_info("maxium size allowed for window: %ux%u", max_width, max_height); + + int scaled_width = image_width; + int scaled_height = image_height; + + double scaling_factor_width = (double)max_width / image_width; + double scaling_factor_height = (double)max_height / image_height; + + if (scaling_factor_height < 1.0 || scaling_factor_width < 1.0) { + double scaling_factor = MIN(scaling_factor_width, scaling_factor_height); + scaled_width = image_width * scaling_factor; + scaled_height = image_height * scaling_factor; + g_info("rendering area will be scaled by a factor of: %.2lf", + scaling_factor); + } + + state->window->width = scaled_width; + state->window->height = scaled_height; + g_info("size of window to render: %ux%u", state->window->width, state->window->height); } @@ -675,8 +683,8 @@ static bool load_layout(struct swappy_state *state) { } static bool init_gtk_window(struct swappy_state *state) { - if (!state->geometry) { - g_critical("no geometry found, did you use -f option?"); + if (!state->original_image) { + g_critical("original image not loaded"); return false; } @@ -725,7 +733,7 @@ static gint command_line_handler(GtkApplication *app, state->temp_file_str = temp_file_str; } - if (!buffer_init_from_file(state)) { + if (!pixbuf_init_from_file(state)) { return EXIT_FAILURE; } } diff --git a/src/buffer.c b/src/buffer.c deleted file mode 100644 index ac4b050..0000000 --- a/src/buffer.c +++ /dev/null @@ -1,94 +0,0 @@ -#include "buffer.h" - -#include - -#include "box.h" -#include "swappy.h" - -bool buffer_init_from_file(struct swappy_state *state) { - char *file = - state->temp_file_str != NULL ? state->temp_file_str : state->file_str; - - g_info("creating cairo image surface from file: %s", file); - - cairo_surface_t *surface = cairo_image_surface_create_from_png(file); - cairo_status_t status = cairo_surface_status(surface); - - if (status) { - g_warning("error while loading png file: %s - cairo status: %s", file, - cairo_status_to_string(status)); - return false; - } - - int width = cairo_image_surface_get_width(surface); - int height = cairo_image_surface_get_height(surface); - - struct swappy_box *geometry = g_new(struct swappy_box, 1); - - geometry->x = 0; - geometry->y = 0; - geometry->width = (int32_t)width; - geometry->height = (int32_t)height; - - g_info("size of image: %dx%d", width, height); - - state->geometry = geometry; - - cairo_pattern_t *output_pattern = cairo_pattern_create_for_surface(surface); - state->patterns = g_list_append(state->patterns, output_pattern); - state->original_image_surface = surface; - - return true; -} - -static void scale_pattern(gpointer data, gpointer user_data) { - struct swappy_state *state = (struct swappy_state *)user_data; - cairo_pattern_t *pattern = (cairo_pattern_t *)data; - int image_width, image_height; - int rendered_width, rendered_height; - - image_width = state->geometry->width; - image_height = state->geometry->height; - - rendered_width = state->drawing_area_rect->width; - rendered_height = state->drawing_area_rect->height; - - cairo_surface_t *scaled = cairo_surface_create_similar( - state->rendered_surface, CAIRO_CONTENT_COLOR_ALPHA, rendered_width, - rendered_height); - cairo_t *cr = cairo_create(scaled); - - double sx = (double)rendered_width / image_width; - double sy = (double)rendered_height / image_height; - - cairo_matrix_t matrix; - cairo_matrix_init_scale(&matrix, 1.0 / sx, 1.0 / sy); - cairo_pattern_set_matrix(pattern, &matrix); - cairo_set_source_surface(cr, state->original_image_surface, 0, 0); - cairo_set_source(cr, pattern); - cairo_paint(cr); - - cairo_destroy(cr); - - if (state->scaled_image_surface) { - cairo_surface_destroy(state->scaled_image_surface); - } - - state->scaled_image_surface = scaled; -} - -void buffer_resize_patterns(struct swappy_state *state) { - g_list_foreach(state->patterns, scale_pattern, state); -} - -static void free_pattern(gpointer data) { - cairo_pattern_t *pattern = data; - cairo_pattern_destroy(pattern); -} - -void buffer_free_all(struct swappy_state *state) { - if (state->patterns) { - g_list_free_full(state->patterns, free_pattern); - state->patterns = NULL; - } -} \ No newline at end of file diff --git a/src/pixbuf.c b/src/pixbuf.c index 41173a1..f06e172 100644 --- a/src/pixbuf.c +++ b/src/pixbuf.c @@ -63,6 +63,21 @@ void pixbuf_save_to_stdout(GdkPixbuf *pixbuf) { g_object_unref(out); } +GdkPixbuf *pixbuf_init_from_file(struct swappy_state *state) { + GError *error = NULL; + char *file = + state->temp_file_str != NULL ? state->temp_file_str : state->file_str; + GdkPixbuf *image = gdk_pixbuf_new_from_file(file, &error); + + if (error != NULL) { + g_error("unable to load file: %s - reason: %s", file, error->message); + return NULL; + } + + state->original_image = image; + return image; +} + void pixbuf_save_to_file(GdkPixbuf *pixbuf, char *file) { if (g_strcmp0(file, "-") == 0) { pixbuf_save_to_stdout(pixbuf); @@ -70,3 +85,43 @@ void pixbuf_save_to_file(GdkPixbuf *pixbuf, char *file) { write_file(pixbuf, file); } } + +void pixbuf_scale_surface_from_widget(struct swappy_state *state, + GtkWidget *widget) { + GtkAllocation *alloc = g_new(GtkAllocation, 1); + GdkPixbuf *image = state->original_image; + gtk_widget_get_allocation(widget, alloc); + + gboolean has_alpha = gdk_pixbuf_get_has_alpha(image); + cairo_format_t format = has_alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24; + gint image_width = gdk_pixbuf_get_width(image); + gint image_height = gdk_pixbuf_get_height(image); + cairo_surface_t *surface = + cairo_image_surface_create(format, image_width, image_height); + + if (!surface) { + g_error("unable to create cairo surface from pixbuf"); + goto cleanup; + } else { + cairo_t *cr; + cr = cairo_create(surface); + double scale_x = (double)alloc->width / image_width; + double scale_y = (double)alloc->height / image_height; + g_info("image scaled on x,y: %.2lf,%.2lf", scale_x, scale_y); + cairo_scale(cr, scale_x, scale_y); + gdk_cairo_set_source_pixbuf(cr, image, 0, 0); + cairo_paint(cr); + cairo_destroy(cr); + } + + g_info("size of area to render: %ux%u", alloc->width, alloc->height); + + if (state->scaled_image_surface) { + cairo_surface_destroy(state->scaled_image_surface); + state->scaled_image_surface = NULL; + } + state->scaled_image_surface = surface; + +cleanup: + g_free(alloc); +}