Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * Copyright  2000 Compaq Computer Corporation, Inc.
      3  * Copyright  2002 Hewlett Packard Company, Inc.
      4  *
      5  * Permission to use, copy, modify, distribute, and sell this software and its
      6  * documentation for any purpose is hereby granted without fee, provided that
      7  * the above copyright notice appear in all copies and that both that
      8  * copyright notice and this permission notice appear in supporting
      9  * documentation, and that the name of Compaq or HP not be used in advertising
     10  * or publicity pertaining to distribution of the software without specific,
     11  * written prior permission.  HP makes no representations about the
     12  * suitability of this software for any purpose.  It is provided "as is"
     13  * without express or implied warranty.
     14  *
     15  * HP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL COMPAQ
     17  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     18  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     19  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     21  *
     22  * Author:  Jim Gettys, HP Labs, HP.
     23  */
     24 
     25 #ifdef HAVE_CONFIG_H
     26 #include <config.h>
     27 #endif
     28 
     29 #include <stdio.h>
     30 #include <X11/Xlib.h>
     31 /* we need to be able to manipulate the Display structure on events */
     32 #include <X11/Xlibint.h>
     33 #include <X11/extensions/render.h>
     34 #include <X11/extensions/Xrender.h>
     35 #include "Xrandrint.h"
     36 
     37 static XExtensionInfo XRRExtensionInfo;
     38 _X_HIDDEN char XRRExtensionName[] = RANDR_NAME;
     39 
     40 static Bool     XRRWireToEvent(Display *dpy, XEvent *event, xEvent *wire);
     41 static Status   XRREventToWire(Display *dpy, XEvent *event, xEvent *wire);
     42 
     43 static int
     44 XRRCloseDisplay (Display *dpy, XExtCodes *codes);
     45 
     46 static /* const */ XExtensionHooks rr_extension_hooks = {
     47     NULL,				/* create_gc */
     48     NULL,				/* copy_gc */
     49     NULL,				/* flush_gc */
     50     NULL,				/* free_gc */
     51     NULL,				/* create_font */
     52     NULL,				/* free_font */
     53     XRRCloseDisplay,			/* close_display */
     54     XRRWireToEvent,			/* wire_to_event */
     55     XRREventToWire,			/* event_to_wire */
     56     NULL,				/* error */
     57     NULL,				/* error_string */
     58 };
     59 
     60 static Bool XRRWireToEvent(Display *dpy, XEvent *event, xEvent *wire)
     61 {
     62     XExtDisplayInfo *info = XRRFindDisplay(dpy);
     63 
     64     RRCheckExtension(dpy, info, False);
     65 
     66     switch ((wire->u.u.type & 0x7F) - info->codes->first_event)
     67     {
     68       case RRScreenChangeNotify: {
     69 	XRRScreenChangeNotifyEvent *aevent= (XRRScreenChangeNotifyEvent *) event;
     70 	xRRScreenChangeNotifyEvent *awire = (xRRScreenChangeNotifyEvent *) wire;
     71 	aevent->type = awire->type & 0x7F;
     72 	aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
     73 	aevent->send_event = (awire->type & 0x80) != 0;
     74 	aevent->display = dpy;
     75 	aevent->window = awire->window;
     76 	aevent->root = awire->root;
     77 	aevent->timestamp = awire->timestamp;
     78 	aevent->config_timestamp = awire->configTimestamp;
     79 	aevent->size_index = awire->sizeID;
     80 	aevent->subpixel_order = awire->subpixelOrder;
     81 	aevent->rotation = awire->rotation;
     82 	aevent->width = awire->widthInPixels;
     83 	aevent->height = awire->heightInPixels;
     84 	aevent->mwidth = awire->widthInMillimeters;
     85 	aevent->mheight = awire->heightInMillimeters;
     86 	return True;
     87       }
     88       case RRNotify: {
     89 	switch (wire->u.u.detail) {
     90 	case RRNotify_OutputChange: {
     91 	    XRROutputChangeNotifyEvent *aevent = (XRROutputChangeNotifyEvent *) event;
     92 	    xRROutputChangeNotifyEvent *awire = (xRROutputChangeNotifyEvent *) wire;
     93 	    aevent->type = awire->type & 0x7F;
     94 	    aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
     95 	    aevent->send_event = (awire->type & 0x80) != 0;
     96 	    aevent->display = dpy;
     97 	    aevent->window = awire->window;
     98 	    aevent->subtype = awire->subCode;
     99 	    aevent->output = awire->output;
    100 	    aevent->crtc = awire->crtc;
    101 	    aevent->mode = awire->mode;
    102 	    aevent->rotation = awire->rotation;
    103 	    aevent->connection = awire->connection;
    104 	    aevent->subpixel_order = awire->subpixelOrder;
    105 	    return True;
    106 	}
    107 	case RRNotify_CrtcChange: {
    108 	    XRRCrtcChangeNotifyEvent *aevent = (XRRCrtcChangeNotifyEvent *) event;
    109 	    xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire;
    110 	    aevent->type = awire->type & 0x7F;
    111 	    aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
    112 	    aevent->send_event = (awire->type & 0x80) != 0;
    113 	    aevent->display = dpy;
    114 	    aevent->window = awire->window;
    115 	    aevent->subtype = awire->subCode;
    116 	    aevent->crtc = awire->crtc;
    117 	    aevent->mode = awire->mode;
    118 	    aevent->rotation = awire->rotation;
    119 	    aevent->x = awire->x;
    120 	    aevent->y = awire->y;
    121 	    aevent->width = awire->width;
    122 	    aevent->height = awire->height;
    123 	    return True;
    124 	}
    125 	case RRNotify_OutputProperty: {
    126 	    XRROutputPropertyNotifyEvent *aevent = (XRROutputPropertyNotifyEvent *) event;
    127 	    xRROutputPropertyNotifyEvent *awire = (xRROutputPropertyNotifyEvent *) wire;
    128 	    aevent->type = awire->type & 0x7F;
    129 	    aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
    130 	    aevent->send_event = (awire->type & 0x80) != 0;
    131 	    aevent->display = dpy;
    132 	    aevent->window = awire->window;
    133 	    aevent->subtype = awire->subCode;
    134 	    aevent->output = awire->output;
    135 	    aevent->property = awire->atom;
    136 	    aevent->timestamp = awire->timestamp;
    137 	    aevent->state = awire->state;
    138 	    return True;
    139 	}
    140 	case RRNotify_ProviderChange: {
    141 	    XRRProviderChangeNotifyEvent *aevent = (XRRProviderChangeNotifyEvent *) event;
    142 	    xRRProviderChangeNotifyEvent *awire = (xRRProviderChangeNotifyEvent *) wire;
    143 	    aevent->type = awire->type & 0x7F;
    144 	    aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
    145 	    aevent->send_event = (awire->type & 0x80) != 0;
    146 	    aevent->display = dpy;
    147 	    aevent->window = awire->window;
    148 	    aevent->subtype = awire->subCode;
    149 	    aevent->provider = awire->provider;
    150 	    aevent->timestamp = awire->timestamp;
    151 	    return True;
    152 	}
    153 	case RRNotify_ProviderProperty: {
    154 	    XRRProviderPropertyNotifyEvent *aevent = (XRRProviderPropertyNotifyEvent *) event;
    155 	    xRRProviderPropertyNotifyEvent *awire = (xRRProviderPropertyNotifyEvent *) wire;
    156 	    aevent->type = awire->type & 0x7F;
    157 	    aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
    158 	    aevent->send_event = (awire->type & 0x80) != 0;
    159 	    aevent->display = dpy;
    160 	    aevent->window = awire->window;
    161 	    aevent->subtype = awire->subCode;
    162 	    aevent->provider = awire->provider;
    163 	    aevent->property = awire->atom;
    164 	    aevent->timestamp = awire->timestamp;
    165 	    aevent->state = awire->state;
    166 	    return True;
    167 	}
    168 	case RRNotify_ResourceChange: {
    169 	    XRRResourceChangeNotifyEvent *aevent = (XRRResourceChangeNotifyEvent *) event;
    170 	    xRRResourceChangeNotifyEvent *awire = (xRRResourceChangeNotifyEvent *) wire;
    171 	    aevent->type = awire->type & 0x7F;
    172 	    aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
    173 	    aevent->send_event = (awire->type & 0x80) != 0;
    174 	    aevent->display = dpy;
    175 	    aevent->window = awire->window;
    176 	    aevent->subtype = awire->subCode;
    177 	    aevent->timestamp = awire->timestamp;
    178 	    return True;
    179 	}
    180 	    break;
    181 	}
    182       }
    183     }
    184 
    185     return False;
    186 }
    187 
    188 static Status XRREventToWire(Display *dpy, XEvent *event, xEvent *wire)
    189 {
    190     XExtDisplayInfo *info = XRRFindDisplay(dpy);
    191 
    192     RRCheckExtension(dpy, info, False);
    193 
    194     switch ((event->type & 0x7F) - info->codes->first_event)
    195     {
    196       case RRScreenChangeNotify: {
    197 	xRRScreenChangeNotifyEvent *awire = (xRRScreenChangeNotifyEvent *) wire;
    198 	XRRScreenChangeNotifyEvent *aevent = (XRRScreenChangeNotifyEvent *) event;
    199 	awire->type = aevent->type | (aevent->send_event ? 0x80 : 0);
    200 	awire->rotation = (CARD8) aevent->rotation;
    201 	awire->sequenceNumber = aevent->serial & 0xFFFF;
    202 	awire->timestamp = aevent->timestamp;
    203 	awire->configTimestamp = aevent->config_timestamp;
    204 	awire->root = aevent->root;
    205 	awire->window = aevent->window;
    206 	awire->sizeID = aevent->size_index;
    207 	awire->subpixelOrder = aevent->subpixel_order;
    208 	awire->widthInPixels = aevent->width;
    209 	awire->heightInPixels = aevent->height;
    210 	awire->widthInMillimeters = aevent->mwidth;
    211 	awire->heightInMillimeters = aevent->mheight;
    212 	return True;
    213       }
    214       case RRNotify: {
    215 	xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire;
    216 	XRRNotifyEvent *aevent = (XRRNotifyEvent *) event;
    217 	awire->type = aevent->type | (aevent->send_event ? 0x80 : 0);
    218 	awire->sequenceNumber = aevent->serial & 0xFFFF;
    219 	awire->subCode = aevent->subtype;
    220 	switch (aevent->subtype) {
    221 	case RRNotify_OutputChange: {
    222 	    xRROutputChangeNotifyEvent *sawire = (xRROutputChangeNotifyEvent *) wire;
    223 	    XRROutputChangeNotifyEvent *saevent = (XRROutputChangeNotifyEvent *) event;
    224 	    sawire->window = saevent->window;
    225 	    sawire->output = saevent->output;
    226 	    sawire->crtc = saevent->crtc;
    227 	    sawire->mode = saevent->mode;
    228 	    sawire->rotation = saevent->rotation;
    229 	    sawire->connection = saevent->connection;
    230 	    sawire->subpixelOrder = saevent->subpixel_order;
    231 	    return True;
    232 	}
    233 	case RRNotify_CrtcChange: {
    234 	    xRRCrtcChangeNotifyEvent *sawire = (xRRCrtcChangeNotifyEvent *) wire;
    235 	    XRRCrtcChangeNotifyEvent *saevent = (XRRCrtcChangeNotifyEvent *) event;
    236 	    sawire->window = saevent->window;
    237 	    sawire->crtc = saevent->crtc;
    238 	    sawire->mode = saevent->mode;
    239 	    sawire->rotation = saevent->rotation;
    240 	    sawire->x = saevent->x;
    241 	    sawire->y = saevent->y;
    242 	    sawire->width = saevent->width;
    243 	    sawire->height = saevent->height;
    244 	    return True;
    245 	}
    246 	case RRNotify_OutputProperty: {
    247 	    xRROutputPropertyNotifyEvent *sawire = (xRROutputPropertyNotifyEvent *) wire;
    248 	    XRROutputPropertyNotifyEvent *saevent = (XRROutputPropertyNotifyEvent *) event;
    249 	    sawire->window = saevent->window;
    250 	    sawire->output = saevent->output;
    251 	    sawire->atom = saevent->property;
    252 	    sawire->timestamp = saevent->timestamp;
    253 	    sawire->state = saevent->state;
    254 	    return True;
    255 	}
    256 	case RRNotify_ProviderChange: {
    257 	    xRRProviderChangeNotifyEvent *sawire = (xRRProviderChangeNotifyEvent *) wire;
    258 	    XRRProviderChangeNotifyEvent *saevent = (XRRProviderChangeNotifyEvent *) event;
    259 	    sawire->window = saevent->window;
    260 	    sawire->provider = saevent->provider;
    261 	    return True;
    262 	}
    263 	case RRNotify_ProviderProperty: {
    264 	    xRRProviderPropertyNotifyEvent *sawire = (xRRProviderPropertyNotifyEvent *) wire;
    265 	    XRRProviderPropertyNotifyEvent *saevent = (XRRProviderPropertyNotifyEvent *) event;
    266 	    sawire->window = saevent->window;
    267 	    sawire->provider = saevent->provider;
    268 	    sawire->atom = saevent->property;
    269 	    sawire->timestamp = saevent->timestamp;
    270 	    sawire->state = saevent->state;
    271 	    return True;
    272 	}
    273 	case RRNotify_ResourceChange: {
    274 	    xRRResourceChangeNotifyEvent *sawire = (xRRResourceChangeNotifyEvent *) wire;
    275 	    XRRResourceChangeNotifyEvent *saevent = (XRRResourceChangeNotifyEvent *) event;
    276 	    sawire->window = saevent->window;
    277 	    sawire->timestamp = saevent->timestamp;
    278 	    return True;
    279 	}
    280 	}
    281       }
    282     }
    283     return False;
    284 }
    285 
    286 _X_HIDDEN XExtDisplayInfo *
    287 XRRFindDisplay (Display *dpy)
    288 {
    289     XExtDisplayInfo *dpyinfo = XextFindDisplay (&XRRExtensionInfo, dpy);
    290 
    291     if (!dpyinfo) {
    292 	XRandRInfo *xrri;
    293 	int numscreens;
    294 
    295 	dpyinfo = XextAddDisplay (&XRRExtensionInfo, dpy,
    296 				  XRRExtensionName,
    297 				  &rr_extension_hooks,
    298 				  RRNumberEvents, NULL);
    299 	numscreens = ScreenCount(dpy);
    300 	xrri = Xmalloc (sizeof(XRandRInfo) +
    301 				 sizeof(char *) * numscreens);
    302 	xrri->config = (XRRScreenConfiguration **)(xrri + 1);
    303 	for (int i = 0; i < numscreens; i++)
    304 	  xrri->config[i] = NULL;
    305 	xrri->major_version = -1;
    306 	dpyinfo->data = (char *) xrri;
    307     }
    308     return dpyinfo;
    309 }
    310 
    311 static int
    312 XRRCloseDisplay (Display *dpy, XExtCodes *codes)
    313 {
    314     XExtDisplayInfo *info = XRRFindDisplay (dpy);
    315 
    316     LockDisplay(dpy);
    317     /*
    318      * free cached data
    319      */
    320     if (XextHasExtension(info)) {
    321 	XRandRInfo *xrri = (XRandRInfo *) info->data;
    322 	if (xrri) {
    323 	    XRRScreenConfiguration **configs = xrri->config;
    324 
    325 	    for (int i = 0; i < ScreenCount(dpy); i++) {
    326 		if (configs[i] != NULL) XFree (configs[i]);
    327 	    }
    328 	    XFree (xrri);
    329 	}
    330     }
    331     UnlockDisplay(dpy);
    332     return XextRemoveDisplay (&XRRExtensionInfo, dpy);
    333 }
    334 
    335 int XRRRootToScreen(Display *dpy, Window root)
    336 {
    337   for (int snum = 0; snum < ScreenCount(dpy); snum++) {
    338     if (RootWindow(dpy, snum) == root) return snum;
    339   }
    340   return -1;
    341 }
    342 
    343 
    344 Bool XRRQueryExtension (Display *dpy,
    345 			int *event_base_return,
    346 			int *error_base_return)
    347 {
    348   XExtDisplayInfo *info = XRRFindDisplay (dpy);
    349 
    350     if (XextHasExtension(info)) {
    351 	*event_base_return = info->codes->first_event;
    352 	*error_base_return = info->codes->first_error;
    353 	return True;
    354     } else {
    355 	return False;
    356     }
    357 }
    358 
    359 _X_HIDDEN Bool
    360 _XRRHasRates (int major, int minor)
    361 {
    362     return major > 1 || (major == 1 && minor >= 1);
    363 }
    364 
    365 Status XRRQueryVersion (Display *dpy,
    366 			    int	    *major_versionp,
    367 			    int	    *minor_versionp)
    368 {
    369     XExtDisplayInfo *info = XRRFindDisplay (dpy);
    370     xRRQueryVersionReply rep;
    371     xRRQueryVersionReq  *req;
    372     XRandRInfo *xrri;
    373 
    374     RRCheckExtension (dpy, info, 0);
    375 
    376     xrri = (XRandRInfo *) info->data;
    377 
    378     /*
    379      * only get the version information from the server if we don't have it already
    380      */
    381     if (xrri->major_version == -1) {
    382       LockDisplay (dpy);
    383       GetReq (RRQueryVersion, req);
    384       req->reqType = info->codes->major_opcode;
    385       req->randrReqType = X_RRQueryVersion;
    386       req->majorVersion = RANDR_MAJOR;
    387       req->minorVersion = RANDR_MINOR;
    388       if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
    389 	UnlockDisplay (dpy);
    390 	SyncHandle ();
    391 	return 0;
    392       }
    393       xrri->major_version = rep.majorVersion;
    394       xrri->minor_version = rep.minorVersion;
    395       xrri->has_rates = _XRRHasRates (xrri->major_version, xrri->minor_version);
    396       UnlockDisplay (dpy);
    397       SyncHandle ();
    398     }
    399     *major_versionp = xrri->major_version;
    400     *minor_versionp = xrri->minor_version;
    401     return 1;
    402 }
    403 
    404 _X_HIDDEN Bool
    405 _XRRVersionHandler (Display	    *dpy,
    406 			xReply	    *rep,
    407 			char	    *buf,
    408 			int	    len,
    409 			XPointer    data)
    410 {
    411     xRRQueryVersionReply	replbuf;
    412     xRRQueryVersionReply	*repl;
    413     _XRRVersionState	*state = (_XRRVersionState *) data;
    414 
    415     if (dpy->last_request_read != state->version_seq)
    416 	return False;
    417     if (rep->generic.type == X_Error)
    418     {
    419 	state->error = True;
    420 	return False;
    421     }
    422     repl = (xRRQueryVersionReply *)
    423 	_XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
    424 		     (SIZEOF(xRRQueryVersionReply) - SIZEOF(xReply)) >> 2,
    425 			True);
    426     state->major_version = repl->majorVersion;
    427     state->minor_version = repl->minorVersion;
    428     return True;
    429 }
    430 
    431 /*
    432  * in protocol version 0.1, routine added to allow selecting for new events.
    433  */
    434 
    435 void XRRSelectInput (Display *dpy, Window window, int mask)
    436 {
    437     XExtDisplayInfo *info = XRRFindDisplay (dpy);
    438     xRRSelectInputReq  *req;
    439 
    440     RRSimpleCheckExtension (dpy, info);
    441 
    442     LockDisplay (dpy);
    443     GetReq (RRSelectInput, req);
    444     req->reqType = info->codes->major_opcode;
    445     req->randrReqType = X_RRSelectInput;
    446     req->window = window;
    447     req->enable = 0;
    448     if (mask) req->enable = mask;
    449     UnlockDisplay (dpy);
    450     SyncHandle ();
    451     return;
    452 }
    453 
    454 int XRRUpdateConfiguration(XEvent *event)
    455 {
    456     XRRScreenChangeNotifyEvent *scevent;
    457     XConfigureEvent *rcevent;
    458     Display *dpy = event->xany.display;
    459     XExtDisplayInfo *info;
    460     XRandRInfo *xrri;
    461     int snum;
    462 
    463     /* first, see if it is a vanilla configure notify event */
    464     if (event->type == ConfigureNotify) {
    465 	rcevent = (XConfigureEvent *) event;
    466 	snum = XRRRootToScreen(dpy, rcevent->window);
    467 	if (snum != -1) {
    468 	    dpy->screens[snum].width   = rcevent->width;
    469 	    dpy->screens[snum].height  = rcevent->height;
    470 	    return 1;
    471 	}
    472     }
    473 
    474     info = XRRFindDisplay(dpy);
    475     RRCheckExtension (dpy, info, 0);
    476 
    477     switch (event->type - info->codes->first_event) {
    478     case RRScreenChangeNotify:
    479 	scevent = (XRRScreenChangeNotifyEvent *) event;
    480 	snum = XRRRootToScreen(dpy,
    481 			       ((XRRScreenChangeNotifyEvent *) event)->root);
    482 	if (snum < 0)
    483 	    return 0;
    484 
    485 	if (scevent->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
    486 		dpy->screens[snum].width   = scevent->height;
    487 		dpy->screens[snum].height  = scevent->width;
    488 		dpy->screens[snum].mwidth  = scevent->mheight;
    489 		dpy->screens[snum].mheight = scevent->mwidth;
    490 	} else {
    491 		dpy->screens[snum].width   = scevent->width;
    492 		dpy->screens[snum].height  = scevent->height;
    493 		dpy->screens[snum].mwidth  = scevent->mwidth;
    494 		dpy->screens[snum].mheight = scevent->mheight;
    495 	}
    496 	XRenderSetSubpixelOrder (dpy, snum, scevent->subpixel_order);
    497 	break;
    498     default:
    499 	return 0;
    500     }
    501     xrri = (XRandRInfo *) info->data;
    502     /*
    503      * so the next time someone wants some data, it will be fetched;
    504      * it might be better to force the round trip immediately, but
    505      * I dislike pounding the server simultaneously when not necessary
    506      */
    507     if (xrri->config[snum] != NULL) {
    508 	XFree (xrri->config[snum]);
    509 	xrri->config[snum] = NULL;
    510     }
    511     return 1;
    512 }
    513