summaryrefslogtreecommitdiffstats
path: root/x11vnc/appshare.c
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc/appshare.c')
-rw-r--r--x11vnc/appshare.c2124
1 files changed, 0 insertions, 2124 deletions
diff --git a/x11vnc/appshare.c b/x11vnc/appshare.c
deleted file mode 100644
index 71cdf17..0000000
--- a/x11vnc/appshare.c
+++ /dev/null
@@ -1,2124 +0,0 @@
-/*
- 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.
-*/
-
-/* -- appshare.c -- */
-
-#include "x11vnc.h"
-
-extern int pick_windowid(unsigned long *num);
-extern char *get_xprop(char *prop, Window win);
-extern int set_xprop(char *prop, Window win, char *value);
-extern void set_env(char *name, char *value);
-extern double dnow(void);
-
-static char *usage =
-"\n"
-" x11vnc -appshare: an experiment in application sharing via x11vnc.\n"
-"\n"
-#if !SMALL_FOOTPRINT
-" Usage: x11vnc -appshare -id windowid -connect viewer_host:0\n"
-" x11vnc -appshare -id pick -connect viewer_host:0\n"
-"\n"
-" Both the -connect option and the -id (or -sid) option are required.\n"
-" (However see the -control option below that can replace -connect.)\n"
-"\n"
-" The VNC viewer at viewer_host MUST be in 'listen' mode. This is because\n"
-" a new VNC connection (and viewer window) is established for each new\n"
-" toplevel window that the application creates. For example:\n"
-"\n"
-" vncviewer -listen 0\n"
-"\n"
-" The '-connect viewer_host:0' indicates the listening viewer to connect to.\n"
-"\n"
-" No password should be used, otherwise it will need to be typed for each\n"
-" new window (or one could use vncviewer -passwd file if the viewer supports\n"
-" that.) For security an SSH tunnel can be used:\n"
-"\n"
-" ssh -R 5500:localhost:5500 user@server_host\n"
-"\n"
-" (then use -connect localhost:0)\n"
-"\n"
-" The -id/-sid option is as in x11vnc(1). It is either a numerical window\n"
-" id or the string 'pick' which will ask the user to click on an app window.\n"
-" To track more than one application at the same time, list their window ids\n"
-" separated by commas (see also the 'add_app' command below.)\n"
-"\n"
-" Additional options:\n"
-"\n"
-" -h, -help Print this help.\n"
-" -debug Print debugging output (same as X11VNC_APPSHARE_DEBUG=1)\n"
-" -showmenus Create a new viewer window even if a new window is\n"
-" completely inside of an existing one. Default is to\n"
-" try to not show them in a new viewer window.\n"
-" -noexit Do not exit if the main app (windowid/pick) window\n"
-" goes away. Default is to exit.\n"
-" -display dpy X DISPLAY to use.\n"
-" -trackdir dir Set tracking directory to 'dir'. x11vnc -appshare does\n"
-" better if it can communicate with the x11vnc's via a\n"
-" file channel. By default a dir in /tmp is used, -trackdir\n"
-" specifies another directory, or use 'none' to disable.\n"
-" -args 'string' Pass options 'string' to x11vnc (e.g. -scale 3/4,\n"
-" -viewonly, -wait, -once, etc.)\n"
-" -env VAR=VAL Set environment variables on cmdline as in x11vnc.\n"
-"\n"
-" -control file This is a file that one edits to manage the appshare\n"
-" mode. It replaces -connect. Lines beginning with '#'\n"
-" are ignored. Initially start off with all of the\n"
-" desired clients in the file, one per line. If you add\n"
-" a new client-line, that client is connected to. If you\n"
-" delete (or comment out) a client-line, that client is\n"
-" disconnected (for this to work, do not disable trackdir.)\n"
-"\n"
-" You can also put cmd= lines in the control file to perform\n"
-" different actions. These are supported:\n"
-"\n"
-" cmd=quit Disconnect all clients and exit.\n"
-" cmd=restart Restart all of the x11vnc's.\n"
-" cmd=noop Do nothing (e.g. ping)\n"
-" cmd=x11vnc Run ps(1) looking for x11vnc's\n"
-" cmd=help Print out help text.\n"
-" cmd=add_window:win Add a window to be watched.\n"
-" cmd=del_window:win Delete a window.\n"
-" cmd=add_app:win Add an application to be watched.\n"
-" cmd=del_app:win Delete an application.\n"
-" cmd=add_client:host Add client ('internal' mode only)\n"
-" cmd=del_client:host Del client ('internal' mode only)\n"
-" cmd=list_windows List all tracked windows.\n"
-" cmd=list_apps List all tracked applications.\n"
-" cmd=list_clients List all connected clients.\n"
-" cmd=list_all List all three.\n"
-" cmd=print_logs Print out the x11vnc logfiles.\n"
-" cmd=debug:n Set -debug to n (0 or 1).\n"
-" cmd=showmenus:n Set -showmenus to n (0 or 1).\n"
-" cmd=noexit:n Set -noexit to n (0 or 1).\n"
-"\n"
-" See the '-command internal' mode described below for a way\n"
-" that tracks connected clients internally (not in a file.)\n"
-"\n"
-" In '-shell' mode (see below) you can type in the above\n"
-" without the leading 'cmd='.\n"
-"\n"
-" For 'add_window' and 'del_window' the 'win' can be a\n"
-" numerical window id or 'pick'. Same for 'add_app'. Be\n"
-" sure to remove or comment out the add/del line quickly\n"
-" (e.g. before picking) or it will be re-run the next time\n"
-" the file is processed.\n"
-"\n"
-" If a file with the same name as the control file but\n"
-" ending with suffix '.cmd' is found, then commands in it\n"
-" (cmd=...) are processed and then the file is truncated.\n"
-" This allows 'one time' command actions to be run. Any\n"
-" client hostnames in the '.cmd' file are ignored. Also\n"
-" see below for the X11VNC_APPSHARE_COMMAND X property\n"
-" which is similar to '.cmd'\n"
-"\n"
-" -control internal Manage connected clients internally, see below.\n"
-" -control shell Same as: -shell -control internal\n"
-"\n"
-" -delay secs Maximum timeout delay before re-checking the control file.\n"
-" It can be a fraction, e.g. -delay 0.25 Default 0.5\n"
-"\n"
-" -shell Simple command line for '-control internal' mode (see the\n"
-" details of this mode below.) Enter '?' for command list.\n"
-"\n"
-" To stop x11vnc -appshare press Ctrl-C, or (if -noexit not supplied) delete\n"
-" the initial app window or exit the application. Or cmd=quit in -control mode.\n"
-"\n"
-#if 0
-" If you want your setup to survive periods of time where there are no clients\n"
-" connected you will need to supply -args '-forever' otherwise the x11vnc's\n"
-" will exit when the last client disconnects. Howerver, _starting_ with no\n"
-" clients (e.g. empty control file) will work without -args '-forever'.\n"
-"\n"
-#endif
-" In addition to the '.cmd' file channel, for faster response you can set\n"
-" X11VNC_APPSHARE_COMMAND X property on the root window to the string that\n"
-" would go into the '.cmd' file. For example:\n"
-"\n"
-" xprop -root -f X11VNC_APPSHARE_COMMAND 8s -set X11VNC_APPSHARE_COMMAND cmd=quit\n"
-"\n"
-" The property value will be set to 'DONE' after the command(s) is processed.\n"
-"\n"
-" If -control file is specified as 'internal' then no control file is used\n"
-" and client tracking is done internally. You must add and delete clients\n"
-" with the cmd=add_client:<client> and cmd=del_client:<client> commands.\n"
-" Note that '-control internal' is required for '-shell' mode. Using\n"
-" '-control shell' implies internal mode and -shell.\n"
-"\n"
-" Limitations:\n"
-"\n"
-" This is a quick lash-up, many things will not work properly.\n"
-"\n"
-" The main idea is to provide simple application sharing for two or more\n"
-" parties to collaborate without needing to share the entire desktop. It\n"
-" provides an improvement over -id/-sid that only shows a single window.\n"
-"\n"
-" Only reverse connections can be done. (Note: one can specify multiple\n"
-" viewing hosts via: -connect host1,host2,host3 or add/remove them\n"
-" dynamically as described above.)\n"
-"\n"
-" If a new window obscures an old one, you will see some or all of the\n"
-" new window in the old one. The hope is this is a popup dialog or menu\n"
-" that will go away soon. Otherwise a user at the physical display will\n"
-" need to move it. (See also the SSVNC viewer features described below.) \n"
-"\n"
-" The viewer side cannot resize or make windows move on the physical\n"
-" display. Again, a user at the physical display may need to help, or\n"
-" use the SSVNC viewer (see Tip below.)\n"
-"\n"
-" Tip: If the application has its own 'resize corner', then dragging\n"
-" it may successfully resize the application window.\n"
-" Tip: Some desktop environments enable moving a window via, say,\n"
-" Alt+Left-Button-Drag. One may be able to move a window this way.\n"
-" Also, e.g., Alt+Right-Button-Drag may resize a window.\n"
-" Tip: Clicking on part of an obscured window may raise it to the top.\n"
-" Also, e.g., Alt+Middle-Button may toggle Raise/Lower.\n"
-"\n"
-" Tip: The SSVNC 1.0.25 unix and macosx vncviewer has 'EscapeKeys' hot\n"
-" keys that will move, resize, raise, and lower the window via the\n"
-" x11vnc -remote_prefix X11VNC_APPSHARE_CMD: feature. So in the\n"
-" viewer while holding down Shift_L+Super_L+Alt_L the arrow keys\n"
-" move the window, PageUp/PageDn/Home/End resize it, and - and +\n"
-" raise and lower it. Key 'M' or Button1 moves the remote window\n"
-" to the +X+Y of the viewer window. Key 'D' or Button3 deletes\n"
-" the remote window.\n"
-"\n"
-" You can run the SSVNC vncviewer with options '-escape default',\n"
-" '-multilisten' and '-env VNCVIEWER_MIN_TITLE=1'; or just run\n"
-" with option '-appshare' to enable these and automatic placement.\n"
-"\n"
-" If any part of a window goes off of the display screen, then x11vnc\n"
-" may be unable to poll it (without crashing), and so the window will\n"
-" stop updating until the window is completely on-screen again.\n"
-"\n"
-" The (stock) vnc viewer does not know where to best position each new\n"
-" viewer window; it likely centers each one (including when resized.)\n"
-" Note: The SSVNC viewer in '-appshare' mode places them correctly.\n"
-"\n"
-" Deleting a viewer window does not delete the real window.\n"
-" Note: The SSVNC viewer Shift+EscapeKeys+Button3 deletes it.\n"
-"\n"
-" Sometimes new window detection fails.\n"
-"\n"
-" Sometimes menu/popup detection fails.\n"
-"\n"
-" Sometimes the contents of a menu/popup window have blacked-out regions.\n"
-" Try -sid or -showmenus as a workaround.\n"
-"\n"
-" If the application starts up a new application (a different process)\n"
-" that new application will not be tracked (but, unfortunately, it may\n"
-" cover up existing windows that are being tracked.) See cmd=add_window\n"
-" and cmd=add_app described above.\n"
-"\n"
-#endif
-;
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define WMAX 192
-#define CMAX 128
-#define AMAX 32
-
-static Window root = None;
-static Window watch[WMAX];
-static Window apps[WMAX];
-static int state[WMAX];
-static char *clients[CMAX];
-static XWindowAttributes attr;
-static char *ticker_atom_str = "X11VNC_APPSHARE_TICKER";
-static Atom ticker_atom = None;
-static char *cmd_atom_str = "X11VNC_APPSHARE_COMMAND";
-static Atom cmd_atom = None;
-static char *connect_to = NULL;
-static char *x11vnc_args = "";
-static char *id_opt = "-id";
-static int skip_menus = 1;
-static int exit_no_app_win = 1;
-static int shell = 0;
-static int tree_depth = 3;
-static char *prompt = "appshare> ";
-static char *x11vnc = "x11vnc";
-static char *control = NULL;
-static char *trackdir = "unset";
-static char *trackpre = "/tmp/x11vnc-appshare-trackdir-tmp";
-static char *tracktmp = NULL;
-static char unique_tag[100];
-static int use_forever = 1;
-static int last_event_type = 0;
-static pid_t helper_pid = 0;
-static pid_t parent_pid = 0;
-static double helper_delay = 0.5;
-static int appshare_debug = 0;
-static double start_time = 0.0;
-
-static void get_wm_name(Window win, char **name);
-static int win_attr(Window win);
-static int get_xy(Window win, int *x, int *y);
-static Window check_inside(Window win);
-static int ours(Window win);
-static void destroy_win(Window win);
-static int same_app(Window win, Window app);
-
-static void ff(void) {
- fflush(stdout);
- fflush(stderr);
-}
-
-static int find_win(Window win) {
- int i;
- for (i=0; i < WMAX; i++) {
- if (watch[i] == win) {
- return i;
- }
- }
- return -1;
-}
-
-static int find_app(Window app) {
- int i;
- for (i=0; i < AMAX; i++) {
- if (apps[i] == app) {
- return i;
- }
- }
- return -1;
-}
-
-static int find_client(char *cl) {
- int i;
- for (i=0; i < CMAX; i++) {
- if (cl == NULL) {
- if (clients[i] == NULL) {
- return i;
- }
- continue;
- }
- if (clients[i] == NULL) {
- continue;
- }
- if (!strcmp(clients[i], cl)) {
- return i;
- }
- }
- return -1;
-}
-
-static int trackdir_pid(Window win) {
- FILE *f;
- int ln = 0, pid = 0;
- char line[1024];
-
- if (!trackdir) {
- return 0;
- }
- sprintf(tracktmp, "%s/0x%lx.log", trackdir, win);
- f = fopen(tracktmp, "r");
- if (!f) {
- return 0;
- }
- while (fgets(line, sizeof(line), f) != NULL) {
- if (ln++ > 30) {
- break;
- }
- if (strstr(line, "x11vnc version:")) {
- char *q = strstr(line, "pid:");
- if (q) {
- int p;
- if (sscanf(q, "pid: %d", &p) == 1) {
- if (p > 0) {
- pid = p;
- break;
- }
- }
- }
- }
- }
- fclose(f);
- return pid;
-}
-
-static void trackdir_cleanup(Window win) {
- char *suffix[] = {"log", "connect", NULL};
- int i=0;
- if (!trackdir) {
- return;
- }
- while (suffix[i] != NULL) {
- sprintf(tracktmp, "%s/0x%lx.%s", trackdir, win, suffix[i]);
- if (appshare_debug && !strcmp(suffix[i], "log")) {
- fprintf(stderr, "keeping: %s\n", tracktmp);
- ff();
- } else {
- if (appshare_debug) {
- fprintf(stderr, "removing: %s\n", tracktmp);
- ff();
- }
- unlink(tracktmp);
- }
- i++;
- }
-}
-
-static void launch(Window win) {
- char *cmd, *tmp, *connto, *name;
- int len, timeo = 30, uf = use_forever;
- int w = 0, h = 0, x = 0, y = 0;
-
- if (win_attr(win)) {
- /* maybe switch to debug only. */
- w = attr.width;
- h = attr.height;
- get_xy(win, &x, &y);
- }
-
- get_wm_name(win, &name);
-
- if (strstr(x11vnc_args, "-once")) {
- uf = 0;
- }
-
- if (control) {
- int i = 0;
- len = 0;
- for (i=0; i < CMAX; i++) {
- if (clients[i] != NULL) {
- len += strlen(clients[i]) + 2;
- }
- }
- connto = (char *) calloc(len, 1);
- for (i=0; i < CMAX; i++) {
- if (clients[i] != NULL) {
- if (connto[0] != '\0') {
- strcat(connto, ",");
- }
- strcat(connto, clients[i]);
- }
- }
- } else {
- connto = strdup(connect_to);
- }
- if (!strcmp(connto, "")) {
- timeo = 0;
- }
- if (uf) {
- timeo = 0;
- }
-
- len = 1000 + strlen(x11vnc) + strlen(connto) + strlen(x11vnc_args)
- + 3 * (trackdir ? strlen(trackdir) : 100);
-
- cmd = (char *) calloc(len, 1);
- tmp = (char *) calloc(len, 1);
-
- sprintf(cmd, "%s %s 0x%lx -bg -quiet %s -nopw -rfbport 0 "
- "-timeout %d -noxdamage -noxinerama -norc -repeat -speeds dsl "
- "-env X11VNC_AVOID_WINDOWS=never -env X11VNC_APPSHARE_ACTIVE=1 "
- "-env X11VNC_NO_CHECK_PM=1 -env %s -novncconnect -shared -nonap "
- "-remote_prefix X11VNC_APPSHARE_CMD:",
- x11vnc, id_opt, win, use_forever ? "-forever" : "-once", timeo, unique_tag);
-
- if (trackdir) {
- FILE *f;
- sprintf(tracktmp, " -noquiet -o %s/0x%lx.log", trackdir, win);
- strcat(cmd, tracktmp);
- sprintf(tracktmp, "%s/0x%lx.connect", trackdir, win);
- f = fopen(tracktmp, "w");
- if (f) {
- fprintf(f, "%s", connto);
- fclose(f);
- sprintf(tmp, " -connect_or_exit '%s'", tracktmp);
- strcat(cmd, tmp);
- } else {
- sprintf(tmp, " -connect_or_exit '%s'", connto);
- strcat(cmd, tmp);
- }
- } else {
- if (!strcmp(connto, "")) {
- sprintf(tmp, " -connect '%s'", connto);
- } else {
- sprintf(tmp, " -connect_or_exit '%s'", connto);
- }
- strcat(cmd, tmp);
- }
- if (uf) {
- char *q = strstr(cmd, "-connect_or_exit");
- if (q) q = strstr(q, "_or_exit");
- if (q) {
- unsigned int i;
- for (i=0; i < strlen("_or_exit"); i++) {
- *q = ' ';
- q++;
- }
- }
- }
-
- strcat(cmd, " ");
- strcat(cmd, x11vnc_args);
-
- fprintf(stdout, "launching: x11vnc for window 0x%08lx %dx%d+%d+%d \"%s\"\n",
- win, w, h, x, y, name);
-
- if (appshare_debug) {
- fprintf(stderr, "\nrunning: %s\n\n", cmd);
- }
- ff();
-
- system(cmd);
-
- free(cmd);
- free(tmp);
- free(connto);
- free(name);
-}
-
-static void stop(Window win) {
- char *cmd;
- int pid = -1;
- int f = find_win(win);
- if (f < 0 || win == None) {
- return;
- }
- if (state[f] == 0) {
- return;
- }
- if (trackdir) {
- pid = trackdir_pid(win);
- if (pid > 0) {
- if (appshare_debug) {fprintf(stderr,
- "sending SIGTERM to: %d\n", pid); ff();}
- kill((pid_t) pid, SIGTERM);
- }
- }
-
- cmd = (char *) malloc(1000 + strlen(x11vnc));
- sprintf(cmd, "pkill -TERM -f '%s %s 0x%lx -bg'", x11vnc, id_opt, win);
- if (appshare_debug) {
- fprintf(stdout, "stopping: 0x%08lx - %s\n", win, cmd);
- } else {
- fprintf(stdout, "stopping: x11vnc for window 0x%08lx "
- "(pid: %d)\n", win, pid);
- }
- ff();
- system(cmd);
-
- sprintf(cmd, "(sleep 0.25 2>/dev/null || sleep 1; pkill -KILL -f '%s "
- "%s 0x%lx -bg') &", x11vnc, id_opt, win);
- system(cmd);
-
- if (trackdir) {
- trackdir_cleanup(win);
- }
-
- free(cmd);
-}
-
-static void kill_helper_pid(void) {
- int status;
- if (helper_pid <= 0) {
- return;
- }
- fprintf(stderr, "stopping: helper_pid: %d\n", (int) helper_pid);
- kill(helper_pid, SIGTERM);
- usleep(50 * 1000);
- kill(helper_pid, SIGKILL);
- usleep(25 * 1000);
-#if LIBVNCSERVER_HAVE_SYS_WAIT_H && LIBVNCSERVER_HAVE_WAITPID
- waitpid(helper_pid, &status, WNOHANG);
-#endif
-}
-
-static void be_helper_pid(char *dpy_str) {
- int cnt = 0;
- int ms = (int) (1000 * helper_delay);
- double last_check = 0.0;
-
- if (ms < 50) ms = 50;
-
-#if NO_X11
- fprintf(stderr, "be_helper_pid: not compiled with X11.\n");
-#else
- dpy = XOpenDisplay(dpy_str);
- ticker_atom = XInternAtom(dpy, ticker_atom_str, False);
-
- while (1) {
- char tmp[32];
- sprintf(tmp, "HELPER_CNT_%08d", cnt++);
- XChangeProperty(dpy, DefaultRootWindow(dpy), ticker_atom, XA_STRING, 8,
- PropModeReplace, (unsigned char *) tmp, strlen(tmp));
- XFlush(dpy);
- usleep(ms*1000);
- if (parent_pid > 0) {
- if(dnow() > last_check + 1.0) {
- last_check = dnow();
- if (kill(parent_pid, 0) != 0) {
- fprintf(stderr, "be_helper_pid: parent %d is gone.\n", (int) parent_pid);
- break;
- }
- }
- }
- }
-#endif
- exit(0);
-}
-
-static void print_logs(void) {
- if (trackdir) {
- DIR *dir = opendir(trackdir);
- if (dir) {
- struct dirent *dp;
- while ( (dp = readdir(dir)) != NULL) {
- FILE *f;
- char *name = dp->d_name;
- if (!strcmp(name, ".") || !strcmp(name, "..")) {
- continue;
- }
- if (strstr(name, "0x") != name) {
- continue;
- }
- if (strstr(name, ".log") == NULL) {
- continue;
- }
- sprintf(tracktmp, "%s/%s", trackdir, name);
- f = fopen(tracktmp, "r");
- if (f) {
- char line[1024];
- fprintf(stderr, "===== x11vnc log %s =====\n", tracktmp);
- while (fgets(line, sizeof(line), f) != NULL) {
- fprintf(stderr, "%s", line);
- }
- fprintf(stderr, "\n");
- ff();
- fclose(f);
- }
- }
- closedir(dir);
- }
- }
-}
-
-static void appshare_cleanup(int s) {
- int i;
- if (s) {}
-
- if (use_forever) {
- /* launch this backup in case they kill -9 us before we terminate everything */
- char cmd[1000];
- sprintf(cmd, "(sleep 3; pkill -TERM -f '%s') &", unique_tag);
- if (appshare_debug) fprintf(stderr, "%s\n", cmd);
- system(cmd);
- }
-
- for (i=0; i < WMAX; i++) {
- if (watch[i] != None) {
- stop(watch[i]);
- }
- }
-
- if (trackdir) {
- DIR *dir = opendir(trackdir);
- if (dir) {
- struct dirent *dp;
- while ( (dp = readdir(dir)) != NULL) {
- char *name = dp->d_name;
- if (!strcmp(name, ".") || !strcmp(name, "..")) {
- continue;
- }
- if (strstr(name, "0x") != name) {
- fprintf(stderr, "skipping: %s\n", name);
- continue;
- }
- if (!appshare_debug) {
- fprintf(stderr, "removing: %s\n", name);
- sprintf(tracktmp, "%s/%s", trackdir, name);
- unlink(tracktmp);
- } else {
- if (appshare_debug) fprintf(stderr, "keeping: %s\n", name);
- }
- }
- closedir(dir);
- }
- if (!appshare_debug) {
- if (strstr(trackdir, trackpre) == trackdir) {
- if (appshare_debug) fprintf(stderr, "removing: %s\n", trackdir);
- rmdir(trackdir);
- }
- }
- ff();
- }
-
- kill_helper_pid();
-
-#if !NO_X11
- XCloseDisplay(dpy);
-#endif
- fprintf(stdout, "done.\n");
- ff();
- exit(0);
-}
-
-static int trap_xerror(Display *d, XErrorEvent *error) {
- if (d || error) {}
- return 0;
-}
-
-#if 0
-typedef struct {
- int x, y; /* location of window */
- int width, height; /* width and height of window */
- int border_width; /* border width of window */
- int depth; /* depth of window */
- Visual *visual; /* the associated visual structure */
- Window root; /* root of screen containing window */
- int class; /* InputOutput, InputOnly*/
- int bit_gravity; /* one of bit gravity values */
- int win_gravity; /* one of the window gravity values */
- int backing_store; /* NotUseful, WhenMapped, Always */
- unsigned long backing_planes;/* planes to be preserved if possible */
- unsigned long backing_pixel;/* value to be used when restoring planes */
- Bool save_under; /* boolean, should bits under be saved? */
- Colormap colormap; /* color map to be associated with window */
- Bool map_installed; /* boolean, is color map currently installed*/
- int map_state; /* IsUnmapped, IsUnviewable, IsViewable */
- long all_event_masks; /* set of events all people have interest in*/
- long your_event_mask; /* my event mask */
- long do_not_propagate_mask; /* set of events that should not propagate */
- Bool override_redirect; /* boolean value for override-redirect */
- Screen *screen; /* back pointer to correct screen */
-} XWindowAttributes;
-#endif
-
-static void get_wm_name(Window win, char **name) {
- int ok;
-
-#if !NO_X11
- XErrorHandler old_handler = XSetErrorHandler(trap_xerror);
- ok = XFetchName(dpy, win, name);
- XSetErrorHandler(old_handler);
-#endif
-
- if (!ok || *name == NULL) {
- *name = strdup("unknown");
- }
-}
-
-static int win_attr(Window win) {
- int ok = 0;
-#if !NO_X11
- XErrorHandler old_handler = XSetErrorHandler(trap_xerror);
- ok = XGetWindowAttributes(dpy, win, &attr);
- XSetErrorHandler(old_handler);
-#endif
-
- if (ok) {
- return 1;
- } else {
- return 0;
- }
-}
-
-static void win_select(Window win, int ignore) {
-#if !NO_X11
- XErrorHandler old_handler = XSetErrorHandler(trap_xerror);
- if (ignore) {
- XSelectInput(dpy, win, 0);
- } else {
- XSelectInput(dpy, win, SubstructureNotifyMask);
- }
- XSync(dpy, False);
- XSetErrorHandler(old_handler);
-#endif
-}
-
-static Window get_parent(Window win) {
- int ok;
- Window r, parent = None, *list = NULL;
- unsigned int nchild;
-
-#if !NO_X11
- XErrorHandler old_handler = XSetErrorHandler(trap_xerror);
- ok = XQueryTree(dpy, win, &r, &parent, &list, &nchild);
- XSetErrorHandler(old_handler);
-
- if (!ok) {
- return None;
- }
- if (list) {
- XFree(list);
- }
-#endif
- return parent;
-}
-
-static int get_xy(Window win, int *x, int *y) {
- Window cr;
- Bool rc = False;
-#if !NO_X11
- XErrorHandler old_handler = XSetErrorHandler(trap_xerror);
-
- rc = XTranslateCoordinates(dpy, win, root, 0, 0, x, y, &cr);
- XSetErrorHandler(old_handler);
-#endif
-
- if (!rc) {
- return 0;
- } else {
- return 1;
- }
-}
-
-static Window check_inside(Window win) {
- int i, nwin = 0;
- int w, h, x, y;
- int Ws[WMAX], Hs[WMAX], Xs[WMAX], Ys[WMAX];
- Window wins[WMAX];
-
- if (!win_attr(win)) {
- return None;
- }
-
- /* store them first to give the win app more time to settle. */
- for (i=0; i < WMAX; i++) {
- int X, Y;
- Window wchk = watch[i];
- if (wchk == None) {
- continue;
- }
- if (state[i] == 0) {
- continue;
- }
- if (!win_attr(wchk)) {
- continue;
- }
- if (!get_xy(wchk, &X, &Y)) {
- continue;
- }
-
- Xs[nwin] = X;
- Ys[nwin] = Y;
- Ws[nwin] = attr.width;
- Hs[nwin] = attr.height;
- wins[nwin] = wchk;
- nwin++;
- }
-
- if (nwin == 0) {
- return None;
- }
-
- if (!win_attr(win)) {
- return None;
- }
- w = attr.width;
- h = attr.height;
-
- get_xy(win, &x, &y);
- if (!get_xy(win, &x, &y)) {
- return None;
- }
-
- for (i=0; i < nwin; i++) {
- int X, Y, W, H;
- Window wchk = wins[i];
- X = Xs[i];
- Y = Ys[i];
- W = Ws[i];
- H = Hs[i];
-
- if (appshare_debug) fprintf(stderr, "check inside: 0x%lx %dx%d+%d+%d %dx%d+%d+%d\n", wchk, w, h, x, y, W, H, X, Y);
-
- if (X <= x && Y <= y) {
- if (x + w <= X + W && y + h < Y + H) {
- return wchk;
- }
- }
- }
-
- return None;
-}
-
-static void add_win(Window win) {
- int idx = find_win(win);
- int free = find_win(None);
- if (idx >= 0) {
- if (appshare_debug) {fprintf(stderr, "already watching window: 0x%lx\n", win); ff();}
- return;
- }
- if (free < 0) {
- fprintf(stderr, "ran out of slots for window: 0x%lx\n", win); ff();
- return;
- }
-
- if (appshare_debug) {fprintf(stderr, "watching: 0x%lx at %d\n", win, free); ff();}
-
- watch[free] = win;
- state[free] = 0;
-
- win_select(win, 0);
-}
-
-static void delete_win(Window win) {
- int i;
- for (i=0; i < WMAX; i++) {
- if (watch[i] == win) {
- watch[i] = None;
- state[i] = 0;
- if (appshare_debug) {fprintf(stderr, "deleting: 0x%lx at %d\n", win, i); ff();}
- }
- }
-}
-
-static void recurse_search(int level, int level_max, Window top, Window app, int *nw) {
- Window w, r, parent, *list = NULL;
- unsigned int nchild;
- int ok = 0;
-
- if (appshare_debug > 1) {
- fprintf(stderr, "level: %d level_max: %d top: 0x%lx app: 0x%lx\n", level, level_max, top, app);
- }
- if (level >= level_max) {
- return;
- }
-
-#if !NO_X11
- ok = XQueryTree(dpy, top, &r, &parent, &list, &nchild);
- if (ok) {
- int i;
- for (i=0; i < (int) nchild; i++) {
- w = list[i];
- if (w == None || find_win(w) >= 0) {
- continue;
- }
- if (ours(w) && w != app) {
- if (appshare_debug) fprintf(stderr, "add level %d 0x%lx %d/%d\n",
- level, w, i, nchild);
- add_win(w);
- (*nw)++;
- }
- }
- for (i=0; i < (int) nchild; i++) {
- w = list[i];
- if (w == None || ours(w)) {
- continue;
- }
- recurse_search(level+1, level_max, w, app, nw);
- }
- }
- if (list) {
- XFree(list);
- }
-#endif
-}
-
-static void add_app(Window app) {
- int i, nw = 0, free = -1;
- XErrorHandler old_handler;
-
-#if !NO_X11
- i = find_app(app);
- if (i >= 0) {
- fprintf(stderr, "already tracking app: 0x%lx\n", app);
- return;
- }
- for (i=0; i < AMAX; i++) {
- if (same_app(apps[i], app)) {
- fprintf(stderr, "already tracking app: 0x%lx via 0x%lx\n", app, apps[i]);
- return;
- }
- }
- free = find_app(None);
- if (free < 0) {
- fprintf(stderr, "ran out of app slots.\n");
- return;
- }
- apps[free] = app;
-
- add_win(app);
-
- old_handler = XSetErrorHandler(trap_xerror);
- recurse_search(0, tree_depth, root, app, &nw);
- XSetErrorHandler(old_handler);
-#endif
- fprintf(stderr, "tracking %d windows related to app window 0x%lx\n", nw, app);
-}
-
-static void del_app(Window app) {
- int i;
- for (i=0; i < WMAX; i++) {
- Window win = watch[i];
- if (win != None) {
- if (same_app(app, win)) {
- destroy_win(win);
- }
- }
- }
- for (i=0; i < AMAX; i++) {
- Window app2 = apps[i];
- if (app2 != None) {
- if (same_app(app, app2)) {
- apps[i] = None;
- }
- }
- }
-}
-
-static void wait_until_empty(char *file) {
- double t = 0.0, dt = 0.05;
- while (t < 1.0) {
- struct stat sb;
- if (stat(file, &sb) != 0) {
- return;
- }
- if (sb.st_size == 0) {
- return;
- }
- t += dt;
- usleep( (int) (dt * 1000 * 1000) );
- }
-}
-
-static void client(char *client, int add) {
- DIR *dir;
- struct dirent *dp;
-
- if (!client) {
- return;
- }
- if (!trackdir) {
- fprintf(stderr, "no trackdir, cannot %s client: %s\n",
- add ? "add" : "disconnect", client);
- ff();
- return;
- }
- fprintf(stdout, "%s client: %s\n", add ? "adding " : "deleting", client);
-
- dir = opendir(trackdir);
- if (!dir) {
- fprintf(stderr, "could not opendir trackdir: %s\n", trackdir);
- return;
- }
- while ( (dp = readdir(dir)) != NULL) {
- char *name = dp->d_name;
- if (!strcmp(name, ".") || !strcmp(name, "..")) {
- continue;
- }
- if (strstr(name, "0x") != name) {
- continue;
- }
- if (strstr(name, ".connect")) {
- FILE *f;
- char *tmp;
- Window twin;
-
- if (scan_hexdec(name, &twin)) {
- int f = find_win(twin);
- if (appshare_debug) {
- fprintf(stderr, "twin: 0x%lx name=%s f=%d\n", twin, name, f);
- ff();
- }
- if (f < 0) {
- continue;
- }
- }
-
- tmp = (char *) calloc(100 + strlen(client), 1);
- sprintf(tracktmp, "%s/%s", trackdir, name);
- if (add) {
- sprintf(tmp, "%s\n", client);
- } else {
- sprintf(tmp, "cmd=close:%s\n", client);
- }
- wait_until_empty(tracktmp);
- f = fopen(tracktmp, "w");
- if (f) {
- if (appshare_debug) {
- fprintf(stderr, "%s client: %s + %s",
- add ? "add" : "disconnect", tracktmp, tmp);
- ff();
- }
- fprintf(f, "%s", tmp);
- fclose(f);
- }
- free(tmp);
- }
- }
- closedir(dir);
-}
-
-static void mapped(Window win) {
- int f;
- if (win == None) {
- return;
- }
- f = find_win(win);
- if (f < 0) {
- if (win_attr(win)) {
- if (get_parent(win) == root) {
- /* XXX more cases? */
- add_win(win);
- }
- }
- }
-}
-
-static void unmapped(Window win) {
- int f = find_win(win);
- if (f < 0 || win == None) {
- return;
- }
- stop(win);
- state[f] = 0;
-}
-
-static void destroy_win(Window win) {
- stop(win);
- delete_win(win);
-}
-
-static Window parse_win(char *str) {
- Window win = None;
- if (!str) {
- return None;
- }
- if (!strcmp(str, "pick") || !strcmp(str, "p")) {
- static double last_pick = 0.0;
- if (dnow() < start_time + 15) {
- ;
- } else if (dnow() < last_pick + 2) {
- return None;
- } else {
- last_pick = dnow();
- }
- if (!pick_windowid(&win)) {
- fprintf(stderr, "parse_win: bad window pick.\n");
- win = None;
- }
- if (win == root) {
- fprintf(stderr, "parse_win: ignoring pick of rootwin 0x%lx.\n", win);
- win = None;
- }
- ff();
- } else if (!scan_hexdec(str, &win)) {
- win = None;
- }
- return win;
-}
-
-static void add_or_del_app(char *str, int add) {
- Window win = parse_win(str);
-
- if (win != None) {
- if (add) {
- add_app(win);
- } else {
- del_app(win);
- }
- } else if (!strcmp(str, "all")) {
- if (!add) {
- int i;
- for (i=0; i < AMAX; i++) {
- if (apps[i] != None) {
- del_app(apps[i]);
- }
- }
- }
- }
-}
-
-static void add_or_del_win(char *str, int add) {
- Window win = parse_win(str);
-
- if (win != None) {
- int f = find_win(win);
- if (add) {
- if (f < 0 && win_attr(win)) {
- add_win(win);
- }
- } else {
- if (f >= 0) {
- destroy_win(win);
- }
- }
- } else if (!strcmp(str, "all")) {
- if (!add) {
- int i;
- for (i=0; i < WMAX; i++) {
- if (watch[i] != None) {
- destroy_win(watch[i]);
- }
- }
- }
- }
-}
-
-static void add_or_del_client(char *str, int add) {
- int i;
-
- if (!str) {
- return;
- }
- if (strcmp(control, "internal")) {
- return;
- }
- if (add) {
- int idx = find_client(str);
- int free = find_client(NULL);
-
- if (idx >=0) {
- fprintf(stderr, "already tracking client: %s in slot %d\n", str, idx);
- ff();
- return;
- }
- if (free < 0) {
- static int cnt = 0;
- if (cnt++ < 10) {
- fprintf(stderr, "ran out of client slots.\n");
- ff();
- }
- return;
- }
- clients[free] = strdup(str);
- client(str, 1);
- } else {
- if (str[0] == '#' || str[0] == '%') {
- if (sscanf(str+1, "%d", &i) == 1) {
- i--;
- if (0 <= i && i < CMAX) {
- if (clients[i] != NULL) {
- client(clients[i], 0);
- free(clients[i]);
- clients[i] = NULL;
- return;
- }
- }
- }
- } else if (!strcmp(str, "all")) {
- for (i=0; i < CMAX; i++) {
- if (clients[i] == NULL) {
- continue;
- }
- client(clients[i], 0);
- free(clients[i]);
- clients[i] = NULL;
- }
- return;
- }
-
- i = find_client(str);
- if (i >= 0) {
- free(clients[i]);
- clients[i] = NULL;
- client(str, 0);
- }
- }
-}
-
-static void restart_x11vnc(void) {
- int i, n = 0;
- Window win, active[WMAX];
- for (i=0; i < WMAX; i++) {
- win = watch[i];
- if (win == None) {
- continue;
- }
- if (state[i]) {
- active[n++] = win;
- stop(win);
- }
- }
- if (n) {
- usleep(1500 * 1000);
- }
- for (i=0; i < n; i++) {
- win = active[i];
- launch(win);
- }
-}
-
-static unsigned long cmask = 0x3fc00000; /* 00111111110000000000000000000000 */
-
-static void init_cmask(void) {
- /* dependent on the X server implementation; XmuClientWindow better? */
- /* xc/programs/Xserver/include/resource.h */
- int didit = 0, res_cnt = 29, client_bits = 8;
-
- if (getenv("X11VNC_APPSHARE_CLIENT_MASK")) {
- unsigned long cr;
- if (sscanf(getenv("X11VNC_APPSHARE_CLIENT_MASK"), "0x%lx", &cr) == 1) {
- cmask = cr;
- didit = 1;
- }
- } else if (getenv("X11VNC_APPSHARE_CLIENT_BITS")) {
- int cr = atoi(getenv("X11VNC_APPSHARE_CLIENT_BITS"));
- if (cr > 0) {
- client_bits = cr;
- }
- }
- if (!didit) {
- cmask = (((1 << client_bits) - 1) << (res_cnt-client_bits));
- }
- fprintf(stderr, "client_mask: 0x%08lx\n", cmask);
-}
-
-static int same_app(Window win, Window app) {
- if ( (win & cmask) == (app & cmask) ) {
- return 1;
- } else {
- return 0;
- }
-}
-
-static int ours(Window win) {
- int i;
- for (i=0; i < AMAX; i++) {
- if (apps[i] != None) {
- if (same_app(win, apps[i])) {
- return 1;
- }
- }
- }
- return 0;
-}
-
-static void list_clients(void) {
- int i, n = 0;
- for (i=0; i < CMAX; i++) {
- if (clients[i] == NULL) {
- continue;
- }
- fprintf(stdout, "client[%02d] %s\n", ++n, clients[i]);
- }
- fprintf(stdout, "total clients: %d\n", n);
- ff();
-}
-
-static void list_windows(void) {
- int i, n = 0;
- for (i=0; i < WMAX; i++) {
- char *name;
- Window win = watch[i];
- if (win == None) {
- continue;
- }
- get_wm_name(win, &name);
- fprintf(stdout, "window[%02d] 0x%08lx state: %d slot: %03d \"%s\"\n",
- ++n, win, state[i], i, name);
- free(name);
- }
- fprintf(stdout, "total windows: %d\n", n);
- ff();
-}
-
-static void list_apps(void) {
- int i, n = 0;
- for (i=0; i < AMAX; i++) {
- char *name;
- Window win = apps[i];
- if (win == None) {
- continue;
- }
- get_wm_name(win, &name);
- fprintf(stdout, "app[%02d] 0x%08lx state: %d slot: %03d \"%s\"\n",
- ++n, win, state[i], i, name);
- free(name);
- }
- fprintf(stdout, "total apps: %d\n", n);
- ff();
-}
-
-static int process_control(char *file, int check_clients) {
- int i, nnew = 0, seen[CMAX];
- char line[1024], *newctl[CMAX];
- FILE *f;
-
- f = fopen(file, "r");
- if (!f) {
- return 1;
- }
- if (check_clients) {
- for (i=0; i < CMAX; i++) {
- seen[i] = 0;
- }
- }
- while (fgets(line, sizeof(line), f) != NULL) {
- char *q = strchr(line, '\n');
- if (q) *q = '\0';
-
- if (appshare_debug) {
- fprintf(stderr, "check_control: %s\n", line);
- ff();
- }
-
- q = lblanks(line);
- if (q[0] == '#') {
- continue;
- }
- if (!strcmp(q, "")) {
- continue;
- }
- if (strstr(q, "cmd=") == q) {
- char *cmd = q + strlen("cmd=");
- if (!strcmp(cmd, "quit")) {
- if (strcmp(control, file) && strstr(file, ".cmd")) {
- FILE *f2 = fopen(file, "w");
- if (f2) fclose(f2);
- }
- appshare_cleanup(0);
- } else if (!strcmp(cmd, "wait")) {
- return 0;
- } else if (strstr(cmd, "bcast:") == cmd) {
- ;
- } else if (strstr(cmd, "del_window:") == cmd) {
- add_or_del_win(cmd + strlen("del_window:"), 0);
- } else if (strstr(cmd, "add_window:") == cmd) {
- add_or_del_win(cmd + strlen("add_window:"), 1);
- } else if (strstr(cmd, "del:") == cmd) {
- add_or_del_win(cmd + strlen("del:"), 0);
- } else if (strstr(cmd, "add:") == cmd) {
- add_or_del_win(cmd + strlen("add:"), 1);
- } else if (strstr(cmd, "del_client:") == cmd) {
- add_or_del_client(cmd + strlen("del_client:"), 0);
- } else if (strstr(cmd, "add_client:") == cmd) {
- add_or_del_client(cmd + strlen("add_client:"), 1);
- } else if (strstr(cmd, "-") == cmd) {
- add_or_del_client(cmd + strlen("-"), 0);
- } else if (strstr(cmd, "+") == cmd) {
- add_or_del_client(cmd + strlen("+"), 1);
- } else if (strstr(cmd, "del_app:") == cmd) {
- add_or_del_app(cmd + strlen("del_app:"), 0);
- } else if (strstr(cmd, "add_app:") == cmd) {
- add_or_del_app(cmd + strlen("add_app:"), 1);
- } else if (strstr(cmd, "debug:") == cmd) {
- appshare_debug = atoi(cmd + strlen("debug:"));
- } else if (strstr(cmd, "showmenus:") == cmd) {
- skip_menus = atoi(cmd + strlen("showmenus:"));
- skip_menus = !(skip_menus);
- } else if (strstr(cmd, "noexit:") == cmd) {
- exit_no_app_win = atoi(cmd + strlen("noexit:"));
- exit_no_app_win = !(exit_no_app_win);
- } else if (strstr(cmd, "use_forever:") == cmd) {
- use_forever = atoi(cmd + strlen("use_forever:"));
- } else if (strstr(cmd, "tree_depth:") == cmd) {
- tree_depth = atoi(cmd + strlen("tree_depth:"));
- } else if (strstr(cmd, "x11vnc_args:") == cmd) {
- x11vnc_args = strdup(cmd + strlen("x11vnc_args:"));
- } else if (strstr(cmd, "env:") == cmd) {
- putenv(cmd + strlen("env:"));
- } else if (strstr(cmd, "noop") == cmd) {
- ;
- } else if (!strcmp(cmd, "restart")) {
- restart_x11vnc();
- } else if (!strcmp(cmd, "list_clients") || !strcmp(cmd, "lc")) {
- list_clients();
- } else if (!strcmp(cmd, "list_windows") || !strcmp(cmd, "lw")) {
- list_windows();
- } else if (!strcmp(cmd, "list_apps") || !strcmp(cmd, "la")) {
- list_apps();
- } else if (!strcmp(cmd, "list_all") || !strcmp(cmd, "ls")) {
- list_windows();
- fprintf(stderr, "\n");
- list_apps();
- fprintf(stderr, "\n");
- list_clients();
- } else if (!strcmp(cmd, "print_logs") || !strcmp(cmd, "pl")) {
- print_logs();
- } else if (!strcmp(cmd, "?") || !strcmp(cmd, "h") || !strcmp(cmd, "help")) {
- fprintf(stderr, "available commands:\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " quit restart noop x11vnc help ? ! !!\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " add_window:win (add:win, add:pick)\n");
- fprintf(stderr, " del_window:win (del:win, del:pick, del:all)\n");
- fprintf(stderr, " add_app:win (add_app:pick)\n");
- fprintf(stderr, " del_app:win (del_app:pick, del_app:all)\n");
- fprintf(stderr, " add_client:host (+host)\n");
- fprintf(stderr, " del_client:host (-host, -all)\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " list_windows (lw)\n");
- fprintf(stderr, " list_apps (la)\n");
- fprintf(stderr, " list_clients (lc)\n");
- fprintf(stderr, " list_all (ls)\n");
- fprintf(stderr, " print_logs (pl)\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " debug:n showmenus:n noexit:n\n");
- } else {
- fprintf(stderr, "unrecognized %s\n", q);
- }
- continue;
- }
- if (check_clients) {
- int idx = find_client(q);
- if (idx >= 0) {
- seen[idx] = 1;
- } else {
- newctl[nnew++] = strdup(q);
- }
- }
- }
- fclose(f);
-
- if (check_clients) {
- for (i=0; i < CMAX; i++) {
- if (clients[i] == NULL) {
- continue;
- }
- if (!seen[i]) {
- client(clients[i], 0);
- free(clients[i]);
- clients[i] = NULL;
- }
- }
- for (i=0; i < nnew; i++) {
- int free = find_client(NULL);
- if (free < 0) {
- static int cnt = 0;
- if (cnt++ < 10) {
- fprintf(stderr, "ran out of client slots.\n");
- ff();
- break;
- }
- continue;
- }
- clients[free] = newctl[i];
- client(newctl[i], 1);
- }
- }
- return 1;
-}
-
-static int check_control(void) {
- static int last_size = -1;
- static time_t last_mtime = 0;
- struct stat sb;
- char *control_cmd;
-
- if (!control) {
- return 1;
- }
-
- if (!strcmp(control, "internal")) {
- return 1;
- }
-
- control_cmd = (char *)malloc(strlen(control) + strlen(".cmd") + 1);
- sprintf(control_cmd, "%s.cmd", control);
- if (stat(control_cmd, &sb) == 0) {
- FILE *f;
- if (sb.st_size > 0) {
- process_control(control_cmd, 0);
- }
- f = fopen(control_cmd, "w");
- if (f) {
- fclose(f);
- }
- }
- free(control_cmd);
-
- if (stat(control, &sb) != 0) {
- return 1;
- }
- if (last_size == (int) sb.st_size && last_mtime == sb.st_mtime) {
- return 1;
- }
- last_size = (int) sb.st_size;
- last_mtime = sb.st_mtime;
-
- return process_control(control, 1);
-}
-
-static void update(void) {
- int i, app_ok = 0;
- if (last_event_type != PropertyNotify) {
- if (appshare_debug) fprintf(stderr, "\nupdate ...\n");
- } else if (appshare_debug > 1) {
- fprintf(stderr, "update ... propertynotify\n");
- }
- if (!check_control()) {
- return;
- }
- for (i=0; i < WMAX; i++) {
- Window win = watch[i];
- if (win == None) {
- continue;
- }
- if (!win_attr(win)) {
- destroy_win(win);
- continue;
- }
- if (find_app(win) >= 0) {
- app_ok++;
- }
- if (state[i] == 0) {
- if (attr.map_state == IsViewable) {
- if (skip_menus) {
- Window inside = check_inside(win);
- if (inside != None) {
- if (appshare_debug) {fprintf(stderr, "skip_menus: window 0x%lx is inside of 0x%lx, not tracking it.\n", win, inside); ff();}
- delete_win(win);
- continue;
- }
- }
- launch(win);
- state[i] = 1;
- }
- } else if (state[i] == 1) {
- if (attr.map_state != IsViewable) {
- stop(win);
- state[i] = 0;
- }
- }
- }
- if (exit_no_app_win && !app_ok) {
- for (i=0; i < AMAX; i++) {
- if (apps[i] != None) {
- fprintf(stdout, "main application window is gone: 0x%lx\n", apps[i]);
- }
- }
- ff();
- appshare_cleanup(0);
- }
- if (last_event_type != PropertyNotify) {
- if (appshare_debug) {fprintf(stderr, "update done.\n"); ff();}
- }
-}
-
-static void exiter(char *msg, int rc) {
- fprintf(stderr, "%s", msg);
- ff();
- kill_helper_pid();
- exit(rc);
-}
-
-static void set_trackdir(void) {
- char tmp[256];
- struct stat sb;
- if (!strcmp(trackdir, "none")) {
- trackdir = NULL;
- return;
- }
- if (!strcmp(trackdir, "unset")) {
- int fd;
- sprintf(tmp, "%s.XXXXXX", trackpre);
- fd = mkstemp(tmp);
- if (fd < 0) {
- strcat(tmp, ": failed to create file.\n");
- exiter(tmp, 1);
- }
- /* XXX race */
- close(fd);
- unlink(tmp);
- if (mkdir(tmp, 0700) != 0) {
- strcat(tmp, ": failed to create dir.\n");
- exiter(tmp, 1);
- }
- trackdir = strdup(tmp);
- }
- if (stat(trackdir, &sb) != 0) {
- if (mkdir(trackdir, 0700) != 0) {
- exiter("could not make trackdir.\n", 1);
- }
- } else if (! S_ISDIR(sb.st_mode)) {
- exiter("trackdir not a directory.\n", 1);
- }
- tracktmp = (char *) calloc(1000 + strlen(trackdir), 1);
-}
-
-static void process_string(char *str) {
- FILE *f;
- char *file;
- if (trackdir) {
- sprintf(tracktmp, "%s/0xprop.cmd", trackdir);
- file = strdup(tracktmp);
- } else {
- char tmp[] = "/tmp/x11vnc-appshare.cmd.XXXXXX";
- int fd = mkstemp(tmp);
- if (fd < 0) {
- return;
- }
- file = strdup(tmp);
- close(fd);
- }
- f = fopen(file, "w");
- if (f) {
- fprintf(f, "%s", str);
- fclose(f);
- process_control(file, 0);
- }
- unlink(file);
- free(file);
-}
-
-static void handle_shell(void) {
- struct timeval tv;
- static char lastline[1000];
- static int first = 1;
- fd_set rfds;
- int fd0 = fileno(stdin);
-
- if (first) {
- memset(lastline, 0, sizeof(lastline));
- first = 0;
- }
-
- FD_ZERO(&rfds);
- FD_SET(fd0, &rfds);
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- select(fd0+1, &rfds, NULL, NULL, &tv);
- if (FD_ISSET(fd0, &rfds)) {
- char line[1000], line2[1010];
- if (fgets(line, sizeof(line), stdin) != NULL) {
- char *str = lblanks(line);
- char *q = strrchr(str, '\n');
- if (q) *q = '\0';
- if (strcmp(str, "")) {
- if (!strcmp(str, "!!")) {
- sprintf(line, "%s", lastline);
- fprintf(stderr, "%s\n", line);
- str = line;
- }
- if (strstr(str, "!") == str) {
- system(str+1);
- } else if (!strcmp(str, "x11vnc") || !strcmp(str, "ps")) {
- char *cmd = "ps -elf | egrep 'PID|x11vnc' | grep -v egrep";
- fprintf(stderr, "%s\n", cmd);
- system(cmd);
- } else {
- sprintf(line2, "cmd=%s", str);
- process_string(line2);
- }
- sprintf(lastline, "%s", str);
- }
- }
- fprintf(stderr, "\n%s", prompt); ff();
- }
-}
-
-static void handle_prop_cmd(void) {
- char *value, *str, *done = "DONE";
-
- if (cmd_atom == None) {
- return;
- }
-
- value = get_xprop(cmd_atom_str, root);
- if (value == NULL) {
- return;
- }
-
- str = lblanks(value);
- if (!strcmp(str, done)) {
- free(value);
- return;
- }
- if (strstr(str, "cmd=quit") == str || strstr(str, "\ncmd=quit")) {
- set_xprop(cmd_atom_str, root, done);
- appshare_cleanup(0);
- }
-
- process_string(str);
-
- free(value);
- set_xprop(cmd_atom_str, root, done);
-}
-
-#define PREFIX if(appshare_debug) fprintf(stderr, " %8.2f 0x%08lx : ", dnow() - start, ev.xany.window);
-
-static void monitor(void) {
-#if !NO_X11
- XEvent ev;
- double start = dnow();
- int got_prop_cmd = 0;
-
- if (shell) {
- update();
- fprintf(stderr, "\n\n");
- process_string("cmd=help");
- fprintf(stderr, "\n%s", prompt); ff();
- }
-
- while (1) {
- int t;
-
- if (XEventsQueued(dpy, QueuedAlready) == 0) {
- update();
- if (got_prop_cmd) {
- handle_prop_cmd();
- }
- got_prop_cmd = 0;
- if (shell) {
- handle_shell();
- }
- }
-
- XNextEvent(dpy, &ev);
-
- last_event_type = ev.type;
-
- switch (ev.type) {
- case Expose:
- PREFIX
- if(appshare_debug) fprintf(stderr, "Expose %04dx%04d+%04d+%04d\n", ev.xexpose.width, ev.xexpose.height, ev.xexpose.x, ev.xexpose.y);
- break;
- case ConfigureNotify:
-#if 0
- PREFIX
- if(appshare_debug) fprintf(stderr, "ConfigureNotify %04dx%04d+%04d+%04d above: 0x%lx\n", ev.xconfigure.width, ev.xconfigure.height, ev.xconfigure.x, ev.xconfigure.y, ev.xconfigure.above);
-#endif
- break;
- case VisibilityNotify:
- PREFIX
- if (appshare_debug) {
- fprintf(stderr, "VisibilityNotify: ");
- t = ev.xvisibility.state;
- if (t == VisibilityFullyObscured) fprintf(stderr, "VisibilityFullyObscured\n");
- if (t == VisibilityPartiallyObscured) fprintf(stderr, "VisibilityPartiallyObscured\n");
- if (t == VisibilityUnobscured) fprintf(stderr, "VisibilityUnobscured\n");
- }
- break;
- case MapNotify:
- PREFIX
- if(appshare_debug) fprintf(stderr, "MapNotify win: 0x%lx\n", ev.xmap.window);
- if (ours(ev.xmap.window)) {
- mapped(ev.xmap.window);
- }
- break;
- case UnmapNotify:
- PREFIX
- if(appshare_debug) fprintf(stderr, "UnmapNotify win: 0x%lx\n", ev.xmap.window);
- if (ours(ev.xmap.window)) {
- unmapped(ev.xmap.window);
- }
- break;
- case MapRequest:
- PREFIX
- if(appshare_debug) fprintf(stderr, "MapRequest\n");
- break;
- case CreateNotify:
- PREFIX
- if(appshare_debug) fprintf(stderr, "CreateNotify parent: 0x%lx win: 0x%lx\n", ev.xcreatewindow.parent, ev.xcreatewindow.window);
- if (ev.xcreatewindow.parent == root && ours(ev.xcreatewindow.window)) {
- if (find_win(ev.xcreatewindow.window) >= 0) {
- destroy_win(ev.xcreatewindow.window);
- }
- add_win(ev.xcreatewindow.window);
- }
- break;
- case DestroyNotify:
- PREFIX
- if(appshare_debug) fprintf(stderr, "DestroyNotify win: 0x%lx\n", ev.xdestroywindow.window);
- if (ours(ev.xdestroywindow.window)) {
- destroy_win(ev.xdestroywindow.window);
- }
- break;
- case ConfigureRequest:
- PREFIX
- if(appshare_debug) fprintf(stderr, "ConfigureRequest\n");
- break;
- case CirculateRequest:
-#if 0
- PREFIX
- if(appshare_debug) fprintf(stderr, "CirculateRequest parent: 0x%lx win: 0x%lx\n", ev.xcirculaterequest.parent, ev.xcirculaterequest.window);
-#endif
- break;
- case CirculateNotify:
-#if 0
- PREFIX
- if(appshare_debug) fprintf(stderr, "CirculateNotify\n");
-#endif
- break;
- case PropertyNotify:
-#if 0
- PREFIX
- if(appshare_debug) fprintf(stderr, "PropertyNotify\n");
-#endif
- if (cmd_atom != None && ev.xproperty.atom == cmd_atom) {
- got_prop_cmd++;
- }
- break;
- case ReparentNotify:
- PREFIX
- if(appshare_debug) fprintf(stderr, "ReparentNotify parent: 0x%lx win: 0x%lx\n", ev.xreparent.parent, ev.xreparent.window);
- if (ours(ev.xreparent.window)) {
- if (ours(ev.xreparent.parent)) {
- destroy_win(ev.xreparent.window);
- } else if (ev.xreparent.parent == root) {
- /* ??? */
- }
- }
- break;
- default:
- PREFIX
- if(appshare_debug) fprintf(stderr, "Unknown: %d\n", ev.type);
- break;
- }
- }
-#endif
-}
-
-int appshare_main(int argc, char *argv[]) {
- int i;
- char *app_str = NULL;
- char *dpy_str = NULL;
- long xselectinput = 0;
-#if NO_X11
- exiter("not compiled with X11\n", 1);
-#else
- for (i=0; i < WMAX; i++) {
- watch[i] = None;
- state[i] = 0;
- }
- for (i=0; i < AMAX; i++) {
- apps[i] = None;
- }
- for (i=0; i < CMAX; i++) {
- clients[i] = NULL;
- }
-
- x11vnc = strdup(argv[0]);
-
- for (i=1; i < argc; i++) {
- int end = (i == argc-1) ? 1 : 0;
- char *s = argv[i];
- if (strstr(s, "--") == s) {
- s++;
- }
-
- if (!strcmp(s, "-h") || !strcmp(s, "-help")) {
- fprintf(stdout, "%s", usage);
- exit(0);
- } else if (!strcmp(s, "-id")) {
- id_opt = "-id";
- if (end) exiter("no -id value supplied\n", 1);
- app_str = strdup(argv[++i]);
- } else if (!strcmp(s, "-sid")) {
- id_opt = "-sid";
- if (end) exiter("no -sid value supplied\n", 1);
- app_str = strdup(argv[++i]);
- } else if (!strcmp(s, "-connect") || !strcmp(s, "-connect_or_exit") || !strcmp(s, "-coe")) {
- if (end) exiter("no -connect value supplied\n", 1);
- connect_to = strdup(argv[++i]);
- } else if (!strcmp(s, "-control")) {
- if (end) exiter("no -control value supplied\n", 1);
- control = strdup(argv[++i]);
- if (!strcmp(control, "shell")) {
- free(control);
- control = strdup("internal");
- shell = 1;
- }
- } else if (!strcmp(s, "-trackdir")) {
- if (end) exiter("no -trackdir value supplied\n", 1);
- trackdir = strdup(argv[++i]);
- } else if (!strcmp(s, "-display")) {
- if (end) exiter("no -display value supplied\n", 1);
- dpy_str = strdup(argv[++i]);
- set_env("DISPLAY", dpy_str);
- } else if (!strcmp(s, "-delay")) {
- if (end) exiter("no -delay value supplied\n", 1);
- helper_delay = atof(argv[++i]);
- } else if (!strcmp(s, "-args")) {
- if (end) exiter("no -args value supplied\n", 1);
- x11vnc_args = strdup(argv[++i]);
- } else if (!strcmp(s, "-env")) {
- if (end) exiter("no -env value supplied\n", 1);
- putenv(argv[++i]);
- } else if (!strcmp(s, "-debug")) {
- appshare_debug++;
- } else if (!strcmp(s, "-showmenus")) {
- skip_menus = 0;
- } else if (!strcmp(s, "-noexit")) {
- exit_no_app_win = 0;
- } else if (!strcmp(s, "-shell")) {
- shell = 1;
- } else if (!strcmp(s, "-nocmds") || !strcmp(s, "-safer")) {
- fprintf(stderr, "ignoring %s in -appshare mode.\n", s);
- } else if (!strcmp(s, "-appshare")) {
- ;
- } else {
- fprintf(stderr, "unrecognized 'x11vnc -appshare' option: %s\n", s);
- exiter("", 1);
- }
- }
-
- if (getenv("X11VNC_APPSHARE_DEBUG")) {
- appshare_debug = atoi(getenv("X11VNC_APPSHARE_DEBUG"));
- }
-
- /* let user override name for multiple instances: */
- if (getenv("X11VNC_APPSHARE_COMMAND_PROPNAME")) {
- cmd_atom_str = strdup(getenv("X11VNC_APPSHARE_COMMAND_PROPNAME"));
- }
- if (getenv("X11VNC_APPSHARE_TICKER_PROPNAME")) {
- ticker_atom_str = strdup(getenv("X11VNC_APPSHARE_TICKER_PROPNAME"));
- }
-
- if (shell) {
- if (!control || strcmp(control, "internal")) {
- exiter("mode -shell requires '-control internal'\n", 1);
- }
- }
-
- if (connect_to == NULL && control != NULL) {
- struct stat sb;
- if (stat(control, &sb) == 0) {
- int len = 100 + sb.st_size;
- FILE *f = fopen(control, "r");
-
- if (f) {
- char *line = (char *) malloc(len);
- connect_to = (char *) calloc(2 * len, 1);
- while (fgets(line, len, f) != NULL) {
- char *q = strchr(line, '\n');
- if (q) *q = '\0';
- q = lblanks(line);
- if (q[0] == '#') {
- continue;
- }
- if (connect_to[0] != '\0') {
- strcat(connect_to, ",");
- }
- strcat(connect_to, q);
- }
- fclose(f);
- }
- fprintf(stderr, "set -connect to: %s\n", connect_to);
- }
- }
- if (0 && connect_to == NULL && control == NULL) {
- exiter("no -connect host or -control file specified.\n", 1);
- }
-
- if (control) {
- pid_t pid;
- parent_pid = getpid();
- pid = fork();
- if (pid == (pid_t) -1) {
- ;
- } else if (pid == 0) {
- be_helper_pid(dpy_str);
- exit(0);
- } else {
- helper_pid = pid;
- }
- }
-
- dpy = XOpenDisplay(dpy_str);
- if (!dpy) {
- exiter("cannot open display\n", 1);
- }
-
- root = DefaultRootWindow(dpy);
-
- xselectinput = SubstructureNotifyMask;
- if (helper_pid > 0) {
- ticker_atom = XInternAtom(dpy, ticker_atom_str, False);
- xselectinput |= PropertyChangeMask;
- }
- XSelectInput(dpy, root, xselectinput);
-
- cmd_atom = XInternAtom(dpy, cmd_atom_str, False);
-
- init_cmask();
-
- sprintf(unique_tag, "X11VNC_APPSHARE_TAG=%d-tag", getpid());
-
- start_time = dnow();
-
- if (app_str == NULL) {
- exiter("no -id/-sid window specified.\n", 1);
- } else {
- char *p, *str = strdup(app_str);
- char *alist[AMAX];
- int i, n = 0;
-
- p = strtok(str, ",");
- while (p) {
- if (n >= AMAX) {
- fprintf(stderr, "ran out of app slots: %s\n", app_str);
- exiter("", 1);
- }
- alist[n++] = strdup(p);
- p = strtok(NULL, ",");
- }
- free(str);
-
- for (i=0; i < n; i++) {
- Window app = None;
- p = alist[i];
- app = parse_win(p);
- free(p);
-
- if (app != None) {
- if (!ours(app)) {
- add_app(app);
- }
- }
- }
- }
-
- set_trackdir();
-
- signal(SIGINT, appshare_cleanup);
- signal(SIGTERM, appshare_cleanup);
-
- rfbLogEnable(0);
-
- if (connect_to) {
- char *p, *str = strdup(connect_to);
- int n = 0;
- p = strtok(str, ",");
- while (p) {
- clients[n++] = strdup(p);
- p = strtok(NULL, ",");
- }
- free(str);
- } else {
- connect_to = strdup("");
- }
-
- for (i=0; i < AMAX; i++) {
- if (apps[i] == None) {
- continue;
- }
- fprintf(stdout, "Using app win: 0x%08lx root: 0x%08lx\n", apps[i], root);
- }
- fprintf(stdout, "\n");
-
- monitor();
-
- appshare_cleanup(0);
-
-#endif
- return 0;
-}
-
OpenPOWER on IntegriCloud