1 /* Nabi - X Input Method server for hangul
2 * Copyright (C) 2003-2008 Choe Hwanjin
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #ifdef HAVE_LIBSM
24
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include <X11/ICE/ICElib.h>
29 #include <X11/SM/SMlib.h>
30
31 #include <gtk/gtk.h>
32
33 #include "debug.h"
34 #include "server.h"
35 #include "session.h"
36 #include "nabi.h"
37
38 static SmcConn session_connection;
39
40 static gboolean
process_ice_messages(GIOChannel * channel,GIOCondition condition,gpointer client_data)41 process_ice_messages(GIOChannel *channel,
42 GIOCondition condition, gpointer client_data)
43 {
44 IceConn ice_conn = (IceConn)client_data;
45 IceProcessMessagesStatus status;
46
47 status = IceProcessMessages(ice_conn, NULL, NULL);
48 if (status == IceProcessMessagesIOError) {
49 nabi_log(1, "ice message process error\n");
50 IceSetShutdownNegotiation(ice_conn, False);
51 IceCloseConnection(ice_conn);
52 }
53
54 return TRUE;
55 }
56
57 static void
ice_watch_proc(IceConn ice_conn,IcePointer client_data,Bool opening,IcePointer * watch_data)58 ice_watch_proc(IceConn ice_conn, IcePointer client_data,
59 Bool opening, IcePointer *watch_data)
60 {
61 guint input_id;
62 if (opening) {
63 GIOChannel *channel;
64
65 channel = g_io_channel_unix_new(IceConnectionNumber(ice_conn));
66 input_id = g_io_add_watch(channel,
67 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI,
68 process_ice_messages, ice_conn);
69 g_io_channel_unref(channel);
70 *watch_data = (IcePointer)GUINT_TO_POINTER(input_id);
71 } else {
72 input_id = GPOINTER_TO_UINT((gpointer) *watch_data);
73 g_source_remove(input_id);
74 }
75 }
76
77 static void
save_yourself_proc(SmcConn smc_conn,SmPointer client_data,int save_type,Bool shutdown,int interact_style,Bool fast)78 save_yourself_proc(SmcConn smc_conn, SmPointer client_data, int save_type,
79 Bool shutdown, int interact_style, Bool fast)
80 {
81 nabi_app_save_config();
82 SmcSaveYourselfDone(smc_conn, True);
83 }
84
85 static void
die_proc(SmcConn smc_conn,SmPointer client_data)86 die_proc(SmcConn smc_conn, SmPointer client_data)
87 {
88 nabi_app_quit();
89 }
90
91 static void
save_complete_proc(SmcConn smc_conn,SmPointer client_data)92 save_complete_proc(SmcConn smc_conn, SmPointer client_data)
93 {
94 }
95
96 static void
shutdown_cancelled_proc(SmcConn smc_conn,SmPointer client_data)97 shutdown_cancelled_proc(SmcConn smc_conn, SmPointer client_data)
98 {
99 SmcSaveYourselfDone(smc_conn, True);
100 }
101
102 static SmProp *
property_new(const char * name,const char * type,...)103 property_new(const char *name, const char *type, ...)
104 {
105 SmProp *prop;
106 SmPropValue *val_list;
107 va_list args;
108 const char *str;
109 int n, i;
110
111 prop = g_malloc(sizeof(SmProp));
112 prop->name = g_strdup(name);
113 prop->type = g_strdup(type);
114
115 va_start(args, type);
116 str = va_arg(args, const char*);
117 for (n = 0; str != NULL; n++, str = va_arg(args, const char*))
118 continue;
119 va_end(args);
120
121 prop->num_vals = n;
122
123 val_list = g_malloc(sizeof(SmPropValue) * n);
124 va_start(args, type);
125 for (i = 0; i < n; i++) {
126 str = va_arg(args, const char*);
127 val_list[i].length = strlen(str);
128 val_list[i].value = g_strdup(str);
129 }
130 va_end(args);
131
132 prop->vals = val_list;
133
134 return prop;
135 }
136
137 static void
property_free(SmProp * prop)138 property_free(SmProp *prop)
139 {
140 int i;
141
142 g_free(prop->name);
143 g_free(prop->type);
144 for (i = 0; i < prop->num_vals; i++)
145 g_free(prop->vals[i].value);
146 g_free(prop->vals);
147 g_free(prop);
148 }
149
150 static void
setup_properties(const char * client_id)151 setup_properties(const char *client_id)
152 {
153 gchar *process_id;
154 gchar *restart_style_hint;
155 const gchar *program;
156 const gchar *user_id;
157 SmProp *prop_list[6];
158
159 if (session_connection == NULL)
160 return;
161
162 process_id = g_strdup_printf("%d", (int) getpid());
163 program = g_get_prgname();
164 user_id = g_get_user_name();
165
166 prop_list[0] = property_new(SmCloneCommand, SmLISTofARRAY8, program, NULL);
167 prop_list[1] = property_new(SmProcessID, SmARRAY8, process_id, NULL);
168 prop_list[2] = property_new(SmProgram, SmARRAY8, program, NULL);
169 if (nabi->status_only)
170 prop_list[3] = property_new(SmRestartCommand, SmLISTofARRAY8,
171 program, "--status-only",
172 "--sm-client-id", client_id, NULL);
173 else
174 prop_list[3] = property_new(SmRestartCommand, SmLISTofARRAY8,
175 program, "--sm-client-id", client_id, NULL);
176 prop_list[4] = property_new(SmUserID, SmARRAY8, user_id, NULL);
177 restart_style_hint = g_strdup_printf("%c", (char)SmRestartImmediately);
178 prop_list[5] = property_new(SmRestartStyleHint,
179 SmCARD8, restart_style_hint, NULL);
180 g_free(restart_style_hint);
181
182 SmcSetProperties(session_connection, 6, prop_list);
183
184 property_free(prop_list[0]);
185 property_free(prop_list[1]);
186 property_free(prop_list[2]);
187 property_free(prop_list[3]);
188 property_free(prop_list[4]);
189 property_free(prop_list[5]);
190
191 g_free(process_id);
192 }
193
194 void
nabi_session_open(char * previos_id)195 nabi_session_open(char *previos_id)
196 {
197 char buf[256];
198 SmcCallbacks callbacks;
199 char *client_id = NULL;
200
201 IceAddConnectionWatch(ice_watch_proc, NULL);
202
203 callbacks.save_yourself.callback = save_yourself_proc;
204 callbacks.save_yourself.client_data = NULL;
205 callbacks.die.callback = die_proc;
206 callbacks.die.client_data = NULL;
207 callbacks.save_complete.callback = save_complete_proc;
208 callbacks.save_complete.client_data = NULL;
209 callbacks.shutdown_cancelled.callback = shutdown_cancelled_proc;
210 callbacks.shutdown_cancelled.client_data = NULL;
211
212 session_connection = SmcOpenConnection(NULL, NULL,
213 SmProtoMajor, SmProtoMinor,
214 SmcSaveYourselfProcMask |
215 SmcDieProcMask |
216 SmcSaveCompleteProcMask |
217 SmcShutdownCancelledProcMask,
218 &callbacks,
219 previos_id,
220 &client_id,
221 sizeof(buf),
222 buf);
223 if (session_connection == NULL) {
224 nabi_log(1, "session: %s\n", buf);
225 return;
226 }
227
228 if (client_id == NULL)
229 return;
230
231 setup_properties(client_id);
232 gdk_set_sm_client_id(client_id);
233
234 g_free(nabi->session_id);
235 nabi->session_id = client_id;
236 return;
237 }
238
239 void
nabi_session_close(void)240 nabi_session_close(void)
241 {
242 char *prop_names[] = { SmRestartStyleHint, 0 };
243
244 if (session_connection == NULL)
245 return;
246
247 SmcDeleteProperties(session_connection, 1, prop_names);
248 SmcCloseConnection(session_connection, 0, NULL);
249 gdk_set_sm_client_id(NULL);
250 g_free(nabi->session_id);
251 nabi->session_id = NULL;
252 }
253
254 #else /* HAVE_LIBSM */
255
nabi_session_open(char * previos_id)256 void nabi_session_open(char *previos_id)
257 {
258 }
259
nabi_session_close(void)260 void nabi_session_close(void)
261 {
262 }
263
264 #endif /* HAVE_LIBSM */
265