Skip to content

Commit 9ea424a

Browse files
committed
Update infobar in a background thread
Thius stops a lot of nasty hitching. It needs libvips 8.15.
1 parent 10c1550 commit 9ea424a

File tree

5 files changed

+112
-21
lines changed

5 files changed

+112
-21
lines changed

src/imagewindow.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ struct _ImageWindow
6060
gint64 last_frame_time;
6161

6262
GSettings *settings;
63+
64+
// use for any bg threads we need
65+
VipsThreadset *threadset;
6366
};
6467

6568
G_DEFINE_TYPE( ImageWindow, image_window, GTK_TYPE_APPLICATION_WINDOW );
@@ -83,6 +86,7 @@ image_window_dispose( GObject *object )
8386
printf( "image_window_dispose:\n" );
8487
#endif /*DEBUG*/
8588

89+
VIPS_FREEF( vips_threadset_free, win->threadset );
8690
VIPS_UNREF( win->tile_source );
8791
VIPS_UNREF( win->tile_cache );
8892
VIPS_FREEF( gtk_widget_unparent, win->right_click_menu );
@@ -1364,6 +1368,8 @@ image_window_init( ImageWindow *win )
13641368
win->last_progress_time = -1;
13651369
win->scale_rate = 1.0;
13661370
win->settings = g_settings_new( APPLICATION_ID );
1371+
// only need a couple of threads
1372+
win->threadset = vips_threadset_new( 2 );
13671373

13681374
gtk_widget_init_template( GTK_WIDGET( win ) );
13691375

@@ -1611,3 +1617,9 @@ image_window_get_mouse_position( ImageWindow *win,
16111617
imagedisplay_gtk_to_image( VIPSDISP_IMAGEDISPLAY( win->imagedisplay ),
16121618
win->last_x_gtk, win->last_y_gtk, x_image, y_image );
16131619
}
1620+
1621+
VipsThreadset *
1622+
image_window_get_threadset( ImageWindow *win )
1623+
{
1624+
return( win->threadset );
1625+
}

src/imagewindow.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ TileSource *image_window_get_tile_source( ImageWindow *win );
1313
void image_window_set_tile_source( ImageWindow *win, TileSource *tile_source );
1414
void image_window_get_mouse_position( ImageWindow *win,
1515
double *image_x, double *image_y );
16+
VipsThreadset *image_window_get_threadset( ImageWindow *win );
1617

1718
#endif /* __IMAGE_WINDOW_H */
1819

src/infobar.c

Lines changed: 87 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ struct _Infobar {
1919
GtkWidget *mag;
2020

2121
GSList *value_widgets;
22+
23+
// a background pixel value fetch is in progress
24+
gboolean updating;
2225
};
2326

2427
G_DEFINE_TYPE( Infobar, infobar, GTK_TYPE_WIDGET );
@@ -137,18 +140,97 @@ infobar_status_value_set_array( Infobar *infobar, double *d )
137140
}
138141
}
139142

143+
/* Asynchronous update of the pixel value ... we need this off the main thread
144+
* or we get awful hitching for some formats.
145+
*/
146+
typedef struct _PixelUpdate {
147+
// what we update, where we get the pixel data
148+
Infobar *infobar;
149+
TileSource *tile_source;
150+
151+
// fetch params
152+
int image_x;
153+
int image_y;
154+
double *vector;
155+
int n;
156+
gboolean result;
157+
} PixelUpdate;
158+
159+
static void
160+
infobar_update_free( PixelUpdate *update )
161+
{
162+
update->infobar->updating = FALSE;
163+
164+
VIPS_UNREF( update->infobar );
165+
VIPS_UNREF( update->tile_source );
166+
VIPS_FREE( update->vector );
167+
VIPS_FREE( update );
168+
}
169+
170+
// runs back in the main thread again ... update the screen
171+
static gboolean
172+
infobar_update_pixel_cb( void *a )
173+
{
174+
PixelUpdate *update = (PixelUpdate *) a;
175+
176+
if( update->result )
177+
infobar_status_value_set_array( update->infobar, update->vector );
178+
179+
infobar_update_free( update );
180+
181+
return( FALSE );
182+
}
183+
184+
// runs in a bg thread
185+
static void
186+
infobar_get_pixel( void *a, void *b )
187+
{
188+
PixelUpdate *update = (PixelUpdate *) a;
189+
190+
update->result = tile_source_get_pixel( update->tile_source,
191+
update->image_x, update->image_y, &update->vector, &update->n );
192+
193+
g_idle_add( infobar_update_pixel_cb, update );
194+
}
195+
196+
// fetch the mouse position pixel and update the screen in a bg thread
197+
static void
198+
infobar_update_pixel( Infobar *infobar )
199+
{
200+
if( !infobar->updating ) {
201+
ImageWindow *win = infobar->win;
202+
PixelUpdate *update = g_new0( PixelUpdate, 1 );
203+
204+
double x_image;
205+
double y_image;
206+
207+
update->infobar = infobar;
208+
update->tile_source = image_window_get_tile_source( win );
209+
image_window_get_mouse_position( infobar->win, &x_image, &y_image );
210+
update->image_x = (int) x_image;
211+
update->image_y = (int) y_image;
212+
infobar->updating = TRUE;
213+
214+
// must stay valid until we are done
215+
g_object_ref( update->infobar );
216+
g_object_ref( update->tile_source );
217+
218+
if( vips_threadset_run(image_window_get_threadset( win ), "pixel",
219+
infobar_get_pixel, update ) )
220+
// if we can't run a bg task, we must free the update
221+
infobar_update_free( update );
222+
}
223+
}
224+
140225
void
141226
infobar_status_update( Infobar *infobar )
142227
{
143-
TileSource *tile_source = image_window_get_tile_source( infobar->win );
144228
double scale = image_window_get_scale( infobar->win );
145229

146230
char str[64];
147231
VipsBuf buf = VIPS_BUF_STATIC( str );
148232
double image_x;
149233
double image_y;
150-
double *vector;
151-
int n;
152234

153235
#ifdef DEBUG
154236
printf( "infobar_status_update:\n" );
@@ -166,13 +248,6 @@ infobar_status_update( Infobar *infobar )
166248
vips_buf_all( &buf ) );
167249
vips_buf_rewind( &buf );
168250

169-
if( tile_source_get_pixel( tile_source, &vector, &n,
170-
image_x, image_y ) ) {
171-
infobar_status_value_set_array( infobar, vector );
172-
g_free( vector );
173-
}
174-
175-
vips_buf_rewind( &buf );
176251
vips_buf_appendf( &buf, "Magnification " );
177252
if( scale >= 1.0 )
178253
vips_buf_appendf( &buf, "%d:1", (int) scale );
@@ -181,6 +256,8 @@ infobar_status_update( Infobar *infobar )
181256
gtk_label_set_text( GTK_LABEL( infobar->mag ),
182257
vips_buf_all( &buf ) );
183258

259+
// queue bg update of pixel value
260+
infobar_update_pixel( infobar );
184261
}
185262

186263
static void

src/tilesource.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1873,8 +1873,8 @@ tile_source_get_base_image( TileSource *tile_source )
18731873
}
18741874

18751875
gboolean
1876-
tile_source_get_pixel( TileSource *tile_source,
1877-
double **vector, int *n, int x, int y )
1876+
tile_source_get_pixel( TileSource *tile_source, int image_x, int image_y,
1877+
double **vector, int *n )
18781878
{
18791879
if( !tile_source->loaded ||
18801880
!tile_source->image )
@@ -1883,21 +1883,22 @@ tile_source_get_pixel( TileSource *tile_source,
18831883
/* x and y are in base image coordinates, so we need to scale by the
18841884
* current z.
18851885
*/
1886-
x /= 1 << tile_source->current_z;
1887-
y /= 1 << tile_source->current_z;
1886+
image_x /= 1 << tile_source->current_z;
1887+
image_y /= 1 << tile_source->current_z;
18881888

18891889
/* Block outside the image.
18901890
*/
1891-
if( x < 0 ||
1892-
y < 0 ||
1893-
x >= tile_source->display->Xsize ||
1894-
y >= tile_source->display->Ysize )
1891+
if( image_x < 0 ||
1892+
image_y < 0 ||
1893+
image_x >= tile_source->display->Xsize ||
1894+
image_y >= tile_source->display->Ysize )
18951895
return( FALSE );
18961896

18971897
/* The ->display image is cached in a sink screen, so this will be
18981898
* reasonably quick, even for things like svg and pdf.
18991899
*/
1900-
if( vips_getpoint( tile_source->display, vector, n, x, y, NULL ) )
1900+
if( vips_getpoint( tile_source->display,
1901+
vector, n, image_x, image_y, NULL ) )
19011902
return( FALSE );
19021903

19031904
return( TRUE );

src/tilesource.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,8 @@ GFile *tile_source_get_file( TileSource *tile_source );
235235

236236
VipsImage *tile_source_get_image( TileSource *tile_source );
237237
VipsImage *tile_source_get_base_image( TileSource *tile_source );
238-
gboolean tile_source_get_pixel( TileSource *tile_source,
239-
double **vector, int *n, int x, int y );
238+
gboolean tile_source_get_pixel( TileSource *tile_source,
239+
int image_x, int image_y, double **vector, int *n );
240240
TileSource *tile_source_duplicate( TileSource *tile_source );
241241

242242
#endif /*__TILE_SOURCE_H*/

0 commit comments

Comments
 (0)