comparison src/session.c @ 4158:a638bc9454a6

[gaim-migrate @ 4386] Forgot this committer: Tailor Script <tailor@pidgin.im>
author Rob Flynn <gaim@robflynn.com>
date Tue, 31 Dec 2002 05:23:12 +0000
parents
children e11393a176d5
comparison
equal deleted inserted replaced
4157:9c31ddae80a1 4158:a638bc9454a6
1 /*
2 * session management for Gaim
3 *
4 * Copyright (C) 2002, Robert McQueen <robot101@debian.org> but
5 * much code shamelessly cribbed from GsmClient (C) 2001 Havoc
6 * Pennington, which is in turn inspired by various other pieces
7 * of code including GnomeClient (C) 1998 Carsten Schaar, Tom
8 * Tromey, and twm session code (C) 1998 The Open Group.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include "gaim.h"
31
32 #ifdef USE_SM
33
34 #include <X11/ICE/ICElib.h>
35 #include <X11/SM/SMlib.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #define ERROR_LENGTH 512
39
40 static IceIOErrorHandler ice_installed_io_error_handler;
41 static SmcConn session = NULL;
42 static gchar *myself = NULL;
43 static gboolean had_first_save = FALSE;
44 gboolean session_managed = FALSE;
45
46 /* ICE belt'n'braces stuff */
47
48 static gboolean ice_process_messages(GIOChannel *channel, GIOCondition condition,
49 gpointer data) {
50 IceConn connection = (IceConn)data;
51 IceProcessMessagesStatus status;
52
53 /* please don't block... please! */
54 status = IceProcessMessages(connection, NULL, NULL);
55
56 if (status == IceProcessMessagesIOError) {
57 debug_printf("Session Management: ICE IO error, closing connection... ");
58
59 /* IO error, please disconnect */
60 IceSetShutdownNegotiation(connection, False);
61 IceCloseConnection(connection);
62
63 debug_printf("done\n");
64
65 /* cancel the handler */
66 return FALSE;
67 }
68
69 /* live to see another day */
70 return TRUE;
71 }
72
73 static void ice_connection_watch(IceConn connection, IcePointer client_data,
74 Bool opening, IcePointer *watch_data) {
75 guint input_id;
76
77 if (opening) {
78 GIOChannel *channel;
79
80 debug_printf("Session Management: handling new ICE connection... ");
81
82 /* ensure ICE connection is not passed to child processes */
83 fcntl(IceConnectionNumber(connection), F_SETFD, FD_CLOEXEC);
84
85 /* get glib to watch the connection for us */
86 channel = g_io_channel_unix_new(IceConnectionNumber(connection));
87 input_id = g_io_add_watch(channel, G_IO_IN | G_IO_ERR,
88 ice_process_messages, connection);
89 g_io_channel_unref(channel);
90
91 /* store the input ID as a pointer for when it closes */
92 *watch_data = (IcePointer)GUINT_TO_POINTER(input_id);
93 } else {
94 debug_printf("Session Management: handling closed ICE connection... ");
95
96 /* get the input ID back and stop watching it */
97 input_id = GPOINTER_TO_UINT((gpointer) *watch_data);
98 g_source_remove(input_id);
99 }
100
101 debug_printf("done\n");
102 }
103
104 /* We call any handler installed before (or after) ice_init but
105 * avoid calling the default libICE handler which does an exit().
106 *
107 * This means we do nothing by default, which is probably correct,
108 * the connection will get closed by libICE
109 */
110
111 static void ice_io_error_handler(IceConn connection) {
112 debug_printf("Session Management: handling ICE IO error... ");
113
114 if (ice_installed_io_error_handler)
115 (*ice_installed_io_error_handler)(connection);
116
117 debug_printf("done\n");
118 }
119
120 static void ice_init() {
121 IceIOErrorHandler default_handler;
122
123 ice_installed_io_error_handler = IceSetIOErrorHandler(NULL);
124 default_handler = IceSetIOErrorHandler(ice_io_error_handler);
125
126 if (ice_installed_io_error_handler == default_handler)
127 ice_installed_io_error_handler = NULL;
128
129 IceAddConnectionWatch(ice_connection_watch, NULL);
130
131 debug_printf("Session Management: ICE initialised\n");
132 }
133
134 /* SM callback handlers */
135
136 void session_save_yourself(SmcConn conn, SmPointer data, int save_type,
137 Bool shutdown, int interact_style, Bool fast) {
138 if (had_first_save == FALSE && save_type == SmSaveLocal &&
139 interact_style == SmInteractStyleNone && !shutdown &&
140 !fast) {
141 /* this is just a dry run, spit it back */
142 debug_printf("Session Management: received first save_yourself\n");
143 SmcSaveYourselfDone(conn, True);
144 had_first_save = TRUE;
145 return;
146 }
147
148 /* tum ti tum... don't add anything else here without *
149 * reading SMlib.PS from an X.org ftp server near you */
150
151 debug_printf("Session Management: received save_yourself\n");
152
153 if (save_type == SmSaveGlobal || save_type == SmSaveBoth) {
154 /* may as well do something ... */
155 save_prefs();
156 }
157
158 SmcSaveYourselfDone(conn, True);
159 }
160
161 void session_die(SmcConn conn, SmPointer data) {
162 debug_printf("Session Management: received die\n");
163 do_quit();
164 }
165
166 void session_save_complete(SmcConn conn, SmPointer data) {
167 debug_printf("Session Management: received save_complete\n");
168 }
169
170 void session_shutdown_cancelled(SmcConn conn, SmPointer data) {
171 debug_printf("Session Management: received shutdown_cancelled\n");
172 }
173
174 /* utility functions stolen from Gnome-client */
175
176 static void session_set_value(SmcConn conn, gchar *name, char *type,
177 int num_vals, SmPropValue *vals) {
178 SmProp *proplist[1];
179 SmProp prop;
180
181 g_return_if_fail(conn);
182
183 prop.name = name;
184 prop.type = type;
185 prop.num_vals = num_vals;
186 prop.vals = vals;
187
188 proplist[0] = &prop;
189 SmcSetProperties(conn, 1, proplist);
190 }
191
192 static void session_set_string(SmcConn conn, gchar *name, gchar *value) {
193 SmPropValue val;
194
195 g_return_if_fail(name);
196
197 val.length = strlen (value)+1;
198 val.value = value;
199
200 session_set_value(conn, name, SmARRAY8, 1, &val);
201 }
202
203 static void session_set_gchar(SmcConn conn, gchar *name, gchar value) {
204 SmPropValue val;
205
206 g_return_if_fail(name);
207
208 val.length = 1;
209 val.value = &value;
210
211 session_set_value(conn, name, SmCARD8, 1, &val);
212 }
213
214 static void session_set_array(SmcConn conn, gchar *name, gchar *array[]) {
215 gint argc;
216 gchar **ptr;
217 gint i;
218
219 SmPropValue *vals;
220
221 g_return_if_fail (name);
222
223 /* We count the number of elements in our array. */
224 for (ptr = array, argc = 0; *ptr ; ptr++, argc++) /* LOOP */;
225
226 /* Now initialize the 'vals' array. */
227 vals = g_new (SmPropValue, argc);
228 for (ptr = array, i = 0 ; i < argc ; ptr++, i++) {
229 vals[i].length = strlen (*ptr);
230 vals[i].value = *ptr;
231 }
232
233 session_set_value(conn, name, SmLISTofARRAY8, argc, vals);
234
235 g_free (vals);
236 }
237
238 #endif /* USE_SM */
239
240 /* setup functions */
241
242 void session_init(gchar *argv0, gchar *previous_id) {
243 #ifdef USE_SM
244 SmcCallbacks callbacks;
245 gchar *client_id = NULL;
246 gchar error[ERROR_LENGTH] = "";
247 gchar *tmp = NULL;
248 gchar *cmd[4] = { NULL, NULL, NULL, NULL };
249
250 if (session != NULL) {
251 /* session is already established, what the hell is going on? */
252 debug_printf("Session Management: duplicated call to session_init!\n");
253 return;
254 }
255
256 if (g_getenv("SESSION_MANAGER") == NULL) {
257 debug_printf("Session Management: no SESSION_MANAGER found, aborting\n");
258 return;
259 }
260
261 ice_init();
262
263 callbacks.save_yourself.callback = session_save_yourself;
264 callbacks.die.callback = session_die;
265 callbacks.save_complete.callback = session_save_complete;
266 callbacks.shutdown_cancelled.callback = session_shutdown_cancelled;
267
268 callbacks.save_yourself.client_data = NULL;
269 callbacks.die.client_data = NULL;
270 callbacks.save_complete.client_data = NULL;
271 callbacks.shutdown_cancelled.client_data = NULL;
272
273 debug_printf("Session Management: connecting with previous ID %s\n", previous_id);
274
275 session = SmcOpenConnection(NULL, "session", SmProtoMajor, SmProtoMinor, SmcSaveYourselfProcMask |
276 SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
277 &callbacks, previous_id, &client_id, ERROR_LENGTH, error);
278
279 if (session == NULL) {
280 if (error[0] != '\0') {
281 debug_printf("Session Management: connection failed with error: %s\n", error);
282 } else {
283 debug_printf("Session Management: connection failed with unknown error\n");
284 }
285 return;
286 }
287
288 tmp = SmcVendor(session);
289 debug_printf("Session Management: connected to manager (%s) with client ID %s\n", tmp, client_id);
290 g_free(tmp);
291
292 session_managed = TRUE;
293 gdk_set_sm_client_id(client_id);
294
295 g_strdup_printf("%d", (int) getpid());
296 session_set_string(session, SmProcessID, tmp);
297 g_free(tmp);
298
299 g_strdup(g_get_user_name());
300 session_set_string(session, SmUserID, tmp);
301 g_free(tmp);
302
303 session_set_gchar(session, SmRestartStyleHint, (gchar) SmRestartIfRunning);
304 session_set_string(session, SmProgram, g_get_prgname());
305
306 myself = g_strdup(argv0);
307 debug_printf("Session Management: using %s as command\n", myself);
308
309 cmd[0] = myself;
310 cmd[1] = NULL;
311 session_set_array(session, SmCloneCommand, cmd);
312
313 cmd[1] = "-v";
314 cmd[2] = NULL;
315 session_set_array(session, SmDiscardCommand, cmd);
316
317 cmd[1] = "--session";
318 cmd[2] = client_id;
319 cmd[3] = NULL;
320 session_set_array(session, SmRestartCommand, cmd);
321 g_free(client_id);
322 #endif /* USE_SM */
323 }
324
325 void session_end() {
326 #ifdef USE_SM
327 if (session == NULL) /* no session to close */
328 return;
329
330 SmcCloseConnection(session, 0, NULL);
331
332 debug_printf("Session Management: connection closed\n");
333 #endif /* USE_SM */
334 }