332 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			332 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Copyright © 2013 Keith Packard
 | |
|  *
 | |
|  * Permission to use, copy, modify, distribute, and sell this software and its
 | |
|  * documentation for any purpose is hereby granted without fee, provided that
 | |
|  * the above copyright notice appear in all copies and that both that copyright
 | |
|  * notice and this permission notice appear in supporting documentation, and
 | |
|  * that the name of the copyright holders not be used in advertising or
 | |
|  * publicity pertaining to distribution of the software without specific,
 | |
|  * written prior permission.  The copyright holders make no representations
 | |
|  * about the suitability of this software for any purpose.  It is provided "as
 | |
|  * is" without express or implied warranty.
 | |
|  *
 | |
|  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | |
|  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | |
|  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | |
|  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | |
|  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | |
|  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 | |
|  * OF THIS SOFTWARE.
 | |
|  */
 | |
| 
 | |
| #ifdef HAVE_XORG_CONFIG_H
 | |
| #include <xorg-config.h>
 | |
| #endif
 | |
| 
 | |
| #include "present_priv.h"
 | |
| #include "randrstr.h"
 | |
| #include <protocol-versions.h>
 | |
| 
 | |
| static int
 | |
| proc_present_query_version(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xPresentQueryVersionReq);
 | |
|     xPresentQueryVersionReply rep = {
 | |
|         .type = X_Reply,
 | |
|         .sequenceNumber = client->sequence,
 | |
|         .length = 0,
 | |
|         .majorVersion = SERVER_PRESENT_MAJOR_VERSION,
 | |
|         .minorVersion = SERVER_PRESENT_MINOR_VERSION
 | |
|     };
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xPresentQueryVersionReq);
 | |
|     (void) stuff;
 | |
|     if (client->swapped) {
 | |
|         swaps(&rep.sequenceNumber);
 | |
|         swapl(&rep.length);
 | |
|         swapl(&rep.majorVersion);
 | |
|         swapl(&rep.minorVersion);
 | |
|     }
 | |
|     WriteToClient(client, sizeof(rep), &rep);
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| #define VERIFY_FENCE_OR_NONE(fence_ptr, fence_id, client, access) do {  \
 | |
|         if ((fence_id) == None)                                         \
 | |
|             (fence_ptr) = NULL;                                         \
 | |
|         else {                                                          \
 | |
|             int __rc__ = SyncVerifyFence(&fence_ptr, fence_id, client, access); \
 | |
|             if (__rc__ != Success)                                      \
 | |
|                 return __rc__;                                          \
 | |
|         }                                                               \
 | |
|     } while (0)
 | |
| 
 | |
| #define VERIFY_CRTC_OR_NONE(crtc_ptr, crtc_id, client, access) do {     \
 | |
|         if ((crtc_id) == None)                                          \
 | |
|             (crtc_ptr) = NULL;                                          \
 | |
|         else {                                                          \
 | |
|             VERIFY_RR_CRTC(crtc_id, crtc_ptr, access);                  \
 | |
|         }                                                               \
 | |
|     } while (0)
 | |
| 
 | |
| static int
 | |
| proc_present_pixmap(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xPresentPixmapReq);
 | |
|     WindowPtr           window;
 | |
|     PixmapPtr           pixmap;
 | |
|     RegionPtr           valid = NULL;
 | |
|     RegionPtr           update = NULL;
 | |
|     SyncFence           *wait_fence;
 | |
|     SyncFence           *idle_fence;
 | |
|     RRCrtcPtr           target_crtc;
 | |
|     int                 ret;
 | |
|     int                 nnotifies;
 | |
|     present_notify_ptr  notifies = NULL;
 | |
| 
 | |
|     REQUEST_AT_LEAST_SIZE(xPresentPixmapReq);
 | |
|     ret = dixLookupWindow(&window, stuff->window, client, DixWriteAccess);
 | |
|     if (ret != Success)
 | |
|         return ret;
 | |
|     ret = dixLookupResourceByType((pointer *) &pixmap, stuff->pixmap, RT_PIXMAP, client, DixReadAccess);
 | |
|     if (ret != Success)
 | |
|         return ret;
 | |
| 
 | |
|     if (window->drawable.depth != pixmap->drawable.depth)
 | |
|         return BadMatch;
 | |
| 
 | |
|     VERIFY_REGION_OR_NONE(valid, stuff->valid, client, DixReadAccess);
 | |
|     VERIFY_REGION_OR_NONE(update, stuff->update, client, DixReadAccess);
 | |
| 
 | |
|     VERIFY_CRTC_OR_NONE(target_crtc, stuff->target_crtc, client, DixReadAccess);
 | |
| 
 | |
|     VERIFY_FENCE_OR_NONE(wait_fence, stuff->wait_fence, client, DixReadAccess);
 | |
|     VERIFY_FENCE_OR_NONE(idle_fence, stuff->idle_fence, client, DixWriteAccess);
 | |
| 
 | |
|     if (stuff->options & ~(PresentAllOptions)) {
 | |
|         client->errorValue = stuff->options;
 | |
|         return BadValue;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * Check to see if remainder is sane
 | |
|      */
 | |
|     if (stuff->divisor == 0) {
 | |
|         if (stuff->remainder != 0) {
 | |
|             client->errorValue = (CARD32) stuff->remainder;
 | |
|             return BadValue;
 | |
|         }
 | |
|     } else {
 | |
|         if (stuff->remainder >= stuff->divisor) {
 | |
|             client->errorValue = (CARD32) stuff->remainder;
 | |
|             return BadValue;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     nnotifies = (client->req_len << 2) - sizeof (xPresentPixmapReq);
 | |
|     if (nnotifies % sizeof (xPresentNotify))
 | |
|         return BadLength;
 | |
| 
 | |
|     nnotifies /= sizeof (xPresentNotify);
 | |
|     if (nnotifies) {
 | |
|         ret = present_create_notifies(client, nnotifies, (xPresentNotify *) (stuff + 1), ¬ifies);
 | |
|         if (ret != Success)
 | |
|             return ret;
 | |
|     }
 | |
| 
 | |
|     ret = present_pixmap(window, pixmap, stuff->serial, valid, update,
 | |
|                          stuff->x_off, stuff->y_off, target_crtc,
 | |
|                          wait_fence, idle_fence, stuff->options,
 | |
|                          stuff->target_msc, stuff->divisor, stuff->remainder, notifies, nnotifies);
 | |
|     if (ret != Success)
 | |
|         present_destroy_notifies(notifies, nnotifies);
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static int
 | |
| proc_present_notify_msc(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xPresentNotifyMSCReq);
 | |
|     WindowPtr   window;
 | |
|     int         rc;
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xPresentNotifyMSCReq);
 | |
|     rc = dixLookupWindow(&window, stuff->window, client, DixReadAccess);
 | |
|     if (rc != Success)
 | |
|         return rc;
 | |
| 
 | |
|     /*
 | |
|      * Check to see if remainder is sane
 | |
|      */
 | |
|     if (stuff->divisor == 0) {
 | |
|         if (stuff->remainder != 0) {
 | |
|             client->errorValue = (CARD32) stuff->remainder;
 | |
|             return BadValue;
 | |
|         }
 | |
|     } else {
 | |
|         if (stuff->remainder >= stuff->divisor) {
 | |
|             client->errorValue = (CARD32) stuff->remainder;
 | |
|             return BadValue;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return present_notify_msc(window, stuff->serial,
 | |
|                               stuff->target_msc, stuff->divisor, stuff->remainder);
 | |
| }
 | |
| 
 | |
| static int
 | |
| proc_present_select_input (ClientPtr client)
 | |
| {
 | |
|     REQUEST(xPresentSelectInputReq);
 | |
|     WindowPtr window;
 | |
|     int rc;
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xPresentSelectInputReq);
 | |
| 
 | |
|     LEGAL_NEW_RESOURCE(stuff->eid, client);
 | |
| 
 | |
|     rc = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
 | |
|     if (rc != Success)
 | |
|         return rc;
 | |
| 
 | |
|     if (stuff->eventMask & ~PresentAllEvents) {
 | |
|         client->errorValue = stuff->eventMask;
 | |
|         return BadValue;
 | |
|     }
 | |
|     return present_select_input(client, stuff->eid, window, stuff->eventMask);
 | |
| }
 | |
| 
 | |
| static int
 | |
| proc_present_query_capabilities (ClientPtr client)
 | |
| {
 | |
|     REQUEST(xPresentQueryCapabilitiesReq);
 | |
|     xPresentQueryCapabilitiesReply rep = {
 | |
|         .type = X_Reply,
 | |
|         .sequenceNumber = client->sequence,
 | |
|         .length = 0,
 | |
|     };
 | |
|     WindowPtr   window;
 | |
|     RRCrtcPtr   crtc = NULL;
 | |
|     int         r;
 | |
| 
 | |
|     r = dixLookupWindow(&window, stuff->target, client, DixGetAttrAccess);
 | |
|     switch (r) {
 | |
|     case Success:
 | |
|         crtc = present_get_crtc(window);
 | |
|         break;
 | |
|     case BadWindow:
 | |
|         VERIFY_RR_CRTC(stuff->target, crtc, DixGetAttrAccess);
 | |
|         break;
 | |
|     default:
 | |
|         return r;
 | |
|     }
 | |
| 
 | |
|     rep.capabilities = present_query_capabilities(crtc);
 | |
| 
 | |
|     if (client->swapped) {
 | |
|         swaps(&rep.sequenceNumber);
 | |
|         swapl(&rep.length);
 | |
|         swapl(&rep.capabilities);
 | |
|     }
 | |
|     WriteToClient(client, sizeof(rep), &rep);
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| int (*proc_present_vector[PresentNumberRequests]) (ClientPtr) = {
 | |
|     proc_present_query_version,            /* 0 */
 | |
|     proc_present_pixmap,                   /* 1 */
 | |
|     proc_present_notify_msc,               /* 2 */
 | |
|     proc_present_select_input,             /* 3 */
 | |
|     proc_present_query_capabilities,       /* 4 */
 | |
| };
 | |
| 
 | |
| int
 | |
| proc_present_dispatch(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xReq);
 | |
|     if (stuff->data >= PresentNumberRequests || !proc_present_vector[stuff->data])
 | |
|         return BadRequest;
 | |
|     return (*proc_present_vector[stuff->data]) (client);
 | |
| }
 | |
| 
 | |
| static int
 | |
| sproc_present_query_version(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xPresentQueryVersionReq);
 | |
| 
 | |
|     swaps(&stuff->length);
 | |
|     swapl(&stuff->majorVersion);
 | |
|     swapl(&stuff->minorVersion);
 | |
|     return (*proc_present_vector[stuff->presentReqType]) (client);
 | |
| }
 | |
| 
 | |
| static int
 | |
| sproc_present_pixmap(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xPresentPixmapReq);
 | |
| 
 | |
|     swaps(&stuff->length);
 | |
|     swapl(&stuff->window);
 | |
|     swapl(&stuff->pixmap);
 | |
|     swapl(&stuff->valid);
 | |
|     swapl(&stuff->update);
 | |
|     swaps(&stuff->x_off);
 | |
|     swaps(&stuff->y_off);
 | |
|     swapll(&stuff->target_msc);
 | |
|     swapll(&stuff->divisor);
 | |
|     swapll(&stuff->remainder);
 | |
|     swapl(&stuff->idle_fence);
 | |
|     return (*proc_present_vector[stuff->presentReqType]) (client);
 | |
| }
 | |
| 
 | |
| static int
 | |
| sproc_present_notify_msc(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xPresentNotifyMSCReq);
 | |
| 
 | |
|     swaps(&stuff->length);
 | |
|     swapl(&stuff->window);
 | |
|     swapll(&stuff->target_msc);
 | |
|     swapll(&stuff->divisor);
 | |
|     swapll(&stuff->remainder);
 | |
|     return (*proc_present_vector[stuff->presentReqType]) (client);
 | |
| }
 | |
| 
 | |
| static int
 | |
| sproc_present_select_input (ClientPtr client)
 | |
| {
 | |
|     REQUEST(xPresentSelectInputReq);
 | |
| 
 | |
|     swaps(&stuff->length);
 | |
|     swapl(&stuff->window);
 | |
|     swapl(&stuff->eventMask);
 | |
|     return (*proc_present_vector[stuff->presentReqType]) (client);
 | |
| }
 | |
| 
 | |
| static int
 | |
| sproc_present_query_capabilities (ClientPtr client)
 | |
| {
 | |
|     REQUEST(xPresentQueryCapabilitiesReq);
 | |
|     swaps(&stuff->length);
 | |
|     swapl(&stuff->target);
 | |
|     return (*proc_present_vector[stuff->presentReqType]) (client);
 | |
| }
 | |
| 
 | |
| int (*sproc_present_vector[PresentNumberRequests]) (ClientPtr) = {
 | |
|     sproc_present_query_version,           /* 0 */
 | |
|     sproc_present_pixmap,                  /* 1 */
 | |
|     sproc_present_notify_msc,              /* 2 */
 | |
|     sproc_present_select_input,            /* 3 */
 | |
|     sproc_present_query_capabilities,      /* 4 */
 | |
| };
 | |
| 
 | |
| int
 | |
| sproc_present_dispatch(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xReq);
 | |
|     if (stuff->data >= PresentNumberRequests || !sproc_present_vector[stuff->data])
 | |
|         return BadRequest;
 | |
|     return (*sproc_present_vector[stuff->data]) (client);
 | |
| }
 |