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