Project

General

Profile

Feature #1686 » 0018-Drop-gtk4x-sources.patch

Marko Lindqvist, 09/17/2025 08:17 PM

View differences:

bootstrap/org.freeciv.gtk4x.desktop
[Desktop Entry]
Name=Freeciv
Name[ca]=Freeciv
Name[es]=Freeciv
Name[fr]=Freeciv
Name[nb]=Freeciv
Name[pt]=Freeciv
Name[ru]=Freeciv
Comment=Turn-based strategy game inspired by the history of human civilization
Comment[ca]=Joc d'estratègia inspirat en la història de la civilització humana
Comment[da]=Strategispil inspireret af den menneskelige civilisations historie
Comment[de]=Rundenbasiertes Strategiespiel, inspiriert durch die Geschichte der menschlichen Zivilisation
Comment[fi]=Ihmiskunnan historian inspiroima vuoropohjainen strategiapeli
Comment[nb]=Strategispill inspirert av historien til menneskelig sivilisasjon
Comment[pt]=Jogo de estratégia por turnos inspirado na História da civilização humana
Comment[ru]=Пошаговая стратегическая игра, вдохновлённая историей человеческой цивилизации
Comment[sv]=Turordningsbaserat strategispel inspirerat av den mänskliga historien
Exec=freeciv-gtk4x
Icon=freeciv-client
StartupNotify=true
Terminal=false
Type=Application
Categories=GTK;Game;StrategyGame;
Keywords=strategy;simulation;civilization;tiles;history;mankind;multiplayer;
bootstrap/org.freeciv.gtk4x.metainfo.xml.in
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<name>Freeciv gtk4x client</name>
<id>org.freeciv.gtk4x</id>
<project_license>GPL-2.0-or-later</project_license>
<metadata_license>CC0</metadata_license>
<developer id="org.freeciv">
<name>Freeciv Team</name>
</developer>
<summary>Gtk4 based client for the Freeciv game</summary>
<description>
<p>
Freeciv is a Free and Open Source empire-building strategy game inspired by the history of human civilization. The game commences in prehistory and your
mission is to lead your tribe from the Stone Age to the Space Age...
</p>
<p>
This client for connecting to network games, or to launch local single-player games, is based on gtk4 widget set.
</p>
</description>
<launchable type="desktop-id">org.freeciv.gtk4x.desktop</launchable>
<url type="homepage">https://www.freeciv.org/</url>
<url type="bugtracker">https://osdn.net/projects/freeciv/ticket/</url>
<url type="faq">https://www.freeciv.org/wiki/FAQ</url>
<url type="donation">https://www.freeciv.org/donate.html</url>
<url type="translate">https://www.freeciv.org/wiki/Translations</url>
<url type="contact">https://www.freeciv.org/maillists.html</url>
<!-- flatpak does not understand these
<url type="vcs-browser">https://github.com/freeciv/freeciv/</url>
<url type="contribute">https://www.freeciv.org/wiki/How_to_Contribute</url>
-->
<releases>
[release]
</releases>
<content_rating type="oars-1.0">
<content_attribute id="social-chat">intense</content_attribute>
</content_rating>
<screenshots>
<screenshot type="default">
<image>https://files.freeciv.org/screenshots/3.1/client.gtk4-3.1.0-beta2.png</image>
</screenshot>
</screenshots>
<update_contact>freeciv-dev@freelists.org</update_contact>
</component>
bootstrap/org.freeciv.gtk4x.mp.desktop
[Desktop Entry]
Name=Freeciv modpack installer (gtk4x)
Name[ru]=Установщик модпаков Freeciv (gtk4x)
Comment=Download and install add-ons for Freeciv
Comment[ru]=Скачивайте и устанавливайте дополнения для Freeciv
Exec=freeciv-mp-gtk4x
Icon=freeciv-modpack
StartupNotify=true
Terminal=false
Type=Application
Categories=GTK;Game;StrategyGame;
Keywords=strategy;simulation;civilization;tiles;history;mankind;multiplayer;download;installer;
bootstrap/org.freeciv.gtk4x.mp.metainfo.xml.in
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<name>Freeciv gtk-4+ modpack installer</name>
<id>org.freeciv.gtk4x.mp</id>
<project_license>GPL-2.0-or-later</project_license>
<metadata_license>CC0</metadata_license>
<developer id="org.freeciv">
<name>Freeciv Team</name>
</developer>
<summary>Gtk-4 based modpack installer for the Freeciv game</summary>
<description>
<p>
Freeciv is a Free and Open Source empire-building strategy game inspired by the history of human civilization. The game commences in prehistory and your
mission is to lead your tribe from the Stone Age to the Space Age...
</p>
<p>
Freeciv modpack utility can be used to automatically download and install custom rulesets, tilesets, soundsets, and maps for freeciv to use.
</p>
</description>
<launchable type="desktop-id">org.freeciv.gtk4x.mp.desktop</launchable>
<url type="homepage">https://www.freeciv.org/</url>
<url type="bugtracker">https://osdn.net/projects/freeciv/ticket/</url>
<url type="faq">https://www.freeciv.org/wiki/FAQ</url>
<url type="donation">https://www.freeciv.org/donate.html</url>
<url type="translate">https://www.freeciv.org/wiki/Translations</url>
<url type="contact">https://www.freeciv.org/maillists.html</url>
<!-- flatpak does not understand these
<url type="vcs-browser">https://github.com/freeciv/freeciv/</url>
<url type="contribute">https://www.freeciv.org/wiki/How_to_Contribute</url>
-->
<releases>
[release]
</releases>
<content_rating type="oars-1.0" />
<screenshots>
<screenshot type="default">
<image>https://files.freeciv.org/screenshots/3.0/modinst.gtk4-3.0.6.png</image>
</screenshot>
</screenshots>
<update_contact>freeciv-dev@freelists.org</update_contact>
</component>
client/gui-gtk-5.0/.gitignore
/Makefile.in
client/gui-gtk-5.0/Makefile.am
## Process this file with automake to produce Makefile.in
noinst_LTLIBRARIES = libgui-gtk5.la
AM_CPPFLAGS = \
-I$(srcdir)/.. \
-I$(srcdir)/../include \
-I$(top_srcdir)/utility \
-I$(top_srcdir)/common \
-I$(top_srcdir)/common/aicore \
-I$(top_srcdir)/common/networking \
-I$(top_srcdir)/common/scriptcore \
-I$(srcdir)/../agents \
-I$(srcdir)/../luascript \
-I$(top_srcdir)/dependencies/tinycthread \
-I$(top_srcdir)/gen_headers/enums \
$(gui_gtk5_cflags) $(SOUND_CFLAGS)
libgui_gtk5_la_SOURCES = \
action_dialog.c \
canvas.c \
canvas.h \
chatline.h \
chatline.c \
choice_dialog.c \
choice_dialog.h \
citizensinfo.c \
citizensinfo.h \
citydlg.c \
citydlg.h \
cityrep.c \
cityrep.h \
cma_fe.c \
cma_fe.h \
colors.c \
colors.h \
connectdlg.c \
connectdlg.h \
dialogs.c \
dialogs.h \
diplodlg.c \
diplodlg.h \
editgui.c \
editgui.h \
editprop.c \
editprop.h \
finddlg.c \
finddlg.h \
gamedlgs.c \
gamedlgs.h \
gotodlg.c \
gotodlg.h \
graphics.c \
graphics.h \
gui_main.c \
gui_main.h \
gui_stuff.c \
gui_stuff.h \
happiness.c \
happiness.h \
helpdlg.c \
helpdlg.h \
infradlg.c \
infradlg.h \
inputdlg.c \
inputdlg.h \
inteldlg.c \
inteldlg.h \
luaconsole.c \
luaconsole.h \
mapctrl.c \
mapctrl.h \
mapview.c \
mapview.h \
menu.c \
menu.h \
messagedlg.c \
messagedlg.h \
messagewin.c \
messagewin.h \
optiondlg.c \
optiondlg.h \
pages.c \
pages.h \
plrdlg.c \
plrdlg.h \
rallypointdlg.c \
rallypointdlg.h \
ratesdlg.h \
repodlgs.c \
repodlgs.h \
soundset_dlg.c \
spaceshipdlg.c \
spaceshipdlg.h \
sprite.c \
sprite.h \
theme_dlg.c \
themes.c \
tileset_dlg.c \
transportdlg.c \
transportdlg.h \
unitselextradlg.c \
unitselextradlg.h \
unitselunitdlg.c \
unitselunitdlg.h \
unitselect.h \
unitselect.c \
voteinfo_bar.c \
voteinfo_bar.h \
wldlg.c \
wldlg.h
libgui_gtk5_la_LIBADD = -lm
client/gui-gtk-5.0/action_dialog.c
/***********************************************************************
Freeciv - Copyright (C) 1996-2005 - Freeciv Development Team
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
***********************************************************************/
#ifdef HAVE_CONFIG_H
#include <fc_config.h>
#endif
#include <gtk/gtk.h>
/* utility */
#include "astring.h"
#include "support.h"
/* common */
#include "actions.h"
#include "game.h"
#include "traderoutes.h"
#include "movement.h"
#include "research.h"
#include "unit.h"
#include "unitlist.h"
/* client */
#include "dialogs_g.h"
#include "chatline.h"
#include "choice_dialog.h"
#include "client_main.h"
#include "climisc.h"
#include "connectdlg_common.h"
#include "control.h"
#include "gui_main.h"
#include "gui_stuff.h"
#include "mapview.h"
#include "packhand.h"
#include "text.h"
/* client/gui-gtk-5.0 */
#include "citydlg.h"
#include "dialogs.h"
#include "unitselextradlg.h"
#include "unitselunitdlg.h"
#include "wldlg.h"
/* Locations for non action enabler controlled buttons. */
#define BUTTON_NEW_UNIT_TGT (ACTION_COUNT + 1)
#define BUTTON_NEW_EXTRA_TGT (BUTTON_NEW_UNIT_TGT + 1)
#define BUTTON_LOCATION (BUTTON_NEW_EXTRA_TGT + 1)
#define BUTTON_WAIT (BUTTON_LOCATION + 1)
#define BUTTON_CANCEL (BUTTON_WAIT + 1)
#define BUTTON_COUNT (BUTTON_CANCEL + 1)
#define BUTTON_NOT_THERE -1
static GtkWidget *act_sel_dialog;
static int action_button_map[BUTTON_COUNT];
static int actor_unit_id;
static int target_ids[ATK_COUNT];
static int target_extra_id;
static bool is_more_user_input_needed = FALSE;
static bool did_not_decide = FALSE;
static bool action_selection_restart = FALSE;
static GtkWidget *spy_tech_shell;
static GtkWidget *spy_sabotage_shell;
/* A structure to hold parameters for actions inside the GUI instead of
* storing the needed data in a global variable. */
struct action_data {
action_id act_id;
int actor_unit_id;
int target_city_id;
int target_unit_id;
int target_tile_id;
int target_building_id;
int target_tech_id;
int target_extra_id;
};
/* TODO: Maybe this should be in the dialog itself? */
static struct action_data *act_sel_dialog_data;
#define FC_TYPE_ACTION_ROW (fc_action_row_get_type())
G_DECLARE_FINAL_TYPE(FcActionRow, fc_action_row, FC, ACTION_ROW, GObject)
struct _FcActionRow
{
GObject parent_instance;
char *name;
int id;
};
struct _FcActionRowClass
{
GObjectClass parent_class;
};
G_DEFINE_TYPE(FcActionRow, fc_action_row, G_TYPE_OBJECT)
/**********************************************************************//**
Finalizing method for FcActionRow
**************************************************************************/
static void fc_action_row_finalize(GObject *gobject)
{
FcActionRow *row = FC_ACTION_ROW(gobject);
free(row->name);
row->name = nullptr;
G_OBJECT_CLASS(fc_action_row_parent_class)->finalize(gobject);
}
/**********************************************************************//**
Initialization method for FcActionRow class
**************************************************************************/
static void
fc_action_row_class_init(FcActionRowClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->finalize = fc_action_row_finalize;
}
/**********************************************************************//**
Initialization method for FcActionRow
**************************************************************************/
static void
fc_action_row_init(FcActionRow *self)
{
self->name = nullptr;
}
/**********************************************************************//**
FcActionRow creation method
**************************************************************************/
static FcActionRow *fc_action_row_new(void)
{
FcActionRow *result;
result = g_object_new(FC_TYPE_ACTION_ROW, nullptr);
return result;
}
/**********************************************************************//**
Create a new action data structure that can be stored in the
dialogs.
**************************************************************************/
static struct action_data *act_data(action_id act_id,
int actor_id,
int target_city_id,
int target_unit_id,
int target_tile_id,
int target_building_id,
int target_tech_id,
int tgt_extra_id)
{
struct action_data *data = fc_malloc(sizeof(*data));
data->act_id = act_id;
data->actor_unit_id = actor_id;
data->target_city_id = target_city_id;
data->target_unit_id = target_unit_id;
data->target_tile_id = target_tile_id;
data->target_building_id = target_building_id;
data->target_tech_id = target_tech_id;
data->target_extra_id = tgt_extra_id;
return data;
}
/**********************************************************************//**
Move the queue of units that need user input forward unless the current
unit is going to need more input.
**************************************************************************/
static void diplomat_queue_handle_primary(void)
{
if (!is_more_user_input_needed) {
/* The client isn't waiting for information for any unanswered follow
* up questions. */
struct unit *actor_unit;
if ((actor_unit = game_unit_by_number(actor_unit_id))) {
/* The action selection dialog wasn't closed because the actor unit
* was lost. */
/* The probabilities didn't just disappear, right? */
fc_assert_action(actor_unit->client.act_prob_cache,
client_unit_init_act_prob_cache(actor_unit));
FC_FREE(actor_unit->client.act_prob_cache);
}
if (action_selection_restart) {
/* The action selection dialog was closed but only so it can be
* redrawn with fresh data. */
action_selection_restart = FALSE;
} else {
/* The action selection process is over, at least for now. */
action_selection_no_longer_in_progress(actor_unit_id);
}
if (did_not_decide) {
/* The action selection dialog was closed but the player didn't
* decide what the unit should do. */
/* Reset so the next action selection dialog does the right thing. */
did_not_decide = FALSE;
} else {
/* An action, or no action at all, was selected. */
action_decision_clear_want(actor_unit_id);
action_selection_next_in_focus(actor_unit_id);
}
}
}
/**********************************************************************//**
Move the queue of units that need user input forward since the
current unit doesn't require the extra input any more.
**************************************************************************/
static void diplomat_queue_handle_secondary(void)
{
/* Stop waiting. Move on to the next queued unit. */
is_more_user_input_needed = FALSE;
diplomat_queue_handle_primary();
}
/**********************************************************************//**
Let the non shared client code know that the action selection process
no longer is in progress for the specified unit.
This allows the client to clean up any client specific assumptions.
**************************************************************************/
void action_selection_no_longer_in_progress_gui_specific(int actor_id)
{
/* Stop assuming the answer to a follow up question will arrive. */
is_more_user_input_needed = FALSE;
}
/**********************************************************************//**
Get the non targeted version of an action so it, if enabled, can appear
in the target selection dialog.
**************************************************************************/
static action_id get_non_targeted_action_id(action_id tgt_action_id)
{
/* Don't add an action mapping here unless the non targeted version is
* selectable in the targeted version's target selection dialog. */
switch ((enum gen_action)tgt_action_id) {
case ACTION_SPY_TARGETED_SABOTAGE_CITY:
return ACTION_SPY_SABOTAGE_CITY;
case ACTION_SPY_TARGETED_SABOTAGE_CITY_ESC:
return ACTION_SPY_SABOTAGE_CITY_ESC;
case ACTION_SPY_TARGETED_STEAL_TECH:
return ACTION_SPY_STEAL_TECH;
case ACTION_SPY_TARGETED_STEAL_TECH_ESC:
return ACTION_SPY_STEAL_TECH_ESC;
default:
/* No non targeted version found. */
return ACTION_NONE;
}
}
/**********************************************************************//**
Get the production targeted version of an action so it, if enabled, can
appear in the target selection dialog.
**************************************************************************/
static action_id get_production_targeted_action_id(action_id tgt_action_id)
{
/* Don't add an action mapping here unless the non targeted version is
* selectable in the targeted version's target selection dialog. */
switch ((enum gen_action)tgt_action_id) {
case ACTION_SPY_TARGETED_SABOTAGE_CITY:
return ACTION_SPY_SABOTAGE_CITY_PRODUCTION;
case ACTION_SPY_TARGETED_SABOTAGE_CITY_ESC:
return ACTION_SPY_SABOTAGE_CITY_PRODUCTION_ESC;
case ACTION_STRIKE_BUILDING:
return ACTION_STRIKE_PRODUCTION;
default:
/* No non targeted version found. */
return ACTION_NONE;
}
}
/**********************************************************************//**
User selected an action from the choice dialog and the action has no
special needs.
**************************************************************************/
static void simple_action_callback(GtkWidget *w, gpointer data)
{
int actor_id, target_id, sub_target;
struct action *paction;
struct action_data *args = act_sel_dialog_data;
bool failed = FALSE;
/* Data */
args->act_id = GPOINTER_TO_INT(data);
paction = action_by_number(args->act_id);
/* Actor */
fc_assert(action_get_actor_kind(paction) == AAK_UNIT);
actor_id = args->actor_unit_id;
if (NULL == game_unit_by_number(actor_id)) {
/* Probably dead. */
failed = TRUE;
}
/* Target */
target_id = IDENTITY_NUMBER_ZERO;
switch (action_get_target_kind(paction)) {
case ATK_CITY:
target_id = args->target_city_id;
if (NULL == game_city_by_number(target_id)) {
/* Probably destroyed. */
failed = TRUE;
}
break;
case ATK_UNIT:
target_id = args->target_unit_id;
if (NULL == game_unit_by_number(target_id)) {
/* Probably dead. */
failed = TRUE;
}
break;
case ATK_STACK:
case ATK_TILE:
case ATK_EXTRAS:
target_id = args->target_tile_id;
if (NULL == index_to_tile(&(wld.map), target_id)) {
/* TODO: Should this be possible at all? If not: add assertion. */
failed = TRUE;
}
break;
case ATK_SELF:
target_id = IDENTITY_NUMBER_ZERO;
break;
case ATK_COUNT:
fc_assert(action_get_target_kind(paction) != ATK_COUNT);
failed = TRUE;
}
/* Sub target. */
sub_target = NO_TARGET;
if (paction->target_complexity != ACT_TGT_COMPL_SIMPLE) {
switch (action_get_sub_target_kind(paction)) {
case ASTK_BUILDING:
sub_target = args->target_building_id;
if (NULL == improvement_by_number(sub_target)) {
/* Did the ruleset change? */
failed = TRUE;
}
break;
case ASTK_TECH:
sub_target = args->target_tech_id;
if (NULL == valid_advance_by_number(sub_target)) {
/* Did the ruleset change? */
failed = TRUE;
}
break;
case ASTK_EXTRA:
case ASTK_EXTRA_NOT_THERE:
/* TODO: Validate if the extra is there? */
sub_target = args->target_extra_id;
if (NULL == extra_by_number(sub_target)) {
/* Did the ruleset change? */
failed = TRUE;
}
break;
case ASTK_NONE:
case ASTK_COUNT:
/* Shouldn't happen. */
fc_assert(action_get_sub_target_kind(paction) != ASTK_NONE);
failed = TRUE;
break;
}
}
/* Send request. */
if (!failed) {
request_do_action(paction->id, actor_id, target_id, sub_target, "");
}
/* Clean up. */
choice_dialog_destroy(act_sel_dialog);
/* No follow up questions. */
act_sel_dialog_data = NULL;
FC_FREE(args);
}
/**********************************************************************//**
User selected an action from the choice dialog that needs details from
the server.
**************************************************************************/
static void request_action_details_callback(GtkWidget *w, gpointer data)
{
int actor_id, target_id;
struct action *paction;
struct action_data *args = act_sel_dialog_data;
bool failed = FALSE;
/* Data */
args->act_id = GPOINTER_TO_INT(data);
paction = action_by_number(args->act_id);
/* Actor */
fc_assert(action_get_actor_kind(paction) == AAK_UNIT);
actor_id = args->actor_unit_id;
if (NULL == game_unit_by_number(actor_id)) {
/* Probably dead. */
failed = TRUE;
}
/* Target */
target_id = IDENTITY_NUMBER_ZERO;
switch (action_get_target_kind(paction)) {
case ATK_CITY:
target_id = args->target_city_id;
if (NULL == game_city_by_number(target_id)) {
/* Probably destroyed. */
failed = TRUE;
}
break;
case ATK_UNIT:
target_id = args->target_unit_id;
if (NULL == game_unit_by_number(target_id)) {
/* Probably dead. */
failed = TRUE;
}
break;
case ATK_STACK:
case ATK_TILE:
case ATK_EXTRAS:
target_id = args->target_tile_id;
if (NULL == index_to_tile(&(wld.map), target_id)) {
/* TODO: Should this be possible at all? If not: add assertion. */
failed = TRUE;
}
break;
case ATK_SELF:
target_id = IDENTITY_NUMBER_ZERO;
break;
case ATK_COUNT:
fc_assert(action_get_target_kind(paction) != ATK_COUNT);
failed = TRUE;
}
/* Send request. */
if (!failed) {
request_action_details(paction->id, actor_id, target_id);
}
/* Wait for the server's reply before moving on to the next unit that
* needs to know what action to take. */
is_more_user_input_needed = TRUE;
/* Clean up. */
choice_dialog_destroy(act_sel_dialog);
/* No client side follow up questions. */
act_sel_dialog_data = NULL;
FC_FREE(args);
}
/**********************************************************************//**
User selected build city from the choice dialog
**************************************************************************/
static void found_city_callback(GtkWidget *w, gpointer data)
{
struct action_data *args = act_sel_dialog_data;
dsend_packet_city_name_suggestion_req(&client.conn,
args->actor_unit_id);
choice_dialog_destroy(act_sel_dialog);
free(args);
}
/**********************************************************************//**
User selected "Upgrade Unit" from choice dialog.
**************************************************************************/
static void upgrade_callback(GtkWidget *w, gpointer data)
{
struct unit *punit;
struct action_data *args = act_sel_dialog_data;
if ((punit = game_unit_by_number(args->actor_unit_id))
&& NULL != game_city_by_number(args->target_city_id)) {
struct unit_list *as_list;
as_list = unit_list_new();
unit_list_append(as_list, punit);
popup_upgrade_dialog(as_list);
unit_list_destroy(as_list);
}
choice_dialog_destroy(act_sel_dialog);
free(args);
}
/**********************************************************************//**
User responded to bribe unit dialog
**************************************************************************/
static void bribe_unit_response(GtkWidget *w, gint response, gpointer data)
{
struct action_data *args = (struct action_data *)data;
if (response == GTK_RESPONSE_YES) {
request_do_action(args->act_id, args->actor_unit_id,
args->target_unit_id, 0, "");
}
gtk_window_destroy(GTK_WINDOW(w));
free(args);
/* The user have answered the follow up question. Move on. */
diplomat_queue_handle_secondary();
}
/**********************************************************************//**
User responded to bribe stack dialog
**************************************************************************/
static void bribe_stack_response(GtkWidget *w, gint response, gpointer data)
{
struct action_data *args = (struct action_data *)data;
if (response == GTK_RESPONSE_YES) {
request_do_action(args->act_id, args->actor_unit_id,
args->target_tile_id, 0, "");
}
gtk_window_destroy(GTK_WINDOW(w));
free(args);
/* The user have answered the follow up question. Move on. */
diplomat_queue_handle_secondary();
}
/**********************************************************************//**
Popup unit bribe dialog
**************************************************************************/
void popup_bribe_unit_dialog(struct unit *actor, struct unit *punit, int cost,
const struct action *paction)
{
GtkWidget *shell;
char buf[1024];
fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
"Treasury contains %d gold.",
client_player()->economic.gold),
client_player()->economic.gold);
if (cost <= client_player()->economic.gold) {
shell = gtk_message_dialog_new(NULL, 0,
GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
/* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
PL_("Bribe unit for %d gold?\n%s",
"Bribe unit for %d gold?\n%s", cost), cost, buf);
gtk_window_set_title(GTK_WINDOW(shell), _("Bribe Enemy Unit"));
setup_dialog(shell, toplevel);
} else {
shell = gtk_message_dialog_new(NULL, 0,
GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
/* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
PL_("Bribing the unit costs %d gold.\n%s",
"Bribing the unit costs %d gold.\n%s", cost), cost, buf);
gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
setup_dialog(shell, toplevel);
}
gtk_window_present(GTK_WINDOW(shell));
g_signal_connect(shell, "response", G_CALLBACK(bribe_unit_response),
act_data(paction->id, actor->id,
0, punit->id, 0,
0, 0, 0));
}
/**********************************************************************//**
Popup stack bribe dialog
**************************************************************************/
void popup_bribe_stack_dialog(struct unit *actor, struct tile *ptile, int cost,
const struct action *paction)
{
GtkWidget *shell;
char buf[1024];
fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
"Treasury contains %d gold.",
client_player()->economic.gold),
client_player()->economic.gold);
if (cost <= client_player()->economic.gold) {
shell = gtk_message_dialog_new(NULL, 0,
GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
/* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
PL_("Bribe unit stack for %d gold?\n%s",
"Bribe unit stack for %d gold?\n%s", cost), cost, buf);
gtk_window_set_title(GTK_WINDOW(shell), _("Bribe Enemy Stack"));
setup_dialog(shell, toplevel);
} else {
shell = gtk_message_dialog_new(NULL, 0,
GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
/* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
PL_("Bribing units costs %d gold.\n%s",
"Bribing units costs %d gold.\n%s", cost), cost, buf);
gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
setup_dialog(shell, toplevel);
}
gtk_window_present(GTK_WINDOW(shell));
g_signal_connect(shell, "response", G_CALLBACK(bribe_stack_response),
act_data(paction->id, actor->id,
0, 0, ptile->index,
0, 0, 0));
}
/**********************************************************************//**
User responded to steal advances dialog
**************************************************************************/
static void spy_advances_response(GtkWidget *w, gint response,
gpointer data)
{
struct action_data *args = (struct action_data *)data;
if (response == GTK_RESPONSE_ACCEPT && args->target_tech_id > 0) {
if (NULL != game_unit_by_number(args->actor_unit_id)
&& NULL != game_city_by_number(args->target_city_id)) {
if (args->target_tech_id == A_UNSET) {
/* This is the untargeted version. */
request_do_action(get_non_targeted_action_id(args->act_id),
args->actor_unit_id, args->target_city_id,
args->target_tech_id, "");
} else {
/* This is the targeted version. */
request_do_action(args->act_id,
args->actor_unit_id, args->target_city_id,
args->target_tech_id, "");
}
}
}
gtk_window_destroy(GTK_WINDOW(spy_tech_shell));
spy_tech_shell = NULL;
free(data);
/* The user have answered the follow up question. Move on. */
diplomat_queue_handle_secondary();
}
/**********************************************************************//**
User selected entry in steal advances dialog
**************************************************************************/
static void spy_advances_callback(GtkSelectionModel *self,
guint position,
guint n_items,
gpointer data)
{
struct action_data *args = (struct action_data *)data;
FcActionRow *row = gtk_single_selection_get_selected_item(
GTK_SINGLE_SELECTION(self));
if (row != NULL) {
args->target_tech_id = row->id;
gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_tech_shell),
GTK_RESPONSE_ACCEPT, TRUE);
} else {
args->target_tech_id = 0;
gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_tech_shell),
GTK_RESPONSE_ACCEPT, FALSE);
}
}
/**********************************************************************//**
Action table cell bind function
**************************************************************************/
static void action_factory_bind(GtkSignalListItemFactory *self,
GtkListItem *list_item,
gpointer user_data)
{
FcActionRow *row;
row = gtk_list_item_get_item(list_item);
gtk_label_set_text(GTK_LABEL(gtk_list_item_get_child(list_item)),
row->name);
}
/**********************************************************************//**
Action table cell setup function
**************************************************************************/
static void action_factory_setup(GtkSignalListItemFactory *self,
GtkListItem *list_item,
gpointer user_data)
{
gtk_list_item_set_child(list_item, gtk_label_new(""));
}
/**********************************************************************//**
Create spy's tech stealing dialog
**************************************************************************/
static void create_advances_list(struct player *pplayer,
struct player *pvictim,
struct action_data *args)
{
GtkWidget *frame, *label, *vgrid;
GListStore *store;
GtkWidget *list;
GtkColumnViewColumn *column;
GtkListItemFactory *factory;
GtkSingleSelection *selection;
struct unit *actor_unit = game_unit_by_number(args->actor_unit_id);
spy_tech_shell = gtk_dialog_new_with_buttons(_("Steal Technology"),
NULL, 0,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Steal"), GTK_RESPONSE_ACCEPT,
NULL);
setup_dialog(spy_tech_shell, toplevel);
gtk_dialog_set_default_response(GTK_DIALOG(spy_tech_shell),
GTK_RESPONSE_ACCEPT);
frame = gtk_frame_new(_("Select Advance to Steal"));
gtk_box_append(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(spy_tech_shell))), frame);
vgrid = gtk_grid_new();
gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
GTK_ORIENTATION_VERTICAL);
gtk_grid_set_row_spacing(GTK_GRID(vgrid), 6);
gtk_frame_set_child(GTK_FRAME(frame), vgrid);
store = g_list_store_new(FC_TYPE_ACTION_ROW);
selection = gtk_single_selection_new(G_LIST_MODEL(store));
list = gtk_column_view_new(GTK_SELECTION_MODEL(selection));
factory = gtk_signal_list_item_factory_new();
g_signal_connect(factory, "bind", G_CALLBACK(action_factory_bind),
nullptr);
g_signal_connect(factory, "setup", G_CALLBACK(action_factory_setup),
nullptr);
column = gtk_column_view_column_new(_("Tech"), factory);
gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
label = g_object_new(GTK_TYPE_LABEL,
"use-underline", TRUE,
"mnemonic-widget", list,
"label", _("_Advances:"),
"xalign", 0.0,
"yalign", 0.5,
NULL);
gtk_grid_attach(GTK_GRID(vgrid), label, 0, 0, 1, 1);
gtk_grid_attach(GTK_GRID(vgrid), list, 0, 1, 1, 1);
/* Now populate the list */
if (pvictim) { /* You don't want to know what lag can do -- Syela */
const struct research *presearch = research_get(pplayer);
const struct research *vresearch = research_get(pvictim);
GValue value = { 0, };
advance_index_iterate(A_FIRST, i) {
if (research_invention_gettable(presearch, i,
game.info.tech_steal_allow_holes)
&& research_invention_state(vresearch, i) == TECH_KNOWN
&& research_invention_state(presearch, i) != TECH_KNOWN) {
FcActionRow *row = fc_action_row_new();
row->name = fc_strdup(research_advance_name_translation(presearch, i));
row->id = i;
g_list_store_append(store, row);
g_object_unref(row);
}
} advance_index_iterate_end;
if (action_prob_possible(actor_unit->client.act_prob_cache[
get_non_targeted_action_id(args->act_id)])) {
FcActionRow *row = fc_action_row_new();
{
struct astring str = ASTRING_INIT;
/* TRANS: %s is a unit name, e.g., Spy */
astr_set(&str, _("At %s's Discretion"),
unit_name_translation(actor_unit));
g_value_set_string(&value, astr_str(&str));
row->name = fc_strdup(astr_str(&str));
astr_free(&str);
}
row->id = A_UNSET;
g_list_store_append(store, row);
g_object_unref(row);
}
}
gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_tech_shell),
GTK_RESPONSE_ACCEPT, FALSE);
gtk_widget_set_visible(gtk_dialog_get_content_area(GTK_DIALOG(spy_tech_shell)),
TRUE);
g_signal_connect(selection, "selection-changed",
G_CALLBACK(spy_advances_callback), args);
g_signal_connect(spy_tech_shell, "response",
G_CALLBACK(spy_advances_response), args);
args->target_tech_id = 0;
}
/**********************************************************************//**
User has responded to spy's sabotage building dialog
**************************************************************************/
static void spy_improvements_response(GtkWidget *w, gint response, gpointer data)
{
struct action_data *args = (struct action_data *)data;
if (response == GTK_RESPONSE_ACCEPT && args->target_building_id > -2) {
if (NULL != game_unit_by_number(args->actor_unit_id)
&& NULL != game_city_by_number(args->target_city_id)) {
if (args->target_building_id == B_LAST) {
/* This is the untargeted version. */
request_do_action(get_non_targeted_action_id(args->act_id),
args->actor_unit_id,
args->target_city_id,
args->target_building_id, "");
} else if (args->target_building_id == -1) {
/* This is the city production version. */
request_do_action(get_production_targeted_action_id(args->act_id),
args->actor_unit_id,
args->target_city_id,
args->target_building_id, "");
} else {
/* This is the targeted version. */
request_do_action(args->act_id,
args->actor_unit_id,
args->target_city_id,
args->target_building_id, "");
}
}
}
gtk_window_destroy(GTK_WINDOW(spy_sabotage_shell));
spy_sabotage_shell = NULL;
free(args);
/* The user have answered the follow up question. Move on. */
diplomat_queue_handle_secondary();
}
/**********************************************************************//**
User has selected new building from spy's sabotage dialog
**************************************************************************/
static void spy_improvements_callback(GtkSelectionModel *self,
guint position,
guint n_items,
gpointer data)
{
struct action_data *args = (struct action_data *)data;
FcActionRow *row = gtk_single_selection_get_selected_item(
GTK_SINGLE_SELECTION(self));
if (row != NULL) {
args->target_building_id = row->id;
gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_sabotage_shell),
GTK_RESPONSE_ACCEPT, TRUE);
} else {
args->target_building_id = -2;
gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_sabotage_shell),
GTK_RESPONSE_ACCEPT, FALSE);
}
}
/**********************************************************************//**
Creates spy's building sabotaging dialog
**************************************************************************/
static void create_improvements_list(struct player *pplayer,
struct city *pcity,
struct action_data *args)
{
GtkWidget *frame, *label, *vgrid;
GListStore *store;
GtkWidget *list;
GtkColumnViewColumn *column;
GtkListItemFactory *factory;
GtkSingleSelection *selection;
struct unit *actor_unit = game_unit_by_number(args->actor_unit_id);
spy_sabotage_shell = gtk_dialog_new_with_buttons(_("Sabotage Improvements"),
NULL, 0,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Sabotage"), GTK_RESPONSE_ACCEPT,
NULL);
setup_dialog(spy_sabotage_shell, toplevel);
gtk_dialog_set_default_response(GTK_DIALOG(spy_sabotage_shell),
GTK_RESPONSE_ACCEPT);
frame = gtk_frame_new(_("Select Improvement to Sabotage"));
gtk_box_append(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(spy_sabotage_shell))), frame);
vgrid = gtk_grid_new();
gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
GTK_ORIENTATION_VERTICAL);
gtk_grid_set_row_spacing(GTK_GRID(vgrid), 6);
gtk_frame_set_child(GTK_FRAME(frame), vgrid);
store = g_list_store_new(FC_TYPE_ACTION_ROW);
selection = gtk_single_selection_new(G_LIST_MODEL(store));
list = gtk_column_view_new(GTK_SELECTION_MODEL(selection));
factory = gtk_signal_list_item_factory_new();
g_signal_connect(factory, "bind", G_CALLBACK(action_factory_bind),
nullptr);
g_signal_connect(factory, "setup", G_CALLBACK(action_factory_setup),
nullptr);
column = gtk_column_view_column_new(_("Improvement"), factory);
gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
label = g_object_new(GTK_TYPE_LABEL,
"use-underline", TRUE,
"mnemonic-widget", list,
"label", _("_Improvements:"),
"xalign", 0.0,
"yalign", 0.5,
NULL);
gtk_grid_attach(GTK_GRID(vgrid), label, 0, 0, 1, 1);
gtk_grid_attach(GTK_GRID(vgrid), list, 0, 1, 1, 1);
/* Now populate the list */
if (action_prob_possible(actor_unit->client.act_prob_cache[
get_production_targeted_action_id(
args->act_id)])) {
FcActionRow *row = fc_action_row_new();
row->name = fc_strdup(_("City Production"));
row->id = -1;
g_list_store_append(store, row);
g_object_unref(row);
}
city_built_iterate(pcity, pimprove) {
if (pimprove->sabotage > 0) {
FcActionRow *row = fc_action_row_new();
row->name = fc_strdup(city_improvement_name_translation(pcity, pimprove));
row->id = improvement_number(pimprove);
g_list_store_append(store, row);
g_object_unref(row);
}
} city_built_iterate_end;
if (action_prob_possible(actor_unit->client.act_prob_cache[
get_non_targeted_action_id(args->act_id)])) {
struct astring str = ASTRING_INIT;
FcActionRow *row = fc_action_row_new();
/* TRANS: %s is a unit name, e.g., Spy */
astr_set(&str, _("At %s's Discretion"),
unit_name_translation(actor_unit));
row->name = fc_strdup(astr_str(&str));
row->id = B_LAST;
g_list_store_append(store, row);
g_object_unref(row);
astr_free(&str);
}
gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_sabotage_shell),
GTK_RESPONSE_ACCEPT, FALSE);
... This diff was truncated because it exceeds the maximum size that can be displayed.
    (1-1/1)