Pay attention to cache behavior, resulting in fast_scale_y being about
[xiph/unicode.git] / snatch / x11.c
blobc57c958c42a6531a82772d811679107602c34ea5
1 /* X11 layer of subversion library to intercept RealPlayer socket and
2 device I/O. --20011101 */
4 #include <stdio.h>
5 #include <errno.h>
6 #include <sys/time.h>
7 #include <X11/Xlib.h>
8 #include "snatchppm.h"
9 #include "waitppm.h"
10 #include "realppm.h"
12 static unsigned long root_window=0;
13 static unsigned long rpshell_window=0;
14 static unsigned long rpmain_window=0;
15 static unsigned long rpmenu_window=0;
16 static unsigned long rpplay_window=0;
17 static long rpplay_width=0;
18 static long rpplay_height=0;
20 static long logo_y=-1;
21 static long logo_prev=-1;
23 static long play_blackleft=-1;
24 static long play_blackright=-1;
25 static long play_blackupper=-1;
26 static long play_blacklower=-1;
28 static unsigned long rpvideo_window=0;
29 static int video_width=-1;
30 static int video_height=-1;
32 static unsigned long rpauth_shell=0;
33 static unsigned long rpauth_main=0;
34 static unsigned long rpauth_password=0;
35 static unsigned long rpauth_username=0;
36 static unsigned long rpauth_okbutton=0;
37 static unsigned long rpauth_cancel=0;
38 static int rpauth_count=0;
39 static int rpauth_already=0;
41 static unsigned long rploc_shell=0;
42 static unsigned long rploc_button=0;
43 static unsigned long rploc_clear=0;
44 static unsigned long rploc_entry=0;
45 static unsigned long rploc_ok=0;
46 static unsigned long rploc_main=0;
47 static int rploc_count=0;
49 static unsigned long rpfile_shell=0;
50 static unsigned long rpfile_main=0;
51 static unsigned long rpfile_entry=0;
52 static int rpfile_lowest=0;
54 static void queue_task(void (*f)(void));
55 static void initialize();
56 static int videocount=0;
57 static int videotime=0;
59 static int depthwarningflag;
61 static void XGetGeometryRoot(unsigned long id,int *root_x,int *root_y){
62 int x=0;
63 int y=0;
64 while(id!=root_window){
65 Window root_return,parent_return,*children;
66 int x_return, y_return;
67 unsigned int width_return, height_return, border_width_return,
68 depth_return;
70 XGetGeometry(Xdisplay,id,&root_return, &x_return, &y_return,
71 &width_return,&height_return,&border_width_return,
72 &depth_return);
73 x+=x_return;
74 y+=y_return;
75 XQueryTree(Xdisplay,id,&root_return,&parent_return,&children,&depth_return);
76 XFree(children);
77 id=parent_return;
79 *root_x=x;
80 *root_y=y;
83 /* Robot events *********************************************************/
85 static void FakeKeycode(int keycode, int modmask, unsigned long window){
86 XKeyEvent event;
87 memset(&event,0,sizeof(event));
89 event.display=Xdisplay;
90 event.type=2; /* key down */
91 event.keycode=keycode;
92 event.root=root_window;
93 event.window=window;
94 event.state=modmask;
96 XSendEvent(Xdisplay,(Window)window,0,0,(XEvent *)&event);
98 /* Don't send the keyups; RP doesn't care and a 'return' or 'space'
99 can close a window... resulting in sending a keyup to a drawable
100 that doesn't exist. */
102 //event.type=3; /* key up */
104 //XSendEvent(Xdisplay,(Window)window,0,0,(XEvent *)&event);
108 static void FakeKeySym(int keysym, int modmask, unsigned long window){
109 KeyCode c=XKeysymToKeycode(Xdisplay,keysym);
111 if((int)XKeycodeToKeysym(Xdisplay,c,0)==keysym){
112 FakeKeycode(c,modmask,window);
113 }else{
114 FakeKeycode(c,1|modmask,window);
119 void FakeButton1(unsigned long window){
120 XButtonEvent event;
121 int root_x,root_y;
123 XGetGeometryRoot(window,&root_x,&root_y);
124 memset(&event,0,sizeof(event));
125 event.display=Xdisplay;
126 event.type=4; /* button down */
127 event.button=1;
128 event.root=root_window;
129 event.x=4;
130 event.y=4;
131 event.x_root=root_x+4;
132 event.y_root=root_y+4;
134 event.window=window;
135 event.same_screen=1;
137 XSendEvent(Xdisplay,(Window)window,0,0,(XEvent *)&event);
139 event.type=5; /* button up */
140 event.state=0x100;
142 XSendEvent(Xdisplay,(Window)window,0,0,(XEvent *)&event);
146 void FakeExposeRPPlay(void){
147 XExposeEvent event;
148 memset(&event,0,sizeof(event));
150 event.display=Xdisplay;
151 event.type=12;
152 event.window=rpplay_window;
153 event.width=rpplay_width;
154 event.height=rpplay_height;
156 XSendEvent(Xdisplay,(Window)rpplay_window,0,0,(XEvent *)&event);
159 void FakeTypeString(unsigned char *buf,unsigned long window){
160 FakeButton1(window);
161 while(*buf){
162 FakeKeySym(*buf,0,window);
163 buf++;
167 static void UsernameAndPassword(void){
169 fprintf(stderr," ...: filling in username and password...\n");
170 if(username)
171 FakeTypeString(username,rpauth_username);
172 if(password)
173 FakeTypeString(password,rpauth_password);
174 FakeButton1(rpauth_okbutton);
176 rpauth_shell=0;
177 rpauth_main=0;
178 rpauth_password=0;
179 rpauth_username=0;
180 rpauth_okbutton=0;
181 rpauth_count=0;
185 static void Location(void){
187 fprintf(stderr," ...: filling in location field...\n");
189 FakeButton1(rploc_clear);
191 if(location)
192 FakeTypeString(location,rploc_entry);
194 FakeButton1(rploc_ok);
196 rploc_shell=0;
197 rploc_main=0;
198 rploc_ok=0;
199 rploc_count=0;
200 rploc_entry=0;
204 static void FileEntry(void){
205 int i;
206 fprintf(stderr," ...: filling in file field...\n");
208 /* gah, hack */
209 for(i=0;i<300;i++)
210 FakeKeySym(XStringToKeysym("BackSpace"),0,rpfile_entry);
212 if(openfile)
213 FakeTypeString(openfile,rpfile_entry);
215 FakeKeySym(XStringToKeysym("Return"),0,rpfile_entry);
217 rpfile_shell=0;
218 rpfile_main=0;
222 /* captured calls ******************************************************/
224 Display *XOpenDisplay(const char *d){
225 initialize();
227 if(!XInitThreads()){
228 fprintf(stderr,"**ERROR: Unable to set multithreading support in Xlib.\n"
229 " exit(1)ing...\n\n");
230 exit(1);
232 Xdisplay=(*xlib_xopen)(d);
233 pthread_mutex_lock(&display_mutex);
234 pthread_cond_signal(&display_cond);
235 pthread_mutex_unlock(&display_mutex);
236 return(Xdisplay);
239 /* we assume the * window is ready when we see the last polylines put
240 into the chosen button window */
241 int XDrawSegments(Display *display, Drawable id, GC gc, XSegment *segments, int nsegments){
243 int ret=(*xlib_xdrawsegments)(display, id, gc, segments, nsegments);
245 if(id==rpauth_cancel){
246 rpauth_cancel=0;
247 queue_task(UsernameAndPassword);
250 if(id==rploc_entry && rploc_button){
251 rploc_button=0;
252 queue_task(Location);
255 if(id==rpfile_entry && rpfile_shell){
256 rpfile_shell=0;
257 queue_task(FileEntry);
259 return(ret);
262 Window XCreateWindow(Display *display,Window parent,
263 int x, int y,
264 unsigned int width, unsigned int height,
265 unsigned int border_width,
266 int depth,
267 unsigned int class,
268 Visual *visual,
269 unsigned long valuemask,
270 XSetWindowAttributes *attributes){
272 Window id=(*xlib_xcreatewindow)(display,parent,x,y,width,height,border_width,
273 depth,class,visual,valuemask,attributes);
275 if(!root_window)
276 root_window=parent;
278 /* Main player windows */
279 if(parent==rpshell_window){
280 rpmain_window=id;
281 rpplay_window=0;
282 if(debug)
283 fprintf(stderr,
284 " ...: RealPlayer main window id=%lx\n",rpmain_window);
286 }else if(rpshell_window){
287 if(parent==rpmain_window){
288 if(!rpplay_window){
289 rpplay_window=id;
291 if(debug)
292 fprintf(stderr,
293 " ...: RealPlayer console window id=%lx\n",rpplay_window);
294 }else{
295 rpmenu_window=id;
297 }else if(parent==rpplay_window){
298 rpvideo_window=id;
299 if(debug)
300 fprintf(stderr,
301 " ...: RealPlayer video window id=%lx\n",rpvideo_window);
305 /* Auth dialog windows */
306 if(parent==rpauth_shell){
307 rpauth_main=id;
309 if(parent==rpauth_main){
310 switch(rpauth_count++){
311 case 5:
312 rpauth_username=id;
313 fprintf(stderr," ...: username window: %lx\n",id);
314 break;
315 case 3:
316 rpauth_password=id;
317 fprintf(stderr," ...: password window: %lx\n",id);
318 break;
319 case 1:
320 rpauth_okbutton=id;
321 fprintf(stderr," ...: OK button: %lx\n",id);
322 break;
323 case 0:
324 rpauth_cancel=id;
325 fprintf(stderr," ...: cancel button: %lx\n",id);
326 break;
330 /* Location dialog windows */
331 if(parent==rploc_shell){
332 rploc_main=id;
334 if(parent==rploc_main || parent==rploc_button){
335 switch(rploc_count++){
336 case 0:
337 rploc_button=id;
338 break;
339 case 1:
340 fprintf(stderr," ...: clear button: %lx\n",id);
341 rploc_clear=id;
342 break;
343 case 3:
344 fprintf(stderr," ...: ok button: %lx\n",id);
345 rploc_ok=id;
346 break;
347 case 5:
348 rploc_main=id;
349 break;
350 case 7:
351 fprintf(stderr," ...: text entry: %lx\n",id);
352 rploc_entry=id;
353 break;
357 /* File dialog windows */
358 if(parent==rpfile_shell){
359 rpfile_main=id;
360 rpfile_lowest=0;
362 if(parent==rpfile_main){
363 if(y>rpfile_lowest){
364 rpfile_entry=id;
365 rpfile_lowest=y;
369 return(id);
372 int XConfigureWindow(Display *display,Window id,unsigned int bitmask,XWindowChanges *values){
374 int ret=(*xlib_xconfigurewindow)(display, id, bitmask, values);
376 if(id==rpplay_window){
378 if(bitmask & CWHeight){
379 rpplay_height=values->height;
380 logo_y=-1;
382 if(bitmask & CWWidth){
383 rpplay_width=values->width;
384 logo_y=-1;
388 if(id==rpvideo_window){
389 if(bitmask & CWHeight){
390 video_height=values->height;
391 CloseOutputFile(0);
393 if(bitmask & CWWidth){
394 video_width=values->width;
395 CloseOutputFile(0);
399 return(ret);
402 int XResizeWindow(Display *display,Window id,unsigned int width,unsigned int height){
404 int ret=(*xlib_xresizewindow)(display, id, width, height);
406 if(id==rpplay_window){
407 rpplay_height=height;
408 rpplay_width=width;
409 logo_y=-1;
412 if(id==rpvideo_window){
413 video_height=height;
414 video_width=width;
415 CloseOutputFile(0);
418 return(ret);
421 int XChangeProperty(Display *display,Window id,Atom property,Atom type,int format,int mode,
422 const unsigned char *data,int n){
424 int ret=(*xlib_xchangeproperty)(display, id, property, type, format, mode, data, n);
426 if(property!=67 || type!=31)return(ret); /* not interested if not WM_CLASS and STRING */
428 /* look for the RealPlayer shell window; the other player windows
429 descend from it in a predicatble pattern */
431 if(rpshell_window==0){
432 if(debug)
433 fprintf(stderr,
434 " ...: looking for our shell window...\n"
435 " candidate: id=%lx, name=%s class=%s\n",
436 id,(data?(char *)data:""),(data?strchr((char *)data,'\0')+1:""));
438 if(n>26 && !memcmp(data,"RealPlayer\0RCACoreAppShell\0",27)){
439 /* it's our shell window above the WM parent */
440 rpshell_window=id;
442 /* re-setup */
443 rpmain_window=0;
444 rpmenu_window=0;
445 rpplay_window=0;
446 rpplay_width=0;
447 rpplay_height=0;
449 logo_y=-1;
450 logo_prev=-1;
452 rpvideo_window=0;
453 video_width=-1;
454 video_height=-1;
456 if(debug)
457 fprintf(stderr," GOT IT!\n");
458 }else{
459 if(debug)
460 fprintf(stderr," nope...\n");
464 /* watch for the auth password window */
465 if(username || password){
467 if(n>=32 && !memcmp(data,"AuthDialogShell\0RCACoreAppShell\0",32)){
468 if(rpauth_already>2){
469 fprintf(stderr,
470 "**ERROR: Password not accepted.\n");
471 rpauth_shell=0;
472 rpauth_already=0;
473 }else{
474 fprintf(stderr,
475 " ...: RealPlayer popped auth window. Watching for username\n"
476 " password and ok button windows\n");
477 rpauth_shell=id;
478 rpauth_count=0;
479 rpauth_username=0;
480 rpauth_password=0;
481 rpauth_okbutton=0;
482 rpauth_already++;
487 /* watch for the open location window */
488 if(location){
489 if(n>=40 && !memcmp(data,"OpenLocationDialogShell\0RCACoreAppShell\0",40)){
490 fprintf(stderr,
491 " ...: RealPlayer popped open location dialog. Watching for\n"
492 " dialog window tree...\n");
493 rploc_shell=id;
494 rploc_count=0;
495 rploc_entry=0;
496 rploc_clear=0;
497 rploc_ok=0;
500 if(openfile){
501 /* watch for the open file window */
502 if(n>=32 && !memcmp(data,"OpenFileDialogShell\0RCACoreAppShell\0",32)){
503 fprintf(stderr,
504 " ...: RealPlayer popped open file dialog.\n");
505 rpfile_shell=id;
506 rpfile_main=0;
509 return(ret);
512 /* hash the image: Real (for some reason) sometimes blits at >> the
513 encoded video framerate [it's not interlaced, so not sure why], so
514 there are lotsa dupes. Hash to see if the frame actually changed.
515 Again, CPU overhead is likely more than made up for in bandwidth
516 savings */
518 static char *workbuffer;
519 static long worksize;
521 /* yes, it's additional CPU load where we don't want any, but the
522 savings in required disk bandwidth is more than worth it (YUV 2:4:0
523 is half the size) */
525 void YUVout(XImage *image){
526 pthread_mutex_lock(&output_mutex);
527 if(outfile_fd>=0){
528 char cbuf[80];
529 int i,j,len;
531 long yuv_w=(image->width>>1)<<1; /* must be even for yuv12 */
532 long yuv_h=(image->height>>1)<<1; /* must be even for yuv12 */
533 long yuv_n=yuv_w*yuv_h*3/2;
535 long a,b;
537 pthread_mutex_unlock(&output_mutex);
538 bigtime(&a,&b);
539 len=sprintf(cbuf,"YUV12 %ld %ld %d %d %ld:",a,b,yuv_w,
540 yuv_h,yuv_n);
542 if(worksize<yuv_n){
543 if(worksize==0)
544 workbuffer=malloc(yuv_n);
545 else
546 workbuffer=realloc(workbuffer,yuv_n);
547 worksize=yuv_n;
551 unsigned char *y1=workbuffer;
552 unsigned char *y2=workbuffer+yuv_w;
553 unsigned char *u=workbuffer+yuv_w*yuv_h;
554 unsigned char *v=u+yuv_w*yuv_h/4;
555 if(image->byte_order){
557 for(i=0;i<yuv_h;i+=2){
558 unsigned char *ptr1=image->data+i*image->bytes_per_line;
559 unsigned char *ptr2=ptr1+image->bytes_per_line;
560 for(j=0;j<yuv_w;j+=2){
561 long yval,uval,vval;
563 yval = ptr1[1]*19595 + ptr1[2]*38470 + ptr1[3]*7471;
564 uval = ptr1[3]*65536 - ptr1[1]*22117 - ptr1[2]*43419;
565 vval = ptr1[1]*65536 - ptr1[2]*54878 - ptr1[3]*10658;
566 *y1++ = yval>>16;
568 yval = ptr1[5]*19595 + ptr1[6]*38470 + ptr1[7]*7471;
569 uval += ptr1[7]*65536 - ptr1[5]*22117 - ptr1[6]*43419;
570 vval += ptr1[5]*65536 - ptr1[6]*54878 - ptr1[7]*10658;
571 *y1++ = yval>>16;
573 yval = ptr2[1]*19595 + ptr2[2]*38470 + ptr2[3]*7471;
574 uval += ptr2[3]*65536 - ptr2[1]*22117 - ptr2[2]*43419;
575 vval += ptr2[1]*65536 - ptr2[2]*54878 - ptr2[3]*10658;
576 *y2++ = yval>>16;
578 yval = ptr2[5]*19595 + ptr2[6]*38470 + ptr2[7]*7471;
579 uval += ptr2[7]*65536 - ptr2[5]*22117 - ptr2[6]*43419;
580 vval += ptr2[5]*65536 - ptr2[6]*54878 - ptr2[7]*10658;
581 *y2++ = yval>>16;
583 *u++ = (uval>>19)+128;
584 *v++ = (vval>>19)+128;
585 ptr1+=8;
586 ptr2+=8;
588 y1+=yuv_w;
589 y2+=yuv_w;
593 }else{
595 for(i=0;i<yuv_h;i+=2){
596 unsigned char *ptr1=image->data+i*image->bytes_per_line;
597 unsigned char *ptr2=ptr1+image->bytes_per_line;
598 for(j=0;j<yuv_w;j+=2){
599 long yval,uval,vval;
601 yval = ptr1[2]*19595 + ptr1[1]*38470 + ptr1[0]*7471;
602 uval = ptr1[0]*65536 - ptr1[2]*22117 - ptr1[1]*43419;
603 vval = ptr1[2]*65536 - ptr1[1]*54878 - ptr1[0]*10658;
604 *y1++ = yval>>16;
606 yval = ptr1[6]*19595 + ptr1[5]*38470 + ptr1[4]*7471;
607 uval += ptr1[4]*65536 - ptr1[6]*22117 - ptr1[5]*43419;
608 vval += ptr1[6]*65536 - ptr1[5]*54878 - ptr1[4]*10658;
609 *y1++ = yval>>16;
611 yval = ptr2[2]*19595 + ptr2[1]*38470 + ptr2[0]*7471;
612 uval += ptr2[0]*65536 - ptr2[2]*22117 - ptr2[1]*43419;
613 vval += ptr2[2]*65536 - ptr2[1]*54878 - ptr2[0]*10658;
614 *y2++ = yval>>16;
616 yval = ptr2[6]*19595 + ptr2[5]*38470 + ptr2[4]*7471;
617 uval += ptr2[4]*65536 - ptr2[6]*22117 - ptr2[5]*43419;
618 vval += ptr2[6]*65536 - ptr2[5]*54878 - ptr2[4]*10658;
619 *y2++ = yval>>16;
621 *u++ = (uval>>19)+128;
622 *v++ = (vval>>19)+128;
623 ptr1+=8;
624 ptr2+=8;
626 y1+=yuv_w;
627 y2+=yuv_w;
632 pthread_mutex_lock(&output_mutex);
633 gwrite(outfile_fd,cbuf,len);
634 gwrite(outfile_fd,workbuffer,yuv_n);
636 pthread_mutex_unlock(&output_mutex);
640 int XPutImage(Display *display,Drawable id,GC gc,XImage *image,
641 int src_x,int src_y,
642 int x, int y,
643 unsigned int d_width,
644 unsigned int d_height){
646 int ret=0;
648 if(id==rpvideo_window){
649 double t=bigtime(NULL,NULL);
650 if(t-videotime)
651 videocount=1;
652 else
653 videocount++;
656 if(snatch_active==1 && id==rpvideo_window){
657 pthread_mutex_lock(&output_mutex);
658 if(outfile_fd>=0 && !output_video_p)CloseOutputFile(1);
659 if(outfile_fd<0 && videocount>4)OpenOutputFile();
660 pthread_mutex_unlock(&output_mutex);
661 /* only do 24 bit zPixmaps for now */
663 if(image->format==2 && image->depth>16 && image->depth<=24){
664 YUVout(image);
665 }else{
666 if(!depthwarningflag)
667 fprintf(stderr,"**ERROR: Right now, Snatch only works with 17-24 bit ZPixmap\n"
668 " based visuals packed into 8bpp 32 bit units. This\n"
669 " X server is not in a 24/32 bit mode. \n");
670 depthwarningflag=1;
675 /* Subvert the Real sign on logo; paste the Snatch logo in.
676 Although this might seem like a vanity issue, the primary reason
677 for doing this is to give the user a clear indication Snatch is
678 working properly, so some care should be taken to get it right. */
680 /* Real uses putimage here even on the local display with MIT-SHM support */
682 if(id==rpplay_window){
683 int width=image->width;
684 int height=image->height;
685 int endian=image->byte_order;
687 if(image->format==2 && image->depth>16 && image->depth<=24){
689 char *ptr=image->data;
690 long i,j,k;
692 /* after a resize, look where to put the logo... */
693 if(logo_y==-1 && height==rpplay_height && width==rpplay_width){
694 int test;
695 play_blackupper=42;
696 play_blacklower=-1;
697 play_blackleft=-1;
698 play_blackright=-1;
700 for(play_blackleft=20;play_blackleft>0;play_blackleft--)
701 if(ptr[play_blackupper*width*4+play_blackleft*4+1]!=0)break;
702 play_blackleft++;
703 for(play_blackright=width-20;play_blackright<width;play_blackright++)
704 if(ptr[play_blackupper*width*4+play_blackright*4+1]!=0)break;
706 if(play_blacklower==-1){
707 play_blacklower=42;
708 for(;play_blacklower<height;play_blacklower++)
709 if(ptr[play_blacklower*width*4+81]!=0)break;
711 if(play_blacklower==height)play_blacklower=-1;
714 for(test=play_blackupper;test<height;test++)
715 if(ptr[test*width*4+(width/2*4)+1]!=0)break;
717 if(test<height && test+snatchheight<play_blacklower){
718 logo_y=test;
720 /* verify enough room to display... */
721 if(test<50){
722 long blacklower;
724 for(blacklower=test;blacklower<height;blacklower++)
725 if(ptr[blacklower*width*4+(20*4)+1]!=0)break;
727 if(blacklower-test<snatchheight){
728 logo_y=-1;
734 /* blank background */
735 if(x==0 && y==0 && (int)d_width==rpplay_width &&
736 (int)d_height==rpplay_height){
737 unsigned char *bptr;
739 if(snatch_active==1)
740 bptr=snatchppm;
741 else
742 bptr=waitppm;
744 if(endian){
745 for(i=play_blackupper;i<play_blacklower;i++)
746 for(j=play_blackleft;j<play_blackright;j++){
747 ptr[i*width*4+j*4]=0x00;
748 ptr[i*width*4+j*4+1]=bptr[0];
749 ptr[i*width*4+j*4+2]=bptr[1];
750 ptr[i*width*4+j*4+3]=bptr[2];
752 }else{
753 for(i=play_blackupper;i<play_blacklower;i++)
754 for(j=play_blackleft;j<play_blackright;j++){
755 ptr[i*width*4+j*4+3]=0x00;
756 ptr[i*width*4+j*4+2]=bptr[0];
757 ptr[i*width*4+j*4+1]=bptr[1];
758 ptr[i*width*4+j*4]=bptr[2];
763 /* paint logo */
764 if(logo_y!=-1){
765 unsigned char *logo=NULL;
766 int logowidth=-1;
767 int logoheight=-1;
769 switch(snatch_active){
770 case 0:
771 logo=realppm;
772 logowidth=realwidth;
773 logoheight=realheight;
774 break;
775 case 1:
776 logo=snatchppm;
777 logowidth=snatchwidth;
778 logoheight=snatchheight;
779 break;
780 case 2:
781 logo=waitppm;
782 logowidth=snatchwidth;
783 logoheight=snatchheight;
784 break;
787 for(i=0;i<logoheight;i++){
788 if(i+logo_y<height){
789 char *snatch;
790 char *real;
792 real=ptr+width*4*(i+logo_y)+(rpplay_width-logowidth)/2*4; /* not the same as *2 */
793 snatch=logo+logowidth*3*i;
795 if(endian){
797 for(k=0,j=0;k<logowidth*3 && j<width*4;){
798 real[++j]=snatch[k++];
799 real[++j]=snatch[k++];
800 real[++j]=snatch[k++];
801 ++j;
804 }else{
805 for(k=0,j=0;k<logowidth*3 && j<width*4;j+=4){
806 real[j+2]=snatch[k++];
807 real[j+1]=snatch[k++];
808 real[j]=snatch[k++];
815 }else{
816 if(!depthwarningflag)
817 fprintf(stderr,"**ERROR: Right now, Snatch only works with 17-24 bit ZPixmap\n"
818 " based visuals packed into 8bpp 32 bit units. This\n"
819 " X server is not in a 24/32 bit mode. \n");
820 depthwarningflag=1;
824 if(!fake_videop)
825 ret=(*xlib_xputimage)(display,id,gc,image,src_x,src_y,x,y,d_width,d_height);
827 return(ret);
830 int XShmPutImage(Display *display,Drawable id,GC gc,XImage *image,
831 int src_x, int src_y, int dest_x, int dest_y,
832 unsigned int width, unsigned int height,
833 Bool send_event){
834 int ret=0;
836 if(id==rpvideo_window){
837 double t=bigtime(NULL,NULL);
838 if(t-videotime>1.)
839 videocount=1;
840 else
841 videocount++;
844 if(snatch_active==1 && id==rpvideo_window){
845 pthread_mutex_lock(&output_mutex);
846 if(outfile_fd>=0 && !output_video_p)CloseOutputFile(1);
847 if(outfile_fd<0 && videocount>4)OpenOutputFile();
848 pthread_mutex_unlock(&output_mutex);
850 /* only do 24 bit zPixmaps for now */
851 if(image->format==2 && image->depth>16 && image->depth<=24){
852 YUVout(image);
853 }else{
854 if(!depthwarningflag)
855 fprintf(stderr,"**ERROR: Right now, Snatch only works with 17-24 bit ZPixmap\n"
856 " based visuals packed into 8bpp 32 bit units. This\n"
857 " X server is not in a 24/32 bit mode. \n");
858 depthwarningflag=1;
862 if(!fake_videop)
863 ret=(*xlib_xshmputimage)(display, id, gc, image, src_x, src_y,
864 dest_x, dest_y, width, height, send_event);
867 return(ret);
870 int XCloseDisplay(Display *d){
871 int ret=(*xlib_xclose)(d);
872 CloseOutputFile(0);
873 if(debug)fprintf(stderr," ...: X display closed; goodbye.\n\n");
874 return(ret);