/* * * Copyright (C) 2009-2011 Colomban Wendling * * 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 3 of the License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "config.h" #include #include #include #include #include #include "utils.h" #include "tiles.h" #include "ovccgtk-board.h" #include "ovccgtk-client.h" #include "ovccgtk-connection-dialog.h" #include "ovccgtk-player-list.h" #define GAME_TILES "tiles.xml" #define GAME_TILESET "tileset.xml" /* bad copy of the bot implemented in libovcc's test */ static gboolean do_try_place_tile (OVCCBoard *board, OVCCPosition *pos, OVCCTile *tile, gpointer user_data) { gsize i; gboolean keep_doing = TRUE; OVCCTile *new_tile = user_data; g_return_val_if_fail (new_tile != NULL, FALSE); for (i = 0; keep_doing && i < 4; i++) { OVCCPosition npos = *pos; int r; switch (i) { case 0: npos.y--; break; case 1: npos.y++; break; case 2: npos.x--; break; case 3: npos.x++; break; } for (r = 0; keep_doing && r < 4; r++) { ovcc_tile_rotate (new_tile, 1); if (ovcc_board_add_tile_check (board, new_tile, &npos)) { ovcc_board_add_tile (board, new_tile, &npos); keep_doing = FALSE; } } } return keep_doing; } static gboolean try_place_tile (OVCCBoard *board, OVCCTile *tile) { return ovcc_board_foreach (board, do_try_place_tile, tile) == FALSE; } static gboolean test_board (OVCCBoard *board, OVCCStack *stack) { OVCCTile *tile; gsize n_success = 0; gsize n_failed = 0; while (NULL != (tile = ovcc_stack_pop (stack))) { if (! try_place_tile (board, tile)) { g_warning ("Failed to place tile %u", ovcc_tile_get_id (tile)); n_failed ++; } else { n_success ++; } g_object_unref (tile); } g_debug ("%zu tiles over %zu placed (%.3u%%)", n_success, (n_success + n_failed), n_success * 100 / (n_success + n_failed)); return n_failed == 0; } static gboolean game_do_try_place_tile (OVCCBoard *board, OVCCPosition *pos, OVCCTile *tile, gpointer user_data) { gsize i; gboolean keep_doing = TRUE; OVCCGame *game = user_data; OVCCTile *new_tile = ovcc_game_get_current_tile (game); g_return_val_if_fail (new_tile != NULL, FALSE); for (i = 0; keep_doing && i < 4; i++) { OVCCPosition npos = *pos; int r; switch (i) { case 0: npos.y--; break; case 1: npos.y++; break; case 2: npos.x--; break; case 3: npos.x++; break; } for (r = 0; keep_doing && r < 4; r++) { if (ovcc_game_place_tile (game, ovcc_game_get_current_player (game), &npos)) { keep_doing = FALSE; } else { ovcc_tile_rotate (new_tile, 1); } } } return keep_doing; } static gboolean game_try_place_tile (OVCCGame *game, OVCCTile *tile) { OVCCBoard *board; board = ovcc_game_get_board (game); return ovcc_board_foreach (board, game_do_try_place_tile, game) == FALSE; } struct _PlaceNextData { OVCCGame *game; guint n_success; guint n_failed; }; static gboolean place_next (gpointer data) { struct _PlaceNextData *pdata = data; OVCCTile *tile; tile = ovcc_game_get_current_tile (pdata->game); if (! tile) { g_debug ("%u tiles over %u placed (%.3u%%)", pdata->n_success, (pdata->n_success + pdata->n_failed), (pdata->n_success + pdata->n_failed) > 0 ? pdata->n_success * 100 / (pdata->n_success + pdata->n_failed) : 0); return FALSE; } if (! game_try_place_tile (pdata->game, tile)) { g_warning ("Failed to place tile %u", ovcc_tile_get_id (tile)); pdata->n_failed ++; } else { pdata->n_success ++; } return TRUE; } static void test_game (OVCCGame *game) { struct _PlaceNextData *pdata; pdata = g_malloc (sizeof *pdata); pdata->game = game; pdata->n_success = 0; pdata->n_failed = 0; g_timeout_add_full (G_PRIORITY_DEFAULT, 100, place_next, pdata, g_free); } static OVCCStack * create_stack (void) { gchar *path; OVCCTilesDef *tiles; GFile *tiles_file; OVCCTileSet *set; GFile *set_file; OVCCStack *stack = NULL; GError *err = NULL; tiles = ovcc_tiles_def_new (); path = data_get_path (GAME_TILES); tiles_file = g_file_new_for_path (path); g_free (path); if (! ovcc_tiles_def_load (tiles, tiles_file, &err)) { msg_error (_("Failed to load tiles: %s"), err->message); g_error_free (err); } else { set = ovcc_tile_set_new (); path = data_get_path (GAME_TILESET); set_file = g_file_new_for_path (path); g_free (path); if (! ovcc_tile_set_load (set, tiles, set_file, &err)) { msg_error (_("Failed to load tile set: %s"), err->message); g_error_free (err); } else { stack = ovcc_stack_new_from_tileset (set); } g_object_unref (set_file); g_object_unref (set); } g_object_unref (tiles_file); g_object_unref (tiles); return stack; } static OVCCBoard * create_board (void) { OVCCStack *stack; OVCCBoard *board = NULL; stack = create_stack (); if (stack) { OVCCTile *tile; tile = ovcc_stack_pop (stack); board = ovcc_board_new (tile); g_object_unref (tile); test_board (board, stack); } g_object_unref (stack); return board; } static void on_unplaceable_tile (OVCCGame *game, OVCCTile *tile, gpointer data) { g_warning ("Cannot place tile #%u, reshaking.", ovcc_tile_get_id (tile)); } static OVCCGame * create_game (void) { gchar *path; OVCCTilesDef *tiles; GFile *tiles_file; OVCCTileSet *set; GFile *set_file; OVCCGame *game = NULL; GError *err = NULL; tiles = ovcc_tiles_def_new (); path = data_get_path (GAME_TILES); tiles_file = g_file_new_for_path (path); g_free (path); if (! ovcc_tiles_def_load (tiles, tiles_file, &err)) { msg_error (_("Failed to load tiles: %s"), err->message); g_error_free (err); } else { set = ovcc_tile_set_new (); path = data_get_path (GAME_TILESET); set_file = g_file_new_for_path (path); g_free (path); if (! ovcc_tile_set_load (set, tiles, set_file, &err)) { msg_error (_("Failed to load tile set: %s"), err->message); g_error_free (err); } else { game = ovcc_game_new (set, NULL); g_signal_connect (game, "unplaceable-tile", G_CALLBACK (on_unplaceable_tile), NULL); ovcc_game_add_player (game, ovcc_player_new ("A"), NULL); ovcc_game_add_player (game, ovcc_player_new ("B"), NULL); } g_object_unref (set_file); g_object_unref (set); } g_object_unref (tiles_file); g_object_unref (tiles); return game; } /* end of bad game fake */ typedef struct _App App; struct _App { GtkWidget *main_window; GtkWidget *statusbar; GtkWidget *tile_counter_label; GtkWidget *current_tile_image; GtkWidget *board_container; GtkWidget *board; GtkWidget *player_list; GtkWidget *connection_dialog; GCancellable *connection_cancel; OVCCGtkClient *client; OVCCGame *game; struct { struct { GtkAction *new; GtkAction *connect; GtkAction *disconnect; GtkAction *start; GtkAction *rotate_tile_clockwise; GtkAction *rotate_tile_counterclockwise; GtkAction *finish_turn; } game; struct { GtkAction *quit; GtkAction *preferences; } app; struct { GtkAction *about; } help; } actions; }; static gint show_message (GtkWindow *parent, GtkMessageType type, GtkButtonsType buttons, const gchar *secondary_text, const gchar *primary_fmt, ...) { gint response; GtkWidget *dialog; const gchar *primary; va_list ap; g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), 0); g_return_val_if_fail (primary_fmt != NULL, 0); va_start (ap, primary_fmt); primary = g_strdup_vprintf (primary_fmt, ap); va_end (ap); dialog = g_object_new (GTK_TYPE_MESSAGE_DIALOG, "message-type", type, "buttons", buttons, "text", primary, "secondary-text", secondary_text, NULL); if (parent != NULL) { gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); } response = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); return response; } static void app_set_status (App *app, const gchar *fmt, ...) { gchar *status; va_list ap; va_start (ap, fmt); status = g_strdup_vprintf (fmt, ap); va_end (ap); gtk_statusbar_pop (GTK_STATUSBAR (app->statusbar), 0); gtk_statusbar_push (GTK_STATUSBAR (app->statusbar), 0, status); g_free (status); } static gboolean load_ui (GtkBuilder *builder, const gchar *filename) { GError *err = NULL; gboolean loaded = FALSE; gchar *path = data_get_path (filename); loaded = gtk_builder_add_from_file (builder, path, &err) > 0; if (! loaded) { show_message (NULL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, err->message, _("Failed to load UI file \"%s\""), path); g_error_free (err); } g_free (path); return loaded; } static void update_tile_image (App *app) { OVCCTile *tile = NULL; guint tiles_left; gchar *label; if (app->game) { tile = ovcc_game_get_current_tile (app->game); tiles_left = ovcc_game_get_n_tiles_left (app->game); label = g_strdup_printf (g_dngettext (NULL, "%u tile left", "%u tiles left", tiles_left), tiles_left); gtk_label_set_text (GTK_LABEL (app->tile_counter_label), label); g_free (label); } if (tile) { GdkPixbuf *pix; pix = tile_get_pixbuf (tile, -1); gtk_image_set_from_pixbuf (GTK_IMAGE (app->current_tile_image), pix); g_object_unref (pix); } else { gtk_image_set_from_stock (GTK_IMAGE (app->current_tile_image), GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_LARGE_TOOLBAR); } } static void rotate_current_tile (App *app, gint wise) { OVCCTile *tile; tile = ovcc_game_get_current_tile (app->game); if (tile) { ovcc_tile_rotate (tile, wise); } update_tile_image (app); } static gboolean app_leave (App *app) { if (! app->client) { return TRUE; } if (app->game && ovcc_game_get_state (app->game) == OVCC_GAME_STATE_STARTED && g_slist_length (ovcc_game_get_players (app->game)) > 1 && show_message (GTK_WINDOW (app->main_window), GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("The game is not finished and you are not the only " "player on it. Do you really want to abort the game " "and leave it?"), _("Do you really want to leave?")) != GTK_RESPONSE_YES) { return FALSE; } else { GError *err = NULL; if (! ovccclient_client_leave (OVCCCLIENT_CLIENT (app->client), &err)) { app_set_status (app, "Ignoring disconnection error: %s", err->message); g_error_free (err); } else { app_set_status (app, "Disconnected!"); } g_object_unref (app->client); app->client = NULL; app->game = NULL; gtk_widget_destroy (app->board); app->board = NULL; update_tile_image (app); gtk_action_set_sensitive (app->actions.game.disconnect, FALSE); gtk_action_set_sensitive (app->actions.game.start, FALSE); gtk_action_set_sensitive (app->actions.game.rotate_tile_clockwise, FALSE); gtk_action_set_sensitive (app->actions.game.rotate_tile_counterclockwise, FALSE); gtk_action_set_sensitive (app->actions.game.connect, TRUE); gtk_action_set_sensitive (app->actions.game.new, TRUE); return TRUE; } } static gboolean app_quit (App *app) { if (app_leave (app)) { gtk_main_quit (); return TRUE; } else { return FALSE; } } G_MODULE_EXPORT gboolean main_window_delete_event_handler (GtkWidget *window, GdkEvent *event, App *app) { return ! app_quit (app); } G_MODULE_EXPORT void game_quit_activate_handler (GtkAction *action, App *app) { app_quit (app); } G_MODULE_EXPORT void rotate_tile_clockwise_activate_handler (GtkAction *action, App *app) { rotate_current_tile (app, 1); } G_MODULE_EXPORT void rotate_tile_counterclockwise_activate_handler (GtkAction *action, App *app) { rotate_current_tile (app, -1); } G_MODULE_EXPORT void game_start_activate_handler (GtkAction *action, App *app) { if (app->game && ovcc_game_get_state (app->game) == OVCC_GAME_STATE_STOPPED) { GError *err = NULL; if (! ovcc_game_start (app->game, &err)) { show_message (GTK_WINDOW (app->main_window), GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, err->message, "Cannot start game"); g_error_free (err); } } } static void finish_turn (App *app) { gtk_action_set_sensitive (app->actions.game.finish_turn, FALSE); g_signal_emit_by_name (app->game, "turn-finished"); /* set board mode to tile for it to stop showing pawn placement infos */ ovccgtk_board_set_state (OVCCGTK_BOARD (app->board), OVCCGTK_BOARD_STATE_TILE); } G_MODULE_EXPORT void game_finish_turn_activate_handler (GtkAction *action, App *app) { finish_turn (app); } static void on_pawn_add_request (OVCCGtkBoard *board, const OVCCPosition *pos, OVCCTileObject *obj, OVCCPawnKind kind, App *app) { OVCCPlayer *player; g_debug ("Add pawn request @ [%d,%d]", pos->x, pos->y); player = ovccclient_client_get_player (OVCCCLIENT_CLIENT (app->client)); if (ovcc_player_place_pawn (player, kind, obj, pos)) { g_debug ("OK, placed."); finish_turn (app); } } static void on_tile_add_request (OVCCGtkBoard *board, const OVCCPosition *pos, App *app) { OVCCTile *tile; g_debug ("Add request @ [%d,%d]", pos->x, pos->y); tile = ovcc_game_get_current_tile (app->game); if (tile) { OVCCPlayer *player; player = ovccclient_client_get_player (OVCCCLIENT_CLIENT (app->client)); if (ovcc_player_place_tile (player, pos)) { g_debug ("OK, placed."); /* TODO: if there is no more pawns, we could finish our turn here (or * somewhere sensible) */ gtk_action_set_sensitive (app->actions.game.finish_turn, TRUE); } } else { show_message (GTK_WINDOW (app->main_window), GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, NULL, "Game already finished!"); } } static void on_current_tile_changed (GObject *object, GParamSpec *pspec, App *app) { /* update current tile image */ update_tile_image (app); } static void on_current_player_changed (OVCCGame *game, GParamSpec *pspec, App *app) { if (ovcc_game_get_state (game) == OVCC_GAME_STATE_STARTED) { OVCCPlayer *me; OVCCPlayer *player; me = ovccclient_client_get_player (OVCCCLIENT_CLIENT (app->client)); player = ovcc_game_get_current_player (game); if (player != me) { app_set_status (app, _("It's the turn of %s"), ovcc_player_get_nick (player)); } else { app_set_status (app, _("It's your turn")); } } } static void on_game_state_changed (OVCCGame *game, GParamSpec *pspec, App *app) { gboolean can_start = FALSE; gboolean started = FALSE; switch (ovcc_game_get_state (game)) { case OVCC_GAME_STATE_ABORTED: app_set_status (app, _("Game aborted")); break; case OVCC_GAME_STATE_FINISHED: app_set_status (app, _("Game finished!")); break; case OVCC_GAME_STATE_STARTED: app_set_status (app, _("Game started!")); started = TRUE; break; case OVCC_GAME_STATE_STOPPED: app_set_status (app, _("Game stopped")); can_start = TRUE; break; } gtk_action_set_sensitive (app->actions.game.start, can_start); gtk_widget_set_sensitive (app->current_tile_image, started); gtk_action_set_sensitive (app->actions.game.rotate_tile_clockwise, started); gtk_action_set_sensitive (app->actions.game.rotate_tile_counterclockwise, started); } static void game_pawn_placed_handler (OVCCGame *game, OVCCPawn *pawn, OVCCTileObject *obj, OVCCPosition *pos, App *app) { /* for now just redraw the position */ ovccgtk_board_queue_position_update (OVCCGTK_BOARD (app->board), pos); } static void game_pawn_removed_handler (OVCCGame *game, OVCCPawn *pawn, OVCCTileObject *obj, OVCCPosition *pos, App *app) { /* for now just redraw the position */ ovccgtk_board_queue_position_update (OVCCGTK_BOARD (app->board), pos); } static void client_place_tile_handler (OVCCClientClient *client, OVCCTile *tile, App *app) { ovccgtk_board_set_state (OVCCGTK_BOARD (app->board), OVCCGTK_BOARD_STATE_TILE); gtk_widget_set_sensitive (app->current_tile_image, TRUE); gtk_action_set_sensitive (app->actions.game.rotate_tile_clockwise, TRUE); gtk_action_set_sensitive (app->actions.game.rotate_tile_counterclockwise, TRUE); } static void client_place_pawn_handler (OVCCClientClient *client, OVCCPosition *pos, App *app) { ovccgtk_board_set_state (OVCCGTK_BOARD (app->board), OVCCGTK_BOARD_STATE_PAWN); gtk_widget_set_sensitive (app->current_tile_image, FALSE); gtk_action_set_sensitive (app->actions.game.rotate_tile_clockwise, FALSE); gtk_action_set_sensitive (app->actions.game.rotate_tile_counterclockwise, FALSE); } static void client_join_ready (GObject *object, GAsyncResult *result, gpointer data) { GError *err = NULL; App *app = data; g_object_unref (app->connection_cancel); app->connection_cancel = NULL; if (! ovccgtk_client_join_finish (result, &err)) { if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { ovccgtk_connection_dialog_set_message (OVCCGTK_CONNECTION_DIALOG (app->connection_dialog), GTK_MESSAGE_INFO, _("Connection was cancelled"), NULL); } else { ovccgtk_connection_dialog_set_message (OVCCGTK_CONNECTION_DIALOG (app->connection_dialog), GTK_MESSAGE_WARNING, _("Failed to connect to server"), err->message); } g_error_free (err); g_object_unref (app->client); app->client = NULL; /* make sure we validate again since we have a validation rule on * app->client == NULL */ ovccgtk_connection_dialog_validate (OVCCGTK_CONNECTION_DIALOG (app->connection_dialog)); gtk_action_set_sensitive (app->actions.game.connect, TRUE); } else { /* hide the dialog we come from on success */ gtk_widget_hide (app->connection_dialog); gtk_action_set_sensitive (app->actions.game.new, FALSE); gtk_action_set_sensitive (app->actions.game.disconnect, TRUE); app_set_status (app, _("Connected!")); g_signal_connect (app->client, "place-tile", G_CALLBACK (client_place_tile_handler), app); g_signal_connect (app->client, "place-pawn", G_CALLBACK (client_place_pawn_handler), app); app->game = ovccclient_client_get_game (OVCCCLIENT_CLIENT (app->client)); g_signal_connect (app->game, "notify::current-tile", G_CALLBACK (on_current_tile_changed), app); g_signal_connect (app->game, "notify::current-player", G_CALLBACK (on_current_player_changed), app); g_signal_connect (app->game, "notify::state", G_CALLBACK (on_game_state_changed), app); g_signal_connect (app->game, "pawn-placed", G_CALLBACK (game_pawn_placed_handler), app); g_signal_connect (app->game, "pawn-removed", G_CALLBACK (game_pawn_removed_handler), app); ovccgtk_player_list_set_game (OVCCGTK_PLAYER_LIST (app->player_list), app->game); ovccgtk_player_list_set_default_player (OVCCGTK_PLAYER_LIST (app->player_list), ovccclient_client_get_player (OVCCCLIENT_CLIENT (app->client))); app->board = ovccgtk_board_new (ovcc_game_get_board (app->game)); g_signal_connect (app->board, "add-tile", G_CALLBACK (on_tile_add_request), app); g_signal_connect (app->board, "add-pawn", G_CALLBACK (on_pawn_add_request), app); gtk_container_add (GTK_CONTAINER (app->board_container), app->board); gtk_widget_show (app->board); update_tile_image (app); gtk_action_set_sensitive (app->actions.game.start, TRUE); } } static void connection_dialog_response_handler (GtkDialog *dialog, gint response, App *app) { OVCCGtkConnectionDialog *dlg = OVCCGTK_CONNECTION_DIALOG (dialog); switch (response) { case GTK_RESPONSE_ACCEPT: case GTK_RESPONSE_OK: { const gchar *host; guint16 port; const gchar *username; OVCCClientServer *server; host = ovccgtk_connection_dialog_get_hostname (dlg); port = ovccgtk_connection_dialog_get_port (dlg); username = ovccgtk_connection_dialog_get_username (dlg); /* FIXME! */ gtk_action_set_sensitive (app->actions.game.connect, FALSE); gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_OK, FALSE); ovccgtk_connection_dialog_set_message (dlg, GTK_MESSAGE_INFO, _("Connecting..."), NULL); if (app->connection_cancel) { g_warning ("connection cancellable isn't NULL, wtf?"); g_object_unref (app->connection_cancel); } app->connection_cancel = g_cancellable_new (); server = ovccclient_server_new (host, port); app->client = ovccgtk_client_new (username); ovccgtk_client_join_async (app->client, server, app->connection_cancel, client_join_ready, app); g_object_unref (server); } break; default: if (app->connection_cancel) { g_cancellable_cancel (app->connection_cancel); } gtk_widget_hide (app->connection_dialog); } } static gboolean connection_dialog_validate_handler (OVCCGtkConnectionDialog *dialog, App *app) { if (app->client != NULL) { ovccgtk_connection_dialog_set_message (dialog, GTK_MESSAGE_INFO, _("You are already connected to a server"), NULL); return FALSE; } return TRUE; } G_MODULE_EXPORT void game_connect_activate_handler (GtkAction *action, App *app) { OVCCGtkConnectionDialog *dialog = OVCCGTK_CONNECTION_DIALOG (app->connection_dialog); ovccgtk_connection_dialog_set_message (dialog, GTK_MESSAGE_INFO, _("Fill in the fields and hit Connect"), NULL); gtk_widget_show (app->connection_dialog); ovccgtk_connection_dialog_validate (dialog); } G_MODULE_EXPORT void game_disconnect_activate_handler (GtkAction *action, App *app) { app_leave (app); } G_MODULE_EXPORT void help_about_activate_handler (GtkAction *action, App *app) { GtkWidget *dialog; const gchar *authors[] = { "Colomban Wendling ", NULL }; dialog = g_object_new (GTK_TYPE_ABOUT_DIALOG, "transient-for", app->main_window, "logo-icon-name", "ovccgtk", "program-name", _("OVCCGtk"), "version", VERSION, "comments", _("A GTK client for OVCC"), "copyright", _("Copyright \xc2\xa9 2009-2013 Colomban Wendling"), "license-type", GTK_LICENSE_GPL_3_0, "translator-credits", _("translator-credits"), "authors", authors, NULL); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } static gboolean ovcc_gtk (int argc, char **argv) { GtkBuilder *builder; gboolean success = FALSE; gchar *icon_path; icon_path = data_get_path ("icons"); gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), icon_path); g_free (icon_path); builder = gtk_builder_new (); if (load_ui (builder, "ovccgtk-application.ui")) { GtkWidget *players_cnt; GtkWidget *board_cnt; App *app; app = g_new0 (App, 1); gtk_builder_connect_signals (builder, app); app->main_window = GTK_WIDGET (gtk_builder_get_object (builder, "main-window")); app->statusbar = GTK_WIDGET (gtk_builder_get_object (builder, "main-statusbar")); board_cnt = GTK_WIDGET (gtk_builder_get_object (builder, "board-container")); players_cnt = GTK_WIDGET (gtk_builder_get_object (builder, "players-container")); app->current_tile_image = GTK_WIDGET (gtk_builder_get_object (builder, "current-tile-image")); app->tile_counter_label = GTK_WIDGET (gtk_builder_get_object (builder, "tiles-left-counter-label")); app->board_container = gtk_viewport_new (NULL, NULL); gtk_container_add (GTK_CONTAINER (board_cnt), app->board_container); app->player_list = ovccgtk_player_list_new (); gtk_container_add (GTK_CONTAINER (players_cnt), app->player_list); /* connection dialog */ app->connection_dialog = ovccgtk_connection_dialog_new (GTK_WINDOW (app->main_window)); g_signal_connect_after (app->connection_dialog, "response", G_CALLBACK (connection_dialog_response_handler), app); g_signal_connect (app->connection_dialog, "validate", G_CALLBACK (connection_dialog_validate_handler), app); /* Actions */ #define GET_ACTION(b, n) GTK_ACTION (gtk_builder_get_object ((b), (n))) app->actions.app.quit = NULL; app->actions.app.preferences = GET_ACTION (builder, "edit-preferences"); app->actions.game.new = GET_ACTION (builder, "game-new"); app->actions.game.connect = GET_ACTION (builder, "game-connect"); app->actions.game.disconnect = GET_ACTION (builder, "game-disconnect"); app->actions.game.start = GET_ACTION (builder, "game-start"); app->actions.game.rotate_tile_clockwise = GET_ACTION (builder, "tile-rotate-clockwise"); app->actions.game.rotate_tile_counterclockwise = GET_ACTION (builder, "tile-rotate-counterclockwise"); app->actions.game.finish_turn = GET_ACTION (builder, "game-finish-turn"); app->actions.help.about = NULL; #undef GET_ACTION gtk_action_set_sensitive (app->actions.game.disconnect, FALSE); gtk_action_set_sensitive (app->actions.game.start, FALSE); gtk_action_set_sensitive (app->actions.game.rotate_tile_clockwise, FALSE); gtk_action_set_sensitive (app->actions.game.rotate_tile_counterclockwise, FALSE); gtk_action_set_sensitive (app->actions.game.finish_turn, FALSE); app_set_status (app, _("Welcome to OVCCGTK!")); gtk_widget_show_all (app->main_window); gtk_main (); g_free (app); success = TRUE; } return success; } int main (int argc, char **argv) { int rv = 1; gtk_init (&argc, &argv); rv = ovcc_gtk (argc, argv) ? 0 : 1; return rv; }