1 /***********************************************************************
2  Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 ***********************************************************************/
13 
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17 
18 /* utility */
19 #include "log.h"
20 #include "support.h"            /* bool */
21 
22 /* common */
23 #include "city.h"
24 #include "connection.h"
25 #include "player.h"
26 
27 /* client/include */
28 #include "canvas_g.h"
29 #include "citydlg_g.h"
30 #include "cityrep_g.h"
31 #include "dialogs_g.h"
32 #include "gui_main_g.h"
33 #include "menu_g.h"
34 #include "pages_g.h"
35 #include "plrdlg_g.h"
36 #include "ratesdlg_g.h"
37 #include "repodlgs_g.h"
38 
39 /* client */
40 #include "client_main.h"
41 #include "connectdlg_common.h"
42 #include "options.h"
43 #include "tilespec.h"
44 #include "zoom.h"
45 
46 #include "update_queue.h"
47 
48 
49 /* Data type in 'update_queue'. */
50 struct update_queue_data {
51   void *data;
52   uq_free_fn_t free_data_func;
53 };
54 
55 static void update_queue_data_destroy(struct update_queue_data *pdata);
56 
57 /* 'struct update_queue_hash' and related functions. */
58 #define SPECHASH_TAG update_queue
59 #define SPECHASH_IKEY_TYPE uq_callback_t
60 #define SPECHASH_IDATA_TYPE struct update_queue_data *
61 #define SPECHASH_IDATA_FREE update_queue_data_destroy
62 #include "spechash.h"
63 #define update_queue_hash_iterate(hash, callback, uq_data)                  \
64   TYPED_HASH_ITERATE(uq_callback_t, const struct update_queue_data *,       \
65                      hash, callback, uq_data)
66 #define update_queue_hash_iterate_end HASH_ITERATE_END
67 
68 /* Type of data listed in 'processing_started_waiting_queue' and
69  * 'processing_finished_waiting_queue'. Real type is
70  * 'struct waiting_queue_list'. */
71 struct waiting_queue_data {
72   uq_callback_t callback;
73   struct update_queue_data *uq_data;
74 };
75 
76 /* 'struct waiting_queue_list' and related functions. */
77 #define SPECLIST_TAG waiting_queue
78 #define SPECLIST_TYPE struct waiting_queue_data
79 #include "speclist.h"
80 #define waiting_queue_list_iterate(list, data)                              \
81   TYPED_LIST_ITERATE(struct waiting_queue_data, list, data)
82 #define waiting_queue_list_iterate_end LIST_ITERATE_END
83 
84 /* 'struct waiting_queue_hash' and related functions. */
85 #define SPECHASH_TAG waiting_queue
86 #define SPECHASH_INT_KEY_TYPE
87 #define SPECHASH_IDATA_TYPE struct waiting_queue_list *
88 #define SPECHASH_IDATA_FREE waiting_queue_list_destroy
89 #include "spechash.h"
90 
91 static struct update_queue_hash *update_queue = NULL;
92 static struct waiting_queue_hash *processing_started_waiting_queue = NULL;
93 static struct waiting_queue_hash *processing_finished_waiting_queue = NULL;
94 static int update_queue_frozen_level = 0;
95 static bool update_queue_has_idle_callback = FALSE;
96 
97 static void update_unqueue(void *data);
98 static inline void update_queue_push(uq_callback_t callback,
99                                      struct update_queue_data *uq_data);
100 
101 /****************************************************************************
102   Create a new update queue data.
103 ****************************************************************************/
104 static inline struct update_queue_data *
update_queue_data_new(void * data,uq_free_fn_t free_data_func)105 update_queue_data_new(void *data, uq_free_fn_t free_data_func)
106 {
107   struct update_queue_data *uq_data = fc_malloc(sizeof(*uq_data));
108 
109   uq_data->data = data;
110   uq_data->free_data_func = free_data_func;
111   return uq_data;
112 }
113 
114 /****************************************************************************
115   Free a update queue data.
116 ****************************************************************************/
update_queue_data_destroy(struct update_queue_data * uq_data)117 static void update_queue_data_destroy(struct update_queue_data *uq_data)
118 {
119   fc_assert_ret(NULL != uq_data);
120   if (NULL != uq_data->free_data_func) {
121     uq_data->free_data_func(uq_data->data);
122   }
123   free(uq_data);
124 }
125 
126 /****************************************************************************
127   Create a new waiting queue data.
128 ****************************************************************************/
129 static inline struct waiting_queue_data *
waiting_queue_data_new(uq_callback_t callback,void * data,uq_free_fn_t free_data_func)130 waiting_queue_data_new(uq_callback_t callback, void *data,
131                        uq_free_fn_t free_data_func)
132 {
133   struct waiting_queue_data *wq_data = fc_malloc(sizeof(*wq_data));
134 
135   wq_data->callback = callback;
136   wq_data->uq_data = update_queue_data_new(data, free_data_func);
137   return wq_data;
138 }
139 
140 /****************************************************************************
141   Free a waiting queue data.
142 ****************************************************************************/
waiting_queue_data_destroy(struct waiting_queue_data * wq_data)143 static void waiting_queue_data_destroy(struct waiting_queue_data *wq_data)
144 {
145   fc_assert_ret(NULL != wq_data);
146   if (NULL != wq_data->uq_data) {
147     /* May be NULL, see waiting_queue_data_extract(). */
148     update_queue_data_destroy(wq_data->uq_data);
149   }
150   free(wq_data);
151 }
152 
153 /****************************************************************************
154   Extract the update_queue_data from the waiting queue data.
155 ****************************************************************************/
156 static inline struct update_queue_data *
waiting_queue_data_extract(struct waiting_queue_data * wq_data)157 waiting_queue_data_extract(struct waiting_queue_data *wq_data)
158 {
159   struct update_queue_data *uq_data = wq_data->uq_data;
160 
161   wq_data->uq_data = NULL;
162   return uq_data;
163 }
164 
165 
166 /****************************************************************************
167   Initialize the update queue.
168 ****************************************************************************/
update_queue_init(void)169 void update_queue_init(void)
170 {
171   if (NULL !=  update_queue) {
172     /* Already initialized. */
173     fc_assert(NULL != processing_started_waiting_queue);
174     fc_assert(NULL != processing_finished_waiting_queue);
175     return;
176   }
177   fc_assert(NULL == processing_started_waiting_queue);
178   fc_assert(NULL == processing_finished_waiting_queue);
179 
180   update_queue = update_queue_hash_new();
181   processing_started_waiting_queue = waiting_queue_hash_new();
182   processing_finished_waiting_queue = waiting_queue_hash_new();
183   update_queue_frozen_level = 0;
184   update_queue_has_idle_callback = FALSE;
185 }
186 
187 /****************************************************************************
188   Free the update queue.
189 ****************************************************************************/
update_queue_free(void)190 void update_queue_free(void)
191 {
192   fc_assert(NULL != update_queue);
193   fc_assert(NULL != processing_started_waiting_queue);
194   fc_assert(NULL != processing_finished_waiting_queue);
195 
196   if (NULL != update_queue) {
197     update_queue_hash_destroy(update_queue);
198     update_queue = NULL;
199   }
200   if (NULL != processing_started_waiting_queue) {
201     waiting_queue_hash_destroy(processing_started_waiting_queue);
202     processing_started_waiting_queue = NULL;
203   }
204   if (NULL != processing_finished_waiting_queue) {
205     waiting_queue_hash_destroy(processing_finished_waiting_queue);
206     processing_finished_waiting_queue = NULL;
207   }
208 
209   update_queue_frozen_level = 0;
210   update_queue_has_idle_callback = FALSE;
211 }
212 
213 /****************************************************************************
214   Freezes the update queue.
215 ****************************************************************************/
update_queue_freeze(void)216 void update_queue_freeze(void)
217 {
218   update_queue_frozen_level++;
219 }
220 
221 /****************************************************************************
222   Free the update queue.
223 ****************************************************************************/
update_queue_thaw(void)224 void update_queue_thaw(void)
225 {
226   update_queue_frozen_level--;
227   if (0 == update_queue_frozen_level
228       && !update_queue_has_idle_callback
229       && NULL != update_queue
230       && 0 < update_queue_hash_size(update_queue)) {
231     update_queue_has_idle_callback = TRUE;
232     add_idle_callback(update_unqueue, NULL);
233   } else if (0 > update_queue_frozen_level) {
234     log_error("update_queue_frozen_level < 0, repairing...");
235     update_queue_frozen_level = 0;
236   }
237 }
238 
239 /****************************************************************************
240   Free the update queue.
241 ****************************************************************************/
update_queue_force_thaw(void)242 void update_queue_force_thaw(void)
243 {
244   while (update_queue_is_frozen()) {
245     update_queue_thaw();
246   }
247 }
248 
249 /****************************************************************************
250   Free the update queue.
251 ****************************************************************************/
update_queue_is_frozen(void)252 bool update_queue_is_frozen(void)
253 {
254   return (0 < update_queue_frozen_level);
255 }
256 
257 /****************************************************************************
258   Moves the instances waiting to the request_id to the callback queue.
259 ****************************************************************************/
260 static inline void
waiting_queue_execute_pending_requests(struct waiting_queue_hash * hash,int request_id)261 waiting_queue_execute_pending_requests(struct waiting_queue_hash *hash,
262                                        int request_id)
263 {
264   struct waiting_queue_list *list;
265 
266   if (NULL == hash || !waiting_queue_hash_lookup(hash, request_id, &list)) {
267     return;
268   }
269 
270   waiting_queue_list_iterate(list, wq_data) {
271     update_queue_push(wq_data->callback, waiting_queue_data_extract(wq_data));
272   } waiting_queue_list_iterate_end;
273   waiting_queue_hash_remove(hash, request_id);
274 }
275 
276 /****************************************************************************
277   Moves the instances waiting to the request_id to the callback queue.
278 ****************************************************************************/
update_queue_processing_started(int request_id)279 void update_queue_processing_started(int request_id)
280 {
281   waiting_queue_execute_pending_requests(processing_started_waiting_queue,
282                                          request_id);
283 }
284 
285 /****************************************************************************
286   Moves the instances waiting to the request_id to the callback queue.
287 ****************************************************************************/
update_queue_processing_finished(int request_id)288 void update_queue_processing_finished(int request_id)
289 {
290   waiting_queue_execute_pending_requests(processing_finished_waiting_queue,
291                                          request_id);
292 }
293 
294 /****************************************************************************
295   Unqueue all updates.
296 ****************************************************************************/
update_unqueue(void * data)297 static void update_unqueue(void *data)
298 {
299   struct update_queue_hash *hash;
300 
301   if (NULL == update_queue) {
302     update_queue_has_idle_callback = FALSE;
303     return;
304   }
305 
306   if (update_queue_is_frozen() || !tileset_is_fully_loaded()) {
307     /* Cannot update now, let's add it again. */
308     update_queue_has_idle_callback = FALSE;
309     return;
310   }
311 
312   /* Replace the old list, don't do recursive stuff, and don't write in the
313    * hash table when we are reading it. */
314   hash = update_queue;
315   update_queue = update_queue_hash_new();
316   update_queue_has_idle_callback = FALSE;
317 
318   /* Invoke callbacks. */
319   update_queue_hash_iterate(hash, callback, uq_data) {
320     callback(uq_data->data);
321   } update_queue_hash_iterate_end;
322   update_queue_hash_destroy(hash);
323 }
324 
325 /****************************************************************************
326   Add a callback to the update queue. NB: you can only set a callback
327   once. Setting a callback twice will overwrite the previous.
328 ****************************************************************************/
update_queue_push(uq_callback_t callback,struct update_queue_data * uq_data)329 static inline void update_queue_push(uq_callback_t callback,
330                                      struct update_queue_data *uq_data)
331 {
332   update_queue_hash_replace(update_queue, callback, uq_data);
333 
334   if (!update_queue_has_idle_callback
335       && !update_queue_is_frozen()) {
336     update_queue_has_idle_callback = TRUE;
337     add_idle_callback(update_unqueue, NULL);
338   }
339 }
340 
341 /****************************************************************************
342   Add a callback to the update queue. NB: you can only set a callback
343   once. Setting a callback twice will overwrite the previous.
344 ****************************************************************************/
update_queue_add(uq_callback_t callback,void * data)345 void update_queue_add(uq_callback_t callback, void *data)
346 {
347   if (NULL != update_queue) {
348     update_queue_push(callback, update_queue_data_new(data, NULL));
349   }
350 }
351 
352 /****************************************************************************
353   Add a callback to the update queue. NB: you can only set a callback
354   once. Setting a callback twice will overwrite the previous.
355 ****************************************************************************/
update_queue_add_full(uq_callback_t callback,void * data,uq_free_fn_t free_data_func)356 void update_queue_add_full(uq_callback_t callback, void *data,
357                            uq_free_fn_t free_data_func)
358 {
359   if (NULL != update_queue) {
360     update_queue_push(callback, update_queue_data_new(data, free_data_func));
361   }
362 }
363 
364 /****************************************************************************
365   Returns whether this callback is listed in the update queue.
366 ****************************************************************************/
update_queue_has_callback(uq_callback_t callback)367 bool update_queue_has_callback(uq_callback_t callback)
368 {
369   return (NULL != update_queue
370           && update_queue_hash_lookup(update_queue, callback, NULL));
371 }
372 
373 /****************************************************************************
374   Returns whether this callback is listed in the update queue and
375   get the its data and free function. 'data' and 'free_data_func' can
376   be NULL.
377 ****************************************************************************/
update_queue_has_callback_full(uq_callback_t callback,const void ** data,uq_free_fn_t * free_data_func)378 bool update_queue_has_callback_full(uq_callback_t callback,
379                                     const void **data,
380                                     uq_free_fn_t *free_data_func)
381 {
382   if (NULL != update_queue) {
383     struct update_queue_data *uq_data;
384 
385     if (update_queue_hash_lookup(update_queue, callback, &uq_data)) {
386       if (NULL != data) {
387         *data = uq_data->data;
388       }
389       if (NULL != free_data_func) {
390         *free_data_func = uq_data->free_data_func;
391       }
392       return TRUE;
393     }
394   }
395   return FALSE;
396 }
397 
398 /****************************************************************************
399   Connects the callback to a network event.
400 ****************************************************************************/
401 static inline void
waiting_queue_add_pending_request(struct waiting_queue_hash * hash,int request_id,uq_callback_t callback,void * data,uq_free_fn_t free_data_func)402 waiting_queue_add_pending_request(struct waiting_queue_hash *hash,
403                                   int request_id, uq_callback_t callback,
404                                   void *data, uq_free_fn_t free_data_func)
405 {
406   if (NULL != hash) {
407     struct waiting_queue_list *list;
408 
409     if (!waiting_queue_hash_lookup(hash, request_id, &list)) {
410       /* The list doesn't exist yet for that request, create it. */
411       list = waiting_queue_list_new_full(waiting_queue_data_destroy);
412       waiting_queue_hash_insert(hash, request_id, list);
413     }
414     waiting_queue_list_append(list, waiting_queue_data_new(callback, data,
415                                                            free_data_func));
416   }
417 }
418 
419 /****************************************************************************
420   Connects the callback to the start of the processing (in server side) of
421   the request.
422 ****************************************************************************/
update_queue_connect_processing_started(int request_id,uq_callback_t callback,void * data)423 void update_queue_connect_processing_started(int request_id,
424                                              uq_callback_t callback,
425                                              void *data)
426 {
427   waiting_queue_add_pending_request(processing_started_waiting_queue,
428                                     request_id, callback, data, NULL);
429 }
430 
431 /****************************************************************************
432   Connects the callback to the start of the processing (in server side) of
433   the request.
434 ****************************************************************************/
update_queue_connect_processing_started_full(int request_id,uq_callback_t callback,void * data,uq_free_fn_t free_data_func)435 void update_queue_connect_processing_started_full(int request_id,
436                                                   uq_callback_t callback,
437                                                   void *data,
438                                                   uq_free_fn_t
439                                                   free_data_func)
440 {
441   waiting_queue_add_pending_request(processing_started_waiting_queue,
442                                     request_id, callback, data,
443                                     free_data_func);
444 }
445 
446 /****************************************************************************
447   Connects the callback to the end of the processing (in server side) of
448   the request.
449 ****************************************************************************/
update_queue_connect_processing_finished(int request_id,uq_callback_t callback,void * data)450 void update_queue_connect_processing_finished(int request_id,
451                                               uq_callback_t callback,
452                                               void *data)
453 {
454   waiting_queue_add_pending_request(processing_finished_waiting_queue,
455                                     request_id, callback, data, NULL);
456 }
457 
458 /****************************************************************************
459   Connects the callback to the end of the processing (in server side) of
460   the request.
461 ****************************************************************************/
update_queue_connect_processing_finished_full(int request_id,uq_callback_t callback,void * data,uq_free_fn_t free_data_func)462 void update_queue_connect_processing_finished_full(int request_id,
463                                                    uq_callback_t callback,
464                                                    void *data,
465                                                    uq_free_fn_t
466                                                    free_data_func)
467 {
468   waiting_queue_add_pending_request(processing_finished_waiting_queue,
469                                     request_id, callback, data,
470                                     free_data_func);
471 }
472 
473 
474 /****************************************************************************
475   Set the client page.
476 ****************************************************************************/
set_client_page_callback(void * data)477 static void set_client_page_callback(void *data)
478 {
479   enum client_pages page = FC_PTR_TO_INT(data);
480 
481   real_set_client_page(page);
482 
483   if (page == PAGE_GAME) {
484     if (has_zoom_support()) {
485       if (gui_options.zoom_set) {
486         zoom_set(gui_options.zoom_default_level);
487       } else {
488         zoom_1_0();
489       }
490     }
491   }
492 }
493 
494 /****************************************************************************
495   Set the client page.
496 ****************************************************************************/
set_client_page(enum client_pages page)497 void set_client_page(enum client_pages page)
498 {
499   log_debug("Requested page: %s.", client_pages_name(page));
500 
501   update_queue_add(set_client_page_callback, FC_INT_TO_PTR(page));
502 }
503 
504 /****************************************************************************
505   Start server and then, set the client page.
506 ****************************************************************************/
client_start_server_and_set_page(enum client_pages page)507 void client_start_server_and_set_page(enum client_pages page)
508 {
509   log_debug("Requested server start + page: %s.", client_pages_name(page));
510 
511   if (client_start_server()) {
512     update_queue_connect_processing_finished(client.conn.client.last_request_id_used,
513                                              set_client_page_callback,
514                                              FC_INT_TO_PTR(page));
515   }
516 }
517 
518 /****************************************************************************
519   Returns the next client page.
520 ****************************************************************************/
get_client_page(void)521 enum client_pages get_client_page(void)
522 {
523   const void *data;
524 
525   if (update_queue_has_callback_full(set_client_page_callback,
526                                      &data, NULL)) {
527     return FC_PTR_TO_INT(data);
528   } else {
529     return get_current_client_page();
530   }
531 }
532 
533 /****************************************************************************
534   Returns whether there's page switching already in progress.
535 ****************************************************************************/
update_queue_is_switching_page(void)536 bool update_queue_is_switching_page(void)
537 {
538   return update_queue_has_callback(set_client_page_callback);
539 }
540 
541 /****************************************************************************
542   Update the menus.
543 ****************************************************************************/
menus_update_callback(void * data)544 static void menus_update_callback(void *data)
545 {
546   if (FC_PTR_TO_INT(data)) {
547     real_menus_init();
548   }
549   real_menus_update();
550 }
551 
552 /****************************************************************************
553   Request the menus to be initialized and updated.
554 ****************************************************************************/
menus_init(void)555 void menus_init(void)
556 {
557   update_queue_add(menus_update_callback, FC_INT_TO_PTR(TRUE));
558 }
559 
560 /****************************************************************************
561   Request the menus to be updated.
562 ****************************************************************************/
menus_update(void)563 void menus_update(void)
564 {
565   if (!update_queue_has_callback(menus_update_callback)) {
566     update_queue_add(menus_update_callback, FC_INT_TO_PTR(FALSE));
567   }
568 }
569 
570 /****************************************************************************
571   Update multipliers/policy dialog.
572 ****************************************************************************/
multipliers_dialog_update(void)573 void multipliers_dialog_update(void)
574 {
575   update_queue_add(real_multipliers_dialog_update, NULL);
576 }
577 
578 /****************************************************************************
579   Update cities gui.
580 ****************************************************************************/
cities_update_callback(void * data)581 static void cities_update_callback(void *data)
582 {
583 #ifdef FREECIV_DEBUG
584 #define NEED_UPDATE(city_update, action)                                    \
585   if (city_update & need_update) {                                          \
586     action;                                                                 \
587     need_update &= ~city_update;                                            \
588   }
589 #else  /* FREECIV_DEBUG */
590 #define NEED_UPDATE(city_update, action)                                    \
591   if (city_update & need_update) {                                          \
592     action;                                                                 \
593   }
594 #endif /* FREECIV_DEBUG */
595 
596   cities_iterate(pcity) {
597     enum city_updates need_update = pcity->client.need_updates;
598 
599     if (CU_NO_UPDATE == need_update) {
600       continue;
601     }
602 
603     /* Clear all updates. */
604     pcity->client.need_updates = CU_NO_UPDATE;
605 
606     NEED_UPDATE(CU_UPDATE_REPORT, real_city_report_update_city(pcity));
607     NEED_UPDATE(CU_UPDATE_DIALOG, real_city_dialog_refresh(pcity));
608     NEED_UPDATE(CU_POPUP_DIALOG, real_city_dialog_popup(pcity));
609 
610 #ifdef FREECIV_DEBUG
611     if (CU_NO_UPDATE != need_update) {
612       log_error("Some city updates not handled "
613                 "for city %s (id %d): %d left.",
614                 city_name_get(pcity), pcity->id, need_update);
615     }
616 #endif /* FREECIV_DEBUG */
617   } cities_iterate_end;
618 #undef NEED_UPDATE
619 }
620 
621 /****************************************************************************
622   Request the city dialog to be popped up for the city.
623 ****************************************************************************/
popup_city_dialog(struct city * pcity)624 void popup_city_dialog(struct city *pcity)
625 {
626   pcity->client.need_updates |= CU_POPUP_DIALOG;
627   update_queue_add(cities_update_callback, NULL);
628 }
629 
630 /****************************************************************************
631   Request the city dialog to be updated for the city.
632 ****************************************************************************/
refresh_city_dialog(struct city * pcity)633 void refresh_city_dialog(struct city *pcity)
634 {
635   pcity->client.need_updates |= CU_UPDATE_DIALOG;
636   update_queue_add(cities_update_callback, NULL);
637 }
638 
639 /****************************************************************************
640   Request the city to be updated in the city report.
641 ****************************************************************************/
city_report_dialog_update_city(struct city * pcity)642 void city_report_dialog_update_city(struct city *pcity)
643 {
644   pcity->client.need_updates |= CU_UPDATE_REPORT;
645   update_queue_add(cities_update_callback, NULL);
646 }
647 
648 
649 /****************************************************************************
650   Update the connection list in the start page.
651 ****************************************************************************/
conn_list_dialog_update(void)652 void conn_list_dialog_update(void)
653 {
654   update_queue_add(real_conn_list_dialog_update, NULL);
655 }
656 
657 
658 /****************************************************************************
659   Update the nation report.
660 ****************************************************************************/
players_dialog_update(void)661 void players_dialog_update(void)
662 {
663   update_queue_add(real_players_dialog_update, NULL);
664 }
665 
666 /****************************************************************************
667   Update the city report.
668 ****************************************************************************/
city_report_dialog_update(void)669 void city_report_dialog_update(void)
670 {
671   update_queue_add(real_city_report_dialog_update, NULL);
672 }
673 
674 /****************************************************************************
675   Update the science report.
676 ****************************************************************************/
science_report_dialog_update(void)677 void science_report_dialog_update(void)
678 {
679   update_queue_add(real_science_report_dialog_update, NULL);
680 }
681 
682 /****************************************************************************
683   Update the economy report.
684 ****************************************************************************/
economy_report_dialog_update(void)685 void economy_report_dialog_update(void)
686 {
687   update_queue_add(real_economy_report_dialog_update, NULL);
688 }
689 
690 /****************************************************************************
691   Update the units report.
692 ****************************************************************************/
units_report_dialog_update(void)693 void units_report_dialog_update(void)
694 {
695   update_queue_add(real_units_report_dialog_update, NULL);
696 }
697 
698 /****************************************************************************
699   Update the units report.
700 ****************************************************************************/
unit_select_dialog_update(void)701 void unit_select_dialog_update(void)
702 {
703   update_queue_add(unit_select_dialog_update_real, NULL);
704 }
705