chiark / gitweb /
before rip out timing stuff and use just minimum snapshot delay
[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 void check_pclose(FILE *f, char *cmd) {
22   int r;
23   eassert(!ferror(f));
24   r= fgetc(f);  eassert(r==EOF);  eassert(feof(f));
25   r= pclose(f);  eassert(r>=0);  eassert(WIFEXITED(r) && !WEXITSTATUS(r));
26   free(cmd);
27 }
28
29 #if 0
30 static CanonImage *screenshot_now(void) {
31   char *cmd;
32   CanonImage *ci;
33   int r;
34   
35   r= asprintf(&cmd, "xwd -silent -id 0x%lx | xwdtopnm", (unsigned long)id);
36   eassert(r>=0);
37   FILE *f= popen(cmd,"r");  eassert(f);
38   ci= file_read_image(f);
39   check_pclose(f, cmd);
40   return ci;
41 }
42 #endif
43
44 static void screenshot_startup(void) {
45   int r;
46   disp= XOpenDisplay(0);  eassert(disp);
47   r= gettimeofday(&tv_startup,0);  eassert(!r);
48 }
49
50 #if 0
51 static CanonImage *single_page(void) {
52   int r;
53   r= XRaiseWindow(disp, id);  eassert(r);
54   r= XSync(disp, False);  eassert(r);
55   return screenshot_now();
56 }
57 #endif
58
59 static void raise_and_set_focus(void) {
60   int r;
61   XWindowAttributes attr;
62   int xpos,ypos, evbase,errbase,majver,minver;
63   unsigned width,height,bd,depth;
64   Window dummy;
65   
66   fprintf(stderr,"PAGING raise_and_set_focus\n");
67
68   r= XTestQueryExtension(disp, &evbase,&errbase,&majver,&minver);
69   eassert(r==True);
70
71   r= XRaiseWindow(disp, id);  eassert(r);
72
73   r= XGetWindowAttributes(disp, id, &attr);  eassert(r);
74   r= XGetGeometry(disp,id, &attr.root,&xpos,&ypos,&width,&height, &bd,&depth);
75   eassert(r);
76
77   r= XTranslateCoordinates(disp, id,attr.root, 160,160, &xpos,&ypos,
78                            &dummy);
79   eassert(r);
80
81   int screen= XScreenNumberOfScreen(attr.screen);
82   XTestFakeMotionEvent(disp,screen, xpos, ypos, 0);
83
84   XTestFakeButtonEvent(disp,1,1, 50);
85   XTestFakeButtonEvent(disp,1,0, 50);
86   r= XSync(disp, False);  eassert(r);
87
88   fprintf(stderr,"PAGING raise_and_set_focus done.\n");
89 }
90
91 /*---------- pager ----------*/
92
93 typedef struct {
94   size_t len;
95   unsigned char d[];
96 } Snapshot;
97
98 static void send_key(KeySym sym) {
99   int r;
100   XTestFakeKeyEvent(disp, keycode(sym),1, 10);
101   XTestFakeKeyEvent(disp, keycode(sym),0, 10);
102   r= XSync(disp, False);  eassert(r);
103 }
104
105 static void send_pgup_many(void) {
106   int i;
107   fprintf(stderr,"PAGING   PageUp\n");
108   for (i=0; i<25; i++)
109     send_key(XK_Prior);
110 }
111 static void send_pgdown(void) {
112   fprintf(stderr,"PAGING   PageDown\n");
113   send_key(XK_Next);
114 }
115
116 static double timestamp(void) {
117   struct timeval tv;
118   int r;
119   
120   r= gettimeofday(&tv,0);  eassert(!r);
121   double t= (tv.tv_sec - tv_startup.tv_sec) +
122             (tv.tv_usec - tv_startup.tv_usec) * 1e-6;
123   fprintf(stderr,"%f\n",t);
124   return t;
125 }
126
127 static double worst_snapshot= 0.050;
128 static double worst_stabilise= 0.100;
129 static size_t snapshot_alloc= 1024;
130
131 static void snapshot(Snapshot **output) {
132   char *cmd;
133   int r;
134   
135   free(*output);  *output=0;
136   double a= timestamp();
137
138   fprintf(stderr,"PAGING   snapshot\n");
139
140   r= asprintf(&cmd, "xwd -silent -id 0x%lx", (unsigned long)id); eassert(r>=0);
141   FILE *f= popen(cmd,"r"); eassert(f);
142
143   int need_alloc=1;
144   size_t used=0;
145   for (;;) {
146     size_t allow= snapshot_alloc - used;
147     if (!allow) {
148       snapshot_alloc <<= 1;
149       need_alloc= 1;
150       fprintf(stderr,"PAGING   snapshot   grow %ld\n", (long)snapshot_alloc);
151       continue;
152     }
153     if (need_alloc) {
154       *output= realloc(*output, sizeof(**output) + snapshot_alloc);
155       eassert(*output);
156       need_alloc= 0;
157     }
158     size_t got= fread((*output)->d, 1, allow, f);
159     if (got==0) break;
160     used += got;
161   }
162   check_pclose(f,cmd);
163
164   (*output)->len= used;
165   snapshot_alloc= used+1;
166   *output= realloc(*output, sizeof(**output) + snapshot_alloc);
167   eassert(*output);
168   
169   double b= timestamp();
170   double it_took= b-a;
171   if (it_took > worst_snapshot)
172     worst_snapshot= it_took;
173
174   fprintf(stderr,"PAGING   snapshot took=%f len=%ld\n",
175           it_took, (long)used);
176 }
177
178 static void snapshot_idle(void) {
179   int r;
180   r= usleep(worst_snapshot * 1e6 * 0.5);
181   /* spend no more than 2/3 of our time constantly snapshotting */
182   eassert(!r);
183 }
184
185 static int identical(const Snapshot *a, const Snapshot *b) {
186   return !(memcmp(a,    b,    sizeof(*a)) ||
187            memcmp(a->d, b->d, a->len));
188 }
189
190 static void wait_for_stability(Snapshot **output,
191                                const Snapshot *previously,
192                                void (*with_keypress)(void)) {
193   Snapshot *last=0;
194   /* waits longer if we're going to return an image identical to previously
195    * if previously==0, all images are considered identical to it */
196
197   double when_started= timestamp();
198   double last_change= when_started;
199   double it_took= -1;
200
201   fprintf(stderr,"PAGING  wait_for_stability"
202           "  worst_snapshot=%f worst_stabilise=%f  previously=%p\n",
203           worst_snapshot, worst_stabilise, previously);
204
205   for (;;) {
206     double at_snapshot= timestamp();
207     snapshot(output);
208     double right_now= timestamp();
209
210     if (!last) {
211       fprintf(stderr,"PAGING  wait_for_stability first...\n");
212       last_change= when_started= right_now;
213       last=*output; *output=0;
214     } else if (!identical(*output,last)) {
215       fprintf(stderr,"PAGING  wait_for_stability changed...\n");
216       last_change= right_now;
217       free(last); last=*output; *output=0;
218       it_took= -1;
219     } else {
220       if (it_took<0)
221         it_took= at_snapshot - when_started;
222
223       double threshold= worst_stabilise + worst_snapshot;
224       if (!previously || identical(*output,previously))
225         threshold *= 2;  threshold += 1.5;
226
227       double stable_for= right_now - last_change;
228       fprintf(stderr,"PAGING  wait_for_stability"
229               "  worst_snapshot=%f worst_stabilise=%f"
230               "  it_took=%f stable_for=%f threshold=%f...\n",
231               worst_snapshot, worst_stabilise,
232               it_took, stable_for, threshold);
233       
234       if (stable_for > threshold)
235         break;
236     }
237     if (with_keypress)
238       with_keypress();
239     snapshot_idle();
240   }
241
242   if (!with_keypress && it_took > worst_stabilise)
243     worst_stabilise= it_took;
244
245   free(last);
246   fprintf(stderr,"PAGING  wait_for_stability done.\n");
247 }
248
249 static void read_pages(void) {
250   Snapshot *current=0, *last=0;
251
252   raise_and_set_focus();
253
254   /* page to the top - keep pressing page up until the image stops changing */
255   wait_for_stability(&last,0, send_pgup_many);
256
257   /* now to actually page down */
258   for (;;) {
259     fprintf(stderr,"PAGING page %d\n",npages);
260     //eassert(npages < MAX_PAGES);
261     //page_images[npages++]=
262     npages++;
263
264     wait_for_stability(&current,last, 0);
265     if (npages &&  /* first pagedown doesn't do much */
266         identical(current,last)) {
267       free(current);
268       break;
269     }
270
271     free(last); last=current; current=0;
272
273     send_pgdown();
274   }
275   fprintf(stderr,"PAGING all done.\n");
276 }    
277
278 int main(int argc, char **argv) {
279   screenshot_startup();
280
281   id= strtoul(*++argv,0,0);
282
283   read_pages();
284   return 0;
285 }
286