mirror of https://github.com/GNOME/gimp.git
Okay, that didn't take quite as long as expected. This is the first cut at
Thu Oct 1 17:10:32 BST 1998 Adam D. Moss <adam@gimp.org> * app/gdisplay.c app/gdisplay.h: Okay, that didn't take quite as long as expected. This is the first cut at a gimp-wide IdleRender in place of the previously synchronous displays_update(). A synchronous displays_update_now() is implemented for stuff like brushes, but it isn't used right now. (Seems to go pretty well without.) I need feedback and (previously nonexistant!) bug reports... please. =)
This commit is contained in:
parent
769bfa6ecd
commit
c615f15e73
12
ChangeLog
12
ChangeLog
|
@ -1,3 +1,15 @@
|
|||
Thu Oct 1 17:10:32 BST 1998 Adam D. Moss <adam@gimp.org>
|
||||
|
||||
* app/gdisplay.c app/gdisplay.h: Okay, that didn't
|
||||
take quite as long as expected. This is the first cut at
|
||||
a gimp-wide IdleRender in place of the previously synchronous
|
||||
displays_update(). A synchronous displays_update_now() is
|
||||
implemented for stuff like brushes, but it isn't used right
|
||||
now. (Seems to go pretty well without.)
|
||||
|
||||
I need feedback and (previously nonexistant!) bug reports...
|
||||
please. =)
|
||||
|
||||
Thu Oct 1 12:44:19 BST 1998 Adam D. Moss <adam@gimp.org>
|
||||
|
||||
* app/floating_sel.c app/gdisplay.c app/gdisplay.h
|
||||
|
|
|
@ -67,6 +67,8 @@ static void gdisplay_draw_cursor (GDisplay *);
|
|||
static void gdisplay_display_area (GDisplay *, int, int, int, int);
|
||||
static guint gdisplay_hash (GDisplay *);
|
||||
|
||||
static void gdisplay_flush_displays_only (GDisplay *gdisp);
|
||||
|
||||
static GHashTable *display_ht = NULL;
|
||||
|
||||
|
||||
|
@ -116,6 +118,11 @@ gdisplay_new (GimpImage *gimage,
|
|||
|
||||
gdisp->progressid = FALSE;
|
||||
|
||||
gdisp->idle_render.idleid = -1;
|
||||
gdisp->idle_render.handlerid = -1;
|
||||
gdisp->idle_render.update_areas = NULL;
|
||||
gdisp->idle_render.active = FALSE;
|
||||
|
||||
/* add the new display to the list so that it isn't lost */
|
||||
display_list = g_slist_append (display_list, (void *) gdisp);
|
||||
|
||||
|
@ -195,6 +202,17 @@ gdisplay_delete (GDisplay *gdisp)
|
|||
|
||||
/* free the selection structure */
|
||||
selection_free (gdisp->select);
|
||||
|
||||
/* If this gdisplay was idlerendering at the time when it was deleted,
|
||||
deactivate the idlerendering thread before deletion! */
|
||||
if (gdisp->idle_render.active)
|
||||
{
|
||||
printf("Deleted idlerendering gdisp %p...\n", gdisp); fflush(stdout);
|
||||
printf("\tIdlerender stops now!\n"); fflush(stdout);
|
||||
gtk_idle_remove (gdisp->idle_render.idleid);
|
||||
gdisp->idle_render.active = FALSE;
|
||||
printf("\tDeletion finished.\n"); fflush(stdout);
|
||||
}
|
||||
|
||||
if (gdisp->scroll_gc)
|
||||
gdk_gc_destroy (gdisp->scroll_gc);
|
||||
|
@ -203,6 +221,8 @@ gdisplay_delete (GDisplay *gdisp)
|
|||
gdisplay_free_area_list (gdisp->update_areas);
|
||||
gdisplay_free_area_list (gdisp->display_areas);
|
||||
|
||||
gdisplay_free_area_list (gdisp->idle_render.update_areas);
|
||||
|
||||
/* free the gimage */
|
||||
gimage_delete (gdisp->gimage);
|
||||
|
||||
|
@ -288,48 +308,152 @@ gdisplay_process_area_list (GSList *list,
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
gdisplay_flush (GDisplay *gdisp)
|
||||
static int
|
||||
idle_render_next_area (GDisplay *gdisp)
|
||||
{
|
||||
GArea *ga;
|
||||
GSList *list;
|
||||
|
||||
list = gdisp->idle_render.update_areas;
|
||||
|
||||
printf(" FLUSH! ");fflush(stdout);
|
||||
if (list == NULL)
|
||||
{
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Flush the items in the displays and updates lists -
|
||||
* but only if gdisplay has been mapped and exposed
|
||||
*/
|
||||
if (!gdisp->select)
|
||||
return;
|
||||
ga = (GArea*) list->data;
|
||||
|
||||
/* First the updates... */
|
||||
gdisp->idle_render.update_areas =
|
||||
g_slist_remove (gdisp->idle_render.update_areas, ga);
|
||||
|
||||
gdisp->idle_render.x = gdisp->idle_render.basex = ga->x1;
|
||||
gdisp->idle_render.y = gdisp->idle_render.basey = ga->y1;
|
||||
gdisp->idle_render.width = ga->x2 - ga->x1;
|
||||
gdisp->idle_render.height = ga->y2 - ga->y1;
|
||||
|
||||
g_free (ga);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
idlerender_callback (gpointer data)
|
||||
{
|
||||
const int CHUNK_WIDTH = 256;
|
||||
const int CHUNK_HEIGHT = 128;
|
||||
int workx, worky, workw, workh;
|
||||
GDisplay* gdisp = data;
|
||||
|
||||
workw = CHUNK_WIDTH;
|
||||
workh = CHUNK_HEIGHT;
|
||||
workx = gdisp->idle_render.x;
|
||||
worky = gdisp->idle_render.y;
|
||||
|
||||
if (workx+workw > gdisp->idle_render.basex+gdisp->idle_render.width)
|
||||
{
|
||||
workw = gdisp->idle_render.basex+gdisp->idle_render.width-workx;
|
||||
}
|
||||
|
||||
if (worky+workh > gdisp->idle_render.basey+gdisp->idle_render.height)
|
||||
{
|
||||
workh = gdisp->idle_render.basey+gdisp->idle_render.height-worky;
|
||||
}
|
||||
|
||||
gdisplay_paint_area (gdisp, workx, worky,
|
||||
workw, workh);
|
||||
gdisplay_flush_displays_only (gdisp);
|
||||
|
||||
gdisp->idle_render.x += CHUNK_WIDTH;
|
||||
if (gdisp->idle_render.x >= gdisp->idle_render.basex+gdisp->idle_render.width)
|
||||
{
|
||||
gdisp->idle_render.x = gdisp->idle_render.basex;
|
||||
gdisp->idle_render.y += CHUNK_HEIGHT;
|
||||
if (gdisp->idle_render.y >=
|
||||
gdisp->idle_render.basey + gdisp->idle_render.height)
|
||||
{
|
||||
if (idle_render_next_area(gdisp) != 0)
|
||||
{
|
||||
/* FINISHED */
|
||||
gdisp->idle_render.active = FALSE;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Still work to do. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gdisplay_idlerender_init (GDisplay *gdisp)
|
||||
{
|
||||
GSList *list;
|
||||
GArea *ga, *new_ga;
|
||||
|
||||
/* We need to merge the IdleRender's and the GDisplay's update_areas list
|
||||
to keep track of which of the updates have been flushed and hence need
|
||||
to be drawn. */
|
||||
list = gdisp->update_areas;
|
||||
while (list)
|
||||
{
|
||||
/* Paint the area specified by the GArea */
|
||||
ga = (GArea *) list->data;
|
||||
new_ga = g_malloc (sizeof(GArea));
|
||||
memcpy (new_ga, ga, sizeof(GArea));
|
||||
|
||||
if ((ga->x1 != ga->x2) && (ga->y1 != ga->y2))
|
||||
{
|
||||
gdisplay_paint_area (gdisp, ga->x1, ga->y1,
|
||||
(ga->x2 - ga->x1), (ga->y2 - ga->y1));
|
||||
/*gdisplay_paint_area (gdisp, ga->x1+random()%(ga->x2 - ga->x1),
|
||||
ga->y1+random()%(ga->y2 - ga->y1),
|
||||
100,100);
|
||||
gdisplay_paint_area (gdisp, ga->x1+random()%(ga->x2 - ga->x1),
|
||||
ga->y1+random()%(ga->y2 - ga->y1),
|
||||
100,100);
|
||||
gdisplay_paint_area (gdisp, ga->x1+random()%(ga->x2 - ga->x1),
|
||||
ga->y1+random()%(ga->y2 - ga->y1),
|
||||
100,100);*/
|
||||
}
|
||||
gdisp->idle_render.update_areas =
|
||||
gdisplay_process_area_list (gdisp->idle_render.update_areas, new_ga);
|
||||
|
||||
list = g_slist_next (list);
|
||||
}
|
||||
/* Free the update lists */
|
||||
gdisp->update_areas = gdisplay_free_area_list (gdisp->update_areas);
|
||||
|
||||
/* Next the displays... */
|
||||
/* If an idlerender was already running, merge the remainder of its
|
||||
unrendered area with the update_areas list, and make it start work
|
||||
on the next unrendered area in the list. */
|
||||
if (gdisp->idle_render.active)
|
||||
{
|
||||
new_ga = g_malloc (sizeof(GArea));
|
||||
new_ga->x1 = gdisp->idle_render.basex;
|
||||
new_ga->y1 = gdisp->idle_render.y;
|
||||
new_ga->x2 = gdisp->idle_render.basex + gdisp->idle_render.width;
|
||||
new_ga->y2 = gdisp->idle_render.y +
|
||||
(gdisp->idle_render.height -
|
||||
(gdisp->idle_render.y - gdisp->idle_render.basey)
|
||||
);
|
||||
|
||||
gdisp->idle_render.update_areas =
|
||||
gdisplay_process_area_list (gdisp->idle_render.update_areas, new_ga);
|
||||
|
||||
idle_render_next_area(gdisp);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gdisp->idle_render.update_areas == NULL)
|
||||
{
|
||||
g_warning ("Wanted to start idlerender thread with no update_areas. (+memleak)");
|
||||
return;
|
||||
}
|
||||
|
||||
idle_render_next_area(gdisp);
|
||||
|
||||
gdisp->idle_render.active = TRUE;
|
||||
|
||||
gdisp->idle_render.idleid =
|
||||
gtk_idle_add_priority (GTK_PRIORITY_LOW,
|
||||
idlerender_callback, gdisp);
|
||||
}
|
||||
|
||||
/* Caller frees gdisp->update_areas */
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gdisplay_flush_displays_only (GDisplay *gdisp)
|
||||
{
|
||||
GSList *list;
|
||||
GArea *ga;
|
||||
|
||||
list = gdisp->display_areas;
|
||||
|
||||
if (list)
|
||||
|
@ -361,7 +485,50 @@ gdisplay_flush (GDisplay *gdisp)
|
|||
|
||||
/* start the currently active tool */
|
||||
active_tool_control (RESUME, (void *) gdisp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gdisplay_flush_whenever (GDisplay *gdisp, gboolean now)
|
||||
{
|
||||
GSList *list;
|
||||
GArea *ga;
|
||||
|
||||
/* Flush the items in the displays and updates lists -
|
||||
* but only if gdisplay has been mapped and exposed
|
||||
*/
|
||||
if (!gdisp->select)
|
||||
return;
|
||||
|
||||
/* First the updates... */
|
||||
if (now)
|
||||
{ /* Synchronous */
|
||||
list = gdisp->update_areas;
|
||||
while (list)
|
||||
{
|
||||
/* Paint the area specified by the GArea */
|
||||
ga = (GArea *) list->data;
|
||||
|
||||
if ((ga->x1 != ga->x2) && (ga->y1 != ga->y2))
|
||||
{
|
||||
gdisplay_paint_area (gdisp, ga->x1, ga->y1,
|
||||
(ga->x2 - ga->x1), (ga->y2 - ga->y1));
|
||||
}
|
||||
|
||||
list = g_slist_next (list);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* Asynchronous */
|
||||
if (gdisp->update_areas)
|
||||
gdisplay_idlerender_init (gdisp);
|
||||
}
|
||||
/* Free the update lists */
|
||||
gdisp->update_areas = gdisplay_free_area_list (gdisp->update_areas);
|
||||
|
||||
/* Next the displays... */
|
||||
gdisplay_flush_displays_only (gdisp);
|
||||
|
||||
/* update the gdisplay's info dialog */
|
||||
if (gdisp->window_info_dialog)
|
||||
|
@ -369,6 +536,20 @@ gdisplay_flush (GDisplay *gdisp)
|
|||
(void *) gdisp);
|
||||
}
|
||||
|
||||
void
|
||||
gdisplay_flush (GDisplay *gdisp)
|
||||
{
|
||||
/* Redraw on idle time */
|
||||
gdisplay_flush_whenever (gdisp, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
gdisplay_flush_now (GDisplay *gdisp)
|
||||
{
|
||||
/* Redraw NOW */
|
||||
gdisplay_flush_whenever (gdisp, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
gdisplay_draw_guides (GDisplay *gdisp)
|
||||
{
|
||||
|
@ -1531,8 +1712,8 @@ gdisplays_delete ()
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
gdisplays_flush ()
|
||||
static void
|
||||
gdisplays_flush_whenever (gboolean now)
|
||||
{
|
||||
static int flushing = FALSE;
|
||||
GSList *list = display_list;
|
||||
|
@ -1553,7 +1734,7 @@ gdisplays_flush ()
|
|||
/* traverse the linked list of displays */
|
||||
while (list)
|
||||
{
|
||||
gdisplay_flush ((GDisplay *) list->data);
|
||||
gdisplay_flush_whenever ((GDisplay *) list->data, now);
|
||||
list = g_slist_next (list);
|
||||
}
|
||||
|
||||
|
@ -1565,207 +1746,21 @@ gdisplays_flush ()
|
|||
flushing = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gdisplays_flush (void)
|
||||
{
|
||||
gdisplays_flush_whenever (FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
gdisplays_flush_now (void)
|
||||
{
|
||||
gdisplays_flush_whenever (TRUE);
|
||||
}
|
||||
|
||||
static guint
|
||||
gdisplay_hash (GDisplay *display)
|
||||
{
|
||||
return (gulong) display;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static void
|
||||
idlerender_gimage_destroy_handler (GimpImage *gimage)
|
||||
{
|
||||
printf("Destroyed gimage at %p which idlerender was interested in...\n",
|
||||
gimage); fflush(stdout);
|
||||
if (idle_active)
|
||||
{
|
||||
printf("Idlerender stops now!\n"); fflush(stdout);
|
||||
gtk_idle_remove (idlerender_idleid);
|
||||
}
|
||||
printf("Destroy handler finished.\n"); fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
idlerender_abort (GimpImage *gimage)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
idlerender_callback (void* unused)
|
||||
{
|
||||
const int CHUNK_WIDTH = 256;
|
||||
const int CHUNK_HEIGHT = 128;
|
||||
int workx, worky, workw, workh;
|
||||
|
||||
workw = CHUNK_WIDTH;
|
||||
workh = CHUNK_HEIGHT;
|
||||
workx = idlerender_x;
|
||||
worky = idlerender_y;
|
||||
|
||||
if (workx+workw > idlerender_basex+idlerender_width)
|
||||
{
|
||||
workw = idlerender_basex+idlerender_width-workx;
|
||||
}
|
||||
|
||||
if (worky+workh > idlerender_basey+idlerender_height)
|
||||
{
|
||||
workh = idlerender_basey+idlerender_height-worky;
|
||||
}
|
||||
|
||||
gdisplays_update_area (idlerender_gimage,
|
||||
workx, worky, workw, workh);
|
||||
gdisplays_flush ();
|
||||
|
||||
idlerender_x += CHUNK_WIDTH;
|
||||
if (idlerender_x >= idlerender_basex+idlerender_width)
|
||||
{
|
||||
idlerender_x = idlerender_basex;
|
||||
idlerender_y += CHUNK_HEIGHT;
|
||||
if (idlerender_y >= idlerender_basey+idlerender_height)
|
||||
{
|
||||
idle_active = 0;
|
||||
|
||||
/* Disconnect signal handler which cared about whether
|
||||
a gimage was destroyed in mid-render */
|
||||
gtk_signal_disconnect (GTK_OBJECT (idlerender_gimage),
|
||||
idlerender_handlerid);
|
||||
|
||||
return (0); /* FINISHED! */
|
||||
}
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
/* Force any outstanding unrendered area in the gimage to be
|
||||
rendered before we return... this is necessary e.g. if we
|
||||
are restarting the idlerender thread for a different gimage. */
|
||||
static void
|
||||
idlerender_force_completion (void)
|
||||
{
|
||||
gtk_idle_remove (idlerender_idleid);
|
||||
|
||||
while (idle_active)
|
||||
idlerender_callback (NULL);
|
||||
}
|
||||
|
||||
|
||||
/* Unify the desired and current (if any) bounding rectangles
|
||||
of areas being idle-redrawn, and restart the idle thread if needed. */
|
||||
static void
|
||||
unify_and_start_idlerender (GimpImage* gimage, int basex, int basey,
|
||||
int width, int height)
|
||||
{
|
||||
|
||||
/* If another gimage is already employing the idlerender thread,
|
||||
force it to finish before starting with this one... */
|
||||
if (idle_active && (idlerender_gimage != gimage) )
|
||||
{
|
||||
printf ("Okay, switched gimage... poke Adam if this does anything "
|
||||
"funny.\n");
|
||||
fflush(stdout);
|
||||
|
||||
idlerender_force_completion();
|
||||
}
|
||||
|
||||
idlerender_gimage = gimage;
|
||||
|
||||
if (idle_active)
|
||||
{
|
||||
int left, right, top, bottom;
|
||||
|
||||
/*printf("(%d,%d) @ Region (%d,%d %dx%d) | (%d,%d %dx%d)\n",
|
||||
idlerender_x, idlerender_y,
|
||||
idlerender_basex, idlerender_basey,
|
||||
idlerender_width, idlerender_height,
|
||||
|
||||
basex, basey,
|
||||
width, height);*/
|
||||
|
||||
top = (basey < idlerender_y) ? basey : idlerender_y;
|
||||
left = (basex < idlerender_basex) ? basex : idlerender_basex;
|
||||
bottom = (basey+height > idlerender_basey+idlerender_height) ?
|
||||
basey+height : idlerender_basey+idlerender_height;
|
||||
right = (basex+width > idlerender_basex+idlerender_width) ?
|
||||
basex+width : idlerender_basex+idlerender_width;
|
||||
|
||||
idlerender_x = idlerender_basex = left;
|
||||
idlerender_y = idlerender_basey = top;
|
||||
idlerender_width = right-left;
|
||||
idlerender_height = bottom-top;
|
||||
|
||||
/*printf(" --> (%d,%d) @ (%d,%d %dx%d)\n",
|
||||
idlerender_x, idlerender_y,
|
||||
idlerender_basex, idlerender_basey,
|
||||
idlerender_width, idlerender_height);*/
|
||||
}
|
||||
else
|
||||
{
|
||||
idlerender_x = idlerender_basex = basex;
|
||||
idlerender_y = idlerender_basey = basey;
|
||||
idlerender_width = width;
|
||||
idlerender_height = height;
|
||||
|
||||
idle_active = 1;
|
||||
/* Catch a signal to stop the idlerender thread if the corresponding
|
||||
gimage is destroyed in mid-render */
|
||||
idlerender_handlerid =
|
||||
gtk_signal_connect (GTK_OBJECT (gimage), "destroy",
|
||||
GTK_SIGNAL_FUNC(idlerender_gimage_destroy_handler),
|
||||
NULL);
|
||||
idlerender_idleid =
|
||||
gtk_idle_add_priority (GTK_PRIORITY_LOW, idlerender_callback, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
reinit_layer_idlerender (GimpImage* gimage, Layer* layer)
|
||||
{
|
||||
int ibasex, ibasey;
|
||||
|
||||
if (! layer)
|
||||
return;
|
||||
|
||||
if (! (gimage = gimp_drawable_gimage (GIMP_DRAWABLE(layer))))
|
||||
return;
|
||||
|
||||
gimp_drawable_offsets (GIMP_DRAWABLE(layer),
|
||||
&ibasex, &ibasey);
|
||||
unify_and_start_idlerender (gimage, ibasex, ibasey,
|
||||
GIMP_DRAWABLE(layer)->width,
|
||||
GIMP_DRAWABLE(layer)->height);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
reinit_drawable_idlerender (GimpImage* gimage, GimpDrawable *drawable)
|
||||
{
|
||||
int ibasex, ibasey;
|
||||
|
||||
if (! drawable)
|
||||
return;
|
||||
|
||||
if (! (gimage = gimp_drawable_gimage (GIMP_DRAWABLE(drawable))))
|
||||
return;
|
||||
|
||||
gimp_drawable_offsets (GIMP_DRAWABLE(drawable),
|
||||
&ibasex, &ibasey);
|
||||
unify_and_start_idlerender (gimage, ibasex, ibasey,
|
||||
GIMP_DRAWABLE(drawable)->width,
|
||||
GIMP_DRAWABLE(drawable)->height);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
reinit_gimage_idlerender (GimpImage* gimage)
|
||||
{
|
||||
unify_and_start_idlerender (gimage, 0, 0, gimage->width, gimage->height);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
|
||||
typedef struct _IdleRenderStruct
|
||||
{
|
||||
GimpImage* gimage;
|
||||
int width;
|
||||
int height;
|
||||
int x;
|
||||
|
@ -52,6 +51,7 @@ typedef struct _IdleRenderStruct
|
|||
guint idleid;
|
||||
guint handlerid;
|
||||
gboolean active;
|
||||
GSList *update_areas; /* flushed update areas */
|
||||
|
||||
} IdleRenderStruct;
|
||||
|
||||
|
@ -157,12 +157,7 @@ void gdisplays_selection_visibility (GimpImage*, SelectionControl);
|
|||
int gdisplays_dirty (void);
|
||||
void gdisplays_delete (void);
|
||||
void gdisplays_flush (void);
|
||||
|
||||
|
||||
/* Idle rerendering of altered areas. */
|
||||
void reinit_layer_idlerender (GimpImage *, Layer *);
|
||||
void reinit_drawable_idlerender (GimpImage *, GimpDrawable *);
|
||||
void reinit_gimage_idlerender (GimpImage *);
|
||||
void gdisplays_flush_now (void);
|
||||
|
||||
|
||||
#endif /* __GDISPLAY_H__ */
|
||||
|
|
|
@ -67,6 +67,8 @@ static void gdisplay_draw_cursor (GDisplay *);
|
|||
static void gdisplay_display_area (GDisplay *, int, int, int, int);
|
||||
static guint gdisplay_hash (GDisplay *);
|
||||
|
||||
static void gdisplay_flush_displays_only (GDisplay *gdisp);
|
||||
|
||||
static GHashTable *display_ht = NULL;
|
||||
|
||||
|
||||
|
@ -116,6 +118,11 @@ gdisplay_new (GimpImage *gimage,
|
|||
|
||||
gdisp->progressid = FALSE;
|
||||
|
||||
gdisp->idle_render.idleid = -1;
|
||||
gdisp->idle_render.handlerid = -1;
|
||||
gdisp->idle_render.update_areas = NULL;
|
||||
gdisp->idle_render.active = FALSE;
|
||||
|
||||
/* add the new display to the list so that it isn't lost */
|
||||
display_list = g_slist_append (display_list, (void *) gdisp);
|
||||
|
||||
|
@ -195,6 +202,17 @@ gdisplay_delete (GDisplay *gdisp)
|
|||
|
||||
/* free the selection structure */
|
||||
selection_free (gdisp->select);
|
||||
|
||||
/* If this gdisplay was idlerendering at the time when it was deleted,
|
||||
deactivate the idlerendering thread before deletion! */
|
||||
if (gdisp->idle_render.active)
|
||||
{
|
||||
printf("Deleted idlerendering gdisp %p...\n", gdisp); fflush(stdout);
|
||||
printf("\tIdlerender stops now!\n"); fflush(stdout);
|
||||
gtk_idle_remove (gdisp->idle_render.idleid);
|
||||
gdisp->idle_render.active = FALSE;
|
||||
printf("\tDeletion finished.\n"); fflush(stdout);
|
||||
}
|
||||
|
||||
if (gdisp->scroll_gc)
|
||||
gdk_gc_destroy (gdisp->scroll_gc);
|
||||
|
@ -203,6 +221,8 @@ gdisplay_delete (GDisplay *gdisp)
|
|||
gdisplay_free_area_list (gdisp->update_areas);
|
||||
gdisplay_free_area_list (gdisp->display_areas);
|
||||
|
||||
gdisplay_free_area_list (gdisp->idle_render.update_areas);
|
||||
|
||||
/* free the gimage */
|
||||
gimage_delete (gdisp->gimage);
|
||||
|
||||
|
@ -288,48 +308,152 @@ gdisplay_process_area_list (GSList *list,
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
gdisplay_flush (GDisplay *gdisp)
|
||||
static int
|
||||
idle_render_next_area (GDisplay *gdisp)
|
||||
{
|
||||
GArea *ga;
|
||||
GSList *list;
|
||||
|
||||
list = gdisp->idle_render.update_areas;
|
||||
|
||||
printf(" FLUSH! ");fflush(stdout);
|
||||
if (list == NULL)
|
||||
{
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Flush the items in the displays and updates lists -
|
||||
* but only if gdisplay has been mapped and exposed
|
||||
*/
|
||||
if (!gdisp->select)
|
||||
return;
|
||||
ga = (GArea*) list->data;
|
||||
|
||||
/* First the updates... */
|
||||
gdisp->idle_render.update_areas =
|
||||
g_slist_remove (gdisp->idle_render.update_areas, ga);
|
||||
|
||||
gdisp->idle_render.x = gdisp->idle_render.basex = ga->x1;
|
||||
gdisp->idle_render.y = gdisp->idle_render.basey = ga->y1;
|
||||
gdisp->idle_render.width = ga->x2 - ga->x1;
|
||||
gdisp->idle_render.height = ga->y2 - ga->y1;
|
||||
|
||||
g_free (ga);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
idlerender_callback (gpointer data)
|
||||
{
|
||||
const int CHUNK_WIDTH = 256;
|
||||
const int CHUNK_HEIGHT = 128;
|
||||
int workx, worky, workw, workh;
|
||||
GDisplay* gdisp = data;
|
||||
|
||||
workw = CHUNK_WIDTH;
|
||||
workh = CHUNK_HEIGHT;
|
||||
workx = gdisp->idle_render.x;
|
||||
worky = gdisp->idle_render.y;
|
||||
|
||||
if (workx+workw > gdisp->idle_render.basex+gdisp->idle_render.width)
|
||||
{
|
||||
workw = gdisp->idle_render.basex+gdisp->idle_render.width-workx;
|
||||
}
|
||||
|
||||
if (worky+workh > gdisp->idle_render.basey+gdisp->idle_render.height)
|
||||
{
|
||||
workh = gdisp->idle_render.basey+gdisp->idle_render.height-worky;
|
||||
}
|
||||
|
||||
gdisplay_paint_area (gdisp, workx, worky,
|
||||
workw, workh);
|
||||
gdisplay_flush_displays_only (gdisp);
|
||||
|
||||
gdisp->idle_render.x += CHUNK_WIDTH;
|
||||
if (gdisp->idle_render.x >= gdisp->idle_render.basex+gdisp->idle_render.width)
|
||||
{
|
||||
gdisp->idle_render.x = gdisp->idle_render.basex;
|
||||
gdisp->idle_render.y += CHUNK_HEIGHT;
|
||||
if (gdisp->idle_render.y >=
|
||||
gdisp->idle_render.basey + gdisp->idle_render.height)
|
||||
{
|
||||
if (idle_render_next_area(gdisp) != 0)
|
||||
{
|
||||
/* FINISHED */
|
||||
gdisp->idle_render.active = FALSE;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Still work to do. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gdisplay_idlerender_init (GDisplay *gdisp)
|
||||
{
|
||||
GSList *list;
|
||||
GArea *ga, *new_ga;
|
||||
|
||||
/* We need to merge the IdleRender's and the GDisplay's update_areas list
|
||||
to keep track of which of the updates have been flushed and hence need
|
||||
to be drawn. */
|
||||
list = gdisp->update_areas;
|
||||
while (list)
|
||||
{
|
||||
/* Paint the area specified by the GArea */
|
||||
ga = (GArea *) list->data;
|
||||
new_ga = g_malloc (sizeof(GArea));
|
||||
memcpy (new_ga, ga, sizeof(GArea));
|
||||
|
||||
if ((ga->x1 != ga->x2) && (ga->y1 != ga->y2))
|
||||
{
|
||||
gdisplay_paint_area (gdisp, ga->x1, ga->y1,
|
||||
(ga->x2 - ga->x1), (ga->y2 - ga->y1));
|
||||
/*gdisplay_paint_area (gdisp, ga->x1+random()%(ga->x2 - ga->x1),
|
||||
ga->y1+random()%(ga->y2 - ga->y1),
|
||||
100,100);
|
||||
gdisplay_paint_area (gdisp, ga->x1+random()%(ga->x2 - ga->x1),
|
||||
ga->y1+random()%(ga->y2 - ga->y1),
|
||||
100,100);
|
||||
gdisplay_paint_area (gdisp, ga->x1+random()%(ga->x2 - ga->x1),
|
||||
ga->y1+random()%(ga->y2 - ga->y1),
|
||||
100,100);*/
|
||||
}
|
||||
gdisp->idle_render.update_areas =
|
||||
gdisplay_process_area_list (gdisp->idle_render.update_areas, new_ga);
|
||||
|
||||
list = g_slist_next (list);
|
||||
}
|
||||
/* Free the update lists */
|
||||
gdisp->update_areas = gdisplay_free_area_list (gdisp->update_areas);
|
||||
|
||||
/* Next the displays... */
|
||||
/* If an idlerender was already running, merge the remainder of its
|
||||
unrendered area with the update_areas list, and make it start work
|
||||
on the next unrendered area in the list. */
|
||||
if (gdisp->idle_render.active)
|
||||
{
|
||||
new_ga = g_malloc (sizeof(GArea));
|
||||
new_ga->x1 = gdisp->idle_render.basex;
|
||||
new_ga->y1 = gdisp->idle_render.y;
|
||||
new_ga->x2 = gdisp->idle_render.basex + gdisp->idle_render.width;
|
||||
new_ga->y2 = gdisp->idle_render.y +
|
||||
(gdisp->idle_render.height -
|
||||
(gdisp->idle_render.y - gdisp->idle_render.basey)
|
||||
);
|
||||
|
||||
gdisp->idle_render.update_areas =
|
||||
gdisplay_process_area_list (gdisp->idle_render.update_areas, new_ga);
|
||||
|
||||
idle_render_next_area(gdisp);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gdisp->idle_render.update_areas == NULL)
|
||||
{
|
||||
g_warning ("Wanted to start idlerender thread with no update_areas. (+memleak)");
|
||||
return;
|
||||
}
|
||||
|
||||
idle_render_next_area(gdisp);
|
||||
|
||||
gdisp->idle_render.active = TRUE;
|
||||
|
||||
gdisp->idle_render.idleid =
|
||||
gtk_idle_add_priority (GTK_PRIORITY_LOW,
|
||||
idlerender_callback, gdisp);
|
||||
}
|
||||
|
||||
/* Caller frees gdisp->update_areas */
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gdisplay_flush_displays_only (GDisplay *gdisp)
|
||||
{
|
||||
GSList *list;
|
||||
GArea *ga;
|
||||
|
||||
list = gdisp->display_areas;
|
||||
|
||||
if (list)
|
||||
|
@ -361,7 +485,50 @@ gdisplay_flush (GDisplay *gdisp)
|
|||
|
||||
/* start the currently active tool */
|
||||
active_tool_control (RESUME, (void *) gdisp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gdisplay_flush_whenever (GDisplay *gdisp, gboolean now)
|
||||
{
|
||||
GSList *list;
|
||||
GArea *ga;
|
||||
|
||||
/* Flush the items in the displays and updates lists -
|
||||
* but only if gdisplay has been mapped and exposed
|
||||
*/
|
||||
if (!gdisp->select)
|
||||
return;
|
||||
|
||||
/* First the updates... */
|
||||
if (now)
|
||||
{ /* Synchronous */
|
||||
list = gdisp->update_areas;
|
||||
while (list)
|
||||
{
|
||||
/* Paint the area specified by the GArea */
|
||||
ga = (GArea *) list->data;
|
||||
|
||||
if ((ga->x1 != ga->x2) && (ga->y1 != ga->y2))
|
||||
{
|
||||
gdisplay_paint_area (gdisp, ga->x1, ga->y1,
|
||||
(ga->x2 - ga->x1), (ga->y2 - ga->y1));
|
||||
}
|
||||
|
||||
list = g_slist_next (list);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* Asynchronous */
|
||||
if (gdisp->update_areas)
|
||||
gdisplay_idlerender_init (gdisp);
|
||||
}
|
||||
/* Free the update lists */
|
||||
gdisp->update_areas = gdisplay_free_area_list (gdisp->update_areas);
|
||||
|
||||
/* Next the displays... */
|
||||
gdisplay_flush_displays_only (gdisp);
|
||||
|
||||
/* update the gdisplay's info dialog */
|
||||
if (gdisp->window_info_dialog)
|
||||
|
@ -369,6 +536,20 @@ gdisplay_flush (GDisplay *gdisp)
|
|||
(void *) gdisp);
|
||||
}
|
||||
|
||||
void
|
||||
gdisplay_flush (GDisplay *gdisp)
|
||||
{
|
||||
/* Redraw on idle time */
|
||||
gdisplay_flush_whenever (gdisp, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
gdisplay_flush_now (GDisplay *gdisp)
|
||||
{
|
||||
/* Redraw NOW */
|
||||
gdisplay_flush_whenever (gdisp, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
gdisplay_draw_guides (GDisplay *gdisp)
|
||||
{
|
||||
|
@ -1531,8 +1712,8 @@ gdisplays_delete ()
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
gdisplays_flush ()
|
||||
static void
|
||||
gdisplays_flush_whenever (gboolean now)
|
||||
{
|
||||
static int flushing = FALSE;
|
||||
GSList *list = display_list;
|
||||
|
@ -1553,7 +1734,7 @@ gdisplays_flush ()
|
|||
/* traverse the linked list of displays */
|
||||
while (list)
|
||||
{
|
||||
gdisplay_flush ((GDisplay *) list->data);
|
||||
gdisplay_flush_whenever ((GDisplay *) list->data, now);
|
||||
list = g_slist_next (list);
|
||||
}
|
||||
|
||||
|
@ -1565,207 +1746,21 @@ gdisplays_flush ()
|
|||
flushing = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gdisplays_flush (void)
|
||||
{
|
||||
gdisplays_flush_whenever (FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
gdisplays_flush_now (void)
|
||||
{
|
||||
gdisplays_flush_whenever (TRUE);
|
||||
}
|
||||
|
||||
static guint
|
||||
gdisplay_hash (GDisplay *display)
|
||||
{
|
||||
return (gulong) display;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static void
|
||||
idlerender_gimage_destroy_handler (GimpImage *gimage)
|
||||
{
|
||||
printf("Destroyed gimage at %p which idlerender was interested in...\n",
|
||||
gimage); fflush(stdout);
|
||||
if (idle_active)
|
||||
{
|
||||
printf("Idlerender stops now!\n"); fflush(stdout);
|
||||
gtk_idle_remove (idlerender_idleid);
|
||||
}
|
||||
printf("Destroy handler finished.\n"); fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
idlerender_abort (GimpImage *gimage)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
idlerender_callback (void* unused)
|
||||
{
|
||||
const int CHUNK_WIDTH = 256;
|
||||
const int CHUNK_HEIGHT = 128;
|
||||
int workx, worky, workw, workh;
|
||||
|
||||
workw = CHUNK_WIDTH;
|
||||
workh = CHUNK_HEIGHT;
|
||||
workx = idlerender_x;
|
||||
worky = idlerender_y;
|
||||
|
||||
if (workx+workw > idlerender_basex+idlerender_width)
|
||||
{
|
||||
workw = idlerender_basex+idlerender_width-workx;
|
||||
}
|
||||
|
||||
if (worky+workh > idlerender_basey+idlerender_height)
|
||||
{
|
||||
workh = idlerender_basey+idlerender_height-worky;
|
||||
}
|
||||
|
||||
gdisplays_update_area (idlerender_gimage,
|
||||
workx, worky, workw, workh);
|
||||
gdisplays_flush ();
|
||||
|
||||
idlerender_x += CHUNK_WIDTH;
|
||||
if (idlerender_x >= idlerender_basex+idlerender_width)
|
||||
{
|
||||
idlerender_x = idlerender_basex;
|
||||
idlerender_y += CHUNK_HEIGHT;
|
||||
if (idlerender_y >= idlerender_basey+idlerender_height)
|
||||
{
|
||||
idle_active = 0;
|
||||
|
||||
/* Disconnect signal handler which cared about whether
|
||||
a gimage was destroyed in mid-render */
|
||||
gtk_signal_disconnect (GTK_OBJECT (idlerender_gimage),
|
||||
idlerender_handlerid);
|
||||
|
||||
return (0); /* FINISHED! */
|
||||
}
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
/* Force any outstanding unrendered area in the gimage to be
|
||||
rendered before we return... this is necessary e.g. if we
|
||||
are restarting the idlerender thread for a different gimage. */
|
||||
static void
|
||||
idlerender_force_completion (void)
|
||||
{
|
||||
gtk_idle_remove (idlerender_idleid);
|
||||
|
||||
while (idle_active)
|
||||
idlerender_callback (NULL);
|
||||
}
|
||||
|
||||
|
||||
/* Unify the desired and current (if any) bounding rectangles
|
||||
of areas being idle-redrawn, and restart the idle thread if needed. */
|
||||
static void
|
||||
unify_and_start_idlerender (GimpImage* gimage, int basex, int basey,
|
||||
int width, int height)
|
||||
{
|
||||
|
||||
/* If another gimage is already employing the idlerender thread,
|
||||
force it to finish before starting with this one... */
|
||||
if (idle_active && (idlerender_gimage != gimage) )
|
||||
{
|
||||
printf ("Okay, switched gimage... poke Adam if this does anything "
|
||||
"funny.\n");
|
||||
fflush(stdout);
|
||||
|
||||
idlerender_force_completion();
|
||||
}
|
||||
|
||||
idlerender_gimage = gimage;
|
||||
|
||||
if (idle_active)
|
||||
{
|
||||
int left, right, top, bottom;
|
||||
|
||||
/*printf("(%d,%d) @ Region (%d,%d %dx%d) | (%d,%d %dx%d)\n",
|
||||
idlerender_x, idlerender_y,
|
||||
idlerender_basex, idlerender_basey,
|
||||
idlerender_width, idlerender_height,
|
||||
|
||||
basex, basey,
|
||||
width, height);*/
|
||||
|
||||
top = (basey < idlerender_y) ? basey : idlerender_y;
|
||||
left = (basex < idlerender_basex) ? basex : idlerender_basex;
|
||||
bottom = (basey+height > idlerender_basey+idlerender_height) ?
|
||||
basey+height : idlerender_basey+idlerender_height;
|
||||
right = (basex+width > idlerender_basex+idlerender_width) ?
|
||||
basex+width : idlerender_basex+idlerender_width;
|
||||
|
||||
idlerender_x = idlerender_basex = left;
|
||||
idlerender_y = idlerender_basey = top;
|
||||
idlerender_width = right-left;
|
||||
idlerender_height = bottom-top;
|
||||
|
||||
/*printf(" --> (%d,%d) @ (%d,%d %dx%d)\n",
|
||||
idlerender_x, idlerender_y,
|
||||
idlerender_basex, idlerender_basey,
|
||||
idlerender_width, idlerender_height);*/
|
||||
}
|
||||
else
|
||||
{
|
||||
idlerender_x = idlerender_basex = basex;
|
||||
idlerender_y = idlerender_basey = basey;
|
||||
idlerender_width = width;
|
||||
idlerender_height = height;
|
||||
|
||||
idle_active = 1;
|
||||
/* Catch a signal to stop the idlerender thread if the corresponding
|
||||
gimage is destroyed in mid-render */
|
||||
idlerender_handlerid =
|
||||
gtk_signal_connect (GTK_OBJECT (gimage), "destroy",
|
||||
GTK_SIGNAL_FUNC(idlerender_gimage_destroy_handler),
|
||||
NULL);
|
||||
idlerender_idleid =
|
||||
gtk_idle_add_priority (GTK_PRIORITY_LOW, idlerender_callback, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
reinit_layer_idlerender (GimpImage* gimage, Layer* layer)
|
||||
{
|
||||
int ibasex, ibasey;
|
||||
|
||||
if (! layer)
|
||||
return;
|
||||
|
||||
if (! (gimage = gimp_drawable_gimage (GIMP_DRAWABLE(layer))))
|
||||
return;
|
||||
|
||||
gimp_drawable_offsets (GIMP_DRAWABLE(layer),
|
||||
&ibasex, &ibasey);
|
||||
unify_and_start_idlerender (gimage, ibasex, ibasey,
|
||||
GIMP_DRAWABLE(layer)->width,
|
||||
GIMP_DRAWABLE(layer)->height);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
reinit_drawable_idlerender (GimpImage* gimage, GimpDrawable *drawable)
|
||||
{
|
||||
int ibasex, ibasey;
|
||||
|
||||
if (! drawable)
|
||||
return;
|
||||
|
||||
if (! (gimage = gimp_drawable_gimage (GIMP_DRAWABLE(drawable))))
|
||||
return;
|
||||
|
||||
gimp_drawable_offsets (GIMP_DRAWABLE(drawable),
|
||||
&ibasex, &ibasey);
|
||||
unify_and_start_idlerender (gimage, ibasex, ibasey,
|
||||
GIMP_DRAWABLE(drawable)->width,
|
||||
GIMP_DRAWABLE(drawable)->height);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
reinit_gimage_idlerender (GimpImage* gimage)
|
||||
{
|
||||
unify_and_start_idlerender (gimage, 0, 0, gimage->width, gimage->height);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
|
||||
typedef struct _IdleRenderStruct
|
||||
{
|
||||
GimpImage* gimage;
|
||||
int width;
|
||||
int height;
|
||||
int x;
|
||||
|
@ -52,6 +51,7 @@ typedef struct _IdleRenderStruct
|
|||
guint idleid;
|
||||
guint handlerid;
|
||||
gboolean active;
|
||||
GSList *update_areas; /* flushed update areas */
|
||||
|
||||
} IdleRenderStruct;
|
||||
|
||||
|
@ -157,12 +157,7 @@ void gdisplays_selection_visibility (GimpImage*, SelectionControl);
|
|||
int gdisplays_dirty (void);
|
||||
void gdisplays_delete (void);
|
||||
void gdisplays_flush (void);
|
||||
|
||||
|
||||
/* Idle rerendering of altered areas. */
|
||||
void reinit_layer_idlerender (GimpImage *, Layer *);
|
||||
void reinit_drawable_idlerender (GimpImage *, GimpDrawable *);
|
||||
void reinit_gimage_idlerender (GimpImage *);
|
||||
void gdisplays_flush_now (void);
|
||||
|
||||
|
||||
#endif /* __GDISPLAY_H__ */
|
||||
|
|
451
app/gdisplay.c
451
app/gdisplay.c
|
@ -67,6 +67,8 @@ static void gdisplay_draw_cursor (GDisplay *);
|
|||
static void gdisplay_display_area (GDisplay *, int, int, int, int);
|
||||
static guint gdisplay_hash (GDisplay *);
|
||||
|
||||
static void gdisplay_flush_displays_only (GDisplay *gdisp);
|
||||
|
||||
static GHashTable *display_ht = NULL;
|
||||
|
||||
|
||||
|
@ -116,6 +118,11 @@ gdisplay_new (GimpImage *gimage,
|
|||
|
||||
gdisp->progressid = FALSE;
|
||||
|
||||
gdisp->idle_render.idleid = -1;
|
||||
gdisp->idle_render.handlerid = -1;
|
||||
gdisp->idle_render.update_areas = NULL;
|
||||
gdisp->idle_render.active = FALSE;
|
||||
|
||||
/* add the new display to the list so that it isn't lost */
|
||||
display_list = g_slist_append (display_list, (void *) gdisp);
|
||||
|
||||
|
@ -195,6 +202,17 @@ gdisplay_delete (GDisplay *gdisp)
|
|||
|
||||
/* free the selection structure */
|
||||
selection_free (gdisp->select);
|
||||
|
||||
/* If this gdisplay was idlerendering at the time when it was deleted,
|
||||
deactivate the idlerendering thread before deletion! */
|
||||
if (gdisp->idle_render.active)
|
||||
{
|
||||
printf("Deleted idlerendering gdisp %p...\n", gdisp); fflush(stdout);
|
||||
printf("\tIdlerender stops now!\n"); fflush(stdout);
|
||||
gtk_idle_remove (gdisp->idle_render.idleid);
|
||||
gdisp->idle_render.active = FALSE;
|
||||
printf("\tDeletion finished.\n"); fflush(stdout);
|
||||
}
|
||||
|
||||
if (gdisp->scroll_gc)
|
||||
gdk_gc_destroy (gdisp->scroll_gc);
|
||||
|
@ -203,6 +221,8 @@ gdisplay_delete (GDisplay *gdisp)
|
|||
gdisplay_free_area_list (gdisp->update_areas);
|
||||
gdisplay_free_area_list (gdisp->display_areas);
|
||||
|
||||
gdisplay_free_area_list (gdisp->idle_render.update_areas);
|
||||
|
||||
/* free the gimage */
|
||||
gimage_delete (gdisp->gimage);
|
||||
|
||||
|
@ -288,48 +308,152 @@ gdisplay_process_area_list (GSList *list,
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
gdisplay_flush (GDisplay *gdisp)
|
||||
static int
|
||||
idle_render_next_area (GDisplay *gdisp)
|
||||
{
|
||||
GArea *ga;
|
||||
GSList *list;
|
||||
|
||||
list = gdisp->idle_render.update_areas;
|
||||
|
||||
printf(" FLUSH! ");fflush(stdout);
|
||||
if (list == NULL)
|
||||
{
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Flush the items in the displays and updates lists -
|
||||
* but only if gdisplay has been mapped and exposed
|
||||
*/
|
||||
if (!gdisp->select)
|
||||
return;
|
||||
ga = (GArea*) list->data;
|
||||
|
||||
/* First the updates... */
|
||||
gdisp->idle_render.update_areas =
|
||||
g_slist_remove (gdisp->idle_render.update_areas, ga);
|
||||
|
||||
gdisp->idle_render.x = gdisp->idle_render.basex = ga->x1;
|
||||
gdisp->idle_render.y = gdisp->idle_render.basey = ga->y1;
|
||||
gdisp->idle_render.width = ga->x2 - ga->x1;
|
||||
gdisp->idle_render.height = ga->y2 - ga->y1;
|
||||
|
||||
g_free (ga);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
idlerender_callback (gpointer data)
|
||||
{
|
||||
const int CHUNK_WIDTH = 256;
|
||||
const int CHUNK_HEIGHT = 128;
|
||||
int workx, worky, workw, workh;
|
||||
GDisplay* gdisp = data;
|
||||
|
||||
workw = CHUNK_WIDTH;
|
||||
workh = CHUNK_HEIGHT;
|
||||
workx = gdisp->idle_render.x;
|
||||
worky = gdisp->idle_render.y;
|
||||
|
||||
if (workx+workw > gdisp->idle_render.basex+gdisp->idle_render.width)
|
||||
{
|
||||
workw = gdisp->idle_render.basex+gdisp->idle_render.width-workx;
|
||||
}
|
||||
|
||||
if (worky+workh > gdisp->idle_render.basey+gdisp->idle_render.height)
|
||||
{
|
||||
workh = gdisp->idle_render.basey+gdisp->idle_render.height-worky;
|
||||
}
|
||||
|
||||
gdisplay_paint_area (gdisp, workx, worky,
|
||||
workw, workh);
|
||||
gdisplay_flush_displays_only (gdisp);
|
||||
|
||||
gdisp->idle_render.x += CHUNK_WIDTH;
|
||||
if (gdisp->idle_render.x >= gdisp->idle_render.basex+gdisp->idle_render.width)
|
||||
{
|
||||
gdisp->idle_render.x = gdisp->idle_render.basex;
|
||||
gdisp->idle_render.y += CHUNK_HEIGHT;
|
||||
if (gdisp->idle_render.y >=
|
||||
gdisp->idle_render.basey + gdisp->idle_render.height)
|
||||
{
|
||||
if (idle_render_next_area(gdisp) != 0)
|
||||
{
|
||||
/* FINISHED */
|
||||
gdisp->idle_render.active = FALSE;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Still work to do. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gdisplay_idlerender_init (GDisplay *gdisp)
|
||||
{
|
||||
GSList *list;
|
||||
GArea *ga, *new_ga;
|
||||
|
||||
/* We need to merge the IdleRender's and the GDisplay's update_areas list
|
||||
to keep track of which of the updates have been flushed and hence need
|
||||
to be drawn. */
|
||||
list = gdisp->update_areas;
|
||||
while (list)
|
||||
{
|
||||
/* Paint the area specified by the GArea */
|
||||
ga = (GArea *) list->data;
|
||||
new_ga = g_malloc (sizeof(GArea));
|
||||
memcpy (new_ga, ga, sizeof(GArea));
|
||||
|
||||
if ((ga->x1 != ga->x2) && (ga->y1 != ga->y2))
|
||||
{
|
||||
gdisplay_paint_area (gdisp, ga->x1, ga->y1,
|
||||
(ga->x2 - ga->x1), (ga->y2 - ga->y1));
|
||||
/*gdisplay_paint_area (gdisp, ga->x1+random()%(ga->x2 - ga->x1),
|
||||
ga->y1+random()%(ga->y2 - ga->y1),
|
||||
100,100);
|
||||
gdisplay_paint_area (gdisp, ga->x1+random()%(ga->x2 - ga->x1),
|
||||
ga->y1+random()%(ga->y2 - ga->y1),
|
||||
100,100);
|
||||
gdisplay_paint_area (gdisp, ga->x1+random()%(ga->x2 - ga->x1),
|
||||
ga->y1+random()%(ga->y2 - ga->y1),
|
||||
100,100);*/
|
||||
}
|
||||
gdisp->idle_render.update_areas =
|
||||
gdisplay_process_area_list (gdisp->idle_render.update_areas, new_ga);
|
||||
|
||||
list = g_slist_next (list);
|
||||
}
|
||||
/* Free the update lists */
|
||||
gdisp->update_areas = gdisplay_free_area_list (gdisp->update_areas);
|
||||
|
||||
/* Next the displays... */
|
||||
/* If an idlerender was already running, merge the remainder of its
|
||||
unrendered area with the update_areas list, and make it start work
|
||||
on the next unrendered area in the list. */
|
||||
if (gdisp->idle_render.active)
|
||||
{
|
||||
new_ga = g_malloc (sizeof(GArea));
|
||||
new_ga->x1 = gdisp->idle_render.basex;
|
||||
new_ga->y1 = gdisp->idle_render.y;
|
||||
new_ga->x2 = gdisp->idle_render.basex + gdisp->idle_render.width;
|
||||
new_ga->y2 = gdisp->idle_render.y +
|
||||
(gdisp->idle_render.height -
|
||||
(gdisp->idle_render.y - gdisp->idle_render.basey)
|
||||
);
|
||||
|
||||
gdisp->idle_render.update_areas =
|
||||
gdisplay_process_area_list (gdisp->idle_render.update_areas, new_ga);
|
||||
|
||||
idle_render_next_area(gdisp);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gdisp->idle_render.update_areas == NULL)
|
||||
{
|
||||
g_warning ("Wanted to start idlerender thread with no update_areas. (+memleak)");
|
||||
return;
|
||||
}
|
||||
|
||||
idle_render_next_area(gdisp);
|
||||
|
||||
gdisp->idle_render.active = TRUE;
|
||||
|
||||
gdisp->idle_render.idleid =
|
||||
gtk_idle_add_priority (GTK_PRIORITY_LOW,
|
||||
idlerender_callback, gdisp);
|
||||
}
|
||||
|
||||
/* Caller frees gdisp->update_areas */
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gdisplay_flush_displays_only (GDisplay *gdisp)
|
||||
{
|
||||
GSList *list;
|
||||
GArea *ga;
|
||||
|
||||
list = gdisp->display_areas;
|
||||
|
||||
if (list)
|
||||
|
@ -361,7 +485,50 @@ gdisplay_flush (GDisplay *gdisp)
|
|||
|
||||
/* start the currently active tool */
|
||||
active_tool_control (RESUME, (void *) gdisp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gdisplay_flush_whenever (GDisplay *gdisp, gboolean now)
|
||||
{
|
||||
GSList *list;
|
||||
GArea *ga;
|
||||
|
||||
/* Flush the items in the displays and updates lists -
|
||||
* but only if gdisplay has been mapped and exposed
|
||||
*/
|
||||
if (!gdisp->select)
|
||||
return;
|
||||
|
||||
/* First the updates... */
|
||||
if (now)
|
||||
{ /* Synchronous */
|
||||
list = gdisp->update_areas;
|
||||
while (list)
|
||||
{
|
||||
/* Paint the area specified by the GArea */
|
||||
ga = (GArea *) list->data;
|
||||
|
||||
if ((ga->x1 != ga->x2) && (ga->y1 != ga->y2))
|
||||
{
|
||||
gdisplay_paint_area (gdisp, ga->x1, ga->y1,
|
||||
(ga->x2 - ga->x1), (ga->y2 - ga->y1));
|
||||
}
|
||||
|
||||
list = g_slist_next (list);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* Asynchronous */
|
||||
if (gdisp->update_areas)
|
||||
gdisplay_idlerender_init (gdisp);
|
||||
}
|
||||
/* Free the update lists */
|
||||
gdisp->update_areas = gdisplay_free_area_list (gdisp->update_areas);
|
||||
|
||||
/* Next the displays... */
|
||||
gdisplay_flush_displays_only (gdisp);
|
||||
|
||||
/* update the gdisplay's info dialog */
|
||||
if (gdisp->window_info_dialog)
|
||||
|
@ -369,6 +536,20 @@ gdisplay_flush (GDisplay *gdisp)
|
|||
(void *) gdisp);
|
||||
}
|
||||
|
||||
void
|
||||
gdisplay_flush (GDisplay *gdisp)
|
||||
{
|
||||
/* Redraw on idle time */
|
||||
gdisplay_flush_whenever (gdisp, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
gdisplay_flush_now (GDisplay *gdisp)
|
||||
{
|
||||
/* Redraw NOW */
|
||||
gdisplay_flush_whenever (gdisp, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
gdisplay_draw_guides (GDisplay *gdisp)
|
||||
{
|
||||
|
@ -1531,8 +1712,8 @@ gdisplays_delete ()
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
gdisplays_flush ()
|
||||
static void
|
||||
gdisplays_flush_whenever (gboolean now)
|
||||
{
|
||||
static int flushing = FALSE;
|
||||
GSList *list = display_list;
|
||||
|
@ -1553,7 +1734,7 @@ gdisplays_flush ()
|
|||
/* traverse the linked list of displays */
|
||||
while (list)
|
||||
{
|
||||
gdisplay_flush ((GDisplay *) list->data);
|
||||
gdisplay_flush_whenever ((GDisplay *) list->data, now);
|
||||
list = g_slist_next (list);
|
||||
}
|
||||
|
||||
|
@ -1565,207 +1746,21 @@ gdisplays_flush ()
|
|||
flushing = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gdisplays_flush (void)
|
||||
{
|
||||
gdisplays_flush_whenever (FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
gdisplays_flush_now (void)
|
||||
{
|
||||
gdisplays_flush_whenever (TRUE);
|
||||
}
|
||||
|
||||
static guint
|
||||
gdisplay_hash (GDisplay *display)
|
||||
{
|
||||
return (gulong) display;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static void
|
||||
idlerender_gimage_destroy_handler (GimpImage *gimage)
|
||||
{
|
||||
printf("Destroyed gimage at %p which idlerender was interested in...\n",
|
||||
gimage); fflush(stdout);
|
||||
if (idle_active)
|
||||
{
|
||||
printf("Idlerender stops now!\n"); fflush(stdout);
|
||||
gtk_idle_remove (idlerender_idleid);
|
||||
}
|
||||
printf("Destroy handler finished.\n"); fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
idlerender_abort (GimpImage *gimage)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
idlerender_callback (void* unused)
|
||||
{
|
||||
const int CHUNK_WIDTH = 256;
|
||||
const int CHUNK_HEIGHT = 128;
|
||||
int workx, worky, workw, workh;
|
||||
|
||||
workw = CHUNK_WIDTH;
|
||||
workh = CHUNK_HEIGHT;
|
||||
workx = idlerender_x;
|
||||
worky = idlerender_y;
|
||||
|
||||
if (workx+workw > idlerender_basex+idlerender_width)
|
||||
{
|
||||
workw = idlerender_basex+idlerender_width-workx;
|
||||
}
|
||||
|
||||
if (worky+workh > idlerender_basey+idlerender_height)
|
||||
{
|
||||
workh = idlerender_basey+idlerender_height-worky;
|
||||
}
|
||||
|
||||
gdisplays_update_area (idlerender_gimage,
|
||||
workx, worky, workw, workh);
|
||||
gdisplays_flush ();
|
||||
|
||||
idlerender_x += CHUNK_WIDTH;
|
||||
if (idlerender_x >= idlerender_basex+idlerender_width)
|
||||
{
|
||||
idlerender_x = idlerender_basex;
|
||||
idlerender_y += CHUNK_HEIGHT;
|
||||
if (idlerender_y >= idlerender_basey+idlerender_height)
|
||||
{
|
||||
idle_active = 0;
|
||||
|
||||
/* Disconnect signal handler which cared about whether
|
||||
a gimage was destroyed in mid-render */
|
||||
gtk_signal_disconnect (GTK_OBJECT (idlerender_gimage),
|
||||
idlerender_handlerid);
|
||||
|
||||
return (0); /* FINISHED! */
|
||||
}
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
/* Force any outstanding unrendered area in the gimage to be
|
||||
rendered before we return... this is necessary e.g. if we
|
||||
are restarting the idlerender thread for a different gimage. */
|
||||
static void
|
||||
idlerender_force_completion (void)
|
||||
{
|
||||
gtk_idle_remove (idlerender_idleid);
|
||||
|
||||
while (idle_active)
|
||||
idlerender_callback (NULL);
|
||||
}
|
||||
|
||||
|
||||
/* Unify the desired and current (if any) bounding rectangles
|
||||
of areas being idle-redrawn, and restart the idle thread if needed. */
|
||||
static void
|
||||
unify_and_start_idlerender (GimpImage* gimage, int basex, int basey,
|
||||
int width, int height)
|
||||
{
|
||||
|
||||
/* If another gimage is already employing the idlerender thread,
|
||||
force it to finish before starting with this one... */
|
||||
if (idle_active && (idlerender_gimage != gimage) )
|
||||
{
|
||||
printf ("Okay, switched gimage... poke Adam if this does anything "
|
||||
"funny.\n");
|
||||
fflush(stdout);
|
||||
|
||||
idlerender_force_completion();
|
||||
}
|
||||
|
||||
idlerender_gimage = gimage;
|
||||
|
||||
if (idle_active)
|
||||
{
|
||||
int left, right, top, bottom;
|
||||
|
||||
/*printf("(%d,%d) @ Region (%d,%d %dx%d) | (%d,%d %dx%d)\n",
|
||||
idlerender_x, idlerender_y,
|
||||
idlerender_basex, idlerender_basey,
|
||||
idlerender_width, idlerender_height,
|
||||
|
||||
basex, basey,
|
||||
width, height);*/
|
||||
|
||||
top = (basey < idlerender_y) ? basey : idlerender_y;
|
||||
left = (basex < idlerender_basex) ? basex : idlerender_basex;
|
||||
bottom = (basey+height > idlerender_basey+idlerender_height) ?
|
||||
basey+height : idlerender_basey+idlerender_height;
|
||||
right = (basex+width > idlerender_basex+idlerender_width) ?
|
||||
basex+width : idlerender_basex+idlerender_width;
|
||||
|
||||
idlerender_x = idlerender_basex = left;
|
||||
idlerender_y = idlerender_basey = top;
|
||||
idlerender_width = right-left;
|
||||
idlerender_height = bottom-top;
|
||||
|
||||
/*printf(" --> (%d,%d) @ (%d,%d %dx%d)\n",
|
||||
idlerender_x, idlerender_y,
|
||||
idlerender_basex, idlerender_basey,
|
||||
idlerender_width, idlerender_height);*/
|
||||
}
|
||||
else
|
||||
{
|
||||
idlerender_x = idlerender_basex = basex;
|
||||
idlerender_y = idlerender_basey = basey;
|
||||
idlerender_width = width;
|
||||
idlerender_height = height;
|
||||
|
||||
idle_active = 1;
|
||||
/* Catch a signal to stop the idlerender thread if the corresponding
|
||||
gimage is destroyed in mid-render */
|
||||
idlerender_handlerid =
|
||||
gtk_signal_connect (GTK_OBJECT (gimage), "destroy",
|
||||
GTK_SIGNAL_FUNC(idlerender_gimage_destroy_handler),
|
||||
NULL);
|
||||
idlerender_idleid =
|
||||
gtk_idle_add_priority (GTK_PRIORITY_LOW, idlerender_callback, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
reinit_layer_idlerender (GimpImage* gimage, Layer* layer)
|
||||
{
|
||||
int ibasex, ibasey;
|
||||
|
||||
if (! layer)
|
||||
return;
|
||||
|
||||
if (! (gimage = gimp_drawable_gimage (GIMP_DRAWABLE(layer))))
|
||||
return;
|
||||
|
||||
gimp_drawable_offsets (GIMP_DRAWABLE(layer),
|
||||
&ibasex, &ibasey);
|
||||
unify_and_start_idlerender (gimage, ibasex, ibasey,
|
||||
GIMP_DRAWABLE(layer)->width,
|
||||
GIMP_DRAWABLE(layer)->height);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
reinit_drawable_idlerender (GimpImage* gimage, GimpDrawable *drawable)
|
||||
{
|
||||
int ibasex, ibasey;
|
||||
|
||||
if (! drawable)
|
||||
return;
|
||||
|
||||
if (! (gimage = gimp_drawable_gimage (GIMP_DRAWABLE(drawable))))
|
||||
return;
|
||||
|
||||
gimp_drawable_offsets (GIMP_DRAWABLE(drawable),
|
||||
&ibasex, &ibasey);
|
||||
unify_and_start_idlerender (gimage, ibasex, ibasey,
|
||||
GIMP_DRAWABLE(drawable)->width,
|
||||
GIMP_DRAWABLE(drawable)->height);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
reinit_gimage_idlerender (GimpImage* gimage)
|
||||
{
|
||||
unify_and_start_idlerender (gimage, 0, 0, gimage->width, gimage->height);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
|
||||
typedef struct _IdleRenderStruct
|
||||
{
|
||||
GimpImage* gimage;
|
||||
int width;
|
||||
int height;
|
||||
int x;
|
||||
|
@ -52,6 +51,7 @@ typedef struct _IdleRenderStruct
|
|||
guint idleid;
|
||||
guint handlerid;
|
||||
gboolean active;
|
||||
GSList *update_areas; /* flushed update areas */
|
||||
|
||||
} IdleRenderStruct;
|
||||
|
||||
|
@ -157,12 +157,7 @@ void gdisplays_selection_visibility (GimpImage*, SelectionControl);
|
|||
int gdisplays_dirty (void);
|
||||
void gdisplays_delete (void);
|
||||
void gdisplays_flush (void);
|
||||
|
||||
|
||||
/* Idle rerendering of altered areas. */
|
||||
void reinit_layer_idlerender (GimpImage *, Layer *);
|
||||
void reinit_drawable_idlerender (GimpImage *, GimpDrawable *);
|
||||
void reinit_gimage_idlerender (GimpImage *);
|
||||
void gdisplays_flush_now (void);
|
||||
|
||||
|
||||
#endif /* __GDISPLAY_H__ */
|
||||
|
|
Loading…
Reference in New Issue