cscg24-guacamole

CSCG 2024 Challenge 'Guacamole Mashup'
git clone https://git.sinitax.com/sinitax/cscg24-guacamole
Log | Files | Refs | sfeed.txt

display.c (11753B)


      1/*
      2 * Licensed to the Apache Software Foundation (ASF) under one
      3 * or more contributor license agreements.  See the NOTICE file
      4 * distributed with this work for additional information
      5 * regarding copyright ownership.  The ASF licenses this file
      6 * to you under the Apache License, Version 2.0 (the
      7 * "License"); you may not use this file except in compliance
      8 * with the License.  You may obtain a copy of the License at
      9 *
     10 *   http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing,
     13 * software distributed under the License is distributed on an
     14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     15 * KIND, either express or implied.  See the License for the
     16 * specific language governing permissions and limitations
     17 * under the License.
     18 */
     19
     20#include "common/cursor.h"
     21#include "common/display.h"
     22#include "common/surface.h"
     23
     24#include <guacamole/client.h>
     25#include <guacamole/mem.h>
     26#include <guacamole/socket.h>
     27
     28#include <pthread.h>
     29#include <stdlib.h>
     30#include <string.h>
     31
     32/**
     33 * Synchronizes all surfaces within the given linked list to the given socket.
     34 * If the provided pointer to the linked list is NULL, this function has no
     35 * effect.
     36 *
     37 * @param layers
     38 *     The head element of the linked list of layers to synchronize, which may
     39 *     be NULL if the list is currently empty.
     40 *
     41 * @param client
     42 *     The client associated with the users receiving the layers.
     43 *
     44 * @param socket
     45 *     The socket over which each layer should be sent.
     46 */
     47static void guac_common_display_dup_layers(guac_common_display_layer* layers,
     48        guac_client* client, guac_socket* socket) {
     49
     50    guac_common_display_layer* current = layers;
     51
     52    /* Synchronize all surfaces in given list */
     53    while (current != NULL) {
     54        guac_common_surface_dup(current->surface, client, socket);
     55        current = current->next;
     56    }
     57
     58}
     59
     60/**
     61 * Frees all layers and associated surfaces within the given list, as well as
     62 * their corresponding list elements. If the provided pointer to the linked
     63 * list is NULL, this function has no effect.
     64 *
     65 * @param layers
     66 *     The head element of the linked list of layers to free, which may be NULL
     67 *     if the list is currently empty.
     68 *
     69 * @param client
     70 *     The client owning the layers wrapped by each of the layers in the list.
     71 */
     72static void guac_common_display_free_layers(guac_common_display_layer* layers,
     73        guac_client* client) {
     74
     75    guac_common_display_layer* current = layers;
     76
     77    /* Free each surface in given list */
     78    while (current != NULL) {
     79
     80        guac_common_display_layer* next = current->next;
     81        guac_layer* layer = current->layer;
     82
     83        /* Free surface */
     84        guac_common_surface_free(current->surface);
     85
     86        /* Destroy layer within remotely-connected client */
     87        guac_protocol_send_dispose(client->socket, layer);
     88
     89        /* Free layer or buffer depending on index */
     90        if (layer->index < 0)
     91            guac_client_free_buffer(client, layer);
     92        else if (layer->index > 0)
     93            guac_client_free_layer(client, layer);
     94
     95        /* Free current element and advance to next */
     96        guac_mem_free(current);
     97        current = next;
     98
     99    }
    100
    101}
    102
    103/**
    104 * Allocates a display and a cursor which are used to represent the remote
    105 * display and cursor.
    106 *
    107 * @param client
    108 *     The client owning the cursor.
    109 *
    110 * @param width
    111 *     The desired width of the display.
    112 *
    113 * @param height
    114 *     The desired height of the display.
    115 *
    116 * @return
    117 *     The newly-allocated display or NULL if display cannot be allocated.
    118 */
    119guac_common_display* guac_common_display_alloc(guac_client* client,
    120        int width, int height) {
    121
    122    /* Allocate display */
    123    guac_common_display* display = guac_mem_alloc(sizeof(guac_common_display));
    124    if (display == NULL)
    125        return NULL;
    126
    127    /* Allocate shared cursor */
    128    display->cursor = guac_common_cursor_alloc(client);
    129    if (display->cursor == NULL) {
    130        guac_mem_free(display);
    131        return NULL;
    132    }
    133
    134    pthread_mutex_init(&display->_lock, NULL);
    135
    136    /* Associate display with given client */
    137    display->client = client;
    138
    139    display->default_surface = guac_common_surface_alloc(client,
    140            client->socket, GUAC_DEFAULT_LAYER, width, height);
    141
    142    /* No initial layers or buffers */
    143    display->layers = NULL;
    144    display->buffers = NULL;
    145
    146    return display;
    147
    148}
    149
    150void guac_common_display_free(guac_common_display* display) {
    151
    152    /* Free shared cursor */
    153    guac_common_cursor_free(display->cursor);
    154
    155    /* Free default surface */
    156    guac_common_surface_free(display->default_surface);
    157
    158    /* Free all layers and buffers */
    159    guac_common_display_free_layers(display->buffers, display->client);
    160    guac_common_display_free_layers(display->layers, display->client);
    161
    162    pthread_mutex_destroy(&display->_lock);
    163    guac_mem_free(display);
    164
    165}
    166
    167void guac_common_display_dup(
    168        guac_common_display* display, guac_client* client,
    169        guac_socket* socket) {
    170
    171    pthread_mutex_lock(&display->_lock);
    172
    173    /* Sunchronize shared cursor */
    174    guac_common_cursor_dup(display->cursor, client, socket);
    175
    176    /* Synchronize default surface */
    177    guac_common_surface_dup(display->default_surface, client, socket);
    178
    179    /* Synchronize all layers and buffers */
    180    guac_common_display_dup_layers(display->layers, client, socket);
    181    guac_common_display_dup_layers(display->buffers, client, socket);
    182
    183    pthread_mutex_unlock(&display->_lock);
    184
    185}
    186
    187void guac_common_display_set_lossless(guac_common_display* display,
    188        int lossless) {
    189
    190    pthread_mutex_lock(&display->_lock);
    191
    192    /* Update lossless setting to be applied to all newly-allocated
    193     * layers/buffers */
    194    display->lossless = lossless;
    195
    196    /* Update losslessness of all allocated layers/buffers */
    197    guac_common_display_layer* current = display->layers;
    198    while (current != NULL) {
    199        guac_common_surface_set_lossless(current->surface, lossless);
    200        current = current->next;
    201    }
    202
    203    /* Update losslessness of default display layer (not included within layers
    204     * list) */
    205    guac_common_surface_set_lossless(display->default_surface, lossless);
    206
    207    pthread_mutex_unlock(&display->_lock);
    208
    209}
    210
    211void guac_common_display_flush(guac_common_display* display) {
    212
    213    pthread_mutex_lock(&display->_lock);
    214
    215    guac_common_display_layer* current = display->layers;
    216
    217    /* Flush all surfaces */
    218    while (current != NULL) {
    219        guac_common_surface_flush(current->surface);
    220        current = current->next;
    221    }
    222
    223    guac_common_surface_flush(display->default_surface);
    224
    225    pthread_mutex_unlock(&display->_lock);
    226
    227}
    228
    229/**
    230 * Allocates and inserts a new element into the given linked list of display
    231 * layers, associating it with the given layer and surface.
    232 *
    233 * @param head
    234 *     A pointer to the head pointer of the list of layers. The head pointer
    235 *     will be updated by this function to point to the newly-allocated
    236 *     display layer.
    237 *
    238 * @param layer
    239 *     The Guacamole layer to associated with the new display layer.
    240 *
    241 * @param surface
    242 *     The surface associated with the given Guacamole layer and which should
    243 *     be associated with the new display layer.
    244 *
    245 * @return
    246 *     The newly-allocated display layer, which has been associated with the
    247 *     provided layer and surface.
    248 */
    249static guac_common_display_layer* guac_common_display_add_layer(
    250        guac_common_display_layer** head, guac_layer* layer,
    251        guac_common_surface* surface) {
    252
    253    guac_common_display_layer* old_head = *head;
    254
    255    guac_common_display_layer* display_layer =
    256        guac_mem_alloc(sizeof(guac_common_display_layer));
    257
    258    /* Init layer/surface pair */
    259    display_layer->layer = layer;
    260    display_layer->surface = surface;
    261
    262    /* Insert list element as the new head */
    263    display_layer->prev = NULL;
    264    display_layer->next = old_head;
    265    *head = display_layer;
    266
    267    /* Update old head to point to new element, if it existed */
    268    if (old_head != NULL)
    269        old_head->prev = display_layer;
    270
    271    return display_layer;
    272
    273}
    274
    275/**
    276 * Removes the given display layer from the linked list whose head pointer is
    277 * provided.
    278 *
    279 * @param head
    280 *     A pointer to the head pointer of the list of layers. The head pointer
    281 *     will be updated by this function if necessary, and will be set to NULL
    282 *     if the display layer being removed is the only layer in the list.
    283 *
    284 * @param display_layer
    285 *     The display layer to remove from the given list.
    286 */
    287static void guac_common_display_remove_layer(guac_common_display_layer** head,
    288        guac_common_display_layer* display_layer) {
    289
    290    /* Update previous element, if it exists */
    291    if (display_layer->prev != NULL)
    292        display_layer->prev->next = display_layer->next;
    293
    294    /* If there is no previous element, update the list head */
    295    else
    296        *head = display_layer->next;
    297
    298    /* Update next element, if it exists */
    299    if (display_layer->next != NULL)
    300        display_layer->next->prev = display_layer->prev;
    301
    302}
    303
    304guac_common_display_layer* guac_common_display_alloc_layer(
    305        guac_common_display* display, int width, int height) {
    306
    307    pthread_mutex_lock(&display->_lock);
    308
    309    /* Allocate Guacamole layer */
    310    guac_layer* layer = guac_client_alloc_layer(display->client);
    311
    312    /* Allocate corresponding surface */
    313    guac_common_surface* surface = guac_common_surface_alloc(display->client,
    314            display->client->socket, layer, width, height);
    315
    316    /* Apply current display losslessness */
    317    guac_common_surface_set_lossless(surface, display->lossless);
    318
    319    /* Add layer and surface to list */
    320    guac_common_display_layer* display_layer =
    321        guac_common_display_add_layer(&display->layers, layer, surface);
    322
    323    pthread_mutex_unlock(&display->_lock);
    324    return display_layer;
    325
    326}
    327
    328guac_common_display_layer* guac_common_display_alloc_buffer(
    329        guac_common_display* display, int width, int height) {
    330
    331    pthread_mutex_lock(&display->_lock);
    332
    333    /* Allocate Guacamole buffer */
    334    guac_layer* buffer = guac_client_alloc_buffer(display->client);
    335
    336    /* Allocate corresponding surface */
    337    guac_common_surface* surface = guac_common_surface_alloc(display->client,
    338            display->client->socket, buffer, width, height);
    339
    340    /* Apply current display losslessness */
    341    guac_common_surface_set_lossless(surface, display->lossless);
    342
    343    /* Add buffer and surface to list */
    344    guac_common_display_layer* display_layer =
    345        guac_common_display_add_layer(&display->buffers, buffer, surface);
    346
    347    pthread_mutex_unlock(&display->_lock);
    348    return display_layer;
    349
    350}
    351
    352void guac_common_display_free_layer(guac_common_display* display,
    353        guac_common_display_layer* display_layer) {
    354
    355    pthread_mutex_lock(&display->_lock);
    356
    357    /* Remove list element from list */
    358    guac_common_display_remove_layer(&display->layers, display_layer);
    359
    360    /* Free associated layer and surface */
    361    guac_common_surface_free(display_layer->surface);
    362    guac_client_free_layer(display->client, display_layer->layer);
    363
    364    /* Free list element */
    365    guac_mem_free(display_layer);
    366
    367    pthread_mutex_unlock(&display->_lock);
    368
    369}
    370
    371void guac_common_display_free_buffer(guac_common_display* display,
    372        guac_common_display_layer* display_buffer) {
    373
    374    pthread_mutex_lock(&display->_lock);
    375
    376    /* Remove list element from list */
    377    guac_common_display_remove_layer(&display->buffers, display_buffer);
    378
    379    /* Free associated layer and surface */
    380    guac_common_surface_free(display_buffer->surface);
    381    guac_client_free_buffer(display->client, display_buffer->layer);
    382
    383    /* Free list element */
    384    guac_mem_free(display_buffer);
    385
    386    pthread_mutex_unlock(&display->_lock);
    387
    388}
    389