diff options
author | Giovanni Panozzo <giovanni@panozzo.it> | 2019-10-27 23:41:37 +0300 |
---|---|---|
committer | Giovanni Panozzo <giovanni@panozzo.it> | 2019-11-01 11:11:27 +0300 |
commit | b5a875e043148d7d72c3681042efa31304f2bba9 (patch) | |
tree | 93783842c633d81301259f3015a150b47063fb60 | |
parent | 06ee121ca368c05dd8765fabd3483b9fa08a8cc2 (diff) |
Plugin connection close refactoring
-rw-r--r-- | plugins/nx/nx_plugin.c | 14 | ||||
-rw-r--r-- | plugins/rdp/rdp_channels.c | 2 | ||||
-rw-r--r-- | plugins/rdp/rdp_cliprdr.c | 2 | ||||
-rw-r--r-- | plugins/rdp/rdp_event.c | 5 | ||||
-rw-r--r-- | plugins/rdp/rdp_plugin.c | 246 | ||||
-rw-r--r-- | plugins/rdp/rdp_plugin.h | 17 | ||||
-rw-r--r-- | plugins/spice/spice_plugin.c | 4 | ||||
-rw-r--r-- | plugins/st/st_plugin.c | 6 | ||||
-rw-r--r-- | plugins/vnc/vnc_plugin.c | 17 | ||||
-rw-r--r-- | plugins/xdmcp/xdmcp_plugin.c | 9 | ||||
-rw-r--r-- | src/include/remmina/plugin.h | 10 | ||||
-rw-r--r-- | src/rcw.c | 16 | ||||
-rw-r--r-- | src/remmina_file.c | 4 | ||||
-rw-r--r-- | src/remmina_file.h | 2 | ||||
-rw-r--r-- | src/remmina_plugin_manager.c | 12 | ||||
-rw-r--r-- | src/remmina_protocol_widget.c | 180 | ||||
-rw-r--r-- | src/remmina_protocol_widget.h | 9 | ||||
-rw-r--r-- | src/remmina_sftp_plugin.c | 2 | ||||
-rw-r--r-- | src/remmina_ssh_plugin.c | 6 |
19 files changed, 362 insertions, 201 deletions
diff --git a/plugins/nx/nx_plugin.c b/plugins/nx/nx_plugin.c index 34f44e037..c16f0bfda 100644 --- a/plugins/nx/nx_plugin.c +++ b/plugins/nx/nx_plugin.c @@ -182,13 +182,13 @@ static void remmina_plugin_nx_remove_window_id(Window window_id) static void remmina_plugin_nx_on_plug_added(GtkSocket *socket, RemminaProtocolWidget *gp) { TRACE_CALL(__func__); - remmina_plugin_nx_service->protocol_plugin_emit_signal(gp, "connect"); + remmina_plugin_nx_service->protocol_plugin_signal_connection_opened(gp); } static void remmina_plugin_nx_on_plug_removed(GtkSocket *socket, RemminaProtocolWidget *gp) { TRACE_CALL(__func__); - remmina_plugin_nx_service->protocol_plugin_close_connection(gp); + remmina_plugin_nx_service->protocol_plugin_signal_connection_closed(gp); } gboolean remmina_plugin_nx_ssh_auth_callback(gchar **passphrase, gpointer userdata) @@ -212,7 +212,7 @@ static void remmina_plugin_nx_on_proxy_exit(GPid pid, gint status, gpointer data TRACE_CALL(__func__); RemminaProtocolWidget *gp = (RemminaProtocolWidget*)data; - remmina_plugin_nx_service->protocol_plugin_close_connection(gp); + remmina_plugin_nx_service->protocol_plugin_signal_connection_closed(gp); } static int remmina_plugin_nx_dummy_handler(Display *dsp, XErrorEvent *err) @@ -539,11 +539,12 @@ static gboolean remmina_plugin_nx_main(RemminaProtocolWidget *gp) static gpointer remmina_plugin_nx_main_thread(gpointer data) { TRACE_CALL(__func__); + RemminaProtocolWidget *gp = (RemminaProtocolWidget *)data; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); CANCEL_ASYNC - if (!remmina_plugin_nx_main((RemminaProtocolWidget*)data)) { - IDLE_ADD((GSourceFunc)remmina_plugin_nx_service->protocol_plugin_close_connection, data); + if (!remmina_plugin_nx_main(gp)) { + remmina_plugin_nx_service->protocol_plugin_signal_connection_closed(gp); } return NULL; } @@ -638,7 +639,7 @@ static gboolean remmina_plugin_nx_close_connection(RemminaProtocolWidget *gp) close(gpdata->event_pipe[0]); close(gpdata->event_pipe[1]); - remmina_plugin_nx_service->protocol_plugin_emit_signal(gp, "disconnect"); + remmina_plugin_nx_service->protocol_plugin_signal_connection_closed(gp); return FALSE; } @@ -795,4 +796,3 @@ remmina_plugin_entry(RemminaPluginService *service) return TRUE; } - diff --git a/plugins/rdp/rdp_channels.c b/plugins/rdp/rdp_channels.c index 60a58db3b..3a750bf8f 100644 --- a/plugins/rdp/rdp_channels.c +++ b/plugins/rdp/rdp_channels.c @@ -74,7 +74,7 @@ void remmina_rdp_OnChannelConnectedEventHandler(rdpContext* context, ChannelConn // "disp" channel connected, save its context pointer rfi->dispcontext = (DispClientContext*)e->pInterface; // Notify rcw to unlock dynres capability - remmina_plugin_service->protocol_plugin_emit_signal(rfi->protocol_widget, "unlock-dynres"); + remmina_plugin_service->protocol_plugin_unlock_dynres(rfi->protocol_widget); // Send monitor layout message here to ask for resize of remote desktop now if (rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_DYNRES) { remmina_rdp_event_send_delayed_monitor_layout(rfi->protocol_widget); diff --git a/plugins/rdp/rdp_cliprdr.c b/plugins/rdp/rdp_cliprdr.c index 464f89a58..62624b206 100644 --- a/plugins/rdp/rdp_cliprdr.c +++ b/plugins/rdp/rdp_cliprdr.c @@ -730,6 +730,8 @@ void remmina_rdp_cliprdr_detach_owner(RemminaProtocolWidget* gp) rfContext* rfi = GET_PLUGIN_DATA(gp); GtkClipboard* gtkClipboard; + if (!rfi || !rfi->drawing_area) return; + gtkClipboard = gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD); if (gtkClipboard && gtk_clipboard_get_owner(gtkClipboard) == (GObject*)gp) { gtk_clipboard_clear(gtkClipboard); diff --git a/plugins/rdp/rdp_event.c b/plugins/rdp/rdp_event.c index 953cf87fc..3842039d4 100644 --- a/plugins/rdp/rdp_event.c +++ b/plugins/rdp/rdp_event.c @@ -949,7 +949,7 @@ void remmina_rdp_event_update_scale(RemminaProtocolWidget* gp) /* In non scaled mode, the plugins forces dimensions of drawing area */ gtk_widget_set_size_request(rfi->drawing_area, width, height); } - remmina_plugin_service->protocol_plugin_emit_signal(gp, "update-align"); + remmina_plugin_service->protocol_plugin_update_align(gp); } static void remmina_rdp_event_connected(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) @@ -960,13 +960,14 @@ static void remmina_rdp_event_connected(RemminaProtocolWidget* gp, RemminaPlugin gdi = ((rdpContext *)rfi)->gdi; - remmina_plugin_service->protocol_plugin_emit_signal(gp, "connect"); gtk_widget_realize(rfi->drawing_area); remmina_rdp_event_create_cairo_surface(rfi); gtk_widget_queue_draw_area(rfi->drawing_area, 0, 0, gdi->width, gdi->height); remmina_rdp_event_update_scale(gp); + + remmina_plugin_service->protocol_plugin_signal_connection_opened(gp); } static void remmina_rdp_event_reconnect_progress(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) diff --git a/plugins/rdp/rdp_plugin.c b/plugins/rdp/rdp_plugin.c index ca932ab80..3d679ac3b 100644 --- a/plugins/rdp/rdp_plugin.c +++ b/plugins/rdp/rdp_plugin.c @@ -34,6 +34,7 @@ * */ + #define _GNU_SOURCE #include "rdp_plugin.h" @@ -54,6 +55,7 @@ #include <freerdp/client/channels.h> #include <freerdp/client/cmdline.h> #include <freerdp/error.h> +#include <freerdp/event.h> #include <winpr/memory.h> #ifdef HAVE_CUPS @@ -152,6 +154,10 @@ static BOOL rf_process_event_queue(RemminaProtocolWidget *gp) g_free(dcml); } break; + case REMMINA_RDP_EVENT_DISCONNECT: + /* Disconnect requested via GUI (i.e.: tab destroy/close) */ + freerdp_abort_connect(rfi->instance); + break; } g_free(event); @@ -391,7 +397,7 @@ static BOOL rf_desktop_resize(rdpContext *context) ui->event.type = REMMINA_RDP_UI_EVENT_UPDATE_SCALE; remmina_rdp_event_queue_ui_sync_retint(gp, ui); - remmina_plugin_service->protocol_plugin_emit_signal(gp, "desktop-resize"); + remmina_plugin_service->protocol_plugin_desktop_resize(gp); return TRUE; } @@ -499,6 +505,8 @@ static BOOL remmina_rdp_post_connect(freerdp *instance) gp = rfi->protocol_widget; rfi->postconnect_error = REMMINA_POSTCONNECT_ERROR_OK; + rfi->attempt_interactive_authentication = FALSE; // We did authenticate! + rfi->srcBpp = rfi->settings->ColorDepth; if (rfi->settings->RemoteFxCodec == FALSE) @@ -529,7 +537,7 @@ static BOOL remmina_rdp_post_connect(freerdp *instance) return FALSE; } - pointer_cache_register_callbacks(instance->update); + // pointer_cache_register_callbacks(instance->update); instance->update->BeginPaint = rf_begin_paint; instance->update->EndPaint = rf_end_paint; @@ -593,7 +601,6 @@ static BOOL remmina_rdp_authenticate(freerdp *instance, char **username, char ** return True; } else { - rfi->user_cancelled = TRUE; return False; } @@ -638,7 +645,6 @@ static BOOL remmina_rdp_proxy_authenticate(RemminaProtocolWidget *gp) return True; } else { - rfi->user_cancelled = TRUE; return False; } @@ -691,7 +697,6 @@ static BOOL remmina_rdp_gw_authenticate(freerdp *instance, char **username, char return True; } else { - rfi->user_cancelled = TRUE; return False; } @@ -737,6 +742,27 @@ static DWORD remmina_rdp_verify_changed_certificate(freerdp *instance, return 0; } +static void remmina_rdp_post_disconnect(freerdp *instance) +{ + TRACE_CALL(__func__); + rfContext *rfi; + + if (!instance || !instance->context) + return; + + rfi = (rfContext *)instance->context; + + PubSub_UnsubscribeChannelConnected(instance->context->pubSub, + (pChannelConnectedEventHandler)remmina_rdp_OnChannelConnectedEventHandler); + PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub, + (pChannelDisconnectedEventHandler)remmina_rdp_OnChannelDisconnectedEventHandler); + + gdi_free(instance); + + remmina_rdp_clipboard_free(rfi); + +} + static void remmina_rdp_main_loop(RemminaProtocolWidget *gp) { TRACE_CALL(__func__); @@ -746,11 +772,14 @@ static void remmina_rdp_main_loop(RemminaProtocolWidget *gp) gchar buf[100]; rfContext *rfi = GET_PLUGIN_DATA(gp); + while (!freerdp_shall_disconnect(rfi->instance)) { nCount = freerdp_get_event_handles(rfi->instance->context, &handles[0], 64); if (rfi->event_handle) handles[nCount++] = rfi->event_handle; + handles[nCount++] = rfi->instance->context->abortEvent; + if (nCount == 0) { fprintf(stderr, "freerdp_get_event_handles failed\n"); break; @@ -772,6 +801,12 @@ static void remmina_rdp_main_loop(RemminaProtocolWidget *gp) } } + /* Check if a processed event called freerdp_abort_connect() and exit if true */ + if (WaitForSingleObject(rfi->instance->context->abortEvent, 0) == WAIT_OBJECT_0) { + /* Session disconnected by local user action */ + break; + } + if (!freerdp_check_event_handles(rfi->instance->context)) { if (rf_auto_reconnect(rfi)) { /* Reset the possible reason/error which made us doing many reconnection reattempts and continue */ @@ -783,6 +818,8 @@ static void remmina_rdp_main_loop(RemminaProtocolWidget *gp) break; } } + freerdp_disconnect(rfi->instance); + g_debug("RDP client disconnected\n"); } int remmina_rdp_load_static_channel_addin(rdpChannels *channels, rdpSettings *settings, char *name, void *data) @@ -1058,6 +1095,7 @@ static gboolean remmina_rdp_main(RemminaProtocolWidget *gp) remmina_plugin_service->protocol_plugin_set_width(gp, rfi->settings->DesktopWidth); remmina_plugin_service->protocol_plugin_set_height(gp, rfi->settings->DesktopHeight); + if (remmina_plugin_service->file_get_string(remminafile, "username")) rfi->settings->Username = strdup(remmina_plugin_service->file_get_string(remminafile, "username")); @@ -1065,11 +1103,10 @@ static gboolean remmina_rdp_main(RemminaProtocolWidget *gp) rfi->settings->Domain = strdup(remmina_plugin_service->file_get_string(remminafile, "domain")); s = remmina_plugin_service->file_get_string(remminafile, "password"); + if (s) rfi->settings->Password = strdup(s); + + rfi->settings->AutoLogonEnabled = 1; - if (s) { - rfi->settings->Password = strdup(s); - rfi->settings->AutoLogonEnabled = 1; - } /** * Proxy support * Proxy settings are hidden at the moment as an advanced feauture @@ -1436,8 +1473,32 @@ static gboolean remmina_rdp_main(RemminaProtocolWidget *gp) freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)parallel); } + /* If needed, force interactive authentication by deleting all authentication fields, + * forcing libfreerdp to call our callbacks for authentication. + This usually happens from a second attempt of connection, never on the 1st one. */ + if (rfi->attempt_interactive_authentication) { + if (rfi->settings->Username) free(rfi->settings->Username); + rfi->settings->Username = NULL; + if (rfi->settings->Password) free(rfi->settings->Password); + rfi->settings->Password = NULL; + if (rfi->settings->Domain) free(rfi->settings->Domain); + rfi->settings->Domain = NULL; + + if (rfi->settings->GatewayDomain) free(rfi->settings->GatewayDomain); + rfi->settings->GatewayDomain = NULL; + if (rfi->settings->GatewayUsername) free(rfi->settings->GatewayUsername); + rfi->settings->GatewayUsername = NULL; + if (rfi->settings->GatewayPassword) free(rfi->settings->GatewayPassword); + rfi->settings->GatewayPassword = NULL; + rfi->settings->GatewayUseSameCredentials = FALSE; + + } + + gboolean orphaned; + if (!freerdp_connect(rfi->instance)) { - if (!rfi->user_cancelled) { + if (GET_PLUGIN_DATA(rfi->protocol_widget) == NULL) orphaned = True; else orphaned = False; + if (!orphaned) { UINT32 e; e = freerdp_get_last_error(rfi->instance->context); @@ -1448,11 +1509,8 @@ static gboolean remmina_rdp_main(RemminaProtocolWidget *gp) #ifdef FREERDP_ERROR_CONNECT_LOGON_FAILURE case FREERDP_ERROR_CONNECT_LOGON_FAILURE: #endif - remmina_plugin_service->protocol_plugin_set_error(gp, _("Authentication to RDP server %s failed.\nCheck username, password and domain."), - rfi->settings->ServerHostname); - // Invalidate the saved password, so the user will be re-asked at next logon - if (!remmina_rdp_authenticate(rfi->instance, NULL, NULL, NULL)) - remmina_plugin_service->file_unsave_password(remminafile); + /* Logon failure, will retry with interactive authentication */ + rfi->attempt_interactive_authentication = TRUE; break; case STATUS_ACCOUNT_LOCKED_OUT: #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT @@ -1540,6 +1598,11 @@ static gboolean remmina_rdp_main(RemminaProtocolWidget *gp) remmina_plugin_service->protocol_plugin_set_error(gp, _("Server %s denied the connection."), rfi->settings->ServerHostname); break; #endif + + case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS: + rfi->user_cancelled = TRUE; + break; + default: g_printf("libfreerdp returned code is %08X\n", e); remmina_plugin_service->protocol_plugin_set_error(gp, _("Unable to connect to RDP server %s"), rfi->settings->ServerHostname); @@ -1550,11 +1613,77 @@ static gboolean remmina_rdp_main(RemminaProtocolWidget *gp) return FALSE; } - remmina_rdp_main_loop(gp); + if (GET_PLUGIN_DATA(rfi->protocol_widget) == NULL) orphaned = True; else orphaned = False; + if (!orphaned && freerdp_get_last_error(rfi->instance->context) == FREERDP_ERROR_SUCCESS && !rfi->user_cancelled) { + remmina_rdp_main_loop(gp); + } return TRUE; } +static void rfi_uninit(rfContext* rfi) +{ + freerdp *instance; + + instance = rfi->instance; + + if (rfi->remmina_plugin_thread) { + rfi->thread_cancelled = TRUE; // Avoid all rf_queue function to run + pthread_cancel(rfi->remmina_plugin_thread); + if (rfi->remmina_plugin_thread) + pthread_join(rfi->remmina_plugin_thread, NULL); + } + + if (instance) { + if (rfi->connected) { + freerdp_abort_connect(instance); + rfi->connected = False; + } + } + + + if (rfi->rfx_context) { + rfx_context_free(rfi->rfx_context); + rfi->rfx_context = NULL; + } + if (instance) { + RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints; + if (pEntryPoints) + IFCALL(pEntryPoints->GlobalUninit); + free(instance->pClientEntryPoints); + freerdp_context_free(instance); /* context is rfContext* rfi */ + freerdp_free(instance); /* This implicitly frees instance->context and rfi is no longer valid */ + } + + +} + +static gboolean complete_cleanup_on_main_thread(gpointer data) +{ + TRACE_CALL(__func__); + + gboolean orphaned; + rfContext *rfi = (rfContext *)data; + RemminaProtocolWidget *gp; + + gp = rfi->protocol_widget; + if (GET_PLUGIN_DATA(gp) == NULL) orphaned = True; else orphaned = False; + + remmina_rdp_cliprdr_detach_owner(gp); + if (!orphaned) remmina_rdp_event_uninit(gp); + + if (!orphaned) g_object_steal_data(G_OBJECT(gp), "plugin-data"); + + rfi_uninit(rfi); + + /* Notify the RemminaProtocolWidget that we closed our connection, and the GUI interface + can be removed */ + if (!orphaned) + remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); + + return G_SOURCE_REMOVE; +} + static gpointer remmina_rdp_main_thread(gpointer data) { TRACE_CALL(__func__); @@ -1564,15 +1693,19 @@ static gpointer remmina_rdp_main_thread(gpointer data) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); CANCEL_ASYNC - gp = (RemminaProtocolWidget *)data; + gp = (RemminaProtocolWidget *)data; rfi = GET_PLUGIN_DATA(gp); - remmina_rdp_main(gp); - rfi->thread = 0; + rfi->attempt_interactive_authentication = FALSE; + do { + remmina_rdp_main(gp); + } while(!remmina_plugin_service->protocol_plugin_has_error(gp) && rfi->attempt_interactive_authentication == TRUE && !rfi->user_cancelled); + + rfi->remmina_plugin_thread = 0; + + /* cleanup */ + g_idle_add(complete_cleanup_on_main_thread, (gpointer)rfi); - /* Signal main thread that we closed the connection. But wait 200ms, because we may - * have outstaiding events to process in the meanwhile */ - g_timeout_add(200, ((GSourceFunc)remmina_plugin_service->protocol_plugin_close_connection), gp); return NULL; } @@ -1586,6 +1719,7 @@ static void remmina_rdp_init(RemminaProtocolWidget *gp) instance = freerdp_new(); instance->PreConnect = remmina_rdp_pre_connect; instance->PostConnect = remmina_rdp_post_connect; + instance->PostDisconnect = remmina_rdp_post_disconnect; instance->Authenticate = remmina_rdp_authenticate; instance->GatewayAuthenticate = remmina_rdp_gw_authenticate; instance->VerifyCertificate = remmina_rdp_verify_certificate; @@ -1602,6 +1736,7 @@ static void remmina_rdp_init(RemminaProtocolWidget *gp) rfi->settings = instance->settings; rfi->connected = False; rfi->is_reconnecting = False; + rfi->user_cancelled = FALSE; freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0); @@ -1615,11 +1750,11 @@ static gboolean remmina_rdp_open_connection(RemminaProtocolWidget *gp) rfi->scale = remmina_plugin_service->remmina_protocol_widget_get_current_scale_mode(gp); - if (pthread_create(&rfi->thread, NULL, remmina_rdp_main_thread, gp)) { + if (pthread_create(&rfi->remmina_plugin_thread, NULL, remmina_rdp_main_thread, gp)) { remmina_plugin_service->protocol_plugin_set_error(gp, "%s", "Failed to initialize pthread. Falling back to non-thread mode…"); - rfi->thread = 0; + rfi->remmina_plugin_thread = 0; return FALSE; } @@ -1630,64 +1765,27 @@ static gboolean remmina_rdp_open_connection(RemminaProtocolWidget *gp) static gboolean remmina_rdp_close_connection(RemminaProtocolWidget *gp) { TRACE_CALL(__func__); + + RemminaPluginRdpEvent rdp_event = { 0 }; rfContext *rfi = GET_PLUGIN_DATA(gp); - freerdp *instance; if (!remmina_plugin_service->is_main_thread()) g_printf("WARNING: %s called on a subthread, may not work or crash remmina.\n", __func__); - /* Immediately deatch GTK clipboard from this connection */ - remmina_rdp_cliprdr_detach_owner(gp); - - if (freerdp_get_last_error(rfi->instance->context) == 0x10005) - remmina_plugin_service->protocol_plugin_set_error(gp, "Another user connected to the server (%s), forcing the disconnection of the current connection.", rfi->settings->ServerHostname); - instance = rfi->instance; - if (rfi->thread) { - rfi->thread_cancelled = TRUE; // Avoid all rf_queue function to run - pthread_cancel(rfi->thread); - - if (rfi->thread) - pthread_join(rfi->thread, NULL); - } - - if (instance) { - if (rfi->connected) { - //freerdp_disconnect(instance); - freerdp_abort_connect(instance); - rfi->connected = False; - } - } - - if (rfi->hdc) { - gdi_DeleteDC(rfi->hdc); - rfi->hdc = NULL; - } - - remmina_rdp_clipboard_free(rfi); - if (rfi->rfx_context) { - rfx_context_free(rfi->rfx_context); - rfi->rfx_context = NULL; - } - - if (instance) { - gdi_free(instance); - cache_free(instance->context->cache); - instance->context->cache = NULL; - } - - /* Destroy event queue. Pending async events will be discarded. Should we flush it ? */ - remmina_rdp_event_uninit(gp); - - if (instance) { - freerdp_context_free(instance); /* context is rfContext* rfi */ - freerdp_free(instance); /* This implicitly frees instance->context and rfi is no longer valid */ + if (rfi && !rfi->connected) { + /* libfreerdp is attempting to connect, we cannot interrupt our main thread + * in the connect phase. + * So we remove "plugin-data" from gp, so our rfi remains "orphan" + */ + remmina_rdp_event_uninit(gp); + g_object_steal_data(G_OBJECT(gp), "plugin-data"); + remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); + return FALSE; } - /* Remove instance->context from gp object data to avoid double free */ - g_object_steal_data(G_OBJECT(gp), "plugin-data"); - /* Now let remmina to complete its disconnection tasks */ - remmina_plugin_service->protocol_plugin_emit_signal(gp, "disconnect"); + rdp_event.type = REMMINA_RDP_EVENT_DISCONNECT; + remmina_rdp_event_event_push(gp, &rdp_event); return FALSE; } diff --git a/plugins/rdp/rdp_plugin.h b/plugins/rdp/rdp_plugin.h index 523c0fa96..de3d3a062 100644 --- a/plugins/rdp/rdp_plugin.h +++ b/plugins/rdp/rdp_plugin.h @@ -111,7 +111,8 @@ typedef enum { 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_TYPE_SEND_MONITOR_LAYOUT, + REMMINA_RDP_EVENT_DISCONNECT } RemminaPluginRdpEventType; struct remmina_plugin_rdp_event { @@ -241,7 +242,8 @@ typedef struct remmina_plugin_rdp_keymap_entry { } RemminaPluginRdpKeymapEntry; struct rf_context { - rdpContext _p; + rdpContext context; + DEFINE_RDP_CLIENT_COMMON(); RemminaProtocolWidget* protocol_widget; @@ -249,7 +251,7 @@ struct rf_context { rdpSettings* settings; freerdp* instance; - pthread_t thread; + pthread_t remmina_plugin_thread; RemminaScaleMode scale; gboolean user_cancelled; gboolean thread_cancelled; @@ -266,6 +268,11 @@ struct rf_context { gboolean connected; gboolean is_reconnecting; + /* 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; @@ -278,7 +285,6 @@ struct rf_context { guint delayed_monitor_layout_handler; gboolean use_client_keymap; - HGDI_DC hdc; gint srcBpp; GdkDisplay* display; GdkVisual* visual; @@ -304,6 +310,8 @@ struct rf_context { 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; }; @@ -316,4 +324,3 @@ 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); - diff --git a/plugins/spice/spice_plugin.c b/plugins/spice/spice_plugin.c index 32219fc75..794a503ce 100644 --- a/plugins/spice/spice_plugin.c +++ b/plugins/spice/spice_plugin.c @@ -157,7 +157,7 @@ static gboolean remmina_plugin_spice_close_connection(RemminaProtocolWidget *gp) spice_session_disconnect(gpdata->session); g_object_unref(gpdata->session); gpdata->session = NULL; - remmina_plugin_service->protocol_plugin_emit_signal(gp, "disconnect"); + remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); } #ifdef SPICE_GTK_CHECK_VERSION @@ -313,7 +313,7 @@ static void remmina_plugin_spice_display_ready_cb(GObject *display, GParamSpec * gtk_widget_show(GTK_WIDGET(display)); remmina_plugin_service->protocol_plugin_register_hostkey(gp, GTK_WIDGET(display)); - remmina_plugin_service->protocol_plugin_emit_signal(gp, "connect"); + remmina_plugin_service->protocol_plugin_signal_connection_opened(gp); } } diff --git a/plugins/st/st_plugin.c b/plugins/st/st_plugin.c index 1b50e705a..5bcc3d9db 100644 --- a/plugins/st/st_plugin.c +++ b/plugins/st/st_plugin.c @@ -68,7 +68,7 @@ static void remmina_plugin_st_on_plug_added(GtkSocket *socket, RemminaProtocolWi RemminaPluginData *gpdata; gpdata = (RemminaPluginData*) g_object_get_data(G_OBJECT(gp), "plugin-data"); remmina_plugin_service->log_printf("[%s] Plugin plug added on socket %d\n", PLUGIN_NAME, gpdata->socket_id); - remmina_plugin_service->protocol_plugin_emit_signal(gp, "connect"); + remmina_plugin_service->protocol_plugin_signal_connection_opened(gp); return; } @@ -76,7 +76,7 @@ static void remmina_plugin_st_on_plug_removed(GtkSocket *socket, RemminaProtocol { TRACE_CALL(__func__); remmina_plugin_service->log_printf("[%s] Plugin plug removed\n", PLUGIN_NAME); - remmina_plugin_service->protocol_plugin_close_connection(gp); + remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); } static void remmina_plugin_st_init(RemminaProtocolWidget *gp) @@ -209,7 +209,7 @@ static gboolean remmina_plugin_st_close_connection(RemminaProtocolWidget *gp) { TRACE_CALL(__func__); remmina_plugin_service->log_printf("[%s] Plugin close connection\n", PLUGIN_NAME); - remmina_plugin_service->protocol_plugin_emit_signal(gp, "disconnect"); + remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); return FALSE; } diff --git a/plugins/vnc/vnc_plugin.c b/plugins/vnc/vnc_plugin.c index 6cf1df80e..08bff2109 100644 --- a/plugins/vnc/vnc_plugin.c +++ b/plugins/vnc/vnc_plugin.c @@ -60,8 +60,6 @@ static const gchar *dot_cursor_xpm[] = #define LOCK_BUFFER(t) if (t) { CANCEL_DEFER } pthread_mutex_lock(&gpdata->buffer_mutex); #define UNLOCK_BUFFER(t) pthread_mutex_unlock(&gpdata->buffer_mutex); if (t) { CANCEL_ASYNC } - - struct onMainThread_cb_data { enum { FUNC_UPDATE_SCALE } func; GtkWidget * widget; @@ -239,7 +237,7 @@ static void remmina_plugin_vnc_update_scale(RemminaProtocolWidget *gp, gboolean /* In non scaled mode, the plugins forces dimensions of drawing area */ gtk_widget_set_size_request(GTK_WIDGET(gpdata->drawing_area), width, height); - remmina_plugin_service->protocol_plugin_emit_signal(gp, "update-align"); + remmina_plugin_service->protocol_plugin_update_align(gp); } gboolean remmina_plugin_vnc_setcursor(RemminaProtocolWidget *gp) @@ -487,7 +485,7 @@ static rfbBool remmina_plugin_vnc_rfb_allocfb(rfbClient *cl) remmina_plugin_vnc_update_scale(gp, scale); /* Notify window of change so that scroll border can be hidden or shown if needed */ - remmina_plugin_service->protocol_plugin_emit_signal(gp, "desktop-resize"); + remmina_plugin_service->protocol_plugin_desktop_resize(gp); /* Refresh the client’s updateRect - bug in xvncclient */ cl->updateRect.w = width; @@ -1027,6 +1025,7 @@ static gboolean remmina_plugin_vnc_incoming_connection(RemminaProtocolWidget *gp return TRUE; } + static gboolean remmina_plugin_vnc_main_loop(RemminaProtocolWidget *gp) { TRACE_CALL(__func__); @@ -1075,7 +1074,7 @@ handle_buffered: if (!HandleRFBServerMessage(cl)) { gpdata->running = FALSE; if (gpdata->connected && !remmina_plugin_service->protocol_plugin_is_closed(gp)) - IDLE_ADD((GSourceFunc)remmina_plugin_service->protocol_plugin_close_connection, gp); + remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); return FALSE; } } @@ -1220,7 +1219,7 @@ static gboolean remmina_plugin_vnc_main(RemminaProtocolWidget *gp) remmina_plugin_service->protocol_plugin_set_error(gp, "%s", vnc_error); gpdata->running = FALSE; - IDLE_ADD((GSourceFunc)remmina_plugin_service->protocol_plugin_close_connection, gp); + remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); return FALSE; } @@ -1229,7 +1228,7 @@ static gboolean remmina_plugin_vnc_main(RemminaProtocolWidget *gp) gpdata->client = cl; - remmina_plugin_service->protocol_plugin_emit_signal(gp, "connect"); + remmina_plugin_service->protocol_plugin_signal_connection_opened(gp); if (remmina_plugin_service->file_get_int(remminafile, "disableserverinput", FALSE)) PermitServerInput(cl, 1); @@ -1609,9 +1608,7 @@ static gboolean remmina_plugin_vnc_close_connection_timeout(RemminaProtocolWidge pthread_mutex_destroy(&gpdata->buffer_mutex); - - - remmina_plugin_service->protocol_plugin_emit_signal(gp, "disconnect"); + remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); return FALSE; } diff --git a/plugins/xdmcp/xdmcp_plugin.c b/plugins/xdmcp/xdmcp_plugin.c index ac8109f07..97f71fc31 100644 --- a/plugins/xdmcp/xdmcp_plugin.c +++ b/plugins/xdmcp/xdmcp_plugin.c @@ -68,14 +68,14 @@ static void remmina_plugin_xdmcp_on_plug_added(GtkSocket *socket, RemminaProtoco TRACE_CALL(__func__); RemminaPluginXdmcpData *gpdata = GET_PLUGIN_DATA(gp); - remmina_plugin_service->protocol_plugin_emit_signal(gp, "connect"); + remmina_plugin_service->protocol_plugin_signal_connection_opened(gp); gpdata->ready = TRUE; } static void remmina_plugin_xdmcp_on_plug_removed(GtkSocket *socket, RemminaProtocolWidget *gp) { TRACE_CALL(__func__); - remmina_plugin_service->protocol_plugin_close_connection(gp); + remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); } static gboolean remmina_plugin_xdmcp_start_xephyr(RemminaProtocolWidget *gp) @@ -228,7 +228,7 @@ remmina_plugin_xdmcp_main_thread(gpointer data) CANCEL_ASYNC if (!remmina_plugin_xdmcp_main((RemminaProtocolWidget*)data)) { - IDLE_ADD((GSourceFunc)remmina_plugin_service->protocol_plugin_close_connection, data); + IDLE_ADD((GSourceFunc)remmina_plugin_service->protocol_plugin_signal_connection_closed, data); } return NULL; } @@ -307,7 +307,7 @@ static gboolean remmina_plugin_xdmcp_close_connection(RemminaProtocolWidget *gp) gpdata->pid = 0; } - remmina_plugin_service->protocol_plugin_emit_signal(gp, "disconnect"); + remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); return FALSE; } @@ -421,4 +421,3 @@ remmina_plugin_entry(RemminaPluginService *service) return TRUE; } - diff --git a/src/include/remmina/plugin.h b/src/include/remmina/plugin.h index 3c28b86f9..d08abd770 100644 --- a/src/include/remmina/plugin.h +++ b/src/include/remmina/plugin.h @@ -165,7 +165,11 @@ typedef struct _RemminaPluginService { gboolean (* protocol_plugin_start_reverse_tunnel)(RemminaProtocolWidget *gp, gint local_port); gboolean (* protocol_plugin_start_xport_tunnel)(RemminaProtocolWidget *gp, RemminaXPortTunnelInitFunc init_func); void (* protocol_plugin_set_display)(RemminaProtocolWidget *gp, gint display); - gboolean (* protocol_plugin_close_connection)(RemminaProtocolWidget *gp); + void (* protocol_plugin_signal_connection_closed)(RemminaProtocolWidget *gp); + void (* protocol_plugin_signal_connection_opened)(RemminaProtocolWidget *gp); + void (* protocol_plugin_update_align)(RemminaProtocolWidget *gp); + void (* protocol_plugin_unlock_dynres)(RemminaProtocolWidget *gp); + void (* protocol_plugin_desktop_resize)(RemminaProtocolWidget *gp); gint (* protocol_plugin_init_authpwd)(RemminaProtocolWidget *gp, RemminaAuthpwdType authpwd_type, gboolean allow_password_saving); gint (* protocol_plugin_init_authuserpwd)(RemminaProtocolWidget *gp, gboolean want_domain, gboolean allow_password_saving); gint (* protocol_plugin_init_certificate)(RemminaProtocolWidget *gp, const gchar* subject, const gchar* issuer, const gchar* fingerprint); @@ -201,7 +205,7 @@ typedef struct _RemminaPluginService { gchar* (*file_get_secret)(RemminaFile * remminafile, const gchar * setting); void (* file_set_int)(RemminaFile *remminafile, const gchar *setting, gint value); gint (* file_get_int)(RemminaFile *remminafile, const gchar *setting, gint default_value); - void (* file_unsave_password)(RemminaFile *remminafile); + void (* file_unsave_passwords)(RemminaFile *remminafile); void (* pref_set_value)(const gchar *key, const gchar *value); gchar* (*pref_get_value)(const gchar * key); @@ -230,5 +234,3 @@ typedef struct _RemminaPluginService { typedef gboolean (*RemminaPluginEntryFunc) (RemminaPluginService *service); G_END_DECLS - - @@ -3701,7 +3701,7 @@ void rco_on_disconnect(RemminaProtocolWidget *gp, gpointer data) RemminaConnectionWindowPriv *priv = cnnobj->cnnwin->priv; GtkWidget *pparent; - g_debug("disconnect signal emitted"); + g_debug("disconnect signal received on RemminaProtocolWidget"); /* Detach the protocol widget from the notebook now, or we risk that a * window delete will destroy cnnobj->proto before we complete disconnection. */ @@ -3729,8 +3729,10 @@ void rco_on_disconnect(RemminaProtocolWidget *gp, gpointer data) RemminaMessagePanel *mp; /* Destroy scrolled_contaner (and viewport) and all its children the plugin created * on it, so they will not receive GUI signals */ - gtk_widget_destroy(cnnobj->scrolled_container); - cnnobj->scrolled_container = NULL; + if (cnnobj->scrolled_container) { + gtk_widget_destroy(cnnobj->scrolled_container); + cnnobj->scrolled_container = NULL; + } cnnobj->viewport = NULL; mp = remmina_message_panel_new(); remmina_message_panel_setup_message(mp, remmina_protocol_widget_get_error_message(gp), cb_lasterror_confirmed, gp); @@ -3829,6 +3831,12 @@ GtkWidget *rcw_open_from_file_full(RemminaFile *remminafile, GCallback disconnec gint view_mode; const gchar *msg; + if (disconnect_cb) { + g_print("disconnect_cb is deprecated inside rcw_open_from_file_full() and should be null"); + return NULL; + } + + /* Create the RemminaConnectionObject */ cnnobj = g_new0(RemminaConnectionObject, 1); cnnobj->remmina_file = remminafile; @@ -3913,8 +3921,6 @@ GtkWidget *rcw_open_from_file_full(RemminaFile *remminafile, GCallback disconnec gtk_widget_show(cnnobj->proto); g_signal_connect(G_OBJECT(cnnobj->proto), "connect", G_CALLBACK(rco_on_connect), cnnobj); - if (disconnect_cb) - *handler = g_signal_connect(G_OBJECT(cnnobj->proto), "disconnect", disconnect_cb, data); g_signal_connect(G_OBJECT(cnnobj->proto), "disconnect", G_CALLBACK(rco_on_disconnect), NULL); g_signal_connect(G_OBJECT(cnnobj->proto), "desktop-resize", G_CALLBACK(rco_on_desktop_resize), NULL); g_signal_connect(G_OBJECT(cnnobj->proto), "update-align", G_CALLBACK(rco_on_update_align), NULL); diff --git a/src/remmina_file.c b/src/remmina_file.c index bfce7113a..eefbb3ffc 100644 --- a/src/remmina_file.c +++ b/src/remmina_file.c @@ -603,13 +603,13 @@ void remmina_file_delete(const gchar *filename) remminafile = remmina_file_load(filename); if (remminafile) { - remmina_file_unsave_password(remminafile); + remmina_file_unsave_passwords(remminafile); remmina_file_free(remminafile); } g_unlink(filename); } -void remmina_file_unsave_password(RemminaFile *remminafile) +void remmina_file_unsave_passwords(RemminaFile *remminafile) { /* Delete all saved secrets for this profile */ diff --git a/src/remmina_file.h b/src/remmina_file.h index 44a559557..01f3914a6 100644 --- a/src/remmina_file.h +++ b/src/remmina_file.h @@ -84,7 +84,7 @@ RemminaFile *remmina_file_dup_temp_protocol(RemminaFile *remminafile, const gcha /* Delete a .remmina file */ void remmina_file_delete(const gchar *filename); /* Delete a "password" field and save into .remmina file */ -void remmina_file_unsave_password(RemminaFile *remminafile); +void remmina_file_unsave_passwords(RemminaFile *remminafile); /* Function used to update the atime and mtime of a given remmina file, partially * taken from suckless sbase */ gchar *remmina_file_get_datetime(RemminaFile *remminafile); diff --git a/src/remmina_plugin_manager.c b/src/remmina_plugin_manager.c index a47b9c5c6..9881ac0df 100644 --- a/src/remmina_plugin_manager.c +++ b/src/remmina_plugin_manager.c @@ -183,7 +183,11 @@ RemminaPluginService remmina_plugin_manager_service = remmina_protocol_widget_start_reverse_tunnel, remmina_protocol_widget_start_xport_tunnel, remmina_protocol_widget_set_display, - remmina_protocol_widget_close_connection, + remmina_protocol_widget_signal_connection_closed, + remmina_protocol_widget_signal_connection_opened, + remmina_protocol_widget_update_align, + remmina_protocol_widget_unlock_dynres, + remmina_protocol_widget_desktop_resize, remmina_protocol_widget_panel_authpwd, remmina_protocol_widget_panel_authuserpwd, remmina_protocol_widget_panel_new_certificate, @@ -217,7 +221,7 @@ RemminaPluginService remmina_plugin_manager_service = remmina_file_get_secret, remmina_file_set_int, remmina_file_get_int, - remmina_file_unsave_password, + remmina_file_unsave_passwords, remmina_pref_set_value, remmina_pref_get_value, @@ -555,7 +559,3 @@ gboolean remmina_plugin_manager_is_encrypted_setting(RemminaProtocolPlugin *pp, return TRUE; } - - - - diff --git a/src/remmina_protocol_widget.c b/src/remmina_protocol_widget.c index 8a1c27c95..e8fbaedc5 100644 --- a/src/remmina_protocol_widget.c +++ b/src/remmina_protocol_widget.c @@ -41,6 +41,8 @@ #include <glib/gi18n.h> #include <stdlib.h> + + #include "remmina_chat_window.h" #include "remmina_masterthread_exec.h" #include "remmina_ext_exec.h" @@ -56,7 +58,6 @@ #include <gdk/gdkwayland.h> #endif - struct _RemminaProtocolWidgetPriv { RemminaFile* remmina_file; @@ -186,28 +187,7 @@ static void remmina_protocol_widget_destroy(RemminaProtocolWidget* gp, gpointer gp->priv = NULL; } -static void remmina_protocol_widget_on_connected(RemminaProtocolWidget* gp, gpointer data) -{ - TRACE_CALL(__func__); -#ifdef HAVE_LIBSSH - if (gp->priv->ssh_tunnel) { - remmina_ssh_tunnel_cancel_accept(gp->priv->ssh_tunnel); - } -#endif - if (gp->priv->listen_message_panel) { - rco_destroy_message_panel(gp->cnnobj, gp->priv->listen_message_panel); - gp->priv->listen_message_panel = NULL; - } - if (gp->priv->connect_message_panel) { - rco_destroy_message_panel(gp->cnnobj, gp->priv->connect_message_panel); - gp->priv->connect_message_panel = NULL; - } -} -static void remmina_protocol_widget_on_disconnected(RemminaProtocolWidget* gp, gpointer data) -{ - TRACE_CALL(__func__); -} void remmina_protocol_widget_grab_focus(RemminaProtocolWidget* gp) { @@ -232,8 +212,6 @@ static void remmina_protocol_widget_init(RemminaProtocolWidget* gp) gp->priv->closed = TRUE; g_signal_connect(G_OBJECT(gp), "destroy", G_CALLBACK(remmina_protocol_widget_destroy), NULL); - g_signal_connect(G_OBJECT(gp), "connect", G_CALLBACK(remmina_protocol_widget_on_connected), NULL); - g_signal_connect(G_OBJECT(gp), "disconnect", G_CALLBACK(remmina_protocol_widget_on_disconnected), NULL); } void remmina_protocol_widget_open_connection_real(gpointer data) @@ -325,63 +303,131 @@ void remmina_protocol_widget_open_connection(RemminaProtocolWidget* gp) remmina_protocol_widget_open_connection_real(gp); } -gboolean remmina_protocol_widget_close_connection(RemminaProtocolWidget* gp) +static gboolean conn_closed(RemminaProtocolWidget* gp) { - TRACE_CALL(__func__); - GdkDisplay *display; -#if GTK_CHECK_VERSION(3, 20, 0) - GdkSeat *seat; -#else - GdkDeviceManager *manager; -#endif - GdkDevice *device = NULL; - gboolean retval; - - if (!GTK_IS_WIDGET(gp) || gp->priv->closed) - return FALSE; + /* Close ssh tunnel */ + #ifdef HAVE_LIBSSH + if (gp->priv->ssh_tunnel) { + remmina_ssh_tunnel_free(gp->priv->ssh_tunnel); + gp->priv->ssh_tunnel = NULL; + } + #endif + /* Exec postcommand */ + remmina_ext_exec_new(gp->priv->remmina_file, "postcommand"); + /* Notify listeners (usually rcw) that the connection is closed */ + g_signal_emit_by_name(G_OBJECT(gp), "disconnect"); + return G_SOURCE_REMOVE; +} +void remmina_protocol_widget_signal_connection_closed(RemminaProtocolWidget* gp) +{ + /* Plugin told us that it closed the connection, + add async event to main thread to complete our close tasks */ + TRACE_CALL(__func__); gp->priv->closed = TRUE; + g_idle_add(conn_closed, (gpointer)gp); +} - display = gtk_widget_get_display(GTK_WIDGET(gp)); -#if GTK_CHECK_VERSION(3, 20, 0) - seat = gdk_display_get_default_seat(display); - device = gdk_seat_get_pointer(seat); -#else - manager = gdk_display_get_device_manager(display); - device = gdk_device_manager_get_client_pointer(manager); -#endif - if (device != NULL) { -#if GTK_CHECK_VERSION(3, 20, 0) - gdk_seat_ungrab(seat); -#else - gdk_device_ungrab(device, GDK_CURRENT_TIME); +static gboolean conn_opened(RemminaProtocolWidget* gp) +{ + TRACE_CALL(__func__); +#ifdef HAVE_LIBSSH + if (gp->priv->ssh_tunnel) { + remmina_ssh_tunnel_cancel_accept(gp->priv->ssh_tunnel); + } #endif + if (gp->priv->listen_message_panel) { + rco_destroy_message_panel(gp->cnnobj, gp->priv->listen_message_panel); + gp->priv->listen_message_panel = NULL; } + if (gp->priv->connect_message_panel) { + rco_destroy_message_panel(gp->cnnobj, gp->priv->connect_message_panel); + gp->priv->connect_message_panel = NULL; + } + g_signal_emit_by_name(G_OBJECT(gp), "connect"); + return G_SOURCE_REMOVE; +} + +void remmina_protocol_widget_signal_connection_opened(RemminaProtocolWidget* gp) +{ + /* Plugin told us that it closed the connection, + add async event to main thread to complete our close tasks */ + TRACE_CALL(__func__); + g_idle_add(conn_opened, (gpointer)gp); +} + +static gboolean update_align(RemminaProtocolWidget* gp) +{ + g_signal_emit_by_name(G_OBJECT(gp), "update-align"); + return G_SOURCE_REMOVE; +} + +void remmina_protocol_widget_update_align(RemminaProtocolWidget* gp) +{ + /* Called by the plugin to do updates on rcw */ + TRACE_CALL(__func__); + g_idle_add(update_align, (gpointer)gp); +} + +static gboolean unlock_dynres(RemminaProtocolWidget* gp) +{ + g_signal_emit_by_name(G_OBJECT(gp), "unlock-dynres"); + return G_SOURCE_REMOVE; +} + +void remmina_protocol_widget_unlock_dynres(RemminaProtocolWidget* gp) +{ + /* Called by the plugin to do updates on rcw */ + TRACE_CALL(__func__); + g_idle_add(unlock_dynres, (gpointer)gp); +} + +static gboolean desktop_resize(RemminaProtocolWidget* gp) +{ + g_signal_emit_by_name(G_OBJECT(gp), "desktop-resize"); + return G_SOURCE_REMOVE; +} + +void remmina_protocol_widget_desktop_resize(RemminaProtocolWidget* gp) +{ + /* Called by the plugin to do updates on rcw */ + TRACE_CALL(__func__); + g_idle_add(desktop_resize, (gpointer)gp); +} + + +void remmina_protocol_widget_close_connection(RemminaProtocolWidget* gp) +{ + TRACE_CALL(__func__); + + /* kindly ask the protocol plugin to close the connection. + Nothing else is done here. */ + + if (!GTK_IS_WIDGET(gp)) + return; if (gp->priv->chat_window) { gtk_widget_destroy(gp->priv->chat_window); gp->priv->chat_window = NULL; } - if (!gp->priv->plugin || !gp->priv->plugin->close_connection) { - remmina_protocol_widget_emit_signal(gp, "disconnect"); - return FALSE; + if (gp->priv->closed) { + /* Connection is already closed by the plugin, but + * rcw is asking to close again (usually after an error panel) + */ + g_signal_emit_by_name(G_OBJECT(gp), "disconnect"); + return; } - retval = gp->priv->plugin->close_connection(gp); + /* Ask the plugin to close, async. + The plugin will emit a "disconnect" signal on gp to call our + remmina_protocol_widget_on_disconnected() when done */ + gp->priv->plugin->close_connection(gp); -#ifdef HAVE_LIBSSH - if (gp->priv->ssh_tunnel) { - remmina_ssh_tunnel_free(gp->priv->ssh_tunnel); - gp->priv->ssh_tunnel = NULL; - } -#endif - - /* Exec postcommand before to close the connection */ - remmina_ext_exec_new(gp->priv->remmina_file, "postcommand"); - return retval; + return; } + /** Check if the plugin accepts keystrokes. */ gboolean remmina_protocol_widget_plugin_receives_keystrokes(RemminaProtocolWidget* gp) @@ -488,6 +534,9 @@ void remmina_protocol_widget_emit_signal(RemminaProtocolWidget* gp, const gchar* { TRACE_CALL(__func__); + g_print("Emitting signals should be used from the object itself, not from another object"); + raise(SIGINT); + if ( !remmina_masterthread_exec_is_main_thread() ) { /* Allow the execution of this function from a non main thread */ RemminaMTExecData *d; @@ -1756,6 +1805,3 @@ void remmina_protocol_widget_update_remote_resolution(RemminaProtocolWidget* gp) gp->priv->profile_remote_width = w; gp->priv->profile_remote_height = h; } - - - diff --git a/src/remmina_protocol_widget.h b/src/remmina_protocol_widget.h index 9b8d87407..566f6d94b 100644 --- a/src/remmina_protocol_widget.h +++ b/src/remmina_protocol_widget.h @@ -94,7 +94,12 @@ gboolean remmina_protocol_widget_is_closed(RemminaProtocolWidget *gp); RemminaFile* remmina_protocol_widget_get_file(RemminaProtocolWidget *gp); void remmina_protocol_widget_open_connection(RemminaProtocolWidget *gp); -gboolean remmina_protocol_widget_close_connection(RemminaProtocolWidget *gp); +void remmina_protocol_widget_close_connection(RemminaProtocolWidget *gp); +void remmina_protocol_widget_signal_connection_closed(RemminaProtocolWidget *gp); +void remmina_protocol_widget_signal_connection_opened(RemminaProtocolWidget *gp); +void remmina_protocol_widget_update_align(RemminaProtocolWidget *gp); +void remmina_protocol_widget_unlock_dynres(RemminaProtocolWidget *gp); +void remmina_protocol_widget_desktop_resize(RemminaProtocolWidget *gp); void remmina_protocol_widget_grab_focus(RemminaProtocolWidget *gp); const RemminaProtocolFeature* remmina_protocol_widget_get_features(RemminaProtocolWidget *gp); gboolean remmina_protocol_widget_query_feature_by_type(RemminaProtocolWidget *gp, RemminaProtocolFeatureType type); @@ -169,5 +174,3 @@ void remmina_protocol_widget_mpdestroy(RemminaConnectionObject *cnnobj, RemminaM G_END_DECLS - - diff --git a/src/remmina_sftp_plugin.c b/src/remmina_sftp_plugin.c index 09bcb113b..f16dc9823 100644 --- a/src/remmina_sftp_plugin.c +++ b/src/remmina_sftp_plugin.c @@ -177,7 +177,7 @@ remmina_plugin_sftp_main_thread(gpointer data) } if (!cont) { if (sftp) remmina_sftp_free(sftp); - IDLE_ADD((GSourceFunc)remmina_plugin_service->protocol_plugin_close_connection, gp); + IDLE_ADD((GSourceFunc)remmina_plugin_service->protocol_plugin_signal_connection_closed, gp); return NULL; } diff --git a/src/remmina_ssh_plugin.c b/src/remmina_ssh_plugin.c index 15e6fbeb8..e1d6752de 100644 --- a/src/remmina_ssh_plugin.c +++ b/src/remmina_ssh_plugin.c @@ -288,7 +288,7 @@ remmina_plugin_ssh_main_thread(gpointer data) if (remmina_ssh_init_session(REMMINA_SSH(shell)) && remmina_ssh_auth(REMMINA_SSH(shell), NULL, gp, remminafile) > 0 && remmina_ssh_shell_open(shell, (RemminaSSHExitFunc) - remmina_plugin_service->protocol_plugin_close_connection, gp)) + remmina_plugin_service->protocol_plugin_signal_connection_closed, gp)) cont = TRUE; } else { /* New SSH Shell connection */ @@ -313,7 +313,7 @@ remmina_plugin_ssh_main_thread(gpointer data) if (ret <= 0) break; if (!remmina_ssh_shell_open(shell, (RemminaSSHExitFunc) - remmina_plugin_service->protocol_plugin_close_connection, gp)) { + remmina_plugin_service->protocol_plugin_signal_connection_closed, gp)) { remmina_plugin_service->protocol_plugin_set_error(gp, "%s", REMMINA_SSH(shell)->error); break; } @@ -328,7 +328,7 @@ remmina_plugin_ssh_main_thread(gpointer data) } if (!cont) { if (shell) remmina_ssh_shell_free(shell); - IDLE_ADD((GSourceFunc)remmina_plugin_service->protocol_plugin_close_connection, gp); + IDLE_ADD((GSourceFunc)remmina_plugin_service->protocol_plugin_signal_connection_closed, gp); return NULL; } |