Complete.Org: Mailing Lists: Archives: freeciv-dev: March 2003:
[Freeciv-Dev] (PR#3424) New flush code
Home

[Freeciv-Dev] (PR#3424) New flush code

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: bursig@xxxxxxxxx
Subject: [Freeciv-Dev] (PR#3424) New flush code
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Sun, 2 Mar 2003 23:49:05 -0800
Reply-to: rt@xxxxxxxxxxxxxx

[rfalke - Fri Feb 28 10:56:30 2003]:

> > One problem is that the SDL event code I used is unreliable.
> Apparently
> > SDL can drop events, particularly before the main loop is entered.
> > After one dropped event the code cannot recover.  A good partial
> > solution would be to move the is_flush_queued=FALSE line into
> > flush_dirty for SDL and possibly other GUIs.
> 
> Are you sure the SDL drops events? Can you prove it? Normally it is
> wrong usage.

Rafal told me that SDL can drop events with no warning.

This doesn't appear to be the case, but after doing some research I
think SDL_PushEvent used to be broken.  It claims to return 0 on
success, -1 on failure - but everyone says it actually returns the
number of events enqueued (0 or 1) on success, and -1 on error. 
Apparently this is not the case anymore (at least for my version of SDL).

According to what I read SDL uses a queue of 127 events, so if this
queue overflows events will be dropped.

I believe this new code handles that correctly, assuming that -1 is
returned when an event is dropped (I haven't actually seen or tested
this).  Rafal also said it failed to update the canvas when map options
are toggled, but that's simply because update_map_canvas_visible is not
called in that case.

I've also updated the patch for current CVS.  It may now be in a final form.

jason

Index: client/climisc.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/climisc.c,v
retrieving revision 1.112
diff -u -r1.112 climisc.c
--- client/climisc.c    2003/02/15 20:26:17     1.112
+++ client/climisc.c    2003/03/03 07:34:44
@@ -111,7 +111,7 @@
            get_nation_name(city_owner(pcity)->nation), pcity->x, pcity->y);
   }
 
-  refresh_tile_mapcanvas(x, y, TRUE);
+  refresh_tile_mapcanvas(x, y, FALSE);
 }
 
 /**************************************************************************
@@ -142,7 +142,7 @@
   popdown_city_dialog(pcity);
   game_remove_city(pcity);
   city_report_dialog_update();
-  refresh_tile_mapcanvas(x, y, TRUE);
+  refresh_tile_mapcanvas(x, y, FALSE);
 }
 
 /**************************************************************************
Index: client/control.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/control.c,v
retrieving revision 1.95
diff -u -r1.95 control.c
--- client/control.c    2003/02/20 21:58:14     1.95
+++ client/control.c    2003/03/03 07:34:45
@@ -110,7 +110,7 @@
     auto_center_on_focus_unit();
 
     punit->focus_status=FOCUS_AVAIL;
-    refresh_tile_mapcanvas(punit->x, punit->y, TRUE);
+    refresh_tile_mapcanvas(punit->x, punit->y, FALSE);
 
     if (punit->activity != ACTIVITY_IDLE || punit->ai.control)  {
       punit->activity = ACTIVITY_IDLE;
@@ -124,7 +124,7 @@
   if (punit_old_focus
       && (!punit || !same_pos(punit_old_focus->x, punit_old_focus->y,
                                   punit->x, punit->y))) {
-    refresh_tile_mapcanvas(punit_old_focus->x, punit_old_focus->y, TRUE);
+    refresh_tile_mapcanvas(punit_old_focus->x, punit_old_focus->y, FALSE);
   }
 
   update_unit_info_label(punit);
@@ -215,7 +215,7 @@
    * because above we change punit_focus directly.
    */
   if(punit_old_focus && punit_old_focus!=punit_focus)
-    refresh_tile_mapcanvas(punit_old_focus->x, punit_old_focus->y, TRUE);
+    refresh_tile_mapcanvas(punit_old_focus->x, punit_old_focus->y, FALSE);
 
   set_unit_focus(punit_focus);
 
@@ -1170,7 +1170,7 @@
   unit_list_unlink(&map_get_tile(x, y)->units, punit);
 
   if(!pinfo->carried)
-    refresh_tile_mapcanvas(x, y, was_teleported);
+    refresh_tile_mapcanvas(x, y, FALSE);
   
   if(game.player_idx==punit->owner && punit->activity!=ACTIVITY_GOTO && 
      auto_center_on_unit && punit->activity!=ACTIVITY_SENTRY &&
@@ -1184,7 +1184,7 @@
       dx=1;
     if(smooth_move_units)
       move_unit_map_canvas(punit, x, y, dx, pinfo->y - punit->y);
-    refresh_tile_mapcanvas(x, y, TRUE);
+    refresh_tile_mapcanvas(x, y, FALSE);
   }
     
   punit->x=pinfo->x;
@@ -1203,12 +1203,12 @@
     } unit_list_iterate_end;
   out:
     if (refresh) {
-      refresh_tile_mapcanvas(x, y, TRUE);
+      refresh_tile_mapcanvas(x, y, FALSE);
     }
   } square_iterate_end;
   
   if(!pinfo->carried && tile_get_known(punit->x,punit->y) == TILE_KNOWN)
-    refresh_tile_mapcanvas(punit->x, punit->y, TRUE);
+    refresh_tile_mapcanvas(punit->x, punit->y, FALSE);
 
   if(get_unit_in_focus()==punit) update_menus();
 }
Index: client/mapview_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.c,v
retrieving revision 1.35
diff -u -r1.35 mapview_common.c
--- client/mapview_common.c     2003/03/01 21:03:55     1.35
+++ client/mapview_common.c     2003/03/03 07:34:45
@@ -99,12 +99,7 @@
     }
 
     if (write_to_screen) {
-      int canvas_start_x, canvas_start_y;
-
-      get_canvas_xy(x, y, &canvas_start_x, &canvas_start_y);
-      canvas_start_y += NORMAL_TILE_HEIGHT - UNIT_TILE_HEIGHT;
-      flush_mapcanvas(canvas_start_x, canvas_start_y,
-                     UNIT_TILE_WIDTH, UNIT_TILE_HEIGHT);
+      flush_dirty();
     }
   }
   overview_update_tile(x, y);
@@ -630,6 +625,8 @@
 void update_map_canvas(int x, int y, int width, int height, 
                       bool write_to_screen)
 {
+  int canvas_start_x, canvas_start_y;
+
   freelog(LOG_DEBUG,
          "update_map_canvas(pos=(%d,%d), size=(%d,%d), write_to_screen=%d)",
          x, y, width, height, write_to_screen);
@@ -704,31 +701,25 @@
 
 
     /* Lastly draw our changes to the screen. */
-    if (write_to_screen) {
-      int canvas_start_x, canvas_start_y;
+    /* top left corner */
+    get_canvas_xy(x, y, &canvas_start_x, &canvas_start_y);
 
-      /* top left corner */
-      get_canvas_xy(x, y, &canvas_start_x, &canvas_start_y);
+    /* top left corner in isometric view */
+    canvas_start_x -= height * NORMAL_TILE_WIDTH / 2;
 
-      /* top left corner in isometric view */
-      canvas_start_x -= height * NORMAL_TILE_WIDTH / 2;
+    /* because of where get_canvas_xy() sets canvas_x */
+    canvas_start_x += NORMAL_TILE_WIDTH / 2;
 
-      /* because of where get_canvas_xy() sets canvas_x */
-      canvas_start_x += NORMAL_TILE_WIDTH / 2;
-
-      /* And because units fill a little extra */
-      canvas_start_y -= NORMAL_TILE_HEIGHT / 2;
-
-      /* Here we draw a rectangle that includes the updated tiles.  This
-       * method can fail if the area wraps off one side of the screen and
-       * back to the other (although this will not be a problem for
-       * update_map_canvas_visible(). */
-      flush_mapcanvas(canvas_start_x, canvas_start_y,
-                     (height + width) * NORMAL_TILE_WIDTH / 2,
-                     (height + width) * NORMAL_TILE_HEIGHT / 2
-                     + NORMAL_TILE_HEIGHT / 2);
-    }
-
+    /* And because units fill a little extra */
+    canvas_start_y += NORMAL_TILE_HEIGHT - UNIT_TILE_HEIGHT;
+
+    /* Here we draw a rectangle that includes the updated tiles.  This
+     * method can fail if the area wraps off one side of the screen and
+     * back to the other. */
+    dirty_rect(canvas_start_x, canvas_start_y,
+              (height + width) * NORMAL_TILE_WIDTH / 2,
+              (height + width) * NORMAL_TILE_HEIGHT / 2
+              + NORMAL_TILE_HEIGHT / 2);
   } else {
     /* not isometric */
     int map_x, map_y;
@@ -743,18 +734,20 @@
       }
     }
 
-    if (write_to_screen) {
-      int canvas_x, canvas_y;
+    /* Here we draw a rectangle that includes the updated tiles.  This
+     * method can fail if the area wraps off one side of the screen and
+     * back to the other. */
+    get_canvas_xy(x, y, &canvas_start_x, &canvas_start_y);
+    dirty_rect(canvas_start_x, canvas_start_y,
+              width * NORMAL_TILE_WIDTH,
+              height * NORMAL_TILE_HEIGHT);
+  }
 
-      /* Here we draw a rectangle that includes the updated tiles.  This
-       * method can fail if the area wraps off one side of the screen and
-       * back to the other (although this will not be a problem for
-       * update_map_canvas_visible(). */
-      get_canvas_xy(x, y, &canvas_x, &canvas_y);
-      flush_mapcanvas(canvas_x, canvas_y,
-                     width * NORMAL_TILE_WIDTH,
-                     height * NORMAL_TILE_HEIGHT);
-    }
+  if (write_to_screen) {
+    /* We never want a partial flush; that would leave the screen in an
+     * inconsistent state.  If the caller tells us to write_to_screen we
+     * simply flush everything immediately. */
+    flush_dirty();
   }
 }
 
@@ -771,6 +764,8 @@
   map_tile_width = (map_win_width - 1) / NORMAL_TILE_WIDTH + 1;
   map_tile_height = (map_win_height - 1) / NORMAL_TILE_HEIGHT + 1;
 
+  dirty_all();
+
   if (is_isometric) {
     /* just find a big rectangle that includes the whole visible area. The
        invisible tiles will not be drawn. */
@@ -785,8 +780,6 @@
   }
 
   show_city_descriptions();
-
-  flush_mapcanvas(0, 0, map_win_width, map_win_height);
 }
 
 /**************************************************************************
@@ -866,10 +859,10 @@
     update_map_canvas(MIN(src_x, dest_x), MIN(src_y, dest_y),
                      src_x == dest_x ? 1 : 2,
                      src_y == dest_y ? 1 : 2,
-                     TRUE);
+                     FALSE);
   } else {
-    refresh_tile_mapcanvas(src_x, src_y, TRUE);
-    refresh_tile_mapcanvas(dest_x, dest_y, TRUE);
+    refresh_tile_mapcanvas(src_x, src_y, FALSE);
+    refresh_tile_mapcanvas(dest_x, dest_y, FALSE);
 
     if (NORMAL_TILE_WIDTH % 2 == 0 || NORMAL_TILE_HEIGHT % 2 == 0) {
       if (dir == DIR8_NORTHEAST) {
@@ -878,12 +871,12 @@
        if (!MAPSTEP(dest_x, dest_y, src_x, src_y, DIR8_EAST)) {
          assert(0);
        }
-       refresh_tile_mapcanvas(dest_x, dest_y, TRUE);
+       refresh_tile_mapcanvas(dest_x, dest_y, FALSE);
       } else if (dir == DIR8_SOUTHWEST) {      /* the same */
        if (!MAPSTEP(dest_x, dest_y, src_x, src_y, DIR8_SOUTH)) {
          assert(0);
        }
-       refresh_tile_mapcanvas(dest_x, dest_y, TRUE);
+       refresh_tile_mapcanvas(dest_x, dest_y, FALSE);
       }
     }
   }
@@ -915,6 +908,8 @@
     assert(0);
   }
 
+  flush_dirty();
+
   if (player_can_see_unit(game.player_ptr, punit) &&
       (tile_visible_mapcanvas(map_x, map_y) ||
        tile_visible_mapcanvas(dest_x, dest_y))) {
@@ -1119,6 +1114,8 @@
     update_city_descriptions();
   }
   needed_updates = UPDATE_NONE;
+
+  flush_dirty();
 }
 
 /**************************************************************************
Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.293
diff -u -r1.293 packhand.c
--- client/packhand.c   2003/02/20 23:00:55     1.293
+++ client/packhand.c   2003/03/03 07:34:46
@@ -190,6 +190,7 @@
 **************************************************************************/
 void handle_nuke_tile(struct packet_nuke_tile *packet)
 {
+  flush_dirty();
   put_nuke_mushroom_pixmaps(packet->x, packet->y);
 }
 
@@ -223,14 +224,15 @@
                       unit_type(punit1)->sound_fight_alt);
 
       if (do_combat_animation) {
+       flush_dirty();
        decrease_unit_hp_smooth(punit0, hp0, punit1, hp1);
       } else {
        punit0->hp = hp0;
        punit1->hp = hp1;
 
        set_units_in_combat(NULL, NULL);
-       refresh_tile_mapcanvas(punit0->x, punit0->y, TRUE);
-       refresh_tile_mapcanvas(punit1->x, punit1->y, TRUE);
+       refresh_tile_mapcanvas(punit0->x, punit0->y, FALSE);
+       refresh_tile_mapcanvas(punit1->x, punit1->y, FALSE);
       }
     }
   }
@@ -503,7 +505,7 @@
                      CITY_MAP_SIZE, CITY_MAP_SIZE, FALSE);
     queue_mapview_update(UPDATE_CITY_DESCRIPTIONS);
   } else {
-    refresh_tile_mapcanvas(pcity->x, pcity->y, TRUE);
+    refresh_tile_mapcanvas(pcity->x, pcity->y, FALSE);
   }
 
   if (city_workers_display==pcity)  {
@@ -914,7 +916,7 @@
 
       if(punit->owner==game.player_idx) 
         refresh_unit_city_dialogs(punit);
-      /*      refresh_tile_mapcanvas(punit->x, punit->y, TRUE);
+      /*      refresh_tile_mapcanvas(punit->x, punit->y, FALSE);
        *      update_unit_pix_label(punit);
        *      update_unit_focus();
        */
@@ -982,7 +984,7 @@
       else {
        do_move_unit(punit, packet); /* nice to see where a unit is going */
        client_remove_unit(punit);
-       refresh_tile_mapcanvas(packet->x, packet->y, TRUE);
+       refresh_tile_mapcanvas(packet->x, packet->y, FALSE);
         return;
       }
       if(pcity)  {
@@ -1052,7 +1054,7 @@
     /*fog of war*/
     if (!(tile_get_known(punit->x,punit->y) == TILE_KNOWN)) {
       client_remove_unit(punit);
-      refresh_tile_mapcanvas(dest_x, dest_y, TRUE);
+      refresh_tile_mapcanvas(dest_x, dest_y, FALSE);
     }
     agents_unit_changed(punit);
   }
@@ -1093,7 +1095,7 @@
   }
 
   if(repaint_unit)
-    refresh_tile_mapcanvas(punit->x, punit->y, TRUE);
+    refresh_tile_mapcanvas(punit->x, punit->y, FALSE);
 
   if (check_focus || get_unit_in_focus() == NULL)
     update_unit_focus(); 
@@ -1703,14 +1705,14 @@
 
     /* the tile itself */
     if (tile_changed || old_known!=ptile->known)
-      refresh_tile_mapcanvas(x, y, TRUE);
+      refresh_tile_mapcanvas(x, y, FALSE);
 
     /* if the terrain or the specials of the tile
        have changed it affects the adjacent tiles */
     if (tile_changed) {
       adjc_iterate(x, y, x1, y1) {
        if (tile_get_known(x1, y1) >= TILE_KNOWN_FOGGED)
-         refresh_tile_mapcanvas(x1, y1, TRUE);
+         refresh_tile_mapcanvas(x1, y1, FALSE);
       }
       adjc_iterate_end;
       return;
@@ -1721,7 +1723,7 @@
     if (old_known == TILE_UNKNOWN && packet->known >= TILE_KNOWN_FOGGED) {     
       cartesian_adjacent_iterate(x, y, x1, y1) {
        if (tile_get_known(x1, y1) >= TILE_KNOWN_FOGGED)
-         refresh_tile_mapcanvas(x1, y1, TRUE);
+         refresh_tile_mapcanvas(x1, y1, FALSE);
       }
       cartesian_adjacent_iterate_end;
     }
Index: client/gui-gtk/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/mapview.c,v
retrieving revision 1.162
diff -u -r1.162 mapview.c
--- client/gui-gtk/mapview.c    2003/03/01 21:03:55     1.162
+++ client/gui-gtk/mapview.c    2003/03/03 07:34:47
@@ -772,6 +772,83 @@
   gdk_draw_pixmap(map_canvas->window, civ_gc, map_canvas_store,
                  canvas_x, canvas_y, canvas_x, canvas_y,
                  pixel_width, pixel_height);
+
+}
+
+#define MAX_DIRTY_RECTS 20
+static int num_dirty_rects = 0;
+static GdkRectangle dirty_rects[MAX_DIRTY_RECTS];
+static bool is_flush_queued = FALSE;
+
+/**************************************************************************
+  A callback invoked as a result of gtk_idle_add, this function simply
+  flushes the mapview canvas.
+**************************************************************************/
+static gint unqueue_flush(gpointer data)
+{
+  flush_dirty();
+  is_flush_queued = FALSE;
+  return 0;
+}
+
+/**************************************************************************
+  Called when a region is marked dirty, this function queues a flush event
+  to be handled later by GTK.  The flush may end up being done
+  by freeciv before then, in which case it will be a wasted call.
+**************************************************************************/
+static void queue_flush(void)
+{
+  if (!is_flush_queued) {
+    gtk_idle_add(unqueue_flush, NULL);
+    is_flush_queued = TRUE;
+  }
+}
+
+/**************************************************************************
+  Mark the rectangular region as 'dirty' so that we know to flush it
+  later.
+**************************************************************************/
+void dirty_rect(int canvas_x, int canvas_y,
+               int pixel_width, int pixel_height)
+{
+  if (num_dirty_rects < MAX_DIRTY_RECTS) {
+    dirty_rects[num_dirty_rects].x = canvas_x;
+    dirty_rects[num_dirty_rects].y = canvas_y;
+    dirty_rects[num_dirty_rects].width = pixel_width;
+    dirty_rects[num_dirty_rects].height = pixel_height;
+    num_dirty_rects++;
+    queue_flush();
+  }
+}
+
+/**************************************************************************
+  Mark the entire screen area as "dirty" so that we can flush it later.
+**************************************************************************/
+void dirty_all(void)
+{
+  num_dirty_rects = MAX_DIRTY_RECTS;
+  queue_flush();
+}
+
+/**************************************************************************
+  Flush all regions that have been previously marked as dirty.  See
+  dirty_rect and dirty_all.  This function is generally called after we've
+  processed a batch of drawing operations.
+**************************************************************************/
+void flush_dirty(void)
+{
+  if (num_dirty_rects == MAX_DIRTY_RECTS) {
+    flush_mapcanvas(0, 0, map_canvas->allocation.width,
+                   map_canvas->allocation.height);
+  } else {
+    int i;
+
+    for (i = 0; i < num_dirty_rects; i++) {
+      flush_mapcanvas(dirty_rects[i].x, dirty_rects[i].y,
+                     dirty_rects[i].width, dirty_rects[i].height);
+    }
+  }
+  num_dirty_rects = 0;
 }
 
 /**************************************************************************
Index: client/gui-gtk-2.0/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/mapview.c,v
retrieving revision 1.50
diff -u -r1.50 mapview.c
--- client/gui-gtk-2.0/mapview.c        2003/03/01 21:03:56     1.50
+++ client/gui-gtk-2.0/mapview.c        2003/03/03 07:34:48
@@ -809,6 +809,45 @@
 }
 
 /**************************************************************************
+  Mark the rectangular region as "dirty" so that we know to flush it
+  later.
+**************************************************************************/
+void dirty_rect(int canvas_x, int canvas_y,
+               int pixel_width, int pixel_height)
+{
+  /* GDK gives an error if we invalidate out-of-bounds parts of the
+     window. */
+  GdkRectangle rect = {MAX(canvas_x, 0), MAX(canvas_y, 0),
+                      MIN(pixel_width,
+                          map_canvas->allocation.width - canvas_x),
+                      MIN(pixel_height,
+                          map_canvas->allocation.height - canvas_y)};
+
+  gdk_window_invalidate_rect(map_canvas->window, &rect, FALSE);
+}
+
+/**************************************************************************
+  Mark the entire screen area as "dirty" so that we can flush it later.
+**************************************************************************/
+void dirty_all(void)
+{
+  GdkRectangle rect = {0, 0, map_canvas->allocation.width,
+                      map_canvas->allocation.height};
+
+  gdk_window_invalidate_rect(map_canvas->window, &rect, FALSE);
+}
+
+/**************************************************************************
+  Flush all regions that have been previously marked as dirty.  See
+  dirty_rect and dirty_all.  This function is generally called after we've
+  processed a batch of drawing operations.
+**************************************************************************/
+void flush_dirty(void)
+{
+  gdk_window_process_updates(map_canvas->window, FALSE);
+}
+
+/**************************************************************************
  Update display of descriptions associated with cities on the main map.
 **************************************************************************/
 void update_city_descriptions(void)
Index: client/gui-mui/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-mui/mapview.c,v
retrieving revision 1.59
diff -u -r1.59 mapview.c
--- client/gui-mui/mapview.c    2003/03/01 21:03:56     1.59
+++ client/gui-mui/mapview.c    2003/03/03 07:34:49
@@ -442,6 +442,34 @@
 }
 
 /**************************************************************************
+  Mark the rectangular region as 'dirty' so that we know to flush it
+  later.
+**************************************************************************/
+void dirty_rect(int canvas_x, int canvas_y,
+               int pixel_width, int pixel_height)
+{
+  /* PORTME */
+}
+
+/**************************************************************************
+  Mark the entire screen area as "dirty" so that we can flush it later.
+**************************************************************************/
+void dirty_all(void)
+{
+  /* PORTME */
+}
+
+/**************************************************************************
+  Flush all regions that have been previously marked as dirty.  See
+  dirty_rect and dirty_all.  This function is generally called after we've
+  processed a batch of drawing operations.
+**************************************************************************/
+void flush_dirty(void)
+{
+  /* PORTME */
+}
+
+/**************************************************************************
  Update display of descriptions associated with cities on the main map.
 **************************************************************************/
 void update_city_descriptions(void)
Index: client/gui-sdl/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-sdl/gui_main.c,v
retrieving revision 1.20
diff -u -r1.20 gui_main.c
--- client/gui-sdl/gui_main.c   2003/03/01 12:11:19     1.20
+++ client/gui-sdl/gui_main.c   2003/03/03 07:34:49
@@ -107,7 +107,8 @@
   NET = 1,
   ANIM = 2,
   TRY_AUTO_CONNECT = 3,
-  SHOW_WIDGET_INFO_LABBEL = 4
+  SHOW_WIDGET_INFO_LABBEL = 4,
+  FLUSH = 5
 };
 
 Uint32 SDL_Client_Flags = 0;
@@ -125,6 +126,7 @@
 static SDL_Event *pNet_User_Event = NULL;
 static SDL_Event *pAnim_User_Event = NULL;
 static SDL_Event *pInfo_User_Event = NULL;
+SDL_Event flush_user_event;
 
 Uint32 widget_info_cunter = 0;
 
@@ -372,6 +374,9 @@
          }
          widget_info_cunter = 1;
        break;
+      case FLUSH:
+       unqueue_flush();
+       break;
        default:
        break;
       }    
@@ -660,6 +665,10 @@
   __Info_User_Event.user.data1 = NULL;
   __Info_User_Event.user.data2 = NULL;
   pInfo_User_Event = &__Info_User_Event;
+
+  flush_user_event.type = SDL_USEREVENT;
+  flush_user_event.user.code = FLUSH;
+  flush_user_event.user.data1 = flush_user_event.user.data2 = NULL;
   
   smooth_move_unit_steps = 8;
   update_city_text_in_refresh_tile = FALSE;
Index: client/gui-sdl/gui_main.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-sdl/gui_main.h,v
retrieving revision 1.9
diff -u -r1.9 gui_main.h
--- client/gui-sdl/gui_main.h   2003/02/21 03:40:06     1.9
+++ client/gui-sdl/gui_main.h   2003/03/03 07:34:49
@@ -53,4 +53,6 @@
 
 void add_autoconnect_to_timer(void);
 
+extern SDL_Event flush_user_event;
+
 #endif                         /* FC__GUI_MAIN_H */
Index: client/gui-sdl/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-sdl/mapview.c,v
retrieving revision 1.35
diff -u -r1.35 mapview.c
--- client/gui-sdl/mapview.c    2003/03/01 21:03:56     1.35
+++ client/gui-sdl/mapview.c    2003/03/03 07:34:50
@@ -240,6 +240,33 @@
   }
 }
 
+static bool is_flush_queued = FALSE;
+
+/**************************************************************************
+  A callback invoked as a result of gtk_idle_add, this function simply
+  flushes the mapview canvas.
+**************************************************************************/
+void unqueue_flush(void)
+{
+  is_flush_queued = FALSE;
+  flush_dirty();
+}
+
+/**************************************************************************
+  Called when a region is marked dirty, this function queues a flush event
+  to be handled later by GTK.  The flush may end up being done
+  by freeciv before then, in which case it will be a wasted call.
+**************************************************************************/
+static void queue_flush(void)
+{
+  if (!is_flush_queued) {
+    if (SDL_PushEvent(&flush_user_event) == 0) {
+      is_flush_queued = TRUE;
+    }
+    /* Else nothing... */
+  }
+}
+
 /**************************************************************************
   Save Flush area used by "end" flush.
 **************************************************************************/
@@ -249,6 +276,7 @@
   SDL_Rect Rect = {canvas_x, canvas_y, pixel_width, pixel_height};
   if ((Main.rects_count < RECT_LIMIT) && correct_rect_region(&Rect)) {
     Main.rects[Main.rects_count++] = Rect;
+    queue_flush();
   }
 }
 
@@ -259,6 +287,7 @@
 {
   if ((Main.rects_count < RECT_LIMIT) && correct_rect_region(&Rect)) {
     Main.rects[Main.rects_count++] = Rect;
+    queue_flush();
   }
 }
 
@@ -268,6 +297,7 @@
 void dirty_all(void)
 {
   Main.rects_count = RECT_LIMIT;
+  queue_flush();
 }
 
 /**************************************************************************
@@ -285,7 +315,6 @@
 **************************************************************************/
 void flush_dirty(void)
 {
-      
   if(!Main.rects_count) {
     return;
   }
Index: client/gui-sdl/mapview.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-sdl/mapview.h,v
retrieving revision 1.6
diff -u -r1.6 mapview.h
--- client/gui-sdl/mapview.h    2003/02/28 12:51:01     1.6
+++ client/gui-sdl/mapview.h    2003/03/03 07:34:50
@@ -38,6 +38,7 @@
 void put_unit_pixmap_draw(struct unit *pUnit, SDL_Surface * pDest,
                          Sint16 map_x, Sint16 map_y);
 void flush_rect(SDL_Rect rect);
+void unqueue_flush(void);
 void sdl_dirty_rect(SDL_Rect rect);
 void flush_all(void);
 
Index: client/gui-stub/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-stub/mapview.c,v
retrieving revision 1.30
diff -u -r1.30 mapview.c
--- client/gui-stub/mapview.c   2003/03/01 21:03:56     1.30
+++ client/gui-stub/mapview.c   2003/03/03 07:34:50
@@ -226,6 +226,33 @@
   /* PORTME */
 }
 
+/**************************************************************************
+  Mark the rectangular region as 'dirty' so that we know to flush it
+  later.
+**************************************************************************/
+void dirty_rect(int canvas_x, int canvas_y,
+               int pixel_width, int pixel_height)
+{
+  /* PORTME */
+}
+
+/**************************************************************************
+  Mark the entire screen area as "dirty" so that we can flush it later.
+**************************************************************************/
+void dirty_all(void)
+{
+  /* PORTME */
+}
+
+/**************************************************************************
+  Flush all regions that have been previously marked as dirty.  See
+  dirty_rect and dirty_all.  This function is generally called after we've
+  processed a batch of drawing operations.
+**************************************************************************/
+void flush_dirty(void)
+{
+  /* PORTME */
+}
 
 /**************************************************************************
   Update (refresh) the locations of the mapview scrollbars (if it uses
Index: client/gui-win32/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-win32/mapview.c,v
retrieving revision 1.62
diff -u -r1.62 mapview.c
--- client/gui-win32/mapview.c  2003/03/01 21:03:56     1.62
+++ client/gui-win32/mapview.c  2003/03/03 07:34:51
@@ -521,6 +521,83 @@
   DeleteDC(mapstoredc);
 }
 
+#define MAX_DIRTY_RECTS 20
+static int num_dirty_rects = 0;
+static struct {
+  int x, y, w, h;
+} dirty_rects[MAX_DIRTY_RECTS];
+bool is_flush_queued = FALSE;
+
+/**************************************************************************
+  A callback invoked as a result of a timer event, this function simply
+  flushes the mapview canvas.
+**************************************************************************/
+static VOID CALLBACK unqueue_flush(HWND hwnd, UINT uMsg, UINT idEvent,
+                                  DWORD dwTime)
+{
+  flush_dirty();
+  is_flush_queued = FALSE;
+}
+
+/**************************************************************************
+  Called when a region is marked dirty, this function queues a flush event
+  to be handled later.  The flush may end up being done by freeciv before
+  then, in which case it will be a wasted call.
+**************************************************************************/
+static void queue_flush(void)
+{
+  if (!is_flush_queued) {
+    SetTimer(root_window, 4, 0, unqueue_flush);
+    is_flush_queued = TRUE;
+  }
+}
+
+/**************************************************************************
+  Mark the rectangular region as 'dirty' so that we know to flush it
+  later.
+**************************************************************************/
+void dirty_rect(int canvas_x, int canvas_y,
+               int pixel_width, int pixel_height)
+{
+  if (num_dirty_rects < MAX_DIRTY_RECTS) {
+    dirty_rects[num_dirty_rects].x = canvas_x;
+    dirty_rects[num_dirty_rects].y = canvas_y;
+    dirty_rects[num_dirty_rects].w = pixel_width;
+    dirty_rects[num_dirty_rects].h = pixel_height;
+    num_dirty_rects++;
+    queue_flush();
+  }
+}
+
+/**************************************************************************
+  Mark the entire screen area as "dirty" so that we can flush it later.
+**************************************************************************/
+void dirty_all(void)
+{
+  num_dirty_rects = MAX_DIRTY_RECTS;
+  queue_flush();
+}
+
+/**************************************************************************
+  Flush all regions that have been previously marked as dirty.  See
+  dirty_rect and dirty_all.  This function is generally called after we've
+  processed a batch of drawing operations.
+**************************************************************************/
+void flush_dirty(void)
+{
+  if (num_dirty_rects == MAX_DIRTY_RECTS) {
+    flush_mapcanvas(0, 0, map_win_width, map_win_height);
+  } else {
+    int i;
+
+    for (i = 0; i < num_dirty_rects; i++) {
+      flush_mapcanvas(dirty_rects[i].x, dirty_rects[i].y,
+                     dirty_rects[i].w, dirty_rects[i].h);
+    }
+  }
+  num_dirty_rects = 0;
+}
+
 /**************************************************************************
 
 **************************************************************************/
Index: client/gui-xaw/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/mapview.c,v
retrieving revision 1.129
diff -u -r1.129 mapview.c
--- client/gui-xaw/mapview.c    2003/03/01 21:03:56     1.129
+++ client/gui-xaw/mapview.c    2003/03/03 07:34:51
@@ -684,6 +684,83 @@
            canvas_x, canvas_y);
 }
 
+#define MAX_DIRTY_RECTS 20
+static int num_dirty_rects = 0;
+static XRectangle dirty_rects[MAX_DIRTY_RECTS];
+bool is_flush_queued = FALSE;
+
+/**************************************************************************
+  A callback invoked as a result of a 0-length timer, this function simply
+  flushes the mapview canvas.
+**************************************************************************/
+static void unqueue_flush(XtPointer client_data, XtIntervalId * id)
+{
+  flush_dirty();
+  is_flush_queued = FALSE;
+}
+
+/**************************************************************************
+  Called when a region is marked dirty, this function queues a flush event
+  to be handled later by Xaw.  The flush may end up being done
+  by freeciv before then, in which case it will be a wasted call.
+**************************************************************************/
+static void queue_flush(void)
+{
+  if (!is_flush_queued) {
+    (void) XtAppAddTimeOut(app_context, 0, unqueue_flush, NULL);
+    is_flush_queued = TRUE;
+  }
+}
+
+/**************************************************************************
+  Mark the rectangular region as 'dirty' so that we know to flush it
+  later.
+**************************************************************************/
+void dirty_rect(int canvas_x, int canvas_y,
+               int pixel_width, int pixel_height)
+{
+  if (num_dirty_rects < MAX_DIRTY_RECTS) {
+    dirty_rects[num_dirty_rects].x = canvas_x;
+    dirty_rects[num_dirty_rects].y = canvas_y;
+    dirty_rects[num_dirty_rects].width = pixel_width;
+    dirty_rects[num_dirty_rects].height = pixel_height;
+    num_dirty_rects++;
+    queue_flush();
+  }
+}
+
+/**************************************************************************
+  Mark the entire screen area as "dirty" so that we can flush it later.
+**************************************************************************/
+void dirty_all(void)
+{
+  num_dirty_rects = MAX_DIRTY_RECTS;
+  queue_flush();
+}
+
+/**************************************************************************
+  Flush all regions that have been previously marked as dirty.  See
+  dirty_rect and dirty_all.  This function is generally called after we've
+  processed a batch of drawing operations.
+**************************************************************************/
+void flush_dirty(void)
+{
+  if (num_dirty_rects == MAX_DIRTY_RECTS) {
+    Dimension width, height;
+
+    XtVaGetValues(map_canvas, XtNwidth, &width, XtNheight, &height, NULL);
+    flush_mapcanvas(0, 0, width, height);
+  } else {
+    int i;
+
+    for (i = 0; i < num_dirty_rects; i++) {
+      flush_mapcanvas(dirty_rects[i].x, dirty_rects[i].y,
+                     dirty_rects[i].width, dirty_rects[i].height);
+    }
+  }
+  num_dirty_rects = 0;
+}
+
 /**************************************************************************
 ...
 **************************************************************************/
Index: client/include/mapview_g.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/include/mapview_g.h,v
retrieving revision 1.35
diff -u -r1.35 mapview_g.h
--- client/include/mapview_g.h  2003/03/01 21:03:57     1.35
+++ client/include/mapview_g.h  2003/03/03 07:34:51
@@ -57,6 +57,10 @@
                  int start_x, int start_y, int dx, int dy);
 void flush_mapcanvas(int canvas_x, int canvas_y,
                     int pixel_width, int pixel_height);
+void dirty_rect(int canvas_x, int canvas_y,
+               int pixel_width, int pixel_height);
+void dirty_all(void);
+void flush_dirty(void);
 
 void update_map_canvas_scrollbars(void);
 

[Prev in Thread] Current Thread [Next in Thread]