text: /*
   * 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((void **) &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), &notifies);
          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;
  
      REQUEST_SIZE_MATCH(xPresentQueryCapabilitiesReq);
      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;
  }
  
  static 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);
      REQUEST_SIZE_MATCH(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);
      REQUEST_AT_LEAST_SIZE(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);
      REQUEST_SIZE_MATCH(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);
      REQUEST_SIZE_MATCH(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);
      REQUEST_SIZE_MATCH(xPresentQueryCapabilitiesReq);
      swaps(&stuff->length);
      swapl(&stuff->target);
      return (*proc_present_vector[stuff->presentReqType]) (client);
  }
  
  static 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);
  }
  