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
15 #ifdef HAVE_CONFIG_H
16 #include <fc_config.h>
17 #endif
18
19 #ifdef AUDIO_SDL
20 /* Though it would happily compile without this include,
21 * it is needed for sound to work.
22 * It defines "main" macro to rename our main() so that
23 * it can install SDL's own. */
24 #ifdef SDL2_PLAIN_INCLUDE
25 #include <SDL.h>
26 #elif AUDIO_SDL1_2
27 /* SDL */
28 #include <SDL/SDL.h>
29 #else /* AUDIO_SDL1_2 */
30 /* SDL2 */
31 #include <SDL2/SDL.h>
32 #endif /* AUDIO_SDL1_2 */
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37
38 #include <X11/Intrinsic.h>
39 #include <X11/StringDefs.h>
40
41 #include <X11/Xaw/Command.h>
42 #include <X11/Xaw/Form.h>
43 #include <X11/Xaw/Box.h>
44 #include <X11/Xaw/Label.h>
45 #include <X11/Xaw/AsciiText.h>
46 #include <X11/Xaw/Scrollbar.h>
47 #include <X11/Xaw/MenuButton.h>
48 #include <X11/Xaw/SimpleMenu.h>
49 #include <X11/Xaw/Paned.h>
50 #include <X11/Xatom.h>
51
52 #include "canvas.h"
53 #include "pixcomm.h"
54
55 /* utility */
56 #include "fc_cmdline.h"
57 #include "fciconv.h"
58 #include "fcintl.h"
59 #include "log.h"
60 #include "support.h"
61
62 /* common */
63 #include "game.h"
64 #include "government.h"
65 #include "map.h"
66 #include "unitlist.h"
67 #include "version.h"
68
69 /* client */
70 #include "chatline_common.h"
71 #include "client_main.h"
72 #include "climisc.h"
73 #include "clinet.h"
74 #include "control.h"
75 #include "editgui_g.h"
76 #include "options.h"
77 #include "text.h"
78 #include "tilespec.h"
79
80 /* gui-xaw */
81 #include "xaw_actions.h"
82 #include "colors.h"
83 #include "dialogs.h"
84 #include "graphics.h"
85 #include "gui_stuff.h" /* I_SW() */
86 #include "mapview.h"
87 #include "menu.h"
88 #include "optiondlg.h"
89 #include "pages.h"
90 #include "resources.h"
91
92 #include "gui_main.h"
93
94 const char *client_string = "gui-xaw";
95
96 const char * const gui_character_encoding = NULL;
97 const bool gui_use_transliteration = TRUE;
98
99 static AppResources appResources;
100
101 /* ids of the units icons in information display: (or 0) */
102 static int unit_ids[MAX_NUM_UNITS_BELOW];
103
104 static void setup_widgets(void);
105
106 void fill_econ_label_pixmaps(void);
107 void fill_unit_below_pixmaps(void);
108
109 /**************************************************************************
110 ...
111 **************************************************************************/
112 XtResource resources[] = {
113 { "GotAppDefFile", "gotAppDefFile", XtRBoolean, sizeof(Boolean),
114 XtOffset(AppResources *,gotAppDefFile), XtRImmediate, (XtPointer)False},
115 { "version", "Version", XtRString, sizeof(String),
116 XtOffset(AppResources *,version), XtRImmediate, (XtPointer)False},
117 #ifdef UNUSED
118 { "log", "Log", XtRString, sizeof(String),
119 XtOffset(AppResources *,logfile), XtRImmediate, (XtPointer)False},
120 { "name", "name", XtRString, sizeof(String),
121 XtOffset(AppResources *,name), XtRImmediate, (XtPointer)False},
122 { "port", "Port", XtRInt, sizeof(int),
123 XtOffset(AppResources *,port), XtRImmediate, (XtPointer)False},
124 { "server", "Server", XtRString, sizeof(String),
125 XtOffset(AppResources *,server), XtRImmediate, (XtPointer)False},
126 { "metaserver", "Metaserver", XtRString, sizeof(String),
127 XtOffset(AppResources *,metaserver), XtRImmediate, (XtPointer)False},
128 { "logLevel", "LogLevel", XtRString, sizeof(String),
129 XtOffset(AppResources *,loglevel_str), XtRImmediate, (XtPointer)False},
130 { "showHelp", "ShowHelp", XtRBoolean, sizeof(Boolean),
131 XtOffset(AppResources *,showHelp), XtRImmediate, (XtPointer)False},
132 { "showVersion", "ShowVersion", XtRBoolean, sizeof(Boolean),
133 XtOffset(AppResources *,showVersion), XtRImmediate, (XtPointer)False},
134 { "tileset", "TileSet", XtRString, sizeof(String),
135 XtOffset(AppResources *,tileset), XtRImmediate, (XtPointer)False},
136 #endif
137 };
138
139 /**************************************************************************
140 ...
141 **************************************************************************/
142 #ifdef UNUSED
143 static XrmOptionDescRec cmd_options[] = {
144 /* { "-help", ".showHelp", XrmoptionNoArg, (XPointer)"True" },*/
145 { "-log", ".log", XrmoptionSepArg, (XPointer)"True" },
146 { "-name", ".name", XrmoptionSepArg, (XPointer)"True" },
147 { "-port", ".port", XrmoptionSepArg, (XPointer)"True" },
148 { "-server", ".server", XrmoptionSepArg, (XPointer)"True" },
149 { "-metaserver",".metaserver",XrmoptionSepArg, (XPointer)"True" },
150 { "-debug", ".logLevel", XrmoptionSepArg, (XPointer)"True" },
151 { "-tiles", ".tileset", XrmoptionSepArg, (XPointer)"True" },
152 /* { "-version", ".showVersion", XrmoptionNoArg, (XPointer)"True" },*/
153 /* { "--help", ".showHelp", XrmoptionNoArg, (XPointer)"True" },*/
154 { "--log", ".log", XrmoptionSepArg, (XPointer)"True" },
155 { "--name", ".name", XrmoptionSepArg, (XPointer)"True" },
156 { "--port", ".port", XrmoptionSepArg, (XPointer)"True" },
157 { "--debug", ".logLevel", XrmoptionSepArg, (XPointer)"True" },
158 { "--server", ".server", XrmoptionSepArg, (XPointer)"True" },
159 { "--metaserver",".metaserver",XrmoptionSepArg, (XPointer)"True" },
160 { "--tiles", ".tileset", XrmoptionSepArg, (XPointer)"True" }
161 /* { "--version", ".showVersion", XrmoptionNoArg, (XPointer)"True" }*/
162 };
163 #endif
164
165 /**************************************************************************/
166
167 static void end_turn_callback(Widget w, XtPointer client_data,
168 XtPointer call_data);
169
170 static void timer_callback(XtPointer client_data, XtIntervalId *id);
171
172 /**************************************************************************/
173
174 struct game_data {
175 int year;
176 int population;
177 int researchedpoints;
178 int money;
179 int tax, luxurary, research;
180 };
181
182 /**************************************************************************/
183
184 Display *display;
185 int display_depth;
186 int screen_number;
187 enum Display_color_type display_color_type;
188 XtAppContext app_context;
189
190 /* this GC will be the default one all thru freeciv */
191 GC civ_gc;
192
193 /* This is for drawing border lines */
194 GC border_line_gc;
195
196 /* and this one is used for filling with the bg color */
197 GC fill_bg_gc;
198 GC fill_tile_gc;
199 Pixmap gray50,gray25;
200
201 /* overall font GC */
202 GC font_gc;
203 XFontSet main_font_set;
204 /* productions font GC */
205 GC prod_font_gc;
206 XFontSet prod_font_set;
207
208 Widget toplevel, main_form, menu_form, below_menu_form, left_column_form;
209 Widget bottom_form;
210 Widget map_form;
211 Widget map_canvas;
212 Widget overview_canvas;
213 Widget map_vertical_scrollbar, map_horizontal_scrollbar;
214 Widget inputline_text, outputwindow_text;
215 Widget econ_label[10];
216 Widget turn_done_button;
217 Widget info_command;
218 Widget bulb_label, sun_label, flake_label, government_label, timeout_label;
219 Widget unit_info_label;
220 Widget unit_pix_canvas;
221 Widget unit_below_canvas[MAX_NUM_UNITS_BELOW];
222 Widget main_vpane;
223 Pixmap unit_below_pixmap[MAX_NUM_UNITS_BELOW];
224 Widget more_arrow_label;
225 Window root_window;
226
227 XtInputId x_input_id;
228 XtIntervalId x_interval_id;
229 Atom wm_delete_window;
230
231 /****************************************************************************
232 Called by the tileset code to set the font size that should be used to
233 draw the city names and productions.
234 ****************************************************************************/
set_city_names_font_sizes(int my_city_names_font_size,int my_city_productions_font_size)235 void set_city_names_font_sizes(int my_city_names_font_size,
236 int my_city_productions_font_size)
237 {
238 log_error("Unimplemented set_city_names_font_sizes.");
239 /* PORTME */
240 }
241
242 #ifdef UNUSED
243 /**************************************************************************
244 ...
245 **************************************************************************/
246 /* This is used below in ui_main(), in commented out code. */
myerr(Display * p,XErrorEvent * e)247 static int myerr(Display *p, XErrorEvent *e)
248 {
249 puts("error");
250 return 0;
251 }
252 #endif
253
254 /**************************************************************************
255 Print extra usage information, including one line help on each option,
256 to stderr.
257 **************************************************************************/
print_usage(void)258 static void print_usage(void)
259 {
260 /* add client-specific usage information here */
261 fc_fprintf(stderr,
262 _("This client accepts the standard X toolkit command-line options\n"
263 "after '--'. See the X(7) man page.\n\n"));
264
265
266 /* TRANS: No full stop after the URL, could cause confusion. */
267 fc_fprintf(stderr, _("Report bugs at %s\n"), BUG_URL);
268 }
269
270 /**************************************************************************
271 Handle commandline options specific to this gui
272 **************************************************************************/
parse_options(int argc,char ** argv)273 static void parse_options(int argc, char **argv)
274 {
275 int i = 1;
276
277 while (i < argc) {
278 if (is_option("--help", argv[i])) {
279 print_usage();
280 exit(EXIT_SUCCESS);
281 } else {
282 fc_fprintf(stderr, _("Unrecognized option: \"%s\"\n"), argv[i]);
283 exit(EXIT_FAILURE);
284 }
285
286 i++;
287 }
288 }
289
290 /**************************************************************************
291 ...
292 **************************************************************************/
toplevel_work_proc(XtPointer client_data)293 static Boolean toplevel_work_proc(XtPointer client_data)
294 {
295 /* This will cause the connect dialog to pop-up.
296 We do it here so that the main window exists when that happens,
297 so that the connect dialog can position itself relative to it. */
298 set_client_state(C_S_DISCONNECTED);
299 return (True);
300 }
301
302 /**************************************************************************
303 ...
304 **************************************************************************/
ui_init(void)305 void ui_init(void)
306 {
307
308 }
309
310 /****************************************************************************
311 Extra initializers for client options.
312 ****************************************************************************/
options_extra_init(void)313 void options_extra_init(void)
314 {
315 /* Nothing to do. */
316 }
317
318 /**************************************************************************
319 Entry point for whole freeciv client program.
320 **************************************************************************/
main(int argc,char ** argv)321 int main(int argc, char **argv)
322 {
323 return client_main(argc, argv);
324 }
325
326 /**************************************************************************
327 Entry point for GUI specific portion. Called from client_main()
328 **************************************************************************/
ui_main(int argc,char * argv[])329 void ui_main(int argc, char *argv[])
330 {
331 int i;
332 struct sprite *icon;
333 const char *rev_ver;
334
335 parse_options(argc, argv);
336
337 /* include later - pain to see the warning at every run */
338 XtSetLanguageProc(NULL, NULL, NULL);
339
340 toplevel = XtVaAppInitialize(
341 &app_context, /* Application context */
342 "Freeciv", /* application class name */
343 #ifdef UNUSED
344 cmd_options, XtNumber(cmd_options),
345 #else
346 NULL, 0,
347 #endif
348 /* command line option list */
349 &argc, argv, /* command line args */
350 &fallback_resources[1], /* for missing app-defaults file */
351 XtNallowShellResize, True,
352 NULL);
353
354 XtGetApplicationResources(toplevel, &appResources, resources,
355 XtNumber(resources), NULL, 0);
356
357 /* XSynchronize(display, 1);
358 XSetErrorHandler(myerr);*/
359
360 if (appResources.version == NULL) {
361 log_fatal(_("No version number in resources."));
362 log_fatal(_("You probably have an old (circa V1.0)"
363 " Freeciv resource file somewhere."));
364 exit(EXIT_FAILURE);
365 }
366
367 /* TODO: Use capabilities here instead of version numbers */
368 if (0 != strncmp(appResources.version, VERSION_STRING,
369 strlen(appResources.version))) {
370 log_fatal(_("Game version does not match Resource version."));
371 log_fatal(_("Game version: %s - Resource version: %s"),
372 VERSION_STRING, appResources.version);
373 log_fatal(_("You might have an old Freeciv resourcefile"
374 " in /usr/lib/X11/app-defaults"));
375 exit(EXIT_FAILURE);
376 }
377
378 if (!appResources.gotAppDefFile) {
379 log_normal(_("Using fallback resources - which is OK"));
380 }
381
382 display = XtDisplay(toplevel);
383 screen_number = XScreenNumberOfScreen(XtScreen(toplevel));
384 display_depth = DefaultDepth(display, screen_number);
385 root_window = DefaultRootWindow(display);
386
387 display_color_type = get_visual();
388
389 if (display_color_type != COLOR_DISPLAY) {
390 log_fatal(_("Only color displays are supported for now..."));
391 /* exit(EXIT_FAILURE); */
392 }
393
394 {
395 XGCValues values;
396 char **missing_charset_list_return;
397 int missing_charset_count_return;
398 char *def_string_return;
399 char *city_names_font, *city_productions_font_name;
400
401 values.graphics_exposures = False;
402 civ_gc = XCreateGC(display, root_window, GCGraphicsExposures, &values);
403
404 city_names_font = fc_strdup("-*-*-*-*-*-*-14-*");
405
406 city_productions_font_name = fc_strdup("-*-*-*-*-*-*-14-*");
407
408 main_font_set = XCreateFontSet(display, city_names_font,
409 &missing_charset_list_return,
410 &missing_charset_count_return,
411 &def_string_return);
412 if (!main_font_set) {
413 log_fatal(_("Unable to open fontset: %s"), city_names_font);
414 log_fatal(_("Doing 'xset fp rehash' may temporarily solve a problem."));
415 exit(EXIT_FAILURE);
416 }
417 for (i = 0; i < missing_charset_count_return; i++) {
418 log_error(_("Font for charset %s is lacking"),
419 missing_charset_list_return[i]);
420 }
421 values.foreground = get_color(tileset, COLOR_MAPVIEW_CITYTEXT)->color.pixel;
422 values.background = get_color(tileset, COLOR_MAPVIEW_UNKNOWN)->color.pixel;
423 font_gc= XCreateGC(display, root_window,
424 GCForeground|GCBackground|GCGraphicsExposures,
425 &values);
426
427 prod_font_set = XCreateFontSet(display, city_productions_font_name,
428 &missing_charset_list_return,
429 &missing_charset_count_return,
430 &def_string_return);
431 if (!prod_font_set) {
432 log_fatal(_("Unable to open fontset: %s"), city_productions_font_name);
433 log_fatal(_("Doing 'xset fp rehash' may temporarily solve a problem."));
434 exit(EXIT_FAILURE);
435 }
436 for (i = 0; i < missing_charset_count_return; i++) {
437 log_error(_("Font for charset %s is lacking"),
438 missing_charset_list_return[i]);
439 }
440 values.foreground = get_color(tileset, COLOR_MAPVIEW_CITYTEXT)->color.pixel;
441 values.background = get_color(tileset, COLOR_MAPVIEW_UNKNOWN)->color.pixel;
442 prod_font_gc= XCreateGC(display, root_window,
443 GCForeground|GCBackground|GCGraphicsExposures,
444 &values);
445
446 values.line_width = BORDER_WIDTH;
447 values.line_style = LineOnOffDash;
448 values.cap_style = CapNotLast;
449 values.join_style = JoinMiter;
450 values.fill_style = FillSolid;
451 border_line_gc = XCreateGC(display, root_window,
452 GCGraphicsExposures|GCLineWidth|GCLineStyle
453 |GCCapStyle|GCJoinStyle|GCFillStyle, &values);
454
455 values.foreground = 0;
456 values.background = 0;
457 fill_bg_gc= XCreateGC(display, root_window,
458 GCForeground|GCBackground|GCGraphicsExposures,
459 &values);
460
461 values.fill_style = FillStippled;
462 fill_tile_gc = XCreateGC(display, root_window,
463 GCForeground|GCBackground|GCFillStyle|GCGraphicsExposures,
464 &values);
465 }
466
467 {
468 char d1[] = {0x03,0x0c,0x03,0x0c};
469 char d2[] = {0x08,0x02,0x08,0x02};
470 gray50 = XCreateBitmapFromData(display, root_window, d1, 4, 4);
471 gray25 = XCreateBitmapFromData(display, root_window, d2, 4, 4);
472 }
473
474 /* 135 below is rough value (could be more intelligent) --dwp */
475 num_units_below = 135 / tileset_full_tile_width(tileset);
476 num_units_below = MIN(num_units_below, MAX_NUM_UNITS_BELOW);
477 num_units_below = MAX(num_units_below, 1);
478
479 /* do setup_widgets before loading the rest of graphics to ensure that
480 setup_widgets() has enough colors available: (on 256-colour systems)
481 */
482 setup_widgets();
483 tileset_init(tileset);
484 tileset_load_tiles(tileset);
485 load_intro_gfx();
486 load_cursors();
487
488 /* FIXME: what about the mask? */
489 icon = get_icon_sprite(tileset, ICON_FREECIV);
490 XtVaSetValues(toplevel, XtNiconPixmap, icon->pixmap, NULL);
491
492 XtSetKeyboardFocus(bottom_form, inputline_text);
493 XtSetKeyboardFocus(below_menu_form, map_canvas);
494
495 InitializeActions(app_context);
496
497 /* Do this outside setup_widgets() so after tiles are loaded */
498 fill_econ_label_pixmaps();
499
500 XtAddCallback(map_horizontal_scrollbar, XtNjumpProc,
501 scrollbar_jump_callback, NULL);
502 XtAddCallback(map_vertical_scrollbar, XtNjumpProc,
503 scrollbar_jump_callback, NULL);
504 XtAddCallback(map_horizontal_scrollbar, XtNscrollProc,
505 scrollbar_scroll_callback, NULL);
506 XtAddCallback(map_vertical_scrollbar, XtNscrollProc,
507 scrollbar_scroll_callback, NULL);
508 XtAddCallback(turn_done_button, XtNcallback, end_turn_callback, NULL);
509
510 XtAppAddWorkProc(app_context, toplevel_work_proc, NULL);
511
512 XtRealizeWidget(toplevel);
513
514 x_interval_id = XtAppAddTimeOut(app_context, TIMER_INTERVAL,
515 timer_callback, NULL);
516
517 init_mapcanvas_and_overview();
518
519 fill_unit_below_pixmaps();
520
521 set_indicator_icons(client_research_sprite(),
522 client_warming_sprite(),
523 client_cooling_sprite(),
524 client_government_sprite());
525
526 wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW", 0);
527 XSetWMProtocols(display, XtWindow(toplevel), &wm_delete_window, 1);
528 XtOverrideTranslations(toplevel,
529 XtParseTranslationTable ("<Message>WM_PROTOCOLS: msg-quit-freeciv()"));
530
531 XtSetSensitive(toplevel, FALSE);
532
533 rev_ver = fc_git_revision();
534 if (rev_ver != NULL) {
535 char buffer[512];
536
537 fc_snprintf(buffer, sizeof(buffer), _("Commit: %s"), rev_ver);
538 output_window_append(ftc_client, buffer);
539 }
540
541 XtAppMainLoop(app_context);
542
543 start_quitting();
544 }
545
546 /**************************************************************************
547 Do any necessary UI-specific cleanup
548 **************************************************************************/
ui_exit(void)549 void ui_exit(void)
550 {
551 }
552
553 /**************************************************************************
554 Return our GUI type
555 **************************************************************************/
get_gui_type(void)556 enum gui_type get_gui_type(void)
557 {
558 return GUI_XAW;
559 }
560
561 /**************************************************************************
562 Callack for when user clicks one of the unit icons on left hand side
563 (units on same square as current unit). Use unit_ids[] data and change
564 focus to clicked unit.
565 **************************************************************************/
unit_icon_callback(Widget w,XtPointer client_data,XtPointer call_data)566 static void unit_icon_callback(Widget w, XtPointer client_data,
567 XtPointer call_data)
568 {
569 struct unit *punit;
570 int i = (size_t)client_data;
571
572 fc_assert_ret(i >= 0 && i < num_units_below);
573 if (unit_ids[i] == 0) { /* no unit displayed at this place */
574 return;
575 }
576 punit = game_unit_by_number(unit_ids[i]);
577 if (punit) { /* should always be true at this point */
578 if (unit_owner(punit) == client.conn.playing) {
579 /* may be non-true if alliance */
580 unit_focus_set(punit);
581 }
582 }
583 }
584
585 /**************************************************************************
586 ...
587 **************************************************************************/
setup_widgets(void)588 void setup_widgets(void)
589 {
590 long i;
591 int econ_label_count=10, econ_label_space=1;
592
593 main_form = XtVaCreateManagedWidget("mainform", formWidgetClass,
594 toplevel,
595 NULL);
596
597 menu_form = XtVaCreateManagedWidget("menuform", formWidgetClass,
598 main_form,
599 NULL);
600 setup_menus(menu_form);
601
602 /*
603 main_vpane= XtVaCreateManagedWidget("mainvpane",
604 panedWidgetClass,
605 main_form,
606 NULL);
607
608 below_menu_form = XtVaCreateManagedWidget("belowmenuform",
609 formWidgetClass,
610 main_vpane,
611 NULL);
612 */
613 below_menu_form = XtVaCreateManagedWidget("belowmenuform",
614 formWidgetClass,
615 main_form,
616 NULL);
617
618 left_column_form = XtVaCreateManagedWidget("leftcolumnform",
619 formWidgetClass,
620 below_menu_form,
621 NULL);
622
623 map_form = XtVaCreateManagedWidget("mapform",
624 formWidgetClass,
625 below_menu_form,
626 NULL);
627
628 bottom_form = XtVaCreateManagedWidget("bottomform",
629 formWidgetClass,
630 /*main_vpane,*/ main_form,
631 NULL);
632
633 overview_canvas = XtVaCreateManagedWidget("overviewcanvas",
634 xfwfcanvasWidgetClass,
635 left_column_form,
636 "exposeProc",
637 (XtArgVal)overview_canvas_expose,
638 "exposeProcData",
639 (XtArgVal)NULL,
640 NULL);
641
642 info_command = XtVaCreateManagedWidget("infocommand",
643 commandWidgetClass,
644 left_column_form,
645 XtNfromVert,
646 (XtArgVal)overview_canvas,
647 NULL);
648
649
650 /* Don't put the citizens in here yet because not loaded yet */
651 for(i=0;i<econ_label_count;i++) {
652 econ_label[i] = XtVaCreateManagedWidget("econlabels",
653 commandWidgetClass,
654 left_column_form,
655 XtNwidth, tileset_small_sprite_width(tileset),
656 XtNheight, tileset_small_sprite_height(tileset),
657 i?XtNfromHoriz:NULL,
658 i?econ_label[i-1]:NULL,
659 XtNhorizDistance, econ_label_space,
660 NULL);
661 }
662
663 bulb_label = XtVaCreateManagedWidget("bulblabel",
664 labelWidgetClass,
665 left_column_form,
666 NULL);
667
668 sun_label = XtVaCreateManagedWidget("sunlabel",
669 labelWidgetClass,
670 left_column_form,
671 NULL);
672
673 flake_label = XtVaCreateManagedWidget("flakelabel",
674 labelWidgetClass,
675 left_column_form,
676 NULL);
677
678 government_label = XtVaCreateManagedWidget("governmentlabel",
679 labelWidgetClass,
680 left_column_form,
681 NULL);
682
683 timeout_label = XtVaCreateManagedWidget("timeoutlabel",
684 labelWidgetClass,
685 left_column_form,
686 NULL);
687
688
689 turn_done_button =
690 I_LW(XtVaCreateManagedWidget("turndonebutton",
691 commandWidgetClass,
692 left_column_form,
693 XtNwidth, econ_label_count*
694 (tileset_small_sprite_width(tileset)+econ_label_space),
695 NULL));
696
697
698 unit_info_label = XtVaCreateManagedWidget("unitinfolabel",
699 labelWidgetClass,
700 left_column_form,
701 NULL);
702
703 unit_pix_canvas = XtVaCreateManagedWidget("unitpixcanvas",
704 pixcommWidgetClass,
705 left_column_form,
706 XtNwidth, tileset_full_tile_width(tileset),
707 XtNheight, tileset_full_tile_height(tileset),
708 NULL);
709
710 for(i=0; i<num_units_below; i++) {
711 char unit_below_name[32];
712 fc_snprintf(unit_below_name, sizeof(unit_below_name),
713 "unitbelowcanvas%ld", i);
714 unit_below_canvas[i] = XtVaCreateManagedWidget(unit_below_name,
715 pixcommWidgetClass,
716 left_column_form,
717 XtNwidth,
718 tileset_full_tile_width(tileset),
719 XtNheight,
720 tileset_full_tile_height(tileset),
721 NULL);
722 XtAddCallback(unit_below_canvas[i], XtNcallback, unit_icon_callback,
723 (XtPointer)i);
724 }
725
726 more_arrow_label =
727 XtVaCreateManagedWidget("morearrowlabel",
728 labelWidgetClass,
729 left_column_form,
730 XtNfromHoriz,
731 (XtArgVal)unit_below_canvas[num_units_below-1],
732 NULL);
733
734 map_vertical_scrollbar = XtVaCreateManagedWidget("mapvertiscrbar",
735 scrollbarWidgetClass,
736 map_form,
737 NULL);
738
739 map_canvas = XtVaCreateManagedWidget("mapcanvas",
740 xfwfcanvasWidgetClass,
741 map_form,
742 "exposeProc",
743 (XtArgVal)map_canvas_expose,
744 "exposeProcData",
745 (XtArgVal)NULL,
746 NULL);
747
748 map_horizontal_scrollbar = XtVaCreateManagedWidget("maphorizscrbar",
749 scrollbarWidgetClass,
750 map_form,
751 NULL);
752
753
754
755 outputwindow_text = I_SW(XtVaCreateManagedWidget("outputwindowtext",
756 asciiTextWidgetClass,
757 bottom_form,
758 NULL));
759
760
761 inputline_text= XtVaCreateManagedWidget("inputlinetext",
762 asciiTextWidgetClass,
763 bottom_form,
764 NULL);
765
766 }
767
768 /**************************************************************************
769 ...
770 **************************************************************************/
xaw_ui_exit(void)771 void xaw_ui_exit(void)
772 {
773 free_mapcanvas_and_overview();
774 tileset_free_tiles(tileset);
775 client_exit();
776 }
777
778 /**************************************************************************
779 ...
780 **************************************************************************/
main_show_info_popup(XEvent * event)781 void main_show_info_popup(XEvent *event)
782 {
783 XButtonEvent *ev = (XButtonEvent *)event;
784
785 if (ev->button == Button1) {
786 Widget p;
787 Position x, y;
788 Dimension w, h;
789
790 p = XtCreatePopupShell("popupinfo",
791 overrideShellWidgetClass,
792 info_command, NULL, 0);
793
794 XtAddCallback(p, XtNpopdownCallback, destroy_me_callback, NULL);
795
796 XtVaCreateManagedWidget("fullinfopopuplabel",
797 labelWidgetClass,
798 p,
799 XtNlabel, get_info_label_text_popup(),
800 NULL);
801
802 XtRealizeWidget(p);
803
804 XtVaGetValues(p, XtNwidth, &w, XtNheight, &h, NULL);
805 XtTranslateCoords(info_command, ev->x, ev->y, &x, &y);
806 XtVaSetValues(p, XtNx, MAX(0, x - w / 2), XtNy, MAX(0, y - h / 2), NULL);
807 XtPopupSpringLoaded(p);
808 }
809 }
810
811 /**************************************************************************
812 Update the connected users list at pregame state.
813 **************************************************************************/
real_conn_list_dialog_update(void * unused)814 void real_conn_list_dialog_update(void *unused)
815 {
816 real_update_start_page();
817 }
818
819 /**************************************************************************
820 ...
821 **************************************************************************/
sound_bell(void)822 void sound_bell(void)
823 {
824 XBell(display, 100);
825 }
826
827 /**************************************************************************
828 ...
829 **************************************************************************/
get_net_input(XtPointer client_data,int * fid,XtInputId * id)830 static void get_net_input(XtPointer client_data, int *fid, XtInputId *id)
831 {
832 input_from_server(*fid);
833 }
834
835 /**************************************************************************
836 ...
837 **************************************************************************/
set_wait_for_writable_socket(struct connection * pc,bool socket_writable)838 static void set_wait_for_writable_socket(struct connection *pc,
839 bool socket_writable)
840 {
841 static bool previous_state = FALSE;
842
843 if (previous_state == socket_writable)
844 return;
845 log_debug("set_wait_for_writable_socket(%d)", socket_writable);
846 XtRemoveInput(x_input_id);
847 x_input_id = XtAppAddInput(app_context, client.conn.sock,
848 (XtPointer) (XtInputReadMask |
849 (socket_writable ?
850 XtInputWriteMask : 0) |
851 XtInputExceptMask),
852 (XtInputCallbackProc) get_net_input, NULL);
853 previous_state = socket_writable;
854 }
855
856 /**************************************************************************
857 This function is called after the client succesfully
858 has connected to the server
859 **************************************************************************/
add_net_input(int sock)860 void add_net_input(int sock)
861 {
862 x_input_id = XtAppAddInput(app_context, sock,
863 (XtPointer) (XtInputReadMask |
864 XtInputExceptMask),
865 (XtInputCallbackProc) get_net_input, NULL);
866 client.conn.notify_of_writable_data = set_wait_for_writable_socket;
867 }
868
869 /**************************************************************************
870 This function is called if the client disconnects
871 from the server
872 **************************************************************************/
remove_net_input(void)873 void remove_net_input(void)
874 {
875 XtRemoveInput(x_input_id);
876 XUndefineCursor(display, XtWindow(map_canvas));
877 }
878
879 /**************************************************************************
880 ...
881 **************************************************************************/
end_turn_callback(Widget w,XtPointer client_data,XtPointer call_data)882 void end_turn_callback(Widget w, XtPointer client_data, XtPointer call_data)
883 {
884 XtSetSensitive(turn_done_button, FALSE);
885
886 user_ended_turn();
887 }
888
889 /**************************************************************************
890 ...
891 **************************************************************************/
timer_callback(XtPointer client_data,XtIntervalId * id)892 void timer_callback(XtPointer client_data, XtIntervalId * id)
893 {
894 int msec = real_timer_callback() * 1000;
895
896 x_interval_id = XtAppAddTimeOut(app_context, msec,
897 timer_callback, NULL);
898 }
899
900 /**************************************************************************
901 Set one of the unit icons in information area based on punit.
902 Use punit==NULL to clear icon.
903 Index 'idx' is -1 for "active unit", or 0 to (num_units_below-1) for
904 units below. Also updates unit_ids[idx] for idx>=0.
905 **************************************************************************/
set_unit_icon(int idx,struct unit * punit)906 void set_unit_icon(int idx, struct unit *punit)
907 {
908 Widget w;
909
910 fc_assert_ret(idx >= -1 && idx < num_units_below);
911 if (idx == -1) {
912 w = unit_pix_canvas;
913 } else {
914 w = unit_below_canvas[idx];
915 unit_ids[idx] = punit ? punit->id : 0;
916 }
917
918 XawPixcommClear(w);
919 if (punit) {
920 struct canvas store = {XawPixcommPixmap(w)};
921
922 put_unit(punit, &store, 1.0, 0, 0);
923 xaw_expose_now(w);
924 }
925 }
926
927 /**************************************************************************
928 Set the "more arrow" for the unit icons to on(1) or off(0).
929 Maintains a static record of current state to avoid unnecessary redraws.
930 Note initial state should match initial gui setup (off).
931 **************************************************************************/
set_unit_icons_more_arrow(bool onoff)932 void set_unit_icons_more_arrow(bool onoff)
933 {
934 static bool showing = FALSE;
935
936 if (onoff && !showing) {
937 /* FIXME: what about the mask? */
938 xaw_set_bitmap(more_arrow_label,
939 get_arrow_sprite(tileset, ARROW_RIGHT)->pixmap);
940 showing = TRUE;
941 }
942 else if(!onoff && showing) {
943 xaw_set_bitmap(more_arrow_label, None);
944 showing = FALSE;
945 }
946 }
947
948 /****************************************************************************
949 Called when the set of units in focus (get_units_in_focus()) changes.
950 Standard updates like update_unit_info_label() are handled in the platform-
951 independent code, so some clients will not need to do anything here.
952 ****************************************************************************/
real_focus_units_changed(void)953 void real_focus_units_changed(void)
954 {
955 /* Nothing to do */
956 }
957
958 struct callback {
959 void (*callback)(void *data);
960 void *data;
961 };
962
963 /****************************************************************************
964 A wrapper for the callback called through add_idle_callback.
965 ****************************************************************************/
idle_callback_wrapper(XtPointer data)966 static Boolean idle_callback_wrapper(XtPointer data)
967 {
968 struct callback *cb = data;
969
970 (cb->callback)(cb->data);
971 free(cb);
972 /* return True if we want to remove WorkProc */
973 return True;
974 }
975
976 /****************************************************************************
977 Enqueue a callback to be called during an idle moment. The 'callback'
978 function should be called sometimes soon, and passed the 'data' pointer
979 as its data.
980 ****************************************************************************/
add_idle_callback(void (callback)(void *),void * data)981 void add_idle_callback(void (callback)(void *), void *data)
982 {
983 struct callback *cb = fc_malloc(sizeof(*cb));
984
985 cb->callback = callback;
986 cb->data = data;
987 XtAppAddWorkProc(app_context, idle_callback_wrapper, cb);
988 }
989
990 /**************************************************************************
991 Called to fill econ_label pixmaps (showing tax/lux/sci rates).
992
993 It may be called again if the tileset changes.
994 **************************************************************************/
fill_econ_label_pixmaps(void)995 void fill_econ_label_pixmaps(void)
996 {
997 int i;
998 int econ_label_count = 10;
999
1000 for(i = 0; i < econ_label_count; i++) {
1001 struct sprite *s = i < 5 ? get_tax_sprite(tileset, O_SCIENCE)
1002 : get_tax_sprite(tileset, O_GOLD);
1003
1004 XtVaSetValues(econ_label[i], XtNbitmap,
1005 s->pixmap, NULL);
1006 XtAddCallback(econ_label[i], XtNcallback, taxrates_callback,
1007 INT_TO_XTPOINTER(i));
1008 }
1009 }
1010
1011 /**************************************************************************
1012 Called to fill unit_below pixmaps. They are on the left of the
1013 screen that shows all of the inactive units in the current tile.
1014
1015 It may be called again if the tileset changes.
1016 **************************************************************************/
fill_unit_below_pixmaps(void)1017 void fill_unit_below_pixmaps(void)
1018 {
1019 long i;
1020
1021 for (i = 0; i < num_units_below; i++) {
1022 /* XtVaSetValues(unit_below_canvas[i],
1023 XtNwidth, tileset_full_tile_width(tileset),
1024 XtNheight, tileset_full_tile_height(tileset),
1025 NULL);
1026 */ unit_below_pixmap[i] = XCreatePixmap(display, XtWindow(overview_canvas),
1027 tileset_full_tile_width(tileset),
1028 tileset_full_tile_height(tileset),
1029 display_depth);
1030 }
1031 }
1032
1033 /**************************************************************************
1034 Called when the tileset is changed to reset indicators pixmaps.
1035 **************************************************************************/
reset_econ_label_pixmaps(void)1036 void reset_econ_label_pixmaps(void)
1037 {
1038 fill_econ_label_pixmaps();
1039 }
1040
1041 /**************************************************************************
1042 Called when the tileset is changed to reset unit pixmaps.
1043 **************************************************************************/
reset_unit_below_pixmaps(void)1044 void reset_unit_below_pixmaps(void)
1045 {
1046 long i;
1047
1048 for (i = 0; i < num_units_below; i++) {
1049 XFreePixmap(display, unit_below_pixmap[i]);
1050 }
1051 xaw_set_bitmap(more_arrow_label, None);
1052 fill_unit_below_pixmaps();
1053
1054 set_unit_icons_more_arrow(FALSE);
1055 if (get_num_units_in_focus() == 1) {
1056 set_unit_icon(-1, head_of_units_in_focus());
1057 } else {
1058 set_unit_icon(-1, NULL);
1059 }
1060 update_unit_pix_label(get_units_in_focus());
1061 }
1062
1063 /****************************************************************************
1064 Assigns focus units to given battlegroup.
1065 ****************************************************************************/
assign_battlegroup(int battlegroup)1066 void assign_battlegroup(int battlegroup)
1067 {
1068 key_unit_assign_battlegroup(battlegroup, FALSE);
1069 }
1070
1071 /****************************************************************************
1072 Brings given battlegroup into focus.
1073 ****************************************************************************/
select_battlegroup(int battlegroup)1074 void select_battlegroup(int battlegroup)
1075 {
1076 key_unit_select_battlegroup(battlegroup, FALSE);
1077 }
1078
1079 /****************************************************************************
1080 Adds focus units to given battlegroup
1081 (or removes unit from battlegoup if battlegroup is the same that unit has).
1082 ****************************************************************************/
add_unit_to_battlegroup(int battlegroup)1083 void add_unit_to_battlegroup(int battlegroup)
1084 {
1085 if (NULL != client.conn.playing && can_client_issue_orders()) {
1086 struct unit *punit;
1087
1088 punit = head_of_units_in_focus();
1089 if (punit && punit->battlegroup == battlegroup) {
1090 /* If top unit already in the same battlegroup, detach it */
1091 unit_change_battlegroup(punit, BATTLEGROUP_NONE);
1092 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
1093 } else {
1094 key_unit_assign_battlegroup(battlegroup, TRUE);
1095 }
1096 }
1097 }
1098
1099 /****************************************************************************
1100 Stub for editor function
1101 ****************************************************************************/
editgui_tileset_changed(void)1102 void editgui_tileset_changed(void)
1103 {}
1104
1105 /****************************************************************************
1106 Stub for editor function
1107 ****************************************************************************/
editgui_refresh(void)1108 void editgui_refresh(void)
1109 {}
1110
1111 /****************************************************************************
1112 Stub for editor function
1113 ****************************************************************************/
editgui_popup_properties(const struct tile_list * tiles,int objtype)1114 void editgui_popup_properties(const struct tile_list *tiles, int objtype)
1115 {}
1116
1117 /****************************************************************************
1118 Stub for editor function
1119 ****************************************************************************/
editgui_popdown_all(void)1120 void editgui_popdown_all(void)
1121 {}
1122
1123 /****************************************************************************
1124 Stub for editor function
1125 ****************************************************************************/
editgui_notify_object_changed(int objtype,int object_id,bool removal)1126 void editgui_notify_object_changed(int objtype, int object_id, bool removal)
1127 {}
1128
1129 /****************************************************************************
1130 Stub for editor function
1131 ****************************************************************************/
editgui_notify_object_created(int tag,int id)1132 void editgui_notify_object_created(int tag, int id)
1133 {}
1134
1135 /**************************************************************************
1136 Updates a gui font style.
1137 **************************************************************************/
gui_update_font(const char * font_name,const char * font_value)1138 void gui_update_font(const char *font_name, const char *font_value)
1139 {
1140 /* PORTME */
1141 }
1142
1143 /**************************************************************************
1144 Insert build information to help
1145 **************************************************************************/
insert_client_build_info(char * outbuf,size_t outlen)1146 void insert_client_build_info(char *outbuf, size_t outlen)
1147 {
1148 /* PORTME */
1149 }
1150