vinagre r325 - in trunk: . src
- From: jwendell svn gnome org
- To: svn-commits-list gnome org
- Subject: vinagre r325 - in trunk: . src
- Date: Sat, 10 May 2008 03:41:22 +0100 (BST)
Author: jwendell
Date: Sat May 10 02:41:21 2008
New Revision: 325
URL: http://svn.gnome.org/viewvc/vinagre?rev=325&view=rev
Log:
2008-05-09 Jonh Wendell <jwendell gnome org>
* lots of files: Closes #519145 â Implement unique instance.
Added:
trunk/src/bacon-message-connection.c
trunk/src/bacon-message-connection.h
trunk/src/vinagre-app.c
trunk/src/vinagre-app.h
trunk/src/vinagre-bacon.c
trunk/src/vinagre-bacon.h
Modified:
trunk/AUTHORS
trunk/ChangeLog
trunk/src/Makefile.am
trunk/src/vinagre-commands.c
trunk/src/vinagre-commands.h
trunk/src/vinagre-main.c
trunk/src/vinagre-tab.c
trunk/src/vinagre-tab.h
trunk/src/vinagre-ui.h
trunk/src/vinagre-utils.c
trunk/src/vinagre-utils.h
trunk/src/vinagre-window-private.h
trunk/src/vinagre-window.c
trunk/src/vinagre-window.h
Modified: trunk/AUTHORS
==============================================================================
--- trunk/AUTHORS (original)
+++ trunk/AUTHORS Sat May 10 02:41:21 2008
@@ -1,5 +1,7 @@
Jonh Wendell <wendell bani com br>
+Some parts of vinagre were based on gedit, so, thanks to gedit crowd.
+
And many thanks to the gtk-vnc development team:
- Anthony Liguori
- Daniel P. Berrange
Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am (original)
+++ trunk/src/Makefile.am Sat May 10 02:41:21 2008
@@ -29,6 +29,9 @@
gossip-cell-renderer-expander.c gossip-cell-renderer-expander.h \
vinagre-mdns.h vinagre-mdns.c \
vinagre-prefs.h vinagre-prefs.c \
+ bacon-message-connection.h bacon-message-connection.c \
+ vinagre-app.h vinagre-app.c \
+ vinagre-bacon.h vinagre-bacon.c \
$(NULL)
vinagre_LDADD = \
Added: trunk/src/bacon-message-connection.c
==============================================================================
--- (empty file)
+++ trunk/src/bacon-message-connection.c Sat May 10 02:41:21 2008
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2003 Bastien Nocera <hadess hadess 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+
+#include "bacon-message-connection.h"
+
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX 108
+#endif
+
+struct BaconMessageConnection {
+ /* A server accepts connections */
+ gboolean is_server;
+
+ /* The socket path itself */
+ char *path;
+
+ /* File descriptor of the socket */
+ int fd;
+ /* Channel to watch */
+ GIOChannel *chan;
+ /* Event id returned by g_io_add_watch() */
+ int conn_id;
+
+ /* Connections accepted by this connection */
+ GSList *accepted_connections;
+
+ /* callback */
+ void (*func) (const char *message, gpointer user_data);
+ gpointer data;
+};
+
+static gboolean
+test_is_socket (const char *path)
+{
+ struct stat s;
+
+ if (stat (path, &s) == -1)
+ return FALSE;
+
+ if (S_ISSOCK (s.st_mode))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+is_owned_by_user_and_socket (const char *path)
+{
+ struct stat s;
+
+ if (stat (path, &s) == -1)
+ return FALSE;
+
+ if (s.st_uid != geteuid ())
+ return FALSE;
+
+ if ((s.st_mode & S_IFSOCK) != S_IFSOCK)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean server_cb (GIOChannel *source,
+ GIOCondition condition, gpointer data);
+
+static gboolean
+setup_connection (BaconMessageConnection *conn)
+{
+ g_return_val_if_fail (conn->chan == NULL, FALSE);
+
+ conn->chan = g_io_channel_unix_new (conn->fd);
+ if (!conn->chan) {
+ return FALSE;
+ }
+ g_io_channel_set_line_term (conn->chan, "\n", 1);
+ conn->conn_id = g_io_add_watch (conn->chan, G_IO_IN, server_cb, conn);
+
+ return TRUE;
+}
+
+static void
+accept_new_connection (BaconMessageConnection *server_conn)
+{
+ BaconMessageConnection *conn;
+ int alen;
+
+ g_return_if_fail (server_conn->is_server);
+
+ conn = g_new0 (BaconMessageConnection, 1);
+ conn->is_server = FALSE;
+ conn->func = server_conn->func;
+ conn->data = server_conn->data;
+
+ conn->fd = accept (server_conn->fd, NULL, (guint *)&alen);
+
+ server_conn->accepted_connections =
+ g_slist_prepend (server_conn->accepted_connections, conn);
+
+ setup_connection (conn);
+}
+
+static gboolean
+server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
+{
+ BaconMessageConnection *conn = (BaconMessageConnection *)data;
+ char *message, *subs, buf;
+ int cd, rc, offset;
+ gboolean finished;
+
+ offset = 0;
+ if (conn->is_server && conn->fd == g_io_channel_unix_get_fd (source)) {
+ accept_new_connection (conn);
+ return TRUE;
+ }
+ message = g_malloc (1);
+ cd = conn->fd;
+ rc = read (cd, &buf, 1);
+ while (rc > 0 && buf != '\n')
+ {
+ message = g_realloc (message, rc + offset + 1);
+ message[offset] = buf;
+ offset = offset + rc;
+ rc = read (cd, &buf, 1);
+ }
+ if (rc <= 0) {
+ g_io_channel_shutdown (conn->chan, FALSE, NULL);
+ g_io_channel_unref (conn->chan);
+ conn->chan = NULL;
+ close (conn->fd);
+ conn->fd = -1;
+ g_free (message);
+ conn->conn_id = 0;
+
+ return FALSE;
+ }
+ message[offset] = '\0';
+
+ subs = message;
+ finished = FALSE;
+
+ while (finished == FALSE && *subs != '\0')
+ {
+ if (conn->func != NULL)
+ (*conn->func) (subs, conn->data);
+
+ subs += strlen (subs) + 1;
+ if (subs - message >= offset)
+ finished = TRUE;
+ }
+
+ g_free (message);
+
+ return TRUE;
+}
+
+static char *
+find_file_with_pattern (const char *dir, const char *pattern)
+{
+ GDir *filedir;
+ char *found_filename;
+ const char *filename;
+ GPatternSpec *pat;
+
+ filedir = g_dir_open (dir, 0, NULL);
+ if (filedir == NULL)
+ return NULL;
+
+ pat = g_pattern_spec_new (pattern);
+ if (pat == NULL)
+ {
+ g_dir_close (filedir);
+ return NULL;
+ }
+
+ found_filename = NULL;
+
+ while ((filename = g_dir_read_name (filedir)))
+ {
+ if (g_pattern_match_string (pat, filename))
+ {
+ char *tmp = g_build_filename (dir, filename, NULL);
+ if (is_owned_by_user_and_socket (tmp))
+ found_filename = g_strdup (filename);
+ g_free (tmp);
+ }
+
+ if (found_filename != NULL)
+ break;
+ }
+
+ g_pattern_spec_free (pat);
+ g_dir_close (filedir);
+
+ return found_filename;
+}
+
+static char *
+socket_filename (const char *prefix)
+{
+ char *pattern, *newfile, *path, *filename;
+ const char *tmpdir;
+
+ pattern = g_strdup_printf ("%s.%s.*", prefix, g_get_user_name ());
+ tmpdir = g_get_tmp_dir ();
+ filename = find_file_with_pattern (tmpdir, pattern);
+ if (filename == NULL)
+ {
+ newfile = g_strdup_printf ("%s.%s.%u", prefix,
+ g_get_user_name (), g_random_int ());
+ path = g_build_filename (tmpdir, newfile, NULL);
+ g_free (newfile);
+ } else {
+ path = g_build_filename (tmpdir, filename, NULL);
+ g_free (filename);
+ }
+
+ g_free (pattern);
+ return path;
+}
+
+static gboolean
+try_server (BaconMessageConnection *conn)
+{
+ struct sockaddr_un uaddr;
+
+ uaddr.sun_family = AF_UNIX;
+ strncpy (uaddr.sun_path, conn->path,
+ MIN (strlen(conn->path)+1, UNIX_PATH_MAX));
+ conn->fd = socket (PF_UNIX, SOCK_STREAM, 0);
+ if (bind (conn->fd, (struct sockaddr *) &uaddr, sizeof (uaddr)) == -1)
+ {
+ conn->fd = -1;
+ return FALSE;
+ }
+ listen (conn->fd, 5);
+
+ if (!setup_connection (conn))
+ return FALSE;
+ return TRUE;
+}
+
+static gboolean
+try_client (BaconMessageConnection *conn)
+{
+ struct sockaddr_un uaddr;
+
+ uaddr.sun_family = AF_UNIX;
+ strncpy (uaddr.sun_path, conn->path,
+ MIN(strlen(conn->path)+1, UNIX_PATH_MAX));
+ conn->fd = socket (PF_UNIX, SOCK_STREAM, 0);
+ if (connect (conn->fd, (struct sockaddr *) &uaddr,
+ sizeof (uaddr)) == -1)
+ {
+ conn->fd = -1;
+ return FALSE;
+ }
+
+ return setup_connection (conn);
+}
+
+BaconMessageConnection *
+bacon_message_connection_new (const char *prefix)
+{
+ BaconMessageConnection *conn;
+
+ g_return_val_if_fail (prefix != NULL, NULL);
+
+ conn = g_new0 (BaconMessageConnection, 1);
+ conn->path = socket_filename (prefix);
+
+ if (test_is_socket (conn->path) == FALSE)
+ {
+ if (!try_server (conn))
+ {
+ bacon_message_connection_free (conn);
+ return NULL;
+ }
+
+ conn->is_server = TRUE;
+ return conn;
+ }
+
+ if (try_client (conn) == FALSE)
+ {
+ unlink (conn->path);
+ try_server (conn);
+ if (conn->fd == -1)
+ {
+ bacon_message_connection_free (conn);
+ return NULL;
+ }
+
+ conn->is_server = TRUE;
+ return conn;
+ }
+
+ conn->is_server = FALSE;
+ return conn;
+}
+
+void
+bacon_message_connection_free (BaconMessageConnection *conn)
+{
+ GSList *child_conn;
+
+ g_return_if_fail (conn != NULL);
+ /* Only servers can accept other connections */
+ g_return_if_fail (conn->is_server != FALSE ||
+ conn->accepted_connections == NULL);
+
+ child_conn = conn->accepted_connections;
+ while (child_conn != NULL) {
+ bacon_message_connection_free (child_conn->data);
+ child_conn = g_slist_next (child_conn);
+ }
+ g_slist_free (conn->accepted_connections);
+
+ if (conn->conn_id) {
+ g_source_remove (conn->conn_id);
+ conn->conn_id = 0;
+ }
+ if (conn->chan) {
+ g_io_channel_shutdown (conn->chan, FALSE, NULL);
+ g_io_channel_unref (conn->chan);
+ }
+
+ if (conn->is_server != FALSE) {
+ unlink (conn->path);
+ }
+ if (conn->fd != -1) {
+ close (conn->fd);
+ }
+
+ g_free (conn->path);
+ g_free (conn);
+}
+
+void
+bacon_message_connection_set_callback (BaconMessageConnection *conn,
+ BaconMessageReceivedFunc func,
+ gpointer user_data)
+{
+ g_return_if_fail (conn != NULL);
+
+ conn->func = func;
+ conn->data = user_data;
+}
+
+void
+bacon_message_connection_send (BaconMessageConnection *conn,
+ const char *message)
+{
+ g_return_if_fail (conn != NULL);
+ g_return_if_fail (message != NULL);
+
+ g_io_channel_write_chars (conn->chan, message, strlen (message),
+ NULL, NULL);
+ g_io_channel_write_chars (conn->chan, "\n", 1, NULL, NULL);
+ g_io_channel_flush (conn->chan, NULL);
+}
+
+gboolean
+bacon_message_connection_get_is_server (BaconMessageConnection *conn)
+{
+ g_return_val_if_fail (conn != NULL, FALSE);
+
+ return conn->is_server;
+}
+
Added: trunk/src/bacon-message-connection.h
==============================================================================
--- (empty file)
+++ trunk/src/bacon-message-connection.h Sat May 10 02:41:21 2008
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2003 Bastien Nocera <hadess hadess 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef BACON_MESSAGE_CONNECTION_H
+#define BACON_MESSAGE_CONNECTION_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef void (*BaconMessageReceivedFunc) (const char *message,
+ gpointer user_data);
+
+typedef struct BaconMessageConnection BaconMessageConnection;
+
+BaconMessageConnection *bacon_message_connection_new (const char *prefix);
+void bacon_message_connection_free (BaconMessageConnection *conn);
+void bacon_message_connection_set_callback (BaconMessageConnection *conn,
+ BaconMessageReceivedFunc func,
+ gpointer user_data);
+void bacon_message_connection_send (BaconMessageConnection *conn,
+ const char *message);
+gboolean bacon_message_connection_get_is_server (BaconMessageConnection *conn);
+
+G_END_DECLS
+
+#endif /* BACON_MESSAGE_CONNECTION_H */
Added: trunk/src/vinagre-app.c
==============================================================================
--- (empty file)
+++ trunk/src/vinagre-app.c Sat May 10 02:41:21 2008
@@ -0,0 +1,274 @@
+/*
+ * vinagre-app.c
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2008 - Jonh Wendell <wendell bani com br>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "vinagre-app.h"
+#include "vinagre-utils.h"
+
+#define VINAGRE_APP_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), VINAGRE_TYPE_APP, VinagreAppPrivate))
+
+
+struct _VinagreAppPrivate
+{
+ GList *windows;
+ VinagreWindow *active_window;
+};
+
+G_DEFINE_TYPE(VinagreApp, vinagre_app, G_TYPE_OBJECT)
+
+static void
+vinagre_app_finalize (GObject *object)
+{
+ VinagreApp *app = VINAGRE_APP (object);
+
+ g_list_free (app->priv->windows);
+
+ G_OBJECT_CLASS (vinagre_app_parent_class)->finalize (object);
+}
+
+static void
+vinagre_app_class_init (VinagreAppClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = vinagre_app_finalize;
+
+ g_type_class_add_private (object_class, sizeof(VinagreAppPrivate));
+}
+
+static void
+vinagre_app_init (VinagreApp *app)
+{
+ app->priv = VINAGRE_APP_GET_PRIVATE (app);
+ app->priv->windows = NULL;
+ app->priv->active_window = NULL;
+}
+
+static void
+app_weak_notify (gpointer data,
+ GObject *where_the_app_was)
+{
+ gtk_main_quit ();
+}
+
+VinagreApp *
+vinagre_app_get_default (void)
+{
+ static VinagreApp *app = NULL;
+
+ if (G_LIKELY (app))
+ return app;
+
+ app = VINAGRE_APP (g_object_new (VINAGRE_TYPE_APP, NULL));
+
+ g_object_add_weak_pointer (G_OBJECT (app),
+ (gpointer) &app);
+ g_object_weak_ref (G_OBJECT (app),
+ app_weak_notify,
+ NULL);
+
+ return app;
+}
+
+static gboolean
+window_focus_in_event (VinagreWindow *window,
+ GdkEventFocus *event,
+ VinagreApp *app)
+{
+ /* updates active_view and active_child when a new toplevel receives focus */
+ g_return_val_if_fail (VINAGRE_IS_WINDOW (window), FALSE);
+
+ app->priv->active_window = window;
+
+ return FALSE;
+}
+
+static void
+window_destroy (VinagreWindow *window,
+ VinagreApp *app)
+{
+ app->priv->windows = g_list_remove (app->priv->windows,
+ window);
+
+ if (window == app->priv->active_window)
+ app->priv->active_window = app->priv->windows != NULL ?
+ app->priv->windows->data : NULL;
+
+ if (app->priv->windows == NULL)
+ g_object_unref (app);
+}
+
+VinagreWindow *
+vinagre_app_create_window (VinagreApp *app, GdkScreen *screen)
+{
+ VinagreWindow *window;
+
+ /*
+ * We need to be careful here, there is a race condition:
+ * when another vinagre is launched it checks active_window,
+ * so we must do our best to ensure that active_window
+ * is never NULL when at least a window exists.
+ */
+ if (app->priv->windows == NULL)
+ app->priv->active_window = window = vinagre_window_new ();
+ else
+ window = vinagre_window_new ();
+
+ app->priv->windows = g_list_prepend (app->priv->windows,
+ window);
+
+ g_signal_connect (window,
+ "focus_in_event",
+ G_CALLBACK (window_focus_in_event),
+ app);
+ g_signal_connect (window,
+ "destroy",
+ G_CALLBACK (window_destroy),
+ app);
+
+ if (screen != NULL)
+ gtk_window_set_screen (GTK_WINDOW (window), screen);
+
+ return window;
+}
+
+const GList *
+vinagre_app_get_windows (VinagreApp *app)
+{
+ g_return_val_if_fail (VINAGRE_IS_APP (app), NULL);
+
+ return app->priv->windows;
+}
+
+VinagreWindow *
+vinagre_app_get_active_window (VinagreApp *app)
+{
+ g_return_val_if_fail (VINAGRE_IS_APP (app), NULL);
+
+ /* make sure our active window is always realized:
+ * this is needed on startup if we launch two vinagre fast
+ * enough that the second instance comes up before the
+ * first one shows its window.
+ */
+
+ if (!GTK_WIDGET_REALIZED (GTK_WIDGET (app->priv->active_window)))
+ gtk_widget_realize (GTK_WIDGET (app->priv->active_window));
+
+ return app->priv->active_window;
+}
+
+static gboolean
+is_in_viewport (VinagreWindow *window,
+ GdkScreen *screen,
+ gint workspace,
+ gint viewport_x,
+ gint viewport_y)
+{
+ GdkScreen *s;
+ GdkDisplay *display;
+ const gchar *cur_name;
+ const gchar *name;
+ gint cur_n;
+ gint n;
+ gint ws;
+ gint sc_width, sc_height;
+ gint x, y, width, height;
+ gint vp_x, vp_y;
+
+ /* Check for screen and display match */
+ display = gdk_screen_get_display (screen);
+ cur_name = gdk_display_get_name (display);
+ cur_n = gdk_screen_get_number (screen);
+
+ s = gtk_window_get_screen (GTK_WINDOW (window));
+ display = gdk_screen_get_display (s);
+ name = gdk_display_get_name (display);
+ n = gdk_screen_get_number (s);
+
+ if (strcmp (cur_name, name) != 0 || cur_n != n)
+ return FALSE;
+
+ /* Check for workspace match */
+ ws = vinagre_utils_get_window_workspace (GTK_WINDOW (window));
+ if (ws != workspace && ws != VINAGRE_ALL_WORKSPACES)
+ return FALSE;
+
+ /* Check for viewport match */
+ gdk_window_get_position (GTK_WIDGET (window)->window, &x, &y);
+ gdk_drawable_get_size (GTK_WIDGET (window)->window, &width, &height);
+ vinagre_utils_get_current_viewport (screen, &vp_x, &vp_y);
+ x += vp_x;
+ y += vp_y;
+
+ sc_width = gdk_screen_get_width (screen);
+ sc_height = gdk_screen_get_height (screen);
+
+ return x + width * .25 >= viewport_x &&
+ x + width * .75 < viewport_x + sc_width &&
+ y >= viewport_y &&
+ y + height < viewport_y + sc_height;
+}
+
+VinagreWindow *
+vinagre_app_get_window_in_viewport (VinagreApp *app,
+ GdkScreen *screen,
+ gint workspace,
+ gint viewport_x,
+ gint viewport_y)
+{
+ VinagreWindow *window;
+ GList *l;
+
+ g_return_val_if_fail (VINAGRE_IS_APP (app), NULL);
+
+ /* first try if the active window */
+ window = app->priv->active_window;
+
+ g_return_val_if_fail (VINAGRE_IS_WINDOW (window), NULL);
+
+ if (is_in_viewport (window, screen, workspace, viewport_x, viewport_y))
+ return window;
+
+ /* otherwise try to see if there is a window on this workspace */
+ for (l = app->priv->windows; l != NULL; l = l->next)
+ {
+ window = l->data;
+
+ if (is_in_viewport (window, screen, workspace, viewport_x, viewport_y))
+ return window;
+ }
+
+ /* no window on this workspace... create a new one */
+ return vinagre_app_create_window (app, screen);
+}
+
+GList *
+vinagre_app_get_connections (VinagreApp *app)
+{
+ return NULL;
+}
+
+/* vim: ts=8 */
Added: trunk/src/vinagre-app.h
==============================================================================
--- (empty file)
+++ trunk/src/vinagre-app.h Sat May 10 02:41:21 2008
@@ -0,0 +1,74 @@
+/*
+ * vinagre-app.h
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2008 - Jonh Wendell <wendell bani com br>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __VINAGRE_APP_H__
+#define __VINAGRE_APP_H__
+
+#include <gtk/gtk.h>
+
+#include "vinagre-window.h"
+
+G_BEGIN_DECLS
+
+#define VINAGRE_TYPE_APP (vinagre_app_get_type())
+#define VINAGRE_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), VINAGRE_TYPE_APP, VinagreApp))
+#define VINAGRE_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), VINAGRE_TYPE_APP, VinagreAppClass))
+#define VINAGRE_IS_APP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VINAGRE_TYPE_APP))
+#define VINAGRE_IS_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VINAGRE_TYPE_APP))
+#define VINAGRE_APP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), VINAGRE_TYPE_APP, VinagreAppClass))
+
+typedef struct _VinagreAppPrivate VinagreAppPrivate;
+typedef struct _VinagreApp VinagreApp;
+typedef struct _VinagreAppClass VinagreAppClass;
+
+struct _VinagreApp
+{
+ GObject object;
+ VinagreAppPrivate *priv;
+};
+
+
+struct _VinagreAppClass
+{
+ GObjectClass parent_class;
+};
+
+
+GType vinagre_app_get_type (void) G_GNUC_CONST;
+
+VinagreApp *vinagre_app_get_default (void);
+
+VinagreWindow *vinagre_app_create_window (VinagreApp *app,
+ GdkScreen *screen);
+
+const GList *vinagre_app_get_windows (VinagreApp *app);
+VinagreWindow *vinagre_app_get_active_window (VinagreApp *app);
+GList *vinagre_app_get_connections (VinagreApp *app);
+
+VinagreWindow *vinagre_app_get_window_in_viewport (VinagreApp *app,
+ GdkScreen *screen,
+ gint workspace,
+ gint viewport_x,
+ gint viewport_y);
+
+G_END_DECLS
+
+#endif /* __VINAGRE_APP_H__ */
+/* vim: ts=8 */
Added: trunk/src/vinagre-bacon.c
==============================================================================
--- (empty file)
+++ trunk/src/vinagre-bacon.c Sat May 10 02:41:21 2008
@@ -0,0 +1,289 @@
+/*
+ * vinagre-bacon.c
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2008 - Jonh Wendell <wendell bani com br>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <string.h>
+#include "bacon-message-connection.h"
+#include "vinagre-utils.h"
+#include "vinagre-connection.h"
+#include "vinagre-app.h"
+#include "vinagre-window.h"
+#include "vinagre-commands.h"
+
+static guint32 startup_timestamp = 0;
+
+static GdkDisplay *
+display_open_if_needed (const gchar *name)
+{
+ GSList *displays;
+ GSList *l;
+ GdkDisplay *display = NULL;
+
+ displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
+
+ for (l = displays; l != NULL; l = l->next)
+ {
+ if (strcmp (gdk_display_get_name ((GdkDisplay *) l->data), name) == 0)
+ {
+ display = l->data;
+ break;
+ }
+ }
+
+ g_slist_free (displays);
+
+ return display != NULL ? display : gdk_display_open (name);
+}
+
+/* serverside */
+void
+vinagre_bacon_message_received (const char *message,
+ gpointer data)
+{
+ gchar **commands;
+ gchar **params;
+ gint workspace;
+ gint viewport_x;
+ gint viewport_y;
+ gchar *display_name;
+ gint screen_number;
+ gint i;
+ VinagreApp *app;
+ VinagreWindow *window;
+ GdkDisplay *display;
+ GdkScreen *screen;
+ gboolean new_window = FALSE;
+ GSList *servers = NULL;
+ GSList *l, *next;
+ VinagreConnection *conn;
+ gchar *error;
+
+ g_return_if_fail (message != NULL);
+
+ commands = g_strsplit (message, "\v", -1);
+
+ /* header */
+ params = g_strsplit (commands[0], "\t", 6);
+ startup_timestamp = atoi (params[0]);
+ display_name = params[1];
+ screen_number = atoi (params[2]);
+ workspace = atoi (params[3]);
+ viewport_x = atoi (params[4]);
+ viewport_y = atoi (params[5]);
+
+ display = display_open_if_needed (display_name);
+ if (display == NULL)
+ {
+ g_warning ("Could not open display %s\n", display_name);
+ g_strfreev (params);
+ goto out;
+ }
+
+ screen = gdk_display_get_screen (display, screen_number);
+ g_strfreev (params);
+
+ /* body */
+ for (i = 1; commands[i] != NULL; i++)
+ {
+ params = g_strsplit (commands[i], "\t", -1);
+
+ if (strcmp (params[0], "NEW-WINDOW") == 0)
+ new_window = TRUE;
+
+ else if (strcmp (params[0], "OPEN-URIS") == 0)
+ {
+ gint n_uris, j;
+ gchar **uris;
+
+ n_uris = atoi (params[1]);
+ uris = g_strsplit (params[2], " ", n_uris);
+
+ for (j = 0; j < n_uris; j++)
+ {
+ conn = vinagre_connection_new_from_string (uris[j], &error);
+ if (conn)
+ servers = g_slist_prepend (servers, conn);
+ }
+
+ g_strfreev (uris);
+ }
+
+ else
+ {
+ g_warning ("Unexpected bacon command");
+ }
+
+ g_strfreev (params);
+ }
+
+ /* execute the commands */
+ app = vinagre_app_get_default ();
+ if (new_window)
+ window = vinagre_app_create_window (app, screen);
+ else
+ /* get a window in the current workspace (if exists) and raise it */
+ window = vinagre_app_get_window_in_viewport (app,
+ screen,
+ workspace,
+ viewport_x,
+ viewport_y);
+
+ for (l = servers; l; l = next)
+ {
+ VinagreConnection *conn = l->data;
+
+ next = l->next;
+ vinagre_cmd_direct_connect (conn, window);
+ }
+
+ /* set the proper interaction time on the window.
+ * Fall back to roundtripping to the X server when we
+ * don't have the timestamp, e.g. when launched from
+ * terminal. We also need to make sure that the window
+ * has been realized otherwise it will not work. lame.
+ */
+ if (!GTK_WIDGET_REALIZED (window))
+ gtk_widget_realize (GTK_WIDGET (window));
+
+ if (startup_timestamp <= 0)
+ startup_timestamp = gdk_x11_get_server_time (GTK_WIDGET (window)->window);
+
+ gdk_x11_window_set_user_time (GTK_WIDGET (window)->window,
+ startup_timestamp);
+ gtk_window_present (GTK_WINDOW (window));
+
+ out:
+ g_strfreev (commands);
+}
+
+/* clientside */
+static void
+vinagre_bacon_send_message (BaconMessageConnection *connection,
+ GSList *servers,
+ gboolean new_window)
+{
+ GdkScreen *screen;
+ GdkDisplay *display;
+ const gchar *display_name;
+ gint screen_number;
+ gint ws;
+ gint viewport_x;
+ gint viewport_y;
+ GString *command;
+
+ /* the messages have the following format:
+ * <--- header ---> <---- body ----->
+ * timestamp \t display_name \t screen_number \t workspace \t viewport_x \t viewport_y \v OP1 \t arg \t arg \v OP2 \t arg \t arg|...
+ *
+ * when the arg is a list of uri, they are separated by a space.
+ * So the delimiters are \v for the commands, \t for the tokens in
+ * a command and ' ' for the uris: note that such delimiters cannot
+ * be part of an uri, this way parsing is easier.
+ */
+
+ screen = gdk_screen_get_default ();
+ display = gdk_screen_get_display (screen);
+
+ display_name = gdk_display_get_name (display);
+ screen_number = gdk_screen_get_number (screen);
+
+ ws = vinagre_utils_get_current_workspace (screen);
+ vinagre_utils_get_current_viewport (screen, &viewport_x, &viewport_y);
+
+ command = g_string_new (NULL);
+
+ /* header */
+ g_string_append_printf (command,
+ "%" G_GUINT32_FORMAT "\t%s\t%d\t%d\t%d\t%d",
+ startup_timestamp,
+ display_name,
+ screen_number,
+ ws,
+ viewport_x,
+ viewport_y);
+
+ /* NEW-WINDOW command */
+ if (new_window)
+ {
+ command = g_string_append_c (command, '\v');
+ command = g_string_append (command, "NEW-WINDOW");
+ }
+
+ /* OPEN_URIS command */
+ if (servers)
+ {
+ GSList *l;
+
+ command = g_string_append_c (command, '\v');
+ command = g_string_append (command, "OPEN-URIS");
+
+ g_string_append_printf (command, "\t%d\t", g_slist_length (servers));
+
+ for (l = servers; l != NULL; l = l->next)
+ {
+ VinagreConnection *conn = l->data;
+ g_string_append_printf (command, "%s:%d",
+ vinagre_connection_get_host (conn),
+ vinagre_connection_get_port (conn));
+ if (l->next != NULL)
+ command = g_string_append_c (command, ' ');
+ }
+ }
+
+ bacon_message_connection_send (connection,
+ command->str);
+
+ g_string_free (command, TRUE);
+}
+
+void
+vinagre_bacon_start (GSList *servers, gboolean new_window)
+{
+ BaconMessageConnection *connection;
+
+ connection = bacon_message_connection_new ("vinagre");
+ if (!connection)
+ {
+ g_warning ("Cannot create the 'vinagre' connection.");
+ return;
+ }
+
+ if (!bacon_message_connection_get_is_server (connection))
+ {
+ vinagre_bacon_send_message (connection, servers, new_window);
+
+ gdk_notify_startup_complete ();
+
+ g_slist_foreach (servers, (GFunc) g_object_unref, NULL);
+ g_slist_free (servers);
+ bacon_message_connection_free (connection);
+
+ exit (0);
+ }
+ else
+ {
+ bacon_message_connection_set_callback (connection,
+ vinagre_bacon_message_received,
+ NULL);
+ }
+}
+/* vim: ts=8 */
Added: trunk/src/vinagre-bacon.h
==============================================================================
--- (empty file)
+++ trunk/src/vinagre-bacon.h Sat May 10 02:41:21 2008
@@ -0,0 +1,27 @@
+/*
+ * vinagre-bacon.h
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2008 - Jonh Wendell <wendell bani com br>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __VINAGRE_BACON_H__
+#define __VINAGRE_BACON_H__
+
+void vinagre_bacon_start (GSList *servers, gboolean new_window);
+
+#endif /* __VINAGRE_BACON_H__ */
+/* vim: ts=8 */
Modified: trunk/src/vinagre-commands.c
==============================================================================
--- trunk/src/vinagre-commands.c (original)
+++ trunk/src/vinagre-commands.c Sat May 10 02:41:21 2008
@@ -42,14 +42,22 @@
vinagre_cmd_direct_connect (VinagreConnection *conn,
VinagreWindow *window)
{
- GtkWidget *tab;
+ VinagreTab *tab;
g_return_if_fail (VINAGRE_IS_WINDOW (window));
- tab = vinagre_tab_new (conn, window);
- vinagre_notebook_add_tab (VINAGRE_NOTEBOOK (window->priv->notebook),
- VINAGRE_TAB (tab),
- -1);
+ tab = vinagre_window_conn_exists (window, conn);
+ if (tab)
+ {
+ vinagre_window_set_active_tab (window, tab);
+ }
+ else
+ {
+ tab = VINAGRE_TAB (vinagre_tab_new (conn, window));
+ vinagre_notebook_add_tab (VINAGRE_NOTEBOOK (window->priv->notebook),
+ VINAGRE_TAB (tab),
+ -1);
+ }
}
/* Machine Menu */
@@ -57,7 +65,7 @@
vinagre_cmd_machine_connect (GtkAction *action,
VinagreWindow *window)
{
- GtkWidget *tab;
+ VinagreTab *tab;
VinagreConnection *conn;
g_return_if_fail (VINAGRE_IS_WINDOW (window));
@@ -66,10 +74,18 @@
if (!conn)
return;
- tab = vinagre_tab_new (conn, window);
- vinagre_notebook_add_tab (VINAGRE_NOTEBOOK (window->priv->notebook),
- VINAGRE_TAB (tab),
- -1);
+ tab = vinagre_window_conn_exists (window, conn);
+ if (tab)
+ {
+ vinagre_window_set_active_tab (window, tab);
+ }
+ else
+ {
+ tab = VINAGRE_TAB (vinagre_tab_new (conn, window));
+ vinagre_notebook_add_tab (VINAGRE_NOTEBOOK (window->priv->notebook),
+ VINAGRE_TAB (tab),
+ -1);
+ }
}
void
@@ -168,6 +184,13 @@
vinagre_window_close_all_tabs (window);
}
+void
+vinagre_cmd_machine_quit (GtkAction *action,
+ VinagreWindow *window)
+{
+ gtk_widget_destroy (GTK_WIDGET (window));
+}
+
/* View Menu */
void
vinagre_cmd_view_show_toolbar (GtkAction *action,
@@ -264,17 +287,24 @@
vinagre_cmd_open_bookmark (VinagreWindow *window,
VinagreConnection *conn)
{
- GtkWidget *tab;
+ VinagreTab *tab;
VinagreConnection *new_conn;
g_return_if_fail (VINAGRE_IS_WINDOW (window));
- new_conn = vinagre_connection_clone (conn);
- tab = vinagre_tab_new (new_conn, window);
- vinagre_notebook_add_tab (VINAGRE_NOTEBOOK (window->priv->notebook),
- VINAGRE_TAB (tab),
- -1);
- gtk_widget_show (tab);
+ tab = vinagre_window_conn_exists (window, conn);
+ if (tab)
+ {
+ vinagre_window_set_active_tab (window, tab);
+ }
+ else
+ {
+ new_conn = vinagre_connection_clone (conn);
+ tab = VINAGRE_TAB (vinagre_tab_new (new_conn, window));
+ vinagre_notebook_add_tab (VINAGRE_NOTEBOOK (window->priv->notebook),
+ VINAGRE_TAB (tab),
+ -1);
+ }
}
void
Modified: trunk/src/vinagre-commands.h
==============================================================================
--- trunk/src/vinagre-commands.h (original)
+++ trunk/src/vinagre-commands.h Sat May 10 02:41:21 2008
@@ -43,6 +43,8 @@
void vinagre_cmd_machine_close_all (GtkAction *action,
VinagreWindow *window);
+void vinagre_cmd_machine_quit (GtkAction *action,
+ VinagreWindow *window);
void vinagre_cmd_view_show_toolbar (GtkAction *action,
VinagreWindow *window);
Modified: trunk/src/vinagre-main.c
==============================================================================
--- trunk/src/vinagre-main.c (original)
+++ trunk/src/vinagre-main.c Sat May 10 02:41:21 2008
@@ -28,21 +28,27 @@
#include "vinagre-commands.h"
#include "vinagre-bookmarks.h"
#include "vinagre-window.h"
+#include "vinagre-app.h"
#include "vinagre-utils.h"
#include "vinagre-prefs.h"
#include "vinagre-mdns.h"
+#include "vinagre-bacon.h"
#include <vncdisplay.h>
/* command line */
static gchar **files = NULL;
static gchar **remaining_args = NULL;
static GSList *servers = NULL;
+static gboolean new_window = FALSE;
static const GOptionEntry options [] =
{
{ "file", 'f', 0, G_OPTION_ARG_FILENAME_ARRAY, &files,
N_("Opens a .vnc file"), N_("filename")},
+ { "new-window", 'n', 0, G_OPTION_ARG_NONE, &new_window,
+ N_("Create a new toplevel window in an existing instance of vinagre"), NULL },
+
{
G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &remaining_args,
NULL, N_("[server:port]") },
@@ -104,7 +110,7 @@
"The following errors have occurred:",
g_slist_length (errors)),
errors,
- GTK_WINDOW (window));
+ window?GTK_WINDOW (window):NULL);
g_slist_free (errors);
}
}
@@ -113,7 +119,8 @@
GOptionContext *context;
GError *error = NULL;
GSList *l, *next;
- VinagreWindow *main_window;
+ VinagreWindow *window;
+ VinagreApp *app;
bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
@@ -135,22 +142,25 @@
}
g_set_application_name (_("Remote Desktop Viewer"));
+ vinagre_main_process_command_line (NULL);
+
+ vinagre_bacon_start (servers, new_window);
if (!g_thread_supported ())
g_thread_init (NULL);
- main_window = vinagre_window_new ();
- gtk_widget_show (GTK_WIDGET(main_window));
+ app = vinagre_app_get_default ();
+ window = vinagre_app_create_window (app, NULL);
+ gtk_widget_show (GTK_WIDGET(window));
vinagre_utils_handle_debug ();
- vinagre_main_process_command_line (main_window);
for (l = servers; l; l = next)
{
VinagreConnection *conn = l->data;
next = l->next;
- vinagre_cmd_direct_connect (conn, main_window);
+ vinagre_cmd_direct_connect (conn, window);
}
g_slist_free (servers);
Modified: trunk/src/vinagre-tab.c
==============================================================================
--- trunk/src/vinagre-tab.c (original)
+++ trunk/src/vinagre-tab.c Sat May 10 02:41:21 2008
@@ -152,6 +152,7 @@
{
case PROP_CONN:
tab->priv->conn = g_value_get_object (value);
+ g_object_set_data (G_OBJECT (tab->priv->conn), VINAGRE_TAB_KEY, tab);
break;
case PROP_WINDOW:
tab->priv->window = g_value_get_object (value);
@@ -917,4 +918,16 @@
return tab->priv->state;
}
+VinagreTab *
+vinagre_tab_get_from_connection (VinagreConnection *conn)
+{
+ gpointer res;
+
+ g_return_val_if_fail (VINAGRE_IS_CONNECTION (conn), NULL);
+
+ res = g_object_get_data (G_OBJECT (conn), VINAGRE_TAB_KEY);
+
+ return (res != NULL) ? VINAGRE_TAB (res) : NULL;
+}
+
/* vim: ts=8 */
Modified: trunk/src/vinagre-tab.h
==============================================================================
--- trunk/src/vinagre-tab.h (original)
+++ trunk/src/vinagre-tab.h Sat May 10 02:41:21 2008
@@ -32,6 +32,7 @@
#define VINAGRE_IS_TAB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VINAGRE_TYPE_TAB))
#define VINAGRE_IS_TAB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VINAGRE_TYPE_TAB))
#define VINAGRE_TAB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), VINAGRE_TYPE_TAB, VinagreTabClass))
+#define VINAGRE_TAB_KEY "VINAGRE_TAB_KEY"
typedef struct _VinagreTabPrivate VinagreTabPrivate;
typedef struct _VinagreTab VinagreTab;
@@ -94,6 +95,8 @@
gboolean vinagre_tab_get_readonly (VinagreTab *tab);
VinagreTabState vinagre_tab_get_state (VinagreTab *tab);
+VinagreTab *vinagre_tab_get_from_connection (VinagreConnection *conn);
+
G_END_DECLS
Modified: trunk/src/vinagre-ui.h
==============================================================================
--- trunk/src/vinagre-ui.h (original)
+++ trunk/src/vinagre-ui.h Sat May 10 02:41:21 2008
@@ -42,7 +42,7 @@
{ "MachineOpen", GTK_STOCK_OPEN, NULL, "<control>O",
N_("Open a .VNC file"), G_CALLBACK (vinagre_cmd_machine_open) },
{ "MachineQuit", GTK_STOCK_QUIT, NULL, "<control>Q",
- N_("Quit the program"), G_CALLBACK (gtk_main_quit) },
+ N_("Quit the program"), G_CALLBACK (vinagre_cmd_machine_quit) },
/* Bookmarks menu */
{ "BookmarksOpen", GTK_STOCK_CONNECT, N_("_Open bookmark"), NULL,
Modified: trunk/src/vinagre-utils.c
==============================================================================
--- trunk/src/vinagre-utils.c (original)
+++ trunk/src/vinagre-utils.c Sat May 10 02:41:21 2008
@@ -28,6 +28,14 @@
#include <config.h>
#endif
+/* For the workspace/viewport stuff */
+#ifdef GDK_WINDOWING_X11
+#include <gdk/gdkx.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#endif
+
GtkWidget *
vinagre_utils_create_small_close_button ()
{
@@ -181,4 +189,164 @@
initialized = TRUE;
}
+
+/* the following two functions are courtesy of galeon */
+
+/**
+ * gedit_utils_get_current_workspace: Get the current workspace
+ *
+ * Get the currently visible workspace for the #GdkScreen.
+ *
+ * If the X11 window property isn't found, 0 (the first workspace)
+ * is returned.
+ */
+guint
+vinagre_utils_get_current_workspace (GdkScreen *screen)
+{
+#ifdef GDK_WINDOWING_X11
+ GdkWindow *root_win;
+ GdkDisplay *display;
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+ guint *current_desktop;
+ gint err, result;
+ guint ret = 0;
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
+
+ root_win = gdk_screen_get_root_window (screen);
+ display = gdk_screen_get_display (screen);
+
+ gdk_error_trap_push ();
+ result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (root_win),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_CURRENT_DESKTOP"),
+ 0, G_MAXLONG, False, XA_CARDINAL, &type, &format, &nitems,
+ &bytes_after, (gpointer) ¤t_desktop);
+ err = gdk_error_trap_pop ();
+
+ if (err != Success || result != Success)
+ return ret;
+
+ if (type == XA_CARDINAL && format == 32 && nitems > 0)
+ ret = current_desktop[0];
+
+ XFree (current_desktop);
+ return ret;
+#else
+ /* FIXME: on mac etc proably there are native APIs
+ * to get the current workspace etc */
+ return 0;
+#endif
+}
+
+/**
+ * gedit_utils_get_window_workspace: Get the workspace the window is on
+ *
+ * This function gets the workspace that the #GtkWindow is visible on,
+ * it returns GEDIT_ALL_WORKSPACES if the window is sticky, or if
+ * the window manager doesn support this function
+ */
+guint
+vinagre_utils_get_window_workspace (GtkWindow *gtkwindow)
+{
+#ifdef GDK_WINDOWING_X11
+ GdkWindow *window;
+ GdkDisplay *display;
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+ guint *workspace;
+ gint err, result;
+ guint ret = VINAGRE_ALL_WORKSPACES;
+
+ g_return_val_if_fail (GTK_IS_WINDOW (gtkwindow), 0);
+ g_return_val_if_fail (GTK_WIDGET_REALIZED (GTK_WIDGET (gtkwindow)), 0);
+
+ window = GTK_WIDGET (gtkwindow)->window;
+ display = gdk_drawable_get_display (window);
+
+ gdk_error_trap_push ();
+ result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"),
+ 0, G_MAXLONG, False, XA_CARDINAL, &type, &format, &nitems,
+ &bytes_after, (gpointer) &workspace);
+ err = gdk_error_trap_pop ();
+
+ if (err != Success || result != Success)
+ return ret;
+
+ if (type == XA_CARDINAL && format == 32 && nitems > 0)
+ ret = workspace[0];
+
+ XFree (workspace);
+ return ret;
+#else
+ /* FIXME: on mac etc proably there are native APIs
+ * to get the current workspace etc */
+ return 0;
+#endif
+}
+
+/**
+ * gedit_utils_get_current_viewport: Get the current viewport origin
+ *
+ * Get the currently visible viewport origin for the #GdkScreen.
+ *
+ * If the X11 window property isn't found, (0, 0) is returned.
+ */
+void
+vinagre_utils_get_current_viewport (GdkScreen *screen,
+ gint *x,
+ gint *y)
+{
+#ifdef GDK_WINDOWING_X11
+ GdkWindow *root_win;
+ GdkDisplay *display;
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+ gulong *coordinates;
+ gint err, result;
+
+ g_return_if_fail (GDK_IS_SCREEN (screen));
+ g_return_if_fail (x != NULL && y != NULL);
+
+ /* Default values for the viewport origin */
+ *x = 0;
+ *y = 0;
+
+ root_win = gdk_screen_get_root_window (screen);
+ display = gdk_screen_get_display (screen);
+
+ gdk_error_trap_push ();
+ result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (root_win),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_DESKTOP_VIEWPORT"),
+ 0, G_MAXLONG, False, XA_CARDINAL, &type, &format, &nitems,
+ &bytes_after, (void*) &coordinates);
+ err = gdk_error_trap_pop ();
+
+ if (err != Success || result != Success)
+ return;
+
+ if (type != XA_CARDINAL || format != 32 || nitems < 2)
+ {
+ XFree (coordinates);
+ return;
+ }
+
+ *x = coordinates[0];
+ *y = coordinates[1];
+ XFree (coordinates);
+#else
+ /* FIXME: on mac etc proably there are native APIs
+ * to get the current workspace etc */
+ *x = 0;
+ *y = 0;
+#endif
+}
+
/* vim: ts=8 */
Modified: trunk/src/vinagre-utils.h
==============================================================================
--- trunk/src/vinagre-utils.h (original)
+++ trunk/src/vinagre-utils.h Sat May 10 02:41:21 2008
@@ -2,7 +2,7 @@
* vinagre-utils.h
* This file is part of vinagre
*
- * Copyright (C) 2007 - Jonh Wendell <wendell bani com br>
+ * Copyright (C) 2007,2008 - Jonh Wendell <wendell bani com br>
*
* 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
@@ -24,6 +24,13 @@
#include <gtk/gtk.h>
#include <glib.h>
+/* useful macro */
+#define GBOOLEAN_TO_POINTER(i) ((gpointer) ((i) ? 2 : 1))
+#define GPOINTER_TO_BOOLEAN(i) ((gboolean) ((((gint)(i)) == 2) ? TRUE : FALSE))
+#define IS_VALID_BOOLEAN(v) (((v == TRUE) || (v == FALSE)) ? TRUE : FALSE)
+
+enum { VINAGRE_ALL_WORKSPACES = 0xffffffff };
+
GtkWidget *vinagre_utils_create_small_close_button (void);
void vinagre_utils_show_error (const gchar *message,
@@ -42,5 +49,12 @@
gssize length);
void vinagre_utils_handle_debug (void);
+
+guint vinagre_utils_get_current_workspace (GdkScreen *screen);
+guint vinagre_utils_get_window_workspace (GtkWindow *gtkwindow);
+void vinagre_utils_get_current_viewport (GdkScreen *screen,
+ gint *x,
+ gint *y);
+
#endif /* __VINAGRE_UTILS_H__ */
/* vim: ts=8 */
Modified: trunk/src/vinagre-window-private.h
==============================================================================
--- trunk/src/vinagre-window-private.h (original)
+++ trunk/src/vinagre-window-private.h Sat May 10 02:41:21 2008
@@ -48,6 +48,7 @@
GtkAction *recent_action;
guint bookmarks_list_menu_ui_id;
guint recents_menu_ui_id;
+ guint update_recents_menu_ui_id;
GtkWidget *toolbar;
GtkWidget *menubar;
Modified: trunk/src/vinagre-window.c
==============================================================================
--- trunk/src/vinagre-window.c (original)
+++ trunk/src/vinagre-window.c Sat May 10 02:41:21 2008
@@ -47,7 +47,7 @@
G_DEFINE_TYPE(VinagreWindow, vinagre_window, GTK_TYPE_WINDOW)
static void
-vinagre_window_finalize (GObject *object)
+vinagre_window_dispose (GObject *object)
{
VinagreWindow *window = VINAGRE_WINDOW (object);
@@ -63,6 +63,37 @@
window->priv->manager = NULL;
}
+ if (window->priv->signal_notebook != 0)
+ {
+ g_signal_handler_disconnect (window->priv->notebook,
+ window->priv->signal_notebook);
+ window->priv->signal_notebook = 0;
+ }
+
+ if (window->priv->signal_clipboard != 0)
+ {
+ GtkClipboard *cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);;
+
+ g_signal_handler_disconnect (cb,
+ window->priv->signal_clipboard);
+ window->priv->signal_clipboard = 0;
+ }
+
+ if (window->priv->update_recents_menu_ui_id != 0)
+ {
+ GtkRecentManager *recent_manager = gtk_recent_manager_get_default ();
+
+ g_signal_handler_disconnect (recent_manager,
+ window->priv->update_recents_menu_ui_id);
+ window->priv->update_recents_menu_ui_id = 0;
+ }
+
+ G_OBJECT_CLASS (vinagre_window_parent_class)->dispose (object);
+}
+
+static void
+vinagre_window_finalize (GObject *object)
+{
G_OBJECT_CLASS (vinagre_window_parent_class)->finalize (object);
}
@@ -71,20 +102,8 @@
GdkEventAny *event)
{
VinagreWindow *window = VINAGRE_WINDOW (widget);
- GtkClipboard *cb;
-
- cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
-
- if (window->priv->signal_notebook > 0)
- g_signal_handler_disconnect (window->priv->notebook,
- window->priv->signal_notebook);
-
- if (window->priv->signal_clipboard > 0)
- g_signal_handler_disconnect (cb,
- window->priv->signal_clipboard);
vinagre_window_close_all_tabs (window);
- gtk_main_quit ();
if (GTK_WIDGET_CLASS (vinagre_window_parent_class)->delete_event)
return GTK_WIDGET_CLASS (vinagre_window_parent_class)->delete_event (widget, event);
@@ -198,7 +217,8 @@
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- object_class->finalize = vinagre_window_finalize;
+ object_class->finalize = vinagre_window_finalize;
+ object_class->dispose = vinagre_window_dispose;
widget_class->key_press_event = vinagre_window_key_press_cb;
widget_class->window_state_event = vinagre_window_state_event_cb;
@@ -291,7 +311,8 @@
g_free (error);
}
-static void update_recent_connections (VinagreWindow *window)
+static void
+update_recent_connections (VinagreWindow *window)
{
VinagreWindowPrivate *p = window->priv;
@@ -465,11 +486,11 @@
update_recent_connections (window);
recent_manager = gtk_recent_manager_get_default ();
- g_signal_connect (recent_manager,
+ window->priv->update_recents_menu_ui_id = g_signal_connect (
+ recent_manager,
"changed",
G_CALLBACK (recent_manager_changed),
window);
-
}
void
@@ -1143,4 +1164,60 @@
return window->priv->manager;
}
+static void
+add_connection (VinagreTab *tab, GList **res)
+{
+ VinagreConnection *conn;
+
+ conn = vinagre_tab_get_conn (tab);
+
+ *res = g_list_prepend (*res, conn);
+}
+
+/* Returns a newly allocated list with all the connections in the window */
+GList *
+vinagre_window_get_connections (VinagreWindow *window)
+{
+ GList *res = NULL;
+
+ g_return_val_if_fail (VINAGRE_IS_WINDOW (window), NULL);
+
+ gtk_container_foreach (GTK_CONTAINER (window->priv->notebook),
+ (GtkCallback)add_connection,
+ &res);
+
+ res = g_list_reverse (res);
+
+ return res;
+}
+
+VinagreTab *
+vinagre_window_conn_exists (VinagreWindow *window, VinagreConnection *conn)
+{
+ VinagreConnection *c;
+ VinagreTab *tab = NULL;
+ GList *l;
+
+ g_return_val_if_fail (VINAGRE_IS_WINDOW (window), NULL);
+ g_return_val_if_fail (VINAGRE_IS_CONNECTION (conn), NULL);
+
+ l = vinagre_window_get_connections (window);
+
+ while (l != NULL)
+ {
+ c = VINAGRE_CONNECTION (l->data);
+
+ if (!strcmp (vinagre_connection_get_host (conn), vinagre_connection_get_host (c)) &&
+ vinagre_connection_get_port (conn) == vinagre_connection_get_port (c))
+ {
+ tab = g_object_get_data (G_OBJECT (c), VINAGRE_TAB_KEY);
+ break;
+ }
+ l = l->next;
+ }
+ g_list_free (l);
+
+ return tab;
+}
+
/* vim: ts=8 */
Modified: trunk/src/vinagre-window.h
==============================================================================
--- trunk/src/vinagre-window.h (original)
+++ trunk/src/vinagre-window.h Sat May 10 02:41:21 2008
@@ -51,9 +51,9 @@
GtkWindowClass parent_class;
};
-GType vinagre_window_get_type (void) G_GNUC_CONST;
+GType vinagre_window_get_type (void) G_GNUC_CONST;
-VinagreWindow *vinagre_window_new ();
+VinagreWindow *vinagre_window_new (void);
VinagreTab *vinagre_window_create_tab (VinagreWindow *window,
gboolean jump_to);
@@ -90,6 +90,11 @@
void vinagre_window_set_title (VinagreWindow *window);
void vinagre_window_update_machine_menu_sensitivity (VinagreWindow *window);
+
+GList *vinagre_window_get_connections (VinagreWindow *window);
+VinagreTab *vinagre_window_conn_exists (VinagreWindow *window,
+ VinagreConnection *conn);
+
G_END_DECLS
#endif /* __VINAGRE_WINDOW_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]