r898: Applied Bernard Jungen's latest patch:
[rox-filer.git] / ROX-Filer / src / sc.c
blob3395bce24a8b7f4b4bd42c6e29813da0d79867ea
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2001, the ROX-Filer team.
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 /* sc.c - XSMP client support */
24 #include <stdlib.h>
25 #include <fcntl.h>
26 #include <gtk/gtk.h>
27 #include <X11/Xlib.h>
28 #include <X11/SM/SMlib.h>
29 #include <pwd.h>
30 #include "sc.h"
32 static SmPropValue *make_list_of_array_value(gchar *vals[], gint nvals)
34 SmPropValue *values = g_new(SmPropValue, nvals);
35 gint i;
37 for(i = 0; i < nvals; i++)
39 values[i].value = g_strdup(vals[i]);
40 values[i].length = strlen(vals[i]);
42 return values;
45 static SmPropValue *make_array_value(gchar *val)
47 SmPropValue *value = g_new(SmPropValue, 1);
49 value->value = g_strdup(val);
50 value->length = strlen(val);
52 return value;
55 static SmPropValue *make_card_value(gchar val)
57 SmPropValue *value = g_new(SmPropValue, 1);
59 value->value = g_memdup(&val, sizeof(gchar));
60 value->length = 1;
62 return value;
65 static SmProperty *find_property(SmClient *client, gchar *name)
67 GSList *list = client->props;
68 SmProperty *prop;
70 while(list)
72 prop = (SmProperty *)list->data;
73 if(strcmp(prop->prop.name, name) == 0)
74 return prop;
75 list = g_slist_next(list);
77 return NULL;
80 static SmProperty *new_property(SmClient *client, gchar *name, gchar *type)
82 SmProperty *prop;
84 prop = g_new(SmProperty, 1);
85 prop->prop.name = g_strdup(name);
86 prop->prop.type = g_strdup(type);
87 prop->prop.vals = NULL;
88 prop->prop.num_vals = 0;
89 #ifdef DEBUG
90 g_printerr("appending prop %s\n", prop->prop.name);
91 #endif
92 client->props = g_slist_append(client->props, prop);
94 return prop;
97 gint close_connection(gpointer data)
99 SmClient *client = (SmClient *)data;
101 SmcCloseConnection(client->conn, 0, NULL);
103 return 0;
106 /* Called when there's data to be read on the ICE file descriptor.
107 Unpacks the message and triggers the correct callback... I think */
109 void poll_ice_messages(gpointer data, gint source, GdkInputCondition condition)
111 SmClient *client = (SmClient *)data;
112 Bool ret;
114 if(IceProcessMessages(client->ice_conn, NULL, &ret) == IceProcessMessagesIOError)
115 SmcCloseConnection(client->conn, 0, NULL);
116 return;
119 /* Called whenever an ICE connection is opened or closed */
121 void ice_watch_fn(IceConn conn, IcePointer client_data,
122 Bool opening, IcePointer *watch_data)
124 SmClient *client = (SmClient *)client_data;
126 if(opening)
128 #ifdef DEBUG
129 g_printerr("Ice connection opened for id %s\n", client->id);
130 #endif
131 client->fd = IceConnectionNumber(conn);
132 fcntl(client->fd, F_SETFD, FD_CLOEXEC);
133 client->input_tag = gdk_input_add(client->fd, GDK_INPUT_READ, &poll_ice_messages, client);
135 else
137 if (IceConnectionNumber(conn) == client->fd)
139 #ifdef DEBUG
140 g_printerr("Ice connection closed for id %s\n", client->id);
141 #endif
142 gdk_input_remove(client->input_tag);
143 sc_destroy(client);
148 /* Callbacks for different SM messages */
150 void sc_save_yourself(SmcConn conn, SmPointer client_data, int save_type,
151 Bool shutdown, int interact_style, Bool fast)
153 SmClient *client = (SmClient *)client_data;
154 gboolean success = TRUE;
155 #ifdef DEBUG
156 g_printerr("%s saving state\n", client->id);
157 #endif
158 if(client->save_yourself_fn)
159 success = client->save_yourself_fn(client);
160 if(success)
161 sc_register_properties(client);
162 SmcSaveYourselfDone(client->conn, success);
165 void sc_shutdown_cancelled(SmcConn conn, SmPointer client_data)
167 SmClient *client = (SmClient *)client_data;
168 #ifdef DEBUG
169 g_printerr("%s shutdown cancelled\n", client->id);
170 #endif
171 if(client->shutdown_cancelled_fn)
172 client->shutdown_cancelled_fn(client);
175 void sc_save_complete(SmcConn conn, SmPointer client_data)
177 SmClient *client = (SmClient *)client_data;
178 #ifdef DEBUG
179 g_printerr("%s save complete\n", client->id);
180 #endif
181 if(client->save_complete_fn)
182 client->save_complete_fn(client);
185 void sc_die(SmcConn conn, SmPointer client_data)
187 SmClient *client = (SmClient *)client_data;
188 #ifdef DEBUG
189 g_printerr("%s dying\n", client->id);
190 #endif
191 if(client->die_fn)
192 client->die_fn(client);
195 gboolean sc_session_up()
197 if(getenv("SESSION_MANAGER") == NULL)
198 return FALSE;
199 return TRUE;
202 SmClient *sc_new(gchar *client_id)
204 SmClient *client;
206 #ifdef DEBUG
207 g_printerr("Creating new sm-client\n");
208 #endif
209 client = g_new(SmClient, 1);
210 client->id = g_strdup(client_id);
211 client->props = NULL;
212 client->conn = NULL;
213 client->ice_conn = NULL;
214 client->fd = -1;
216 return client;
219 void sc_destroy(SmClient *client)
221 GSList *list = client->props;
222 SmProperty *prop;
224 #ifdef DEBUG
225 g_printerr("destroying client\n");
226 #endif
227 while(list)
229 prop = (SmProperty *)list->data;
230 g_free(prop->prop.vals->value);
231 g_free(prop->prop.vals);
232 g_free(prop->prop.name);
233 g_free(prop->prop.type);
234 g_free(prop);
235 list = g_slist_next(list);
237 g_slist_free(client->props);
238 g_free(client->id);
239 g_free(client);
242 /* Set a property with a SmLISTofARRAY8 value as in SmRestartCommand,
243 SmCloneCommand and SmDiscardCommand */
245 void sc_set_list_of_array_prop(SmClient *client, gchar *name, gchar *vals[], gint nvals)
247 SmProperty *prop = find_property(client, name);
248 SmPropValue *value = make_list_of_array_value(vals, nvals);
250 if(prop == NULL)
251 prop = new_property(client, name, SmLISTofARRAY8);
253 else
254 g_free(prop->prop.vals);
256 prop->prop.vals = value;
257 prop->prop.num_vals = nvals;
258 prop->set = TRUE;
261 /* Set a prop with a SmARRAY8 value, SmProgram, SmUserID and
262 SmDiscardCommand (if using XSM) are suitable victims. */
264 void sc_set_array_prop(SmClient *client, gchar *name, gchar *vals)
266 SmProperty *prop = find_property(client, name);
267 SmPropValue *value = make_array_value(vals);
269 if(prop == NULL)
270 prop = new_property(client, name, SmARRAY8);
272 else
273 g_free(prop->prop.vals);
275 prop->prop.vals = value;
276 prop->prop.num_vals = 1;
277 prop->set = TRUE;
280 /* This one is for the SmRestarStyleHint */
282 void sc_set_card_prop(SmClient *client, gchar *name, gchar val)
284 SmProperty *prop = find_property(client, name);
285 SmPropValue *value = make_card_value(val);
287 if(prop == NULL)
288 prop = new_property(client, name, SmCARD8);
290 else
291 g_free(prop->prop.vals);
293 prop->prop.vals = value;
294 prop->prop.num_vals = 1;
295 prop->set = TRUE;
298 /* Puts a pointer to a SmPropValue in val_ret and
299 the number of values in nvals_ret (they are in an array ).
300 It looks like this:
301 typedef struct {
302 int length;
303 SmPointer value;
304 } SmPropValue;
305 The values are those stored in the SmClient struct,
306 They're not fetched from the session manager */
308 void sc_get_prop_value(SmClient *client, gchar *name, SmPropValue **val_ret, gint *nvals_ret)
310 SmProperty *prop = find_property(client, name);
312 if(!prop)
314 *val_ret = NULL;
315 *nvals_ret = 0;
317 else
319 *val_ret = prop->prop.vals;
320 *nvals_ret = prop->prop.num_vals;
324 /* Stores set properties in the session manager */
326 void sc_register_properties(SmClient *client)
328 GPtrArray *set_props= g_ptr_array_new();
329 GSList *list = client->props;
330 SmProperty *prop;
331 #ifdef DEBUG
332 gint i;
333 #endif
335 while(list)
337 prop = (SmProperty *)list->data;
338 if(prop->set == TRUE)
340 g_ptr_array_add(set_props, &prop->prop);
341 prop->set = FALSE;
343 list = g_slist_next(list);
345 #ifdef DEBUG
346 g_printerr("Registering props:\n");
347 for(i = 0; i < set_props->len; i++)
349 prop = g_ptr_array_index(set_props, i);
350 g_printerr("%s\n", prop->prop.name);
352 #endif
353 if(set_props->len > 0)
354 SmcSetProperties(client->conn, set_props->len, (SmProp **)set_props->pdata);
356 g_ptr_array_free(set_props, TRUE);
359 /* Connects to the session manager */
361 gboolean sc_connect(SmClient *client)
363 gchar error_str[256];
364 gchar *client_id_ret = NULL;
365 SmcConn conn = NULL;
366 SmcCallbacks callbacks = { { &sc_save_yourself, (SmPointer)client },
367 { &sc_die, (SmPointer)client },
368 { &sc_save_complete, (SmPointer)client },
369 { &sc_shutdown_cancelled, (SmPointer)client } };
372 if(IceAddConnectionWatch(&ice_watch_fn, client) == 0)
374 g_printerr("Session Manager: IceAddConnectionWatch failed\n");
375 return FALSE;
378 if((conn = SmcOpenConnection(NULL, /* network ids */
379 NULL, /* context */
380 1, 0, /* protocol major, minor */
381 SmcSaveYourselfProcMask |
382 SmcSaveCompleteProcMask |
383 SmcShutdownCancelledProcMask |
384 SmcDieProcMask,
385 &callbacks,
386 client->id, &client_id_ret,
387 sizeof(error_str), error_str)) == NULL)
389 g_printerr("Session Manager: Init error\n");
390 return FALSE;
393 client->id = g_strdup(client_id_ret);
394 client->conn = conn;
395 client->ice_conn = SmcGetIceConnection(conn);
396 gdk_set_sm_client_id(client->id);
397 XFree(client_id_ret);
399 gtk_quit_add(0, &close_connection, client);
401 return TRUE;