Merge pull request #110 from glyptodon/fake-merge-screen-sharing-002-common
GUAC-1389: Bring common up to date with screen sharing changes.
This commit is contained in:
commit
0d984f3886
@ -37,6 +37,7 @@ DIST_SUBDIRS = \
|
||||
|
||||
SUBDIRS = \
|
||||
src/libguac \
|
||||
src/common \
|
||||
tests
|
||||
|
||||
if ENABLE_COMMON_SSH
|
||||
|
@ -27,8 +27,12 @@ noinst_LTLIBRARIES = libguac_common.la
|
||||
|
||||
noinst_HEADERS = \
|
||||
guac_io.h \
|
||||
guac_blank_cursor.h \
|
||||
guac_clipboard.h \
|
||||
guac_cursor.h \
|
||||
guac_display.h \
|
||||
guac_dot_cursor.h \
|
||||
guac_ibar_cursor.h \
|
||||
guac_iconv.h \
|
||||
guac_json.h \
|
||||
guac_list.h \
|
||||
@ -39,8 +43,12 @@ noinst_HEADERS = \
|
||||
|
||||
libguac_common_la_SOURCES = \
|
||||
guac_io.c \
|
||||
guac_blank_cursor.c \
|
||||
guac_clipboard.c \
|
||||
guac_cursor.c \
|
||||
guac_display.c \
|
||||
guac_dot_cursor.c \
|
||||
guac_ibar_cursor.c \
|
||||
guac_iconv.c \
|
||||
guac_json.c \
|
||||
guac_list.c \
|
||||
|
78
src/common/guac_blank_cursor.c
Normal file
78
src/common/guac_blank_cursor.c
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/layer.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/* Dimensions */
|
||||
const int guac_common_blank_cursor_width = 1;
|
||||
const int guac_common_blank_cursor_height = 1;
|
||||
|
||||
/* Format */
|
||||
const cairo_format_t guac_common_blank_cursor_format = CAIRO_FORMAT_ARGB32;
|
||||
const int guac_common_blank_cursor_stride = 4;
|
||||
|
||||
/* Embedded blank cursor graphic */
|
||||
unsigned char guac_common_blank_cursor[] = {
|
||||
|
||||
0x00,0x00,0x00,0x00
|
||||
|
||||
};
|
||||
|
||||
void guac_common_set_blank_cursor(guac_user* user) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
guac_socket* socket = user->socket;
|
||||
|
||||
/* Draw to buffer */
|
||||
guac_layer* cursor = guac_client_alloc_buffer(client);
|
||||
|
||||
cairo_surface_t* graphic = cairo_image_surface_create_for_data(
|
||||
guac_common_blank_cursor,
|
||||
guac_common_blank_cursor_format,
|
||||
guac_common_blank_cursor_width,
|
||||
guac_common_blank_cursor_height,
|
||||
guac_common_blank_cursor_stride);
|
||||
|
||||
guac_user_stream_png(user, socket, GUAC_COMP_SRC, cursor,
|
||||
0, 0, graphic);
|
||||
cairo_surface_destroy(graphic);
|
||||
|
||||
/* Set cursor */
|
||||
guac_protocol_send_cursor(socket, 0, 0, cursor, 0, 0,
|
||||
guac_common_blank_cursor_width,
|
||||
guac_common_blank_cursor_height);
|
||||
|
||||
/* Free buffer */
|
||||
guac_client_free_buffer(client, cursor);
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Client cursor image set to generic transparent (blank) cursor.");
|
||||
|
||||
}
|
||||
|
67
src/common/guac_blank_cursor.h
Normal file
67
src/common/guac_blank_cursor.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_COMMON_BLANK_CURSOR_H
|
||||
#define GUAC_COMMON_BLANK_CURSOR_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Width of the embedded transparent (blank) mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_blank_cursor_width;
|
||||
|
||||
/**
|
||||
* Height of the embedded transparent (blank) mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_blank_cursor_height;
|
||||
|
||||
/**
|
||||
* Number of bytes in each row of the embedded transparent (blank) mouse cursor
|
||||
* graphic.
|
||||
*/
|
||||
extern const int guac_common_blank_cursor_stride;
|
||||
|
||||
/**
|
||||
* The Cairo grapic format of the transparent (blank) mouse cursor graphic.
|
||||
*/
|
||||
extern const cairo_format_t guac_common_blank_cursor_format;
|
||||
|
||||
/**
|
||||
* Embedded transparent (blank) mouse cursor graphic.
|
||||
*/
|
||||
extern unsigned char guac_common_blank_cursor[];
|
||||
|
||||
/**
|
||||
* Sets the cursor of the remote display to the embedded transparent (blank)
|
||||
* cursor graphic.
|
||||
*
|
||||
* @param user
|
||||
* The guac_user to send the cursor to.
|
||||
*/
|
||||
void guac_common_set_blank_cursor(guac_user* user);
|
||||
|
||||
#endif
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/stream.h>
|
||||
#include <guacamole/user.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@ -48,16 +49,32 @@ void guac_common_clipboard_free(guac_common_clipboard* clipboard) {
|
||||
free(clipboard);
|
||||
}
|
||||
|
||||
void guac_common_clipboard_send(guac_common_clipboard* clipboard, guac_client* client) {
|
||||
/**
|
||||
* Callback for guac_client_foreach_user() which sends clipboard data to each
|
||||
* connected client.
|
||||
*
|
||||
* @param user
|
||||
* The user to send the clipboard data to.
|
||||
*
|
||||
* @param
|
||||
* A pointer to the guac_common_clipboard structure containing the
|
||||
* clipboard data that should be sent to the given user.
|
||||
*
|
||||
* @return
|
||||
* Always NULL.
|
||||
*/
|
||||
static void* __send_user_clipboard(guac_user* user, void* data) {
|
||||
|
||||
guac_common_clipboard* clipboard = (guac_common_clipboard*) data;
|
||||
|
||||
char* current = clipboard->buffer;
|
||||
int remaining = clipboard->length;
|
||||
|
||||
/* Begin stream */
|
||||
guac_stream* stream = guac_client_alloc_stream(client);
|
||||
guac_protocol_send_clipboard(client->socket, stream, clipboard->mimetype);
|
||||
guac_stream* stream = guac_user_alloc_stream(user);
|
||||
guac_protocol_send_clipboard(user->socket, stream, clipboard->mimetype);
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
guac_user_log(user, GUAC_LOG_DEBUG,
|
||||
"Created stream %i for %s clipboard data.",
|
||||
stream->index, clipboard->mimetype);
|
||||
|
||||
@ -70,8 +87,8 @@ void guac_common_clipboard_send(guac_common_clipboard* clipboard, guac_client* c
|
||||
block_size = remaining;
|
||||
|
||||
/* Send block */
|
||||
guac_protocol_send_blob(client->socket, stream, current, block_size);
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
guac_protocol_send_blob(user->socket, stream, current, block_size);
|
||||
guac_user_log(user, GUAC_LOG_DEBUG,
|
||||
"Sent %i bytes of clipboard data on stream %i.",
|
||||
block_size, stream->index);
|
||||
|
||||
@ -81,14 +98,22 @@ void guac_common_clipboard_send(guac_common_clipboard* clipboard, guac_client* c
|
||||
|
||||
}
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
guac_user_log(user, GUAC_LOG_DEBUG,
|
||||
"Clipboard stream %i complete.",
|
||||
stream->index);
|
||||
|
||||
/* End stream */
|
||||
guac_protocol_send_end(client->socket, stream);
|
||||
guac_client_free_stream(client, stream);
|
||||
guac_protocol_send_end(user->socket, stream);
|
||||
guac_user_free_stream(user, stream);
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_clipboard_send(guac_common_clipboard* clipboard, guac_client* client) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Broadcasting clipboard to all connected users.");
|
||||
guac_client_foreach_user(client, __send_user_clipboard, clipboard);
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Broadcast of clipboard complete.");
|
||||
}
|
||||
|
||||
void guac_common_clipboard_reset(guac_common_clipboard* clipboard, const char* mimetype) {
|
||||
|
314
src/common/guac_cursor.c
Normal file
314
src/common/guac_cursor.c
Normal file
@ -0,0 +1,314 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "guac_blank_cursor.h"
|
||||
#include "guac_dot_cursor.h"
|
||||
#include "guac_cursor.h"
|
||||
#include "guac_ibar_cursor.h"
|
||||
#include "guac_pointer_cursor.h"
|
||||
#include "guac_surface.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
guac_common_cursor* guac_common_cursor_alloc(guac_client* client) {
|
||||
|
||||
guac_common_cursor* cursor = malloc(sizeof(guac_common_cursor));
|
||||
if (cursor == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Associate cursor with client and allocate cursor layer */
|
||||
cursor->client = client;
|
||||
cursor->layer= guac_client_alloc_layer(client);
|
||||
|
||||
/* Allocate initial image buffer */
|
||||
cursor->image_buffer_size = GUAC_COMMON_CURSOR_DEFAULT_SIZE;
|
||||
cursor->image_buffer = malloc(cursor->image_buffer_size);
|
||||
|
||||
/* No cursor image yet */
|
||||
cursor->width = 0;
|
||||
cursor->height = 0;
|
||||
cursor->surface = NULL;
|
||||
cursor->hotspot_x = 0;
|
||||
cursor->hotspot_y = 0;
|
||||
|
||||
/* No user has moved the mouse yet */
|
||||
cursor->user = NULL;
|
||||
|
||||
/* Start cursor in upper-left */
|
||||
cursor->x = 0;
|
||||
cursor->y = 0;
|
||||
|
||||
return cursor;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_free(guac_common_cursor* cursor) {
|
||||
|
||||
/* Free image buffer and surface */
|
||||
free(cursor->image_buffer);
|
||||
if (cursor->surface != NULL)
|
||||
cairo_surface_destroy(cursor->surface);
|
||||
|
||||
/* Return layer to pool */
|
||||
guac_client_free_layer(cursor->client, cursor->layer);
|
||||
|
||||
free(cursor);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_dup(guac_common_cursor* cursor, guac_user* user,
|
||||
guac_socket* socket) {
|
||||
|
||||
/* Synchronize location */
|
||||
guac_protocol_send_move(socket, cursor->layer, GUAC_DEFAULT_LAYER,
|
||||
cursor->x - cursor->hotspot_x,
|
||||
cursor->y - cursor->hotspot_y,
|
||||
0);
|
||||
|
||||
/* Synchronize cursor image */
|
||||
if (cursor->surface != NULL) {
|
||||
guac_protocol_send_size(socket, cursor->layer,
|
||||
cursor->width, cursor->height);
|
||||
|
||||
guac_user_stream_png(user, socket, GUAC_COMP_SRC,
|
||||
cursor->layer, 0, 0, cursor->surface);
|
||||
}
|
||||
|
||||
guac_socket_flush(socket);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_move(guac_common_cursor* cursor, guac_user* user,
|
||||
int x, int y) {
|
||||
|
||||
guac_user* last_user = cursor->user;
|
||||
|
||||
/* Update current user of cursor */
|
||||
if (last_user != user) {
|
||||
|
||||
cursor->user = user;
|
||||
|
||||
/* Make cursor layer visible to previous user */
|
||||
if (last_user != NULL) {
|
||||
guac_protocol_send_shade(last_user->socket, cursor->layer, 255);
|
||||
guac_socket_flush(last_user->socket);
|
||||
}
|
||||
|
||||
/* Show hardware cursor */
|
||||
guac_protocol_send_cursor(user->socket,
|
||||
cursor->hotspot_x, cursor->hotspot_y,
|
||||
cursor->layer, 0, 0, cursor->width, cursor->height);
|
||||
|
||||
/* Hide cursor layer from new user */
|
||||
guac_protocol_send_shade(user->socket, cursor->layer, 0);
|
||||
guac_socket_flush(user->socket);
|
||||
|
||||
}
|
||||
|
||||
/* Update cursor position */
|
||||
cursor->x = x;
|
||||
cursor->y = y;
|
||||
|
||||
guac_protocol_send_move(cursor->client->socket, cursor->layer,
|
||||
GUAC_DEFAULT_LAYER,
|
||||
x - cursor->hotspot_x,
|
||||
y - cursor->hotspot_y,
|
||||
0);
|
||||
|
||||
guac_socket_flush(cursor->client->socket);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the cursor image buffer has enough room to fit an image with the
|
||||
* given characteristics. Existing image buffer data may be destroyed.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor whose buffer size should be checked. If this cursor lacks
|
||||
* sufficient space to contain a cursor image of the specified width,
|
||||
* height, and stride, the current contents of this cursor will be
|
||||
* destroyed and replaced with an new buffer having sufficient space.
|
||||
*
|
||||
* @param width
|
||||
* The required cursor width, in pixels.
|
||||
*
|
||||
* @param height
|
||||
* The required cursor height, in pixels.
|
||||
*
|
||||
* @param stride
|
||||
* The number of bytes in each row of image data.
|
||||
*/
|
||||
static void guac_common_cursor_resize(guac_common_cursor* cursor,
|
||||
int width, int height, int stride) {
|
||||
|
||||
int minimum_size = height * stride;
|
||||
|
||||
/* Grow image buffer if necessary */
|
||||
if (cursor->image_buffer_size < minimum_size) {
|
||||
|
||||
/* Calculate new size */
|
||||
cursor->image_buffer_size = minimum_size*2;
|
||||
|
||||
/* Destructively reallocate image buffer */
|
||||
free(cursor->image_buffer);
|
||||
cursor->image_buffer = malloc(cursor->image_buffer_size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for guac_client_foreach_user() which sends the current cursor image
|
||||
* as PNG data to each connected client.
|
||||
*
|
||||
* @param user
|
||||
* The user to send the cursor image to.
|
||||
*
|
||||
* @param data
|
||||
* A pointer to the guac_common_cursor structure containing the cursor
|
||||
* image that should be sent to the given user.
|
||||
*
|
||||
* @return
|
||||
* Always NULL.
|
||||
*/
|
||||
static void* __send_user_cursor_image(guac_user* user, void* data) {
|
||||
|
||||
guac_common_cursor* cursor = (guac_common_cursor*) data;
|
||||
|
||||
guac_user_stream_png(user, user->socket, GUAC_COMP_SRC,
|
||||
cursor->layer, 0, 0, cursor->surface);
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_set_argb(guac_common_cursor* cursor, int hx, int hy,
|
||||
unsigned const char* data, int width, int height, int stride) {
|
||||
|
||||
/* Copy image data */
|
||||
guac_common_cursor_resize(cursor, width, height, stride);
|
||||
memcpy(cursor->image_buffer, data, height * stride);
|
||||
|
||||
if (cursor->surface != NULL)
|
||||
cairo_surface_destroy(cursor->surface);
|
||||
|
||||
cursor->surface = cairo_image_surface_create_for_data(cursor->image_buffer,
|
||||
CAIRO_FORMAT_ARGB32, width, height, stride);
|
||||
|
||||
/* Set new cursor parameters */
|
||||
cursor->width = width;
|
||||
cursor->height = height;
|
||||
cursor->hotspot_x = hx;
|
||||
cursor->hotspot_y = hy;
|
||||
|
||||
/* Update location based on new hotspot */
|
||||
guac_protocol_send_move(cursor->client->socket, cursor->layer,
|
||||
GUAC_DEFAULT_LAYER,
|
||||
cursor->x - hx,
|
||||
cursor->y - hy,
|
||||
0);
|
||||
|
||||
/* Broadcast new cursor image to all users */
|
||||
guac_protocol_send_size(cursor->client->socket, cursor->layer,
|
||||
width, height);
|
||||
|
||||
guac_client_foreach_user(cursor->client, __send_user_cursor_image, cursor);
|
||||
|
||||
guac_socket_flush(cursor->client->socket);
|
||||
|
||||
/* Update hardware cursor of current user */
|
||||
if (cursor->user != NULL) {
|
||||
guac_protocol_send_cursor(cursor->user->socket, hx, hy,
|
||||
cursor->layer, 0, 0, width, height);
|
||||
|
||||
guac_socket_flush(cursor->user->socket);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_set_surface(guac_common_cursor* cursor, int hx, int hy,
|
||||
guac_common_surface* surface) {
|
||||
|
||||
/* Set cursor to surface contents */
|
||||
guac_common_cursor_set_argb(cursor, hx, hy, surface->buffer,
|
||||
surface->width, surface->height, surface->stride);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_set_pointer(guac_common_cursor* cursor) {
|
||||
|
||||
guac_common_cursor_set_argb(cursor, 0, 0,
|
||||
guac_common_pointer_cursor,
|
||||
guac_common_pointer_cursor_width,
|
||||
guac_common_pointer_cursor_height,
|
||||
guac_common_pointer_cursor_stride);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_set_dot(guac_common_cursor* cursor) {
|
||||
|
||||
guac_common_cursor_set_argb(cursor, 2, 2,
|
||||
guac_common_dot_cursor,
|
||||
guac_common_dot_cursor_width,
|
||||
guac_common_dot_cursor_height,
|
||||
guac_common_dot_cursor_stride);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_set_ibar(guac_common_cursor* cursor) {
|
||||
|
||||
guac_common_cursor_set_argb(cursor,
|
||||
guac_common_ibar_cursor_width / 2,
|
||||
guac_common_ibar_cursor_height / 2,
|
||||
guac_common_ibar_cursor,
|
||||
guac_common_ibar_cursor_width,
|
||||
guac_common_ibar_cursor_height,
|
||||
guac_common_ibar_cursor_stride);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_set_blank(guac_common_cursor* cursor) {
|
||||
|
||||
guac_common_cursor_set_argb(cursor, 0, 0,
|
||||
guac_common_blank_cursor,
|
||||
guac_common_blank_cursor_width,
|
||||
guac_common_blank_cursor_height,
|
||||
guac_common_blank_cursor_stride);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_remove_user(guac_common_cursor* cursor,
|
||||
guac_user* user) {
|
||||
|
||||
/* Disassociate from given user */
|
||||
if (cursor->user == user)
|
||||
cursor->user = NULL;
|
||||
|
||||
}
|
||||
|
270
src/common/guac_cursor.h
Normal file
270
src/common/guac_cursor.h
Normal file
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GUAC_COMMON_CURSOR_H
|
||||
#define GUAC_COMMON_CURSOR_H
|
||||
|
||||
#include "guac_surface.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* The default size of the cursor image buffer.
|
||||
*/
|
||||
#define GUAC_COMMON_CURSOR_DEFAULT_SIZE 64*64*4
|
||||
|
||||
/**
|
||||
* Cursor object which maintains and synchronizes the current mouse cursor
|
||||
* state across all users of a specific client.
|
||||
*/
|
||||
typedef struct guac_common_cursor {
|
||||
|
||||
/**
|
||||
* The client to maintain the mouse cursor for.
|
||||
*/
|
||||
guac_client* client;
|
||||
|
||||
/**
|
||||
* The cursor layer. This layer will be available to all connected users,
|
||||
* but will be visible only to those users who are not moving the mouse.
|
||||
*/
|
||||
guac_layer* layer;
|
||||
|
||||
/**
|
||||
* The width of the cursor image, in pixels.
|
||||
*/
|
||||
int width;
|
||||
|
||||
/**
|
||||
* The height of the cursor image, in pixels.
|
||||
*/
|
||||
int height;
|
||||
|
||||
/**
|
||||
* Arbitrary image data buffer, backing the Cairo surface used to store
|
||||
* the cursor image.
|
||||
*/
|
||||
unsigned char* image_buffer;
|
||||
|
||||
/**
|
||||
* The size of the image data buffer, in bytes.
|
||||
*/
|
||||
int image_buffer_size;
|
||||
|
||||
/**
|
||||
* The current cursor image, if any. If the mouse cursor has not yet been
|
||||
* set, this will be NULL.
|
||||
*/
|
||||
cairo_surface_t* surface;
|
||||
|
||||
/**
|
||||
* The X coordinate of the hotspot of the mouse cursor.
|
||||
*/
|
||||
int hotspot_x;
|
||||
|
||||
/**
|
||||
* The Y coordinate of the hotspot of the mouse cursor.
|
||||
*/
|
||||
int hotspot_y;
|
||||
|
||||
/**
|
||||
* The last user to move the mouse, or NULL if no user has moved the
|
||||
* mouse yet.
|
||||
*/
|
||||
guac_user* user;
|
||||
|
||||
/**
|
||||
* The X coordinate of the current mouse cursor location.
|
||||
*/
|
||||
int x;
|
||||
|
||||
/**
|
||||
* The Y coordinate of the current mouse cursor location.
|
||||
*/
|
||||
int y;
|
||||
|
||||
} guac_common_cursor;
|
||||
|
||||
/**
|
||||
* Allocates a new cursor object which maintains and synchronizes the current
|
||||
* mouse cursor state across all users of the given client.
|
||||
*
|
||||
* @param client
|
||||
* The client for which this object shall maintain the mouse cursor.
|
||||
*
|
||||
* @return
|
||||
* The newly-allocated mouse cursor.
|
||||
*/
|
||||
guac_common_cursor* guac_common_cursor_alloc(guac_client* client);
|
||||
|
||||
/**
|
||||
* Frees the given cursor.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to free.
|
||||
*/
|
||||
void guac_common_cursor_free(guac_common_cursor* cursor);
|
||||
|
||||
/**
|
||||
* Sends the current state of this cursor across the given socket, including
|
||||
* the current cursor image. The resulting cursor on the remote display will
|
||||
* be visible.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to send.
|
||||
*
|
||||
* @param user
|
||||
* The user receiving the updated cursor.
|
||||
*
|
||||
* @param socket
|
||||
* The socket over which the updated cursor should be sent.
|
||||
*/
|
||||
void guac_common_cursor_dup(guac_common_cursor* cursor, guac_user* user,
|
||||
guac_socket* socket);
|
||||
|
||||
/**
|
||||
* Moves the mouse cursor, marking the given user as the most recent user of
|
||||
* the mouse. The remote mouse cursor will be hidden for this user and shown
|
||||
* for all others.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor being moved.
|
||||
*
|
||||
* @param user
|
||||
* The user that moved the cursor.
|
||||
*
|
||||
* @param x
|
||||
* The new X coordinate of the cursor.
|
||||
*
|
||||
* @param y
|
||||
* The new Y coordinate of the cursor.
|
||||
*/
|
||||
void guac_common_cursor_move(guac_common_cursor* cursor, guac_user* user,
|
||||
int x, int y);
|
||||
|
||||
/**
|
||||
* Sets the cursor image to the given raw image data. This raw image data must
|
||||
* be in 32-bit ARGB format, having 8 bits per color component, where the
|
||||
* alpha component is stored in the high-order 8 bits, and blue is stored
|
||||
* in the low-order 8 bits.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to set the image of.
|
||||
*
|
||||
* @param hx
|
||||
* The X coordinate of the hotspot of the new cursor image.
|
||||
*
|
||||
* @param hy
|
||||
* The Y coordinate of the hotspot of the new cursor image.
|
||||
*
|
||||
* @param data
|
||||
* A pointer to raw 32-bit ARGB image data.
|
||||
*
|
||||
* @param width
|
||||
* The width of the given image data, in pixels.
|
||||
*
|
||||
* @param height
|
||||
* The height of the given image data, in pixels.
|
||||
*
|
||||
* @param stride
|
||||
* The number of bytes in a single row of image data.
|
||||
*/
|
||||
void guac_common_cursor_set_argb(guac_common_cursor* cursor, int hx, int hy,
|
||||
unsigned const char* data, int width, int height, int stride);
|
||||
|
||||
/**
|
||||
* Sets the cursor image to the contents of the given surface. The entire
|
||||
* contents of the surface are used, and the dimensions of the resulting
|
||||
* cursor will be the dimensions of the given surface.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to set the image of.
|
||||
*
|
||||
* @param hx
|
||||
* The X coordinate of the hotspot of the new cursor image.
|
||||
*
|
||||
* @param hy
|
||||
* The Y coordinate of the hotspot of the new cursor image.
|
||||
*
|
||||
* @param surface
|
||||
* The surface containing the cursor image.
|
||||
*/
|
||||
void guac_common_cursor_set_surface(guac_common_cursor* cursor, int hx, int hy,
|
||||
guac_common_surface* surface);
|
||||
|
||||
/**
|
||||
* Set the cursor of the remote display to the embedded "pointer" graphic. The
|
||||
* pointer graphic is a black arrow with white border.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to set the image of.
|
||||
*/
|
||||
void guac_common_cursor_set_pointer(guac_common_cursor* cursor);
|
||||
|
||||
/**
|
||||
* Set the cursor of the remote display to the embedded "dot" graphic. The dot
|
||||
* graphic is a small black square with white border.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to set the image of.
|
||||
*/
|
||||
void guac_common_cursor_set_dot(guac_common_cursor* cursor);
|
||||
|
||||
/**
|
||||
* Sets the cursor of the remote display to the embedded "I-bar" graphic. The
|
||||
* I-bar graphic is a small black "I" shape with white border, used to indicate
|
||||
* the presence of selectable or editable text.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to set the image of.
|
||||
*/
|
||||
void guac_common_cursor_set_ibar(guac_common_cursor* cursor);
|
||||
|
||||
/**
|
||||
* Sets the cursor of the remote display to the embedded transparent (blank)
|
||||
* graphic, effectively hiding the mouse cursor.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to set the image of.
|
||||
*/
|
||||
void guac_common_cursor_set_blank(guac_common_cursor* cursor);
|
||||
|
||||
/**
|
||||
* Removes the given user, such that future synchronization will not occur.
|
||||
* This is necessary when a user leaves the connection. If a user leaves the
|
||||
* connection and this is not called, the corresponding guac_user and socket
|
||||
* may cease to be valid, and future synchronization attempts will segfault.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to remove the user from.
|
||||
*
|
||||
* @param user
|
||||
* The user to remove.
|
||||
*/
|
||||
void guac_common_cursor_remove_user(guac_common_cursor* cursor,
|
||||
guac_user* user);
|
||||
|
||||
#endif
|
301
src/common/guac_display.c
Normal file
301
src/common/guac_display.c
Normal file
@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "guac_cursor.h"
|
||||
#include "guac_display.h"
|
||||
#include "guac_surface.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/socket.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Synchronizes all surfaces within the given linked list to the given socket.
|
||||
* If the provided pointer to the linked list is NULL, this function has no
|
||||
* effect.
|
||||
*
|
||||
* @param layers
|
||||
* The head element of the linked list of layers to synchronize, which may
|
||||
* be NULL if the list is currently empty.
|
||||
*
|
||||
* @param user
|
||||
* The user receiving the layers.
|
||||
*
|
||||
* @param socket
|
||||
* The socket over which each layer should be sent.
|
||||
*/
|
||||
static void guac_common_display_dup_layers(guac_common_display_layer* layers,
|
||||
guac_user* user, guac_socket* socket) {
|
||||
|
||||
guac_common_display_layer* current = layers;
|
||||
|
||||
/* Synchronize all surfaces in given list */
|
||||
while (current != NULL) {
|
||||
guac_common_surface_dup(current->surface, user, socket);
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees all layers and associated surfaces within the given list, as well as
|
||||
* their corresponding list elements. If the provided pointer to the linked
|
||||
* list is NULL, this function has no effect.
|
||||
*
|
||||
* @param layers
|
||||
* The head element of the linked list of layers to free, which may be NULL
|
||||
* if the list is currently empty.
|
||||
*
|
||||
* @param client
|
||||
* The client owning the layers wrapped by each of the layers in the list.
|
||||
*/
|
||||
static void guac_common_display_free_layers(guac_common_display_layer* layers,
|
||||
guac_client* client) {
|
||||
|
||||
guac_common_display_layer* current = layers;
|
||||
|
||||
/* Free each surface in given list */
|
||||
while (current != NULL) {
|
||||
|
||||
guac_common_display_layer* next = current->next;
|
||||
guac_layer* layer = current->layer;
|
||||
|
||||
/* Free surface */
|
||||
guac_common_surface_free(current->surface);
|
||||
|
||||
/* Free layer or buffer depending on index */
|
||||
if (layer->index < 0)
|
||||
guac_client_free_buffer(client, layer);
|
||||
else if (layer->index > 0)
|
||||
guac_client_free_layer(client, layer);
|
||||
|
||||
/* Free current element and advance to next */
|
||||
free(current);
|
||||
current = next;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
guac_common_display* guac_common_display_alloc(guac_client* client,
|
||||
int width, int height) {
|
||||
|
||||
/* Allocate display */
|
||||
guac_common_display* display = malloc(sizeof(guac_common_display));
|
||||
if (display == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Associate display with given client */
|
||||
display->client = client;
|
||||
|
||||
/* Allocate shared cursor */
|
||||
display->cursor = guac_common_cursor_alloc(client);
|
||||
|
||||
display->default_surface = guac_common_surface_alloc(client,
|
||||
client->socket, GUAC_DEFAULT_LAYER, width, height);
|
||||
|
||||
/* No initial layers or buffers */
|
||||
display->layers = NULL;
|
||||
display->buffers = NULL;
|
||||
|
||||
return display;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_display_free(guac_common_display* display) {
|
||||
|
||||
/* Free shared cursor */
|
||||
guac_common_cursor_free(display->cursor);
|
||||
|
||||
/* Free default surface */
|
||||
guac_common_surface_free(display->default_surface);
|
||||
|
||||
/* Free all layers and buffers */
|
||||
guac_common_display_free_layers(display->buffers, display->client);
|
||||
guac_common_display_free_layers(display->layers, display->client);
|
||||
|
||||
free(display);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_display_dup(guac_common_display* display, guac_user* user,
|
||||
guac_socket* socket) {
|
||||
|
||||
/* Sunchronize shared cursor */
|
||||
guac_common_cursor_dup(display->cursor, user, socket);
|
||||
|
||||
/* Synchronize default surface */
|
||||
guac_common_surface_dup(display->default_surface, user, socket);
|
||||
|
||||
/* Synchronize all layers and buffers */
|
||||
guac_common_display_dup_layers(display->layers, user, socket);
|
||||
guac_common_display_dup_layers(display->buffers, user, socket);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_display_flush(guac_common_display* display) {
|
||||
guac_common_surface_flush(display->default_surface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates and inserts a new element into the given linked list of display
|
||||
* layers, associating it with the given layer and surface.
|
||||
*
|
||||
* @param head
|
||||
* A pointer to the head pointer of the list of layers. The head pointer
|
||||
* will be updated by this function to point to the newly-allocated
|
||||
* display layer.
|
||||
*
|
||||
* @param layer
|
||||
* The Guacamole layer to associated with the new display layer.
|
||||
*
|
||||
* @param surface
|
||||
* The surface associated with the given Guacamole layer and which should
|
||||
* be associated with the new display layer.
|
||||
*
|
||||
* @return
|
||||
* The newly-allocated display layer, which has been associated with the
|
||||
* provided layer and surface.
|
||||
*/
|
||||
static guac_common_display_layer* guac_common_display_add_layer(
|
||||
guac_common_display_layer** head, guac_layer* layer,
|
||||
guac_common_surface* surface) {
|
||||
|
||||
guac_common_display_layer* old_head = *head;
|
||||
|
||||
guac_common_display_layer* display_layer =
|
||||
malloc(sizeof(guac_common_display_layer));
|
||||
|
||||
/* Init layer/surface pair */
|
||||
display_layer->layer = layer;
|
||||
display_layer->surface = surface;
|
||||
|
||||
/* Insert list element as the new head */
|
||||
display_layer->prev = NULL;
|
||||
display_layer->next = old_head;
|
||||
*head = display_layer;
|
||||
|
||||
/* Update old head to point to new element, if it existed */
|
||||
if (old_head != NULL)
|
||||
old_head->prev = display_layer;
|
||||
|
||||
return display_layer;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given display layer from the linked list whose head pointer is
|
||||
* provided.
|
||||
*
|
||||
* @param head
|
||||
* A pointer to the head pointer of the list of layers. The head pointer
|
||||
* will be updated by this function if necessary, and will be set to NULL
|
||||
* if the display layer being removed is the only layer in the list.
|
||||
*
|
||||
* @param display_layer
|
||||
* The display layer to remove from the given list.
|
||||
*/
|
||||
static void guac_common_display_remove_layer(guac_common_display_layer** head,
|
||||
guac_common_display_layer* display_layer) {
|
||||
|
||||
/* Update previous element, if it exists */
|
||||
if (display_layer->prev != NULL)
|
||||
display_layer->prev->next = display_layer->next;
|
||||
|
||||
/* If there is no previous element, update the list head */
|
||||
else
|
||||
*head = display_layer->next;
|
||||
|
||||
/* Update next element, if it exists */
|
||||
if (display_layer->next != NULL)
|
||||
display_layer->next->prev = display_layer->prev;
|
||||
|
||||
}
|
||||
|
||||
guac_common_display_layer* guac_common_display_alloc_layer(
|
||||
guac_common_display* display, int width, int height) {
|
||||
|
||||
guac_layer* layer;
|
||||
guac_common_surface* surface;
|
||||
|
||||
/* Allocate Guacamole layer */
|
||||
layer = guac_client_alloc_layer(display->client);
|
||||
|
||||
/* Allocate corresponding surface */
|
||||
surface = guac_common_surface_alloc(display->client,
|
||||
display->client->socket, layer, width, height);
|
||||
|
||||
/* Add layer and surface to list */
|
||||
return guac_common_display_add_layer(&display->layers, layer, surface);
|
||||
|
||||
}
|
||||
|
||||
guac_common_display_layer* guac_common_display_alloc_buffer(
|
||||
guac_common_display* display, int width, int height) {
|
||||
|
||||
guac_layer* buffer;
|
||||
guac_common_surface* surface;
|
||||
|
||||
/* Allocate Guacamole buffer */
|
||||
buffer = guac_client_alloc_buffer(display->client);
|
||||
|
||||
/* Allocate corresponding surface */
|
||||
surface = guac_common_surface_alloc(display->client,
|
||||
display->client->socket, buffer, width, height);
|
||||
|
||||
/* Add buffer and surface to list */
|
||||
return guac_common_display_add_layer(&display->buffers, buffer, surface);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_display_free_layer(guac_common_display* display,
|
||||
guac_common_display_layer* display_layer) {
|
||||
|
||||
/* Remove list element from list */
|
||||
guac_common_display_remove_layer(&display->layers, display_layer);
|
||||
|
||||
/* Free associated layer and surface */
|
||||
guac_common_surface_free(display_layer->surface);
|
||||
guac_client_free_layer(display->client, display_layer->layer);
|
||||
|
||||
/* Free list element */
|
||||
free(display_layer);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_display_free_buffer(guac_common_display* display,
|
||||
guac_common_display_layer* display_buffer) {
|
||||
|
||||
/* Remove list element from list */
|
||||
guac_common_display_remove_layer(&display->buffers, display_buffer);
|
||||
|
||||
/* Free associated layer and surface */
|
||||
guac_common_surface_free(display_buffer->surface);
|
||||
guac_client_free_buffer(display->client, display_buffer->layer);
|
||||
|
||||
/* Free list element */
|
||||
free(display_buffer);
|
||||
|
||||
}
|
||||
|
226
src/common/guac_display.h
Normal file
226
src/common/guac_display.h
Normal file
@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_COMMON_DISPLAY_H
|
||||
#define GUAC_COMMON_DISPLAY_H
|
||||
|
||||
#include "guac_cursor.h"
|
||||
#include "guac_surface.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/socket.h>
|
||||
|
||||
/**
|
||||
* A list element representing a pairing of a Guacamole layer with a
|
||||
* corresponding guac_common_surface which wraps that layer. Adjacent layers
|
||||
* within the same list are pointed to with traditional prev/next pointers. The
|
||||
* order of layers in lists need not correspond in any way to the natural
|
||||
* ordering of those layers' indexes nor their stacking order (Z-order) within
|
||||
* the display.
|
||||
*/
|
||||
typedef struct guac_common_display_layer guac_common_display_layer;
|
||||
|
||||
struct guac_common_display_layer {
|
||||
|
||||
/**
|
||||
* A Guacamole layer.
|
||||
*/
|
||||
guac_layer* layer;
|
||||
|
||||
/**
|
||||
* The surface which wraps the associated layer.
|
||||
*/
|
||||
guac_common_surface* surface;
|
||||
|
||||
/**
|
||||
* The layer immediately prior to this layer within the list containing
|
||||
* this layer, or NULL if this is the first layer/buffer in the list.
|
||||
*/
|
||||
guac_common_display_layer* prev;
|
||||
|
||||
/**
|
||||
* The layer immediately following this layer within the list containing
|
||||
* this layer, or NULL if this is the last layer/buffer in the list.
|
||||
*/
|
||||
guac_common_display_layer* next;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Abstracts a remote Guacamole display, having an associated client,
|
||||
* default surface, mouse cursor, and various allocated buffers and layers.
|
||||
*/
|
||||
typedef struct guac_common_display {
|
||||
|
||||
/**
|
||||
* The client associate with this display.
|
||||
*/
|
||||
guac_client* client;
|
||||
|
||||
/**
|
||||
* The default surface of the client display.
|
||||
*/
|
||||
guac_common_surface* default_surface;
|
||||
|
||||
/**
|
||||
* Client-wide cursor, synchronized across all users.
|
||||
*/
|
||||
guac_common_cursor* cursor;
|
||||
|
||||
/**
|
||||
* The first element within a linked list of all currently-allocated
|
||||
* layers, or NULL if no layers are currently allocated. The default layer,
|
||||
* layer #0, is stored within default_surface and will not have a
|
||||
* corresponding element within this list.
|
||||
*/
|
||||
guac_common_display_layer* layers;
|
||||
|
||||
/**
|
||||
* The first element within a linked list of all currently-allocated
|
||||
* buffers, or NULL if no buffers are currently allocated.
|
||||
*/
|
||||
guac_common_display_layer* buffers;
|
||||
|
||||
} guac_common_display;
|
||||
|
||||
/**
|
||||
* Allocates a new display, abstracting the cursor and buffer/layer allocation
|
||||
* operations of the given guac_client such that client state can be easily
|
||||
* synchronized to joining users.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client to associate with this display.
|
||||
*
|
||||
* @param width
|
||||
* The initial width of the display, in pixels.
|
||||
*
|
||||
* @param height
|
||||
* The initial height of the display, in pixels.
|
||||
*
|
||||
* @return
|
||||
* The newly-allocated display.
|
||||
*/
|
||||
guac_common_display* guac_common_display_alloc(guac_client* client,
|
||||
int width, int height);
|
||||
|
||||
/**
|
||||
* Frees the given display, and any associated resources, including any
|
||||
* allocated buffers/layers.
|
||||
*
|
||||
* @param display
|
||||
* The display to free.
|
||||
*/
|
||||
void guac_common_display_free(guac_common_display* display);
|
||||
|
||||
/**
|
||||
* Duplicates the state of the given display to the given socket. Any pending
|
||||
* changes to buffers, layers, or the default layer are not flushed.
|
||||
*
|
||||
* @param display
|
||||
* The display whose state should be sent along the given socket.
|
||||
*
|
||||
* @param user
|
||||
* The user receiving the display state.
|
||||
*
|
||||
* @param socket
|
||||
* The socket over which the display state should be sent.
|
||||
*/
|
||||
void guac_common_display_dup(guac_common_display* display, guac_user* user,
|
||||
guac_socket* socket);
|
||||
|
||||
/**
|
||||
* Flushes pending changes to the given display. All pending operations will
|
||||
* become visible to any connected users.
|
||||
*
|
||||
* @param display
|
||||
* The display to flush.
|
||||
*/
|
||||
void guac_common_display_flush(guac_common_display* display);
|
||||
|
||||
/**
|
||||
* Allocates a new layer, returning a new wrapped layer and corresponding
|
||||
* surface. The layer may be reused from a previous allocation, if that layer
|
||||
* has since been freed.
|
||||
*
|
||||
* @param display
|
||||
* The display to allocate a new layer from.
|
||||
*
|
||||
* @param width
|
||||
* The width of the layer to allocate, in pixels.
|
||||
*
|
||||
* @param height
|
||||
* The height of the layer to allocate, in pixels.
|
||||
*
|
||||
* @return
|
||||
* A newly-allocated layer.
|
||||
*/
|
||||
guac_common_display_layer* guac_common_display_alloc_layer(
|
||||
guac_common_display* display, int width, int height);
|
||||
|
||||
/**
|
||||
* Allocates a new buffer, returning a new wrapped buffer and corresponding
|
||||
* surface. The buffer may be reused from a previous allocation, if that buffer
|
||||
* has since been freed.
|
||||
*
|
||||
* @param display
|
||||
* The display to allocate a new buffer from.
|
||||
*
|
||||
* @param width
|
||||
* The width of the buffer to allocate, in pixels.
|
||||
*
|
||||
* @param height
|
||||
* The height of the buffer to allocate, in pixels.
|
||||
*
|
||||
* @return
|
||||
* A newly-allocated buffer.
|
||||
*/
|
||||
guac_common_display_layer* guac_common_display_alloc_buffer(
|
||||
guac_common_display* display, int width, int height);
|
||||
|
||||
/**
|
||||
* Frees the given surface and associated layer, returning the layer to the
|
||||
* given display for future use.
|
||||
*
|
||||
* @param display
|
||||
* The display originally allocating the layer.
|
||||
*
|
||||
* @param display_layer
|
||||
* The layer to free.
|
||||
*/
|
||||
void guac_common_display_free_layer(guac_common_display* display,
|
||||
guac_common_display_layer* display_layer);
|
||||
|
||||
/**
|
||||
* Frees the given surface and associated buffer, returning the buffer to the
|
||||
* given display for future use.
|
||||
*
|
||||
* @param display
|
||||
* The display originally allocating the buffer.
|
||||
*
|
||||
* @param display_buffer
|
||||
* The buffer to free.
|
||||
*/
|
||||
void guac_common_display_free_buffer(guac_common_display* display,
|
||||
guac_common_display_layer* display_buffer);
|
||||
|
||||
#endif
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <guacamole/layer.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/* Macros for prettying up the embedded image. */
|
||||
#define X 0x00,0x00,0x00,0xFF
|
||||
@ -52,9 +53,10 @@ unsigned char guac_common_dot_cursor[] = {
|
||||
|
||||
};
|
||||
|
||||
void guac_common_set_dot_cursor(guac_client* client) {
|
||||
void guac_common_set_dot_cursor(guac_user* user) {
|
||||
|
||||
guac_socket* socket = client->socket;
|
||||
guac_client* client = user->client;
|
||||
guac_socket* socket = user->socket;
|
||||
|
||||
/* Draw to buffer */
|
||||
guac_layer* cursor = guac_client_alloc_buffer(client);
|
||||
@ -66,7 +68,7 @@ void guac_common_set_dot_cursor(guac_client* client) {
|
||||
guac_common_dot_cursor_height,
|
||||
guac_common_dot_cursor_stride);
|
||||
|
||||
guac_client_stream_png(client, socket, GUAC_COMP_SRC, cursor,
|
||||
guac_user_stream_png(user, socket, GUAC_COMP_SRC, cursor,
|
||||
0, 0, graphic);
|
||||
cairo_surface_destroy(graphic);
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Width of the embedded mouse cursor graphic.
|
||||
@ -57,8 +57,8 @@ extern unsigned char guac_common_dot_cursor[];
|
||||
/**
|
||||
* Set the cursor of the remote display to the embedded cursor graphic.
|
||||
*
|
||||
* @param client The guac_client to send the cursor to.
|
||||
* @param user The guac_user to send the cursor to.
|
||||
*/
|
||||
void guac_common_set_dot_cursor(guac_client* client);
|
||||
void guac_common_set_dot_cursor(guac_user* user);
|
||||
|
||||
#endif
|
||||
|
101
src/common/guac_ibar_cursor.c
Normal file
101
src/common/guac_ibar_cursor.c
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/layer.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/* Macros for prettying up the embedded image. */
|
||||
#define X 0x00,0x00,0x00,0xFF
|
||||
#define U 0x80,0x80,0x80,0xFF
|
||||
#define O 0xFF,0xFF,0xFF,0xFF
|
||||
#define _ 0x00,0x00,0x00,0x00
|
||||
|
||||
/* Dimensions */
|
||||
const int guac_common_ibar_cursor_width = 7;
|
||||
const int guac_common_ibar_cursor_height = 16;
|
||||
|
||||
/* Format */
|
||||
const cairo_format_t guac_common_ibar_cursor_format = CAIRO_FORMAT_ARGB32;
|
||||
const int guac_common_ibar_cursor_stride = 28;
|
||||
|
||||
/* Embedded I-bar graphic */
|
||||
unsigned char guac_common_ibar_cursor[] = {
|
||||
|
||||
X,X,X,X,X,X,X,
|
||||
X,O,O,U,O,O,X,
|
||||
X,X,X,O,X,X,X,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
X,X,X,O,X,X,X,
|
||||
X,O,O,U,O,O,X,
|
||||
X,X,X,X,X,X,X
|
||||
|
||||
};
|
||||
|
||||
void guac_common_set_ibar_cursor(guac_user* user) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
guac_socket* socket = user->socket;
|
||||
|
||||
/* Draw to buffer */
|
||||
guac_layer* cursor = guac_client_alloc_buffer(client);
|
||||
|
||||
cairo_surface_t* graphic = cairo_image_surface_create_for_data(
|
||||
guac_common_ibar_cursor,
|
||||
guac_common_ibar_cursor_format,
|
||||
guac_common_ibar_cursor_width,
|
||||
guac_common_ibar_cursor_height,
|
||||
guac_common_ibar_cursor_stride);
|
||||
|
||||
guac_user_stream_png(user, socket, GUAC_COMP_SRC, cursor,
|
||||
0, 0, graphic);
|
||||
cairo_surface_destroy(graphic);
|
||||
|
||||
/* Set cursor */
|
||||
guac_protocol_send_cursor(socket, 0, 0, cursor,
|
||||
guac_common_ibar_cursor_width / 2,
|
||||
guac_common_ibar_cursor_height / 2,
|
||||
guac_common_ibar_cursor_width,
|
||||
guac_common_ibar_cursor_height);
|
||||
|
||||
/* Free buffer */
|
||||
guac_client_free_buffer(client, cursor);
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Client cursor image set to generic built-in I-bar.");
|
||||
|
||||
}
|
||||
|
65
src/common/guac_ibar_cursor.h
Normal file
65
src/common/guac_ibar_cursor.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_COMMON_IBAR_CURSOR_H
|
||||
#define GUAC_COMMON_IBAR_CURSOR_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Width of the embedded I-bar mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_ibar_cursor_width;
|
||||
|
||||
/**
|
||||
* Height of the embedded I-bar mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_ibar_cursor_height;
|
||||
|
||||
/**
|
||||
* Number of bytes in each row of the embedded I-bar mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_ibar_cursor_stride;
|
||||
|
||||
/**
|
||||
* The Cairo grapic format of the I-bar mouse cursor graphic.
|
||||
*/
|
||||
extern const cairo_format_t guac_common_ibar_cursor_format;
|
||||
|
||||
/**
|
||||
* Embedded I-bar mouse cursor graphic.
|
||||
*/
|
||||
extern unsigned char guac_common_ibar_cursor[];
|
||||
|
||||
/**
|
||||
* Sets the cursor of the remote display to the embedded I-bar cursor graphic.
|
||||
*
|
||||
* @param user
|
||||
* The guac_user to send the cursor to.
|
||||
*/
|
||||
void guac_common_set_ibar_cursor(guac_user* user);
|
||||
|
||||
#endif
|
||||
|
@ -28,17 +28,17 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/stream.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
void guac_common_json_flush(guac_client* client, guac_stream* stream,
|
||||
void guac_common_json_flush(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state) {
|
||||
|
||||
/* If JSON buffer is non-empty, write contents to blob and reset */
|
||||
if (json_state->size > 0) {
|
||||
guac_protocol_send_blob(client->socket, stream,
|
||||
guac_protocol_send_blob(user->socket, stream,
|
||||
json_state->buffer, json_state->size);
|
||||
|
||||
/* Reset JSON buffer size */
|
||||
@ -48,7 +48,7 @@ void guac_common_json_flush(guac_client* client, guac_stream* stream,
|
||||
|
||||
}
|
||||
|
||||
int guac_common_json_write(guac_client* client, guac_stream* stream,
|
||||
int guac_common_json_write(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state, const char* buffer, int length) {
|
||||
|
||||
int blob_written = 0;
|
||||
@ -66,7 +66,7 @@ int guac_common_json_write(guac_client* client, guac_stream* stream,
|
||||
|
||||
/* Flush if more room is needed */
|
||||
if (json_state->size + blob_length > sizeof(json_state->buffer)) {
|
||||
guac_common_json_flush(client, stream, json_state);
|
||||
guac_common_json_flush(user, stream, json_state);
|
||||
blob_written = 1;
|
||||
}
|
||||
|
||||
@ -86,14 +86,14 @@ int guac_common_json_write(guac_client* client, guac_stream* stream,
|
||||
|
||||
}
|
||||
|
||||
int guac_common_json_write_string(guac_client* client,
|
||||
int guac_common_json_write_string(guac_user* user,
|
||||
guac_stream* stream, guac_common_json_state* json_state,
|
||||
const char* str) {
|
||||
|
||||
int blob_written = 0;
|
||||
|
||||
/* Write starting quote */
|
||||
blob_written |= guac_common_json_write(client, stream,
|
||||
blob_written |= guac_common_json_write(user, stream,
|
||||
json_state, "\"", 1);
|
||||
|
||||
/* Write given string, escaping as necessary */
|
||||
@ -105,11 +105,11 @@ int guac_common_json_write_string(guac_client* client,
|
||||
|
||||
/* Write any string content up to current character */
|
||||
if (current != str)
|
||||
blob_written |= guac_common_json_write(client, stream,
|
||||
blob_written |= guac_common_json_write(user, stream,
|
||||
json_state, str, current - str);
|
||||
|
||||
/* Escape the quote that was just read */
|
||||
blob_written |= guac_common_json_write(client, stream,
|
||||
blob_written |= guac_common_json_write(user, stream,
|
||||
json_state, "\\", 1);
|
||||
|
||||
/* Reset string */
|
||||
@ -121,18 +121,18 @@ int guac_common_json_write_string(guac_client* client,
|
||||
|
||||
/* Write any remaining string content */
|
||||
if (current != str)
|
||||
blob_written |= guac_common_json_write(client, stream,
|
||||
blob_written |= guac_common_json_write(user, stream,
|
||||
json_state, str, current - str);
|
||||
|
||||
/* Write ending quote */
|
||||
blob_written |= guac_common_json_write(client, stream,
|
||||
blob_written |= guac_common_json_write(user, stream,
|
||||
json_state, "\"", 1);
|
||||
|
||||
return blob_written;
|
||||
|
||||
}
|
||||
|
||||
int guac_common_json_write_property(guac_client* client, guac_stream* stream,
|
||||
int guac_common_json_write_property(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state, const char* name,
|
||||
const char* value) {
|
||||
|
||||
@ -140,19 +140,19 @@ int guac_common_json_write_property(guac_client* client, guac_stream* stream,
|
||||
|
||||
/* Write leading comma if not first property */
|
||||
if (json_state->properties_written != 0)
|
||||
blob_written |= guac_common_json_write(client, stream,
|
||||
blob_written |= guac_common_json_write(user, stream,
|
||||
json_state, ",", 1);
|
||||
|
||||
/* Write property name */
|
||||
blob_written |= guac_common_json_write_string(client, stream,
|
||||
blob_written |= guac_common_json_write_string(user, stream,
|
||||
json_state, name);
|
||||
|
||||
/* Separate name from value with colon */
|
||||
blob_written |= guac_common_json_write(client, stream,
|
||||
blob_written |= guac_common_json_write(user, stream,
|
||||
json_state, ":", 1);
|
||||
|
||||
/* Write property value */
|
||||
blob_written |= guac_common_json_write_string(client, stream,
|
||||
blob_written |= guac_common_json_write_string(user, stream,
|
||||
json_state, value);
|
||||
|
||||
json_state->properties_written++;
|
||||
@ -161,7 +161,7 @@ int guac_common_json_write_property(guac_client* client, guac_stream* stream,
|
||||
|
||||
}
|
||||
|
||||
void guac_common_json_begin_object(guac_client* client, guac_stream* stream,
|
||||
void guac_common_json_begin_object(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state) {
|
||||
|
||||
/* Init JSON state */
|
||||
@ -169,15 +169,15 @@ void guac_common_json_begin_object(guac_client* client, guac_stream* stream,
|
||||
json_state->properties_written = 0;
|
||||
|
||||
/* Write leading brace - no blob can possibly be written by this */
|
||||
assert(!guac_common_json_write(client, stream, json_state, "{", 1));
|
||||
assert(!guac_common_json_write(user, stream, json_state, "{", 1));
|
||||
|
||||
}
|
||||
|
||||
int guac_common_json_end_object(guac_client* client, guac_stream* stream,
|
||||
int guac_common_json_end_object(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state) {
|
||||
|
||||
/* Write final brace of JSON object */
|
||||
return guac_common_json_write(client, stream, json_state, "}", 1);
|
||||
return guac_common_json_write(user, stream, json_state, "}", 1);
|
||||
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/stream.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* The current streaming state of an arbitrary JSON object, consisting of
|
||||
@ -55,13 +55,13 @@ typedef struct guac_common_json_state {
|
||||
} guac_common_json_state;
|
||||
|
||||
/**
|
||||
* Given a stream, the client to which it belongs, and the current stream state
|
||||
* Given a stream, the user to which it belongs, and the current stream state
|
||||
* of a JSON object, flushes the contents of the JSON buffer to a blob
|
||||
* instruction. Note that this will flush the JSON buffer only, and will not
|
||||
* necessarily flush the underlying guac_socket of the client.
|
||||
* necessarily flush the underlying guac_socket of the user.
|
||||
*
|
||||
* @param client
|
||||
* The client to which the data will be flushed.
|
||||
* @param user
|
||||
* The user to which the data will be flushed.
|
||||
*
|
||||
* @param stream
|
||||
* The stream through which the flushed data should be sent as a blob.
|
||||
@ -69,16 +69,16 @@ typedef struct guac_common_json_state {
|
||||
* @param json_state
|
||||
* The state object whose buffer should be flushed.
|
||||
*/
|
||||
void guac_common_json_flush(guac_client* client, guac_stream* stream,
|
||||
void guac_common_json_flush(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state);
|
||||
|
||||
/**
|
||||
* Given a stream, the client to which it belongs, and the current stream state
|
||||
* Given a stream, the user to which it belongs, and the current stream state
|
||||
* of a JSON object, writes the contents of the given buffer to the JSON buffer
|
||||
* of the stream state, flushing as necessary.
|
||||
*
|
||||
* @param client
|
||||
* The client to which the data will be flushed as necessary.
|
||||
* @param user
|
||||
* The user to which the data will be flushed as necessary.
|
||||
*
|
||||
* @param stream
|
||||
* The stream through which the flushed data should be sent as a blob, if
|
||||
@ -97,17 +97,17 @@ void guac_common_json_flush(guac_client* client, guac_stream* stream,
|
||||
* @return
|
||||
* Non-zero if at least one blob was written, zero otherwise.
|
||||
*/
|
||||
int guac_common_json_write(guac_client* client, guac_stream* stream,
|
||||
int guac_common_json_write(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state, const char* buffer, int length);
|
||||
|
||||
/**
|
||||
* Given a stream, the client to which it belongs, and the current stream state
|
||||
* Given a stream, the user to which it belongs, and the current stream state
|
||||
* of a JSON object state, writes the given string as a proper JSON string,
|
||||
* including starting and ending quotes. The contents of the string will be
|
||||
* escaped as necessary.
|
||||
*
|
||||
* @param client
|
||||
* The client to which the data will be flushed as necessary.
|
||||
* @param user
|
||||
* The user to which the data will be flushed as necessary.
|
||||
*
|
||||
* @param stream
|
||||
* The stream through which the flushed data should be sent as a blob, if
|
||||
@ -123,17 +123,17 @@ int guac_common_json_write(guac_client* client, guac_stream* stream,
|
||||
* @return
|
||||
* Non-zero if at least one blob was written, zero otherwise.
|
||||
*/
|
||||
int guac_common_json_write_string(guac_client* client,
|
||||
int guac_common_json_write_string(guac_user* user,
|
||||
guac_stream* stream, guac_common_json_state* json_state,
|
||||
const char* str);
|
||||
|
||||
/**
|
||||
* Given a stream, the client to which it belongs, and the current stream state
|
||||
* Given a stream, the user to which it belongs, and the current stream state
|
||||
* of a JSON object, writes the given JSON property name/value pair. The
|
||||
* name and value will be written as proper JSON strings separated by a colon.
|
||||
*
|
||||
* @param client
|
||||
* The client to which the data will be flushed as necessary.
|
||||
* @param user
|
||||
* The user to which the data will be flushed as necessary.
|
||||
*
|
||||
* @param stream
|
||||
* The stream through which the flushed data should be sent as a blob, if
|
||||
@ -152,18 +152,18 @@ int guac_common_json_write_string(guac_client* client,
|
||||
* @return
|
||||
* Non-zero if at least one blob was written, zero otherwise.
|
||||
*/
|
||||
int guac_common_json_write_property(guac_client* client, guac_stream* stream,
|
||||
int guac_common_json_write_property(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state, const char* name,
|
||||
const char* value);
|
||||
|
||||
/**
|
||||
* Given a stream, the client to which it belongs, and the current stream state
|
||||
* Given a stream, the user to which it belongs, and the current stream state
|
||||
* of a JSON object, initializes the state for writing a new JSON object. Note
|
||||
* that although the client and stream must be provided, no instruction or
|
||||
* that although the user and stream must be provided, no instruction or
|
||||
* blobs will be written due to any call to this function.
|
||||
*
|
||||
* @param client
|
||||
* The client associated with the given stream.
|
||||
* @param user
|
||||
* The user associated with the given stream.
|
||||
*
|
||||
* @param stream
|
||||
* The stream associated with the JSON object being written.
|
||||
@ -171,17 +171,17 @@ int guac_common_json_write_property(guac_client* client, guac_stream* stream,
|
||||
* @param json_state
|
||||
* The state object to initialize.
|
||||
*/
|
||||
void guac_common_json_begin_object(guac_client* client, guac_stream* stream,
|
||||
void guac_common_json_begin_object(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state);
|
||||
|
||||
/**
|
||||
* Given a stream, the client to which it belongs, and the current stream state
|
||||
* Given a stream, the user to which it belongs, and the current stream state
|
||||
* of a JSON object, completes writing that JSON object by writing the final
|
||||
* terminating brace. This function must only be called following a
|
||||
* corresponding call to guac_common_json_begin_object().
|
||||
*
|
||||
* @param client
|
||||
* The client associated with the given stream.
|
||||
* @param user
|
||||
* The user associated with the given stream.
|
||||
*
|
||||
* @param stream
|
||||
* The stream associated with the JSON object being written.
|
||||
@ -192,7 +192,7 @@ void guac_common_json_begin_object(guac_client* client, guac_stream* stream,
|
||||
* @return
|
||||
* Non-zero if at least one blob was written, zero otherwise.
|
||||
*/
|
||||
int guac_common_json_end_object(guac_client* client, guac_stream* stream,
|
||||
int guac_common_json_end_object(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state);
|
||||
|
||||
#endif
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <guacamole/layer.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/* Macros for prettying up the embedded image. */
|
||||
#define X 0x00,0x00,0x00,0xFF
|
||||
@ -63,9 +64,10 @@ unsigned char guac_common_pointer_cursor[] = {
|
||||
|
||||
};
|
||||
|
||||
void guac_common_set_pointer_cursor(guac_client* client) {
|
||||
void guac_common_set_pointer_cursor(guac_user* user) {
|
||||
|
||||
guac_socket* socket = client->socket;
|
||||
guac_client* client = user->client;
|
||||
guac_socket* socket = user->socket;
|
||||
|
||||
/* Draw to buffer */
|
||||
guac_layer* cursor = guac_client_alloc_buffer(client);
|
||||
@ -77,7 +79,7 @@ void guac_common_set_pointer_cursor(guac_client* client) {
|
||||
guac_common_pointer_cursor_height,
|
||||
guac_common_pointer_cursor_stride);
|
||||
|
||||
guac_client_stream_png(client, socket, GUAC_COMP_SRC, cursor,
|
||||
guac_user_stream_png(user, socket, GUAC_COMP_SRC, cursor,
|
||||
0, 0, graphic);
|
||||
cairo_surface_destroy(graphic);
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Width of the embedded mouse cursor graphic.
|
||||
@ -57,8 +57,8 @@ extern unsigned char guac_common_pointer_cursor[];
|
||||
/**
|
||||
* Set the cursor of the remote display to the embedded cursor graphic.
|
||||
*
|
||||
* @param client The guac_client to send the cursor to.
|
||||
* @param user The guac_user to send the cursor to.
|
||||
*/
|
||||
void guac_common_set_pointer_cursor(guac_client* client);
|
||||
void guac_common_set_pointer_cursor(guac_user* user);
|
||||
|
||||
#endif
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/timestamp.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
@ -1303,15 +1304,18 @@ static void __guac_common_surface_flush_to_png(guac_common_surface* surface) {
|
||||
const guac_layer* layer = surface->layer;
|
||||
|
||||
/* Get Cairo surface for specified rect */
|
||||
unsigned char* buffer = surface->buffer + surface->dirty_rect.y * surface->stride + surface->dirty_rect.x * 4;
|
||||
cairo_surface_t* rect = cairo_image_surface_create_for_data(buffer, CAIRO_FORMAT_RGB24,
|
||||
surface->dirty_rect.width,
|
||||
surface->dirty_rect.height,
|
||||
surface->stride);
|
||||
unsigned char* buffer = surface->buffer
|
||||
+ surface->dirty_rect.y * surface->stride
|
||||
+ surface->dirty_rect.x * 4;
|
||||
|
||||
cairo_surface_t* rect = cairo_image_surface_create_for_data(buffer,
|
||||
CAIRO_FORMAT_RGB24, surface->dirty_rect.width,
|
||||
surface->dirty_rect.height, surface->stride);
|
||||
|
||||
/* Send PNG for rect */
|
||||
guac_client_stream_png(surface->client, socket, GUAC_COMP_OVER,
|
||||
layer, surface->dirty_rect.x, surface->dirty_rect.y, rect);
|
||||
|
||||
cairo_surface_destroy(rect);
|
||||
surface->realized = 1;
|
||||
|
||||
@ -1347,16 +1351,19 @@ static void __guac_common_surface_flush_to_jpeg(guac_common_surface* surface) {
|
||||
&surface->dirty_rect, &max);
|
||||
|
||||
/* Get Cairo surface for specified rect */
|
||||
unsigned char* buffer = surface->buffer + surface->dirty_rect.y * surface->stride + surface->dirty_rect.x * 4;
|
||||
cairo_surface_t* rect = cairo_image_surface_create_for_data(buffer, CAIRO_FORMAT_RGB24,
|
||||
surface->dirty_rect.width,
|
||||
surface->dirty_rect.height,
|
||||
surface->stride);
|
||||
unsigned char* buffer = surface->buffer
|
||||
+ surface->dirty_rect.y * surface->stride
|
||||
+ surface->dirty_rect.x * 4;
|
||||
|
||||
cairo_surface_t* rect = cairo_image_surface_create_for_data(buffer,
|
||||
CAIRO_FORMAT_RGB24, surface->dirty_rect.width,
|
||||
surface->dirty_rect.height, surface->stride);
|
||||
|
||||
/* Send JPEG for rect */
|
||||
guac_client_stream_jpeg(surface->client, socket, GUAC_COMP_OVER, layer,
|
||||
surface->dirty_rect.x, surface->dirty_rect.y, rect,
|
||||
GUAC_SURFACE_JPEG_IMAGE_QUALITY);
|
||||
|
||||
cairo_surface_destroy(rect);
|
||||
surface->realized = 1;
|
||||
|
||||
@ -1397,14 +1404,14 @@ static void __guac_common_surface_flush_to_webp(guac_common_surface* surface) {
|
||||
+ surface->dirty_rect.x * 4;
|
||||
|
||||
cairo_surface_t* rect = cairo_image_surface_create_for_data(buffer,
|
||||
CAIRO_FORMAT_RGB24,
|
||||
surface->dirty_rect.width, surface->dirty_rect.height,
|
||||
surface->stride);
|
||||
CAIRO_FORMAT_RGB24, surface->dirty_rect.width,
|
||||
surface->dirty_rect.height, surface->stride);
|
||||
|
||||
/* Send WebP for rect */
|
||||
guac_client_stream_webp(surface->client, socket, GUAC_COMP_OVER, layer,
|
||||
surface->dirty_rect.x, surface->dirty_rect.y, rect,
|
||||
GUAC_SURFACE_WEBP_IMAGE_QUALITY, 0);
|
||||
|
||||
cairo_surface_destroy(rect);
|
||||
surface->realized = 1;
|
||||
|
||||
@ -1524,3 +1531,25 @@ void guac_common_surface_flush(guac_common_surface* surface) {
|
||||
|
||||
}
|
||||
|
||||
void guac_common_surface_dup(guac_common_surface* surface, guac_user* user,
|
||||
guac_socket* socket) {
|
||||
|
||||
/* Do nothing if not realized */
|
||||
if (!surface->realized)
|
||||
return;
|
||||
|
||||
/* Sync size to new socket */
|
||||
guac_protocol_send_size(socket, surface->layer, surface->width, surface->height);
|
||||
|
||||
/* Get entire surface */
|
||||
cairo_surface_t* rect = cairo_image_surface_create_for_data(
|
||||
surface->buffer, CAIRO_FORMAT_RGB24,
|
||||
surface->width, surface->height, surface->stride);
|
||||
|
||||
/* Send PNG for rect */
|
||||
guac_user_stream_png(user, socket, GUAC_COMP_OVER, surface->layer,
|
||||
0, 0, rect);
|
||||
cairo_surface_destroy(rect);
|
||||
|
||||
}
|
||||
|
||||
|
@ -337,5 +337,21 @@ void guac_common_surface_flush(guac_common_surface* surface);
|
||||
*/
|
||||
void guac_common_surface_flush_deferred(guac_common_surface* surface);
|
||||
|
||||
/**
|
||||
* Duplicates the contents of the current surface to the given socket. Pending
|
||||
* changes are not flushed.
|
||||
*
|
||||
* @param surface
|
||||
* The surface to duplicate.
|
||||
*
|
||||
* @param user
|
||||
* The user receiving the surface.
|
||||
*
|
||||
* @param socket
|
||||
* The socket over which the surface contents should be sent.
|
||||
*/
|
||||
void guac_common_surface_dup(guac_common_surface* surface, guac_user* user,
|
||||
guac_socket* socket);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -28,6 +28,7 @@ check_PROGRAMS = test_libguac
|
||||
|
||||
noinst_HEADERS = \
|
||||
client/client_suite.h \
|
||||
common/common_suite.h \
|
||||
protocol/suite.h \
|
||||
util/util_suite.h
|
||||
|
||||
@ -36,6 +37,10 @@ test_libguac_SOURCES = \
|
||||
client/client_suite.c \
|
||||
client/buffer_pool.c \
|
||||
client/layer_pool.c \
|
||||
common/common_suite.c \
|
||||
common/guac_iconv.c \
|
||||
common/guac_string.c \
|
||||
common/guac_rect.c \
|
||||
protocol/suite.c \
|
||||
protocol/base64_decode.c \
|
||||
protocol/instruction_parse.c \
|
||||
@ -48,9 +53,11 @@ test_libguac_SOURCES = \
|
||||
|
||||
test_libguac_CFLAGS = \
|
||||
-Werror -Wall -pedantic \
|
||||
@COMMON_INCLUDE@ \
|
||||
@LIBGUAC_INCLUDE@
|
||||
|
||||
test_libguac_LDADD = \
|
||||
@COMMON_LTLIB@ \
|
||||
@CUNIT_LIBS@ \
|
||||
@LIBGUAC_LTLIB@
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user