diff --git a/doc/geany.txt b/doc/geany.txt index fa826de5f8..9a5ddea376 100644 --- a/doc/geany.txt +++ b/doc/geany.txt @@ -2674,6 +2674,12 @@ number_non_ft_menu_items The maximum number of menu items in the 3 independent build section. number_exec_menu_items The maximum number of menu items in the 2 on restart execute section of the Build menu. +**``socket`` group** +socket_remote_cmd_port TCP port number to be used for inter 2 on restart + process communication (i.e. with other + Geany instances, e.g. "Open with Geany"). + Only available on Windows, valid port + range: 1024 to 65535. ================================ =========================================== ========== =========== Statusbar Templates diff --git a/src/keyfile.c b/src/keyfile.c index a5f6e9dfdf..d7ac4bad4d 100644 --- a/src/keyfile.c +++ b/src/keyfile.c @@ -46,6 +46,7 @@ #include "printing.h" #include "project.h" #include "sciwrappers.h" +#include "socket.h" #include "stash.h" #include "support.h" #include "symbols.h" @@ -274,6 +275,14 @@ static void init_pref_groups(void) stash_group_add_boolean(group, &search_prefs.replace_and_find_by_default, "replace_and_find_by_default", TRUE); + group = stash_group_new(PACKAGE); + configuration_add_various_pref_group(group, "socket"); + +#ifdef G_OS_WIN32 + stash_group_add_integer(group, (gint*)&prefs.socket_remote_cmd_port, + "socket_remote_cmd_port", SOCKET_WINDOWS_REMOTE_CMD_PORT); +#endif + /* Note: Interface-related various prefs are in ui_init_prefs() */ /* various build-menu prefs */ diff --git a/src/libmain.c b/src/libmain.c index e161623abf..22ae4556ab 100644 --- a/src/libmain.c +++ b/src/libmain.c @@ -395,6 +395,34 @@ static void get_line_and_column_from_filename(gchar *filename, gint *line, gint #ifdef G_OS_WIN32 +static gint get_windows_socket_port(void) +{ + /* Read config file early to get TCP port number as we need it for IPC before all + * other settings are read in load_settings() */ + gchar *configfile = g_build_filename(app->configdir, "geany.conf", NULL); + GKeyFile *config = g_key_file_new(); + gint port_number; + + if (! g_file_test(configfile, G_FILE_TEST_IS_REGULAR)) + { + geany_debug( + "No user config file found, use default TCP port (%s).", + SOCKET_WINDOWS_REMOTE_CMD_PORT); + g_free(configfile); + return SOCKET_WINDOWS_REMOTE_CMD_PORT; + } + g_key_file_load_from_file(config, configfile, G_KEY_FILE_NONE, NULL); + port_number = utils_get_setting_integer(config, PACKAGE, "socket_remote_cmd_port", + SOCKET_WINDOWS_REMOTE_CMD_PORT); + geany_debug("Using TCP port number %d for IPC", port_number); + g_free(configfile); + g_key_file_free(config); + g_return_val_if_fail(port_number >= 1024 && port_number <= (gint)G_MAXUINT16, + SOCKET_WINDOWS_REMOTE_CMD_PORT); + return port_number; +} + + static void change_working_directory_on_windows(void) { gchar *install_dir = win32_get_installation_dir(); @@ -1089,9 +1117,13 @@ gint main_lib(gint argc, gchar **argv) /* check and create (unix domain) socket for remote operation */ if (! socket_info.ignore_socket) { + gushort socket_port = 0; +#ifdef G_OS_WIN32 + socket_port = (gushort) get_windows_socket_port(); +#endif socket_info.lock_socket = -1; socket_info.lock_socket_tag = 0; - socket_info.lock_socket = socket_init(argc, argv); + socket_info.lock_socket = socket_init(argc, argv, socket_port); /* Quit if filenames were sent to first instance or the list of open * documents has been printed */ if ((socket_info.lock_socket == -2 /* socket exists */ && argc > 1) || diff --git a/src/prefs.h b/src/prefs.h index dcf33a5029..09b8c7ba6d 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -39,6 +39,9 @@ typedef struct GeanyPrefs gchar *default_open_path; /**< Default path to look for files when no other path is appropriate. */ gchar *custom_plugin_path; gboolean save_wingeom; +#ifdef G_OS_WIN32 + gint socket_remote_cmd_port; +#endif } GeanyPrefs; diff --git a/src/socket.c b/src/socket.c index d667b40bde..26e23c8c42 100644 --- a/src/socket.c +++ b/src/socket.c @@ -95,7 +95,6 @@ #ifdef G_OS_WIN32 -#define REMOTE_CMD_PORT 49876 #define SOCKET_IS_VALID(s) ((s) != INVALID_SOCKET) #else #define SOCKET_IS_VALID(s) ((s) >= 0) @@ -248,7 +247,7 @@ static void check_socket_permissions(void) * (taken from Sylpheed, thanks) * Returns the created socket, -1 if an error occurred or -2 if another socket exists and files * were sent to it. */ -gint socket_init(gint argc, gchar **argv) +gint socket_init(gint argc, gchar **argv, G_GNUC_UNUSED gushort socket_port) { gint sock; #ifdef G_OS_WIN32 @@ -269,13 +268,13 @@ gint socket_init(gint argc, gchar **argv) * and which is unused. This port number has to be guessed by the first and new instance * and the only data is the configuration directory path. * For now we use one port number, that is we support only one instance at all. */ - sock = socket_fd_open_inet(REMOTE_CMD_PORT); + sock = socket_fd_open_inet(socket_port); if (sock < 0) return -1; return sock; } - sock = socket_fd_connect_inet(REMOTE_CMD_PORT); + sock = socket_fd_connect_inet(socket_port); if (sock < 0) return -1; #else diff --git a/src/socket.h b/src/socket.h index 4bc017c6bc..d81645e46b 100644 --- a/src/socket.h +++ b/src/socket.h @@ -26,6 +26,11 @@ G_BEGIN_DECLS +/* Used on Windows for TCP socket based IPC. + * The port number is just random but should be below 49152 as Hyper-V tends to bind + * dynamic port ranges from 49152 to 65535. */ +#define SOCKET_WINDOWS_REMOTE_CMD_PORT 45937 + struct SocketInfo { gboolean ignore_socket; @@ -37,7 +42,7 @@ struct SocketInfo extern struct SocketInfo socket_info; -gint socket_init(gint argc, gchar **argv); +gint socket_init(gint argc, gchar **argv, gushort socket_port); gboolean socket_lock_input_cb(GIOChannel *source, GIOCondition condition, gpointer data);