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)
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 ***********************************************************************/
15 #include <fc_config.h>
36 #include "mpcmdline.h"
41 static GtkWidget
*statusbar
;
42 static GtkWidget
*progressbar
;
43 static GtkWidget
*main_list
;
44 static GtkListStore
*main_store
;
45 static GtkWidget
*URL_input
;
46 static gboolean downloading
= FALSE
;
48 struct fcmp_params fcmp
= {
49 .list_url
= MODPACK_LIST_URL
,
54 static gboolean
quit_dialog_callback(void);
60 #define ML_COL_SUBTYPE 4
64 #define ML_COL_COUNT 7
68 #define ML_STORE_SIZE 9
70 /****************************************************************
72 ****************************************************************/
73 static void modinst_quit(void)
75 save_install_info_lists(&fcmp
);
77 registry_module_close();
83 /****************************************************************
84 This is the response callback for the dialog with the message:
85 Are you sure you want to quit?
86 ****************************************************************/
87 static void quit_dialog_response(GtkWidget
*dialog
, gint response
)
89 gtk_widget_destroy(dialog
);
90 if (response
== GTK_RESPONSE_YES
) {
95 /****************************************************************
96 Popups the quit dialog if
97 ****************************************************************/
98 static gboolean
quit_dialog_callback(void)
101 /* Download in progress. Confirm quit from user. */
102 static GtkWidget
*dialog
;
105 dialog
= gtk_message_dialog_new(NULL
,
109 _("Are you sure you want to quit?"));
111 gtk_window_set_position(GTK_WINDOW(dialog
), GTK_WIN_POS_MOUSE
);
113 g_signal_connect(dialog
, "response",
114 G_CALLBACK(quit_dialog_response
), NULL
);
115 g_signal_connect(dialog
, "destroy",
116 G_CALLBACK(gtk_widget_destroyed
), &dialog
);
119 gtk_window_present(GTK_WINDOW(dialog
));
122 /* User loses no work by quitting, so let's not annoy him/her
123 * with confirmation dialog. */
127 /* Stop emission of event. */
131 /**************************************************************************
132 Progress indications from downloader
133 **************************************************************************/
134 static void msg_callback(const char *msg
)
136 gtk_label_set_text(GTK_LABEL(statusbar
), msg
);
139 /**************************************************************************
140 Progress indications from downloader
141 **************************************************************************/
142 static void pbar_callback(int downloaded
, int max
)
144 /* Control file already downloaded */
145 double fraction
= (double) downloaded
/ (max
);
147 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressbar
), fraction
);
155 /**************************************************************************
156 Main thread handling of message sent from downloader thread.
157 **************************************************************************/
158 static gboolean
msg_main_thread(gpointer user_data
)
160 struct msg_data
*data
= (struct msg_data
*)user_data
;
162 msg_callback(data
->msg
);
169 /**************************************************************************
170 Downloader thread message callback.
171 **************************************************************************/
172 static void msg_dl_thread(const char *msg
)
174 struct msg_data
*data
= fc_malloc(sizeof(*data
));
178 gdk_threads_add_idle(msg_main_thread
, data
);
186 /**************************************************************************
187 Main thread handling of progressbar update sent from downloader thread.
188 **************************************************************************/
189 static gboolean
pbar_main_thread(gpointer user_data
)
191 struct pbar_data
*data
= (struct pbar_data
*)user_data
;
193 pbar_callback(data
->current
, data
->max
);
200 /**************************************************************************
201 Downloader thread progress bar callback.
202 **************************************************************************/
203 static void pbar_dl_thread(int current
, int max
)
205 struct pbar_data
*data
= fc_malloc(sizeof(*data
));
207 data
->current
= current
;
210 gdk_threads_add_idle(pbar_main_thread
, data
);
213 /**************************************************************************
214 Main thread handling of versionlist update requested by downloader thread
215 **************************************************************************/
216 static gboolean
versionlist_update_main_thread(gpointer user_data
)
220 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(main_store
), &iter
)) {
222 const char *name_str
;
224 const char *new_inst
;
225 enum modpack_type type
;
227 gtk_tree_model_get(GTK_TREE_MODEL(main_store
), &iter
,
228 ML_COL_NAME
, &name_str
,
234 new_inst
= get_installed_version(name_str
, type
);
236 if (new_inst
== NULL
) {
237 new_inst
= _("Not installed");
240 gtk_list_store_set(main_store
, &iter
,
241 ML_COL_INST
, new_inst
,
244 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(main_store
), &iter
));
250 /**************************************************************************
251 Downloader thread requests versionlist update.
252 **************************************************************************/
253 static void versionlist_update_dl_thread(void)
255 gdk_threads_add_idle(versionlist_update_main_thread
, NULL
);
259 /**************************************************************************
260 Entry point for downloader thread
261 **************************************************************************/
262 static gpointer
download_thread(gpointer data
)
266 errmsg
= download_modpack(data
, &fcmp
, msg_dl_thread
, pbar_dl_thread
);
268 if (errmsg
== NULL
) {
269 msg_dl_thread(_("Ready"));
271 msg_dl_thread(errmsg
);
276 versionlist_update_dl_thread();
283 /**************************************************************************
284 Download modpack, display error message dialogs
285 **************************************************************************/
286 static void gui_download_modpack(const char *URL
)
292 gtk_label_set_text(GTK_LABEL(statusbar
),
293 _("Another download already active"));
299 URLbuf
= fc_malloc(strlen(URL
) + 1);
303 downloader
= g_thread_create(download_thread
, URLbuf
, FALSE
, NULL
);
304 if (downloader
== NULL
) {
305 gtk_label_set_text(GTK_LABEL(statusbar
),
306 _("Failed to start downloader"));
311 /**************************************************************************
312 Install modpack button clicked
313 **************************************************************************/
314 static void install_clicked(GtkWidget
*w
, gpointer data
)
316 GtkEntry
*URL_in
= data
;
317 const char *URL
= gtk_entry_get_text(URL_in
);
319 gui_download_modpack(URL
);
322 /**************************************************************************
324 **************************************************************************/
325 static void URL_return(GtkEntry
*w
, gpointer data
)
329 URL
= gtk_entry_get_text(w
);
330 gui_download_modpack(URL
);
333 /**************************************************************************
334 Callback for getting main list row tooltip
335 **************************************************************************/
336 static gboolean
query_main_list_tooltip_cb(GtkWidget
*widget
,
338 gboolean keyboard_tip
,
343 GtkTreeView
*tree_view
= GTK_TREE_VIEW(widget
);
347 if (!gtk_tree_view_get_tooltip_context(tree_view
, &x
, &y
,
349 &model
, NULL
, &iter
)) {
353 gtk_tree_model_get(model
, &iter
,
358 gtk_tooltip_set_markup(tooltip
, notes
);
366 /**************************************************************************
367 Build main modpack list view
368 **************************************************************************/
369 static void setup_modpack_list(const char *name
, const char *URL
,
370 const char *version
, const char *license
,
371 enum modpack_type type
, const char *subtype
,
375 const char *type_str
;
377 const char *inst_str
;
379 if (modpack_type_is_valid(type
)) {
380 type_str
= _(modpack_type_name(type
));
382 /* TRANS: Unknown modpack type */
386 if (license
!= NULL
) {
389 /* TRANS: License of modpack is not known */
390 lic_str
= Q_("?license:Unknown");
393 inst_str
= get_installed_version(name
, type
);
394 if (inst_str
== NULL
) {
395 inst_str
= _("Not installed");
398 gtk_list_store_append(main_store
, &iter
);
399 gtk_list_store_set(main_store
, &iter
,
402 ML_COL_INST
, inst_str
,
403 ML_COL_TYPE
, type_str
,
404 ML_COL_SUBTYPE
, subtype
,
412 /**************************************************************************
413 Callback called when entry from main modpack list selected
414 **************************************************************************/
415 static void select_from_list(GtkTreeSelection
*select
, gpointer data
)
421 if (!gtk_tree_selection_get_selected(select
, &model
, &it
)) {
425 gtk_tree_model_get(model
, &it
, ML_COL_URL
, &URL
, -1);
427 gtk_entry_set_text(GTK_ENTRY(URL_input
), URL
);
430 /**************************************************************************
432 **************************************************************************/
433 static void modinst_setup_widgets(GtkWidget
*toplevel
)
435 GtkWidget
*mbox
, *Ubox
;
436 GtkWidget
*version_label
;
437 GtkWidget
*install_button
, *install_label
;
438 GtkWidget
*URL_label
;
439 GtkCellRenderer
*renderer
;
440 GtkTreeSelection
*selection
;
443 const char *rev_ver
= fc_svn_revision();
445 mbox
= gtk_vbox_new(FALSE
, 4);
447 if (rev_ver
== NULL
) {
448 rev_ver
= fc_git_revision();
450 if (rev_ver
== NULL
) {
451 fc_snprintf(verbuf
, sizeof(verbuf
), "%s%s", word_version(), VERSION_STRING
);
453 fc_snprintf(verbuf
, sizeof(verbuf
), _("%s%s\ncommit: %s"),
454 word_version(), VERSION_STRING
, rev_ver
);
457 fc_snprintf(verbuf
, sizeof(verbuf
), "%s%s (%s)", word_version(), VERSION_STRING
,
461 version_label
= gtk_label_new(verbuf
);
463 main_list
= gtk_tree_view_new();
464 renderer
= gtk_cell_renderer_text_new();
465 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(main_list
),
467 _("Name"), renderer
, "text", 0,
469 renderer
= gtk_cell_renderer_text_new();
470 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(main_list
),
472 _("Version"), renderer
, "text", 1,
474 renderer
= gtk_cell_renderer_text_new();
475 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(main_list
),
477 _("Installed"), renderer
, "text", 2,
479 renderer
= gtk_cell_renderer_text_new();
480 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(main_list
),
485 renderer
= gtk_cell_renderer_text_new();
486 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(main_list
),
491 renderer
= gtk_cell_renderer_text_new();
492 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(main_list
),
495 _("License"), renderer
, "text", 5,
497 renderer
= gtk_cell_renderer_text_new();
498 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(main_list
),
500 _("URL"), renderer
, "text", 6,
502 selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(main_list
));
503 g_signal_connect(selection
, "changed", G_CALLBACK(select_from_list
), NULL
);
505 install_button
= gtk_button_new();
506 install_label
= gtk_label_new(_("Install modpack"));
507 gtk_label_set_mnemonic_widget(GTK_LABEL(install_label
), install_button
);
508 g_object_set_data(G_OBJECT(install_button
), "label", install_label
);
509 gtk_container_add(GTK_CONTAINER(install_button
), install_label
);
511 Ubox
= gtk_hbox_new(FALSE
, 4);
512 URL_label
= gtk_label_new_with_mnemonic(_("Modpack URL"));
514 URL_input
= gtk_entry_new();
515 gtk_entry_set_width_chars(GTK_ENTRY(URL_input
),
516 strlen(EXAMPLE_URL
));
517 gtk_entry_set_text(GTK_ENTRY(URL_input
), DEFAULT_URL_START
);
518 g_signal_connect(URL_input
, "activate",
519 G_CALLBACK(URL_return
), NULL
);
521 g_signal_connect(install_button
, "clicked",
522 G_CALLBACK(install_clicked
), URL_input
);
524 gtk_box_pack_start(GTK_BOX(Ubox
), URL_label
, TRUE
, TRUE
, 0);
525 gtk_box_pack_end(GTK_BOX(Ubox
), URL_input
, TRUE
, TRUE
, 0);
527 progressbar
= gtk_progress_bar_new();
529 statusbar
= gtk_label_new(_("Select modpack to install"));
531 gtk_box_pack_start(GTK_BOX(mbox
), version_label
, TRUE
, TRUE
, 0);
532 gtk_box_pack_start(GTK_BOX(mbox
), main_list
, TRUE
, TRUE
, 0);
533 gtk_box_pack_start(GTK_BOX(mbox
), Ubox
, TRUE
, TRUE
, 0);
534 gtk_box_pack_start(GTK_BOX(mbox
), install_button
, TRUE
, TRUE
, 0);
535 gtk_box_pack_start(GTK_BOX(mbox
), progressbar
, TRUE
, TRUE
, 0);
536 gtk_box_pack_end(GTK_BOX(mbox
), statusbar
, TRUE
, TRUE
, 0);
538 gtk_container_add(GTK_CONTAINER(toplevel
), mbox
);
540 main_store
= gtk_list_store_new((ML_STORE_SIZE
), G_TYPE_STRING
, G_TYPE_STRING
,
541 G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_STRING
,
542 G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_INT
,
544 errmsg
= download_modpack_list(&fcmp
, setup_modpack_list
, msg_callback
);
545 gtk_tree_view_set_model(GTK_TREE_VIEW(main_list
), GTK_TREE_MODEL(main_store
));
547 g_object_set(main_list
, "has-tooltip", TRUE
, NULL
);
548 g_signal_connect(main_list
, "query-tooltip",
549 G_CALLBACK(query_main_list_tooltip_cb
), NULL
);
551 g_object_unref(main_store
);
553 if (errmsg
!= NULL
) {
554 gtk_label_set_text(GTK_LABEL(statusbar
), errmsg
);
558 /**************************************************************************
559 Entry point of the freeciv-modpack program
560 **************************************************************************/
561 int main(int argc
, char *argv
[])
564 int loglevel
= LOG_NORMAL
;
568 init_character_encodings(FC_DEFAULT_DATA_ENCODING
, FALSE
);
569 registry_module_init();
575 log_init(NULL
, loglevel
, NULL
, NULL
, -1);
577 /* This modifies argv! */
578 ui_options
= fcmp_parse_cmdline(argc
, argv
);
580 if (ui_options
!= -1) {
582 load_install_info_lists(&fcmp
);
584 /* Process GTK arguments */
585 gtk_init(&ui_options
, &argv
);
587 toplevel
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
589 gtk_widget_realize(toplevel
);
590 gtk_widget_set_name(toplevel
, "Freeciv-modpack");
591 gtk_window_set_title(GTK_WINDOW(toplevel
),
592 _("Freeciv modpack installer (gtk2)"));
594 /* Keep the icon of the executable on Windows */
597 /* Unlike main client, this only works if installed. Ignore any
598 * errors loading the icon. */
600 (void) gtk_window_set_icon_from_file(GTK_WINDOW(toplevel
), MPICON_PATH
,
603 #endif /* WIN32_NATIVE */
605 g_signal_connect(toplevel
, "delete_event",
606 G_CALLBACK(quit_dialog_callback
), NULL
);
608 modinst_setup_widgets(toplevel
);
610 gtk_widget_show_all(toplevel
);
612 if (fcmp
.autoinstall
!= NULL
) {
613 gui_download_modpack(fcmp
.autoinstall
);
618 save_install_info_lists(&fcmp
);