Patchwork [22/23] gtk: show a window for each graphical QemuConsole

login
register
mail settings
Submitter Gerd Hoffmann
Date March 20, 2013, 9:43 a.m.
Message ID <1363772625-9182-23-git-send-email-kraxel@redhat.com>
Download mbox | patch
Permalink /patch/229286/
State New
Headers show

Comments

Gerd Hoffmann - March 20, 2013, 9:43 a.m.
Multihead support:  For each graphical console we'll create a gtk
window, so with multiple graphics cards installed you get a gtk window
for each.  vte tabs are attached to the console #0 window.
---
 ui/gtk.c |   40 +++++++++++++++++++++++++++-------------
 1 file changed, 27 insertions(+), 13 deletions(-)
Anthony Liguori - March 20, 2013, 1:04 p.m.
Gerd Hoffmann <kraxel@redhat.com> writes:

> Multihead support:  For each graphical console we'll create a gtk
> window, so with multiple graphics cards installed you get a gtk window
> for each.  vte tabs are attached to the console #0 window.

This is neat but I'm not sure if the user experience is right.

Each window would have independent grab.  Each window would have
independent full screen.

I'm not sure there's an obviously right solution but it's worth
discussing.  I do like the idea of having two windows but perhaps we
should make the second window have a no menu bar with a title that
indicates that it's a secondary display?

Regards,

Anthony Liguori

> ---
>  ui/gtk.c |   40 +++++++++++++++++++++++++++-------------
>  1 file changed, 27 insertions(+), 13 deletions(-)
>
> diff --git a/ui/gtk.c b/ui/gtk.c
> index 512e974..1c86054 100644
> --- a/ui/gtk.c
> +++ b/ui/gtk.c
> @@ -159,8 +159,6 @@ typedef struct GtkDisplayState
>      bool external_pause_update;
>  } GtkDisplayState;
>  
> -static GtkDisplayState *global_state;
> -
>  /** Utility Functions **/
>  
>  static bool gd_is_grab_active(GtkDisplayState *s)
> @@ -1210,7 +1208,7 @@ static void gd_connect_signals(GtkDisplayState *s)
>                       G_CALLBACK(gd_leave_event), s);
>  }
>  
> -static void gd_create_menus(GtkDisplayState *s)
> +static void gd_create_menus(GtkDisplayState *s, bool vtetabs)
>  {
>      GtkStockItem item;
>      GtkAccelGroup *accel_group;
> @@ -1302,11 +1300,13 @@ static void gd_create_menus(GtkDisplayState *s)
>      gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK);
>      gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->vga_item);
>  
> -    for (i = 0; i < nb_vcs; i++) {
> -        VirtualConsole *vc = &s->vc[i];
> +    if (vtetabs) {
> +        for (i = 0; i < nb_vcs; i++) {
> +            VirtualConsole *vc = &s->vc[i];
>  
> -        group = gd_vc_init(s, vc, i, group);
> -        s->nb_vcs++;
> +            group = gd_vc_init(s, vc, i, group);
> +            s->nb_vcs++;
> +        }
>      }
>  
>      separator = gtk_separator_menu_item_new();
> @@ -1336,14 +1336,13 @@ static const DisplayChangeListenerOps dcl_ops = {
>      .dpy_cursor_define = gd_cursor_define,
>  };
>  
> -void gtk_display_init(DisplayState *ds)
> +static void gtk_display_init_one(DisplayState *ds, QemuConsole *con,
> +                                 bool vtetabs)
>  {
>      GtkDisplayState *s = g_malloc0(sizeof(*s));
>  
> -    gtk_init(NULL, NULL);
> -
>      s->dcl.ops = &dcl_ops;
> -    s->dcl.con = qemu_console_lookup_by_index(0);
> +    s->dcl.con = con;
>  
>      s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
>  #if GTK_CHECK_VERSION(3, 2, 0)
> @@ -1371,7 +1370,7 @@ void gtk_display_init(DisplayState *ds)
>  
>      gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), s->drawing_area, gtk_label_new("VGA"));
>  
> -    gd_create_menus(s);
> +    gd_create_menus(s, vtetabs);
>  
>      gd_connect_signals(s);
>  
> @@ -1400,6 +1399,21 @@ void gtk_display_init(DisplayState *ds)
>      gtk_widget_show_all(s->window);
>  
>      register_displaychangelistener(ds, &s->dcl);
> +}
>  
> -    global_state = s;
> +void gtk_display_init(DisplayState *ds)
> +{
> +    QemuConsole *con;
> +    int i = 0;
> +
> +    gtk_init(NULL, NULL);
> +
> +    con = qemu_console_lookup_by_index(i++);
> +    gtk_display_init_one(ds, con, true);
> +    while ((con = qemu_console_lookup_by_index(i++)) != NULL) {
> +        if (!qemu_console_is_graphic(con)) {
> +            break;
> +        }
> +        gtk_display_init_one(ds, con, false);
> +    }
>  }
> -- 
> 1.7.9.7
Gerd Hoffmann - March 20, 2013, 3:22 p.m.
On 03/20/13 14:04, Anthony Liguori wrote:
> Gerd Hoffmann <kraxel@redhat.com> writes:
> 
>> Multihead support:  For each graphical console we'll create a gtk
>> window, so with multiple graphics cards installed you get a gtk window
>> for each.  vte tabs are attached to the console #0 window.
> 
> This is neat but I'm not sure if the user experience is right.
> 
> Each window would have independent grab.  Each window would have
> independent full screen.
> 
> I'm not sure there's an obviously right solution but it's worth
> discussing.  I do like the idea of having two windows but perhaps we
> should make the second window have a no menu bar with a title that
> indicates that it's a secondary display?

Sure there is plenty of room for improvements, but I think those can go
in incrementally ...

/me went for another window because placing the secondary display into a
tab doesn't make that much sense, and this is the minimal patch doing
just that.

It's also not really usable (yet) anyway as we don't have input routing,
atm there is absolutely no way for the guest to figure which display
(absolute) mouse events where coming from.

cheers,
  Gerd
Igor Mitsyanko - March 20, 2013, 7:29 p.m.
On 03/20/2013 01:43 PM, Gerd Hoffmann wrote:
>
>> Multihead support:  For each graphical console we'll create a gtk
>> window, so with multiple graphics cards installed you get a gtk window
>> for each.  vte tabs are attached to the console #0 window.
>> ---
>>   ui/gtk.c |   40 +++++++++++++++++++++++++++---**----------
>>   1 file changed, 27 insertions(+), 13 deletions(-)
>>
>>
>

This patch doesn't seem to apply to current master.
Peter Maydell - March 20, 2013, 8:06 p.m.
On 20 March 2013 09:43, Gerd Hoffmann <kraxel@redhat.com> wrote:
> Multihead support:  For each graphical console we'll create a gtk
> window, so with multiple graphics cards installed you get a gtk window
> for each.  vte tabs are attached to the console #0 window.

So is this going to mean arm's vexpress-a9 gets a pointless
new second window? [there are two display devices in it].

If so, we're going to need to model what the hardware actually
does, which is that there's a single connection on the back
of the box for a monitor, and it's guest software controllable
which of the two display devices is routed to the connection...

-- PMM
Gerd Hoffmann - March 21, 2013, 7:52 a.m.
On 03/20/13 21:06, Peter Maydell wrote:
> On 20 March 2013 09:43, Gerd Hoffmann <kraxel@redhat.com> wrote:
>> Multihead support:  For each graphical console we'll create a gtk
>> window, so with multiple graphics cards installed you get a gtk window
>> for each.  vte tabs are attached to the console #0 window.
> 
> So is this going to mean arm's vexpress-a9 gets a pointless
> new second window? [there are two display devices in it].

I don't think so, given that multiple graphical consoles are not really
supported by qemu today.

Basically you get one window per graphical_console_init().

> If so, we're going to need to model what the hardware actually
> does, which is that there's a single connection on the back
> of the box for a monitor, and it's guest software controllable
> which of the two display devices is routed to the connection...

How does this work in 1.4?

cheers,
  Gerd
Gerd Hoffmann - March 21, 2013, 8:51 a.m.
On 03/21/13 08:52, Gerd Hoffmann wrote:
> On 03/20/13 21:06, Peter Maydell wrote:
>> On 20 March 2013 09:43, Gerd Hoffmann <kraxel@redhat.com> wrote:
>>> Multihead support:  For each graphical console we'll create a gtk
>>> window, so with multiple graphics cards installed you get a gtk window
>>> for each.  vte tabs are attached to the console #0 window.
>>
>> So is this going to mean arm's vexpress-a9 gets a pointless
>> new second window? [there are two display devices in it].
> 
> I don't think so, given that multiple graphical consoles are not really
> supported by qemu today.
> 
> Basically you get one window per graphical_console_init().

Ahem, well, there is a second window now.

>> If so, we're going to need to model what the hardware actually
>> does, which is that there's a single connection on the back
>> of the box for a monitor, and it's guest software controllable
>> which of the two display devices is routed to the connection...
> 
> How does this work in 1.4?

I guess the second display device was never ever shown anywhere?

cheers,
  Gerd
Peter Maydell - March 21, 2013, 10:55 a.m.
On 21 March 2013 08:51, Gerd Hoffmann <kraxel@redhat.com> wrote:
> On 03/21/13 08:52, Gerd Hoffmann wrote:
>> On 03/20/13 21:06, Peter Maydell wrote:
>>> On 20 March 2013 09:43, Gerd Hoffmann <kraxel@redhat.com> wrote:
>>>> Multihead support:  For each graphical console we'll create a gtk
>>>> window, so with multiple graphics cards installed you get a gtk window
>>>> for each.  vte tabs are attached to the console #0 window.
>>>
>>> So is this going to mean arm's vexpress-a9 gets a pointless
>>> new second window? [there are two display devices in it].
>>
>> I don't think so, given that multiple graphical consoles are not really
>> supported by qemu today.
>>
>> Basically you get one window per graphical_console_init().
>
> Ahem, well, there is a second window now.

Thought there might be :-)

>>> If so, we're going to need to model what the hardware actually
>>> does, which is that there's a single connection on the back
>>> of the box for a monitor, and it's guest software controllable
>>> which of the two display devices is routed to the connection...
>>
>> How does this work in 1.4?
>
> I guess the second display device was never ever shown anywhere?

Correct. We rely on "last display device wins" plus the fact this
happens to match up with the device Linux chooses for display.
This is obviously not great but up til now QEMU hasn't actually
supported multiple display devices so I haven't worried about it.

-- PMM
Gerd Hoffmann - March 21, 2013, 2:43 p.m.
Hi,

>>>> If so, we're going to need to model what the hardware actually
>>>> does, which is that there's a single connection on the back
>>>> of the box for a monitor, and it's guest software controllable
>>>> which of the two display devices is routed to the connection...
>>>
>>> How does this work in 1.4?
>>
>> I guess the second display device was never ever shown anywhere?
> 
> Correct. We rely on "last display device wins" plus the fact this
> happens to match up with the device Linux chooses for display.
> This is obviously not great but up til now QEMU hasn't actually
> supported multiple display devices so I haven't worried about it.

Ok.

I think the most sensible way to handle this is to implement the output
routing device, make it own the (single) QemuConsole, and depending on
the router state the one or the other display device is allowed to
render to the QemuConsole.

Alternative would be to give a QemuConsole to each display device (like
it is today), then add graphics_hw_{activate,deactivate} ops and have
UIs react on it.  I suspect that would quickly become a bit messy though
with all the different UIs we have.  Also with gtk you could end up with
the vte tabs being attached to a window with an inactive display device ...

Comments?

cheers,
  Gerd
Anthony Liguori - March 21, 2013, 6:25 p.m.
Gerd Hoffmann <kraxel@redhat.com> writes:

>   Hi,
>
>>>>> If so, we're going to need to model what the hardware actually
>>>>> does, which is that there's a single connection on the back
>>>>> of the box for a monitor, and it's guest software controllable
>>>>> which of the two display devices is routed to the connection...
>>>>
>>>> How does this work in 1.4?
>>>
>>> I guess the second display device was never ever shown anywhere?
>> 
>> Correct. We rely on "last display device wins" plus the fact this
>> happens to match up with the device Linux chooses for display.
>> This is obviously not great but up til now QEMU hasn't actually
>> supported multiple display devices so I haven't worried about it.
>
> Ok.
>
> I think the most sensible way to handle this is to implement the output
> routing device, make it own the (single) QemuConsole, and depending on
> the router state the one or the other display device is allowed to
> render to the QemuConsole.

Where does the switching happen in hardware?  Is this two devices with a
DVI port with a switch on it to have a single output port or it is
something more sophisticated where there are two memory regions and a
register is used to select which one is written out?

Regards,

Anthony Liguori
Peter Maydell - March 22, 2013, 11:19 a.m.
On 21 March 2013 18:25, Anthony Liguori <aliguori@us.ibm.com> wrote:
> Gerd Hoffmann <kraxel@redhat.com> writes:
>> I think the most sensible way to handle this is to implement the output
>> routing device, make it own the (single) QemuConsole, and depending on
>> the router state the one or the other display device is allowed to
>> render to the QemuConsole.
>
> Where does the switching happen in hardware?  Is this two devices with a
> DVI port with a switch on it to have a single output port or it is
> something more sophisticated where there are two memory regions and a
> register is used to select which one is written out?

The motherboard has a DVI multiplexer, which selects between the
two video+audio output streams (actually it selects between three
sources but we don't model the second daughterboard at all). I think
these streams are not actually DVI but they are certainly video
with pixel clock and S/PDIF audio already. There's a config register
in the motherboard which selects which source should go out to the
DVI connector. Conceptually I think it should look like this:

                             /-----\
   [ PL111 ] ===(video)====> |     |
                             | MUX | ===(video)===> [display]
   [ PL111 ] ===(video)====> |     |
                             \-----/
                                ^
   [arm_sysregs]---(qemu_irq)---/

(where [] means a device and () a kind of connection.)

If we supported routing of audio output we could in theory run
the audio through the mux in the same way.

-- PMM

Patch

diff --git a/ui/gtk.c b/ui/gtk.c
index 512e974..1c86054 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -159,8 +159,6 @@  typedef struct GtkDisplayState
     bool external_pause_update;
 } GtkDisplayState;
 
-static GtkDisplayState *global_state;
-
 /** Utility Functions **/
 
 static bool gd_is_grab_active(GtkDisplayState *s)
@@ -1210,7 +1208,7 @@  static void gd_connect_signals(GtkDisplayState *s)
                      G_CALLBACK(gd_leave_event), s);
 }
 
-static void gd_create_menus(GtkDisplayState *s)
+static void gd_create_menus(GtkDisplayState *s, bool vtetabs)
 {
     GtkStockItem item;
     GtkAccelGroup *accel_group;
@@ -1302,11 +1300,13 @@  static void gd_create_menus(GtkDisplayState *s)
     gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK);
     gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->vga_item);
 
-    for (i = 0; i < nb_vcs; i++) {
-        VirtualConsole *vc = &s->vc[i];
+    if (vtetabs) {
+        for (i = 0; i < nb_vcs; i++) {
+            VirtualConsole *vc = &s->vc[i];
 
-        group = gd_vc_init(s, vc, i, group);
-        s->nb_vcs++;
+            group = gd_vc_init(s, vc, i, group);
+            s->nb_vcs++;
+        }
     }
 
     separator = gtk_separator_menu_item_new();
@@ -1336,14 +1336,13 @@  static const DisplayChangeListenerOps dcl_ops = {
     .dpy_cursor_define = gd_cursor_define,
 };
 
-void gtk_display_init(DisplayState *ds)
+static void gtk_display_init_one(DisplayState *ds, QemuConsole *con,
+                                 bool vtetabs)
 {
     GtkDisplayState *s = g_malloc0(sizeof(*s));
 
-    gtk_init(NULL, NULL);
-
     s->dcl.ops = &dcl_ops;
-    s->dcl.con = qemu_console_lookup_by_index(0);
+    s->dcl.con = con;
 
     s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 #if GTK_CHECK_VERSION(3, 2, 0)
@@ -1371,7 +1370,7 @@  void gtk_display_init(DisplayState *ds)
 
     gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), s->drawing_area, gtk_label_new("VGA"));
 
-    gd_create_menus(s);
+    gd_create_menus(s, vtetabs);
 
     gd_connect_signals(s);
 
@@ -1400,6 +1399,21 @@  void gtk_display_init(DisplayState *ds)
     gtk_widget_show_all(s->window);
 
     register_displaychangelistener(ds, &s->dcl);
+}
 
-    global_state = s;
+void gtk_display_init(DisplayState *ds)
+{
+    QemuConsole *con;
+    int i = 0;
+
+    gtk_init(NULL, NULL);
+
+    con = qemu_console_lookup_by_index(i++);
+    gtk_display_init_one(ds, con, true);
+    while ((con = qemu_console_lookup_by_index(i++)) != NULL) {
+        if (!qemu_console_is_graphic(con)) {
+            break;
+        }
+        gtk_display_init_one(ds, con, false);
+    }
 }