/* * Remmina - The GTK+ Remote Desktop Client * Copyright (C) 2010-2011 Vic Lee * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. * If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. * If you * do not wish to do so, delete this exception statement from your * version. * If you delete this exception statement from all source * files in the program, then also delete it here. * */ #pragma once #include "common/remmina_plugin.h" #include #include #include #include #include #include #include #include #include #include #ifdef GDK_WINDOWING_X11 #include #elif defined(GDK_WINDOWING_WAYLAND) #include #endif #include /** * FREERDP_CHECK_VERSION: * @major: major version (e.g. 2 for version 2.1.0) * @minor: minor version (e.g. 0 for version 2.1.0) * @release: release version (e.g. 0 for version 2.1.0) * * Returns %TRUE if the version of the FRERDDP header files * is the same as or newer than the passed-in version. * * Returns: %TRUE if FREERDP headers are new enough */ #define FREERDP_CHECK_VERSION(major,minor,revision) \ (FREERDP_VERSION_MAJOR > (major) || \ (FREERDP_VERSION_MAJOR == (major) && FREERDP_VERSION_MINOR > (minor)) || \ (FREERDP_VERSION_MAJOR == (major) && FREERDP_VERSION_MINOR == (minor) && \ FREERDP_VERSION_REVISION >= (revision))) /** * Constants to workaround FreeRDP issue #5417 (min resolution in AVC mode) * Must be 4 aligned (multiple of 4). * We should instead check destRect and be sure the condition is met * See https://gitlab.com/Remmina/Remmina/-/issues/2507 for a deep discussion */ #define AVC_MIN_DESKTOP_WIDTH 644 #define AVC_MIN_DESKTOP_HEIGHT 480 typedef struct rf_context rfContext; #define GET_PLUGIN_DATA(gp) (rfContext *)g_object_get_data(G_OBJECT(gp), "plugin-data") /** * Performance Flags, from FreeRDP source * * PERF_FLAG_NONE 0x00000000 * PERF_DISABLE_WALLPAPER 0x00000001 * PERF_DISABLE_FULLWINDOWDRAG 0x00000002 * PERF_DISABLE_MENUANIMATIONS 0x00000004 * PERF_DISABLE_THEMING 0x00000008 * PERF_DISABLE_CURSOR_SHADOW 0x00000020 * PERF_DISABLE_CURSORSETTINGS 0x00000040 * PERF_ENABLE_FONT_SMOOTHING 0x00000080 * PERF_ENABLE_DESKTOP_COMPOSITION 0x00000100 */ /* Poor (default) - all disabled */ #define DEFAULT_QUALITY_0 0x6f /* Medium - only THEMING, CURSOR_SHADOW and CURSORSETTINGS enabled, all other disabled */ #define DEFAULT_QUALITY_1 0x07 /* Good - WALLPAPER, FONT_SMOOTHING, DESKTOP_COMPOSITION disabled, all other enabled */ #define DEFAULT_QUALITY_2 0x01 /* Best - DESKTOP_COMPOSITION disabled, all other enabled */ #define DEFAULT_QUALITY_9 0x80 extern RemminaPluginService *remmina_plugin_service; #define REMMINA_PLUGIN_INFO(fmt, ...) \ remmina_plugin_service->_remmina_info(__func__, fmt, ##__VA_ARGS__) #define REMMINA_PLUGIN_MESSAGE(fmt, ...) \ remmina_plugin_service->_remmina_message(__func, fmt, ##__VA_ARGS__) #define REMMINA_PLUGIN_DEBUG(fmt, ...) \ remmina_plugin_service->_remmina_debug(__func__, fmt, ##__VA_ARGS__) #define REMMINA_PLUGIN_WARNING(fmt, ...) \ remmina_plugin_service->_remmina_warning(__func__, fmt, ##__VA_ARGS__) /* This will intentionally crash Remmina */ #define REMMINA_PLUGIN_ERROR(fmt, ...) \ remmina_plugin_service->_remmina_error(__func__, fmt, ##__VA_ARGS__) #define REMMINA_PLUGIN_CRITICAL(fmt, ...) \ remmina_plugin_service->_remmina_critical(__func__, fmt, ##__VA_ARGS__) #define REMMINA_PLUGIN_AUDIT(fmt, ...) \ remmina_plugin_service->_remmina_audit(__func__, fmt, ##__VA_ARGS__) struct rf_clipboard { rfContext * rfi; CliprdrClientContext * context; wClipboard * system; int requestedFormatId; UINT32 format; gulong clipboard_handler; pthread_mutex_t transfer_clip_mutex; pthread_cond_t transfer_clip_cond; enum { SCDW_NONE, SCDW_BUSY_WAIT, SCDW_ABORTING } srv_clip_data_wait; gpointer srv_data; pthread_mutex_t srv_data_mutex; UINT32 server_html_format_id; /* Stats for clipboard download */ struct timeval clientformatdatarequest_tv; }; typedef struct rf_clipboard rfClipboard; struct rf_pointer { rdpPointer pointer; GdkCursor * cursor; }; typedef struct rf_pointer rfPointer; #ifdef RF_BITMAP struct rf_bitmap { rdpBitmap bitmap; Pixmap pixmap; cairo_surface_t * surface; }; typedef struct rf_bitmap rfBitmap; #endif #ifdef RF_GLYPH struct rf_glyph { rdpGlyph glyph; Pixmap pixmap; }; typedef struct rf_glyph rfGlyph; #endif typedef enum { REMMINA_RDP_EVENT_TYPE_SCANCODE, REMMINA_RDP_EVENT_TYPE_SCANCODE_UNICODE, REMMINA_RDP_EVENT_TYPE_MOUSE, REMMINA_RDP_EVENT_TYPE_CLIPBOARD_SEND_CLIENT_FORMAT_LIST, REMMINA_RDP_EVENT_TYPE_CLIPBOARD_SEND_CLIENT_FORMAT_DATA_RESPONSE, REMMINA_RDP_EVENT_TYPE_CLIPBOARD_SEND_CLIENT_FORMAT_DATA_REQUEST, REMMINA_RDP_EVENT_TYPE_SEND_MONITOR_LAYOUT, REMMINA_RDP_EVENT_DISCONNECT } RemminaPluginRdpEventType; struct remmina_plugin_rdp_event { RemminaPluginRdpEventType type; union { struct { BOOL up; BOOL extended; UINT8 key_code; UINT32 unicode_code; BOOL extended1; } key_event; struct { UINT16 flags; UINT16 x; UINT16 y; BOOL extended; } mouse_event; struct { CLIPRDR_FORMAT_LIST *pFormatList; } clipboard_formatlist; struct { BYTE * data; int size; } clipboard_formatdataresponse; struct { CLIPRDR_FORMAT_DATA_REQUEST *pFormatDataRequest; } clipboard_formatdatarequest; struct { gint Flags; gint Left; gint Top; gint width; gint height; gint desktopOrientation; gint desktopScaleFactor; gint deviceScaleFactor; gint physicalWidth; gint physicalHeight; } monitor_layout; }; }; typedef struct remmina_plugin_rdp_event RemminaPluginRdpEvent; typedef enum { REMMINA_RDP_UI_UPDATE_REGIONS = 0, REMMINA_RDP_UI_CONNECTED, REMMINA_RDP_UI_RECONNECT_PROGRESS, REMMINA_RDP_UI_CURSOR, REMMINA_RDP_UI_NOCODEC, REMMINA_RDP_UI_CLIPBOARD, REMMINA_RDP_UI_EVENT } RemminaPluginRdpUiType; typedef enum { REMMINA_RDP_UI_CLIPBOARD_FORMATLIST, REMMINA_RDP_UI_CLIPBOARD_GET_DATA, REMMINA_RDP_UI_CLIPBOARD_SET_DATA } RemminaPluginRdpUiClipboardType; typedef enum { REMMINA_RDP_POINTER_NEW, REMMINA_RDP_POINTER_FREE, REMMINA_RDP_POINTER_SET, REMMINA_RDP_POINTER_NULL, REMMINA_RDP_POINTER_DEFAULT, REMMINA_RDP_POINTER_SETPOS } RemminaPluginRdpUiPointerType; typedef enum { REMMINA_RDP_UI_EVENT_UPDATE_SCALE, REMMINA_RDP_UI_EVENT_DESTROY_CAIRO_SURFACE } RemminaPluginRdpUiEeventType; typedef struct { gint x, y, w, h; } region; struct remmina_plugin_rdp_ui_object { RemminaPluginRdpUiType type; gboolean sync; gboolean complete; pthread_mutex_t sync_wait_mutex; pthread_cond_t sync_wait_cond; union { struct { region *ureg; gint ninvalid; } reg; struct { rdpContext * context; rfPointer * pointer; RemminaPluginRdpUiPointerType type; } cursor; struct { gint left; gint top; RFX_MESSAGE * message; } rfx; struct { gint left; gint top; gint width; gint height; UINT8 * bitmap; } nocodec; struct { RemminaPluginRdpUiClipboardType type; GtkTargetList * targetlist; UINT32 format; rfClipboard * clipboard; gpointer data; } clipboard; struct { RemminaPluginRdpUiEeventType type; } event; struct { gint x; gint y; } pos; }; /* We can also return values here, usually integers*/ int retval; /* Some functions also may return a pointer. */ void * retptr; }; typedef struct remmina_plugin_rdp_keymap_entry { unsigned orig_keycode; unsigned translated_keycode; } RemminaPluginRdpKeymapEntry; struct rf_context { rdpClientContext clientContext; RemminaProtocolWidget *protocol_widget; /* main */ pthread_t remmina_plugin_thread; RemminaScaleMode scale; gboolean user_cancelled; gboolean thread_cancelled; CliprdrClientContext * cliprdr; DispClientContext * dispcontext; RDP_PLUGIN_DATA rdpdr_data[5]; RDP_PLUGIN_DATA drdynvc_data[5]; gchar rdpsnd_options[20]; gboolean rdpgfxchan; gboolean connected; gboolean is_reconnecting; gboolean stop_reconnecting_requested; /* orphaned: rf_context has still one or more libfreerdp thread active, * but no longer maintained by an open RemminaProtocolWidget/tab. * When the orphaned thread terminates, we must cleanup rf_context. */ gboolean orphaned; int reconnect_maxattempts; int reconnect_nattempt; gboolean sw_gdi; GtkWidget * drawing_area; gint scale_width; gint scale_height; gdouble scale_x; gdouble scale_y; guint delayed_monitor_layout_handler; gboolean use_client_keymap; gint srcBpp; GdkDisplay * display; GdkVisual * visual; cairo_surface_t * surface; cairo_format_t cairo_format; gint bpp; gint scanline_pad; gint * colormap; guint object_id_seq; GHashTable * object_table; GAsyncQueue * ui_queue; pthread_mutex_t ui_queue_mutex; guint ui_handler; GArray * pressed_keys; GAsyncQueue * event_queue; gint event_pipe[2]; HANDLE event_handle; UINT16 last_x; UINT16 last_y; rfClipboard clipboard; GArray * keymap; /* Array of RemminaPluginRdpKeymapEntry */ gboolean attempt_interactive_authentication; enum { REMMINA_POSTCONNECT_ERROR_OK = 0, REMMINA_POSTCONNECT_ERROR_GDI_INIT = 1, REMMINA_POSTCONNECT_ERROR_NO_H264 } postconnect_error; }; typedef struct remmina_plugin_rdp_ui_object RemminaPluginRdpUiObject; void rf_init(RemminaProtocolWidget *gp); void rf_uninit(RemminaProtocolWidget *gp); void rf_get_fds(RemminaProtocolWidget *gp, void **rfds, int *rcount); BOOL rf_check_fds(RemminaProtocolWidget *gp); void rf_object_free(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *obj); void remmina_rdp_event_event_push(RemminaProtocolWidget *gp, const RemminaPluginRdpEvent *e);