~ubuntu-branches/debian/lenny/italc/lenny

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Patrick Winnertz
  • Date: 2008-06-17 13:46:54 UTC
  • mto: This revision was merged to the branch mainline in revision 5.
  • Revision ID: james.westby@ubuntu.com-20080617134654-2y5m7ki93r5c1ysf
Tags: upstream-1.0.9~rc3
ImportĀ upstreamĀ versionĀ 1.0.9~rc3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -- xrecord.c -- */
 
2
 
 
3
#include "x11vnc.h"
 
4
#include "xwrappers.h"
 
5
#include "win_utils.h"
 
6
#include "cleanup.h"
 
7
#include "userinput.h"
 
8
#include "winattr_t.h"
 
9
#include "scrollevent_t.h"
 
10
#include "unixpw.h"
 
11
 
 
12
#define SCR_EV_MAX 128
 
13
scroll_event_t scr_ev[SCR_EV_MAX];
 
14
int scr_ev_cnt;
 
15
 
 
16
int xrecording = 0;
 
17
int xrecord_set_by_keys = 0;
 
18
int xrecord_set_by_mouse = 0;
 
19
Window xrecord_focus_window = None;
 
20
Window xrecord_wm_window = None;
 
21
Window xrecord_ptr_window = None;
 
22
KeySym xrecord_keysym = NoSymbol;
 
23
 
 
24
#define NAMEINFO 2048
 
25
char xrecord_name_info[NAMEINFO];
 
26
 
 
27
#define SCR_ATTR_CACHE 8
 
28
winattr_t scr_attr_cache[SCR_ATTR_CACHE];
 
29
static double attr_cache_max_age = 1.5;
 
30
 
 
31
Display *rdpy_data = NULL;              /* Data connection for RECORD */
 
32
Display *rdpy_ctrl = NULL;              /* Control connection for RECORD */
 
33
 
 
34
Display *gdpy_ctrl = NULL;
 
35
int xserver_grabbed = 0;
 
36
 
 
37
int trap_record_xerror(Display *, XErrorEvent *);
 
38
 
 
39
void initialize_xrecord(void);
 
40
void shutdown_xrecord(void);
 
41
int xrecord_skip_keysym(rfbKeySym keysym);
 
42
int xrecord_skip_button(int new, int old);
 
43
int xrecord_scroll_keysym(rfbKeySym keysym);
 
44
void check_xrecord_reset(int force);
 
45
void xrecord_watch(int start, int setby);
 
46
 
 
47
 
 
48
#if LIBVNCSERVER_HAVE_RECORD
 
49
static XRecordRange *rr_CA = NULL;
 
50
static XRecordRange *rr_CW = NULL;
 
51
static XRecordRange *rr_GS = NULL;
 
52
static XRecordRange *rr_scroll[10];
 
53
static XRecordContext rc_scroll;
 
54
static XRecordClientSpec rcs_scroll;
 
55
static XRecordRange *rr_grab[10];
 
56
static XRecordContext rc_grab;
 
57
static XRecordClientSpec rcs_grab;
 
58
#endif
 
59
static XErrorEvent *trapped_record_xerror_event;
 
60
static Display *gdpy_data = NULL;
 
61
 
 
62
static void xrecord_grabserver(int start);
 
63
static int xrecord_vi_scroll_keysym(rfbKeySym keysym);
 
64
static int xrecord_emacs_scroll_keysym(rfbKeySym keysym);
 
65
static int lookup_attr_cache(Window win, int *cache_index, int *next_index);
 
66
#if LIBVNCSERVER_HAVE_RECORD
 
67
static void record_CA(XPointer ptr, XRecordInterceptData *rec_data);
 
68
static void record_CW(XPointer ptr, XRecordInterceptData *rec_data);
 
69
static void record_switch(XPointer ptr, XRecordInterceptData *rec_data);
 
70
static void record_grab(XPointer ptr, XRecordInterceptData *rec_data);
 
71
static void shutdown_record_context(XRecordContext rc, int bequiet, int reopen);
 
72
#endif
 
73
static void check_xrecord_grabserver(void);
 
74
 
 
75
 
 
76
int trap_record_xerror(Display *d, XErrorEvent *error) {
 
77
        trapped_record_xerror = 1;
 
78
        trapped_record_xerror_event = error;
 
79
 
 
80
        if (d) {} /* unused vars warning: */
 
81
 
 
82
        return 0;
 
83
}
 
84
 
 
85
static void xrecord_grabserver(int start) {
 
86
        XErrorHandler old_handler = NULL;
 
87
        int rc = 0;
 
88
 
 
89
        if (debug_grabs) {
 
90
                fprintf(stderr, "xrecord_grabserver%d/%d %.5f\n",
 
91
                        xserver_grabbed, start, dnowx());
 
92
        }
 
93
 
 
94
        if (! gdpy_ctrl || ! gdpy_data) {
 
95
                return;
 
96
        }
 
97
#if LIBVNCSERVER_HAVE_RECORD
 
98
        if (!start) {
 
99
                if (! rc_grab) {
 
100
                        return;
 
101
                }
 
102
                XRecordDisableContext(gdpy_ctrl, rc_grab);
 
103
                XRecordFreeContext(gdpy_ctrl, rc_grab);
 
104
                XFlush_wr(gdpy_ctrl);
 
105
                rc_grab = 0;
 
106
                return;
 
107
        }
 
108
 
 
109
        xserver_grabbed = 0;
 
110
 
 
111
        rr_grab[0] = rr_GS;
 
112
        rcs_grab = XRecordAllClients;
 
113
 
 
114
        rc_grab = XRecordCreateContext(gdpy_ctrl, 0, &rcs_grab, 1, rr_grab, 1);
 
115
        trapped_record_xerror = 0;
 
116
        old_handler = XSetErrorHandler(trap_record_xerror);
 
117
 
 
118
        XSync(gdpy_ctrl, True);
 
119
 
 
120
        if (! rc_grab || trapped_record_xerror) {
 
121
                XCloseDisplay_wr(gdpy_ctrl);
 
122
                XCloseDisplay_wr(gdpy_data);
 
123
                gdpy_ctrl = NULL;
 
124
                gdpy_data = NULL;
 
125
                XSetErrorHandler(old_handler);
 
126
                return;
 
127
        }
 
128
        rc = XRecordEnableContextAsync(gdpy_data, rc_grab, record_grab, NULL);
 
129
        if (!rc || trapped_record_xerror) {
 
130
                XCloseDisplay_wr(gdpy_ctrl);
 
131
                XCloseDisplay_wr(gdpy_data);
 
132
                gdpy_ctrl = NULL;
 
133
                gdpy_data = NULL;
 
134
                XSetErrorHandler(old_handler);
 
135
                return;
 
136
        }
 
137
        XSetErrorHandler(old_handler);
 
138
        XFlush_wr(gdpy_data);
 
139
#else
 
140
        if (!rc || !old_handler) {}
 
141
#endif
 
142
        if (debug_grabs) {
 
143
                fprintf(stderr, "xrecord_grabserver-done: %.5f\n", dnowx());
 
144
        }
 
145
}
 
146
 
 
147
void initialize_xrecord(void) {
 
148
        use_xrecord = 0;
 
149
        if (! xrecord_present) {
 
150
                return;
 
151
        }
 
152
        if (nofb) {
 
153
                return;
 
154
        }
 
155
        if (noxrecord) {
 
156
                return;
 
157
        }
 
158
        RAWFB_RET_VOID
 
159
#if LIBVNCSERVER_HAVE_RECORD
 
160
 
 
161
        if (rr_CA) XFree_wr(rr_CA);
 
162
        if (rr_CW) XFree_wr(rr_CW);
 
163
        if (rr_GS) XFree_wr(rr_GS);
 
164
 
 
165
        rr_CA = XRecordAllocRange();
 
166
        rr_CW = XRecordAllocRange();
 
167
        rr_GS = XRecordAllocRange();
 
168
        if (!rr_CA || !rr_CW || !rr_GS) {
 
169
                return;
 
170
        }
 
171
        /* protocol request ranges: */
 
172
        rr_CA->core_requests.first = X_CopyArea;
 
173
        rr_CA->core_requests.last  = X_CopyArea;
 
174
        
 
175
        rr_CW->core_requests.first = X_ConfigureWindow;
 
176
        rr_CW->core_requests.last  = X_ConfigureWindow;
 
177
 
 
178
        rr_GS->core_requests.first = X_GrabServer;
 
179
        rr_GS->core_requests.last  = X_UngrabServer;
 
180
 
 
181
        X_LOCK;
 
182
        /* open a 2nd control connection to DISPLAY: */
 
183
        if (rdpy_data) {
 
184
                XCloseDisplay_wr(rdpy_data);
 
185
                rdpy_data = NULL;
 
186
        }
 
187
        if (rdpy_ctrl) {
 
188
                XCloseDisplay_wr(rdpy_ctrl);
 
189
                rdpy_ctrl = NULL;
 
190
        }
 
191
        rdpy_ctrl = XOpenDisplay_wr(DisplayString(dpy));
 
192
        if (!rdpy_ctrl) {
 
193
                fprintf(stderr, "rdpy_ctrl open failed: %s / %s / %s / %s\n", getenv("DISPLAY"), DisplayString(dpy), getenv("XAUTHORITY"), getenv("XAUTHORIT_"));
 
194
        }
 
195
        XSync(dpy, True);
 
196
        XSync(rdpy_ctrl, True);
 
197
        /* open datalink connection to DISPLAY: */
 
198
        rdpy_data = XOpenDisplay_wr(DisplayString(dpy));
 
199
        if (!rdpy_data) {
 
200
                fprintf(stderr, "rdpy_data open failed\n");
 
201
        }
 
202
        if (!rdpy_ctrl || ! rdpy_data) {
 
203
                X_UNLOCK;
 
204
                return;
 
205
        }
 
206
        disable_grabserver(rdpy_ctrl, 0);
 
207
        disable_grabserver(rdpy_data, 0);
 
208
 
 
209
        use_xrecord = 1;
 
210
 
 
211
        /*
 
212
         * now set up the GrabServer watcher.  We get GrabServer
 
213
         * deadlock in XRecordCreateContext() even with XTestGrabServer
 
214
         * in place, why?  Not sure, so we manually watch for grabs...
 
215
         */
 
216
        if (gdpy_data) {
 
217
                XCloseDisplay_wr(gdpy_data);
 
218
                gdpy_data = NULL;
 
219
        }
 
220
        if (gdpy_ctrl) {
 
221
                XCloseDisplay_wr(gdpy_ctrl);
 
222
                gdpy_ctrl = NULL;
 
223
        }
 
224
        xserver_grabbed = 0;
 
225
 
 
226
        gdpy_ctrl = XOpenDisplay_wr(DisplayString(dpy));
 
227
        if (!gdpy_ctrl) {
 
228
                fprintf(stderr, "gdpy_ctrl open failed\n");
 
229
        }
 
230
        XSync(dpy, True);
 
231
        XSync(gdpy_ctrl, True);
 
232
        gdpy_data = XOpenDisplay_wr(DisplayString(dpy));
 
233
        if (!gdpy_data) {
 
234
                fprintf(stderr, "gdpy_data open failed\n");
 
235
        }
 
236
        if (gdpy_ctrl && gdpy_data) {
 
237
                disable_grabserver(gdpy_ctrl, 0);
 
238
                disable_grabserver(gdpy_data, 0);
 
239
                xrecord_grabserver(1);
 
240
        }
 
241
        X_UNLOCK;
 
242
#endif
 
243
}
 
244
 
 
245
void shutdown_xrecord(void) {
 
246
#if LIBVNCSERVER_HAVE_RECORD
 
247
 
 
248
        if (debug_grabs) {
 
249
                fprintf(stderr, "shutdown_xrecord%d %.5f\n",
 
250
                        xserver_grabbed, dnowx());
 
251
        }
 
252
 
 
253
        if (rr_CA) XFree_wr(rr_CA);
 
254
        if (rr_CW) XFree_wr(rr_CW);
 
255
        if (rr_GS) XFree_wr(rr_GS);
 
256
 
 
257
        rr_CA = NULL;
 
258
        rr_CW = NULL;
 
259
        rr_GS = NULL;
 
260
 
 
261
        X_LOCK;
 
262
        if (rdpy_ctrl && rc_scroll) {
 
263
                XRecordDisableContext(rdpy_ctrl, rc_scroll);
 
264
                XRecordFreeContext(rdpy_ctrl, rc_scroll);
 
265
                XSync(rdpy_ctrl, False);
 
266
                rc_scroll = 0;
 
267
        }
 
268
                
 
269
        if (gdpy_ctrl && rc_grab) {
 
270
                XRecordDisableContext(gdpy_ctrl, rc_grab);
 
271
                XRecordFreeContext(gdpy_ctrl, rc_grab);
 
272
                XSync(gdpy_ctrl, False);
 
273
                rc_grab = 0;
 
274
        }
 
275
                
 
276
        if (rdpy_data) {
 
277
                XCloseDisplay_wr(rdpy_data);
 
278
                rdpy_data = NULL;
 
279
        }
 
280
        if (rdpy_ctrl) {
 
281
                XCloseDisplay_wr(rdpy_ctrl);
 
282
                rdpy_ctrl = NULL;
 
283
        }
 
284
        if (gdpy_data) {
 
285
                XCloseDisplay_wr(gdpy_data);
 
286
                gdpy_data = NULL;
 
287
        }
 
288
        if (gdpy_ctrl) {
 
289
                XCloseDisplay_wr(gdpy_ctrl);
 
290
                gdpy_ctrl = NULL;
 
291
        }
 
292
        xserver_grabbed = 0;
 
293
        X_UNLOCK;
 
294
#endif
 
295
        use_xrecord = 0;
 
296
 
 
297
        if (debug_grabs) {
 
298
                fprintf(stderr, "shutdown_xrecord-done: %.5f\n", dnowx());
 
299
        }
 
300
}
 
301
 
 
302
int xrecord_skip_keysym(rfbKeySym keysym) {
 
303
        KeySym sym = (KeySym) keysym;
 
304
        int ok = -1, matched = 0;
 
305
 
 
306
        if (scroll_key_list) {
 
307
                int k, exclude = 0;
 
308
                if (scroll_key_list[0]) {
 
309
                        exclude = 1;
 
310
                }
 
311
                k = 1;
 
312
                while (scroll_key_list[k] != NoSymbol) {
 
313
                        if (scroll_key_list[k++] == sym) {
 
314
                                matched = 1;
 
315
                                break;
 
316
                        }
 
317
                }
 
318
                if (exclude) {
 
319
                        if (matched) {
 
320
                                return 1;
 
321
                        } else {
 
322
                                ok = 1;
 
323
                        }
 
324
                } else {
 
325
                        if (matched) {
 
326
                                ok = 1;
 
327
                        } else {
 
328
                                ok = 0;
 
329
                        }
 
330
                }
 
331
        }
 
332
        if (ok == 1) {
 
333
                return 0;
 
334
        } else if (ok == 0) {
 
335
                return 1;
 
336
        }
 
337
 
 
338
        /* apply various heuristics: */
 
339
 
 
340
        if (IsModifierKey(sym)) {
 
341
                /* Shift, Control, etc, usu. generate no scrolls */
 
342
                return 1;
 
343
        }
 
344
        if (sym == XK_space && scroll_term) {
 
345
                /* space in a terminal is usu. full page... */
 
346
                Window win;
 
347
                static Window prev_top = None;
 
348
                int size = 256;
 
349
                static char name[256];
 
350
 
 
351
                X_LOCK;
 
352
                win = query_pointer(rootwin);
 
353
                X_UNLOCK;
 
354
                if (win != None && win != rootwin) {
 
355
                        if (prev_top != None && win == prev_top) {
 
356
                                ;       /* use cached result */
 
357
                        } else {
 
358
                                prev_top = win;
 
359
                                X_LOCK;
 
360
                                win = descend_pointer(6, win, name, size);
 
361
                                X_UNLOCK;
 
362
                        }
 
363
                        if (match_str_list(name, scroll_term)) {
 
364
                                return 1;
 
365
                        }
 
366
                }
 
367
        }
 
368
 
 
369
        /* TBD use typing_rate() so */
 
370
        return 0;
 
371
}
 
372
 
 
373
int xrecord_skip_button(int new, int old) {
 
374
        /* unused vars warning: */
 
375
        if (new || old) {} 
 
376
 
 
377
        return 0;
 
378
}
 
379
 
 
380
static int xrecord_vi_scroll_keysym(rfbKeySym keysym) {
 
381
        KeySym sym = (KeySym) keysym;
 
382
        if (sym == XK_J || sym == XK_j || sym == XK_K || sym == XK_k) {
 
383
                return 1;       /* vi */
 
384
        }
 
385
        if (sym == XK_D || sym == XK_d || sym == XK_U || sym == XK_u) {
 
386
                return 1;       /* Ctrl-d/u */
 
387
        }
 
388
        if (sym == XK_Z || sym == XK_z) {
 
389
                return 1;       /* zz, zt, zb .. */
 
390
        }
 
391
        return 0;
 
392
}
 
393
 
 
394
static int xrecord_emacs_scroll_keysym(rfbKeySym keysym) {
 
395
        KeySym sym = (KeySym) keysym;
 
396
        if (sym == XK_N || sym == XK_n || sym == XK_P || sym == XK_p) {
 
397
                return 1;       /* emacs */
 
398
        }
 
399
        /* Must be some more ... */
 
400
        return 0;
 
401
}
 
402
 
 
403
int xrecord_scroll_keysym(rfbKeySym keysym) {
 
404
        KeySym sym = (KeySym) keysym;
 
405
        /* X11/keysymdef.h */
 
406
 
 
407
        if (sym == XK_Return || sym == XK_KP_Enter || sym == XK_Linefeed) {
 
408
                return 1;       /* Enter */
 
409
        }
 
410
        if (sym==XK_Up || sym==XK_KP_Up || sym==XK_Down || sym==XK_KP_Down) {
 
411
                return 1;       /* U/D arrows */
 
412
        }
 
413
        if (sym == XK_Left || sym == XK_KP_Left || sym == XK_Right ||
 
414
            sym == XK_KP_Right) {
 
415
                return 1;       /* L/R arrows */
 
416
        }
 
417
        if (xrecord_vi_scroll_keysym(keysym)) {
 
418
                return 1;
 
419
        }
 
420
        if (xrecord_emacs_scroll_keysym(keysym)) {
 
421
                return 1;
 
422
        }
 
423
        return 0;
 
424
}
 
425
 
 
426
static int lookup_attr_cache(Window win, int *cache_index, int *next_index) {
 
427
        double now, t, oldest = 0.0;
 
428
        int i, old_index = -1, count = 0;
 
429
        Window cwin;
 
430
 
 
431
        *cache_index = -1;
 
432
        *next_index  = -1;
 
433
        
 
434
        if (win == None) {
 
435
                return 0;
 
436
        }
 
437
        if (attr_cache_max_age == 0.0) {
 
438
                return 0;
 
439
        }
 
440
 
 
441
        dtime0(&now);
 
442
        for (i=0; i < SCR_ATTR_CACHE; i++) {
 
443
 
 
444
                cwin = scr_attr_cache[i].win;
 
445
                t = scr_attr_cache[i].time;
 
446
 
 
447
                if (now > t + attr_cache_max_age) {
 
448
                        /* expire it even if it is the one we want */
 
449
                        scr_attr_cache[i].win = cwin = None;
 
450
                        scr_attr_cache[i].fetched = 0;
 
451
                        scr_attr_cache[i].valid = 0;
 
452
                }
 
453
 
 
454
                if (*next_index == -1 && cwin == None) {
 
455
                        *next_index = i;
 
456
                }
 
457
                if (*next_index == -1) {
 
458
                        /* record oldest */
 
459
                        if (old_index == -1 || t < oldest) {
 
460
                                oldest = t;
 
461
                                old_index = i;
 
462
                        }
 
463
                }
 
464
                if (cwin != None) {
 
465
                        count++;
 
466
                }
 
467
                if (cwin == win) {
 
468
                        if (*cache_index == -1) {
 
469
                                *cache_index = i;
 
470
                        } else {
 
471
                                /* remove dups */
 
472
                                scr_attr_cache[i].win = None;
 
473
                                scr_attr_cache[i].fetched = 0;
 
474
                                scr_attr_cache[i].valid = 0;
 
475
                        }
 
476
                }
 
477
        }
 
478
        if (*next_index == -1) {
 
479
                *next_index = old_index;
 
480
        }
 
481
 
 
482
if (0) fprintf(stderr, "lookup_attr_cache count: %d\n", count);
 
483
        if (*cache_index != -1) {
 
484
                return 1;
 
485
        } else {
 
486
                return 0;
 
487
        }
 
488
}
 
489
 
 
490
 
 
491
static XID xrecord_seq = 0;
 
492
static double xrecord_start = 0.0;
 
493
 
 
494
#if LIBVNCSERVER_HAVE_RECORD
 
495
static void record_CA(XPointer ptr, XRecordInterceptData *rec_data) {
 
496
        xCopyAreaReq *req;
 
497
        Window src = None, dst = None, c;
 
498
        XWindowAttributes attr;
 
499
        int src_x, src_y, dst_x, dst_y, rx, ry;
 
500
        int good = 1, dx, dy, k=0, i;
 
501
        unsigned int w, h;
 
502
        int dba = 0, db = debug_scroll;
 
503
        int cache_index, next_index, valid;
 
504
 
 
505
        if (dba || db) {
 
506
                if (rec_data->category == XRecordFromClient) {
 
507
                        req = (xCopyAreaReq *) rec_data->data;
 
508
                        if (req->reqType == X_CopyArea) {
 
509
                                src = req->srcDrawable;
 
510
                                dst = req->dstDrawable;
 
511
                        }
 
512
                }
 
513
        }
 
514
 
 
515
if (dba || db > 1) fprintf(stderr, "record_CA-%d id_base: 0x%lx  ptr: 0x%lx "
 
516
        "seq: 0x%lx rc: 0x%lx  cat: %d  swapped: %d 0x%lx/0x%lx\n", k++,
 
517
        rec_data->id_base, (unsigned long) ptr, xrecord_seq, rc_scroll,
 
518
        rec_data->category, rec_data->client_swapped, src, dst);
 
519
 
 
520
        if (! xrecording) {
 
521
                return;
 
522
        }
 
523
if (db > 1) fprintf(stderr, "record_CA-%d\n", k++);
 
524
 
 
525
        if (rec_data->id_base == 0) {
 
526
                return;
 
527
        }
 
528
if (db > 1) fprintf(stderr, "record_CA-%d\n", k++);
 
529
 
 
530
        if ((XID) ptr != xrecord_seq) {
 
531
                return;
 
532
        }
 
533
if (db > 1) fprintf(stderr, "record_CA-%d\n", k++);
 
534
 
 
535
        if (rec_data->category != XRecordFromClient) {
 
536
                return;
 
537
        }
 
538
if (db > 1) fprintf(stderr, "record_CA-%d\n", k++);
 
539
 
 
540
        req = (xCopyAreaReq *) rec_data->data;
 
541
 
 
542
        if (req->reqType != X_CopyArea) {
 
543
                return;
 
544
        }
 
545
if (db > 1) fprintf(stderr, "record_CA-%d\n", k++);
 
546
 
 
547
/*
 
548
 
 
549
xterm, gnome-terminal, others.
 
550
 
 
551
Note we miss the X_ImageText8 that clears the block cursor.  So there is a
 
552
short period of time with a painting error: two cursors, one above the other.
 
553
 
 
554
 X_ImageText8 
 
555
    draw: 0x8c00017 nChars: 1, gc: 0x8c00013, x: 101, y: 585, chars=' '
 
556
 X_ClearArea 
 
557
    window: 0x8c00018, x:   2, y: 217, w:  10, h:   5
 
558
 X_FillPoly 
 
559
    draw: 0x8c00018 gc: 0x8c0000a, shape: 0, coordMode: 0,
 
560
 X_FillPoly 
 
561
    draw: 0x8c00018 gc: 0x8c0000b, shape: 0, coordMode: 0,
 
562
 X_CopyArea 
 
563
    src: 0x8c00017, dst: 0x8c00017, gc: 0x8c00013, srcX:  17, srcY:  15, dstX:  17, dstY:   2, w: 480, h: 572
 
564
 X_ChangeWindowAttributes 
 
565
 X_ClearArea 
 
566
    window: 0x8c00017, x:  17, y: 574, w: 480, h:  13
 
567
 X_ChangeWindowAttributes 
 
568
 
 
569
 */
 
570
 
 
571
        src = req->srcDrawable;
 
572
        dst = req->dstDrawable;
 
573
        src_x = req->srcX;
 
574
        src_y = req->srcY;
 
575
        dst_x = req->dstX;
 
576
        dst_y = req->dstY;
 
577
        w = req->width;
 
578
        h = req->height;
 
579
 
 
580
        if (w*h < (unsigned int) scrollcopyrect_min_area) {
 
581
                good = 0;
 
582
        } else if (!src || !dst) {
 
583
                good = 0;
 
584
        } else if (src != dst) {
 
585
                good = 0;
 
586
        } else if (scr_ev_cnt >= SCR_EV_MAX) {
 
587
                good = 0;
 
588
        }
 
589
 
 
590
        dx = dst_x - src_x;
 
591
        dy = dst_y - src_y;
 
592
 
 
593
        if (dx != 0 && dy != 0) {
 
594
                good = 0;
 
595
        }
 
596
 
 
597
        if (! good) {
 
598
                return;
 
599
        }
 
600
if (db > 1) fprintf(stderr, "record_CA-%d\n", k++);
 
601
 
 
602
        /*
 
603
         * after all of the above succeeds, now contact X server.
 
604
         * we try to get away with some caching here.
 
605
         */
 
606
        if (lookup_attr_cache(src, &cache_index, &next_index)) {
 
607
                i = cache_index;
 
608
                attr.x = scr_attr_cache[i].x;
 
609
                attr.y = scr_attr_cache[i].y;
 
610
                attr.width = scr_attr_cache[i].width;
 
611
                attr.height = scr_attr_cache[i].height;
 
612
                attr.map_state = scr_attr_cache[i].map_state;
 
613
                rx = scr_attr_cache[i].rx;
 
614
                ry = scr_attr_cache[i].ry;
 
615
                valid = scr_attr_cache[i].valid;
 
616
 
 
617
        } else {
 
618
                valid = valid_window(src, &attr, 1);
 
619
 
 
620
                if (valid) {
 
621
                        if (!xtranslate(src, rootwin, 0, 0, &rx, &ry, &c, 1)) {
 
622
                                valid = 0;
 
623
                        }
 
624
                }
 
625
                if (next_index >= 0) {
 
626
                        i = next_index;
 
627
                        scr_attr_cache[i].win = src;
 
628
                        scr_attr_cache[i].fetched = 1;
 
629
                        scr_attr_cache[i].valid = valid;
 
630
                        scr_attr_cache[i].time = dnow();
 
631
                        if (valid) {
 
632
                                scr_attr_cache[i].x = attr.x;
 
633
                                scr_attr_cache[i].y = attr.y;
 
634
                                scr_attr_cache[i].width = attr.width;
 
635
                                scr_attr_cache[i].height = attr.height;
 
636
                                scr_attr_cache[i].border_width = attr.border_width;
 
637
                                scr_attr_cache[i].depth = attr.depth;
 
638
                                scr_attr_cache[i].class = attr.class;
 
639
                                scr_attr_cache[i].backing_store =
 
640
                                    attr.backing_store;
 
641
                                scr_attr_cache[i].map_state = attr.map_state;
 
642
 
 
643
                                scr_attr_cache[i].rx = rx;
 
644
                                scr_attr_cache[i].ry = ry;
 
645
                        }
 
646
                }
 
647
        }
 
648
 
 
649
        if (! valid) {
 
650
                return;
 
651
        }
 
652
if (db > 1) fprintf(stderr, "record_CA-%d\n", k++);
 
653
 
 
654
        if (attr.map_state != IsViewable) {
 
655
                return;
 
656
        }
 
657
 
 
658
 
 
659
 if (0 || dba || db) {
 
660
        double st, dt;
 
661
        st = (double) rec_data->server_time/1000.0;
 
662
        dt = (dnow() - servertime_diff) - st;
 
663
        fprintf(stderr, "record_CA-%d *FOUND_SCROLL: src: 0x%lx dx: %d dy: %d "
 
664
        "x: %d y: %d w: %d h: %d st: %.4f %.4f  %.4f\n", k++, src, dx, dy,
 
665
        src_x, src_y, w, h, st, dt, dnowx());
 
666
 }
 
667
 
 
668
        i = scr_ev_cnt;
 
669
 
 
670
        scr_ev[i].win = src;
 
671
        scr_ev[i].frame = None;
 
672
        scr_ev[i].dx = dx;
 
673
        scr_ev[i].dy = dy;
 
674
        scr_ev[i].x = rx + dst_x;
 
675
        scr_ev[i].y = ry + dst_y;
 
676
        scr_ev[i].w = w;
 
677
        scr_ev[i].h = h;
 
678
        scr_ev[i].t = ((double) rec_data->server_time)/1000.0;
 
679
        scr_ev[i].win_x = rx;
 
680
        scr_ev[i].win_y = ry;
 
681
        scr_ev[i].win_w = attr.width;
 
682
        scr_ev[i].win_h = attr.height;
 
683
        scr_ev[i].new_x = 0;
 
684
        scr_ev[i].new_y = 0;
 
685
        scr_ev[i].new_w = 0;
 
686
        scr_ev[i].new_h = 0;
 
687
 
 
688
        if (dx == 0) {
 
689
                if (dy > 0) {
 
690
                        scr_ev[i].new_x = rx + src_x;
 
691
                        scr_ev[i].new_y = ry + src_y;
 
692
                        scr_ev[i].new_w = w;
 
693
                        scr_ev[i].new_h = dy;
 
694
                } else {
 
695
                        scr_ev[i].new_x = rx + src_x;
 
696
                        scr_ev[i].new_y = ry + dst_y + h;
 
697
                        scr_ev[i].new_w = w;
 
698
                        scr_ev[i].new_h = -dy;
 
699
                }
 
700
        } else if (dy == 0) {
 
701
                if (dx > 0) {
 
702
                        scr_ev[i].new_x = rx + src_x;
 
703
                        scr_ev[i].new_y = rx + src_y;
 
704
                        scr_ev[i].new_w = dx;
 
705
                        scr_ev[i].new_h = h;
 
706
                } else {
 
707
                        scr_ev[i].new_x = rx + dst_x + w;
 
708
                        scr_ev[i].new_y = ry + src_y;
 
709
                        scr_ev[i].new_w = -dx;
 
710
                        scr_ev[i].new_h = h;
 
711
                }
 
712
        }
 
713
 
 
714
        scr_ev_cnt++;
 
715
}
 
716
 
 
717
typedef struct cw_event {
 
718
        Window win;
 
719
        int x, y, w, h;
 
720
} cw_event_t;
 
721
 
 
722
#define MAX_CW 128
 
723
static cw_event_t cw_events[MAX_CW];
 
724
 
 
725
static void record_CW(XPointer ptr, XRecordInterceptData *rec_data) {
 
726
        xConfigureWindowReq *req;
 
727
        Window win = None, c;
 
728
        Window src = None, dst = None;
 
729
        XWindowAttributes attr;
 
730
        int absent = 0x100000;
 
731
        int src_x, src_y, dst_x, dst_y, rx, ry;
 
732
        int good = 1, dx, dy, k=0, i, j, match, list[3];
 
733
        int f_x, f_y, f_w, f_h;
 
734
        int x, y, w, h;
 
735
        int x0, y0, w0, h0, x1, y1, w1, h1, x2, y2, w2, h2;
 
736
        static int index = 0;
 
737
        unsigned int vals[4];
 
738
        unsigned tmask;
 
739
        char *data;
 
740
        int dba = 0, db = debug_scroll;
 
741
        int cache_index, next_index, valid;
 
742
 
 
743
        if (db) {
 
744
                if (rec_data->category == XRecordFromClient) {
 
745
                        req = (xConfigureWindowReq *) rec_data->data;
 
746
                        if (req->reqType == X_ConfigureWindow) {
 
747
                                src = req->window;
 
748
                        }
 
749
                }
 
750
        }
 
751
 
 
752
if (dba || db > 1) fprintf(stderr, "record_CW-%d id_base: 0x%lx  ptr: 0x%lx "
 
753
        "seq: 0x%lx rc: 0x%lx  cat: %d  swapped: %d 0x%lx/0x%lx\n", k++,
 
754
        rec_data->id_base, (unsigned long) ptr, xrecord_seq, rc_scroll,
 
755
        rec_data->category, rec_data->client_swapped, src, dst);
 
756
 
 
757
 
 
758
        if (! xrecording) {
 
759
                return;
 
760
        }
 
761
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
 
762
 
 
763
        if ((XID) ptr != xrecord_seq) {
 
764
                return;
 
765
        }
 
766
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
 
767
 
 
768
        if (rec_data->id_base == 0) {
 
769
                return;
 
770
        }
 
771
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
 
772
 
 
773
        if (rec_data->category == XRecordStartOfData) {
 
774
                index = 0;
 
775
                return;
 
776
        }
 
777
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
 
778
 
 
779
        if (rec_data->category != XRecordFromClient) {
 
780
                return;
 
781
        }
 
782
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
 
783
 
 
784
        if (rec_data->client_swapped) {
 
785
                return;
 
786
        }
 
787
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
 
788
 
 
789
        req = (xConfigureWindowReq *) rec_data->data;
 
790
 
 
791
        if (req->reqType != X_ConfigureWindow) {
 
792
                return;
 
793
        }
 
794
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
 
795
 
 
796
        tmask = req->mask;
 
797
 
 
798
        tmask &= ~CWX;
 
799
        tmask &= ~CWY;
 
800
        tmask &= ~CWWidth;
 
801
        tmask &= ~CWHeight;
 
802
 
 
803
        if (tmask) {
 
804
                /* require no more than these 4 flags */
 
805
                return;
 
806
        }
 
807
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
 
808
 
 
809
        f_x = req->mask & CWX;
 
810
        f_y = req->mask & CWY;
 
811
        f_w = req->mask & CWWidth;
 
812
        f_h = req->mask & CWHeight;
 
813
 
 
814
        if (! f_x || ! f_y)  {
 
815
                if (f_w && f_h) {
 
816
                        ;       /* netscape 4.x style */
 
817
                } else {
 
818
                        return;
 
819
                }
 
820
        }
 
821
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
 
822
 
 
823
        if ( (f_w && !f_h) || (!f_w && f_h) ) {
 
824
                return;
 
825
        }
 
826
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
 
827
                
 
828
        for (i=0; i<4; i++) {
 
829
                vals[i] = 0;
 
830
        }
 
831
 
 
832
        data = (char *)req;
 
833
        data += sz_xConfigureWindowReq;
 
834
 
 
835
        for (i=0; i<req->length; i++) {
 
836
                unsigned int v;
 
837
                /*
 
838
                 * We use unsigned int for the values.  There were
 
839
                 * some crashes on 64bit machines with unsigned longs.
 
840
                 * Need to check that X protocol sends 32bit values.
 
841
                 */
 
842
                v = *( (unsigned int *) data);
 
843
if (db > 1) fprintf(stderr, "  vals[%d]  0x%x/%d\n", i, v, v);
 
844
                vals[i] = v;
 
845
                data += sizeof(unsigned int);
 
846
        }
 
847
 
 
848
        if (index >= MAX_CW) {
 
849
                int i, j;
 
850
 
 
851
                /* FIXME, circular, etc. */
 
852
                for (i=0; i<2; i++) {
 
853
                        j = MAX_CW - 2 + i;
 
854
                        cw_events[i].win = cw_events[j].win;
 
855
                        cw_events[i].x = cw_events[j].x;
 
856
                        cw_events[i].y = cw_events[j].y;
 
857
                        cw_events[i].w = cw_events[j].w;
 
858
                        cw_events[i].h = cw_events[j].h;
 
859
                }
 
860
                index = 2;
 
861
        }
 
862
 
 
863
        if (! f_x && ! f_y) {
 
864
                /* netscape 4.x style  CWWidth,CWHeight */
 
865
                vals[2] = vals[0];
 
866
                vals[3] = vals[1];
 
867
                vals[0] = 0;
 
868
                vals[1] = 0;
 
869
        }
 
870
 
 
871
        cw_events[index].win = req->window;
 
872
 
 
873
        if (! f_x) {
 
874
                cw_events[index].x = absent;
 
875
        } else {
 
876
                cw_events[index].x = (int) vals[0];
 
877
        }
 
878
        if (! f_y) {
 
879
                cw_events[index].y = absent;
 
880
        } else {
 
881
                cw_events[index].y = (int) vals[1];
 
882
        }
 
883
 
 
884
        if (! f_w) {
 
885
                cw_events[index].w = absent;
 
886
        } else {
 
887
                cw_events[index].w = (int) vals[2];
 
888
        }
 
889
        if (! f_h) {
 
890
                cw_events[index].h = absent;
 
891
        } else {
 
892
                cw_events[index].h = (int) vals[3];
 
893
        }
 
894
 
 
895
        x = cw_events[index].x;
 
896
        y = cw_events[index].y;
 
897
        w = cw_events[index].w;
 
898
        h = cw_events[index].h;
 
899
        win = cw_events[index].win;
 
900
 
 
901
if (dba || db) fprintf(stderr, "  record_CW ind: %d win: 0x%lx x: %d y: %d w: %d h: %d\n",
 
902
        index, win, x, y, w, h);
 
903
 
 
904
        index++;
 
905
 
 
906
        if (index < 3) {
 
907
                good = 0;
 
908
        } else if (w != absent && h != absent &&
 
909
            w*h < scrollcopyrect_min_area) {
 
910
                good = 0;
 
911
        }
 
912
 
 
913
        if (! good) {
 
914
                return;
 
915
        }
 
916
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
 
917
 
 
918
        match = 0;
 
919
        for (j=index - 1; j >= 0; j--) {
 
920
                if (cw_events[j].win == win) {
 
921
                        list[match++] = j;
 
922
                }
 
923
                if (match >= 3) {
 
924
                        break;
 
925
                }
 
926
        }
 
927
 
 
928
        if (match != 3) {
 
929
                return;
 
930
        }
 
931
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
 
932
 
 
933
/*
 
934
 
 
935
Mozilla:
 
936
 
 
937
Up arrow: window moves down a bit (dy > 0):
 
938
 
 
939
 X_ConfigureWindow 
 
940
    length: 7, window: 0x2e000cd, mask: 0xf, v0 0,  v1 -18,  v2 760,  v3 906,  v4 327692,  v5 48234701,  v6 3, 
 
941
        CW-mask: CWX,CWY,CWWidth,CWHeight,
 
942
 X_ConfigureWindow 
 
943
    length: 5, window: 0x2e000cd, mask: 0x3, v0 0,  v1 0,  v2 506636,  v3 48234701,  v4 48234511, 
 
944
        CW-mask: CWX,CWY,
 
945
 X_ConfigureWindow 
 
946
    length: 7, window: 0x2e000cd, mask: 0xf, v0 0,  v1 0,  v2 760,  v3 888,  v4 65579,  v5 0,  v6 108009, 
 
947
        CW-mask: CWX,CWY,CWWidth,CWHeight,
 
948
 
 
949
Down arrow: window moves up a bit (dy < 0):
 
950
 
 
951
 X_ConfigureWindow 
 
952
    length: 7, window: 0x2e000cd, mask: 0xf, v0 0,  v1 0,  v2 760,  v3 906,  v4 327692,  v5 48234701,  v6 262147, 
 
953
        CW-mask: CWX,CWY,CWWidth,CWHeight,
 
954
 X_ConfigureWindow 
 
955
    length: 5, window: 0x2e000cd, mask: 0x3, v0 0,  v1 -18,  v2 506636,  v3 48234701,  v4 48234511, 
 
956
        CW-mask: CWX,CWY,
 
957
 X_ConfigureWindow 
 
958
    length: 7, window: 0x2e000cd, mask: 0xf, v0 0,  v1 0,  v2 760,  v3 888,  v4 96555,  v5 48265642,  v6 48265262, 
 
959
        CW-mask: CWX,CWY,CWWidth,CWHeight,
 
960
 
 
961
 
 
962
Netscape 4.x
 
963
 
 
964
Up arrow:
 
965
71.76142   0.01984 X_ConfigureWindow
 
966
    length: 7, window: 0x9800488, mask: 0xf, v0 0,  v1 -15,  v2 785,  v3 882,  v4 327692,  v5 159384712,  v6 1769484,
 
967
        CW-mask: CWX,CWY,CWWidth,CWHeight,
 
968
71.76153   0.00011 X_ConfigureWindow
 
969
    length: 5, window: 0x9800488, mask: 0xc, v0 785,  v1 867,  v2 329228,  v3 159384712,  v4 159383555,
 
970
        CW-mask:       CWWidth,CWHeight,
 
971
                XXX,XXX
 
972
71.76157   0.00003 X_ConfigureWindow
 
973
    length: 5, window: 0x9800488, mask: 0x3, v0 0,  v1 0,  v2 131132,  v3 159385313,  v4 328759,
 
974
        CW-mask: CWX,CWY,
 
975
                         XXX,XXX
 
976
 
 
977
Down arrow:
 
978
72.93147   0.01990 X_ConfigureWindow
 
979
    length: 5, window: 0x9800488, mask: 0xc, v0 785,  v1 882,  v2 328972,  v3 159384712,  v4 159383555,
 
980
        CW-mask:       CWWidth,CWHeight,
 
981
                XXX,XXX
 
982
72.93156   0.00009 X_ConfigureWindow
 
983
    length: 5, window: 0x9800488, mask: 0x3, v0 0,  v1 -15,  v2 458764,  v3 159384712,  v4 159383567,
 
984
        CW-mask: CWX,CWY,
 
985
72.93160   0.00004 X_ConfigureWindow
 
986
    length: 7, window: 0x9800488, mask: 0xf, v0 0,  v1 0,  v2 785,  v3 867,  v4 131132,  v5 159385335,  v6 328759,
 
987
        CW-mask: CWX,CWY,CWWidth,CWHeight,
 
988
 
 
989
 
 
990
sadly, probably need to handle some more...
 
991
 
 
992
 */
 
993
        x0 = cw_events[list[2]].x;
 
994
        y0 = cw_events[list[2]].y;
 
995
        w0 = cw_events[list[2]].w;
 
996
        h0 = cw_events[list[2]].h;
 
997
 
 
998
        x1 = cw_events[list[1]].x;
 
999
        y1 = cw_events[list[1]].y;
 
1000
        w1 = cw_events[list[1]].w;
 
1001
        h1 = cw_events[list[1]].h;
 
1002
 
 
1003
        x2 = cw_events[list[0]].x;
 
1004
        y2 = cw_events[list[0]].y;
 
1005
        w2 = cw_events[list[0]].w;
 
1006
        h2 = cw_events[list[0]].h;
 
1007
 
 
1008
        /* see NS4 XXX's above: */
 
1009
        if (w2 == absent || h2 == absent) {
 
1010
                /* up arrow */
 
1011
                if (w2 == absent) {
 
1012
                        w2 = w1;
 
1013
                }
 
1014
                if (h2 == absent) {
 
1015
                        h2 = h1;
 
1016
                }
 
1017
        }
 
1018
        if (x1 == absent || y1 == absent) {
 
1019
                /* up arrow */
 
1020
                if (x1 == absent) {
 
1021
                        x1 = x2;
 
1022
                }
 
1023
                if (y1 == absent) {
 
1024
                        y1 = y2;
 
1025
                }
 
1026
        }
 
1027
        if (x0 == absent || y0 == absent) {
 
1028
                /* down arrow */
 
1029
                if (x0 == absent) {
 
1030
                        /* hmmm... what to do */
 
1031
                        x0 = x2;
 
1032
                }
 
1033
                if (y0 == absent) {
 
1034
                        y0 = y2;
 
1035
                }
 
1036
        }
 
1037
 
 
1038
if (dba) fprintf(stderr, "%d/%d/%d/%d  %d/%d/%d/%d  %d/%d/%d/%d\n", x0, y0, w0, h0, x1, y1, w1, h1, x2, y2, w2, h2);
 
1039
 
 
1040
        dy = y1 - y0;
 
1041
        dx = x1 - x0;
 
1042
 
 
1043
        src_x = x2;
 
1044
        src_y = y2;
 
1045
        w = w2;
 
1046
        h = h2;
 
1047
 
 
1048
        /* check w and h before we modify them */
 
1049
        if (w <= 0 || h <= 0) {
 
1050
                good = 0;
 
1051
        } else if (w == absent || h == absent) {
 
1052
                good = 0;
 
1053
        }
 
1054
        if (! good) {
 
1055
                return;
 
1056
        }
 
1057
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
 
1058
 
 
1059
        if (dy > 0) {
 
1060
                h -= dy;        
 
1061
        } else {
 
1062
                h += dy;        
 
1063
                src_y -= dy;
 
1064
        }
 
1065
        if (dx > 0) {
 
1066
                w -= dx;        
 
1067
        } else {
 
1068
                w += dx;        
 
1069
                src_x -= dx;
 
1070
        }
 
1071
 
 
1072
        dst_x = src_x + dx;
 
1073
        dst_y = src_y + dy;
 
1074
 
 
1075
        if (x0 == absent || x1 == absent || x2 == absent) {
 
1076
                good = 0;
 
1077
        } else if (y0 == absent || y1 == absent || y2 == absent) {
 
1078
                good = 0;
 
1079
        } else if (dx != 0 && dy != 0) {
 
1080
                good = 0;
 
1081
        } else if (w0 - w2 != nabs(dx)) {
 
1082
                good = 0;
 
1083
        } else if (h0 - h2 != nabs(dy)) {
 
1084
                good = 0;
 
1085
        } else if (scr_ev_cnt >= SCR_EV_MAX) {
 
1086
                good = 0;
 
1087
        }
 
1088
 
 
1089
        if (! good) {
 
1090
                return;
 
1091
        }
 
1092
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
 
1093
 
 
1094
        /*
 
1095
         * geometry OK.
 
1096
         * after all of the above succeeds, now contact X server.
 
1097
         */
 
1098
        if (lookup_attr_cache(win, &cache_index, &next_index)) {
 
1099
                i = cache_index;
 
1100
                attr.x = scr_attr_cache[i].x;
 
1101
                attr.y = scr_attr_cache[i].y;
 
1102
                attr.width = scr_attr_cache[i].width;
 
1103
                attr.height = scr_attr_cache[i].height;
 
1104
                attr.map_state = scr_attr_cache[i].map_state;
 
1105
                rx = scr_attr_cache[i].rx;
 
1106
                ry = scr_attr_cache[i].ry;
 
1107
                valid = scr_attr_cache[i].valid;
 
1108
 
 
1109
if (0) fprintf(stderr, "lookup_attr_cache hit:  %2d %2d 0x%lx %d\n",
 
1110
    cache_index, next_index, win, valid);
 
1111
 
 
1112
        } else {
 
1113
                valid = valid_window(win, &attr, 1);
 
1114
 
 
1115
if (0) fprintf(stderr, "lookup_attr_cache MISS: %2d %2d 0x%lx %d\n",
 
1116
    cache_index, next_index, win, valid);
 
1117
 
 
1118
                if (valid) {
 
1119
                        if (!xtranslate(win, rootwin, 0, 0, &rx, &ry, &c, 1)) {
 
1120
                                valid = 0;
 
1121
                        }
 
1122
                }
 
1123
                if (next_index >= 0) {
 
1124
                        i = next_index;
 
1125
                        scr_attr_cache[i].win = win;
 
1126
                        scr_attr_cache[i].fetched = 1;
 
1127
                        scr_attr_cache[i].valid = valid;
 
1128
                        scr_attr_cache[i].time = dnow();
 
1129
                        if (valid) {
 
1130
                                scr_attr_cache[i].x = attr.x;
 
1131
                                scr_attr_cache[i].y = attr.y;
 
1132
                                scr_attr_cache[i].width = attr.width;
 
1133
                                scr_attr_cache[i].height = attr.height;
 
1134
                                scr_attr_cache[i].depth = attr.depth;
 
1135
                                scr_attr_cache[i].class = attr.class;
 
1136
                                scr_attr_cache[i].backing_store =
 
1137
                                    attr.backing_store;
 
1138
                                scr_attr_cache[i].map_state = attr.map_state;
 
1139
 
 
1140
                                scr_attr_cache[i].rx = rx;
 
1141
                                scr_attr_cache[i].ry = ry;
 
1142
                        }
 
1143
                }
 
1144
        }
 
1145
 
 
1146
        if (! valid) {
 
1147
                return;
 
1148
        }
 
1149
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
 
1150
 
 
1151
        if (attr.map_state != IsViewable) {
 
1152
                return;
 
1153
        }
 
1154
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
 
1155
 
 
1156
 if (0 || dba || db) {
 
1157
        double st, dt;
 
1158
        st = (double) rec_data->server_time/1000.0;
 
1159
        dt = (dnow() - servertime_diff) - st;
 
1160
        fprintf(stderr, "record_CW-%d *FOUND_SCROLL: win: 0x%lx dx: %d dy: %d "
 
1161
        "x: %d y: %d w: %d h: %d  st: %.4f  dt: %.4f  %.4f\n", k++, win,
 
1162
        dx, dy, src_x, src_y, w, h, st, dt, dnowx());
 
1163
 }
 
1164
 
 
1165
        i = scr_ev_cnt;
 
1166
 
 
1167
        scr_ev[i].win = win;
 
1168
        scr_ev[i].frame = None;
 
1169
        scr_ev[i].dx = dx;
 
1170
        scr_ev[i].dy = dy;
 
1171
        scr_ev[i].x = rx + dst_x;
 
1172
        scr_ev[i].y = ry + dst_y;
 
1173
        scr_ev[i].w = w;
 
1174
        scr_ev[i].h = h;
 
1175
        scr_ev[i].t = ((double) rec_data->server_time)/1000.0;
 
1176
        scr_ev[i].win_x = rx;
 
1177
        scr_ev[i].win_y = ry;
 
1178
        scr_ev[i].win_w = attr.width;
 
1179
        scr_ev[i].win_h = attr.height;
 
1180
        scr_ev[i].new_x = 0;
 
1181
        scr_ev[i].new_y = 0;
 
1182
        scr_ev[i].new_w = 0;
 
1183
        scr_ev[i].new_h = 0;
 
1184
 
 
1185
        if (dx == 0) {
 
1186
                if (dy > 0) {
 
1187
                        scr_ev[i].new_x = rx + src_x;
 
1188
                        scr_ev[i].new_y = ry + src_y;
 
1189
                        scr_ev[i].new_w = w;
 
1190
                        scr_ev[i].new_h = dy;
 
1191
                } else {
 
1192
                        scr_ev[i].new_x = rx + src_x;
 
1193
                        scr_ev[i].new_y = ry + dst_y + h;
 
1194
                        scr_ev[i].new_w = w;
 
1195
                        scr_ev[i].new_h = -dy;
 
1196
                }
 
1197
        } else if (dy == 0) {
 
1198
                if (dx > 0) {
 
1199
                        scr_ev[i].new_x = rx + src_x;
 
1200
                        scr_ev[i].new_y = rx + src_y;
 
1201
                        scr_ev[i].new_w = dx;
 
1202
                        scr_ev[i].new_h = h;
 
1203
                } else {
 
1204
                        scr_ev[i].new_x = rx + dst_x + w;
 
1205
                        scr_ev[i].new_y = ry + src_y;
 
1206
                        scr_ev[i].new_w = -dx;
 
1207
                        scr_ev[i].new_h = h;
 
1208
                }
 
1209
        }
 
1210
 
 
1211
        /* indicate we have a new one */
 
1212
        scr_ev_cnt++;
 
1213
 
 
1214
        index = 0;
 
1215
}
 
1216
 
 
1217
static void record_switch(XPointer ptr, XRecordInterceptData *rec_data) {
 
1218
        static int first = 1;
 
1219
        xReq *req;
 
1220
 
 
1221
        if (first) {
 
1222
                int i;
 
1223
                for (i=0; i<SCR_ATTR_CACHE; i++) {
 
1224
                        scr_attr_cache[i].win = None;
 
1225
                        scr_attr_cache[i].fetched = 0;
 
1226
                        scr_attr_cache[i].valid = 0;
 
1227
                        scr_attr_cache[i].time = 0.0;
 
1228
                }
 
1229
                first = 0;
 
1230
        }
 
1231
 
 
1232
        /* should handle control msgs, start/stop/etc */
 
1233
        if (rec_data->category == XRecordStartOfData) {
 
1234
                record_CW(ptr, rec_data);
 
1235
        } else if (rec_data->category == XRecordEndOfData) {
 
1236
                ;
 
1237
        } else if (rec_data->category == XRecordClientStarted) {
 
1238
                ;
 
1239
        } else if (rec_data->category == XRecordClientDied) {
 
1240
                ;
 
1241
        } else if (rec_data->category == XRecordFromServer) {
 
1242
                ;
 
1243
        }
 
1244
 
 
1245
        if (rec_data->category != XRecordFromClient) {
 
1246
                XRecordFreeData(rec_data);
 
1247
                return;
 
1248
        }
 
1249
 
 
1250
        req = (xReq *) rec_data->data;
 
1251
 
 
1252
        if (req->reqType == X_CopyArea) {
 
1253
                record_CA(ptr, rec_data);
 
1254
        } else if (req->reqType == X_ConfigureWindow) {
 
1255
                record_CW(ptr, rec_data);
 
1256
        } else {
 
1257
                ;
 
1258
        }
 
1259
        XRecordFreeData(rec_data);
 
1260
}
 
1261
 
 
1262
static void record_grab(XPointer ptr, XRecordInterceptData *rec_data) {
 
1263
        xReq *req;
 
1264
        int db = 0;
 
1265
 
 
1266
        if (debug_grabs) db = 1;
 
1267
 
 
1268
        /* should handle control msgs, start/stop/etc */
 
1269
        if (rec_data->category == XRecordStartOfData) {
 
1270
                ;
 
1271
        } else if (rec_data->category == XRecordEndOfData) {
 
1272
                ;
 
1273
        } else if (rec_data->category == XRecordClientStarted) {
 
1274
                ;
 
1275
        } else if (rec_data->category == XRecordClientDied) {
 
1276
                ;
 
1277
        } else if (rec_data->category == XRecordFromServer) {
 
1278
                ;
 
1279
        }
 
1280
 
 
1281
        if (rec_data->category != XRecordFromClient) {
 
1282
                XRecordFreeData(rec_data);
 
1283
                return;
 
1284
        }
 
1285
 
 
1286
        req = (xReq *) rec_data->data;
 
1287
 
 
1288
        if (req->reqType == X_GrabServer) {
 
1289
                double now = dnowx();
 
1290
                xserver_grabbed++;
 
1291
                if (db) rfbLog("X server Grabbed:    %d %.5f\n", xserver_grabbed, now);
 
1292
                if (xserver_grabbed > 1) {
 
1293
                        /* 
 
1294
                         * some apps do multiple grabs... very unlikely
 
1295
                         * two apps will be doing it at same time.
 
1296
                         */
 
1297
                        xserver_grabbed = 1;
 
1298
                }
 
1299
        } else if (req->reqType == X_UngrabServer) {
 
1300
                double now = dnowx();
 
1301
                xserver_grabbed--;
 
1302
                if (xserver_grabbed < 0) {
 
1303
                        xserver_grabbed = 0;
 
1304
                }
 
1305
                if (db) rfbLog("X server Un-Grabbed: %d %.5f\n", xserver_grabbed, now);
 
1306
        } else {
 
1307
                ;
 
1308
        }
 
1309
        XRecordFreeData(rec_data);
 
1310
 
 
1311
        /* unused vars warning: */
 
1312
        if (ptr) {} 
 
1313
}
 
1314
#endif
 
1315
 
 
1316
static void check_xrecord_grabserver(void) {
 
1317
#if LIBVNCSERVER_HAVE_RECORD
 
1318
        int last_val, cnt = 0, i, max = 10;
 
1319
        double d;
 
1320
        if (!gdpy_ctrl || !gdpy_data) {
 
1321
                return;
 
1322
        }
 
1323
        if (unixpw_in_progress) return;
 
1324
 
 
1325
        dtime0(&d);
 
1326
        XFlush_wr(gdpy_ctrl);
 
1327
        for (i=0; i<max; i++) {
 
1328
                last_val = xserver_grabbed;
 
1329
                XRecordProcessReplies(gdpy_data);
 
1330
                if (xserver_grabbed != last_val) {
 
1331
                        cnt++;
 
1332
                } else if (i > 2) {
 
1333
                        break;
 
1334
                }
 
1335
        }
 
1336
        if (cnt) {
 
1337
                XFlush_wr(gdpy_ctrl);
 
1338
        }
 
1339
 if (debug_grabs && cnt > 0) {
 
1340
        d = dtime(&d);
 
1341
fprintf(stderr, "check_xrecord_grabserver: cnt=%d i=%d %.4f\n", cnt, i, d);
 
1342
 }
 
1343
#endif
 
1344
}
 
1345
 
 
1346
#if LIBVNCSERVER_HAVE_RECORD
 
1347
static void shutdown_record_context(XRecordContext rc, int bequiet, int reopen) {
 
1348
        int ret1, ret2;
 
1349
        int verb = (!bequiet && !quiet);
 
1350
 
 
1351
        RAWFB_RET_VOID
 
1352
        if (0 || debug_scroll) {
 
1353
                rfbLog("shutdown_record_context(0x%lx, %d, %d)\n", rc,
 
1354
                    bequiet, reopen);
 
1355
                verb = 1;
 
1356
        }
 
1357
 
 
1358
        ret1 = XRecordDisableContext(rdpy_ctrl, rc);
 
1359
        if (!ret1 && verb) {
 
1360
                rfbLog("XRecordDisableContext(0x%lx) failed.\n", rc);   
 
1361
        }
 
1362
        ret2 = XRecordFreeContext(rdpy_ctrl, rc);
 
1363
        if (!ret2 && verb) {
 
1364
                rfbLog("XRecordFreeContext(0x%lx) failed.\n", rc);      
 
1365
        }
 
1366
        XFlush_wr(rdpy_ctrl);
 
1367
 
 
1368
        if (reopen == 2 && ret1 && ret2) {
 
1369
                reopen = 0;     /* 2 means reopen only on failure  */
 
1370
        }
 
1371
        if (reopen && gdpy_ctrl) {
 
1372
                check_xrecord_grabserver();
 
1373
                if (xserver_grabbed) {
 
1374
                        rfbLog("shutdown_record_context: skip reopen,"
 
1375
                            " server grabbed\n");       
 
1376
                        reopen = 0;
 
1377
                }
 
1378
        }
 
1379
        if (reopen) {
 
1380
                char *dpystr = DisplayString(dpy);
 
1381
 
 
1382
                if (debug_scroll) {
 
1383
                        rfbLog("closing RECORD data connection.\n");
 
1384
                }
 
1385
                XCloseDisplay_wr(rdpy_data);
 
1386
                rdpy_data = NULL;
 
1387
 
 
1388
                if (debug_scroll) {
 
1389
                        rfbLog("closing RECORD control connection.\n");
 
1390
                }
 
1391
                XCloseDisplay_wr(rdpy_ctrl);
 
1392
                rdpy_ctrl = NULL;
 
1393
 
 
1394
                rdpy_ctrl = XOpenDisplay_wr(dpystr);
 
1395
 
 
1396
                if (! rdpy_ctrl) {
 
1397
                        rfbLog("Failed to reopen RECORD control connection:"
 
1398
                            "%s\n", dpystr);
 
1399
                        rfbLog("  disabling RECORD scroll detection.\n");
 
1400
                        use_xrecord = 0;
 
1401
                        return;
 
1402
                }
 
1403
                XSync(dpy, False);
 
1404
 
 
1405
                disable_grabserver(rdpy_ctrl, 0);
 
1406
                XSync(rdpy_ctrl, True);
 
1407
 
 
1408
                rdpy_data = XOpenDisplay_wr(dpystr);
 
1409
 
 
1410
                if (! rdpy_data) {
 
1411
                        rfbLog("Failed to reopen RECORD data connection:"
 
1412
                            "%s\n", dpystr);
 
1413
                        rfbLog("  disabling RECORD scroll detection.\n");
 
1414
                        XCloseDisplay_wr(rdpy_ctrl);
 
1415
                        rdpy_ctrl = NULL;
 
1416
                        use_xrecord = 0;
 
1417
                        return;
 
1418
                }
 
1419
                disable_grabserver(rdpy_data, 0);
 
1420
 
 
1421
                if (debug_scroll || (! bequiet && reopen == 2)) {
 
1422
                        rfbLog("reopened RECORD data and control display"
 
1423
                            " connections: %s\n", dpystr);
 
1424
                }
 
1425
        }
 
1426
}
 
1427
#endif
 
1428
 
 
1429
void check_xrecord_reset(int force) {
 
1430
        static double last_reset = 0.0;
 
1431
        int reset_time  = 60, require_idle  = 10;
 
1432
        int reset_time2 = 600, require_idle2 = 40;
 
1433
        double now = 0.0;
 
1434
        XErrorHandler old_handler = NULL;
 
1435
 
 
1436
        if (gdpy_ctrl) {
 
1437
                X_LOCK;
 
1438
                check_xrecord_grabserver();
 
1439
                X_UNLOCK;
 
1440
        } else {
 
1441
                /* more dicey if not watching grabserver */
 
1442
                reset_time = reset_time2;
 
1443
                require_idle = require_idle2;
 
1444
        }
 
1445
 
 
1446
        if (!use_xrecord) {
 
1447
                return;
 
1448
        }
 
1449
        if (xrecording) {
 
1450
                return;
 
1451
        }
 
1452
        if (button_mask) {
 
1453
                return;
 
1454
        }
 
1455
        if (xserver_grabbed) {
 
1456
                return;
 
1457
        }
 
1458
 
 
1459
        if (unixpw_in_progress) return;
 
1460
 
 
1461
#if LIBVNCSERVER_HAVE_RECORD
 
1462
        if (! rc_scroll) {
 
1463
                return;
 
1464
        }
 
1465
        now = dnow();
 
1466
        if (last_reset == 0.0) {
 
1467
                last_reset = now;
 
1468
                return;
 
1469
        }
 
1470
        /*
 
1471
         * try to wait for a break in input to reopen the displays
 
1472
         * this is only to avoid XGrabServer deadlock on the repopens.
 
1473
         */
 
1474
        if (force) {
 
1475
                ;
 
1476
        } else if (now < last_reset + reset_time) {
 
1477
                return;
 
1478
        } else if (now < last_pointer_click_time + require_idle)  {
 
1479
                return;
 
1480
        } else if (now < last_keyboard_time + require_idle)  {
 
1481
                return;
 
1482
        }
 
1483
        X_LOCK;
 
1484
        trapped_record_xerror = 0;
 
1485
        old_handler = XSetErrorHandler(trap_record_xerror);
 
1486
 
 
1487
        /* unlikely, but check again since we will definitely be doing it. */
 
1488
        if (gdpy_ctrl) {
 
1489
                check_xrecord_grabserver();
 
1490
                if (xserver_grabbed) {
 
1491
                        XSetErrorHandler(old_handler);
 
1492
                        X_UNLOCK;
 
1493
                        return;
 
1494
                }
 
1495
        }
 
1496
        
 
1497
        shutdown_record_context(rc_scroll, 0, 1);
 
1498
        rc_scroll = 0;
 
1499
 
 
1500
        XSetErrorHandler(old_handler);
 
1501
        X_UNLOCK;
 
1502
 
 
1503
        last_reset = now;
 
1504
#else
 
1505
        if (!old_handler || now == 0.0 || !last_reset || !force) {}
 
1506
#endif
 
1507
}
 
1508
 
 
1509
#define RECORD_ERROR_MSG \
 
1510
        if (! quiet) { \
 
1511
                rfbLog("trapped RECORD XError: %s %d/%d/%d (0x%lx)\n", \
 
1512
                    xerror_string(trapped_record_xerror_event), \
 
1513
                    (int) trapped_record_xerror_event->error_code, \
 
1514
                    (int) trapped_record_xerror_event->request_code, \
 
1515
                    (int) trapped_record_xerror_event->minor_code, \
 
1516
                    (int) trapped_record_xerror_event->resourceid); \
 
1517
        }
 
1518
 
 
1519
void xrecord_watch(int start, int setby) {
 
1520
#if LIBVNCSERVER_HAVE_RECORD
 
1521
        Window focus, wm, c, clast;
 
1522
        static double create_time = 0.0;
 
1523
        int rc;
 
1524
        int do_shutdown = 0;
 
1525
        int reopen_dpys = 1;
 
1526
        XErrorHandler old_handler = NULL;
 
1527
        static Window last_win = None, last_result = None;
 
1528
#endif
 
1529
        int db = debug_scroll;
 
1530
        double now;
 
1531
        static double last_error = 0.0;
 
1532
 
 
1533
if (0) db = 1;
 
1534
 
 
1535
        if (nofb) {
 
1536
                xrecording = 0;
 
1537
                return;
 
1538
        }
 
1539
        if (use_threads) {
 
1540
                /* XXX not working */
 
1541
                use_xrecord = 0;
 
1542
                xrecording = 0;
 
1543
                return;
 
1544
        }
 
1545
 
 
1546
        dtime0(&now);
 
1547
        if (now < last_error + 0.5) {
 
1548
                return;
 
1549
        }
 
1550
 
 
1551
        if (gdpy_ctrl) {
 
1552
                X_LOCK;
 
1553
                check_xrecord_grabserver();
 
1554
                X_UNLOCK;
 
1555
                if (xserver_grabbed) {
 
1556
if (db || debug_grabs) fprintf(stderr, "xrecord_watch: %d/%d  out xserver_grabbed\n", start, setby);
 
1557
                        return;
 
1558
                }
 
1559
        }
 
1560
 
 
1561
#if LIBVNCSERVER_HAVE_RECORD
 
1562
        if (! start) {
 
1563
                int shut_reopen = 2, shut_time = 25;
 
1564
if (db || debug_grabs) fprintf(stderr, "XRECORD OFF: %d/%d  %.4f\n", xrecording, setby, now - x11vnc_start);
 
1565
                xrecording = 0;
 
1566
                if (! rc_scroll) {
 
1567
                        xrecord_focus_window = None;
 
1568
                        xrecord_wm_window = None;
 
1569
                        xrecord_ptr_window = None;
 
1570
                        xrecord_keysym = NoSymbol;
 
1571
                        rcs_scroll = 0;
 
1572
                        return;
 
1573
                }
 
1574
 
 
1575
                if (! do_shutdown && now > create_time + shut_time) {
 
1576
                        /* XXX unstable if we keep a RECORD going forever */
 
1577
                        do_shutdown = 1;
 
1578
                }
 
1579
 
 
1580
                SCR_LOCK;
 
1581
                
 
1582
                if (do_shutdown) {
 
1583
if (db > 1) fprintf(stderr, "=== shutdown-scroll 0x%lx\n", rc_scroll);
 
1584
                        X_LOCK;
 
1585
                        trapped_record_xerror = 0;
 
1586
                        old_handler = XSetErrorHandler(trap_record_xerror);
 
1587
 
 
1588
                        shutdown_record_context(rc_scroll, 0, shut_reopen);
 
1589
                        rc_scroll = 0;
 
1590
 
 
1591
                        /*
 
1592
                         * n.b. there is a grabserver issue wrt
 
1593
                         * XRecordCreateContext() even though rdpy_ctrl
 
1594
                         * is set imprevious to grabs.  Perhaps a bug
 
1595
                         * in the X server or library...
 
1596
                         *
 
1597
                         * If there are further problems, a thought
 
1598
                         * to recreate rc_scroll right after the
 
1599
                         * reopen.
 
1600
                         */
 
1601
 
 
1602
                        if (! use_xrecord) {
 
1603
                                XSetErrorHandler(old_handler);
 
1604
                                X_UNLOCK;
 
1605
                                SCR_UNLOCK;
 
1606
                                return;
 
1607
                        }
 
1608
 
 
1609
                        XRecordProcessReplies(rdpy_data);
 
1610
 
 
1611
                        if (trapped_record_xerror) {
 
1612
                                RECORD_ERROR_MSG;
 
1613
                                last_error = now;
 
1614
                        }
 
1615
 
 
1616
                        XSetErrorHandler(old_handler);
 
1617
                        X_UNLOCK;
 
1618
                        SCR_UNLOCK;
 
1619
 
 
1620
                } else {
 
1621
                        if (rcs_scroll) {
 
1622
if (db > 1) fprintf(stderr, "=== disab-scroll 0x%lx 0x%lx\n", rc_scroll, rcs_scroll);
 
1623
                                X_LOCK;
 
1624
                                trapped_record_xerror = 0;
 
1625
                                old_handler =
 
1626
                                    XSetErrorHandler(trap_record_xerror);
 
1627
 
 
1628
                                rcs_scroll = XRecordCurrentClients;
 
1629
                                XRecordUnregisterClients(rdpy_ctrl, rc_scroll,
 
1630
                                    &rcs_scroll, 1);
 
1631
                                XRecordDisableContext(rdpy_ctrl, rc_scroll);
 
1632
                                XFlush_wr(rdpy_ctrl);
 
1633
                                XRecordProcessReplies(rdpy_data);
 
1634
 
 
1635
                                if (trapped_record_xerror) {
 
1636
                                        RECORD_ERROR_MSG;
 
1637
 
 
1638
                                        shutdown_record_context(rc_scroll,
 
1639
                                            0, reopen_dpys);
 
1640
                                        rc_scroll = 0;
 
1641
 
 
1642
                                        last_error = now;
 
1643
 
 
1644
                                        if (! use_xrecord) {
 
1645
                                                XSetErrorHandler(old_handler);
 
1646
                                                X_UNLOCK;
 
1647
                                                SCR_UNLOCK;
 
1648
                                                return;
 
1649
                                        }
 
1650
                                }
 
1651
                                XSetErrorHandler(old_handler);
 
1652
                                X_UNLOCK;
 
1653
                        }
 
1654
                }
 
1655
 
 
1656
                SCR_UNLOCK;
 
1657
                /*
 
1658
                 * XXX if we do a XFlush_wr(rdpy_ctrl) here we get:
 
1659
                 *
 
1660
 
 
1661
                X Error of failed request:  XRecordBadContext
 
1662
                  Major opcode of failed request:  145 (RECORD)
 
1663
                  Minor opcode of failed request:  5 (XRecordEnableContext)
 
1664
                  Context in failed request:  0x2200013
 
1665
                  Serial number of failed request:  29
 
1666
                  Current serial number in output stream:  29
 
1667
 
 
1668
                 *
 
1669
                 * need to figure out what is going on... since it may lead
 
1670
                 * infrequent failures.
 
1671
                 */
 
1672
                xrecord_focus_window = None;
 
1673
                xrecord_wm_window = None;
 
1674
                xrecord_ptr_window = None;
 
1675
                xrecord_keysym = NoSymbol;
 
1676
                rcs_scroll = 0;
 
1677
                return;
 
1678
        }
 
1679
if (db || debug_grabs) fprintf(stderr, "XRECORD ON:  %d/%d  %.4f\n", xrecording, setby, now - x11vnc_start);
 
1680
 
 
1681
        if (xrecording) {
 
1682
                return;
 
1683
        }
 
1684
 
 
1685
        if (do_shutdown && rc_scroll) {
 
1686
                static int didmsg = 0;
 
1687
                /* should not happen... */
 
1688
                if (0 || !didmsg) {
 
1689
                        rfbLog("warning: do_shutdown && rc_scroll\n");
 
1690
                        didmsg = 1;
 
1691
                }
 
1692
                xrecord_watch(0, SCR_NONE);
 
1693
        }
 
1694
 
 
1695
        xrecording = 0;
 
1696
        xrecord_focus_window = None;
 
1697
        xrecord_wm_window = None;
 
1698
        xrecord_ptr_window = None;
 
1699
        xrecord_keysym = NoSymbol;
 
1700
        xrecord_set_by_keys  = 0;
 
1701
        xrecord_set_by_mouse = 0;
 
1702
 
 
1703
        /* get the window with focus and mouse pointer: */
 
1704
        clast = None;
 
1705
        focus = None;
 
1706
        wm = None;
 
1707
 
 
1708
        X_LOCK;
 
1709
        SCR_LOCK;
 
1710
#if 0
 
1711
        /*
 
1712
         * xrecord_focus_window / focus not currently used... save a
 
1713
         * round trip to the X server for now.
 
1714
         * N.B. our heuristic is inaccurate: if he is scrolling and
 
1715
         * drifts off of the scrollbar onto another application we
 
1716
         * will catch that application, not the starting ones.
 
1717
         * check_xrecord_{keys,mouse} mitigates this somewhat by
 
1718
         * delaying calls to xrecord_watch as much as possible.
 
1719
         */
 
1720
        XGetInputFocus(dpy, &focus, &i);
 
1721
#endif
 
1722
 
 
1723
        wm = query_pointer(rootwin);
 
1724
        if (wm) {
 
1725
                c = wm;
 
1726
        } else {
 
1727
                c = rootwin;
 
1728
        }
 
1729
 
 
1730
        /* descend a bit to avoid wm frames: */
 
1731
        if (c != rootwin && c == last_win) {
 
1732
                /* use cached results to avoid roundtrips: */
 
1733
                clast = last_result;
 
1734
        } else if (scroll_good_all == NULL && scroll_skip_all == NULL) {
 
1735
                /* more efficient if name info not needed. */
 
1736
                xrecord_name_info[0] = '\0';
 
1737
                clast = descend_pointer(6, c, NULL, 0);
 
1738
        } else {
 
1739
                char *nm;
 
1740
                int matched_good = 0, matched_skip = 0;
 
1741
 
 
1742
                clast = descend_pointer(6, c, xrecord_name_info, NAMEINFO);
 
1743
if (db) fprintf(stderr, "name_info: %s\n", xrecord_name_info);
 
1744
 
 
1745
                nm = xrecord_name_info;
 
1746
 
 
1747
                if (scroll_good_all) {
 
1748
                        matched_good += match_str_list(nm, scroll_good_all);
 
1749
                }
 
1750
                if (setby == SCR_KEY && scroll_good_key) {
 
1751
                        matched_good += match_str_list(nm, scroll_good_key);
 
1752
                }
 
1753
                if (setby == SCR_MOUSE && scroll_good_mouse) {
 
1754
                        matched_good += match_str_list(nm, scroll_good_mouse);
 
1755
                }
 
1756
                if (scroll_skip_all) {
 
1757
                        matched_skip += match_str_list(nm, scroll_skip_all);
 
1758
                }
 
1759
                if (setby == SCR_KEY && scroll_skip_key) {
 
1760
                        matched_skip += match_str_list(nm, scroll_skip_key);
 
1761
                }
 
1762
                if (setby == SCR_MOUSE && scroll_skip_mouse) {
 
1763
                        matched_skip += match_str_list(nm, scroll_skip_mouse);
 
1764
                }
 
1765
 
 
1766
                if (!matched_good && matched_skip) {
 
1767
                        clast = None;
 
1768
                }
 
1769
        }
 
1770
        if (c != rootwin) {
 
1771
                /* cache results for possible use next call */
 
1772
                last_win = c;
 
1773
                last_result = clast;
 
1774
        }
 
1775
 
 
1776
        if (!clast || clast == rootwin) {
 
1777
if (db) fprintf(stderr, "--- xrecord_watch: SKIP.\n");
 
1778
                X_UNLOCK;
 
1779
                SCR_UNLOCK;
 
1780
                return;
 
1781
        }
 
1782
 
 
1783
        /* set protocol request ranges: */
 
1784
        rr_scroll[0] = rr_CA;
 
1785
        rr_scroll[1] = rr_CW;
 
1786
 
 
1787
        /*
 
1788
         * start trapping... there still are some occasional failures
 
1789
         * not yet understood, likely some race condition WRT the 
 
1790
         * context being setup.
 
1791
         */
 
1792
        trapped_record_xerror = 0;
 
1793
        old_handler = XSetErrorHandler(trap_record_xerror);
 
1794
 
 
1795
        if (! rc_scroll) {
 
1796
                /* do_shutdown case or first time in */
 
1797
 
 
1798
                if (gdpy_ctrl) {
 
1799
                        /*
 
1800
                         * Even though rdpy_ctrl is impervious to grabs
 
1801
                         * at this point, we still get deadlock, why?
 
1802
                         * It blocks in the library find_display() call.
 
1803
                         */
 
1804
                        check_xrecord_grabserver();
 
1805
                        if (xserver_grabbed) {
 
1806
                                XSetErrorHandler(old_handler);
 
1807
                                X_UNLOCK;
 
1808
                                SCR_UNLOCK;
 
1809
                                return;
 
1810
                        }
 
1811
                }
 
1812
                rcs_scroll = (XRecordClientSpec) clast;
 
1813
                rc_scroll = XRecordCreateContext(rdpy_ctrl, 0, &rcs_scroll, 1,
 
1814
                    rr_scroll, 2);
 
1815
 
 
1816
                if (! do_shutdown) {
 
1817
                        XSync(rdpy_ctrl, False);
 
1818
                }
 
1819
if (db) fprintf(stderr, "NEW rc:    0x%lx\n", rc_scroll);
 
1820
                if (rc_scroll) {
 
1821
                        dtime0(&create_time);
 
1822
                } else {
 
1823
                        rcs_scroll = 0;
 
1824
                }
 
1825
 
 
1826
        } else if (! do_shutdown) {
 
1827
                if (rcs_scroll) {
 
1828
                        /*
 
1829
                         * should have been unregistered in xrecord_watch(0)...
 
1830
                         */
 
1831
                        rcs_scroll = XRecordCurrentClients;
 
1832
                        XRecordUnregisterClients(rdpy_ctrl, rc_scroll,
 
1833
                            &rcs_scroll, 1);
 
1834
 
 
1835
if (db > 1) fprintf(stderr, "=2= unreg-scroll 0x%lx 0x%lx\n", rc_scroll, rcs_scroll);
 
1836
 
 
1837
                }
 
1838
                
 
1839
                rcs_scroll = (XRecordClientSpec) clast;
 
1840
 
 
1841
if (db > 1) fprintf(stderr, "=-=   reg-scroll 0x%lx 0x%lx\n", rc_scroll, rcs_scroll);
 
1842
 
 
1843
                if (!XRecordRegisterClients(rdpy_ctrl, rc_scroll, 0,
 
1844
                    &rcs_scroll, 1, rr_scroll, 2)) {
 
1845
                        if (1 || now > last_error + 60) {
 
1846
                                rfbLog("failed to register client 0x%lx with"
 
1847
                                    " X RECORD context rc_scroll.\n", clast);
 
1848
                        }
 
1849
                        last_error = now;
 
1850
                        rcs_scroll = 0;
 
1851
                        /* continue on for now... */
 
1852
                }
 
1853
        }
 
1854
 
 
1855
        XFlush_wr(rdpy_ctrl);
 
1856
 
 
1857
if (db) fprintf(stderr, "rc_scroll: 0x%lx\n", rc_scroll);
 
1858
        if (trapped_record_xerror) {
 
1859
                RECORD_ERROR_MSG;
 
1860
        }
 
1861
 
 
1862
        if (! rc_scroll) {
 
1863
                XSetErrorHandler(old_handler);
 
1864
                X_UNLOCK;
 
1865
                SCR_UNLOCK;
 
1866
                use_xrecord = 0;
 
1867
                rfbLog("failed to create X RECORD context rc_scroll.\n");
 
1868
                rfbLog("  switching to -noscrollcopyrect mode.\n");
 
1869
                return;
 
1870
        } else if (! rcs_scroll || trapped_record_xerror) {
 
1871
                /* try again later */
 
1872
                shutdown_record_context(rc_scroll, 0, reopen_dpys);
 
1873
                rc_scroll = 0;
 
1874
                last_error = now;
 
1875
 
 
1876
                XSetErrorHandler(old_handler);
 
1877
                X_UNLOCK;
 
1878
                SCR_UNLOCK;
 
1879
                return;
 
1880
        }
 
1881
 
 
1882
        xrecord_focus_window = focus;
 
1883
#if 0
 
1884
        /* xrecord_focus_window currently unused. */
 
1885
        if (! xrecord_focus_window) {
 
1886
                xrecord_focus_window = clast;
 
1887
        }
 
1888
#endif
 
1889
        xrecord_wm_window = wm;
 
1890
        if (! xrecord_wm_window) {
 
1891
                xrecord_wm_window = clast;
 
1892
        }
 
1893
 
 
1894
        xrecord_ptr_window = clast;
 
1895
 
 
1896
        xrecording = 1;
 
1897
        xrecord_seq++;
 
1898
        dtime0(&xrecord_start);
 
1899
 
 
1900
        rc = XRecordEnableContextAsync(rdpy_data, rc_scroll, record_switch,
 
1901
            (XPointer) xrecord_seq);
 
1902
 
 
1903
        if (!rc || trapped_record_xerror) {
 
1904
                if (1 || now > last_error + 60) {
 
1905
                        rfbLog("failed to enable RECORD context "
 
1906
                            "rc_scroll: 0x%lx rc: %d\n", rc_scroll, rc);
 
1907
                        if (trapped_record_xerror) {
 
1908
                                RECORD_ERROR_MSG;
 
1909
                        }
 
1910
                }
 
1911
                shutdown_record_context(rc_scroll, 0, reopen_dpys);
 
1912
                rc_scroll = 0;
 
1913
                last_error = now;
 
1914
                xrecording = 0;
 
1915
                /* continue on for now... */
 
1916
        }
 
1917
        XSetErrorHandler(old_handler);
 
1918
 
 
1919
        /* XXX this may cause more problems than it solves... */
 
1920
        if (use_xrecord) {
 
1921
                XFlush_wr(rdpy_data);
 
1922
        }
 
1923
 
 
1924
        X_UNLOCK;
 
1925
        SCR_UNLOCK;
 
1926
#endif
 
1927
}
 
1928
 
 
1929