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

[Freeciv-Dev] Re: (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] Re: (PR#3424) New flush code
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Thu, 6 Mar 2003 03:19:20 -0800
Reply-to: rt@xxxxxxxxxxxxxx

Raimar Falke wrote:
> On Tue, Mar 04, 2003 at 07:26:30PM -0800, Jason Short wrote:
> 
>>Raimar Falke wrote:
>>
>>>On Sun, Mar 02, 2003 at 11:49:05PM -0800, Jason Short wrote:
>>
>>>>+static void queue_flush(void)
>>>>+{
>>>>+  if (!is_flush_queued) {
>>>>+    if (SDL_PushEvent(&flush_user_event) == 0) {
>>>>+      is_flush_queued = TRUE;
>>>>+    }
>>>
>>>
>>>>+    /* Else nothing... */
>>>
>>>
>>>Here have lost a flush call. Bad.
>>
>>This should be sufficiently rare that it's not *that* bad.  I don't 
>>really see a way around it.
> 
> 
> We can at least write "You stomped about an SDL limitation please
> report to freeciv-dev@..." This way we can get an grip how common this
> is.

Done.  I've also updated it to some other CVS changes.

> What about a new doc/README.mapview? It will talk about the layers,
> where animation, grid and goto lines are drawn, what buffers exists
> and so on. I think that you have already written this. You can recycle
> one of your mails for this.

I will (hopefully) provide a doc/README.drawing as a separate patch.

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/06 11:12:07
@@ -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/06 11:12:08
@@ -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.36
diff -u -r1.36 mapview_common.c
--- client/mapview_common.c     2003/03/06 09:35:11     1.36
+++ client/mapview_common.c     2003/03/06 11:12:08
@@ -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);
@@ -610,6 +605,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);
@@ -684,31 +681,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;
-
-      /* 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);
-    }
+    /* 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 - 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;
@@ -723,18 +714,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();
   }
 }
 
@@ -743,6 +736,8 @@
 **************************************************************************/
 void update_map_canvas_visible(void)
 {
+  dirty_all();
+
   if (is_isometric) {
     /* just find a big rectangle that includes the whole visible area. The
        invisible tiles will not be drawn. */
@@ -759,8 +754,6 @@
   }
 
   show_city_descriptions();
-
-  flush_mapcanvas(0, 0, mapview_canvas.width, mapview_canvas.height);
 }
 
 /**************************************************************************
@@ -833,10 +826,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) {
@@ -845,12 +838,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);
       }
     }
   }
@@ -882,6 +875,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))) {
@@ -1086,6 +1081,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.294
diff -u -r1.294 packhand.c
--- client/packhand.c   2003/03/06 09:11:18     1.294
+++ client/packhand.c   2003/03/06 11:12:10
@@ -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(); 
@@ -1705,14 +1707,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;
@@ -1723,7 +1725,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.163
diff -u -r1.163 mapview.c
--- client/gui-gtk/mapview.c    2003/03/06 09:35:11     1.163
+++ client/gui-gtk/mapview.c    2003/03/06 11:12:11
@@ -756,6 +756,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.51
diff -u -r1.51 mapview.c
--- client/gui-gtk-2.0/mapview.c        2003/03/06 09:35:11     1.51
+++ client/gui-gtk-2.0/mapview.c        2003/03/06 11:12:11
@@ -794,6 +794,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.60
diff -u -r1.60 mapview.c
--- client/gui-mui/mapview.c    2003/03/06 09:35:11     1.60
+++ client/gui-mui/mapview.c    2003/03/06 11:12:12
@@ -427,6 +427,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/06 11:12:12
@@ -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/06 11:12:12
@@ -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.36
diff -u -r1.36 mapview.c
--- client/gui-sdl/mapview.c    2003/03/06 09:35:11     1.36
+++ client/gui-sdl/mapview.c    2003/03/06 11:12:13
@@ -224,6 +224,40 @@
   }
 }
 
+static bool is_flush_queued = FALSE;
+
+/**************************************************************************
+  A callback invoked as a result of a FLUSH event, 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 SDL.  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 {
+      /* We don't want to set is_flush_queued in this case, since then
+       * the flush code would simply stop working.  But this means the
+       * below message may be repeated many times. */
+      freelog(LOG_ERROR,
+             _("The SDL event buffer is full; you may see drawing errors\n"
+               "as a result.  If you see this message often, please\n"
+               "report it to freeciv-dev@xxxxxxxxxxx."));
+    }
+  }
+}
+
 /**************************************************************************
   Save Flush area used by "end" flush.
 **************************************************************************/
@@ -233,6 +267,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();
   }
 }
 
@@ -243,6 +278,7 @@
 {
   if ((Main.rects_count < RECT_LIMIT) && correct_rect_region(&Rect)) {
     Main.rects[Main.rects_count++] = Rect;
+    queue_flush();
   }
 }
 
@@ -252,6 +288,7 @@
 void dirty_all(void)
 {
   Main.rects_count = RECT_LIMIT;
+  queue_flush();
 }
 
 /**************************************************************************
@@ -269,7 +306,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/06 11:12:13
@@ -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.31
diff -u -r1.31 mapview.c
--- client/gui-stub/mapview.c   2003/03/06 09:35:11     1.31
+++ client/gui-stub/mapview.c   2003/03/06 11:12:13
@@ -206,6 +206,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.63
diff -u -r1.63 mapview.c
--- client/gui-win32/mapview.c  2003/03/06 09:35:11     1.63
+++ client/gui-win32/mapview.c  2003/03/06 11:12:14
@@ -507,6 +507,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.130
diff -u -r1.130 mapview.c
--- client/gui-xaw/mapview.c    2003/03/06 09:35:11     1.130
+++ client/gui-xaw/mapview.c    2003/03/06 11:12:15
@@ -665,6 +665,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.36
diff -u -r1.36 mapview_g.h
--- client/include/mapview_g.h  2003/03/06 09:35:12     1.36
+++ client/include/mapview_g.h  2003/03/06 11:12:15
@@ -52,6 +52,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]