diff mbox

[RFC] Fix pasting into serial console in GTK ui

Message ID 20161223151253.21338-1-msuchanek@suse.de (mailing list archive)
State New, archived
Headers show

Commit Message

Michal Suchanek Dec. 23, 2016, 3:12 p.m. UTC
This copies the timer hack from ui/console.c kbd_send_chars to ui/gtk.c
gd_vc_in.

There is no fd-like object to peek repatedly so the paste data is saved
in a free-floating buffer only submitted to gtk_timeout_add. Multiple
pastes can potentially interleave if qemu blocks for long or the user
pastes fast.

Signed-off-by: Michal Suchanek <msuchanek@suse.de>
---
 ui/gtk.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 53 insertions(+), 4 deletions(-)

Comments

no-reply@patchew.org Dec. 23, 2016, 3:16 p.m. UTC | #1
Hi,

Your series seems to have some coding style problems. See output below for
more information:

Type: series
Message-id: 20161223151253.21338-1-msuchanek@suse.de
Subject: [Qemu-devel] [RFC PATCH] Fix pasting into serial console in GTK ui

=== TEST SCRIPT BEGIN ===
#!/bin/bash

BASE=base
n=1
total=$(git log --oneline $BASE.. | wc -l)
failed=0

# Useful git options
git config --local diff.renamelimit 0
git config --local diff.renames True

commits="$(git log --format=%H --reverse $BASE..)"
for c in $commits; do
    echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..."
    if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
        failed=1
        echo
    fi
    n=$((n+1))
done

exit $failed
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
From https://github.com/patchew-project/qemu
 * [new tag]         patchew/20161223151253.21338-1-msuchanek@suse.de -> patchew/20161223151253.21338-1-msuchanek@suse.de
Switched to a new branch 'test'
74e9646 Fix pasting into serial console in GTK ui

=== OUTPUT BEGIN ===
Checking PATCH 1/1: Fix pasting into serial console in GTK ui...
ERROR: space prohibited after that open parenthesis '('
#51: FILE: ui/gtk.c:1755:
+    if ( size > len) {

ERROR: braces {} are necessary for all arms of this statement
#57: FILE: ui/gtk.c:1761:
+    if (inbuf->sent < inbuf->size)
[...]
+    else {
[...]

ERROR: braces {} are necessary for all arms of this statement
#74: FILE: ui/gtk.c:1778:
+        if (!inbuf)
[...]

total: 3 errors, 0 warnings, 70 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

=== OUTPUT END ===

Test command exited with code: 1


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org
Paolo Bonzini Dec. 23, 2016, 4:29 p.m. UTC | #2
On 23/12/2016 16:12, Michal Suchanek wrote:
> This copies the timer hack from ui/console.c kbd_send_chars to ui/gtk.c
> gd_vc_in.
> 
> There is no fd-like object to peek repatedly so the paste data is saved
> in a free-floating buffer only submitted to gtk_timeout_add. Multiple
> pastes can potentially interleave if qemu blocks for long or the user
> pastes fast.

Do not use a timer, instead set chr->chr_accept_input in gd_vc_handler.
The callback can do basically what you are doing in gd_vc_in_timer.  The
buffer can be just a GString plus a "head" pointer, in VirtualConsole.
Once the head catches up with the tail, you can free the GString.

Paolo
Michal Suchanek Jan. 2, 2017, 3:17 p.m. UTC | #3
Hello,

On Fri, 23 Dec 2016 17:29:28 +0100
Paolo Bonzini <pbonzini@redhat.com> wrote:

> On 23/12/2016 16:12, Michal Suchanek wrote:
> > This copies the timer hack from ui/console.c kbd_send_chars to
> > ui/gtk.c gd_vc_in.
> > 
> > There is no fd-like object to peek repatedly so the paste data is
> > saved in a free-floating buffer only submitted to gtk_timeout_add.
> > Multiple pastes can potentially interleave if qemu blocks for long
> > or the user pastes fast.  
> 
> Do not use a timer, instead set chr->chr_accept_input in
> gd_vc_handler. The callback can do basically what you are doing in
> gd_vc_in_timer.  The buffer can be just a GString plus a "head"
> pointer, in VirtualConsole. Once the head catches up with the tail,
> you can free the GString.

How do you propose to use that callback? I did not find a
documentation for it. It takes no argument (except the chr object self)
so there is no way to pass in the buffer. It cannot be replaced -
it is set in non-ui code in multiple places and never in ui code.

Thanks

Michal
Gerd Hoffmann Jan. 3, 2017, 1:32 p.m. UTC | #4
Hi,

> How do you propose to use that callback? I did not find a
> documentation for it. It takes no argument (except the chr object self)
> so there is no way to pass in the buffer. It cannot be replaced -
> it is set in non-ui code in multiple places and never in ui code.

No docs, but see backend/msmouse.c where I've added chr_accept_input
support recently.

cheers,
  Gerd
diff mbox

Patch

diff --git a/ui/gtk.c b/ui/gtk.c
index a216216..b3810c7 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1715,11 +1715,15 @@  static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp)
     return chr;
 }
 
-static gboolean gd_vc_in(VteTerminal *terminal, gchar *text, guint size,
-                         gpointer user_data)
-{
-    VirtualConsole *vc = user_data;
+struct vc_in_buffer {
+    VirtualConsole *vc;
+    gchar *text;
+    guint size;
+    guint sent;
+};
 
+static gboolean do_gd_vc_in(VirtualConsole *vc, gchar *text, guint size)
+{
     if (vc->vte.echo) {
         VteTerminal *term = VTE_TERMINAL(vc->vte.terminal);
         int i;
@@ -1742,6 +1746,51 @@  static gboolean gd_vc_in(VteTerminal *terminal, gchar *text, guint size,
     return TRUE;
 }
 
+static gint gd_vc_in_timer(gpointer data)
+{
+    struct vc_in_buffer *inbuf = data;
+    VirtualConsole *vc = inbuf->vc;
+    int len = qemu_chr_be_can_write(vc->vte.chr);
+    int size = inbuf->size - inbuf->sent;
+    if ( size > len) {
+        size = len;
+    }
+    do_gd_vc_in(vc, inbuf->text + inbuf->sent, size);
+
+    inbuf->sent += size;
+    if (inbuf->sent < inbuf->size)
+        return TRUE;
+    else {
+        g_clear_pointer(&inbuf->text, g_free);
+        g_free(inbuf);
+        return FALSE;
+    }
+}
+
+static gboolean gd_vc_in(VteTerminal *terminal, gchar *text, guint size,
+                         gpointer user_data)
+{
+    VirtualConsole *vc = user_data;
+    int len = qemu_chr_be_can_write(vc->vte.chr);
+
+    if (size > len) {
+        struct vc_in_buffer *inbuf = g_try_new0(struct vc_in_buffer, 1);
+        if (!inbuf)
+            return FALSE;
+        inbuf->text = g_strndup(text, size);
+        if (!inbuf->text) {
+            g_free(inbuf);
+            return FALSE;
+        }
+        inbuf->vc = vc;
+        inbuf->size = size;
+        inbuf->sent = len;
+        size = len;
+        g_timeout_add(1, gd_vc_in_timer, inbuf);
+    }
+    return do_gd_vc_in(vc, text, size);
+}
+
 static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc,
                               CharDriverState *chr, int idx,
                               GSList *group, GtkWidget *view_menu)