Complete.Org: Mailing Lists: Archives: freeciv-dev: February 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, 27 Feb 2003 01:39:17 -0800
Reply-to: rt@xxxxxxxxxxxxxx

Raimar Falke wrote:
> On Wed, Feb 26, 2003 at 04:35:16AM -0800, Jason Short wrote:
> 
>>Raimar Falke wrote:

>From the GTK page above:
> 
> Example 2. Updating the GUI during a long computation
> 
>       /* computation going on */
> ...
>         while (gtk_events_pending())
>         gtk_main_iteration();
> ...
>       /* computation continued */
>  
> I don't want to outwit the library. Both libraries provide a way to go a
> layer deeper. With this extra control we can code a solution to the flush case
> which is 100% correct and quite simple.

The problem is it is not simple.  I've already given a specific example 
of how it can fail in a difficult-to-trace way.  The general problem is 
that this code should be kept localized, and should not depend on global 
changes done somewhere far away.

Note, this "general problem" was a problem for the original architecture 
as well.  When you call center_tile_mapcanvas you have to know to call 
flush_dirty afterwards.  Fortunately, we can do better.

>>One example is that gtk_main is re-entrant (although I doubt we use this 
>>feature).  If it were ever used, it would completely break the flush code.
> 
> It would also break win32, mui and sdl. We would have to find an alternative
> for these anyway.

Why would a change to gui-gtk ever break gui-win32?

>>In the worst case this could be done 
>>simply by adding a timeout with a timer of 0; gtk also supports this 
>>type of operation via gtk_idle_add().\
> 
> This is also possible.

Patch attached.

I've added this form of support for GTK, XAW, and Win32, while removing 
the flush_dirty calls from these GUIs.

It seems reasonable to take this a step further and do it the same way 
for gui-sdl.  I believe this can be done with SDL_AddTimer, but I'm not 
familiar enough with the code to write this.  If that were done then all 
GUIs (except MUI which just has stubs) would be supported, and we could 
remove all flush_dirty calls from the common code except for the 
animation ones.

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/02/27 09:37:03
@@ -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);
 }
 
 /**************************************************************************
@@ -368,6 +368,7 @@
   OUT:
     ;                          /* do nothing */
   }
+  flush_dirty();
 }
 
 /**************************************************************************
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/02/27 09:37:04
@@ -82,6 +82,7 @@
     hover_unit = 0;
   hover_state = state;
   exit_goto_state();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -110,7 +111,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,11 +125,12 @@
   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);
   update_menus();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -215,7 +217,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);
 
@@ -236,6 +238,8 @@
   if (auto_turn_done && punit_old_focus && !punit_focus && non_ai_unit_focus) {
     key_end_turn();
   }
+
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -916,6 +920,7 @@
 
   draw_map_grid^=1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -929,6 +934,7 @@
 
   draw_city_names ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
  
  /**************************************************************************
@@ -942,6 +948,7 @@
 
   draw_city_growth = !draw_city_growth;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -955,6 +962,7 @@
 
   draw_city_productions ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -968,6 +976,7 @@
 
   draw_terrain ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -981,6 +990,7 @@
 
   draw_coastline ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -994,6 +1004,7 @@
 
   draw_roads_rails ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1007,6 +1018,7 @@
 
   draw_irrigation ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1020,6 +1032,7 @@
 
   draw_mines ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1033,6 +1046,7 @@
 
   draw_fortress_airbase ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1046,6 +1060,7 @@
 
   draw_specials ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1059,6 +1074,7 @@
 
   draw_pollution ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1072,6 +1088,7 @@
 
   draw_cities ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1085,6 +1102,7 @@
 
   draw_units ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1098,6 +1116,7 @@
 
   draw_focus_unit ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1113,6 +1132,7 @@
   update_map_canvas_visible();
   refresh_overview_canvas();
   refresh_overview_viewrect();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1120,10 +1140,12 @@
 **************************************************************************/
 void request_center_focus_unit(void)
 {
-  struct unit *punit;
+  struct unit *punit = get_unit_in_focus();
   
-  if((punit=get_unit_in_focus()))
+  if (punit) {
     center_tile_mapcanvas(punit->x, punit->y);
+    flush_dirty();
+  }
 }
 
 /**************************************************************************
@@ -1170,7 +1192,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 +1206,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 +1225,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();
 }
@@ -1371,6 +1393,8 @@
 
     update_unit_info_label(punit);
   }
+
+  flush_dirty();
 }
 
 /**************************************************************************
Index: client/mapctrl_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapctrl_common.c,v
retrieving revision 1.5
diff -u -r1.5 mapctrl_common.c
--- client/mapctrl_common.c     2003/01/09 19:21:17     1.5
+++ client/mapctrl_common.c     2003/02/27 09:37:04
@@ -94,6 +94,7 @@
     get_line_dest(&old_x, &old_y);
     if (!same_pos(old_x, old_y, x, y)) {
       draw_line(x, y);
+      flush_dirty();
     }
   }
 }
Index: client/mapview_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.c,v
retrieving revision 1.33
diff -u -r1.33 mapview_common.c
--- client/mapview_common.c     2003/02/27 00:31:09     1.33
+++ client/mapview_common.c     2003/02/27 09:37:05
@@ -45,7 +45,7 @@
   if (tile_visible_mapcanvas(x, y)) {
     update_map_canvas(x, y, 1, 1, FALSE);
 
-    if (write_to_screen && (draw_city_names || draw_city_productions)) {
+    if (draw_city_names || draw_city_productions) {
       /* FIXME: update_map_canvas() will overwrite the city descriptions.
        * This is a workaround that redraws the city descriptions (most of
        * the time).  Although it seems inefficient to redraw the
@@ -91,12 +91,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);
@@ -628,6 +623,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);
@@ -702,31 +699,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;
@@ -741,18 +732,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();
   }
 }
 
@@ -769,6 +762,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. */
@@ -783,8 +778,6 @@
   }
 
   show_city_descriptions();
-
-  flush_mapcanvas(0, 0, map_win_width, map_win_height);
 }
 
 /**************************************************************************
@@ -864,10 +857,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) {
@@ -876,12 +869,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);
       }
     }
   }
@@ -913,6 +906,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))) {
@@ -1117,6 +1112,8 @@
     update_city_descriptions();
   }
   needed_updates = UPDATE_NONE;
+
+  flush_dirty();
 }
 
 /**************************************************************************
Index: client/messagewin_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/messagewin_common.c,v
retrieving revision 1.11
diff -u -r1.11 messagewin_common.c
--- client/messagewin_common.c  2003/02/19 23:46:16     1.11
+++ client/messagewin_common.c  2003/02/27 09:37:06
@@ -209,6 +209,10 @@
        * highlighted at all - this is left up to the GUI. */
       popup_city_dialog(pcity, FALSE);
     }
+    
+    if (center_when_popup_city || pcity) {
+      flush_dirty();
+    }
   }
 }
 
@@ -222,6 +226,7 @@
   if (messages[message_index].location_ok) {
     center_tile_mapcanvas(messages[message_index].x,
                          messages[message_index].y);
+    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/02/27 09:37:08
@@ -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/tilespec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v
retrieving revision 1.110
diff -u -r1.110 tilespec.c
--- client/tilespec.c   2003/02/05 07:19:43     1.110
+++ client/tilespec.c   2003/02/27 09:37:10
@@ -361,6 +361,7 @@
   }
   tileset_changed();
   center_tile_mapcanvas(center_x, center_y);
+  flush_dirty();
 }
 
 /**************************************************************************
Index: client/gui-gtk/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/mapview.c,v
retrieving revision 1.161
diff -u -r1.161 mapview.c
--- client/gui-gtk/mapview.c    2003/02/27 00:31:10     1.161
+++ client/gui-gtk/mapview.c    2003/02/27 09:37:12
@@ -790,6 +790,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.49
diff -u -r1.49 mapview.c
--- client/gui-gtk-2.0/mapview.c        2003/02/27 00:31:10     1.49
+++ client/gui-gtk-2.0/mapview.c        2003/02/27 09:37:13
@@ -827,6 +827,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/cityrep.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-mui/cityrep.c,v
retrieving revision 1.26
diff -u -r1.26 cityrep.c
--- client/gui-mui/cityrep.c    2003/02/15 20:26:17     1.26
+++ client/gui-mui/cityrep.c    2003/02/27 09:37:14
@@ -181,6 +181,7 @@
   if (pcity)
   {
     center_tile_mapcanvas(pcity->x, pcity->y);
+    flush_dirty();
   }
 }
 
@@ -197,6 +198,7 @@
   {
     if (center_when_popup_city) {
       center_tile_mapcanvas(pcity->x, pcity->y);
+      flush_dirty();
     }
     popup_city_dialog(pcity, 0);
   }
Index: client/gui-mui/dialogs.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-mui/dialogs.c,v
retrieving revision 1.49
diff -u -r1.49 dialogs.c
--- client/gui-mui/dialogs.c    2003/02/12 22:49:51     1.49
+++ client/gui-mui/dialogs.c    2003/02/27 09:37:15
@@ -161,6 +161,7 @@
   center_tile_mapcanvas(obj->x, obj->y);
   set(obj->pwnd, MUIA_Window_Open, FALSE);
   DoMethod(app, MUIM_Application_PushMethod, app, 4, MUIM_CallHook, 
&civstandard_hook, notify_close_real, obj->pwnd);
+  flush_dirty();
 }
 
 /****************************************************************
Index: client/gui-mui/finddlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-mui/finddlg.c,v
retrieving revision 1.7
diff -u -r1.7 finddlg.c
--- client/gui-mui/finddlg.c    2002/11/14 09:14:56     1.7
+++ client/gui-mui/finddlg.c    2003/02/27 09:37:15
@@ -77,8 +77,10 @@
 
     set(find_wnd, MUIA_Window_Open, FALSE);
 
-    if ((pcity = game_find_city_by_name(string)))
+    if ((pcity = game_find_city_by_name(string))) {
       center_tile_mapcanvas(pcity->x, pcity->y);
+      flush_dirty();
+    }
   }
 }
 
Index: client/gui-mui/gotodlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-mui/gotodlg.c,v
retrieving revision 1.12
diff -u -r1.12 gotodlg.c
--- client/gui-mui/gotodlg.c    2002/11/14 09:14:56     1.12
+++ client/gui-mui/gotodlg.c    2003/02/27 09:37:15
@@ -76,6 +76,7 @@
 // remove me
 #if DISABLED
     center_tile_mapcanvas(pdestcity->x, pdestcity->y);
+    flush_dirty();
 #endif
     if (punit && unit_can_airlift_to(punit, pcity))
     {
Index: client/gui-mui/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-mui/mapview.c,v
retrieving revision 1.58
diff -u -r1.58 mapview.c
--- client/gui-mui/mapview.c    2003/02/04 23:12:31     1.58
+++ client/gui-mui/mapview.c    2003/02/27 09:37:15
@@ -462,6 +462,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-stub/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-stub/mapview.c,v
retrieving revision 1.29
diff -u -r1.29 mapview.c
--- client/gui-stub/mapview.c   2003/02/27 00:31:10     1.29
+++ client/gui-stub/mapview.c   2003/02/27 09:37:16
@@ -245,6 +245,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.61
diff -u -r1.61 mapview.c
--- client/gui-win32/mapview.c  2003/02/27 00:31:10     1.61
+++ client/gui-win32/mapview.c  2003/02/27 09:37:17
@@ -537,6 +537,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.128
diff -u -r1.128 mapview.c
--- client/gui-xaw/mapview.c    2003/02/27 00:31:11     1.128
+++ client/gui-xaw/mapview.c    2003/02/27 09:37:18
@@ -701,6 +701,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.34
diff -u -r1.34 mapview_g.h
--- client/include/mapview_g.h  2003/02/27 00:31:11     1.34
+++ client/include/mapview_g.h  2003/02/27 09:37:18
@@ -59,6 +59,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]