void spice_display_send_button(SpiceDisplay *display, int button, bool down) { SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); int button_mask; switch (button) { case SPICE_MOUSE_BUTTON_LEFT: button_mask = SPICE_MOUSE_BUTTON_MASK_LEFT; break; case SPICE_MOUSE_BUTTON_MIDDLE: button_mask = SPICE_MOUSE_BUTTON_MASK_MIDDLE; break; case SPICE_MOUSE_BUTTON_RIGHT: button_mask = SPICE_MOUSE_BUTTON_MASK_RIGHT; break; default: return; } if (down) { d->mouse_button_mask |= button_mask; if (d->inputs) spice_inputs_button_press(d->inputs, button, d->mouse_button_mask); } else { d->mouse_button_mask &= ~button_mask; if (d->inputs) spice_inputs_button_release(d->inputs, button, d->mouse_button_mask); } }
static void spice_display_init(SpiceDisplay *display) { SpiceDisplayPrivate *d; d = display->priv = SPICE_DISPLAY_GET_PRIVATE(display); memset(d, 0, sizeof(*d)); }
JNIEXPORT void JNICALL Java_com_iiordanov_aSPICE_SpiceCommunicator_UpdateBitmap (JNIEnv* env, jobject obj, jobject bitmap, gint x, gint y, gint width, gint height) { uchar* pixels; SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(global_display); if (AndroidBitmap_lockPixels(env, bitmap, (void**)&pixels) < 0) { __android_log_write(6, "android-io", "AndroidBitmap_lockPixels() failed!"); return; } int slen = d->width * 4; int offset = (slen * y) + (x * 4); uchar *source = d->data; uchar *sourcepix = (uchar*) &source[offset]; uchar *destpix = (uchar*) &pixels[offset]; for (int i = 0; i < height; i++) { for (int j = 0; j < width * 4; j += 4) { destpix[j + 0] = sourcepix[j + 2]; destpix[j + 1] = sourcepix[j + 1]; destpix[j + 2] = sourcepix[j + 0]; } sourcepix = sourcepix + slen; destpix = destpix + slen; } AndroidBitmap_unlockPixels(env, bitmap); }
/** * spice_display_new: * @session: a #SpiceSession * @id: the display channel ID to associate with #SpiceDisplay * * Returns: a new #SpiceDisplay widget. **/ SpiceDisplay *spice_display_new(SpiceSession *session, int id) { SpiceDisplay *display; SpiceDisplayPrivate *d; GList *list; GList *it; display = g_object_new(SPICE_TYPE_DISPLAY, NULL); d = SPICE_DISPLAY_GET_PRIVATE(display); d->session = g_object_ref(session); d->channel_id = id; SPICE_DEBUG("channel_id:%d",d->channel_id); g_signal_connect(session, "channel-new", G_CALLBACK(channel_new), display); g_signal_connect(session, "channel-destroy", G_CALLBACK(channel_destroy), display); list = spice_session_get_channels(session); for (it = g_list_first(list); it != NULL; it = g_list_next(it)) { channel_new(session, it->data, (gpointer*)display); } g_list_free(list); return display; }
static void channel_destroy(SpiceSession *s, SpiceChannel *channel, gpointer data) { SpiceDisplay *display = data; SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); int id; g_object_get(channel, "channel-id", &id, NULL); SPICE_DEBUG("channel_destroy %d", id); if (SPICE_IS_MAIN_CHANNEL(channel)) { disconnect_main(display); return; } if (SPICE_IS_DISPLAY_CHANNEL(channel)) { if (id != d->channel_id) return; disconnect_display(display); return; } if (SPICE_IS_CURSOR_CHANNEL(channel)) { if (id != d->channel_id) return; disconnect_cursor(display); return; } if (SPICE_IS_INPUTS_CHANNEL(channel)) { d->inputs = NULL; return; } }
static void spice_display_dispose(GObject *obj) { SpiceDisplay *display = SPICE_DISPLAY(obj); SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); SPICE_DEBUG("spice display dispose"); disconnect_main(display); disconnect_display(display); //disconnect_cursor(display); //if (d->clipboard) { // g_signal_handlers_disconnect_by_func(d->clipboard, G_CALLBACK(clipboard_owner_change), // display); // d->clipboard = NULL; //} //if (d->clipboard_primary) { // g_signal_handlers_disconnect_by_func(d->clipboard_primary, G_CALLBACK(clipboard_owner_change), // display); // d->clipboard_primary = NULL; //} if (d->session) { g_signal_handlers_disconnect_by_func(d->session, G_CALLBACK(channel_new), display); g_signal_handlers_disconnect_by_func(d->session, G_CALLBACK(channel_destroy), display); g_object_unref(d->session); d->session = NULL; } }
static void update_mouse_mode(SpiceChannel *channel, gpointer data) { SpiceDisplay *display = data; SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); int mode; g_object_get(channel, "mouse-mode", &mode, NULL); uiCallbackMouseMode(d->ctx, mode == SPICE_MOUSE_MODE_CLIENT); }
static void cursor_set(SpiceCursorChannel *cursor, int w, int h, int hot_x, int hot_y, void *bitmap, void *data) { SpiceDisplay *display = data; SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); uiCallbackCursorConfig(d->ctx, true, bitmap, w, h, hot_x, hot_y); }
static void disable_secondary_displays(SpiceMainChannel *channel, gpointer data) { __android_log_write(6, "android-spice", "disable_secondary_displays"); SpiceDisplay *display = data; SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); spice_main_set_display_enabled(d->main, -1, FALSE); spice_main_set_display_enabled(d->main, 0, FALSE); spice_main_send_monitor_config(d->main); }
static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data) { //__android_log_write(ANDROID_LOG_DEBUG, TAG, "channel_new"); SpiceDisplay *display = data; SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); int id; g_object_get(channel, "channel-id", &id, NULL); if (SPICE_IS_MAIN_CHANNEL(channel)) { d->main = SPICE_MAIN_CHANNEL(channel); spice_g_signal_connect_object(channel, "main-mouse-update", G_CALLBACK(update_mouse_mode), display, 0); update_mouse_mode(channel, display); // TODO: For now, connect to this signal with a callback that disables // any secondary displays that crop up. g_signal_connect(channel, "main-agent-update", G_CALLBACK(disable_secondary_displays), display); return; } if (SPICE_IS_DISPLAY_CHANNEL(channel)) { if (id != d->channel_id) return; d->display = channel; g_signal_connect(channel, "display-primary-create", G_CALLBACK(primary_create), display); g_signal_connect(channel, "display-primary-destroy", G_CALLBACK(primary_destroy), display); g_signal_connect(channel, "display-invalidate", G_CALLBACK(invalidate), display); spice_channel_connect(channel); return; } if (SPICE_IS_CURSOR_CHANNEL(channel)) { if (id != d->channel_id) return; d->cursor = SPICE_CURSOR_CHANNEL(channel); g_signal_connect(channel, "cursor-set", G_CALLBACK(cursor_set), display); g_signal_connect(channel, "cursor-hide", G_CALLBACK(cursor_hide), display); g_signal_connect(channel, "cursor-reset", G_CALLBACK(cursor_reset), display); spice_channel_connect(channel); return; } if (SPICE_IS_INPUTS_CHANNEL(channel)) { d->inputs = SPICE_INPUTS_CHANNEL(channel); spice_channel_connect(channel); return; } }
void spice_display_send_scroll(SpiceDisplay *display, int button, int count) { SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); if (d->inputs) { for (int i = 0; i < count; i++) { spice_inputs_button_press(d->inputs, button, d->mouse_button_mask); spice_inputs_button_release(d->inputs, button, d->mouse_button_mask); } } }
static void spice_display_init(SpiceDisplay *display) { global_display = display; SpiceDisplayPrivate *d; d = display->priv = SPICE_DISPLAY_GET_PRIVATE(display); memset(d, 0, sizeof(*d)); d->have_mitshm = true; d->mouse_last_x = -1; d->mouse_last_y = -1; }
gint get_display_id(SpiceDisplay *display) { SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); /* supported monitor_id only with display channel #0 */ if (d->channel_id == 0 && d->monitor_id >= 0) return d->monitor_id; g_return_val_if_fail(d->monitor_id <= 0, -1); return d->channel_id; }
void spice_display_send_pointer(SpiceDisplay *display, bool absolute, int x, int y) { SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); if (d->inputs) { if (absolute) spice_inputs_position(d->inputs, x, y, d->channel_id, d->mouse_button_mask); else spice_inputs_motion(d->inputs, x, y, d->mouse_button_mask); } }
static void disconnect_main(SpiceDisplay *display) { SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); if (d->main == NULL) return; g_signal_handlers_disconnect_by_func(d->main, G_CALLBACK(update_mouse_mode), display); g_signal_handlers_disconnect_by_func(d->main, G_CALLBACK(disable_secondary_displays), display); d->main = NULL; }
JNIEXPORT void JNICALL Java_com_iiordanov_aSPICE_SpiceCommunicator_UpdateBitmap (JNIEnv* env, jobject obj, jobject bitmap, gint x, gint y, gint width, gint height) { void* pixels; SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(global_display); if (AndroidBitmap_lockPixels(env, bitmap, &pixels) < 0) { __android_log_write(6, "android-io", "AndroidBitmap_lockPixels() failed!"); return; } //__android_log_write(6, "android-io", "Copying new data into pixels."); updatePixels (pixels, d->data, x, y, width, height, d->width, d->height, 4); AndroidBitmap_unlockPixels(env, bitmap); }
static void primary_destroy(SpiceChannel *channel, gpointer data) { SpiceDisplay *display = SPICE_DISPLAY(data); SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); //spicex_image_destroy(display); d->format = 0; d->width = 0; d->height = 0; d->stride = 0; d->shmid = 0; d->data = 0; d->data_origin = 0; }
void spice_display_request_resolution(SpiceDisplay *display, int w, int h) { SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); spice_main_update_display(d->main, get_display_id(display), 0, 0, w, h, TRUE); spice_main_set_display_enabled(d->main, -1, TRUE); // TODO: Sending the monitor config right away may be causing guest OS to shut down. /* if (spice_main_send_monitor_config(d->main)) { __android_log_write(ANDROID_LOG_DEBUG, TAG, "Successfully sent monitor config"); } else { __android_log_write(ANDROID_LOG_WARN, TAG, "Failed to send monitor config"); }*/ }
static void disconnect_display(SpiceDisplay *display) { SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); if (d->display == NULL) return; g_signal_handlers_disconnect_by_func(d->display, G_CALLBACK(primary_create), display); g_signal_handlers_disconnect_by_func(d->display, G_CALLBACK(primary_destroy), display); g_signal_handlers_disconnect_by_func(d->display, G_CALLBACK(invalidate), display); d->display = NULL; }
static void disconnect_cursor(SpiceDisplay *display) { SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); if (d->cursor == NULL) return; g_signal_handlers_disconnect_by_func(d->cursor, G_CALLBACK(cursor_set), display); g_signal_handlers_disconnect_by_func(d->cursor, G_CALLBACK(cursor_hide), display); g_signal_handlers_disconnect_by_func(d->cursor, G_CALLBACK(cursor_reset), display); d->cursor = NULL; }
static void invalidate(SpiceChannel *channel, gint x, gint y, gint w, gint h, gpointer data) { SpiceDisplay *display = data; if (!do_color_convert(display, x, y, w, h)) return; SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); if (x + w > d->width || y + h > d->height) { __android_log_write(6, "android-spice", "Not drawing."); } else { uiCallbackInvalidate (d, x, y, w, h); } }
static void primary_create(SpiceChannel *channel, gint format, gint width, gint height, gint stride, gint shmid, gpointer imgdata, gpointer data) { __android_log_write(6, "android-spice", "primary_create"); SpiceDisplay *display = data; SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); d->format = format; d->stride = stride; d->shmid = shmid; d->width = width; d->height = height; d->data_origin = d->data = imgdata; uiCallbackSettingsChanged (0, width, height, 4); }
JNIEXPORT void JNICALL Java_com_iiordanov_aSPICE_SpiceCommunicator_SpiceRequestResolution(JNIEnv* env, jobject obj, jint x, jint y) { SpiceDisplay* display = global_display; SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); spice_main_update_display(d->main, get_display_id(display), 0, 0, x, y, TRUE); spice_main_set_display_enabled(d->main, -1, TRUE); // TODO: Sending the monitor config right away may be causing guest OS to shut down. /* if (spice_main_send_monitor_config(d->main)) { __android_log_write(6, "android-io", "Successfully sent monitor config"); } else { __android_log_write(6, "android-io", "Failed to send monitor config"); }*/ }
static void disconnect_main(SpiceDisplay *display) { SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); //gint i; if (d->main == NULL) return; //g_signal_handlers_disconnect_by_func(d->main, G_CALLBACK(mouse_update), // display); d->main = NULL; //for (i = 0; i < CLIPBOARD_LAST; ++i) { // d->clipboard_by_guest[i] = FALSE; // d->clip_grabbed[i] = FALSE; // d->nclip_targets[i] = 0; //} }
JNIEXPORT void JNICALL Java_com_iiordanov_aSPICE_SpiceCommunicator_SpiceKeyEvent(JNIEnv * env, jobject obj, jboolean down, jint hardware_keycode) { SpiceDisplay* display = global_display; SpiceDisplayPrivate* d = SPICE_DISPLAY_GET_PRIVATE(display); SPICE_DEBUG("%s %s: keycode: %d", __FUNCTION__, "Key", hardware_keycode); if (!d->inputs) return; if (down) { send_key(display, hardware_keycode, 1); } else { send_key(display, hardware_keycode, 0); } }
JNIEXPORT void JNICALL Java_com_iiordanov_aSPICE_SpiceCommunicator_SpiceButtonEvent(JNIEnv * env, jobject obj, jint x, jint y, jint metaState, jint type) { SpiceDisplay* display = global_display; SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); //char buf[60]; //snprintf (buf, 60, "Pointer event: %d at x: %d, y: %d", type, x, y); //__android_log_write(6, "android-io", buf); if (!d->inputs || (x >= 0 && x < d->width && y >= 0 && y < d->height)) { gboolean down = (type & PTRFLAGS_DOWN) != 0; int mouseButton = type &~ PTRFLAGS_DOWN; int newMask = update_mask (mouseButton, down); gint dx; gint dy; switch (d->mouse_mode) { case SPICE_MOUSE_MODE_CLIENT: //__android_log_write(6, "android-io", "spice mouse mode client"); spice_inputs_position(d->inputs, x, y, d->channel_id, newMask); break; case SPICE_MOUSE_MODE_SERVER: //__android_log_write(6, "android-io", "spice mouse mode server"); dx = d->mouse_last_x != -1 ? x - d->mouse_last_x : 0; dy = d->mouse_last_y != -1 ? y - d->mouse_last_y : 0; spice_inputs_motion(d->inputs, dx, dy, newMask); d->mouse_last_x = x; d->mouse_last_y = y; break; default: g_warn_if_reached(); break; } if (mouseButton != SPICE_MOUSE_BUTTON_INVALID) { if (down) { //__android_log_write(6, "android-io", "Button press"); spice_inputs_button_press(d->inputs, mouseButton, newMask); } else { //__android_log_write(6, "android-io", "Button release"); // This sleep is an ugly hack to prevent stuck buttons after a drag/drop gesture. usleep(50000); spice_inputs_button_release(d->inputs, mouseButton, newMask); } } } }
static gboolean do_color_convert(SpiceDisplay *display, gint x, gint y, gint w, gint h) { SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); int i, j, maxy, maxx, miny, minx; guint32 *dest = d->data; guint16 *src = d->data_origin; if (!d->convert) return true; g_return_val_if_fail(d->format == SPICE_SURFACE_FMT_16_555 || d->format == SPICE_SURFACE_FMT_16_565, false); miny = MAX(y, 0); minx = MAX(x, 0); maxy = MIN(y + h, d->height); maxx = MIN(x + w, d->width); dest += (d->stride / 4) * miny; src += (d->stride / 2) * miny; if (d->format == SPICE_SURFACE_FMT_16_555) { for (j = miny; j < maxy; j++) { for (i = minx; i < maxx; i++) { dest[i] = CONVERT_0555_TO_0888(src[i]); } dest += d->stride / 4; src += d->stride / 2; } } else if (d->format == SPICE_SURFACE_FMT_16_565) { for (j = miny; j < maxy; j++) { for (i = minx; i < maxx; i++) { dest[i] = CONVERT_0565_TO_0888(src[i]); } dest += d->stride / 4; src += d->stride / 2; } } return true; }
static gboolean release_guest_clipboard(gpointer data) { SpiceDisplay *display; SpiceDisplayPrivate *d; display = global_display(); if (global_display() == NULL) { return FALSE; } d = SPICE_DISPLAY_GET_PRIVATE(display); if (d->main == NULL) { return FALSE; } spice_main_clipboard_selection_release(d->main, VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD); clipboardOwner = CB_OWNER_NONE; return FALSE; }
static void primary_create(SpiceChannel *channel, gint format, gint width, gint height, gint stride, gint shmid, gpointer imgdata, gpointer data) { __android_log_write(6, "android-spice", "primary_create"); SpiceDisplay *display = data; SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); // TODO: For now, don't do anything for secondary monitors if (get_display_id(display) > 0) { return; } d->format = format; d->stride = stride; d->shmid = shmid; d->width = width; d->height = height; d->data_origin = d->data = imgdata; uiCallbackSettingsChanged (0, width, height, 4); }
void spice_display_copy_pixels(SpiceDisplay *display, uint32_t *dest, int x, int y, int width, int height) { SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); uint32_t *source = d->data; uint32_t *sourcepix = &source[(d->width * y) + x]; uint32_t *destpix = &dest[(d->width * y) + x]; //__android_log_print(ANDROID_LOG_DEBUG, TAG, "Drawing x: %d, y: %d, w: %d, h: %d, wBuf: %d, hBuf: %d", x, y, width, height, d->width, d->height); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { // ARGB -> R G B X uint32_t value = sourcepix[j] << 8; #if BYTE_ORDER == LITTLE_ENDIAN value = __builtin_bswap32(value); #endif destpix[j] = value; } sourcepix = sourcepix + d->width; destpix = destpix + d->width; } }