--- terminal/main.c | 3 terminal/terminal-gdbus.c | 175 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 176 insertions(+), 2 deletions(-) Index: xfce4-terminal-0.6.1/terminal/main.c =================================================================== --- xfce4-terminal-0.6.1.orig/terminal/main.c 2013-01-31 20:08:58.000000000 -0500 +++ xfce4-terminal-0.6.1/terminal/main.c 2013-03-26 22:22:55.000000000 -0400 @@ -256,7 +256,8 @@ main (int argc, char **argv) || g_error_matches (error, TERMINAL_ERROR, TERMINAL_ERROR_DISPLAY_MISMATCH)) { /* don't try to establish another service here */ - disable_server = TRUE; + if (!g_error_matches (error, TERMINAL_ERROR, TERMINAL_ERROR_DISPLAY_MISMATCH)) + disable_server = TRUE; #ifdef G_ENABLE_DEBUG g_debug ("%s mismatch when invoking remote terminal: %s", Index: xfce4-terminal-0.6.1/terminal/terminal-gdbus.c =================================================================== --- xfce4-terminal-0.6.1.orig/terminal/terminal-gdbus.c 2013-01-01 07:09:30.000000000 -0500 +++ xfce4-terminal-0.6.1/terminal/terminal-gdbus.c 2013-03-27 22:38:52.000000000 -0400 @@ -32,8 +32,137 @@ #include #include #include +#include +static gchar* gdbus_encode_name (const gchar *name); +static gchar* gdbus_decode_name (const gchar *name); +static gchar* gdbus_make_screen_service (const gchar *screen); +static gboolean gdbus_check_screen_service (const gchar *name, + const gchar *screen); + + +/* + * encode name to dbus allowed chars + * [^0-9A-Za-z] => _0xXX_ + */ +static gchar* +gdbus_encode_name (const gchar *name) +{ + GString *gstring; + gchar c; + + if (name == NULL) + return NULL; + + gstring = g_string_sized_new (strlen (name) + 1); + if (gstring == NULL) + return NULL; + + while ((c = *name++)) + { + if ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z')) + { + g_string_append_c (gstring, c); + } + else + { + g_string_append_printf (gstring, "_0x%02X_", c); + } + } + + return g_string_free (gstring, FALSE /* free_segment */); +} + + +static gchar* +gdbus_decode_name (const gchar *name) +{ + GString *gstring; + gchar c; + + if (name == NULL) + return NULL; + + gstring = g_string_sized_new (strlen (name) + 1); + if (gstring == NULL) + return NULL; + + while ((c = *name++)) + { + if (c == '_') + { + const gchar *undl = strchr (name, '_'); + gchar *endp = NULL; + long code = strtol (name, &endp, 0); + if (*undl == '_' && endp == undl && code >= 0 && code <= 255) + { + c = (gchar) code; + name = undl + 1; + } + } + g_string_append_c (gstring, c); + } + + return g_string_free (gstring, FALSE /* free_segment */); +} + + +/* + * Generate dbus service per screen ($DISPLAY) + * TERMINAL_DBUS_SERVICE.screen.$DISPLAY(encoded) + */ +static gchar* +gdbus_make_screen_service (const gchar *screen) +{ + GString *gstring = NULL; + gchar *encoded_screen = NULL; + gchar *encoded_service = NULL; + + if (screen == NULL) + goto out; + + gstring = g_string_new (TERMINAL_DBUS_SERVICE); + if (gstring == NULL) + goto out; + + gstring = g_string_append (gstring, ".screen."); + if (gstring == NULL) + goto out; + + encoded_screen = gdbus_encode_name (screen); + if (encoded_screen == NULL) + goto out; + + gstring = g_string_append (gstring, encoded_screen); + if (gstring == NULL) + goto out; + + encoded_service = g_string_free(gstring, FALSE /* free_segment */); + gstring = NULL; + +out: + if (gstring) + { + g_string_free(gstring, TRUE /* free_segment */); + } + g_free(encoded_screen); + return encoded_service; +} + + +static gboolean +gdbus_check_screen_service (const gchar *name, + const gchar *screen) +{ + gchar *screen_service = gdbus_make_screen_service (screen); + gboolean ret = g_strcmp0 (name, screen_service); + g_free (screen_service); + return ret; +} + static const gchar terminal_gdbus_introspection_xml[] = "" @@ -157,6 +286,8 @@ terminal_gdbus_register_service (Termina GError **error) { guint owner_id; + guint screen_owner_id; + gchar*screen_service; terminal_return_val_if_fail (TERMINAL_IS_APP (app), FALSE); @@ -169,7 +300,21 @@ terminal_gdbus_register_service (Termina app, NULL); - return (owner_id != 0); + screen_owner_id = 0; + if ((screen_service = gdbus_make_screen_service (g_getenv ("DISPLAY"))) != NULL) + { + screen_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, + screen_service, + G_BUS_NAME_OWNER_FLAGS_NONE, + terminal_gdbus_bus_acquired, + NULL, + NULL, + app, + NULL); + g_free (screen_service); + } + + return (owner_id != 0 || screen_owner_id != 0); } @@ -184,6 +329,7 @@ terminal_gdbus_invoke_launch (gint a GError *err = NULL; gboolean result; guint32 uid; + gchar *screen_service; terminal_return_val_if_fail (argc == (gint) g_strv_length (argv), FALSE); @@ -209,6 +355,33 @@ terminal_gdbus_invoke_launch (gint a NULL, &err); + if (reply == NULL && + g_error_matches (err, TERMINAL_ERROR, TERMINAL_ERROR_DISPLAY_MISMATCH) && + (screen_service = gdbus_make_screen_service (g_getenv ("DISPLAY"))) != NULL) + { + GError *new_err = NULL; + + reply = g_dbus_connection_call_sync (connection, + screen_service, + TERMINAL_DBUS_PATH, + TERMINAL_DBUS_INTERFACE, + TERMINAL_DBUS_METHOD_LAUNCH, + g_variant_new ("(u^ay^aay)", + uid, + g_getenv ("DISPLAY"), + argv), + NULL, + G_DBUS_CALL_FLAGS_NO_AUTO_START, + 2000, + NULL, + &new_err); + + g_free (screen_service); + g_clear_error (&new_err); + if (reply != NULL) + g_clear_error (&err); + } + g_object_unref (connection); result = (reply != NULL);