1 /*
2    Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3    All rights reserved.
4 
5 This file is part of x11vnc.
6 
7 x11vnc is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at
10 your option) any later version.
11 
12 x11vnc is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with x11vnc; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20 or see <http://www.gnu.org/licenses/>.
21 
22 In addition, as a special exception, Karl J. Runge
23 gives permission to link the code of its release of x11vnc with the
24 OpenSSL project's "OpenSSL" library (or with modified versions of it
25 that use the same license as the "OpenSSL" library), and distribute
26 the linked executables.  You must obey the GNU General Public License
27 in all respects for all of the code used other than "OpenSSL".  If you
28 modify this file, you may extend this exception to your version of the
29 file, but you are not obligated to do so.  If you do not wish to do
30 so, delete this exception statement from your version.
31 */
32 
33 /* -- solid.c -- */
34 
35 #include "x11vnc.h"
36 #include "win_utils.h"
37 #include "xwrappers.h"
38 #include "connections.h"
39 #include "cleanup.h"
40 #include "xevents.h"
41 
42 char *guess_desktop(void);
43 void solid_bg(int restore);
44 char *dbus_session(void);
45 
46 
47 static void usr_bin_path(int restore);
48 static int dt_cmd(char *cmd);
49 static char *cmd_output(char *cmd);
50 XImage *solid_root(char *color);
51 static void solid_cde(char *color);
52 static void solid_gnome(char *color);
53 static void solid_kde(char *color);
54 static void solid_macosx(int restore);
55 
usr_bin_path(int restore)56 static void usr_bin_path(int restore) {
57 	static char *oldpath = NULL;
58 	char *newpath;
59 	char addpath[] = "/usr/bin:/bin:";
60 
61 	if (restore) {
62 		if (oldpath) {
63 			set_env("PATH", oldpath);
64 			free(oldpath);
65 			oldpath = NULL;
66 		}
67 		return;
68 	}
69 
70 	if (getenv("PATH")) {
71 		oldpath = strdup(getenv("PATH"));
72 	} else {
73 		oldpath = strdup("/usr/bin");
74 	}
75 	newpath = (char *) malloc(strlen(oldpath) + strlen(addpath) + 1);
76 	newpath[0] = '\0';
77 	strcat(newpath, addpath);
78 	strcat(newpath, oldpath);
79 	set_env("PATH", newpath);
80 	free(newpath);
81 }
82 
dt_cmd(char * cmd)83 static int dt_cmd(char *cmd) {
84 	int rc;
85 
86 	RAWFB_RET(0)
87 
88 	if (!cmd || *cmd == '\0') {
89 		return 0;
90 	}
91 
92 	/* dt */
93 	if (no_external_cmds || !cmd_ok("dt")) {
94 		rfbLog("cannot run external commands in -nocmds mode:\n");
95 		rfbLog("   \"%s\"\n", cmd);
96 		rfbLog("   dt_cmd: returning 1\n");
97 		return 1;
98 	}
99 
100 	if (getenv("DISPLAY") == NULL) {
101 		set_env("DISPLAY", DisplayString(dpy));
102 	}
103 
104 	rfbLog("running command:\n");
105 	if (!quiet) {
106 		fprintf(stderr, "\n  %s\n\n", cmd);
107 	}
108 	usr_bin_path(0);
109 	close_exec_fds();
110 	rc = system(cmd);
111 	usr_bin_path(1);
112 
113 	if (rc >= 256) {
114 		rc = rc/256;
115 	}
116 	return rc;
117 }
118 
cmd_output(char * cmd)119 static char *cmd_output(char *cmd) {
120 	FILE *p;
121 	static char output[50000];
122 	char line[1024];
123 	int rc;
124 
125 	if (!cmd || *cmd == '\0') {
126 		return "";
127 	}
128 
129 	if (no_external_cmds) {
130 		rfbLog("cannot run external commands in -nocmds mode:\n");
131 		rfbLog("   \"%s\"\n", cmd);
132 		rfbLog("   cmd_output: null string.\n");
133 		return "";
134 	}
135 
136 	rfbLog("running pipe:\n");
137 	if (!quiet) {
138 		fprintf(stderr, "\n  %s\n\n", cmd);
139 	}
140 	usr_bin_path(0);
141 	close_exec_fds();
142 	p = popen(cmd, "r");
143 	usr_bin_path(1);
144 
145 	output[0] = '\0';
146 
147 	while (fgets(line, 1024, p) != NULL) {
148 		if (strlen(output) + strlen(line) + 1 < 50000) {
149 			strcat(output, line);
150 		}
151 	}
152 	rc = pclose(p);
153 	return(output);
154 }
155 
156 static char *last_color = NULL;
157 
get_pixel(char * color)158 unsigned long get_pixel(char *color) {
159 #if NO_X11
160 	return 0;
161 #else
162 	XColor cdef;
163 	Colormap cmap;
164 	unsigned long pixel = BlackPixel(dpy, scr);
165 	if (depth > 8 || strcmp(color, solid_default)) {
166 		cmap = DefaultColormap (dpy, scr);
167 		if (XParseColor(dpy, cmap, color, &cdef) &&
168 		    XAllocColor(dpy, cmap, &cdef)) {
169 			pixel = cdef.pixel;
170 		} else {
171 			rfbLog("error parsing/allocing color: %s\n", color);
172 		}
173 	}
174 	return pixel;
175 #endif
176 }
177 
solid_root(char * color)178 XImage *solid_root(char *color) {
179 #if NO_X11
180 	RAWFB_RET_VOID
181 	if (!color) {}
182 	return NULL;
183 #else
184 	Window expose;
185 	static XImage *image = NULL;
186 	Pixmap pixmap;
187 	XGCValues gcv;
188 	GC gc;
189 	XSetWindowAttributes swa;
190 	Visual visual;
191 	static unsigned long mask, pixel = 0;
192 
193 	RAWFB_RET(NULL)
194 
195 	if (subwin || window != rootwin) {
196 		rfbLog("cannot set subwin to solid color, must be rootwin\n");
197 		return NULL;
198 	}
199 
200 	/* create the "clear" window just for generating exposures */
201 	swa.override_redirect = True;
202 	swa.backing_store = NotUseful;
203 	swa.save_under = False;
204 	swa.background_pixmap = None;
205 	visual.visualid = CopyFromParent;
206 	mask = (CWOverrideRedirect|CWBackingStore|CWSaveUnder|CWBackPixmap);
207 	expose = XCreateWindow(dpy, window, 0, 0, wdpy_x, wdpy_y, 0, depth,
208 	    InputOutput, &visual, mask, &swa);
209 
210 	if (! color) {
211 
212 		if (! image) {
213 			/* whoops */
214 			XDestroyWindow(dpy, expose);
215 			rfbLog("no root snapshot available.\n");
216 			return NULL;
217 		}
218 
219 		/* restore the root window from the XImage snapshot */
220 		pixmap = XCreatePixmap(dpy, window, wdpy_x, wdpy_y, depth);
221 
222 		/* draw the image to a pixmap: */
223 		gcv.function = GXcopy;
224 		gcv.plane_mask = AllPlanes;
225 		gc = XCreateGC(dpy, window, GCFunction|GCPlaneMask, &gcv);
226 
227 		XPutImage(dpy, pixmap, gc, image, 0, 0, 0, 0, wdpy_x, wdpy_y);
228 
229 		gcv.foreground = gcv.background = BlackPixel(dpy, scr);
230 		gc = XCreateGC(dpy, window, GCForeground|GCBackground, &gcv);
231 
232 		rfbLog("restoring root snapshot...\n");
233 		/* set the pixmap as the bg: */
234 		XSetWindowBackgroundPixmap(dpy, window, pixmap);
235 		XFreePixmap(dpy, pixmap);
236 		XClearWindow(dpy, window);
237 		XFlush_wr(dpy);
238 
239 		/* generate exposures */
240 		XMapWindow(dpy, expose);
241 		XSync(dpy, False);
242 		XDestroyWindow(dpy, expose);
243 		return NULL;
244 	}
245 
246 	if (! image) {
247 		/* need to retrieve a snapshot of the root background: */
248 		Window iwin;
249 		XSetWindowAttributes iswa;
250 
251 		/* create image window: */
252 		iswa.override_redirect = True;
253 		iswa.backing_store = NotUseful;
254 		iswa.save_under = False;
255 		iswa.background_pixmap = ParentRelative;
256 
257 		iwin = XCreateWindow(dpy, window, 0, 0, wdpy_x, wdpy_y, 0,
258 		    depth, InputOutput, &visual, mask, &iswa);
259 
260 		rfbLog("snapshotting background...\n");
261 
262 		XMapWindow(dpy, iwin);
263 		XSync(dpy, False);
264 		image = XGetImage(dpy, iwin, 0, 0, wdpy_x, wdpy_y, AllPlanes,
265 		    ZPixmap);
266 		XSync(dpy, False);
267 		XDestroyWindow(dpy, iwin);
268 		rfbLog("done.\n");
269 	}
270 	if (color == (char *) 0x1) {
271 		/* caller will XDestroyImage it: */
272 		XImage *xi = image;
273 		image = NULL;
274 		return xi;
275 	}
276 
277 	/* use black for low colors or failure */
278 	pixel = get_pixel(color);
279 
280 	rfbLog("setting solid background...\n");
281 	XSetWindowBackground(dpy, window, pixel);
282 	XMapWindow(dpy, expose);
283 	XSync(dpy, False);
284 	XDestroyWindow(dpy, expose);
285 #endif	/* NO_X11 */
286 	return NULL;
287 }
288 
solid_cde(char * color)289 static void solid_cde(char *color) {
290 #if NO_X11
291 	RAWFB_RET_VOID
292 	if (!color) {}
293 	return;
294 #else
295 	int wsmax = 16;
296 	static XImage *image[16];
297 	static Window ws_wins[16];
298 	static int nws = -1;
299 
300 	Window expose;
301 	Pixmap pixmap;
302 	XGCValues gcv;
303 	GC gc;
304 	XSetWindowAttributes swa;
305 	Visual visual;
306 	unsigned long mask, pixel;
307 	XColor cdef;
308 	Colormap cmap;
309 	int n;
310 
311 	RAWFB_RET_VOID
312 
313 	if (subwin || window != rootwin) {
314 		rfbLog("cannot set subwin to solid color, must be rootwin\n");
315 		return;
316 	}
317 
318 	/* create the "clear" window just for generating exposures */
319 	swa.override_redirect = True;
320 	swa.backing_store = NotUseful;
321 	swa.save_under = False;
322 	swa.background_pixmap = None;
323 	visual.visualid = CopyFromParent;
324 	mask = (CWOverrideRedirect|CWBackingStore|CWSaveUnder|CWBackPixmap);
325 	expose = XCreateWindow(dpy, window, 0, 0, wdpy_x, wdpy_y, 0, depth,
326 	    InputOutput, &visual, mask, &swa);
327 
328 	if (! color) {
329 		/* restore the backdrop windows from the XImage snapshots */
330 
331 		for (n=0; n < nws; n++) {
332 			Window twin;
333 
334 			if (! image[n]) {
335 				continue;
336 			}
337 
338 			twin = ws_wins[n];
339 			if (! twin) {
340 				twin = rootwin;
341 			}
342 			if (! valid_window(twin, NULL, 0)) {
343 				continue;
344 			}
345 
346 			pixmap = XCreatePixmap(dpy, twin, wdpy_x, wdpy_y,
347 			    depth);
348 
349 			/* draw the image to a pixmap: */
350 			gcv.function = GXcopy;
351 			gcv.plane_mask = AllPlanes;
352 			gc = XCreateGC(dpy, twin, GCFunction|GCPlaneMask, &gcv);
353 
354 			XPutImage(dpy, pixmap, gc, image[n], 0, 0, 0, 0,
355 			    wdpy_x, wdpy_y);
356 
357 			gcv.foreground = gcv.background = BlackPixel(dpy, scr);
358 			gc = XCreateGC(dpy, twin, GCForeground|GCBackground,
359 			    &gcv);
360 
361 			rfbLog("restoring CDE ws%d snapshot to 0x%lx\n",
362 			    n, twin);
363 			/* set the pixmap as the bg: */
364 			XSetWindowBackgroundPixmap(dpy, twin, pixmap);
365 			XFreePixmap(dpy, pixmap);
366 			XClearWindow(dpy, twin);
367 			XFlush_wr(dpy);
368 		}
369 
370 		/* generate exposures */
371 		XMapWindow(dpy, expose);
372 		XSync(dpy, False);
373 		XDestroyWindow(dpy, expose);
374 		return;
375 	}
376 
377 	if (nws < 0) {
378 		/* need to retrieve snapshots of the ws backgrounds: */
379 		Window iwin, wm_win;
380 		XSetWindowAttributes iswa;
381 		Atom dt_list, wm_info, type;
382 		int format;
383 		unsigned long length, after;
384 		unsigned char *data;
385 		unsigned long *dp;	/* crash on 64bit with int */
386 
387 		nws = 0;
388 
389 		/* extract the hidden wm properties about backdrops: */
390 
391 		wm_info = XInternAtom(dpy, "_MOTIF_WM_INFO", True);
392 		if (wm_info == None) {
393 			return;
394 		}
395 
396 		XGetWindowProperty(dpy, rootwin, wm_info, 0L, 10L, False,
397 		    AnyPropertyType, &type, &format, &length, &after, &data);
398 
399 		/*
400 		 * xprop -notype -root _MOTIF_WM_INFO
401 		 * _MOTIF_WM_INFO = 0x2, 0x580028
402 		 */
403 
404 		if (length < 2 || format != 32 || after != 0) {
405 			return;
406 		}
407 
408 		dp = (unsigned long *) data;
409 		wm_win = (Window) *(dp+1);	/* 2nd item. */
410 
411 
412 		dt_list = XInternAtom(dpy, "_DT_WORKSPACE_LIST", True);
413 		if (dt_list == None) {
414 			return;
415 		}
416 
417 		XGetWindowProperty(dpy, wm_win, dt_list, 0L, 10L, False,
418 		   AnyPropertyType, &type, &format, &length, &after, &data);
419 
420 		nws = length;
421 
422 		if (nws > wsmax) {
423 			nws = wsmax;
424 		}
425 		if (nws < 0) {
426 			nws = 0;
427 		}
428 
429 		rfbLog("special CDE win: 0x%lx, %d workspaces\n", wm_win, nws);
430 		if (nws == 0) {
431 			return;
432 		}
433 
434 		for (n=0; n<nws; n++) {
435 			Atom ws_atom;
436 			char tmp[32];
437 			Window twin;
438 			XWindowAttributes attr;
439 			int i, cnt;
440 
441 			image[n] = NULL;
442 			ws_wins[n] = 0x0;
443 
444 			sprintf(tmp, "_DT_WORKSPACE_INFO_ws%d", n);
445 			ws_atom = XInternAtom(dpy, tmp, False);
446 			if (ws_atom == None) {
447 				continue;
448 			}
449 			XGetWindowProperty(dpy, wm_win, ws_atom, 0L, 100L,
450 			   False, AnyPropertyType, &type, &format, &length,
451 			   &after, &data);
452 
453 			if (format != 8 || after != 0) {
454 				continue;
455 			}
456 			/*
457 			 * xprop -notype -id wm_win
458 			 * _DT_WORKSPACE_INFO_ws0 = "One", "3", "0x2f2f4a",
459 			 * "0x63639c", "0x103", "1", "0x58044e"
460 			 */
461 
462 			cnt = 0;
463 			twin = 0x0;
464 			for (i=0; i< (int) length; i++) {
465 				if (*(data+i) != '\0') {
466 					continue;
467 				}
468 				cnt++;	/* count nulls to indicate field */
469 				if (cnt == 6) {
470 					/* one past the null: */
471 					char *q = (char *) (data+i+1);
472 					unsigned long in;
473 					if (sscanf(q, "0x%lx", &in) == 1) {
474 						twin = (Window) in;
475 						break;
476 					}
477 				}
478 			}
479 			ws_wins[n] = twin;
480 
481 			if (! twin) {
482 				twin = rootwin;
483 			}
484 
485 			XGetWindowAttributes(dpy, twin, &attr);
486 			if (twin != rootwin) {
487 				if (attr.map_state != IsViewable) {
488 					XMapWindow(dpy, twin);
489 				}
490 				XRaiseWindow(dpy, twin);
491 			}
492 			XSync(dpy, False);
493 
494 			/* create image window: */
495 			iswa.override_redirect = True;
496 			iswa.backing_store = NotUseful;
497 			iswa.save_under = False;
498 			iswa.background_pixmap = ParentRelative;
499 			visual.visualid = CopyFromParent;
500 
501 			iwin = XCreateWindow(dpy, twin, 0, 0, wdpy_x, wdpy_y,
502 			    0, depth, InputOutput, &visual, mask, &iswa);
503 
504 			rfbLog("snapshotting CDE backdrop ws%d 0x%lx -> "
505 			    "0x%lx ...\n", n, twin, iwin);
506 			XMapWindow(dpy, iwin);
507 			XSync(dpy, False);
508 
509 			image[n] = XGetImage(dpy, iwin, 0, 0, wdpy_x, wdpy_y,
510 			    AllPlanes, ZPixmap);
511 			XSync(dpy, False);
512 			XDestroyWindow(dpy, iwin);
513 			if (twin != rootwin) {
514 				XLowerWindow(dpy, twin);
515 				if (attr.map_state != IsViewable) {
516 					XUnmapWindow(dpy, twin);
517 				}
518 			}
519 		}
520 	}
521 	if (nws == 0) {
522 		return;
523 	}
524 
525 	/* use black for low colors or failure */
526 	pixel = BlackPixel(dpy, scr);
527 	if (depth > 8 || strcmp(color, solid_default)) {
528 		cmap = DefaultColormap (dpy, scr);
529 		if (XParseColor(dpy, cmap, color, &cdef) &&
530 		    XAllocColor(dpy, cmap, &cdef)) {
531 			pixel = cdef.pixel;
532 		} else {
533 			rfbLog("error parsing/allocing color: %s\n", color);
534 		}
535 	}
536 
537 	rfbLog("setting solid backgrounds...\n");
538 
539 	for (n=0; n < nws; n++)  {
540 		Window twin = ws_wins[n];
541 		if (image[n] == NULL) {
542 			continue;
543 		}
544 		if (! twin)  {
545 			twin = rootwin;
546 		}
547 		XSetWindowBackground(dpy, twin, pixel);
548 	}
549 	XMapWindow(dpy, expose);
550 	XSync(dpy, False);
551 	XDestroyWindow(dpy, expose);
552 #endif	/* NO_X11 */
553 }
554 
555 static char _dbus_str[1100];
556 
dbus_session(void)557 char *dbus_session(void) {
558 	char *dbus_env = getenv("DBUS_SESSION_BUS_ADDRESS");
559 	char tmp[1000];
560 
561 	if (dbus_env != NULL && strlen(dbus_env) > 0) {
562 		return "";
563 	}
564 	if (!dpy) {
565 		return "";
566 	}
567 #if NO_X11
568 	return "";
569 #else
570 	{
571 		Atom dbus_prop, dbus_pid;
572 		Window r, w, *children;
573 		int sbest = -1;
574 		unsigned int ui;
575 		int rc, i;
576 
577 		memset(_dbus_str, 0, sizeof(_dbus_str));
578 
579 		X_LOCK;
580 		dbus_prop = XInternAtom(dpy, "_DBUS_SESSION_BUS_ADDRESS", True);
581 		dbus_pid  = XInternAtom(dpy, "_DBUS_SESSION_BUS_PID", True);
582 		X_UNLOCK;
583 		if (dbus_prop == None) {
584 			return "";
585 		}
586 
587 		X_LOCK;
588 		memset(tmp, 0, sizeof(tmp));
589 		get_prop(tmp, sizeof(tmp)-1, dbus_prop, None);
590 		X_UNLOCK;
591 		if (strcmp(tmp, "")) {
592 			if (!strchr(tmp, '\'')) {
593 				sprintf(_dbus_str, "env DBUS_SESSION_BUS_ADDRESS='%s'", tmp);
594 				return _dbus_str;
595 			}
596 		}
597 
598 		X_LOCK;
599 		rc = XQueryTree_wr(dpy, rootwin, &r, &w, &children, &ui);
600 		X_UNLOCK;
601 		if (!rc || children == NULL || ui == 0) {
602 			return "";
603 		}
604 		for (i=0; i < (int) ui; i++) {
605 			int pid = -1;
606 
607 			X_LOCK;
608 			memset(tmp, 0, sizeof(tmp));
609 			get_prop(tmp, sizeof(tmp)-1, dbus_prop, children[i]);
610 			if (dbus_pid != None) {
611 				Atom atype;
612 				int aformat;
613 				unsigned long nitems, bafter;
614 				unsigned char *prop;
615 				if (XGetWindowProperty(dpy, children[i], dbus_pid,
616 				    0, 1, False, XA_CARDINAL, &atype, &aformat,
617 				    &nitems, &bafter, &prop) == Success
618 				    && atype == XA_CARDINAL) {
619 					pid = *((int *) prop);
620 					XFree_wr(prop);
621 				}
622 			}
623 			X_UNLOCK;
624 
625 			if (strcmp(tmp, "")  && !strchr(tmp, '\'')) {
626 				int score = 0;
627 				if (1 < pid && pid < 10000000) {
628 					struct stat sb;
629 					char procfile[32];
630 
631 					sprintf(procfile, "/proc/%d", pid);
632 					if (stat(procfile, &sb) == 0) {
633 						score += 10000000;
634 					}
635 					score += pid;
636 				}
637 				if (getenv("X11VNC_DBUS_DEBUG")) fprintf(stderr, "win: 0x%lx  pid: %8d  score: %8d  str: %s\n", children[i], pid, score, tmp);
638 				if (score > sbest) {
639 					sprintf(_dbus_str, "env DBUS_SESSION_BUS_ADDRESS='%s'", tmp);
640 					sbest = score;
641 				}
642 			}
643 		}
644 		X_LOCK;
645 		XFree_wr(children);
646 		X_UNLOCK;
647 
648 		return _dbus_str;
649 	}
650 #endif
651 }
652 
solid_gnome(char * color)653 static void solid_gnome(char *color) {
654 #if NO_X11
655 	RAWFB_RET_VOID
656 	if (!color) {}
657 	return;
658 #else
659 	char get_color[] = "%s gconftool-2 --get "
660 	    "/desktop/gnome/background/primary_color";
661 	char set_color[] = "%s gconftool-2 --set --type string "
662 	    "/desktop/gnome/background/primary_color '%s'";
663 	char get_option[] = "%s gconftool-2 --get "
664 	    "/desktop/gnome/background/picture_options";
665 	char set_option[] = "%s gconftool-2 --set --type string "
666 	    "/desktop/gnome/background/picture_options '%s'";
667 #if 0
668 	char get_shading[] = "%s gconftool-2 --get "
669 	    "/desktop/gnome/background/color_shading_type";
670 	char set_shading[] = "%s gconftool-2 --set --type string "
671 	    "/desktop/gnome/background/color_shading_type '%s'";
672 	char get_filename[] = "%s gconftool-2 --get "
673 	    "/desktop/gnome/background/picture_filename";
674 	char set_filename[] = "%s gconftool-2 --set --type string "
675 	    "/desktop/gnome/background/picture_filename '%s'";
676 #endif
677 	static char *orig_color = NULL;
678 	static char *orig_option = NULL;
679 	char *cmd, *dbus = "";
680 
681 	RAWFB_RET_VOID
682 
683 	dbus = dbus_session();
684 	rfbLog("guessed dbus: %s\n", dbus);
685 
686 	if (! color) {
687 		if (! orig_color) {
688 			orig_color = strdup("#FFFFFF");
689 		}
690 		if (! orig_option) {
691 			orig_option = strdup("stretched");
692 		}
693 		if (strstr(orig_color, "'") != NULL)  {
694 			rfbLog("invalid color: %s\n", orig_color);
695 			return;
696 		}
697 		if (strstr(orig_option, "'") != NULL)  {
698 			rfbLog("invalid option: %s\n", orig_option);
699 			return;
700 		}
701 		cmd = (char *) malloc(strlen(set_option) - 2 + strlen(orig_option) + strlen(dbus) + 1);
702 		sprintf(cmd, set_option, dbus, orig_option);
703 		dt_cmd(cmd);
704 		free(cmd);
705 		cmd = (char *) malloc(strlen(set_color) - 2 + strlen(orig_color) + strlen(dbus) + 1);
706 		sprintf(cmd, set_color, dbus, orig_color);
707 		dt_cmd(cmd);
708 		free(cmd);
709 		return;
710 	}
711 
712 	if (! orig_color) {
713 		char *q;
714 		if (cmd_ok("dt")) {
715 			cmd = (char *) malloc(strlen(get_color) + strlen(dbus) + 1);
716 			sprintf(cmd, get_color, dbus);
717 			orig_color = strdup(cmd_output(cmd));
718 			free(cmd);
719 		} else {
720 			orig_color = "";
721 		}
722 		if (*orig_color == '\0') {
723 			orig_color = strdup("#FFFFFF");
724 		}
725 		if ((q = strchr(orig_color, '\n')) != NULL) {
726 			*q = '\0';
727 		}
728 	}
729 	if (! orig_option) {
730 		char *q;
731 		if (cmd_ok("dt")) {
732 			cmd = (char *) malloc(strlen(get_option) + strlen(dbus) + 1);
733 			sprintf(cmd, get_option, dbus);
734 			orig_option = strdup(cmd_output(cmd));
735 			free(cmd);
736 		} else {
737 			orig_color = "";
738 		}
739 		if (*orig_option == '\0') {
740 			orig_option = strdup("stretched");
741 		}
742 		if ((q = strchr(orig_option, '\n')) != NULL) {
743 			*q = '\0';
744 		}
745 	}
746 	if (strstr(color, "'") != NULL)  {
747 		rfbLog("invalid color: %s\n", color);
748 		return;
749 	}
750 	cmd = (char *) malloc(strlen(set_color) + strlen(color) + strlen(dbus) + 1);
751 	sprintf(cmd, set_color, dbus, color);
752 	dt_cmd(cmd);
753 	free(cmd);
754 
755 	cmd = (char *) malloc(strlen(set_option) + strlen("none") + strlen(dbus) + 1);
756 	sprintf(cmd, set_option, dbus, "none");
757 	dt_cmd(cmd);
758 	free(cmd);
759 
760 #if 0
761 	cmd = (char *) malloc(strlen(set_filename) + strlen("none") + 1);
762 	sprintf(cmd, set_filename, dbus, "none");
763 	dt_cmd(cmd);
764 	free(cmd);
765 #endif
766 
767 #endif	/* NO_X11 */
768 }
769 
solid_xfce(char * color)770 static void solid_xfce(char *color) {
771 #if NO_X11
772 	RAWFB_RET_VOID
773 	if (!color) {}
774 	return;
775 #else
776 	char get_image_show[]  = "%s xfconf-query -v -c xfce4-desktop -p /backdrop/screen0/monitor0/image-show";
777 	char set_image_show[]  = "%s xfconf-query -v -c xfce4-desktop -p /backdrop/screen0/monitor0/image-show -s '%s'";
778 	char get_color_style[] = "%s xfconf-query -v -c xfce4-desktop -p /backdrop/screen0/monitor0/color-style";
779 	char set_color_style[] = "%s xfconf-query -v -c xfce4-desktop -p /backdrop/screen0/monitor0/color-style -s '%s'";
780 
781 	static char *orig_image_show = NULL;
782 	static char *orig_color_style = NULL;
783 	char *cmd, *dbus = "";
784 
785 	RAWFB_RET_VOID
786 
787 	dbus = dbus_session();
788 	rfbLog("guessed dbus: %s\n", dbus);
789 
790 	if (! color) {
791 		if (! orig_image_show) {
792 			orig_image_show = "true";
793 		}
794 		if (! orig_color_style) {
795 			orig_color_style = "0";
796 		}
797 		if (strstr(orig_image_show, "'") != NULL)  {
798 			rfbLog("invalid image show: %s\n", orig_image_show);
799 			return;
800 		}
801 		if (strstr(orig_color_style, "'") != NULL)  {
802 			rfbLog("invalid color style: %s\n", orig_color_style);
803 			return;
804 		}
805 		if (orig_image_show[0] != '\0') {
806 			cmd = (char *) malloc(strlen(set_image_show) - 2 + strlen(orig_image_show) + strlen(dbus) + 1);
807 			sprintf(cmd, set_image_show, dbus, orig_image_show);
808 			dt_cmd(cmd);
809 			free(cmd);
810 		}
811 		if (orig_color_style[0] != '\0') {
812 			cmd = (char *) malloc(strlen(set_color_style) - 2 + strlen(orig_color_style) + strlen(dbus) + 1);
813 			sprintf(cmd, set_color_style, dbus, orig_color_style);
814 			dt_cmd(cmd);
815 			free(cmd);
816 		}
817 		return;
818 	}
819 
820 	if (! orig_image_show) {
821 		char *q;
822 		orig_image_show = "";
823 		if (cmd_ok("dt")) {
824 			cmd = (char *) malloc(strlen(get_image_show) + strlen(dbus) + 1);
825 			sprintf(cmd, get_image_show, dbus);
826 			orig_image_show = strdup(cmd_output(cmd));
827 			if ((q = strrchr(orig_image_show, '\n')) != NULL) {
828 				*q = '\0';
829 			}
830 			fprintf(stderr, "get_image_show returned: '%s'\n\n", orig_image_show);
831 			free(cmd);
832 			if (strcasecmp(orig_image_show, "false") && strcasecmp(orig_image_show, "true")) {
833 				fprintf(stderr, "unrecognized image_show, disabling.\n");
834 				free(orig_image_show);
835 				orig_image_show = "";
836 			}
837 		}
838 	}
839 	if (! orig_color_style) {
840 		char *q;
841 		orig_color_style = "";
842 		if (cmd_ok("dt")) {
843 			cmd = (char *) malloc(strlen(get_color_style) + strlen(dbus) + 1);
844 			sprintf(cmd, get_color_style, dbus);
845 			orig_color_style = strdup(cmd_output(cmd));
846 			if ((q = strrchr(orig_color_style, '\n')) != NULL) {
847 				*q = '\0';
848 			}
849 			fprintf(stderr, "get_color_style returned: '%s'\n\n", orig_color_style);
850 			free(cmd);
851 			if (strlen(orig_color_style) > 1 || !isdigit((unsigned char) (*orig_color_style))) {
852 				fprintf(stderr, "unrecognized color_style, disabling.\n");
853 				free(orig_color_style);
854 				orig_color_style = "";
855 			}
856 		}
857 	}
858 
859 	if (strstr(color, "'") != NULL)  {
860 		rfbLog("invalid color: %s\n", color);
861 		return;
862 	}
863 
864 	cmd = (char *) malloc(strlen(set_color_style) + strlen("0") + strlen(dbus) + 1);
865 	sprintf(cmd, set_color_style, dbus, "0");
866 	dt_cmd(cmd);
867 	free(cmd);
868 
869 	cmd = (char *) malloc(strlen(set_image_show) + strlen("false") + strlen(dbus) + 1);
870 	sprintf(cmd, set_image_show, dbus, "false");
871 	dt_cmd(cmd);
872 	free(cmd);
873 
874 #endif	/* NO_X11 */
875 }
876 
877 
dcop_session(void)878 static char *dcop_session(void) {
879 	char *empty = strdup("");
880 #if NO_X11
881 	RAWFB_RET(empty);
882 	return empty;
883 #else
884 	char list_sessions[] = "dcop --user '%s' --list-sessions";
885 	int len;
886 	char *cmd, *host, *user = NULL;
887 	char *out, *p, *ds, *dsn = NULL, *sess = NULL, *sess2 = NULL;
888 	int db = 0;
889 
890 	RAWFB_RET(empty);
891 
892 	if (getenv("SESSION_MANAGER")) {
893 		return empty;
894 	}
895 
896 	user = get_user_name();
897 	if (strstr(user, "'") != NULL)  {
898 		rfbLog("invalid user: %s\n", user);
899 		free(user);
900 		return empty;
901 	}
902 
903 	len = strlen(list_sessions) + strlen(user) + 1;
904 	cmd = (char *) malloc(len);
905 	sprintf(cmd, list_sessions, user);
906 
907 	out = strdup(cmd_output(cmd));
908 	free(cmd);
909 	free(user);
910 
911 	ds = DisplayString(dpy);
912 	if (!ds || !strcmp(ds, "")) {
913 		ds = getenv("DISPLAY");
914 	}
915 	if (!ds) {
916 		ds = ":0";
917 	}
918 	ds = strdup(ds);
919 	p = strrchr(ds, '.');
920 	if (p) *p = '\0';
921 
922 	dsn = strchr(ds, ':');
923 	if (dsn) {
924 		*dsn = '_';
925 	} else {
926 		free(ds);
927 		ds = strdup("_0");
928 		dsn = ds;
929 	}
930 	if (db) fprintf(stderr, "ds:  %s\n", ds);
931 	if (db) fprintf(stderr, "dsn: %s\n", dsn);
932 
933 	host = this_host();
934 	if (host) {
935 		char *h2 = (char *) malloc(strlen(host) + 2 + 1);
936 		sprintf(h2, "_%s_", host);
937 		free(host);
938 		host = h2;
939 	} else {
940 		host = strdup("");
941 	}
942 	if (db) fprintf(stderr, "host: %s\n", host);
943 
944 	p = strtok(out, "\n");
945 	while (p) {
946 		char *q = strstr(p, ".DCOP");
947 		if (db) fprintf(stderr, "p:  %s\n", p);
948 		if (q == NULL) {
949 			;
950 		} else if (host) {
951 			if (strstr(q, host)) {
952 				char *r = strstr(p, dsn);
953 				int n = strlen(dsn);
954 				if(r && !isalnum((int) *(r+n))) {
955 					sess = strdup(q);
956 					break;
957 				} else {
958 					if (sess2) {
959 						free(sess2);
960 					}
961 					sess2 = strdup(q);
962 				}
963 			}
964 		} else {
965 			char *r = strstr(p, dsn);
966 			int n = strlen(dsn);
967 			if(r && !isalnum((int) *(r+n))) {
968 				sess = strdup(q);
969 				break;
970 			}
971 		}
972 		p = strtok(NULL, "\n");
973 	}
974 	free(ds);
975 	free(out);
976 	free(host);
977 	if (!sess && sess2) {
978 		sess = sess2;
979 	}
980 	if (!sess || strchr(sess, '\'')) {
981 		if (sess) free(sess);
982 		sess = strdup("--all-sessions");
983 	} else {
984 		len = strlen("--session ") + 2 + strlen(sess) + 1;
985 		cmd = (char *) malloc(len);
986 		sprintf(cmd, "--session '%s'", sess);
987 		free(sess);
988 		sess = cmd;
989 	}
990 	return sess;
991 #endif
992 }
993 
solid_kde(char * color)994 static void solid_kde(char *color) {
995 #if NO_X11
996 	RAWFB_RET_VOID
997 	if (!color) {}
998 	return;
999 #else
1000 	char set_color[] =
1001 	    "dcop --user '%s' %s kdesktop KBackgroundIface setColor '%s' 1";
1002 	char bg_off[] =
1003 	    "dcop --user '%s' %s kdesktop KBackgroundIface setBackgroundEnabled 0";
1004 	char bg_on[] =
1005 	    "dcop --user '%s' %s kdesktop KBackgroundIface setBackgroundEnabled 1";
1006 	char *cmd, *user = NULL, *sess;
1007 	int len;
1008 
1009 	RAWFB_RET_VOID
1010 
1011 	user = get_user_name();
1012 	if (strstr(user, "'") != NULL)  {
1013 		rfbLog("invalid user: %s\n", user);
1014 		free(user);
1015 		return;
1016 	}
1017 
1018 	set_env("DISPLAY", DisplayString(dpy));
1019 
1020 	if (! color) {
1021 		sess = dcop_session();
1022 		len = strlen(bg_on) + strlen(user) + strlen(sess) + 1;
1023 		cmd = (char *) malloc(len);
1024 		sprintf(cmd, bg_on, user, sess);
1025 
1026 		dt_cmd(cmd);
1027 
1028 		free(cmd);
1029 		free(user);
1030 		free(sess);
1031 
1032 		return;
1033 	}
1034 
1035 	if (strstr(color, "'") != NULL)  {
1036 		rfbLog("invalid color: %s\n", color);
1037 		return;
1038 	}
1039 
1040 	sess = dcop_session();
1041 
1042 	len = strlen(set_color) + strlen(user) + strlen(sess) + strlen(color) + 1;
1043 	cmd = (char *) malloc(len);
1044 	sprintf(cmd, set_color, user, sess, color);
1045 	dt_cmd(cmd);
1046 	free(cmd);
1047 
1048 	len = strlen(bg_off) + strlen(user) + strlen(sess) + 1;
1049 	cmd = (char *) malloc(len);
1050 	sprintf(cmd, bg_off, user, sess);
1051 	dt_cmd(cmd);
1052 	free(cmd);
1053 	free(user);
1054 #endif	/* NO_X11 */
1055 }
1056 
kde_no_animate(int restore)1057 void kde_no_animate(int restore) {
1058 #if NO_X11
1059 	if (!restore) {}
1060 	RAWFB_RET_VOID
1061 	return;
1062 #else
1063 	char query_setting[] =
1064 	    "kreadconfig  --file kwinrc --group Windows --key AnimateMinimize";
1065 	char kwinrc_off[] =
1066 	    "kwriteconfig --file kwinrc --group Windows --key AnimateMinimize --type bool false";
1067 	char kwinrc_on[] =
1068 	    "kwriteconfig --file kwinrc --group Windows --key AnimateMinimize --type bool true";
1069 	char kwin_reconfigure[] =
1070 	    "dcop --user '%s' %s kwin KWinInterface reconfigure";
1071 	char *cmd, *cmd2, *out, *user = NULL, *sess;
1072 	int len;
1073 	static int anim_state = 1;
1074 
1075 	RAWFB_RET_VOID
1076 
1077 	if (ncache_keep_anims) {
1078 		return;
1079 	}
1080 
1081 	if (restore) {
1082 		if (anim_state == 1) {
1083 			return;
1084 		}
1085 
1086 		user = get_user_name();
1087 		if (strstr(user, "'") != NULL)  {
1088 			rfbLog("invalid user: %s\n", user);
1089 			free(user);
1090 			return;
1091 		}
1092 
1093 		sess = dcop_session();
1094 
1095 		len = strlen(kwin_reconfigure) + strlen(user) + strlen(sess) + 1;
1096 		cmd = (char *) malloc(len);
1097 		sprintf(cmd, kwin_reconfigure, user, sess);
1098 		rfbLog("\n");
1099 		rfbLog("Restoring KDE kwinrc settings.\n");
1100 		rfbLog("\n");
1101 		dt_cmd(cmd);
1102 		free(cmd);
1103 		free(user);
1104 		free(sess);
1105 		anim_state = 1;
1106 		return;
1107 	} else {
1108 		if (anim_state == 0) {
1109 			return;
1110 		}
1111 		anim_state = 0;
1112 	}
1113 
1114 	user = get_user_name();
1115 	if (strstr(user, "'") != NULL)  {
1116 		rfbLog("invalid user: %s\n", user);
1117 		free(user);
1118 		return;
1119 	}
1120 	out = cmd_output(query_setting);
1121 
1122 
1123 	if (!out || strstr(out, "false")) {
1124 		rfbLog("\n");
1125 		rfbLog("********************************************************\n");
1126 		rfbLog("KDE kwinrc AnimateMinimize is false. Good.\n");
1127 		rfbLog("********************************************************\n");
1128 		rfbLog("\n");
1129 		free(user);
1130 		return;
1131 	}
1132 
1133 	rfbLog("\n");
1134 	rfbLog("********************************************************\n");
1135 	rfbLog("To improve the -ncache client-side caching performance\n");
1136 	rfbLog("temporarily setting KDE kwinrc AnimateMinimize to false.\n");
1137 	rfbLog("It will be reset for the next session or when VNC client\n");
1138 	rfbLog("disconnects.  Or you can use the Control Center GUI to\n");
1139 	rfbLog("change it now (toggle its setting a few times):\n");
1140 	rfbLog("   Desktop -> Window Behavior -> Moving\n");
1141 	rfbLog("********************************************************\n");
1142 	rfbLog("\n");
1143 
1144 	set_env("DISPLAY", DisplayString(dpy));
1145 
1146 	sess = dcop_session();
1147 	len = strlen(kwin_reconfigure) + strlen(user) + strlen(sess) + 1;
1148 	cmd = (char *) malloc(len);
1149 	sprintf(cmd, kwin_reconfigure, user, sess);
1150 
1151 	len = 1 + strlen("sleep 10") + 2 + strlen(kwinrc_off) + 2 + strlen(cmd) + 2 + strlen("sleep 5") + 2 + strlen(kwinrc_on) + 3 + 1;
1152 	cmd2 = (char *) malloc(len);
1153 
1154 	sprintf(cmd2, "(sleep 10; %s; %s; sleep 5; %s) &", kwinrc_off, cmd, kwinrc_on);
1155 
1156 	dt_cmd(cmd2);
1157 	free(cmd);
1158 	free(cmd2);
1159 	free(user);
1160 	free(sess);
1161 #endif	/* NO_X11 */
1162 }
1163 
gnome_no_animate(void)1164 void gnome_no_animate(void) {
1165 	;
1166 }
1167 
1168 static pid_t solid_macosx_pid = 0;
1169 extern char macosx_solid_background[];
1170 
solid_macosx(int restore)1171 static void solid_macosx(int restore) {
1172 	char tmp[] = "/tmp/macosx_solid_background.XXXXXX";
1173 	pid_t pid, parent = getpid();
1174 
1175 	if (restore) {
1176 		rfbLog("restore pid: %d\n", (int) solid_macosx_pid);
1177 		if (solid_macosx_pid > 0) {
1178 #if 0
1179 			int i, status;
1180 #endif
1181 			rfbLog("kill -TERM macosx_solid_background helper pid: %d\n", (int) solid_macosx_pid);
1182 			kill(solid_macosx_pid, SIGTERM);
1183 #if 0
1184 #if LIBVNCSERVER_HAVE_SYS_WAIT_H
1185 #if LIBVNCSERVER_HAVE_WAITPID
1186 			for (i=0; i < 7; i++) {
1187 				usleep(1000 * 1000);
1188 				waitpid(solid_macosx_pid, &status, WNOHANG);
1189 				if (kill(solid_macosx_pid, 0) != 0) {
1190 					break;
1191 				}
1192 			}
1193 #endif
1194 #endif
1195 #endif
1196 			solid_macosx_pid = 0;
1197 		}
1198 		return;
1199 	}
1200 	if (no_external_cmds || !cmd_ok("dt")) {
1201 		return;
1202 	}
1203 #if LIBVNCSERVER_HAVE_FORK
1204 	pid = fork();
1205 
1206 	if (pid == -1) {
1207 		perror("fork");
1208 		return;
1209 	}
1210 	if (pid == 0) {
1211 		int fd = mkstemp(tmp);
1212 #if LIBVNCSERVER_HAVE_SETSID
1213 		setsid();
1214 #else
1215 		setpgrp();
1216 #endif
1217 		if (fd >= 0) {
1218 			char num[32];
1219 			write(fd, macosx_solid_background, strlen(macosx_solid_background));
1220 			close(fd);
1221 			sprintf(num, "%d", (int) parent);
1222 			set_env("SS_WATCH_PID", num);
1223 			execlp("/bin/sh", "/bin/sh", tmp, (char *) NULL);
1224 		}
1225 		exit(1);
1226 	}
1227 	solid_macosx_pid = pid;
1228 	rfbLog("macosx_solid_background helper pid: %d\n", (int) solid_macosx_pid);
1229 	usleep(2750 * 1000);
1230 	unlink(tmp);
1231 #endif
1232 }
1233 
guess_desktop(void)1234 char *guess_desktop(void) {
1235 #if NO_X11
1236 	RAWFB_RET("root")
1237 	return "root";
1238 #else
1239 	Atom prop;
1240 
1241 	RAWFB_RET("root")
1242 
1243 	if (wmdt_str && *wmdt_str != '\0') {
1244 		char *s = wmdt_str;
1245 		lowercase(s);
1246 		if (strstr(s, "xfce")) {
1247 			return "xfce";
1248 		}
1249 		if (strstr(s, "gnome") || strstr(s, "metacity")) {
1250 			return "gnome";
1251 		}
1252 		if (strstr(s, "kde") || strstr(s, "kwin")) {
1253 			return "kde";
1254 		}
1255 		if (strstr(s, "cde")) {
1256 			return "cde";
1257 		}
1258 		return "root";
1259 	}
1260 
1261 	if (! dpy) {
1262 		return "";
1263 	}
1264 
1265 	prop = XInternAtom(dpy, "XFCE_DESKTOP_WINDOW", True);
1266 	if (prop != None) return "xfce";
1267 
1268 	/* special case windowmaker */
1269 	prop = XInternAtom(dpy, "_WINDOWMAKER_WM_PROTOCOLS", True);
1270 	if (prop != None)  return "root";
1271 
1272 	prop = XInternAtom(dpy, "_WINDOWMAKER_COMMAND", True);
1273 	if (prop != None) return "root";
1274 
1275 	prop = XInternAtom(dpy, "NAUTILUS_DESKTOP_WINDOW_ID", True);
1276 	if (prop != None) return "gnome";
1277 
1278 	prop = XInternAtom(dpy, "KWIN_RUNNING", True);
1279 	if (prop != None) {
1280 		prop = XInternAtom(dpy, "_KDE_RUNNING", True);
1281 		if (prop != None) {
1282 			prop = XInternAtom(dpy, "KDE_DESKTOP_WINDOW", True);
1283 			if (prop != None) return "kde";
1284 		}
1285 	}
1286 
1287 	prop = XInternAtom(dpy, "_MOTIF_WM_INFO", True);
1288 	if (prop != None) {
1289 		prop = XInternAtom(dpy, "_DT_WORKSPACE_LIST", True);
1290 		if (prop != None) return "cde";
1291 	}
1292 	return "root";
1293 #endif	/* NO_X11 */
1294 }
1295 
solid_image(char * color)1296 XImage *solid_image(char *color) {
1297 #if NO_X11
1298 	RAWFB_RET(NULL)
1299 	return NULL;
1300 #else
1301 	XImage *image = NULL;
1302 	unsigned long pixel = 0;
1303 	int x, y;
1304 
1305 	RAWFB_RET(NULL)
1306 
1307 	if (!color) {
1308 		color = last_color;
1309 	}
1310 
1311 	if (!color) {
1312 		return NULL;
1313 	}
1314 
1315 	image = XGetImage(dpy, rootwin, 0, 0, wdpy_x, wdpy_y, AllPlanes,
1316 	    ZPixmap);
1317 
1318 	if (!image) {
1319 		return NULL;
1320 	}
1321 	pixel = get_pixel(color);
1322 
1323 	for (y=0; y<wdpy_y; y++) {
1324 		for (x=0; x<wdpy_x; x++) {
1325 			XPutPixel(image, x, y, pixel);
1326 		}
1327 	}
1328 	return image;
1329 #endif	/* NO_X11 */
1330 }
1331 
solid_bg(int restore)1332 void solid_bg(int restore) {
1333 	static int desktop = -1;
1334 	static int solid_on = 0;
1335 	static char *prev_str;
1336 	char *dtname, *color;
1337 
1338 	if (started_as_root == 1 && users_list) {
1339 		/* we are still root, don't try. */
1340 		return;
1341 	}
1342 
1343 	if (macosx_console) {
1344 		solid_macosx(restore);
1345 		return;
1346 	}
1347 
1348 	RAWFB_RET_VOID
1349 
1350 	if (restore) {
1351 		if (! solid_on) {
1352 			return;
1353 		}
1354 		if (desktop == 0) {
1355 			solid_root(NULL);
1356 		} else if (desktop == 1) {
1357 			solid_gnome(NULL);
1358 		} else if (desktop == 2) {
1359 			solid_kde(NULL);
1360 		} else if (desktop == 3) {
1361 			solid_cde(NULL);
1362 		} else if (desktop == 4) {
1363 			solid_xfce(NULL);
1364 		}
1365 		solid_on = 0;
1366 		return;
1367 	}
1368 	if (! solid_str) {
1369 		return;
1370 	}
1371 	if (solid_on && !strcmp(prev_str, solid_str)) {
1372 		return;
1373 	}
1374 	if (strstr(solid_str, "guess:") == solid_str
1375 	    || !strchr(solid_str, ':')) {
1376 		dtname = guess_desktop();
1377 		rfbLog("guessed desktop: %s\n", dtname);
1378 	} else {
1379 		if (strstr(solid_str, "gnome:") == solid_str) {
1380 			dtname = "gnome";
1381 		} else if (strstr(solid_str, "kde:") == solid_str) {
1382 			dtname = "kde";
1383 		} else if (strstr(solid_str, "cde:") == solid_str) {
1384 			dtname = "cde";
1385 		} else if (strstr(solid_str, "xfce:") == solid_str) {
1386 			dtname = "xfce";
1387 		} else {
1388 			dtname = "root";
1389 		}
1390 	}
1391 
1392 	color = strchr(solid_str, ':');
1393 	if (! color) {
1394 		color = solid_str;
1395 	} else {
1396 		color++;
1397 		if (*color == '\0') {
1398 			color = solid_default;
1399 		}
1400 	}
1401 	if (last_color) {
1402 		free(last_color);
1403 	}
1404 	last_color = strdup(color);
1405 
1406 	if (!strcmp(dtname, "gnome")) {
1407 		desktop = 1;
1408 		solid_gnome(color);
1409 	} else if (!strcmp(dtname, "kde")) {
1410 		desktop = 2;
1411 		solid_kde(color);
1412 	} else if (!strcmp(dtname, "cde")) {
1413 		desktop = 3;
1414 		solid_cde(color);
1415 	} else if (!strcmp(dtname, "xfce")) {
1416 		desktop = 4;
1417 		solid_xfce(color);
1418 	} else {
1419 		desktop = 0;
1420 		solid_root(color);
1421 	}
1422 	if (prev_str) {
1423 		free(prev_str);
1424 	}
1425 	prev_str = strdup(solid_str);
1426 	solid_on = 1;
1427 }
1428 
1429 
1430