diff --git a/src/main.c b/src/main.c
index 1b195e7..ccae4b9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -118,8 +118,15 @@ static gboolean no_plugins = FALSE;
 static gboolean dummy = FALSE;
 static gchar * libsm_client_id = NULL;
 
+/* WARNING: Do not change values of variables where values of command-line options are stored!
+ * This is, they must remain unchanged after `g_option_context_parse' returns.
+ * Otherwise, "restart command" for X session management will be filled improperly.
+ *
+ * NOTE: Currently optentries of type G_OPTION_ARG_CALLBACK are not supported by
+ * X session management support implementation.
+ */
 /* in alphabetical order of short options */
-static GOptionEntry entries[] =
+GOptionEntry optentries[] =
 {
 	{ "column", 0, 0, G_OPTION_ARG_INT, &cl_options.goto_column, N_("Set initial column number for the first opened file (useful in conjunction with --line)"), NULL },
 	{ "config", 'c', 0, G_OPTION_ARG_FILENAME, &alternate_config, N_("Use an alternate configuration directory"), NULL },
@@ -146,9 +153,38 @@ static GOptionEntry entries[] =
 	{ "version", 'V', 0, G_OPTION_ARG_NONE, &show_version, N_("Show version and exit"), NULL },
 	{ "dummy", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &dummy, NULL, NULL }, /* for +NNN line number arguments */
 	{ "libsm-client-id", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &libsm_client_id, NULL, NULL },
+	/* add new options here and in `optentries_aux' below */
 	{ NULL, 0, 0, 0, NULL, NULL, NULL }
 };
 
+GeanyOptionEntryAux optentries_aux[] = {
+	{FALSE}, /* "column" */
+	{TRUE},  /* "config" */
+	{FALSE}, /* "ft-names */
+	{FALSE}, /* "generate-tags" */
+	{FALSE}, /* "no-preprocessing" */
+#ifdef HAVE_SOCKET
+	{TRUE},  /* "new-instance" */
+	{TRUE},  /* "socket-file" */
+#endif
+	{FALSE}, /* "line" */
+	{TRUE},  /* "no-msgwin" */
+	{TRUE},  /* "no-ctags" */
+#ifdef HAVE_PLUGINS
+	{TRUE},  /* "no-plugins" */
+#endif
+	{FALSE}, /* "print-prefix" */
+	{TRUE},  /* "no-session" */
+#ifdef HAVE_VTE
+	{TRUE},  /* "no-terminal" */
+	{TRUE},  /* "vte-lib" */
+#endif
+	{TRUE},  /* "verbose" */
+	{FALSE}, /* "version" */
+	{FALSE}, /* "dummy" */
+	{FALSE}, /* "libsm-client-id" option is handled separately */
+};
+
 
 static void setup_window_position(void)
 {
@@ -489,7 +525,7 @@ static void parse_command_line_options(gint *argc, gchar ***argv)
 	}
 
 	context = g_option_context_new(_("[FILES...]"));
-	g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE);
+	g_option_context_add_main_entries(context, optentries, GETTEXT_PACKAGE);
 	g_option_group_set_translation_domain(g_option_context_get_main_group(context), GETTEXT_PACKAGE);
 	g_option_context_add_group(context, gtk_get_option_group(FALSE));
 	g_option_context_parse(context, argc, argv, &error);
diff --git a/src/main.h b/src/main.h
index ee8572f..87d1c0e 100644
--- a/src/main.h
+++ b/src/main.h
@@ -25,6 +25,20 @@
 #ifndef GEANY_MAIN_H
 #define GEANY_MAIN_H
 
+/** Information about command line entries that can not be stored in GOptionEntry. */
+typedef struct
+{
+	/**
+	 * Indicates whether the value of a command-line option should go to "restart command".
+	 * See X session management support implementation in sm.{c,h}.
+	 */
+	gboolean persist_upon_restart;
+}
+GeanyOptionEntryAux;
+
+extern GOptionEntry optentries[];
+extern GeanyOptionEntryAux optentries_aux[];
+
 typedef struct
 {
 	gboolean	new_instance;
diff --git a/src/sm.c b/src/sm.c
index c5767e7..957181f 100644
--- a/src/sm.c
+++ b/src/sm.c
@@ -390,53 +390,37 @@ static void sm_set_constant_props(SmcConn smcon)
  */
 static void sm_set_runtime_props(SmcConn smcon)
 {
-	const gint page_count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(main_widgets.notebook));
+	GArray * arr = g_array_new(FALSE, FALSE, sizeof(SmPropValue));
+	gint arr_filenames_begin = -1;
 
-	GArray * arr;
-	gint arr_real_len, arr_filenames_begin;
-
-	SmProp restart_command_prop, clone_command_prop;
-	SmPropValue * val;
+	GOptionEntry * optentry;
+	SmPropValue val;
 	SmProp * prop;
+	SmProp restart_command_prop, clone_command_prop;
 	gint i;
 
 
-		/*
-		 * Allocate space for `page_count+5' elements:
-		 *   * two elements for program name and client ID;
-		 *   * possibly one element for "--no-session" option;
-		 *   * possibly one element for "--new-instance" option;
-		 *   * possible one element for "--" to separate options and filenames;
-		 *   * max `page_count' elements for file paths.
-		 * The number of actually used elements is saved in `arr_real_len'.
-		 * Variable `arr_filenames_begin' stores the index in the array where
-		 *   the list of filenames begin. If there are no filenames in `arr',
-		 *   the value is -1.
-		 */
-	arr = g_array_sized_new(FALSE, FALSE, sizeof(SmPropValue), page_count + 5);
-	arr_real_len = 0;
-	arr_filenames_begin = -1;
-
-	((SmPropValue *)arr->data)[arr_real_len++] = sm_program_val;
-	((SmPropValue *)arr->data)[arr_real_len++] = sm_client_id_arg_val;
-
-	if (!cl_options.load_session)
-	{
-		val = ((SmPropValue *)arr->data) + arr_real_len++;
-		val->length = 2; /* length of "-s" */
-		val->value = "-s";
-	}
-
-#ifdef HAVE_SOCKET
-	if (cl_options.new_instance)
+	g_array_append_val(arr, sm_program_val);
+		/* "libsm-client-id" option requires special handling */
+	g_array_append_val(arr, sm_client_id_arg_val);
+		/* handle other command-line options */
+	for (i = 0, optentry = optentries; optentry->long_name; i++, optentry++)
 	{
-		val = ((SmPropValue *)arr->data) + arr_real_len++;
-		val->length = 2; /* length of "-i" */
-		val->value = "-i";
+		if (optentries_aux[i].persist_upon_restart)
+		{
+			GArray * arr2 = utils_option_entry_reverse_parse(optentry);
+			gchar ** ss = (gchar **)arr2->data;
+			for (; *ss; ss++)
+			{
+				val.length = strlen(*ss);
+				val.value = *ss;
+				g_array_append_val(arr, val);
+			}
+			/* elements are freed after `arr' is used */
+			g_array_free(arr2, TRUE);
+		}
 	}
-#endif
 
-	/* TODO: handle other command-line options */
 
 	if (cl_options.load_session && !cl_options.new_instance)
 	{
@@ -448,12 +432,12 @@ static void sm_set_runtime_props(SmcConn smcon)
 	else
 	{
 		/* Specify file names in the command line */
+		const gint page_count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(main_widgets.notebook));
 
-		val = ((SmPropValue *)arr->data) + arr_real_len++;
-		val->length = 2; /* length of "--" */
-		val->value = "--";
-
-		arr_filenames_begin = arr_real_len;
+		val.length = 2;
+		val.value = "--";
+		g_array_append_val(arr, val);
+		arr_filenames_begin = arr->len;
 
 		/*
 		 * NOTE: compare this cycle with the one inside
@@ -464,12 +448,12 @@ static void sm_set_runtime_props(SmcConn smcon)
 			GeanyDocument * doc = document_get_from_page(i);
 			if (doc && doc->real_path)
 			{
-				/* this string will be freed when `arr' is no longer needed */
+				/* freed after `arr' is used */
 				gchar * locale_filename = utils_get_locale_from_utf8(doc->file_name);
 
-				val = ((SmPropValue *)arr->data) + arr_real_len++;
-				val->length = strlen(locale_filename);
-				val->value = locale_filename;
+				val.length = strlen(locale_filename);
+				val.value = locale_filename;
+				g_array_append_val(arr, val);
 			}
 		}
 	}
@@ -477,7 +461,7 @@ static void sm_set_runtime_props(SmcConn smcon)
 
 	restart_command_prop.name = SmRestartCommand;
 	restart_command_prop.type = SmLISTofARRAY8;
-	restart_command_prop.num_vals = arr_real_len;
+	restart_command_prop.num_vals = arr->len;
 	restart_command_prop.vals = (SmPropValue *)arr->data;
 	prop = &restart_command_prop;
 	SmcSetProperties(smcon, 1, &prop);
@@ -489,14 +473,15 @@ static void sm_set_runtime_props(SmcConn smcon)
 	((SmPropValue *)arr->data)[1] = sm_program_val;
 	clone_command_prop.name = SmCloneCommand;
 	clone_command_prop.type = SmLISTofARRAY8;
-	clone_command_prop.num_vals = arr_real_len - 1;
+	clone_command_prop.num_vals = arr->len - 1;
 	clone_command_prop.vals = ((SmPropValue *)arr->data) + 1;
 	prop = &clone_command_prop;
 	SmcSetProperties(smcon, 1, &prop);
 
 
-	if (arr_filenames_begin != -1)
-		for (i = arr_filenames_begin; i < arr_real_len; i++)
+		/* free allocated strings storing command-line options and file names */
+	for (i = 2; i < arr->len; i++)
+		if (i != (arr_filenames_begin - 1))
 			g_free(((SmPropValue *)arr->data)[i].value);
 	g_array_free(arr, TRUE);
 }
diff --git a/src/utils.c b/src/utils.c
index f9363ef..ab8dc7f 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1885,7 +1885,7 @@ gchar *utils_get_help_url(const gchar *suffix)
 		g_free(uri);
 		uri = g_strconcat(GEANY_HOMEPAGE, "manual/", VERSION, "/index.html", NULL);
 	}
-	
+
 	if (suffix != NULL)
 	{
 		setptr(uri, g_strconcat(uri, suffix, NULL));
@@ -1894,3 +1894,69 @@ gchar *utils_get_help_url(const gchar *suffix)
 	return uri;
 }
 
+
+GArray * utils_option_entry_reverse_parse(const GOptionEntry * optentry)
+{
+	GArray * ret = g_array_new(TRUE, TRUE, sizeof(gchar *));
+	gchar * s;
+	gchar ** ss;
+
+	switch (optentry->arg)
+	{
+		case G_OPTION_ARG_NONE:
+			{
+				gboolean val = *(gboolean *)optentry->arg_data;
+				gboolean reverse = (optentry->flags & G_OPTION_FLAG_REVERSE);
+				if (val && !reverse || !val && reverse) /* logical XOR */
+				{
+					s = g_strdup_printf("--%s", optentry->long_name);
+					g_array_append_val(ret, s);
+				}
+			}
+			break;
+
+		case G_OPTION_ARG_INT:
+			s = g_strdup_printf("--%s=%d",
+				optentry->long_name, *(gint *)optentry->arg_data);
+  		g_array_append_val(ret, s);
+  		break;
+#if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 12
+		case G_OPTION_ARG_INT64:
+			s = g_strdup_printf("--%s=%" G_GINT64_MODIFIER "d",
+				optentry->long_name, *(gint64 *)optentry->arg_data);
+			g_array_append_val(ret, s);
+  		break;
+		case G_OPTION_ARG_DOUBLE:
+			s = g_strdup_printf("--%s=%f",
+  			optentry->long_name, *(gdouble *)optentry->arg_data);
+			g_array_append_val(ret, s);
+  		break;
+#endif
+
+  	case G_OPTION_ARG_STRING:
+		case G_OPTION_ARG_FILENAME:
+			if (*(gchar **)optentry->arg_data)
+			{
+				s = g_strdup_printf("--%s=%s", optentry->long_name, *(gchar **)optentry->arg_data);
+				g_array_append_val(ret, s);
+			}
+			break;
+  	case G_OPTION_ARG_STRING_ARRAY:
+  	case G_OPTION_ARG_FILENAME_ARRAY:
+  		for (ss = *(gchar ***)optentry->arg_data; *ss; ss++)
+  		{
+				s = g_strdup_printf("--%s=%s", optentry->long_name, *ss);
+  			g_array_append_val(ret, s);
+			}
+  		break;
+
+  	case G_OPTION_ARG_CALLBACK:
+  		g_warning("%s: %s\n", G_STRFUNC,
+  			"Cannot reverse parse option entries of type G_OPTION_ARG_CALLBACK");
+  		break;
+  	default:
+  		g_warning("%s: %s: %d\n", G_STRFUNC, "Unknown option entry type", optentry->arg);
+  		break;
+	}
+	return ret;
+}
diff --git a/src/utils.h b/src/utils.h
index a2c6f70..7c92ece 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -229,4 +229,20 @@ gchar *utils_str_middle_truncate(const gchar *string, guint truncate_length);
 
 gchar *utils_str_remove_chars(gchar *string, const gchar *chars);
 
+
+/**
+ * "Reverse parse" @c GOptionEntry
+ *
+ * @param optentry    Object to parse.
+ * @return            Null-terminated array of strings (@c gchar*).
+ *
+ * Function takes the information about the option entry stored in @c optentry
+ * and the option's value by the address stored in @c optentry. It returns an array
+ * of strings such that it specifies the option's value when used like @c argv.
+ *
+ * Elements of the resulting array must be freed with @c g_free(). The array
+ * itself must be freed with @c g_array_free().
+ */
+GArray * utils_option_entry_reverse_parse(const GOptionEntry * optentry);
+
 #endif
