7 #include <X11/extensions/XTest.h>
8 #include <X11/keysym.h>
11 CanonImage *page_images[MAX_PAGES];
14 static XWindowAttributes attr;
17 static struct timeval tv_startup;
18 static unsigned wwidth, wheight;
19 static int wxpos, wypos;
21 static KeyCode keycode(KeySym sym) {
22 return XKeysymToKeycode(disp,sym);
25 void screenshot_startup(void) {
27 disp= XOpenDisplay(0); eassert(disp);
28 r= gettimeofday(&tv_startup,0); eassert(!r);
31 /*---------- pager ----------*/
33 typedef XImage Snapshot;
35 static double last_input;
36 static const double min_update_allowance= 0.25;
38 static double timestamp(void) {
42 r= gettimeofday(&tv,0); eassert(!r);
43 double t= (tv.tv_sec - tv_startup.tv_sec) +
44 (tv.tv_usec - tv_startup.tv_usec) * 1e-6;
45 fprintf(stderr,"%f\n",t);
48 static void delay(double need_sleep) {
50 fprintf(stderr,"PAGING delay %f\n",need_sleep);
51 r= usleep(need_sleep * 1e6); eassert(!r);
54 static void sync_after_input(void) {
56 r= XSync(disp, False); eassert(r);
57 last_input= timestamp();
60 static void send_key(KeySym sym) {
61 XTestFakeKeyEvent(disp, keycode(sym),1, 10);
62 XTestFakeKeyEvent(disp, keycode(sym),0, 10);
65 static void send_pgup_many(void) {
69 fprintf(stderr,"PAGING PageUp x %d\n",i);
72 static void send_pgdown(void) {
74 fprintf(stderr,"PAGING PageDown\n");
78 static void free_snapshot(Snapshot **io) {
79 if (*io) XDestroyImage(*io);
83 static void snapshot(Snapshot **output) {
88 free_snapshot(output);
90 fprintf(stderr,"PAGING snapshot\n");
93 *output= XGetImage(disp,id, 0,0, wwidth,wheight, AllPlanes, ZPixmap);
96 fprintf(stderr,"PAGING snapshot done.\n");
99 static int identical(const Snapshot *a, const Snapshot *b) {
100 if (!(a->width == b->width &&
101 a->height == b->height &&
102 a->bytes_per_line == b->bytes_per_line &&
103 a->format == b->format))
105 return !memcmp(a->data, b->data, a->bytes_per_line * a->height);
108 static void wait_for_stability(Snapshot **output,
109 const Snapshot *previously,
110 void (*with_keypress)(void)) {
112 /* waits longer if we're going to return an image identical to previously
113 * if previously==0, all images are considered identical to it */
115 fprintf(stderr,"PAGING wait_for_stability"
116 " last_input=%f previously=%p\n",
117 last_input, previously);
120 double at_snapshot= timestamp();
121 double need_sleep= min_update_allowance - (at_snapshot - last_input);
122 if (need_sleep > 0) { delay(need_sleep); continue; }
126 if (!with_keypress &&
127 !(previously && identical(*output,previously))) {
128 fprintf(stderr,"PAGING wait_for_stability simple\n");
132 if (last && identical(*output,last)) {
133 fprintf(stderr,"PAGING wait_for_stability stabilised\n");
137 fprintf(stderr,"PAGING wait_for_stability retry\n");
139 free_snapshot(&last); last=*output; *output=0;
147 free_snapshot(&last);
148 fprintf(stderr,"PAGING wait_for_stability done.\n");
151 static void raise_and_get_details(void) {
153 int evbase,errbase,majver,minver;
157 fprintf(stderr,"PAGING raise_and_get_details\n");
159 r= XTestQueryExtension(disp, &evbase,&errbase,&majver,&minver);
162 r= XRaiseWindow(disp, id); eassert(r);
164 r= XGetWindowAttributes(disp, id, &attr); eassert(r);
165 r= XGetGeometry(disp,id, &attr.root,
166 &wxpos,&wypos, &wwidth,&wheight,
170 r= XTranslateCoordinates(disp, id,attr.root, 160,160, &wxpos,&wypos,
175 static void set_focus(void) {
176 int screen= XScreenNumberOfScreen(attr.screen);
178 fprintf(stderr,"PAGING set_focus\n");
180 XTestFakeMotionEvent(disp,screen, wxpos,wypos, 0);
182 XTestFakeButtonEvent(disp,1,1, 50);
183 XTestFakeButtonEvent(disp,1,0, 50);
186 fprintf(stderr,"PAGING raise_and_set_focus done.\n");
189 #define SAMPLEMASK 0xfful
195 static void compute_shift_mask(ShMask *sm, unsigned long ximage_mask) {
200 if (ximage_mask <= (SAMPLEMASK>>1)) {
201 sm->lshift++; ximage_mask <<= 1;
202 } else if (ximage_mask > SAMPLEMASK) {
203 sm->rshift++; ximage_mask >>= 1;
207 assert(!(sm->lshift && sm->rshift));
209 assert(sm->lshift < LONG_BIT);
210 assert(sm->rshift < LONG_BIT);
213 static CanonImage *convert_page(Snapshot *sn) {
214 ShMask shiftmasks[3];
217 fprintf(screenshots_file,
220 "255\n", sn->width, sn->height);
222 #define COMPUTE_SHIFT_MASK(ix, rgb) \
223 compute_shift_mask(&shiftmasks[ix], sn->rgb##_mask)
224 COMPUTE_SHIFT_MASK(0, red);
225 COMPUTE_SHIFT_MASK(1, green);
226 COMPUTE_SHIFT_MASK(2, blue);
228 CANONICALISE_IMAGE(im, sn->width, sn->height, {
229 long xrgb= XGetPixel(sn, x, y);
232 for (i=0; i<3; i++) {
234 unsigned long sample=
235 ((xrgb << shiftmasks[i].lshift)
236 >> shiftmasks[i].rshift) & SAMPLEMASK;
238 fputc(sample, screenshots_file);
242 eassert(!fflush(screenshots_file));
247 void take_screenshots(void) {
248 Snapshot *current=0, *last=0;
251 /* find the window and check it's on the right kind of screen */
252 raise_and_get_details();
253 wait_for_stability(¤t,0,0);
254 test= convert_page(current);
255 find_structure(test);
258 /* page to the top - keep pressing page up until the image stops changing */
260 wait_for_stability(¤t,0, send_pgup_many);
262 /* now to actually page down */
264 fprintf(stderr,"paging page %d\n",npages);
266 eassert(npages < MAX_PAGES);
267 page_images[npages]= convert_page(current);
268 free_snapshot(&last); last=current; current=0;
270 fprintf(stderr,"PAGING page %d converted\n",npages);
272 wait_for_stability(¤t,last, 0);
273 if (npages && /* first pagedown doesn't do much */
274 identical(current,last)) {
275 free_snapshot(¤t);
282 fprintf(stderr,"PAGING all done.\n");
285 void take_one_screenshot(void) {
288 raise_and_get_details();
290 wait_for_stability(¤t,0,0);
291 page_images[0]= convert_page(current);
295 void set_yppclient_window(unsigned long wul) {
299 void find_yppclient_window(void) {
301 eassert(!"finding client window NYI");