FreeRDP/client/Wayland/wlf_window.c
Manuel Bachmann a9cf8b5838 wlfreerdp: add keyboard and mouse wheel support, fix bugs
This commit does the following:

* fix the keyboard logic (which now fully works), add support for vertical mouse wheel events ;
* make the rendering a lot more efficient, by using RDP damage information to refresh only the relevant part of the buffer ;
* fix two race conditions. wlfreerdp should not crash anymore now ;
* fix shm_open() and shm_unlink() calls ;
* improve the code style.

Signed-off-by: Manuel Bachmann <tarnyko@tarnyko.net>
2014-11-26 10:46:05 +01:00

221 lines
5.9 KiB
C

/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Wayland Windows
*
* Copyright 2014 Manuel Bachmann <tarnyko@tarnyko.net>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include "wlf_window.h"
static void wl_shell_surface_handle_ping(void* data, struct wl_shell_surface* shell_surface, uint32_t serial)
{
wl_shell_surface_pong(shell_surface, serial);
}
static void wl_shell_surface_handle_configure(void* data, struct wl_shell_surface* shell_surface, unsigned int edges, int32_t width, int32_t height)
{
wlfWindow* window = data;
window->width = width;
window->height = height;
}
static const struct wl_shell_surface_listener wl_shell_surface_listener =
{
wl_shell_surface_handle_ping,
wl_shell_surface_handle_configure,
NULL
};
static void wl_buffer_release(void* data, struct wl_buffer* wl_buffer)
{
wlfBuffer* buffer = data;
buffer->busy = FALSE;
}
static const struct wl_buffer_listener wl_buffer_listener =
{
wl_buffer_release
};
static const struct wl_callback_listener wl_callback_listener;
static void wl_callback_done(void* data, struct wl_callback* callback, uint32_t time)
{
wlfWindow* window = data;
wlfBuffer* buffer;
struct wl_shm_pool* shm_pool;
void* shm_data;
void* free_data;
int fd;
int fdt;
if (!window->buffers[0].busy)
buffer = &window->buffers[0];
else if (!window->buffers[1].busy)
buffer = &window->buffers[1];
else
return;
if (!buffer->buffer) {
fd = shm_open("/wlfreerdp_shm", O_CREAT | O_RDWR, 0666);
fdt = ftruncate(fd, window->width * window->height * 4);
if (fdt != 0)
{
WLog_ERR(TAG, "window_redraw: could not allocate memory");
close(fd);
return;
}
shm_data = mmap(NULL, window->width * window->height * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (shm_data == MAP_FAILED)
{
WLog_ERR(TAG, "window_redraw: failed to memory map buffer");
close(fd);
return;
}
shm_pool = wl_shm_create_pool(window->display->shm, fd, window->width * window->height * 4);
buffer->buffer = wl_shm_pool_create_buffer(shm_pool, 0, window->width, window->height, window->width* 4, WL_SHM_FORMAT_XRGB8888);
wl_buffer_add_listener(buffer->buffer, &wl_buffer_listener, buffer);
wl_shm_pool_destroy(shm_pool);
shm_unlink("/wlfreerdp_shm");
close(fd);
free_data = buffer->shm_data;
buffer->shm_data = shm_data;
munmap(free_data, window->width * window->height * 4);
}
/* this is the real surface data */
memcpy(buffer->shm_data, (void*) window->data, window->width * window->height * 4);
wl_surface_attach(window->surface, buffer->buffer, 0, 0);
wl_surface_damage(window->surface, 0, 0, window->width, window->height);
if (callback) wl_callback_destroy(callback);
window->callback = wl_surface_frame(window->surface);
wl_callback_add_listener(window->callback, &wl_callback_listener, window);
wl_surface_commit(window->surface);
buffer->busy = TRUE;
}
static const struct wl_callback_listener wl_callback_listener =
{
wl_callback_done
};
wlfWindow* wlf_CreateDesktopWindow(wlfContext* wlfc, char* name, int width, int height, BOOL decorations)
{
wlfWindow* window;
window = (wlfWindow*) calloc(1, sizeof(wlfWindow));
if (window)
{
window->width = width;
window->height = height;
window->fullscreen = FALSE;
window->buffers[0].busy = FALSE;
window->buffers[1].busy = FALSE;
window->callback = NULL;
window->display = wlfc->display;
window->surface = wl_compositor_create_surface(window->display->compositor);
window->shell_surface = wl_shell_get_shell_surface(window->display->shell, window->surface);
wl_shell_surface_add_listener(window->shell_surface, &wl_shell_surface_listener, window);
wl_shell_surface_set_toplevel(window->shell_surface);
wlf_ResizeDesktopWindow(wlfc, window, width, height);
wl_surface_damage(window->surface, 0, 0, window->width, window->height);
}
wlf_SetWindowText(wlfc, window, name);
return window;
}
void wlf_ResizeDesktopWindow(wlfContext* wlfc, wlfWindow* window, int width, int height)
{
window->width = width;
window->height = height;
}
void wlf_SetWindowText(wlfContext* wlfc, wlfWindow* window, char* name)
{
wl_shell_surface_set_title(window->shell_surface, name);
}
void wlf_SetWindowFullscreen(wlfContext* wlfc, wlfWindow* window, BOOL fullscreen)
{
if (fullscreen)
{
wl_shell_surface_set_fullscreen(window->shell_surface, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, NULL);
window->fullscreen = TRUE;
}
}
void wlf_ShowWindow(wlfContext* wlfc, wlfWindow* window, BYTE state)
{
switch (state)
{
case WINDOW_HIDE:
case WINDOW_SHOW_MINIMIZED:
/* xdg_surface_set_minimized(window->xdg_surface); */
break;
case WINDOW_SHOW_MAXIMIZED:
wl_shell_surface_set_maximized(window->shell_surface, NULL);
break;
case WINDOW_SHOW:
wl_shell_surface_set_toplevel(window->shell_surface);
break;
}
}
void wlf_UpdateWindowArea(wlfContext* wlfc, wlfWindow* window, int x, int y, int width, int height)
{
wl_callback_done(window, NULL, 0);
}
void wlf_DestroyWindow(wlfContext* wlfc, wlfWindow* window)
{
if (window == NULL)
return;
if (wlfc->window == window)
wlfc->window = NULL;
if (window->buffers[0].buffer)
wl_buffer_destroy(window->buffers[0].buffer);
if (window->buffers[1].buffer)
wl_buffer_destroy(window->buffers[1].buffer);
if (window->shell_surface)
wl_shell_surface_destroy(window->shell_surface);
if (window->surface)
wl_surface_destroy(window->surface);
free(window->data);
free(window);
}