diff options
-rw-r--r-- | plugins/st/CMakeLists.txt | 54 | ||||
-rw-r--r-- | plugins/st/scalable/emblems/remmina-tool-symbolic.svg | 85 | ||||
-rw-r--r-- | plugins/st/st_plugin.c | 305 | ||||
-rw-r--r-- | plugins/st/st_plugin_config.h | 46 |
4 files changed, 490 insertions, 0 deletions
diff --git a/plugins/st/CMakeLists.txt b/plugins/st/CMakeLists.txt new file mode 100644 index 0000000..91a7d51 --- /dev/null +++ b/plugins/st/CMakeLists.txt @@ -0,0 +1,54 @@ +# remmina-plugin-st - The GTK+ Remote Desktop Client +# +# Copyright (C) 2016-2021 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. + + +set(REMMINA_PLUGIN_ST_SRCS + st_plugin_config.h + st_plugin.c +) + +add_library(remmina-plugin-st MODULE ${REMMINA_PLUGIN_ST_SRCS}) +set_target_properties(remmina-plugin-st PROPERTIES PREFIX "") +set_target_properties(remmina-plugin-st PROPERTIES NO_SONAME 1) + +include_directories(${REMMINA_COMMON_INCLUDE_DIRS} ${GTK_INCLUDE_DIRS}) +target_link_libraries(remmina-plugin-st ${REMMINA_COMMON_LIBRARIES}) + +install(TARGETS remmina-plugin-st DESTINATION ${REMMINA_PLUGINDIR}) + +install(FILES + scalable/emblems/remmina-tool-symbolic.svg + DESTINATION ${APPICONSCALE_EMBLEMS_DIR}) + +if(WITH_ICON_CACHE) + gtk_update_icon_cache("${REMMINA_DATADIR}/icons/hicolor") +endif() diff --git a/plugins/st/scalable/emblems/remmina-tool-symbolic.svg b/plugins/st/scalable/emblems/remmina-tool-symbolic.svg new file mode 100644 index 0000000..e5225de --- /dev/null +++ b/plugins/st/scalable/emblems/remmina-tool-symbolic.svg @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="99.772003" + height="100.72199" + viewBox="0 0 26.39801 26.649359" + version="1.1" + id="svg8" + inkscape:version="0.92.3 (2405546, 2018-03-11)" + sodipodi:docname="exec.svg"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:zoom="2.9679935" + inkscape:cx="50.5106" + inkscape:cy="35.232277" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:document-rotation="0" + showgrid="false" + borderlayer="true" + inkscape:showpageshadow="true" + units="px" + inkscape:pagecheckerboard="false" + showguides="true" + inkscape:window-width="1366" + inkscape:window-height="715" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + objecttolerance="10" + guidetolerance="10" + inkscape:snap-tangential="true" + inkscape:snap-perpendicular="true" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0"> + <inkscape:grid + type="xygrid" + id="grid10" + dotted="false" + originx="-171.36867" + originy="-105.18187" /> + </sodipodi:namedview> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + <cc:license + rdf:resource="" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-171.36866,-165.16877)"> + <path + d="m 189.51722,165.16877 v 0.22886 l -8.68441,11.84222 c 0.25135,0.073 0.49873,0.15902 0.74109,0.25797 -0.86016,-0.34845 -1.79599,-0.55112 -2.78077,-0.55112 -1.9685,0 -3.85524,0.78554 -5.24616,2.17831 -0.39237,0.39291 -0.73924,0.82841 -1.03452,1.29858 l 3.4544,3.4544 -2.30399,3.14192 c 0.55113,1.06389 1.41949,1.92987 2.48444,2.47809 l 3.13875,-2.30082 3.45758,3.45758 c 0.46937,-0.29634 0.90381,-0.64426 1.2954,-1.03743 1.39276,-1.39092 2.17646,-3.27793 2.17831,-5.24616 0,-0.95885 -0.19738,-1.86875 -0.52837,-2.71013 0.09,0.21855 0.1696,0.44106 0.23839,0.66702 l 11.83931,-8.90985 z m -13.34082,0.37068 -4.66592,4.6691 6.0579,6.05499 4.66619,-4.66593 z m 15.39029,15.39028 -4.6662,4.66911 6.05817,6.05816 4.66619,-4.66937 z m -18.96401,7.42421 -1.23402,1.81425 1.64968,1.64994 1.68222,-1.23428 c -0.83318,-0.55086 -1.54676,-1.26444 -2.09788,-2.09762 z" + id="path32" + inkscape:connector-curvature="0" + style="isolation:isolate;fill:#171717;stroke-width:0.26458332" /> + </g> +</svg> diff --git a/plugins/st/st_plugin.c b/plugins/st/st_plugin.c new file mode 100644 index 0000000..f5512a0 --- /dev/null +++ b/plugins/st/st_plugin.c @@ -0,0 +1,305 @@ +/* + * Remmina - The GTK+ Remote Desktop Client + * Copyright (C) 2017-2021 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. + * + */ + +#include "st_plugin_config.h" + +#include "common/remmina_plugin.h" + +#include <gdk/gdkkeysyms.h> +#include <gtk/gtk.h> +#include <gtk/gtkx.h> +#include <glib.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <unistd.h> + +#define REMMINA_PLUGIN_ST_FEATURE_GTKSOCKET 1 + +typedef struct _RemminaPluginData +{ + GtkWidget *socket; + gint socket_id; + GPid pid; +} RemminaPluginData; + +static RemminaPluginService *remmina_plugin_service = NULL; +#define REMMINA_PLUGIN_DEBUG(fmt, ...) remmina_plugin_service->_remmina_debug(__func__, fmt, ##__VA_ARGS__) + +static gboolean remmina_st_query_feature(RemminaProtocolWidget* gp, const RemminaProtocolFeature* feature) +{ + TRACE_CALL(__func__); + return TRUE; +} + + +static void remmina_plugin_st_on_plug_added(GtkSocket *socket, RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + RemminaPluginData *gpdata; + gpdata = (RemminaPluginData*) g_object_get_data(G_OBJECT(gp), "plugin-data"); + REMMINA_PLUGIN_DEBUG("[%s] Plugin plug added on socket %d", PLUGIN_NAME, gpdata->socket_id); + remmina_plugin_service->protocol_plugin_signal_connection_opened(gp); + return; +} + +static void remmina_plugin_st_on_plug_removed(GtkSocket *socket, RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + REMMINA_PLUGIN_DEBUG("[%s] Plugin plug removed", PLUGIN_NAME); + remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); +} + +static void remmina_plugin_st_init(RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + REMMINA_PLUGIN_DEBUG("[%s] Plugin init", PLUGIN_NAME); + RemminaPluginData *gpdata; + + gpdata = g_new0(RemminaPluginData, 1); + g_object_set_data_full(G_OBJECT(gp), "plugin-data", gpdata, g_free); + + gpdata->socket = gtk_socket_new(); + remmina_plugin_service->protocol_plugin_register_hostkey(gp, gpdata->socket); + gtk_widget_show(gpdata->socket); + g_signal_connect(G_OBJECT(gpdata->socket), "plug-added", G_CALLBACK(remmina_plugin_st_on_plug_added), gp); + g_signal_connect(G_OBJECT(gpdata->socket), "plug-removed", G_CALLBACK(remmina_plugin_st_on_plug_removed), gp); + gtk_container_add(GTK_CONTAINER(gp), gpdata->socket); +} + +static gboolean remmina_plugin_st_open_connection(RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + REMMINA_PLUGIN_DEBUG("[%s] Plugin open connection", PLUGIN_NAME); +#define ADD_ARGUMENT(name, value) \ + { \ + argv[argc] = g_strdup(name); \ + argv_debug[argc] = g_strdup(name); \ + argc++; \ + if (value != NULL) \ + { \ + argv[argc] = value; \ + argv_debug[argc++] = g_strdup(g_strcmp0(name, "-p") != 0 ? value : "XXXXX"); \ + } \ + } + RemminaPluginData *gpdata; + RemminaFile *remminafile; + GError *error = NULL; + gchar *argv[50]; // Contains all the arguments + gchar *argv_debug[50]; // Contains all the arguments + gchar *command_line; // The whole command line obtained from argv_debug + const gchar *term; // Terminal emulator name from remimna profile. + const gchar *wflag = NULL; + const gchar *command; // The command to be passed to the terminal (if any) + gboolean isterm = FALSE; + gint argc; + gint i; + + gpdata = (RemminaPluginData*) g_object_get_data(G_OBJECT(gp), "plugin-data"); + remminafile = remmina_plugin_service->protocol_plugin_get_file(gp); + + if (!remmina_plugin_service->file_get_int(remminafile, "detached", FALSE)) { + remmina_plugin_service->protocol_plugin_set_width(gp, 640); + remmina_plugin_service->protocol_plugin_set_height(gp, 480); + gtk_widget_set_size_request(GTK_WIDGET(gp), 640, 480); + gpdata->socket_id = gtk_socket_get_id(GTK_SOCKET(gpdata->socket)); + } + + term = remmina_plugin_service->file_get_string(remminafile, "terminal"); + + if (g_strcmp0(term, "st") == 0) { + /* on Debian based distros st is packaged as stterm */ + if (!g_find_program_in_path(term)) + term = "stterm"; + wflag = "-w"; + isterm = TRUE; + }else if (g_strcmp0(term, "urxvt") == 0) { + wflag = "-embed"; + isterm = TRUE; + }else if (g_strcmp0(term, "xterm") == 0) { + wflag = "-xrm 'XTerm*allowSendEvents: true' -into"; + isterm = TRUE; + }else if (g_strcmp0(term, "vim") == 0) { + wflag = "-g --socketid"; + isterm = FALSE; + }else if (g_strcmp0(term, "emacs") == 0) { + wflag = "--parent-id"; + isterm = FALSE; + } + if (!g_find_program_in_path(term)) { + remmina_plugin_service->protocol_plugin_set_error(gp, "%s not found", term); + return FALSE; + } + + argc = 0; + // Main executable name + ADD_ARGUMENT(g_strdup_printf("%s", term), NULL); + // Embed st-window in another window + if (gpdata->socket_id != 0) + ADD_ARGUMENT(g_strdup(wflag), g_strdup_printf("%i", gpdata->socket_id)); + // Add eventually any additional arguments set by the user + command = remmina_plugin_service->file_get_string(remminafile, "cmd"); + if(command && isterm) + ADD_ARGUMENT("-e", g_strdup_printf("%s", command)); + if(command && !isterm) + ADD_ARGUMENT("", g_strdup_printf("%s", command)); + // End of the arguments list + ADD_ARGUMENT(NULL, NULL); + // Retrieve the whole command line + command_line = g_strjoinv(g_strdup(" "), (gchar **)&argv_debug[0]); + REMMINA_PLUGIN_DEBUG("[%s] starting %s", PLUGIN_NAME, command_line); + // Execute the external process st + g_spawn_command_line_async(command_line, &error); + g_free(command_line); + + // Free the arguments list + for (i = 0; i < argc; i++) + { + g_free(argv_debug[i]); + g_free(argv[i]); + } + // Show error message + if (error) { + remmina_plugin_service->protocol_plugin_set_error(gp, "%s", error->message); + g_error_free(error); + return FALSE; + } + // Show attached window socket ID + if (!remmina_plugin_service->file_get_int(remminafile, "detached", FALSE)) { + REMMINA_PLUGIN_DEBUG("[%s] attached window to socket %d", + PLUGIN_NAME, gpdata->socket_id); + return TRUE; + } + else + { + return FALSE; + } +} + +static gboolean remmina_plugin_st_close_connection(RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + REMMINA_PLUGIN_DEBUG("[%s] Plugin close connection", PLUGIN_NAME); + remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); + return FALSE; +} + +static gpointer term_list[] = +{ + "st", "Suckless Simple Terminal", + "urxvt", "rxvt-unicode", + "xterm", "Xterm", + "emacs", "GNU Emacs", + "vim", "Vim Text Editor", + NULL +}; + +/* Array of RemminaProtocolSetting for basic settings. + * Each item is composed by: + * a) RemminaProtocolSettingType for setting type + * b) Setting name + * c) Setting description + * d) Compact disposition + * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO + * f) Setting Tooltip + */ +static const RemminaProtocolSetting remmina_plugin_st_basic_settings[] = +{ + { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "terminal", N_("Terminal Emulator"), FALSE, term_list, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "cmd", N_("Command to be executed"), FALSE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL } +}; + +/* Array of RemminaProtocolSetting for advanced settings. + * Each item is composed by: + * a) RemminaProtocolSettingType for setting type + * b) Setting name + * c) Setting description + * d) Compact disposition + * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO + * f) Setting Tooltip + */ +static const RemminaProtocolSetting remmina_plugin_st_advanced_settings[] = +{ + { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "detached", N_("Detached window"), TRUE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL } +}; + +/* Array for available features. + * The last element of the array must be REMMINA_PROTOCOL_FEATURE_TYPE_END. */ +static const RemminaProtocolFeature remmina_st_features[] = +{ + { REMMINA_PROTOCOL_FEATURE_TYPE_GTKSOCKET, REMMINA_PLUGIN_ST_FEATURE_GTKSOCKET, NULL, NULL, NULL}, + { REMMINA_PROTOCOL_FEATURE_TYPE_END, 0, NULL, NULL, NULL} +}; + +/* Protocol plugin definition and features */ +static RemminaProtocolPlugin remmina_plugin = +{ + REMMINA_PLUGIN_TYPE_PROTOCOL, // Type + PLUGIN_NAME, // Name + PLUGIN_DESCRIPTION, // Description + GETTEXT_PACKAGE, // Translation domain + PLUGIN_VERSION, // Version number + PLUGIN_APPICON, // Icon for normal connection + PLUGIN_APPICON, // Icon for SSH connection + remmina_plugin_st_basic_settings, // Array for basic settings + remmina_plugin_st_advanced_settings, // Array for advanced settings + REMMINA_PROTOCOL_SSH_SETTING_NONE, // SSH settings type + remmina_st_features, // Array for available features + remmina_plugin_st_init, // Plugin initialization + remmina_plugin_st_open_connection, // Plugin open connection + remmina_plugin_st_close_connection, // Plugin close connection + remmina_st_query_feature, // Query for available features + NULL, // Call a feature + NULL, // Send a keystroke + NULL, // Capture screenshot + NULL, // RCW map event + NULL // RCW unmap event +}; + +G_MODULE_EXPORT gboolean remmina_plugin_entry(RemminaPluginService *service) +{ + TRACE_CALL(__func__); + remmina_plugin_service = service; + + bindtextdomain(GETTEXT_PACKAGE, REMMINA_RUNTIME_LOCALEDIR); + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); + + + if (!service->register_plugin((RemminaPlugin *) &remmina_plugin)) + { + return FALSE; + } + return TRUE; +} diff --git a/plugins/st/st_plugin_config.h b/plugins/st/st_plugin_config.h new file mode 100644 index 0000000..2733849 --- /dev/null +++ b/plugins/st/st_plugin_config.h @@ -0,0 +1,46 @@ +/* + * Remmina - The GTK+ Remote Desktop Client + * Copyright (C) 2016-2021 Antenore Gatta, Giovanni Panozzo + * + * Initially based on the plugin "Remmina Plugin EXEC", created and written by + * Fabio Castelli (Muflone) <muflone@vbsimple.net>. + * + * 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 +#ifndef __PLUGIN_CONFIG_H +#define __PLUGIN_CONFIG_H + +#define PLUGIN_NAME "ST" +#define PLUGIN_DESCRIPTION N_("Remmina simple terminal") +#define PLUGIN_VERSION "1.0.0.0" +#define PLUGIN_APPICON "remmina-tool-symbolic" +#endif |