rroutput.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. /*
  2. * Copyright © 2006 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 copyright
  7. * notice and this permission notice appear in supporting documentation, and
  8. * that the name of the copyright holders not be used in advertising or
  9. * publicity pertaining to distribution of the software without specific,
  10. * written prior permission. The copyright holders make no representations
  11. * about the suitability of this software for any purpose. It is provided "as
  12. * is" without express or implied warranty.
  13. *
  14. * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15. * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  16. * EVENT SHALL THE COPYRIGHT HOLDERS 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 PERFORMANCE
  20. * OF THIS SOFTWARE.
  21. */
  22. #include "randrstr.h"
  23. RESTYPE RROutputType;
  24. /*
  25. * Notify the output of some change
  26. */
  27. void
  28. RROutputChanged(RROutputPtr output, Bool configChanged)
  29. {
  30. ScreenPtr pScreen = output->pScreen;
  31. output->changed = TRUE;
  32. if (pScreen) {
  33. rrScrPriv(pScreen);
  34. pScrPriv->changed = TRUE;
  35. if (configChanged)
  36. pScrPriv->configChanged = TRUE;
  37. }
  38. }
  39. /*
  40. * Create an output
  41. */
  42. RROutputPtr
  43. RROutputCreate(const char *name, int nameLength, void *devPrivate)
  44. {
  45. RROutputPtr output;
  46. if (!RRInit())
  47. return NULL;
  48. output = malloc(sizeof(RROutputRec) + nameLength + 1);
  49. if (!output)
  50. return NULL;
  51. output->id = FakeClientID(0);
  52. output->pScreen = NULL;
  53. output->name = (char *) (output + 1);
  54. output->nameLength = nameLength;
  55. memcpy(output->name, name, nameLength);
  56. output->name[nameLength] = '\0';
  57. output->connection = RR_UnknownConnection;
  58. output->subpixelOrder = SubPixelUnknown;
  59. output->mmWidth = 0;
  60. output->mmHeight = 0;
  61. output->crtc = NULL;
  62. output->numCrtcs = 0;
  63. output->crtcs = NULL;
  64. output->numClones = 0;
  65. output->clones = NULL;
  66. output->numModes = 0;
  67. output->numPreferred = 0;
  68. output->modes = NULL;
  69. output->properties = NULL;
  70. output->changed = FALSE;
  71. output->devPrivate = devPrivate;
  72. if (!AddResource(output->id, RROutputType, (pointer) output))
  73. return NULL;
  74. return output;
  75. }
  76. /*
  77. * Attach an Output to a screen. This is done as a separate step
  78. * so that an xf86-based driver can create Outputs in PreInit
  79. * before the Screen has been created
  80. */
  81. Bool
  82. RROutputAttachScreen(RROutputPtr output, ScreenPtr pScreen)
  83. {
  84. rrScrPriv(pScreen);
  85. RROutputPtr *outputs;
  86. if (pScrPriv->numOutputs)
  87. outputs = realloc(pScrPriv->outputs,
  88. (pScrPriv->numOutputs + 1) * sizeof(RROutputPtr));
  89. else
  90. outputs = malloc(sizeof(RROutputPtr));
  91. if (!outputs)
  92. return FALSE;
  93. output->pScreen = pScreen;
  94. pScrPriv->outputs = outputs;
  95. pScrPriv->outputs[pScrPriv->numOutputs++] = output;
  96. RROutputChanged(output, FALSE);
  97. return TRUE;
  98. }
  99. /*
  100. * Notify extension that output parameters have been changed
  101. */
  102. Bool
  103. RROutputSetClones(RROutputPtr output, RROutputPtr * clones, int numClones)
  104. {
  105. RROutputPtr *newClones;
  106. int i;
  107. if (numClones == output->numClones) {
  108. for (i = 0; i < numClones; i++)
  109. if (output->clones[i] != clones[i])
  110. break;
  111. if (i == numClones)
  112. return TRUE;
  113. }
  114. if (numClones) {
  115. newClones = malloc(numClones * sizeof(RROutputPtr));
  116. if (!newClones)
  117. return FALSE;
  118. memcpy(newClones, clones, numClones * sizeof(RROutputPtr));
  119. }
  120. else
  121. newClones = NULL;
  122. if (output->clones)
  123. free(output->clones);
  124. output->clones = newClones;
  125. output->numClones = numClones;
  126. RROutputChanged(output, TRUE);
  127. return TRUE;
  128. }
  129. Bool
  130. RROutputSetModes(RROutputPtr output,
  131. RRModePtr * modes, int numModes, int numPreferred)
  132. {
  133. RRModePtr *newModes;
  134. int i;
  135. if (numModes == output->numModes && numPreferred == output->numPreferred) {
  136. for (i = 0; i < numModes; i++)
  137. if (output->modes[i] != modes[i])
  138. break;
  139. if (i == numModes) {
  140. for (i = 0; i < numModes; i++)
  141. RRModeDestroy(modes[i]);
  142. return TRUE;
  143. }
  144. }
  145. if (numModes) {
  146. newModes = malloc(numModes * sizeof(RRModePtr));
  147. if (!newModes)
  148. return FALSE;
  149. memcpy(newModes, modes, numModes * sizeof(RRModePtr));
  150. }
  151. else
  152. newModes = NULL;
  153. if (output->modes) {
  154. for (i = 0; i < output->numModes; i++)
  155. RRModeDestroy(output->modes[i]);
  156. free(output->modes);
  157. }
  158. output->modes = newModes;
  159. output->numModes = numModes;
  160. output->numPreferred = numPreferred;
  161. RROutputChanged(output, TRUE);
  162. return TRUE;
  163. }
  164. Bool
  165. RROutputSetCrtcs(RROutputPtr output, RRCrtcPtr * crtcs, int numCrtcs)
  166. {
  167. RRCrtcPtr *newCrtcs;
  168. int i;
  169. if (numCrtcs == output->numCrtcs) {
  170. for (i = 0; i < numCrtcs; i++)
  171. if (output->crtcs[i] != crtcs[i])
  172. break;
  173. if (i == numCrtcs)
  174. return TRUE;
  175. }
  176. if (numCrtcs) {
  177. newCrtcs = malloc(numCrtcs * sizeof(RRCrtcPtr));
  178. if (!newCrtcs)
  179. return FALSE;
  180. memcpy(newCrtcs, crtcs, numCrtcs * sizeof(RRCrtcPtr));
  181. }
  182. else
  183. newCrtcs = NULL;
  184. free(output->crtcs);
  185. output->crtcs = newCrtcs;
  186. output->numCrtcs = numCrtcs;
  187. RROutputChanged(output, TRUE);
  188. return TRUE;
  189. }
  190. void
  191. RROutputSetCrtc(RROutputPtr output, RRCrtcPtr crtc)
  192. {
  193. if (output->crtc == crtc)
  194. return;
  195. output->crtc = crtc;
  196. RROutputChanged(output, FALSE);
  197. }
  198. Bool
  199. RROutputSetConnection(RROutputPtr output, CARD8 connection)
  200. {
  201. if (output->connection == connection)
  202. return TRUE;
  203. output->connection = connection;
  204. RROutputChanged(output, TRUE);
  205. return TRUE;
  206. }
  207. Bool
  208. RROutputSetSubpixelOrder(RROutputPtr output, int subpixelOrder)
  209. {
  210. if (output->subpixelOrder == subpixelOrder)
  211. return TRUE;
  212. output->subpixelOrder = subpixelOrder;
  213. RROutputChanged(output, FALSE);
  214. return TRUE;
  215. }
  216. Bool
  217. RROutputSetPhysicalSize(RROutputPtr output, int mmWidth, int mmHeight)
  218. {
  219. if (output->mmWidth == mmWidth && output->mmHeight == mmHeight)
  220. return TRUE;
  221. output->mmWidth = mmWidth;
  222. output->mmHeight = mmHeight;
  223. RROutputChanged(output, FALSE);
  224. return TRUE;
  225. }
  226. void
  227. RRDeliverOutputEvent(ClientPtr client, WindowPtr pWin, RROutputPtr output)
  228. {
  229. ScreenPtr pScreen = pWin->drawable.pScreen;
  230. rrScrPriv(pScreen);
  231. xRROutputChangeNotifyEvent oe;
  232. RRCrtcPtr crtc = output->crtc;
  233. RRModePtr mode = crtc ? crtc->mode : 0;
  234. oe.type = RRNotify + RREventBase;
  235. oe.subCode = RRNotify_OutputChange;
  236. oe.timestamp = pScrPriv->lastSetTime.milliseconds;
  237. oe.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
  238. oe.window = pWin->drawable.id;
  239. oe.output = output->id;
  240. if (crtc) {
  241. oe.crtc = crtc->id;
  242. oe.mode = mode ? mode->mode.id : None;
  243. oe.rotation = crtc->rotation;
  244. }
  245. else {
  246. oe.crtc = None;
  247. oe.mode = None;
  248. oe.rotation = RR_Rotate_0;
  249. }
  250. oe.connection = output->connection;
  251. oe.subpixelOrder = output->subpixelOrder;
  252. WriteEventsToClient(client, 1, (xEvent *) &oe);
  253. }
  254. /*
  255. * Destroy a Output at shutdown
  256. */
  257. void
  258. RROutputDestroy(RROutputPtr crtc)
  259. {
  260. FreeResource(crtc->id, 0);
  261. }
  262. static int
  263. RROutputDestroyResource(pointer value, XID pid)
  264. {
  265. RROutputPtr output = (RROutputPtr) value;
  266. ScreenPtr pScreen = output->pScreen;
  267. if (pScreen) {
  268. rrScrPriv(pScreen);
  269. int i;
  270. for (i = 0; i < pScrPriv->numOutputs; i++) {
  271. if (pScrPriv->outputs[i] == output) {
  272. memmove(pScrPriv->outputs + i, pScrPriv->outputs + i + 1,
  273. (pScrPriv->numOutputs - (i + 1)) * sizeof(RROutputPtr));
  274. --pScrPriv->numOutputs;
  275. break;
  276. }
  277. }
  278. }
  279. if (output->modes)
  280. free(output->modes);
  281. if (output->crtcs)
  282. free(output->crtcs);
  283. if (output->clones)
  284. free(output->clones);
  285. RRDeleteAllOutputProperties(output);
  286. free(output);
  287. return 1;
  288. }
  289. /*
  290. * Initialize output type
  291. */
  292. Bool
  293. RROutputInit(void)
  294. {
  295. RROutputType = CreateNewResourceType(RROutputDestroyResource);
  296. if (!RROutputType)
  297. return FALSE;
  298. #ifdef XResExtension
  299. RegisterResourceName(RROutputType, "OUTPUT");
  300. #endif
  301. return TRUE;
  302. }
  303. #define OutputInfoExtra (SIZEOF(xRRGetOutputInfoReply) - 32)
  304. int
  305. ProcRRGetOutputInfo(ClientPtr client)
  306. {
  307. REQUEST(xRRGetOutputInfoReq);;
  308. xRRGetOutputInfoReply rep;
  309. RROutputPtr output;
  310. CARD8 *extra;
  311. unsigned long extraLen;
  312. ScreenPtr pScreen;
  313. rrScrPrivPtr pScrPriv;
  314. RRCrtc *crtcs;
  315. RRMode *modes;
  316. RROutput *clones;
  317. char *name;
  318. int i;
  319. REQUEST_SIZE_MATCH(xRRGetOutputInfoReq);
  320. output = LookupOutput(client, stuff->output, SecurityReadAccess);
  321. if (!output)
  322. return RRErrorBase + BadRROutput;
  323. pScreen = output->pScreen;
  324. pScrPriv = rrGetScrPriv(pScreen);
  325. rep.type = X_Reply;
  326. rep.sequenceNumber = client->sequence;
  327. rep.length = OutputInfoExtra >> 2;
  328. rep.timestamp = pScrPriv->lastSetTime.milliseconds;
  329. rep.crtc = output->crtc ? output->crtc->id : None;
  330. rep.mmWidth = output->mmWidth;
  331. rep.mmHeight = output->mmHeight;
  332. rep.connection = output->connection;
  333. rep.subpixelOrder = output->subpixelOrder;
  334. rep.nCrtcs = output->numCrtcs;
  335. rep.nModes = output->numModes;
  336. rep.nPreferred = output->numPreferred;
  337. rep.nClones = output->numClones;
  338. rep.nameLength = output->nameLength;
  339. extraLen = ((output->numCrtcs +
  340. output->numModes +
  341. output->numClones + ((rep.nameLength + 3) >> 2)) << 2);
  342. if (extraLen) {
  343. rep.length += extraLen >> 2;
  344. extra = malloc(extraLen);
  345. if (!extra)
  346. return BadAlloc;
  347. }
  348. else
  349. extra = NULL;
  350. crtcs = (RRCrtc *) extra;
  351. modes = (RRMode *) (crtcs + output->numCrtcs);
  352. clones = (RROutput *) (modes + output->numModes);
  353. name = (char *) (clones + output->numClones);
  354. for (i = 0; i < output->numCrtcs; i++) {
  355. crtcs[i] = output->crtcs[i]->id;
  356. if (client->swapped)
  357. swapl(&crtcs[i]);
  358. }
  359. for (i = 0; i < output->numModes; i++) {
  360. modes[i] = output->modes[i]->mode.id;
  361. if (client->swapped)
  362. swapl(&modes[i]);
  363. }
  364. for (i = 0; i < output->numClones; i++) {
  365. clones[i] = output->clones[i]->id;
  366. if (client->swapped)
  367. swapl(&clones[i]);
  368. }
  369. memcpy(name, output->name, output->nameLength);
  370. if (client->swapped) {
  371. swaps(&rep.sequenceNumber);
  372. swapl(&rep.length);
  373. swapl(&rep.timestamp);
  374. swapl(&rep.crtc);
  375. swapl(&rep.mmWidth);
  376. swapl(&rep.mmHeight);
  377. swaps(&rep.nCrtcs);
  378. swaps(&rep.nModes);
  379. swaps(&rep.nClones);
  380. swaps(&rep.nameLength);
  381. }
  382. WriteToClient(client, sizeof(xRRGetOutputInfoReply), (char *) &rep);
  383. if (extraLen) {
  384. WriteToClient(client, extraLen, (char *) extra);
  385. free(extra);
  386. }
  387. return client->noClientException;
  388. }