Mercurial > pidgin
annotate src/session.c @ 6179:16e384bb7fbf
[gaim-migrate @ 6664]
Core/UI split the core initialization and shutdown. I think I got all the
bugs worked out. It's looking nice and stable here, but if it causes CVS to
go to hell for everyone.. er, try to fix it or let me know :) I don't have
this in patch form.
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Thu, 17 Jul 2003 10:35:43 +0000 |
parents | 059d95c67cda |
children | 9083f92e0d58 |
rev | line source |
---|---|
4158 | 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 */ | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5593
diff
changeset
|
25 #include "internal.h" |
4158 | 26 |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5593
diff
changeset
|
27 #include "debug.h" |
4158 | 28 |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5593
diff
changeset
|
29 extern char *opt_rcfile_arg; |
4158 | 30 |
31 #ifdef USE_SM | |
32 | |
33 #include <X11/ICE/ICElib.h> | |
34 #include <X11/SM/SMlib.h> | |
35 #include <unistd.h> | |
36 #include <fcntl.h> | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5593
diff
changeset
|
37 |
4158 | 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) { | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
57 gaim_debug(GAIM_DEBUG_INFO, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
58 "ICE IO error, closing connection... "); |
4158 | 59 |
60 /* IO error, please disconnect */ | |
61 IceSetShutdownNegotiation(connection, False); | |
62 IceCloseConnection(connection); | |
63 | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
64 gaim_debug(GAIM_DEBUG_INFO, NULL, "done.\n"); |
4158 | 65 |
66 /* cancel the handler */ | |
67 return FALSE; | |
68 } | |
69 | |
70 /* live to see another day */ | |
71 return TRUE; | |
72 } | |
73 | |
74 static void ice_connection_watch(IceConn connection, IcePointer client_data, | |
75 Bool opening, IcePointer *watch_data) { | |
76 guint input_id; | |
77 | |
78 if (opening) { | |
79 GIOChannel *channel; | |
80 | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
81 gaim_debug(GAIM_DEBUG_INFO, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
82 "Handling new ICE connection... "); |
4158 | 83 |
84 /* ensure ICE connection is not passed to child processes */ | |
85 fcntl(IceConnectionNumber(connection), F_SETFD, FD_CLOEXEC); | |
86 | |
87 /* get glib to watch the connection for us */ | |
88 channel = g_io_channel_unix_new(IceConnectionNumber(connection)); | |
89 input_id = g_io_add_watch(channel, G_IO_IN | G_IO_ERR, | |
90 ice_process_messages, connection); | |
91 g_io_channel_unref(channel); | |
92 | |
93 /* store the input ID as a pointer for when it closes */ | |
94 *watch_data = (IcePointer)GUINT_TO_POINTER(input_id); | |
95 } else { | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
96 gaim_debug(GAIM_DEBUG_INFO, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
97 "Handling closed ICE connection... "); |
4158 | 98 |
99 /* get the input ID back and stop watching it */ | |
100 input_id = GPOINTER_TO_UINT((gpointer) *watch_data); | |
101 g_source_remove(input_id); | |
102 } | |
103 | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
104 gaim_debug(GAIM_DEBUG_INFO, NULL, "done.\n"); |
4158 | 105 } |
106 | |
107 /* We call any handler installed before (or after) ice_init but | |
108 * avoid calling the default libICE handler which does an exit(). | |
109 * | |
110 * This means we do nothing by default, which is probably correct, | |
111 * the connection will get closed by libICE | |
112 */ | |
113 | |
114 static void ice_io_error_handler(IceConn connection) { | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
115 gaim_debug(GAIM_DEBUG_INFO, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
116 "Handling ICE IO error... "); |
4158 | 117 |
118 if (ice_installed_io_error_handler) | |
119 (*ice_installed_io_error_handler)(connection); | |
120 | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
121 gaim_debug(GAIM_DEBUG_INFO, NULL, "done.\n"); |
4158 | 122 } |
123 | |
124 static void ice_init() { | |
125 IceIOErrorHandler default_handler; | |
126 | |
127 ice_installed_io_error_handler = IceSetIOErrorHandler(NULL); | |
128 default_handler = IceSetIOErrorHandler(ice_io_error_handler); | |
129 | |
130 if (ice_installed_io_error_handler == default_handler) | |
131 ice_installed_io_error_handler = NULL; | |
132 | |
133 IceAddConnectionWatch(ice_connection_watch, NULL); | |
134 | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
135 gaim_debug(GAIM_DEBUG_INFO, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
136 "ICE initialized.\n"); |
4158 | 137 } |
138 | |
4281 | 139 /* my magic utility function */ |
140 | |
141 static gchar **session_make_command(gchar *client_id) { | |
142 gint i = 2; | |
143 gint j = 0; | |
144 gchar **ret; | |
145 | |
146 if (client_id) i += 2; | |
147 if (opt_rcfile_arg) i += 2; | |
148 | |
149 ret = g_new(gchar *, i); | |
150 ret[j++] = g_strdup(myself); | |
151 | |
152 if (client_id) { | |
153 ret[j++] = g_strdup("--session"); | |
154 ret[j++] = g_strdup(client_id); | |
155 } | |
156 | |
157 if (opt_rcfile_arg) { | |
158 ret[j++] = g_strdup("--file"); | |
159 ret[j++] = g_strdup(opt_rcfile_arg); | |
160 } | |
161 | |
162 ret[j++] = NULL; | |
163 | |
164 return ret; | |
165 } | |
166 | |
4158 | 167 /* SM callback handlers */ |
168 | |
169 void session_save_yourself(SmcConn conn, SmPointer data, int save_type, | |
170 Bool shutdown, int interact_style, Bool fast) { | |
171 if (had_first_save == FALSE && save_type == SmSaveLocal && | |
172 interact_style == SmInteractStyleNone && !shutdown && | |
173 !fast) { | |
174 /* this is just a dry run, spit it back */ | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
175 gaim_debug(GAIM_DEBUG_INFO, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
176 "Received first save_yourself\n"); |
4158 | 177 SmcSaveYourselfDone(conn, True); |
178 had_first_save = TRUE; | |
179 return; | |
180 } | |
181 | |
182 /* tum ti tum... don't add anything else here without * | |
183 * reading SMlib.PS from an X.org ftp server near you */ | |
184 | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
185 gaim_debug(GAIM_DEBUG_INFO, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
186 "Received save_yourself\n"); |
4158 | 187 |
188 if (save_type == SmSaveGlobal || save_type == SmSaveBoth) { | |
189 /* may as well do something ... */ | |
5593
b07aa997ddd8
[gaim-migrate @ 5997]
Christian Hammond <chipx86@chipx86.com>
parents:
5211
diff
changeset
|
190 /* or not -- save_prefs(); */ |
4158 | 191 } |
192 | |
193 SmcSaveYourselfDone(conn, True); | |
194 } | |
195 | |
196 void session_die(SmcConn conn, SmPointer data) { | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
197 gaim_debug(GAIM_DEBUG_INFO, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
198 "Received die\n"); |
6179
16e384bb7fbf
[gaim-migrate @ 6664]
Christian Hammond <chipx86@chipx86.com>
parents:
5872
diff
changeset
|
199 gaim_core_quit(); |
4158 | 200 } |
201 | |
202 void session_save_complete(SmcConn conn, SmPointer data) { | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
203 gaim_debug(GAIM_DEBUG_INFO, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
204 "Received save_complete\n"); |
4158 | 205 } |
206 | |
207 void session_shutdown_cancelled(SmcConn conn, SmPointer data) { | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
208 gaim_debug(GAIM_DEBUG_INFO, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
209 "Received shutdown_cancelled\n"); |
4158 | 210 } |
211 | |
212 /* utility functions stolen from Gnome-client */ | |
213 | |
214 static void session_set_value(SmcConn conn, gchar *name, char *type, | |
215 int num_vals, SmPropValue *vals) { | |
216 SmProp *proplist[1]; | |
217 SmProp prop; | |
218 | |
219 g_return_if_fail(conn); | |
220 | |
221 prop.name = name; | |
222 prop.type = type; | |
223 prop.num_vals = num_vals; | |
224 prop.vals = vals; | |
225 | |
226 proplist[0] = ∝ | |
227 SmcSetProperties(conn, 1, proplist); | |
228 } | |
229 | |
230 static void session_set_string(SmcConn conn, gchar *name, gchar *value) { | |
231 SmPropValue val; | |
232 | |
233 g_return_if_fail(name); | |
234 | |
235 val.length = strlen (value)+1; | |
236 val.value = value; | |
237 | |
238 session_set_value(conn, name, SmARRAY8, 1, &val); | |
239 } | |
240 | |
241 static void session_set_gchar(SmcConn conn, gchar *name, gchar value) { | |
242 SmPropValue val; | |
243 | |
244 g_return_if_fail(name); | |
245 | |
246 val.length = 1; | |
247 val.value = &value; | |
248 | |
249 session_set_value(conn, name, SmCARD8, 1, &val); | |
250 } | |
251 | |
252 static void session_set_array(SmcConn conn, gchar *name, gchar *array[]) { | |
253 gint argc; | |
254 gchar **ptr; | |
255 gint i; | |
256 | |
257 SmPropValue *vals; | |
258 | |
259 g_return_if_fail (name); | |
260 | |
261 /* We count the number of elements in our array. */ | |
262 for (ptr = array, argc = 0; *ptr ; ptr++, argc++) /* LOOP */; | |
263 | |
264 /* Now initialize the 'vals' array. */ | |
265 vals = g_new (SmPropValue, argc); | |
266 for (ptr = array, i = 0 ; i < argc ; ptr++, i++) { | |
267 vals[i].length = strlen (*ptr); | |
268 vals[i].value = *ptr; | |
269 } | |
270 | |
271 session_set_value(conn, name, SmLISTofARRAY8, argc, vals); | |
272 | |
273 g_free (vals); | |
274 } | |
275 | |
276 #endif /* USE_SM */ | |
277 | |
278 /* setup functions */ | |
279 | |
280 void session_init(gchar *argv0, gchar *previous_id) { | |
281 #ifdef USE_SM | |
282 SmcCallbacks callbacks; | |
283 gchar *client_id = NULL; | |
284 gchar error[ERROR_LENGTH] = ""; | |
285 gchar *tmp = NULL; | |
4281 | 286 gchar **cmd = NULL; |
4158 | 287 |
288 if (session != NULL) { | |
289 /* session is already established, what the hell is going on? */ | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
290 gaim_debug(GAIM_DEBUG_WARNING, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
291 "Duplicated call to session_init!\n"); |
4158 | 292 return; |
293 } | |
294 | |
295 if (g_getenv("SESSION_MANAGER") == NULL) { | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
296 gaim_debug(GAIM_DEBUG_ERROR, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
297 "No SESSION_MANAGER found, aborting.\n"); |
4158 | 298 return; |
299 } | |
300 | |
301 ice_init(); | |
302 | |
303 callbacks.save_yourself.callback = session_save_yourself; | |
304 callbacks.die.callback = session_die; | |
305 callbacks.save_complete.callback = session_save_complete; | |
306 callbacks.shutdown_cancelled.callback = session_shutdown_cancelled; | |
307 | |
308 callbacks.save_yourself.client_data = NULL; | |
309 callbacks.die.client_data = NULL; | |
310 callbacks.save_complete.client_data = NULL; | |
311 callbacks.shutdown_cancelled.client_data = NULL; | |
312 | |
4544 | 313 if (previous_id) { |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
314 gaim_debug(GAIM_DEBUG_INFO, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
315 "Connecting with previous ID %s\n", previous_id); |
4544 | 316 } else { |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
317 gaim_debug(GAIM_DEBUG_INFO, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
318 "Connecting with no previous ID\n"); |
4544 | 319 } |
4158 | 320 |
321 session = SmcOpenConnection(NULL, "session", SmProtoMajor, SmProtoMinor, SmcSaveYourselfProcMask | | |
322 SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask, | |
323 &callbacks, previous_id, &client_id, ERROR_LENGTH, error); | |
324 | |
325 if (session == NULL) { | |
326 if (error[0] != '\0') { | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
327 gaim_debug(GAIM_DEBUG_ERROR, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
328 "Connection failed with error: %s\n", error); |
4158 | 329 } else { |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
330 gaim_debug(GAIM_DEBUG_ERROR, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
331 "Connetion failed with unknown error.\n"); |
4158 | 332 } |
333 return; | |
334 } | |
335 | |
336 tmp = SmcVendor(session); | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
337 gaim_debug(GAIM_DEBUG_INFO, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
338 "Connected to manager (%s) with client ID %s\n", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
339 tmp, client_id); |
4158 | 340 g_free(tmp); |
341 | |
342 session_managed = TRUE; | |
343 gdk_set_sm_client_id(client_id); | |
344 | |
4265 | 345 tmp = g_get_current_dir(); |
346 session_set_string(session, SmCurrentDirectory, tmp); | |
347 g_free(tmp); | |
348 | |
4210 | 349 tmp = g_strdup_printf("%d", (int) getpid()); |
4158 | 350 session_set_string(session, SmProcessID, tmp); |
351 g_free(tmp); | |
352 | |
4210 | 353 tmp = g_strdup(g_get_user_name()); |
4158 | 354 session_set_string(session, SmUserID, tmp); |
355 g_free(tmp); | |
356 | |
357 session_set_gchar(session, SmRestartStyleHint, (gchar) SmRestartIfRunning); | |
358 session_set_string(session, SmProgram, g_get_prgname()); | |
359 | |
360 myself = g_strdup(argv0); | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
361 gaim_debug(GAIM_DEBUG_MISC, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
362 "Using %s as command\n", myself); |
4158 | 363 |
4281 | 364 cmd = session_make_command(NULL); |
4158 | 365 session_set_array(session, SmCloneCommand, cmd); |
4281 | 366 g_strfreev(cmd); |
4158 | 367 |
4265 | 368 /* this is currently useless, but gnome-session warns 'the following applications will not |
369 save their current status' bla bla if we don't have it and the user checks 'Save Session' | |
370 when they log out */ | |
4281 | 371 cmd = g_new(gchar *, 2); |
372 cmd[0] = g_strdup("/bin/true"); | |
373 cmd[1] = NULL; | |
4158 | 374 session_set_array(session, SmDiscardCommand, cmd); |
4281 | 375 g_strfreev(cmd); |
4158 | 376 |
4281 | 377 cmd = session_make_command(client_id); |
4158 | 378 session_set_array(session, SmRestartCommand, cmd); |
4281 | 379 g_strfreev(cmd); |
380 | |
4158 | 381 g_free(client_id); |
382 #endif /* USE_SM */ | |
383 } | |
384 | |
385 void session_end() { | |
386 #ifdef USE_SM | |
387 if (session == NULL) /* no session to close */ | |
388 return; | |
389 | |
390 SmcCloseConnection(session, 0, NULL); | |
391 | |
5211
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
392 gaim_debug(GAIM_DEBUG_INFO, "Session Management", |
0241d6b6702d
[gaim-migrate @ 5581]
Christian Hammond <chipx86@chipx86.com>
parents:
4544
diff
changeset
|
393 "Connection closed.\n"); |
4158 | 394 #endif /* USE_SM */ |
395 } |