Author: post
Date: 2011-12-29 01:51:27 +0100 (Thu, 29 Dec 2011)
New Revision: 4065

Modified:
   trunk/src/gtk-interface.c
   trunk/src/rs-preview-widget.c
Log:
Do image rendering asynchronious in a separate thread for much more responsive 
GUI.

Modified: trunk/src/gtk-interface.c
===================================================================
--- trunk/src/gtk-interface.c   2011-12-28 22:13:04 UTC (rev 4064)
+++ trunk/src/gtk-interface.c   2011-12-29 00:51:27 UTC (rev 4065)
@@ -257,7 +257,6 @@
        }
        /* Set photo in preview-widget */
        rs_preview_widget_set_photo(RS_PREVIEW_WIDGET(rs->preview), photo);
-       rs_toolbox_set_photo(RS_TOOLBOX(rs->tools), photo);
        rs->photo->proposed_crop = NULL;
        GTK_CATCHUP();
        if (rs->photo && NULL==rs->photo->crop && rs->photo->proposed_crop)

Modified: trunk/src/rs-preview-widget.c
===================================================================
--- trunk/src/rs-preview-widget.c       2011-12-28 22:13:04 UTC (rev 4064)
+++ trunk/src/rs-preview-widget.c       2011-12-29 00:51:27 UTC (rev 4065)
@@ -95,6 +95,16 @@
        SPLIT_VERTICAL,
 } VIEW_SPLIT;
 
+typedef struct {
+       GThread *thread_id;
+       RSPreviewWidget *preview;
+       GCond* render;
+       GMutex *render_mutex;
+       GdkRectangle dirty_area;
+       gboolean render_pending;
+       gboolean finish_rendering;
+} ThreadInfo;
+
 const static gint PADDING = 3;
 const static gint SPLITTER_WIDTH = 4;
 #define MAX_VIEWS 2 /* maximum 32! */
@@ -131,6 +141,7 @@
        gboolean zoom_to_fit;
        gboolean exposure_mask;
        gboolean keep_quick_enabled;
+       gboolean last_required_direct_redraw;
 
        GdkColor bgcolor; /* Background color of widget */
        VIEW_SPLIT split;
@@ -206,6 +217,7 @@
        RSColorSpace *display_color_space;
        RSColorSpace *exposure_color_space;
        guint status_num;
+       ThreadInfo *render_thread;
 };
 
 /* Define the boiler plate stuff using the predefined macro */
@@ -252,6 +264,8 @@
 static void crop_find_size_from_aspect(RS_RECT *roi, gdouble aspect, CROP_NEAR 
state);
 static CROP_NEAR crop_near(RS_RECT *roi, gint x, gint y);
 static gboolean make_cbdata(RSPreviewWidget *preview, const gint view, 
RS_PREVIEW_CALLBACK_DATA *cbdata, gint screen_x, gint screen_y, gint real_x, 
gint real_y);
+static gpointer render_thread_func(gpointer _thread_info);
+static void rs_preview_do_render(RSPreviewWidget *preview, GdkRectangle 
*dirty_area);
 
 /**
  * Class initializer
@@ -296,6 +310,14 @@
 static void
 rs_preview_widget_init(RSPreviewWidget *preview)
 {
+       static GStaticMutex render_mutex = G_STATIC_MUTEX_INIT;
+       preview->render_thread = g_new(ThreadInfo, 1);
+       preview->render_thread->preview = preview;
+       preview->render_thread->render = g_cond_new();
+       preview->render_thread->render_mutex = 
g_static_mutex_get_mutex(&render_mutex);
+       preview->render_thread->finish_rendering = FALSE;
+       g_mutex_lock(preview->render_thread->render_mutex);
+       preview->render_thread->thread_id = g_thread_create(render_thread_func, 
preview->render_thread, TRUE, NULL);
        gint i;
        GtkTable *table = GTK_TABLE(preview);
        GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(preview));
@@ -480,7 +502,7 @@
        gint i;
        gchar *name;
 
-
+       gdk_threads_enter();
        RSColorSpace *new_cs = rs_get_display_profile(GTK_WIDGET(preview));
        RSColorSpace *exp_cs = rs_color_space_new_singleton("RSSrgb");
 
@@ -503,7 +525,10 @@
                rs_navigator_set_colorspace(RS_NAVIGATOR(preview->navigator), 
new_cs);
 
        if (preview->display_color_space == new_cs && 
preview->exposure_color_space == exp_cs)
+       {
+               gdk_threads_leave();
                return;
+       }
 
        preview->display_color_space = new_cs;
        preview->exposure_color_space = exp_cs;
@@ -515,6 +540,7 @@
                DIRTY(preview->dirty[i], ALL);
                
rs_filter_param_set_object(RS_FILTER_PARAM(preview->request[i]), "colorspace", 
preview->display_color_space);
        }
+       gdk_threads_leave();
 }
 /**
  * Select zoom-to-fit of a RSPreviewWidget
@@ -696,6 +722,7 @@
                photo->thumbnail_filter = preview->navigator_filter_end;
                g_signal_connect(G_OBJECT(preview->photo), "lens-changed", 
G_CALLBACK(lens_changed), preview);
                g_signal_connect(G_OBJECT(preview->photo), "profile-changed", 
G_CALLBACK(profile_changed), preview);
+               rs_preview_widget_update(preview, TRUE);
        }
 }
 
@@ -716,6 +743,9 @@
        g_list_free(filters);
 
        for(view=0;view<MAX_VIEWS;view++) 
+               g_signal_handlers_block_by_func(preview->filter_end[view], 
G_CALLBACK(filter_changed), preview);
+
+       for(view=0;view<MAX_VIEWS;view++) 
        {
                rs_filter_request_set_quick(preview->request[view], TRUE);
                filters = g_list_append(NULL, preview->filter_end[view]);
@@ -723,7 +753,13 @@
                g_list_free(filters);
        }
 
+       /* Set toolbox while display updates are locked */
+       rs_toolbox_set_photo(RS_TOOLBOX(preview->toolbox), preview->photo);
 
+       for(view=0;view<MAX_VIEWS;view++) 
+               g_signal_handlers_unblock_by_func(preview->filter_end[view], 
G_CALLBACK(filter_changed), preview);
+
+
        g_object_set(preview->navigator_filter_scale,
                "bounding-box", TRUE,
                "width", NAVIGATOR_WIDTH*2,
@@ -1362,7 +1398,7 @@
 get_canvas_placement(RSPreviewWidget *preview, const guint view, GdkRectangle 
*placement)
 {
        gint xoffset = 0, yoffset = 0;
-       gint width, height;
+       gint width = 0, height = 0;
 
        g_assert(VIEW_IS_VALID(view));
        g_assert(placement);
@@ -1507,385 +1543,7 @@
        return cr;
 }
 
-static void
-redraw(RSPreviewWidget *preview, GdkRectangle *dirty_area)
-{
-       GdkRectangle area;
-       GdkRectangle placement;
-       GtkWidget *widget = GTK_WIDGET(preview->canvas);
-       GdkWindow *window = widget->window;
-       GdkDrawable *drawable = GDK_DRAWABLE(window);
-       GdkGC *gc = gdk_gc_new(drawable);
-       gint i;
-       cairo_t *cr = NULL;
-       const static gdouble dashes[] = { 4.0, 4.0, };
-       gint width, height;
 
-#define CAIRO_LINE(cr, x1, y1, x2, y2) do { \
-       cairo_move_to((cr), (x1), (y1)); \
-       cairo_line_to((cr), (x2), (y2)); } while (0);
-
-       gdk_window_begin_paint_rect(window, dirty_area);
-
-       for(i=0;i<preview->views;i++)
-       {
-               rs_filter_get_size_simple(preview->filter_end[i], 
preview->request[i], &width, &height);
-
-               if (preview->zoom_to_fit)
-                       get_placement(preview, i, &placement);
-               else
-               {
-                       if (width > 
GTK_WIDGET(preview->canvas)->allocation.width)
-                               placement.x = 
-gtk_adjustment_get_value(preview->hadjustment);
-                       else
-                               placement.x = 
((GTK_WIDGET(preview->canvas)->allocation.width)-width)/2;
-
-                       if (height > 
GTK_WIDGET(preview->canvas)->allocation.height)
-                               placement.y = 
-gtk_adjustment_get_value(preview->vadjustment);
-                       else
-                               placement.y = 
((GTK_WIDGET(preview->canvas)->allocation.height)-height)/2;
-
-                       placement.width = width;
-                       placement.height = height;
-               }
-
-               /* Render the photo itself */
-               if (gdk_rectangle_intersect(dirty_area, &placement, &area))
-               {
-                       GdkRectangle roi = area;
-                       roi.x -= placement.x;
-                       roi.y -= placement.y;
-
-                       if (!preview->last_roi[i])
-                               preview->last_roi[i] = g_new(GdkRectangle, 1);
-                       *preview->last_roi[i] = roi;
-
-                       if (preview->zoom_to_fit)
-                               rs_filter_request_set_roi(preview->request[i], 
NULL);
-                       else
-                               rs_filter_request_set_roi(preview->request[i], 
&roi);
-
-                       /* Clone, now so it cannot change while filters are 
being called */
-                       RSFilterRequest *new_request = 
rs_filter_request_clone(preview->request[i]);  
-
-                       RSFilterResponse *response = 
rs_filter_get_image8(preview->filter_end[i], new_request);
-                       GdkPixbuf *buffer = 
rs_filter_response_get_image8(response);
-
-                       if (buffer)
-                       {
-                               if (area.x-placement.x >= 0 && 
area.x-placement.x + area.width <= gdk_pixbuf_get_width(buffer)
-                                       && area.y-placement.y >= 0 && 
area.y-placement.y + area.height <= gdk_pixbuf_get_height(buffer))
-                                       gdk_draw_pixbuf(drawable, gc,
-                                               buffer,
-                                               area.x-placement.x,
-                                               area.y-placement.y,
-                                               area.x, area.y,
-                                               area.width, area.height,
-                                               GDK_RGB_DITHER_NONE, 0, 0);
-
-                               g_object_unref(buffer);
-                       }
-
-                       if(preview->views > 1 && 
rs_filter_request_get_quick(new_request) && !preview->keep_quick_enabled)
-                       {
-                               
rs_filter_request_set_quick(preview->request[i], FALSE);
-                               gdk_window_invalidate_rect(window, &area, 
FALSE);
-                       }
-                       else if(rs_filter_request_get_quick(new_request) && 
!preview->keep_quick_enabled)
-                       {
-                               /* Catch up, so we can get new signals */
-                               gdk_window_end_paint(window);
-                               g_object_unref(gc);
-                               g_object_unref(new_request);
-                               g_object_unref(response);
-                               if (!(preview->photo && preview->photo->signal 
&& *preview->photo->signal == MAIN_SIGNAL_CANCEL_LOAD))
-                               {
-                                       
rs_filter_request_set_quick(preview->request[i], FALSE);
-                                       gdk_window_invalidate_rect(window, 
&area, FALSE);
-                               }
-                               return;
-                       }
-                       else if (preview->photo && NULL==preview->photo->crop 
&& NULL==preview->photo->proposed_crop)
-                       {
-                               preview->photo->proposed_crop = 
g_new(RS_RECT,1);
-                               if (ABS(preview->photo->angle) < 0.001 &&
-                                       
rs_filter_param_get_integer(RS_FILTER_PARAM(response), "proposed-crop-x1", 
&preview->photo->proposed_crop->x1) &&
-                                               
rs_filter_param_get_integer(RS_FILTER_PARAM(response), "proposed-crop-y1", 
&preview->photo->proposed_crop->y1) &&
-                                                       
rs_filter_param_get_integer(RS_FILTER_PARAM(response), "proposed-crop-x2", 
&preview->photo->proposed_crop->x2) &&
-                                                               
rs_filter_param_get_integer(RS_FILTER_PARAM(response), "proposed-crop-y2", 
&preview->photo->proposed_crop->y2))
-                               {
-                                       if (preview->photo->orientation)
-                                               
rs_photo_rotate_rect_inverse(preview->photo, preview->photo->proposed_crop);
-                               }
-                               else 
-                               {
-                                       g_free(preview->photo->proposed_crop);
-                                       preview->photo->proposed_crop = NULL;
-                               }
-                       }
-                       g_object_unref(new_request);
-                       g_object_unref(response);
-               }
-
-               if (preview->state & DRAW_ROI)
-               {
-                       gfloat scale;
-                       if (!cr)
-                               cr = redraw_cairo_init(drawable, dirty_area);
-                       gchar *text;
-                       cairo_text_extents_t te;
-
-                       gint x1,y1,x2,y2;
-                       /* Translate to screen coordinates */
-                       g_object_get(preview->filter_resample[i], "scale", 
&scale, NULL);
-                       x1 = preview->roi.x1 * scale;
-                       y1 = preview->roi.y1 * scale;
-                       x2 = preview->roi.x2 * scale;
-                       y2 = preview->roi.y2 * scale;
-
-                       text = g_strdup_printf("%d x %d", 
preview->roi.x2-preview->roi.x1, preview->roi.y2-preview->roi.y1);
-
-                       /* creates a rectangle that matches the photo */
-                       gdk_cairo_rectangle(cr, &placement);
-
-                       /* Translate to photo coordinates */
-                       cairo_translate(cr, placement.x, placement.y);
-
-                       /* creates a rectangle that matches ROI */
-                       cairo_rectangle(cr, x1, y1, x2-x1, y2-y1);
-                       /* create fill rule that only fills between the two 
rectangles */
-                       cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
-                       cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.5);
-                       /* fill acording to rule */
-                       cairo_fill_preserve (cr);
-                       /* center rectangle */
-                       cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
-                       cairo_stroke (cr);
-
-                       cairo_set_line_width(cr, 2.0);
-
-                       cairo_set_dash(cr, dashes, 0, 0.0);
-                       cairo_set_source_rgba(cr, 0.8, 0.8, 0.8, 0.5);
-                       cairo_rectangle(cr, x1, y1, x2-x1, y2-y1);
-                       cairo_stroke(cr);
-
-                       cairo_set_line_width(cr, 1.0);
-                       cairo_set_dash(cr, dashes, 2, 0.0);
-                       cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.6);
-                       /* Print size below rectangle */
-                       cairo_select_font_face(cr, "Arial", 
CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
-                       cairo_set_font_size(cr, 12.0);
-               cairo_text_extents (cr, text, &te);
-                       if (y2 > (placement.height-18))
-                               cairo_move_to(cr, (x2+x1)/2.0 - te.width/2.0, 
y2-5.0);
-                       else
-                               cairo_move_to(cr, (x2+x1)/2.0 - te.width/2.0, 
y2+14.0);
-                       cairo_show_text (cr, text);
-
-                       switch(preview->roi_grid)
-                       {
-                               case ROI_GRID_NONE:
-                                       break;
-                               case ROI_GRID_GOLDEN:
-                               {
-                                       gdouble goldenratio = ((1+sqrt(5))/2);
-                                       gint t, golden;
-
-                                       /* vertical */
-                                       golden = ((x2-x1)/goldenratio);
-
-                                       t = (x1+golden);
-                                       CAIRO_LINE(cr, t, y1, t, y2);
-                                       t = (x2-golden);
-                                       CAIRO_LINE(cr, t, y1, t, y2);
-
-                                       /* horizontal */
-                                       golden = ((y2-y1)/goldenratio);
-
-                                       t = (y1+golden);
-                                       CAIRO_LINE(cr, x1, t, x2, t);
-                                       t = (y2-golden);
-                                       CAIRO_LINE(cr, x1, t, x2, t);
-                                       break;
-                               }
-                               case ROI_GRID_THIRDS:
-                               {
-                                       gint t;
-
-                                       /* vertical */
-                                       t = ((x2-x1+1)/3*1+x1);
-                                       CAIRO_LINE(cr, t, y1, t, y2);
-                                       t = ((x2-x1+1)/3*2+x1);
-                                       CAIRO_LINE(cr, t, y1, t, y2);
-
-                                       /* horizontal */
-                                       t = ((y2-y1+1)/3*1+y1);
-                                       CAIRO_LINE(cr, x1, t, x2, t);
-                                       t = ((y2-y1+1)/3*2+y1);
-                                       CAIRO_LINE(cr, x1, t, x2, t);
-                                       break;
-                               }
-
-                               case ROI_GRID_GOLDEN_TRIANGLES1:
-                               {
-                                       gdouble goldenratio = ((1+sqrt(5))/2);
-                                       gint t, golden;
-
-                                       golden = ((x2-x1)/goldenratio);
-
-                                       CAIRO_LINE(cr, x1, y1, x2, y2);
-
-                                       t = (x2-golden);
-                                       CAIRO_LINE(cr, x1, y2, t, y1);
-
-                                       t = (x1+golden);
-                                       CAIRO_LINE(cr, x2, y1, t, y2);
-                                       break;
-                               }
-                               case ROI_GRID_GOLDEN_TRIANGLES2:
-                               {
-                                       gdouble goldenratio = ((1+sqrt(5))/2);
-                                       gint t, golden;
-
-                                       golden = ((x2-x1)/goldenratio);
-
-                                       CAIRO_LINE(cr, x2, y1, x1, y2);
-
-                                       t = (x2-golden);
-                                       CAIRO_LINE(cr, x1, y1, t, y2);
-
-                                       t = (x1+golden);
-                                       CAIRO_LINE(cr, x2, y2, t, y1);
-                                       break;
-                               }
-
-                               case ROI_GRID_HARMONIOUS_TRIANGLES1:
-                               {
-                                       gdouble goldenratio = ((1+sqrt(5))/2);
-                                       gint t, golden;
-
-                                       golden = ((x2-x1)/goldenratio);
-
-                                       CAIRO_LINE(cr, x1, y1, x2, y2);
-
-                                       t = (x1+golden);
-                                       CAIRO_LINE(cr, x1, y2, t, y1);
-
-                                       t = (x2-golden);
-                                       CAIRO_LINE(cr, x2, y1, t, y2);
-                                       break;
-                               }
-                               case ROI_GRID_HARMONIOUS_TRIANGLES2:
-                               {
-                                       gdouble goldenratio = ((1+sqrt(5))/2);
-                                       gint t, golden;
-
-                                       golden = ((x2-x1)/goldenratio);
-
-                                       CAIRO_LINE(cr, x1, y2, x2, y1);
-
-                                       t = (x1+golden);
-                                       CAIRO_LINE(cr, x1, y1, t, y2);
-
-                                       t = (x2-golden);
-                                       CAIRO_LINE(cr, x2, y2, t, y1);
-                                       break;
-                               }
-                       }
-                       cairo_stroke(cr);
-
-                       /* Translate "back" */
-                       cairo_translate(cr, -placement.x, -placement.y);
-                       gtk_label_set_text(GTK_LABEL(preview->crop_size_label), 
text);
-                       g_free(text);
-               }
-
-               /* Draw snapshot-identifier */
-               if (preview->views > 1)
-               {
-                       if (!cr)
-                               cr = redraw_cairo_init(drawable, dirty_area);
-                       GdkRectangle canvas;
-                       const gchar *txt;
-                       switch (preview->snapshot[i])
-                       {
-                               case 0:
-                                       txt = "A";
-                                       break;
-                               case 1:
-                                       txt = "B";
-                                       break;
-                               case 2:
-                                       txt = "C";
-                                       break;
-                               default:
-                                       txt = "-";
-                                       break;
-                       }
-                       get_canvas_placement(preview, i, &canvas);
-
-                       cairo_set_dash(cr, dashes, 0, 0.0);
-                       cairo_select_font_face(cr, "Arial", 
CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
-                       cairo_set_font_size(cr, 20.0);
-
-                       cairo_set_source_rgba(cr, 0.2, 0.2, 0.2, 0.7);
-                       cairo_move_to(cr, canvas.x+3.0, canvas.y+21.0);
-                       cairo_text_path(cr, txt);
-                       cairo_fill(cr);
-
-                       cairo_set_source_rgba(cr, 0.7, 0.7, 0.7, 1.0);
-                       cairo_move_to(cr, canvas.x+3.0, canvas.y+21.0);
-                       cairo_text_path(cr, txt);
-                       cairo_stroke(cr);
-               }
-       }
-
-       /* Draw straighten-line */
-       if (preview->state & STRAIGHTEN_MOVE)
-       {
-               if (!cr)
-                       cr = redraw_cairo_init(drawable, dirty_area);
-               cairo_set_line_width(cr, 1.0);
-
-               cairo_set_dash(cr, dashes, 2, 0.0);
-               cairo_set_source_rgba(cr, 0.8, 0.8, 0.8, 1.0);
-               cairo_move_to(cr, preview->straighten_start.x, 
preview->straighten_start.y);
-               cairo_line_to(cr, preview->straighten_end.x, 
preview->straighten_end.y);
-               cairo_stroke(cr);
-
-               cairo_set_dash(cr, dashes, 2, 10.0);
-               cairo_set_source_rgba(cr, 0.2, 0.2, 0.2, 1.0);
-               cairo_move_to(cr, preview->straighten_start.x, 
preview->straighten_start.y);
-               cairo_line_to(cr, preview->straighten_end.x, 
preview->straighten_end.y);
-               cairo_stroke(cr);
-       }
-
-       /* Draw splitters */
-       if (preview->views>0)
-       {
-               for(i=1;i<preview->views;i++)
-               {
-                       if (preview->split == SPLIT_VERTICAL)
-                               gtk_paint_vline(GTK_WIDGET(preview)->style, 
window, GTK_STATE_NORMAL, NULL, widget, NULL,
-                                       0,
-                                       
GTK_WIDGET(preview->canvas)->allocation.height,
-                                       i * 
GTK_WIDGET(preview)->allocation.width/preview->views - SPLITTER_WIDTH/2);
-                       else if (preview->split == SPLIT_HORIZONTAL)
-                               gtk_paint_hline(GTK_WIDGET(preview)->style, 
window, GTK_STATE_NORMAL, NULL, widget, NULL,
-                                       0,
-                                       
GTK_WIDGET(preview->canvas)->allocation.width,
-                                       i * 
GTK_WIDGET(preview)->allocation.height/preview->views - SPLITTER_WIDTH/2);
-               }
-       }
-
-       g_object_unref(gc);
-       if (cr)
-               cairo_destroy(cr);
-
-       gdk_window_end_paint(window);
-#undef CAIRO_LINE
-}
-
 static void
 realize(GtkWidget *widget, gpointer data)
 {
@@ -2841,3 +2499,466 @@
        g_object_unref(image);
        return TRUE;
 }
+
+static void
+rs_preview_do_render(RSPreviewWidget *preview, GdkRectangle *dirty_area)
+{
+       GdkRectangle area;
+       GdkRectangle placement;
+       GtkWidget *widget = GTK_WIDGET(preview->canvas);
+       GdkWindow *window = widget->window;
+       GdkDrawable *drawable = GDK_DRAWABLE(window);
+       GdkGC *gc = gdk_gc_new(drawable);
+       gint i;
+       cairo_t *cr = NULL;
+       const static gdouble dashes[] = { 4.0, 4.0, };
+       gint width, height;
+
+#define CAIRO_LINE(cr, x1, y1, x2, y2) do { \
+       cairo_move_to((cr), (x1), (y1)); \
+       cairo_line_to((cr), (x2), (y2)); } while (0);
+
+       gdk_window_begin_paint_rect(window, dirty_area);
+
+       for(i=0;i<preview->views;i++)
+       {
+               rs_filter_get_size_simple(preview->filter_end[i], 
preview->request[i], &width, &height);
+
+               if (preview->zoom_to_fit)
+                       get_placement(preview, i, &placement);
+               else
+               {
+                       if (width > 
GTK_WIDGET(preview->canvas)->allocation.width)
+                               placement.x = 
-gtk_adjustment_get_value(preview->hadjustment);
+                       else
+                               placement.x = 
((GTK_WIDGET(preview->canvas)->allocation.width)-width)/2;
+
+                       if (height > 
GTK_WIDGET(preview->canvas)->allocation.height)
+                               placement.y = 
-gtk_adjustment_get_value(preview->vadjustment);
+                       else
+                               placement.y = 
((GTK_WIDGET(preview->canvas)->allocation.height)-height)/2;
+
+                       placement.width = width;
+                       placement.height = height;
+               }
+
+               /* Render the photo itself */
+               if (gdk_rectangle_intersect(dirty_area, &placement, &area))
+               {
+                       GdkRectangle roi = area;
+                       roi.x -= placement.x;
+                       roi.y -= placement.y;
+
+                       if (!preview->last_roi[i])
+                               preview->last_roi[i] = g_new(GdkRectangle, 1);
+                       *preview->last_roi[i] = roi;
+
+                       if (preview->zoom_to_fit)
+                               rs_filter_request_set_roi(preview->request[i], 
NULL);
+                       else
+                               rs_filter_request_set_roi(preview->request[i], 
&roi);
+
+                       /* Clone, now so it cannot change while filters are 
being called */
+                       RSFilterRequest *new_request = 
rs_filter_request_clone(preview->request[i]);  
+
+                       RSFilterResponse *response = 
rs_filter_get_image8(preview->filter_end[i], new_request);
+                       GdkPixbuf *buffer = 
rs_filter_response_get_image8(response);
+
+                       if (buffer)
+                       {
+                               if (area.x-placement.x >= 0 && 
area.x-placement.x + area.width <= gdk_pixbuf_get_width(buffer)
+                                       && area.y-placement.y >= 0 && 
area.y-placement.y + area.height <= gdk_pixbuf_get_height(buffer))
+                                       gdk_draw_pixbuf(drawable, gc,
+                                               buffer,
+                                               area.x-placement.x,
+                                               area.y-placement.y,
+                                               area.x, area.y,
+                                               area.width, area.height,
+                                               GDK_RGB_DITHER_NONE, 0, 0);
+
+                               g_object_unref(buffer);
+                       }
+
+                       if(preview->views > 1 && 
rs_filter_request_get_quick(new_request) && !preview->keep_quick_enabled)
+                       {
+                               
rs_filter_request_set_quick(preview->request[i], FALSE);
+                               gdk_window_invalidate_rect(window, &area, 
FALSE);
+                       }
+                       else if(rs_filter_request_get_quick(new_request) && 
!preview->keep_quick_enabled)
+                       {
+                               /* Catch up, so we can get new signals */
+                               gdk_window_end_paint(window);
+                               g_object_unref(gc);
+                               g_object_unref(new_request);
+                               g_object_unref(response);
+                               if (!(preview->photo && preview->photo->signal 
&& *preview->photo->signal == MAIN_SIGNAL_CANCEL_LOAD))
+                               {
+                                       
rs_filter_request_set_quick(preview->request[i], FALSE);
+                                       gdk_window_invalidate_rect(window, 
&area, FALSE);
+                               }
+                               return;
+                       }
+                       else if (preview->photo && NULL==preview->photo->crop 
&& NULL==preview->photo->proposed_crop)
+                       {
+                               preview->photo->proposed_crop = 
g_new(RS_RECT,1);
+                               if (ABS(preview->photo->angle) < 0.001 &&
+                                       
rs_filter_param_get_integer(RS_FILTER_PARAM(response), "proposed-crop-x1", 
&preview->photo->proposed_crop->x1) &&
+                                               
rs_filter_param_get_integer(RS_FILTER_PARAM(response), "proposed-crop-y1", 
&preview->photo->proposed_crop->y1) &&
+                                                       
rs_filter_param_get_integer(RS_FILTER_PARAM(response), "proposed-crop-x2", 
&preview->photo->proposed_crop->x2) &&
+                                                               
rs_filter_param_get_integer(RS_FILTER_PARAM(response), "proposed-crop-y2", 
&preview->photo->proposed_crop->y2))
+                               {
+                                       if (preview->photo->orientation)
+                                               
rs_photo_rotate_rect_inverse(preview->photo, preview->photo->proposed_crop);
+                               }
+                               else 
+                               {
+                                       g_free(preview->photo->proposed_crop);
+                                       preview->photo->proposed_crop = NULL;
+                               }
+                       }
+                       g_object_unref(new_request);
+                       g_object_unref(response);
+               }
+
+               if (preview->state & DRAW_ROI)
+               {
+                       gfloat scale;
+                       if (!cr)
+                               cr = redraw_cairo_init(drawable, dirty_area);
+                       gchar *text;
+                       cairo_text_extents_t te;
+
+                       gint x1,y1,x2,y2;
+                       /* Translate to screen coordinates */
+                       g_object_get(preview->filter_resample[i], "scale", 
&scale, NULL);
+                       x1 = preview->roi.x1 * scale;
+                       y1 = preview->roi.y1 * scale;
+                       x2 = preview->roi.x2 * scale;
+                       y2 = preview->roi.y2 * scale;
+
+                       text = g_strdup_printf("%d x %d", 
preview->roi.x2-preview->roi.x1, preview->roi.y2-preview->roi.y1);
+
+                       /* creates a rectangle that matches the photo */
+                       gdk_cairo_rectangle(cr, &placement);
+
+                       /* Translate to photo coordinates */
+                       cairo_translate(cr, placement.x, placement.y);
+
+                       /* creates a rectangle that matches ROI */
+                       cairo_rectangle(cr, x1, y1, x2-x1, y2-y1);
+                       /* create fill rule that only fills between the two 
rectangles */
+                       cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+                       cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.5);
+                       /* fill acording to rule */
+                       cairo_fill_preserve (cr);
+                       /* center rectangle */
+                       cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
+                       cairo_stroke (cr);
+
+                       cairo_set_line_width(cr, 2.0);
+
+                       cairo_set_dash(cr, dashes, 0, 0.0);
+                       cairo_set_source_rgba(cr, 0.8, 0.8, 0.8, 0.5);
+                       cairo_rectangle(cr, x1, y1, x2-x1, y2-y1);
+                       cairo_stroke(cr);
+
+                       cairo_set_line_width(cr, 1.0);
+                       cairo_set_dash(cr, dashes, 2, 0.0);
+                       cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.6);
+                       /* Print size below rectangle */
+                       cairo_select_font_face(cr, "Arial", 
CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+                       cairo_set_font_size(cr, 12.0);
+                               cairo_text_extents (cr, text, &te);
+                       if (y2 > (placement.height-18))
+                               cairo_move_to(cr, (x2+x1)/2.0 - te.width/2.0, 
y2-5.0);
+                       else
+                               cairo_move_to(cr, (x2+x1)/2.0 - te.width/2.0, 
y2+14.0);
+                       cairo_show_text (cr, text);
+
+                       switch(preview->roi_grid)
+                       {
+                               case ROI_GRID_NONE:
+                                       break;
+                               case ROI_GRID_GOLDEN:
+                               {
+                                       gdouble goldenratio = ((1+sqrt(5))/2);
+                                       gint t, golden;
+
+                                       /* vertical */
+                                       golden = ((x2-x1)/goldenratio);
+
+                                       t = (x1+golden);
+                                       CAIRO_LINE(cr, t, y1, t, y2);
+                                       t = (x2-golden);
+                                       CAIRO_LINE(cr, t, y1, t, y2);
+
+                                       /* horizontal */
+                                       golden = ((y2-y1)/goldenratio);
+
+                                       t = (y1+golden);
+                                       CAIRO_LINE(cr, x1, t, x2, t);
+                                       t = (y2-golden);
+                                       CAIRO_LINE(cr, x1, t, x2, t);
+                                       break;
+                               }
+                               case ROI_GRID_THIRDS:
+                               {
+                                       gint t;
+
+                                       /* vertical */
+                                       t = ((x2-x1+1)/3*1+x1);
+                                       CAIRO_LINE(cr, t, y1, t, y2);
+                                       t = ((x2-x1+1)/3*2+x1);
+                                       CAIRO_LINE(cr, t, y1, t, y2);
+
+                                       /* horizontal */
+                                       t = ((y2-y1+1)/3*1+y1);
+                                       CAIRO_LINE(cr, x1, t, x2, t);
+                                       t = ((y2-y1+1)/3*2+y1);
+                                       CAIRO_LINE(cr, x1, t, x2, t);
+                                       break;
+                               }
+
+                               case ROI_GRID_GOLDEN_TRIANGLES1:
+                               {
+                                       gdouble goldenratio = ((1+sqrt(5))/2);
+                                       gint t, golden;
+
+                                       golden = ((x2-x1)/goldenratio);
+
+                                       CAIRO_LINE(cr, x1, y1, x2, y2);
+
+                                       t = (x2-golden);
+                                       CAIRO_LINE(cr, x1, y2, t, y1);
+
+                                       t = (x1+golden);
+                                       CAIRO_LINE(cr, x2, y1, t, y2);
+                                       break;
+                               }
+                               case ROI_GRID_GOLDEN_TRIANGLES2:
+                               {
+                                       gdouble goldenratio = ((1+sqrt(5))/2);
+                                       gint t, golden;
+
+                                       golden = ((x2-x1)/goldenratio);
+
+                                       CAIRO_LINE(cr, x2, y1, x1, y2);
+
+                                       t = (x2-golden);
+                                       CAIRO_LINE(cr, x1, y1, t, y2);
+
+                                       t = (x1+golden);
+                                       CAIRO_LINE(cr, x2, y2, t, y1);
+                                       break;
+                               }
+
+                               case ROI_GRID_HARMONIOUS_TRIANGLES1:
+                               {
+                                       gdouble goldenratio = ((1+sqrt(5))/2);
+                                       gint t, golden;
+
+                                       golden = ((x2-x1)/goldenratio);
+
+                                       CAIRO_LINE(cr, x1, y1, x2, y2);
+
+                                       t = (x1+golden);
+                                       CAIRO_LINE(cr, x1, y2, t, y1);
+
+                                       t = (x2-golden);
+                                       CAIRO_LINE(cr, x2, y1, t, y2);
+                                       break;
+                               }
+                               case ROI_GRID_HARMONIOUS_TRIANGLES2:
+                               {
+                                       gdouble goldenratio = ((1+sqrt(5))/2);
+                                       gint t, golden;
+
+                                       golden = ((x2-x1)/goldenratio);
+
+                                       CAIRO_LINE(cr, x1, y2, x2, y1);
+
+                                       t = (x1+golden);
+                                       CAIRO_LINE(cr, x1, y1, t, y2);
+
+                                       t = (x2-golden);
+                                       CAIRO_LINE(cr, x2, y2, t, y1);
+                                       break;
+                               }
+                       }
+                       cairo_stroke(cr);
+
+                       /* Translate "back" */
+                       cairo_translate(cr, -placement.x, -placement.y);
+                       gtk_label_set_text(GTK_LABEL(preview->crop_size_label), 
text);
+                       g_free(text);
+               }
+
+               /* Draw snapshot-identifier */
+               if (preview->views > 1)
+               {
+                       if (!cr)
+                               cr = redraw_cairo_init(drawable, dirty_area);
+                       GdkRectangle canvas;
+                       const gchar *txt;
+                       switch (preview->snapshot[i])
+                       {
+                               case 0:
+                                       txt = "A";
+                                       break;
+                               case 1:
+                                       txt = "B";
+                                       break;
+                               case 2:
+                                       txt = "C";
+                                       break;
+                               default:
+                                       txt = "-";
+                                       break;
+                       }
+                       get_canvas_placement(preview, i, &canvas);
+
+                       cairo_set_dash(cr, dashes, 0, 0.0);
+                       cairo_select_font_face(cr, "Arial", 
CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+                       cairo_set_font_size(cr, 20.0);
+
+                       cairo_set_source_rgba(cr, 0.2, 0.2, 0.2, 0.7);
+                       cairo_move_to(cr, canvas.x+3.0, canvas.y+21.0);
+                       cairo_text_path(cr, txt);
+                       cairo_fill(cr);
+
+                       cairo_set_source_rgba(cr, 0.7, 0.7, 0.7, 1.0);
+                       cairo_move_to(cr, canvas.x+3.0, canvas.y+21.0);
+                       cairo_text_path(cr, txt);
+                       cairo_stroke(cr);
+               }
+       }
+
+       /* Draw straighten-line */
+       if (preview->state & STRAIGHTEN_MOVE)
+       {
+               if (!cr)
+                       cr = redraw_cairo_init(drawable, dirty_area);
+               cairo_set_line_width(cr, 1.0);
+
+               cairo_set_dash(cr, dashes, 2, 0.0);
+               cairo_set_source_rgba(cr, 0.8, 0.8, 0.8, 1.0);
+               cairo_move_to(cr, preview->straighten_start.x, 
preview->straighten_start.y);
+               cairo_line_to(cr, preview->straighten_end.x, 
preview->straighten_end.y);
+               cairo_stroke(cr);
+
+               cairo_set_dash(cr, dashes, 2, 10.0);
+               cairo_set_source_rgba(cr, 0.2, 0.2, 0.2, 1.0);
+               cairo_move_to(cr, preview->straighten_start.x, 
preview->straighten_start.y);
+               cairo_line_to(cr, preview->straighten_end.x, 
preview->straighten_end.y);
+               cairo_stroke(cr);
+       }
+
+       /* Draw splitters */
+       if (preview->views>0)
+       {
+               for(i=1;i<preview->views;i++)
+               {
+                       if (preview->split == SPLIT_VERTICAL)
+                               gtk_paint_vline(GTK_WIDGET(preview)->style, 
window, GTK_STATE_NORMAL, NULL, widget, NULL,
+                                       0,
+                                       
GTK_WIDGET(preview->canvas)->allocation.height,
+                                       i * 
GTK_WIDGET(preview)->allocation.width/preview->views - SPLITTER_WIDTH/2);
+                       else if (preview->split == SPLIT_HORIZONTAL)
+                               gtk_paint_hline(GTK_WIDGET(preview)->style, 
window, GTK_STATE_NORMAL, NULL, widget, NULL,
+                                       0,
+                                       
GTK_WIDGET(preview->canvas)->allocation.width,
+                                       i * 
GTK_WIDGET(preview)->allocation.height/preview->views - SPLITTER_WIDTH/2);
+               }
+       }
+
+       g_object_unref(gc);
+       if (cr)
+               cairo_destroy(cr);
+       gdk_window_end_paint(window);
+}
+
+static void
+redraw(RSPreviewWidget *preview, GdkRectangle *dirty_area)
+{
+       if (!preview->photo)
+               return;
+
+       /* Cases where we need immediate re-draw */
+       gboolean direct_redraw = 
(rs_filter_request_get_quick(preview->request[0])) || 
+                       (preview->state & DRAW_ROI) ||
+                       (preview->state & STRAIGHTEN_MOVE) ||
+                       (preview->views > 1);
+
+       /* The first re-draw cannot be asynchronious, since it will flicker */
+       if (preview->last_required_direct_redraw && !direct_redraw)
+       {
+               preview->last_required_direct_redraw = FALSE;
+               direct_redraw = TRUE;
+       }
+       else
+       {
+               preview->last_required_direct_redraw = direct_redraw;
+       }
+
+       /* Should this thread handle rendering itself */
+       if (direct_redraw)
+       {
+               /* We need to make sure that the render thread isn't running or 
waiting for futher events */
+               preview->render_thread->finish_rendering = TRUE;
+               gdk_threads_leave();
+               g_mutex_lock(preview->render_thread->render_mutex);
+               preview->render_thread->dirty_area.width = 
preview->render_thread->dirty_area.height = 0;
+               while (preview->render_thread->render_pending) 
+               {
+                       g_cond_signal(preview->render_thread->render);
+                       g_mutex_unlock(preview->render_thread->render_mutex);
+                       g_usleep(1000);
+                       g_mutex_lock(preview->render_thread->render_mutex);
+               }
+               gdk_threads_enter();
+               rs_preview_do_render(preview, dirty_area);
+               preview->render_thread->finish_rendering = FALSE;
+               g_mutex_unlock(preview->render_thread->render_mutex);
+               return;
+       }
+       /* Send as asynchronious event to render thread */
+       gdk_threads_leave();
+       g_mutex_lock(preview->render_thread->render_mutex);
+       gdk_threads_enter();
+       preview->render_thread->dirty_area = *dirty_area;
+       g_cond_signal(preview->render_thread->render);
+       g_mutex_unlock(preview->render_thread->render_mutex);
+}
+
+
+static gpointer
+render_thread_func(gpointer _thread_info)
+{
+       ThreadInfo* t = _thread_info;
+       GTimeVal render_timeout;
+       GdkRectangle dirty_area_accum;
+       while (1)
+       {
+               t->render_pending = FALSE;
+               g_cond_wait(t->render, t->render_mutex);
+               t->render_pending = TRUE;
+               dirty_area_accum = t->dirty_area;
+               /* Let's see if we should get another update, wait until that 
stops happening */
+               /* If we receive a finish_rendering, also stop waiting for 
further events */
+               do {
+                       g_get_current_time(&render_timeout);
+                       /* Add 50ms to current time */
+                       g_time_val_add(&render_timeout, 50 * 1000); 
+                       gdk_rectangle_union(&dirty_area_accum, &t->dirty_area, 
&dirty_area_accum);
+               } while (!t->finish_rendering && TRUE == 
g_cond_timed_wait(t->render, t->render_mutex, &render_timeout) && 
!t->finish_rendering);
+
+               /* Do the render */
+               gdk_threads_enter();
+               rs_preview_do_render(t->preview, &dirty_area_accum);
+               GTK_CATCHUP();
+               gdk_threads_leave();
+#undef CAIRO_LINE
+               
+       }
+       return NULL;
+}


_______________________________________________
Rawstudio-commit mailing list
[email protected]
http://rawstudio.org/cgi-bin/mailman/listinfo/rawstudio-commit

Reply via email to