damageext.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. /*
  2. * Copyright © 2002 Keith Packard
  3. *
  4. * Permission to use, copy, modify, distribute, and sell this software and its
  5. * documentation for any purpose is hereby granted without fee, provided that
  6. * the above copyright notice appear in all copies and that both that
  7. * copyright notice and this permission notice appear in supporting
  8. * documentation, and that the name of Keith Packard not be used in
  9. * advertising or publicity pertaining to distribution of the software without
  10. * specific, written prior permission. Keith Packard makes no
  11. * representations about the suitability of this software for any purpose. It
  12. * is provided "as is" without express or implied warranty.
  13. *
  14. * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15. * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  16. * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17. * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18. * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  19. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  20. * PERFORMANCE OF THIS SOFTWARE.
  21. */
  22. #ifdef HAVE_DIX_CONFIG_H
  23. #include <dix-config.h>
  24. #endif
  25. #include "damageextint.h"
  26. #include "extinit.h"
  27. unsigned char DamageReqCode;
  28. int DamageEventBase;
  29. int DamageErrorBase;
  30. int DamageClientPrivateIndex;
  31. RESTYPE DamageExtType;
  32. RESTYPE DamageExtWinType;
  33. /* Version of the damage extension supported by the server, as opposed to the
  34. * DAMAGE_* defines from damageproto for what version the proto header
  35. * supports.
  36. */
  37. #define SERVER_DAMAGE_MAJOR 1
  38. #define SERVER_DAMAGE_MINOR 1
  39. #define prScreen screenInfo.screens[0]
  40. static void
  41. DamageExtNotify(DamageExtPtr pDamageExt, BoxPtr pBoxes, int nBoxes)
  42. {
  43. ClientPtr pClient = pDamageExt->pClient;
  44. DamageClientPtr pDamageClient = GetDamageClient(pClient);
  45. DrawablePtr pDrawable = pDamageExt->pDrawable;
  46. xDamageNotifyEvent ev;
  47. int i;
  48. UpdateCurrentTimeIf();
  49. ev = (xDamageNotifyEvent) {
  50. .type = DamageEventBase + XDamageNotify,
  51. .level = pDamageExt->level,
  52. .drawable = pDamageExt->drawable,
  53. .damage = pDamageExt->id,
  54. .timestamp = currentTime.milliseconds,
  55. .geometry.x = pDrawable->x,
  56. .geometry.y = pDrawable->y,
  57. .geometry.width = pDrawable->width,
  58. .geometry.height = pDrawable->height
  59. };
  60. if (pBoxes) {
  61. for (i = 0; i < nBoxes; i++) {
  62. ev.level = pDamageExt->level;
  63. if (i < nBoxes - 1)
  64. ev.level |= DamageNotifyMore;
  65. ev.area.x = pBoxes[i].x1;
  66. ev.area.y = pBoxes[i].y1;
  67. ev.area.width = pBoxes[i].x2 - pBoxes[i].x1;
  68. ev.area.height = pBoxes[i].y2 - pBoxes[i].y1;
  69. WriteEventsToClient(pClient, 1, (xEvent *) &ev);
  70. }
  71. }
  72. else {
  73. ev.area.x = 0;
  74. ev.area.y = 0;
  75. ev.area.width = pDrawable->width;
  76. ev.area.height = pDrawable->height;
  77. WriteEventsToClient(pClient, 1, (xEvent *) &ev);
  78. }
  79. /* Composite extension marks clients with manual Subwindows as critical */
  80. if (pDamageClient->critical > 0) {
  81. SetCriticalOutputPending();
  82. pClient->smart_priority = SMART_MAX_PRIORITY;
  83. }
  84. }
  85. static void
  86. DamageExtReport(DamagePtr pDamage, RegionPtr pRegion, void *closure)
  87. {
  88. DamageExtPtr pDamageExt = closure;
  89. switch (pDamageExt->level) {
  90. case DamageReportRawRegion:
  91. case DamageReportDeltaRegion:
  92. DamageExtNotify(pDamageExt, REGION_RECTS(pRegion),
  93. REGION_NUM_RECTS(pRegion));
  94. break;
  95. case DamageReportBoundingBox:
  96. DamageExtNotify(pDamageExt, REGION_EXTENTS(pRegion), 1);
  97. break;
  98. case DamageReportNonEmpty:
  99. DamageExtNotify(pDamageExt, NullBox, 0);
  100. break;
  101. case DamageReportNone:
  102. break;
  103. }
  104. }
  105. static void
  106. DamageExtDestroy(DamagePtr pDamage, void *closure)
  107. {
  108. DamageExtPtr pDamageExt = closure;
  109. pDamageExt->pDamage = 0;
  110. if (pDamageExt->id)
  111. FreeResource(pDamageExt->id, RT_NONE);
  112. }
  113. void
  114. DamageExtSetCritical(ClientPtr pClient, Bool critical)
  115. {
  116. DamageClientPtr pDamageClient = GetDamageClient(pClient);
  117. if (pDamageClient)
  118. pDamageClient->critical += critical ? 1 : -1;
  119. }
  120. static int
  121. ProcDamageQueryVersion(ClientPtr client)
  122. {
  123. DamageClientPtr pDamageClient = GetDamageClient(client);
  124. xDamageQueryVersionReply rep;
  125. REQUEST(xDamageQueryVersionReq);
  126. REQUEST_SIZE_MATCH(xDamageQueryVersionReq);
  127. rep.type = X_Reply;
  128. rep.length = 0;
  129. rep.sequenceNumber = client->sequence;
  130. if (stuff->majorVersion < SERVER_DAMAGE_MAJOR) {
  131. rep.majorVersion = stuff->majorVersion;
  132. rep.minorVersion = stuff->minorVersion;
  133. }
  134. else {
  135. rep.majorVersion = SERVER_DAMAGE_MAJOR;
  136. if (stuff->majorVersion == SERVER_DAMAGE_MAJOR &&
  137. stuff->minorVersion < SERVER_DAMAGE_MINOR)
  138. rep.minorVersion = stuff->minorVersion;
  139. else
  140. rep.minorVersion = SERVER_DAMAGE_MINOR;
  141. }
  142. pDamageClient->major_version = rep.majorVersion;
  143. pDamageClient->minor_version = rep.minorVersion;
  144. if (client->swapped) {
  145. swaps(&rep.sequenceNumber);
  146. swapl(&rep.length);
  147. swapl(&rep.majorVersion);
  148. swapl(&rep.minorVersion);
  149. }
  150. WriteToClient(client, sizeof(xDamageQueryVersionReply), (char *) &rep);
  151. return (client->noClientException);
  152. }
  153. static int
  154. ProcDamageCreate(ClientPtr client)
  155. {
  156. DrawablePtr pDrawable;
  157. DamageExtPtr pDamageExt;
  158. DamageReportLevel level;
  159. RegionPtr pRegion;
  160. REQUEST(xDamageCreateReq);
  161. REQUEST_SIZE_MATCH(xDamageCreateReq);
  162. LEGAL_NEW_RESOURCE(stuff->damage, client);
  163. SECURITY_VERIFY_DRAWABLE(pDrawable, stuff->drawable, client,
  164. SecurityReadAccess);
  165. switch (stuff->level) {
  166. case XDamageReportRawRectangles:
  167. level = DamageReportRawRegion;
  168. break;
  169. case XDamageReportDeltaRectangles:
  170. level = DamageReportDeltaRegion;
  171. break;
  172. case XDamageReportBoundingBox:
  173. level = DamageReportBoundingBox;
  174. break;
  175. case XDamageReportNonEmpty:
  176. level = DamageReportNonEmpty;
  177. break;
  178. default:
  179. client->errorValue = stuff->level;
  180. return BadValue;
  181. }
  182. pDamageExt = malloc(sizeof(DamageExtRec));
  183. if (!pDamageExt)
  184. return BadAlloc;
  185. pDamageExt->id = stuff->damage;
  186. pDamageExt->pDrawable = pDrawable;
  187. pDamageExt->level = level;
  188. pDamageExt->pClient = client;
  189. pDamageExt->pDamage = DamageCreate(DamageExtReport,
  190. DamageExtDestroy,
  191. level,
  192. FALSE, pDrawable->pScreen, pDamageExt);
  193. if (!pDamageExt->pDamage) {
  194. free(pDamageExt);
  195. return BadAlloc;
  196. }
  197. if (!AddResource(stuff->damage, DamageExtType, (pointer) pDamageExt))
  198. return BadAlloc;
  199. DamageRegister(pDamageExt->pDrawable, pDamageExt->pDamage);
  200. if (pDrawable->type == DRAWABLE_WINDOW) {
  201. pRegion = &((WindowPtr) pDrawable)->borderClip;
  202. DamageDamageRegion(pDrawable, pRegion);
  203. }
  204. return (client->noClientException);
  205. }
  206. static int
  207. ProcDamageDestroy(ClientPtr client)
  208. {
  209. REQUEST(xDamageDestroyReq);
  210. DamageExtPtr pDamageExt;
  211. REQUEST_SIZE_MATCH(xDamageDestroyReq);
  212. VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, SecurityWriteAccess);
  213. FreeResource(stuff->damage, RT_NONE);
  214. return (client->noClientException);
  215. }
  216. static int
  217. ProcDamageSubtract(ClientPtr client)
  218. {
  219. REQUEST(xDamageSubtractReq);
  220. DamageExtPtr pDamageExt;
  221. RegionPtr pRepair;
  222. RegionPtr pParts;
  223. REQUEST_SIZE_MATCH(xDamageSubtractReq);
  224. VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, SecurityWriteAccess);
  225. VERIFY_REGION_OR_NONE(pRepair, stuff->repair, client, SecurityWriteAccess);
  226. VERIFY_REGION_OR_NONE(pParts, stuff->parts, client, SecurityWriteAccess);
  227. if (pDamageExt->level != DamageReportRawRegion) {
  228. DamagePtr pDamage = pDamageExt->pDamage;
  229. if (pRepair) {
  230. if (pParts)
  231. REGION_INTERSECT(pParts, DamageRegion(pDamage),
  232. pRepair);
  233. if (DamageSubtract(pDamage, pRepair))
  234. DamageExtReport(pDamage, DamageRegion(pDamage),
  235. (void *) pDamageExt);
  236. }
  237. else {
  238. if (pParts)
  239. REGION_COPY(pParts, DamageRegion(pDamage));
  240. DamageEmpty(pDamage);
  241. }
  242. }
  243. return (client->noClientException);
  244. }
  245. static int
  246. ProcDamageAdd(ClientPtr client)
  247. {
  248. REQUEST(xDamageAddReq);
  249. DrawablePtr pDrawable;
  250. RegionPtr pRegion;
  251. REQUEST_SIZE_MATCH(xDamageAddReq);
  252. VERIFY_REGION(pRegion, stuff->region, client, SecurityWriteAccess);
  253. SECURITY_VERIFY_DRAWABLE(pDrawable, stuff->drawable, client,
  254. SecurityReadAccess);
  255. /* The region is relative to the drawable origin, so translate it out to
  256. * screen coordinates like damage expects.
  257. */
  258. REGION_TRANSLATE(pRegion, pDrawable->x, pDrawable->y);
  259. DamageDamageRegion(pDrawable, pRegion);
  260. REGION_TRANSLATE(pRegion, -pDrawable->x, -pDrawable->y);
  261. return (client->noClientException);
  262. }
  263. /* Major version controls available requests */
  264. static const int version_requests[] = {
  265. X_DamageQueryVersion, /* before client sends QueryVersion */
  266. X_DamageAdd, /* Version 1 */
  267. };
  268. #define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0]))
  269. int (*ProcDamageVector[XDamageNumberRequests]) (ClientPtr) = {
  270. /*************** Version 1 ******************/
  271. ProcDamageQueryVersion,
  272. ProcDamageCreate, ProcDamageDestroy, ProcDamageSubtract,
  273. /*************** Version 1.1 ****************/
  274. ProcDamageAdd,};
  275. static int
  276. ProcDamageDispatch(ClientPtr client)
  277. {
  278. REQUEST(xDamageReq);
  279. DamageClientPtr pDamageClient = GetDamageClient(client);
  280. if (pDamageClient->major_version >= NUM_VERSION_REQUESTS)
  281. return BadRequest;
  282. if (stuff->damageReqType > version_requests[pDamageClient->major_version])
  283. return BadRequest;
  284. return (*ProcDamageVector[stuff->damageReqType]) (client);
  285. }
  286. static int
  287. SProcDamageQueryVersion(ClientPtr client)
  288. {
  289. REQUEST(xDamageQueryVersionReq);
  290. swaps(&stuff->length);
  291. REQUEST_SIZE_MATCH(xDamageQueryVersionReq);
  292. swapl(&stuff->majorVersion);
  293. swapl(&stuff->minorVersion);
  294. return (*ProcDamageVector[stuff->damageReqType]) (client);
  295. }
  296. static int
  297. SProcDamageCreate(ClientPtr client)
  298. {
  299. REQUEST(xDamageCreateReq);
  300. swaps(&stuff->length);
  301. REQUEST_SIZE_MATCH(xDamageCreateReq);
  302. swapl(&stuff->damage);
  303. swapl(&stuff->drawable);
  304. return (*ProcDamageVector[stuff->damageReqType]) (client);
  305. }
  306. static int
  307. SProcDamageDestroy(ClientPtr client)
  308. {
  309. REQUEST(xDamageDestroyReq);
  310. swaps(&stuff->length);
  311. REQUEST_SIZE_MATCH(xDamageDestroyReq);
  312. swapl(&stuff->damage);
  313. return (*ProcDamageVector[stuff->damageReqType]) (client);
  314. }
  315. static int
  316. SProcDamageSubtract(ClientPtr client)
  317. {
  318. REQUEST(xDamageSubtractReq);
  319. swaps(&stuff->length);
  320. REQUEST_SIZE_MATCH(xDamageSubtractReq);
  321. swapl(&stuff->damage);
  322. swapl(&stuff->repair);
  323. swapl(&stuff->parts);
  324. return (*ProcDamageVector[stuff->damageReqType]) (client);
  325. }
  326. static int
  327. SProcDamageAdd(ClientPtr client)
  328. {
  329. REQUEST(xDamageAddReq);
  330. swaps(&stuff->length);
  331. REQUEST_SIZE_MATCH(xDamageSubtractReq);
  332. swapl(&stuff->drawable);
  333. swapl(&stuff->region);
  334. return (*ProcDamageVector[stuff->damageReqType]) (client);
  335. }
  336. int (*SProcDamageVector[XDamageNumberRequests]) (ClientPtr) = {
  337. /*************** Version 1 ******************/
  338. SProcDamageQueryVersion,
  339. SProcDamageCreate, SProcDamageDestroy, SProcDamageSubtract,
  340. /*************** Version 1.1 ****************/
  341. SProcDamageAdd,};
  342. static int
  343. SProcDamageDispatch(ClientPtr client)
  344. {
  345. REQUEST(xDamageReq);
  346. if (stuff->damageReqType >= XDamageNumberRequests)
  347. return BadRequest;
  348. return (*SProcDamageVector[stuff->damageReqType]) (client);
  349. }
  350. static void
  351. DamageClientCallback(CallbackListPtr *list, pointer closure, pointer data)
  352. {
  353. NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
  354. ClientPtr pClient = clientinfo->client;
  355. DamageClientPtr pDamageClient = GetDamageClient(pClient);
  356. pDamageClient->critical = 0;
  357. pDamageClient->major_version = 0;
  358. pDamageClient->minor_version = 0;
  359. }
  360. /*ARGSUSED*/ static void
  361. DamageResetProc(ExtensionEntry * extEntry)
  362. {
  363. DeleteCallback(&ClientStateCallback, DamageClientCallback, 0);
  364. }
  365. static int
  366. FreeDamageExt(pointer value, XID did)
  367. {
  368. DamageExtPtr pDamageExt = (DamageExtPtr) value;
  369. /*
  370. * Get rid of the resource table entry hanging from the window id
  371. */
  372. pDamageExt->id = 0;
  373. if (WindowDrawable(pDamageExt->pDrawable->type))
  374. FreeResourceByType(pDamageExt->pDrawable->id, DamageExtWinType, TRUE);
  375. if (pDamageExt->pDamage) {
  376. DamageUnregister(pDamageExt->pDrawable, pDamageExt->pDamage);
  377. DamageDestroy(pDamageExt->pDamage);
  378. }
  379. free(pDamageExt);
  380. return Success;
  381. }
  382. static int
  383. FreeDamageExtWin(pointer value, XID wid)
  384. {
  385. DamageExtPtr pDamageExt = (DamageExtPtr) value;
  386. if (pDamageExt->id)
  387. FreeResource(pDamageExt->id, RT_NONE);
  388. return Success;
  389. }
  390. void
  391. SDamageNotifyEvent(xDamageNotifyEvent * from, xDamageNotifyEvent * to)
  392. {
  393. to->type = from->type;
  394. cpswaps(from->sequenceNumber, to->sequenceNumber);
  395. cpswapl(from->drawable, to->drawable);
  396. cpswapl(from->damage, to->damage);
  397. cpswaps(from->area.x, to->area.x);
  398. cpswaps(from->area.y, to->area.y);
  399. cpswaps(from->area.width, to->area.width);
  400. cpswaps(from->area.height, to->area.height);
  401. cpswaps(from->geometry.x, to->geometry.x);
  402. cpswaps(from->geometry.y, to->geometry.y);
  403. cpswaps(from->geometry.width, to->geometry.width);
  404. cpswaps(from->geometry.height, to->geometry.height);
  405. }
  406. void
  407. DamageExtensionInit(void)
  408. {
  409. ExtensionEntry *extEntry;
  410. int s;
  411. for (s = 0; s < screenInfo.numScreens; s++)
  412. DamageSetup(screenInfo.screens[s]);
  413. DamageExtType = CreateNewResourceType(FreeDamageExt);
  414. if (!DamageExtType)
  415. return;
  416. DamageExtWinType = CreateNewResourceType(FreeDamageExtWin);
  417. if (!DamageExtWinType)
  418. return;
  419. DamageClientPrivateIndex = AllocateClientPrivateIndex();
  420. if (!AllocateClientPrivate(DamageClientPrivateIndex,
  421. sizeof(DamageClientRec)))
  422. return;
  423. if (!AddCallback(&ClientStateCallback, DamageClientCallback, 0))
  424. return;
  425. if ((extEntry = AddExtension(DAMAGE_NAME, XDamageNumberEvents,
  426. XDamageNumberErrors,
  427. ProcDamageDispatch, SProcDamageDispatch,
  428. DamageResetProc, StandardMinorOpcode)) != 0) {
  429. DamageReqCode = (unsigned char) extEntry->base;
  430. DamageEventBase = extEntry->eventBase;
  431. DamageErrorBase = extEntry->errorBase;
  432. EventSwapVector[DamageEventBase + XDamageNotify] =
  433. (EventSwapPtr) SDamageNotifyEvent;
  434. }
  435. }