[Xcb] xcbrandr

Jeremy Kolb jkolb at brandeis.edu
Wed Feb 9 12:12:57 PST 2005


Here's my port of xrandr.  My computer doesn't support rotations but 
they should work, everything else worked fine on my machine.  Feel free 
to test it.

I didn't change the copyright notice, not sure if I have to or not.

Should this be put in xcb-demos?

Jeremy
-------------- next part --------------
/*
 * $XFree86: xc/programs/xrandr/xrandr.c,v 1.11 2002/10/14 18:01:43 keithp Exp $
 *
 * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
 * Copyright © 2002 Hewlett Pacard Company, Inc.
 *
 * 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 Keith Packard or HP not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Keith Packard and HP makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * KEITH PACKARD and HP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL KEITH PACKARD 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.
 *
 * Blame Jim Gettys for any bugs; he wrote most of the client side code,
 * and part of the server code for randr.
 *
 * Ported to XCB by Jeremy Kolb 2/8/2005
 */

#include <stdio.h>
#include <X11/XCB/xcb.h>
#include <X11/XCB/randr.h>
#include <X11/XCB/render.h>	/* we share subpixel information */
#include <string.h>
#include <stdlib.h>

#define CurrentTime 0L /* special time apparently*/

static char *program_name;

static char *direction[5] = {
  "normal", 
  "left", 
  "inverted", 
  "right",
  "\n"};

/* subpixel order */
static char *order[6] = {
  "unknown",
  "horizontal rgb",
  "horizontal bgr",
  "vertical rgb",
  "vertical bgr",
  "no subpixels"};


static void
usage(void)
{
  fprintf(stderr, "usage: %s [options]\n", program_name);
  fprintf(stderr, "  where options are:\n");
  fprintf(stderr, "  -display <display> or -d <display>\n");
  fprintf(stderr, "  -help\n");
  fprintf(stderr, "  -o <normal,inverted,left,right,0,1,2,3>\n");
  fprintf(stderr, "            or --orientation <normal,inverted,left,right,0,1,2,3>\n");
  fprintf(stderr, "  -q        or --query\n");
  fprintf(stderr, "  -s <size>/<width>x<height> or --size <size>/<width>x<height>\n");
  fprintf(stderr, "  -r <rate> or --rate <rate>\n");
  fprintf(stderr, "  -v        or --version\n");
  fprintf(stderr, "  -x        (reflect in x)\n");
  fprintf(stderr, "  -y        (reflect in y)\n");
  fprintf(stderr, "  --screen <screen>\n");
  fprintf(stderr, "  --verbose\n");
  
  exit(1);
  /*NOTREACHED*/
}

// Same idea as xc/lib/Xrandr.c (XRRConfigRates).
// Returns the rates for a given screen.
// Would be nice to put in another library or something.
short*
ConfigRates(XCBRandRGetScreenInfoRep *config, int sizeID, int *nrates)
{
    int i = 0;
    short *ents;
    XCBRandRRefreshRatesIter ri = XCBRandRGetScreenInfoRatesIter(config);
    
    while (i++ < sizeID) {
	XCBRandRRefreshRatesNext(&ri);
    }
    
    ents = XCBRandRRefreshRatesRates(ri.data);
    *nrates = XCBRandRRefreshRatesRatesLength(ri.data);
    
    if (!nrates) {
	*nrates = 0;
	return 0;
    }
    
    return ents;
}

int
main (int argc, char **argv)
{
  XCBConnection  *c;
  XCBRandRScreenSize *sizes;
  XCBRandRGetScreenInfoRep *sc;
  int		nsize;
  int		nrate;
  short		*rates;
  XCBSCREEN	*root;
  int		status = XCBRandRSetConfigFailed;
  int		rot = -1;
  int		verbose = 0, query = 0;
  short		rotation, current_rotation, rotations;
  XCBGenericEvent *event;
  XCBRandRScreenChangeNotifyEvent *sce;
  char          *display_name = NULL;
  char		*host;
  int		display;
  int 		i, j;
  int		current_size;
  short		current_rate;
  short		rate = -1;
  short		size = -1;
  int		dirind = 0;
  static int	setit = 0;
  int		screen = -1;
  int		version = 0;
  int		event_base, error_base;
  short		reflection = 0;
  int		width = 0, height = 0;
  int		have_pixel_size = 0;
  XCBGenericError *err;

  program_name = argv[0];
  if (argc == 1) query = 1;
  for (i = 1; i < argc; i++) {
    if (!strcmp ("-display", argv[i]) || !strcmp ("-d", argv[i])) {
      if (++i>=argc) usage ();
      display_name = argv[i];
      continue;
    }
    if (!strcmp("-help", argv[i])) {
      usage();
      continue;
    }
    if (!strcmp ("--verbose", argv[i])) {
      verbose = 1;
      continue;
    }

    if (!strcmp ("-s", argv[i]) || !strcmp ("--size", argv[i])) {
      if (++i>=argc) usage ();
      if (sscanf (argv[i], "%dx%d", &width, &height) == 2)
	have_pixel_size = 1;
      else {
	size = atoi (argv[i]);
	if (size < 0) usage();
      }
      setit = 1;
      continue;
    }

    if (!strcmp ("-r", argv[i]) || !strcmp ("--rate", argv[i])) {
      if (++i>=argc) usage ();
      rate = atoi (argv[i]);
      if (rate < 0) usage();
      setit = 1;
      continue;
    }

    if (!strcmp ("-v", argv[i]) || !strcmp ("--version", argv[i])) {
      version = 1;
      continue;
    }

    if (!strcmp ("-x", argv[i])) {
      reflection |= XCBRandRRotationReflect_X;
      setit = 1;
      continue;
    }
    if (!strcmp ("-y", argv[i])) {
      reflection |= XCBRandRRotationReflect_Y;
      setit = 1;
      continue;
    }
    if (!strcmp ("--screen", argv[i])) {
      if (++i>=argc) usage ();
      screen = atoi (argv[i]);
      if (screen < 0) usage();
      continue;
    }
    if (!strcmp ("-q", argv[i]) || !strcmp ("--query", argv[i])) {
      query = 1;
      continue;
    }
    if (!strcmp ("-o", argv[i]) || !strcmp ("--orientation", argv[i])) {
      char *endptr;
      if (++i>=argc) usage ();
      dirind = strtol(argv[i], &endptr, 0);
      if (*endptr != '\0') {
	for (dirind = 0; dirind < 4; dirind++) {
	  if (strcmp (direction[dirind], argv[i]) == 0) break;
	}
	if ((dirind < 0) || (dirind > 3))  usage();
      }
      rot = dirind;
      setit = 1;
      continue;
    }
    
    usage();
  }
 
  if (verbose) query = 1;

  if (!XCBParseDisplay(display_name, &host, &display, &screen)) {
      fprintf(stderr, "Invalid DISPLAY\n");
      exit(1);
  }

  int fd = XCBOpen(host, display);
  free(host);
  if (fd == -1) {
      fprintf(stderr, "Error: XCBOpen\n");
      exit(1);
  }

  /* Now we open the connection */
  XCBAuthInfo auth;
  XCBGetAuthInfo(fd, &auth);
  c = XCBConnect(fd, &auth);

  /* Free auth data */
  free(auth.name);
  free(auth.data);
  
  if (!c) {
      fprintf (stderr, "Can't open display %s\n", display_name);
      exit (1);
  }
  if (screen < 0)
    screen = 0;

/* TODO: Figure out a way to do this later...
  if (screen >= ScreenCount (c)) {
    fprintf (stderr, "Invalid screen number %d (display has %d)\n",
	     screen, ScreenCount (c));
    exit (1);
  }
*/
		
  root = XCBConnSetupSuccessRepRootsIter(XCBGetSetup(c)).data;
  XCBRandRGetScreenInfoCookie scookie;

  int major_version, minor_version;
  XCBRandRQueryVersionRep *rr_version;
  rr_version = XCBRandRQueryVersionReply(c, XCBRandRQueryVersion(c, 1, 1), &err);
  major_version = rr_version->major_version;
  minor_version = rr_version->minor_version;

  scookie = XCBRandRGetScreenInfo(c, root->root);
  sc = XCBRandRGetScreenInfoReply(c, scookie, &err);

  if (sc == NULL || err) {
	fprintf(stderr, "Can't get screen info.\n");
	exit (1);
  }

  current_rotation = sc->rotation;
  current_size = sc->sizeID;
  
  nsize = sc->nSizes;
  sizes = XCBRandRGetScreenInfoSizes(sc);

  if (have_pixel_size) {
    for (size = 0; size < nsize; size++)
    {
      if (sizes[size].width == width && sizes[size].height == height)
	break;
    }
  }
  else if (size < 0)
    size = current_size;

  if (size >= nsize) usage();

  if (rot < 0)
  {
    for (rot = 0; rot < 4; rot++)
	if (1 << rot == (current_rotation & 0xf))
	    break;
  }

  current_rate = sc->rate;
  
  if (rate < 0)
  {
    if (size == current_size)
	rate = current_rate;
    else
	rate = 0;
  }

  if (version) {
    printf("Server reports RandR version %d.%d\n", 
	   major_version, minor_version);
  }
  
  if (query) {
    printf(" SZ:    Pixels          Physical       Refresh\n");
    for (i = 0; i < nsize; i++) {
      printf ("%c%-2d %5d x %-5d  (%4dmm x%4dmm )",
	   i == current_size ? '*' : ' ',
	   i, sizes[i].width, sizes[i].height,
	   sizes[i].mwidth, sizes[i].mheight);
      rates = ConfigRates (sc, i, &nrate);

      if (nrate) printf ("  ");
      for (j = 0; j < nrate; j++)
	printf ("%c%-4d",
		i == current_size && rates[j] == current_rate ? '*' : ' ',
		rates[j]);
      printf ("\n");
    }
  }

  //rotations = XRRConfigRotations(sc, &current_rotation);
  rotations = sc->rotation;

  rotation = 1 << rot ;
  if (query) {
    for (i = 0; i < 4; i ++) {
      if ((current_rotation >> i) & 1) 
	printf("Current rotation - %s\n", direction[i]);
    }

    printf("Current reflection - ");
    if (current_rotation & (XCBRandRRotationReflect_X|XCBRandRRotationReflect_Y))
    {
	if (current_rotation & XCBRandRRotationReflect_X) printf ("X Axis ");
	if (current_rotation & XCBRandRRotationReflect_Y) printf ("Y Axis");
    }
    else
	printf ("none");
    printf ("\n");
    

    printf ("Rotations possible - ");
    for (i = 0; i < 4; i ++) {
      if ((rotations >> i) & 1)  printf("%s ", direction[i]);
    }
    printf ("\n");

    printf ("Reflections possible - ");
    if (rotations & (XCBRandRRotationReflect_X|XCBRandRRotationReflect_Y))
    {
        if (rotations & XCBRandRRotationReflect_X) printf ("X Axis ");
	if (rotations & XCBRandRRotationReflect_Y) printf ("Y Axis");
    }
    else
	printf ("none");
    printf ("\n");
  }

  if (verbose) { 
    printf("Setting size to %d, rotation to %s\n",  size, direction[rot]);

    printf ("Setting reflection on ");
    if (reflection)
    {
	if (reflection & XCBRandRRotationReflect_X) printf ("X Axis ");
	if (reflection & XCBRandRRotationReflect_Y) printf ("Y Axis");
    }
    else
	printf ("neither axis");
    printf ("\n");

    if (reflection & XCBRandRRotationReflect_X) printf("Setting reflection on X axis\n");

    if (reflection & XCBRandRRotationReflect_Y) printf("Setting reflection on Y axis\n");
  }

  /* we should test configureNotify on the root window */
  CARD16 mask = (CARD16) StructureNotifyMask;
  CARD32 values[1];
  values[0] = 1;
  XCBConfigureWindow(c, root->root, mask, values);

  if (setit) XCBRandRSelectInput (c, root->root, XCBRandRSMScreenChangeNotify);

  if (setit) {
    XCBRandRSetScreenConfigCookie sscc;
    sscc = XCBRandRSetScreenConfig(c, root->root, CurrentTime, sc->config_timestamp, size,
	    (short) (rotation | reflection), rate);
    status = XCBRandRSetScreenConfigReply(c, sscc, &err)->status;
    
    if (err && status) {
	fprintf(stderr, "Can't set the screen. Error Code: %i Status:%i\n",
		err->error_code, status);
	exit(1);
    }
  }
    
  const XCBQueryExtensionRep *qrre_rep = XCBRandRInit(c);
  event_base = qrre_rep->first_event;
  error_base = qrre_rep->first_error;
  
  if (verbose && setit) {
    if (status == XCBRandRSetConfigSuccess)
      {
	while (1) {
	int spo;
	event = XCBWaitEvent(c);
	
	printf ("Event received, type = %d\n", event->response_type);
	//update Xlib's knowledge of the event
	////Not sure what the equiv of this is or if we need it.
	//XRRUpdateConfiguration (&event);
	
	if (event->response_type == ConfigureNotify)
	  printf("Received ConfigureNotify Event!\n");
	
	switch (event->response_type - event_base) {
	case XCBRandRScreenChangeNotify:
	  sce = (XCBRandRScreenChangeNotifyEvent *) event;

	  printf("Got a screen change notify event!\n");
	  printf(" window = %d\n root = %d\n size_index = %d\n rotation %d\n", 
	       (int) sce->request_window.xid, (int) sce->root.xid, 
	       sce->sizeID,  sce->rotation);
	  printf(" timestamp = %ld, config_timestamp = %ld\n",
	       sce->timestamp, sce->config_timestamp);
	  printf(" Rotation = %x\n", sce->rotation);
	  printf(" %d X %d pixels, %d X %d mm\n",
		 sce->width, sce->height, sce->mwidth, sce->mheight);
	  
	  printf("Display width   %d, height   %d\n",
		 root->width_in_pixels, root->height_in_pixels);
	  printf("Display widthmm %d, heightmm %d\n", 
		 root->width_in_millimeters, root->height_in_millimeters);
	  
	  spo = sce->subpixel_order;
	  if ((spo < 0) || (spo > 5))
	    printf ("Unknown subpixel order, value = %d\n", spo);
	  else printf ("new Subpixel rendering model is %s\n", order[spo]);
	  break;
	default:
	  if (event->response_type != ConfigureNotify) 
	    printf("unknown event received, type = %d!\n", event->response_type);
	}
	}
      }
  }
  //XRRFreeScreenConfigInfo(sc);
  free(sc);
  free(c);
  return(0);
}


More information about the xcb mailing list