file: factor a bit setting accelerators code
Rename internal toggle-fullscreen menu accel name

This avoid confusion with other fullscreen state property
file: learn to set secure-attention hotkey
Unify configured hotkey behaviour

Whether the hotkeys are set through command line, controller or file, we
should get the same keybinding result (clear unspecified, and enable
global bindings)

However, when started from command line arguments, without --hotkey
argument, it will have basic non-global default bindings.

https://bugzilla.redhat.com/show_bug.cgi?id=1023447
Drop basic fullscreen mode

Remove the distinction between --full-screen and --full-screen=auto-conf.  Just
make --full-screen behave like auto-conf did.  There's really no advantage to
having two slightly different fullscreen startup modes.
Disconnect fullscreen map-event handler when leaving fullscreen

When we enter fullscreen mode before the window is shown, we set up a signal
handler to enter fullscreen mode when the window is mapped.  If we then leave
fullscreen mode before the window is mapped, we don't disconnect this handler,
so it will still enter fullscreen mode when it is shown.

Fixes rhbz #1009513
build-sys: Use gtk+ 3.0 by default

virt-viewer currenty builds with gtk+ 2.0 by default. Nowadays, gtk+ 2.0 is
legacy, and this default is inconsistent with spice-gtk which defaults to
gtk+ 3.0. This commit switches the default to gtk+ 3.0
Fix window title after failed connection

When using the connection dialog, if the user picks an invalid
URI first causing a failed connection, and then picks/enters a valid
URI, remote-viewer window title will be set to the first invalid URI,
not to the second one which was entered.

As the user may have specified a window title to use on the command
line (-t option), we need to be careful not to override that when
setting the window title on the second attempt.

Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1024309
Handle virt_viewer_app_start() errors

remote_viewer_deactivated() can be calling virt_viewer_app_start()
without checking whether it returns TRUE or FALSE. It returns FALSE
when it was not successful (when it failed to parse the URI to connect
to for example, or whe the user presses Cancel in the connection dialog).

This means that if the user starts remote-viewer, enters a valid URI
in the connection dialog to which it cannot connect to
(spice://example.com:999) and then presses Cancel in the connection
dialog that appears after the connection  failure, then remote-viewer
will be sitting there with an empty window doing nothing.

This commit ensures we chain to the parent class when
virt_viewer_app_start() returns FALSE, which causes remote-viewer to
exit.
Reshow connection dialog on errors

remote-viewer behaviour is currently inconsistent in the connection dialog:
if the user enters a valid URI, but then remote-viewer fails to connect
to it, then we'll show again the connection dialog through a call
to virt_viewer_app_start() in remote_viewer_deactivated(). If instead we
enter an invalid URI in the connection dialog, then remote-viewer will
report an error and quit.

This commit makes sure in the latter case, we report the error and show
again the connection dialog. The user can press 'Cancel' in the
connection dialog to get out of remote-viewer as in this case, we
return directly FALSE rather than going through the cleanup: label
and looping.
Hide all windows on disconnection

When starting remote-viewer without argument, we are showing a
window where the user can enter connection details. We then
go on to try and connect to the URI the user specified, and if
the connection fails, we disconnect from the remote server, and then
we show again the connection window so that the user can correct the
URI if he entered it wrong.
However, when this happens, the window for the previous connection
will still be visible even if connection failed. To avoid this,
this commit makes sure we hide all windows when we get a disconnection
event.

Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1024309
Remove obsolete use of SpiceChannel:virt-viewer-display object data

Commit 0d58d9c72 removed the setting of the
SpiceChannel:virt-viewer-display object data, but there was still a
call to g_object_get_data() trying to use it. Since it's only used to
output a debug log, we can remove this call and fix up the debug log.
session: Don't hold VirtViewerDisplay refs on channel destroy

VirtViewerSessionSpice creates a reference-holding VirtViewerDisplay
array and associates it with the display SpiceChannel with
g_object_set_data(channel, "virt-viewer-displays").

When virt_viewer_session_spice_channel_destroy() is called and the display
channel is being destroyed, we should ensure these VirtViewerDisplay
references are dropped or the displays could outlive the session.

In my testing (start qemu with a f20 live cd, connect to it, when the
kernel has started booting and qxl is initialized (4 displays listed in the
display submenu), kill qemu), I was getting "invalid unclassed pointer in
cast to 'VirtViewerSessionSpice'" warnings through

    #0  0x00000035bac504e9 in g_logv (log_domain=0x35bb039aa4 "GLib-GObject",
        log_level=G_LOG_LEVEL_WARNING, format=<optimized out>,
        args=args@entry=0x7fffffffc7c0) at gmessages.c:989
    #1  0x00000035bac5063f in g_log (
        log_domain=log_domain@entry=0x35bb039aa4 "GLib-GObject",
        log_level=log_level@entry=G_LOG_LEVEL_WARNING,
        format=format@entry=0x35bb041010 "invalid unclassed pointer in cast to '%s'")
        at gmessages.c:1025
    #2  0x00000035bb032e09 in g_type_check_instance_cast (type_instance=0x665580,
        iface_type=<optimized out>) at gtype.c:4025
    #3  0x0000000000426e9f in get_main (self=0x894190) at virt-viewer-display-spice.c:92
    #4  0x0000000000426ece in show_hint_changed (self=0x894190)
        at virt-viewer-display-spice.c:100
    #5  0x00000035bb010298 in g_closure_invoke (closure=0x9f47c0,
        return_value=return_value@entry=0x0, n_param_values=2,
        param_values=param_values@entry=0x7fffffffcad0,
        invocation_hint=invocation_hint@entry=0x7fffffffca70) at gclosure.c:777
    #6  0x00000035bb02235d in signal_emit_unlocked_R (node=node@entry=0x651f60,
        detail=detail@entry=1782, instance=instance@entry=0x894190,
        emission_return=emission_return@entry=0x0,
        instance_and_params=instance_and_params@entry=0x7fffffffcad0) at gsignal.c:3586
    #7  0x00000035bb02a0f2 in g_signal_emit_valist (instance=<optimized out>,
        signal_id=<optimized out>, detail=<optimized out>,
        var_args=var_args@entry=0x7fffffffcc60) at gsignal.c:3330
    #8  0x00000035bb02a3af in g_signal_emit (instance=<optimized out>,
        signal_id=<optimized out>, detail=<optimized out>) at gsignal.c:3386
    #9  0x00000035bb014945 in g_object_dispatch_properties_changed (object=0x894190,
        n_pspecs=92, pspecs=0x0) at gobject.c:1047
    #10 0x00000035bb017019 in g_object_notify_by_spec_internal (pspec=<optimized out>,
        object=0x894190) at gobject.c:1141
    #11 g_object_notify (object=0x894190, property_name=<optimized out>) at gobject.c:1183
    #12 0x000000000041b617 in virt_viewer_display_set_show_hint (self=0x894190, mask=1,
        enable=0) at virt-viewer-display.c:659
    #13 0x000000000042712c in update_display_ready (self=0x894190)
        at virt-viewer-display-spice.c:156
    #14 0x00000035bb010298 in g_closure_invoke (closure=0x6ba480,
        return_value=return_value@entry=0x0, n_param_values=2,
        param_values=param_values@entry=0x7fffffffcfb0,
        invocation_hint=invocation_hint@entry=0x7fffffffcf50) at gclosure.c:777
    #15 0x00000035bb02235d in signal_emit_unlocked_R (node=node@entry=0x651f60,
        detail=detail@entry=1798, instance=instance@entry=0xa2c250,
        emission_return=emission_return@entry=0x0,
        instance_and_params=instance_and_params@entry=0x7fffffffcfb0) at gsignal.c:3586
    #16 0x00000035bb02a0f2 in g_signal_emit_valist (instance=<optimized out>,
        signal_id=<optimized out>, detail=<optimized out>,
        var_args=var_args@entry=0x7fffffffd140) at gsignal.c:3330
    #17 0x00000035bb02a3af in g_signal_emit (instance=<optimized out>,
        signal_id=<optimized out>, detail=<optimized out>) at gsignal.c:3386
    #18 0x00000035bb014945 in g_object_dispatch_properties_changed (object=0xa2c250,
        n_pspecs=92, pspecs=0x0) at gobject.c:1047
    #19 0x00000035bb017019 in g_object_notify_by_spec_internal (pspec=<optimized out>,
        object=0xa2c250) at gobject.c:1141
    #20 g_object_notify (object=0xa2c250, property_name=<optimized out>) at gobject.c:1183
    #21 0x00007ffff7044d9a in update_ready (display=0xa2c250) at spice-widget.c:257
    #22 0x00007ffff7044df0 in set_monitor_ready (self=0xa2c250, ready=0)
        at spice-widget.c:265
    #23 0x00007ffff7049bb3 in primary_destroy (channel=0x9f40b0, data=0xa2c250)
        at spice-widget.c:2131
    #24 0x00007ffff704afd5 in channel_destroy (s=0x892880, channel=0x9f40b0, data=0xa2c250)
        at spice-widget.c:2444
    #25 0x00000035bb010298 in g_closure_invoke (closure=0xa27850,
        return_value=return_value@entry=0x0, n_param_values=2,
        param_values=param_values@entry=0x7fffffffd570,
        invocation_hint=invocation_hint@entry=0x7fffffffd510) at gclosure.c:777
    #26 0x00000035bb02235d in signal_emit_unlocked_R (node=node@entry=0x7cf600,
        detail=detail@entry=0, instance=instance@entry=0x892880,
        emission_return=emission_return@entry=0x0,
        instance_and_params=instance_and_params@entry=0x7fffffffd570) at gsignal.c:3586
    #27 0x00000035bb02a0f2 in g_signal_emit_valist (instance=<optimized out>,
        signal_id=<optimized out>, detail=<optimized out>,
        var_args=var_args@entry=0x7fffffffd700) at gsignal.c:3330
    #28 0x00000035bb02a3af in g_signal_emit (instance=<optimized out>,
        signal_id=<optimized out>, detail=<optimized out>) at gsignal.c:3386
    #29 0x00007ffff6ceba87 in spice_session_channel_destroy (session=0x892880,
        channel=0x9f40b0) at spice-session.c:1923
    #30 0x00007ffff6cecf05 in spice_channel_dispose (gobject=0x9f40b0)
        at spice-channel.c:149
    #31 0x00007ffff6cf912c in spice_display_channel_dispose (object=0x9f40b0)
        at channel-display.c:136
    #32 0x00000035bb014ee8 in g_object_unref (_object=0x9f40b0) at gobject.c:3160
    #33 0x00007ffff6cf300c in spice_channel_delayed_unref (data=0x9f40b0)
        at spice-channel.c:2135
    #34 0x00000035bac492a6 in g_main_dispatch (context=0x67a6b0) at gmain.c:3066
    #35 g_main_context_dispatch (context=context@entry=0x67a6b0) at gmain.c:3642
    #36 0x00000035bac49628 in g_main_context_iterate (context=0x67a6b0,
        block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>)
        at gmain.c:3713
    #37 0x00000035bac49a3a in g_main_loop_run (loop=0x7baf60) at gmain.c:3907
    #38 0x00000035bfdaa2d5 in gtk_main () at gtkmain.c:1158
    #39 0x000000000042caf1 in main (argc=1, argv=0x7fffffffdc78) at remote-viewer-main.c:179

In that backtrace, the last ref to the VirtViewerDisplay instances is held by the
SpiceChannel:virt-viewer-displays object data which will only be released after
completion of spice_display_channel_dispose()
Fix leak of VirtViewerApp::windows hash table key

The VirtViewerApp::windows hash table owns the memory for both the keys
and values it stores. virt_viewer_app_remove_nth_window() uses
g_hash_table_steal() which does not call the 'free' function neither for
the key nor for the value. This method takes care of releasing the
reference for the value it extracted from the hash table, but not for the
key.
This commit fixes by explicitly taking a reference on the value rather than
stealing the one held by the hash table. We can then replace the use of
g_hash_table_steal() with g_hash_table_remove() which will take care of
freeing the removed key.
Add ability to define custom display->monitor mapping per vm

Fullscreen mode generally just assigns display 1 to monitor 1, display 2 to
monitor 2, etc. For custom setups, you can define a monitor mapping in the
settings keyfile per-vm. This requires a vm uuid (so only works in virt-viewer
or on versions of spice-server that send the uuid over the wire).  The format is
pretty basic:

    [6485b20f-e9da-614c-72b0-60a7857e7886]
    monitor-mapping=2;3

The group name ("6485b20f-e9da-614c-72b0-60a7857e7886") is the uuid id of the
vm. This group has a single key: monitor-mapping. This key is an array of
integers describing the order in which to assign the monitors to a guest
display. Any monitors that are not listed in this array will not be configured
at startup.  For instance:

    monitor-mapping=2;1

will attempt to configure 2 displays on the guest and assign the first display
to monitor 2 and the second display to monitor 1.

    monitor-mapping=2

will only configure a single display on the guest and place it on the second
monitor.  Any monitor numbers listed in the keyfile are greater than the number
of monitors that are physically present, they will be ignored.
Ensure auto-conf is only done once

Auto-conf should only happen at startup. It is triggered from several places due
to the somewhat unreliable ordering of events, but that doesn't mean we want to
run it several times. This patch ensures that we only do it once.
separate fullscreen_set_active into a separate function
Remove non-functional VIRT_VIEWER_HIDE env behavior

VIRT_VIEWER_HIDE could be set as an environment variable to (theoretically) hide
displays whenever they were not ready.  Unfortunately, this bit of functionality
appears bitrotten and doesn't work anymore (it prevents windows from opening
when you click 'view > displays > display 2', for instance).
Ensure all windows obey initial --zoom setting

There are cases where multiple VirtViewerWindow objects are created before the
VirtViewerApp constructor has a chance to run. Since the constructor has not yet
run, priv->main_window will still be NULL, the test in
virt_viewer_app_window_new() will fail, and they will not get their initial zoom
level set.  When the constructor finally runs, it set the zoom level of the main
window to the value set on the command line, but all other windows that had
already been created retained the default 100% zoom level.

By creating the main_window in the instance init function, we ensure that the
main window is created before we get any 'session-display-added' signals and all
displays will start out with consistent zoom levels.
Do all display alignment in virt-viewer

Don't rely on spice-gtk to do any alignment of displays.  This patch sets the
disable-display-align property on the SpiceMainChannel, and makes the
VirtViewerSession in charge of doing all alignment. This means that every
display has to tell the VirtViewerSession when its "virtual monitor" has changed
configuration (and wants to reconfigure its display on the guest), rather than
sending it directly to the Main Channel.  The session will then align the
displays (if necessary), and the spice session will send down new configuration
for all displays at once. This solves a couple of problems:

1. It allows the session to send down absolute coordinates only in the case
   where *all* windows are fullscreen (so that we can still support
   vertically-stacked displays, etc).  But it auto-aligns displays if only a
   subset of the displays are in fullscreen mode. This solves the problem of
   overlapping regions on different displays when one monitor is in fullscreen
   because only one monitor's configuration was updated and the others were not
   aligned.
2. Allows us to always align based on the current position of each display. This
   contrasts with the earlier behavior where the position used for alignment was
   the window's position at the time when it was last resized. This caused
   displays to be arranged in a seemingly non-deterministic manner if one window
   was moved and then another window was resized (causing a display
   re-configuration).

Solves rhbz#1002156