chiark / gitweb /
"trusting" pager collector - do not confirm lack of motion, but do wait 0.5s each...
[ypp-sc-tools.db-live.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 /*---------- pager ----------*/
60
61 typedef struct {
62   size_t len;
63   unsigned char d[];
64 } Snapshot;
65
66 static size_t snapshot_alloc= 1024;
67 static double last_input;
68 static const double min_update_allowance= 0.5;
69
70 static double timestamp(void) {
71   struct timeval tv;
72   int r;
73   
74   r= gettimeofday(&tv,0);  eassert(!r);
75   double t= (tv.tv_sec - tv_startup.tv_sec) +
76             (tv.tv_usec - tv_startup.tv_usec) * 1e-6;
77   fprintf(stderr,"%f\n",t);
78   return t;
79 }
80 static void delay(double need_sleep) {
81   int r;
82   fprintf(stderr,"PAGING     delay %f\n",need_sleep);
83   r= usleep(need_sleep * 1e6);  eassert(!r);
84 }
85
86 static void sync_after_input(void) {
87   int r;
88   r= XSync(disp, False);  eassert(r);
89   last_input= timestamp();
90 }
91
92 static void send_key(KeySym sym) {
93   XTestFakeKeyEvent(disp, keycode(sym),1, 10);
94   XTestFakeKeyEvent(disp, keycode(sym),0, 10);
95 }
96
97 static void send_pgup_many(void) {
98   int i;
99   for (i=0; i<25; i++)
100     send_key(XK_Prior);
101   fprintf(stderr,"PAGING   PageUp x %d\n",i);
102   sync_after_input();
103 }
104 static void send_pgdown(void) {
105   send_key(XK_Next);
106   fprintf(stderr,"PAGING   PageDown\n");
107   sync_after_input();
108 }
109
110 static void snapshot(Snapshot **output) {
111   char *cmd;
112   int r;
113   
114   free(*output);  *output=0;
115
116   fprintf(stderr,"PAGING   snapshot\n");
117
118   r= asprintf(&cmd, "xwd -silent -id 0x%lx", (unsigned long)id); eassert(r>=0);
119   FILE *f= popen(cmd,"r"); eassert(f);
120
121   int need_alloc=1;
122   size_t used=0;
123   for (;;) {
124     size_t allow= snapshot_alloc - used;
125     if (!allow) {
126       snapshot_alloc <<= 1;
127       need_alloc= 1;
128       fprintf(stderr,"PAGING   snapshot   grow %ld\n", (long)snapshot_alloc);
129       continue;
130     }
131     if (need_alloc) {
132       *output= realloc(*output, sizeof(**output) + snapshot_alloc);
133       eassert(*output);
134       need_alloc= 0;
135     }
136     size_t got= fread((*output)->d, 1, allow, f);
137     if (got==0) break;
138     used += got;
139   }
140   check_pclose(f,cmd);
141
142   (*output)->len= used;
143   snapshot_alloc= used+1;
144   *output= realloc(*output, sizeof(**output) + snapshot_alloc);
145   eassert(*output);
146   
147   fprintf(stderr,"PAGING   snapshot len=%ld\n", (long)used);
148 }
149
150 static int identical(const Snapshot *a, const Snapshot *b) {
151   return !(memcmp(a,    b,    sizeof(*a)) ||
152            memcmp(a->d, b->d, a->len));
153 }
154
155 static void wait_for_stability(Snapshot **output,
156                                const Snapshot *previously,
157                                void (*with_keypress)(void)) {
158   Snapshot *last=0;
159   /* waits longer if we're going to return an image identical to previously
160    * if previously==0, all images are considered identical to it */
161
162   fprintf(stderr,"PAGING  wait_for_stability"
163           "  last_input=%f previously=%p\n",
164           last_input, previously);
165
166   for (;;) {
167     double at_snapshot= timestamp();
168     double need_sleep= min_update_allowance - (at_snapshot - last_input);
169     if (need_sleep > 0) { delay(need_sleep); continue; }
170
171     snapshot(output);
172
173     if (!with_keypress &&
174         !(previously && identical(*output,previously))) {
175       fprintf(stderr,"PAGING  wait_for_stability  simple\n");
176       break;
177     }
178
179     if (last && identical(*output,last)) {
180       fprintf(stderr,"PAGING  wait_for_stability  stabilised\n");
181       break;
182     }
183     
184     fprintf(stderr,"PAGING  wait_for_stability  retry\n");
185
186     free(last); last=*output; *output=0;
187
188     if (with_keypress)
189       with_keypress();
190
191     delay(0.5);
192   }
193
194   free(last);
195   fprintf(stderr,"PAGING  wait_for_stability done.\n");
196 }
197
198 static void raise_and_set_focus(void) {
199   int r;
200   XWindowAttributes attr;
201   int xpos,ypos, evbase,errbase,majver,minver;
202   unsigned width,height,bd,depth;
203   Window dummy;
204   
205   fprintf(stderr,"PAGING raise_and_set_focus\n");
206
207   r= XTestQueryExtension(disp, &evbase,&errbase,&majver,&minver);
208   eassert(r==True);
209
210   r= XRaiseWindow(disp, id);  eassert(r);
211
212   r= XGetWindowAttributes(disp, id, &attr);  eassert(r);
213   r= XGetGeometry(disp,id, &attr.root,&xpos,&ypos,&width,&height, &bd,&depth);
214   eassert(r);
215
216   r= XTranslateCoordinates(disp, id,attr.root, 160,160, &xpos,&ypos,
217                            &dummy);
218   eassert(r);
219
220   int screen= XScreenNumberOfScreen(attr.screen);
221   XTestFakeMotionEvent(disp,screen, xpos, ypos, 0);
222
223   XTestFakeButtonEvent(disp,1,1, 50);
224   XTestFakeButtonEvent(disp,1,0, 50);
225
226   sync_after_input();
227   fprintf(stderr,"PAGING raise_and_set_focus done.\n");
228 }
229
230
231
232 static void read_pages(void) {
233   Snapshot *current=0, *last=0;
234
235   raise_and_set_focus();
236
237   /* page to the top - keep pressing page up until the image stops changing */
238   wait_for_stability(&last,0, send_pgup_many);
239
240   /* now to actually page down */
241   for (;;) {
242     fprintf(stderr,"PAGING page %d\n",npages);
243     //eassert(npages < MAX_PAGES);
244     //page_images[npages++]=
245
246     wait_for_stability(&current,last, 0);
247     if (npages &&  /* first pagedown doesn't do much */
248         identical(current,last)) {
249       free(current);
250       break;
251     }
252
253     free(last); last=current; current=0;
254
255     send_pgdown();
256     npages++;
257   }
258   fprintf(stderr,"PAGING all done.\n");
259 }    
260
261 int main(int argc, char **argv) {
262   screenshot_startup();
263
264   id= strtoul(*++argv,0,0);
265
266   read_pages();
267   return 0;
268 }
269