| /* |
| Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com> |
| All rights reserved. |
| |
| This file is part of x11vnc. |
| |
| x11vnc is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or (at |
| your option) any later version. |
| |
| x11vnc is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with x11vnc; if not, write to the Free Software |
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA |
| or see <http://www.gnu.org/licenses/>. |
| |
| In addition, as a special exception, Karl J. Runge |
| gives permission to link the code of its release of x11vnc with the |
| OpenSSL project's "OpenSSL" library (or with modified versions of it |
| that use the same license as the "OpenSSL" library), and distribute |
| the linked executables. You must obey the GNU General Public License |
| in all respects for all of the code used other than "OpenSSL". If you |
| modify this file, you may extend this exception to your version of the |
| file, but you are not obligated to do so. If you do not wish to do |
| so, delete this exception statement from your version. |
| */ |
| |
| /* -- solid.c -- */ |
| |
| #include "x11vnc.h" |
| #include "win_utils.h" |
| #include "xwrappers.h" |
| #include "connections.h" |
| #include "cleanup.h" |
| #include "xevents.h" |
| |
| char *guess_desktop(void); |
| void solid_bg(int restore); |
| char *dbus_session(void); |
| |
| |
| static void usr_bin_path(int restore); |
| static int dt_cmd(char *cmd); |
| static char *cmd_output(char *cmd); |
| XImage *solid_root(char *color); |
| static void solid_cde(char *color); |
| static void solid_gnome(char *color); |
| static void solid_kde(char *color); |
| static void solid_macosx(int restore); |
| |
| static void usr_bin_path(int restore) { |
| static char *oldpath = NULL; |
| char *newpath; |
| char addpath[] = "/usr/bin:/bin:"; |
| |
| if (restore) { |
| if (oldpath) { |
| set_env("PATH", oldpath); |
| free(oldpath); |
| oldpath = NULL; |
| } |
| return; |
| } |
| |
| if (getenv("PATH")) { |
| oldpath = strdup(getenv("PATH")); |
| } else { |
| oldpath = strdup("/usr/bin"); |
| } |
| newpath = (char *) malloc(strlen(oldpath) + strlen(addpath) + 1); |
| newpath[0] = '\0'; |
| strcat(newpath, addpath); |
| strcat(newpath, oldpath); |
| set_env("PATH", newpath); |
| free(newpath); |
| } |
| |
| static int dt_cmd(char *cmd) { |
| int rc; |
| |
| RAWFB_RET(0) |
| |
| if (!cmd || *cmd == '\0') { |
| return 0; |
| } |
| |
| /* dt */ |
| if (no_external_cmds || !cmd_ok("dt")) { |
| rfbLog("cannot run external commands in -nocmds mode:\n"); |
| rfbLog(" \"%s\"\n", cmd); |
| rfbLog(" dt_cmd: returning 1\n"); |
| return 1; |
| } |
| |
| if (getenv("DISPLAY") == NULL) { |
| set_env("DISPLAY", DisplayString(dpy)); |
| } |
| |
| rfbLog("running command:\n"); |
| if (!quiet) { |
| fprintf(stderr, "\n %s\n\n", cmd); |
| } |
| usr_bin_path(0); |
| close_exec_fds(); |
| rc = system(cmd); |
| usr_bin_path(1); |
| |
| if (rc >= 256) { |
| rc = rc/256; |
| } |
| return rc; |
| } |
| |
| static char *cmd_output(char *cmd) { |
| FILE *p; |
| static char output[50000]; |
| char line[1024]; |
| int rc; |
| |
| if (!cmd || *cmd == '\0') { |
| return ""; |
| } |
| |
| if (no_external_cmds) { |
| rfbLog("cannot run external commands in -nocmds mode:\n"); |
| rfbLog(" \"%s\"\n", cmd); |
| rfbLog(" cmd_output: null string.\n"); |
| return ""; |
| } |
| |
| rfbLog("running pipe:\n"); |
| if (!quiet) { |
| fprintf(stderr, "\n %s\n\n", cmd); |
| } |
| usr_bin_path(0); |
| close_exec_fds(); |
| p = popen(cmd, "r"); |
| usr_bin_path(1); |
| |
| output[0] = '\0'; |
| |
| while (fgets(line, 1024, p) != NULL) { |
| if (strlen(output) + strlen(line) + 1 < 50000) { |
| strcat(output, line); |
| } |
| } |
| rc = pclose(p); |
| return(output); |
| } |
| |
| static char *last_color = NULL; |
| |
| unsigned long get_pixel(char *color) { |
| #if NO_X11 |
| return 0; |
| #else |
| XColor cdef; |
| Colormap cmap; |
| unsigned long pixel = BlackPixel(dpy, scr); |
| if (depth > 8 || strcmp(color, solid_default)) { |
| cmap = DefaultColormap (dpy, scr); |
| if (XParseColor(dpy, cmap, color, &cdef) && |
| XAllocColor(dpy, cmap, &cdef)) { |
| pixel = cdef.pixel; |
| } else { |
| rfbLog("error parsing/allocing color: %s\n", color); |
| } |
| } |
| return pixel; |
| #endif |
| } |
| |
| XImage *solid_root(char *color) { |
| #if NO_X11 |
| RAWFB_RET_VOID |
| if (!color) {} |
| return NULL; |
| #else |
| Window expose; |
| static XImage *image = NULL; |
| Pixmap pixmap; |
| XGCValues gcv; |
| GC gc; |
| XSetWindowAttributes swa; |
| Visual visual; |
| static unsigned long mask, pixel = 0; |
| |
| RAWFB_RET(NULL) |
| |
| if (subwin || window != rootwin) { |
| rfbLog("cannot set subwin to solid color, must be rootwin\n"); |
| return NULL; |
| } |
| |
| /* create the "clear" window just for generating exposures */ |
| swa.override_redirect = True; |
| swa.backing_store = NotUseful; |
| swa.save_under = False; |
| swa.background_pixmap = None; |
| visual.visualid = CopyFromParent; |
| mask = (CWOverrideRedirect|CWBackingStore|CWSaveUnder|CWBackPixmap); |
| expose = XCreateWindow(dpy, window, 0, 0, wdpy_x, wdpy_y, 0, depth, |
| InputOutput, &visual, mask, &swa); |
| |
| if (! color) { |
| |
| if (! image) { |
| /* whoops */ |
| XDestroyWindow(dpy, expose); |
| rfbLog("no root snapshot available.\n"); |
| return NULL; |
| } |
| |
| /* restore the root window from the XImage snapshot */ |
| pixmap = XCreatePixmap(dpy, window, wdpy_x, wdpy_y, depth); |
| |
| /* draw the image to a pixmap: */ |
| gcv.function = GXcopy; |
| gcv.plane_mask = AllPlanes; |
| gc = XCreateGC(dpy, window, GCFunction|GCPlaneMask, &gcv); |
| |
| XPutImage(dpy, pixmap, gc, image, 0, 0, 0, 0, wdpy_x, wdpy_y); |
| |
| gcv.foreground = gcv.background = BlackPixel(dpy, scr); |
| gc = XCreateGC(dpy, window, GCForeground|GCBackground, &gcv); |
| |
| rfbLog("restoring root snapshot...\n"); |
| /* set the pixmap as the bg: */ |
| XSetWindowBackgroundPixmap(dpy, window, pixmap); |
| XFreePixmap(dpy, pixmap); |
| XClearWindow(dpy, window); |
| XFlush_wr(dpy); |
| |
| /* generate exposures */ |
| XMapWindow(dpy, expose); |
| XSync(dpy, False); |
| XDestroyWindow(dpy, expose); |
| return NULL; |
| } |
| |
| if (! image) { |
| /* need to retrieve a snapshot of the root background: */ |
| Window iwin; |
| XSetWindowAttributes iswa; |
| |
| /* create image window: */ |
| iswa.override_redirect = True; |
| iswa.backing_store = NotUseful; |
| iswa.save_under = False; |
| iswa.background_pixmap = ParentRelative; |
| |
| iwin = XCreateWindow(dpy, window, 0, 0, wdpy_x, wdpy_y, 0, |
| depth, InputOutput, &visual, mask, &iswa); |
| |
| rfbLog("snapshotting background...\n"); |
| |
| XMapWindow(dpy, iwin); |
| XSync(dpy, False); |
| image = XGetImage(dpy, iwin, 0, 0, wdpy_x, wdpy_y, AllPlanes, |
| ZPixmap); |
| XSync(dpy, False); |
| XDestroyWindow(dpy, iwin); |
| rfbLog("done.\n"); |
| } |
| if (color == (char *) 0x1) { |
| /* caller will XDestroyImage it: */ |
| XImage *xi = image; |
| image = NULL; |
| return xi; |
| } |
| |
| /* use black for low colors or failure */ |
| pixel = get_pixel(color); |
| |
| rfbLog("setting solid background...\n"); |
| XSetWindowBackground(dpy, window, pixel); |
| XMapWindow(dpy, expose); |
| XSync(dpy, False); |
| XDestroyWindow(dpy, expose); |
| #endif /* NO_X11 */ |
| return NULL; |
| } |
| |
| static void solid_cde(char *color) { |
| #if NO_X11 |
| RAWFB_RET_VOID |
| if (!color) {} |
| return; |
| #else |
| int wsmax = 16; |
| static XImage *image[16]; |
| static Window ws_wins[16]; |
| static int nws = -1; |
| |
| Window expose; |
| Pixmap pixmap; |
| XGCValues gcv; |
| GC gc; |
| XSetWindowAttributes swa; |
| Visual visual; |
| unsigned long mask, pixel; |
| XColor cdef; |
| Colormap cmap; |
| int n; |
| |
| RAWFB_RET_VOID |
| |
| if (subwin || window != rootwin) { |
| rfbLog("cannot set subwin to solid color, must be rootwin\n"); |
| return; |
| } |
| |
| /* create the "clear" window just for generating exposures */ |
| swa.override_redirect = True; |
| swa.backing_store = NotUseful; |
| swa.save_under = False; |
| swa.background_pixmap = None; |
| visual.visualid = CopyFromParent; |
| mask = (CWOverrideRedirect|CWBackingStore|CWSaveUnder|CWBackPixmap); |
| expose = XCreateWindow(dpy, window, 0, 0, wdpy_x, wdpy_y, 0, depth, |
| InputOutput, &visual, mask, &swa); |
| |
| if (! color) { |
| /* restore the backdrop windows from the XImage snapshots */ |
| |
| for (n=0; n < nws; n++) { |
| Window twin; |
| |
| if (! image[n]) { |
| continue; |
| } |
| |
| twin = ws_wins[n]; |
| if (! twin) { |
| twin = rootwin; |
| } |
| if (! valid_window(twin, NULL, 0)) { |
| continue; |
| } |
| |
| pixmap = XCreatePixmap(dpy, twin, wdpy_x, wdpy_y, |
| depth); |
| |
| /* draw the image to a pixmap: */ |
| gcv.function = GXcopy; |
| gcv.plane_mask = AllPlanes; |
| gc = XCreateGC(dpy, twin, GCFunction|GCPlaneMask, &gcv); |
| |
| XPutImage(dpy, pixmap, gc, image[n], 0, 0, 0, 0, |
| wdpy_x, wdpy_y); |
| |
| gcv.foreground = gcv.background = BlackPixel(dpy, scr); |
| gc = XCreateGC(dpy, twin, GCForeground|GCBackground, |
| &gcv); |
| |
| rfbLog("restoring CDE ws%d snapshot to 0x%lx\n", |
| n, twin); |
| /* set the pixmap as the bg: */ |
| XSetWindowBackgroundPixmap(dpy, twin, pixmap); |
| XFreePixmap(dpy, pixmap); |
| XClearWindow(dpy, twin); |
| XFlush_wr(dpy); |
| } |
| |
| /* generate exposures */ |
| XMapWindow(dpy, expose); |
| XSync(dpy, False); |
| XDestroyWindow(dpy, expose); |
| return; |
| } |
| |
| if (nws < 0) { |
| /* need to retrieve snapshots of the ws backgrounds: */ |
| Window iwin, wm_win; |
| XSetWindowAttributes iswa; |
| Atom dt_list, wm_info, type; |
| int format; |
| unsigned long length, after; |
| unsigned char *data; |
| unsigned long *dp; /* crash on 64bit with int */ |
| |
| nws = 0; |
| |
| /* extract the hidden wm properties about backdrops: */ |
| |
| wm_info = XInternAtom(dpy, "_MOTIF_WM_INFO", True); |
| if (wm_info == None) { |
| return; |
| } |
| |
| XGetWindowProperty(dpy, rootwin, wm_info, 0L, 10L, False, |
| AnyPropertyType, &type, &format, &length, &after, &data); |
| |
| /* |
| * xprop -notype -root _MOTIF_WM_INFO |
| * _MOTIF_WM_INFO = 0x2, 0x580028 |
| */ |
| |
| if (length < 2 || format != 32 || after != 0) { |
| return; |
| } |
| |
| dp = (unsigned long *) data; |
| wm_win = (Window) *(dp+1); /* 2nd item. */ |
| |
| |
| dt_list = XInternAtom(dpy, "_DT_WORKSPACE_LIST", True); |
| if (dt_list == None) { |
| return; |
| } |
| |
| XGetWindowProperty(dpy, wm_win, dt_list, 0L, 10L, False, |
| AnyPropertyType, &type, &format, &length, &after, &data); |
| |
| nws = length; |
| |
| if (nws > wsmax) { |
| nws = wsmax; |
| } |
| if (nws < 0) { |
| nws = 0; |
| } |
| |
| rfbLog("special CDE win: 0x%lx, %d workspaces\n", wm_win, nws); |
| if (nws == 0) { |
| return; |
| } |
| |
| for (n=0; n<nws; n++) { |
| Atom ws_atom; |
| char tmp[32]; |
| Window twin; |
| XWindowAttributes attr; |
| int i, cnt; |
| |
| image[n] = NULL; |
| ws_wins[n] = 0x0; |
| |
| sprintf(tmp, "_DT_WORKSPACE_INFO_ws%d", n); |
| ws_atom = XInternAtom(dpy, tmp, False); |
| if (ws_atom == None) { |
| continue; |
| } |
| XGetWindowProperty(dpy, wm_win, ws_atom, 0L, 100L, |
| False, AnyPropertyType, &type, &format, &length, |
| &after, &data); |
| |
| if (format != 8 || after != 0) { |
| continue; |
| } |
| /* |
| * xprop -notype -id wm_win |
| * _DT_WORKSPACE_INFO_ws0 = "One", "3", "0x2f2f4a", |
| * "0x63639c", "0x103", "1", "0x58044e" |
| */ |
| |
| cnt = 0; |
| twin = 0x0; |
| for (i=0; i< (int) length; i++) { |
| if (*(data+i) != '\0') { |
| continue; |
| } |
| cnt++; /* count nulls to indicate field */ |
| if (cnt == 6) { |
| /* one past the null: */ |
| char *q = (char *) (data+i+1); |
| unsigned long in; |
| if (sscanf(q, "0x%lx", &in) == 1) { |
| twin = (Window) in; |
| break; |
| } |
| } |
| } |
| ws_wins[n] = twin; |
| |
| if (! twin) { |
| twin = rootwin; |
| } |
| |
| XGetWindowAttributes(dpy, twin, &attr); |
| if (twin != rootwin) { |
| if (attr.map_state != IsViewable) { |
| XMapWindow(dpy, twin); |
| } |
| XRaiseWindow(dpy, twin); |
| } |
| XSync(dpy, False); |
| |
| /* create image window: */ |
| iswa.override_redirect = True; |
| iswa.backing_store = NotUseful; |
| iswa.save_under = False; |
| iswa.background_pixmap = ParentRelative; |
| visual.visualid = CopyFromParent; |
| |
| iwin = XCreateWindow(dpy, twin, 0, 0, wdpy_x, wdpy_y, |
| 0, depth, InputOutput, &visual, mask, &iswa); |
| |
| rfbLog("snapshotting CDE backdrop ws%d 0x%lx -> " |
| "0x%lx ...\n", n, twin, iwin); |
| XMapWindow(dpy, iwin); |
| XSync(dpy, False); |
| |
| image[n] = XGetImage(dpy, iwin, 0, 0, wdpy_x, wdpy_y, |
| AllPlanes, ZPixmap); |
| XSync(dpy, False); |
| XDestroyWindow(dpy, iwin); |
| if (twin != rootwin) { |
| XLowerWindow(dpy, twin); |
| if (attr.map_state != IsViewable) { |
| XUnmapWindow(dpy, twin); |
| } |
| } |
| } |
| } |
| if (nws == 0) { |
| return; |
| } |
| |
| /* use black for low colors or failure */ |
| pixel = BlackPixel(dpy, scr); |
| if (depth > 8 || strcmp(color, solid_default)) { |
| cmap = DefaultColormap (dpy, scr); |
| if (XParseColor(dpy, cmap, color, &cdef) && |
| XAllocColor(dpy, cmap, &cdef)) { |
| pixel = cdef.pixel; |
| } else { |
| rfbLog("error parsing/allocing color: %s\n", color); |
| } |
| } |
| |
| rfbLog("setting solid backgrounds...\n"); |
| |
| for (n=0; n < nws; n++) { |
| Window twin = ws_wins[n]; |
| if (image[n] == NULL) { |
| continue; |
| } |
| if (! twin) { |
| twin = rootwin; |
| } |
| XSetWindowBackground(dpy, twin, pixel); |
| } |
| XMapWindow(dpy, expose); |
| XSync(dpy, False); |
| XDestroyWindow(dpy, expose); |
| #endif /* NO_X11 */ |
| } |
| |
| static char _dbus_str[1100]; |
| |
| char *dbus_session(void) { |
| char *dbus_env = getenv("DBUS_SESSION_BUS_ADDRESS"); |
| char tmp[1000]; |
| |
| if (dbus_env != NULL && strlen(dbus_env) > 0) { |
| return ""; |
| } |
| if (!dpy) { |
| return ""; |
| } |
| #if NO_X11 |
| return ""; |
| #else |
| { |
| Atom dbus_prop, dbus_pid; |
| Window r, w, *children; |
| int sbest = -1; |
| unsigned int ui; |
| int rc, i; |
| |
| memset(_dbus_str, 0, sizeof(_dbus_str)); |
| |
| X_LOCK; |
| dbus_prop = XInternAtom(dpy, "_DBUS_SESSION_BUS_ADDRESS", True); |
| dbus_pid = XInternAtom(dpy, "_DBUS_SESSION_BUS_PID", True); |
| X_UNLOCK; |
| if (dbus_prop == None) { |
| return ""; |
| } |
| |
| X_LOCK; |
| memset(tmp, 0, sizeof(tmp)); |
| get_prop(tmp, sizeof(tmp)-1, dbus_prop, None); |
| X_UNLOCK; |
| if (strcmp(tmp, "")) { |
| if (!strchr(tmp, '\'')) { |
| sprintf(_dbus_str, "env DBUS_SESSION_BUS_ADDRESS='%s'", tmp); |
| return _dbus_str; |
| } |
| } |
| |
| X_LOCK; |
| rc = XQueryTree_wr(dpy, rootwin, &r, &w, &children, &ui); |
| X_UNLOCK; |
| if (!rc || children == NULL || ui == 0) { |
| return ""; |
| } |
| for (i=0; i < (int) ui; i++) { |
| int pid = -1; |
| |
| X_LOCK; |
| memset(tmp, 0, sizeof(tmp)); |
| get_prop(tmp, sizeof(tmp)-1, dbus_prop, children[i]); |
| if (dbus_pid != None) { |
| Atom atype; |
| int aformat; |
| unsigned long nitems, bafter; |
| unsigned char *prop; |
| if (XGetWindowProperty(dpy, children[i], dbus_pid, |
| 0, 1, False, XA_CARDINAL, &atype, &aformat, |
| &nitems, &bafter, &prop) == Success |
| && atype == XA_CARDINAL) { |
| pid = *((int *) prop); |
| XFree_wr(prop); |
| } |
| } |
| X_UNLOCK; |
| |
| if (strcmp(tmp, "") && !strchr(tmp, '\'')) { |
| int score = 0; |
| if (1 < pid && pid < 10000000) { |
| struct stat sb; |
| char procfile[32]; |
| |
| sprintf(procfile, "/proc/%d", pid); |
| if (stat(procfile, &sb) == 0) { |
| score += 10000000; |
| } |
| score += pid; |
| } |
| if (getenv("X11VNC_DBUS_DEBUG")) fprintf(stderr, "win: 0x%lx pid: %8d score: %8d str: %s\n", children[i], pid, score, tmp); |
| if (score > sbest) { |
| sprintf(_dbus_str, "env DBUS_SESSION_BUS_ADDRESS='%s'", tmp); |
| sbest = score; |
| } |
| } |
| } |
| X_LOCK; |
| XFree_wr(children); |
| X_UNLOCK; |
| |
| return _dbus_str; |
| } |
| #endif |
| } |
| |
| static void solid_gnome(char *color) { |
| #if NO_X11 |
| RAWFB_RET_VOID |
| if (!color) {} |
| return; |
| #else |
| char get_color[] = "%s gconftool-2 --get " |
| "/desktop/gnome/background/primary_color"; |
| char set_color[] = "%s gconftool-2 --set --type string " |
| "/desktop/gnome/background/primary_color '%s'"; |
| char get_option[] = "%s gconftool-2 --get " |
| "/desktop/gnome/background/picture_options"; |
| char set_option[] = "%s gconftool-2 --set --type string " |
| "/desktop/gnome/background/picture_options '%s'"; |
| #if 0 |
| char get_shading[] = "%s gconftool-2 --get " |
| "/desktop/gnome/background/color_shading_type"; |
| char set_shading[] = "%s gconftool-2 --set --type string " |
| "/desktop/gnome/background/color_shading_type '%s'"; |
| char get_filename[] = "%s gconftool-2 --get " |
| "/desktop/gnome/background/picture_filename"; |
| char set_filename[] = "%s gconftool-2 --set --type string " |
| "/desktop/gnome/background/picture_filename '%s'"; |
| #endif |
| static char *orig_color = NULL; |
| static char *orig_option = NULL; |
| char *cmd, *dbus = ""; |
| |
| RAWFB_RET_VOID |
| |
| dbus = dbus_session(); |
| rfbLog("guessed dbus: %s\n", dbus); |
| |
| if (! color) { |
| if (! orig_color) { |
| orig_color = strdup("#FFFFFF"); |
| } |
| if (! orig_option) { |
| orig_option = strdup("stretched"); |
| } |
| if (strstr(orig_color, "'") != NULL) { |
| rfbLog("invalid color: %s\n", orig_color); |
| return; |
| } |
| if (strstr(orig_option, "'") != NULL) { |
| rfbLog("invalid option: %s\n", orig_option); |
| return; |
| } |
| cmd = (char *) malloc(strlen(set_option) - 2 + strlen(orig_option) + strlen(dbus) + 1); |
| sprintf(cmd, set_option, dbus, orig_option); |
| dt_cmd(cmd); |
| free(cmd); |
| cmd = (char *) malloc(strlen(set_color) - 2 + strlen(orig_color) + strlen(dbus) + 1); |
| sprintf(cmd, set_color, dbus, orig_color); |
| dt_cmd(cmd); |
| free(cmd); |
| return; |
| } |
| |
| if (! orig_color) { |
| char *q; |
| if (cmd_ok("dt")) { |
| cmd = (char *) malloc(strlen(get_color) + strlen(dbus) + 1); |
| sprintf(cmd, get_color, dbus); |
| orig_color = strdup(cmd_output(cmd)); |
| free(cmd); |
| } else { |
| orig_color = ""; |
| } |
| if (*orig_color == '\0') { |
| orig_color = strdup("#FFFFFF"); |
| } |
| if ((q = strchr(orig_color, '\n')) != NULL) { |
| *q = '\0'; |
| } |
| } |
| if (! orig_option) { |
| char *q; |
| if (cmd_ok("dt")) { |
| cmd = (char *) malloc(strlen(get_option) + strlen(dbus) + 1); |
| sprintf(cmd, get_option, dbus); |
| orig_option = strdup(cmd_output(cmd)); |
| free(cmd); |
| } else { |
| orig_color = ""; |
| } |
| if (*orig_option == '\0') { |
| orig_option = strdup("stretched"); |
| } |
| if ((q = strchr(orig_option, '\n')) != NULL) { |
| *q = '\0'; |
| } |
| } |
| if (strstr(color, "'") != NULL) { |
| rfbLog("invalid color: %s\n", color); |
| return; |
| } |
| cmd = (char *) malloc(strlen(set_color) + strlen(color) + strlen(dbus) + 1); |
| sprintf(cmd, set_color, dbus, color); |
| dt_cmd(cmd); |
| free(cmd); |
| |
| cmd = (char *) malloc(strlen(set_option) + strlen("none") + strlen(dbus) + 1); |
| sprintf(cmd, set_option, dbus, "none"); |
| dt_cmd(cmd); |
| free(cmd); |
| |
| #if 0 |
| cmd = (char *) malloc(strlen(set_filename) + strlen("none") + 1); |
| sprintf(cmd, set_filename, dbus, "none"); |
| dt_cmd(cmd); |
| free(cmd); |
| #endif |
| |
| #endif /* NO_X11 */ |
| } |
| |
| static void solid_xfce(char *color) { |
| #if NO_X11 |
| RAWFB_RET_VOID |
| if (!color) {} |
| return; |
| #else |
| char get_image_show[] = "%s xfconf-query -v -c xfce4-desktop -p /backdrop/screen0/monitor0/image-show"; |
| char set_image_show[] = "%s xfconf-query -v -c xfce4-desktop -p /backdrop/screen0/monitor0/image-show -s '%s'"; |
| char get_color_style[] = "%s xfconf-query -v -c xfce4-desktop -p /backdrop/screen0/monitor0/color-style"; |
| char set_color_style[] = "%s xfconf-query -v -c xfce4-desktop -p /backdrop/screen0/monitor0/color-style -s '%s'"; |
| |
| static char *orig_image_show = NULL; |
| static char *orig_color_style = NULL; |
| char *cmd, *dbus = ""; |
| |
| RAWFB_RET_VOID |
| |
| dbus = dbus_session(); |
| rfbLog("guessed dbus: %s\n", dbus); |
| |
| if (! color) { |
| if (! orig_image_show) { |
| orig_image_show = "true"; |
| } |
| if (! orig_color_style) { |
| orig_color_style = "0"; |
| } |
| if (strstr(orig_image_show, "'") != NULL) { |
| rfbLog("invalid image show: %s\n", orig_image_show); |
| return; |
| } |
| if (strstr(orig_color_style, "'") != NULL) { |
| rfbLog("invalid color style: %s\n", orig_color_style); |
| return; |
| } |
| if (orig_image_show[0] != '\0') { |
| cmd = (char *) malloc(strlen(set_image_show) - 2 + strlen(orig_image_show) + strlen(dbus) + 1); |
| sprintf(cmd, set_image_show, dbus, orig_image_show); |
| dt_cmd(cmd); |
| free(cmd); |
| } |
| if (orig_color_style[0] != '\0') { |
| cmd = (char *) malloc(strlen(set_color_style) - 2 + strlen(orig_color_style) + strlen(dbus) + 1); |
| sprintf(cmd, set_color_style, dbus, orig_color_style); |
| dt_cmd(cmd); |
| free(cmd); |
| } |
| return; |
| } |
| |
| if (! orig_image_show) { |
| char *q; |
| orig_image_show = ""; |
| if (cmd_ok("dt")) { |
| cmd = (char *) malloc(strlen(get_image_show) + strlen(dbus) + 1); |
| sprintf(cmd, get_image_show, dbus); |
| orig_image_show = strdup(cmd_output(cmd)); |
| if ((q = strrchr(orig_image_show, '\n')) != NULL) { |
| *q = '\0'; |
| } |
| fprintf(stderr, "get_image_show returned: '%s'\n\n", orig_image_show); |
| free(cmd); |
| if (strcasecmp(orig_image_show, "false") && strcasecmp(orig_image_show, "true")) { |
| fprintf(stderr, "unrecognized image_show, disabling.\n"); |
| free(orig_image_show); |
| orig_image_show = ""; |
| } |
| } |
| } |
| if (! orig_color_style) { |
| char *q; |
| orig_color_style = ""; |
| if (cmd_ok("dt")) { |
| cmd = (char *) malloc(strlen(get_color_style) + strlen(dbus) + 1); |
| sprintf(cmd, get_color_style, dbus); |
| orig_color_style = strdup(cmd_output(cmd)); |
| if ((q = strrchr(orig_color_style, '\n')) != NULL) { |
| *q = '\0'; |
| } |
| fprintf(stderr, "get_color_style returned: '%s'\n\n", orig_color_style); |
| free(cmd); |
| if (strlen(orig_color_style) > 1 || !isdigit((unsigned char) (*orig_color_style))) { |
| fprintf(stderr, "unrecognized color_style, disabling.\n"); |
| free(orig_color_style); |
| orig_color_style = ""; |
| } |
| } |
| } |
| |
| if (strstr(color, "'") != NULL) { |
| rfbLog("invalid color: %s\n", color); |
| return; |
| } |
| |
| cmd = (char *) malloc(strlen(set_color_style) + strlen("0") + strlen(dbus) + 1); |
| sprintf(cmd, set_color_style, dbus, "0"); |
| dt_cmd(cmd); |
| free(cmd); |
| |
| cmd = (char *) malloc(strlen(set_image_show) + strlen("false") + strlen(dbus) + 1); |
| sprintf(cmd, set_image_show, dbus, "false"); |
| dt_cmd(cmd); |
| free(cmd); |
| |
| #endif /* NO_X11 */ |
| } |
| |
| |
| static char *dcop_session(void) { |
| char *empty = strdup(""); |
| #if NO_X11 |
| RAWFB_RET(empty); |
| return empty; |
| #else |
| char list_sessions[] = "dcop --user '%s' --list-sessions"; |
| int len; |
| char *cmd, *host, *user = NULL; |
| char *out, *p, *ds, *dsn = NULL, *sess = NULL, *sess2 = NULL; |
| int db = 0; |
| |
| RAWFB_RET(empty); |
| |
| if (getenv("SESSION_MANAGER")) { |
| return empty; |
| } |
| |
| user = get_user_name(); |
| if (strstr(user, "'") != NULL) { |
| rfbLog("invalid user: %s\n", user); |
| free(user); |
| return empty; |
| } |
| |
| len = strlen(list_sessions) + strlen(user) + 1; |
| cmd = (char *) malloc(len); |
| sprintf(cmd, list_sessions, user); |
| |
| out = strdup(cmd_output(cmd)); |
| free(cmd); |
| free(user); |
| |
| ds = DisplayString(dpy); |
| if (!ds || !strcmp(ds, "")) { |
| ds = getenv("DISPLAY"); |
| } |
| if (!ds) { |
| ds = ":0"; |
| } |
| ds = strdup(ds); |
| p = strrchr(ds, '.'); |
| if (p) *p = '\0'; |
| |
| dsn = strchr(ds, ':'); |
| if (dsn) { |
| *dsn = '_'; |
| } else { |
| free(ds); |
| ds = strdup("_0"); |
| dsn = ds; |
| } |
| if (db) fprintf(stderr, "ds: %s\n", ds); |
| if (db) fprintf(stderr, "dsn: %s\n", dsn); |
| |
| host = this_host(); |
| if (host) { |
| char *h2 = (char *) malloc(strlen(host) + 2 + 1); |
| sprintf(h2, "_%s_", host); |
| free(host); |
| host = h2; |
| } else { |
| host = strdup(""); |
| } |
| if (db) fprintf(stderr, "host: %s\n", host); |
| |
| p = strtok(out, "\n"); |
| while (p) { |
| char *q = strstr(p, ".DCOP"); |
| if (db) fprintf(stderr, "p: %s\n", p); |
| if (q == NULL) { |
| ; |
| } else if (host) { |
| if (strstr(q, host)) { |
| char *r = strstr(p, dsn); |
| int n = strlen(dsn); |
| if(r && !isalnum((int) *(r+n))) { |
| sess = strdup(q); |
| break; |
| } else { |
| if (sess2) { |
| free(sess2); |
| } |
| sess2 = strdup(q); |
| } |
| } |
| } else { |
| char *r = strstr(p, dsn); |
| int n = strlen(dsn); |
| if(r && !isalnum((int) *(r+n))) { |
| sess = strdup(q); |
| break; |
| } |
| } |
| p = strtok(NULL, "\n"); |
| } |
| free(ds); |
| free(out); |
| free(host); |
| if (!sess && sess2) { |
| sess = sess2; |
| } |
| if (!sess || strchr(sess, '\'')) { |
| if (sess) free(sess); |
| sess = strdup("--all-sessions"); |
| } else { |
| len = strlen("--session ") + 2 + strlen(sess) + 1; |
| cmd = (char *) malloc(len); |
| sprintf(cmd, "--session '%s'", sess); |
| free(sess); |
| sess = cmd; |
| } |
| return sess; |
| #endif |
| } |
| |
| static void solid_kde(char *color) { |
| #if NO_X11 |
| RAWFB_RET_VOID |
| if (!color) {} |
| return; |
| #else |
| char set_color[] = |
| "dcop --user '%s' %s kdesktop KBackgroundIface setColor '%s' 1"; |
| char bg_off[] = |
| "dcop --user '%s' %s kdesktop KBackgroundIface setBackgroundEnabled 0"; |
| char bg_on[] = |
| "dcop --user '%s' %s kdesktop KBackgroundIface setBackgroundEnabled 1"; |
| char *cmd, *user = NULL, *sess; |
| int len; |
| |
| RAWFB_RET_VOID |
| |
| user = get_user_name(); |
| if (strstr(user, "'") != NULL) { |
| rfbLog("invalid user: %s\n", user); |
| free(user); |
| return; |
| } |
| |
| set_env("DISPLAY", DisplayString(dpy)); |
| |
| if (! color) { |
| sess = dcop_session(); |
| len = strlen(bg_on) + strlen(user) + strlen(sess) + 1; |
| cmd = (char *) malloc(len); |
| sprintf(cmd, bg_on, user, sess); |
| |
| dt_cmd(cmd); |
| |
| free(cmd); |
| free(user); |
| free(sess); |
| |
| return; |
| } |
| |
| if (strstr(color, "'") != NULL) { |
| rfbLog("invalid color: %s\n", color); |
| return; |
| } |
| |
| sess = dcop_session(); |
| |
| len = strlen(set_color) + strlen(user) + strlen(sess) + strlen(color) + 1; |
| cmd = (char *) malloc(len); |
| sprintf(cmd, set_color, user, sess, color); |
| dt_cmd(cmd); |
| free(cmd); |
| |
| len = strlen(bg_off) + strlen(user) + strlen(sess) + 1; |
| cmd = (char *) malloc(len); |
| sprintf(cmd, bg_off, user, sess); |
| dt_cmd(cmd); |
| free(cmd); |
| free(user); |
| #endif /* NO_X11 */ |
| } |
| |
| void kde_no_animate(int restore) { |
| #if NO_X11 |
| if (!restore) {} |
| RAWFB_RET_VOID |
| return; |
| #else |
| char query_setting[] = |
| "kreadconfig --file kwinrc --group Windows --key AnimateMinimize"; |
| char kwinrc_off[] = |
| "kwriteconfig --file kwinrc --group Windows --key AnimateMinimize --type bool false"; |
| char kwinrc_on[] = |
| "kwriteconfig --file kwinrc --group Windows --key AnimateMinimize --type bool true"; |
| char kwin_reconfigure[] = |
| "dcop --user '%s' %s kwin KWinInterface reconfigure"; |
| char *cmd, *cmd2, *out, *user = NULL, *sess; |
| int len; |
| static int anim_state = 1; |
| |
| RAWFB_RET_VOID |
| |
| if (ncache_keep_anims) { |
| return; |
| } |
| |
| if (restore) { |
| if (anim_state == 1) { |
| return; |
| } |
| |
| user = get_user_name(); |
| if (strstr(user, "'") != NULL) { |
| rfbLog("invalid user: %s\n", user); |
| free(user); |
| return; |
| } |
| |
| sess = dcop_session(); |
| |
| len = strlen(kwin_reconfigure) + strlen(user) + strlen(sess) + 1; |
| cmd = (char *) malloc(len); |
| sprintf(cmd, kwin_reconfigure, user, sess); |
| rfbLog("\n"); |
| rfbLog("Restoring KDE kwinrc settings.\n"); |
| rfbLog("\n"); |
| dt_cmd(cmd); |
| free(cmd); |
| free(user); |
| free(sess); |
| anim_state = 1; |
| return; |
| } else { |
| if (anim_state == 0) { |
| return; |
| } |
| anim_state = 0; |
| } |
| |
| user = get_user_name(); |
| if (strstr(user, "'") != NULL) { |
| rfbLog("invalid user: %s\n", user); |
| free(user); |
| return; |
| } |
| out = cmd_output(query_setting); |
| |
| |
| if (!out || strstr(out, "false")) { |
| rfbLog("\n"); |
| rfbLog("********************************************************\n"); |
| rfbLog("KDE kwinrc AnimateMinimize is false. Good.\n"); |
| rfbLog("********************************************************\n"); |
| rfbLog("\n"); |
| free(user); |
| return; |
| } |
| |
| rfbLog("\n"); |
| rfbLog("********************************************************\n"); |
| rfbLog("To improve the -ncache client-side caching performance\n"); |
| rfbLog("temporarily setting KDE kwinrc AnimateMinimize to false.\n"); |
| rfbLog("It will be reset for the next session or when VNC client\n"); |
| rfbLog("disconnects. Or you can use the Control Center GUI to\n"); |
| rfbLog("change it now (toggle its setting a few times):\n"); |
| rfbLog(" Desktop -> Window Behavior -> Moving\n"); |
| rfbLog("********************************************************\n"); |
| rfbLog("\n"); |
| |
| set_env("DISPLAY", DisplayString(dpy)); |
| |
| sess = dcop_session(); |
| len = strlen(kwin_reconfigure) + strlen(user) + strlen(sess) + 1; |
| cmd = (char *) malloc(len); |
| sprintf(cmd, kwin_reconfigure, user, sess); |
| |
| len = 1 + strlen("sleep 10") + 2 + strlen(kwinrc_off) + 2 + strlen(cmd) + 2 + strlen("sleep 5") + 2 + strlen(kwinrc_on) + 3 + 1; |
| cmd2 = (char *) malloc(len); |
| |
| sprintf(cmd2, "(sleep 10; %s; %s; sleep 5; %s) &", kwinrc_off, cmd, kwinrc_on); |
| |
| dt_cmd(cmd2); |
| free(cmd); |
| free(cmd2); |
| free(user); |
| free(sess); |
| #endif /* NO_X11 */ |
| } |
| |
| void gnome_no_animate(void) { |
| ; |
| } |
| |
| static pid_t solid_macosx_pid = 0; |
| extern char macosx_solid_background[]; |
| |
| static void solid_macosx(int restore) { |
| char tmp[] = "/tmp/macosx_solid_background.XXXXXX"; |
| pid_t pid, parent = getpid(); |
| |
| if (restore) { |
| rfbLog("restore pid: %d\n", (int) solid_macosx_pid); |
| if (solid_macosx_pid > 0) { |
| #if 0 |
| int i, status; |
| #endif |
| rfbLog("kill -TERM macosx_solid_background helper pid: %d\n", (int) solid_macosx_pid); |
| kill(solid_macosx_pid, SIGTERM); |
| #if 0 |
| #if LIBVNCSERVER_HAVE_SYS_WAIT_H |
| #if LIBVNCSERVER_HAVE_WAITPID |
| for (i=0; i < 7; i++) { |
| usleep(1000 * 1000); |
| waitpid(solid_macosx_pid, &status, WNOHANG); |
| if (kill(solid_macosx_pid, 0) != 0) { |
| break; |
| } |
| } |
| #endif |
| #endif |
| #endif |
| solid_macosx_pid = 0; |
| } |
| return; |
| } |
| if (no_external_cmds || !cmd_ok("dt")) { |
| return; |
| } |
| #if LIBVNCSERVER_HAVE_FORK |
| pid = fork(); |
| |
| if (pid == -1) { |
| perror("fork"); |
| return; |
| } |
| if (pid == 0) { |
| int fd = mkstemp(tmp); |
| #if LIBVNCSERVER_HAVE_SETSID |
| setsid(); |
| #else |
| setpgrp(); |
| #endif |
| if (fd >= 0) { |
| char num[32]; |
| write(fd, macosx_solid_background, strlen(macosx_solid_background)); |
| close(fd); |
| sprintf(num, "%d", (int) parent); |
| set_env("SS_WATCH_PID", num); |
| execlp("/bin/sh", "/bin/sh", tmp, (char *) NULL); |
| } |
| exit(1); |
| } |
| solid_macosx_pid = pid; |
| rfbLog("macosx_solid_background helper pid: %d\n", (int) solid_macosx_pid); |
| usleep(2750 * 1000); |
| unlink(tmp); |
| #endif |
| } |
| |
| char *guess_desktop(void) { |
| #if NO_X11 |
| RAWFB_RET("root") |
| return "root"; |
| #else |
| Atom prop; |
| |
| RAWFB_RET("root") |
| |
| if (wmdt_str && *wmdt_str != '\0') { |
| char *s = wmdt_str; |
| lowercase(s); |
| if (strstr(s, "xfce")) { |
| return "xfce"; |
| } |
| if (strstr(s, "gnome") || strstr(s, "metacity")) { |
| return "gnome"; |
| } |
| if (strstr(s, "kde") || strstr(s, "kwin")) { |
| return "kde"; |
| } |
| if (strstr(s, "cde")) { |
| return "cde"; |
| } |
| return "root"; |
| } |
| |
| if (! dpy) { |
| return ""; |
| } |
| |
| prop = XInternAtom(dpy, "XFCE_DESKTOP_WINDOW", True); |
| if (prop != None) return "xfce"; |
| |
| /* special case windowmaker */ |
| prop = XInternAtom(dpy, "_WINDOWMAKER_WM_PROTOCOLS", True); |
| if (prop != None) return "root"; |
| |
| prop = XInternAtom(dpy, "_WINDOWMAKER_COMMAND", True); |
| if (prop != None) return "root"; |
| |
| prop = XInternAtom(dpy, "NAUTILUS_DESKTOP_WINDOW_ID", True); |
| if (prop != None) return "gnome"; |
| |
| prop = XInternAtom(dpy, "KWIN_RUNNING", True); |
| if (prop != None) { |
| prop = XInternAtom(dpy, "_KDE_RUNNING", True); |
| if (prop != None) { |
| prop = XInternAtom(dpy, "KDE_DESKTOP_WINDOW", True); |
| if (prop != None) return "kde"; |
| } |
| } |
| |
| prop = XInternAtom(dpy, "_MOTIF_WM_INFO", True); |
| if (prop != None) { |
| prop = XInternAtom(dpy, "_DT_WORKSPACE_LIST", True); |
| if (prop != None) return "cde"; |
| } |
| return "root"; |
| #endif /* NO_X11 */ |
| } |
| |
| XImage *solid_image(char *color) { |
| #if NO_X11 |
| RAWFB_RET(NULL) |
| return NULL; |
| #else |
| XImage *image = NULL; |
| unsigned long pixel = 0; |
| int x, y; |
| |
| RAWFB_RET(NULL) |
| |
| if (!color) { |
| color = last_color; |
| } |
| |
| if (!color) { |
| return NULL; |
| } |
| |
| image = XGetImage(dpy, rootwin, 0, 0, wdpy_x, wdpy_y, AllPlanes, |
| ZPixmap); |
| |
| if (!image) { |
| return NULL; |
| } |
| pixel = get_pixel(color); |
| |
| for (y=0; y<wdpy_y; y++) { |
| for (x=0; x<wdpy_x; x++) { |
| XPutPixel(image, x, y, pixel); |
| } |
| } |
| return image; |
| #endif /* NO_X11 */ |
| } |
| |
| void solid_bg(int restore) { |
| static int desktop = -1; |
| static int solid_on = 0; |
| static char *prev_str; |
| char *dtname, *color; |
| |
| if (started_as_root == 1 && users_list) { |
| /* we are still root, don't try. */ |
| return; |
| } |
| |
| if (macosx_console) { |
| solid_macosx(restore); |
| return; |
| } |
| |
| RAWFB_RET_VOID |
| |
| if (restore) { |
| if (! solid_on) { |
| return; |
| } |
| if (desktop == 0) { |
| solid_root(NULL); |
| } else if (desktop == 1) { |
| solid_gnome(NULL); |
| } else if (desktop == 2) { |
| solid_kde(NULL); |
| } else if (desktop == 3) { |
| solid_cde(NULL); |
| } else if (desktop == 4) { |
| solid_xfce(NULL); |
| } |
| solid_on = 0; |
| return; |
| } |
| if (! solid_str) { |
| return; |
| } |
| if (solid_on && !strcmp(prev_str, solid_str)) { |
| return; |
| } |
| if (strstr(solid_str, "guess:") == solid_str |
| || !strchr(solid_str, ':')) { |
| dtname = guess_desktop(); |
| rfbLog("guessed desktop: %s\n", dtname); |
| } else { |
| if (strstr(solid_str, "gnome:") == solid_str) { |
| dtname = "gnome"; |
| } else if (strstr(solid_str, "kde:") == solid_str) { |
| dtname = "kde"; |
| } else if (strstr(solid_str, "cde:") == solid_str) { |
| dtname = "cde"; |
| } else if (strstr(solid_str, "xfce:") == solid_str) { |
| dtname = "xfce"; |
| } else { |
| dtname = "root"; |
| } |
| } |
| |
| color = strchr(solid_str, ':'); |
| if (! color) { |
| color = solid_str; |
| } else { |
| color++; |
| if (*color == '\0') { |
| color = solid_default; |
| } |
| } |
| if (last_color) { |
| free(last_color); |
| } |
| last_color = strdup(color); |
| |
| if (!strcmp(dtname, "gnome")) { |
| desktop = 1; |
| solid_gnome(color); |
| } else if (!strcmp(dtname, "kde")) { |
| desktop = 2; |
| solid_kde(color); |
| } else if (!strcmp(dtname, "cde")) { |
| desktop = 3; |
| solid_cde(color); |
| } else if (!strcmp(dtname, "xfce")) { |
| desktop = 4; |
| solid_xfce(color); |
| } else { |
| desktop = 0; |
| solid_root(color); |
| } |
| if (prev_str) { |
| free(prev_str); |
| } |
| prev_str = strdup(solid_str); |
| solid_on = 1; |
| } |
| |
| |