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 void check_pclose(FILE *f, char *cmd) {
24 r= fgetc(f); eassert(r==EOF); eassert(feof(f));
25 r= pclose(f); eassert(r>=0); eassert(WIFEXITED(r) && !WEXITSTATUS(r));
30 static CanonImage *screenshot_now(void) {
35 r= asprintf(&cmd, "xwd -silent -id 0x%lx | xwdtopnm", (unsigned long)id);
37 FILE *f= popen(cmd,"r"); eassert(f);
38 ci= file_read_image(f);
44 static void screenshot_startup(void) {
46 disp= XOpenDisplay(0); eassert(disp);
47 r= gettimeofday(&tv_startup,0); eassert(!r);
51 static CanonImage *single_page(void) {
53 r= XRaiseWindow(disp, id); eassert(r);
54 r= XSync(disp, False); eassert(r);
55 return screenshot_now();
59 static void raise_and_set_focus(void) {
61 XWindowAttributes attr;
62 int xpos,ypos, evbase,errbase,majver,minver;
63 unsigned width,height,bd,depth;
66 fprintf(stderr,"PAGING raise_and_set_focus\n");
68 r= XTestQueryExtension(disp, &evbase,&errbase,&majver,&minver);
71 r= XRaiseWindow(disp, id); eassert(r);
73 r= XGetWindowAttributes(disp, id, &attr); eassert(r);
74 r= XGetGeometry(disp,id, &attr.root,&xpos,&ypos,&width,&height, &bd,&depth);
77 r= XTranslateCoordinates(disp, id,attr.root, 160,160, &xpos,&ypos,
81 int screen= XScreenNumberOfScreen(attr.screen);
82 XTestFakeMotionEvent(disp,screen, xpos, ypos, 0);
84 XTestFakeButtonEvent(disp,1,1, 50);
85 XTestFakeButtonEvent(disp,1,0, 50);
86 r= XSync(disp, False); eassert(r);
88 fprintf(stderr,"PAGING raise_and_set_focus done.\n");
91 /*---------- pager ----------*/
98 static void send_key(KeySym sym) {
100 XTestFakeKeyEvent(disp, keycode(sym),1, 10);
101 XTestFakeKeyEvent(disp, keycode(sym),0, 10);
102 r= XSync(disp, False); eassert(r);
105 static void send_pgup_many(void) {
107 fprintf(stderr,"PAGING PageUp\n");
111 static void send_pgdown(void) {
112 fprintf(stderr,"PAGING PageDown\n");
116 static double timestamp(void) {
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);
127 static double worst_snapshot= 0.050;
128 static double worst_stabilise= 0.100;
129 static size_t snapshot_alloc= 1024;
131 static void snapshot(Snapshot **output) {
135 free(*output); *output=0;
136 double a= timestamp();
138 fprintf(stderr,"PAGING snapshot\n");
140 r= asprintf(&cmd, "xwd -silent -id 0x%lx", (unsigned long)id); eassert(r>=0);
141 FILE *f= popen(cmd,"r"); eassert(f);
146 size_t allow= snapshot_alloc - used;
148 snapshot_alloc <<= 1;
150 fprintf(stderr,"PAGING snapshot grow %ld\n", (long)snapshot_alloc);
154 *output= realloc(*output, sizeof(**output) + snapshot_alloc);
158 size_t got= fread((*output)->d, 1, allow, f);
164 (*output)->len= used;
165 snapshot_alloc= used+1;
166 *output= realloc(*output, sizeof(**output) + snapshot_alloc);
169 double b= timestamp();
171 if (it_took > worst_snapshot)
172 worst_snapshot= it_took;
174 fprintf(stderr,"PAGING snapshot took=%f len=%ld\n",
175 it_took, (long)used);
178 static void snapshot_idle(void) {
180 r= usleep(worst_snapshot * 1e6 * 0.5);
181 /* spend no more than 2/3 of our time constantly snapshotting */
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));
190 static void wait_for_stability(Snapshot **output,
191 const Snapshot *previously,
192 void (*with_keypress)(void)) {
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 */
197 double when_started= timestamp();
198 double last_change= when_started;
201 fprintf(stderr,"PAGING wait_for_stability"
202 " worst_snapshot=%f worst_stabilise=%f previously=%p\n",
203 worst_snapshot, worst_stabilise, previously);
206 double at_snapshot= timestamp();
208 double right_now= timestamp();
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;
221 it_took= at_snapshot - when_started;
223 double threshold= worst_stabilise + worst_snapshot;
224 if (!previously || identical(*output,previously))
225 threshold *= 2; threshold += 1.5;
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);
234 if (stable_for > threshold)
242 if (!with_keypress && it_took > worst_stabilise)
243 worst_stabilise= it_took;
246 fprintf(stderr,"PAGING wait_for_stability done.\n");
249 static void read_pages(void) {
250 Snapshot *current=0, *last=0;
252 raise_and_set_focus();
254 /* page to the top - keep pressing page up until the image stops changing */
255 wait_for_stability(&last,0, send_pgup_many);
257 /* now to actually page down */
259 fprintf(stderr,"PAGING page %d\n",npages);
260 //eassert(npages < MAX_PAGES);
261 //page_images[npages++]=
264 wait_for_stability(¤t,last, 0);
265 if (npages && /* first pagedown doesn't do much */
266 identical(current,last)) {
271 free(last); last=current; current=0;
275 fprintf(stderr,"PAGING all done.\n");
278 int main(int argc, char **argv) {
279 screenshot_startup();
281 id= strtoul(*++argv,0,0);