Mercurial > pidgin.yaz
annotate src/gtksession.c @ 12424:7c2e2c4d45a4
[gaim-migrate @ 14731]
Add prototypes, make things static, or #if 0 out unused function as necessary to get zephyr to compile without prototype warnings. It's painfully obvious that this code was written before prototypes existed, or at least before they became standard. As we need to maintain source compatibility with an external libzephyr, I can't really start adding header files. If someone cares about this protocol, feel free to clean this up a bit. My only concern is that I caught any actual mistakes and that it compiles without spurious warnings that would distract us from problems elsewhere.
committer: Tailor Script <tailor@pidgin.im>
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Thu, 08 Dec 2005 23:38:36 +0000 |
parents | bc249de5ea02 |
children |
rev | line source |
---|---|
12246 | 1 /* |
2 * @file gtksession.c X Windows session management API | |
3 * @ingroup gtkui | |
4 * | |
5 * Gaim is the legal property of its developers, whose names are too numerous | |
6 * to list here. Please refer to the COPYRIGHT file distributed with this | |
7 * source distribution. | |
8 * | |
9 * This program is free software; you can redistribute it and/or modify | |
10 * it under the terms of the GNU General Public License as published by | |
11 * the Free Software Foundation; either version 2 of the License, or | |
12 * (at your option) any later version. | |
13 * | |
14 * This program is distributed in the hope that it will be useful, | |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 * GNU General Public License for more details. | |
18 * | |
19 * You should have received a copy of the GNU General Public License | |
20 * along with this program; if not, write to the Free Software | |
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 * | |
23 */ | |
24 #include "internal.h" | |
25 | |
26 #include "core.h" | |
27 #include "debug.h" | |
28 #include "eventloop.h" | |
12410
bc249de5ea02
[gaim-migrate @ 14717]
Richard Laager <rlaager@wiktel.com>
parents:
12246
diff
changeset
|
29 #include "gtksession.h" |
12246 | 30 |
31 #ifdef USE_SM | |
32 | |
33 #include <X11/ICE/ICElib.h> | |
34 #include <X11/SM/SMlib.h> | |
35 #include <gdk/gdkx.h> | |
36 #include <unistd.h> | |
37 #include <fcntl.h> | |
38 | |
39 #define ERROR_LENGTH 512 | |
40 | |
41 static IceIOErrorHandler ice_installed_io_error_handler; | |
42 static SmcConn session = NULL; | |
43 static gchar *myself = NULL; | |
44 static gboolean had_first_save = FALSE; | |
45 static gboolean session_managed = FALSE; | |
46 | |
47 /* ICE belt'n'braces stuff */ | |
48 | |
49 struct ice_connection_info { | |
50 IceConn connection; | |
51 guint input_id; | |
52 }; | |
53 | |
54 static void ice_process_messages(gpointer data, gint fd, | |
55 GaimInputCondition condition) { | |
56 struct ice_connection_info *conninfo = (struct ice_connection_info*) data; | |
57 IceProcessMessagesStatus status; | |
58 | |
59 /* please don't block... please! */ | |
60 status = IceProcessMessages(conninfo->connection, NULL, NULL); | |
61 | |
62 if (status == IceProcessMessagesIOError) { | |
63 gaim_debug(GAIM_DEBUG_INFO, "Session Management", | |
64 "ICE IO error, closing connection... "); | |
65 | |
66 /* IO error, please disconnect */ | |
67 IceSetShutdownNegotiation(conninfo->connection, False); | |
68 IceCloseConnection(conninfo->connection); | |
69 | |
70 gaim_debug(GAIM_DEBUG_INFO, NULL, "done.\n"); | |
71 | |
72 /* cancel the handler */ | |
73 gaim_input_remove(conninfo->input_id); | |
74 } | |
75 } | |
76 | |
77 static void ice_connection_watch(IceConn connection, IcePointer client_data, | |
78 Bool opening, IcePointer *watch_data) { | |
79 struct ice_connection_info *conninfo = NULL; | |
80 | |
81 if (opening) { | |
82 gaim_debug(GAIM_DEBUG_INFO, "Session Management", | |
83 "Handling new ICE connection... "); | |
84 | |
85 /* ensure ICE connection is not passed to child processes */ | |
86 fcntl(IceConnectionNumber(connection), F_SETFD, FD_CLOEXEC); | |
87 | |
88 conninfo = g_new(struct ice_connection_info, 1); | |
89 conninfo->connection = connection; | |
90 | |
91 /* watch the connection */ | |
92 conninfo->input_id = gaim_input_add(IceConnectionNumber(connection), GAIM_INPUT_READ, | |
93 ice_process_messages, conninfo); | |
94 *watch_data = conninfo; | |
95 } else { | |
96 gaim_debug(GAIM_DEBUG_INFO, "Session Management", | |
97 "Handling closed ICE connection... "); | |
98 | |
99 /* get the input ID back and stop watching it */ | |
100 conninfo = (struct ice_connection_info*) *watch_data; | |
101 gaim_input_remove(conninfo->input_id); | |
102 g_free(conninfo); | |
103 } | |
104 | |
105 gaim_debug(GAIM_DEBUG_INFO, NULL, "done.\n"); | |
106 } | |
107 | |
108 /* We call any handler installed before (or after) ice_init but | |
109 * avoid calling the default libICE handler which does an exit(). | |
110 * | |
111 * This means we do nothing by default, which is probably correct, | |
112 * the connection will get closed by libICE | |
113 */ | |
114 | |
115 static void ice_io_error_handler(IceConn connection) { | |
116 gaim_debug(GAIM_DEBUG_INFO, "Session Management", | |
117 "Handling ICE IO error... "); | |
118 | |
119 if (ice_installed_io_error_handler) | |
120 (*ice_installed_io_error_handler)(connection); | |
121 | |
122 gaim_debug(GAIM_DEBUG_INFO, NULL, "done.\n"); | |
123 } | |
124 | |
125 static void ice_init() { | |
126 IceIOErrorHandler default_handler; | |
127 | |
128 ice_installed_io_error_handler = IceSetIOErrorHandler(NULL); | |
129 default_handler = IceSetIOErrorHandler(ice_io_error_handler); | |
130 | |
131 if (ice_installed_io_error_handler == default_handler) | |
132 ice_installed_io_error_handler = NULL; | |
133 | |
134 IceAddConnectionWatch(ice_connection_watch, NULL); | |
135 | |
136 gaim_debug(GAIM_DEBUG_INFO, "Session Management", | |
137 "ICE initialized.\n"); | |
138 } | |
139 | |
140 /* my magic utility function */ | |
141 | |
142 static gchar **session_make_command(gchar *client_id, gchar *config_dir) { | |
143 gint i = 2; | |
144 gint j = 0; | |
145 gchar **ret; | |
146 | |
147 if (client_id) i += 2; | |
148 if (config_dir) i += 2; /* we will specify gaim's user dir */ | |
149 | |
150 ret = g_new(gchar *, i); | |
151 ret[j++] = g_strdup(myself); | |
152 | |
153 if (client_id) { | |
154 ret[j++] = g_strdup("--session"); | |
155 ret[j++] = g_strdup(client_id); | |
156 } | |
157 | |
158 if (config_dir) { | |
159 ret[j++] = g_strdup("--config"); | |
160 ret[j++] = g_strdup(config_dir); | |
161 } | |
162 | |
163 ret[j++] = NULL; | |
164 | |
165 return ret; | |
166 } | |
167 | |
168 /* SM callback handlers */ | |
169 | |
170 static void session_save_yourself(SmcConn conn, SmPointer data, int save_type, | |
171 Bool shutdown, int interact_style, Bool fast) { | |
172 if (had_first_save == FALSE && save_type == SmSaveLocal && | |
173 interact_style == SmInteractStyleNone && !shutdown && | |
174 !fast) { | |
175 /* this is just a dry run, spit it back */ | |
176 gaim_debug(GAIM_DEBUG_INFO, "Session Management", | |
177 "Received first save_yourself\n"); | |
178 SmcSaveYourselfDone(conn, True); | |
179 had_first_save = TRUE; | |
180 return; | |
181 } | |
182 | |
183 /* tum ti tum... don't add anything else here without * | |
184 * reading SMlib.PS from an X.org ftp server near you */ | |
185 | |
186 gaim_debug(GAIM_DEBUG_INFO, "Session Management", | |
187 "Received save_yourself\n"); | |
188 | |
189 if (save_type == SmSaveGlobal || save_type == SmSaveBoth) { | |
190 /* may as well do something ... */ | |
191 /* or not -- save_prefs(); */ | |
192 } | |
193 | |
194 SmcSaveYourselfDone(conn, True); | |
195 } | |
196 | |
197 static void session_die(SmcConn conn, SmPointer data) { | |
198 gaim_debug(GAIM_DEBUG_INFO, "Session Management", | |
199 "Received die\n"); | |
200 gaim_core_quit(); | |
201 } | |
202 | |
203 static void session_save_complete(SmcConn conn, SmPointer data) { | |
204 gaim_debug(GAIM_DEBUG_INFO, "Session Management", | |
205 "Received save_complete\n"); | |
206 } | |
207 | |
208 static void session_shutdown_cancelled(SmcConn conn, SmPointer data) { | |
209 gaim_debug(GAIM_DEBUG_INFO, "Session Management", | |
210 "Received shutdown_cancelled\n"); | |
211 } | |
212 | |
213 /* utility functions stolen from Gnome-client */ | |
214 | |
215 static void session_set_value(SmcConn conn, gchar *name, char *type, | |
216 int num_vals, SmPropValue *vals) { | |
217 SmProp *proplist[1]; | |
218 SmProp prop; | |
219 | |
220 g_return_if_fail(conn); | |
221 | |
222 prop.name = name; | |
223 prop.type = type; | |
224 prop.num_vals = num_vals; | |
225 prop.vals = vals; | |
226 | |
227 proplist[0] = ∝ | |
228 SmcSetProperties(conn, 1, proplist); | |
229 } | |
230 | |
231 static void session_set_string(SmcConn conn, gchar *name, gchar *value) { | |
232 SmPropValue val; | |
233 | |
234 g_return_if_fail(name); | |
235 | |
236 val.length = strlen (value)+1; | |
237 val.value = value; | |
238 | |
239 session_set_value(conn, name, SmARRAY8, 1, &val); | |
240 } | |
241 | |
242 static void session_set_gchar(SmcConn conn, gchar *name, gchar value) { | |
243 SmPropValue val; | |
244 | |
245 g_return_if_fail(name); | |
246 | |
247 val.length = 1; | |
248 val.value = &value; | |
249 | |
250 session_set_value(conn, name, SmCARD8, 1, &val); | |
251 } | |
252 | |
253 static void session_set_array(SmcConn conn, gchar *name, gchar *array[]) { | |
254 gint argc; | |
255 gchar **ptr; | |
256 gint i; | |
257 | |
258 SmPropValue *vals; | |
259 | |
260 g_return_if_fail (name); | |
261 | |
262 /* We count the number of elements in our array. */ | |
263 for (ptr = array, argc = 0; *ptr ; ptr++, argc++) /* LOOP */; | |
264 | |
265 /* Now initialize the 'vals' array. */ | |
266 vals = g_new (SmPropValue, argc); | |
267 for (ptr = array, i = 0 ; i < argc ; ptr++, i++) { | |
268 vals[i].length = strlen (*ptr); | |
269 vals[i].value = *ptr; | |
270 } | |
271 | |
272 session_set_value(conn, name, SmLISTofARRAY8, argc, vals); | |
273 | |
274 g_free (vals); | |
275 } | |
276 | |
277 #endif /* USE_SM */ | |
278 | |
279 /* setup functions */ | |
280 | |
281 void | |
282 gaim_gtk_session_init(gchar *argv0, gchar *previous_id, gchar *config_dir) | |
283 { | |
284 #ifdef USE_SM | |
285 SmcCallbacks callbacks; | |
286 gchar *client_id = NULL; | |
287 gchar error[ERROR_LENGTH] = ""; | |
288 gchar *tmp = NULL; | |
289 gchar **cmd = NULL; | |
290 | |
291 if (session != NULL) { | |
292 /* session is already established, what the hell is going on? */ | |
293 gaim_debug(GAIM_DEBUG_WARNING, "Session Management", | |
294 "Duplicated call to gaim_gtk_session_init!\n"); | |
295 return; | |
296 } | |
297 | |
298 if (g_getenv("SESSION_MANAGER") == NULL) { | |
299 gaim_debug(GAIM_DEBUG_ERROR, "Session Management", | |
300 "No SESSION_MANAGER found, aborting.\n"); | |
301 return; | |
302 } | |
303 | |
304 ice_init(); | |
305 | |
306 callbacks.save_yourself.callback = session_save_yourself; | |
307 callbacks.die.callback = session_die; | |
308 callbacks.save_complete.callback = session_save_complete; | |
309 callbacks.shutdown_cancelled.callback = session_shutdown_cancelled; | |
310 | |
311 callbacks.save_yourself.client_data = NULL; | |
312 callbacks.die.client_data = NULL; | |
313 callbacks.save_complete.client_data = NULL; | |
314 callbacks.shutdown_cancelled.client_data = NULL; | |
315 | |
316 if (previous_id) { | |
317 gaim_debug(GAIM_DEBUG_INFO, "Session Management", | |
318 "Connecting with previous ID %s\n", previous_id); | |
319 } else { | |
320 gaim_debug(GAIM_DEBUG_INFO, "Session Management", | |
321 "Connecting with no previous ID\n"); | |
322 } | |
323 | |
324 session = SmcOpenConnection(NULL, "session", SmProtoMajor, SmProtoMinor, SmcSaveYourselfProcMask | | |
325 SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask, | |
326 &callbacks, previous_id, &client_id, ERROR_LENGTH, error); | |
327 | |
328 if (session == NULL) { | |
329 if (error[0] != '\0') { | |
330 gaim_debug(GAIM_DEBUG_ERROR, "Session Management", | |
331 "Connection failed with error: %s\n", error); | |
332 } else { | |
333 gaim_debug(GAIM_DEBUG_ERROR, "Session Management", | |
334 "Connetion failed with unknown error.\n"); | |
335 } | |
336 return; | |
337 } | |
338 | |
339 tmp = SmcVendor(session); | |
340 gaim_debug(GAIM_DEBUG_INFO, "Session Management", | |
341 "Connected to manager (%s) with client ID %s\n", | |
342 tmp, client_id); | |
343 g_free(tmp); | |
344 | |
345 session_managed = TRUE; | |
346 gdk_set_sm_client_id(client_id); | |
347 | |
348 tmp = g_get_current_dir(); | |
349 session_set_string(session, SmCurrentDirectory, tmp); | |
350 g_free(tmp); | |
351 | |
352 tmp = g_strdup_printf("%d", (int) getpid()); | |
353 session_set_string(session, SmProcessID, tmp); | |
354 g_free(tmp); | |
355 | |
356 tmp = g_strdup(g_get_user_name()); | |
357 session_set_string(session, SmUserID, tmp); | |
358 g_free(tmp); | |
359 | |
360 session_set_gchar(session, SmRestartStyleHint, (gchar) SmRestartIfRunning); | |
361 session_set_string(session, SmProgram, g_get_prgname()); | |
362 | |
363 myself = g_strdup(argv0); | |
364 gaim_debug(GAIM_DEBUG_MISC, "Session Management", | |
365 "Using %s as command\n", myself); | |
366 | |
367 cmd = session_make_command(NULL, config_dir); | |
368 session_set_array(session, SmCloneCommand, cmd); | |
369 g_strfreev(cmd); | |
370 | |
371 /* this is currently useless, but gnome-session warns 'the following applications will not | |
372 save their current status' bla bla if we don't have it and the user checks 'Save Session' | |
373 when they log out */ | |
374 cmd = g_new(gchar *, 2); | |
375 cmd[0] = g_strdup("/bin/true"); | |
376 cmd[1] = NULL; | |
377 session_set_array(session, SmDiscardCommand, cmd); | |
378 g_strfreev(cmd); | |
379 | |
380 cmd = session_make_command(client_id, config_dir); | |
381 session_set_array(session, SmRestartCommand, cmd); | |
382 g_strfreev(cmd); | |
383 | |
384 g_free(client_id); | |
385 #endif /* USE_SM */ | |
386 } | |
387 | |
388 void | |
389 gaim_gtk_session_end() | |
390 { | |
391 #ifdef USE_SM | |
392 if (session == NULL) /* no session to close */ | |
393 return; | |
394 | |
395 SmcCloseConnection(session, 0, NULL); | |
396 | |
397 gaim_debug(GAIM_DEBUG_INFO, "Session Management", | |
398 "Connection closed.\n"); | |
399 #endif /* USE_SM */ | |
400 } |