- Use PeekMessage loop around GetMessage.
[wine] / graphics / x11drv / clipping.c
1 /*
2  * X11DRV clipping functions
3  *
4  * Copyright 1998 Huw Davies
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include "ts_xlib.h"
24
25 #include <stdio.h>
26
27 #include "gdi.h"
28 #include "x11drv.h"
29 #include "wine/debug.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
32
33 /***********************************************************************
34  *           X11DRV_GetRegionData
35  *
36  * Calls GetRegionData on the given region and converts the rectangle
37  * array to XRectangle format. The returned buffer must be freed by
38  * caller using HeapFree(GetProcessHeap(),...).
39  * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
40  */
41 RGNDATA *X11DRV_GetRegionData( HRGN hrgn, HDC hdc_lptodp )
42 {
43     RGNDATA *data;
44     DWORD size;
45     int i;
46     RECT *rect, tmp;
47     XRectangle *xrect;
48
49     if (!(size = GetRegionData( hrgn, 0, NULL ))) return NULL;
50     if (sizeof(XRectangle) > sizeof(RECT))
51     {
52         /* add extra size for XRectangle array */
53         int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
54         size += count * (sizeof(XRectangle) - sizeof(RECT));
55     }
56     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL;
57     if (!GetRegionData( hrgn, size, data ))
58     {
59         HeapFree( GetProcessHeap(), 0, data );
60         return NULL;
61     }
62
63     rect = (RECT *)data->Buffer;
64     xrect = (XRectangle *)data->Buffer;
65     if (hdc_lptodp)  /* map to device coordinates */
66     {
67         LPtoDP( hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2 );
68         for (i = 0; i < data->rdh.nCount; i++)
69         {
70             if (rect[i].right < rect[i].left)
71             {
72                 INT tmp = rect[i].right;
73                 rect[i].right = rect[i].left;
74                 rect[i].left = tmp;
75             }
76             if (rect[i].bottom < rect[i].top)
77             {
78                 INT tmp = rect[i].bottom;
79                 rect[i].bottom = rect[i].top;
80                 rect[i].top = tmp;
81             }
82         }
83     }
84
85     if (sizeof(XRectangle) > sizeof(RECT))
86     {
87         /* need to start from the end */
88         for (i = data->rdh.nCount-1; i >=0; i--)
89         {
90             tmp = rect[i];
91             xrect[i].x      = tmp.left;
92             xrect[i].y      = tmp.top;
93             xrect[i].width  = tmp.right - tmp.left;
94             xrect[i].height = tmp.bottom - tmp.top;
95         }
96     }
97     else
98     {
99         for (i = 0; i < data->rdh.nCount; i++)
100         {
101             tmp = rect[i];
102             xrect[i].x      = tmp.left;
103             xrect[i].y      = tmp.top;
104             xrect[i].width  = tmp.right - tmp.left;
105             xrect[i].height = tmp.bottom - tmp.top;
106         }
107     }
108     return data;
109 }
110
111
112 /***********************************************************************
113  *           X11DRV_SetDeviceClipping
114  */
115 void X11DRV_SetDeviceClipping( X11DRV_PDEVICE *physDev, HRGN hrgn )
116 {
117     RGNDATA *data;
118
119     if (!(data = X11DRV_GetRegionData( hrgn, 0 ))) return;
120     TSXSetClipRectangles( gdi_display, physDev->gc, physDev->org.x, physDev->org.y,
121                           (XRectangle *)data->Buffer, data->rdh.nCount, YXBanded );
122     HeapFree( GetProcessHeap(), 0, data );
123 }
124
125
126 /***********************************************************************
127  *           X11DRV_SetDrawable
128  *
129  * Set the drawable, clipping mode and origin for a DC.
130  */
131 void X11DRV_SetDrawable( HDC hdc, Drawable drawable, int mode, const POINT *org,
132                          const POINT *drawable_org )
133 {
134     DC *dc = DC_GetDCPtr( hdc );
135     if (dc)
136     {
137         X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
138
139         physDev->org = *org;
140         physDev->drawable = drawable;
141         physDev->drawable_org = *drawable_org;
142         TSXSetSubwindowMode( gdi_display, physDev->gc, mode );
143         if(physDev->xrender)
144           X11DRV_XRender_UpdateDrawable( physDev );
145         GDI_ReleaseObj( hdc );
146     }
147 }
148
149
150 /***********************************************************************
151  *           X11DRV_StartGraphicsExposures
152  *
153  * Set the DC in graphics exposures mode
154  */
155 void X11DRV_StartGraphicsExposures( HDC hdc )
156 {
157     DC *dc = DC_GetDCPtr( hdc );
158     if (dc)
159     {
160         X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
161         TSXSetGraphicsExposures( gdi_display, physDev->gc, True );
162         physDev->exposures = 0;
163         GDI_ReleaseObj( hdc );
164     }
165 }
166
167
168 /***********************************************************************
169  *           X11DRV_EndGraphicsExposures
170  *
171  * End the graphics exposures mode and process the events
172  */
173 void X11DRV_EndGraphicsExposures( HDC hdc, HRGN hrgn )
174 {
175     HRGN tmp = 0;
176     DC *dc = DC_GetDCPtr( hdc );
177
178     if (dc)
179     {
180         XEvent event;
181         X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
182
183         SetRectRgn( hrgn, 0, 0, 0, 0 );
184         wine_tsx11_lock();
185         XSetGraphicsExposures( gdi_display, physDev->gc, False );
186         if (physDev->exposures)
187         {
188             XSync( gdi_display, False );
189             for (;;)
190             {
191                 XWindowEvent( gdi_display, physDev->drawable, ~0, &event );
192                 if (event.type == NoExpose) break;
193                 if (event.type == GraphicsExpose)
194                 {
195                     int x = event.xgraphicsexpose.x - physDev->org.x;
196                     int y = event.xgraphicsexpose.y - physDev->org.y;
197
198                     TRACE( "got %d,%d %dx%d count %d\n",
199                            x, y, event.xgraphicsexpose.width, event.xgraphicsexpose.height,
200                            event.xgraphicsexpose.count );
201
202                     if (!tmp) tmp = CreateRectRgn( 0, 0, 0, 0 );
203                     SetRectRgn( tmp, x, y,
204                                 x + event.xgraphicsexpose.width,
205                                 y + event.xgraphicsexpose.height );
206                     CombineRgn( hrgn, hrgn, tmp, RGN_OR );
207                     if (!event.xgraphicsexpose.count) break;
208                 }
209                 else
210                 {
211                     ERR( "got unexpected event %d\n", event.type );
212                     break;
213                 }
214                 if (tmp) DeleteObject( tmp );
215             }
216         }
217         wine_tsx11_unlock();
218         GDI_ReleaseObj( hdc );
219     }
220 }