chiark / gitweb /
66c3ad8d8c59f1f850e5dffea6b5df94ba873efd
[ypp-sc-tools.db-test.git] / pctb / pages.c
1 /*
2   */
3
4 #include "ocr.h"
5
6 #include <X11/Xlib.h>
7 #include <X11/extensions/XTest.h>
8 #include <X11/keysym.h>
9
10 CanonImage *page_images[MAX_PAGES];
11 int npages;
12
13 static Window id;
14 static Display *disp;
15 static struct timeval tv_startup;
16
17 static KeyCode keycode(KeySym sym) {
18   return XKeysymToKeycode(disp,sym);
19 }
20
21 static CanonImage *screenshot_now(void) {
22   char *cmd;
23   CanonImage *ci;
24   int r;
25   
26   r= asprintf(&cmd, "xwd -silent -id 0x%lx | xwdtopnm", (unsigned long)id);
27   eassert(r>=0);
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));
32   free(cmd);
33   return ci;
34 }
35
36 static void screenshot_startup(void) {
37   int r;
38   disp= XOpenDisplay(0);  eassert(disp);
39   r= gettimeofday(&tv_startup,0);  eassert(!r);
40 }
41
42 #if 0
43 static CanonImage *single_page(void) {
44   int r;
45   r= XRaiseWindow(disp, id);  eassert(r);
46   r= XSync(disp, False);  eassert(r);
47   return screenshot_now();
48 }
49 #endif
50
51 static void raise_and_set_focus(void) {
52   int r;
53   XWindowAttributes attr;
54   int xpos,ypos, evbase,errbase,majver,minver;
55   unsigned width,height,bd,depth;
56   Window dummy;
57   
58   fprintf(stderr,"PAGING raise_and_set_focus\n");
59
60   r= XTestQueryExtension(disp, &evbase,&errbase,&majver,&minver);
61   eassert(r==True);
62
63   r= XRaiseWindow(disp, id);  eassert(r);
64
65   r= XGetWindowAttributes(disp, id, &attr);  eassert(r);
66   r= XGetGeometry(disp,id, &attr.root,&xpos,&ypos,&width,&height, &bd,&depth);
67   eassert(r);
68
69   r= XTranslateCoordinates(disp, id,attr.root, 160,160, &xpos,&ypos,
70                            &dummy);
71   eassert(r);
72
73   int screen= XScreenNumberOfScreen(attr.screen);
74   XTestFakeMotionEvent(disp,screen, xpos, ypos, 0);
75
76   XTestFakeButtonEvent(disp,1,1, 50);
77   XTestFakeButtonEvent(disp,1,0, 50);
78   r= XSync(disp, False);  eassert(r);
79
80   fprintf(stderr,"PAGING raise_and_set_focus done.\n");
81 }
82
83 static void send_key(KeySym sym) {
84   int r;
85   XTestFakeKeyEvent(disp, keycode(sym),1, 10);
86   XTestFakeKeyEvent(disp, keycode(sym),0, 10);
87   r= XSync(disp, False);  eassert(r);
88 }
89
90 static void send_pgup(void) {
91   fprintf(stderr,"PAGING   PageUp\n");
92   send_key(XK_Prior);
93 }
94 static void send_pgdown(void) {
95   fprintf(stderr,"PAGING   PageDown\n");
96   send_key(XK_Next);
97 }
98
99 static double timestamp(void) {
100   struct timeval tv;
101   int r;
102   
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;
106 }
107
108 static double worst_snapshot= 0.050, worst_stabilise= 0.100;
109
110 static void snapshot(CanonImage **output) {
111   free(*output);
112   double a= timestamp();
113   *output= screenshot_now();
114   fprintf(stderr,"PAGING   snapshot\n");
115   double b= timestamp();
116   double it_took= b-a;
117   fprintf(stderr,"PAGING   snapshot took=%f\n",it_took);
118   if (it_took > worst_snapshot)
119     worst_snapshot= it_took;
120 }
121
122 static void snapshot_idle(void) {
123   int r;
124   r= usleep(worst_snapshot * 1e6 * 2);
125   /* spend no more than 1/3 of our time constantly snapshotting */
126   eassert(!r);
127 }
128
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));
132 }
133
134 static void wait_for_stability(CanonImage **output,
135                                const CanonImage *previously,
136                                void (*with_keypress)(void)) {
137   CanonImage *last=0;
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 */
140
141   double when_started= timestamp();
142   double last_change= when_started;
143   double it_took= -1;
144
145   fprintf(stderr,"PAGING  wait_for_stability"
146           "  worst_snapshot=%f worst_stabilise=%f\n",
147           worst_snapshot, worst_stabilise);
148
149   for (;;) {
150     snapshot(output);
151     double right_now= timestamp();
152
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;
157       it_took= -1;
158     } else {
159       if (it_took<0)
160         it_took= right_now - when_started;
161
162       double threshold= (worst_stabilise + worst_snapshot) * 3;
163       if (!previously || identical(*output,previously))
164         threshold *= 2;  threshold += 1.5;
165
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);
172       
173       if (stable_for > threshold)
174         break;
175     }
176     if (with_keypress)
177       with_keypress();
178     snapshot_idle();
179   }
180
181   if (it_took > worst_stabilise)
182     worst_stabilise= it_took;
183
184   free(last);
185   fprintf(stderr,"PAGING  wait_for_stability done.\n");
186 }
187
188 static void read_pages(void) {
189   CanonImage *current=0, *last;
190
191   raise_and_set_focus();
192
193   /* page to the top - keep pressing page up until the image stops changing */
194   wait_for_stability(&current,0, send_pgup);
195
196   /* now to actually page down */
197   for (;;) {
198     fprintf(stderr,"PAGING page %d\n",npages);
199     eassert(npages < MAX_PAGES);
200     page_images[npages++]= last= current;
201     send_pgdown();
202     wait_for_stability(&current,last, 0);
203     if (npages &&  /* first pagedown doesn't do much */
204         identical(current,last)) {
205       free(current);
206       break;
207     }
208   }
209   fprintf(stderr,"PAGING all done.\n");
210 }    
211
212 int main(int argc, char **argv) {
213   screenshot_startup();
214
215   id= strtoul(*++argv,0,0);
216
217   read_pages();
218   return 0;
219 }
220