2 * ion/mod_sm/sm_session.c
4 * Copyright (c) Tuomo Valkonen 2004-2009.
6 * Based on the code of the 'sm' module for Ion1 by an unknown contributor.
8 * This is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
17 #include <sys/types.h>
20 #include <libtu/misc.h>
23 #include <X11/SM/SMlib.h>
25 #include <libextl/readconfig.h>
26 #include <libmainloop/select.h>
27 #include <libmainloop/exec.h>
28 #include <ioncore/exec.h>
29 #include <ioncore/global.h>
30 #include <ioncore/ioncore.h>
31 #include "sm_session.h"
34 static IceConn ice_sm_conn
=NULL
;
35 static SmcConn sm_conn
=NULL
;
38 static char *sm_client_id
=NULL
;
39 static char restart_hint
=SmRestartImmediately
;
41 static Bool sent_save_done
=FALSE
;
43 /* Function to be called when sm tells client save is complete */
44 static void (*save_complete_fn
)();
46 void mod_sm_set_ion_id(const char *client_id
)
54 sm_client_id
=scopy(client_id
);
57 char *mod_sm_get_ion_id()
62 /* Called when there's data to be read.
63 IcePcocessMessages determines message protocol,
64 unpacks the message and sends it to the client via
65 registered callbacks. */
67 static void sm_process_messages(int UNUSED(fd
), void *UNUSED(data
))
71 if(IceProcessMessages(ice_sm_conn
, NULL
, &ret
)==IceProcessMessagesIOError
){
76 /* Callback triggered when an Ice connection is
79 static void sm_ice_watch_fd(IceConn conn
,
80 IcePointer
UNUSED(client_data
),
82 IcePointer
*UNUSED(watch_data
))
85 if(sm_fd
!=-1){ /* shouldn't happen */
86 warn(TR("Too many ICE connections."));
89 sm_fd
=IceConnectionNumber(conn
);
90 cloexec_braindamage_fix(sm_fd
);
91 mainloop_register_input_fd(sm_fd
, NULL
, &sm_process_messages
);
95 if (IceConnectionNumber(conn
)==sm_fd
){
96 mainloop_unregister_input_fd(sm_fd
);
102 /* Store restart information and stuff in the session manager */
104 static void sm_set_some_properties()
106 SmPropValue program_val
, userid_val
;
107 SmProp program_prop
, userid_prop
, clone_prop
;
110 props
[0]=&program_prop
;
111 props
[1]=&userid_prop
;
112 props
[2]=&clone_prop
;
114 program_val
.value
=ioncore_g
.argv
[0];
115 program_val
.length
=strlen(program_val
.value
);
116 program_prop
.name
=SmProgram
;
117 program_prop
.type
=SmARRAY8
;
118 program_prop
.num_vals
=1;
119 program_prop
.vals
=&program_val
;
121 userid_val
.value
=getenv("USER");
122 userid_val
.length
=strlen(userid_val
.value
);
123 userid_prop
.name
=SmUserID
;
124 userid_prop
.type
=SmARRAY8
;
125 userid_prop
.num_vals
=1;
126 userid_prop
.vals
=&userid_val
;
128 clone_prop
.name
=SmCloneCommand
;
129 clone_prop
.type
=SmLISTofARRAY8
;
130 clone_prop
.num_vals
=1;
131 clone_prop
.vals
=&program_val
;
133 SmcSetProperties(sm_conn
,
134 sizeof(props
)/sizeof(props
[0]),
138 static void sm_set_other_properties()
140 char *restore
="-session";
141 char *clientid
="-smclientid";
142 char *rmprog
="/bin/rm";
145 const char *sdir
=NULL
, *cid
=NULL
;
147 SmPropValue discard_val
[3];
148 SmProp discard_prop
={ SmDiscardCommand
, SmLISTofARRAY8
, 3, NULL
};
149 SmPropValue restart_hint_val
, *restart_val
=NULL
;
150 SmProp restart_hint_prop
={ SmRestartStyleHint
, SmCARD8
, 1, NULL
};
151 SmProp restart_prop
={ SmRestartCommand
, SmLISTofARRAY8
, 0, NULL
};
155 discard_prop
.vals
=discard_val
;
156 restart_hint_prop
.vals
=&restart_hint_val
;
158 props
[0]=&restart_prop
;
159 props
[1]=&restart_hint_prop
;
160 /*props[2]=&discard_prop;*/
162 sdir
=extl_sessiondir();
163 cid
=mod_sm_get_ion_id();
165 if(sdir
==NULL
|| cid
==NULL
)
168 restart_hint_val
.value
=&restart_hint
;
169 restart_hint_val
.length
=1;
171 restart_val
=(SmPropValue
*)malloc((ioncore_g
.argc
+4)*sizeof(SmPropValue
));
172 for(i
=0; i
<ioncore_g
.argc
; i
++){
173 if(strcmp(ioncore_g
.argv
[i
], restore
)==0 ||
174 strcmp(ioncore_g
.argv
[i
], clientid
)==0){
177 restart_val
[nvals
].value
=ioncore_g
.argv
[i
];
178 restart_val
[nvals
++].length
=strlen(ioncore_g
.argv
[i
]);
181 restart_val
[nvals
].value
=restore
;
182 restart_val
[nvals
++].length
=strlen(restore
);
183 restart_val
[nvals
].value
=(char*)sdir
;
184 restart_val
[nvals
++].length
=strlen(sdir
);
185 restart_val
[nvals
].value
=clientid
;
186 restart_val
[nvals
++].length
=strlen(clientid
);
187 restart_val
[nvals
].value
=(char*)cid
;
188 restart_val
[nvals
++].length
=strlen(cid
);
189 restart_prop
.num_vals
=nvals
;
190 restart_prop
.vals
=restart_val
;
191 discard_val
[0].length
=strlen(rmprog
);
192 discard_val
[0].value
=rmprog
;
193 discard_val
[1].length
=strlen(rmarg
);
194 discard_val
[1].value
=rmarg
;
195 discard_val
[2].length
=strlen(sdir
);
196 discard_val
[2].value
=(char*)sdir
;
198 SmcSetProperties(sm_conn
,
199 sizeof(props
)/sizeof(props
[0]),
205 static void sm_set_properties()
207 static bool init
=TRUE
;
210 sm_set_some_properties();
214 sm_set_other_properties();
218 /* Callback for the save yourself phase 2 message.
219 This message is sent by the sm when other clients in the session are finished
220 saving state. This is requested in the save yourself callback by clients
221 like this one that manages other clients. */
223 static void sm_save_yourself_phase2(SmcConn conn
, SmPointer
UNUSED(client_data
))
227 if(!(success
=ioncore_do_snapshot(TRUE
)))
228 warn(TR("Failed to save session state"));
232 SmcSaveYourselfDone(conn
, success
);
236 /* Callback. Called when the client recieves a save yourself
237 message from the sm. */
239 static void sm_save_yourself(SmcConn
UNUSED(conn
),
240 SmPointer
UNUSED(client_data
),
241 int UNUSED(save_type
),
242 Bool
UNUSED(shutdown
),
243 int UNUSED(interact_style
),
246 if(!SmcRequestSaveYourselfPhase2(sm_conn
, sm_save_yourself_phase2
, NULL
)){
247 warn(TR("Failed to request save-yourself-phase2 from "
248 "session manager."));
249 SmcSaveYourselfDone(sm_conn
, False
);
252 sent_save_done
=FALSE
;
256 /* Response to the shutdown cancelled message */
258 static void sm_shutdown_cancelled(SmcConn conn
, SmPointer
UNUSED(client_data
))
260 save_complete_fn
=NULL
;
262 SmcSaveYourselfDone(conn
, False
);
269 static void sm_save_complete(SmcConn
UNUSED(conn
), SmPointer
UNUSED(client_data
))
271 if(save_complete_fn
){
273 save_complete_fn
=NULL
;
279 static void sm_die(SmcConn conn
, SmPointer
UNUSED(client_data
))
281 assert(conn
==sm_conn
);
286 /* Connects to the sm and registers
287 callbacks for different messages */
289 bool mod_sm_init_session()
292 char *new_client_id
=NULL
;
295 if(getenv("SESSION_MANAGER")==0){
296 warn(TR("SESSION_MANAGER environment variable not set."));
300 if(IceAddConnectionWatch(&sm_ice_watch_fd
, NULL
) == 0){
301 warn(TR("Session Manager: IceAddConnectionWatch failed."));
305 memset(&smcall
, 0, sizeof(smcall
));
306 smcall
.save_yourself
.callback
=&sm_save_yourself
;
307 smcall
.save_yourself
.client_data
=NULL
;
308 smcall
.die
.callback
=&sm_die
;
309 smcall
.die
.client_data
=NULL
;
310 smcall
.save_complete
.callback
=&sm_save_complete
;
311 smcall
.save_complete
.client_data
=NULL
;
312 smcall
.shutdown_cancelled
.callback
=&sm_shutdown_cancelled
;
313 smcall
.shutdown_cancelled
.client_data
=NULL
;
315 if((sm_conn
=SmcOpenConnection(NULL
, /* network ids */
317 1, 0, /* protocol major, minor */
318 SmcSaveYourselfProcMask
|
319 SmcSaveCompleteProcMask
|
320 SmcShutdownCancelledProcMask
|
323 sm_client_id
, &new_client_id
,
324 sizeof(error_str
), error_str
)) == NULL
)
326 warn(TR("Unable to connect to the session manager."));
330 mod_sm_set_ion_id(new_client_id
);
333 ice_sm_conn
=SmcGetIceConnection(sm_conn
);
342 SmcCloseConnection(sm_conn
, 0, NULL
);
349 mainloop_unregister_input_fd(sm_fd
);
354 if(sm_client_id
!=NULL
){
361 static void sm_exit()
363 sm_die(sm_conn
, NULL
);
367 static void sm_restart()
369 ioncore_do_restart();
373 void mod_sm_smhook(int what
)
375 save_complete_fn
=NULL
;
380 case IONCORE_SM_RESIGN
:
381 restart_hint
=SmRestartIfRunning
;
383 /*SmcRequestSaveYourself(sm_conn, SmSaveBoth, False,
384 SmInteractStyleAny, False, False);
385 save_complete_fn=&sm_exit;*/
388 case IONCORE_SM_SHUTDOWN
:
389 restart_hint
=SmRestartIfRunning
;
390 SmcRequestSaveYourself(sm_conn
, SmSaveBoth
, True
,
391 SmInteractStyleAny
, False
, True
);
393 case IONCORE_SM_RESTART
:
394 restart_hint
=SmRestartImmediately
;
395 SmcRequestSaveYourself(sm_conn
, SmSaveBoth
, False
,
396 SmInteractStyleAny
, False
, False
);
397 save_complete_fn
=&sm_exit
;
399 case IONCORE_SM_RESTART_OTHER
:
400 restart_hint
=SmRestartIfRunning
;
401 SmcRequestSaveYourself(sm_conn
, SmSaveBoth
, False
,
402 SmInteractStyleAny
, False
, False
);
403 save_complete_fn
=&sm_restart
;
405 case IONCORE_SM_SNAPSHOT
:
406 restart_hint
=SmRestartImmediately
;
407 SmcRequestSaveYourself(sm_conn
, SmSaveBoth
, False
,
408 SmInteractStyleAny
, False
, True
);