Migrated queue from layer to client, restored GUAC_DEFAULT_LAYER.
This commit is contained in:
parent
820a4b1fff
commit
185d23fb5e
@ -103,6 +103,120 @@ typedef int guac_client_clipboard_handler(guac_client* client, char* copied);
|
||||
*/
|
||||
typedef int guac_client_free_handler(guac_client* client);
|
||||
|
||||
typedef struct guac_client_update guac_client_update;
|
||||
|
||||
/**
|
||||
* The type of a layer update (png, copy, or rect, for
|
||||
* example).
|
||||
*/
|
||||
typedef enum guac_client_update_type_t {
|
||||
|
||||
GUAC_CLIENT_UPDATE_PNG,
|
||||
GUAC_CLIENT_UPDATE_COPY,
|
||||
GUAC_CLIENT_UPDATE_CLIP,
|
||||
GUAC_CLIENT_UPDATE_RECT
|
||||
|
||||
} guac_client_update_type_t;
|
||||
|
||||
/**
|
||||
* Represents an abstract graphical update or state change
|
||||
* of a client, including dirty rectangle information.
|
||||
*/
|
||||
struct guac_client_update {
|
||||
|
||||
/**
|
||||
* The type of this update. Update type corresponds
|
||||
* directly to the instruction that would be sent
|
||||
* if the queue is flushed.
|
||||
*/
|
||||
guac_client_update_type_t type;
|
||||
|
||||
/**
|
||||
* The composite mode to use in this update.
|
||||
*/
|
||||
guac_composite_mode_t mode;
|
||||
|
||||
/**
|
||||
* The layer to retrieve image data from.
|
||||
*/
|
||||
const guac_layer* src_layer;
|
||||
|
||||
/**
|
||||
* The surface to retrieve image data from.
|
||||
*/
|
||||
cairo_surface_t* src_image;
|
||||
|
||||
/**
|
||||
* The red component of the source color.
|
||||
*/
|
||||
int src_red;
|
||||
|
||||
/**
|
||||
* The green component of the source color.
|
||||
*/
|
||||
int src_green;
|
||||
|
||||
/**
|
||||
* The blue component of the source color.
|
||||
*/
|
||||
int src_blue;
|
||||
|
||||
/**
|
||||
* The alpha component of the source color.
|
||||
*/
|
||||
int src_alpha;
|
||||
|
||||
/**
|
||||
* The X coordinage of the upper-left corner of the
|
||||
* source rectangle.
|
||||
*/
|
||||
int src_x;
|
||||
|
||||
/**
|
||||
* The Y coordinage of the upper-left corner of the
|
||||
* source rectangle.
|
||||
*/
|
||||
int src_y;
|
||||
|
||||
/**
|
||||
* The layer this update should affect.
|
||||
*/
|
||||
const guac_layer* dst_layer;
|
||||
|
||||
/**
|
||||
* The X coordinate of the upper-left corner of the
|
||||
* destination rectangle.
|
||||
*/
|
||||
int dst_x;
|
||||
|
||||
/**
|
||||
* The Y coordinate of the upper-left corner of the
|
||||
* destination rectangle.
|
||||
*/
|
||||
int dst_y;
|
||||
|
||||
/**
|
||||
* The width of the destination or source rectangle.
|
||||
* The dimensions of the destination and source
|
||||
* rectangles are always identical.
|
||||
*/
|
||||
int width;
|
||||
|
||||
/**
|
||||
* The height of the destination or source rectangle.
|
||||
* The dimensions of the destination and source
|
||||
* rectangles are always identical.
|
||||
*/
|
||||
int height;
|
||||
|
||||
/**
|
||||
* The next update in the update queue, if any.
|
||||
*/
|
||||
guac_client_update* next;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Possible current states of the Guacamole client. Currently, the only
|
||||
* two states are RUNNING and STOPPING.
|
||||
@ -165,9 +279,14 @@ struct guac_client {
|
||||
guac_layer* all_layers;
|
||||
|
||||
/**
|
||||
* Pointer to a pre-allocated default layer (layer 0)
|
||||
* The first element in this client's update queue.
|
||||
*/
|
||||
guac_layer* default_layer;
|
||||
guac_client_update* update_queue_head;
|
||||
|
||||
/**
|
||||
* The last element in this client's update queue.
|
||||
*/
|
||||
guac_client_update* update_queue_tail;
|
||||
|
||||
/**
|
||||
* The time (in milliseconds) of receipt of the last sync message from
|
||||
@ -378,4 +497,96 @@ guac_layer* guac_client_alloc_layer(guac_client* client, int index);
|
||||
*/
|
||||
void guac_client_free_buffer(guac_client* client, guac_layer* layer);
|
||||
|
||||
/**
|
||||
* Queues a png instruction in the given client. The client may combine
|
||||
* and re-order multiple instructions into more efficient instructions
|
||||
* providing the end result is the same image.
|
||||
*
|
||||
* @param client The proxy client which will queue the instruction.
|
||||
* @param layer The destination layer.
|
||||
* @param mode The composite mode to use.
|
||||
* @param x The destination X coordinate.
|
||||
* @param y The destination Y coordinate.
|
||||
* @param surface A cairo surface containing the image data to send.
|
||||
*/
|
||||
void guac_client_queue_png(guac_client* client, guac_composite_mode_t mode,
|
||||
const guac_layer* layer, int x, int y, cairo_surface_t* surface);
|
||||
|
||||
/**
|
||||
* Queues a copy instruction in a given client. The client may combine
|
||||
* and re-order multiple instructions into more efficient instructions
|
||||
* providing the end result is the same image.
|
||||
*
|
||||
* @param client The proxy client which will queue the instruction.
|
||||
* @param srcl The source layer.
|
||||
* @param srcx The X coordinate of the source rectangle.
|
||||
* @param srcy The Y coordinate of the source rectangle.
|
||||
* @param w The width of the source rectangle.
|
||||
* @param h The height of the source rectangle.
|
||||
* @param mode The composite mode to use.
|
||||
* @param dstl The destination layer.
|
||||
* @param dstx The X coordinate of the destination, where the source rectangle
|
||||
* should be copied.
|
||||
* @param dsty The Y coordinate of the destination, where the source rectangle
|
||||
* should be copied.
|
||||
*/
|
||||
void guac_client_queue_copy(guac_client* client,
|
||||
const guac_layer* srcl, int srcx, int srcy, int w, int h,
|
||||
guac_composite_mode_t mode, const guac_layer* dstl, int dstx, int dsty);
|
||||
|
||||
/**
|
||||
* Queues a clip instruction in a given client. The client may combine
|
||||
* and re-order multiple instructions into more efficient instructions
|
||||
* providing the end result is the same image.
|
||||
*
|
||||
* @param client The proxy client which will queue the instruction.
|
||||
* @param layer The layer to set the clipping region of.
|
||||
* @param x The X coordinate of the clipping rectangle.
|
||||
* @param y The Y coordinate of the clipping rectangle.
|
||||
* @param width The width of the clipping rectangle.
|
||||
* @param height The height of the clipping rectangle.
|
||||
*/
|
||||
void guac_client_queue_clip(guac_client* client, const guac_layer* layer,
|
||||
int x, int y, int width, int height);
|
||||
|
||||
/**
|
||||
* Queues a rect instruction in a given layer. The layer may combine
|
||||
* and re-order multiple instructions into more efficient instructions
|
||||
* providing the end result is the same image.
|
||||
*
|
||||
* @param client The proxy client which will queue the instruction.
|
||||
* @param mode The composite mode to use.
|
||||
* @param layer The destination layer.
|
||||
* @param x The X coordinate of the rectangle.
|
||||
* @param y The Y coordinate of the rectangle.
|
||||
* @param width The width of the rectangle.
|
||||
* @param height The height of the rectangle.
|
||||
* @param r The red component of the color of the rectangle.
|
||||
* @param g The green component of the color of the rectangle.
|
||||
* @param b The blue component of the color of the rectangle.
|
||||
* @param a The alpha (transparency) component of the color of the rectangle.
|
||||
*/
|
||||
void guac_client_queue_rect(guac_client* client,
|
||||
const guac_layer* layer, guac_composite_mode_t mode,
|
||||
int x, int y, int width, int height,
|
||||
int r, int g, int b, int a);
|
||||
|
||||
/**
|
||||
* Flushes any queued instructions in the given client, sending those
|
||||
* instructions over the given GUACIO connection. These instructions
|
||||
* may not be identical to the instructions originally queued; they
|
||||
* may be re-ordered or combined providing the end result of executing
|
||||
* all instructions sent by guac_client_queue_flush() is identical to
|
||||
* executing all previously queued instructions as specified and in order.
|
||||
*
|
||||
* @param client The client to flush.
|
||||
* @return Zero on success, non-zero on error.
|
||||
*/
|
||||
int guac_client_queue_flush(guac_client* client);
|
||||
|
||||
/**
|
||||
* The default Guacamole client layer, layer 0.
|
||||
*/
|
||||
extern const guac_layer* GUAC_DEFAULT_LAYER;
|
||||
|
||||
#endif
|
||||
|
@ -104,121 +104,8 @@ typedef enum guac_composite_mode_t {
|
||||
|
||||
} guac_composite_mode_t;
|
||||
|
||||
typedef struct guac_layer_update guac_layer_update;
|
||||
typedef struct guac_layer guac_layer;
|
||||
|
||||
|
||||
/**
|
||||
* The type of a layer update (png, copy, or rect, for
|
||||
* example).
|
||||
*/
|
||||
typedef enum guac_layer_update_type_t {
|
||||
|
||||
GUAC_LAYER_UPDATE_PNG,
|
||||
GUAC_LAYER_UPDATE_COPY,
|
||||
GUAC_LAYER_UPDATE_CLIP,
|
||||
GUAC_LAYER_UPDATE_RECT
|
||||
|
||||
} guac_layer_update_type_t;
|
||||
|
||||
/**
|
||||
* Represents an abstract graphical update or state change
|
||||
* of a layer, including dirty rectangle information.
|
||||
*/
|
||||
struct guac_layer_update {
|
||||
|
||||
/**
|
||||
* The type of this update. Update type corresponds
|
||||
* directly to the instruction that would be sent
|
||||
* if the queue is flushed.
|
||||
*/
|
||||
guac_layer_update_type_t type;
|
||||
|
||||
/**
|
||||
* The composite mode to use in this update.
|
||||
*/
|
||||
guac_composite_mode_t mode;
|
||||
|
||||
/**
|
||||
* The layer to retrieve image data from.
|
||||
*/
|
||||
const guac_layer* src_layer;
|
||||
|
||||
/**
|
||||
* The surface to retrieve image data from.
|
||||
*/
|
||||
cairo_surface_t* src_image;
|
||||
|
||||
/**
|
||||
* The red component of the source color.
|
||||
*/
|
||||
int src_red;
|
||||
|
||||
/**
|
||||
* The green component of the source color.
|
||||
*/
|
||||
int src_green;
|
||||
|
||||
/**
|
||||
* The blue component of the source color.
|
||||
*/
|
||||
int src_blue;
|
||||
|
||||
/**
|
||||
* The alpha component of the source color.
|
||||
*/
|
||||
int src_alpha;
|
||||
|
||||
/**
|
||||
* The X coordinage of the upper-left corner of the
|
||||
* source rectangle.
|
||||
*/
|
||||
int src_x;
|
||||
|
||||
/**
|
||||
* The Y coordinage of the upper-left corner of the
|
||||
* source rectangle.
|
||||
*/
|
||||
int src_y;
|
||||
|
||||
/**
|
||||
* The layer this update should affect.
|
||||
*/
|
||||
guac_layer* dst_layer;
|
||||
|
||||
/**
|
||||
* The X coordinate of the upper-left corner of the
|
||||
* destination rectangle.
|
||||
*/
|
||||
int dst_x;
|
||||
|
||||
/**
|
||||
* The Y coordinate of the upper-left corner of the
|
||||
* destination rectangle.
|
||||
*/
|
||||
int dst_y;
|
||||
|
||||
/**
|
||||
* The width of the destination or source rectangle.
|
||||
* The dimensions of the destination and source
|
||||
* rectangles are always identical.
|
||||
*/
|
||||
int width;
|
||||
|
||||
/**
|
||||
* The height of the destination or source rectangle.
|
||||
* The dimensions of the destination and source
|
||||
* rectangles are always identical.
|
||||
*/
|
||||
int height;
|
||||
|
||||
/**
|
||||
* The next update in the update queue, if any.
|
||||
*/
|
||||
guac_layer_update* next;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a single layer within the Guacamole protocol.
|
||||
*/
|
||||
@ -240,16 +127,6 @@ struct guac_layer {
|
||||
*/
|
||||
guac_layer* next_available;
|
||||
|
||||
/**
|
||||
* The first element in this layer's update queue.
|
||||
*/
|
||||
guac_layer_update* update_queue_head;
|
||||
|
||||
/**
|
||||
* The last element in this layer's update queue.
|
||||
*/
|
||||
guac_layer_update* update_queue_tail;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -47,6 +47,17 @@
|
||||
#include "client.h"
|
||||
#include "client-handlers.h"
|
||||
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
guac_layer __GUAC_DEFAULT_LAYER = {
|
||||
.index = 0,
|
||||
.next = NULL,
|
||||
.next_available = NULL
|
||||
};
|
||||
|
||||
const guac_layer* GUAC_DEFAULT_LAYER = &__GUAC_DEFAULT_LAYER;
|
||||
|
||||
guac_client* __guac_alloc_client(GUACIO* io) {
|
||||
|
||||
/* Allocate new client (not handoff) */
|
||||
@ -58,13 +69,13 @@ guac_client* __guac_alloc_client(GUACIO* io) {
|
||||
client->last_received_timestamp = client->last_sent_timestamp = guac_current_timestamp();
|
||||
client->state = RUNNING;
|
||||
|
||||
client->all_layers = NULL;
|
||||
client->all_layers = NULL;
|
||||
client->available_buffers = NULL;
|
||||
|
||||
client->next_buffer_index = -1;
|
||||
client->update_queue_head = NULL;
|
||||
client->update_queue_tail = NULL;
|
||||
|
||||
/* Allocate default layer */
|
||||
client->default_layer = guac_client_alloc_layer(client, 0);
|
||||
client->next_buffer_index = -1;
|
||||
|
||||
return client;
|
||||
}
|
||||
@ -75,8 +86,6 @@ guac_layer* guac_client_alloc_layer(guac_client* client, int index) {
|
||||
|
||||
/* Init new layer */
|
||||
allocd_layer = malloc(sizeof(guac_layer));
|
||||
allocd_layer->update_queue_head = NULL;
|
||||
allocd_layer->update_queue_tail = NULL;
|
||||
|
||||
/* Add to all_layers list */
|
||||
allocd_layer->next = client->all_layers;
|
||||
@ -104,8 +113,6 @@ guac_layer* guac_client_alloc_buffer(guac_client* client) {
|
||||
/* Init new layer */
|
||||
allocd_layer = malloc(sizeof(guac_layer));
|
||||
allocd_layer->index = client->next_buffer_index--;
|
||||
allocd_layer->update_queue_head = NULL;
|
||||
allocd_layer->update_queue_tail = NULL;
|
||||
|
||||
/* Add to all_layers list */
|
||||
allocd_layer->next = client->all_layers;
|
||||
@ -123,21 +130,6 @@ void guac_client_free_buffer(guac_client* client, guac_layer* layer) {
|
||||
layer->next_available = client->available_buffers;
|
||||
client->available_buffers = layer;
|
||||
|
||||
/* Free all queued updates */
|
||||
while (layer->update_queue_head != NULL) {
|
||||
|
||||
/* Get unflushed update, update queue head */
|
||||
guac_layer_update* unflushed_update = layer->update_queue_head;
|
||||
layer->update_queue_head = unflushed_update->next;
|
||||
|
||||
/* Free update */
|
||||
free(unflushed_update);
|
||||
|
||||
}
|
||||
|
||||
/* Queue is now empty */
|
||||
layer->update_queue_tail = NULL;
|
||||
|
||||
}
|
||||
|
||||
guac_client* guac_get_client(int client_fd) {
|
||||
@ -339,23 +331,23 @@ void guac_free_client(guac_client* client) {
|
||||
guac_layer* layer = client->all_layers;
|
||||
client->all_layers = layer->next;
|
||||
|
||||
/* Free all queued updates */
|
||||
while (layer->update_queue_head != NULL) {
|
||||
|
||||
/* Get unflushed update, update queue head */
|
||||
guac_layer_update* unflushed_update = layer->update_queue_head;
|
||||
layer->update_queue_head = unflushed_update->next;
|
||||
|
||||
/* Free update */
|
||||
free(unflushed_update);
|
||||
|
||||
}
|
||||
|
||||
/* Free layer */
|
||||
free(layer);
|
||||
|
||||
}
|
||||
|
||||
/* Free all queued updates */
|
||||
while (client->update_queue_head != NULL) {
|
||||
|
||||
/* Get unflushed update, update queue head */
|
||||
guac_client_update* unflushed_update = client->update_queue_head;
|
||||
client->update_queue_head = unflushed_update->next;
|
||||
|
||||
/* Free update */
|
||||
free(unflushed_update);
|
||||
|
||||
}
|
||||
|
||||
free(client);
|
||||
}
|
||||
|
||||
@ -506,3 +498,332 @@ int guac_client_handle_instruction(guac_client* client, guac_instruction* instru
|
||||
|
||||
}
|
||||
|
||||
void __guac_client_queue_add_update(guac_client* client, guac_client_update* update) {
|
||||
|
||||
/* Add update to queue tail */
|
||||
if (client->update_queue_tail != NULL)
|
||||
client->update_queue_tail = client->update_queue_tail->next = update;
|
||||
|
||||
/* Set both head and tail if necessary */
|
||||
else
|
||||
client->update_queue_tail = client->update_queue_head = update;
|
||||
|
||||
update->next = NULL;
|
||||
|
||||
}
|
||||
|
||||
void guac_client_queue_png(guac_client* client, guac_composite_mode_t mode,
|
||||
const guac_layer* layer, int x, int y, cairo_surface_t* surface) {
|
||||
|
||||
/* Allocate update */
|
||||
guac_client_update* update = (guac_client_update*) malloc(sizeof(guac_client_update));
|
||||
|
||||
/* Set parameters of update */
|
||||
update->type = GUAC_CLIENT_UPDATE_PNG;
|
||||
update->mode = mode;
|
||||
update->src_image = surface;
|
||||
update->dst_layer = layer;
|
||||
update->dst_x = x;
|
||||
update->dst_y = y;
|
||||
update->width = cairo_image_surface_get_width(surface);
|
||||
update->height = cairo_image_surface_get_height(surface);
|
||||
|
||||
/* Add to client queue */
|
||||
__guac_client_queue_add_update(client, update);
|
||||
|
||||
}
|
||||
|
||||
void guac_client_queue_copy(guac_client* client,
|
||||
const guac_layer* srcl, int srcx, int srcy, int w, int h,
|
||||
guac_composite_mode_t mode, const guac_layer* dstl, int dstx, int dsty) {
|
||||
|
||||
/* Allocate update */
|
||||
guac_client_update* update = (guac_client_update*) malloc(sizeof(guac_client_update));
|
||||
|
||||
/* Set parameters of update */
|
||||
update->type = GUAC_CLIENT_UPDATE_COPY;
|
||||
update->mode = mode;
|
||||
update->src_layer = srcl;
|
||||
update->src_x = srcx;
|
||||
update->src_y = srcy;
|
||||
update->width = w;
|
||||
update->height = h;
|
||||
update->dst_layer = dstl;
|
||||
update->dst_x = dstx;
|
||||
update->dst_y = dsty;
|
||||
|
||||
/* Add to client queue */
|
||||
__guac_client_queue_add_update(client, update);
|
||||
|
||||
}
|
||||
|
||||
void guac_client_queue_clip(guac_client* client, const guac_layer* layer,
|
||||
int x, int y, int width, int height) {
|
||||
|
||||
/* Allocate update */
|
||||
guac_client_update* update = (guac_client_update*) malloc(sizeof(guac_client_update));
|
||||
|
||||
/* Set parameters of update */
|
||||
update->type = GUAC_CLIENT_UPDATE_CLIP;
|
||||
update->dst_x = x;
|
||||
update->dst_y = y;
|
||||
update->width = width;
|
||||
update->height = height;
|
||||
|
||||
/* Add to client queue */
|
||||
__guac_client_queue_add_update(client, update);
|
||||
|
||||
}
|
||||
|
||||
void guac_client_queue_rect(guac_client* client,
|
||||
const guac_layer* layer, guac_composite_mode_t mode,
|
||||
int x, int y, int width, int height,
|
||||
int r, int g, int b, int a) {
|
||||
|
||||
/* Allocate update */
|
||||
guac_client_update* update = (guac_client_update*) malloc(sizeof(guac_client_update));
|
||||
|
||||
/* Set parameters of update */
|
||||
update->type = GUAC_CLIENT_UPDATE_RECT;
|
||||
update->mode = mode;
|
||||
update->src_red = r;
|
||||
update->src_green = g;
|
||||
update->src_blue = b;
|
||||
update->src_alpha = a;
|
||||
update->dst_x = x;
|
||||
update->dst_y = y;
|
||||
update->width = width;
|
||||
update->height = height;
|
||||
|
||||
/* Add to client queue */
|
||||
__guac_client_queue_add_update(client, update);
|
||||
|
||||
}
|
||||
|
||||
int __guac_client_update_intersects(
|
||||
const guac_client_update* update1, const guac_client_update* update2) {
|
||||
|
||||
/* If update1 X is within width of update2
|
||||
or update2 X is within width of update1 */
|
||||
if ((update1->dst_x >= update2->dst_x && update1->dst_x < update2->dst_x + update2->width)
|
||||
|| (update2->dst_x >= update1->dst_x && update2->dst_x < update1->dst_x + update2->width)) {
|
||||
|
||||
/* If update1 Y is within height of update2
|
||||
or update2 Y is within height of update1 */
|
||||
if ((update1->dst_y >= update2->dst_y && update1->dst_y < update2->dst_y + update2->height)
|
||||
|| (update2->dst_y >= update1->dst_y && update2->dst_y < update1->dst_y + update2->height)) {
|
||||
|
||||
/* Register instersection */
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Otherwise, no intersection */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_client_queue_flush(guac_client* client) {
|
||||
|
||||
GUACIO* io = client->io;
|
||||
|
||||
while (client->update_queue_head != NULL) {
|
||||
|
||||
guac_client_update* later_update;
|
||||
int update_merged = 0;
|
||||
|
||||
/* Get next update, update queue head. */
|
||||
guac_client_update* update = client->update_queue_head;
|
||||
client->update_queue_head = update->next;
|
||||
|
||||
/* Send instruction appropriate for update type */
|
||||
switch (update->type) {
|
||||
|
||||
/* "png" instruction */
|
||||
case GUAC_CLIENT_UPDATE_PNG:
|
||||
|
||||
/* Decide whether or not to send */
|
||||
later_update = update->next;
|
||||
while (later_update != NULL) {
|
||||
|
||||
/* If destination rectangles intersect */
|
||||
if (__guac_client_update_intersects(update, later_update)) {
|
||||
|
||||
cairo_surface_t* merged_surface;
|
||||
cairo_t* cairo;
|
||||
int merged_x, merged_y, merged_width, merged_height;
|
||||
|
||||
/* Cannot combine anything if intersection with non-PNG */
|
||||
if (later_update->type != GUAC_CLIENT_UPDATE_PNG)
|
||||
break;
|
||||
|
||||
/* Cannot combine if modes differ */
|
||||
if (later_update->mode != update->mode)
|
||||
break;
|
||||
|
||||
/* For now, only combine for GUAC_COMP_OVER */
|
||||
if (later_update->mode != GUAC_COMP_OVER)
|
||||
break;
|
||||
|
||||
/* Calculate merged dimensions */
|
||||
merged_x = MIN(update->dst_x, later_update->dst_x);
|
||||
merged_y = MIN(update->dst_y, later_update->dst_y);
|
||||
|
||||
merged_width = MAX(
|
||||
update->dst_x + update->width,
|
||||
later_update->dst_x + later_update->width
|
||||
) - merged_x;
|
||||
|
||||
merged_height = MAX(
|
||||
update->dst_y + update->height,
|
||||
later_update->dst_y + later_update->height
|
||||
) - merged_y;
|
||||
|
||||
/* Create surface for merging */
|
||||
merged_surface = cairo_image_surface_create(
|
||||
CAIRO_FORMAT_ARGB32, merged_width, merged_height);
|
||||
|
||||
/* Get drawing context */
|
||||
cairo = cairo_create(merged_surface);
|
||||
|
||||
/* Draw first update within merged surface */
|
||||
cairo_set_source_surface(cairo,
|
||||
update->src_image,
|
||||
update->dst_x - merged_x,
|
||||
update->dst_y - merged_y);
|
||||
|
||||
cairo_rectangle(cairo,
|
||||
update->dst_x - merged_x,
|
||||
update->dst_y - merged_y,
|
||||
update->width,
|
||||
update->height);
|
||||
|
||||
cairo_fill(cairo);
|
||||
|
||||
/* Draw second update within merged surface */
|
||||
cairo_set_source_surface(cairo,
|
||||
later_update->src_image,
|
||||
later_update->dst_x - merged_x,
|
||||
later_update->dst_y - merged_y);
|
||||
|
||||
cairo_rectangle(cairo,
|
||||
later_update->dst_x - merged_x,
|
||||
later_update->dst_y - merged_y,
|
||||
later_update->width,
|
||||
later_update->height);
|
||||
|
||||
cairo_fill(cairo);
|
||||
|
||||
/* Done drawing */
|
||||
cairo_destroy(cairo);
|
||||
|
||||
/* Alter update dimensions */
|
||||
later_update->dst_x = merged_x;
|
||||
later_update->dst_y = merged_y;
|
||||
later_update->width = merged_width;
|
||||
later_update->height = merged_height;
|
||||
|
||||
/* Alter update to include merged data*/
|
||||
cairo_surface_destroy(later_update->src_image);
|
||||
later_update->src_image = merged_surface;
|
||||
|
||||
update_merged = 1;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* Get next update */
|
||||
later_update = later_update->next;
|
||||
|
||||
}
|
||||
|
||||
/* Send instruction if update was not merged */
|
||||
if (!update_merged) {
|
||||
if (guac_send_png(io,
|
||||
update->mode,
|
||||
update->dst_layer,
|
||||
update->dst_x,
|
||||
update->dst_y,
|
||||
update->src_image
|
||||
)) {
|
||||
cairo_surface_destroy(update->src_image);
|
||||
free(update);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
cairo_surface_destroy(update->src_image);
|
||||
break;
|
||||
|
||||
/* "copy" instruction */
|
||||
case GUAC_CLIENT_UPDATE_COPY:
|
||||
|
||||
if (guac_send_copy(io,
|
||||
update->src_layer,
|
||||
update->src_x,
|
||||
update->src_y,
|
||||
update->width,
|
||||
update->height,
|
||||
update->mode,
|
||||
update->dst_layer,
|
||||
update->dst_x,
|
||||
update->dst_y
|
||||
)) {
|
||||
free(update);
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* "clip" instruction */
|
||||
case GUAC_CLIENT_UPDATE_CLIP:
|
||||
|
||||
if (guac_send_clip(io,
|
||||
update->dst_layer,
|
||||
update->dst_x,
|
||||
update->dst_y,
|
||||
update->width,
|
||||
update->height
|
||||
)) {
|
||||
free(update);
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* "rect" instruction */
|
||||
case GUAC_CLIENT_UPDATE_RECT:
|
||||
|
||||
if (guac_send_rect(io,
|
||||
update->mode,
|
||||
update->dst_layer,
|
||||
update->dst_x,
|
||||
update->dst_y,
|
||||
update->width,
|
||||
update->height,
|
||||
update->src_red,
|
||||
update->src_green,
|
||||
update->src_blue,
|
||||
update->src_alpha
|
||||
)) {
|
||||
free(update);
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
} /* end of switch update type */
|
||||
|
||||
/* Free update */
|
||||
free(update);
|
||||
|
||||
}
|
||||
|
||||
/* Queue is now empty */
|
||||
client->update_queue_tail = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -63,9 +63,6 @@
|
||||
#include "guacio.h"
|
||||
#include "protocol.h"
|
||||
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
ssize_t __guac_write_length_string(GUACIO* io, const char* str) {
|
||||
|
||||
return
|
||||
@ -521,329 +518,3 @@ void guac_sleep(int millis) {
|
||||
|
||||
}
|
||||
|
||||
void __guac_layer_add_update(guac_layer* layer, guac_layer_update* update) {
|
||||
|
||||
/* Add update to queue tail */
|
||||
if (layer->update_queue_tail != NULL)
|
||||
layer->update_queue_tail = layer->update_queue_tail->next = update;
|
||||
|
||||
/* Set both head and tail if necessary */
|
||||
else
|
||||
layer->update_queue_tail = layer->update_queue_head = update;
|
||||
|
||||
update->next = NULL;
|
||||
|
||||
}
|
||||
|
||||
void guac_layer_png(guac_layer* layer, guac_composite_mode_t mode,
|
||||
int x, int y, cairo_surface_t* surface) {
|
||||
|
||||
/* Allocate update */
|
||||
guac_layer_update* update = (guac_layer_update*) malloc(sizeof(guac_layer_update));
|
||||
|
||||
/* Set parameters of update */
|
||||
update->type = GUAC_LAYER_UPDATE_PNG;
|
||||
update->mode = mode;
|
||||
update->src_image = surface;
|
||||
update->dst_layer = layer;
|
||||
update->dst_x = x;
|
||||
update->dst_y = y;
|
||||
update->width = cairo_image_surface_get_width(surface);
|
||||
update->height = cairo_image_surface_get_height(surface);
|
||||
|
||||
/* Add to layer queue */
|
||||
__guac_layer_add_update(layer, update);
|
||||
|
||||
}
|
||||
|
||||
void guac_layer_copy(guac_layer* layer, guac_composite_mode_t mode,
|
||||
const guac_layer* srcl, int srcx, int srcy, int w, int h,
|
||||
int dstx, int dsty) {
|
||||
|
||||
/* Allocate update */
|
||||
guac_layer_update* update = (guac_layer_update*) malloc(sizeof(guac_layer_update));
|
||||
|
||||
/* Set parameters of update */
|
||||
update->type = GUAC_LAYER_UPDATE_COPY;
|
||||
update->mode = mode;
|
||||
update->src_layer = srcl;
|
||||
update->src_x = srcx;
|
||||
update->src_y = srcy;
|
||||
update->width = w;
|
||||
update->height = h;
|
||||
update->dst_layer = layer;
|
||||
update->dst_x = dstx;
|
||||
update->dst_y = dsty;
|
||||
|
||||
/* Add to layer queue */
|
||||
__guac_layer_add_update(layer, update);
|
||||
|
||||
}
|
||||
|
||||
void guac_layer_clip(guac_layer* layer,
|
||||
int x, int y, int width, int height) {
|
||||
|
||||
/* Allocate update */
|
||||
guac_layer_update* update = (guac_layer_update*) malloc(sizeof(guac_layer_update));
|
||||
|
||||
/* Set parameters of update */
|
||||
update->type = GUAC_LAYER_UPDATE_CLIP;
|
||||
update->dst_x = x;
|
||||
update->dst_y = y;
|
||||
update->width = width;
|
||||
update->height = height;
|
||||
|
||||
/* Add to layer queue */
|
||||
__guac_layer_add_update(layer, update);
|
||||
|
||||
}
|
||||
|
||||
void guac_layer_rect(guac_layer* layer, guac_composite_mode_t mode,
|
||||
int x, int y, int width, int height,
|
||||
int r, int g, int b, int a) {
|
||||
|
||||
/* Allocate update */
|
||||
guac_layer_update* update = (guac_layer_update*) malloc(sizeof(guac_layer_update));
|
||||
|
||||
/* Set parameters of update */
|
||||
update->type = GUAC_LAYER_UPDATE_RECT;
|
||||
update->mode = mode;
|
||||
update->src_red = r;
|
||||
update->src_green = g;
|
||||
update->src_blue = b;
|
||||
update->src_alpha = a;
|
||||
update->dst_x = x;
|
||||
update->dst_y = y;
|
||||
update->width = width;
|
||||
update->height = height;
|
||||
|
||||
/* Add to layer queue */
|
||||
__guac_layer_add_update(layer, update);
|
||||
|
||||
}
|
||||
|
||||
int __guac_layer_update_intersects(
|
||||
const guac_layer_update* update1, const guac_layer_update* update2) {
|
||||
|
||||
/* If update1 X is within width of update2
|
||||
or update2 X is within width of update1 */
|
||||
if ((update1->dst_x >= update2->dst_x && update1->dst_x < update2->dst_x + update2->width)
|
||||
|| (update2->dst_x >= update1->dst_x && update2->dst_x < update1->dst_x + update2->width)) {
|
||||
|
||||
/* If update1 Y is within height of update2
|
||||
or update2 Y is within height of update1 */
|
||||
if ((update1->dst_y >= update2->dst_y && update1->dst_y < update2->dst_y + update2->height)
|
||||
|| (update2->dst_y >= update1->dst_y && update2->dst_y < update1->dst_y + update2->height)) {
|
||||
|
||||
/* Register instersection */
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Otherwise, no intersection */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_layer_flush(guac_layer* layer, GUACIO* io) {
|
||||
|
||||
while (layer->update_queue_head != NULL) {
|
||||
|
||||
guac_layer_update* later_update;
|
||||
int update_merged = 0;
|
||||
|
||||
/* Get next update, update queue head. */
|
||||
guac_layer_update* update = layer->update_queue_head;
|
||||
layer->update_queue_head = update->next;
|
||||
|
||||
/* Send instruction appropriate for update type */
|
||||
switch (update->type) {
|
||||
|
||||
/* "png" instruction */
|
||||
case GUAC_LAYER_UPDATE_PNG:
|
||||
|
||||
/* Decide whether or not to send */
|
||||
later_update = update->next;
|
||||
while (later_update != NULL) {
|
||||
|
||||
/* If destination rectangles intersect */
|
||||
if (__guac_layer_update_intersects(update, later_update)) {
|
||||
|
||||
cairo_surface_t* merged_surface;
|
||||
cairo_t* cairo;
|
||||
int merged_x, merged_y, merged_width, merged_height;
|
||||
|
||||
/* Cannot combine anything if intersection with non-PNG */
|
||||
if (later_update->type != GUAC_LAYER_UPDATE_PNG)
|
||||
break;
|
||||
|
||||
/* Cannot combine if modes differ */
|
||||
if (later_update->mode != update->mode)
|
||||
break;
|
||||
|
||||
/* For now, only combine for GUAC_COMP_OVER */
|
||||
if (later_update->mode != GUAC_COMP_OVER)
|
||||
break;
|
||||
|
||||
/* Calculate merged dimensions */
|
||||
merged_x = MIN(update->dst_x, later_update->dst_x);
|
||||
merged_y = MIN(update->dst_y, later_update->dst_y);
|
||||
|
||||
merged_width = MAX(
|
||||
update->dst_x + update->width,
|
||||
later_update->dst_x + later_update->width
|
||||
) - merged_x;
|
||||
|
||||
merged_height = MAX(
|
||||
update->dst_y + update->height,
|
||||
later_update->dst_y + later_update->height
|
||||
) - merged_y;
|
||||
|
||||
/* Create surface for merging */
|
||||
merged_surface = cairo_image_surface_create(
|
||||
CAIRO_FORMAT_ARGB32, merged_width, merged_height);
|
||||
|
||||
/* Get drawing context */
|
||||
cairo = cairo_create(merged_surface);
|
||||
|
||||
/* Draw first update within merged surface */
|
||||
cairo_set_source_surface(cairo,
|
||||
update->src_image,
|
||||
update->dst_x - merged_x,
|
||||
update->dst_y - merged_y);
|
||||
|
||||
cairo_rectangle(cairo,
|
||||
update->dst_x - merged_x,
|
||||
update->dst_y - merged_y,
|
||||
update->width,
|
||||
update->height);
|
||||
|
||||
cairo_fill(cairo);
|
||||
|
||||
/* Draw second update within merged surface */
|
||||
cairo_set_source_surface(cairo,
|
||||
later_update->src_image,
|
||||
later_update->dst_x - merged_x,
|
||||
later_update->dst_y - merged_y);
|
||||
|
||||
cairo_rectangle(cairo,
|
||||
later_update->dst_x - merged_x,
|
||||
later_update->dst_y - merged_y,
|
||||
later_update->width,
|
||||
later_update->height);
|
||||
|
||||
cairo_fill(cairo);
|
||||
|
||||
/* Done drawing */
|
||||
cairo_destroy(cairo);
|
||||
|
||||
/* Alter update dimensions */
|
||||
later_update->dst_x = merged_x;
|
||||
later_update->dst_y = merged_y;
|
||||
later_update->width = merged_width;
|
||||
later_update->height = merged_height;
|
||||
|
||||
/* Alter update to include merged data*/
|
||||
cairo_surface_destroy(later_update->src_image);
|
||||
later_update->src_image = merged_surface;
|
||||
|
||||
update_merged = 1;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* Get next update */
|
||||
later_update = later_update->next;
|
||||
|
||||
}
|
||||
|
||||
/* Send instruction if update was not merged */
|
||||
if (!update_merged) {
|
||||
if (guac_send_png(io,
|
||||
update->mode,
|
||||
update->dst_layer,
|
||||
update->dst_x,
|
||||
update->dst_y,
|
||||
update->src_image
|
||||
)) {
|
||||
cairo_surface_destroy(update->src_image);
|
||||
free(update);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
cairo_surface_destroy(update->src_image);
|
||||
break;
|
||||
|
||||
/* "copy" instruction */
|
||||
case GUAC_LAYER_UPDATE_COPY:
|
||||
|
||||
if (guac_send_copy(io,
|
||||
update->src_layer,
|
||||
update->src_x,
|
||||
update->src_y,
|
||||
update->width,
|
||||
update->height,
|
||||
update->mode,
|
||||
update->dst_layer,
|
||||
update->dst_x,
|
||||
update->dst_y
|
||||
)) {
|
||||
free(update);
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* "clip" instruction */
|
||||
case GUAC_LAYER_UPDATE_CLIP:
|
||||
|
||||
if (guac_send_clip(io,
|
||||
update->dst_layer,
|
||||
update->dst_x,
|
||||
update->dst_y,
|
||||
update->width,
|
||||
update->height
|
||||
)) {
|
||||
free(update);
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* "rect" instruction */
|
||||
case GUAC_LAYER_UPDATE_RECT:
|
||||
|
||||
if (guac_send_rect(io,
|
||||
update->mode,
|
||||
update->dst_layer,
|
||||
update->dst_x,
|
||||
update->dst_y,
|
||||
update->width,
|
||||
update->height,
|
||||
update->src_red,
|
||||
update->src_green,
|
||||
update->src_blue,
|
||||
update->src_alpha
|
||||
)) {
|
||||
free(update);
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
} /* end of switch update type */
|
||||
|
||||
/* Free update */
|
||||
free(update);
|
||||
|
||||
}
|
||||
|
||||
/* Queue is now empty */
|
||||
layer->update_queue_tail = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user