Skip to content

Commit

Permalink
GUACAMOLE-377: Migrate VNC support to guac_display API.
Browse files Browse the repository at this point in the history
  • Loading branch information
mike-jumper committed Jun 18, 2024
1 parent aeabd26 commit 74b1bc0
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 143 deletions.
5 changes: 3 additions & 2 deletions src/protocols/vnc/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#endif

#include <guacamole/client.h>
#include <guacamole/display.h>
#include <guacamole/mem.h>
#include <guacamole/recording.h>

Expand Down Expand Up @@ -89,7 +90,7 @@ static int guac_vnc_join_pending_handler(guac_client* client) {

/* Synchronize with current display */
if (vnc_client->display != NULL) {
guac_common_display_dup(vnc_client->display, client, broadcast_socket);
guac_display_dup(vnc_client->display, broadcast_socket);
guac_socket_flush(broadcast_socket);
}

Expand Down Expand Up @@ -192,7 +193,7 @@ int guac_vnc_client_free_handler(guac_client* client) {

/* Free display */
if (vnc_client->display != NULL)
guac_common_display_free(vnc_client->display);
guac_display_free(vnc_client->display);

#ifdef ENABLE_PULSE
/* If audio enabled, stop streaming */
Expand Down
7 changes: 3 additions & 4 deletions src/protocols/vnc/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@
#include "config.h"

#include "client.h"
#include "common/cursor.h"
#include "common/display.h"
#include "common/surface.h"
#include "vnc.h"

#include <cairo/cairo.h>
Expand All @@ -46,7 +43,8 @@
#include <syslog.h>

void guac_vnc_cursor(rfbClient* client, int x, int y, int w, int h, int bpp) {

/* TODO */
#if 0
guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY);
guac_vnc_client* vnc_client = (guac_vnc_client*) gc->data;

Expand Down Expand Up @@ -128,5 +126,6 @@ void guac_vnc_cursor(rfbClient* client, int x, int y, int w, int h, int bpp) {
free(client->rcMask);
client->rcMask = NULL;
}
#endif
}

110 changes: 52 additions & 58 deletions src/protocols/vnc/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

#include "client.h"
#include "common/iconv.h"
#include "common/surface.h"
#include "vnc.h"

#include <cairo/cairo.h>
Expand Down Expand Up @@ -49,98 +48,93 @@ void guac_vnc_update(rfbClient* client, int x, int y, int w, int h) {
guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY);
guac_vnc_client* vnc_client = (guac_vnc_client*) gc->data;

int dx, dy;

/* Cairo image buffer */
int stride;
unsigned char* buffer;
unsigned char* buffer_row_current;
cairo_surface_t* surface;

/* VNC framebuffer */
unsigned int bpp;
unsigned int fb_stride;
unsigned char* fb_row_current;

/* Ignore extra update if already handled by copyrect */
if (vnc_client->copy_rect_used) {
vnc_client->copy_rect_used = 0;
return;
}

/* Init Cairo buffer */
stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, w);
buffer = guac_mem_alloc(h, stride);
buffer_row_current = buffer;
/* Begin drawing operation directly to default layer */
guac_display_layer* default_layer = guac_display_default_layer(vnc_client->display);
guac_display_layer_raw_context* context = guac_display_layer_open_raw(default_layer);

bpp = client->format.bitsPerPixel/8;
fb_stride = bpp * client->width;
fb_row_current = client->frameBuffer + (y * fb_stride) + (x * bpp);
/* Convert operation coordinates to guac_rect for easier manipulation */
guac_rect op_bounds;
guac_rect_init(&op_bounds, x, y, w, h);

/* Copy image data from VNC client to PNG */
for (dy = y; dy<y+h; dy++) {
/* Ensure draw is within current bounds of the pending frame */
guac_rect_constrain(&op_bounds, &context->bounds);

unsigned int* buffer_current;
unsigned char* fb_current;

/* Get current buffer row, advance to next */
buffer_current = (unsigned int*) buffer_row_current;
buffer_row_current += stride;
/* VNC framebuffer */
unsigned int vnc_bpp = client->format.bitsPerPixel / 8;
size_t vnc_stride = guac_mem_ckd_mul_or_die(vnc_bpp, client->width);
const unsigned char* vnc_current_row = GUAC_RECT_CONST_BUFFER(op_bounds, client->frameBuffer, vnc_stride, vnc_bpp);

unsigned char* layer_current_row = context->buffer + (op_bounds.top * context->stride) + (op_bounds.left * 4);
for (int dy = op_bounds.top; dy < op_bounds.bottom; dy++) {

/* Get current framebuffer row, advance to next */
fb_current = fb_row_current;
fb_row_current += fb_stride;
/* Get current Guacamole buffer row, advance to next */
uint32_t* layer_current_pixel = (uint32_t*) layer_current_row;
layer_current_row += context->stride;

for (dx = x; dx<x+w; dx++) {
/* Get current VNC framebuffer row, advance to next */
const unsigned char* vnc_current_pixel = vnc_current_row;
vnc_current_row += vnc_stride;

unsigned char red, green, blue;
unsigned int v;
for (int dx = op_bounds.left; dx < op_bounds.right; dx++) {

switch (bpp) {
/* Read current VNC pixel value */
uint32_t v;
switch (vnc_bpp) {
case 4:
v = *((uint32_t*) fb_current);
v = *((uint32_t*) vnc_current_pixel);
break;

case 2:
v = *((uint16_t*) fb_current);
v = *((uint16_t*) vnc_current_pixel);
break;

default:
v = *((uint8_t*) fb_current);
v = *((uint8_t*) vnc_current_pixel);
}

/* Translate value to RGB */
red = (v >> client->format.redShift) * 0x100 / (client->format.redMax + 1);
green = (v >> client->format.greenShift) * 0x100 / (client->format.greenMax+ 1);
blue = (v >> client->format.blueShift) * 0x100 / (client->format.blueMax + 1);
/* Translate value to 32-bit RGB */
uint8_t red = (v >> client->format.redShift) * 0x100 / (client->format.redMax + 1);
uint8_t green = (v >> client->format.greenShift) * 0x100 / (client->format.greenMax + 1);
uint8_t blue = (v >> client->format.blueShift) * 0x100 / (client->format.blueMax + 1);

/* Output RGB */
if (vnc_client->settings->swap_red_blue)
*(buffer_current++) = (blue << 16) | (green << 8) | red;
*(layer_current_pixel++) = 0xFF000000 | (blue << 16) | (green << 8) | red;
else
*(buffer_current++) = (red << 16) | (green << 8) | blue;
*(layer_current_pixel++) = 0xFF000000 | (red << 16) | (green << 8) | blue;

fb_current += bpp;
/* Advance to next pixel in VNC framebuffer */
vnc_current_pixel += vnc_bpp;

}
}

/* Create surface from decoded buffer */
surface = cairo_image_surface_create_for_data(buffer, CAIRO_FORMAT_RGB24,
w, h, stride);
/* Mark modified region as dirty */
guac_rect_extend(&context->dirty, &op_bounds);

/* Draw directly to default layer */
guac_common_surface_draw(vnc_client->display->default_surface,
x, y, surface);
/* Draw operation is now complete */
guac_display_layer_close_raw(default_layer, context);

}

/* Free surface */
cairo_surface_destroy(surface);
guac_mem_free(buffer);
void guac_vnc_update_finished(rfbClient* client) {

guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY);
guac_vnc_client* vnc_client = (guac_vnc_client*) gc->data;

guac_display_end_multiple_frames(vnc_client->display, 1);

}

void guac_vnc_copyrect(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y) {

/* TODO */
#if 0
guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY);
guac_vnc_client* vnc_client = (guac_vnc_client*) gc->data;

Expand All @@ -150,7 +144,7 @@ void guac_vnc_copyrect(rfbClient* client, int src_x, int src_y, int w, int h, in
vnc_client->display->default_surface, dest_x, dest_y);

vnc_client->copy_rect_used = 1;

#endif
}

void guac_vnc_set_pixel_format(rfbClient* client, int color_depth) {
Expand Down Expand Up @@ -199,7 +193,7 @@ rfbBool guac_vnc_malloc_framebuffer(rfbClient* rfb_client) {

/* Resize surface */
if (vnc_client->display != NULL)
guac_common_surface_resize(vnc_client->display->default_surface,
guac_display_layer_resize(guac_display_default_layer(vnc_client->display),
rfb_client->width, rfb_client->height);

/* Use original, wrapped proc */
Expand Down
11 changes: 11 additions & 0 deletions src/protocols/vnc/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@
*/
void guac_vnc_update(rfbClient* client, int x, int y, int w, int h);

/**
* Callback invoked by libVNCServer when all binary image data for the current
* frame has been received from the VNC server. The image data that frame will
* have been exposed via previous calls to guac_vnc_update().
*
* @param client
* The VNC client associated with the VNC session in which the new image
* was received.
*/
void guac_vnc_update_finished(rfbClient* client);

/**
* Callback invoked by libVNCServer when it receives a CopyRect message.
* CopyRect specified a rectangle of source data within the display and a
Expand Down
5 changes: 2 additions & 3 deletions src/protocols/vnc/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@

#include "config.h"

#include "common/cursor.h"
#include "common/display.h"
#include "vnc.h"

#include <guacamole/display.h>
#include <guacamole/recording.h>
#include <guacamole/user.h>
#include <rfb/rfbclient.h>
Expand All @@ -34,7 +33,7 @@ int guac_vnc_user_mouse_handler(guac_user* user, int x, int y, int mask) {
rfbClient* rfb_client = vnc_client->rfb_client;

/* Store current mouse location/state */
guac_common_cursor_update(vnc_client->display->cursor, user, x, y, mask);
guac_display_notify_user_moved_mouse(vnc_client->display, user, x, y, mask);

/* Report mouse position within recording */
if (vnc_client->recording != NULL)
Expand Down
1 change: 0 additions & 1 deletion src/protocols/vnc/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

#include "client.h"
#include "common/iconv.h"
#include "common/surface.h"

#include <cairo/cairo.h>
#include <guacamole/client.h>
Expand Down
1 change: 0 additions & 1 deletion src/protocols/vnc/log.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

#include "client.h"
#include "common/iconv.h"
#include "common/surface.h"

#include <cairo/cairo.h>
#include <guacamole/client.h>
Expand Down
8 changes: 3 additions & 5 deletions src/protocols/vnc/user.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

#include "clipboard.h"
#include "input.h"
#include "common/display.h"
#include "common/dot_cursor.h"
#include "common/pointer_cursor.h"
#include "user.h"
Expand All @@ -35,6 +34,7 @@
#include <guacamole/argv.h>
#include <guacamole/audio.h>
#include <guacamole/client.h>
#include <guacamole/display.h>
#include <guacamole/socket.h>
#include <guacamole/user.h>
#include <rfb/rfbclient.h>
Expand Down Expand Up @@ -121,10 +121,8 @@ int guac_vnc_user_leave_handler(guac_user* user) {

guac_vnc_client* vnc_client = (guac_vnc_client*) user->client->data;

if (vnc_client->display) {
/* Update shared cursor state */
guac_common_cursor_remove_user(vnc_client->display->cursor, user);
}
if (vnc_client->display)
guac_display_notify_user_left(vnc_client->display, user);

/* Free settings if not owner (owner settings will be freed with client) */
if (!user->owner) {
Expand Down
Loading

0 comments on commit 74b1bc0

Please sign in to comment.