static gboolean clipboard_request(SpiceMainChannel *main, guint selection, guint type, gpointer user_data) { g_return_val_if_fail(SPICE_IS_GTK_SESSION(user_data), FALSE); SpiceGtkSession *self = user_data; SpiceGtkSessionPrivate *s = self->priv; GdkAtom atom; GtkClipboard* cb; int m; if (read_only(self)) return FALSE; cb = get_clipboard_from_selection(s, selection); g_return_val_if_fail(cb != NULL, FALSE); for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) { if (atom2agent[m].vdagent == type) break; } g_return_val_if_fail(m < SPICE_N_ELEMENTS(atom2agent), FALSE); atom = gdk_atom_intern_static_string(atom2agent[m].xatom); gtk_clipboard_request_contents(cb, atom, clipboard_received_cb, weak_ref(G_OBJECT(self))); return TRUE; }
static gboolean clipboard_grab(SpiceMainChannel *main, guint selection, guint32* types, guint32 ntypes, gpointer user_data) { g_return_val_if_fail(SPICE_IS_GTK_SESSION(user_data), FALSE); SpiceGtkSession *self = user_data; SpiceGtkSessionPrivate *s = self->priv; GtkTargetEntry targets[SPICE_N_ELEMENTS(atom2agent)]; gboolean target_selected[SPICE_N_ELEMENTS(atom2agent)] = { FALSE, }; gboolean found; GtkClipboard* cb; int m, n, i; cb = get_clipboard_from_selection(s, selection); g_return_val_if_fail(cb != NULL, FALSE); i = 0; for (n = 0; n < ntypes; ++n) { found = FALSE; for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) { if (atom2agent[m].vdagent == types[n] && !target_selected[m]) { found = TRUE; g_return_val_if_fail(i < SPICE_N_ELEMENTS(atom2agent), FALSE); targets[i].target = (gchar*)atom2agent[m].xatom; targets[i].flags = 0; targets[i].info = m; target_selected[m] = TRUE; i += 1; } } if (!found) { g_warning("clipboard: couldn't find a matching type for: %d", types[n]); } } g_free(s->clip_targets[selection]); s->nclip_targets[selection] = i; s->clip_targets[selection] = g_memdup(targets, sizeof(GtkTargetEntry) * i); /* Receiving a grab implies we've released our own grab */ s->clip_grabbed[selection] = FALSE; if (read_only(self) || !s->auto_clipboard_enable || s->nclip_targets[selection] == 0) goto skip_grab_clipboard; if (!gtk_clipboard_set_with_owner(cb, targets, i, clipboard_get, clipboard_clear, G_OBJECT(self))) { g_warning("clipboard grab failed"); return FALSE; } s->clipboard_by_guest[selection] = TRUE; s->clip_hasdata[selection] = FALSE; skip_grab_clipboard: return TRUE; }
static void clipboard_received_cb(GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer user_data) { WeakRef *weakref = user_data; SpiceGtkSession *self = (SpiceGtkSession*)weakref->object; weak_unref(weakref); if (self == NULL) return; g_return_if_fail(SPICE_IS_GTK_SESSION(self)); SpiceGtkSessionPrivate *s = self->priv; gint len = 0, m; guint32 type = VD_AGENT_CLIPBOARD_NONE; gchar* name; GdkAtom atom; int selection; selection = get_selection_from_clipboard(s, clipboard); g_return_if_fail(selection != -1); len = gtk_selection_data_get_length(selection_data); if (len == -1) { SPICE_DEBUG("empty clipboard"); len = 0; } else if (len == 0) { SPICE_DEBUG("TODO: what should be done here?"); } else { atom = gtk_selection_data_get_data_type(selection_data); name = gdk_atom_name(atom); for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) { if (strcasecmp(name, atom2agent[m].xatom) == 0) { break; } } if (m >= SPICE_N_ELEMENTS(atom2agent)) { g_warning("clipboard_received for unsupported type: %s", name); } else { type = atom2agent[m].vdagent; } g_free(name); } spice_main_clipboard_selection_notify(s->main, selection, type, gtk_selection_data_get_data(selection_data), len); }
static const char * spice_log_level_to_string(SpiceLogLevel level) { #ifdef _MSC_VER /* MSVC++ does not implement C99 */ static const char *to_string[] = { "ERROR", "CRITICAL", "Warning", "Info", "Debug"}; #else static const char *to_string[] = { [ SPICE_LOG_LEVEL_ERROR ] = "ERROR", [ SPICE_LOG_LEVEL_CRITICAL ] = "CRITICAL", [ SPICE_LOG_LEVEL_WARNING ] = "Warning", [ SPICE_LOG_LEVEL_INFO ] = "Info", [ SPICE_LOG_LEVEL_DEBUG ] = "Debug", }; #endif const char *str = NULL; if (level < SPICE_N_ELEMENTS(to_string)) { str = to_string[level]; } return str; }
static void clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, gpointer user_data) { g_return_if_fail(SPICE_IS_GTK_SESSION(user_data)); RunInfo ri = { NULL, }; SpiceGtkSession *self = user_data; SpiceGtkSessionPrivate *s = self->priv; gulong clipboard_handler; gulong agent_handler; int selection; SPICE_DEBUG("clipboard get"); selection = get_selection_from_clipboard(s, clipboard); g_return_if_fail(selection != -1); g_return_if_fail(info < SPICE_N_ELEMENTS(atom2agent)); g_return_if_fail(s->main != NULL); ri.selection_data = selection_data; ri.info = info; ri.loop = g_main_loop_new(NULL, FALSE); ri.selection = selection; clipboard_handler = g_signal_connect(s->main, "main-clipboard-selection", G_CALLBACK(clipboard_got_from_guest), &ri); agent_handler = g_signal_connect(s->main, "notify::agent-connected", G_CALLBACK(clipboard_agent_connected), &ri); spice_main_clipboard_selection_request(s->main, selection, atom2agent[info].vdagent); /* apparently, this is needed to avoid dead-lock, from gtk_dialog_run */ gdk_threads_leave(); g_main_loop_run(ri.loop); gdk_threads_enter(); g_main_loop_unref(ri.loop); ri.loop = NULL; g_signal_handler_disconnect(s->main, clipboard_handler); g_signal_handler_disconnect(s->main, agent_handler); }
static void channel_destroy(SpiceSession *s, SpiceChannel *channel, gpointer data) { __android_log_write(ANDROID_LOG_INFO, "android-spice", "channel_destroy called"); spice_connection *conn = data; int id; g_object_get(channel, "channel-id", &id, NULL); if (SPICE_IS_MAIN_CHANNEL(channel)) { SPICE_DEBUG("zap main channel"); conn->main = NULL; } if (SPICE_IS_DISPLAY_CHANNEL(channel)) { if (id >= SPICE_N_ELEMENTS(conn->wins)) return; if (conn->wins[id] == NULL) return; SPICE_DEBUG("zap display channel (#%d)", id); destroy_spice_window(conn->wins[id]); conn->wins[id] = NULL; } if (SPICE_IS_PLAYBACK_CHANNEL(channel)) { SPICE_DEBUG("zap audio channel"); } if (SPICE_IS_USBREDIR_CHANNEL(channel)) { __android_log_write(ANDROID_LOG_INFO, "android-spice", "Destroyed USB channel."); //update_auto_usbredir_sensitive(conn); } //if (SPICE_IS_PORT_CHANNEL(channel)) { // if (SPICE_PORT_CHANNEL(channel) == stdin_port) // stdin_port = NULL; //} conn->channels--; char buf[100]; snprintf (buf, 100, "Number of channels: %d", conn->channels); __android_log_write(ANDROID_LOG_INFO, "android-spice", buf); if (conn->channels > 0) { return; } connection_destroy(conn); }
static void spice_channel_constructed(GObject *gobject) { SpiceChannel *channel = SPICE_CHANNEL(gobject); spice_channel *c = channel->priv; const char *desc = NULL; if (c->channel_type < SPICE_N_ELEMENTS(channel_desc)) desc = channel_desc[c->channel_type]; snprintf(c->name, sizeof(c->name), "%s-%d:%d", desc ? desc : "unknown", c->channel_type, c->channel_id); SPICE_DEBUG("%s: %s", c->name, __FUNCTION__); c->connection_id = spice_session_get_connection_id(c->session); spice_session_channel_new(c->session, channel); /* Chain up to the parent class */ if (G_OBJECT_CLASS(spice_channel_parent_class)->constructed) G_OBJECT_CLASS(spice_channel_parent_class)->constructed(gobject); }
void send_key(SpiceDisplay *display, int scancode, int down) { SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); uint32_t i, b, m; if (!d->inputs) return; i = scancode / 32; b = scancode % 32; m = (1 << b); g_return_if_fail(i < SPICE_N_ELEMENTS(d->key_state)); if (down) { spice_inputs_key_press(d->inputs, scancode); d->key_state[i] |= m; } else { if (!(d->key_state[i] & m)) { return; } spice_inputs_key_release(d->inputs, scancode); d->key_state[i] &= ~m; } }
static void clipboard_get_targets(GtkClipboard *clipboard, GdkAtom *atoms, gint n_atoms, gpointer user_data) { WeakRef *weakref = user_data; SpiceGtkSession *self = (SpiceGtkSession*)weakref->object; weak_unref(weakref); if (self == NULL) return; g_return_if_fail(SPICE_IS_GTK_SESSION(self)); SpiceGtkSessionPrivate *s = self->priv; guint32 types[SPICE_N_ELEMENTS(atom2agent)]; char *name; int a, m, t; int selection; if (s->main == NULL) return; selection = get_selection_from_clipboard(s, clipboard); g_return_if_fail(selection != -1); SPICE_DEBUG("%s:", __FUNCTION__); if (spice_util_get_debug()) { for (a = 0; a < n_atoms; a++) { name = gdk_atom_name(atoms[a]); SPICE_DEBUG(" \"%s\"", name); g_free(name); } } memset(types, 0, sizeof(types)); for (a = 0; a < n_atoms; a++) { name = gdk_atom_name(atoms[a]); for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) { if (strcasecmp(name, atom2agent[m].xatom) != 0) { continue; } /* found match */ for (t = 0; t < SPICE_N_ELEMENTS(atom2agent); t++) { if (types[t] == atom2agent[m].vdagent) { /* type already in list */ break; } if (types[t] == 0) { /* add type to empty slot */ types[t] = atom2agent[m].vdagent; break; } } break; } g_free(name); } for (t = 0; t < SPICE_N_ELEMENTS(atom2agent); t++) { if (types[t] == 0) { break; } } if (!s->clip_grabbed[selection] && t > 0) { s->clip_grabbed[selection] = TRUE; if (spice_main_agent_test_capability(s->main, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) spice_main_clipboard_selection_grab(s->main, selection, types, t); /* Sending a grab causes the agent to do an impicit release */ s->nclip_targets[selection] = 0; } }
RedClient::RedClient(Application& application) : RedChannel(*this, SPICE_CHANNEL_MAIN, 0, new MainChannelLoop(*this)) , _application (application) , _port (-1) , _sport (-1) , _protocol (0) , _connection_id (0) , _mouse_mode (SPICE_MOUSE_MODE_SERVER) , _notify_disconnect (false) , _auto_display_res (false) , _agent_reply_wait_type (VD_AGENT_END_MESSAGE) , _aborting (false) , _msg_attach_channels_sent(false) , _agent_connected (false) , _agent_mon_config_sent (false) , _agent_disp_config_sent (false) , _agent_msg (new VDAgentMessage) , _agent_msg_data (NULL) , _agent_msg_pos (0) , _agent_out_msg (NULL) , _agent_out_msg_size (0) , _agent_out_msg_pos (0) , _agent_tokens (0) , _agent_timer (new AgentTimer(this)) , _agent_caps_size(0) , _agent_caps(NULL) , _migrate (*this) , _glz_window (_glz_debug) , _during_migration (false) { Platform::set_clipboard_listener(this); MainChannelLoop* message_loop = static_cast<MainChannelLoop*>(get_message_handler()); uint32_t default_caps_size = SPICE_N_ELEMENTS(default_agent_caps); _agent_caps_size = VD_AGENT_CAPS_SIZE; ASSERT(VD_AGENT_CAPS_SIZE >= default_caps_size); _agent_caps = new uint32_t[_agent_caps_size]; memcpy(_agent_caps, default_agent_caps, default_caps_size); message_loop->set_handler(SPICE_MSG_MIGRATE, &RedClient::handle_migrate); message_loop->set_handler(SPICE_MSG_SET_ACK, &RedClient::handle_set_ack); message_loop->set_handler(SPICE_MSG_PING, &RedClient::handle_ping); message_loop->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &RedClient::handle_wait_for_channels); message_loop->set_handler(SPICE_MSG_DISCONNECTING, &RedClient::handle_disconnect); message_loop->set_handler(SPICE_MSG_NOTIFY, &RedClient::handle_notify); message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_BEGIN, &RedClient::handle_migrate_begin); message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_CANCEL, &RedClient::handle_migrate_cancel); message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_END, &RedClient::handle_migrate_end); message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST, &RedClient::handle_migrate_switch_host); message_loop->set_handler(SPICE_MSG_MAIN_INIT, &RedClient::handle_init); message_loop->set_handler(SPICE_MSG_MAIN_CHANNELS_LIST, &RedClient::handle_channels); message_loop->set_handler(SPICE_MSG_MAIN_MOUSE_MODE, &RedClient::handle_mouse_mode); message_loop->set_handler(SPICE_MSG_MAIN_MULTI_MEDIA_TIME, &RedClient::handle_mm_time); message_loop->set_handler(SPICE_MSG_MAIN_AGENT_CONNECTED, &RedClient::handle_agent_connected); message_loop->set_handler(SPICE_MSG_MAIN_AGENT_DISCONNECTED, &RedClient::handle_agent_disconnected); message_loop->set_handler(SPICE_MSG_MAIN_AGENT_DATA, &RedClient::handle_agent_data); message_loop->set_handler(SPICE_MSG_MAIN_AGENT_TOKEN, &RedClient::handle_agent_tokens); set_capability(SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE); start(); }
static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data) { spice_connection *conn = data; int id; g_object_get(channel, "channel-id", &id, NULL); conn->channels++; SPICE_DEBUG("new channel (#%d)", id); if (SPICE_IS_MAIN_CHANNEL(channel)) { SPICE_DEBUG("new main channel"); conn->main = SPICE_MAIN_CHANNEL(channel); g_signal_connect(channel, "channel-event", G_CALLBACK(main_channel_event), conn); //g_signal_connect(channel, "main-mouse-update", // G_CALLBACK(main_mouse_update), conn); //g_signal_connect(channel, "main-agent-update", // G_CALLBACK(main_agent_update), conn); //main_mouse_update(channel, conn); //main_agent_update(channel, conn); } if (SPICE_IS_DISPLAY_CHANNEL(channel)) { if (id >= SPICE_N_ELEMENTS(conn->wins)) return; if (conn->wins[id] != NULL) return; SPICE_DEBUG("new display channel (#%d)", id); conn->wins[id] = create_spice_window(conn, channel, id); //g_signal_connect(channel, "display-mark", // G_CALLBACK(display_mark), conn->wins[id]); //update_auto_usbredir_sensitive(conn); } if (SPICE_IS_INPUTS_CHANNEL(channel)) { SPICE_DEBUG("new inputs channel"); //g_signal_connect(channel, "inputs-modifiers", // G_CALLBACK(inputs_modifiers), conn); } if (soundEnabled && SPICE_IS_PLAYBACK_CHANNEL(channel)) { SPICE_DEBUG("new audio channel"); conn->audio = spice_audio_get(s, NULL); } if (SPICE_IS_USBREDIR_CHANNEL(channel)) { __android_log_write(ANDROID_LOG_INFO, "android-spice", "Created USB channel, attempting to add devices"); SpiceUsbDeviceManager *manager = spice_usb_device_manager_get(s, NULL); GPtrArray *devices = spice_usb_device_manager_get_devices(manager); if (devices) { for (int i = 0; i < devices->len; i++) { __android_log_write(ANDROID_LOG_INFO, "android-spicy", "Devices found, connecting..."); usb_device_added(manager, g_ptr_array_index(devices, i), NULL); } g_ptr_array_unref(devices); } } //if (SPICE_IS_PORT_CHANNEL(channel)) { // g_signal_connect(channel, "notify::port-opened", // G_CALLBACK(port_opened), conn); // g_signal_connect(channel, "port-data", // G_CALLBACK(port_data), conn); // spice_channel_connect(channel); //} }