r328: Changed the install script so that the CVS directories don't get installed.
[rox-filer.git] / ROX-Filer / src / remote.c
blobac13f1a349eeb63063e080c80d6d800830dab811
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@ecs.soton.ac.uk>.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* This code is used to communicate between two copies of the filer:
23 * If the filer is run and the same version of the filer is already
24 * running on the same machine then the new copy simply asks the old
25 * one deal with it and quits.
28 #include "config.h"
30 #include <gdk/gdkx.h>
31 #include <X11/X.h>
32 #include <X11/Xatom.h>
33 #include <gtk/gtk.h>
34 #include <gtk/gtkinvisible.h>
36 #include "main.h"
37 #include "support.h"
38 #include "filer.h"
39 #include "gui_support.h"
40 #include "run.h"
41 #include "remote.h"
43 static GdkAtom filer_atom; /* _ROX_FILER_VERSION_HOST */
44 static GdkAtom ipc_atom; /* _ROX_FILER_OPEN */
46 /* Static prototypes */
47 static GdkWindow *get_existing_ipc_window();
48 static gboolean get_ipc_property(GdkWindow *window, Window *r_xid);
49 static gboolean ipc_prop_changed(GtkWidget *window,
50 GdkEventProperty *event,
51 gpointer data);
53 /****************************************************************
54 * EXTERNAL INTERFACE *
55 ****************************************************************/
58 /* Try to get an already-running filer to handle things (only if
59 * new_copy is FALSE); TRUE if we succeed.
60 * Create and IPC widget so that future filers can contact us.
62 * See main() for a description of 'to_open'.
64 gboolean remote_init(GString *to_open, gboolean new_copy)
66 guchar *unique_id;
67 GdkWindowPrivate *window;
68 GdkWindow *existing_ipc_window;
69 GtkWidget *ipc_window;
71 unique_id = g_strdup_printf("_ROX_FILER_%s_%s",
72 VERSION, our_host_name());
73 filer_atom = gdk_atom_intern(unique_id, FALSE);
74 g_free(unique_id);
76 ipc_atom = gdk_atom_intern("_ROX_FILER_OPEN", FALSE);
78 existing_ipc_window = new_copy ? NULL : get_existing_ipc_window();
79 if (existing_ipc_window)
81 gdk_property_change(existing_ipc_window, ipc_atom, XA_STRING, 8,
82 GDK_PROP_MODE_APPEND, to_open->str, to_open->len);
83 return TRUE;
86 /* Note: possible race-condition here if two filers both
87 * start at the same time and one isn't already running.
88 * Oh well.
91 ipc_window = gtk_invisible_new();
92 gtk_widget_realize(ipc_window);
94 window = (GdkWindowPrivate *) ipc_window->window;
96 /* Make the IPC window contain a property pointing to
97 * itself - this can then be used to check that it really
98 * is an IPC window.
100 gdk_property_change(ipc_window->window, filer_atom,
101 XA_WINDOW, 32, GDK_PROP_MODE_REPLACE,
102 (guchar *) &window->xwindow, 1);
104 /* Get notified when the IPC property is changed */
105 gtk_widget_add_events(ipc_window, GDK_PROPERTY_CHANGE_MASK);
106 gtk_signal_connect(GTK_OBJECT(ipc_window), "property-notify-event",
107 GTK_SIGNAL_FUNC(ipc_prop_changed), NULL);
109 /* Make the root window contain a pointer to the IPC window */
110 gdk_property_change(GDK_ROOT_PARENT(), filer_atom,
111 XA_WINDOW, 32, GDK_PROP_MODE_REPLACE,
112 (guchar *) &window->xwindow, 1);
114 return FALSE;
118 /****************************************************************
119 * INTERNAL FUNCTIONS *
120 ****************************************************************/
122 /* Get the remote IPC window of the already-running filer if there
123 * is one.
125 static GdkWindow *get_existing_ipc_window()
127 Window xid, xid_confirm;
128 GdkWindow *window;
130 if (!get_ipc_property(GDK_ROOT_PARENT(), &xid))
131 return NULL;
133 window = gdk_window_foreign_new(xid);
134 if (!window)
135 return NULL;
137 if (!get_ipc_property(window, &xid_confirm) || xid_confirm != xid)
138 return NULL;
140 return window;
143 /* Returns the 'rox_atom' property of 'window' */
144 static gboolean get_ipc_property(GdkWindow *window, Window *r_xid)
146 guchar *data;
147 gint format, length;
148 gboolean retval = FALSE;
150 if (gdk_property_get(window, filer_atom, XA_WINDOW, 0, 4,
151 FALSE, NULL, &format, &length, &data) && data)
153 if (format == 32 && length == 4)
155 retval = TRUE;
156 *r_xid = *((Window *) data);
158 g_free(data);
161 return retval;
165 static gboolean ipc_prop_changed(GtkWidget *window,
166 GdkEventProperty *event,
167 gpointer data)
169 if (event->atom == ipc_atom)
171 gint grab_len = 4096;
172 gint length;
173 guchar *data;
175 while (1)
178 if (!(gdk_property_get(window->window, ipc_atom,
179 XA_STRING, 0, grab_len,
180 TRUE, NULL, NULL,
181 &length, &data) && data))
182 return TRUE; /* Error? */
184 if (length >= grab_len)
186 /* Didn't get all of it - try again */
187 grab_len <<= 1;
188 g_free(data);
189 continue;
192 data = g_realloc(data, length + 1);
193 data[length] = '\0';
195 run_list(data);
197 g_free(data);
198 break;
201 return TRUE;
204 return FALSE;