r271: Added the IPC code to CVS.
[rox-filer.git] / ROX-Filer / src / remote.c
blob8da3d248b4a6db8cb2b33c66d4a3b131f0767c79
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"
41 static GdkAtom filer_atom; /* _ROX_FILER_VERSION_HOST */
42 static GdkAtom ipc_atom; /* _ROX_FILER_OPEN */
44 /* Static prototypes */
45 static GdkWindow *get_existing_ipc_window();
46 static gboolean get_ipc_property(GdkWindow *window, Window *r_xid);
47 static gboolean ipc_prop_changed(GtkWidget *window,
48 GdkEventProperty *event,
49 gpointer data);
50 static void send_request(GdkWindow *ipc_window, int argc, char **argv);
51 static void open_dirs(guchar *data, int length);
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 gboolean remote_init(int argc, char **argv, gboolean new_copy)
64 guchar *unique_id;
65 GdkWindowPrivate *window;
66 GdkWindow *existing_ipc_window;
67 GtkWidget *ipc_window;
69 unique_id = g_strdup_printf("_ROX_FILER_%s_%s",
70 VERSION, our_host_name());
71 filer_atom = gdk_atom_intern(unique_id, FALSE);
72 g_free(unique_id);
74 ipc_atom = gdk_atom_intern("_ROX_FILER_OPEN", FALSE);
76 existing_ipc_window = new_copy ? NULL : get_existing_ipc_window();
77 if (existing_ipc_window)
79 send_request(existing_ipc_window, argc, argv);
80 return TRUE;
83 /* Note: possible race-condition here if two filers both
84 * start at the same time and one isn't already running.
85 * Oh well.
88 ipc_window = gtk_invisible_new();
89 gtk_widget_realize(ipc_window);
91 window = (GdkWindowPrivate *) ipc_window->window;
93 /* Make the IPC window contain a property pointing to
94 * itself - this can then be used to check that it really
95 * is an IPC window.
97 gdk_property_change(ipc_window->window, filer_atom,
98 XA_WINDOW, 32, GDK_PROP_MODE_REPLACE,
99 (guchar *) &window->xwindow, 1);
101 /* Get notified when the IPC property is changed */
102 gtk_widget_add_events(ipc_window, GDK_PROPERTY_CHANGE_MASK);
103 gtk_signal_connect(GTK_OBJECT(ipc_window), "property-notify-event",
104 GTK_SIGNAL_FUNC(ipc_prop_changed), NULL);
106 /* Make the root window contain a pointer to the IPC window */
107 gdk_property_change(GDK_ROOT_PARENT(), filer_atom,
108 XA_WINDOW, 32, GDK_PROP_MODE_REPLACE,
109 (guchar *) &window->xwindow, 1);
111 return FALSE;
115 /****************************************************************
116 * INTERNAL FUNCTIONS *
117 ****************************************************************/
119 /* Get the remote IPC window of the already-running filer if there
120 * is one.
122 static GdkWindow *get_existing_ipc_window()
124 Window xid, xid_confirm;
125 GdkWindow *window;
127 if (!get_ipc_property(GDK_ROOT_PARENT(), &xid))
128 return NULL;
130 window = gdk_window_foreign_new(xid);
131 if (!window)
132 return NULL;
134 if (!get_ipc_property(window, &xid_confirm) || xid_confirm != xid)
135 return NULL;
137 return window;
140 /* Returns the 'rox_atom' property of 'window' */
141 static gboolean get_ipc_property(GdkWindow *window, Window *r_xid)
143 guchar *data;
144 gint format, length;
145 gboolean retval = FALSE;
147 if (gdk_property_get(window, filer_atom, XA_WINDOW, 0, 4,
148 FALSE, NULL, &format, &length, &data) && data)
150 if (format == 32 && length == 4)
152 retval = TRUE;
153 *r_xid = *((Window *) data);
155 g_free(data);
158 return retval;
162 static gboolean ipc_prop_changed(GtkWidget *window,
163 GdkEventProperty *event,
164 gpointer data)
166 if (event->atom == ipc_atom)
168 gint grab_len = 4096;
169 gint length;
170 guchar *data;
172 while (1)
175 if (!gdk_property_get(window->window, ipc_atom,
176 XA_STRING, 0, grab_len,
177 TRUE, NULL, NULL,
178 &length, &data) && data)
179 return TRUE; /* Error? */
181 if (length >= grab_len)
183 /* Didn't get all of it - try again */
184 grab_len <<= 1;
185 g_free(data);
186 continue;
189 data = g_realloc(data, length + 1);
190 data[length] = '\0';
192 open_dirs(data, length);
194 g_free(data);
195 break;
198 return TRUE;
201 return FALSE;
204 static void send_request(GdkWindow *ipc_window, int argc, char **argv)
206 char *data, *d;
207 int i, size = 0;
209 if (argc == 0)
211 argc = 1;
212 argv = &home_dir;
215 for (i = 0; i < argc; i++)
216 size += strlen(argv[i]) + 1;
218 data = g_malloc(size);
220 d = data;
221 for (i = 0; i < argc; i++)
223 int len;
225 len = strlen(argv[i]);
226 memcpy(d, argv[i], len + 1);
227 d += len + 1;
230 gdk_property_change(ipc_window, ipc_atom, XA_STRING, 8,
231 GDK_PROP_MODE_APPEND, data, size);
233 g_free(data);
236 /* data is a sequence of nul-term'd strings */
237 static void open_dirs(guchar *data, int length)
239 while (length > 0)
241 int len;
243 if (*data)
244 filer_opendir(data, PANEL_NO);
246 len = strlen(data) + 1;
247 data += len;
248 length -= len;