[gnome-chess/chess-telepathy-networking-support-664946-rebase: 58/64] [gnome-chess-channel-handler] Handle channels
- From: Chandni Verma <vchandni src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-chess/chess-telepathy-networking-support-664946-rebase: 58/64] [gnome-chess-channel-handler] Handle channels
- Date: Sun, 23 Dec 2012 03:43:29 +0000 (UTC)
commit 3f37597023e0a79c963c190bcbe919ef2550f23c
Author: Chandni Verma <chandniverma2112 gmail com>
Date: Wed Sep 26 21:02:24 2012 +0530
[gnome-chess-channel-handler] Handle channels
src/chess-pgn.vala | 10 +
src/gnome-chess-channel-handler.vala | 560 +++++++++++++++++++++++++++++++++-
2 files changed, 567 insertions(+), 3 deletions(-)
---
diff --git a/src/chess-pgn.vala b/src/chess-pgn.vala
index ebce1b9..04d1b0e 100644
--- a/src/chess-pgn.vala
+++ b/src/chess-pgn.vala
@@ -74,6 +74,16 @@ public class PGNGame
get { return tags.lookup ("Time"); }
set { tags.insert ("Time", value); }
}
+ public string utcdate
+ {
+ get { return tags.lookup ("UTCDate"); }
+ set { tags.insert ("UTCDate", value); }
+ }
+ public string utctime
+ {
+ get { return tags.lookup ("UTCTime"); }
+ set { tags.insert ("UTCTime", value); }
+ }
public string round
{
get { return tags.lookup ("Round"); }
diff --git a/src/gnome-chess-channel-handler.vala b/src/gnome-chess-channel-handler.vala
index 35cb0f5..3e86d02 100644
--- a/src/gnome-chess-channel-handler.vala
+++ b/src/gnome-chess-channel-handler.vala
@@ -40,17 +40,60 @@ public class HandlerApplication : Application
private GamesContacts.IndividualView? individual_view = null;
private GamesContacts.LiveSearch? search_widget;
+ private Gtk.TreeView channel_view;
+
/* Objects from gnome-chess-game-window.ui */
private Gtk.Widget view_box;
private Gtk.Widget handler_menubar;
+ private bool is_activated = false;
+ private TelepathyGLib.SimpleHandler tp_handler;
+
+ private enum ChannelsColumn
+ {
+ USER_ACTION_TIME, /* tp-time of channel creation */
+ TARGET_CONTACT, /* target contact */
+ CHANNEL, /* tube channel */
+ OUR_COLOUR_WHITE, /* our piece color */
+ PGN_GAME,
+ HISTORY_MODEL,
+ HISTORY_COMBO_ACTIVE_ITER,
+ CHESS_GAME,
+ CHESS_SCENE,
+ INFO_BAR,
+ INFO_BAR_VISIBILITY,
+ GAME_NEEDS_SAVING,
+ NUM_COLS
+ }
+
+ /* Channels */
+ Gtk.ListStore channels;
+ Gtk.TreeIter? selected_channel_iter = null;
+
public HandlerApplication ()
{
Object (
- application_id: TelepathyGLib.CLIENT_BUS_NAME_BASE + "Gnome.Chess",
+ application_id: "org.gnome.gnome-chess.handler",
flags: ApplicationFlags.FLAGS_NONE);
chess_networking_init ();
+ channels = new Gtk.ListStore (ChannelsColumn.NUM_COLS,
+ typeof (int64), /* USER_ACTION_TIME */
+ typeof (TelepathyGLib.Contact), /* TARGET_CONTACT */
+ typeof (TelepathyGLib.Channel), /* CHANNEL */
+ typeof (bool), /* OUR_COLOUR_WHITE */
+ typeof (PGNGame), /* PGN_GAME */
+ typeof (Gtk.TreeModel), /* HISTORY_MODEL */
+ typeof (Gtk.TreeIter), /* HISTORY_COMBO_ACTIVE_ITER */
+ typeof (ChessGame), /* CHESS_GAME */
+ typeof (ChessScene), /* CHESS_SCENE */
+ typeof (Gtk.InfoBar), /* INFO_BAR */
+ typeof (bool), /* INFO_BAR_VISIBILITY */
+ typeof (bool) /* GAME_NEEDS_SAVING */
+ // typeof (), /* */
+ );
+
+ (channel_view).cursor_changed.connect (cursor_changed_cb);
settings = new Settings ("org.gnome.gnome-chess");
settings_common = new Settings ("org.gnome.gnome-chess.games-common");
@@ -83,6 +126,79 @@ public class HandlerApplication : Application
handler_window.show_all ();
}
+ private bool change_view (Gtk.TreeModel model, Gtk.TreePath path, Gtk.TreeIter channel_iter)
+ {
+ ChessGame? game = null;
+ ChessScene? scene = null;
+ bool view_visible = true;
+
+ channels get (channel_iter, ChannelsColumn.CHESS_GAME, out game, ChannelsColumn.CHESS_SCENE, out scene);
+ assert (game != null && scene != null);
+ ChessView chess_view = (game as Object).get_data<ChessView> ("chess-view");
+ if (chess_view != null)
+ {
+ view_visible = chess_view.get_visible ();
+ view_container.remove (chess_view);
+ chess_view.destroy ();
+ }
+ if (settings_common.get_boolean ("show-3d"))
+ chess_view = new ChessView3D ();
+ else
+ chess_view = new ChessView2D ();
+ chess_view.set_size_request (300, 300);
+ chess_view.scene = scene;
+ view_container.add (chess_view);
+ chess_view.set_visible (view_visible);
+
+ return false;
+ }
+
+ private void settings_changed_cb (Settings settings_common, string key)
+ {
+ if (key == "show-3d")
+ {
+ channels foreach (change_view);
+ }
+ }
+
+ private void show_game ()
+ {
+ TelepathyGLib.Contact? remote_player = null;
+ int64 action_time = -1;
+
+ if (selected_channel_iter == null)
+ {
+ debug ("No channel iteration selected");
+ return;
+ }
+ channels get (selected_channel_iter, ChannelsColumn.TARGET_CONTACT, out remote_player, ChannelsColumn.USER_ACTION_TIME, out action_time);
+
+ if (remote_player != null && action_time != -1)
+ {
+ debug ("Showing game with %s. Initiation timeframe: %llu", remote_player.identifier, action_time);
+ }
+ }
+
+ private void cursor_changed_cb ()
+ {
+ Gtk.TreePath? path;
+ Gtk.TreeIter iter;
+
+ channel_view.get_cursor (out path, null);
+ if (path == null)
+ {
+ debug ("Couldn't obtain path the cursor is at");
+ return;
+ }
+
+ if (channels.get_iter (out iter, path))
+ {
+ selected_channel_iter = iter;
+
+ show_game ();
+ }
+ }
+
private void create_handler_window ()
{
string [] objects_from_traditional_window =
@@ -106,6 +222,7 @@ public class HandlerApplication : Application
contacts_box = (Gtk.Widget) builder.get_object ("contacts_box");
alignment_play = (Gtk.Widget) builder.get_object ("alignment_play");
+ channel_view = new Gtk.TreeView ();
/* Add objects from gnome-chess-game-window.ui */
try {
@@ -114,6 +231,7 @@ public class HandlerApplication : Application
objects_from_traditional_window);
view_box = (Gtk.Widget) builder.get_object ("view_box");
+ view_container = (Gtk.Container) builder.get_object ("view_container");
handler_menubar = (Gtk.Widget) builder.get_object ("menubar");
handler_menubar.unparent ();
@@ -134,6 +252,9 @@ public class HandlerApplication : Application
handler_window.title = _("Chess");
prepare_contact_list ();
+
+ channel_view = new Gtk.TreeView ();
+ channel_view.model = channels;
}
private void prepare_contact_list ()
@@ -168,20 +289,452 @@ public class HandlerApplication : Application
(contacts_box as Gtk.Container).add (search_widget);
}
+ [CCode (cname = "G_MODULE_EXPORT channels_clicked_cb", instance_pos=-1)]
+ public void channels_clicked_cb (Gtk.Button button)
+ {
+ scrolledwindow_list.remove (contacts_box);
+ scrolledwindow_list.add (channel_view);
+ }
+
+ [CCode (cname = "G_MODULE_EXPORT contacts_clicked_cb", instance_pos=-1)]
+ public void contacts_clicked_cb (Gtk.Button button)
+ {
+ scrolledwindow_list.remove (channel_view);
+ scrolledwindow_list.add (contacts_box);
+ }
+
+ [CCode (cname = "G_MODULE_EXPORT goa_clicked_cb", instance_pos=-1)]
+ public void goa_clicked_cb (Gtk.Button button)
+ {
+ }
+
[CCode (cname = "G_MODULE_EXPORT quit_cb", instance_pos = -1)]
- private new void quit_cb (Gtk.Widget widget)
+ public override void quit_cb (Gtk.Widget widget)
{
quit_game ();
}
+ private bool save_game_and_remove_channel (Gtk.TreeModel model, Gtk.TreePath path, Gtk.TreeIter channel_iter)
+ {
+ TelepathyGLib.Channel? channel = null;
+ int64 initiation_time = -1;
+ ChessGame game;
+ PGNGame pgn_game;
+ bool game_needs_saving;
+
+ channels get (channel_iter, ChannelsColumn.USER_ACTION_TIME, out initiation_time, ChannelsColumn.CHANNEL, out channel);
+
+ debug ("Removing chess tube channel with %s initiated at instance: %lld", channel.target_contact.identifier, initiation_time);
+
+ return false;
+ }
+
/* Quits the application */
- public new void quit_game ()
+ private void quit_game ()
{
Settings.sync ();
+ channels foreach (save_game_and_remove_channel);
+ }
+
+ private new void game_move_cb (ChessGame game, ChessMove move)
+ {
+ Gtk.TreeIter *channel_iter;
+ ChessView chess_view;
+
+ channel_iter = (game as Object).get_data ("channel-iter");
+ chess_view = (game as Object).get_data<ChessView> ("chess-view");
+
+ /* Need to save after each move */
+ channels set (*channel_iter, ChannelsColumn.GAME_NEEDS_SAVING, true);
+
+ if (move.number > pgn_game.moves.length ())
+ pgn_game.moves.append (move.get_san ());
+
+ Gtk.ListStore model;
+ ChessScene scene;
+ channels get (*channel_iter, ChannelsColumn.HISTORY_MODEL, out model, ChannelsColumn.CHESS_SCENE, out scene);
+
+ Gtk.TreeIter iter;
+ model.append (out iter);
+ model.set (iter, 1, move.number, -1);
+ set_move_text (iter, move, scene, model);
+
+ /* Follow the latest move */
+ if (move.number == game.n_moves && scene.move_number == -1)
+ channels set (*channel_iter, ChannelsColumn.HISTORY_COMBO_ACTIVE_ITER, iter);
+
+ update_history_model (game, scene, model);
+
+ /* UI updation */
+ if (selected_channel_iter == *channel_iter)
+ {
+ update_history_panel (game,scene, model);
+ update_control_buttons ();
+ }
+
+ /* TODO: Acknowledge if opponent made this move */
+
+ chess_view.queue_draw ();
+ }
+
+ private void create_and_add_game (TelepathyGLib.DBusTubeChannel tube,
+ Gtk.TreeIter iter)
+ {
+ /* Create a new game with the offered parameters */
+ Variant tube_params = tube.dup_parameters_vardict ();
+ bool our_color_white;
+ tube_params.lookup ("offerer-white", "b", out our_color_white);
+ int32 duration;
+ tube_params.lookup ("duration", "i", out duration);
+
+ var pgn_game = new PGNGame ();
+ var now = new DateTime.now_local ();
+ var now_UTC = now.to_utc ();
+ pgn_game.date = now.format ("%Y.%m.%d");
+ pgn_game.time = now.format ("%H:%M:%S");
+ pgn_game.utcdate = now_UTC.format ("%Y.%m.%d");
+ pgn_game.utctime = now_UTC.format ("%H:%M:%S");
+ if (duration > 0)
+ pgn_game.time_control = "%d".printf (duration);
+
+ var history_model = new Gtk.ListStore (2, typeof (string), typeof (int));
+
+ string fen = ChessGame.STANDARD_SETUP;
+ string[] moves = new string[pgn_game.moves.length ()];
+ var i = 0;
+ foreach (var move in pgn_game.moves)
+ moves[i++] = move;
+
+ if (pgn_game.set_up)
+ {
+ if (pgn_game.fen != null)
+ fen = pgn_game.fen;
+ else
+ warning ("Chess game has SetUp tag but no FEN tag");
+ }
+ var game = new ChessGame (fen, moves);
+ (game as Object).set_data<PGNGame> ("pgn-game", pgn_game);
+ (game as Object).set_data<Gtk.TreeIter*> ("channel-iter", &iter);
+
+ if (pgn_game.time_control != null)
+ {
+ var controls = pgn_game.time_control.split (":");
+ foreach (var control in controls)
+ {
+ /* We only support simple timeouts */
+ var timeout_duration = int.parse (control);
+ if (timeout_duration > 0)
+ game.clock = new ChessClock (timeout_duration, timeout_duration);
+ }
+ }
+
+ game.moved.connect (game_move_cb);
+ game.ended.connect (game_end_cb);
+ if (game.clock != null)
+ game.clock.tick.connect (game_clock_tick_cb);
+
+ ChessScene scene = new ChessScene ();
+ scene.changed.connect (scene_changed_cb);
+ scene.choose_promotion_type.connect (show_promotion_type_selector);
+ scene.game = game;
+
+ Gtk.InfoBar info_bar;
+
+ info_bar = new Gtk.InfoBar ();
+ var content_area = (Gtk.Container) info_bar.get_content_area ();
+ (view_box as Gtk.Box).pack_start (info_bar, false, true, 0);
+ var vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 6);
+ vbox.show ();
+ content_area.add (vbox);
+ var info_title_label = new Gtk.Label ("");
+ info_title_label.show ();
+ vbox.pack_start (info_title_label, false, true, 0);
+ vbox.hexpand = true;
+ vbox.vexpand = false;
+ var info_label = new Gtk.Label ("");
+ info_label.show ();
+ vbox.pack_start (info_label, true, true, 0);
+
+ info_bar.hide ();
+
+ (game as Object).set_data<Gtk.InfoBar> ("info-bar", info_bar);
+ (game as Object).set_data<Gtk.Label> ("info-title-label", info_title_label);
+ (game as Object).set_data<Gtk.Label> ("info-label", info_label);
+
+ ChessView chess_view;
+ if (settings_common.get_boolean ("show-3d"))
+ chess_view = new ChessView3D ();
+ else
+ chess_view = new ChessView2D ();
+ chess_view.set_size_request (300, 300);
+ /* This connects scene.changed() to a handler that draws view everytime scene changes */
+ chess_view.scene = scene;
+
+ (game as Object).set_data<ChessView> ("chess-view", chess_view);
+
+ bool game_needs_saving = false;
+ game.start ();
+
+ if (game.result != ChessResult.IN_PROGRESS)
+ game_end_cb (game);
+
+ white_time_label.queue_draw ();
+ black_time_label.queue_draw ();
+
+ channels.insert_with_values (null, -1,
+ ChannelsColumn.OUR_COLOUR_WHITE, our_color_white,
+ ChannelsColumn.PGN_GAME, pgn_game,
+ ChannelsColumn.HISTORY_MODEL, history_model,
+ ChannelsColumn.CHESS_GAME, game,
+ ChannelsColumn.CHESS_SCENE, scene,
+ ChannelsColumn.INFO_BAR, info_bar,
+ ChannelsColumn.INFO_BAR_VISIBILITY, info_bar.visible,
+ ChannelsColumn.GAME_NEEDS_SAVING, game_needs_saving);
+ }
+
+ private void register_objects (DBusConnection connection,
+ TelepathyGLib.DBusTubeChannel tube,
+ Gtk.TreeIter channel_iter)
+ {
+ // display_game ();
+ }
+
+ private void offer_tube (TelepathyGLib.DBusTubeChannel tube,
+ Gtk.TreeIter channel_iter)
+ {
+ DBusConnection? connection = null;
+ bool play_as_white = settings_common.get_boolean ("play-as-white");
+ Value colour_val = play_as_white;
+ int32 duration = settings_common.get_int ("duration");
+ Value duration_val = duration;
+
+ HashTable<string, Value?>? tube_params = new HashTable<string, Value?> (str_hash, str_equal);
+ tube_params.insert ("offerer-white", colour_val);
+ tube_params.insert ("duration", duration_val);
+
+ debug ("Offering tube with offerer-white:%s and duration:%ld",
+ colour_val.get_boolean () ? "true" : "false", duration_val.get_int ());
+// debug ("Parameters passed: %s", );
+ tube.offer_async.begin ((HashTable<void*, void*>?)tube_params,
+ (obj, res)=>{
+ try
+ {
+ connection = tube.offer_async.end (res);
+ }
+ catch (Error e)
+ {
+ debug ("Failed to offer tube to %s: %s",
+ (tube as TelepathyGLib.Channel).target_contact.identifier,
+ e.message);
+ // display_channel_error (channel_iter, e, "Failed to offer chess game channel to %s", (tube as TelepathyGLib.Channel).target_contact.identifier);
+ debug ("Closing channel.");
+ (tube as TelepathyGLib.Channel).close_async.begin ((obj, res)=>
+ {
+ try
+ {
+ (tube as TelepathyGLib.Channel).close_async.end (res);
+ }
+ catch (Error e)
+ {
+ debug ("Couldn't close the channel: %s", e.message);
+ }
+ });
+
+
+ /* Nothing to do */
+ return;
+ }
+
+ assert (connection != null);
+
+ debug ("Tube opened.");
+ connection.notify["closed"].connect (
+ (s, p)=>{
+ debug ("Connection to %s closed unexpectedly",
+ (tube as
+ TelepathyGLib.Channel).target_contact.identifier);
+ }
+ );
+ create_and_add_game (tube, channel_iter);
+ register_objects (connection, tube, channel_iter);
+ }
+ );
+ }
+
+ private void accept_tube (TelepathyGLib.DBusTubeChannel tube,
+ Gtk.TreeIter channel_iter)
+ {
+ DBusConnection? connection = null;
+
+ debug ("Accepting tube");
+ tube.accept_async.begin (
+ (obj, res)=>{
+ try
+ {
+ connection = tube.accept_async.end (res);
+ }
+ catch (Error e)
+ {
+ debug ("Failed to accept tube from %s: %s",
+ (tube as TelepathyGLib.Channel).target_contact.identifier,
+ e.message);
+// display_error (channel_iter, e, "Failed to offer chess game channel to %s", (tube as TelepathyGLib.Channel).target_contact.identifer);
+ debug ("Closing channel.");
+
+ (tube as TelepathyGLib.Channel).close_async.begin ((obj, res)=>
+ {
+ try
+ {
+ (tube as TelepathyGLib.Channel).close_async.end (res);
+ }
+ catch (Error e)
+ {
+ debug ("Couldn't close the channel: %s", e.message);
+ }
+ });
+
+ /* Nothing to do */
+ return;
+ }
+
+ assert (connection != null);
+
+ debug ("Tube opened.");
+ connection.notify["closed"].connect (
+ (s, p)=>{
+ debug ("Connection to %s closed unexpectedly",
+ (tube as
+ TelepathyGLib.Channel).target_contact.identifier);
+ }
+ );
+ create_and_add_game (tube, channel_iter);
+ }
+ );
+
+ }
+
+ private void tube_invalidated_cb (TelepathyGLib.Proxy tube_channel,
+ uint domain,
+ int code,
+ string message)
+ {
+ debug ("Tube has been invalidated: %s", message);
+
+ channels foreach ((model, path, iter)=>
+ {
+ TelepathyGLib.Channel stored_tube;
+ uint64 user_action_time;
+ channels get (iter, ChannelsColumn.CHANNEL, out stored_tube,
+ ChannelsColumn.USER_ACTION_TIME, out user_action_time);
+
+ if (stored_tube == tube_channel)
+ {
+ debug ("Removing chess dbus-tube channel initiated at timeframe %llu with remote player %s",
+ user_action_time, stored_tube.target_contact.identifier);
+ channels.remove (iter);
+ return true;
+ }
+
+ return false;
+ }
+ );
+ }
+
+ public void handle_channels (TelepathyGLib.SimpleHandler handler,
+ TelepathyGLib.Account account,
+ TelepathyGLib.Connection conn,
+ List<TelepathyGLib.Channel> channel_bundle,
+ List<TelepathyGLib.ChannelRequest> requests,
+ int64 action_time,
+ TelepathyGLib.HandleChannelsContext context)
+ {
+ Error error = new TelepathyGLib.Error.NOT_AVAILABLE (
+ "No channel to be handled");
+
+ debug ("Handling channels");
+
+ foreach (TelepathyGLib.Channel tube_channel in channel_bundle)
+ {
+ Gtk.TreeIter iter;
+
+ if (! (tube_channel is TelepathyGLib.DBusTubeChannel))
+ continue;
+ if ((tube_channel as TelepathyGLib.DBusTubeChannel).service_name !=
+ TelepathyGLib.CLIENT_BUS_NAME_BASE + "Games.Glchess")
+ continue;
+
+ /* Add channel to list of currently handled channels */
+ channels.insert_with_values (out iter, -1,
+ ChannelsColumn.USER_ACTION_TIME, action_time,
+ ChannelsColumn.TARGET_CONTACT, tube_channel.target_contact,
+ ChannelsColumn.CHANNEL, tube_channel);
+
+ if (tube_channel.requested)
+ {
+ /* We created this channel. Make a tube offer and wait for
+ * approval */
+ offer_tube (tube_channel as TelepathyGLib.DBusTubeChannel, iter);
+ // display_waiting_for_approval (iter);
+ }
+ else
+ {
+ /* This is an incoming channel request */
+ accept_tube (tube_channel as TelepathyGLib.DBusTubeChannel, iter);
+ }
+
+ (tube_channel as TelepathyGLib.Proxy).invalidated.connect (
+ tube_invalidated_cb);
+
+ context.accept ();
+ /* Only one of accept() or fail() can be called on context */
+ return;
+ }
+
+ debug ("Rejecting channels");
+ context.fail (error);
+
+ return;
}
public override void activate ()
{
+ if (!is_activated)
+ {
+ /* Create and register our telepathy client handler as a one-off */
+
+ tp_handler = new TelepathyGLib.SimpleHandler.with_am (
+ TelepathyGLib.AccountManager.dup (),
+ true, /* Bypass approval */
+ true, /* Requests */
+ "Games.Glchess",
+ false, /* Uniquify name */
+ handle_channels);
+
+ var filter = new HashTable<string, Value?> (str_hash, str_equal);
+ filter.insert (
+ TelepathyGLib.PROP_CHANNEL_CHANNEL_TYPE,
+ TelepathyGLib.IFACE_CHANNEL_TYPE_DBUS_TUBE);
+ filter.insert (
+ TelepathyGLib.PROP_CHANNEL_TARGET_HANDLE_TYPE,
+ 1);
+ filter.insert (
+ TelepathyGLib.PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME,
+ TelepathyGLib.CLIENT_BUS_NAME_BASE + "Games.Glchess");
+
+ (tp_handler as TelepathyGLib.BaseClient).add_handler_filter (filter);
+
+ try {
+ (tp_handler as TelepathyGLib.BaseClient).register ();
+ }
+ catch (Error e) {
+ debug ("Failed to register handler: %s", e.message);
+ }
+
+ debug ("Waiting for tube offer");
+
+ is_activated = true;
+ }
+
/* Handler window has been created by constructor already. Show it. */
handler_window.show_all ();
handler_window.present ();
@@ -248,3 +801,4 @@ class GlChessChannelHandler
return result;
}
}
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]