1/*
2 * Xephyr - A kdrive X server thats runs in a host X window.
3 *          Authored by Matthew Allum <mallum@openedhand.com>
4 *
5 * Copyright © 2007 OpenedHand Ltd
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of OpenedHand Ltd not be used in
12 * advertising or publicity pertaining to distribution of the software without
13 * specific, written prior permission. OpenedHand Ltd makes no
14 * representations about the suitability of this software for any purpose.  It
15 * is provided "as is" without express or implied warranty.
16 *
17 * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19 * EVENT SHALL OpenedHand Ltd BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23 * PERFORMANCE OF THIS SOFTWARE.
24 *
25 * Authors:
26 *    Dodji Seketeli <dodji@openedhand.com>
27 */
28#ifdef HAVE_CONFIG_H
29#include <kdrive-config.h>
30#endif
31/*
32 * including some server headers (like kdrive-config.h)
33 * might define the macro _XSERVER64
34 * on 64 bits machines. That macro must _NOT_ be defined for Xlib
35 * client code, otherwise bad things happen.
36 * So let's undef that macro if necessary.
37 */
38#ifdef _XSERVER64
39#undef _XSERVER64
40#endif
41#include <X11/Xutil.h>
42#include <X11/Xlibint.h>
43#include <X11/extensions/Xvlib.h>
44#include <X11/extensions/Xvproto.h>
45#include <X11/extensions/Xext.h>
46#include <X11/extensions/extutil.h>
47#define _HAVE_XALLOC_DECLS
48
49#include "hostx.h"
50#include "ephyrhostvideo.h"
51#include "ephyrlog.h"
52
53#ifndef TRUE
54#define TRUE 1
55#endif /*TRUE*/
56
57#ifndef FALSE
58#define FALSE 0
59#endif /*FALSE*/
60
61static XExtensionInfo _xv_info_data;
62static XExtensionInfo *xv_info = &_xv_info_data;
63static char *xv_extension_name = XvName;
64static char *xv_error_string(Display *dpy, int code, XExtCodes *codes,
65                             char * buf, int n);
66static int xv_close_display(Display *dpy, XExtCodes *codes);
67static Bool xv_wire_to_event(Display *dpy, XEvent *host, xEvent *wire);
68
69static XExtensionHooks xv_extension_hooks = {
70    NULL,                               /* create_gc */
71    NULL,                               /* copy_gc */
72    NULL,                               /* flush_gc */
73    NULL,                               /* free_gc */
74    NULL,                               /* create_font */
75    NULL,                               /* free_font */
76    xv_close_display,                   /* close_display */
77    xv_wire_to_event,                   /* wire_to_event */
78    NULL,                               /* event_to_wire */
79    NULL,                               /* error */
80    xv_error_string                     /* error_string */
81};
82
83
84static char *xv_error_list[] =
85{
86   "BadPort",       /* XvBadPort     */
87   "BadEncoding",   /* XvBadEncoding */
88   "BadControl"     /* XvBadControl  */
89};
90
91
92#define XvCheckExtension(dpy, i, val) \
93  XextCheckExtension(dpy, i, xv_extension_name, val)
94#define XvGetReq(name, req) \
95        WORD64ALIGN\
96        if ((dpy->bufptr + SIZEOF(xv##name##Req)) > dpy->bufmax)\
97                _XFlush(dpy);\
98        req = (xv##name##Req *)(dpy->last_req = dpy->bufptr);\
99        req->reqType = info->codes->major_opcode;\
100        req->xvReqType = xv_##name; \
101        req->length = (SIZEOF(xv##name##Req))>>2;\
102        dpy->bufptr += SIZEOF(xv##name##Req);\
103        dpy->request++
104
105static XEXT_GENERATE_CLOSE_DISPLAY (xv_close_display, xv_info)
106
107
108static XEXT_GENERATE_FIND_DISPLAY (xv_find_display, xv_info,
109                                   xv_extension_name,
110                                   &xv_extension_hooks,
111                                   XvNumEvents, NULL)
112
113static XEXT_GENERATE_ERROR_STRING (xv_error_string, xv_extension_name,
114                                   XvNumErrors, xv_error_list)
115
116struct _EphyrHostXVAdaptorArray {
117    XvAdaptorInfo *adaptors ;
118    unsigned int nb_adaptors ;
119};
120
121/*heavily copied from libx11*/
122#define BUFSIZE 2048
123static void
124ephyrHostXVLogXErrorEvent (Display *a_display,
125                           XErrorEvent *a_err_event,
126                           FILE *a_fp)
127{
128    char buffer[BUFSIZ];
129    char mesg[BUFSIZ];
130    char number[32];
131    const char *mtype = "XlibMessage";
132    register _XExtension *ext = (_XExtension *)NULL;
133    _XExtension *bext = (_XExtension *)NULL;
134    Display *dpy = a_display ;
135
136    XGetErrorText(dpy, a_err_event->error_code, buffer, BUFSIZ);
137    XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ);
138    (void) fprintf(a_fp, "%s:  %s\n  ", mesg, buffer);
139    XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d",
140            mesg, BUFSIZ);
141    (void) fprintf(a_fp, mesg, a_err_event->request_code);
142    if (a_err_event->request_code < 128) {
143        sprintf(number, "%d", a_err_event->request_code);
144        XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ);
145    } else {
146        for (ext = dpy->ext_procs;
147                ext && (ext->codes.major_opcode != a_err_event->request_code);
148                ext = ext->next)
149            ;
150        if (ext)
151            strcpy(buffer, ext->name);
152        else
153            buffer[0] = '\0';
154    }
155    (void) fprintf(a_fp, " (%s)\n", buffer);
156    if (a_err_event->request_code >= 128) {
157        XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d",
158                mesg, BUFSIZ);
159        fputs("  ", a_fp);
160        (void) fprintf(a_fp, mesg, a_err_event->minor_code);
161        if (ext) {
162            sprintf(mesg, "%s.%d", ext->name, a_err_event->minor_code);
163            XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ);
164            (void) fprintf(a_fp, " (%s)", buffer);
165        }
166        fputs("\n", a_fp);
167    }
168    if (a_err_event->error_code >= 128) {
169        /* kludge, try to find the extension that caused it */
170        buffer[0] = '\0';
171        for (ext = dpy->ext_procs; ext; ext = ext->next) {
172            if (ext->error_string)
173                (*ext->error_string)(dpy, a_err_event->error_code, &ext->codes,
174                        buffer, BUFSIZ);
175            if (buffer[0]) {
176                bext = ext;
177                break;
178            }
179            if (ext->codes.first_error &&
180                    ext->codes.first_error < (int)a_err_event->error_code &&
181                    (!bext || ext->codes.first_error > bext->codes.first_error))
182                bext = ext;
183        }
184        if (bext)
185            sprintf(buffer, "%s.%d", bext->name,
186                    a_err_event->error_code - bext->codes.first_error);
187        else
188            strcpy(buffer, "Value");
189        XGetErrorDatabaseText(dpy, mtype, buffer, "", mesg, BUFSIZ);
190        if (mesg[0]) {
191            fputs("  ", a_fp);
192            (void) fprintf(a_fp, mesg, a_err_event->resourceid);
193            fputs("\n", a_fp);
194        }
195        /* let extensions try to print the values */
196        for (ext = dpy->ext_procs; ext; ext = ext->next) {
197            if (ext->error_values)
198                (*ext->error_values)(dpy, a_err_event, a_fp);
199        }
200    } else if ((a_err_event->error_code == BadWindow) ||
201            (a_err_event->error_code == BadPixmap) ||
202            (a_err_event->error_code == BadCursor) ||
203            (a_err_event->error_code == BadFont) ||
204            (a_err_event->error_code == BadDrawable) ||
205            (a_err_event->error_code == BadColor) ||
206            (a_err_event->error_code == BadGC) ||
207            (a_err_event->error_code == BadIDChoice) ||
208            (a_err_event->error_code == BadValue) ||
209            (a_err_event->error_code == BadAtom)) {
210        if (a_err_event->error_code == BadValue)
211            XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x",
212                    mesg, BUFSIZ);
213        else if (a_err_event->error_code == BadAtom)
214            XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x",
215                    mesg, BUFSIZ);
216        else
217            XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
218                    mesg, BUFSIZ);
219        fputs("  ", a_fp);
220        (void) fprintf(a_fp, mesg, a_err_event->resourceid);
221        fputs("\n", a_fp);
222    }
223    XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d",
224            mesg, BUFSIZ);
225    fputs("  ", a_fp);
226    (void) fprintf(a_fp, mesg, a_err_event->serial);
227    XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
228            mesg, BUFSIZ);
229    fputs("\n  ", a_fp);
230    (void) fprintf(a_fp, mesg, dpy->request);
231    fputs("\n", a_fp);
232}
233
234static int
235ephyrHostXVErrorHandler (Display *a_display,
236                         XErrorEvent *a_error_event)
237{
238    EPHYR_LOG_ERROR ("got an error from the host xserver:\n") ;
239    ephyrHostXVLogXErrorEvent (a_display, a_error_event, stderr) ;
240    return Success ;
241}
242
243void
244ephyrHostXVInit (void)
245{
246    static Bool s_initialized ;
247
248    if (s_initialized)
249        return ;
250    XSetErrorHandler (ephyrHostXVErrorHandler) ;
251    s_initialized = TRUE ;
252}
253
254Bool
255ephyrHostXVQueryAdaptors (EphyrHostXVAdaptorArray **a_adaptors)
256{
257    EphyrHostXVAdaptorArray *result=NULL ;
258    int ret=0 ;
259    Bool is_ok=FALSE ;
260
261    EPHYR_RETURN_VAL_IF_FAIL (a_adaptors, FALSE) ;
262
263    EPHYR_LOG ("enter\n") ;
264
265    result = calloc (1, sizeof (EphyrHostXVAdaptorArray)) ;
266    if (!result)
267        goto out ;
268
269    ret = XvQueryAdaptors (hostx_get_display (),
270                           DefaultRootWindow (hostx_get_display ()),
271                           &result->nb_adaptors,
272                           &result->adaptors) ;
273    if (ret != Success) {
274        EPHYR_LOG_ERROR ("failed to query host adaptors: %d\n", ret) ;
275        goto out ;
276    }
277    *a_adaptors = result ;
278    is_ok = TRUE ;
279
280out:
281    EPHYR_LOG ("leave\n") ;
282    return is_ok ;
283}
284
285void
286ephyrHostXVAdaptorArrayDelete (EphyrHostXVAdaptorArray *a_adaptors)
287{
288    if (!a_adaptors)
289        return ;
290    if (a_adaptors->adaptors) {
291        XvFreeAdaptorInfo (a_adaptors->adaptors) ;
292        a_adaptors->adaptors = NULL ;
293        a_adaptors->nb_adaptors = 0 ;
294    }
295    XFree (a_adaptors) ;
296}
297
298int
299ephyrHostXVAdaptorArrayGetSize (const EphyrHostXVAdaptorArray *a_this)
300{
301    EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ;
302    return a_this->nb_adaptors ;
303}
304
305EphyrHostXVAdaptor*
306ephyrHostXVAdaptorArrayAt (const EphyrHostXVAdaptorArray *a_this,
307                           int a_index)
308{
309    EPHYR_RETURN_VAL_IF_FAIL (a_this, NULL) ;
310
311    if (a_index >= a_this->nb_adaptors)
312        return NULL ;
313    return (EphyrHostXVAdaptor*)&a_this->adaptors[a_index] ;
314}
315
316char
317ephyrHostXVAdaptorGetType (const EphyrHostXVAdaptor *a_this)
318{
319    EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ;
320    return ((XvAdaptorInfo*)a_this)->type ;
321}
322
323const char*
324ephyrHostXVAdaptorGetName (const EphyrHostXVAdaptor *a_this)
325{
326    EPHYR_RETURN_VAL_IF_FAIL (a_this, NULL) ;
327
328    return ((XvAdaptorInfo*)a_this)->name ;
329}
330
331EphyrHostVideoFormat*
332ephyrHostXVAdaptorGetVideoFormats (const EphyrHostXVAdaptor *a_this,
333                                   int *a_nb_formats)
334{
335    EphyrHostVideoFormat *formats=NULL ;
336    int nb_formats=0, i=0 ;
337    XVisualInfo *visual_info, visual_info_template ;
338    int nb_visual_info ;
339
340    EPHYR_RETURN_VAL_IF_FAIL (a_this, NULL) ;
341
342    nb_formats = ((XvAdaptorInfo*)a_this)->num_formats ;
343    formats = calloc (nb_formats, sizeof (EphyrHostVideoFormat)) ;
344    for (i=0; i < nb_formats; i++) {
345        memset (&visual_info_template, 0, sizeof (visual_info_template)) ;
346        visual_info_template.visualid =
347                            ((XvAdaptorInfo*)a_this)->formats[i].visual_id;
348        visual_info = XGetVisualInfo (hostx_get_display (),
349                                      VisualIDMask,
350                                      &visual_info_template,
351                                      &nb_visual_info) ;
352        formats[i].depth = ((XvAdaptorInfo*)a_this)->formats[i].depth ;
353        formats[i].visual_class = visual_info->class ;
354        XFree (visual_info) ;
355    }
356    if (a_nb_formats)
357        *a_nb_formats = nb_formats ;
358    return formats ;
359}
360
361int
362ephyrHostXVAdaptorGetNbPorts (const EphyrHostXVAdaptor *a_this)
363{
364    EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ;
365
366    return ((XvAdaptorInfo*)a_this)->num_ports ;
367}
368
369int
370ephyrHostXVAdaptorGetFirstPortID (const EphyrHostXVAdaptor *a_this)
371{
372    EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ;
373
374    return ((XvAdaptorInfo*)a_this)->base_id ;
375}
376
377Bool
378ephyrHostXVAdaptorHasPutVideo (const EphyrHostXVAdaptor *a_this,
379                               Bool *a_result)
380{
381    EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ;
382
383    if ((((XvAdaptorInfo*)a_this)->type & (XvVideoMask | XvInputMask)) ==
384		    (XvVideoMask | XvInputMask))
385        *a_result = TRUE ;
386    else
387        *a_result = FALSE ;
388    return TRUE ;
389}
390
391Bool
392ephyrHostXVAdaptorHasGetVideo (const EphyrHostXVAdaptor *a_this,
393                               Bool *a_result)
394{
395    if ((((XvAdaptorInfo*)a_this)->type & (XvVideoMask | XvOutputMask)) ==
396		    (XvVideoMask | XvOutputMask))
397        *a_result = TRUE ;
398    else
399        *a_result = FALSE ;
400    return TRUE ;
401}
402
403Bool
404ephyrHostXVAdaptorHasPutStill (const EphyrHostXVAdaptor *a_this,
405                               Bool *a_result)
406{
407    EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ;
408
409    if ((((XvAdaptorInfo*)a_this)->type & (XvStillMask | XvInputMask)) ==
410		    (XvStillMask | XvInputMask))
411        *a_result = TRUE ;
412    else
413        *a_result = FALSE ;
414    return TRUE ;
415}
416
417Bool
418ephyrHostXVAdaptorHasGetStill (const EphyrHostXVAdaptor *a_this,
419                               Bool *a_result)
420{
421    EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ;
422
423    if ((((XvAdaptorInfo*)a_this)->type & (XvStillMask | XvOutputMask)) ==
424		    (XvStillMask | XvOutputMask))
425        *a_result = TRUE ;
426    else
427        *a_result = FALSE ;
428    return TRUE ;
429}
430
431Bool
432ephyrHostXVAdaptorHasPutImage (const EphyrHostXVAdaptor *a_this,
433                               Bool *a_result)
434{
435    EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ;
436
437    if ((((XvAdaptorInfo*)a_this)->type & (XvImageMask | XvInputMask)) ==
438		    (XvImageMask | XvInputMask))
439        *a_result = TRUE ;
440    else
441        *a_result = FALSE ;
442    return TRUE ;
443}
444
445Bool
446ephyrHostXVQueryEncodings (int a_port_id,
447                           EphyrHostEncoding **a_encodings,
448                           unsigned int *a_num_encodings)
449{
450    EphyrHostEncoding *encodings=NULL ;
451    XvEncodingInfo *encoding_info=NULL ;
452    unsigned int num_encodings=0, i;
453    int ret=0 ;
454
455    EPHYR_RETURN_VAL_IF_FAIL (a_encodings && a_num_encodings, FALSE) ;
456
457    ret = XvQueryEncodings (hostx_get_display (),
458                            a_port_id,
459                            &num_encodings,
460                            &encoding_info) ;
461    if (num_encodings && encoding_info) {
462        encodings = calloc (num_encodings, sizeof (EphyrHostEncoding)) ;
463        for (i=0; i<num_encodings; i++) {
464            encodings[i].id = encoding_info[i].encoding_id ;
465            encodings[i].name = strdup (encoding_info[i].name) ;
466            encodings[i].width = encoding_info[i].width ;
467            encodings[i].height = encoding_info[i].height ;
468            encodings[i].rate.numerator = encoding_info[i].rate.numerator ;
469            encodings[i].rate.denominator = encoding_info[i].rate.denominator ;
470        }
471    }
472    if (encoding_info) {
473        XvFreeEncodingInfo (encoding_info) ;
474        encoding_info = NULL ;
475    }
476    *a_encodings = encodings ;
477    *a_num_encodings = num_encodings ;
478
479    if (ret != Success)
480        return FALSE ;
481    return TRUE ;
482}
483
484void
485ephyrHostEncodingsDelete (EphyrHostEncoding *a_encodings,
486                          int a_num_encodings)
487{
488    int i=0 ;
489
490    if (!a_encodings)
491        return ;
492    for (i=0; i < a_num_encodings; i++) {
493        free(a_encodings[i].name) ;
494        a_encodings[i].name = NULL ;
495    }
496    free(a_encodings) ;
497}
498
499void
500ephyrHostAttributesDelete (EphyrHostAttribute *a_attributes)
501{
502    if (!a_attributes)
503        return ;
504    XFree (a_attributes) ;
505}
506
507Bool
508ephyrHostXVQueryPortAttributes (int a_port_id,
509                                EphyrHostAttribute **a_attributes,
510                                int *a_num_attributes)
511{
512    EPHYR_RETURN_VAL_IF_FAIL (a_attributes && a_num_attributes, FALSE) ;
513
514    *a_attributes =
515        (EphyrHostAttribute*)XvQueryPortAttributes (hostx_get_display (),
516                                                    a_port_id,
517                                                    a_num_attributes);
518
519    return TRUE ;
520}
521
522Bool
523ephyrHostXVQueryImageFormats (int a_port_id,
524                              EphyrHostImageFormat **a_formats,
525                              int *a_num_format)
526{
527    XvImageFormatValues *result=NULL ;
528
529    EPHYR_RETURN_VAL_IF_FAIL (a_formats && a_num_format, FALSE) ;
530
531    result = XvListImageFormats (hostx_get_display (),
532                                 a_port_id,
533                                 a_num_format) ;
534    *a_formats = (EphyrHostImageFormat*) result ;
535    return TRUE ;
536
537}
538
539Bool
540ephyrHostXVSetPortAttribute (int a_port_id,
541                             int a_atom,
542                             int a_attr_value)
543{
544    int res=Success ;
545
546    EPHYR_LOG ("atom,name,value: (%d,%s,%d)\n",
547               a_atom,
548               XGetAtomName (hostx_get_display (), a_atom),
549               a_attr_value) ;
550
551    res = XvSetPortAttribute (hostx_get_display (),
552                              a_port_id,
553                              a_atom,
554                              a_attr_value) ;
555    if (res != Success) {
556        EPHYR_LOG_ERROR ("XvSetPortAttribute() failed: %d\n", res) ;
557        return FALSE ;
558    }
559    XFlush (hostx_get_display ()) ;
560    EPHYR_LOG ("leave\n") ;
561
562    return TRUE ;
563}
564
565Bool
566ephyrHostXVGetPortAttribute (int a_port_id,
567                             int a_atom,
568                             int *a_attr_value)
569{
570    int res=Success ;
571    Bool ret=FALSE ;
572
573    EPHYR_RETURN_VAL_IF_FAIL (a_attr_value, FALSE) ;
574
575    EPHYR_LOG ("enter, a_port_id: %d, a_atomid: %d, attr_name: %s\n",
576               a_port_id, a_atom, XGetAtomName (hostx_get_display (), a_atom)) ;
577
578    res = XvGetPortAttribute (hostx_get_display (),
579                              a_port_id,
580                              a_atom,
581                              a_attr_value) ;
582    if (res != Success) {
583        EPHYR_LOG_ERROR ("XvGetPortAttribute() failed: %d \n", res) ;
584        goto out ;
585    }
586    EPHYR_LOG ("atom,value: (%d, %d)\n", a_atom, *a_attr_value) ;
587
588    ret = TRUE ;
589
590out:
591    EPHYR_LOG ("leave\n") ;
592    return ret ;
593}
594
595Bool
596ephyrHostXVQueryBestSize (int a_port_id,
597                          Bool a_motion,
598                          unsigned int a_frame_w,
599                          unsigned int a_frame_h,
600                          unsigned int a_drw_w,
601                          unsigned int a_drw_h,
602                          unsigned int *a_actual_w,
603                          unsigned int *a_actual_h)
604{
605    int res=0 ;
606    Bool is_ok=FALSE ;
607
608    EPHYR_RETURN_VAL_IF_FAIL (a_actual_w && a_actual_h, FALSE) ;
609
610    EPHYR_LOG ("enter: frame (%dx%d), drw (%dx%d)\n",
611               a_frame_w, a_frame_h,
612               a_drw_w, a_drw_h) ;
613
614    res = XvQueryBestSize (hostx_get_display (),
615                           a_port_id,
616                           a_motion,
617                           a_frame_w, a_frame_h,
618                           a_drw_w, a_drw_h,
619                           a_actual_w, a_actual_h) ;
620    if (res != Success) {
621        EPHYR_LOG_ERROR ("XvQueryBestSize() failed: %d\n", res) ;
622        goto out ;
623    }
624    XSync (hostx_get_display (), FALSE) ;
625
626    EPHYR_LOG ("actual (%dx%d)\n", *a_actual_w, *a_actual_h) ;
627    is_ok = TRUE ;
628
629out:
630    EPHYR_LOG ("leave\n") ;
631    return is_ok ;
632}
633
634static Bool
635xv_wire_to_event(Display *dpy, XEvent *host, xEvent *wire)
636{
637    XExtDisplayInfo *info = xv_find_display (dpy);
638    XvEvent *re    = (XvEvent *)host;
639    xvEvent *event = (xvEvent *)wire;
640
641    XvCheckExtension(dpy, info, False);
642
643    switch ((event->u.u.type & 0x7F) - info->codes->first_event) {
644        case XvVideoNotify:
645            re->xvvideo.type = event->u.u.type & 0x7f;
646            re->xvvideo.serial =
647            _XSetLastRequestRead(dpy, (xGenericReply *)event);
648            re->xvvideo.send_event = ((event->u.u.type & 0x80) != 0);
649            re->xvvideo.display = dpy;
650            re->xvvideo.time = event->u.videoNotify.time;
651            re->xvvideo.reason = event->u.videoNotify.reason;
652            re->xvvideo.drawable = event->u.videoNotify.drawable;
653            re->xvvideo.port_id = event->u.videoNotify.port;
654            break;
655        case XvPortNotify:
656            re->xvport.type = event->u.u.type & 0x7f;
657            re->xvport.serial =
658            _XSetLastRequestRead(dpy, (xGenericReply *)event);
659            re->xvport.send_event = ((event->u.u.type & 0x80) != 0);
660            re->xvport.display = dpy;
661            re->xvport.time = event->u.portNotify.time;
662            re->xvport.port_id = event->u.portNotify.port;
663            re->xvport.attribute = event->u.portNotify.attribute;
664            re->xvport.value = event->u.portNotify.value;
665            break;
666        default:
667            return False;
668    }
669
670    return True ;
671}
672
673Bool
674ephyrHostXVQueryImageAttributes (int a_port_id,
675                                 int a_image_id /*image fourcc code*/,
676                                 unsigned short *a_width,
677                                 unsigned short *a_height,
678                                 int *a_image_size,
679                                 int *a_pitches,
680                                 int *a_offsets)
681{
682    Display *dpy = hostx_get_display () ;
683    Bool ret=FALSE ;
684    XExtDisplayInfo *info = xv_find_display (dpy);
685    xvQueryImageAttributesReq *req=NULL;
686    xvQueryImageAttributesReply rep;
687
688    EPHYR_RETURN_VAL_IF_FAIL (a_width, FALSE) ;
689    EPHYR_RETURN_VAL_IF_FAIL (a_height, FALSE) ;
690    EPHYR_RETURN_VAL_IF_FAIL (a_image_size, FALSE) ;
691
692    XvCheckExtension (dpy, info, FALSE);
693
694    LockDisplay (dpy);
695
696    XvGetReq (QueryImageAttributes, req);
697    req->id = a_image_id;
698    req->port = a_port_id;
699    req->width = *a_width;
700    req->height = *a_height;
701    /*
702     * read the reply
703     */
704    if (!_XReply (dpy, (xReply *)&rep, 0, xFalse)) {
705        EPHYR_LOG_ERROR ("QeryImageAttribute req failed\n") ;
706        goto out ;
707    }
708    if (a_pitches && a_offsets) {
709        _XRead (dpy,
710                (char*)a_pitches,
711                rep.num_planes << 2);
712        _XRead (dpy,
713                (char*)a_offsets,
714                rep.num_planes << 2);
715    } else {
716        _XEatData(dpy, rep.length << 2);
717    }
718    *a_width = rep.width ;
719    *a_height = rep.height ;
720    *a_image_size = rep.data_size ;
721
722    ret = TRUE ;
723
724out:
725    UnlockDisplay (dpy) ;
726    SyncHandle ();
727    return ret ;
728}
729
730Bool
731ephyrHostGetAtom (const char* a_name,
732                  Bool a_create_if_not_exists,
733                  int *a_atom)
734{
735    int atom=None ;
736
737    EPHYR_RETURN_VAL_IF_FAIL (a_atom, FALSE) ;
738
739    atom = XInternAtom (hostx_get_display (), a_name, a_create_if_not_exists);
740    if (atom == None) {
741        return FALSE ;
742    }
743    *a_atom = atom ;
744    return TRUE ;
745}
746
747char*
748ephyrHostGetAtomName (int a_atom)
749{
750    return XGetAtomName (hostx_get_display (), a_atom) ;
751}
752
753void
754ephyrHostFree (void *a_pointer)
755{
756    if (a_pointer)
757        XFree (a_pointer) ;
758}
759
760Bool
761ephyrHostXVPutImage (int a_screen_num,
762                     int a_port_id,
763                     int a_image_id,
764                     int a_drw_x,
765                     int a_drw_y,
766                     int a_drw_w,
767                     int a_drw_h,
768                     int a_src_x,
769                     int a_src_y,
770                     int a_src_w,
771                     int a_src_h,
772                     int a_image_width,
773                     int a_image_height,
774                     unsigned char *a_buf,
775                     EphyrHostBox *a_clip_rects,
776                     int a_clip_rect_nums )
777{
778    Bool is_ok=TRUE ;
779    XvImage *xv_image=NULL ;
780    GC gc=0 ;
781    XGCValues gc_values;
782    Display *dpy = hostx_get_display () ;
783    XRectangle *rects=NULL ;
784    int res = 0 ;
785
786    EPHYR_RETURN_VAL_IF_FAIL (a_buf, FALSE) ;
787
788    EPHYR_LOG ("enter, num_clip_rects: %d\n", a_clip_rect_nums) ;
789
790    memset (&gc_values, 0, sizeof (gc_values)) ;
791    gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values);
792    if (!gc) {
793        EPHYR_LOG_ERROR ("failed to create gc \n") ;
794        goto out ;
795    }
796    xv_image = (XvImage*) XvCreateImage (hostx_get_display (),
797                                         a_port_id, a_image_id,
798                                         NULL, a_image_width, a_image_height) ;
799    if (!xv_image) {
800        EPHYR_LOG_ERROR ("failed to create image\n") ;
801        goto out ;
802    }
803    xv_image->data = (char*)a_buf ;
804    if (a_clip_rect_nums) {
805        int i=0 ;
806        rects = calloc (a_clip_rect_nums, sizeof (XRectangle)) ;
807        for (i=0; i < a_clip_rect_nums; i++) {
808            rects[i].x = a_clip_rects[i].x1 ;
809            rects[i].y = a_clip_rects[i].y1 ;
810            rects[i].width = a_clip_rects[i].x2 - a_clip_rects[i].x1;
811            rects[i].height = a_clip_rects[i].y2 - a_clip_rects[i].y1;
812            EPHYR_LOG ("(x,y,w,h): (%d,%d,%d,%d)\n",
813                       rects[i].x, rects[i].y,
814                       rects[i].width, rects[i].height) ;
815        }
816        XSetClipRectangles (dpy, gc, 0, 0, rects, a_clip_rect_nums, YXBanded) ;
817        /*this always returns 1*/
818    }
819    res = XvPutImage (dpy, a_port_id,
820                      hostx_get_window (a_screen_num),
821                      gc, xv_image,
822                      a_src_x, a_src_y, a_src_w, a_src_h,
823                      a_drw_x, a_drw_y, a_drw_w, a_drw_h) ;
824    if (res != Success) {
825        EPHYR_LOG_ERROR ("XvPutImage() failed: %d\n", res) ;
826        goto out ;
827    }
828    is_ok = TRUE ;
829
830out:
831    if (xv_image) {
832        XFree (xv_image) ;
833        xv_image = NULL ;
834    }
835    if (gc) {
836        XFreeGC (dpy, gc) ;
837        gc = NULL ;
838    }
839    free(rects);
840    rects = NULL;
841    EPHYR_LOG ("leave\n") ;
842    return is_ok ;
843}
844
845Bool
846ephyrHostXVPutVideo (int a_screen_num, int a_port_id,
847                     int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h,
848                     int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h)
849{
850    Bool is_ok=FALSE ;
851    int res=FALSE ;
852    GC gc=0 ;
853    XGCValues gc_values;
854    Display *dpy=hostx_get_display () ;
855
856    EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ;
857
858    gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values);
859    if (!gc) {
860        EPHYR_LOG_ERROR ("failed to create gc \n") ;
861        goto out ;
862    }
863    res = XvPutVideo (dpy, a_port_id, hostx_get_window (a_screen_num), gc,
864                      a_vid_x, a_vid_y, a_vid_w, a_vid_h,
865                      a_drw_x, a_drw_y, a_drw_w, a_drw_h) ;
866
867    if (res != Success) {
868        EPHYR_LOG_ERROR ("XvPutVideo() failed: %d\n", res) ;
869        goto out ;
870    }
871
872    is_ok = TRUE ;
873
874out:
875    if (gc) {
876        XFreeGC (dpy, gc) ;
877        gc = NULL ;
878    }
879    return is_ok ;
880}
881
882Bool
883ephyrHostXVGetVideo (int a_screen_num, int a_port_id,
884                     int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h,
885                     int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h)
886{
887    Bool is_ok=FALSE ;
888    int res=FALSE ;
889    GC gc=0 ;
890    XGCValues gc_values;
891    Display *dpy=hostx_get_display () ;
892
893    EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ;
894
895    gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values);
896    if (!gc) {
897        EPHYR_LOG_ERROR ("failed to create gc \n") ;
898        goto out ;
899    }
900    res = XvGetVideo (dpy, a_port_id, hostx_get_window (a_screen_num), gc,
901                      a_vid_x, a_vid_y, a_vid_w, a_vid_h,
902                      a_drw_x, a_drw_y, a_drw_w, a_drw_h) ;
903
904    if (res != Success) {
905        EPHYR_LOG_ERROR ("XvGetVideo() failed: %d\n", res) ;
906        goto out ;
907    }
908
909    is_ok = TRUE ;
910
911out:
912    if (gc) {
913        XFreeGC (dpy, gc) ;
914        gc = NULL ;
915    }
916    return is_ok ;
917}
918
919Bool
920ephyrHostXVPutStill (int a_screen_num, int a_port_id,
921                     int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h,
922                     int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h)
923{
924    Bool is_ok=FALSE ;
925    int res=FALSE ;
926    GC gc=0 ;
927    XGCValues gc_values;
928    Display *dpy=hostx_get_display () ;
929
930    EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ;
931
932    gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values);
933    if (!gc) {
934        EPHYR_LOG_ERROR ("failed to create gc \n") ;
935        goto out ;
936    }
937    res = XvPutStill (dpy, a_port_id, hostx_get_window (a_screen_num), gc,
938                      a_vid_x, a_vid_y, a_vid_w, a_vid_h,
939                      a_drw_x, a_drw_y, a_drw_w, a_drw_h) ;
940
941    if (res != Success) {
942        EPHYR_LOG_ERROR ("XvPutStill() failed: %d\n", res) ;
943        goto out ;
944    }
945
946    is_ok = TRUE ;
947
948out:
949    if (gc) {
950        XFreeGC (dpy, gc) ;
951        gc = NULL ;
952    }
953    return is_ok ;
954}
955
956Bool
957ephyrHostXVGetStill (int a_screen_num, int a_port_id,
958                     int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h,
959                     int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h)
960{
961    Bool is_ok=FALSE ;
962    int res=FALSE ;
963    GC gc=0 ;
964    XGCValues gc_values;
965    Display *dpy=hostx_get_display () ;
966
967    EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ;
968
969    gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values);
970    if (!gc) {
971        EPHYR_LOG_ERROR ("failed to create gc \n") ;
972        goto out ;
973    }
974    res = XvGetStill (dpy, a_port_id, hostx_get_window (a_screen_num), gc,
975                      a_vid_x, a_vid_y, a_vid_w, a_vid_h,
976                      a_drw_x, a_drw_y, a_drw_w, a_drw_h) ;
977
978    if (res != Success) {
979        EPHYR_LOG_ERROR ("XvGetStill() failed: %d\n", res) ;
980        goto out ;
981    }
982
983    is_ok = TRUE ;
984
985out:
986    if (gc) {
987        XFreeGC (dpy, gc) ;
988        gc = NULL ;
989    }
990    return is_ok ;
991}
992
993Bool
994ephyrHostXVStopVideo (int a_screen_num, int a_port_id)
995{
996    int ret=0 ;
997    Bool is_ok=FALSE ;
998    Display *dpy = hostx_get_display () ;
999
1000    EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ;
1001
1002    EPHYR_LOG ("enter\n") ;
1003
1004    ret = XvStopVideo (dpy, a_port_id, hostx_get_window (a_screen_num)) ;
1005    if (ret != Success) {
1006        EPHYR_LOG_ERROR ("XvStopVideo() failed: %d \n", ret) ;
1007        goto out ;
1008    }
1009    is_ok = TRUE ;
1010
1011out:
1012    EPHYR_LOG ("leave\n") ;
1013    return is_ok ;
1014}
1015
1016