r367: Running a second copy of the filer as another user will start a new copy
[rox-filer.git] / ROX-Filer / src / remote.c
blobf15c18b8dbc45dcd8418301ab9f9f13af962930c
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@users.sourceforge.net>.
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 "global.h"
38 #include "main.h"
39 #include "support.h"
40 #include "gui_support.h"
41 #include "run.h"
42 #include "remote.h"
44 static GdkAtom filer_atom; /* _ROX_FILER_VERSION_HOST */
45 static GdkAtom ipc_atom; /* _ROX_FILER_OPEN */
47 /* Static prototypes */
48 static GdkWindow *get_existing_ipc_window();
49 static gboolean get_ipc_property(GdkWindow *window, Window *r_xid);
50 static gboolean ipc_prop_changed(GtkWidget *window,
51 GdkEventProperty *event,
52 gpointer data);
54 /****************************************************************
55 * EXTERNAL INTERFACE *
56 ****************************************************************/
59 /* Try to get an already-running filer to handle things (only if
60 * new_copy is FALSE); TRUE if we succeed.
61 * Create and IPC widget so that future filers can contact us.
63 * See main() for a description of 'to_open'.
65 gboolean remote_init(GString *to_open, gboolean new_copy)
67 guchar *unique_id;
68 GdkWindowPrivate *window;
69 GdkWindow *existing_ipc_window;
70 GtkWidget *ipc_window;
72 unique_id = g_strdup_printf("_ROX_FILER_%d_%s_%s",
73 euid, VERSION, our_host_name());
74 filer_atom = gdk_atom_intern(unique_id, FALSE);
75 g_free(unique_id);
77 ipc_atom = gdk_atom_intern("_ROX_FILER_OPEN", FALSE);
79 existing_ipc_window = new_copy ? NULL : get_existing_ipc_window();
80 if (existing_ipc_window)
82 gdk_property_change(existing_ipc_window, ipc_atom, XA_STRING, 8,
83 GDK_PROP_MODE_APPEND, to_open->str, to_open->len);
84 return TRUE;
87 /* Note: possible race-condition here if two filers both
88 * start at the same time and one isn't already running.
89 * Oh well.
92 ipc_window = gtk_invisible_new();
93 gtk_widget_realize(ipc_window);
95 window = (GdkWindowPrivate *) ipc_window->window;
97 /* Make the IPC window contain a property pointing to
98 * itself - this can then be used to check that it really
99 * is an IPC window.
101 gdk_property_change(ipc_window->window, filer_atom,
102 XA_WINDOW, 32, GDK_PROP_MODE_REPLACE,
103 (guchar *) &window->xwindow, 1);
105 /* Get notified when the IPC property is changed */
106 gtk_widget_add_events(ipc_window, GDK_PROPERTY_CHANGE_MASK);
107 gtk_signal_connect(GTK_OBJECT(ipc_window), "property-notify-event",
108 GTK_SIGNAL_FUNC(ipc_prop_changed), NULL);
110 /* Make the root window contain a pointer to the IPC window */
111 gdk_property_change(GDK_ROOT_PARENT(), filer_atom,
112 XA_WINDOW, 32, GDK_PROP_MODE_REPLACE,
113 (guchar *) &window->xwindow, 1);
115 return FALSE;
119 /****************************************************************
120 * INTERNAL FUNCTIONS *
121 ****************************************************************/
123 /* Get the remote IPC window of the already-running filer if there
124 * is one.
126 static GdkWindow *get_existing_ipc_window()
128 Window xid, xid_confirm;
129 GdkWindow *window;
131 if (!get_ipc_property(GDK_ROOT_PARENT(), &xid))
132 return NULL;
134 window = gdk_window_foreign_new(xid);
135 if (!window)
136 return NULL;
138 if (!get_ipc_property(window, &xid_confirm) || xid_confirm != xid)
139 return NULL;
141 return window;
144 /* Returns the 'rox_atom' property of 'window' */
145 static gboolean get_ipc_property(GdkWindow *window, Window *r_xid)
147 guchar *data;
148 gint format, length;
149 gboolean retval = FALSE;
151 if (gdk_property_get(window, filer_atom, XA_WINDOW, 0, 4,
152 FALSE, NULL, &format, &length, &data) && data)
154 if (format == 32 && length == 4)
156 retval = TRUE;
157 *r_xid = *((Window *) data);
159 g_free(data);
162 return retval;
166 static gboolean ipc_prop_changed(GtkWidget *window,
167 GdkEventProperty *event,
168 gpointer data)
170 if (event->atom == ipc_atom)
172 gint grab_len = 4096;
173 gint length;
174 guchar *data;
176 while (1)
179 if (!(gdk_property_get(window->window, ipc_atom,
180 XA_STRING, 0, grab_len,
181 TRUE, NULL, NULL,
182 &length, &data) && data))
183 return TRUE; /* Error? */
185 if (length >= grab_len)
187 /* Didn't get all of it - try again */
188 grab_len <<= 1;
189 g_free(data);
190 continue;
193 data = g_realloc(data, length + 1);
194 data[length] = '\0';
196 run_list(data);
198 g_free(data);
199 break;
202 return TRUE;
205 return FALSE;