You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

vncHooks.cc 48KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. *
  3. * This is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This software is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  16. * USA.
  17. */
  18. #include <stdio.h>
  19. #include "XserverDesktop.h"
  20. #include "vncHooks.h"
  21. extern "C" {
  22. #define class c_class
  23. #define private c_private
  24. #include "scrnintstr.h"
  25. #include "windowstr.h"
  26. #include "gcstruct.h"
  27. #include "regionstr.h"
  28. #include "dixfontstr.h"
  29. #include "colormapst.h"
  30. #ifdef RENDER
  31. #include "picturestr.h"
  32. #endif
  33. #ifdef GC_HAS_COMPOSITE_CLIP
  34. #define COMPOSITE_CLIP(gc) ((gc)->pCompositeClip)
  35. #else
  36. #include "mfb.h"
  37. #define COMPOSITE_CLIP(gc) \
  38. (((mfbPrivGCPtr)((gc)->devPrivates[mfbGCPrivateIndex].ptr))->pCompositeClip)
  39. #endif
  40. #undef class
  41. #undef private
  42. }
  43. #include "RegionHelper.h"
  44. #define DBGPRINT(x) //(fprintf x)
  45. // MAX_RECTS_PER_OP is the maximum number of rectangles we generate from
  46. // operations like Polylines and PolySegment. If the operation is more complex
  47. // than this, we simply use the bounding box. Ideally it would be a
  48. // command-line option, but that would involve an extra malloc each time, so we
  49. // fix it here.
  50. #define MAX_RECTS_PER_OP 5
  51. static unsigned long vncHooksGeneration = 0;
  52. // vncHooksScreenRec and vncHooksGCRec contain pointers to the original
  53. // functions which we "wrap" in order to hook the screen changes. The screen
  54. // functions are each wrapped individually, while the GC "funcs" and "ops" are
  55. // wrapped as a unit.
  56. typedef struct {
  57. XserverDesktop* desktop;
  58. CloseScreenProcPtr CloseScreen;
  59. CreateGCProcPtr CreateGC;
  60. PaintWindowBackgroundProcPtr PaintWindowBackground;
  61. PaintWindowBorderProcPtr PaintWindowBorder;
  62. CopyWindowProcPtr CopyWindow;
  63. ClearToBackgroundProcPtr ClearToBackground;
  64. RestoreAreasProcPtr RestoreAreas;
  65. InstallColormapProcPtr InstallColormap;
  66. StoreColorsProcPtr StoreColors;
  67. DisplayCursorProcPtr DisplayCursor;
  68. ScreenBlockHandlerProcPtr BlockHandler;
  69. #ifdef RENDER
  70. CompositeProcPtr Composite;
  71. #endif
  72. } vncHooksScreenRec, *vncHooksScreenPtr;
  73. typedef struct {
  74. GCFuncs *wrappedFuncs;
  75. GCOps *wrappedOps;
  76. } vncHooksGCRec, *vncHooksGCPtr;
  77. static int vncHooksScreenIndex;
  78. static int vncHooksGCIndex;
  79. // screen functions
  80. static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen);
  81. static Bool vncHooksCreateGC(GCPtr pGC);
  82. static void vncHooksPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion,
  83. int what);
  84. static void vncHooksPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion,
  85. int what);
  86. static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
  87. RegionPtr pOldRegion);
  88. static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w,
  89. int h, Bool generateExposures);
  90. static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr prgnExposed);
  91. static void vncHooksInstallColormap(ColormapPtr pColormap);
  92. static void vncHooksStoreColors(ColormapPtr pColormap, int ndef,
  93. xColorItem* pdef);
  94. static Bool vncHooksDisplayCursor(ScreenPtr pScreen, CursorPtr cursor);
  95. static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout,
  96. pointer pReadmask);
  97. #ifdef RENDER
  98. static void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask,
  99. PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask,
  100. INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
  101. #endif
  102. // GC "funcs"
  103. static void vncHooksValidateGC(GCPtr pGC, unsigned long changes,
  104. DrawablePtr pDrawable);
  105. static void vncHooksChangeGC(GCPtr pGC, unsigned long mask);
  106. static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst);
  107. static void vncHooksDestroyGC(GCPtr pGC);
  108. static void vncHooksChangeClip(GCPtr pGC, int type, pointer pValue,int nrects);
  109. static void vncHooksDestroyClip(GCPtr pGC);
  110. static void vncHooksCopyClip(GCPtr dst, GCPtr src);
  111. static GCFuncs vncHooksGCFuncs = {
  112. vncHooksValidateGC, vncHooksChangeGC, vncHooksCopyGC, vncHooksDestroyGC,
  113. vncHooksChangeClip, vncHooksDestroyClip, vncHooksCopyClip,
  114. };
  115. // GC "ops"
  116. static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit,
  117. DDXPointPtr pptInit, int *pwidthInit,
  118. int fSorted);
  119. static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
  120. DDXPointPtr ppt, int *pwidth, int nspans,
  121. int fSorted);
  122. static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
  123. int x, int y, int w, int h, int leftPad,
  124. int format, char *pBits);
  125. static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst,
  126. GCPtr pGC, int srcx, int srcy, int w, int h,
  127. int dstx, int dsty);
  128. static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst,
  129. GCPtr pGC, int srcx, int srcy, int w, int h,
  130. int dstx, int dsty, unsigned long plane);
  131. static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode,
  132. int npt, xPoint *pts);
  133. static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode,
  134. int npt, DDXPointPtr ppts);
  135. static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
  136. xSegment *segs);
  137. static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects,
  138. xRectangle *rects);
  139. static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
  140. xArc *arcs);
  141. static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape,
  142. int mode, int count, DDXPointPtr pts);
  143. static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects,
  144. xRectangle *rects);
  145. static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
  146. xArc *arcs);
  147. static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
  148. int count, char *chars);
  149. static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
  150. int count, unsigned short *chars);
  151. static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
  152. int count, char *chars);
  153. static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
  154. int count, unsigned short *chars);
  155. static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
  156. int y, unsigned int nglyph,
  157. CharInfoPtr *ppci, pointer pglyphBase);
  158. static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
  159. int y, unsigned int nglyph,
  160. CharInfoPtr *ppci, pointer pglyphBase);
  161. static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap,
  162. DrawablePtr pDrawable, int w, int h, int x,
  163. int y);
  164. static GCOps vncHooksGCOps = {
  165. vncHooksFillSpans, vncHooksSetSpans, vncHooksPutImage, vncHooksCopyArea,
  166. vncHooksCopyPlane, vncHooksPolyPoint, vncHooksPolylines, vncHooksPolySegment,
  167. vncHooksPolyRectangle, vncHooksPolyArc, vncHooksFillPolygon,
  168. vncHooksPolyFillRect, vncHooksPolyFillArc, vncHooksPolyText8,
  169. vncHooksPolyText16, vncHooksImageText8, vncHooksImageText16,
  170. vncHooksImageGlyphBlt, vncHooksPolyGlyphBlt, vncHooksPushPixels
  171. };
  172. /////////////////////////////////////////////////////////////////////////////
  173. // vncHooksInit() is called at initialisation time and every time the server
  174. // resets. It is called once for each screen, but the indexes are only
  175. // allocated once for each server generation.
  176. Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop)
  177. {
  178. vncHooksScreenPtr vncHooksScreen;
  179. if (vncHooksGeneration != serverGeneration) {
  180. vncHooksGeneration = serverGeneration;
  181. vncHooksScreenIndex = AllocateScreenPrivateIndex();
  182. if (vncHooksScreenIndex < 0) {
  183. ErrorF("vncHooksInit: AllocateScreenPrivateIndex failed\n");
  184. return FALSE;
  185. }
  186. vncHooksGCIndex = AllocateGCPrivateIndex();
  187. if (vncHooksGCIndex < 0) {
  188. ErrorF("vncHooksInit: AllocateGCPrivateIndex failed\n");
  189. return FALSE;
  190. }
  191. }
  192. if (!AllocateGCPrivate(pScreen, vncHooksGCIndex, sizeof(vncHooksGCRec))) {
  193. ErrorF("vncHooksInit: AllocateGCPrivate failed\n");
  194. return FALSE;
  195. }
  196. vncHooksScreen = (vncHooksScreenPtr)xnfalloc(sizeof(vncHooksScreenRec));
  197. pScreen->devPrivates[vncHooksScreenIndex].ptr = (pointer)vncHooksScreen;
  198. vncHooksScreen->desktop = desktop;
  199. vncHooksScreen->CloseScreen = pScreen->CloseScreen;
  200. vncHooksScreen->CreateGC = pScreen->CreateGC;
  201. vncHooksScreen->PaintWindowBackground = pScreen->PaintWindowBackground;
  202. vncHooksScreen->PaintWindowBorder = pScreen->PaintWindowBorder;
  203. vncHooksScreen->CopyWindow = pScreen->CopyWindow;
  204. vncHooksScreen->ClearToBackground = pScreen->ClearToBackground;
  205. vncHooksScreen->RestoreAreas = pScreen->RestoreAreas;
  206. vncHooksScreen->InstallColormap = pScreen->InstallColormap;
  207. vncHooksScreen->StoreColors = pScreen->StoreColors;
  208. vncHooksScreen->DisplayCursor = pScreen->DisplayCursor;
  209. vncHooksScreen->BlockHandler = pScreen->BlockHandler;
  210. #ifdef RENDER
  211. PictureScreenPtr ps;
  212. ps = GetPictureScreenIfSet(pScreen);
  213. if (ps) {
  214. vncHooksScreen->Composite = ps->Composite;
  215. }
  216. #endif
  217. pScreen->CloseScreen = vncHooksCloseScreen;
  218. pScreen->CreateGC = vncHooksCreateGC;
  219. pScreen->PaintWindowBackground = vncHooksPaintWindowBackground;
  220. pScreen->PaintWindowBorder = vncHooksPaintWindowBorder;
  221. pScreen->CopyWindow = vncHooksCopyWindow;
  222. pScreen->ClearToBackground = vncHooksClearToBackground;
  223. pScreen->RestoreAreas = vncHooksRestoreAreas;
  224. pScreen->InstallColormap = vncHooksInstallColormap;
  225. pScreen->StoreColors = vncHooksStoreColors;
  226. pScreen->DisplayCursor = vncHooksDisplayCursor;
  227. pScreen->BlockHandler = vncHooksBlockHandler;
  228. #ifdef RENDER
  229. if (ps) {
  230. ps->Composite = vncHooksComposite;
  231. }
  232. #endif
  233. return TRUE;
  234. }
  235. /////////////////////////////////////////////////////////////////////////////
  236. //
  237. // screen functions
  238. //
  239. // SCREEN_UNWRAP and SCREEN_REWRAP unwrap and rewrap the given screen function.
  240. // It would be nice to do this with a C++ class, but each function is of a
  241. // distinct type, so it would have to use templates, and it's not worth that
  242. // much pain.
  243. #define SCREEN_UNWRAP(scrn,field) \
  244. ScreenPtr pScreen = scrn; \
  245. vncHooksScreenPtr vncHooksScreen \
  246. = ((vncHooksScreenPtr)pScreen->devPrivates[vncHooksScreenIndex].ptr); \
  247. pScreen->field = vncHooksScreen->field; \
  248. DBGPRINT((stderr,"vncHooks" #field " called\n"));
  249. #define SCREEN_REWRAP(field) pScreen->field = vncHooks##field;
  250. // CloseScreen - unwrap the screen functions and call the original CloseScreen
  251. // function
  252. static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen_)
  253. {
  254. SCREEN_UNWRAP(pScreen_, CloseScreen);
  255. pScreen->CreateGC = vncHooksScreen->CreateGC;
  256. pScreen->PaintWindowBackground = vncHooksScreen->PaintWindowBackground;
  257. pScreen->PaintWindowBorder = vncHooksScreen->PaintWindowBorder;
  258. pScreen->CopyWindow = vncHooksScreen->CopyWindow;
  259. pScreen->ClearToBackground = vncHooksScreen->ClearToBackground;
  260. pScreen->RestoreAreas = vncHooksScreen->RestoreAreas;
  261. pScreen->InstallColormap = vncHooksScreen->InstallColormap;
  262. pScreen->StoreColors = vncHooksScreen->StoreColors;
  263. pScreen->DisplayCursor = vncHooksScreen->DisplayCursor;
  264. pScreen->BlockHandler = vncHooksScreen->BlockHandler;
  265. xfree((pointer)vncHooksScreen);
  266. DBGPRINT((stderr,"vncHooksCloseScreen: unwrapped screen functions\n"));
  267. return (*pScreen->CloseScreen)(i, pScreen);
  268. }
  269. // CreateGC - wrap the "GC funcs"
  270. static Bool vncHooksCreateGC(GCPtr pGC)
  271. {
  272. SCREEN_UNWRAP(pGC->pScreen, CreateGC);
  273. vncHooksGCPtr vncHooksGC
  274. = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr;
  275. Bool ret = (*pScreen->CreateGC) (pGC);
  276. vncHooksGC->wrappedOps = 0;
  277. vncHooksGC->wrappedFuncs = pGC->funcs;
  278. pGC->funcs = &vncHooksGCFuncs;
  279. SCREEN_REWRAP(CreateGC);
  280. return ret;
  281. }
  282. // PaintWindowBackground - changed region is the given region
  283. static void vncHooksPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion,
  284. int what)
  285. {
  286. SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindowBackground);
  287. RegionHelper changed(pScreen, pRegion);
  288. (*pScreen->PaintWindowBackground) (pWin, pRegion, what);
  289. vncHooksScreen->desktop->add_changed(changed.reg);
  290. SCREEN_REWRAP(PaintWindowBackground);
  291. }
  292. // PaintWindowBorder - changed region is the given region
  293. static void vncHooksPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion,
  294. int what)
  295. {
  296. SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindowBorder);
  297. RegionHelper changed(pScreen, pRegion);
  298. (*pScreen->PaintWindowBorder) (pWin, pRegion, what);
  299. vncHooksScreen->desktop->add_changed(changed.reg);
  300. SCREEN_REWRAP(PaintWindowBorder);
  301. }
  302. // CopyWindow - destination of the copy is the old region, clipped by
  303. // borderClip, translated by the delta. This call only does the copy - it
  304. // doesn't affect any other bits.
  305. static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
  306. RegionPtr pOldRegion)
  307. {
  308. SCREEN_UNWRAP(pWin->drawable.pScreen, CopyWindow);
  309. RegionHelper copied(pScreen, pOldRegion);
  310. int dx = pWin->drawable.x - ptOldOrg.x;
  311. int dy = pWin->drawable.y - ptOldOrg.y;
  312. REGION_TRANSLATE(pScreen, copied.reg, dx, dy);
  313. REGION_INTERSECT(pWin->drawable.pScreen, copied.reg, copied.reg,
  314. &pWin->borderClip);
  315. (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion);
  316. vncHooksScreen->desktop->add_copied(copied.reg, dx, dy);
  317. SCREEN_REWRAP(CopyWindow);
  318. }
  319. // ClearToBackground - changed region is the given rectangle, clipped by
  320. // clipList, but only if generateExposures is false.
  321. static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w,
  322. int h, Bool generateExposures)
  323. {
  324. SCREEN_UNWRAP(pWin->drawable.pScreen, ClearToBackground);
  325. BoxRec box;
  326. box.x1 = x + pWin->drawable.x;
  327. box.y1 = y + pWin->drawable.y;
  328. box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width);
  329. box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height);
  330. RegionHelper changed(pScreen, &box, 0);
  331. REGION_INTERSECT(pScreen, changed.reg, changed.reg, &pWin->clipList);
  332. (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures);
  333. if (!generateExposures) {
  334. vncHooksScreen->desktop->add_changed(changed.reg);
  335. }
  336. SCREEN_REWRAP(ClearToBackground);
  337. }
  338. // RestoreAreas - changed region is the given region
  339. static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr pRegion)
  340. {
  341. SCREEN_UNWRAP(pWin->drawable.pScreen, RestoreAreas);
  342. RegionHelper changed(pScreen, pRegion);
  343. RegionPtr result = (*pScreen->RestoreAreas) (pWin, pRegion);
  344. vncHooksScreen->desktop->add_changed(changed.reg);
  345. SCREEN_REWRAP(RestoreAreas);
  346. return result;
  347. }
  348. // InstallColormap - get the new colormap
  349. static void vncHooksInstallColormap(ColormapPtr pColormap)
  350. {
  351. SCREEN_UNWRAP(pColormap->pScreen, InstallColormap);
  352. (*pScreen->InstallColormap) (pColormap);
  353. vncHooksScreen->desktop->setColormap(pColormap);
  354. SCREEN_REWRAP(InstallColormap);
  355. }
  356. // StoreColors - get the colormap changes
  357. static void vncHooksStoreColors(ColormapPtr pColormap, int ndef,
  358. xColorItem* pdef)
  359. {
  360. SCREEN_UNWRAP(pColormap->pScreen, StoreColors);
  361. (*pScreen->StoreColors) (pColormap, ndef, pdef);
  362. vncHooksScreen->desktop->setColourMapEntries(pColormap, ndef, pdef);
  363. SCREEN_REWRAP(StoreColors);
  364. }
  365. // DisplayCursor - get the cursor shape
  366. static Bool vncHooksDisplayCursor(ScreenPtr pScreen_, CursorPtr cursor)
  367. {
  368. SCREEN_UNWRAP(pScreen_, DisplayCursor);
  369. Bool ret = (*pScreen->DisplayCursor) (pScreen, cursor);
  370. vncHooksScreen->desktop->setCursor(cursor);
  371. SCREEN_REWRAP(DisplayCursor);
  372. return ret;
  373. }
  374. // BlockHandler - ignore any changes during the block handler - it's likely
  375. // these are just drawing the cursor.
  376. static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout,
  377. pointer pReadmask)
  378. {
  379. SCREEN_UNWRAP(screenInfo.screens[i], BlockHandler);
  380. vncHooksScreen->desktop->ignoreHooks(true);
  381. (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
  382. vncHooksScreen->desktop->ignoreHooks(false);
  383. SCREEN_REWRAP(BlockHandler);
  384. }
  385. // Composite - needed for RENDER
  386. #ifdef RENDER
  387. void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask,
  388. PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask,
  389. INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
  390. {
  391. ScreenPtr pScreen = pDst->pDrawable->pScreen;
  392. vncHooksScreenPtr vncHooksScreen = ((vncHooksScreenPtr)pScreen->devPrivates[vncHooksScreenIndex].ptr);
  393. BoxRec box;
  394. PictureScreenPtr ps = GetPictureScreen(pScreen);
  395. rfb::Rect rect1, rect2;
  396. rect1.setXYWH(pDst->pDrawable->x + xDst,
  397. pDst->pDrawable->y + yDst,
  398. width,
  399. height);
  400. rect2 = rect1.intersect(vncHooksScreen->desktop->getRect());
  401. if (!rect2.is_empty()) {
  402. box.x1 = rect2.tl.x;
  403. box.y1 = rect2.tl.y;
  404. box.x2 = rect2.br.x;
  405. box.y2 = rect2.br.y;
  406. RegionHelper changed(pScreen, &box, 0);
  407. vncHooksScreen->desktop->add_changed(changed.reg);
  408. }
  409. ps->Composite = vncHooksScreen->Composite;
  410. (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc,
  411. xMask, yMask, xDst, yDst, width, height);
  412. ps->Composite = vncHooksComposite;
  413. }
  414. #endif /* RENDER */
  415. /////////////////////////////////////////////////////////////////////////////
  416. //
  417. // GC "funcs"
  418. //
  419. // GCFuncUnwrapper is a helper class which unwraps the GC funcs and ops in its
  420. // constructor and rewraps them in its destructor.
  421. class GCFuncUnwrapper {
  422. public:
  423. GCFuncUnwrapper(GCPtr pGC_) : pGC(pGC_) {
  424. vncHooksGC = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr;
  425. pGC->funcs = vncHooksGC->wrappedFuncs;
  426. if (vncHooksGC->wrappedOps)
  427. pGC->ops = vncHooksGC->wrappedOps;
  428. }
  429. ~GCFuncUnwrapper() {
  430. vncHooksGC->wrappedFuncs = pGC->funcs;
  431. pGC->funcs = &vncHooksGCFuncs;
  432. if (vncHooksGC->wrappedOps) {
  433. vncHooksGC->wrappedOps = pGC->ops;
  434. pGC->ops = &vncHooksGCOps;
  435. }
  436. }
  437. GCPtr pGC;
  438. vncHooksGCPtr vncHooksGC;
  439. };
  440. // ValidateGC - wrap the "ops" if a viewable window
  441. static void vncHooksValidateGC(GCPtr pGC, unsigned long changes,
  442. DrawablePtr pDrawable)
  443. {
  444. GCFuncUnwrapper u(pGC);
  445. DBGPRINT((stderr,"vncHooksValidateGC called\n"));
  446. (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
  447. u.vncHooksGC->wrappedOps = 0;
  448. if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr)pDrawable)->viewable) {
  449. WindowPtr pWin = (WindowPtr)pDrawable;
  450. RegionPtr pRegion = &pWin->clipList;
  451. if (pGC->subWindowMode == IncludeInferiors)
  452. pRegion = &pWin->borderClip;
  453. if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion)) {
  454. u.vncHooksGC->wrappedOps = pGC->ops;
  455. DBGPRINT((stderr,"vncHooksValidateGC: wrapped GC ops\n"));
  456. }
  457. }
  458. }
  459. // Other GC funcs - just unwrap and call on
  460. static void vncHooksChangeGC(GCPtr pGC, unsigned long mask) {
  461. GCFuncUnwrapper u(pGC);
  462. (*pGC->funcs->ChangeGC) (pGC, mask);
  463. }
  464. static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst) {
  465. GCFuncUnwrapper u(dst);
  466. (*dst->funcs->CopyGC) (src, mask, dst);
  467. }
  468. static void vncHooksDestroyGC(GCPtr pGC) {
  469. GCFuncUnwrapper u(pGC);
  470. (*pGC->funcs->DestroyGC) (pGC);
  471. }
  472. static void vncHooksChangeClip(GCPtr pGC, int type, pointer pValue, int nrects)
  473. {
  474. GCFuncUnwrapper u(pGC);
  475. (*pGC->funcs->ChangeClip) (pGC, type, pValue, nrects);
  476. }
  477. static void vncHooksDestroyClip(GCPtr pGC) {
  478. GCFuncUnwrapper u(pGC);
  479. (*pGC->funcs->DestroyClip) (pGC);
  480. }
  481. static void vncHooksCopyClip(GCPtr dst, GCPtr src) {
  482. GCFuncUnwrapper u(dst);
  483. (*dst->funcs->CopyClip) (dst, src);
  484. }
  485. /////////////////////////////////////////////////////////////////////////////
  486. //
  487. // GC "ops"
  488. //
  489. // GCOpUnwrapper is a helper class which unwraps the GC funcs and ops in its
  490. // constructor and rewraps them in its destructor.
  491. class GCOpUnwrapper {
  492. public:
  493. GCOpUnwrapper(DrawablePtr pDrawable, GCPtr pGC_)
  494. : pGC(pGC_), pScreen(pDrawable->pScreen)
  495. {
  496. vncHooksGC = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr;
  497. oldFuncs = pGC->funcs;
  498. pGC->funcs = vncHooksGC->wrappedFuncs;
  499. pGC->ops = vncHooksGC->wrappedOps;
  500. }
  501. ~GCOpUnwrapper() {
  502. vncHooksGC->wrappedOps = pGC->ops;
  503. pGC->funcs = oldFuncs;
  504. pGC->ops = &vncHooksGCOps;
  505. }
  506. GCPtr pGC;
  507. vncHooksGCPtr vncHooksGC;
  508. GCFuncs* oldFuncs;
  509. ScreenPtr pScreen;
  510. };
  511. #define GC_OP_UNWRAPPER(pDrawable, pGC, name) \
  512. GCOpUnwrapper u(pDrawable, pGC); \
  513. ScreenPtr pScreen = (pDrawable)->pScreen; \
  514. vncHooksScreenPtr vncHooksScreen \
  515. = ((vncHooksScreenPtr)pScreen->devPrivates[vncHooksScreenIndex].ptr); \
  516. DBGPRINT((stderr,"vncHooks" #name " called\n"));
  517. // FillSpans - changed region is the whole of borderClip. This is pessimistic,
  518. // but I believe this function is rarely used so it doesn't matter.
  519. static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit,
  520. DDXPointPtr pptInit, int *pwidthInit,
  521. int fSorted)
  522. {
  523. GC_OP_UNWRAPPER(pDrawable, pGC, FillSpans);
  524. RegionHelper changed(pScreen, &((WindowPtr)pDrawable)->borderClip);
  525. (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted);
  526. vncHooksScreen->desktop->add_changed(changed.reg);
  527. }
  528. // SetSpans - changed region is the whole of borderClip. This is pessimistic,
  529. // but I believe this function is rarely used so it doesn't matter.
  530. static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
  531. DDXPointPtr ppt, int *pwidth, int nspans,
  532. int fSorted)
  533. {
  534. GC_OP_UNWRAPPER(pDrawable, pGC, SetSpans);
  535. RegionHelper changed(pScreen, &((WindowPtr)pDrawable)->borderClip);
  536. (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
  537. vncHooksScreen->desktop->add_changed(changed.reg);
  538. }
  539. // PutImage - changed region is the given rectangle, clipped by pCompositeClip
  540. static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
  541. int x, int y, int w, int h, int leftPad,
  542. int format, char *pBits)
  543. {
  544. GC_OP_UNWRAPPER(pDrawable, pGC, PutImage);
  545. BoxRec box;
  546. box.x1 = x + pDrawable->x;
  547. box.y1 = y + pDrawable->y;
  548. box.x2 = box.x1 + w;
  549. box.y2 = box.y1 + h;
  550. RegionHelper changed(pScreen, &box, 0);
  551. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  552. (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format,
  553. pBits);
  554. vncHooksScreen->desktop->add_changed(changed.reg);
  555. }
  556. // CopyArea - destination of the copy is the dest rectangle, clipped by
  557. // pCompositeClip. Any parts of the destination which cannot be copied from
  558. // the source (could be all of it) go into the changed region.
  559. static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst,
  560. GCPtr pGC, int srcx, int srcy, int w, int h,
  561. int dstx, int dsty)
  562. {
  563. GC_OP_UNWRAPPER(pDst, pGC, CopyArea);
  564. BoxRec box;
  565. box.x1 = dstx + pDst->x;
  566. box.y1 = dsty + pDst->y;
  567. box.x2 = box.x1 + w;
  568. box.y2 = box.y1 + h;
  569. RegionHelper dst(pScreen, &box, 0);
  570. REGION_INTERSECT(pScreen, dst.reg, dst.reg, COMPOSITE_CLIP(pGC));
  571. RegionHelper src(pScreen);
  572. if ((pSrc->type == DRAWABLE_WINDOW) && (pSrc->pScreen == pScreen)) {
  573. box.x1 = srcx + pSrc->x;
  574. box.y1 = srcy + pSrc->y;
  575. box.x2 = box.x1 + w;
  576. box.y2 = box.y1 + h;
  577. src.init(&box, 0);
  578. REGION_INTERSECT(pScreen, src.reg, src.reg, &((WindowPtr)pSrc)->clipList);
  579. REGION_TRANSLATE(pScreen, src.reg,
  580. dstx + pDst->x - srcx - pSrc->x,
  581. dsty + pDst->y - srcy - pSrc->y);
  582. } else {
  583. src.init(NullBox, 0);
  584. }
  585. RegionHelper changed(pScreen, NullBox, 0);
  586. REGION_SUBTRACT(pScreen, changed.reg, dst.reg, src.reg);
  587. REGION_INTERSECT(pScreen, dst.reg, dst.reg, src.reg);
  588. RegionPtr rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h,
  589. dstx, dsty);
  590. if (REGION_NOTEMPTY(pScreen, dst.reg))
  591. vncHooksScreen->desktop->add_copied(dst.reg,
  592. dstx + pDst->x - srcx - pSrc->x,
  593. dsty + pDst->y - srcy - pSrc->y);
  594. if (REGION_NOTEMPTY(pScreen, changed.reg))
  595. vncHooksScreen->desktop->add_changed(changed.reg);
  596. return rgn;
  597. }
  598. // CopyPlane - changed region is the destination rectangle, clipped by
  599. // pCompositeClip
  600. static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst,
  601. GCPtr pGC, int srcx, int srcy, int w, int h,
  602. int dstx, int dsty, unsigned long plane)
  603. {
  604. GC_OP_UNWRAPPER(pDst, pGC, CopyPlane);
  605. BoxRec box;
  606. box.x1 = dstx + pDst->x;
  607. box.y1 = dsty + pDst->y;
  608. box.x2 = box.x1 + w;
  609. box.y2 = box.y1 + h;
  610. RegionHelper changed(pScreen, &box, 0);
  611. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  612. RegionPtr rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h,
  613. dstx, dsty, plane);
  614. vncHooksScreen->desktop->add_changed(changed.reg);
  615. return rgn;
  616. }
  617. // PolyPoint - changed region is the bounding rect, clipped by pCompositeClip
  618. static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode,
  619. int npt, xPoint *pts)
  620. {
  621. GC_OP_UNWRAPPER(pDrawable, pGC, PolyPoint);
  622. if (npt == 0) {
  623. (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
  624. return;
  625. }
  626. int minX = pts[0].x;
  627. int maxX = pts[0].x;
  628. int minY = pts[0].y;
  629. int maxY = pts[0].y;
  630. if (mode == CoordModePrevious) {
  631. int x = pts[0].x;
  632. int y = pts[0].y;
  633. for (int i = 1; i < npt; i++) {
  634. x += pts[i].x;
  635. y += pts[i].y;
  636. if (x < minX) minX = x;
  637. if (x > maxX) maxX = x;
  638. if (y < minY) minY = y;
  639. if (y > maxY) maxY = y;
  640. }
  641. } else {
  642. for (int i = 1; i < npt; i++) {
  643. if (pts[i].x < minX) minX = pts[i].x;
  644. if (pts[i].x > maxX) maxX = pts[i].x;
  645. if (pts[i].y < minY) minY = pts[i].y;
  646. if (pts[i].y > maxY) maxY = pts[i].y;
  647. }
  648. }
  649. BoxRec box;
  650. box.x1 = minX + pDrawable->x;
  651. box.y1 = minY + pDrawable->y;
  652. box.x2 = maxX + 1 + pDrawable->x;
  653. box.y2 = maxY + 1 + pDrawable->y;
  654. RegionHelper changed(pScreen, &box, 0);
  655. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  656. (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
  657. vncHooksScreen->desktop->add_changed(changed.reg);
  658. }
  659. // Polylines - changed region is the union of the bounding rects of each line,
  660. // clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP lines,
  661. // just use the bounding rect of all the lines.
  662. static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode,
  663. int npt, DDXPointPtr ppts)
  664. {
  665. GC_OP_UNWRAPPER(pDrawable, pGC, Polylines);
  666. if (npt == 0) {
  667. (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
  668. return;
  669. }
  670. int nRegRects = npt - 1;
  671. xRectangle regRects[MAX_RECTS_PER_OP];
  672. int lw = pGC->lineWidth;
  673. if (lw == 0) lw = 1;
  674. if (npt == 1)
  675. {
  676. // a single point
  677. nRegRects = 1;
  678. regRects[0].x = pDrawable->x + ppts[0].x - lw;
  679. regRects[0].y = pDrawable->y + ppts[0].y - lw;
  680. regRects[0].width = 2*lw;
  681. regRects[0].height = 2*lw;
  682. }
  683. else
  684. {
  685. /*
  686. * mitered joins can project quite a way from
  687. * the line end; the 11 degree miter limit limits
  688. * this extension to lw / (2 * tan(11/2)), rounded up
  689. * and converted to int yields 6 * lw
  690. */
  691. int extra = lw / 2;
  692. if (pGC->joinStyle == JoinMiter) {
  693. extra = 6 * lw;
  694. }
  695. int prevX, prevY, curX, curY;
  696. int rectX1, rectY1, rectX2, rectY2;
  697. int minX, minY, maxX, maxY;
  698. prevX = ppts[0].x + pDrawable->x;
  699. prevY = ppts[0].y + pDrawable->y;
  700. minX = maxX = prevX;
  701. minY = maxY = prevY;
  702. for (int i = 0; i < nRegRects; i++) {
  703. if (mode == CoordModeOrigin) {
  704. curX = pDrawable->x + ppts[i+1].x;
  705. curY = pDrawable->y + ppts[i+1].y;
  706. } else {
  707. curX = prevX + ppts[i+1].x;
  708. curY = prevY + ppts[i+1].y;
  709. }
  710. if (prevX > curX) {
  711. rectX1 = curX - extra;
  712. rectX2 = prevX + extra + 1;
  713. } else {
  714. rectX1 = prevX - extra;
  715. rectX2 = curX + extra + 1;
  716. }
  717. if (prevY > curY) {
  718. rectY1 = curY - extra;
  719. rectY2 = prevY + extra + 1;
  720. } else {
  721. rectY1 = prevY - extra;
  722. rectY2 = curY + extra + 1;
  723. }
  724. if (nRegRects <= MAX_RECTS_PER_OP) {
  725. regRects[i].x = rectX1;
  726. regRects[i].y = rectY1;
  727. regRects[i].width = rectX2 - rectX1;
  728. regRects[i].height = rectY2 - rectY1;
  729. } else {
  730. if (rectX1 < minX) minX = rectX1;
  731. if (rectY1 < minY) minY = rectY1;
  732. if (rectX2 > maxX) maxX = rectX2;
  733. if (rectY2 > maxY) maxY = rectY2;
  734. }
  735. prevX = curX;
  736. prevY = curY;
  737. }
  738. if (nRegRects > MAX_RECTS_PER_OP) {
  739. regRects[0].x = minX;
  740. regRects[0].y = minY;
  741. regRects[0].width = maxX - minX;
  742. regRects[0].height = maxY - minY;
  743. nRegRects = 1;
  744. }
  745. }
  746. RegionHelper changed(pScreen, nRegRects, regRects);
  747. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  748. (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
  749. vncHooksScreen->desktop->add_changed(changed.reg);
  750. }
  751. // PolySegment - changed region is the union of the bounding rects of each
  752. // segment, clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP
  753. // segments, just use the bounding rect of all the segments.
  754. static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
  755. xSegment *segs)
  756. {
  757. GC_OP_UNWRAPPER(pDrawable, pGC, PolySegment);
  758. if (nseg == 0) {
  759. (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
  760. return;
  761. }
  762. xRectangle regRects[MAX_RECTS_PER_OP];
  763. int nRegRects = nseg;
  764. int lw = pGC->lineWidth;
  765. int extra = lw / 2;
  766. int rectX1, rectY1, rectX2, rectY2;
  767. int minX, minY, maxX, maxY;
  768. minX = maxX = segs[0].x1;
  769. minY = maxY = segs[0].y1;
  770. for (int i = 0; i < nseg; i++) {
  771. if (segs[i].x1 > segs[i].x2) {
  772. rectX1 = pDrawable->x + segs[i].x2 - extra;
  773. rectX2 = pDrawable->x + segs[i].x1 + extra + 1;
  774. } else {
  775. rectX1 = pDrawable->x + segs[i].x1 - extra;
  776. rectX2 = pDrawable->x + segs[i].x2 + extra + 1;
  777. }
  778. if (segs[i].y1 > segs[i].y2) {
  779. rectY1 = pDrawable->y + segs[i].y2 - extra;
  780. rectY2 = pDrawable->y + segs[i].y1 + extra + 1;
  781. } else {
  782. rectY1 = pDrawable->y + segs[i].y1 - extra;
  783. rectY2 = pDrawable->y + segs[i].y2 + extra + 1;
  784. }
  785. if (nseg <= MAX_RECTS_PER_OP) {
  786. regRects[i].x = rectX1;
  787. regRects[i].y = rectY1;
  788. regRects[i].width = rectX2 - rectX1;
  789. regRects[i].height = rectY2 - rectY1;
  790. } else {
  791. if (rectX1 < minX) minX = rectX1;
  792. if (rectY1 < minY) minY = rectY1;
  793. if (rectX2 > maxX) maxX = rectX2;
  794. if (rectY2 > maxY) maxY = rectY2;
  795. }
  796. }
  797. if (nseg > MAX_RECTS_PER_OP) {
  798. regRects[0].x = minX;
  799. regRects[0].y = minY;
  800. regRects[0].width = maxX - minX;
  801. regRects[0].height = maxY - minY;
  802. nRegRects = 1;
  803. }
  804. RegionHelper changed(pScreen, nRegRects, regRects);
  805. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  806. (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
  807. vncHooksScreen->desktop->add_changed(changed.reg);
  808. }
  809. // PolyRectangle - changed region is the union of the bounding rects around
  810. // each side of the outline rectangles, clipped by pCompositeClip. If there
  811. // are more than MAX_RECTS_PER_OP rectangles, just use the bounding rect of all
  812. // the rectangles.
  813. static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects,
  814. xRectangle *rects)
  815. {
  816. GC_OP_UNWRAPPER(pDrawable, pGC, PolyRectangle);
  817. if (nrects == 0) {
  818. (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
  819. return;
  820. }
  821. xRectangle regRects[MAX_RECTS_PER_OP*4];
  822. int nRegRects = nrects * 4;
  823. int lw = pGC->lineWidth;
  824. int extra = lw / 2;
  825. int rectX1, rectY1, rectX2, rectY2;
  826. int minX, minY, maxX, maxY;
  827. minX = maxX = rects[0].x;
  828. minY = maxY = rects[0].y;
  829. for (int i = 0; i < nrects; i++) {
  830. if (nrects <= MAX_RECTS_PER_OP) {
  831. regRects[i*4].x = rects[i].x - extra + pDrawable->x;
  832. regRects[i*4].y = rects[i].y - extra + pDrawable->y;
  833. regRects[i*4].width = rects[i].width + 1 + 2 * extra;
  834. regRects[i*4].height = 1 + 2 * extra;
  835. regRects[i*4+1].x = rects[i].x - extra + pDrawable->x;
  836. regRects[i*4+1].y = rects[i].y - extra + pDrawable->y;
  837. regRects[i*4+1].width = 1 + 2 * extra;
  838. regRects[i*4+1].height = rects[i].height + 1 + 2 * extra;
  839. regRects[i*4+2].x = rects[i].x + rects[i].width - extra + pDrawable->x;
  840. regRects[i*4+2].y = rects[i].y - extra + pDrawable->y;
  841. regRects[i*4+2].width = 1 + 2 * extra;
  842. regRects[i*4+2].height = rects[i].height + 1 + 2 * extra;
  843. regRects[i*4+3].x = rects[i].x - extra + pDrawable->x;
  844. regRects[i*4+3].y = rects[i].y + rects[i].height - extra + pDrawable->y;
  845. regRects[i*4+3].width = rects[i].width + 1 + 2 * extra;
  846. regRects[i*4+3].height = 1 + 2 * extra;
  847. } else {
  848. rectX1 = pDrawable->x + rects[i].x - extra;
  849. rectY1 = pDrawable->y + rects[i].y - extra;
  850. rectX2 = pDrawable->x + rects[i].x + rects[i].width + extra+1;
  851. rectY2 = pDrawable->y + rects[i].y + rects[i].height + extra+1;
  852. if (rectX1 < minX) minX = rectX1;
  853. if (rectY1 < minY) minY = rectY1;
  854. if (rectX2 > maxX) maxX = rectX2;
  855. if (rectY2 > maxY) maxY = rectY2;
  856. }
  857. }
  858. if (nrects > MAX_RECTS_PER_OP) {
  859. regRects[0].x = minX;
  860. regRects[0].y = minY;
  861. regRects[0].width = maxX - minX;
  862. regRects[0].height = maxY - minY;
  863. nRegRects = 1;
  864. }
  865. RegionHelper changed(pScreen, nRegRects, regRects);
  866. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  867. (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
  868. vncHooksScreen->desktop->add_changed(changed.reg);
  869. }
  870. // PolyArc - changed region is the union of bounding rects around each arc,
  871. // clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP
  872. // arcs, just use the bounding rect of all the arcs.
  873. static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
  874. xArc *arcs)
  875. {
  876. GC_OP_UNWRAPPER(pDrawable, pGC, PolyArc);
  877. if (narcs == 0) {
  878. (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
  879. return;
  880. }
  881. xRectangle regRects[MAX_RECTS_PER_OP];
  882. int nRegRects = narcs;
  883. int lw = pGC->lineWidth;
  884. if (lw == 0) lw = 1;
  885. int extra = lw / 2;
  886. int rectX1, rectY1, rectX2, rectY2;
  887. int minX, minY, maxX, maxY;
  888. minX = maxX = arcs[0].x;
  889. minY = maxY = arcs[0].y;
  890. for (int i = 0; i < narcs; i++) {
  891. if (narcs <= MAX_RECTS_PER_OP) {
  892. regRects[i].x = arcs[i].x - extra + pDrawable->x;
  893. regRects[i].y = arcs[i].y - extra + pDrawable->y;
  894. regRects[i].width = arcs[i].width + lw;
  895. regRects[i].height = arcs[i].height + lw;
  896. } else {
  897. rectX1 = pDrawable->x + arcs[i].x - extra;
  898. rectY1 = pDrawable->y + arcs[i].y - extra;
  899. rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw;
  900. rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw;
  901. if (rectX1 < minX) minX = rectX1;
  902. if (rectY1 < minY) minY = rectY1;
  903. if (rectX2 > maxX) maxX = rectX2;
  904. if (rectY2 > maxY) maxY = rectY2;
  905. }
  906. }
  907. if (narcs > MAX_RECTS_PER_OP) {
  908. regRects[0].x = minX;
  909. regRects[0].y = minY;
  910. regRects[0].width = maxX - minX;
  911. regRects[0].height = maxY - minY;
  912. nRegRects = 1;
  913. }
  914. RegionHelper changed(pScreen, nRegRects, regRects);
  915. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  916. (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
  917. vncHooksScreen->desktop->add_changed(changed.reg);
  918. }
  919. // FillPolygon - changed region is the bounding rect around the polygon,
  920. // clipped by pCompositeClip
  921. static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape,
  922. int mode, int count, DDXPointPtr pts)
  923. {
  924. GC_OP_UNWRAPPER(pDrawable, pGC, FillPolygon);
  925. if (count == 0) {
  926. (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
  927. return;
  928. }
  929. int minX = pts[0].x;
  930. int maxX = pts[0].x;
  931. int minY = pts[0].y;
  932. int maxY = pts[0].y;
  933. if (mode == CoordModePrevious) {
  934. int x = pts[0].x;
  935. int y = pts[0].y;
  936. for (int i = 1; i < count; i++) {
  937. x += pts[i].x;
  938. y += pts[i].y;
  939. if (x < minX) minX = x;
  940. if (x > maxX) maxX = x;
  941. if (y < minY) minY = y;
  942. if (y > maxY) maxY = y;
  943. }
  944. } else {
  945. for (int i = 1; i < count; i++) {
  946. if (pts[i].x < minX) minX = pts[i].x;
  947. if (pts[i].x > maxX) maxX = pts[i].x;
  948. if (pts[i].y < minY) minY = pts[i].y;
  949. if (pts[i].y > maxY) maxY = pts[i].y;
  950. }
  951. }
  952. BoxRec box;
  953. box.x1 = minX + pDrawable->x;
  954. box.y1 = minY + pDrawable->y;
  955. box.x2 = maxX + 1 + pDrawable->x;
  956. box.y2 = maxY + 1 + pDrawable->y;
  957. RegionHelper changed(pScreen, &box, 0);
  958. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  959. (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
  960. vncHooksScreen->desktop->add_changed(changed.reg);
  961. }
  962. // PolyFillRect - changed region is the union of the rectangles, clipped by
  963. // pCompositeClip. If there are more than MAX_RECTS_PER_OP rectangles, just
  964. // use the bounding rect of all the rectangles.
  965. static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects,
  966. xRectangle *rects)
  967. {
  968. GC_OP_UNWRAPPER(pDrawable, pGC, PolyFillRect);
  969. if (nrects == 0) {
  970. (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
  971. return;
  972. }
  973. xRectangle regRects[MAX_RECTS_PER_OP];
  974. int nRegRects = nrects;
  975. int rectX1, rectY1, rectX2, rectY2;
  976. int minX, minY, maxX, maxY;
  977. minX = maxX = rects[0].x;
  978. minY = maxY = rects[0].y;
  979. for (int i = 0; i < nrects; i++) {
  980. if (nrects <= MAX_RECTS_PER_OP) {
  981. regRects[i].x = rects[i].x + pDrawable->x;
  982. regRects[i].y = rects[i].y + pDrawable->y;
  983. regRects[i].width = rects[i].width;
  984. regRects[i].height = rects[i].height;
  985. } else {
  986. rectX1 = pDrawable->x + rects[i].x;
  987. rectY1 = pDrawable->y + rects[i].y;
  988. rectX2 = pDrawable->x + rects[i].x + rects[i].width;
  989. rectY2 = pDrawable->y + rects[i].y + rects[i].height;
  990. if (rectX1 < minX) minX = rectX1;
  991. if (rectY1 < minY) minY = rectY1;
  992. if (rectX2 > maxX) maxX = rectX2;
  993. if (rectY2 > maxY) maxY = rectY2;
  994. }
  995. }
  996. if (nrects > MAX_RECTS_PER_OP) {
  997. regRects[0].x = minX;
  998. regRects[0].y = minY;
  999. regRects[0].width = maxX - minX;
  1000. regRects[0].height = maxY - minY;
  1001. nRegRects = 1;
  1002. }
  1003. RegionHelper changed(pScreen, nRegRects, regRects);
  1004. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  1005. (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
  1006. vncHooksScreen->desktop->add_changed(changed.reg);
  1007. }
  1008. // PolyFillArc - changed region is the union of bounding rects around each arc,
  1009. // clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP arcs,
  1010. // just use the bounding rect of all the arcs.
  1011. static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
  1012. xArc *arcs)
  1013. {
  1014. GC_OP_UNWRAPPER(pDrawable, pGC, PolyFillArc);
  1015. if (narcs == 0) {
  1016. (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
  1017. return;
  1018. }
  1019. xRectangle regRects[MAX_RECTS_PER_OP];
  1020. int nRegRects = narcs;
  1021. int lw = pGC->lineWidth;
  1022. if (lw == 0) lw = 1;
  1023. int extra = lw / 2;
  1024. int rectX1, rectY1, rectX2, rectY2;
  1025. int minX, minY, maxX, maxY;
  1026. minX = maxX = arcs[0].x;
  1027. minY = maxY = arcs[0].y;
  1028. for (int i = 0; i < narcs; i++) {
  1029. if (narcs <= MAX_RECTS_PER_OP) {
  1030. regRects[i].x = arcs[i].x - extra + pDrawable->x;
  1031. regRects[i].y = arcs[i].y - extra + pDrawable->y;
  1032. regRects[i].width = arcs[i].width + lw;
  1033. regRects[i].height = arcs[i].height + lw;
  1034. } else {
  1035. rectX1 = pDrawable->x + arcs[i].x - extra;
  1036. rectY1 = pDrawable->y + arcs[i].y - extra;
  1037. rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw;
  1038. rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw;
  1039. if (rectX1 < minX) minX = rectX1;
  1040. if (rectY1 < minY) minY = rectY1;
  1041. if (rectX2 > maxX) maxX = rectX2;
  1042. if (rectY2 > maxY) maxY = rectY2;
  1043. }
  1044. }
  1045. if (narcs > MAX_RECTS_PER_OP) {
  1046. regRects[0].x = minX;
  1047. regRects[0].y = minY;
  1048. regRects[0].width = maxX - minX;
  1049. regRects[0].height = maxY - minY;
  1050. nRegRects = 1;
  1051. }
  1052. RegionHelper changed(pScreen, nRegRects, regRects);
  1053. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  1054. (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
  1055. vncHooksScreen->desktop->add_changed(changed.reg);
  1056. }
  1057. // GetTextBoundingRect - calculate a bounding rectangle around n chars of a
  1058. // font. Not particularly accurate, but good enough.
  1059. static void GetTextBoundingRect(DrawablePtr pDrawable, FontPtr font, int x,
  1060. int y, int nchars, BoxPtr box)
  1061. {
  1062. int ascent = __rfbmax(FONTASCENT(font), FONTMAXBOUNDS(font, ascent));
  1063. int descent = __rfbmax(FONTDESCENT(font), FONTMAXBOUNDS(font, descent));
  1064. int charWidth = __rfbmax(FONTMAXBOUNDS(font,rightSideBearing),
  1065. FONTMAXBOUNDS(font,characterWidth));
  1066. box->x1 = pDrawable->x + x;
  1067. box->y1 = pDrawable->y + y - ascent;
  1068. box->x2 = box->x1 + charWidth * nchars;
  1069. box->y2 = box->y1 + ascent + descent;
  1070. if (FONTMINBOUNDS(font,leftSideBearing) < 0)
  1071. box->x1 += FONTMINBOUNDS(font,leftSideBearing);
  1072. }
  1073. // PolyText8 - changed region is bounding rect around count chars, clipped by
  1074. // pCompositeClip
  1075. static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
  1076. int count, char *chars)
  1077. {
  1078. GC_OP_UNWRAPPER(pDrawable, pGC, PolyText8);
  1079. if (count == 0)
  1080. return (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
  1081. BoxRec box;
  1082. GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
  1083. RegionHelper changed(pScreen, &box, 0);
  1084. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  1085. int ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
  1086. vncHooksScreen->desktop->add_changed(changed.reg);
  1087. return ret;
  1088. }
  1089. // PolyText16 - changed region is bounding rect around count chars, clipped by
  1090. // pCompositeClip
  1091. static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
  1092. int count, unsigned short *chars)
  1093. {
  1094. GC_OP_UNWRAPPER(pDrawable, pGC, PolyText16);
  1095. if (count == 0)
  1096. return (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
  1097. BoxRec box;
  1098. GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
  1099. RegionHelper changed(pScreen, &box, 0);
  1100. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  1101. int ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
  1102. vncHooksScreen->desktop->add_changed(changed.reg);
  1103. return ret;
  1104. }
  1105. // ImageText8 - changed region is bounding rect around count chars, clipped by
  1106. // pCompositeClip
  1107. static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
  1108. int count, char *chars)
  1109. {
  1110. GC_OP_UNWRAPPER(pDrawable, pGC, ImageText8);
  1111. if (count == 0) {
  1112. (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
  1113. return;
  1114. }
  1115. BoxRec box;
  1116. GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
  1117. RegionHelper changed(pScreen, &box, 0);
  1118. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  1119. (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
  1120. vncHooksScreen->desktop->add_changed(changed.reg);
  1121. }
  1122. // ImageText16 - changed region is bounding rect around count chars, clipped by
  1123. // pCompositeClip
  1124. static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
  1125. int count, unsigned short *chars)
  1126. {
  1127. GC_OP_UNWRAPPER(pDrawable, pGC, ImageText16);
  1128. if (count == 0) {
  1129. (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
  1130. return;
  1131. }
  1132. BoxRec box;
  1133. GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
  1134. RegionHelper changed(pScreen, &box, 0);
  1135. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  1136. (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
  1137. vncHooksScreen->desktop->add_changed(changed.reg);
  1138. }
  1139. // ImageGlyphBlt - changed region is bounding rect around nglyph chars, clipped
  1140. // by pCompositeClip
  1141. static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
  1142. int y, unsigned int nglyph,
  1143. CharInfoPtr *ppci, pointer pglyphBase)
  1144. {
  1145. GC_OP_UNWRAPPER(pDrawable, pGC, ImageGlyphBlt);
  1146. if (nglyph == 0) {
  1147. (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
  1148. return;
  1149. }
  1150. BoxRec box;
  1151. GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box);
  1152. RegionHelper changed(pScreen, &box, 0);
  1153. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  1154. (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
  1155. vncHooksScreen->desktop->add_changed(changed.reg);
  1156. }
  1157. // PolyGlyphBlt - changed region is bounding rect around nglyph chars, clipped
  1158. // by pCompositeClip
  1159. static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
  1160. int y, unsigned int nglyph,
  1161. CharInfoPtr *ppci, pointer pglyphBase)
  1162. {
  1163. GC_OP_UNWRAPPER(pDrawable, pGC, PolyGlyphBlt);
  1164. if (nglyph == 0) {
  1165. (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
  1166. return;
  1167. }
  1168. BoxRec box;
  1169. GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box);
  1170. RegionHelper changed(pScreen, &box, 0);
  1171. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  1172. (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
  1173. vncHooksScreen->desktop->add_changed(changed.reg);
  1174. }
  1175. // PushPixels - changed region is the given rectangle, clipped by
  1176. // pCompositeClip
  1177. static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap,
  1178. DrawablePtr pDrawable, int w, int h, int x,
  1179. int y)
  1180. {
  1181. GC_OP_UNWRAPPER(pDrawable, pGC, PushPixels);
  1182. BoxRec box;
  1183. box.x1 = x + pDrawable->x;
  1184. box.y1 = y + pDrawable->y;
  1185. box.x2 = box.x1 + w;
  1186. box.y2 = box.y1 + h;
  1187. RegionHelper changed(pScreen, &box, 0);
  1188. REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
  1189. (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y);
  1190. vncHooksScreen->desktop->add_changed(changed.reg);
  1191. }