Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * Copyright  2003 Keith Packard
      3  * Copyright  2007 Eric Anholt
      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 Keith Packard not be used in
     10  * advertising or publicity pertaining to distribution of the software without
     11  * specific, written prior permission.  Keith Packard makes no
     12  * representations about the suitability of this software for any purpose.  It
     13  * is provided "as is" without express or implied warranty.
     14  *
     15  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     17  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     19  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     20  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     21  * PERFORMANCE OF THIS SOFTWARE.
     22  */
     23 
     24 #ifdef HAVE_CONFIG_H
     25 #include <config.h>
     26 #endif
     27 #include "xdamageint.h"
     28 #include <X11/Xfuncproto.h>
     29 
     30 XDamageExtInfo XDamageExtensionInfo;
     31 
     32 const char XDamageExtensionName[] = DAMAGE_NAME;
     33 
     34 static int
     35 XDamageCloseDisplay (Display *dpy, XExtCodes *codes);
     36 
     37 static Bool
     38 XDamageWireToEvent(Display *dpy, XEvent *event, xEvent *wire);
     39 
     40 static Status
     41 XDamageEventToWire(Display *dpy, XEvent *event, xEvent *wire);
     42 
     43 /*
     44  * XDamageExtAddDisplay - add a display to this extension. (Replaces
     45  * XextAddDisplay)
     46  */
     47 static XDamageExtDisplayInfo *
     48 XDamageExtAddDisplay (XDamageExtInfo	*extinfo,
     49                       Display		*dpy,
     50                       const char	*ext_name)
     51 {
     52     XDamageExtDisplayInfo    *info;
     53 
     54     info = Xmalloc (sizeof (XDamageExtDisplayInfo));
     55     if (!info) return NULL;
     56     info->display = dpy;
     57 
     58     info->codes = XInitExtension (dpy, ext_name);
     59 
     60     /*
     61      * if the server has the extension, then we can initialize the
     62      * appropriate function vectors
     63      */
     64     if (info->codes) {
     65 	xDamageQueryVersionReply	rep;
     66 	xDamageQueryVersionReq	*req;
     67         XESetCloseDisplay (dpy, info->codes->extension,
     68                            XDamageCloseDisplay);
     69 	for (int ev = info->codes->first_event;
     70 	     ev < info->codes->first_event + XDamageNumberEvents;
     71 	     ev++)
     72 	{
     73 	    XESetWireToEvent (dpy, ev, XDamageWireToEvent);
     74 	    XESetEventToWire (dpy, ev, XDamageEventToWire);
     75 	}
     76 	/*
     77 	 * Get the version info
     78 	 */
     79 	LockDisplay (dpy);
     80 	GetReq (DamageQueryVersion, req);
     81 	req->reqType = (CARD8) info->codes->major_opcode;
     82 	req->damageReqType = X_DamageQueryVersion;
     83 	req->majorVersion = DAMAGE_MAJOR;
     84 	req->minorVersion = DAMAGE_MINOR;
     85 	if (!_XReply (dpy, (xReply *) &rep, 0, xTrue))
     86 	{
     87 	    UnlockDisplay (dpy);
     88 	    SyncHandle ();
     89 	    Xfree(info);
     90 	    return NULL;
     91 	}
     92 	info->major_version = rep.majorVersion;
     93 	info->minor_version = rep.minorVersion;
     94 	UnlockDisplay (dpy);
     95 	SyncHandle ();
     96     } else {
     97 	/* The server doesn't have this extension.
     98 	 * Use a private Xlib-internal extension to hang the close_display
     99 	 * hook on so that the "cache" (extinfo->cur) is properly cleaned.
    100 	 * (XBUG 7955)
    101 	 */
    102 	XExtCodes *codes = XAddExtension(dpy);
    103 	if (!codes) {
    104 	    Xfree(info);
    105 	    return NULL;
    106 	}
    107         XESetCloseDisplay (dpy, codes->extension, XDamageCloseDisplay);
    108     }
    109 
    110     /*
    111      * now, chain it onto the list
    112      */
    113     _XLockMutex(_Xglobal_lock);
    114     info->next = extinfo->head;
    115     extinfo->head = info;
    116     extinfo->cur = info;
    117     extinfo->ndisplays++;
    118     _XUnlockMutex(_Xglobal_lock);
    119     return info;
    120 }
    121 
    122 
    123 /*
    124  * XDamageExtRemoveDisplay - remove the indicated display from the
    125  * extension object. (Replaces XextRemoveDisplay.)
    126  */
    127 static int
    128 XDamageExtRemoveDisplay (XDamageExtInfo *extinfo, const Display *dpy)
    129 {
    130     XDamageExtDisplayInfo *info, *prev;
    131 
    132     /*
    133      * locate this display and its back link so that it can be removed
    134      */
    135     _XLockMutex(_Xglobal_lock);
    136     prev = NULL;
    137     for (info = extinfo->head; info; info = info->next) {
    138 	if (info->display == dpy) break;
    139 	prev = info;
    140     }
    141     if (!info) {
    142 	_XUnlockMutex(_Xglobal_lock);
    143 	return 0;		/* hmm, actually an error */
    144     }
    145 
    146     /*
    147      * remove the display from the list; handles going to zero
    148      */
    149     if (prev)
    150 	prev->next = info->next;
    151     else
    152 	extinfo->head = info->next;
    153 
    154     extinfo->ndisplays--;
    155     if (info == extinfo->cur) extinfo->cur = NULL;  /* flush cache */
    156     _XUnlockMutex(_Xglobal_lock);
    157 
    158     Xfree (info);
    159     return 1;
    160 }
    161 
    162 /*
    163  * XDamageExtFindDisplay - look for a display in this extension; keeps a
    164  * cache of the most-recently used for efficiency. (Replaces
    165  * XextFindDisplay.)
    166  */
    167 static XDamageExtDisplayInfo *
    168 XDamageExtFindDisplay (XDamageExtInfo *extinfo,
    169 		       const Display  *dpy)
    170 {
    171     XDamageExtDisplayInfo *info;
    172 
    173     /*
    174      * see if this was the most recently accessed display
    175      */
    176     if ((info = extinfo->cur) && info->display == dpy)
    177 	return info;
    178 
    179     /*
    180      * look for display in list
    181      */
    182     _XLockMutex(_Xglobal_lock);
    183     for (info = extinfo->head; info; info = info->next) {
    184 	if (info->display == dpy) {
    185 	    extinfo->cur = info;     /* cache most recently used */
    186 	    _XUnlockMutex(_Xglobal_lock);
    187 	    return info;
    188 	}
    189     }
    190     _XUnlockMutex(_Xglobal_lock);
    191 
    192     return NULL;
    193 }
    194 
    195 XDamageExtDisplayInfo *
    196 XDamageFindDisplay (Display *dpy)
    197 {
    198     XDamageExtDisplayInfo *info;
    199 
    200     info = XDamageExtFindDisplay (&XDamageExtensionInfo, dpy);
    201     if (!info)
    202 	info = XDamageExtAddDisplay (&XDamageExtensionInfo, dpy,
    203 				    XDamageExtensionName);
    204     return info;
    205 }
    206 
    207 static int
    208 XDamageCloseDisplay (Display *dpy, _X_UNUSED XExtCodes *codes)
    209 {
    210     return XDamageExtRemoveDisplay (&XDamageExtensionInfo, dpy);
    211 }
    212 
    213 static Bool
    214 XDamageWireToEvent(Display *dpy, XEvent *event, xEvent *wire)
    215 {
    216     XDamageExtDisplayInfo *info = XDamageFindDisplay(dpy);
    217 
    218     XDamageCheckExtension(dpy, info, False);
    219 
    220     switch ((wire->u.u.type & 0x7F) - info->codes->first_event)
    221     {
    222     case XDamageNotify: {
    223 	XDamageNotifyEvent *aevent = (XDamageNotifyEvent *) event;
    224 	xDamageNotifyEvent *awire = (xDamageNotifyEvent *) wire;
    225 
    226 	aevent->type = awire->type & 0x7F;
    227 	aevent->serial = _XSetLastRequestRead(dpy,
    228 					      (xGenericReply *) wire);
    229 	aevent->send_event = (awire->type & 0x80) != 0;
    230 	aevent->display = dpy;
    231 	aevent->drawable = awire->drawable;
    232 	aevent->damage = awire->damage;
    233 	aevent->level = awire->level & ~DamageNotifyMore;
    234 	aevent->more = (awire->level & DamageNotifyMore) ? True : False;
    235 	aevent->timestamp = awire->timestamp;
    236 	aevent->area.x = awire->area.x;
    237 	aevent->area.y = awire->area.y;
    238 	aevent->area.width = awire->area.width;
    239 	aevent->area.height = awire->area.height;
    240 	aevent->geometry.x = awire->geometry.x;
    241 	aevent->geometry.y = awire->geometry.y;
    242 	aevent->geometry.width = awire->geometry.width;
    243 	aevent->geometry.height = awire->geometry.height;
    244 	return True;
    245     }
    246     }
    247     return False;
    248 }
    249 
    250 static Status
    251 XDamageEventToWire(Display *dpy, XEvent *event, xEvent *wire)
    252 {
    253     XDamageExtDisplayInfo *info = XDamageFindDisplay(dpy);
    254 
    255     XDamageCheckExtension(dpy, info, False);
    256 
    257     switch ((event->type & 0x7F) - info->codes->first_event)
    258     {
    259     case XDamageNotify: {
    260 	XDamageNotifyEvent *aevent;
    261 	xDamageNotifyEvent *awire;
    262 	awire = (xDamageNotifyEvent *) wire;
    263 	aevent = (XDamageNotifyEvent *) event;
    264 	awire->type = (CARD8) aevent->type | (aevent->send_event ? 0x80 : 0);
    265 	awire->drawable = (CARD32) aevent->drawable;
    266 	awire->damage = (CARD32) aevent->damage;
    267 	awire->level = (CARD8) aevent->level | (aevent->more ? DamageNotifyMore : 0);
    268 	awire->timestamp = (CARD32) aevent->timestamp;
    269 	awire->area.x = aevent->area.x;
    270 	awire->area.y = aevent->area.y;
    271 	awire->area.width = aevent->area.width;
    272 	awire->area.height = aevent->area.height;
    273 	awire->geometry.x = aevent->geometry.x;
    274 	awire->geometry.y = aevent->geometry.y;
    275 	awire->geometry.width = aevent->geometry.width;
    276 	awire->geometry.height = aevent->geometry.height;
    277 	return True;
    278     }
    279     }
    280     return False;
    281 }
    282 
    283 Bool
    284 XDamageQueryExtension (Display *dpy,
    285 			int *event_base_return,
    286 			int *error_base_return)
    287 {
    288     XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy);
    289 
    290     if (XDamageHasExtension(info))
    291     {
    292 	*event_base_return = info->codes->first_event;
    293 	*error_base_return = info->codes->first_error;
    294 	return True;
    295     }
    296     else
    297 	return False;
    298 }
    299 
    300 Status
    301 XDamageQueryVersion (Display *dpy,
    302 		    int	    *major_version_return,
    303 		    int	    *minor_version_return)
    304 {
    305     XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
    306 
    307     XDamageCheckExtension (dpy, info, 0);
    308 
    309     *major_version_return = info->major_version;
    310     *minor_version_return = info->minor_version;
    311     return 1;
    312 }
    313 
    314 Damage
    315 XDamageCreate (Display *dpy, Drawable drawable, int level)
    316 {
    317     XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
    318     xDamageCreateReq		*req;
    319     Damage			damage;
    320 
    321     XDamageCheckExtension (dpy, info, 0);
    322     LockDisplay (dpy);
    323     GetReq (DamageCreate, req);
    324     req->reqType = (CARD8) info->codes->major_opcode;
    325     req->damageReqType = X_DamageCreate;
    326     damage = XAllocID (dpy);
    327     req->damage = (CARD32) damage;
    328     req->drawable = (CARD32) drawable;
    329     req->level = (CARD8) level;
    330     UnlockDisplay (dpy);
    331     SyncHandle ();
    332     return damage;
    333 }
    334 
    335 void
    336 XDamageDestroy (Display *dpy, Damage damage)
    337 {
    338     XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
    339     xDamageDestroyReq		*req;
    340 
    341     XDamageSimpleCheckExtension (dpy, info);
    342     LockDisplay (dpy);
    343     GetReq (DamageDestroy, req);
    344     req->reqType = (CARD8) info->codes->major_opcode;
    345     req->damageReqType = X_DamageDestroy;
    346     req->damage = (CARD32) damage;
    347     UnlockDisplay (dpy);
    348     SyncHandle ();
    349 }
    350 
    351 void
    352 XDamageSubtract (Display *dpy, Damage damage,
    353 		 XserverRegion repair, XserverRegion parts)
    354 {
    355     XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
    356     xDamageSubtractReq		*req;
    357 
    358     XDamageSimpleCheckExtension (dpy, info);
    359     LockDisplay (dpy);
    360     GetReq (DamageSubtract, req);
    361     req->reqType = (CARD8) info->codes->major_opcode;
    362     req->damageReqType = X_DamageSubtract;
    363     req->damage = (CARD32) damage;
    364     req->repair = (CARD32) repair;
    365     req->parts = (CARD32) parts;
    366     UnlockDisplay (dpy);
    367     SyncHandle ();
    368 }
    369 
    370 void
    371 XDamageAdd (Display *dpy, Drawable drawable, XserverRegion region)
    372 {
    373     XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
    374     xDamageAddReq		*req;
    375 
    376     XDamageSimpleCheckExtension (dpy, info);
    377     LockDisplay (dpy);
    378     GetReq (DamageAdd, req);
    379     req->reqType = (CARD8) info->codes->major_opcode;
    380     req->damageReqType = X_DamageAdd;
    381     req->drawable = (CARD32) drawable;
    382     req->region = (CARD32) region;
    383 
    384     UnlockDisplay (dpy);
    385     SyncHandle ();
    386 }
    387