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