~ubuntu-branches/debian/jessie/italc/jessie

« back to all changes in this revision

Viewing changes to ica/x11/x11vnc/appshare.c

  • Committer: Bazaar Package Importer
  • Author(s): Patrick Winnertz
  • Date: 2011-02-11 14:50:22 UTC
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20110211145022-sn173siax6lywjus
Tags: upstream-1.0.13
ImportĀ upstreamĀ versionĀ 1.0.13

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
/* -- appshare.c -- */
 
34
 
 
35
#include "x11vnc.h"
 
36
 
 
37
extern int pick_windowid(unsigned long *num);
 
38
extern char *get_xprop(char *prop, Window win);
 
39
extern int set_xprop(char *prop, Window win, char *value);
 
40
extern void set_env(char *name, char *value);
 
41
extern double dnow(void);
 
42
 
 
43
static char *usage =
 
44
"\n"
 
45
"  x11vnc -appshare: an experiment in application sharing via x11vnc.\n"
 
46
"\n"
 
47
#if !SMALL_FOOTPRINT
 
48
"  Usage:   x11vnc -appshare -id windowid -connect viewer_host:0\n"
 
49
"           x11vnc -appshare -id pick     -connect viewer_host:0\n"
 
50
"\n"
 
51
"  Both the -connect option and the -id (or -sid) option are required.\n"
 
52
"  (However see the -control option below that can replace -connect.)\n"
 
53
"\n"
 
54
"  The VNC viewer at viewer_host MUST be in 'listen' mode.  This is because\n"
 
55
"  a new VNC connection (and viewer window) is established for each new\n"
 
56
"  toplevel window that the application creates.  For example:\n"
 
57
"\n"
 
58
"       vncviewer -listen 0\n"
 
59
"\n"
 
60
"  The '-connect viewer_host:0' indicates the listening viewer to connect to.\n"
 
61
"\n"
 
62
"  No password should be used, otherwise it will need to be typed for each\n"
 
63
"  new window (or one could use vncviewer -passwd file if the viewer supports\n"
 
64
"  that.)  For security an SSH tunnel can be used:\n"
 
65
"\n"
 
66
"       ssh -R 5500:localhost:5500 user@server_host\n"
 
67
"\n"
 
68
"  (then use -connect localhost:0)\n"
 
69
"\n"
 
70
"  The -id/-sid option is as in x11vnc(1).  It is either a numerical window\n"
 
71
"  id or the string 'pick' which will ask the user to click on an app window.\n"
 
72
"  To track more than one application at the same time, list their window ids\n"
 
73
"  separated by commas (see also the 'add_app' command below.)\n"
 
74
"\n"
 
75
"  Additional options:\n"
 
76
"\n"
 
77
"      -h, -help      Print this help.\n"
 
78
"      -debug         Print debugging output (same as X11VNC_APPSHARE_DEBUG=1)\n"
 
79
"      -showmenus     Create a new viewer window even if a new window is\n"
 
80
"                     completely inside of an existing one.  Default is to\n"
 
81
"                     try to not show them in a new viewer window.\n"
 
82
"      -noexit        Do not exit if the main app (windowid/pick) window\n"
 
83
"                     goes away.  Default is to exit.\n"
 
84
"      -display dpy   X DISPLAY to use.\n"
 
85
"      -trackdir dir  Set tracking directory to 'dir'. x11vnc -appshare does\n"
 
86
"                     better if it can communicate with the x11vnc's via a\n"
 
87
"                     file channel. By default a dir in /tmp is used, -trackdir\n"
 
88
"                     specifies another directory, or use 'none' to disable.\n"
 
89
"      -args 'string' Pass options 'string' to x11vnc (e.g. -scale 3/4,\n"
 
90
"                     -viewonly, -wait, -once, etc.)\n"
 
91
"      -env VAR=VAL   Set environment variables on cmdline as in x11vnc.\n"
 
92
"\n"
 
93
"      -control file  This is a file that one edits to manage the appshare\n"
 
94
"                     mode.  It replaces -connect.  Lines beginning with '#'\n"
 
95
"                     are ignored.  Initially start off with all of the\n"
 
96
"                     desired clients in the file, one per line.  If you add\n"
 
97
"                     a new client-line, that client is connected to. If you\n"
 
98
"                     delete (or comment out) a client-line, that client is\n"
 
99
"                     disconnected (for this to work, do not disable trackdir.)\n"
 
100
"\n"
 
101
"                     You can also put cmd= lines in the control file to perform\n"
 
102
"                     different actions.  These are supported:\n"
 
103
"\n"
 
104
"                         cmd=quit            Disconnect all clients and exit.\n"
 
105
"                         cmd=restart         Restart all of the x11vnc's.\n"
 
106
"                         cmd=noop            Do nothing (e.g. ping)\n"
 
107
"                         cmd=x11vnc          Run ps(1) looking for x11vnc's\n"
 
108
"                         cmd=help            Print out help text.\n"
 
109
"                         cmd=add_window:win  Add a window to be watched.\n"
 
110
"                         cmd=del_window:win  Delete a window.\n"
 
111
"                         cmd=add_app:win     Add an application to be watched.\n"
 
112
"                         cmd=del_app:win     Delete an application.\n"
 
113
"                         cmd=add_client:host Add client ('internal' mode only)\n"
 
114
"                         cmd=del_client:host Del client ('internal' mode only)\n"
 
115
"                         cmd=list_windows    List all tracked windows.\n"
 
116
"                         cmd=list_apps       List all tracked applications.\n"
 
117
"                         cmd=list_clients    List all connected clients.\n"
 
118
"                         cmd=list_all        List all three.\n"
 
119
"                         cmd=print_logs      Print out the x11vnc logfiles.\n"
 
120
"                         cmd=debug:n         Set -debug to n (0 or 1).\n"
 
121
"                         cmd=showmenus:n     Set -showmenus to n (0 or 1).\n"
 
122
"                         cmd=noexit:n        Set -noexit to n (0 or 1).\n"
 
123
"\n"
 
124
"                     See the '-command internal' mode described below for a way\n"
 
125
"                     that tracks connected clients internally (not in a file.)\n"
 
126
"\n"
 
127
"                     In '-shell' mode (see below) you can type in the above\n"
 
128
"                     without the leading 'cmd='.\n"
 
129
"\n"
 
130
"                     For 'add_window' and 'del_window' the 'win' can be a\n"
 
131
"                     numerical window id or 'pick'.  Same for 'add_app'.  Be\n"
 
132
"                     sure to remove or comment out the add/del line quickly\n"
 
133
"                     (e.g. before picking) or it will be re-run the next time\n"
 
134
"                     the file is processed.\n"
 
135
"\n"
 
136
"                     If a file with the same name as the control file but\n"
 
137
"                     ending with suffix '.cmd' is found, then commands in it\n"
 
138
"                     (cmd=...) are processed and then the file is truncated.\n"
 
139
"                     This allows 'one time' command actions to be run.  Any\n"
 
140
"                     client hostnames in the '.cmd' file are ignored.  Also\n"
 
141
"                     see below for the X11VNC_APPSHARE_COMMAND X property\n"
 
142
"                     which is similar to '.cmd'\n"
 
143
"\n"
 
144
"      -control internal   Manage connected clients internally, see below.\n"
 
145
"      -control shell      Same as: -shell -control internal\n"
 
146
"\n"
 
147
"      -delay secs    Maximum timeout delay before re-checking the control file.\n"
 
148
"                     It can be a fraction, e.g. -delay 0.25  Default 0.5\n"
 
149
"\n"
 
150
"      -shell         Simple command line for '-control internal' mode (see the\n"
 
151
"                     details of this mode below.)  Enter '?' for command list.\n"
 
152
"\n"
 
153
"  To stop x11vnc -appshare press Ctrl-C, or (if -noexit not supplied) delete\n"
 
154
"  the initial app window or exit the application. Or cmd=quit in -control mode.\n"
 
155
"\n"
 
156
#if 0
 
157
"  If you want your setup to survive periods of time where there are no clients\n"
 
158
"  connected you will need to supply -args '-forever' otherwise the x11vnc's\n"
 
159
"  will exit when the last client disconnects.  Howerver, _starting_ with no\n"
 
160
"  clients (e.g. empty control file) will work without -args '-forever'.\n"
 
161
"\n"
 
162
#endif
 
163
"  In addition to the '.cmd' file channel, for faster response you can set\n"
 
164
"  X11VNC_APPSHARE_COMMAND X property on the root window to the string that\n"
 
165
"  would go into the '.cmd' file.  For example:\n"
 
166
"\n"
 
167
" xprop -root -f X11VNC_APPSHARE_COMMAND 8s -set X11VNC_APPSHARE_COMMAND cmd=quit\n"
 
168
"\n"
 
169
"  The property value will be set to 'DONE' after the command(s) is processed.\n"
 
170
"\n"
 
171
"  If -control file is specified as 'internal' then no control file is used\n"
 
172
"  and client tracking is done internally.  You must add and delete clients\n"
 
173
"  with the cmd=add_client:<client> and cmd=del_client:<client> commands.\n"
 
174
"  Note that '-control internal' is required for '-shell' mode.  Using\n"
 
175
"  '-control shell' implies internal mode and -shell.\n"
 
176
"\n"
 
177
"  Limitations:\n"
 
178
"\n"
 
179
"     This is a quick lash-up, many things will not work properly.\n"
 
180
"\n"
 
181
"     The main idea is to provide simple application sharing for two or more\n"
 
182
"     parties to collaborate without needing to share the entire desktop.  It\n"
 
183
"     provides an improvement over -id/-sid that only shows a single window.\n"
 
184
"\n"
 
185
"     Only reverse connections can be done.  (Note: one can specify multiple\n"
 
186
"     viewing hosts via: -connect host1,host2,host3 or add/remove them\n"
 
187
"     dynamically as described above.)\n"
 
188
"\n"
 
189
"     If a new window obscures an old one, you will see some or all of the\n"
 
190
"     new window in the old one.  The hope is this is a popup dialog or menu\n"
 
191
"     that will go away soon.  Otherwise a user at the physical display will\n"
 
192
"     need to move it. (See also the SSVNC viewer features described below.) \n"
 
193
"\n"
 
194
"     The viewer side cannot resize or make windows move on the physical\n"
 
195
"     display.  Again, a user at the physical display may need to help, or\n"
 
196
"     use the SSVNC viewer (see Tip below.)\n"
 
197
"\n"
 
198
"     Tip: If the application has its own 'resize corner', then dragging\n"
 
199
"          it may successfully resize the application window.\n"
 
200
"     Tip: Some desktop environments enable moving a window via, say,\n"
 
201
"          Alt+Left-Button-Drag.  One may be able to move a window this way.\n"
 
202
"          Also, e.g., Alt+Right-Button-Drag may resize a window.\n"
 
203
"     Tip: Clicking on part of an obscured window may raise it to the top.\n"
 
204
"          Also, e.g., Alt+Middle-Button may toggle Raise/Lower.\n"
 
205
"\n"
 
206
"     Tip: The SSVNC 1.0.25 unix and macosx vncviewer has 'EscapeKeys' hot\n"
 
207
"          keys that will move, resize, raise, and lower the window via the\n"
 
208
"          x11vnc -remote_prefix X11VNC_APPSHARE_CMD: feature.  So in the\n"
 
209
"          viewer while holding down Shift_L+Super_L+Alt_L the arrow keys\n"
 
210
"          move the window, PageUp/PageDn/Home/End resize it, and - and +\n"
 
211
"          raise and lower it.  Key 'M' or Button1 moves the remote window\n"
 
212
"          to the +X+Y of the viewer window.  Key 'D' or Button3 deletes\n"
 
213
"          the remote window.\n"
 
214
"\n"
 
215
"          You can run the SSVNC vncviewer with options '-escape default',\n"
 
216
"          '-multilisten' and '-env VNCVIEWER_MIN_TITLE=1'; or just run\n"
 
217
"          with option '-appshare' to enable these and automatic placement.\n"
 
218
"\n"
 
219
"     If any part of a window goes off of the display screen, then x11vnc\n"
 
220
"     may be unable to poll it (without crashing), and so the window will\n"
 
221
"     stop updating until the window is completely on-screen again.\n"
 
222
"\n"
 
223
"     The (stock) vnc viewer does not know where to best position each new\n"
 
224
"     viewer window; it likely centers each one (including when resized.)\n"
 
225
"     Note: The SSVNC viewer in '-appshare' mode places them correctly.\n"
 
226
"\n"
 
227
"     Deleting a viewer window does not delete the real window.\n"
 
228
"     Note: The SSVNC viewer Shift+EscapeKeys+Button3 deletes it.\n"
 
229
"\n"
 
230
"     Sometimes new window detection fails.\n"
 
231
"\n"
 
232
"     Sometimes menu/popup detection fails.\n"
 
233
"\n"
 
234
"     Sometimes the contents of a menu/popup window have blacked-out regions.\n"
 
235
"     Try -sid or -showmenus as a workaround.\n"
 
236
"\n"
 
237
"     If the application starts up a new application (a different process)\n"
 
238
"     that new application will not be tracked (but, unfortunately, it may\n"
 
239
"     cover up existing windows that are being tracked.) See cmd=add_window\n"
 
240
"     and cmd=add_app described above.\n"
 
241
"\n"
 
242
#endif
 
243
;
 
244
 
 
245
#include <stdio.h>
 
246
#include <stdlib.h>
 
247
#include <string.h>
 
248
 
 
249
#define WMAX 192
 
250
#define CMAX 128
 
251
#define AMAX 32
 
252
 
 
253
static Window root = None;
 
254
static Window watch[WMAX];
 
255
static Window apps[WMAX];
 
256
static int state[WMAX];
 
257
static char *clients[CMAX];
 
258
static XWindowAttributes attr;
 
259
static char *ticker_atom_str = "X11VNC_APPSHARE_TICKER";
 
260
static Atom ticker_atom = None;
 
261
static char *cmd_atom_str = "X11VNC_APPSHARE_COMMAND";
 
262
static Atom cmd_atom = None;
 
263
static char *connect_to = NULL;
 
264
static char *x11vnc_args = "";
 
265
static char *id_opt = "-id";
 
266
static int skip_menus = 1;
 
267
static int exit_no_app_win = 1;
 
268
static int shell = 0;
 
269
static int tree_depth = 3;
 
270
static char *prompt = "appshare> ";
 
271
static char *x11vnc = "x11vnc";
 
272
static char *control = NULL;
 
273
static char *trackdir = "unset";
 
274
static char *trackpre = "/tmp/x11vnc-appshare-trackdir-tmp";
 
275
static char *tracktmp = NULL;
 
276
static char unique_tag[100];
 
277
static int use_forever = 1;
 
278
static int last_event_type = 0;
 
279
static pid_t helper_pid = 0;
 
280
static pid_t parent_pid = 0;
 
281
static double helper_delay = 0.5;
 
282
static int appshare_debug = 0;
 
283
static double start_time = 0.0;
 
284
 
 
285
static void get_wm_name(Window win, char **name);
 
286
static int win_attr(Window win);
 
287
static int get_xy(Window win, int *x, int *y);
 
288
static Window check_inside(Window win);
 
289
static int ours(Window win);
 
290
static void destroy_win(Window win);
 
291
static int same_app(Window win, Window app);
 
292
 
 
293
static void ff(void) {
 
294
        fflush(stdout);
 
295
        fflush(stderr);
 
296
}
 
297
 
 
298
static int find_win(Window win) {
 
299
        int i;
 
300
        for (i=0; i < WMAX; i++) {
 
301
                if (watch[i] == win) {
 
302
                        return i;
 
303
                }
 
304
        }
 
305
        return -1;
 
306
}
 
307
 
 
308
static int find_app(Window app) {
 
309
        int i;
 
310
        for (i=0; i < AMAX; i++) {
 
311
                if (apps[i] == app) {
 
312
                        return i;
 
313
                }
 
314
        }
 
315
        return -1;
 
316
}
 
317
 
 
318
static int find_client(char *cl) {
 
319
        int i;
 
320
        for (i=0; i < CMAX; i++) {
 
321
                if (cl == NULL) {
 
322
                        if (clients[i] == NULL) {
 
323
                                return i;
 
324
                        }
 
325
                        continue;
 
326
                }
 
327
                if (clients[i] == NULL) {
 
328
                        continue;
 
329
                }
 
330
                if (!strcmp(clients[i], cl)) {
 
331
                        return i;
 
332
                }
 
333
        }
 
334
        return -1;
 
335
}
 
336
 
 
337
static int trackdir_pid(Window win) {
 
338
        FILE *f;
 
339
        int ln = 0, pid = 0;
 
340
        char line[1024];
 
341
 
 
342
        if (!trackdir) {
 
343
                return 0;
 
344
        }
 
345
        sprintf(tracktmp, "%s/0x%lx.log", trackdir, win);
 
346
        f = fopen(tracktmp, "r");
 
347
        if (!f) {
 
348
                return 0;
 
349
        }
 
350
        while (fgets(line, sizeof(line), f) != NULL) {
 
351
                if (ln++ > 30) {
 
352
                        break;
 
353
                }
 
354
                if (strstr(line, "x11vnc version:")) {
 
355
                        char *q = strstr(line, "pid:");
 
356
                        if (q) {
 
357
                                int p;
 
358
                                if (sscanf(q, "pid: %d", &p) == 1) {
 
359
                                        if (p > 0) {
 
360
                                                pid = p;
 
361
                                                break;
 
362
                                        }
 
363
                                }
 
364
                        }
 
365
                }
 
366
        }
 
367
        fclose(f);
 
368
        return pid;
 
369
}
 
370
 
 
371
static void trackdir_cleanup(Window win) {
 
372
        char *suffix[] = {"log", "connect", NULL};
 
373
        int i=0;
 
374
        if (!trackdir) {
 
375
                return;
 
376
        }
 
377
        while (suffix[i] != NULL) {
 
378
                sprintf(tracktmp, "%s/0x%lx.%s", trackdir, win, suffix[i]);
 
379
                if (appshare_debug && !strcmp(suffix[i], "log")) {
 
380
                        fprintf(stderr, "keeping:  %s\n", tracktmp);
 
381
                        ff();
 
382
                } else {
 
383
                        if (appshare_debug) {
 
384
                                fprintf(stderr, "removing: %s\n", tracktmp);
 
385
                                ff();
 
386
                        }
 
387
                        unlink(tracktmp);
 
388
                }
 
389
                i++;
 
390
        }
 
391
}
 
392
 
 
393
static void launch(Window win) {
 
394
        char *cmd, *tmp, *connto, *name;
 
395
        int len, timeo = 30, uf = use_forever;
 
396
        int w = 0, h = 0, x = 0, y = 0;
 
397
 
 
398
        if (win_attr(win)) {
 
399
                /* maybe switch to debug only. */
 
400
                w = attr.width;
 
401
                h = attr.height;
 
402
                get_xy(win, &x, &y);
 
403
        }
 
404
 
 
405
        get_wm_name(win, &name);
 
406
 
 
407
        if (strstr(x11vnc_args, "-once")) {
 
408
                uf = 0;
 
409
        }
 
410
 
 
411
        if (control) {
 
412
                int i = 0;
 
413
                len = 0;
 
414
                for (i=0; i < CMAX; i++) {
 
415
                        if (clients[i] != NULL) {
 
416
                                len += strlen(clients[i]) + 2;
 
417
                        }
 
418
                }
 
419
                connto = (char *) calloc(len, 1);
 
420
                for (i=0; i < CMAX; i++) {
 
421
                        if (clients[i] != NULL) {
 
422
                                if (connto[0] != '\0') {
 
423
                                        strcat(connto, ",");
 
424
                                }
 
425
                                strcat(connto, clients[i]);
 
426
                        }
 
427
                }
 
428
        } else {
 
429
                connto = strdup(connect_to);
 
430
        }
 
431
        if (!strcmp(connto, "")) {
 
432
                timeo = 0;
 
433
        }
 
434
        if (uf) {
 
435
                timeo = 0;
 
436
        }
 
437
        
 
438
        len = 1000 + strlen(x11vnc) + strlen(connto) + strlen(x11vnc_args)
 
439
            + 3 * (trackdir ? strlen(trackdir) : 100);
 
440
 
 
441
        cmd = (char *) calloc(len, 1);
 
442
        tmp = (char *) calloc(len, 1);
 
443
 
 
444
        sprintf(cmd, "%s %s 0x%lx -bg -quiet %s -nopw -rfbport 0 "
 
445
            "-timeout %d -noxdamage -noxinerama -norc -repeat -speeds dsl "
 
446
            "-env X11VNC_AVOID_WINDOWS=never -env X11VNC_APPSHARE_ACTIVE=1 "
 
447
            "-env X11VNC_NO_CHECK_PM=1 -env %s -novncconnect -shared -nonap "
 
448
            "-remote_prefix X11VNC_APPSHARE_CMD:",
 
449
            x11vnc, id_opt, win, use_forever ? "-forever" : "-once", timeo, unique_tag);
 
450
 
 
451
        if (trackdir) {
 
452
                FILE *f;
 
453
                sprintf(tracktmp, " -noquiet -o %s/0x%lx.log", trackdir, win);
 
454
                strcat(cmd, tracktmp);
 
455
                sprintf(tracktmp, "%s/0x%lx.connect", trackdir, win);
 
456
                f = fopen(tracktmp, "w");
 
457
                if (f) {
 
458
                        fprintf(f, "%s", connto);
 
459
                        fclose(f);
 
460
                        sprintf(tmp, " -connect_or_exit '%s'", tracktmp);
 
461
                        strcat(cmd, tmp);
 
462
                } else {
 
463
                        sprintf(tmp, " -connect_or_exit '%s'", connto);
 
464
                        strcat(cmd, tmp);
 
465
                }
 
466
        } else {
 
467
                if (!strcmp(connto, "")) {
 
468
                        sprintf(tmp, " -connect '%s'", connto);
 
469
                } else {
 
470
                        sprintf(tmp, " -connect_or_exit '%s'", connto);
 
471
                }
 
472
                strcat(cmd, tmp);
 
473
        }
 
474
        if (uf) {
 
475
                char *q = strstr(cmd, "-connect_or_exit");
 
476
                if (q) q = strstr(q, "_or_exit");
 
477
                if (q) {
 
478
                        unsigned int i;
 
479
                        for (i=0; i < strlen("_or_exit"); i++) {
 
480
                                *q = ' ';
 
481
                                q++;
 
482
                        }
 
483
                }
 
484
        }
 
485
 
 
486
        strcat(cmd, " ");
 
487
        strcat(cmd, x11vnc_args);
 
488
 
 
489
        fprintf(stdout, "launching: x11vnc for window 0x%08lx %dx%d+%d+%d \"%s\"\n",
 
490
            win, w, h, x, y, name);
 
491
 
 
492
        if (appshare_debug) {
 
493
                fprintf(stderr, "\nrunning:   %s\n\n", cmd);
 
494
        }
 
495
        ff();
 
496
 
 
497
        system(cmd);
 
498
 
 
499
        free(cmd);
 
500
        free(tmp);
 
501
        free(connto);
 
502
        free(name);
 
503
}
 
504
 
 
505
static void stop(Window win) {
 
506
        char *cmd;
 
507
        int pid = -1;
 
508
        int f = find_win(win);
 
509
        if (f < 0 || win == None) {
 
510
                return;
 
511
        }
 
512
        if (state[f] == 0) {
 
513
                return;
 
514
        }
 
515
        if (trackdir) {
 
516
                pid = trackdir_pid(win);
 
517
                if (pid > 0) {
 
518
                        if (appshare_debug) {fprintf(stderr,
 
519
                            "sending SIGTERM to: %d\n", pid); ff();}
 
520
                        kill((pid_t) pid, SIGTERM);
 
521
                }
 
522
        }
 
523
 
 
524
        cmd = (char *) malloc(1000 + strlen(x11vnc));
 
525
        sprintf(cmd, "pkill -TERM -f '%s %s 0x%lx -bg'", x11vnc, id_opt, win);
 
526
        if (appshare_debug) {
 
527
                fprintf(stdout, "stopping:  0x%08lx - %s\n", win, cmd);
 
528
        } else {
 
529
                fprintf(stdout, "stopping:  x11vnc for window 0x%08lx  "
 
530
                    "(pid: %d)\n", win, pid);
 
531
        }
 
532
        ff();
 
533
        system(cmd);
 
534
 
 
535
        sprintf(cmd, "(sleep 0.25 2>/dev/null || sleep 1; pkill -KILL -f '%s "
 
536
            "%s 0x%lx -bg') &", x11vnc, id_opt, win);
 
537
        system(cmd);
 
538
 
 
539
        if (trackdir) {
 
540
                trackdir_cleanup(win);
 
541
        }
 
542
 
 
543
        free(cmd);
 
544
}
 
545
 
 
546
static void kill_helper_pid(void) {
 
547
        int status;
 
548
        if (helper_pid <= 0) {
 
549
                return;
 
550
        }
 
551
        fprintf(stderr, "stopping: helper_pid: %d\n", (int) helper_pid);
 
552
        kill(helper_pid, SIGTERM);
 
553
        usleep(50 * 1000);
 
554
        kill(helper_pid, SIGKILL);
 
555
        usleep(25 * 1000);
 
556
#if LIBVNCSERVER_HAVE_SYS_WAIT_H && LIBVNCSERVER_HAVE_WAITPID 
 
557
        waitpid(helper_pid, &status, WNOHANG); 
 
558
#endif
 
559
}
 
560
 
 
561
static void be_helper_pid(char *dpy_str) {
 
562
        int cnt = 0;
 
563
        int ms = (int) (1000 * helper_delay);
 
564
        double last_check = 0.0;
 
565
 
 
566
        if (ms < 50) ms = 50;
 
567
 
 
568
#if NO_X11
 
569
        fprintf(stderr, "be_helper_pid: not compiled with X11.\n");
 
570
#else
 
571
        dpy = XOpenDisplay(dpy_str);
 
572
        ticker_atom = XInternAtom(dpy, ticker_atom_str, False);
 
573
 
 
574
        while (1) {
 
575
                char tmp[32];
 
576
                sprintf(tmp, "HELPER_CNT_%08d", cnt++);
 
577
                XChangeProperty(dpy, DefaultRootWindow(dpy), ticker_atom, XA_STRING, 8,
 
578
                    PropModeReplace, (unsigned char *) tmp, strlen(tmp));
 
579
                XFlush(dpy);
 
580
                usleep(ms*1000);
 
581
                if (parent_pid > 0) {
 
582
                        if(dnow() > last_check + 1.0) {
 
583
                                last_check = dnow();
 
584
                                if (kill(parent_pid, 0) != 0) {
 
585
                                        fprintf(stderr, "be_helper_pid: parent %d is gone.\n", (int) parent_pid);
 
586
                                        break;
 
587
                                }
 
588
                        }
 
589
                }
 
590
        }
 
591
#endif
 
592
        exit(0);
 
593
}
 
594
 
 
595
static void print_logs(void) {
 
596
        if (trackdir) {
 
597
                DIR *dir = opendir(trackdir);
 
598
                if (dir) {
 
599
                        struct dirent *dp;
 
600
                        while ( (dp = readdir(dir)) != NULL) {
 
601
                                FILE *f;
 
602
                                char *name = dp->d_name;
 
603
                                if (!strcmp(name, ".") || !strcmp(name, "..")) {
 
604
                                        continue;
 
605
                                }
 
606
                                if (strstr(name, "0x") != name) {
 
607
                                        continue;
 
608
                                }
 
609
                                if (strstr(name, ".log") == NULL) {
 
610
                                        continue;
 
611
                                }
 
612
                                sprintf(tracktmp, "%s/%s", trackdir, name);
 
613
                                f = fopen(tracktmp, "r");
 
614
                                if (f) {
 
615
                                        char line[1024];
 
616
                                        fprintf(stderr, "===== x11vnc log %s =====\n", tracktmp);
 
617
                                        while (fgets(line, sizeof(line), f) != NULL) {
 
618
                                                fprintf(stderr, "%s", line);
 
619
                                        }
 
620
                                        fprintf(stderr, "\n");
 
621
                                        ff();
 
622
                                        fclose(f);
 
623
                                }
 
624
                        }
 
625
                        closedir(dir);
 
626
                }
 
627
        }
 
628
}
 
629
 
 
630
static void appshare_cleanup(int s) {
 
631
        int i;
 
632
        if (s) {}
 
633
 
 
634
        if (use_forever) {
 
635
                /* launch this backup in case they kill -9 us before we terminate everything */
 
636
                char cmd[1000];
 
637
                sprintf(cmd, "(sleep 3; pkill -TERM -f '%s') &", unique_tag);
 
638
                if (appshare_debug) fprintf(stderr, "%s\n", cmd);
 
639
                system(cmd);
 
640
        }
 
641
 
 
642
        for (i=0; i < WMAX; i++) {
 
643
                if (watch[i] != None) {
 
644
                        stop(watch[i]);
 
645
                }
 
646
        }
 
647
 
 
648
        if (trackdir) {
 
649
                DIR *dir = opendir(trackdir);
 
650
                if (dir) {
 
651
                        struct dirent *dp;
 
652
                        while ( (dp = readdir(dir)) != NULL) {
 
653
                                char *name = dp->d_name;
 
654
                                if (!strcmp(name, ".") || !strcmp(name, "..")) {
 
655
                                        continue;
 
656
                                }
 
657
                                if (strstr(name, "0x") != name) {
 
658
                                        fprintf(stderr, "skipping: %s\n", name);
 
659
                                        continue;
 
660
                                }
 
661
                                if (!appshare_debug) {
 
662
                                        fprintf(stderr, "removing: %s\n", name);
 
663
                                        sprintf(tracktmp, "%s/%s", trackdir, name);
 
664
                                        unlink(tracktmp);
 
665
                                } else {
 
666
                                        if (appshare_debug) fprintf(stderr, "keeping:  %s\n", name);
 
667
                                }
 
668
                        }
 
669
                        closedir(dir);
 
670
                }
 
671
                if (!appshare_debug) {
 
672
                        if (strstr(trackdir, trackpre) == trackdir) {
 
673
                                if (appshare_debug) fprintf(stderr, "removing: %s\n", trackdir);
 
674
                                rmdir(trackdir);
 
675
                        }
 
676
                }
 
677
                ff();
 
678
        }
 
679
 
 
680
        kill_helper_pid();
 
681
                        
 
682
#if !NO_X11
 
683
        XCloseDisplay(dpy);
 
684
#endif
 
685
        fprintf(stdout, "done.\n");
 
686
        ff();
 
687
        exit(0);
 
688
}
 
689
 
 
690
static int trap_xerror(Display *d, XErrorEvent *error) {
 
691
        if (d || error) {}
 
692
        return 0;
 
693
}
 
694
 
 
695
#if 0
 
696
typedef struct {
 
697
    int x, y;                   /* location of window */
 
698
    int width, height;          /* width and height of window */
 
699
    int border_width;           /* border width of window */
 
700
    int depth;                  /* depth of window */
 
701
    Visual *visual;             /* the associated visual structure */
 
702
    Window root;                /* root of screen containing window */
 
703
    int class;                  /* InputOutput, InputOnly*/
 
704
    int bit_gravity;            /* one of bit gravity values */
 
705
    int win_gravity;            /* one of the window gravity values */
 
706
    int backing_store;          /* NotUseful, WhenMapped, Always */
 
707
    unsigned long backing_planes;/* planes to be preserved if possible */
 
708
    unsigned long backing_pixel;/* value to be used when restoring planes */
 
709
    Bool save_under;            /* boolean, should bits under be saved? */
 
710
    Colormap colormap;          /* color map to be associated with window */
 
711
    Bool map_installed;         /* boolean, is color map currently installed*/
 
712
    int map_state;              /* IsUnmapped, IsUnviewable, IsViewable */
 
713
    long all_event_masks;       /* set of events all people have interest in*/
 
714
    long your_event_mask;       /* my event mask */
 
715
    long do_not_propagate_mask; /* set of events that should not propagate */
 
716
    Bool override_redirect;     /* boolean value for override-redirect */
 
717
    Screen *screen;             /* back pointer to correct screen */
 
718
} XWindowAttributes;
 
719
#endif
 
720
 
 
721
static void get_wm_name(Window win, char **name) {
 
722
        int ok;
 
723
 
 
724
#if !NO_X11
 
725
        XErrorHandler old_handler = XSetErrorHandler(trap_xerror);
 
726
        ok = XFetchName(dpy, win, name);
 
727
        XSetErrorHandler(old_handler);
 
728
#endif
 
729
 
 
730
        if (!ok || *name == NULL) {
 
731
                *name = strdup("unknown");
 
732
        }
 
733
}
 
734
 
 
735
static int win_attr(Window win) {
 
736
        int ok = 0;
 
737
#if !NO_X11
 
738
        XErrorHandler old_handler = XSetErrorHandler(trap_xerror);
 
739
        ok = XGetWindowAttributes(dpy, win, &attr);
 
740
        XSetErrorHandler(old_handler);
 
741
#endif
 
742
 
 
743
        if (ok) {
 
744
                return 1;
 
745
        } else {
 
746
                return 0;
 
747
        }
 
748
}
 
749
 
 
750
static void win_select(Window win, int ignore) {
 
751
#if !NO_X11
 
752
        XErrorHandler old_handler = XSetErrorHandler(trap_xerror);
 
753
        if (ignore) {
 
754
                XSelectInput(dpy, win, 0);
 
755
        } else {
 
756
                XSelectInput(dpy, win, SubstructureNotifyMask);
 
757
        }
 
758
        XSync(dpy, False);
 
759
        XSetErrorHandler(old_handler);
 
760
#endif
 
761
}
 
762
 
 
763
static Window get_parent(Window win) {
 
764
        int ok;
 
765
        Window r, parent = None, *list = NULL;
 
766
        unsigned int nchild;
 
767
 
 
768
#if !NO_X11
 
769
        XErrorHandler old_handler = XSetErrorHandler(trap_xerror);
 
770
        ok = XQueryTree(dpy, win, &r, &parent, &list, &nchild);
 
771
        XSetErrorHandler(old_handler);
 
772
 
 
773
        if (!ok) {
 
774
                return None;
 
775
        }
 
776
        if (list) {
 
777
                XFree(list);
 
778
        }
 
779
#endif
 
780
        return parent;
 
781
}
 
782
 
 
783
static int get_xy(Window win, int *x, int *y) {
 
784
        Window cr;
 
785
        Bool rc = False; 
 
786
#if !NO_X11
 
787
        XErrorHandler old_handler = XSetErrorHandler(trap_xerror);
 
788
 
 
789
        rc = XTranslateCoordinates(dpy, win, root, 0, 0, x, y, &cr);
 
790
        XSetErrorHandler(old_handler);
 
791
#endif
 
792
 
 
793
        if (!rc) {
 
794
                return 0;
 
795
        } else {
 
796
                return 1;
 
797
        }
 
798
}
 
799
 
 
800
static Window check_inside(Window win) {
 
801
        int i, nwin = 0;
 
802
        int w, h, x, y;
 
803
        int Ws[WMAX], Hs[WMAX], Xs[WMAX], Ys[WMAX];
 
804
        Window wins[WMAX];
 
805
 
 
806
        if (!win_attr(win)) {
 
807
                return None; 
 
808
        }
 
809
 
 
810
        /* store them first to give the win app more time to settle.  */
 
811
        for (i=0; i < WMAX; i++) {
 
812
                int X, Y;
 
813
                Window wchk = watch[i];
 
814
                if (wchk == None) {
 
815
                        continue;
 
816
                }
 
817
                if (state[i] == 0) {
 
818
                        continue;
 
819
                }
 
820
                if (!win_attr(wchk)) {
 
821
                        continue;
 
822
                }
 
823
                if (!get_xy(wchk, &X, &Y)) {
 
824
                        continue;
 
825
                }
 
826
 
 
827
                Xs[nwin] = X;
 
828
                Ys[nwin] = Y;
 
829
                Ws[nwin] = attr.width;
 
830
                Hs[nwin] = attr.height;
 
831
                wins[nwin] = wchk;
 
832
                nwin++;
 
833
        }
 
834
 
 
835
        if (nwin == 0) {
 
836
                return None;
 
837
        }
 
838
 
 
839
        if (!win_attr(win)) {
 
840
                return None; 
 
841
        }
 
842
        w = attr.width;
 
843
        h = attr.height;
 
844
 
 
845
        get_xy(win, &x, &y);
 
846
        if (!get_xy(win, &x, &y)) {
 
847
                return None;
 
848
        }
 
849
 
 
850
        for (i=0; i < nwin; i++) {
 
851
                int X, Y, W, H;
 
852
                Window wchk = wins[i];
 
853
                X = Xs[i];
 
854
                Y = Ys[i];
 
855
                W = Ws[i];
 
856
                H = Hs[i];
 
857
 
 
858
                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);
 
859
 
 
860
                if (X <= x && Y <= y) {
 
861
                        if (x + w  <= X + W && y + h < Y + H) {
 
862
                                return wchk;
 
863
                        }
 
864
                }
 
865
        }
 
866
 
 
867
        return None;
 
868
}
 
869
 
 
870
static void add_win(Window win) {
 
871
        int idx  = find_win(win);
 
872
        int free = find_win(None);
 
873
        if (idx >= 0) {
 
874
                if (appshare_debug) {fprintf(stderr, "already watching window: 0x%lx\n", win); ff();}
 
875
                return;
 
876
        }
 
877
        if (free < 0) {
 
878
                fprintf(stderr, "ran out of slots for window: 0x%lx\n", win); ff();
 
879
                return;
 
880
        }
 
881
 
 
882
        if (appshare_debug) {fprintf(stderr, "watching: 0x%lx at %d\n", win, free); ff();}
 
883
 
 
884
        watch[free] = win;
 
885
        state[free] = 0;
 
886
 
 
887
        win_select(win, 0);
 
888
}
 
889
 
 
890
static void delete_win(Window win) {
 
891
        int i;
 
892
        for (i=0; i < WMAX; i++) {
 
893
                if (watch[i] == win) {
 
894
                        watch[i] = None;
 
895
                        state[i] = 0;
 
896
                        if (appshare_debug) {fprintf(stderr, "deleting: 0x%lx at %d\n", win, i); ff();}
 
897
                }
 
898
        }
 
899
}
 
900
 
 
901
static void recurse_search(int level, int level_max, Window top, Window app, int *nw) {
 
902
        Window w, r, parent, *list = NULL;
 
903
        unsigned int nchild;
 
904
        int ok = 0;
 
905
 
 
906
        if (appshare_debug > 1) {
 
907
                fprintf(stderr, "level: %d level_max: %d  top: 0x%lx  app: 0x%lx\n", level, level_max, top, app);
 
908
        }
 
909
        if (level >= level_max) {
 
910
                return;
 
911
        }
 
912
        
 
913
#if !NO_X11
 
914
        ok = XQueryTree(dpy, top, &r, &parent, &list, &nchild);
 
915
        if (ok) {
 
916
                int i;
 
917
                for (i=0; i < (int) nchild; i++) {
 
918
                        w = list[i];
 
919
                        if (w == None || find_win(w) >= 0) {
 
920
                                continue;
 
921
                        }
 
922
                        if (ours(w) && w != app) {
 
923
                                if (appshare_debug) fprintf(stderr, "add level %d 0x%lx %d/%d\n",
 
924
                                    level, w, i, nchild);
 
925
                                add_win(w);
 
926
                                (*nw)++;
 
927
                        }
 
928
                }
 
929
                for (i=0; i < (int) nchild; i++) {
 
930
                        w = list[i];
 
931
                        if (w == None || ours(w)) {
 
932
                                continue;
 
933
                        } 
 
934
                        recurse_search(level+1, level_max, w, app, nw);
 
935
                }
 
936
        }
 
937
        if (list) {
 
938
                XFree(list);
 
939
        }
 
940
#endif
 
941
}
 
942
                
 
943
static void add_app(Window app) {
 
944
        int i, nw = 0, free = -1;
 
945
        XErrorHandler old_handler;
 
946
 
 
947
#if !NO_X11
 
948
        i = find_app(app);
 
949
        if (i >= 0) {
 
950
                fprintf(stderr, "already tracking app: 0x%lx\n", app);
 
951
                return;
 
952
        }
 
953
        for (i=0; i < AMAX; i++) {
 
954
                if (same_app(apps[i], app)) {
 
955
                        fprintf(stderr, "already tracking app: 0x%lx via 0x%lx\n", app, apps[i]);
 
956
                        return;
 
957
                }
 
958
        }
 
959
        free = find_app(None);
 
960
        if (free < 0) {
 
961
                fprintf(stderr, "ran out of app slots.\n");
 
962
                return;
 
963
        }
 
964
        apps[free] = app;
 
965
 
 
966
        add_win(app);
 
967
 
 
968
        old_handler = XSetErrorHandler(trap_xerror);
 
969
        recurse_search(0, tree_depth, root, app, &nw);
 
970
        XSetErrorHandler(old_handler);
 
971
#endif
 
972
        fprintf(stderr, "tracking %d windows related to app window 0x%lx\n", nw, app);
 
973
}
 
974
 
 
975
static void del_app(Window app) {
 
976
        int i;
 
977
        for (i=0; i < WMAX; i++) {
 
978
                Window win = watch[i];
 
979
                if (win != None) {
 
980
                        if (same_app(app, win)) {
 
981
                                destroy_win(win);
 
982
                        }
 
983
                }
 
984
        }
 
985
        for (i=0; i < AMAX; i++) {
 
986
                Window app2 = apps[i];
 
987
                if (app2 != None) {
 
988
                        if (same_app(app, app2)) {
 
989
                                apps[i] = None;
 
990
                        }
 
991
                }
 
992
        }
 
993
}
 
994
 
 
995
static void wait_until_empty(char *file) {
 
996
        double t = 0.0, dt = 0.05;
 
997
        while (t < 1.0) {
 
998
                struct stat sb;
 
999
                if (stat(file, &sb) != 0) {
 
1000
                        return;
 
1001
                }
 
1002
                if (sb.st_size == 0) {
 
1003
                        return;
 
1004
                }
 
1005
                t += dt;
 
1006
                usleep( (int) (dt * 1000 * 1000) );
 
1007
        }
 
1008
}
 
1009
 
 
1010
static void client(char *client, int add) {
 
1011
        DIR *dir;
 
1012
        struct dirent *dp;
 
1013
 
 
1014
        if (!client) {
 
1015
                return;
 
1016
        }
 
1017
        if (!trackdir) {
 
1018
                fprintf(stderr, "no trackdir, cannot %s client: %s\n",
 
1019
                    add ? "add" : "disconnect", client);
 
1020
                ff();
 
1021
                return;
 
1022
        }
 
1023
        fprintf(stdout, "%s client: %s\n", add ? "adding  " : "deleting", client);
 
1024
 
 
1025
        dir = opendir(trackdir);
 
1026
        if (!dir) {
 
1027
                fprintf(stderr, "could not opendir trackdir: %s\n", trackdir);
 
1028
                return;
 
1029
        }
 
1030
        while ( (dp = readdir(dir)) != NULL) {
 
1031
                char *name = dp->d_name;
 
1032
                if (!strcmp(name, ".") || !strcmp(name, "..")) {
 
1033
                        continue;
 
1034
                }
 
1035
                if (strstr(name, "0x") != name) {
 
1036
                        continue;
 
1037
                }
 
1038
                if (strstr(name, ".connect")) {
 
1039
                        FILE *f;
 
1040
                        char *tmp;
 
1041
                        Window twin;
 
1042
 
 
1043
                        if (scan_hexdec(name, &twin)) {
 
1044
                                int f = find_win(twin);
 
1045
                                if (appshare_debug) {
 
1046
                                        fprintf(stderr, "twin: 0x%lx name=%s f=%d\n", twin, name, f);
 
1047
                                        ff();
 
1048
                                }
 
1049
                                if (f < 0) {
 
1050
                                        continue;
 
1051
                                }
 
1052
                        }
 
1053
 
 
1054
                        tmp = (char *) calloc(100 + strlen(client), 1);
 
1055
                        sprintf(tracktmp, "%s/%s", trackdir, name);
 
1056
                        if (add) {
 
1057
                                sprintf(tmp, "%s\n", client);
 
1058
                        } else {
 
1059
                                sprintf(tmp, "cmd=close:%s\n", client);
 
1060
                        }
 
1061
                        wait_until_empty(tracktmp);
 
1062
                        f = fopen(tracktmp, "w");
 
1063
                        if (f) {
 
1064
                                if (appshare_debug) {
 
1065
                                        fprintf(stderr, "%s client: %s + %s",
 
1066
                                        add ? "add" : "disconnect", tracktmp, tmp);
 
1067
                                        ff();
 
1068
                                }
 
1069
                                fprintf(f, "%s", tmp);
 
1070
                                fclose(f);
 
1071
                        }
 
1072
                        free(tmp);
 
1073
                }
 
1074
        }
 
1075
        closedir(dir);
 
1076
}
 
1077
 
 
1078
static void mapped(Window win) {
 
1079
        int f;
 
1080
        if (win == None) {
 
1081
                return;
 
1082
        }
 
1083
        f = find_win(win);
 
1084
        if (f < 0) {
 
1085
                if (win_attr(win)) {
 
1086
                        if (get_parent(win) == root) {
 
1087
                                /* XXX more cases? */
 
1088
                                add_win(win);
 
1089
                        }
 
1090
                }
 
1091
        }
 
1092
}
 
1093
 
 
1094
static void unmapped(Window win) {
 
1095
        int f = find_win(win);
 
1096
        if (f < 0 || win == None) {
 
1097
                return;
 
1098
        }
 
1099
        stop(win);      
 
1100
        state[f] = 0;
 
1101
}
 
1102
 
 
1103
static void destroy_win(Window win) {
 
1104
        stop(win);
 
1105
        delete_win(win);
 
1106
}
 
1107
 
 
1108
static Window parse_win(char *str) {
 
1109
        Window win = None;
 
1110
        if (!str) {
 
1111
                return None;
 
1112
        }
 
1113
        if (!strcmp(str, "pick") || !strcmp(str, "p")) {
 
1114
                static double last_pick = 0.0;
 
1115
                if (dnow() < start_time + 15) {
 
1116
                        ;
 
1117
                } else if (dnow() < last_pick + 2) {
 
1118
                        return None;
 
1119
                } else {
 
1120
                        last_pick = dnow();
 
1121
                }
 
1122
                if (!pick_windowid(&win)) {
 
1123
                        fprintf(stderr, "parse_win: bad window pick.\n");
 
1124
                        win = None;
 
1125
                }
 
1126
                if (win == root) {
 
1127
                        fprintf(stderr, "parse_win: ignoring pick of rootwin 0x%lx.\n", win);
 
1128
                        win = None;
 
1129
                }
 
1130
                ff();
 
1131
        } else if (!scan_hexdec(str, &win)) {
 
1132
                win = None;
 
1133
        }
 
1134
        return win;
 
1135
}
 
1136
 
 
1137
static void add_or_del_app(char *str, int add) {
 
1138
        Window win = parse_win(str);
 
1139
 
 
1140
        if (win != None) {
 
1141
                if (add) {
 
1142
                        add_app(win);
 
1143
                } else {
 
1144
                        del_app(win);
 
1145
                }
 
1146
        } else if (!strcmp(str, "all")) {
 
1147
                if (!add) {
 
1148
                        int i;
 
1149
                        for (i=0; i < AMAX; i++) {
 
1150
                                if (apps[i] != None) {
 
1151
                                        del_app(apps[i]);
 
1152
                                }
 
1153
                        }
 
1154
                }
 
1155
        }
 
1156
}
 
1157
 
 
1158
static void add_or_del_win(char *str, int add) {
 
1159
        Window win = parse_win(str);
 
1160
 
 
1161
        if (win != None) {
 
1162
                int f = find_win(win);
 
1163
                if (add) {
 
1164
                        if (f < 0 && win_attr(win)) {
 
1165
                                add_win(win);
 
1166
                        }
 
1167
                } else {
 
1168
                        if (f >= 0) {
 
1169
                                destroy_win(win);
 
1170
                        }
 
1171
                }
 
1172
        } else if (!strcmp(str, "all")) {
 
1173
                if (!add) {
 
1174
                        int i;
 
1175
                        for (i=0; i < WMAX; i++) {
 
1176
                                if (watch[i] != None) {
 
1177
                                        destroy_win(watch[i]);
 
1178
                                }
 
1179
                        }
 
1180
                }
 
1181
        } 
 
1182
}
 
1183
 
 
1184
static void add_or_del_client(char *str, int add) {
 
1185
        int i;
 
1186
 
 
1187
        if (!str) {
 
1188
                return;
 
1189
        }
 
1190
        if (strcmp(control, "internal")) {
 
1191
                return;
 
1192
        }
 
1193
        if (add) {
 
1194
                int idx  = find_client(str);
 
1195
                int free = find_client(NULL);
 
1196
 
 
1197
                if (idx >=0) {
 
1198
                        fprintf(stderr, "already tracking client: %s in slot %d\n", str, idx);
 
1199
                        ff();
 
1200
                        return;
 
1201
                }
 
1202
                if (free < 0) {
 
1203
                        static int cnt = 0;
 
1204
                        if (cnt++ < 10) {
 
1205
                                fprintf(stderr, "ran out of client slots.\n");
 
1206
                                ff();
 
1207
                        }
 
1208
                        return;
 
1209
                }
 
1210
                clients[free] = strdup(str);
 
1211
                client(str, 1);
 
1212
        } else {
 
1213
                if (str[0] == '#' || str[0] == '%') {
 
1214
                        if (sscanf(str+1, "%d", &i) == 1) {
 
1215
                                i--;
 
1216
                                if (0 <= i && i < CMAX) {
 
1217
                                        if (clients[i] != NULL) {
 
1218
                                                client(clients[i], 0);
 
1219
                                                free(clients[i]);
 
1220
                                                clients[i] = NULL;
 
1221
                                                return;
 
1222
                                        }
 
1223
                                }
 
1224
                        }
 
1225
                } else if (!strcmp(str, "all")) {
 
1226
                        for (i=0; i < CMAX; i++) {
 
1227
                                if (clients[i] == NULL) {
 
1228
                                        continue;
 
1229
                                }
 
1230
                                client(clients[i], 0);
 
1231
                                free(clients[i]);
 
1232
                                clients[i] = NULL;
 
1233
                        }
 
1234
                        return;
 
1235
                }
 
1236
 
 
1237
                i = find_client(str);
 
1238
                if (i >= 0) {
 
1239
                        free(clients[i]);
 
1240
                        clients[i] = NULL;
 
1241
                        client(str, 0);
 
1242
                }
 
1243
        }
 
1244
}
 
1245
 
 
1246
static void restart_x11vnc(void) {
 
1247
        int i, n = 0;
 
1248
        Window win, active[WMAX];
 
1249
        for (i=0; i < WMAX; i++) {
 
1250
                win = watch[i];
 
1251
                if (win == None) {
 
1252
                        continue;
 
1253
                }
 
1254
                if (state[i]) {
 
1255
                        active[n++] = win;
 
1256
                        stop(win);
 
1257
                }
 
1258
        }
 
1259
        if (n) {
 
1260
                usleep(1500 * 1000);
 
1261
        }
 
1262
        for (i=0; i < n; i++) {
 
1263
                win = active[i];
 
1264
                launch(win);
 
1265
        }
 
1266
}
 
1267
 
 
1268
static unsigned long cmask = 0x3fc00000; /* 00111111110000000000000000000000 */
 
1269
 
 
1270
static void init_cmask(void) {
 
1271
        /* dependent on the X server implementation; XmuClientWindow better? */
 
1272
        /* xc/programs/Xserver/include/resource.h */
 
1273
        int didit = 0, res_cnt = 29, client_bits = 8;
 
1274
 
 
1275
        if (getenv("X11VNC_APPSHARE_CLIENT_MASK")) {
 
1276
                unsigned long cr;
 
1277
                if (sscanf(getenv("X11VNC_APPSHARE_CLIENT_MASK"), "0x%lx", &cr) == 1) {
 
1278
                        cmask = cr;
 
1279
                        didit = 1;
 
1280
                }
 
1281
        } else if (getenv("X11VNC_APPSHARE_CLIENT_BITS")) {
 
1282
                int cr = atoi(getenv("X11VNC_APPSHARE_CLIENT_BITS"));
 
1283
                if (cr > 0) {
 
1284
                        client_bits = cr;
 
1285
                }
 
1286
        }
 
1287
        if (!didit) {
 
1288
                cmask = (((1 << client_bits) - 1) << (res_cnt-client_bits));
 
1289
        }
 
1290
        fprintf(stderr, "client_mask: 0x%08lx\n", cmask);
 
1291
}
 
1292
 
 
1293
static int same_app(Window win, Window app) {
 
1294
        if ( (win & cmask) == (app & cmask) ) {
 
1295
                return 1;
 
1296
        } else {
 
1297
                return 0;
 
1298
        }
 
1299
}
 
1300
 
 
1301
static int ours(Window win) {
 
1302
        int i;
 
1303
        for (i=0; i < AMAX; i++) {
 
1304
                if (apps[i] != None) {
 
1305
                        if (same_app(win, apps[i])) {
 
1306
                                return 1;
 
1307
                        }
 
1308
                }
 
1309
        }
 
1310
        return 0;
 
1311
}
 
1312
 
 
1313
static void list_clients(void) {
 
1314
        int i, n = 0;
 
1315
        for (i=0; i < CMAX; i++) {
 
1316
                if (clients[i] == NULL) {
 
1317
                        continue;
 
1318
                }
 
1319
                fprintf(stdout, "client[%02d] %s\n", ++n, clients[i]);
 
1320
        }
 
1321
        fprintf(stdout, "total clients: %d\n", n);
 
1322
        ff();
 
1323
}
 
1324
 
 
1325
static void list_windows(void) {
 
1326
        int i, n = 0;
 
1327
        for (i=0; i < WMAX; i++) {
 
1328
                char *name;
 
1329
                Window win = watch[i];
 
1330
                if (win == None) {
 
1331
                        continue;
 
1332
                }
 
1333
                get_wm_name(win, &name);
 
1334
                fprintf(stdout, "window[%02d] 0x%08lx state: %d slot: %03d \"%s\"\n",
 
1335
                    ++n, win, state[i], i, name);
 
1336
                free(name);
 
1337
        }
 
1338
        fprintf(stdout, "total windows: %d\n", n);
 
1339
        ff();
 
1340
}
 
1341
 
 
1342
static void list_apps(void) {
 
1343
        int i, n = 0;
 
1344
        for (i=0; i < AMAX; i++) {
 
1345
                char *name;
 
1346
                Window win = apps[i];
 
1347
                if (win == None) {
 
1348
                        continue;
 
1349
                }
 
1350
                get_wm_name(win, &name);
 
1351
                fprintf(stdout, "app[%02d] 0x%08lx state: %d slot: %03d \"%s\"\n",
 
1352
                    ++n, win, state[i], i, name);
 
1353
                free(name);
 
1354
        }
 
1355
        fprintf(stdout, "total apps: %d\n", n);
 
1356
        ff();
 
1357
}
 
1358
 
 
1359
static int process_control(char *file, int check_clients) {
 
1360
        int i, nnew = 0, seen[CMAX];
 
1361
        char line[1024], *new[CMAX];
 
1362
        FILE *f;
 
1363
 
 
1364
        f = fopen(file, "r");
 
1365
        if (!f) {
 
1366
                return 1;
 
1367
        }
 
1368
        if (check_clients) {
 
1369
                for (i=0; i < CMAX; i++) {
 
1370
                        seen[i] = 0;
 
1371
                }
 
1372
        }
 
1373
        while (fgets(line, sizeof(line), f) != NULL) {
 
1374
                char *q = strchr(line, '\n');
 
1375
                if (q) *q = '\0';
 
1376
 
 
1377
                if (appshare_debug) {
 
1378
                        fprintf(stderr, "check_control: %s\n", line);
 
1379
                        ff();
 
1380
                }
 
1381
 
 
1382
                q = lblanks(line);
 
1383
                if (q[0] == '#') {
 
1384
                        continue;
 
1385
                }
 
1386
                if (!strcmp(q, "")) {
 
1387
                        continue;
 
1388
                }
 
1389
                if (strstr(q, "cmd=") == q) {
 
1390
                        char *cmd = q + strlen("cmd=");
 
1391
                        if (!strcmp(cmd, "quit")) {
 
1392
                                if (strcmp(control, file) && strstr(file, ".cmd")) {
 
1393
                                        FILE *f2 = fopen(file, "w");
 
1394
                                        if (f2) fclose(f2);
 
1395
                                }
 
1396
                                appshare_cleanup(0);
 
1397
                        } else if (!strcmp(cmd, "wait")) {
 
1398
                                return 0;
 
1399
                        } else if (strstr(cmd, "bcast:") == cmd) {
 
1400
                                ;
 
1401
                        } else if (strstr(cmd, "del_window:") == cmd) {
 
1402
                                add_or_del_win(cmd + strlen("del_window:"), 0);
 
1403
                        } else if (strstr(cmd, "add_window:") == cmd) {
 
1404
                                add_or_del_win(cmd + strlen("add_window:"), 1);
 
1405
                        } else if (strstr(cmd, "del:") == cmd) {
 
1406
                                add_or_del_win(cmd + strlen("del:"), 0);
 
1407
                        } else if (strstr(cmd, "add:") == cmd) {
 
1408
                                add_or_del_win(cmd + strlen("add:"), 1);
 
1409
                        } else if (strstr(cmd, "del_client:") == cmd) {
 
1410
                                add_or_del_client(cmd + strlen("del_client:"), 0);
 
1411
                        } else if (strstr(cmd, "add_client:") == cmd) {
 
1412
                                add_or_del_client(cmd + strlen("add_client:"), 1);
 
1413
                        } else if (strstr(cmd, "-") == cmd) {
 
1414
                                add_or_del_client(cmd + strlen("-"), 0);
 
1415
                        } else if (strstr(cmd, "+") == cmd) {
 
1416
                                add_or_del_client(cmd + strlen("+"), 1);
 
1417
                        } else if (strstr(cmd, "del_app:") == cmd) {
 
1418
                                add_or_del_app(cmd + strlen("del_app:"), 0);
 
1419
                        } else if (strstr(cmd, "add_app:") == cmd) {
 
1420
                                add_or_del_app(cmd + strlen("add_app:"), 1);
 
1421
                        } else if (strstr(cmd, "debug:") == cmd) {
 
1422
                                appshare_debug = atoi(cmd + strlen("debug:"));
 
1423
                        } else if (strstr(cmd, "showmenus:") == cmd) {
 
1424
                                skip_menus = atoi(cmd + strlen("showmenus:"));
 
1425
                                skip_menus = !(skip_menus);
 
1426
                        } else if (strstr(cmd, "noexit:") == cmd) {
 
1427
                                exit_no_app_win = atoi(cmd + strlen("noexit:"));
 
1428
                                exit_no_app_win = !(exit_no_app_win);
 
1429
                        } else if (strstr(cmd, "use_forever:") == cmd) {
 
1430
                                use_forever = atoi(cmd + strlen("use_forever:"));
 
1431
                        } else if (strstr(cmd, "tree_depth:") == cmd) {
 
1432
                                tree_depth = atoi(cmd + strlen("tree_depth:"));
 
1433
                        } else if (strstr(cmd, "x11vnc_args:") == cmd) {
 
1434
                                x11vnc_args = strdup(cmd + strlen("x11vnc_args:"));
 
1435
                        } else if (strstr(cmd, "env:") == cmd) {
 
1436
                                putenv(cmd + strlen("env:"));
 
1437
                        } else if (strstr(cmd, "noop") == cmd) {
 
1438
                                ;
 
1439
                        } else if (!strcmp(cmd, "restart")) {
 
1440
                                restart_x11vnc();
 
1441
                        } else if (!strcmp(cmd, "list_clients") || !strcmp(cmd, "lc")) {
 
1442
                                list_clients();
 
1443
                        } else if (!strcmp(cmd, "list_windows") || !strcmp(cmd, "lw")) {
 
1444
                                list_windows();
 
1445
                        } else if (!strcmp(cmd, "list_apps") || !strcmp(cmd, "la")) {
 
1446
                                list_apps();
 
1447
                        } else if (!strcmp(cmd, "list_all") || !strcmp(cmd, "ls")) {
 
1448
                                list_windows();
 
1449
                                fprintf(stderr, "\n");
 
1450
                                list_apps();
 
1451
                                fprintf(stderr, "\n");
 
1452
                                list_clients();
 
1453
                        } else if (!strcmp(cmd, "print_logs") || !strcmp(cmd, "pl")) {
 
1454
                                print_logs();
 
1455
                        } else if (!strcmp(cmd, "?") || !strcmp(cmd, "h") || !strcmp(cmd, "help")) {
 
1456
                                fprintf(stderr, "available commands:\n");
 
1457
                                fprintf(stderr, "\n");
 
1458
                                fprintf(stderr, "   quit restart noop x11vnc help ? ! !!\n");
 
1459
                                fprintf(stderr, "\n");
 
1460
                                fprintf(stderr, "   add_window:win  (add:win, add:pick)\n");
 
1461
                                fprintf(stderr, "   del_window:win  (del:win, del:pick, del:all)\n");
 
1462
                                fprintf(stderr, "   add_app:win     (add_app:pick)\n");
 
1463
                                fprintf(stderr, "   del_app:win     (del_app:pick, del_app:all)\n");
 
1464
                                fprintf(stderr, "   add_client:host (+host)\n");
 
1465
                                fprintf(stderr, "   del_client:host (-host, -all)\n");
 
1466
                                fprintf(stderr, "\n");
 
1467
                                fprintf(stderr, "   list_windows    (lw)\n");
 
1468
                                fprintf(stderr, "   list_apps       (la)\n");
 
1469
                                fprintf(stderr, "   list_clients    (lc)\n");
 
1470
                                fprintf(stderr, "   list_all        (ls)\n");
 
1471
                                fprintf(stderr, "   print_logs      (pl)\n");
 
1472
                                fprintf(stderr, "\n");
 
1473
                                fprintf(stderr, "   debug:n   showmenus:n   noexit:n\n");
 
1474
                        } else {
 
1475
                                fprintf(stderr, "unrecognized %s\n", q);
 
1476
                        }
 
1477
                        continue;
 
1478
                }
 
1479
                if (check_clients) {
 
1480
                        int idx = find_client(q);
 
1481
                        if (idx >= 0) {
 
1482
                                seen[idx] = 1;
 
1483
                        } else {
 
1484
                                new[nnew++] = strdup(q);
 
1485
                        }
 
1486
                }
 
1487
        }
 
1488
        fclose(f);
 
1489
 
 
1490
        if (check_clients) {
 
1491
                for (i=0; i < CMAX; i++) {
 
1492
                        if (clients[i] == NULL) {
 
1493
                                continue;
 
1494
                        }
 
1495
                        if (!seen[i]) {
 
1496
                                client(clients[i], 0);
 
1497
                                free(clients[i]);
 
1498
                                clients[i] = NULL;
 
1499
                        }
 
1500
                }
 
1501
                for (i=0; i < nnew; i++) {
 
1502
                        int free = find_client(NULL);
 
1503
                        if (free < 0) {
 
1504
                                static int cnt = 0;
 
1505
                                if (cnt++ < 10) {
 
1506
                                        fprintf(stderr, "ran out of client slots.\n");
 
1507
                                        ff();
 
1508
                                        break;
 
1509
                                }
 
1510
                                continue;
 
1511
                        }
 
1512
                        clients[free] = new[i];
 
1513
                        client(new[i], 1);
 
1514
                }
 
1515
        }
 
1516
        return 1;
 
1517
}
 
1518
 
 
1519
static int check_control(void) {
 
1520
        static int last_size = -1;
 
1521
        static time_t last_mtime = 0;
 
1522
        struct stat sb;
 
1523
        char *control_cmd;
 
1524
 
 
1525
        if (!control) {
 
1526
                return 1;
 
1527
        }
 
1528
 
 
1529
        if (!strcmp(control, "internal")) {
 
1530
                return 1;
 
1531
        }
 
1532
                
 
1533
        control_cmd = (char *)malloc(strlen(control) + strlen(".cmd") + 1);
 
1534
        sprintf(control_cmd, "%s.cmd", control);
 
1535
        if (stat(control_cmd, &sb) == 0) {
 
1536
                FILE *f;
 
1537
                if (sb.st_size > 0) {
 
1538
                        process_control(control_cmd, 0);
 
1539
                }
 
1540
                f = fopen(control_cmd, "w");
 
1541
                if (f) {
 
1542
                        fclose(f);
 
1543
                }
 
1544
        }
 
1545
        free(control_cmd);
 
1546
 
 
1547
        if (stat(control, &sb) != 0) {
 
1548
                return 1;
 
1549
        }
 
1550
        if (last_size == (int) sb.st_size && last_mtime == sb.st_mtime) {
 
1551
                return 1;
 
1552
        }
 
1553
        last_size = (int) sb.st_size;
 
1554
        last_mtime = sb.st_mtime;
 
1555
 
 
1556
        return process_control(control, 1);
 
1557
}
 
1558
 
 
1559
static void update(void) {
 
1560
        int i, app_ok = 0;
 
1561
        if (last_event_type != PropertyNotify) {
 
1562
                if (appshare_debug) fprintf(stderr, "\nupdate ...\n");
 
1563
        } else if (appshare_debug > 1) {
 
1564
                fprintf(stderr, "update ... propertynotify\n");
 
1565
        }
 
1566
        if (!check_control()) {
 
1567
                return;
 
1568
        }
 
1569
        for (i=0; i < WMAX; i++) {
 
1570
                Window win = watch[i];
 
1571
                if (win == None) {
 
1572
                        continue;
 
1573
                }
 
1574
                if (!win_attr(win)) {
 
1575
                        destroy_win(win);
 
1576
                        continue;
 
1577
                }
 
1578
                if (find_app(win) >= 0) {
 
1579
                        app_ok++;
 
1580
                }
 
1581
                if (state[i] == 0) {
 
1582
                        if (attr.map_state == IsViewable) {
 
1583
                                if (skip_menus) {
 
1584
                                        Window inside = check_inside(win);
 
1585
                                        if (inside != None) {
 
1586
                                                if (appshare_debug) {fprintf(stderr, "skip_menus: window 0x%lx is inside of 0x%lx, not tracking it.\n", win, inside); ff();}
 
1587
                                                delete_win(win);
 
1588
                                                continue;
 
1589
                                        }
 
1590
                                }
 
1591
                                launch(win);
 
1592
                                state[i] = 1;
 
1593
                        }
 
1594
                } else if (state[i] == 1) {
 
1595
                        if (attr.map_state != IsViewable) {
 
1596
                                stop(win);
 
1597
                                state[i] = 0;
 
1598
                        }
 
1599
                }
 
1600
        }
 
1601
        if (exit_no_app_win && !app_ok) {
 
1602
                for (i=0; i < AMAX; i++) {
 
1603
                        if (apps[i] != None) {
 
1604
                                fprintf(stdout, "main application window is gone: 0x%lx\n", apps[i]);
 
1605
                        }
 
1606
                }
 
1607
                ff();
 
1608
                appshare_cleanup(0);
 
1609
        }
 
1610
        if (last_event_type != PropertyNotify) {
 
1611
                if (appshare_debug) {fprintf(stderr, "update done.\n"); ff();}
 
1612
        }
 
1613
}
 
1614
 
 
1615
static void exiter(char *msg, int rc) {
 
1616
        fprintf(stderr, "%s", msg);
 
1617
        ff();
 
1618
        kill_helper_pid();
 
1619
        exit(rc);
 
1620
}
 
1621
 
 
1622
static void set_trackdir(void) {
 
1623
        char tmp[256];
 
1624
        struct stat sb;
 
1625
        if (!strcmp(trackdir, "none")) {
 
1626
                trackdir = NULL;
 
1627
                return;
 
1628
        }
 
1629
        if (!strcmp(trackdir, "unset")) {
 
1630
                int fd;
 
1631
                sprintf(tmp, "%s.XXXXXX", trackpre);
 
1632
                fd = mkstemp(tmp);
 
1633
                if (fd < 0) {
 
1634
                        strcat(tmp, ": failed to create file.\n");
 
1635
                        exiter(tmp, 1);
 
1636
                }
 
1637
                /* XXX race */
 
1638
                close(fd);
 
1639
                unlink(tmp);
 
1640
                if (mkdir(tmp, 0700) != 0) {
 
1641
                        strcat(tmp, ": failed to create dir.\n");
 
1642
                        exiter(tmp, 1);
 
1643
                }
 
1644
                trackdir = strdup(tmp);
 
1645
        }
 
1646
        if (stat(trackdir, &sb) != 0) {
 
1647
                if (mkdir(trackdir, 0700) != 0) {
 
1648
                        exiter("could not make trackdir.\n", 1);
 
1649
                }
 
1650
        } else if (! S_ISDIR(sb.st_mode)) {
 
1651
                exiter("trackdir not a directory.\n", 1);
 
1652
        }
 
1653
        tracktmp = (char *) calloc(1000 + strlen(trackdir), 1);
 
1654
}
 
1655
 
 
1656
static void process_string(char *str) {
 
1657
        FILE *f;
 
1658
        char *file;
 
1659
        if (trackdir) {
 
1660
                sprintf(tracktmp, "%s/0xprop.cmd", trackdir);
 
1661
                file = strdup(tracktmp);
 
1662
        } else {
 
1663
                char tmp[] = "/tmp/x11vnc-appshare.cmd.XXXXXX";
 
1664
                int fd = mkstemp(tmp);
 
1665
                if (fd < 0) {
 
1666
                        return;
 
1667
                }
 
1668
                file = strdup(tmp);
 
1669
                close(fd);
 
1670
        }
 
1671
        f = fopen(file, "w");
 
1672
        if (f) {
 
1673
                fprintf(f, "%s", str);
 
1674
                fclose(f);
 
1675
                process_control(file, 0);
 
1676
        }
 
1677
        unlink(file);
 
1678
        free(file);
 
1679
}
 
1680
 
 
1681
static void handle_shell(void) {
 
1682
        struct timeval tv;
 
1683
        static char lastline[1000];
 
1684
        static int first = 1;
 
1685
        fd_set rfds;
 
1686
        int fd0 = fileno(stdin);
 
1687
 
 
1688
        if (first) {
 
1689
                memset(lastline, 0, sizeof(lastline));
 
1690
                first = 0;
 
1691
        }
 
1692
 
 
1693
        FD_ZERO(&rfds);
 
1694
        FD_SET(fd0, &rfds);
 
1695
        tv.tv_sec = 0; 
 
1696
        tv.tv_usec = 0; 
 
1697
        select(fd0+1, &rfds, NULL, NULL, &tv);
 
1698
        if (FD_ISSET(fd0, &rfds)) {
 
1699
                char line[1000], line2[1010];
 
1700
                if (fgets(line, sizeof(line), stdin) != NULL) {
 
1701
                        char *str = lblanks(line);
 
1702
                        char *q = strrchr(str, '\n');
 
1703
                        if (q) *q = '\0';
 
1704
                        if (strcmp(str, "")) {
 
1705
                                if (!strcmp(str, "!!")) {
 
1706
                                        sprintf(line, "%s", lastline);
 
1707
                                        fprintf(stderr, "%s\n", line);
 
1708
                                        str = line;
 
1709
                                }
 
1710
                                if (strstr(str, "!") == str) {
 
1711
                                        system(str+1);
 
1712
                                } else if (!strcmp(str, "x11vnc") || !strcmp(str, "ps")) {
 
1713
                                        char *cmd = "ps -elf | egrep 'PID|x11vnc' | grep -v egrep";
 
1714
                                        fprintf(stderr, "%s\n", cmd);
 
1715
                                        system(cmd);
 
1716
                                } else {
 
1717
                                        sprintf(line2, "cmd=%s", str);
 
1718
                                        process_string(line2);
 
1719
                                }
 
1720
                                sprintf(lastline, "%s", str);
 
1721
                        }
 
1722
                }
 
1723
                fprintf(stderr, "\n%s", prompt); ff();
 
1724
        }
 
1725
}
 
1726
 
 
1727
static void handle_prop_cmd(void) {
 
1728
        char *value, *str, *done = "DONE";
 
1729
 
 
1730
        if (cmd_atom == None) {
 
1731
                return;
 
1732
        }
 
1733
 
 
1734
        value = get_xprop(cmd_atom_str, root);
 
1735
        if (value == NULL) {
 
1736
                return;
 
1737
        }
 
1738
 
 
1739
        str = lblanks(value);
 
1740
        if (!strcmp(str, done)) {
 
1741
                free(value);
 
1742
                return;
 
1743
        }
 
1744
        if (strstr(str, "cmd=quit") == str || strstr(str, "\ncmd=quit")) {
 
1745
                set_xprop(cmd_atom_str, root, done);
 
1746
                appshare_cleanup(0);
 
1747
        }
 
1748
 
 
1749
        process_string(str);
 
1750
 
 
1751
        free(value);
 
1752
        set_xprop(cmd_atom_str, root, done);
 
1753
}
 
1754
 
 
1755
#define PREFIX if(appshare_debug) fprintf(stderr, "  %8.2f  0x%08lx : ", dnow() - start, ev.xany.window);
 
1756
 
 
1757
static void monitor(void) {
 
1758
#if !NO_X11
 
1759
        XEvent ev;
 
1760
        double start = dnow();
 
1761
        int got_prop_cmd = 0;
 
1762
 
 
1763
        if (shell) {
 
1764
                update();
 
1765
                fprintf(stderr, "\n\n");
 
1766
                process_string("cmd=help");
 
1767
                fprintf(stderr, "\n%s", prompt); ff();
 
1768
        }
 
1769
 
 
1770
        while (1) {
 
1771
                int t;
 
1772
 
 
1773
                if (XEventsQueued(dpy, QueuedAlready) == 0) {
 
1774
                        update();
 
1775
                        if (got_prop_cmd) {
 
1776
                                handle_prop_cmd();
 
1777
                        }
 
1778
                        got_prop_cmd = 0;
 
1779
                        if (shell) {
 
1780
                                handle_shell();
 
1781
                        }
 
1782
                }
 
1783
 
 
1784
                XNextEvent(dpy, &ev);
 
1785
 
 
1786
                last_event_type = ev.type;
 
1787
 
 
1788
                switch (ev.type) {
 
1789
                case Expose:
 
1790
                        PREFIX
 
1791
                        if(appshare_debug) fprintf(stderr, "Expose %04dx%04d+%04d+%04d\n", ev.xexpose.width, ev.xexpose.height, ev.xexpose.x, ev.xexpose.y);
 
1792
                        break;
 
1793
                case ConfigureNotify:
 
1794
#if 0
 
1795
                        PREFIX
 
1796
                        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);
 
1797
#endif
 
1798
                        break;
 
1799
                case VisibilityNotify:
 
1800
                        PREFIX
 
1801
                        if (appshare_debug) {
 
1802
                        fprintf(stderr, "VisibilityNotify: ");
 
1803
                        t = ev.xvisibility.state;
 
1804
                        if (t == VisibilityFullyObscured)     fprintf(stderr, "VisibilityFullyObscured\n");
 
1805
                        if (t == VisibilityPartiallyObscured) fprintf(stderr, "VisibilityPartiallyObscured\n");
 
1806
                        if (t == VisibilityUnobscured)        fprintf(stderr, "VisibilityUnobscured\n");
 
1807
                        }
 
1808
                        break;
 
1809
                case MapNotify:
 
1810
                        PREFIX
 
1811
                        if(appshare_debug) fprintf(stderr, "MapNotify      win: 0x%lx\n", ev.xmap.window);
 
1812
                        if (ours(ev.xmap.window)) {
 
1813
                                mapped(ev.xmap.window);
 
1814
                        }
 
1815
                        break;
 
1816
                case UnmapNotify:
 
1817
                        PREFIX
 
1818
                        if(appshare_debug) fprintf(stderr, "UnmapNotify    win: 0x%lx\n", ev.xmap.window);
 
1819
                        if (ours(ev.xmap.window)) {
 
1820
                                unmapped(ev.xmap.window);
 
1821
                        }
 
1822
                        break;
 
1823
                case MapRequest:
 
1824
                        PREFIX
 
1825
                        if(appshare_debug) fprintf(stderr, "MapRequest\n");
 
1826
                        break;
 
1827
                case CreateNotify:
 
1828
                        PREFIX
 
1829
                        if(appshare_debug) fprintf(stderr, "CreateNotify parent: 0x%lx  win: 0x%lx\n", ev.xcreatewindow.parent, ev.xcreatewindow.window);
 
1830
                        if (ev.xcreatewindow.parent == root && ours(ev.xcreatewindow.window)) {
 
1831
                                if (find_win(ev.xcreatewindow.window) >= 0) {
 
1832
                                        destroy_win(ev.xcreatewindow.window);
 
1833
                                }
 
1834
                                add_win(ev.xcreatewindow.window);
 
1835
                        }
 
1836
                        break;
 
1837
                case DestroyNotify:
 
1838
                        PREFIX
 
1839
                        if(appshare_debug) fprintf(stderr, "DestroyNotify  win: 0x%lx\n", ev.xdestroywindow.window);
 
1840
                        if (ours(ev.xdestroywindow.window)) {
 
1841
                                destroy_win(ev.xdestroywindow.window);
 
1842
                        }
 
1843
                        break;
 
1844
                case ConfigureRequest:
 
1845
                        PREFIX
 
1846
                        if(appshare_debug) fprintf(stderr, "ConfigureRequest\n");
 
1847
                        break;
 
1848
                case CirculateRequest:
 
1849
#if 0
 
1850
                        PREFIX
 
1851
                        if(appshare_debug) fprintf(stderr, "CirculateRequest parent: 0x%lx  win: 0x%lx\n", ev.xcirculaterequest.parent, ev.xcirculaterequest.window);
 
1852
#endif
 
1853
                        break;
 
1854
                case CirculateNotify:
 
1855
#if 0
 
1856
                        PREFIX
 
1857
                        if(appshare_debug) fprintf(stderr, "CirculateNotify\n");
 
1858
#endif
 
1859
                        break;
 
1860
                case PropertyNotify:
 
1861
#if 0
 
1862
                        PREFIX
 
1863
                        if(appshare_debug) fprintf(stderr, "PropertyNotify\n");
 
1864
#endif
 
1865
                        if (cmd_atom != None && ev.xproperty.atom == cmd_atom) {
 
1866
                                got_prop_cmd++;
 
1867
                        }
 
1868
                        break;
 
1869
                case ReparentNotify:
 
1870
                        PREFIX
 
1871
                        if(appshare_debug) fprintf(stderr, "ReparentNotify parent: 0x%lx  win: 0x%lx\n", ev.xreparent.parent, ev.xreparent.window);
 
1872
                        if (ours(ev.xreparent.window)) {
 
1873
                                if (ours(ev.xreparent.parent)) {
 
1874
                                        destroy_win(ev.xreparent.window);
 
1875
                                } else if (ev.xreparent.parent == root) {
 
1876
                                        /* ??? */
 
1877
                                }
 
1878
                        }
 
1879
                        break;
 
1880
                default:
 
1881
                        PREFIX
 
1882
                        if(appshare_debug) fprintf(stderr, "Unknown: %d\n", ev.type);
 
1883
                        break;
 
1884
                }
 
1885
        }
 
1886
#endif
 
1887
}
 
1888
 
 
1889
int appshare_main(int argc, char *argv[]) {
 
1890
        int i;
 
1891
        char *app_str = NULL;
 
1892
        char *dpy_str = NULL;
 
1893
        long xselectinput = 0;
 
1894
#if NO_X11
 
1895
        exiter("not compiled with X11\n", 1);
 
1896
#else
 
1897
        for (i=0; i < WMAX; i++) {
 
1898
                watch[i] = None;
 
1899
                state[i] = 0;
 
1900
        }
 
1901
        for (i=0; i < AMAX; i++) {
 
1902
                apps[i]  = None;
 
1903
        }
 
1904
        for (i=0; i < CMAX; i++) {
 
1905
                clients[i] = NULL;
 
1906
        }
 
1907
 
 
1908
        x11vnc = strdup(argv[0]);
 
1909
 
 
1910
        for (i=1; i < argc; i++) {
 
1911
                int end = (i == argc-1) ? 1 : 0;
 
1912
                char *s = argv[i];
 
1913
                if (strstr(s, "--") == s) {
 
1914
                        s++;
 
1915
                }
 
1916
 
 
1917
                if (!strcmp(s, "-h") || !strcmp(s, "-help")) {
 
1918
                        fprintf(stdout, "%s", usage);
 
1919
                        exit(0);
 
1920
                } else if (!strcmp(s, "-id")) {
 
1921
                        id_opt = "-id";
 
1922
                        if (end) exiter("no -id value supplied\n", 1);
 
1923
                        app_str = strdup(argv[++i]);
 
1924
                } else if (!strcmp(s, "-sid")) {
 
1925
                        id_opt = "-sid";
 
1926
                        if (end) exiter("no -sid value supplied\n", 1);
 
1927
                        app_str = strdup(argv[++i]);
 
1928
                } else if (!strcmp(s, "-connect") || !strcmp(s, "-connect_or_exit") || !strcmp(s, "-coe")) {
 
1929
                        if (end) exiter("no -connect value supplied\n", 1);
 
1930
                        connect_to = strdup(argv[++i]);
 
1931
                } else if (!strcmp(s, "-control")) {
 
1932
                        if (end) exiter("no -control value supplied\n", 1);
 
1933
                        control = strdup(argv[++i]);
 
1934
                        if (!strcmp(control, "shell")) {
 
1935
                                free(control);
 
1936
                                control = strdup("internal");
 
1937
                                shell = 1;
 
1938
                        }
 
1939
                } else if (!strcmp(s, "-trackdir")) {
 
1940
                        if (end) exiter("no -trackdir value supplied\n", 1);
 
1941
                        trackdir = strdup(argv[++i]);
 
1942
                } else if (!strcmp(s, "-display")) {
 
1943
                        if (end) exiter("no -display value supplied\n", 1);
 
1944
                        dpy_str = strdup(argv[++i]);
 
1945
                        set_env("DISPLAY", dpy_str);
 
1946
                } else if (!strcmp(s, "-delay")) {
 
1947
                        if (end) exiter("no -delay value supplied\n", 1);
 
1948
                        helper_delay = atof(argv[++i]);
 
1949
                } else if (!strcmp(s, "-args")) {
 
1950
                        if (end) exiter("no -args value supplied\n", 1);
 
1951
                        x11vnc_args = strdup(argv[++i]);
 
1952
                } else if (!strcmp(s, "-env")) {
 
1953
                        if (end) exiter("no -env value supplied\n", 1);
 
1954
                        putenv(argv[++i]);
 
1955
                } else if (!strcmp(s, "-debug")) {
 
1956
                        appshare_debug++;
 
1957
                } else if (!strcmp(s, "-showmenus")) {
 
1958
                        skip_menus = 0;
 
1959
                } else if (!strcmp(s, "-noexit")) {
 
1960
                        exit_no_app_win = 0;
 
1961
                } else if (!strcmp(s, "-shell")) {
 
1962
                        shell = 1;
 
1963
                } else if (!strcmp(s, "-nocmds") || !strcmp(s, "-safer")) {
 
1964
                        fprintf(stderr, "ignoring %s in -appshare mode.\n", s);
 
1965
                } else if (!strcmp(s, "-appshare")) {
 
1966
                        ;
 
1967
                } else {
 
1968
                        fprintf(stderr, "unrecognized 'x11vnc -appshare' option: %s\n", s);
 
1969
                        exiter("", 1);
 
1970
                }
 
1971
        }
 
1972
 
 
1973
        if (getenv("X11VNC_APPSHARE_DEBUG")) {
 
1974
                appshare_debug = atoi(getenv("X11VNC_APPSHARE_DEBUG"));
 
1975
        }
 
1976
 
 
1977
        /* let user override name for multiple instances: */
 
1978
        if (getenv("X11VNC_APPSHARE_COMMAND_PROPNAME")) {
 
1979
                cmd_atom_str = strdup(getenv("X11VNC_APPSHARE_COMMAND_PROPNAME"));
 
1980
        }
 
1981
        if (getenv("X11VNC_APPSHARE_TICKER_PROPNAME")) {
 
1982
                ticker_atom_str = strdup(getenv("X11VNC_APPSHARE_TICKER_PROPNAME"));
 
1983
        }
 
1984
 
 
1985
        if (shell) {
 
1986
                if (!control || strcmp(control, "internal")) {
 
1987
                        exiter("mode -shell requires '-control internal'\n", 1);
 
1988
                }
 
1989
        }
 
1990
 
 
1991
        if (connect_to == NULL && control != NULL) {
 
1992
                struct stat sb;
 
1993
                if (stat(control, &sb) == 0) {
 
1994
                        int len = 100 + sb.st_size;
 
1995
                        FILE *f = fopen(control, "r");
 
1996
 
 
1997
                        if (f) {
 
1998
                                char *line = (char *) malloc(len);
 
1999
                                connect_to = (char *) calloc(2 * len, 1);
 
2000
                                while (fgets(line, len, f) != NULL) {
 
2001
                                        char *q = strchr(line, '\n');
 
2002
                                        if (q) *q = '\0';
 
2003
                                        q = lblanks(line);
 
2004
                                        if (q[0] == '#') {
 
2005
                                                continue;
 
2006
                                        }
 
2007
                                        if (connect_to[0] != '\0') {
 
2008
                                                strcat(connect_to, ",");
 
2009
                                        }
 
2010
                                        strcat(connect_to, q);
 
2011
                                }
 
2012
                                fclose(f);
 
2013
                        }
 
2014
                        fprintf(stderr, "set -connect to: %s\n", connect_to);
 
2015
                }
 
2016
        }
 
2017
        if (0 && connect_to == NULL && control == NULL) {
 
2018
                exiter("no -connect host or -control file specified.\n", 1);
 
2019
        }
 
2020
 
 
2021
        if (control) {
 
2022
                pid_t pid;
 
2023
                parent_pid = getpid();
 
2024
                pid = fork();
 
2025
                if (pid == (pid_t) -1) {
 
2026
                        ;
 
2027
                } else if (pid == 0) {
 
2028
                        be_helper_pid(dpy_str);
 
2029
                        exit(0);
 
2030
                } else {
 
2031
                        helper_pid = pid;
 
2032
                }
 
2033
        }
 
2034
 
 
2035
        dpy = XOpenDisplay(dpy_str);
 
2036
        if (!dpy) {
 
2037
                exiter("cannot open display\n", 1);
 
2038
        }
 
2039
 
 
2040
        root = DefaultRootWindow(dpy);
 
2041
 
 
2042
        xselectinput = SubstructureNotifyMask;
 
2043
        if (helper_pid > 0) {
 
2044
                ticker_atom = XInternAtom(dpy, ticker_atom_str, False);
 
2045
                xselectinput |= PropertyChangeMask;
 
2046
        }
 
2047
        XSelectInput(dpy, root, xselectinput);
 
2048
 
 
2049
        cmd_atom = XInternAtom(dpy, cmd_atom_str, False);
 
2050
 
 
2051
        init_cmask();
 
2052
 
 
2053
        sprintf(unique_tag, "X11VNC_APPSHARE_TAG=%d-tag", getpid());
 
2054
 
 
2055
        start_time = dnow();
 
2056
 
 
2057
        if (app_str == NULL) {
 
2058
                exiter("no -id/-sid window specified.\n", 1);
 
2059
        } else {
 
2060
                char *p, *str = strdup(app_str);
 
2061
                char *alist[AMAX];
 
2062
                int i, n = 0;
 
2063
 
 
2064
                p = strtok(str, ",");
 
2065
                while (p) {
 
2066
                        if (n >= AMAX) {
 
2067
                                fprintf(stderr, "ran out of app slots: %s\n", app_str);
 
2068
                                exiter("", 1);
 
2069
                        }
 
2070
                        alist[n++] = strdup(p);
 
2071
                        p = strtok(NULL, ",");
 
2072
                }
 
2073
                free(str);
 
2074
 
 
2075
                for (i=0; i < n; i++) {
 
2076
                        Window app = None;
 
2077
                        p = alist[i];
 
2078
                        app = parse_win(p);
 
2079
                        free(p);
 
2080
 
 
2081
                        if (app != None) {
 
2082
                                if (!ours(app)) {
 
2083
                                        add_app(app);
 
2084
                                }
 
2085
                        }
 
2086
                }
 
2087
        }
 
2088
 
 
2089
        set_trackdir();
 
2090
 
 
2091
        signal(SIGINT,  appshare_cleanup);
 
2092
        signal(SIGTERM, appshare_cleanup);
 
2093
 
 
2094
        rfbLogEnable(0);
 
2095
 
 
2096
        if (connect_to) {
 
2097
                char *p, *str = strdup(connect_to);
 
2098
                int n = 0;
 
2099
                p = strtok(str, ",");
 
2100
                while (p) {
 
2101
                        clients[n++] = strdup(p);
 
2102
                        p = strtok(NULL, ",");
 
2103
                }
 
2104
                free(str);
 
2105
        } else {
 
2106
                connect_to = strdup("");
 
2107
        }
 
2108
 
 
2109
        for (i=0; i < AMAX; i++) {
 
2110
                if (apps[i] == None) {
 
2111
                        continue;
 
2112
                }
 
2113
                fprintf(stdout, "Using app win: 0x%08lx  root: 0x%08lx\n", apps[i], root);
 
2114
        }
 
2115
        fprintf(stdout, "\n");
 
2116
 
 
2117
        monitor();
 
2118
 
 
2119
        appshare_cleanup(0);
 
2120
 
 
2121
#endif
 
2122
        return 0;
 
2123
}
 
2124