When mixer is not available, recommend SDL2_mixer instead of SDL1.2 mixer
[freeciv.git] / client / gui-sdl / gui_main.c
blob478e3ccb463a703efa26bab26a18de35d97f3a3b
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.
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 ***********************************************************************/
14 /***********************************************************************
15 gui_main.c - description
16 -------------------
17 begin : Sun Jun 30 2002
18 copyright : (C) 2002 by Rafał Bursig
19 email : Rafał Bursig <bursig@poczta.fm>
20 ***********************************************************************/
22 #ifdef HAVE_CONFIG_H
23 #include <fc_config.h>
24 #endif
26 #include "fc_prehdrs.h"
28 #include <errno.h>
30 #ifdef HAVE_LOCALE_H
31 #include <locale.h>
32 #endif
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
38 /* SDL */
39 #include <SDL/SDL.h>
41 /* utility */
42 #include "fc_cmdline.h"
43 #include "fciconv.h"
44 #include "fcintl.h"
45 #include "log.h"
46 #include "netintf.h"
48 /* common */
49 #include "unitlist.h"
51 /* client */
52 #include "client_main.h"
53 #include "climisc.h"
54 #include "clinet.h"
55 #include "editgui_g.h"
56 #include "tilespec.h"
57 #include "update_queue.h"
59 /* gui-sdl */
60 #include "chatline.h"
61 #include "citydlg.h"
62 #include "cityrep.h"
63 #include "diplodlg.h"
64 #include "graphics.h"
65 #include "gui_id.h"
66 #include "gui_mouse.h"
67 #include "gui_tilespec.h"
68 #include "inteldlg.h"
69 #include "mapctrl.h"
70 #include "mapview.h"
71 #include "menu.h"
72 #include "messagewin.h"
73 #include "optiondlg.h"
74 #include "repodlgs.h"
75 #include "themespec.h"
76 #include "spaceshipdlg.h"
77 #include "widget.h"
79 #include "gui_main.h"
81 #define UNITS_TIMER_INTERVAL 128 /* milliseconds */
82 #define MAP_SCROLL_TIMER_INTERVAL 500
84 const char *client_string = "gui-sdl";
86 /* The real GUI character encoding is UTF-16 which is not supported by
87 * fciconv code at this time. Conversion between UTF-8 and UTF-16 is done
88 * in gui_iconv.c */
89 const char * const gui_character_encoding = "UTF-8";
90 const bool gui_use_transliteration = FALSE;
92 Uint32 SDL_Client_Flags = 0;
94 Uint32 widget_info_counter = 0;
95 int MOVE_STEP_X = DEFAULT_MOVE_STEP;
96 int MOVE_STEP_Y = DEFAULT_MOVE_STEP;
97 extern bool draw_goto_patrol_lines;
98 SDL_Event *pFlush_User_Event = NULL;
99 bool is_unit_move_blocked;
100 bool LSHIFT;
101 bool RSHIFT;
102 bool LCTRL;
103 bool RCTRL;
104 bool LALT;
105 int city_names_font_size = 12;
106 int city_productions_font_size = 12;
108 /* ================================ Private ============================ */
109 static int net_socket = -1;
110 static bool autoconnect = FALSE;
111 static bool is_map_scrolling = FALSE;
112 static enum direction8 scroll_dir;
114 static struct mouse_button_behavior button_behavior;
116 static SDL_Event *pNet_User_Event = NULL;
117 static SDL_Event *pAnim_User_Event = NULL;
118 static SDL_Event *pInfo_User_Event = NULL;
119 static SDL_Event *pMap_Scroll_User_Event = NULL;
121 static void print_usage(void);
122 static void parse_options(int argc, char **argv);
123 static int check_scroll_area(int x, int y);
125 enum USER_EVENT_ID {
126 EVENT_ERROR = 0,
127 NET,
128 ANIM,
129 TRY_AUTO_CONNECT,
130 SHOW_WIDGET_INFO_LABBEL,
131 FLUSH,
132 MAP_SCROLL,
133 EXIT_FROM_EVENT_LOOP
136 struct callback {
137 void (*callback)(void *data);
138 void *data;
141 #define SPECLIST_TAG callback
142 #define SPECLIST_TYPE struct callback
143 #include "speclist.h"
145 struct callback_list *callbacks;
147 /* =========================================================== */
149 /****************************************************************************
150 Called by the tileset code to set the font size that should be used to
151 draw the city names and productions.
152 ****************************************************************************/
153 void set_city_names_font_sizes(int my_city_names_font_size,
154 int my_city_productions_font_size)
156 city_names_font_size = my_city_names_font_size;
157 city_productions_font_size = my_city_productions_font_size;
160 /**************************************************************************
161 Print extra usage information, including one line help on each option,
162 to stderr.
163 **************************************************************************/
164 static void print_usage(void)
166 /* add client-specific usage information here */
167 fc_fprintf(stderr,
168 _(" -f, --fullscreen\tStart Client in Fullscreen mode\n"));
169 fc_fprintf(stderr, _(" -e, --eventthread\tInit Event Subsystem in "
170 "other thread (only Linux and BeOS)\n"));
171 fc_fprintf(stderr, _(" -t, --theme THEME\tUse GUI theme THEME\n"));
173 /* TRANS: No full stop after the URL, could cause confusion. */
174 fc_fprintf(stderr, _("Report bugs at %s\n"), BUG_URL);
177 /**************************************************************************
178 Search for command line options. right now, it's just help
179 semi-useless until we have options that aren't the same across all clients.
180 **************************************************************************/
181 static void parse_options(int argc, char **argv)
183 int i = 1;
184 char *option = NULL;
186 while (i < argc) {
187 if (is_option("--help", argv[i])) {
188 print_usage();
189 exit(EXIT_SUCCESS);
190 } else if (is_option("--fullscreen", argv[i])) {
191 gui_options.gui_sdl_fullscreen = TRUE;
192 } else if (is_option("--eventthread", argv[i])) {
193 /* init events in other thread ( only linux and BeOS ) */
194 SDL_InitSubSystem(SDL_INIT_EVENTTHREAD);
195 } else if ((option = get_option_malloc("--theme", argv, &i, argc, FALSE))) {
196 sz_strlcpy(gui_options.gui_sdl_default_theme_name, option);
197 free(option);
198 } else {
199 fc_fprintf(stderr, _("Unrecognized option: \"%s\"\n"), argv[i]);
200 exit(EXIT_FAILURE);
203 i++;
207 /**************************************************************************
208 Main handler for key presses
209 **************************************************************************/
210 static Uint16 main_key_down_handler(SDL_keysym Key, void *pData)
212 static struct widget *pWidget;
213 if ((pWidget = find_next_widget_for_key(NULL, Key)) != NULL) {
214 return widget_pressed_action(pWidget);
215 } else {
216 if (Key.sym == SDLK_TAB) {
217 /* input */
218 popup_input_line();
219 } else {
220 if (map_event_handler(Key)
221 && C_S_RUNNING == client_state()) {
222 switch (Key.sym) {
223 case SDLK_RETURN:
224 case SDLK_KP_ENTER:
225 if (LSHIFT || RSHIFT) {
226 disable_focus_animation();
227 key_end_turn();
228 } else {
229 struct unit *pUnit;
230 struct city *pCity;
231 if (NULL != (pUnit = head_of_units_in_focus()) &&
232 (pCity = tile_city(unit_tile(pUnit))) != NULL &&
233 city_owner(pCity) == client.conn.playing) {
234 popup_city_dialog(pCity);
237 return ID_ERROR;
239 case SDLK_F2:
240 units_report_dialog_popup(FALSE);
241 return ID_ERROR;
243 case SDLK_F4:
244 city_report_dialog_popup(FALSE);
245 return ID_ERROR;
247 case SDLK_F7:
248 send_report_request(REPORT_WONDERS_OF_THE_WORLD);
249 return ID_ERROR;
251 case SDLK_F8:
252 send_report_request(REPORT_TOP_5_CITIES);
253 return ID_ERROR;
255 case SDLK_F9:
256 if (meswin_dialog_is_open()) {
257 meswin_dialog_popdown();
258 } else {
259 meswin_dialog_popup(TRUE);
261 flush_dirty();
262 return ID_ERROR;
264 case SDLK_F11:
265 send_report_request(REPORT_DEMOGRAPHIC);
266 return ID_ERROR;
268 case SDLK_F12:
269 popup_spaceship_dialog(client.conn.playing);
270 return ID_ERROR;
272 case SDLK_ASTERISK:
273 send_report_request(REPORT_ACHIEVEMENTS);
274 return ID_ERROR;
276 default:
277 return ID_ERROR;
283 return ID_ERROR;
286 /**************************************************************************
287 Main key release handler.
288 **************************************************************************/
289 static Uint16 main_key_up_handler(SDL_keysym Key, void *pData)
291 if(pSellected_Widget) {
292 unsellect_widget_action();
294 return ID_ERROR;
297 /**************************************************************************
298 Main mouse click handler.
299 **************************************************************************/
300 static Uint16 main_mouse_button_down_handler(SDL_MouseButtonEvent *pButtonEvent, void *pData)
302 struct widget *pWidget;
304 if ((pWidget = find_next_widget_at_pos(NULL,
305 pButtonEvent->x,
306 pButtonEvent->y)) != NULL) {
307 if (!(get_wstate(pWidget) == FC_WS_DISABLED)) {
308 return widget_pressed_action(pWidget);
310 } else {
311 /* no visible widget at this position -> map click */
312 #ifdef UNDER_CE
313 if (!check_scroll_area(pButtonEvent->x, pButtonEvent->y)) {
314 #endif
315 if (!button_behavior.counting) {
316 /* start counting */
317 button_behavior.counting = TRUE;
318 button_behavior.button_down_ticks = SDL_GetTicks();
319 *button_behavior.event = *pButtonEvent;
320 button_behavior.hold_state = MB_HOLD_SHORT;
321 button_behavior.ptile = canvas_pos_to_tile(pButtonEvent->x, pButtonEvent->y);
323 #ifdef UNDER_CE
325 #endif
327 return ID_ERROR;
330 /**************************************************************************
331 Main mouse button release handler.
332 **************************************************************************/
333 static Uint16 main_mouse_button_up_handler(SDL_MouseButtonEvent *pButtonEvent, void *pData)
335 if (button_behavior.button_down_ticks /* button wasn't pressed over a widget */
336 && !find_next_widget_at_pos(NULL, pButtonEvent->x, pButtonEvent->y)) {
337 *button_behavior.event = *pButtonEvent;
338 button_up_on_map(&button_behavior);
341 button_behavior.counting = FALSE;
342 button_behavior.button_down_ticks = 0;
344 is_map_scrolling = FALSE;
346 return ID_ERROR;
349 #ifdef UNDER_CE
350 #define SCROLL_MAP_AREA 8
351 #else
352 #define SCROLL_MAP_AREA 1
353 #endif
355 /**************************************************************************
356 Main handler for mouse movement handling.
357 **************************************************************************/
358 static Uint16 main_mouse_motion_handler(SDL_MouseMotionEvent *pMotionEvent, void *pData)
360 static struct widget *pWidget;
361 struct tile *ptile;
363 /* stop evaluating button hold time when moving to another tile in medium
364 * hold state or above */
365 if (button_behavior.counting && (button_behavior.hold_state >= MB_HOLD_MEDIUM)) {
366 ptile = canvas_pos_to_tile(pMotionEvent->x, pMotionEvent->y);
367 if (tile_index(ptile) != tile_index(button_behavior.ptile)) {
368 button_behavior.counting = FALSE;
372 if(draw_goto_patrol_lines) {
373 update_line(pMotionEvent->x, pMotionEvent->y);
376 #ifndef UNDER_CE
377 if (gui_options.gui_sdl_fullscreen) {
378 check_scroll_area(pMotionEvent->x, pMotionEvent->y);
380 #endif /* UNDER_CE */
382 if ((pWidget = find_next_widget_at_pos(NULL,
383 pMotionEvent->x,
384 pMotionEvent->y)) != NULL) {
385 update_mouse_cursor(CURSOR_DEFAULT);
386 if (!(get_wstate(pWidget) == FC_WS_DISABLED)) {
387 widget_sellected_action(pWidget);
389 } else {
390 if (pSellected_Widget) {
391 unsellect_widget_action();
392 } else {
393 control_mouse_cursor(canvas_pos_to_tile(pMotionEvent->x, pMotionEvent->y));
397 draw_mouse_cursor();
399 return ID_ERROR;
402 /**************************************************************************
403 this is called every TIMER_INTERVAL milliseconds whilst we are in
404 gui_main_loop() (which is all of the time) TIMER_INTERVAL needs to be .5s
405 **************************************************************************/
406 static void update_button_hold_state(void)
408 /* button pressed */
409 if (button_behavior.counting) {
410 if (((SDL_GetTicks() - button_behavior.button_down_ticks) >= MB_MEDIUM_HOLD_DELAY)
411 && ((SDL_GetTicks() - button_behavior.button_down_ticks) < MB_LONG_HOLD_DELAY)) {
413 if (button_behavior.hold_state != MB_HOLD_MEDIUM) {
414 button_behavior.hold_state = MB_HOLD_MEDIUM;
415 button_down_on_map(&button_behavior);
418 } else if (((SDL_GetTicks() - button_behavior.button_down_ticks)
419 >= MB_LONG_HOLD_DELAY)) {
421 if (button_behavior.hold_state != MB_HOLD_LONG) {
422 button_behavior.hold_state = MB_HOLD_LONG;
423 button_down_on_map(&button_behavior);
429 return;
432 /**************************************************************************
433 Check if coordinate is in scroll area.
434 **************************************************************************/
435 static int check_scroll_area(int x, int y) {
437 SDL_Rect rect_north = {0, 0, Main.map->w, SCROLL_MAP_AREA};
438 SDL_Rect rect_east = {Main.map->w - SCROLL_MAP_AREA, 0, SCROLL_MAP_AREA, Main.map->h};
439 SDL_Rect rect_south = {0, Main.map->h - SCROLL_MAP_AREA, Main.map->w, SCROLL_MAP_AREA};
440 SDL_Rect rect_west = {0, 0, SCROLL_MAP_AREA, Main.map->h};
442 if (is_in_rect_area(x, y, rect_north)) {
443 is_map_scrolling = TRUE;
444 if (is_in_rect_area(x, y, rect_west)) {
445 scroll_dir = DIR8_NORTHWEST;
446 } else if (is_in_rect_area(x, y, rect_east)) {
447 scroll_dir = DIR8_NORTHEAST;
448 } else {
449 scroll_dir = DIR8_NORTH;
451 } else if (is_in_rect_area(x, y, rect_south)) {
452 is_map_scrolling = TRUE;
453 if (is_in_rect_area(x, y, rect_west)) {
454 scroll_dir = DIR8_SOUTHWEST;
455 } else if (is_in_rect_area(x, y, rect_east)) {
456 scroll_dir = DIR8_SOUTHEAST;
457 } else {
458 scroll_dir = DIR8_SOUTH;
460 } else if (is_in_rect_area(x, y, rect_east)) {
461 is_map_scrolling = TRUE;
462 scroll_dir = DIR8_EAST;
463 } else if (is_in_rect_area(x, y, rect_west)) {
464 is_map_scrolling = TRUE;
465 scroll_dir = DIR8_WEST;
466 } else {
467 is_map_scrolling = FALSE;
470 return is_map_scrolling;
473 /* ============================ Public ========================== */
475 /**************************************************************************
476 Instruct event loop to exit.
477 **************************************************************************/
478 void force_exit_from_event_loop(void)
480 SDL_Event Event;
482 Event.type = SDL_USEREVENT;
483 Event.user.code = EXIT_FROM_EVENT_LOOP;
484 Event.user.data1 = NULL;
485 Event.user.data2 = NULL;
487 SDL_PushEvent(&Event);
490 /**************************************************************************
491 Filter out mouse motion events for too small movement to react to.
492 This function may run in a separate event thread.
493 **************************************************************************/
494 int FilterMouseMotionEvents(const SDL_Event *event)
496 if (event->type == SDL_MOUSEMOTION) {
497 static int x = 0, y = 0;
498 if ( ((MOVE_STEP_X > 0) && (abs(event->motion.x - x) >= MOVE_STEP_X)) ||
499 ((MOVE_STEP_Y > 0) && (abs(event->motion.y - y) >= MOVE_STEP_Y)) ) {
500 x = event->motion.x;
501 y = event->motion.y;
502 return(1); /* Catch it */
503 } else {
504 return(0); /* Drop it, we've handled it */
507 return(1);
510 /**************************************************************************
511 SDL-client main loop.
512 **************************************************************************/
513 Uint16 gui_event_loop(void *pData,
514 void (*loop_action)(void *pData),
515 Uint16 (*key_down_handler)(SDL_keysym Key, void *pData),
516 Uint16 (*key_up_handler)(SDL_keysym Key, void *pData),
517 Uint16 (*mouse_button_down_handler)(SDL_MouseButtonEvent *pButtonEvent, void *pData),
518 Uint16 (*mouse_button_up_handler)(SDL_MouseButtonEvent *pButtonEvent, void *pData),
519 Uint16 (*mouse_motion_handler)(SDL_MouseMotionEvent *pMotionEvent, void *pData))
521 Uint16 ID;
522 static fc_timeval tv;
523 static fd_set civfdset;
524 Uint32 t_current, t_last_unit_anim, t_last_map_scrolling;
525 Uint32 real_timer_next_call;
526 static int result, schot_nr = 0;
527 static char schot[32];
529 ID = ID_ERROR;
530 t_last_map_scrolling = t_last_unit_anim = real_timer_next_call = SDL_GetTicks();
531 while (ID == ID_ERROR) {
532 /* ========================================= */
533 /* net check with 10ms delay event loop */
534 if (net_socket >= 0) {
535 FD_ZERO(&civfdset);
537 if (net_socket >= 0) {
538 FD_SET(net_socket, &civfdset);
541 tv.tv_sec = 0;
542 tv.tv_usec = 10000;/* 10ms */
544 result = fc_select(net_socket + 1, &civfdset, NULL, NULL, &tv);
545 if (result < 0) {
546 if (errno != EINTR) {
547 break;
548 } else {
549 continue;
551 } else {
552 if (result > 0) {
553 if ((net_socket >= 0) && FD_ISSET(net_socket, &civfdset)) {
554 SDL_PushEvent(pNet_User_Event);
558 } else { /* if connection is not establish */
559 SDL_Delay(10);
561 /* ========================================= */
563 t_current = SDL_GetTicks();
565 if (t_current > real_timer_next_call) {
566 real_timer_next_call = t_current + (real_timer_callback() * 1000);
569 if ((t_current - t_last_unit_anim) > UNITS_TIMER_INTERVAL) {
570 if (autoconnect) {
571 widget_info_counter++;
572 SDL_PushEvent(pAnim_User_Event);
573 } else {
574 SDL_PushEvent(pAnim_User_Event);
577 t_last_unit_anim = SDL_GetTicks();
580 if (is_map_scrolling) {
581 if ((t_current - t_last_map_scrolling) > MAP_SCROLL_TIMER_INTERVAL) {
582 SDL_PushEvent(pMap_Scroll_User_Event);
583 t_last_map_scrolling = SDL_GetTicks();
585 } else {
586 t_last_map_scrolling = SDL_GetTicks();
589 if (widget_info_counter > 0) {
590 SDL_PushEvent(pInfo_User_Event);
591 widget_info_counter = 0;
594 /* ========================================= */
596 if (loop_action) {
597 loop_action(pData);
600 /* ========================================= */
602 while (SDL_PollEvent(&Main.event) == 1) {
604 switch (Main.event.type) {
606 case SDL_QUIT:
607 return MAX_ID;
608 break;
610 case SDL_KEYUP:
611 switch (Main.event.key.keysym.sym) {
612 /* find if Shifts are released */
613 case SDLK_RSHIFT:
614 RSHIFT = FALSE;
615 break;
616 case SDLK_LSHIFT:
617 LSHIFT = FALSE;
618 break;
619 case SDLK_LCTRL:
620 LCTRL = FALSE;
621 break;
622 case SDLK_RCTRL:
623 RCTRL = FALSE;
624 break;
625 case SDLK_LALT:
626 LALT = FALSE;
627 break;
628 default:
629 if(key_up_handler) {
630 ID = key_up_handler(Main.event.key.keysym, pData);
632 break;
634 break;
636 case SDL_KEYDOWN:
637 switch(Main.event.key.keysym.sym) {
638 case SDLK_PRINT:
639 fc_snprintf(schot, sizeof(schot), "fc_%05d.bmp", schot_nr++);
640 log_normal(_("Making screenshot %s"), schot);
641 SDL_SaveBMP(Main.screen, schot);
642 break;
644 case SDLK_RSHIFT:
645 /* Right Shift is Pressed */
646 RSHIFT = TRUE;
647 break;
649 case SDLK_LSHIFT:
650 /* Left Shift is Pressed */
651 LSHIFT = TRUE;
652 break;
654 case SDLK_LCTRL:
655 /* Left CTRL is Pressed */
656 LCTRL = TRUE;
657 break;
659 case SDLK_RCTRL:
660 /* Right CTRL is Pressed */
661 RCTRL = TRUE;
662 break;
664 case SDLK_LALT:
665 /* Left ALT is Pressed */
666 LALT = TRUE;
667 break;
669 default:
670 if(key_down_handler) {
671 ID = key_down_handler(Main.event.key.keysym, pData);
673 break;
675 break;
677 case SDL_MOUSEBUTTONDOWN:
678 if(mouse_button_down_handler) {
679 ID = mouse_button_down_handler(&Main.event.button, pData);
681 break;
683 case SDL_MOUSEBUTTONUP:
684 if(mouse_button_up_handler) {
685 ID = mouse_button_up_handler(&Main.event.button, pData);
687 break;
689 case SDL_MOUSEMOTION:
690 if(mouse_motion_handler) {
691 ID = mouse_motion_handler(&Main.event.motion, pData);
693 break;
695 case SDL_USEREVENT:
696 switch(Main.event.user.code) {
697 case NET:
698 input_from_server(net_socket);
699 break;
700 case ANIM:
701 update_button_hold_state();
702 animate_mouse_cursor();
703 draw_mouse_cursor();
704 break;
705 case SHOW_WIDGET_INFO_LABBEL:
706 draw_widget_info_label();
707 break;
708 case TRY_AUTO_CONNECT:
709 if (try_to_autoconnect()) {
710 pInfo_User_Event->user.code = SHOW_WIDGET_INFO_LABBEL;
711 autoconnect = FALSE;
713 break;
714 case FLUSH:
715 unqueue_flush();
716 break;
717 case MAP_SCROLL:
718 scroll_mapview(scroll_dir);
719 break;
720 case EXIT_FROM_EVENT_LOOP:
721 return MAX_ID;
722 break;
723 default:
724 break;
726 break;
731 if (ID == ID_ERROR) {
732 if (callbacks && callback_list_size(callbacks) > 0) {
733 struct callback *cb = callback_list_get(callbacks, 0);
734 callback_list_remove(callbacks, cb);
735 (cb->callback)(cb->data);
736 free(cb);
741 return ID;
744 /* ============ Freeciv native game function =========== */
746 /**************************************************************************
747 Do any necessary pre-initialization of the UI, if necessary.
748 **************************************************************************/
749 void ui_init(void)
751 char device[20];
752 /* struct widget *pInit_String = NULL;*/
753 SDL_Surface *pBgd;
754 Uint32 iSDL_Flags;
756 button_behavior.counting = FALSE;
757 button_behavior.button_down_ticks = 0;
758 button_behavior.hold_state = MB_HOLD_SHORT;
759 button_behavior.event = fc_calloc(1, sizeof(SDL_MouseButtonEvent));
761 SDL_Client_Flags = 0;
762 iSDL_Flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
764 /* auto center new windows in X enviroment */
765 putenv((char *)"SDL_VIDEO_CENTERED=yes");
767 init_sdl(iSDL_Flags);
769 log_normal(_("Using Video Output: %s"),
770 SDL_VideoDriverName(device, sizeof(device)));
772 /* create splash screen */
773 #ifdef SMALL_SCREEN
775 SDL_Surface *pTmpSurf = load_surf(fileinfoname(get_data_dirs(),
776 "misc/intro.png"));
777 pBgd = zoomSurface(pTmpSurf, DEFAULT_ZOOM, DEFAULT_ZOOM, 0);
778 FREESURFACE(pTmpSurf);
780 #else /* SMALL_SCREEN */
781 pBgd = load_surf(fileinfoname(get_data_dirs(), "misc/intro.png"));
782 #endif /* SMALL_SCREEN */
784 if (pBgd && SDL_GetVideoInfo()->wm_available) {
785 set_video_mode(pBgd->w, pBgd->h, SDL_SWSURFACE | SDL_ANYFORMAT);
786 #if 0
788 * call this for other than X enviroments - currently not supported.
790 center_main_window_on_screen();
791 #endif /* 0 */
792 alphablit(pBgd, NULL, Main.map, NULL);
793 putframe(Main.map,
794 0, 0, Main.map->w - 1, Main.map->h - 1,
795 &(SDL_Color){255, 255, 255, 255});
796 FREESURFACE(pBgd);
797 SDL_WM_SetCaption(_("SDL Client for Freeciv"), _("Freeciv"));
798 } else {
800 #ifndef SMALL_SCREEN
801 set_video_mode(640, 480, SDL_SWSURFACE | SDL_ANYFORMAT);
802 #else /* SMALL_SCREEN */
803 set_video_mode(320, 240, SDL_SWSURFACE | SDL_ANYFORMAT);
804 #endif /* SMALL_SCREEN */
806 if(pBgd) {
807 blit_entire_src(pBgd, Main.map, (Main.map->w - pBgd->w) / 2,
808 (Main.map->h - pBgd->h) / 2);
809 FREESURFACE(pBgd);
810 } else {
811 SDL_FillRect(Main.map, NULL, SDL_MapRGB(Main.map->format, 0, 0, 128));
812 SDL_WM_SetCaption(_("SDL Client for Freeciv"), _("Freeciv"));
816 #if 0
817 /* create label beackground */
818 pBgd = create_surf_alpha(adj_size(350), adj_size(50), SDL_SWSURFACE);
820 SDL_FillRect(pBgd, NULL, SDL_MapRGBA(pBgd->format, 255, 255, 255, 128));
821 putframe(pBgd, 0, 0, pBgd->w - 1, pBgd->h - 1, SDL_MapRGB(pBgd->format, 0, 0, 0));
823 pInit_String = create_iconlabel(pBgd, Main.gui,
824 create_str16_from_char(_("Initializing Client"), adj_font(20)),
825 WF_ICON_CENTER|WF_FREE_THEME);
826 pInit_String->string16->style |= SF_CENTER;
828 draw_label(pInit_String,
829 (Main.screen->w - pInit_String->size.w) / 2,
830 (Main.screen->h - pInit_String->size.h) / 2);
832 flush_all();
834 copy_chars_to_string16(pInit_String->string16,
835 _("Waiting for the beginning of the game"));
837 #endif /* 0 */
839 flush_all();
842 /****************************************************************************
843 Really resize the main window.
844 ****************************************************************************/
845 static void real_resize_window_callback(void *data)
847 struct widget *widget;
848 Uint32 flags = Main.screen->flags;
850 if (gui_options.gui_sdl_fullscreen) {
851 flags |= SDL_FULLSCREEN;
852 } else {
853 flags &= ~SDL_FULLSCREEN;
855 set_video_mode(gui_options.gui_sdl_screen.width, gui_options.gui_sdl_screen.height,
856 flags);
858 if (C_S_RUNNING == client_state()) {
859 /* Move units window to botton-right corner. */
860 set_new_unitinfo_window_pos();
861 /* Move minimap window to botton-left corner. */
862 set_new_minimap_window_pos();
864 /* Move cooling/warming icons to botton-right corner. */
865 widget = get_widget_pointer_form_main_list(ID_WARMING_ICON);
866 widget_set_position(widget, (Main.screen->w - adj_size(10)
867 - (widget->size.w * 2)), widget->size.y);
869 widget = get_widget_pointer_form_main_list(ID_COOLING_ICON);
870 widget_set_position(widget, (Main.screen->w - adj_size(10)
871 - widget->size.w), widget->size.y);
873 map_canvas_resized(Main.screen->w, Main.screen->h);
874 update_info_label();
875 update_unit_info_label(get_units_in_focus());
876 center_on_something(); /* With redrawing full map. */
877 update_order_widgets();
878 } else {
879 draw_intro_gfx();
880 dirty_all();
882 flush_all();
885 /****************************************************************************
886 Resize the main window.
887 ****************************************************************************/
888 static void resize_window_callback(struct option *poption)
890 update_queue_add(real_resize_window_callback, NULL);
893 /****************************************************************************
894 Extra initializers for client options. Here we make set the callback
895 for the specific gui-sdl options.
896 ****************************************************************************/
897 void options_extra_init(void)
899 struct option *poption;
901 #define option_var_set_callback(var, callback) \
902 if ((poption = optset_option_by_name(client_optset, #var))) { \
903 option_set_changed_callback(poption, callback); \
904 } else { \
905 log_error("Didn't find option %s!", #var); \
908 option_var_set_callback(gui_sdl_fullscreen, resize_window_callback);
909 option_var_set_callback(gui_sdl_screen, resize_window_callback);
910 #undef option_var_set_callback
913 /**************************************************************************
914 Remove double messages caused by message configured to both MW_MESSAGES
915 and MW_OUTPUT.
916 **************************************************************************/
917 static void clear_double_messages_call(void)
919 int i;
920 /* clear double call */
921 for(i = 0; i <= event_type_max(); i++) {
922 if (messages_where[i] & MW_MESSAGES) {
923 messages_where[i] &= ~MW_OUTPUT;
928 /**************************************************************************
929 Entry point for freeciv client program. SDL has macro magic to turn
930 this in to function named SDL_main() and it provides actual main()
931 itself.
932 **************************************************************************/
933 int main(int argc, char **argv)
935 return client_main(argc, argv);
938 /**************************************************************************
939 The main loop for the UI. This is called from main(), and when it
940 exits the client will exit.
941 **************************************************************************/
942 void ui_main(int argc, char *argv[])
944 SDL_Event __Net_User_Event;
945 SDL_Event __Anim_User_Event;
946 SDL_Event __Info_User_Event;
947 SDL_Event __Flush_User_Event;
948 SDL_Event __pMap_Scroll_User_Event;
950 parse_options(argc, argv);
952 __Net_User_Event.type = SDL_USEREVENT;
953 __Net_User_Event.user.code = NET;
954 __Net_User_Event.user.data1 = NULL;
955 __Net_User_Event.user.data2 = NULL;
956 pNet_User_Event = &__Net_User_Event;
958 __Anim_User_Event.type = SDL_USEREVENT;
959 __Anim_User_Event.user.code = EVENT_ERROR;
960 __Anim_User_Event.user.data1 = NULL;
961 __Anim_User_Event.user.data2 = NULL;
962 pAnim_User_Event = &__Anim_User_Event;
964 __Info_User_Event.type = SDL_USEREVENT;
965 __Info_User_Event.user.code = SHOW_WIDGET_INFO_LABBEL;
966 __Info_User_Event.user.data1 = NULL;
967 __Info_User_Event.user.data2 = NULL;
968 pInfo_User_Event = &__Info_User_Event;
970 __Flush_User_Event.type = SDL_USEREVENT;
971 __Flush_User_Event.user.code = FLUSH;
972 __Flush_User_Event.user.data1 = NULL;
973 __Flush_User_Event.user.data2 = NULL;
974 pFlush_User_Event = &__Flush_User_Event;
976 __pMap_Scroll_User_Event.type = SDL_USEREVENT;
977 __pMap_Scroll_User_Event.user.code = MAP_SCROLL;
978 __pMap_Scroll_User_Event.user.data1 = NULL;
979 __pMap_Scroll_User_Event.user.data2 = NULL;
980 pMap_Scroll_User_Event = &__pMap_Scroll_User_Event;
982 is_unit_move_blocked = FALSE;
984 SDL_Client_Flags |= (CF_DRAW_PLAYERS_NEUTRAL_STATUS|
985 CF_DRAW_PLAYERS_WAR_STATUS|
986 CF_DRAW_PLAYERS_CEASEFIRE_STATUS|
987 CF_DRAW_PLAYERS_PEACE_STATUS|
988 CF_DRAW_PLAYERS_ALLIANCE_STATUS);
990 tileset_init(tileset);
991 tileset_load_tiles(tileset);
992 tileset_use_preferred_theme(tileset);
994 load_cursors();
996 callbacks = callback_list_new();
998 diplomacy_dialog_init();
999 intel_dialog_init();
1001 clear_double_messages_call();
1003 setup_auxiliary_tech_icons();
1005 if (gui_options.gui_sdl_fullscreen) {
1006 #ifdef SMALL_SCREEN
1007 #ifdef UNDER_CE
1008 /* set 320x240 fullscreen */
1009 set_video_mode(gui_options.gui_sdl_screen.width,
1010 gui_options.gui_sdl_screen.height,
1011 SDL_SWSURFACE | SDL_ANYFORMAT | SDL_FULLSCREEN);
1012 #else /* UNDER_CE */
1013 /* small screen on desktop -> don't set 320x240 fullscreen mode */
1014 set_video_mode(gui_options.gui_sdl_screen.width,
1015 gui_options.gui_sdl_screen.height,
1016 SDL_SWSURFACE | SDL_ANYFORMAT);
1017 #endif /* UNDER_CE */
1018 #else /* SMALL_SCREEN */
1019 set_video_mode(gui_options.gui_sdl_screen.width,
1020 gui_options.gui_sdl_screen.height,
1021 SDL_SWSURFACE | SDL_ANYFORMAT | SDL_FULLSCREEN);
1022 #endif /* SMALL_SCREEN */
1024 } else {
1026 #ifdef SMALL_SCREEN
1027 #ifdef UNDER_CE
1028 set_video_mode(gui_options.gui_sdl_screen.width,
1029 gui_options.gui_sdl_screen.height,
1030 SDL_SWSURFACE | SDL_ANYFORMAT);
1031 #else /* UNDER_CE */
1032 set_video_mode(gui_options.gui_sdl_screen.width,
1033 gui_options.gui_sdl_screen.height,
1034 SDL_SWSURFACE | SDL_ANYFORMAT);
1035 #endif /* UNDER_CE */
1036 #else /* SMALL_SCREEN */
1037 set_video_mode(gui_options.gui_sdl_screen.width,
1038 gui_options.gui_sdl_screen.height,
1039 SDL_SWSURFACE | SDL_ANYFORMAT);
1040 #endif /* SMALL_SCREEN */
1042 #if 0
1044 * call this for other that X enviroments - currently not supported.
1046 center_main_window_on_screen();
1047 #endif /* 0 */
1050 /* SDL_WM_SetCaption(_("SDL Client for Freeciv"), _("Freeciv")); */
1052 /* this need correct Main.screen size */
1053 init_mapcanvas_and_overview();
1055 set_client_state(C_S_DISCONNECTED);
1057 /* Main game loop */
1058 gui_event_loop(NULL, NULL, main_key_down_handler, main_key_up_handler,
1059 main_mouse_button_down_handler, main_mouse_button_up_handler,
1060 main_mouse_motion_handler);
1061 start_quitting();
1064 /**************************************************************************
1065 Do any necessary UI-specific cleanup
1066 **************************************************************************/
1067 void ui_exit()
1070 #if defined UNDER_CE && defined SMALL_SCREEN
1071 /* change back to window mode to restore the title bar */
1072 set_video_mode(320, 240, SDL_SWSURFACE | SDL_ANYFORMAT);
1073 #endif
1075 free_mapcanvas_and_overview();
1077 free_auxiliary_tech_icons();
1078 free_intro_radar_sprites();
1080 diplomacy_dialog_done();
1081 intel_dialog_done();
1083 callback_list_destroy(callbacks);
1085 unload_cursors();
1087 FC_FREE(button_behavior.event);
1089 meswin_dialog_popdown();
1091 del_main_list();
1093 free_font_system();
1094 theme_free(theme);
1096 quit_sdl();
1099 /**************************************************************************
1100 Return our GUI type
1101 **************************************************************************/
1102 enum gui_type get_gui_type(void)
1104 return GUI_SDL;
1107 /**************************************************************************
1108 Make a bell noise (beep). This provides low-level sound alerts even
1109 if there is no real sound support.
1110 **************************************************************************/
1111 void sound_bell(void)
1113 log_debug("sound_bell : PORT ME");
1116 /**************************************************************************
1117 Show Focused Unit Animation.
1118 **************************************************************************/
1119 void enable_focus_animation(void)
1121 pAnim_User_Event->user.code = ANIM;
1122 SDL_Client_Flags |= CF_FOCUS_ANIMATION;
1125 /**************************************************************************
1126 Don't show Focused Unit Animation.
1127 **************************************************************************/
1128 void disable_focus_animation(void)
1130 SDL_Client_Flags &= ~CF_FOCUS_ANIMATION;
1133 /**************************************************************************
1134 Wait for data on the given socket. Call input_from_server() when data
1135 is ready to be read.
1136 **************************************************************************/
1137 void add_net_input(int sock)
1139 log_debug("Connection UP (%d)", sock);
1140 net_socket = sock;
1141 autoconnect = FALSE;
1142 enable_focus_animation();
1145 /**************************************************************************
1146 Stop waiting for any server network data. See add_net_input().
1147 **************************************************************************/
1148 void remove_net_input(void)
1150 log_debug("Connection DOWN... ");
1151 net_socket = (-1);
1152 disable_focus_animation();
1153 draw_goto_patrol_lines = FALSE;
1154 update_mouse_cursor(CURSOR_DEFAULT);
1157 /****************************************************************************
1158 Enqueue a callback to be called during an idle moment. The 'callback'
1159 function should be called sometimes soon, and passed the 'data' pointer
1160 as its data.
1161 ****************************************************************************/
1162 void add_idle_callback(void (callback)(void *), void *data)
1164 struct callback *cb = fc_malloc(sizeof(*cb));
1166 cb->callback = callback;
1167 cb->data = data;
1169 callback_list_prepend(callbacks, cb);
1172 /****************************************************************************
1173 Stub for editor function
1174 ****************************************************************************/
1175 void editgui_tileset_changed(void)
1178 /****************************************************************************
1179 Stub for editor function
1180 ****************************************************************************/
1181 void editgui_refresh(void)
1184 /****************************************************************************
1185 Stub for editor function
1186 ****************************************************************************/
1187 void editgui_popup_properties(const struct tile_list *tiles, int objtype)
1190 /****************************************************************************
1191 Stub for editor function
1192 ****************************************************************************/
1193 void editgui_popdown_all(void)
1196 /****************************************************************************
1197 Stub for editor function
1198 ****************************************************************************/
1199 void editgui_notify_object_changed(int objtype, int object_id, bool removal)
1202 /****************************************************************************
1203 Stub for editor function
1204 ****************************************************************************/
1205 void editgui_notify_object_created(int tag, int id)
1208 /**************************************************************************
1209 Updates a gui font style.
1210 **************************************************************************/
1211 void gui_update_font(const char *font_name, const char *font_value)
1213 /* PORTME */
1216 /**************************************************************************
1217 Insert build information to help
1218 **************************************************************************/
1219 void insert_client_build_info(char *outbuf, size_t outlen)
1221 /* PORTME */
1224 /**************************************************************************
1225 Make dynamic adjustments to first-launch default options.
1226 **************************************************************************/
1227 void adjust_default_options(void)
1229 /* Nothing in case of this gui */