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