[hotssh] Add API to request pty size, use it



commit 25f66c9ea130913260d93bea3f2c3de8cfb43705
Author: Colin Walters <walters verbum org>
Date:   Thu Oct 10 19:13:24 2013 -0400

    Add API to request pty size, use it

 libgssh/gssh-channel-private.h |   13 +++++++-
 libgssh/gssh-channel.c         |   65 ++++++++++++++++++++++++++++++++++++++-
 libgssh/gssh-channel.h         |   11 +++++++
 libgssh/gssh-connection.c      |    2 +-
 src/hotssh-win.c               |   60 ++++++++++++++++++++++++++++++++++++-
 5 files changed, 145 insertions(+), 6 deletions(-)
---
diff --git a/libgssh/gssh-channel-private.h b/libgssh/gssh-channel-private.h
index 6f9d7dd..2b861c1 100644
--- a/libgssh/gssh-channel-private.h
+++ b/libgssh/gssh-channel-private.h
@@ -30,7 +30,12 @@ struct _GSshChannel
   GIOStream parent;
 
   GSshConnection *connection;
+  gboolean have_pty;
   LIBSSH2_CHANNEL *libsshchannel;
+
+  GTask *pty_size_task;
+  guint pty_width;
+  guint pty_height;
   
   GSshChannelInputStream *input_stream;
   GSshChannelOutputStream *output_stream;
@@ -41,5 +46,9 @@ struct _GSshChannelClass
   GIOStreamClass parent_class;
 };
 
-GSshChannel       *_gssh_channel_new (GSshConnection *connection,
-                                          LIBSSH2_CHANNEL *libsshchannel);
+GSshChannel       *_gssh_channel_new (GSshConnection  *connection,
+                                      gboolean         have_pty,
+                                      LIBSSH2_CHANNEL *libsshchannel);
+
+
+void _gssh_channel_iteration (GSshChannel    *self);
diff --git a/libgssh/gssh-channel.c b/libgssh/gssh-channel.c
index a212809..f2c92ae 100644
--- a/libgssh/gssh-channel.c
+++ b/libgssh/gssh-channel.c
@@ -86,6 +86,65 @@ gssh_channel_close_finish (GIOStream     *stream,
   return G_IO_STREAM_CLASS (gssh_channel_parent_class)->close_finish (stream, result, error);
 }
 
+void
+_gssh_channel_iteration (GSshChannel              *self)
+{
+  int rc;
+  GError *local_error = NULL;
+
+  if (self->pty_size_task)
+    {
+      GTask *orig_pty_size_task = self->pty_size_task;
+      rc = libssh2_channel_request_pty_size (self->libsshchannel,
+                                             self->pty_width, self->pty_height);
+      if (rc == LIBSSH2_ERROR_EAGAIN)
+        ;
+      else 
+        {
+          self->pty_size_task = NULL;
+          if (rc < 0)
+            {
+              _gssh_set_error_from_libssh2 (&local_error, "Failed to set pty size",
+                                            self->connection->session);
+              g_task_return_error (orig_pty_size_task, local_error);
+            }
+          else
+            {
+              g_assert (rc == 0);
+              g_task_return_boolean (orig_pty_size_task, TRUE);
+            }
+          g_object_unref (orig_pty_size_task);
+        }
+    }
+}
+
+void
+gssh_channel_request_pty_size_async (GSshChannel         *self,
+                                     guint                width,
+                                     guint                height,
+                                     GCancellable        *cancellable,
+                                     GAsyncReadyCallback  callback,
+                                     gpointer             user_data)
+{
+  g_return_if_fail (self->have_pty);
+  g_return_if_fail (self->pty_size_task == NULL);
+
+  self->pty_size_task = g_task_new (self, cancellable, callback, user_data);
+  self->pty_width = width;
+  self->pty_height = height;
+
+  _gssh_channel_iteration (self);
+}
+
+gboolean
+gssh_channel_request_pty_size_finish (GSshChannel         *self,
+                                      GAsyncResult        *res,
+                                      GError             **error)
+{
+  g_return_val_if_fail (g_task_is_valid (res, self), FALSE);
+  return g_task_propagate_boolean (G_TASK (res), error);
+}
+
 static void
 gssh_channel_init (GSshChannel *self)
 {
@@ -114,14 +173,16 @@ gssh_channel_class_init (GSshChannelClass *class)
 }
 
 GSshChannel *
-_gssh_channel_new (GSshConnection *connection,
-                     LIBSSH2_CHANNEL *libsshchannel)
+_gssh_channel_new (GSshConnection   *connection,
+                   gboolean         have_pty,
+                   LIBSSH2_CHANNEL *libsshchannel)
 {
   GSshChannel *self = (GSshChannel*)g_object_new (GSSH_TYPE_CHANNEL, NULL);
   /* We don't hold a ref; if the connection goes away, it will ensure
    * this pointer is zeroed.
    */
   self->connection = connection; 
+  self->have_pty = have_pty; 
   self->libsshchannel = libsshchannel; 
   return self;
 }
diff --git a/libgssh/gssh-channel.h b/libgssh/gssh-channel.h
index 9575b69..33d4a29 100644
--- a/libgssh/gssh-channel.h
+++ b/libgssh/gssh-channel.h
@@ -28,3 +28,14 @@
 typedef struct _GSshChannelClass    GSshChannelClass;
 
 GType                   gssh_channel_get_type     (void);
+
+void gssh_channel_request_pty_size_async (GSshChannel         *self,
+                                          guint                width,
+                                          guint                height,
+                                          GCancellable        *cancellable,
+                                          GAsyncReadyCallback  callback,
+                                          gpointer             user_data);
+
+gboolean gssh_channel_request_pty_size_finish (GSshChannel         *self,
+                                               GAsyncResult        *res,
+                                               GError             **error);
diff --git a/libgssh/gssh-connection.c b/libgssh/gssh-connection.c
index 21d55a8..8a5cd27 100644
--- a/libgssh/gssh-connection.c
+++ b/libgssh/gssh-connection.c
@@ -297,7 +297,7 @@ process_channels (GSshConnection   *self,
 
                 g_assert (rc == 0);
 
-                new_channel = _gssh_channel_new (self, data->libssh2channel);
+                new_channel = _gssh_channel_new (self, TRUE, data->libssh2channel);
                 g_hash_table_insert (self->channels, new_channel, new_channel);
 
                 g_task_return_pointer (task, new_channel, g_object_unref);
diff --git a/src/hotssh-win.c b/src/hotssh-win.c
index 7f1c338..c8a33c3 100644
--- a/src/hotssh-win.c
+++ b/src/hotssh-win.c
@@ -1,6 +1,6 @@
 #include "hotssh-app.h"
 #include "hotssh-win.h"
-#include "gssh-connection.h"
+#include "gssh.h"
 
 #include "libgsystem.h"
 
@@ -52,6 +52,8 @@ struct _HotSshWindowPrivate
   GSshConnection *connection;
   GSshChannel *channel;
 
+  gboolean need_pty_size_request;
+  gboolean sent_pty_size_request;
   gboolean have_outstanding_write;
   gboolean have_outstanding_auth;
   GQueue write_queue;
@@ -424,6 +426,61 @@ on_connect_cancel (GtkButton     *button,
 }
 
 static void
+send_pty_size_request (HotSshWindow             *self);
+
+static void
+on_pty_size_complete (GObject                    *src,
+                     GAsyncResult               *result,
+                     gpointer                    user_data)
+{
+  HotSshWindow *self = user_data;
+  HotSshWindowPrivate *priv = hotssh_window_get_instance_private (self);
+  GError *local_error = NULL;
+
+  g_debug ("pty size request complete");
+  priv->sent_pty_size_request = FALSE;
+
+  if (!gssh_channel_request_pty_size_finish (priv->channel, result, &local_error))
+    goto out;
+
+  if (priv->need_pty_size_request)
+    send_pty_size_request (self);
+
+ out:
+  if (local_error)
+    page_transition_take_error (self, local_error);
+}
+
+static void
+send_pty_size_request (HotSshWindow             *self)
+{
+  HotSshWindowPrivate *priv = hotssh_window_get_instance_private (self);
+  guint width = vte_terminal_get_column_count ((VteTerminal*)priv->terminal);
+  guint height = vte_terminal_get_row_count ((VteTerminal*)priv->terminal);
+  
+  priv->need_pty_size_request = FALSE;
+  priv->sent_pty_size_request = TRUE;
+  gssh_channel_request_pty_size_async (priv->channel, width, height,
+                                      priv->cancellable, on_pty_size_complete, self);
+}
+
+static void
+on_terminal_size_allocate (GtkWidget    *widget,
+                          GdkRectangle *allocation,
+                          gpointer      user_data)
+{
+  HotSshWindow *self = user_data;
+  HotSshWindowPrivate *priv = hotssh_window_get_instance_private (self);
+
+  if (priv->channel)
+    {
+      priv->need_pty_size_request = TRUE;
+      if (!priv->sent_pty_size_request)
+       send_pty_size_request (self);
+    }
+}
+
+static void
 hotssh_window_init (HotSshWindow *self)
 {
   HotSshWindowPrivate *priv = hotssh_window_get_instance_private (self);
@@ -438,6 +495,7 @@ hotssh_window_init (HotSshWindow *self)
   g_signal_connect_swapped (priv->password_submit, "clicked", G_CALLBACK (submit_password), self);
 
   priv->terminal = vte_terminal_new ();
+  g_signal_connect ((GObject*)priv->terminal, "size-allocate", G_CALLBACK (on_terminal_size_allocate), self);
   g_signal_connect ((GObject*)priv->terminal, "commit", G_CALLBACK (on_terminal_commit), self);
   gtk_box_pack_start ((GtkBox*)priv->terminal_box, (GtkWidget*)priv->terminal, TRUE, TRUE, 0);
   gtk_widget_show_all (priv->terminal_box);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]