more clipboard bits
[spice-gtk:spice-gtk-elmarco.git] / gtk / channel-main.c
1 #include "spice-client.h"
2 #include "spice-common.h"
3
4 #include "spice-session-priv.h"
5
6 #include <spice/vd_agent.h>
7
8 #define SPICE_MAIN_CHANNEL_GET_PRIVATE(obj)                             \
9     (G_TYPE_INSTANCE_GET_PRIVATE((obj), SPICE_TYPE_MAIN_CHANNEL, spice_main_channel))
10
11 struct spice_main_channel {
12     enum SpiceMouseMode         mouse_mode;
13     int                         agent_connected;
14     int                         agent_tokens;
15     uint8_t                     *agent_msg;
16     uint8_t                     *agent_msg_pos;
17     uint8_t                     *agent_msg_size;
18     struct {
19         int                     x;
20         int                     y;
21         int                     width;
22         int                     height;
23     } display[1];
24 };
25
26 G_DEFINE_TYPE(SpiceMainChannel, spice_main_channel, SPICE_TYPE_CHANNEL)
27
28 enum {
29     SPICE_MAIN_MOUSE_MODE,
30     SPICE_MAIN_AGENT_EVENT,
31
32     SPICE_MAIN_LAST_SIGNAL,
33 };
34
35 static guint signals[SPICE_MAIN_LAST_SIGNAL];
36
37 static void spice_main_handle_msg(SpiceChannel *channel, spice_msg_in *msg);
38
39 /* ------------------------------------------------------------------ */
40
41 static void spice_main_channel_init(SpiceMainChannel *channel)
42 {
43     spice_main_channel *c;
44
45     fprintf(stderr, "%s\n", __FUNCTION__);
46
47     c = channel->priv = SPICE_MAIN_CHANNEL_GET_PRIVATE(channel);
48     memset(c, 0, sizeof(*c));
49 }
50
51 static void spice_main_channel_finalize(GObject *obj)
52 {
53     fprintf(stderr, "%s\n", __FUNCTION__);
54
55     if (G_OBJECT_CLASS(spice_main_channel_parent_class)->finalize)
56         G_OBJECT_CLASS(spice_main_channel_parent_class)->finalize(obj);
57 }
58
59 static void spice_main_channel_class_init(SpiceMainChannelClass *klass)
60 {
61     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
62     SpiceChannelClass *channel_class = SPICE_CHANNEL_CLASS(klass);
63
64     fprintf(stderr, "%s\n", __FUNCTION__);
65
66     gobject_class->finalize     = spice_main_channel_finalize;
67     channel_class->handle_msg   = spice_main_handle_msg;
68
69     signals[SPICE_MAIN_MOUSE_MODE] =
70         g_signal_new("spice-main-mouse-mode",
71                      G_OBJECT_CLASS_TYPE(gobject_class),
72                      G_SIGNAL_RUN_FIRST,
73                      G_STRUCT_OFFSET(SpiceMainChannelClass, spice_main_mouse_mode),
74                      NULL, NULL,
75                      g_cclosure_marshal_VOID__INT,
76                      G_TYPE_NONE,
77                      1,
78                      G_TYPE_INT);
79
80     signals[SPICE_MAIN_AGENT_EVENT] =
81         g_signal_new("spice-main-agent-event",
82                      G_OBJECT_CLASS_TYPE(gobject_class),
83                      G_SIGNAL_RUN_FIRST,
84                      G_STRUCT_OFFSET(SpiceMainChannelClass, spice_main_agent_event),
85                      NULL, NULL,
86                      g_cclosure_marshal_VOID__INT,
87                      G_TYPE_NONE,
88                      1,
89                      G_TYPE_INT);
90
91     g_type_class_add_private(klass, sizeof(spice_main_channel));
92 }
93
94 /* ------------------------------------------------------------------ */
95
96 static void agent_monitors_config(SpiceChannel *channel)
97 {
98     spice_main_channel *c = SPICE_MAIN_CHANNEL(channel)->priv;
99     spice_msg_out *out;
100     VDAgentMessage* msg;
101     VDAgentMonitorsConfig *mon;
102     int i, monitors = 1;
103     size_t size;
104
105     if (!c->agent_connected)
106         return;
107     for (i = 0; i < monitors; i++) {
108         if (!c->display[i].width ||
109             !c->display[i].height)
110             return;
111     }
112
113     size = sizeof(VDAgentMonitorsConfig) + sizeof(VDAgentMonConfig) * monitors;
114     out = spice_msg_out_new(channel, SPICE_MSGC_MAIN_AGENT_DATA);
115     msg = (VDAgentMessage*)
116         spice_marshaller_reserve_space(out->marshaller, sizeof(VDAgentMessage));
117     mon = (VDAgentMonitorsConfig*)
118         spice_marshaller_reserve_space(out->marshaller, size);
119
120     msg->protocol = VD_AGENT_PROTOCOL;
121     msg->type = VD_AGENT_MONITORS_CONFIG;
122     msg->opaque = 0;
123     msg->size = size;
124
125     mon->num_of_monitors = monitors;
126     mon->flags = 0;
127     for (i = 0; i < monitors; i++) {
128         mon->monitors[i].depth  = 32;
129         mon->monitors[i].width  = c->display[i].width;
130         mon->monitors[i].height = c->display[i].height;
131         mon->monitors[i].x = c->display[i].x;
132         mon->monitors[i].y = c->display[i].y;
133         fprintf(stderr, "%s: #%d %dx%d+%d+%d @ %d bpp\n", __FUNCTION__, i,
134                 mon->monitors[i].width, mon->monitors[i].height,
135                 mon->monitors[i].x, mon->monitors[i].y,
136                 mon->monitors[i].depth);
137     }
138
139     spice_msg_out_send(out);
140     spice_msg_out_put(out);
141 }
142
143 static void agent_start(SpiceChannel *channel)
144 {
145     spice_main_channel *c = SPICE_MAIN_CHANNEL(channel)->priv;
146     SpiceMsgcMainAgentStart agent_start = {
147         .num_tokens = ~0,
148     };
149     spice_msg_out *out;
150
151     c->agent_connected = true;
152     g_signal_emit(channel, signals[SPICE_MAIN_AGENT_EVENT], 0,
153                   SPICE_AGENT_CONNECT);
154
155     out = spice_msg_out_new(channel, SPICE_MSGC_MAIN_AGENT_START);
156     out->marshallers->msgc_main_agent_start(out->marshaller, &agent_start);
157     spice_msg_out_send(out);
158     spice_msg_out_put(out);
159
160     agent_monitors_config(channel);
161 }
162
163 static void agent_stopped(SpiceChannel *channel)
164 {
165     spice_main_channel *c = SPICE_MAIN_CHANNEL(channel)->priv;
166
167     c->agent_connected = false;
168     g_signal_emit(channel, signals[SPICE_MAIN_AGENT_EVENT], 0,
169                   SPICE_AGENT_DISCONNECT);
170 }
171
172 static void set_mouse_mode(SpiceChannel *channel, uint32_t supported, uint32_t current)
173 {
174     spice_main_channel *c = SPICE_MAIN_CHANNEL(channel)->priv;
175
176     if (c->mouse_mode != current) {
177         c->mouse_mode = current;
178         g_signal_emit(channel, signals[SPICE_MAIN_MOUSE_MODE], 0, current);
179     }
180
181     /* switch to client mode if possible */
182     if ((supported & SPICE_MOUSE_MODE_CLIENT) && (current != SPICE_MOUSE_MODE_CLIENT)) {
183         SpiceMsgcMainMouseModeRequest req = {
184             .mode = SPICE_MOUSE_MODE_CLIENT,
185         };
186         spice_msg_out *out;
187         out = spice_msg_out_new(channel, SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST);
188         out->marshallers->msgc_main_mouse_mode_request(out->marshaller, &req);
189         spice_msg_out_send(out);
190         spice_msg_out_put(out);
191     }
192 }
193
194 static void main_handle_init(SpiceChannel *channel, spice_msg_in *in)
195 {
196     spice_main_channel *c = SPICE_MAIN_CHANNEL(channel)->priv;
197     SpiceMsgMainInit *init = spice_msg_in_parsed(in);
198     SpiceSession *session;
199     spice_msg_out *out;
200
201     g_object_get(channel, "spice-session", &session, NULL);
202     spice_session_set_connection_id(session, init->session_id);
203
204     out = spice_msg_out_new(channel, SPICE_MSGC_MAIN_ATTACH_CHANNELS);
205     spice_msg_out_send(out);
206     spice_msg_out_put(out);
207
208     set_mouse_mode(channel, init->supported_mouse_modes, init->current_mouse_mode);
209
210     c->agent_tokens = init->agent_tokens;
211     if (init->agent_connected) {
212         agent_start(channel);
213     }
214
215 #if 0
216     set_mm_time(init->multi_media_time);
217 #endif
218 }
219
220 static void main_handle_mm_time(SpiceChannel *channel, spice_msg_in *in)
221 {
222     fprintf(stderr, "%s: TODO\n", __FUNCTION__);
223 #if 0
224     set_mm_time(init->multi_media_time);
225 #endif
226 }
227
228 static void main_handle_channels_list(SpiceChannel *channel, spice_msg_in *in)
229 {
230     SpiceMsgChannels *msg = spice_msg_in_parsed(in);
231     SpiceSession *session;
232     SpiceChannel *add;
233     int i;
234
235     g_object_get(channel, "spice-session", &session, NULL);
236     for (i = 0; i < msg->num_of_channels; i++) {
237         add = spice_channel_new(session, msg->channels[i].type,
238                                 msg->channels[i].id);
239     }
240 }
241
242 static void main_handle_mouse_mode(SpiceChannel *channel, spice_msg_in *in)
243 {
244     SpiceMsgMainMouseMode *msg = spice_msg_in_parsed(in);
245     set_mouse_mode(channel, msg->supported_modes, msg->current_mode);
246 }
247
248 static void main_handle_agent_connected(SpiceChannel *channel, spice_msg_in *in)
249 {
250     agent_start(channel);
251 }
252
253 static void main_handle_agent_disconnected(SpiceChannel *channel, spice_msg_in *in)
254 {
255     agent_stopped(channel);
256 }
257
258 static void main_handle_agent_data(SpiceChannel *channel, spice_msg_in *in)
259 {
260     spice_main_channel *c = SPICE_MAIN_CHANNEL(channel)->priv;
261     VDAgentMessage *msg;
262     int len;
263
264     spice_msg_in_hexdump(in);
265
266     if (!c->agent_msg) {
267         msg = spice_msg_in_raw(in, &len);
268         assert(len > sizeof(VDAgentMessage));
269         if (msg->size + sizeof(VDAgentMessage) > len) {
270             fprintf(stderr, "%s: TODO: start buffer\n", __FUNCTION__);
271         } else {
272             assert(msg->size + sizeof(VDAgentMessage) == len);
273             goto complete;
274         }
275     } else {
276         fprintf(stderr, "%s: TODO: fill buffer\n", __FUNCTION__);
277     }
278     return;
279
280 complete:
281     switch (msg->type) {
282     case VD_AGENT_REPLY:
283     {
284         VDAgentReply *reply = (VDAgentReply*)(msg+1);
285         fprintf(stderr, "%s: reply: type %d, %s\n", __FUNCTION__, reply->type,
286                 reply->error == VD_AGENT_SUCCESS ? "success" : "error");
287         break;
288     }
289     case VD_AGENT_CLIPBOARD:
290         fprintf(stderr, "%s: clipboard\n", __FUNCTION__);
291         break;
292     default:
293         fprintf(stderr, "unsupported agent message type %u size %u\n",
294                 msg->type, msg->size);
295     }
296 }
297
298 static void main_handle_agent_token(SpiceChannel *channel, spice_msg_in *in)
299 {
300     fprintf(stderr, "%s: TODO\n", __FUNCTION__);
301 }
302
303 static spice_msg_handler main_handlers[] = {
304     [ SPICE_MSG_SET_ACK ]                  = spice_channel_handle_set_ack,
305     [ SPICE_MSG_PING ]                     = spice_channel_handle_ping,
306     [ SPICE_MSG_NOTIFY ]                   = spice_channel_handle_notify,
307
308     [ SPICE_MSG_MAIN_INIT ]                = main_handle_init,
309     [ SPICE_MSG_MAIN_CHANNELS_LIST ]       = main_handle_channels_list,
310     [ SPICE_MSG_MAIN_MOUSE_MODE ]          = main_handle_mouse_mode,
311     [ SPICE_MSG_MAIN_MULTI_MEDIA_TIME ]    = main_handle_mm_time,
312
313     [ SPICE_MSG_MAIN_AGENT_CONNECTED ]     = main_handle_agent_connected,
314     [ SPICE_MSG_MAIN_AGENT_DISCONNECTED ]  = main_handle_agent_disconnected,
315     [ SPICE_MSG_MAIN_AGENT_DATA ]          = main_handle_agent_data,
316     [ SPICE_MSG_MAIN_AGENT_TOKEN ]         = main_handle_agent_token,
317 };
318
319 static void spice_main_handle_msg(SpiceChannel *channel, spice_msg_in *msg)
320 {
321     int type = spice_msg_in_type(msg);
322     assert(type < SPICE_N_ELEMENTS(main_handlers));
323     assert(main_handlers[type] != NULL);
324     main_handlers[type](channel, msg);
325 }
326
327 enum SpiceMouseMode spice_main_get_mouse_mode(SpiceChannel *channel)
328 {
329     spice_main_channel *c = SPICE_MAIN_CHANNEL(channel)->priv;
330     return c->mouse_mode;
331 }
332
333 void spice_main_set_display(SpiceChannel *channel, int id,
334                             int x, int y, int width, int height)
335 {
336     spice_main_channel *c = SPICE_MAIN_CHANNEL(channel)->priv;
337
338     if (id < SPICE_N_ELEMENTS(c->display)) {
339         c->display[id].x      = x;
340         c->display[id].y      = y;
341         c->display[id].width  = width;
342         c->display[id].height = height;
343         agent_monitors_config(channel);
344     }
345 }
346
347 void spice_main_clipboard_grab(SpiceChannel *channel, int *types, int ntypes)
348 {
349     fprintf(stderr, "%s: TODO (%d types)\n", __FUNCTION__, ntypes);
350 }
351
352 void spice_main_clipboard_release(SpiceChannel *channel)
353 {
354     fprintf(stderr, "%s: TODO\n", __FUNCTION__);
355 }