blob: 1321bf32812b5eeba083c33ecd048ac80ca470fa [file] [log] [blame]
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +00001/* Copyright (C) 2002-2003 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
19#include <stdio.h>
20#include "XserverDesktop.h"
21#include "vncHooks.h"
22
23extern "C" {
24#define class c_class
25#define private c_private
26#include "scrnintstr.h"
27#include "windowstr.h"
28#include "gcstruct.h"
29#include "regionstr.h"
30#include "dixfontstr.h"
31#include "colormapst.h"
Peter Åstrandf1794c32005-03-10 13:28:04 +000032#ifdef RENDER
33#include "picturestr.h"
34#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000035
36#ifdef GC_HAS_COMPOSITE_CLIP
37#define COMPOSITE_CLIP(gc) ((gc)->pCompositeClip)
38#else
39#include "mfb.h"
40#define COMPOSITE_CLIP(gc) \
41 (((mfbPrivGCPtr)((gc)->devPrivates[mfbGCPrivateIndex].ptr))->pCompositeClip)
42#endif
43
44#undef class
45#undef private
46}
47
48#include "RegionHelper.h"
49
50#define DBGPRINT(x) //(fprintf x)
51
52// MAX_RECTS_PER_OP is the maximum number of rectangles we generate from
53// operations like Polylines and PolySegment. If the operation is more complex
54// than this, we simply use the bounding box. Ideally it would be a
55// command-line option, but that would involve an extra malloc each time, so we
56// fix it here.
57#define MAX_RECTS_PER_OP 5
58
59static unsigned long vncHooksGeneration = 0;
60
61// vncHooksScreenRec and vncHooksGCRec contain pointers to the original
62// functions which we "wrap" in order to hook the screen changes. The screen
63// functions are each wrapped individually, while the GC "funcs" and "ops" are
64// wrapped as a unit.
65
66typedef struct {
67 XserverDesktop* desktop;
68
69 CloseScreenProcPtr CloseScreen;
70 CreateGCProcPtr CreateGC;
71 PaintWindowBackgroundProcPtr PaintWindowBackground;
72 PaintWindowBorderProcPtr PaintWindowBorder;
73 CopyWindowProcPtr CopyWindow;
74 ClearToBackgroundProcPtr ClearToBackground;
75 RestoreAreasProcPtr RestoreAreas;
76 InstallColormapProcPtr InstallColormap;
77 StoreColorsProcPtr StoreColors;
78 DisplayCursorProcPtr DisplayCursor;
79 ScreenBlockHandlerProcPtr BlockHandler;
Peter Åstrandf1794c32005-03-10 13:28:04 +000080#ifdef RENDER
81 CompositeProcPtr Composite;
82#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000083} vncHooksScreenRec, *vncHooksScreenPtr;
84
85typedef struct {
86 GCFuncs *wrappedFuncs;
87 GCOps *wrappedOps;
88} vncHooksGCRec, *vncHooksGCPtr;
89
90static int vncHooksScreenIndex;
91static int vncHooksGCIndex;
92
93
94// screen functions
95
96static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen);
97static Bool vncHooksCreateGC(GCPtr pGC);
98static void vncHooksPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion,
99 int what);
100static void vncHooksPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion,
101 int what);
102static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
103 RegionPtr pOldRegion);
104static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w,
105 int h, Bool generateExposures);
106static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr prgnExposed);
107static void vncHooksInstallColormap(ColormapPtr pColormap);
108static void vncHooksStoreColors(ColormapPtr pColormap, int ndef,
109 xColorItem* pdef);
110static Bool vncHooksDisplayCursor(ScreenPtr pScreen, CursorPtr cursor);
111static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout,
112 pointer pReadmask);
Peter Åstrandf1794c32005-03-10 13:28:04 +0000113#ifdef RENDER
114static void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask,
115 PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask,
116 INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
117#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000118
119// GC "funcs"
120
121static void vncHooksValidateGC(GCPtr pGC, unsigned long changes,
122 DrawablePtr pDrawable);
123static void vncHooksChangeGC(GCPtr pGC, unsigned long mask);
124static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst);
125static void vncHooksDestroyGC(GCPtr pGC);
126static void vncHooksChangeClip(GCPtr pGC, int type, pointer pValue,int nrects);
127static void vncHooksDestroyClip(GCPtr pGC);
128static void vncHooksCopyClip(GCPtr dst, GCPtr src);
129
130static GCFuncs vncHooksGCFuncs = {
131 vncHooksValidateGC, vncHooksChangeGC, vncHooksCopyGC, vncHooksDestroyGC,
132 vncHooksChangeClip, vncHooksDestroyClip, vncHooksCopyClip,
133};
134
135// GC "ops"
136
137static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit,
138 DDXPointPtr pptInit, int *pwidthInit,
139 int fSorted);
140static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
141 DDXPointPtr ppt, int *pwidth, int nspans,
142 int fSorted);
143static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
144 int x, int y, int w, int h, int leftPad,
145 int format, char *pBits);
146static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst,
147 GCPtr pGC, int srcx, int srcy, int w, int h,
148 int dstx, int dsty);
149static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst,
150 GCPtr pGC, int srcx, int srcy, int w, int h,
151 int dstx, int dsty, unsigned long plane);
152static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode,
153 int npt, xPoint *pts);
154static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode,
155 int npt, DDXPointPtr ppts);
156static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
157 xSegment *segs);
158static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects,
159 xRectangle *rects);
160static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
161 xArc *arcs);
162static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape,
163 int mode, int count, DDXPointPtr pts);
164static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects,
165 xRectangle *rects);
166static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
167 xArc *arcs);
168static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
169 int count, char *chars);
170static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
171 int count, unsigned short *chars);
172static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
173 int count, char *chars);
174static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
175 int count, unsigned short *chars);
176static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
177 int y, unsigned int nglyph,
178 CharInfoPtr *ppci, pointer pglyphBase);
179static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
180 int y, unsigned int nglyph,
181 CharInfoPtr *ppci, pointer pglyphBase);
182static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap,
183 DrawablePtr pDrawable, int w, int h, int x,
184 int y);
185
186static GCOps vncHooksGCOps = {
187 vncHooksFillSpans, vncHooksSetSpans, vncHooksPutImage, vncHooksCopyArea,
188 vncHooksCopyPlane, vncHooksPolyPoint, vncHooksPolylines, vncHooksPolySegment,
189 vncHooksPolyRectangle, vncHooksPolyArc, vncHooksFillPolygon,
190 vncHooksPolyFillRect, vncHooksPolyFillArc, vncHooksPolyText8,
191 vncHooksPolyText16, vncHooksImageText8, vncHooksImageText16,
192 vncHooksImageGlyphBlt, vncHooksPolyGlyphBlt, vncHooksPushPixels
193};
194
195
196
197/////////////////////////////////////////////////////////////////////////////
198// vncHooksInit() is called at initialisation time and every time the server
199// resets. It is called once for each screen, but the indexes are only
200// allocated once for each server generation.
201
202Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop)
203{
204 vncHooksScreenPtr vncHooksScreen;
205
206 if (vncHooksGeneration != serverGeneration) {
207 vncHooksGeneration = serverGeneration;
208
209 vncHooksScreenIndex = AllocateScreenPrivateIndex();
210 if (vncHooksScreenIndex < 0) {
211 ErrorF("vncHooksInit: AllocateScreenPrivateIndex failed\n");
212 return FALSE;
213 }
214
215 vncHooksGCIndex = AllocateGCPrivateIndex();
216 if (vncHooksGCIndex < 0) {
217 ErrorF("vncHooksInit: AllocateGCPrivateIndex failed\n");
218 return FALSE;
219 }
220 }
221
222 if (!AllocateGCPrivate(pScreen, vncHooksGCIndex, sizeof(vncHooksGCRec))) {
223 ErrorF("vncHooksInit: AllocateGCPrivate failed\n");
224 return FALSE;
225 }
226
227 vncHooksScreen = (vncHooksScreenPtr)xnfalloc(sizeof(vncHooksScreenRec));
228 pScreen->devPrivates[vncHooksScreenIndex].ptr = (pointer)vncHooksScreen;
229
230 vncHooksScreen->desktop = desktop;
231
232 vncHooksScreen->CloseScreen = pScreen->CloseScreen;
233 vncHooksScreen->CreateGC = pScreen->CreateGC;
234 vncHooksScreen->PaintWindowBackground = pScreen->PaintWindowBackground;
235 vncHooksScreen->PaintWindowBorder = pScreen->PaintWindowBorder;
236 vncHooksScreen->CopyWindow = pScreen->CopyWindow;
237 vncHooksScreen->ClearToBackground = pScreen->ClearToBackground;
238 vncHooksScreen->RestoreAreas = pScreen->RestoreAreas;
239 vncHooksScreen->InstallColormap = pScreen->InstallColormap;
240 vncHooksScreen->StoreColors = pScreen->StoreColors;
241 vncHooksScreen->DisplayCursor = pScreen->DisplayCursor;
242 vncHooksScreen->BlockHandler = pScreen->BlockHandler;
Peter Åstrandf1794c32005-03-10 13:28:04 +0000243#ifdef RENDER
244 PictureScreenPtr ps;
245 ps = GetPictureScreenIfSet(pScreen);
246 if (ps) {
247 vncHooksScreen->Composite = ps->Composite;
248 }
249#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000250
251 pScreen->CloseScreen = vncHooksCloseScreen;
252 pScreen->CreateGC = vncHooksCreateGC;
253 pScreen->PaintWindowBackground = vncHooksPaintWindowBackground;
254 pScreen->PaintWindowBorder = vncHooksPaintWindowBorder;
255 pScreen->CopyWindow = vncHooksCopyWindow;
256 pScreen->ClearToBackground = vncHooksClearToBackground;
257 pScreen->RestoreAreas = vncHooksRestoreAreas;
258 pScreen->InstallColormap = vncHooksInstallColormap;
259 pScreen->StoreColors = vncHooksStoreColors;
260 pScreen->DisplayCursor = vncHooksDisplayCursor;
261 pScreen->BlockHandler = vncHooksBlockHandler;
Peter Åstrandf1794c32005-03-10 13:28:04 +0000262#ifdef RENDER
263 if (ps) {
264 ps->Composite = vncHooksComposite;
265 }
266#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000267
268 return TRUE;
269}
270
271
272
273/////////////////////////////////////////////////////////////////////////////
274//
275// screen functions
276//
277
278// SCREEN_UNWRAP and SCREEN_REWRAP unwrap and rewrap the given screen function.
279// It would be nice to do this with a C++ class, but each function is of a
280// distinct type, so it would have to use templates, and it's not worth that
281// much pain.
282
283#define SCREEN_UNWRAP(scrn,field) \
284 ScreenPtr pScreen = scrn; \
285 vncHooksScreenPtr vncHooksScreen \
286 = ((vncHooksScreenPtr)pScreen->devPrivates[vncHooksScreenIndex].ptr); \
287 pScreen->field = vncHooksScreen->field; \
288 DBGPRINT((stderr,"vncHooks" #field " called\n"));
289
290#define SCREEN_REWRAP(field) pScreen->field = vncHooks##field;
291
292
293// CloseScreen - unwrap the screen functions and call the original CloseScreen
294// function
295
296static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen_)
297{
298 SCREEN_UNWRAP(pScreen_, CloseScreen);
299
300 pScreen->CreateGC = vncHooksScreen->CreateGC;
301 pScreen->PaintWindowBackground = vncHooksScreen->PaintWindowBackground;
302 pScreen->PaintWindowBorder = vncHooksScreen->PaintWindowBorder;
303 pScreen->CopyWindow = vncHooksScreen->CopyWindow;
304 pScreen->ClearToBackground = vncHooksScreen->ClearToBackground;
305 pScreen->RestoreAreas = vncHooksScreen->RestoreAreas;
306 pScreen->InstallColormap = vncHooksScreen->InstallColormap;
307 pScreen->StoreColors = vncHooksScreen->StoreColors;
308 pScreen->DisplayCursor = vncHooksScreen->DisplayCursor;
309 pScreen->BlockHandler = vncHooksScreen->BlockHandler;
310
311 xfree((pointer)vncHooksScreen);
312
313 DBGPRINT((stderr,"vncHooksCloseScreen: unwrapped screen functions\n"));
314
315 return (*pScreen->CloseScreen)(i, pScreen);
316}
317
318// CreateGC - wrap the "GC funcs"
319
320static Bool vncHooksCreateGC(GCPtr pGC)
321{
322 SCREEN_UNWRAP(pGC->pScreen, CreateGC);
323
324 vncHooksGCPtr vncHooksGC
325 = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr;
326
327 Bool ret = (*pScreen->CreateGC) (pGC);
328
329 vncHooksGC->wrappedOps = 0;
330 vncHooksGC->wrappedFuncs = pGC->funcs;
331 pGC->funcs = &vncHooksGCFuncs;
332
333 SCREEN_REWRAP(CreateGC);
334
335 return ret;
336}
337
338// PaintWindowBackground - changed region is the given region
339
340static void vncHooksPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion,
341 int what)
342{
343 SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindowBackground);
344
345 RegionHelper changed(pScreen, pRegion);
346
347 (*pScreen->PaintWindowBackground) (pWin, pRegion, what);
348
349 vncHooksScreen->desktop->add_changed(changed.reg);
350
351 SCREEN_REWRAP(PaintWindowBackground);
352}
353
354// PaintWindowBorder - changed region is the given region
355
356static void vncHooksPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion,
357 int what)
358{
359 SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindowBorder);
360
361 RegionHelper changed(pScreen, pRegion);
362
363 (*pScreen->PaintWindowBorder) (pWin, pRegion, what);
364
365 vncHooksScreen->desktop->add_changed(changed.reg);
366
367 SCREEN_REWRAP(PaintWindowBorder);
368}
369
370// CopyWindow - destination of the copy is the old region, clipped by
371// borderClip, translated by the delta. This call only does the copy - it
372// doesn't affect any other bits.
373
374static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
375 RegionPtr pOldRegion)
376{
377 SCREEN_UNWRAP(pWin->drawable.pScreen, CopyWindow);
378
379 RegionHelper copied(pScreen, pOldRegion);
380 int dx = pWin->drawable.x - ptOldOrg.x;
381 int dy = pWin->drawable.y - ptOldOrg.y;
382 REGION_TRANSLATE(pScreen, copied.reg, dx, dy);
383 REGION_INTERSECT(pWin->drawable.pScreen, copied.reg, copied.reg,
384 &pWin->borderClip);
385
386 (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion);
387
388 vncHooksScreen->desktop->add_copied(copied.reg, dx, dy);
389
390 SCREEN_REWRAP(CopyWindow);
391}
392
393// ClearToBackground - changed region is the given rectangle, clipped by
394// clipList, but only if generateExposures is false.
395
396static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w,
397 int h, Bool generateExposures)
398{
399 SCREEN_UNWRAP(pWin->drawable.pScreen, ClearToBackground);
400
401 BoxRec box;
402 box.x1 = x + pWin->drawable.x;
403 box.y1 = y + pWin->drawable.y;
404 box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width);
405 box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height);
406
407 RegionHelper changed(pScreen, &box, 0);
408
409 REGION_INTERSECT(pScreen, changed.reg, changed.reg, &pWin->clipList);
410
411 (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures);
412
413 if (!generateExposures) {
414 vncHooksScreen->desktop->add_changed(changed.reg);
415 }
416
417 SCREEN_REWRAP(ClearToBackground);
418}
419
420// RestoreAreas - changed region is the given region
421
422static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr pRegion)
423{
424 SCREEN_UNWRAP(pWin->drawable.pScreen, RestoreAreas);
425
426 RegionHelper changed(pScreen, pRegion);
427
428 RegionPtr result = (*pScreen->RestoreAreas) (pWin, pRegion);
429
430 vncHooksScreen->desktop->add_changed(changed.reg);
431
432 SCREEN_REWRAP(RestoreAreas);
433
434 return result;
435}
436
437// InstallColormap - get the new colormap
438
439static void vncHooksInstallColormap(ColormapPtr pColormap)
440{
441 SCREEN_UNWRAP(pColormap->pScreen, InstallColormap);
442
443 (*pScreen->InstallColormap) (pColormap);
444
445 vncHooksScreen->desktop->setColormap(pColormap);
446
447 SCREEN_REWRAP(InstallColormap);
448}
449
450// StoreColors - get the colormap changes
451
452static void vncHooksStoreColors(ColormapPtr pColormap, int ndef,
453 xColorItem* pdef)
454{
455 SCREEN_UNWRAP(pColormap->pScreen, StoreColors);
456
457 (*pScreen->StoreColors) (pColormap, ndef, pdef);
458
459 vncHooksScreen->desktop->setColourMapEntries(pColormap, ndef, pdef);
460
461 SCREEN_REWRAP(StoreColors);
462}
463
464// DisplayCursor - get the cursor shape
465
466static Bool vncHooksDisplayCursor(ScreenPtr pScreen_, CursorPtr cursor)
467{
468 SCREEN_UNWRAP(pScreen_, DisplayCursor);
469
470 Bool ret = (*pScreen->DisplayCursor) (pScreen, cursor);
471
472 vncHooksScreen->desktop->setCursor(cursor);
473
474 SCREEN_REWRAP(DisplayCursor);
475
476 return ret;
477}
478
479// BlockHandler - ignore any changes during the block handler - it's likely
480// these are just drawing the cursor.
481
482static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout,
483 pointer pReadmask)
484{
485 SCREEN_UNWRAP(screenInfo.screens[i], BlockHandler);
486
487 vncHooksScreen->desktop->ignoreHooks(true);
488
489 (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
490
491 vncHooksScreen->desktop->ignoreHooks(false);
492
493 SCREEN_REWRAP(BlockHandler);
494}
495
Peter Åstrandf1794c32005-03-10 13:28:04 +0000496// Composite - needed for RENDER
497
498#ifdef RENDER
499void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask,
500 PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask,
501 INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
502{
503 ScreenPtr pScreen = pDst->pDrawable->pScreen;
504 vncHooksScreenPtr vncHooksScreen = ((vncHooksScreenPtr)pScreen->devPrivates[vncHooksScreenIndex].ptr);
505 BoxRec box;
506 PictureScreenPtr ps = GetPictureScreen(pScreen);
507
508 box.x1 = pDst->pDrawable->x + xDst;
509 box.y1 = pDst->pDrawable->y + yDst;
510 box.x2 = box.x1 + width;
511 box.y2 = box.y1 + height;
512
513 RegionHelper changed(pScreen, &box, 0);
514 vncHooksScreen->desktop->add_changed(changed.reg);
515
516 ps->Composite = vncHooksScreen->Composite;
517 (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc,
518 xMask, yMask, xDst, yDst, width, height);
519 ps->Composite = vncHooksComposite;
520}
521
522#endif /* RENDER */
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000523
524
525/////////////////////////////////////////////////////////////////////////////
526//
527// GC "funcs"
528//
529
530// GCFuncUnwrapper is a helper class which unwraps the GC funcs and ops in its
531// constructor and rewraps them in its destructor.
532
533class GCFuncUnwrapper {
534public:
535 GCFuncUnwrapper(GCPtr pGC_) : pGC(pGC_) {
536 vncHooksGC = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr;
537 pGC->funcs = vncHooksGC->wrappedFuncs;
538 if (vncHooksGC->wrappedOps)
539 pGC->ops = vncHooksGC->wrappedOps;
540 }
541 ~GCFuncUnwrapper() {
542 vncHooksGC->wrappedFuncs = pGC->funcs;
543 pGC->funcs = &vncHooksGCFuncs;
544 if (vncHooksGC->wrappedOps) {
545 vncHooksGC->wrappedOps = pGC->ops;
546 pGC->ops = &vncHooksGCOps;
547 }
548 }
549 GCPtr pGC;
550 vncHooksGCPtr vncHooksGC;
551};
552
553
554// ValidateGC - wrap the "ops" if a viewable window
555
556static void vncHooksValidateGC(GCPtr pGC, unsigned long changes,
557 DrawablePtr pDrawable)
558{
559 GCFuncUnwrapper u(pGC);
560
561 DBGPRINT((stderr,"vncHooksValidateGC called\n"));
562
563 (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
564
565 u.vncHooksGC->wrappedOps = 0;
566 if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr)pDrawable)->viewable) {
567 WindowPtr pWin = (WindowPtr)pDrawable;
568 RegionPtr pRegion = &pWin->clipList;
569
570 if (pGC->subWindowMode == IncludeInferiors)
571 pRegion = &pWin->borderClip;
572 if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion)) {
573 u.vncHooksGC->wrappedOps = pGC->ops;
574 DBGPRINT((stderr,"vncHooksValidateGC: wrapped GC ops\n"));
575 }
576 }
577}
578
579// Other GC funcs - just unwrap and call on
580
581static void vncHooksChangeGC(GCPtr pGC, unsigned long mask) {
582 GCFuncUnwrapper u(pGC);
583 (*pGC->funcs->ChangeGC) (pGC, mask);
584}
585static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst) {
586 GCFuncUnwrapper u(dst);
587 (*dst->funcs->CopyGC) (src, mask, dst);
588}
589static void vncHooksDestroyGC(GCPtr pGC) {
590 GCFuncUnwrapper u(pGC);
591 (*pGC->funcs->DestroyGC) (pGC);
592}
593static void vncHooksChangeClip(GCPtr pGC, int type, pointer pValue, int nrects)
594{
595 GCFuncUnwrapper u(pGC);
596 (*pGC->funcs->ChangeClip) (pGC, type, pValue, nrects);
597}
598static void vncHooksDestroyClip(GCPtr pGC) {
599 GCFuncUnwrapper u(pGC);
600 (*pGC->funcs->DestroyClip) (pGC);
601}
602static void vncHooksCopyClip(GCPtr dst, GCPtr src) {
603 GCFuncUnwrapper u(dst);
604 (*dst->funcs->CopyClip) (dst, src);
605}
606
607
608/////////////////////////////////////////////////////////////////////////////
609//
610// GC "ops"
611//
612
613// GCOpUnwrapper is a helper class which unwraps the GC funcs and ops in its
614// constructor and rewraps them in its destructor.
615
616class GCOpUnwrapper {
617public:
618 GCOpUnwrapper(DrawablePtr pDrawable, GCPtr pGC_)
619 : pGC(pGC_), pScreen(pDrawable->pScreen)
620 {
621 vncHooksGC = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr;
622 oldFuncs = pGC->funcs;
623 pGC->funcs = vncHooksGC->wrappedFuncs;
624 pGC->ops = vncHooksGC->wrappedOps;
625 }
626 ~GCOpUnwrapper() {
627 vncHooksGC->wrappedOps = pGC->ops;
628 pGC->funcs = oldFuncs;
629 pGC->ops = &vncHooksGCOps;
630 }
631 GCPtr pGC;
632 vncHooksGCPtr vncHooksGC;
633 GCFuncs* oldFuncs;
634 ScreenPtr pScreen;
635};
636
637#define GC_OP_UNWRAPPER(pDrawable, pGC, name) \
638 GCOpUnwrapper u(pDrawable, pGC); \
639 ScreenPtr pScreen = (pDrawable)->pScreen; \
640 vncHooksScreenPtr vncHooksScreen \
641 = ((vncHooksScreenPtr)pScreen->devPrivates[vncHooksScreenIndex].ptr); \
642 DBGPRINT((stderr,"vncHooks" #name " called\n"));
643
644
645// FillSpans - changed region is the whole of borderClip. This is pessimistic,
646// but I believe this function is rarely used so it doesn't matter.
647
648static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit,
649 DDXPointPtr pptInit, int *pwidthInit,
650 int fSorted)
651{
652 GC_OP_UNWRAPPER(pDrawable, pGC, FillSpans);
653
654 RegionHelper changed(pScreen, &((WindowPtr)pDrawable)->borderClip);
655
656 (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted);
657
658 vncHooksScreen->desktop->add_changed(changed.reg);
659}
660
661// SetSpans - changed region is the whole of borderClip. This is pessimistic,
662// but I believe this function is rarely used so it doesn't matter.
663
664static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
665 DDXPointPtr ppt, int *pwidth, int nspans,
666 int fSorted)
667{
668 GC_OP_UNWRAPPER(pDrawable, pGC, SetSpans);
669
670 RegionHelper changed(pScreen, &((WindowPtr)pDrawable)->borderClip);
671
672 (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
673
674 vncHooksScreen->desktop->add_changed(changed.reg);
675}
676
677// PutImage - changed region is the given rectangle, clipped by pCompositeClip
678
679static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
680 int x, int y, int w, int h, int leftPad,
681 int format, char *pBits)
682{
683 GC_OP_UNWRAPPER(pDrawable, pGC, PutImage);
684
685 BoxRec box;
686 box.x1 = x + pDrawable->x;
687 box.y1 = y + pDrawable->y;
688 box.x2 = box.x1 + w;
689 box.y2 = box.y1 + h;
690
691 RegionHelper changed(pScreen, &box, 0);
692
693 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
694
695 (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format,
696 pBits);
697
698 vncHooksScreen->desktop->add_changed(changed.reg);
699}
700
701// CopyArea - destination of the copy is the dest rectangle, clipped by
702// pCompositeClip. Any parts of the destination which cannot be copied from
703// the source (could be all of it) go into the changed region.
704
705static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst,
706 GCPtr pGC, int srcx, int srcy, int w, int h,
707 int dstx, int dsty)
708{
709 GC_OP_UNWRAPPER(pDst, pGC, CopyArea);
710
711 BoxRec box;
712 box.x1 = dstx + pDst->x;
713 box.y1 = dsty + pDst->y;
714 box.x2 = box.x1 + w;
715 box.y2 = box.y1 + h;
716
717 RegionHelper dst(pScreen, &box, 0);
718 REGION_INTERSECT(pScreen, dst.reg, dst.reg, COMPOSITE_CLIP(pGC));
719
720 RegionHelper src(pScreen);
721
722 if ((pSrc->type == DRAWABLE_WINDOW) && (pSrc->pScreen == pScreen)) {
723 box.x1 = srcx + pSrc->x;
724 box.y1 = srcy + pSrc->y;
725 box.x2 = box.x1 + w;
726 box.y2 = box.y1 + h;
727
728 src.init(&box, 0);
729 REGION_INTERSECT(pScreen, src.reg, src.reg, &((WindowPtr)pSrc)->clipList);
730 REGION_TRANSLATE(pScreen, src.reg,
731 dstx + pDst->x - srcx - pSrc->x,
732 dsty + pDst->y - srcy - pSrc->y);
733 } else {
734 src.init(NullBox, 0);
735 }
736
737 RegionHelper changed(pScreen, NullBox, 0);
738 REGION_SUBTRACT(pScreen, changed.reg, dst.reg, src.reg);
739 REGION_INTERSECT(pScreen, dst.reg, dst.reg, src.reg);
740
741 RegionPtr rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h,
742 dstx, dsty);
743
744 if (REGION_NOTEMPTY(pScreen, dst.reg))
745 vncHooksScreen->desktop->add_copied(dst.reg,
746 dstx + pDst->x - srcx - pSrc->x,
747 dsty + pDst->y - srcy - pSrc->y);
748
749 if (REGION_NOTEMPTY(pScreen, changed.reg))
750 vncHooksScreen->desktop->add_changed(changed.reg);
751
752 return rgn;
753}
754
755
756// CopyPlane - changed region is the destination rectangle, clipped by
757// pCompositeClip
758
759static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst,
760 GCPtr pGC, int srcx, int srcy, int w, int h,
761 int dstx, int dsty, unsigned long plane)
762{
763 GC_OP_UNWRAPPER(pDst, pGC, CopyPlane);
764
765 BoxRec box;
766 box.x1 = dstx + pDst->x;
767 box.y1 = dsty + pDst->y;
768 box.x2 = box.x1 + w;
769 box.y2 = box.y1 + h;
770
771 RegionHelper changed(pScreen, &box, 0);
772
773 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
774
775 RegionPtr rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h,
776 dstx, dsty, plane);
777 vncHooksScreen->desktop->add_changed(changed.reg);
778
779 return rgn;
780}
781
782// PolyPoint - changed region is the bounding rect, clipped by pCompositeClip
783
784static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode,
785 int npt, xPoint *pts)
786{
787 GC_OP_UNWRAPPER(pDrawable, pGC, PolyPoint);
788
789 if (npt == 0) {
790 (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
791 return;
792 }
793
794 int minX = pts[0].x;
795 int maxX = pts[0].x;
796 int minY = pts[0].y;
797 int maxY = pts[0].y;
798
799 if (mode == CoordModePrevious) {
800 int x = pts[0].x;
801 int y = pts[0].y;
802
803 for (int i = 1; i < npt; i++) {
804 x += pts[i].x;
805 y += pts[i].y;
806 if (x < minX) minX = x;
807 if (x > maxX) maxX = x;
808 if (y < minY) minY = y;
809 if (y > maxY) maxY = y;
810 }
811 } else {
812 for (int i = 1; i < npt; i++) {
813 if (pts[i].x < minX) minX = pts[i].x;
814 if (pts[i].x > maxX) maxX = pts[i].x;
815 if (pts[i].y < minY) minY = pts[i].y;
816 if (pts[i].y > maxY) maxY = pts[i].y;
817 }
818 }
819
820 BoxRec box;
821 box.x1 = minX + pDrawable->x;
822 box.y1 = minY + pDrawable->y;
823 box.x2 = maxX + 1 + pDrawable->x;
824 box.y2 = maxY + 1 + pDrawable->y;
825
826 RegionHelper changed(pScreen, &box, 0);
827
828 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
829
830 (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
831
832 vncHooksScreen->desktop->add_changed(changed.reg);
833}
834
835// Polylines - changed region is the union of the bounding rects of each line,
836// clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP lines,
837// just use the bounding rect of all the lines.
838
839static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode,
840 int npt, DDXPointPtr ppts)
841{
842 GC_OP_UNWRAPPER(pDrawable, pGC, Polylines);
843
844 if (npt == 0) {
845 (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
846 return;
847 }
848
849 int nRegRects = npt - 1;
850 xRectangle regRects[MAX_RECTS_PER_OP];
851
852 int lw = pGC->lineWidth;
853 if (lw == 0) lw = 1;
854
855 if (npt == 1)
856 {
857 // a single point
858 nRegRects = 1;
859 regRects[0].x = pDrawable->x + ppts[0].x - lw;
860 regRects[0].y = pDrawable->y + ppts[0].y - lw;
861 regRects[0].width = 2*lw;
862 regRects[0].height = 2*lw;
863 }
864 else
865 {
866 /*
867 * mitered joins can project quite a way from
868 * the line end; the 11 degree miter limit limits
869 * this extension to lw / (2 * tan(11/2)), rounded up
870 * and converted to int yields 6 * lw
871 */
872
873 int extra = lw / 2;
874 if (pGC->joinStyle == JoinMiter) {
875 extra = 6 * lw;
876 }
877
878 int prevX, prevY, curX, curY;
879 int rectX1, rectY1, rectX2, rectY2;
880 int minX, minY, maxX, maxY;
881
882 prevX = ppts[0].x + pDrawable->x;
883 prevY = ppts[0].y + pDrawable->y;
884 minX = maxX = prevX;
885 minY = maxY = prevY;
886
887 for (int i = 0; i < nRegRects; i++) {
888 if (mode == CoordModeOrigin) {
889 curX = pDrawable->x + ppts[i+1].x;
890 curY = pDrawable->y + ppts[i+1].y;
891 } else {
892 curX = prevX + ppts[i+1].x;
893 curY = prevY + ppts[i+1].y;
894 }
895
896 if (prevX > curX) {
897 rectX1 = curX - extra;
898 rectX2 = prevX + extra + 1;
899 } else {
900 rectX1 = prevX - extra;
901 rectX2 = curX + extra + 1;
902 }
903
904 if (prevY > curY) {
905 rectY1 = curY - extra;
906 rectY2 = prevY + extra + 1;
907 } else {
908 rectY1 = prevY - extra;
909 rectY2 = curY + extra + 1;
910 }
911
912 if (nRegRects <= MAX_RECTS_PER_OP) {
913 regRects[i].x = rectX1;
914 regRects[i].y = rectY1;
915 regRects[i].width = rectX2 - rectX1;
916 regRects[i].height = rectY2 - rectY1;
917 } else {
918 if (rectX1 < minX) minX = rectX1;
919 if (rectY1 < minY) minY = rectY1;
920 if (rectX2 > maxX) maxX = rectX2;
921 if (rectY2 > maxY) maxY = rectY2;
922 }
923
924 prevX = curX;
925 prevY = curY;
926 }
927
928 if (nRegRects > MAX_RECTS_PER_OP) {
929 regRects[0].x = minX;
930 regRects[0].y = minY;
931 regRects[0].width = maxX - minX;
932 regRects[0].height = maxY - minY;
933 nRegRects = 1;
934 }
935 }
936
937 RegionHelper changed(pScreen, nRegRects, regRects);
938
939 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
940
941 (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
942
943 vncHooksScreen->desktop->add_changed(changed.reg);
944}
945
946// PolySegment - changed region is the union of the bounding rects of each
947// segment, clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP
948// segments, just use the bounding rect of all the segments.
949
950static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
951 xSegment *segs)
952{
953 GC_OP_UNWRAPPER(pDrawable, pGC, PolySegment);
954
955 if (nseg == 0) {
956 (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
957 return;
958 }
959
960 xRectangle regRects[MAX_RECTS_PER_OP];
961 int nRegRects = nseg;
962
963 int lw = pGC->lineWidth;
964 int extra = lw / 2;
965
966 int rectX1, rectY1, rectX2, rectY2;
967 int minX, minY, maxX, maxY;
968
969 minX = maxX = segs[0].x1;
970 minY = maxY = segs[0].y1;
971
972 for (int i = 0; i < nseg; i++) {
973 if (segs[i].x1 > segs[i].x2) {
974 rectX1 = pDrawable->x + segs[i].x2 - extra;
975 rectX2 = pDrawable->x + segs[i].x1 + extra + 1;
976 } else {
977 rectX1 = pDrawable->x + segs[i].x1 - extra;
978 rectX2 = pDrawable->x + segs[i].x2 + extra + 1;
979 }
980
981 if (segs[i].y1 > segs[i].y2) {
982 rectY1 = pDrawable->y + segs[i].y2 - extra;
983 rectY2 = pDrawable->y + segs[i].y1 + extra + 1;
984 } else {
985 rectY1 = pDrawable->y + segs[i].y1 - extra;
986 rectY2 = pDrawable->y + segs[i].y2 + extra + 1;
987 }
988
989 if (nseg <= MAX_RECTS_PER_OP) {
990 regRects[i].x = rectX1;
991 regRects[i].y = rectY1;
992 regRects[i].width = rectX2 - rectX1;
993 regRects[i].height = rectY2 - rectY1;
994 } else {
995 if (rectX1 < minX) minX = rectX1;
996 if (rectY1 < minY) minY = rectY1;
997 if (rectX2 > maxX) maxX = rectX2;
998 if (rectY2 > maxY) maxY = rectY2;
999 }
1000 }
1001
1002 if (nseg > MAX_RECTS_PER_OP) {
1003 regRects[0].x = minX;
1004 regRects[0].y = minY;
1005 regRects[0].width = maxX - minX;
1006 regRects[0].height = maxY - minY;
1007 nRegRects = 1;
1008 }
1009
1010 RegionHelper changed(pScreen, nRegRects, regRects);
1011
1012 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1013
1014 (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
1015
1016 vncHooksScreen->desktop->add_changed(changed.reg);
1017}
1018
1019// PolyRectangle - changed region is the union of the bounding rects around
1020// each side of the outline rectangles, clipped by pCompositeClip. If there
1021// are more than MAX_RECTS_PER_OP rectangles, just use the bounding rect of all
1022// the rectangles.
1023
1024static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects,
1025 xRectangle *rects)
1026{
1027 GC_OP_UNWRAPPER(pDrawable, pGC, PolyRectangle);
1028
1029 if (nrects == 0) {
1030 (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
1031 return;
1032 }
1033
1034 xRectangle regRects[MAX_RECTS_PER_OP*4];
1035 int nRegRects = nrects * 4;
1036
1037 int lw = pGC->lineWidth;
1038 int extra = lw / 2;
1039
1040 int rectX1, rectY1, rectX2, rectY2;
1041 int minX, minY, maxX, maxY;
1042
1043 minX = maxX = rects[0].x;
1044 minY = maxY = rects[0].y;
1045
1046 for (int i = 0; i < nrects; i++) {
1047 if (nrects <= MAX_RECTS_PER_OP) {
1048 regRects[i*4].x = rects[i].x - extra + pDrawable->x;
1049 regRects[i*4].y = rects[i].y - extra + pDrawable->y;
1050 regRects[i*4].width = rects[i].width + 1 + 2 * extra;
1051 regRects[i*4].height = 1 + 2 * extra;
1052
1053 regRects[i*4+1].x = rects[i].x - extra + pDrawable->x;
1054 regRects[i*4+1].y = rects[i].y - extra + pDrawable->y;
1055 regRects[i*4+1].width = 1 + 2 * extra;
1056 regRects[i*4+1].height = rects[i].height + 1 + 2 * extra;
1057
1058 regRects[i*4+2].x = rects[i].x + rects[i].width - extra + pDrawable->x;
1059 regRects[i*4+2].y = rects[i].y - extra + pDrawable->y;
1060 regRects[i*4+2].width = 1 + 2 * extra;
1061 regRects[i*4+2].height = rects[i].height + 1 + 2 * extra;
1062
1063 regRects[i*4+3].x = rects[i].x - extra + pDrawable->x;
1064 regRects[i*4+3].y = rects[i].y + rects[i].height - extra + pDrawable->y;
1065 regRects[i*4+3].width = rects[i].width + 1 + 2 * extra;
1066 regRects[i*4+3].height = 1 + 2 * extra;
1067 } else {
1068 rectX1 = pDrawable->x + rects[i].x - extra;
1069 rectY1 = pDrawable->y + rects[i].y - extra;
1070 rectX2 = pDrawable->x + rects[i].x + rects[i].width + extra+1;
1071 rectY2 = pDrawable->y + rects[i].y + rects[i].height + extra+1;
1072 if (rectX1 < minX) minX = rectX1;
1073 if (rectY1 < minY) minY = rectY1;
1074 if (rectX2 > maxX) maxX = rectX2;
1075 if (rectY2 > maxY) maxY = rectY2;
1076 }
1077 }
1078
1079 if (nrects > MAX_RECTS_PER_OP) {
1080 regRects[0].x = minX;
1081 regRects[0].y = minY;
1082 regRects[0].width = maxX - minX;
1083 regRects[0].height = maxY - minY;
1084 nRegRects = 1;
1085 }
1086
1087 RegionHelper changed(pScreen, nRegRects, regRects);
1088
1089 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1090
1091 (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
1092
1093 vncHooksScreen->desktop->add_changed(changed.reg);
1094}
1095
1096// PolyArc - changed region is the union of bounding rects around each arc,
1097// clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP
1098// arcs, just use the bounding rect of all the arcs.
1099
1100static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
1101 xArc *arcs)
1102{
1103 GC_OP_UNWRAPPER(pDrawable, pGC, PolyArc);
1104
1105 if (narcs == 0) {
1106 (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
1107 return;
1108 }
1109
1110 xRectangle regRects[MAX_RECTS_PER_OP];
1111 int nRegRects = narcs;
1112
1113 int lw = pGC->lineWidth;
1114 if (lw == 0) lw = 1;
1115 int extra = lw / 2;
1116
1117 int rectX1, rectY1, rectX2, rectY2;
1118 int minX, minY, maxX, maxY;
1119
1120 minX = maxX = arcs[0].x;
1121 minY = maxY = arcs[0].y;
1122
1123 for (int i = 0; i < narcs; i++) {
1124 if (narcs <= MAX_RECTS_PER_OP) {
1125 regRects[i].x = arcs[i].x - extra + pDrawable->x;
1126 regRects[i].y = arcs[i].y - extra + pDrawable->y;
1127 regRects[i].width = arcs[i].width + lw;
1128 regRects[i].height = arcs[i].height + lw;
1129 } else {
1130 rectX1 = pDrawable->x + arcs[i].x - extra;
1131 rectY1 = pDrawable->y + arcs[i].y - extra;
1132 rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw;
1133 rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw;
1134 if (rectX1 < minX) minX = rectX1;
1135 if (rectY1 < minY) minY = rectY1;
1136 if (rectX2 > maxX) maxX = rectX2;
1137 if (rectY2 > maxY) maxY = rectY2;
1138 }
1139 }
1140
1141 if (narcs > MAX_RECTS_PER_OP) {
1142 regRects[0].x = minX;
1143 regRects[0].y = minY;
1144 regRects[0].width = maxX - minX;
1145 regRects[0].height = maxY - minY;
1146 nRegRects = 1;
1147 }
1148
1149 RegionHelper changed(pScreen, nRegRects, regRects);
1150
1151 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1152
1153 (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
1154
1155 vncHooksScreen->desktop->add_changed(changed.reg);
1156}
1157
1158
1159// FillPolygon - changed region is the bounding rect around the polygon,
1160// clipped by pCompositeClip
1161
1162static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape,
1163 int mode, int count, DDXPointPtr pts)
1164{
1165 GC_OP_UNWRAPPER(pDrawable, pGC, FillPolygon);
1166
1167 if (count == 0) {
1168 (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
1169 return;
1170 }
1171
1172 int minX = pts[0].x;
1173 int maxX = pts[0].x;
1174 int minY = pts[0].y;
1175 int maxY = pts[0].y;
1176
1177 if (mode == CoordModePrevious) {
1178 int x = pts[0].x;
1179 int y = pts[0].y;
1180
1181 for (int i = 1; i < count; i++) {
1182 x += pts[i].x;
1183 y += pts[i].y;
1184 if (x < minX) minX = x;
1185 if (x > maxX) maxX = x;
1186 if (y < minY) minY = y;
1187 if (y > maxY) maxY = y;
1188 }
1189 } else {
1190 for (int i = 1; i < count; i++) {
1191 if (pts[i].x < minX) minX = pts[i].x;
1192 if (pts[i].x > maxX) maxX = pts[i].x;
1193 if (pts[i].y < minY) minY = pts[i].y;
1194 if (pts[i].y > maxY) maxY = pts[i].y;
1195 }
1196 }
1197
1198 BoxRec box;
1199 box.x1 = minX + pDrawable->x;
1200 box.y1 = minY + pDrawable->y;
1201 box.x2 = maxX + 1 + pDrawable->x;
1202 box.y2 = maxY + 1 + pDrawable->y;
1203
1204 RegionHelper changed(pScreen, &box, 0);
1205
1206 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1207
1208 (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
1209
1210 vncHooksScreen->desktop->add_changed(changed.reg);
1211}
1212
1213// PolyFillRect - changed region is the union of the rectangles, clipped by
1214// pCompositeClip. If there are more than MAX_RECTS_PER_OP rectangles, just
1215// use the bounding rect of all the rectangles.
1216
1217static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects,
1218 xRectangle *rects)
1219{
1220 GC_OP_UNWRAPPER(pDrawable, pGC, PolyFillRect);
1221
1222 if (nrects == 0) {
1223 (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
1224 return;
1225 }
1226
1227 xRectangle regRects[MAX_RECTS_PER_OP];
1228 int nRegRects = nrects;
1229 int rectX1, rectY1, rectX2, rectY2;
1230 int minX, minY, maxX, maxY;
1231 minX = maxX = rects[0].x;
1232 minY = maxY = rects[0].y;
1233
1234 for (int i = 0; i < nrects; i++) {
1235 if (nrects <= MAX_RECTS_PER_OP) {
1236 regRects[i].x = rects[i].x + pDrawable->x;
1237 regRects[i].y = rects[i].y + pDrawable->y;
1238 regRects[i].width = rects[i].width;
1239 regRects[i].height = rects[i].height;
1240 } else {
1241 rectX1 = pDrawable->x + rects[i].x;
1242 rectY1 = pDrawable->y + rects[i].y;
1243 rectX2 = pDrawable->x + rects[i].x + rects[i].width;
1244 rectY2 = pDrawable->y + rects[i].y + rects[i].height;
1245 if (rectX1 < minX) minX = rectX1;
1246 if (rectY1 < minY) minY = rectY1;
1247 if (rectX2 > maxX) maxX = rectX2;
1248 if (rectY2 > maxY) maxY = rectY2;
1249 }
1250 }
1251
1252 if (nrects > MAX_RECTS_PER_OP) {
1253 regRects[0].x = minX;
1254 regRects[0].y = minY;
1255 regRects[0].width = maxX - minX;
1256 regRects[0].height = maxY - minY;
1257 nRegRects = 1;
1258 }
1259
1260 RegionHelper changed(pScreen, nRegRects, regRects);
1261
1262 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1263
1264 (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
1265
1266 vncHooksScreen->desktop->add_changed(changed.reg);
1267}
1268
1269// PolyFillArc - changed region is the union of bounding rects around each arc,
1270// clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP arcs,
1271// just use the bounding rect of all the arcs.
1272
1273static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
1274 xArc *arcs)
1275{
1276 GC_OP_UNWRAPPER(pDrawable, pGC, PolyFillArc);
1277
1278 if (narcs == 0) {
1279 (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
1280 return;
1281 }
1282
1283 xRectangle regRects[MAX_RECTS_PER_OP];
1284 int nRegRects = narcs;
1285
1286 int lw = pGC->lineWidth;
1287 if (lw == 0) lw = 1;
1288 int extra = lw / 2;
1289
1290 int rectX1, rectY1, rectX2, rectY2;
1291 int minX, minY, maxX, maxY;
1292
1293 minX = maxX = arcs[0].x;
1294 minY = maxY = arcs[0].y;
1295
1296 for (int i = 0; i < narcs; i++) {
1297 if (narcs <= MAX_RECTS_PER_OP) {
1298 regRects[i].x = arcs[i].x - extra + pDrawable->x;
1299 regRects[i].y = arcs[i].y - extra + pDrawable->y;
1300 regRects[i].width = arcs[i].width + lw;
1301 regRects[i].height = arcs[i].height + lw;
1302 } else {
1303 rectX1 = pDrawable->x + arcs[i].x - extra;
1304 rectY1 = pDrawable->y + arcs[i].y - extra;
1305 rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw;
1306 rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw;
1307 if (rectX1 < minX) minX = rectX1;
1308 if (rectY1 < minY) minY = rectY1;
1309 if (rectX2 > maxX) maxX = rectX2;
1310 if (rectY2 > maxY) maxY = rectY2;
1311 }
1312 }
1313
1314 if (narcs > MAX_RECTS_PER_OP) {
1315 regRects[0].x = minX;
1316 regRects[0].y = minY;
1317 regRects[0].width = maxX - minX;
1318 regRects[0].height = maxY - minY;
1319 nRegRects = 1;
1320 }
1321
1322 RegionHelper changed(pScreen, nRegRects, regRects);
1323
1324 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1325
1326 (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
1327
1328 vncHooksScreen->desktop->add_changed(changed.reg);
1329}
1330
1331// GetTextBoundingRect - calculate a bounding rectangle around n chars of a
1332// font. Not particularly accurate, but good enough.
1333
1334static void GetTextBoundingRect(DrawablePtr pDrawable, FontPtr font, int x,
1335 int y, int nchars, BoxPtr box)
1336{
1337 int ascent = max(FONTASCENT(font), FONTMAXBOUNDS(font, ascent));
1338 int descent = max(FONTDESCENT(font), FONTMAXBOUNDS(font, descent));
1339 int charWidth = max(FONTMAXBOUNDS(font,rightSideBearing),
1340 FONTMAXBOUNDS(font,characterWidth));
1341
1342 box->x1 = pDrawable->x + x;
1343 box->y1 = pDrawable->y + y - ascent;
1344 box->x2 = box->x1 + charWidth * nchars;
1345 box->y2 = box->y1 + ascent + descent;
1346
1347 if (FONTMINBOUNDS(font,leftSideBearing) < 0)
1348 box->x1 += FONTMINBOUNDS(font,leftSideBearing);
1349}
1350
1351// PolyText8 - changed region is bounding rect around count chars, clipped by
1352// pCompositeClip
1353
1354static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
1355 int count, char *chars)
1356{
1357 GC_OP_UNWRAPPER(pDrawable, pGC, PolyText8);
1358
1359 if (count == 0)
1360 return (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
1361
1362 BoxRec box;
1363 GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
1364
1365 RegionHelper changed(pScreen, &box, 0);
1366
1367 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1368
1369 int ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
1370
1371 vncHooksScreen->desktop->add_changed(changed.reg);
1372
1373 return ret;
1374}
1375
1376// PolyText16 - changed region is bounding rect around count chars, clipped by
1377// pCompositeClip
1378
1379static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
1380 int count, unsigned short *chars)
1381{
1382 GC_OP_UNWRAPPER(pDrawable, pGC, PolyText16);
1383
1384 if (count == 0)
1385 return (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
1386
1387 BoxRec box;
1388 GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
1389
1390 RegionHelper changed(pScreen, &box, 0);
1391
1392 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1393
1394 int ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
1395
1396 vncHooksScreen->desktop->add_changed(changed.reg);
1397
1398 return ret;
1399}
1400
1401// ImageText8 - changed region is bounding rect around count chars, clipped by
1402// pCompositeClip
1403
1404static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
1405 int count, char *chars)
1406{
1407 GC_OP_UNWRAPPER(pDrawable, pGC, ImageText8);
1408
1409 if (count == 0) {
1410 (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
1411 return;
1412 }
1413
1414 BoxRec box;
1415 GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
1416
1417 RegionHelper changed(pScreen, &box, 0);
1418
1419 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1420
1421 (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
1422
1423 vncHooksScreen->desktop->add_changed(changed.reg);
1424}
1425
1426// ImageText16 - changed region is bounding rect around count chars, clipped by
1427// pCompositeClip
1428
1429static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
1430 int count, unsigned short *chars)
1431{
1432 GC_OP_UNWRAPPER(pDrawable, pGC, ImageText16);
1433
1434 if (count == 0) {
1435 (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
1436 return;
1437 }
1438
1439 BoxRec box;
1440 GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
1441
1442 RegionHelper changed(pScreen, &box, 0);
1443
1444 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1445
1446 (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
1447
1448 vncHooksScreen->desktop->add_changed(changed.reg);
1449}
1450
1451// ImageGlyphBlt - changed region is bounding rect around nglyph chars, clipped
1452// by pCompositeClip
1453
1454static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
1455 int y, unsigned int nglyph,
1456 CharInfoPtr *ppci, pointer pglyphBase)
1457{
1458 GC_OP_UNWRAPPER(pDrawable, pGC, ImageGlyphBlt);
1459
1460 if (nglyph == 0) {
1461 (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
1462 return;
1463 }
1464
1465 BoxRec box;
1466 GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box);
1467
1468 RegionHelper changed(pScreen, &box, 0);
1469
1470 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1471
1472 (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
1473
1474 vncHooksScreen->desktop->add_changed(changed.reg);
1475}
1476
1477// PolyGlyphBlt - changed region is bounding rect around nglyph chars, clipped
1478// by pCompositeClip
1479
1480static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
1481 int y, unsigned int nglyph,
1482 CharInfoPtr *ppci, pointer pglyphBase)
1483{
1484 GC_OP_UNWRAPPER(pDrawable, pGC, PolyGlyphBlt);
1485
1486 if (nglyph == 0) {
1487 (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
1488 return;
1489 }
1490
1491 BoxRec box;
1492 GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box);
1493
1494 RegionHelper changed(pScreen, &box, 0);
1495
1496 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1497
1498 (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
1499
1500 vncHooksScreen->desktop->add_changed(changed.reg);
1501}
1502
1503// PushPixels - changed region is the given rectangle, clipped by
1504// pCompositeClip
1505
1506static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap,
1507 DrawablePtr pDrawable, int w, int h, int x,
1508 int y)
1509{
1510 GC_OP_UNWRAPPER(pDrawable, pGC, PushPixels);
1511
1512 BoxRec box;
1513 box.x1 = x + pDrawable->x;
1514 box.y1 = y + pDrawable->y;
1515 box.x2 = box.x1 + w;
1516 box.y2 = box.y1 + h;
1517
1518 RegionHelper changed(pScreen, &box, 0);
1519
1520 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1521
1522 (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y);
1523
1524 vncHooksScreen->desktop->add_changed(changed.reg);
1525}