"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "xlab-0.8.3/record.c" of archive xlab-0.8.3.tar.gz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 /*
2 * $Id: record.c,v 1.8 1998/07/24 11:59:16 marc Exp $
3 *
4 * Code to record / play back X events in script
5 *
6 * (c) Copyright 1996, 1997, 1998 Marc Vertes
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <X11/Xlib.h>
12 #include <X11/Xutil.h>
13 #include <X11/keysym.h>
14 #include "scope.h"
15 #include "server.h"
16 #include "record.h"
17 #include "x11.h"
18
19 extern Display *Dpy;
20
21 static char script_line[256]; /* stored script line */
22
23 struct WinTab wintab[MAXWTAB];
24 struct WinAlias winalias[MAXWTAB];
25
26 long maxalias = 0;
27 long maxwtab = 0;
28 int replay_counter = 0;
29 int first_replay = 1;
30 int first_event_in_replay = 0;
31
32 int xRootPointer, yRootPointer; /* coordinates of pointer in the root window */
33 void (*Resource_Handler)() = 0; /* handler to call */
34 void *Resource_userdata = 0; /* user data to pass */
35 XID Resource_resource = 0;
36 TimerID Resource_timeout = 0; /* timeout when resource doesn't appear */
37 int Resource_index = 0; /* resource index within fd */
38 FD Resource_fd = 0; /* resource file descriptor */
39
40 /* Synthetic X event rebuild from script */
41 struct Synth_ev {
42 Window win;
43 Window subw;
44 Window rootw;
45 Time time;
46 FD fd;
47 unsigned short type; /* Event type in binary form */
48 short state;
49 short detail;
50 short same;
51 short x, y;
52 short rootx, rooty;
53 unsigned short seq;
54 unsigned char evbuf[32];
55 } synth_ev;
56
57 #define TheRootWindow wintab[0].newpar
58
59 /*--------------------------------------------------------------*/
60 int start_record(filename)
61 char *filename;
62 {
63 if (Playback != PLAYBACK_INACTIVE && Playback != PLAYBACK_COMPLETE) {
64 fprintf(stderr, "Cannot record and play back in same session.\n");
65 return (1);
66 }
67 strcpy(RecordFileName, filename);
68 RecordFile = fopen(RecordFileName, "w");
69 if (RecordFile == 0) {
70 perror(RecordFileName);
71 return (1);
72 }
73 fclose(RecordFile);
74 RecordFile = 0;
75 Record = 1;
76 return (0);
77 }
78
79 /*--------------------------------------------------------------*/
80 void stop_record()
81 {
82 CloseFile(RecordFile);
83 fclose(RecordFile);
84 Record = 0;
85 first_replay = 0;
86 }
87
88 /*--------------------------------------------------------------*/
89 static FILE *OpenFile(name, priv)
90 char *name;
91 char *priv;
92 {
93 register FILE *file;
94 register int fid;
95
96 /* open file */
97 file = fopen(name, priv);
98
99 /* deal with failure. snarky messages are OK, we've pretested files */
100 if (file == 0) {
101 panic("OpenFile failure.\n");
102 }
103 /*
104 * set up file descriptor in this program's table.
105 * Seems to be necessary at least for SUN Solaris.
106 */
107 fid = fileno(file);
108 UsingFD(fid, 0);
109 return file;
110
111 }
112
113 /*--------------------------------------------------------------*/
114 void CloseFile(file)
115 FILE *file;
116 {
117 int fid = fileno(file);
118 NotUsingFD(fid);
119 }
120
121 /*--------------------------------------------------------------*/
122 /*
123 * TimeDilation expresses the time dilation in percent.
124 * if TimeDilation = 200, then we want the thing to play back
125 * twice as fast, so we want to cut all times in half.
126 */
127 unsigned long int Dilate(deltat)
128 unsigned long int deltat;
129 {
130 unsigned long int result;
131 result = deltat;
132 result = ((deltat * 100) + ((TimeDilation / 2) - 1)) / TimeDilation;
133 return result;
134 }
135
136 /*--------------------------------------------------------------*/
137 static long int NextScriptEvent(buf, n)
138 char *buf;
139 long int n;
140 {
141 /*
142 * This function reads the next script event
143 * and returns it in a buffer.
144 */
145 char *result;
146 int goodline = 0;
147 int event;
148
149 /* open up the recording file if necessary, first time through */
150 if (PlaybackFile == 0) {
151 PlaybackFile = OpenFile(PlaybackFileName, "r");
152 Playback = PLAYBACK_ACTIVE;
153 first_event_in_replay = 1;
154 }
155 /* skip blanks and comments */
156 while (goodline == 0) {
157 buf[0] = '\0';
158 result = fgets(buf, n, PlaybackFile);
159 if (result == 0)
160 return -1;
161
162 /* skip comment-type lines */
163 if (buf[0] != '\0') {
164 event = ascii_to_event_type(buf);
165 if (event != 0) {
166 goodline = 1;
167 }
168 }
169 }
170 return strlen(buf);
171 }
172
173 /*--------------------------------------------------------------*/
174 /*
175 * this timer function is called when
176 * the wait for a window to become mapped
177 * runs out...
178 * It issues a warning message, then proceeds as
179 * if the window had, in fact, appeared.
180 *
181 * Under some failure conditions, this causes an
182 * error cascade.
183 */
184 static void ResourceNeverAppeared(timer, window)
185 TimerID timer;
186 XID window;
187 {
188 if (window != TheRootWindow) {
189 fprintf(stderr, "Playback failure\n");
190 fprintf(stderr, " Timed out waiting for window %8.8x ( %8.8x )\n", (unsigned int) window,
191 OriginalWid(window));
192 fprintf(stderr, " %s\n", script_line);
193 Errorcount++;
194 }
195 /* call the wait handler, attempting to carry on with the run */
196
197 if (Resource_Handler)
198 (*Resource_Handler) (Resource_resource, Resource_userdata);
199
200 /* clear off the waiting flag in the resource status map */
201 if (Resource_index < MAXRESOURCESTATUS) {
202 CS[Resource_fd].ResourceStatus[Resource_index] &= ~RES_Waiting;
203 }
204 /* Restore the resource-wait information to initial state */
205 Resource_Handler = 0;
206 Resource_userdata = 0;
207 Resource_resource = 0;
208 Resource_timeout = 0;
209 Resource_index = 0;
210 Resource_fd = 0;
211 }
212
213 /*--------------------------------------------------------------*/
214 /* get the FD to which this window 'belongs' */
215 int GetResourceBaseFd(resource)
216 XID resource;
217 {
218 long ifd;
219 unsigned long int c_res_base;
220
221 for (ifd = 1; ifd <= HighestFD; ifd++) {
222 c_res_base = resource & ~CS[ifd].ResourceIdMask;
223 if (FDD[ifd].Busy) {
224 if (c_res_base == CS[ifd].ResourceIdBase)
225 return ifd;
226 } else {
227 if (c_res_base == CS[ifd].ResourceIdBase) {
228 fprintf(stderr,
229 "Playback Error. fd %ld for resource %x (%x) is not valid anymore\n",
230 ifd, (unsigned int) resource, OriginalWid(resource));
231 return 0;
232 }
233 }
234 }
235 /* maybe an external window */
236 if ((resource != TheRootWindow) && (OriginalWid(resource) != 0))
237 fprintf(stderr, "Playback Error. Couldn't find an fd for resource %x (%x)\n",
238 (unsigned int) resource, OriginalWid(resource));
239 return(0);
240 }
241
242 /*-------------------------------------------------------------*/
243 /*
244 * this function can be called when somebody
245 * wants to wait for a window to appear.
246 */
247 void WaitForWindowMapped(fd, resource, handler, user_data)
248 int fd;
249 XID resource;
250 void (*handler) ();
251 void *user_data;
252
253 {
254 int ifd;
255 int res_index = resource & CS[fd].ResourceIdMask;
256
257
258 if (Resource_Handler)
259 panic("already waiting for a resource....only one allowed!");
260
261 if (res_index >= MAXRESOURCESTATUS) {
262 warn("res_index beyond MAXRESOURCESTATUS in WaitForWindowMapped.");
263 /* beyond the resource count; just assume it's available */
264 if (handler)
265 (*handler) (resource, user_data);
266 return;
267 }
268 /* No check for first EnterNotify event */
269 if (first_event_in_replay && synth_ev.type == EnterNotify) {
270 first_event_in_replay = 0;
271 if (handler)
272 (*handler) (resource, user_data);
273 return;
274 }
275 ifd = GetResourceBaseFd(resource);
276
277 /*
278 * a completeness test
279 */
280 if (resource != TheRootWindow) { /** 'res_unmapped' **/
281 if (ifd == 0 && OriginalWid(resource) != 0) {
282 fprintf(stderr, "Playback Error. Contradiction ifd=0 resource %x (%x)\n",
283 (unsigned int) resource, OriginalWid(resource));
284 ReadPlaybackEvent(20L, fd);
285 return;
286 }
287 if ((ifd != 0) && OriginalWid(resource) == 0) {
288 fprintf(stderr,
289 "Playback Error.Probably window destroyed. ifd = %d resource %x (0)\n",
290 ifd, (unsigned int) resource);
291 CS[ifd].ResourceStatus[res_index] = 0;
292 ReadPlaybackEvent(20L, fd);
293 return;
294 }
295 }
296 /*
297 * if the window is mapped or its is an external window
298 */
299 if ((ifd == 0) || CS[fd].ResourceStatus[res_index] == RES_Mapped ||
300 CS[ifd].ResourceStatus[res_index] == RES_Mapped) {
301 (*handler) (resource, user_data);
302 return;
303 }
304 CS[ifd].ResourceStatus[res_index] |= RES_Waiting;
305 Resource_Handler = handler;
306 Resource_userdata = user_data;
307 Resource_resource = resource;
308 Resource_timeout = CreateTimer(2000, (void (*)()) ResourceNeverAppeared, (void *) resource);
309 Resource_index = res_index;
310 Resource_fd = ifd;
311 debug(4, (stderr, "WAIT FOR %7x FD = %d IFD = %d\n", (unsigned int) resource, fd, ifd));
312 }
313
314 /*-------------------------------------------------------------*/
315 /* debugging aid */
316 char *getstat(status)
317 int status;
318 {
319
320 switch (status) {
321 case 0:
322 return "Unseen";
323 case 1:
324 return "Seen";
325 case 2:
326 return "Mapped";
327 case 3:
328 return "Unmapped";
329 case 128:
330 return "Wait";
331 case 129:
332 return "Wait&Seen";
333 case 130:
334 return "Wait&Mapped";
335 case 131:
336 return "Wait&Unmapp";
337 default:
338 return "illegal status";
339 }
340 }
341
342 /*-------------------------------------------------------------*/
343 /*
344 * this routine gets called from the event formatters
345 * in decode11.c
346 * it is used to maintain event status.
347 */
348 void WindowStatusAnnounce(fd, buf, n, status)
349 FD fd;
350 unsigned char *buf;
351 int n;
352 ResStatus status;
353 {
354 XID resource = ILong(&buf[n]);
355 int res_index = resource & CS[fd].ResourceIdMask;
356 int waiting = 0;
357 ResStatus oldstatus;
358 int ifd, i;
359
360 enterprocedure("WindowStatusAnnounce");
361
362 ifd = GetResourceBaseFd(resource);
363
364 if ((resource == 0) || (ifd == 0))
365 return;
366
367 debug(4, (stderr,
368 "curwin=%7x resindx = %3d waitwin=%7x FD = %d IFD = %d \n",
369 (unsigned int) resource, res_index, (unsigned int) Resource_resource, fd, ifd));
370
371 debug(4, (stderr,
372 " enstat = %10s oldstat = %10s nwstat = ",
373 getstat(status),
374 getstat(CS[ifd].ResourceStatus[res_index])));
375
376 if (res_index < MAXRESOURCESTATUS) {
377 oldstatus = CS[ifd].ResourceStatus[res_index];
378 if (oldstatus & RES_Waiting)
379 waiting = 1;
380 CS[ifd].ResourceStatus[res_index] = status | (oldstatus & RES_Waiting);
381 }
382 /* if we were waiting for the resource and it is now mapped ... */
383 if (resource == Resource_resource) {
384 if (waiting & (status == RES_Mapped)) {
385 /* blast the wait timeout */
386 if (Resource_timeout)
387 DeleteTimer(Resource_timeout);
388
389 /* call the resource handler, if any */
390 if (Resource_Handler)
391 (*Resource_Handler) (Resource_resource, Resource_userdata);
392
393 /* zap the waiting bit in the resource map */
394 if (Resource_index < MAXRESOURCESTATUS) {
395 CS[Resource_fd].ResourceStatus[Resource_index] &= ~RES_Waiting;
396 }
397 /* Restore the resource-wait information to initial state */
398 Resource_Handler = 0;
399 Resource_userdata = 0;
400 Resource_resource = 0;
401 Resource_timeout = 0;
402 Resource_index = 0;
403 Resource_fd = 0;
404 }
405 }
406 if (status == RES_Mapped) {
407 CS[ifd].ResourceStatus[res_index] |= RES_Mapped;
408
409 /* indicate that the children of this window are also mapped */
410 for (i = 0; i < maxwtab; i++) {
411 if (wintab[i].newpar == resource) {
412 int ifdchild;
413 int res_indexchild;
414
415 ifdchild = GetResourceBaseFd(wintab[i].newid);
416 res_indexchild = wintab[i].newid & CS[ifdchild].ResourceIdMask;
417
418 if (ifdchild) {
419 CS[ifdchild].ResourceStatus[res_indexchild] &= ~RES_Waiting;
420 CS[ifdchild].ResourceStatus[res_indexchild] |= RES_Mapped;
421 }
422 }
423 }
424 }
425 debug(4, (stderr, "%10s Wait = %1d\n", getstat(CS[ifd].ResourceStatus[res_index]), waiting));
426 return;
427 }
428
429 /*--------------------------------------------------------------*/
430 void AnnouncePlaybackError(dpy, erev)
431 Display *dpy;
432 XErrorEvent *erev;
433 {
434 if (synth_ev.type != EnterNotify) {
435 fprintf(stderr, "Playback failure\n");
436 fprintf(stderr, " Unable to move pointer into window %8.8x (%x)\n",
437 (unsigned int) erev->resourceid, OriginalWid(erev->resourceid));
438 fprintf(stderr, " %s\n", script_line);
439 Errorcount++;
440 }
441 }
442
443 /*--------------------------------------------------------------*/
444 void SendPlaybackEvent(timer, fd)
445 TimerID timer;
446 int fd;
447 {
448 struct timeval tv;
449 FD pairfd = FDPair(fd);
450 unsigned short int seq = 0;
451 Time timestamp, t;
452
453 /* obtain the sequence number from the client-side CS structure */
454 if (pairfd >= StaticMaxFD)
455 pairfd = -1;
456 if (pairfd >= 0)
457 seq = CS[pairfd].SequenceNumber;
458
459 /* compute timestamp based on previously noted time offset */
460 gettimeofday(&tv, 0);
461 t = tv.tv_sec * 1000;
462 t += tv.tv_usec / 1000;
463 timestamp = t + CS[fd].TimeOffset;
464
465 /* it's time to send the event to the program under test.. */
466 /* convert it to a wire-format event buffer */
467 OShort(&synth_ev.evbuf[2], seq);
468 OLong(&synth_ev.evbuf[4], timestamp);
469 OShort(&synth_ev.evbuf[20], xRootPointer);
470 OShort(&synth_ev.evbuf[22], yRootPointer);
471 ReplaceWid(synth_ev.evbuf, 12);
472 ReplaceWid(synth_ev.evbuf, 16);
473
474 WriteToClient(fd, synth_ev.evbuf, 32);
475
476 /* if Shift + Ctrl + Button 1, activate screen_capture */
477 if ((synth_ev.type == ButtonRelease) &&
478 (synth_ev.state & ShiftMask) &&
479 (synth_ev.state & ControlMask))
480 screen_capture();
481
482 /* read the next event from the script file */
483 ReadPlaybackEvent(timer, fd);
484 }
485
486 /*--------------------------------------------------------------*/
487 extern int whichGrab;
488 extern int status;
489
490 void WarpPlaybackEvent(session_window, fd)
491 Window session_window;
492 int fd;
493 {
494 /*
495 * This function decodes part of a stored script_line,
496 * and warps the server pointer to the selected
497 * position. It is called when the window is known to be mapped.
498 * This function ends by registering a callback to
499 * "SendPlaybackEvent" for 20 ms later.
500 */
501 Window saved_window;
502 static int first = 0;
503 /* more variables to query pointer */
504 Window root_return, child_return;
505 int win_x_return, win_y_return;
506 unsigned int mask_Return;
507
508 if (first == 0) {
509 (void) XSetErrorHandler((int (*)()) AnnouncePlaybackError);
510 first = 1;
511 }
512 saved_window = NewWid(synth_ev.win);
513
514 /* EnterNotify events always causes problems */
515 if (!(synth_ev.type == 7 &&
516 saved_window == TheRootWindow && synth_ev.subw == 0)) {
517
518 if (saved_window) {
519 XWarpPointer(Dpy, None, saved_window, 0, 0, 0, 0, synth_ev.x, synth_ev.y);
520
521 /*
522 * This code does not work in all cases where you 'drag a window'
523 * because the server or pointer is grabbed by another client
524 */
525 if (!((whichGrab == 4 /*server */ || whichGrab == 1 /*pntr */ ) && status == 1)) {
526 XSync(Dpy, False);
527 /*
528 * Get root_x and root_y for the pointer, to set event coord accordingly
529 */
530 XQueryPointer(Dpy, saved_window, &root_return, &child_return,
531 &xRootPointer, &yRootPointer, &win_x_return, &win_y_return, &mask_Return);
532 } else {
533 XFlush(Dpy);
534 if (saved_window == TheRootWindow) {
535 xRootPointer = synth_ev.x;
536 yRootPointer = synth_ev.y;
537 }
538 }
539 CreateTimer(20L, (void (*)()) SendPlaybackEvent, (void *) fd);
540 return;
541 }
542 }
543 ReadPlaybackEvent(20L, fd);
544 }
545
546
547 /*--------------------------------------------------------------*/
548 void TranslatePlaybackEvent(timer, fd)
549 TimerID timer;
550 int fd;
551 {
552 /*
553 * This function decodes part of a stored script_line,
554 * and waits for the named window to appear.
555 */
556 Window session_window = NewWid(synth_ev.win);
557
558 if (session_window == 0)
559 fprintf(stderr, "Error. session_window = 0 \n");
560 WaitForWindowMapped(fd, session_window, (void (*)()) WarpPlaybackEvent, (void *) fd);
561 }
562
563 /*--------------------------------------------------------------*/
564 void end_replay()
565 {
566 CloseFile(PlaybackFile);
567 warn("Playback completed");
568 Playback = PLAYBACK_COMPLETE;
569 replay_counter--;
570 if (replay_counter > 0) {
571 warn("Activate next playback event");
572 start_replay(PlaybackFileName);
573 }
574 }
575
576 /*--------------------------------------------------------------*/
577 void ReadPlaybackEvent(timer, fd)
578 TimerID timer;
579 int fd;
580 {
581 /*
582 * This function reads an event from the script file.
583 * It then establishes a timer call back to
584 * activate WarpPlaybackEvent at the appropriate time
585 * (based on the elapsed time specified in the script file.)
586 *
587 * If NextScriptEvent comes back = -1, it's the end of
588 * the script file; forget about further timer callbacks.
589 * However, don't stop the xscript pseudo-server, because
590 * it should stay running until client-under-test disconnect.
591 */
592 long int linelen = NextScriptEvent(script_line, 256);
593 unsigned long int delay, delay2;
594
595 if (linelen < 0) {
596 /*
597 * End of file ... wait 5 seconds to let application finish
598 * windows closing.
599 * Mark playback as complete
600 */
601 warn("Playback completion in 5s");
602 CreateTimer(5000, end_replay, (void *) 0);
603 } else {
604 /*
605 * Process next event from file.
606 */
607 if (ReadSynthEvent(script_line) == 1) {
608 ReadPlaybackEvent(20L, fd);
609 return;
610 }
611 delay = synth_ev.time;
612
613 switch (synth_ev.type) {
614 case ButtonPress:
615 /*
616 * to avoid fouling up double clicks,
617 * don't mess around with delay times before ButtonPress < 250 ms
618 */
619 if (delay < DoubleClickTime) {
620 /* delay is shorter than doubleclick time, don't touch it */
621 delay2 = delay;
622 } else {
623 /*
624 * Original delay is longer than doubleclick time,
625 * don't let recomputed delay end up shorter than doubleclick time
626 */
627 delay2 = Dilate(delay);
628 if (delay2 < DoubleClickTime)
629 delay2 = delay;
630 }
631 break;
632
633 default:
634 /*
635 * It's OK to compress other event delays more-or-less arbitrarily
636 */
637 delay2 = Dilate(delay);
638 break;
639 }
640
641 /* subtract delay time we'll use for waiting for motion */
642 if (delay2 > 20)
643 delay2 -= 20;
644 else
645 delay2 = 0;
646
647 if (delay2 < 5)
648 delay2 = 5;
649 debug(128, (stderr, "%ld=delay %s\n", delay2, script_line));
650 CreateTimer(delay2, (void (*)()) TranslatePlaybackEvent, (void *) synth_ev.fd);
651 }
652 }
653
654 /*--------------------------------------------------------------*/
655 int start_replay(filename)
656 char *filename;
657 {
658 if (Record) {
659 fprintf(stderr, "Cannot record and play back in same session.\n");
660 return (1);
661 }
662 if (Playback != PLAYBACK_INACTIVE && Playback != PLAYBACK_COMPLETE) {
663 fprintf(stderr, "Previous playback not yet completed.\n");
664 return (1);
665 }
666 strcpy(PlaybackFileName, filename);
667
668 /* ensure we can open playback file correctly */
669 PlaybackFile = fopen(PlaybackFileName, "r");
670 if (PlaybackFile == 0) {
671 perror(PlaybackFileName);
672 return (1);
673 }
674 fclose(PlaybackFile);
675 PlaybackFile = 0;
676 Playback = PLAYBACK_PENDING;
677
678 /* read playbackfile to to extract Windows info */
679 if (first_replay) {
680 LoadWtab("PlaybackFileName");
681 first_replay = 0;
682 } else {
683 CreateTimer(5000, (void (*)()) ReadPlaybackEvent, (void *) 0);
684 }
685 return (0);
686 }
687
688 /*--------------------------------------------------------------*/
689 void RecordEvent(fd, buf, n)
690 FD fd;
691 unsigned char *buf;
692 long n;
693 {
694 register short type = IByte(&buf[0]); /* event type */
695
696 if (RecordFile == 0) {
697 /* open up the recording file if necessary, first time through */
698 RecordFile = OpenFile(RecordFileName, "w");
699 }
700 /* high-order bit means SendEvent generated */
701 if (type & 0x80) {
702 type = type & 0x7F;
703 }
704 /*
705 * note that we can't cast stuff to
706 * the XEvent structure here, because
707 * the information is in a message buffer,
708 * not correctly unpacked and byteswapped.
709 */
710 switch (type) {
711 case ButtonPress:
712 case ButtonRelease:
713 case KeyPress:
714 case KeyRelease:
715 case MotionNotify:
716 case EnterNotify:
717 /* process the event */
718 event_to_ascii(fd, buf, RecordFile);
719 break;
720 default:
721 /*EMPTY *//* ignore the event */
722 break;
723 }
724 }
725
726 /*-------------------------------------------------------------*/
727 void RecordRequest(fd, buf, n)
728 FD fd;
729 unsigned char *buf;
730 long n;
731 {
732 register short request = IByte(&buf[0]); /* request type */
733 unsigned long wid = ILong(&buf[4]);
734
735 if (RecordFile == 0) {
736 /* open up the recording file if necessary, first time through */
737 RecordFile = OpenFile(RecordFileName, "w");
738 }
739 switch (request) {
740 case 1: /* CreateWindow */
741 if (!MatchCreateWinRec(buf))
742 req_to_ascii(fd, buf, RecordFile);
743 break;
744
745 case 4: /* DestroyWindow */
746 SetInferiorsDelflag(wid, 1);
747 SetDelflag(wid, 1);
748 break;
749
750 case 5: /* DestroySubWindows */
751 SetInferiorsDelflag(wid, 1);
752 break;
753 }
754 }
755
756 /*-------------------------------------------------------------*/
757 /*
758 *returns 1 if a window is found, 0 otherwise
759 */
760 int MatchCreateWinRec(buf)
761 unsigned char *buf;
762 {
763 unsigned long wid, parent, mask;
764 int depth, x, y, width, height;
765 long i;
766
767 depth = IByte(&buf[1]);
768 wid = ILong(&buf[4]);
769 parent = ILong(&buf[8]);
770 x = IShort(&buf[12]);
771 y = IShort(&buf[14]);
772 width = IShort(&buf[16]);
773 height = IShort(&buf[18]);
774 mask = ILong(&buf[28]);
775
776 for (i = 0; i < maxwtab; i++) {
777 if (parent == wintab[i].parent &&
778 depth == wintab[i].depth &&
779 mask == wintab[i].mask &&
780 x == wintab[i].x &&
781 y == wintab[i].y &&
782 width == wintab[i].width &&
783 height == wintab[i].height &&
784 wintab[i].delflag != 0) {
785 /*
786 * could match this window: means that a previously
787 * destroyed window has been created again.
788 * alias it to the original and reset the deleted flag
789 */
790 wintab[i].delflag = 0;
791 if (maxalias < MAXALIAS) {
792 winalias[maxalias].wid = wid;
793 winalias[maxalias].alias = wintab[i].wid;
794 maxalias++;
795 } else {
796 fprintf(stderr, "Max number of window aliases reached, increase MAXALIAS.\n");
797 }
798 return (1);
799 }
800 }
801 /*
802 * Couldn't match window, add it int the table.
803 * Set newid and newpart to current wid and parent,
804 * to match directly if we replay in the same session.
805 */
806 wintab[maxwtab].wid = wid;
807 wintab[maxwtab].newid = wid;
808 wintab[maxwtab].parent = parent;
809 wintab[maxwtab].newpar = parent;
810 wintab[maxwtab].depth = depth;
811 wintab[maxwtab].x = x;
812 wintab[maxwtab].y = y;
813 wintab[maxwtab].width = width;
814 wintab[maxwtab].height = height;
815 wintab[maxwtab].mask = mask;
816 maxwtab++;
817 return (0);
818 }
819
820 /*-------------------------------------------------------------*/
821 void LoadWtab(filename)
822 char *filename;
823 {
824 char line[256];
825 int lsize = 256;
826 unsigned int wid, parent, m;
827 int d, x, y, w, h;
828 char header[20];
829
830 PlaybackFile = fopen(PlaybackFileName, "r");
831
832 while (fgets(line, lsize, PlaybackFile) && maxwtab <= MAXWTAB) {
833 if (line[0] == 'X') {
834 if (9 != sscanf(line, "%s %x %x %x %d %d %d %d %x",
835 header, &wid, &parent, &d, &x, &y, &w, &h, &m))
836 warn("Error decoding in LoadWtab");
837
838 wintab[maxwtab].wid = wid;
839 wintab[maxwtab].parent = parent;
840 wintab[maxwtab].depth = d;
841 wintab[maxwtab].x = x;
842 wintab[maxwtab].y = y;
843 wintab[maxwtab].width = w;
844 wintab[maxwtab].height = h;
845 wintab[maxwtab].mask = m;
846 maxwtab++;
847 }
848 }
849 if (maxwtab == MAXWTAB) {
850 warn("LoadWtab: Number max of XCreateWindow reached, increase MAXWTAB");
851 }
852 fclose(PlaybackFile);
853 PlaybackFile = 0;
854 }
855
856 /*-------------------------------------------------------------*/
857 /* mainly a debugging aid. get the original window */
858 int OriginalWid(wid)
859 unsigned long wid;
860 {
861 long i;
862
863 for (i = 0; i < maxwtab; i++)
864 if (wintab[i].newid == wid)
865 return wintab[i].wid;
866 return 0;
867 }
868 /*-------------------------------------------------------------*/
869 int NewWid(wid)
870 unsigned long wid;
871 {
872 long i;
873
874 for (i = 0; i < maxwtab; i++)
875 if (wintab[i].wid == wid)
876 return(wintab[i].newid ? wintab[i].newid : wid);
877
878 if (wid != TheRootWindow) {
879 fprintf(stderr, "NewWid: Couldn't match Window id %lx\n", wid);
880 }
881 return wid;
882
883 }
884 /*-------------------------------------------------------------*/
885 void SetNewParent(old, new)
886 unsigned long old, new;
887 {
888 long i;
889
890 for (i = 0; i < maxwtab; i++)
891 if (wintab[i].parent == old)
892 wintab[i].newpar = new;
893 }
894
895 /*-------------------------------------------------------------*/
896 void SetNewid(old, new)
897 unsigned long old, new;
898 {
899 long i;
900
901 for (i = 0; i < maxwtab; i++)
902 if (wintab[i].newid == old)
903 wintab[i].newid = new;
904 }
905
906 /*-------------------------------------------------------------*/
907 unsigned long GetWinAlias(wid)
908 unsigned long wid;
909 {
910 long i;
911
912 for (i = 0; i < maxalias; i++)
913 if (winalias[i].wid == wid)
914 return (winalias[i].alias);
915
916 return (wid);
917 }
918
919 /*-------------------------------------------------------------*/
920 void SetInferiorsNewid(wid, new)
921 unsigned long wid, new;
922 {
923 long i;
924
925 for (i = 0; i < maxwtab; i++) {
926 if (wintab[i].newpar == wid) {
927 SetInferiorsNewid