Add support for SPICE.
[virt-click.git] / vnc.c
1 /* virt-click
2  * Copyright (C) 2011 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  *
18  * Parts are derived from 'gvnccapture':
19  *
20  * Vnc Image Capture
21  *
22  * Copyright (C) 2010 Daniel P. Berrange <dan@berrange.com>
23  *
24  * This library is free software; you can redistribute it and/or
25  * modify it under the terms of the GNU Lesser General Public
26  * License as published by the Free Software Foundation; either
27  * version 2.0 of the License, or (at your option) any later version.
28  *
29  * This library is distributed in the hope that it will be useful,
30  * but WITHOUT ANY WARRANTY; without even the implied warranty of
31  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
32  * Lesser General Public License for more details.
33  *
34  * You should have received a copy of the GNU Lesser General Public
35  * License along with this library; if not, write to the Free Software
36  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
37  */
38
39 #include <config.h>
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45
46 #include <glib/gi18n.h>
47 #include <vncconnection.h>
48 #include <vncbaseframebuffer.h>
49
50 #include "click.h"
51
52 static void initialized (VncConnection *conn, gpointer opaque);
53 static void disconnected (VncConnection *conn, gpointer opaque);
54 static int click (struct self_t *self, int x, int y, int b);
55 static void shutdown (self_t *self);
56
57 static callbacks_t callbacks = {
58   .click = click,
59   .shutdown = shutdown,
60 };
61
62 static gchar *vnc;
63 static gchar *host;
64 static int port;
65
66 static GOptionEntry vnc_entries[] = {
67   { "vnc", 0, 0,  G_OPTION_ARG_STRING,
68     &vnc, "Connect to VNC server directly", NULL },
69   { NULL }
70 };
71 static GOptionGroup *vnc_group;
72
73 GOptionGroup *
74 vc_vnc_cmdline_get_option_group (void)
75 {
76   if (vnc_group == NULL) {
77     vnc_group = g_option_group_new ("vnc",
78                                     _("VNC Options:"),
79                                     _("Show VNC Options"),
80                                     NULL, NULL);
81     g_option_group_add_entries (vnc_group, vnc_entries);
82   }
83   return vnc_group;
84 }
85
86 gboolean
87 vc_vnc_is_selected (void)
88 {
89   return vnc != NULL;
90 }
91
92 void
93 vc_vnc_setup (self_t *self)
94 {
95   gchar *display;
96   gchar *port_str;
97
98   self->callbacks = &callbacks;
99
100   if (verbose)
101     vnc_util_set_debug (TRUE);
102
103   if (vnc[0] == ':') {
104     host = g_strdup ("localhost");
105     display = vnc;
106   } else {
107     host = g_strdup (vnc);
108     display = strchr (host, ':');
109   }
110   if (display) {
111     *display = 0;
112     display++;
113     port = 5900 + atoi (display);
114   } else
115     port = 5900;
116
117   self->conn = vnc_connection_new ();
118
119   g_signal_connect (self->conn, "vnc-initialized",
120                     G_CALLBACK(initialized), self);
121   g_signal_connect (self->conn, "vnc-disconnected",
122                     G_CALLBACK(disconnected), self);
123   g_signal_connect (self->conn, "vnc-auth-choose-type",
124                     G_CALLBACK(vc_vnc_auth_choose_type), self);
125   g_signal_connect (self->conn, "vnc-auth-choose-subtype",
126                     G_CALLBACK(vc_vnc_auth_choose_type), self);
127   g_signal_connect (self->conn, "vnc-auth-credential",
128                     G_CALLBACK(vc_vnc_auth_credential), self);
129
130   port_str = g_strdup_printf ("%d", port);
131   vnc_connection_open_host (self->conn, host, port_str);
132   g_free (port_str);
133 }
134
135 static void
136 initialized (VncConnection *conn,
137              gpointer opaque)
138 {
139   self_t *self = opaque;
140   gint32 encodings[] = {  VNC_CONNECTION_ENCODING_DESKTOP_RESIZE,
141                           VNC_CONNECTION_ENCODING_ZRLE,
142                           VNC_CONNECTION_ENCODING_HEXTILE,
143                           VNC_CONNECTION_ENCODING_RRE,
144                           VNC_CONNECTION_ENCODING_COPY_RECT,
145                           VNC_CONNECTION_ENCODING_RAW };
146   gint32 *encodingsp;
147   int n_encodings;
148
149   if (verbose)
150     fprintf (stderr, "Connected to %s:%d\n", host, port - 5900);
151
152   /* Remember that we managed to connect. */
153   self->connected = TRUE;
154
155   /* Send encodings.
156    * NB: Although this step is useless, you *MUST* send encodings otherwise
157    * qemu's internal VNC server refuses to parse any other events.
158    */
159   encodingsp = encodings;
160   n_encodings = G_N_ELEMENTS(encodings);
161
162   if (!vnc_connection_set_encodings(conn, n_encodings, encodingsp)) {
163     self->ret = EXIT_FAILURE;
164     vnc_connection_shutdown (self->conn);
165     return;
166   }
167
168   /* Issue the command. */
169   vc_issue_command (self);
170 }
171
172 static void
173 disconnected (VncConnection *conn G_GNUC_UNUSED,
174               gpointer opaque)
175 {
176   self_t *self = opaque;
177
178   if (self->connected) {
179     self->ret = EXIT_SUCCESS;
180     if (verbose)
181       fprintf (stderr, "Disconnected from %s:%d\n",
182                host, port - 5900);
183   } else {
184     fprintf (stderr, "vnc: unable to connect to %s:%d\n",
185              host, port - 5900);
186     self->ret = EXIT_FAILURE;
187   }
188
189   g_main_quit(self->loop);
190 }
191
192 static void
193 shutdown (self_t *self)
194 {
195   vnc_connection_shutdown (self->conn);
196   g_object_unref (self->conn);
197   g_free (host);
198 }
199
200 static int
201 click (struct self_t *self, int x, int y, int b)
202 {
203   unsigned mask = b > 0 ? 1 << (b-1) : 0;
204
205   if (!vnc_connection_pointer_event (self->conn, mask, x, y))
206     return -1;
207
208   return 0;
209 }