void guac_display_dup()

in src/libguac/display.c [196:292]


void guac_display_dup(guac_display* display, guac_socket* socket) {

    guac_client* client = display->client;
    guac_rwlock_acquire_read_lock(&display->last_frame.lock);

    /* Wait for any pending frame to finish being sent to established users of
     * the connection before syncing any new users (doing otherwise could
     * result in trailing instructions of that pending frame getting sent to
     * new users after they finish joining, even though they are already in
     * sync with that frame, and those trailing instructions may not have the
     * intended meaning in context of the new users' remote displays) */
    guac_flag_wait_and_lock(&display->render_state,
            GUAC_DISPLAY_RENDER_STATE_FRAME_NOT_IN_PROGRESS);

    /* Sync the state of all layers/buffers */
    guac_display_layer* current = display->last_frame.layers;
    while (current != NULL) {

        const guac_layer* layer = current->layer;

        guac_rect layer_bounds;
        guac_display_layer_get_bounds(current, &layer_bounds);

        int width = guac_rect_width(&layer_bounds);
        int height = guac_rect_height(&layer_bounds);
        guac_protocol_send_size(socket, layer, width, height);

        if (width > 0 && height > 0) {

            /* Get Cairo surface covering layer bounds */
            unsigned char* buffer = GUAC_DISPLAY_LAYER_STATE_MUTABLE_BUFFER(current->last_frame, layer_bounds);
            cairo_surface_t* rect = cairo_image_surface_create_for_data(buffer,
                        current->opaque ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32,
                        width, height, current->last_frame.buffer_stride);

            /* Send PNG for rect */
            guac_client_stream_png(client, socket, GUAC_COMP_OVER, layer, 0, 0, rect);

            /* Resync copy of previous frame */
            guac_protocol_send_copy(socket,
                    layer, 0, 0, width, height,
                    GUAC_COMP_OVER, current->last_frame_buffer, 0, 0);

            cairo_surface_destroy(rect);

        }

        /* Resync any properties that are specific to non-buffer layers */
        if (current->layer->index > 0) {

            /* Resync layer opacity */
            guac_protocol_send_shade(socket, current->layer,
                    current->last_frame.opacity);

            /* Resync layer position/hierarchy */
            guac_protocol_send_move(socket, current->layer,
                    current->last_frame.parent,
                    current->last_frame.x,
                    current->last_frame.y,
                    current->last_frame.z);

        }

        /* Resync multitouch support */
        if (current->layer->index >= 0) {
            guac_protocol_send_set_int(socket, current->layer,
                    GUAC_PROTOCOL_LAYER_PARAMETER_MULTI_TOUCH,
                    current->last_frame.touches);
        }

        current = current->last_frame.next;

    }

    /* Synchronize mouse cursor */
    guac_display_layer* cursor = display->cursor_buffer;
    guac_protocol_send_cursor(socket,
            display->last_frame.cursor_hotspot_x,
            display->last_frame.cursor_hotspot_y,
            cursor->layer, 0, 0,
            cursor->last_frame.width,
            cursor->last_frame.height);

    /* Synchronize mouse location */
    guac_protocol_send_mouse(socket, display->last_frame.cursor_x, display->last_frame.cursor_y,
            display->last_frame.cursor_mask, client->last_sent_timestamp);

    /* The initial frame synchronizing the newly-joined users is now complete */
    guac_protocol_send_sync(socket, client->last_sent_timestamp, display->last_frame.frames);

    /* Further rendering for the current connection can now safely continue */
    guac_flag_unlock(&display->render_state);
    guac_rwlock_release_lock(&display->last_frame.lock);

    guac_socket_flush(socket);

}