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)
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
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 */
26 #include <X11/SM/SMlib.h>
32 static SmPropValue
*make_list_of_array_value(const gchar
*vals
[], gint nvals
)
34 SmPropValue
*values
= g_new(SmPropValue
, nvals
);
37 for(i
= 0; i
< nvals
; i
++)
39 values
[i
].value
= g_strdup(vals
[i
]);
40 values
[i
].length
= strlen(vals
[i
]);
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
);
55 static SmPropValue
*make_card_value(gchar val
)
57 SmPropValue
*value
= g_new(SmPropValue
, 1);
59 value
->value
= g_memdup(&val
, sizeof(gchar
));
65 static SmProperty
*find_property(SmClient
*client
, const gchar
*name
)
67 GSList
*list
= client
->props
;
70 for (; list
; list
= list
->next
)
72 prop
= (SmProperty
*)list
->data
;
73 if (strcmp(prop
->prop
.name
, name
) == 0)
79 static SmProperty
*new_property(SmClient
*client
,
80 const gchar
*name
, const gchar
*type
)
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;
90 g_printerr("appending prop %s\n", prop
->prop
.name
);
92 client
->props
= g_slist_append(client
->props
, prop
);
97 static gint
close_connection(gpointer data
)
99 SmClient
*client
= (SmClient
*)data
;
101 SmcCloseConnection(client
->conn
, 0, NULL
);
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
;
115 if (IceProcessMessages(client
->ice_conn
, NULL
, &ret
) ==
116 IceProcessMessagesIOError
)
117 SmcCloseConnection(client
->conn
, 0, NULL
);
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
;
131 g_printerr("Ice connection opened for id %s\n", client
->id
);
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
);
139 if (IceConnectionNumber(conn
) == client
->fd
)
142 g_printerr("Ice connection closed for id %s\n", client
->id
);
144 gdk_input_remove(client
->input_tag
);
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
;
158 g_printerr("%s saving state\n", client
->id
);
160 if(client
->save_yourself_fn
)
161 success
= client
->save_yourself_fn(client
);
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
;
171 g_printerr("%s shutdown cancelled\n", client
->id
);
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
;
181 g_printerr("%s save complete\n", client
->id
);
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
;
191 g_printerr("%s dying\n", client
->id
);
194 client
->die_fn(client
);
197 gboolean
sc_session_up()
199 if(getenv("SESSION_MANAGER") == NULL
)
204 SmClient
*sc_new(const gchar
*client_id
)
209 g_printerr("Creating new sm-client\n");
211 client
= g_new(SmClient
, 1);
212 client
->id
= g_strdup(client_id
);
213 client
->props
= NULL
;
215 client
->ice_conn
= NULL
;
221 void sc_destroy(SmClient
*client
)
223 GSList
*list
= client
->props
;
227 g_printerr("destroying client\n");
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
);
238 g_slist_free(client
->props
);
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
,
248 const char *vals
[], gint nvals
)
250 SmProperty
*prop
= find_property(client
, name
);
251 SmPropValue
*value
= make_list_of_array_value(vals
, nvals
);
254 prop
= new_property(client
, name
, SmLISTofARRAY8
);
257 g_free(prop
->prop
.vals
);
259 prop
->prop
.vals
= value
;
260 prop
->prop
.num_vals
= nvals
;
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
);
273 prop
= new_property(client
, name
, SmARRAY8
);
276 g_free(prop
->prop
.vals
);
278 prop
->prop
.vals
= value
;
279 prop
->prop
.num_vals
= 1;
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
);
291 prop
= new_property(client
, name
, SmCARD8
);
294 g_free(prop
->prop
.vals
);
296 prop
->prop
.vals
= value
;
297 prop
->prop
.num_vals
= 1;
301 /* Puts a pointer to a SmPropValue in val_ret and
302 the number of values in nvals_ret (they are in an array ).
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
);
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
;
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
);
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
);
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
;
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");
386 if((conn
= SmcOpenConnection(NULL
, /* network ids */
388 1, 0, /* protocol major, minor */
389 SmcSaveYourselfProcMask
|
390 SmcSaveCompleteProcMask
|
391 SmcShutdownCancelledProcMask
|
394 client
->id
, &client_id_ret
,
395 sizeof(error_str
), error_str
)) == NULL
)
397 g_printerr("Session Manager: Init error\n");
401 client
->id
= g_strdup(client_id_ret
);
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
);