Converted README to markdown
[rox-filer.git] / ROX-Filer / src / sc.c
blobd7939efd3739623eeaefa0d4dba88456471081e6
1 /*
2 * ROX-Filer, filer for the ROX desktop project
3 * Copyright (C) 2006, Thomas Leonard and others (see changelog for details).
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place, Suite 330, Boston, MA 02111-1307 USA
20 /* sc.c - XSMP client support */
22 #include <stdlib.h>
23 #include <fcntl.h>
24 #include <gtk/gtk.h>
25 #include <X11/Xlib.h>
26 #include <X11/SM/SMlib.h>
27 #include <pwd.h>
28 #include <string.h>
30 #include "sc.h"
32 static SmPropValue *make_list_of_array_value(const 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(const 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, const gchar *name)
67 GSList *list = client->props;
68 SmProperty *prop;
70 for (; list; list = list->next)
72 prop = (SmProperty *)list->data;
73 if (strcmp(prop->prop.name, name) == 0)
74 return prop;
76 return NULL;
79 static SmProperty *new_property(SmClient *client,
80 const gchar *name, const 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 static 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 static void poll_ice_messages(gpointer data, gint source,
110 GdkInputCondition condition)
112 SmClient *client = (SmClient *)data;
113 Bool ret;
115 if (IceProcessMessages(client->ice_conn, NULL, &ret) ==
116 IceProcessMessagesIOError)
117 SmcCloseConnection(client->conn, 0, NULL);
118 return;
121 /* Called whenever an ICE connection is opened or closed */
123 static void ice_watch_fn(IceConn conn, IcePointer client_data,
124 Bool opening, IcePointer *watch_data)
126 SmClient *client = (SmClient *)client_data;
128 if(opening)
130 #ifdef DEBUG
131 g_printerr("Ice connection opened for id %s\n", client->id);
132 #endif
133 client->fd = IceConnectionNumber(conn);
134 fcntl(client->fd, F_SETFD, FD_CLOEXEC);
135 client->input_tag = gdk_input_add(client->fd, GDK_INPUT_READ, &poll_ice_messages, client);
137 else
139 if (IceConnectionNumber(conn) == client->fd)
141 #ifdef DEBUG
142 g_printerr("Ice connection closed for id %s\n", client->id);
143 #endif
144 gdk_input_remove(client->input_tag);
145 sc_destroy(client);
150 /* Callbacks for different SM messages */
152 static void sc_save_yourself(SmcConn conn, SmPointer client_data, int save_type,
153 Bool shutdown, int interact_style, Bool fast)
155 SmClient *client = (SmClient *)client_data;
156 gboolean success = TRUE;
157 #ifdef DEBUG
158 g_printerr("%s saving state\n", client->id);
159 #endif
160 if(client->save_yourself_fn)
161 success = client->save_yourself_fn(client);
162 if(success)
163 sc_register_properties(client);
164 SmcSaveYourselfDone(client->conn, success);
167 static void sc_shutdown_cancelled(SmcConn conn, SmPointer client_data)
169 SmClient *client = (SmClient *)client_data;
170 #ifdef DEBUG
171 g_printerr("%s shutdown cancelled\n", client->id);
172 #endif
173 if(client->shutdown_cancelled_fn)
174 client->shutdown_cancelled_fn(client);
177 static void sc_save_complete(SmcConn conn, SmPointer client_data)
179 SmClient *client = (SmClient *)client_data;
180 #ifdef DEBUG
181 g_printerr("%s save complete\n", client->id);
182 #endif
183 if(client->save_complete_fn)
184 client->save_complete_fn(client);
187 static void sc_die(SmcConn conn, SmPointer client_data)
189 SmClient *client = (SmClient *)client_data;
190 #ifdef DEBUG
191 g_printerr("%s dying\n", client->id);
192 #endif
193 if(client->die_fn)
194 client->die_fn(client);
197 gboolean sc_session_up()
199 if(getenv("SESSION_MANAGER") == NULL)
200 return FALSE;
201 return TRUE;
204 SmClient *sc_new(const gchar *client_id)
206 SmClient *client;
208 #ifdef DEBUG
209 g_printerr("Creating new sm-client\n");
210 #endif
211 client = g_new(SmClient, 1);
212 client->id = g_strdup(client_id);
213 client->props = NULL;
214 client->conn = NULL;
215 client->ice_conn = NULL;
216 client->fd = -1;
218 return client;
221 void sc_destroy(SmClient *client)
223 GSList *list = client->props;
224 SmProperty *prop;
226 #ifdef DEBUG
227 g_printerr("destroying client\n");
228 #endif
229 for (; list; list = list->next)
231 prop = (SmProperty *)list->data;
232 g_free(prop->prop.vals->value);
233 g_free(prop->prop.vals);
234 g_free(prop->prop.name);
235 g_free(prop->prop.type);
236 g_free(prop);
238 g_slist_free(client->props);
239 g_free(client->id);
240 g_free(client);
243 /* Set a property with a SmLISTofARRAY8 value as in SmRestartCommand,
244 SmCloneCommand and SmDiscardCommand */
246 void sc_set_list_of_array_prop(SmClient *client,
247 const gchar *name,
248 const char *vals[], gint nvals)
250 SmProperty *prop = find_property(client, name);
251 SmPropValue *value = make_list_of_array_value(vals, nvals);
253 if(prop == NULL)
254 prop = new_property(client, name, SmLISTofARRAY8);
256 else
257 g_free(prop->prop.vals);
259 prop->prop.vals = value;
260 prop->prop.num_vals = nvals;
261 prop->set = TRUE;
264 /* Set a prop with a SmARRAY8 value, SmProgram, SmUserID and
265 SmDiscardCommand (if using XSM) are suitable victims. */
267 void sc_set_array_prop(SmClient *client, const gchar *name, const gchar *vals)
269 SmProperty *prop = find_property(client, name);
270 SmPropValue *value = make_array_value(vals);
272 if(prop == NULL)
273 prop = new_property(client, name, SmARRAY8);
275 else
276 g_free(prop->prop.vals);
278 prop->prop.vals = value;
279 prop->prop.num_vals = 1;
280 prop->set = TRUE;
283 /* This one is for the SmRestarStyleHint */
285 void sc_set_card_prop(SmClient *client, const gchar *name, const gchar val)
287 SmProperty *prop = find_property(client, name);
288 SmPropValue *value = make_card_value(val);
290 if(prop == NULL)
291 prop = new_property(client, name, SmCARD8);
293 else
294 g_free(prop->prop.vals);
296 prop->prop.vals = value;
297 prop->prop.num_vals = 1;
298 prop->set = TRUE;
301 /* Puts a pointer to a SmPropValue in val_ret and
302 the number of values in nvals_ret (they are in an array ).
303 It looks like this:
304 typedef struct {
305 int length;
306 SmPointer value;
307 } SmPropValue;
308 The values are those stored in the SmClient struct,
309 They're not fetched from the session manager */
311 void sc_get_prop_value(SmClient *client, const gchar *name,
312 SmPropValue **val_ret, gint *nvals_ret)
314 SmProperty *prop = find_property(client, name);
316 if(!prop)
318 *val_ret = NULL;
319 *nvals_ret = 0;
321 else
323 *val_ret = prop->prop.vals;
324 *nvals_ret = prop->prop.num_vals;
328 /* Stores set properties in the session manager */
330 void sc_register_properties(SmClient *client)
332 GPtrArray *set_props= g_ptr_array_new();
333 GSList *list = client->props;
334 SmProperty *prop;
335 #ifdef DEBUG
336 gint i;
337 #endif
339 for (; list; list = list->next)
341 prop = (SmProperty *)list->data;
342 if(prop->set == TRUE)
344 g_ptr_array_add(set_props, &prop->prop);
345 prop->set = FALSE;
348 #ifdef DEBUG
349 g_printerr("Registering props:\n");
350 for(i = 0; i < set_props->len; i++)
352 prop = g_ptr_array_index(set_props, i);
353 g_printerr("%s\n", prop->prop.name);
355 #endif
356 if(set_props->len > 0)
357 SmcSetProperties(client->conn, set_props->len, (SmProp **)set_props->pdata);
359 g_ptr_array_free(set_props, TRUE);
362 /* Connects to the session manager */
364 gboolean sc_connect(SmClient *client)
366 gchar error_str[256];
367 gchar *client_id_ret = NULL;
368 SmcConn conn = NULL;
369 SmcCallbacks callbacks;
371 callbacks.save_yourself.callback = &sc_save_yourself;
372 callbacks.save_yourself.client_data = (SmPointer)client;
373 callbacks.die.callback = &sc_die;
374 callbacks.die.client_data = (SmPointer)client;
375 callbacks.save_complete.callback = &sc_save_complete;
376 callbacks.save_complete.client_data = (SmPointer)client;
377 callbacks.shutdown_cancelled.callback = &sc_shutdown_cancelled;
378 callbacks.shutdown_cancelled.client_data = (SmPointer)client;
380 if(IceAddConnectionWatch(&ice_watch_fn, client) == 0)
382 g_printerr("Session Manager: IceAddConnectionWatch failed\n");
383 return FALSE;
386 if((conn = SmcOpenConnection(NULL, /* network ids */
387 NULL, /* context */
388 1, 0, /* protocol major, minor */
389 SmcSaveYourselfProcMask |
390 SmcSaveCompleteProcMask |
391 SmcShutdownCancelledProcMask |
392 SmcDieProcMask,
393 &callbacks,
394 client->id, &client_id_ret,
395 sizeof(error_str), error_str)) == NULL)
397 g_printerr("Session Manager: Init error\n");
398 return FALSE;
401 client->id = g_strdup(client_id_ret);
402 client->conn = conn;
403 client->ice_conn = SmcGetIceConnection(conn);
404 gdk_set_sm_client_id(client->id);
405 XFree(client_id_ret);
407 gtk_quit_add(0, &close_connection, client);
409 return TRUE;