File: | smproxy.c |
Location: | line 976, column 12 |
Description: | Potential leak of memory pointed to by 'prop1.vals' |
1 | /****************************************************************************** | |||||
2 | ||||||
3 | Copyright 1994, 1998 The Open Group | |||||
4 | ||||||
5 | Permission to use, copy, modify, distribute, and sell this software and its | |||||
6 | documentation for any purpose is hereby granted without fee, provided that | |||||
7 | the above copyright notice appear in all copies and that both that | |||||
8 | copyright notice and this permission notice appear in supporting | |||||
9 | documentation. | |||||
10 | ||||||
11 | The above copyright notice and this permission notice shall be included in | |||||
12 | all copies or substantial portions of the Software. | |||||
13 | ||||||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
17 | OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | |||||
18 | AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||||
19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||||
20 | ||||||
21 | Except as contained in this notice, the name of The Open Group shall not be | |||||
22 | used in advertising or otherwise to promote the sale, use or other dealings | |||||
23 | in this Software without prior written authorization from The Open Group. | |||||
24 | ||||||
25 | Author: Ralph Mor, X Consortium | |||||
26 | ******************************************************************************/ | |||||
27 | ||||||
28 | #include "smproxy.h" | |||||
29 | #include <unistd.h> | |||||
30 | #include <X11/Xmu/WinUtil.h> | |||||
31 | ||||||
32 | static XtAppContext appContext; | |||||
33 | static Display *disp; | |||||
34 | ||||||
35 | static Atom wmProtocolsAtom; | |||||
36 | static Atom wmSaveYourselfAtom; | |||||
37 | static Atom wmStateAtom; | |||||
38 | static Atom smClientIdAtom; | |||||
39 | static Atom wmClientLeaderAtom; | |||||
40 | ||||||
41 | static Boolint debug = 0; | |||||
42 | ||||||
43 | static SmcConn proxy_smcConn; | |||||
44 | static XtInputId proxy_iceInputId; | |||||
45 | static char *proxy_clientId = NULL((void*)0); | |||||
46 | ||||||
47 | WinInfo *win_head = NULL((void*)0); | |||||
48 | ||||||
49 | static int proxy_count = 0; | |||||
50 | static int die_count = 0; | |||||
51 | ||||||
52 | static Boolint ok_to_die = 0; | |||||
53 | ||||||
54 | static Boolint caught_error = 0; | |||||
55 | ||||||
56 | static Boolint sent_save_done = 0; | |||||
57 | ||||||
58 | static int Argc; | |||||
59 | static char **Argv; | |||||
60 | ||||||
61 | static Boolint HasSaveYourself ( Window window ); | |||||
62 | static Boolint HasXSMPsupport ( Window window ); | |||||
63 | static WinInfo * GetClientLeader ( WinInfo *winptr ); | |||||
64 | static char * CheckFullyQuantifiedName ( char *name, int *newstring ); | |||||
65 | static void FinishSaveYourself ( WinInfo *winInfo, Boolint has_WM_SAVEYOURSELF ); | |||||
66 | static void SaveYourselfCB ( SmcConn smcConn, SmPointer clientData, int saveType, | |||||
67 | Boolint shutdown, int interactStyle, Boolint fast ); | |||||
68 | static void DieCB ( SmcConn smcConn, SmPointer clientData ); | |||||
69 | static void SaveCompleteCB ( SmcConn smcConn, SmPointer clientData ); | |||||
70 | static void ShutdownCancelledCB ( SmcConn smcConn, SmPointer clientData ); | |||||
71 | static void ProcessIceMsgProc ( XtPointer client_data, int *source, XtInputId *id ); | |||||
72 | static void NullIceErrorHandler ( IceConn iceConn, Boolint swap, | |||||
73 | int offendingMinorOpCode, | |||||
74 | unsigned long offendingSequence, | |||||
75 | int errorClass, int severity, IcePointer values ); | |||||
76 | static void ConnectClientToSM ( WinInfo *winInfo ); | |||||
77 | static int MyErrorHandler ( Display *display, XErrorEvent *event ); | |||||
78 | static Boolint LookupWindow ( Window window, WinInfo **ptr_ret, WinInfo **prev_ptr_ret ); | |||||
79 | static WinInfo * AddNewWindow ( Window window ); | |||||
80 | static void RemoveWindow ( WinInfo *winptr ); | |||||
81 | static void Got_WM_STATE ( WinInfo *winptr ); | |||||
82 | static void HandleCreate ( XCreateWindowEvent *event ); | |||||
83 | static void HandleDestroy ( XDestroyWindowEvent *event ); | |||||
84 | static void HandleUpdate ( XPropertyEvent *event ); | |||||
85 | static void ProxySaveYourselfPhase2CB ( SmcConn smcConn, SmPointer clientData ); | |||||
86 | static void ProxySaveYourselfCB ( SmcConn smcConn, SmPointer clientData, | |||||
87 | int saveType, Boolint shutdown, int interactStyle, | |||||
88 | Boolint fast ); | |||||
89 | static void ProxyDieCB ( SmcConn smcConn, SmPointer clientData ); | |||||
90 | static void ProxySaveCompleteCB ( SmcConn smcConn, SmPointer clientData ); | |||||
91 | static void ProxyShutdownCancelledCB ( SmcConn smcConn, SmPointer clientData ); | |||||
92 | static Statusint ConnectProxyToSM ( char *previous_id ); | |||||
93 | static void CheckForExistingWindows ( Window root ); | |||||
94 | ||||||
95 | ||||||
96 | static Boolint | |||||
97 | HasSaveYourself(Window window) | |||||
98 | { | |||||
99 | Atom *protocols; | |||||
100 | int numProtocols; | |||||
101 | int i, found; | |||||
102 | ||||||
103 | protocols = NULL((void*)0); | |||||
104 | ||||||
105 | if (XGetWMProtocols (disp, window, &protocols, &numProtocols) != True1) | |||||
106 | return (False0); | |||||
107 | ||||||
108 | found = 0; | |||||
109 | ||||||
110 | if (protocols != NULL((void*)0)) | |||||
111 | { | |||||
112 | for (i = 0; i < numProtocols; i++) | |||||
113 | if (protocols[i] == wmSaveYourselfAtom) | |||||
114 | found = 1; | |||||
115 | ||||||
116 | XFree (protocols); | |||||
117 | } | |||||
118 | ||||||
119 | return (found); | |||||
120 | } | |||||
121 | ||||||
122 | ||||||
123 | ||||||
124 | static Boolint | |||||
125 | HasXSMPsupport(Window window) | |||||
126 | { | |||||
127 | XTextProperty tp; | |||||
128 | Boolint hasIt = 0; | |||||
129 | ||||||
130 | if (XGetTextProperty (disp, window, &tp, smClientIdAtom)) | |||||
131 | { | |||||
132 | if (tp.encoding == XA_STRING((Atom) 31) && tp.format == 8 && tp.nitems != 0) | |||||
133 | hasIt = 1; | |||||
134 | ||||||
135 | if (tp.value) | |||||
136 | XFree ((char *) tp.value); | |||||
137 | } | |||||
138 | ||||||
139 | return (hasIt); | |||||
140 | } | |||||
141 | ||||||
142 | ||||||
143 | ||||||
144 | static WinInfo * | |||||
145 | GetClientLeader(WinInfo *winptr) | |||||
146 | { | |||||
147 | Atom actual_type; | |||||
148 | int actual_format; | |||||
149 | unsigned long nitems, bytesafter; | |||||
150 | unsigned long *datap = NULL((void*)0); | |||||
151 | WinInfo *leader_winptr = NULL((void*)0); | |||||
152 | Boolint failure = 0; | |||||
153 | ||||||
154 | if (XGetWindowProperty (disp, winptr->window, wmClientLeaderAtom, | |||||
155 | 0L, 1L, False0, AnyPropertyType0L, &actual_type, &actual_format, | |||||
156 | &nitems, &bytesafter, (unsigned char **) &datap) == Success0) | |||||
157 | { | |||||
158 | if (actual_type == XA_WINDOW((Atom) 33) && actual_format == 32 && | |||||
159 | nitems == 1 && bytesafter == 0) | |||||
160 | { | |||||
161 | Window leader_win = *((Window *) datap); | |||||
162 | ||||||
163 | if (!LookupWindow (leader_win, &leader_winptr, NULL((void*)0))) | |||||
164 | failure = 1; | |||||
165 | } | |||||
166 | ||||||
167 | if (datap) | |||||
168 | XFree (datap); | |||||
169 | } | |||||
170 | ||||||
171 | if (failure) | |||||
172 | { | |||||
173 | /* The client leader was defined, but we couldn't find the window */ | |||||
174 | ||||||
175 | return (NULL((void*)0)); | |||||
176 | } | |||||
177 | else if (leader_winptr) | |||||
178 | { | |||||
179 | /* We found the real client leader */ | |||||
180 | ||||||
181 | return (leader_winptr); | |||||
182 | } | |||||
183 | else | |||||
184 | { | |||||
185 | /* There is no client leader defined, return this window */ | |||||
186 | ||||||
187 | return (winptr); | |||||
188 | } | |||||
189 | } | |||||
190 | ||||||
191 | ||||||
192 | ||||||
193 | static char * | |||||
194 | CheckFullyQuantifiedName(char *name, int *newstring) | |||||
195 | { | |||||
196 | /* | |||||
197 | * Due to a bug in Xlib (for hpux in particular), some clients | |||||
198 | * will have a WM_CLIENT_MACHINE that is not fully quantified. | |||||
199 | * For example, we might get "excon" instead of "excon.x.org". | |||||
200 | * This really stinks. The best we can do is tag on our own | |||||
201 | * domain name. | |||||
202 | */ | |||||
203 | ||||||
204 | if (strchr (name, '.') != NULL((void*)0)) | |||||
205 | { | |||||
206 | *newstring = 0; | |||||
207 | return (name); | |||||
208 | } | |||||
209 | else | |||||
210 | { | |||||
211 | char hostnamebuf[80]; | |||||
212 | char *firstDot; | |||||
213 | ||||||
214 | gethostname (hostnamebuf, sizeof hostnamebuf); | |||||
215 | firstDot = strchr (hostnamebuf, '.'); | |||||
216 | ||||||
217 | if (!firstDot) | |||||
218 | { | |||||
219 | *newstring = 0; | |||||
220 | return (name); | |||||
221 | } | |||||
222 | else | |||||
223 | { | |||||
224 | char *newptr; | |||||
225 | ||||||
226 | if (asprintf (&newptr, "%s.%s", name, firstDot + 1) == -1) { | |||||
227 | *newstring = 0; | |||||
228 | return NULL((void*)0); | |||||
229 | } | |||||
230 | *newstring = 1; | |||||
231 | return (newptr); | |||||
232 | } | |||||
233 | } | |||||
234 | } | |||||
235 | ||||||
236 | ||||||
237 | ||||||
238 | static void | |||||
239 | FinishSaveYourself(WinInfo *winInfo, Boolint has_WM_SAVEYOURSELF) | |||||
240 | { | |||||
241 | SmProp prop1, prop2, prop3, *props[3]; | |||||
242 | SmPropValue prop1val, prop2val, prop3val; | |||||
243 | int i; | |||||
244 | ||||||
245 | if (!winInfo->got_first_save_yourself) | |||||
246 | { | |||||
247 | char userId[20], restartService[80]; | |||||
248 | char *fullyQuantifiedName; | |||||
249 | int newstring; | |||||
250 | ||||||
251 | prop1.name = SmProgram"Program"; | |||||
252 | prop1.type = SmARRAY8"ARRAY8"; | |||||
253 | prop1.num_vals = 1; | |||||
254 | prop1.vals = &prop1val; | |||||
255 | prop1val.value = (SmPointer) winInfo->wm_command[0]; | |||||
256 | prop1val.length = strlen (winInfo->wm_command[0]); | |||||
257 | ||||||
258 | snprintf (userId, sizeof(userId), "%ld", (long)getuid())__builtin___snprintf_chk (userId, sizeof(userId), 0, __builtin_object_size (userId, 2 > 1 ? 1 : 0), "%ld", (long)getuid()); | |||||
259 | prop2.name = SmUserID"UserID"; | |||||
260 | prop2.type = SmARRAY8"ARRAY8"; | |||||
261 | prop2.num_vals = 1; | |||||
262 | prop2.vals = &prop2val; | |||||
263 | prop2val.value = (SmPointer) userId; | |||||
264 | prop2val.length = strlen (userId); | |||||
265 | ||||||
266 | fullyQuantifiedName = CheckFullyQuantifiedName ( | |||||
267 | (char *) winInfo->wm_client_machine.value, &newstring); | |||||
268 | snprintf (restartService, sizeof(restartService),__builtin___snprintf_chk (restartService, sizeof(restartService ), 0, __builtin_object_size (restartService, 2 > 1 ? 1 : 0 ), "rstart-rsh/%s", fullyQuantifiedName) | |||||
269 | "rstart-rsh/%s", fullyQuantifiedName)__builtin___snprintf_chk (restartService, sizeof(restartService ), 0, __builtin_object_size (restartService, 2 > 1 ? 1 : 0 ), "rstart-rsh/%s", fullyQuantifiedName); | |||||
270 | if (newstring) | |||||
271 | free (fullyQuantifiedName); | |||||
272 | ||||||
273 | prop3.name = "_XC_RestartService"; | |||||
274 | prop3.type = SmLISTofARRAY8"LISTofARRAY8"; | |||||
275 | prop3.num_vals = 1; | |||||
276 | prop3.vals = &prop3val; | |||||
277 | prop3val.value = (SmPointer) restartService; | |||||
278 | prop3val.length = strlen (restartService); | |||||
279 | ||||||
280 | props[0] = &prop1; | |||||
281 | props[1] = &prop2; | |||||
282 | props[2] = &prop3; | |||||
283 | ||||||
284 | SmcSetProperties (winInfo->smc_conn, 3, props); | |||||
285 | ||||||
286 | winInfo->got_first_save_yourself = 1; | |||||
287 | } | |||||
288 | ||||||
289 | prop1.name = SmRestartCommand"RestartCommand"; | |||||
290 | prop1.type = SmLISTofARRAY8"LISTofARRAY8"; | |||||
291 | prop1.num_vals = winInfo->wm_command_count; | |||||
292 | ||||||
293 | prop1.vals = (SmPropValue *) malloc ( | |||||
294 | winInfo->wm_command_count * sizeof (SmPropValue)); | |||||
295 | ||||||
296 | if (!prop1.vals) | |||||
297 | { | |||||
298 | SmcSaveYourselfDone (winInfo->smc_conn, False0); | |||||
299 | return; | |||||
300 | } | |||||
301 | ||||||
302 | for (i = 0; i < winInfo->wm_command_count; i++) | |||||
303 | { | |||||
304 | prop1.vals[i].value = (SmPointer) winInfo->wm_command[i]; | |||||
305 | prop1.vals[i].length = strlen (winInfo->wm_command[i]); | |||||
306 | } | |||||
307 | ||||||
308 | prop2.name = SmCloneCommand"CloneCommand"; | |||||
309 | prop2.type = SmLISTofARRAY8"LISTofARRAY8"; | |||||
310 | prop2.num_vals = winInfo->wm_command_count; | |||||
311 | prop2.vals = prop1.vals; | |||||
312 | ||||||
313 | props[0] = &prop1; | |||||
314 | props[1] = &prop2; | |||||
315 | ||||||
316 | SmcSetProperties (winInfo->smc_conn, 2, props); | |||||
317 | ||||||
318 | free ((char *) prop1.vals); | |||||
319 | ||||||
320 | /* | |||||
321 | * If the client doesn't support WM_SAVE_YOURSELF, we should | |||||
322 | * return failure for the save, since we really don't know if | |||||
323 | * the application needed to save state. | |||||
324 | */ | |||||
325 | ||||||
326 | SmcSaveYourselfDone (winInfo->smc_conn, has_WM_SAVEYOURSELF); | |||||
327 | } | |||||
328 | ||||||
329 | ||||||
330 | ||||||
331 | static void | |||||
332 | SaveYourselfCB(SmcConn smcConn, SmPointer clientData, int saveType, | |||||
333 | Boolint shutdown, int interactStyle, Boolint fast) | |||||
334 | { | |||||
335 | WinInfo *winInfo = (WinInfo *) clientData; | |||||
336 | ||||||
337 | if (!winInfo->has_save_yourself) | |||||
338 | { | |||||
339 | FinishSaveYourself (winInfo, False0); | |||||
340 | } | |||||
341 | else | |||||
342 | { | |||||
343 | XClientMessageEvent saveYourselfMessage; | |||||
344 | ||||||
345 | ||||||
346 | /* Send WM_SAVE_YOURSELF */ | |||||
347 | ||||||
348 | saveYourselfMessage.type = ClientMessage33; | |||||
349 | saveYourselfMessage.window = winInfo->window; | |||||
350 | saveYourselfMessage.message_type = wmProtocolsAtom; | |||||
351 | saveYourselfMessage.format = 32; | |||||
352 | saveYourselfMessage.data.l[0] = wmSaveYourselfAtom; | |||||
353 | saveYourselfMessage.data.l[1] = CurrentTime0L; | |||||
354 | ||||||
355 | if (XSendEvent (disp, winInfo->window, False0, NoEventMask0L, | |||||
356 | (XEvent *) &saveYourselfMessage)) | |||||
357 | { | |||||
358 | winInfo->waiting_for_update = 1; | |||||
359 | ||||||
360 | if (debug) | |||||
361 | { | |||||
362 | printf ("Sent SAVE YOURSELF to 0x%x\n", | |||||
363 | (unsigned int)winInfo->window); | |||||
364 | printf ("\n"); | |||||
365 | } | |||||
366 | } | |||||
367 | else | |||||
368 | { | |||||
369 | if (debug) | |||||
370 | { | |||||
371 | printf ("Failed to send SAVE YOURSELF to 0x%x\n", | |||||
372 | (unsigned int)winInfo->window); | |||||
373 | printf ("\n"); | |||||
374 | } | |||||
375 | } | |||||
376 | } | |||||
377 | } | |||||
378 | ||||||
379 | ||||||
380 | ||||||
381 | static void | |||||
382 | DieCB(SmcConn smcConn, SmPointer clientData) | |||||
383 | { | |||||
384 | WinInfo *winInfo = (WinInfo *) clientData; | |||||
385 | ||||||
386 | SmcCloseConnection (winInfo->smc_conn, 0, NULL((void*)0)); | |||||
387 | winInfo->smc_conn = NULL((void*)0); | |||||
388 | XtRemoveInput (winInfo->input_id); | |||||
389 | ||||||
390 | /* Now tell the client to die */ | |||||
391 | ||||||
392 | if (debug) | |||||
393 | printf ("Trying to kill 0x%x\n", (unsigned int)winInfo->window); | |||||
394 | ||||||
395 | XSync (disp, 0); | |||||
396 | XKillClient (disp, winInfo->window); | |||||
397 | XSync (disp, 0); | |||||
398 | ||||||
399 | ||||||
400 | /* | |||||
401 | * Proxy must exit when all clients die, and the proxy itself | |||||
402 | * must have received a Die. | |||||
403 | */ | |||||
404 | ||||||
405 | die_count++; | |||||
406 | ||||||
407 | if (die_count == proxy_count && ok_to_die) | |||||
408 | { | |||||
409 | exit (0); | |||||
410 | } | |||||
411 | } | |||||
412 | ||||||
413 | ||||||
414 | ||||||
415 | static void | |||||
416 | SaveCompleteCB(SmcConn smcConn, SmPointer clientData) | |||||
417 | { | |||||
418 | /* | |||||
419 | * Nothing to do here. | |||||
420 | */ | |||||
421 | } | |||||
422 | ||||||
423 | ||||||
424 | ||||||
425 | static void | |||||
426 | ShutdownCancelledCB(SmcConn smcConn, SmPointer clientData) | |||||
427 | { | |||||
428 | /* | |||||
429 | * Since we did not request to interact or request save yourself | |||||
430 | * phase 2, we know we already sent the save yourself done, so | |||||
431 | * there is nothing to do here. | |||||
432 | */ | |||||
433 | } | |||||
434 | ||||||
435 | ||||||
436 | ||||||
437 | static void | |||||
438 | ProcessIceMsgProc(XtPointer client_data, int *source, XtInputId *id) | |||||
439 | { | |||||
440 | IceConn ice_conn = (IceConn) client_data; | |||||
441 | ||||||
442 | IceProcessMessages (ice_conn, NULL((void*)0), NULL((void*)0)); | |||||
443 | } | |||||
444 | ||||||
445 | ||||||
446 | ||||||
447 | static void | |||||
448 | NullIceErrorHandler(IceConn iceConn, Boolint swap, int offendingMinorOpcode, | |||||
449 | unsigned long offendingSequence, int errorClass, | |||||
450 | int severity, IcePointer values) | |||||
451 | { | |||||
452 | return; | |||||
453 | } | |||||
454 | ||||||
455 | ||||||
456 | static void | |||||
457 | ConnectClientToSM(WinInfo *winInfo) | |||||
458 | { | |||||
459 | char errorMsg[256]; | |||||
460 | unsigned long mask; | |||||
461 | SmcCallbacks callbacks; | |||||
462 | IceConn ice_conn; | |||||
463 | char *prevId; | |||||
464 | ||||||
465 | mask = SmcSaveYourselfProcMask(1L << 0) | SmcDieProcMask(1L << 1) | | |||||
466 | SmcSaveCompleteProcMask(1L << 2) | SmcShutdownCancelledProcMask(1L << 3); | |||||
467 | ||||||
468 | callbacks.save_yourself.callback = SaveYourselfCB; | |||||
469 | callbacks.save_yourself.client_data = (SmPointer) winInfo; | |||||
470 | ||||||
471 | callbacks.die.callback = DieCB; | |||||
472 | callbacks.die.client_data = (SmPointer) winInfo; | |||||
473 | ||||||
474 | callbacks.save_complete.callback = SaveCompleteCB; | |||||
475 | callbacks.save_complete.client_data = (SmPointer) winInfo; | |||||
476 | ||||||
477 | callbacks.shutdown_cancelled.callback = ShutdownCancelledCB; | |||||
478 | callbacks.shutdown_cancelled.client_data = (SmPointer) winInfo; | |||||
479 | ||||||
480 | prevId = LookupClientID (winInfo); | |||||
481 | ||||||
482 | /* | |||||
483 | * In case a protocol error occurs when opening the connection, | |||||
484 | * (e.g. an authentication error), we set a null error handler | |||||
485 | * before the open, then restore the default handler after the open. | |||||
486 | */ | |||||
487 | ||||||
488 | IceSetErrorHandler (NullIceErrorHandler); | |||||
489 | ||||||
490 | winInfo->smc_conn = SmcOpenConnection ( | |||||
491 | NULL((void*)0), /* use SESSION_MANAGER env */ | |||||
492 | (SmPointer) winInfo, /* force a new connection */ | |||||
493 | SmProtoMajor1, | |||||
494 | SmProtoMinor0, | |||||
495 | mask, | |||||
496 | &callbacks, | |||||
497 | prevId, | |||||
498 | &winInfo->client_id, | |||||
499 | 256, errorMsg); | |||||
500 | ||||||
501 | IceSetErrorHandler (NULL((void*)0)); | |||||
502 | ||||||
503 | if (winInfo->smc_conn == NULL((void*)0)) | |||||
504 | return; | |||||
505 | ||||||
506 | ice_conn = SmcGetIceConnection (winInfo->smc_conn); | |||||
507 | ||||||
508 | winInfo->input_id = XtAppAddInput ( | |||||
509 | appContext, | |||||
510 | IceConnectionNumber (ice_conn), | |||||
511 | (XtPointer) XtInputReadMask(1L<<0), | |||||
512 | ProcessIceMsgProc, | |||||
513 | (XtPointer) ice_conn); | |||||
514 | ||||||
515 | if (debug) | |||||
516 | { | |||||
517 | printf ("Connected to SM, window = 0x%x\n", | |||||
518 | (unsigned int)winInfo->window); | |||||
519 | printf ("\n"); | |||||
520 | } | |||||
521 | ||||||
522 | proxy_count++; | |||||
523 | } | |||||
524 | ||||||
525 | ||||||
526 | ||||||
527 | static int | |||||
528 | MyErrorHandler(Display *display, XErrorEvent *event) | |||||
529 | { | |||||
530 | caught_error = 1; | |||||
531 | return 0; | |||||
532 | } | |||||
533 | ||||||
534 | ||||||
535 | ||||||
536 | static Boolint | |||||
537 | LookupWindow(Window window, WinInfo **ptr_ret, WinInfo **prev_ptr_ret) | |||||
538 | { | |||||
539 | WinInfo *ptr, *prev; | |||||
540 | ||||||
541 | ptr = win_head; | |||||
542 | prev = NULL((void*)0); | |||||
543 | ||||||
544 | while (ptr) | |||||
545 | { | |||||
546 | if (ptr->window == window) | |||||
547 | break; | |||||
548 | else | |||||
549 | { | |||||
550 | prev = ptr; | |||||
551 | ptr = ptr->next; | |||||
552 | } | |||||
553 | } | |||||
554 | ||||||
555 | if (ptr) | |||||
556 | { | |||||
557 | if (ptr_ret) | |||||
558 | *ptr_ret = ptr; | |||||
559 | if (prev_ptr_ret) | |||||
560 | *prev_ptr_ret = prev; | |||||
561 | return (1); | |||||
562 | } | |||||
563 | else | |||||
564 | return (0); | |||||
565 | } | |||||
566 | ||||||
567 | ||||||
568 | ||||||
569 | static WinInfo * | |||||
570 | AddNewWindow(Window window) | |||||
571 | { | |||||
572 | WinInfo *newptr; | |||||
573 | ||||||
574 | if (LookupWindow (window, NULL((void*)0), NULL((void*)0))) | |||||
575 | return (NULL((void*)0)); | |||||
576 | ||||||
577 | newptr = (WinInfo *) malloc (sizeof (WinInfo)); | |||||
578 | ||||||
579 | if (newptr == NULL((void*)0)) | |||||
580 | return (NULL((void*)0)); | |||||
581 | ||||||
582 | newptr->next = win_head; | |||||
583 | win_head = newptr; | |||||
584 | ||||||
585 | newptr->window = window; | |||||
586 | newptr->smc_conn = NULL((void*)0); | |||||
587 | newptr->tested_for_sm_client_id = 0; | |||||
588 | newptr->client_id = NULL((void*)0); | |||||
589 | newptr->wm_command = NULL((void*)0); | |||||
590 | newptr->wm_command_count = 0; | |||||
591 | newptr->class.res_name = NULL((void*)0); | |||||
592 | newptr->class.res_class = NULL((void*)0); | |||||
593 | newptr->wm_name = NULL((void*)0); | |||||
594 | newptr->wm_client_machine.value = NULL((void*)0); | |||||
595 | newptr->wm_client_machine.nitems = 0; | |||||
596 | newptr->has_save_yourself = 0; | |||||
597 | newptr->waiting_for_update = 0; | |||||
598 | newptr->got_first_save_yourself = 0; | |||||
599 | ||||||
600 | return (newptr); | |||||
601 | } | |||||
602 | ||||||
603 | ||||||
604 | ||||||
605 | static void | |||||
606 | RemoveWindow(WinInfo *winptr) | |||||
607 | { | |||||
608 | WinInfo *ptr, *prev; | |||||
609 | ||||||
610 | if (LookupWindow (winptr->window, &ptr, &prev)) | |||||
611 | { | |||||
612 | if (prev == NULL((void*)0)) | |||||
613 | win_head = ptr->next; | |||||
614 | else | |||||
615 | prev->next = ptr->next; | |||||
616 | ||||||
617 | if (ptr->client_id) | |||||
618 | free (ptr->client_id); | |||||
619 | ||||||
620 | if (ptr->wm_command) | |||||
621 | XFreeStringList (ptr->wm_command); | |||||
622 | ||||||
623 | if (ptr->wm_name) | |||||
624 | XFree (ptr->wm_name); | |||||
625 | ||||||
626 | if (ptr->wm_client_machine.value) | |||||
627 | XFree (ptr->wm_client_machine.value); | |||||
628 | ||||||
629 | if (ptr->class.res_name) | |||||
630 | XFree (ptr->class.res_name); | |||||
631 | ||||||
632 | if (ptr->class.res_class) | |||||
633 | XFree (ptr->class.res_class); | |||||
634 | ||||||
635 | free ((char *) ptr); | |||||
636 | } | |||||
637 | } | |||||
638 | ||||||
639 | ||||||
640 | ||||||
641 | static void | |||||
642 | Got_WM_STATE(WinInfo *winptr) | |||||
643 | { | |||||
644 | WinInfo *leader_winptr; | |||||
645 | ||||||
646 | /* | |||||
647 | * If we already got WM_STATE and tested for SM_CLIENT_ID, we | |||||
648 | * shouldn't do it again. | |||||
649 | */ | |||||
650 | ||||||
651 | if (winptr->tested_for_sm_client_id) | |||||
652 | { | |||||
653 | return; | |||||
654 | } | |||||
655 | ||||||
656 | ||||||
657 | /* | |||||
658 | * Set a null error handler, in case this window goes away | |||||
659 | * behind our back. | |||||
660 | */ | |||||
661 | ||||||
662 | caught_error = 0; | |||||
663 | XSetErrorHandler (MyErrorHandler); | |||||
664 | ||||||
665 | ||||||
666 | /* | |||||
667 | * Get the client leader window. | |||||
668 | */ | |||||
669 | ||||||
670 | leader_winptr = GetClientLeader (winptr); | |||||
671 | ||||||
672 | if (caught_error) | |||||
673 | { | |||||
674 | caught_error = 0; | |||||
675 | RemoveWindow (winptr); | |||||
676 | XSetErrorHandler (NULL((void*)0)); | |||||
677 | return; | |||||
678 | } | |||||
679 | ||||||
680 | ||||||
681 | /* | |||||
682 | * If we already checked for SM_CLIENT_ID on the client leader | |||||
683 | * window, don't do it again. | |||||
684 | */ | |||||
685 | ||||||
686 | if (!leader_winptr || leader_winptr->tested_for_sm_client_id) | |||||
687 | { | |||||
688 | caught_error = 0; | |||||
689 | XSetErrorHandler (NULL((void*)0)); | |||||
690 | return; | |||||
691 | } | |||||
692 | ||||||
693 | leader_winptr->tested_for_sm_client_id = 1; | |||||
694 | ||||||
695 | if (!HasXSMPsupport (leader_winptr->window)) | |||||
696 | { | |||||
697 | XFetchName (disp, leader_winptr->window, &leader_winptr->wm_name); | |||||
698 | ||||||
699 | XGetCommand (disp, leader_winptr->window, | |||||
700 | &leader_winptr->wm_command, | |||||
701 | &leader_winptr->wm_command_count); | |||||
702 | ||||||
703 | XGetClassHint (disp, leader_winptr->window, &leader_winptr->class); | |||||
704 | ||||||
705 | XGetWMClientMachine (disp, leader_winptr->window, | |||||
706 | &leader_winptr->wm_client_machine); | |||||
707 | ||||||
708 | if (leader_winptr->wm_name != NULL((void*)0) && | |||||
709 | leader_winptr->wm_command != NULL((void*)0) && | |||||
710 | leader_winptr->wm_command_count > 0 && | |||||
711 | leader_winptr->class.res_name != NULL((void*)0) && | |||||
712 | leader_winptr->class.res_class != NULL((void*)0) && | |||||
713 | leader_winptr->wm_client_machine.value != NULL((void*)0) && | |||||
714 | leader_winptr->wm_client_machine.nitems != 0) | |||||
715 | { | |||||
716 | leader_winptr->has_save_yourself = | |||||
717 | HasSaveYourself (leader_winptr->window); | |||||
718 | ||||||
719 | ConnectClientToSM (leader_winptr); | |||||
720 | } | |||||
721 | } | |||||
722 | ||||||
723 | XSync (disp, 0); | |||||
724 | XSetErrorHandler (NULL((void*)0)); | |||||
725 | ||||||
726 | if (caught_error) | |||||
727 | { | |||||
728 | caught_error = 0; | |||||
729 | RemoveWindow (leader_winptr); | |||||
730 | } | |||||
731 | } | |||||
732 | ||||||
733 | ||||||
734 | ||||||
735 | static void | |||||
736 | HandleCreate(XCreateWindowEvent *event) | |||||
737 | { | |||||
738 | Atom actual_type; | |||||
739 | int actual_format; | |||||
740 | unsigned long nitems, bytesafter; | |||||
741 | unsigned long *datap = NULL((void*)0); | |||||
742 | WinInfo *winptr; | |||||
743 | Boolint got_wm_state = 0; | |||||
744 | ||||||
745 | /* | |||||
746 | * We are waiting for all proxy connections to close so we can die. | |||||
747 | * Don't handle new connections. | |||||
748 | */ | |||||
749 | ||||||
750 | if (ok_to_die) | |||||
751 | return; | |||||
752 | ||||||
753 | ||||||
754 | /* | |||||
755 | * Add the new window | |||||
756 | */ | |||||
757 | ||||||
758 | if ((winptr = AddNewWindow (event->window)) == NULL((void*)0)) | |||||
759 | return; | |||||
760 | ||||||
761 | ||||||
762 | /* | |||||
763 | * Right after the window was created, it might have been destroyed, | |||||
764 | * so the following Xlib calls might fail. Need to catch the error | |||||
765 | * by installing an error handler. | |||||
766 | */ | |||||
767 | ||||||
768 | caught_error = 0; | |||||
769 | XSetErrorHandler (MyErrorHandler); | |||||
770 | ||||||
771 | ||||||
772 | /* | |||||
773 | * Select for Property Notify on the window so we can determine | |||||
774 | * when WM_STATE is defined. To avoid a race condition, we must | |||||
775 | * do this _before_ we check for WM_STATE right now. | |||||
776 | * | |||||
777 | * Select for Substructure Notify so we can determine when the | |||||
778 | * window is destroyed. | |||||
779 | */ | |||||
780 | ||||||
781 | XSelectInput (disp, event->window, | |||||
782 | SubstructureNotifyMask(1L<<19) | PropertyChangeMask(1L<<22)); | |||||
783 | ||||||
784 | ||||||
785 | /* | |||||
786 | * WM_STATE may already be there. Check now. | |||||
787 | */ | |||||
788 | ||||||
789 | if (XGetWindowProperty (disp, event->window, wmStateAtom, | |||||
790 | 0L, 2L, False0, AnyPropertyType0L, | |||||
791 | &actual_type, &actual_format, &nitems, &bytesafter, | |||||
792 | (unsigned char **) &datap) == Success0 && datap) | |||||
793 | { | |||||
794 | if (nitems > 0) | |||||
795 | got_wm_state = 1; | |||||
796 | ||||||
797 | if (datap) | |||||
798 | XFree ((char *) datap); | |||||
799 | } | |||||
800 | ||||||
801 | XSync (disp, 0); | |||||
802 | XSetErrorHandler (NULL((void*)0)); | |||||
803 | ||||||
804 | if (caught_error) | |||||
805 | { | |||||
806 | caught_error = 0; | |||||
807 | RemoveWindow (winptr); | |||||
808 | } | |||||
809 | else if (got_wm_state) | |||||
810 | { | |||||
811 | Got_WM_STATE (winptr); | |||||
812 | } | |||||
813 | } | |||||
814 | ||||||
815 | ||||||
816 | ||||||
817 | static void | |||||
818 | HandleDestroy(XDestroyWindowEvent *event) | |||||
819 | { | |||||
820 | WinInfo *winptr; | |||||
821 | ||||||
822 | if (LookupWindow (event->window, &winptr, NULL((void*)0))) | |||||
823 | { | |||||
824 | if (winptr->smc_conn) | |||||
825 | { | |||||
826 | SmcCloseConnection (winptr->smc_conn, 0, NULL((void*)0)); | |||||
827 | XtRemoveInput (winptr->input_id); | |||||
828 | proxy_count--; | |||||
829 | } | |||||
830 | ||||||
831 | if (debug) | |||||
832 | { | |||||
833 | printf ("Removed window (window = 0x%x)\n", | |||||
834 | (unsigned int)winptr->window); | |||||
835 | printf ("\n"); | |||||
836 | } | |||||
837 | ||||||
838 | RemoveWindow (winptr); | |||||
839 | } | |||||
840 | } | |||||
841 | ||||||
842 | ||||||
843 | ||||||
844 | static void | |||||
845 | HandleUpdate(XPropertyEvent *event) | |||||
846 | { | |||||
847 | Window window = event->window; | |||||
848 | WinInfo *winptr; | |||||
849 | ||||||
850 | if (!LookupWindow (window, &winptr, NULL((void*)0))) | |||||
851 | return; | |||||
852 | ||||||
853 | if (event->atom == wmStateAtom) | |||||
854 | { | |||||
855 | Got_WM_STATE (winptr); | |||||
856 | } | |||||
857 | else if (event->atom == XA_WM_COMMAND((Atom) 34) && winptr->waiting_for_update) | |||||
858 | { | |||||
859 | /* Finish off the Save Yourself */ | |||||
860 | ||||||
861 | if (winptr->wm_command) | |||||
862 | { | |||||
863 | XFreeStringList (winptr->wm_command); | |||||
864 | winptr->wm_command = NULL((void*)0); | |||||
865 | winptr->wm_command_count = 0; | |||||
866 | } | |||||
867 | ||||||
868 | XGetCommand (disp, window, | |||||
869 | &winptr->wm_command, | |||||
870 | &winptr->wm_command_count); | |||||
871 | ||||||
872 | winptr->waiting_for_update = 0; | |||||
873 | FinishSaveYourself (winptr, True1); | |||||
874 | } | |||||
875 | } | |||||
876 | ||||||
877 | ||||||
878 | ||||||
879 | static void | |||||
880 | ProxySaveYourselfPhase2CB(SmcConn smcConn, SmPointer clientData) | |||||
881 | { | |||||
882 | char *filename; | |||||
883 | Boolint success = True1; | |||||
884 | SmProp prop1, prop2, prop3, *props[3]; | |||||
885 | SmPropValue prop1val, prop2val, prop3val; | |||||
886 | char *discardCommand; | |||||
887 | int numVals, i; | |||||
888 | static int first_time = 1; | |||||
889 | ||||||
890 | if (first_time) | |||||
| ||||||
891 | { | |||||
892 | char userId[20]; | |||||
893 | char hint = SmRestartIfRunning0; | |||||
894 | ||||||
895 | prop1.name = SmProgram"Program"; | |||||
896 | prop1.type = SmARRAY8"ARRAY8"; | |||||
897 | prop1.num_vals = 1; | |||||
898 | prop1.vals = &prop1val; | |||||
899 | prop1val.value = Argv[0]; | |||||
900 | prop1val.length = strlen (Argv[0]); | |||||
901 | ||||||
902 | snprintf (userId, sizeof(userId), "%ld", (long)getuid())__builtin___snprintf_chk (userId, sizeof(userId), 0, __builtin_object_size (userId, 2 > 1 ? 1 : 0), "%ld", (long)getuid()); | |||||
903 | prop2.name = SmUserID"UserID"; | |||||
904 | prop2.type = SmARRAY8"ARRAY8"; | |||||
905 | prop2.num_vals = 1; | |||||
906 | prop2.vals = &prop2val; | |||||
907 | prop2val.value = (SmPointer) userId; | |||||
908 | prop2val.length = strlen (userId); | |||||
909 | ||||||
910 | prop3.name = SmRestartStyleHint"RestartStyleHint"; | |||||
911 | prop3.type = SmCARD8"CARD8"; | |||||
912 | prop3.num_vals = 1; | |||||
913 | prop3.vals = &prop3val; | |||||
914 | prop3val.value = (SmPointer) &hint; | |||||
915 | prop3val.length = 1; | |||||
916 | ||||||
917 | props[0] = &prop1; | |||||
918 | props[1] = &prop2; | |||||
919 | props[2] = &prop3; | |||||
920 | ||||||
921 | SmcSetProperties (smcConn, 3, props); | |||||
922 | ||||||
923 | first_time = 0; | |||||
924 | } | |||||
925 | ||||||
926 | if ((filename = WriteProxyFile ()) == NULL((void*)0)) | |||||
927 | { | |||||
928 | success = False0; | |||||
929 | goto finishUp; | |||||
930 | } | |||||
931 | ||||||
932 | prop1.name = SmRestartCommand"RestartCommand"; | |||||
933 | prop1.type = SmLISTofARRAY8"LISTofARRAY8"; | |||||
934 | ||||||
935 | prop1.vals = (SmPropValue *) malloc ( | |||||
936 | (Argc + 4) * sizeof (SmPropValue)); | |||||
937 | ||||||
938 | if (!prop1.vals) | |||||
939 | { | |||||
940 | success = False0; | |||||
941 | goto finishUp; | |||||
942 | } | |||||
943 | ||||||
944 | numVals = 0; | |||||
945 | ||||||
946 | for (i = 0; i < Argc; i++) | |||||
947 | { | |||||
948 | if (strcmp (Argv[i], "-clientId") == 0 || | |||||
949 | strcmp (Argv[i], "-restore") == 0) | |||||
950 | { | |||||
951 | i++; | |||||
952 | } | |||||
953 | else | |||||
954 | { | |||||
955 | prop1.vals[numVals].value = (SmPointer) Argv[i]; | |||||
956 | prop1.vals[numVals++].length = strlen (Argv[i]); | |||||
957 | } | |||||
958 | } | |||||
959 | ||||||
960 | prop1.vals[numVals].value = (SmPointer) "-clientId"; | |||||
961 | prop1.vals[numVals++].length = 9; | |||||
962 | ||||||
963 | prop1.vals[numVals].value = (SmPointer) proxy_clientId; | |||||
964 | prop1.vals[numVals++].length = strlen (proxy_clientId); | |||||
965 | ||||||
966 | prop1.vals[numVals].value = (SmPointer) "-restore"; | |||||
967 | prop1.vals[numVals++].length = 8; | |||||
968 | ||||||
969 | prop1.vals[numVals].value = (SmPointer) filename; | |||||
970 | prop1.vals[numVals++].length = strlen (filename); | |||||
971 | ||||||
972 | prop1.num_vals = numVals; | |||||
973 | ||||||
974 | ||||||
975 | if (asprintf (&discardCommand, "rm %s", filename) == -1) { | |||||
976 | success = False0; | |||||
| ||||||
977 | goto finishUp; | |||||
978 | } | |||||
979 | prop2.name = SmDiscardCommand"DiscardCommand"; | |||||
980 | prop2.type = SmARRAY8"ARRAY8"; | |||||
981 | prop2.num_vals = 1; | |||||
982 | prop2.vals = &prop2val; | |||||
983 | prop2val.value = (SmPointer) discardCommand; | |||||
984 | prop2val.length = strlen (discardCommand); | |||||
985 | ||||||
986 | props[0] = &prop1; | |||||
987 | props[1] = &prop2; | |||||
988 | ||||||
989 | SmcSetProperties (smcConn, 2, props); | |||||
990 | free ((char *) prop1.vals); | |||||
991 | free (discardCommand); | |||||
992 | ||||||
993 | finishUp: | |||||
994 | ||||||
995 | SmcSaveYourselfDone (smcConn, success); | |||||
996 | sent_save_done = 1; | |||||
997 | ||||||
998 | if (filename) | |||||
999 | free (filename); | |||||
1000 | } | |||||
1001 | ||||||
1002 | ||||||
1003 | ||||||
1004 | static void | |||||
1005 | ProxySaveYourselfCB(SmcConn smcConn, SmPointer clientData, int saveType, | |||||
1006 | Boolint shutdown, int interactStyle, Boolint fast) | |||||
1007 | { | |||||
1008 | /* | |||||
1009 | * We want the proxy to respond to the Save Yourself after all | |||||
1010 | * the regular XSMP clients have finished with the save (and possibly | |||||
1011 | * interacted with the user). | |||||
1012 | */ | |||||
1013 | ||||||
1014 | if (!SmcRequestSaveYourselfPhase2 (smcConn, | |||||
1015 | ProxySaveYourselfPhase2CB, NULL((void*)0))) | |||||
1016 | { | |||||
1017 | SmcSaveYourselfDone (smcConn, False0); | |||||
1018 | sent_save_done = 1; | |||||
1019 | } | |||||
1020 | else | |||||
1021 | sent_save_done = 0; | |||||
1022 | } | |||||
1023 | ||||||
1024 | ||||||
1025 | ||||||
1026 | static void | |||||
1027 | ProxyDieCB(SmcConn smcConn, SmPointer clientData) | |||||
1028 | { | |||||
1029 | SmcCloseConnection (proxy_smcConn, 0, NULL((void*)0)); | |||||
1030 | XtRemoveInput (proxy_iceInputId); | |||||
1031 | ||||||
1032 | if (die_count == proxy_count) | |||||
1033 | exit (0); | |||||
1034 | else | |||||
1035 | ok_to_die = 1; | |||||
1036 | } | |||||
1037 | ||||||
1038 | ||||||
1039 | ||||||
1040 | static void | |||||
1041 | ProxySaveCompleteCB(SmcConn smcConn, SmPointer clientData) | |||||
1042 | { | |||||
1043 | ; | |||||
1044 | } | |||||
1045 | ||||||
1046 | ||||||
1047 | ||||||
1048 | static void | |||||
1049 | ProxyShutdownCancelledCB(SmcConn smcConn, SmPointer clientData) | |||||
1050 | { | |||||
1051 | if (!sent_save_done) | |||||
1052 | { | |||||
1053 | SmcSaveYourselfDone (smcConn, False0); | |||||
1054 | sent_save_done = 1; | |||||
1055 | } | |||||
1056 | } | |||||
1057 | ||||||
1058 | ||||||
1059 | ||||||
1060 | static Statusint | |||||
1061 | ConnectProxyToSM(char *previous_id) | |||||
1062 | { | |||||
1063 | char errorMsg[256]; | |||||
1064 | unsigned long mask; | |||||
1065 | SmcCallbacks callbacks; | |||||
1066 | IceConn iceConn; | |||||
1067 | ||||||
1068 | mask = SmcSaveYourselfProcMask(1L << 0) | SmcDieProcMask(1L << 1) | | |||||
1069 | SmcSaveCompleteProcMask(1L << 2) | SmcShutdownCancelledProcMask(1L << 3); | |||||
1070 | ||||||
1071 | callbacks.save_yourself.callback = ProxySaveYourselfCB; | |||||
1072 | callbacks.save_yourself.client_data = (SmPointer) NULL((void*)0); | |||||
1073 | ||||||
1074 | callbacks.die.callback = ProxyDieCB; | |||||
1075 | callbacks.die.client_data = (SmPointer) NULL((void*)0); | |||||
1076 | ||||||
1077 | callbacks.save_complete.callback = ProxySaveCompleteCB; | |||||
1078 | callbacks.save_complete.client_data = (SmPointer) NULL((void*)0); | |||||
1079 | ||||||
1080 | callbacks.shutdown_cancelled.callback = ProxyShutdownCancelledCB; | |||||
1081 | callbacks.shutdown_cancelled.client_data = (SmPointer) NULL((void*)0); | |||||
1082 | ||||||
1083 | proxy_smcConn = SmcOpenConnection ( | |||||
1084 | NULL((void*)0), /* use SESSION_MANAGER env */ | |||||
1085 | (SmPointer) appContext, | |||||
1086 | SmProtoMajor1, | |||||
1087 | SmProtoMinor0, | |||||
1088 | mask, | |||||
1089 | &callbacks, | |||||
1090 | previous_id, | |||||
1091 | &proxy_clientId, | |||||
1092 | 256, errorMsg); | |||||
1093 | ||||||
1094 | if (proxy_smcConn == NULL((void*)0)) | |||||
1095 | return (0); | |||||
1096 | ||||||
1097 | iceConn = SmcGetIceConnection (proxy_smcConn); | |||||
1098 | ||||||
1099 | proxy_iceInputId = XtAppAddInput ( | |||||
1100 | appContext, | |||||
1101 | IceConnectionNumber (iceConn), | |||||
1102 | (XtPointer) XtInputReadMask(1L<<0), | |||||
1103 | ProcessIceMsgProc, | |||||
1104 | (XtPointer) iceConn); | |||||
1105 | ||||||
1106 | return (1); | |||||
1107 | } | |||||
1108 | ||||||
1109 | ||||||
1110 | ||||||
1111 | static void | |||||
1112 | CheckForExistingWindows(Window root) | |||||
1113 | { | |||||
1114 | Window dontCare1, dontCare2, *children, client_window; | |||||
1115 | unsigned int nchildren, i; | |||||
1116 | XCreateWindowEvent event; | |||||
1117 | ||||||
1118 | /* | |||||
1119 | * We query the root tree for all windows created thus far. | |||||
1120 | * Note that at any moment after XQueryTree is called, a | |||||
1121 | * window may be deleted. So we must take extra care to make | |||||
1122 | * sure a window really exists. | |||||
1123 | */ | |||||
1124 | ||||||
1125 | XQueryTree (disp, root, &dontCare1, &dontCare2, &children, &nchildren); | |||||
1126 | ||||||
1127 | for (i = 0; i < nchildren; i++) | |||||
1128 | { | |||||
1129 | event.window = children[i]; | |||||
1130 | ||||||
1131 | HandleCreate (&event); | |||||
1132 | ||||||
1133 | caught_error = 0; | |||||
1134 | XSetErrorHandler (MyErrorHandler); | |||||
1135 | ||||||
1136 | client_window = XmuClientWindow (disp, children[i]); | |||||
1137 | ||||||
1138 | XSetErrorHandler (NULL((void*)0)); | |||||
1139 | ||||||
1140 | if (!caught_error && client_window != children[i]) | |||||
1141 | { | |||||
1142 | event.window = client_window; | |||||
1143 | HandleCreate (&event); | |||||
1144 | } | |||||
1145 | } | |||||
1146 | } | |||||
1147 | ||||||
1148 | ||||||
1149 | ||||||
1150 | int | |||||
1151 | main (int argc, char *argv[]) | |||||
1152 | { | |||||
1153 | char *restore_filename = NULL((void*)0); | |||||
1154 | char *client_id = NULL((void*)0); | |||||
1155 | int i, zero = 0; | |||||
1156 | ||||||
1157 | Argc = argc; | |||||
1158 | Argv = argv; | |||||
1159 | ||||||
1160 | for (i = 1; i < argc; i++) | |||||
1161 | { | |||||
1162 | if (argv[i][0] == '-') | |||||
1163 | { | |||||
1164 | switch (argv[i][1]) | |||||
1165 | { | |||||
1166 | case 'd': /* -debug */ | |||||
1167 | debug = 1; | |||||
1168 | continue; | |||||
1169 | ||||||
1170 | case 'c': /* -clientId */ | |||||
1171 | if (++i >= argc) { | |||||
1172 | fprintf (stderr__stderrp, "%s: -clientId requires an argument\n", | |||||
1173 | argv[0]); | |||||
1174 | goto usage; | |||||
1175 | } | |||||
1176 | client_id = argv[i]; | |||||
1177 | continue; | |||||
1178 | ||||||
1179 | case 'r': /* -restore */ | |||||
1180 | if (++i >= argc) { | |||||
1181 | fprintf (stderr__stderrp, "%s: -restore requires an argument\n", | |||||
1182 | argv[0]); | |||||
1183 | goto usage; | |||||
1184 | } | |||||
1185 | restore_filename = argv[i]; | |||||
1186 | continue; | |||||
1187 | ||||||
1188 | case 'v': | |||||
1189 | puts (PACKAGE_STRING"smproxy 1.0.6"); | |||||
1190 | exit (0); | |||||
1191 | } | |||||
1192 | } | |||||
1193 | ||||||
1194 | fprintf (stderr__stderrp, "%s: unrecognized argument: %s\n", argv[0], argv[i]); | |||||
1195 | ||||||
1196 | usage: | |||||
1197 | ||||||
1198 | fprintf (stderr__stderrp, | |||||
1199 | "usage: %s [-clientId id] [-restore file] [-debug] [-version]\n", | |||||
1200 | argv[0]); | |||||
1201 | exit (1); | |||||
1202 | } | |||||
1203 | ||||||
1204 | ||||||
1205 | XtToolkitInitialize (); | |||||
1206 | appContext = XtCreateApplicationContext (); | |||||
1207 | ||||||
1208 | if (!(disp = XtOpenDisplay (appContext, NULL((void*)0), "SM-PROXY", "SM-PROXY", | |||||
1209 | NULL((void*)0), 0, &zero, NULL((void*)0)))) | |||||
1210 | { | |||||
1211 | fprintf (stderr__stderrp, "smproxy: unable to open display\n"); | |||||
1212 | exit (1); | |||||
1213 | } | |||||
1214 | ||||||
1215 | if (restore_filename) | |||||
1216 | ReadProxyFile (restore_filename); | |||||
1217 | ||||||
1218 | if (!ConnectProxyToSM (client_id)) | |||||
1219 | { | |||||
1220 | fprintf (stderr__stderrp, "smproxy: unable to connect to session manager\n"); | |||||
1221 | exit (1); | |||||
1222 | } | |||||
1223 | ||||||
1224 | wmProtocolsAtom = XInternAtom (disp, "WM_PROTOCOLS", False0); | |||||
1225 | wmSaveYourselfAtom = XInternAtom (disp, "WM_SAVE_YOURSELF", False0); | |||||
1226 | wmStateAtom = XInternAtom (disp, "WM_STATE", False0); | |||||
1227 | smClientIdAtom = XInternAtom (disp, "SM_CLIENT_ID", False0); | |||||
1228 | wmClientLeaderAtom = XInternAtom (disp, "WM_CLIENT_LEADER", False0); | |||||
1229 | ||||||
1230 | for (i = 0; i < ScreenCount (disp)(((_XPrivDisplay)(disp))->nscreens); i++) | |||||
1231 | { | |||||
1232 | Window root = RootWindow (disp, i)((&((_XPrivDisplay)(disp))->screens[i])->root); | |||||
1233 | XSelectInput (disp, root, SubstructureNotifyMask(1L<<19) | PropertyChangeMask(1L<<22)); | |||||
1234 | CheckForExistingWindows (root); | |||||
1235 | } | |||||
1236 | ||||||
1237 | while (1) | |||||
1238 | { | |||||
1239 | XEvent event; | |||||
1240 | ||||||
1241 | XtAppNextEvent (appContext, &event); | |||||
1242 | ||||||
1243 | switch (event.type) | |||||
1244 | { | |||||
1245 | case CreateNotify16: | |||||
1246 | HandleCreate (&event.xcreatewindow); | |||||
1247 | break; | |||||
1248 | ||||||
1249 | case DestroyNotify17: | |||||
1250 | HandleDestroy (&event.xdestroywindow); | |||||
1251 | break; | |||||
1252 | ||||||
1253 | case PropertyNotify28: | |||||
1254 | HandleUpdate (&event.xproperty); | |||||
1255 | break; | |||||
1256 | ||||||
1257 | default: | |||||
1258 | XtDispatchEvent (&event); | |||||
1259 | break; | |||||
1260 | } | |||||
1261 | } | |||||
1262 | exit(0); | |||||
1263 | } |