7 #include <X11/extensions/XTest.h>
8 #include <X11/keysym.h>
10 CanonImage *page_images[MAX_PAGES];
15 static struct timeval tv_startup;
17 static KeyCode keycode(KeySym sym) {
18 return XKeysymToKeycode(disp,sym);
21 static CanonImage *screenshot_now(void) {
26 r= asprintf(&cmd, "xwd -silent -id 0x%lx | xwdtopnm", (unsigned long)id);
28 FILE *f= popen(cmd,"r"); eassert(f);
29 ci= file_read_image(f);
30 r= fgetc(f); eassert(r==EOF); eassert(feof(f));
31 r= pclose(f); eassert(r>=0); eassert(WIFEXITED(r) && !WEXITSTATUS(r));
36 static void screenshot_startup(void) {
38 disp= XOpenDisplay(0); eassert(disp);
39 r= gettimeofday(&tv_startup,0); eassert(!r);
43 static CanonImage *single_page(void) {
45 r= XRaiseWindow(disp, id); eassert(r);
46 r= XSync(disp, False); eassert(r);
47 return screenshot_now();
51 static void raise_and_set_focus(void) {
53 XWindowAttributes attr;
54 int xpos,ypos, evbase,errbase,majver,minver;
55 unsigned width,height,bd,depth;
58 fprintf(stderr,"PAGING raise_and_set_focus\n");
60 r= XTestQueryExtension(disp, &evbase,&errbase,&majver,&minver);
63 r= XRaiseWindow(disp, id); eassert(r);
65 r= XGetWindowAttributes(disp, id, &attr); eassert(r);
66 r= XGetGeometry(disp,id, &attr.root,&xpos,&ypos,&width,&height, &bd,&depth);
69 r= XTranslateCoordinates(disp, id,attr.root, 160,160, &xpos,&ypos,
73 int screen= XScreenNumberOfScreen(attr.screen);
74 XTestFakeMotionEvent(disp,screen, xpos, ypos, 0);
76 XTestFakeButtonEvent(disp,1,1, 50);
77 XTestFakeButtonEvent(disp,1,0, 50);
78 r= XSync(disp, False); eassert(r);
80 fprintf(stderr,"PAGING raise_and_set_focus done.\n");
83 static void send_key(KeySym sym) {
85 XTestFakeKeyEvent(disp, keycode(sym),1, 10);
86 XTestFakeKeyEvent(disp, keycode(sym),0, 10);
87 r= XSync(disp, False); eassert(r);
90 static void send_pgup(void) {
91 fprintf(stderr,"PAGING PageUp\n");
94 static void send_pgdown(void) {
95 fprintf(stderr,"PAGING PageDown\n");
99 static double timestamp(void) {
103 r= gettimeofday(&tv,0); eassert(!r);
104 return (tv.tv_sec - tv_startup.tv_sec) +
105 (tv.tv_usec - tv_startup.tv_usec) * 1e-6;
108 static double worst_snapshot= 0.050, worst_stabilise= 0.100;
110 static void snapshot(CanonImage **output) {
112 double a= timestamp();
113 *output= screenshot_now();
114 fprintf(stderr,"PAGING snapshot\n");
115 double b= timestamp();
117 fprintf(stderr,"PAGING snapshot took=%f\n",it_took);
118 if (it_took > worst_snapshot)
119 worst_snapshot= it_took;
122 static void snapshot_idle(void) {
124 r= usleep(worst_snapshot * 1e6 * 2);
125 /* spend no more than 1/3 of our time constantly snapshotting */
129 static int identical(const CanonImage *a, const CanonImage *b) {
130 return !(memcmp(a, b, sizeof(*a)) ||
131 memcmp(a->d, b->d, a->w * a->h));
134 static void wait_for_stability(CanonImage **output,
135 const CanonImage *previously,
136 void (*with_keypress)(void)) {
138 /* waits longer if we're going to return an image identical to previously
139 * if previously==0, all images are considered identical to it */
141 double when_started= timestamp();
142 double last_change= when_started;
145 fprintf(stderr,"PAGING wait_for_stability"
146 " worst_snapshot=%f worst_stabilise=%f\n",
147 worst_snapshot, worst_stabilise);
151 double right_now= timestamp();
153 if (!last || !identical(*output,last)) {
154 fprintf(stderr,"PAGING wait_for_stability changed...\n");
155 last_change= right_now;
156 free(last); last=*output; *output=0;
160 it_took= right_now - when_started;
162 double threshold= (worst_stabilise + worst_snapshot) * 3;
163 if (!previously || identical(*output,previously))
164 threshold *= 2; threshold += 1.5;
166 double stable_for= right_now - last_change;
167 fprintf(stderr,"PAGING wait_for_stability"
168 " worst_snapshot=%f worst_stabilise=%f"
169 " stable for %f thresh %f...\n",
170 worst_snapshot, worst_stabilise,
171 stable_for, threshold);
173 if (stable_for > threshold)
181 if (it_took > worst_stabilise)
182 worst_stabilise= it_took;
185 fprintf(stderr,"PAGING wait_for_stability done.\n");
188 static void read_pages(void) {
189 CanonImage *current=0, *last;
191 raise_and_set_focus();
193 /* page to the top - keep pressing page up until the image stops changing */
194 wait_for_stability(¤t,0, send_pgup);
196 /* now to actually page down */
198 fprintf(stderr,"PAGING page %d\n",npages);
199 eassert(npages < MAX_PAGES);
200 page_images[npages++]= last= current;
202 wait_for_stability(¤t,last, 0);
203 if (npages && /* first pagedown doesn't do much */
204 identical(current,last)) {
209 fprintf(stderr,"PAGING all done.\n");
212 int main(int argc, char **argv) {
213 screenshot_startup();
215 id= strtoul(*++argv,0,0);