1 /* DirectDrawClipper implementation 2 * 3 * Copyright 2000 (c) Marcus Meissner 4 * Copyright 2000 (c) TransGaming Technologies Inc. 5 * Copyright 2006 (c) Stefan Dösinger 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include "config.h" 23 #include "wine/port.h" 24 25 #include "ddraw_private.h" 26 27 WINE_DEFAULT_DEBUG_CHANNEL(ddraw); 28 29 static inline struct ddraw_clipper *impl_from_IDirectDrawClipper(IDirectDrawClipper *iface) 30 { 31 return CONTAINING_RECORD(iface, struct ddraw_clipper, IDirectDrawClipper_iface); 32 } 33 34 static HRESULT WINAPI ddraw_clipper_QueryInterface(IDirectDrawClipper *iface, REFIID iid, void **object) 35 { 36 struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface); 37 38 TRACE("iface %p, iid %s, object %p.\n", iface, debugstr_guid(iid), object); 39 40 if (IsEqualGUID(&IID_IDirectDrawClipper, iid) 41 || IsEqualGUID(&IID_IUnknown, iid)) 42 { 43 IDirectDrawClipper_AddRef(&clipper->IDirectDrawClipper_iface); 44 *object = &clipper->IDirectDrawClipper_iface; 45 return S_OK; 46 } 47 48 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); 49 *object = NULL; 50 51 return E_NOINTERFACE; 52 } 53 54 static ULONG WINAPI ddraw_clipper_AddRef(IDirectDrawClipper *iface) 55 { 56 struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface); 57 ULONG refcount = InterlockedIncrement(&clipper->ref); 58 59 TRACE("%p increasing refcount to %u.\n", clipper, refcount); 60 61 return refcount; 62 } 63 64 static ULONG WINAPI ddraw_clipper_Release(IDirectDrawClipper *iface) 65 { 66 struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface); 67 ULONG refcount = InterlockedDecrement(&clipper->ref); 68 69 TRACE("%p decreasing refcount to %u.\n", clipper, refcount); 70 71 if (!refcount) 72 { 73 if (clipper->region) 74 DeleteObject(clipper->region); 75 heap_free(clipper); 76 } 77 78 return refcount; 79 } 80 81 static HRESULT WINAPI ddraw_clipper_SetHWnd(IDirectDrawClipper *iface, DWORD flags, HWND window) 82 { 83 struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface); 84 85 TRACE("iface %p, flags %#x, window %p.\n", iface, flags, window); 86 87 if (flags) 88 { 89 FIXME("flags %#x, not supported.\n", flags); 90 return DDERR_INVALIDPARAMS; 91 } 92 93 wined3d_mutex_lock(); 94 clipper->window = window; 95 wined3d_mutex_unlock(); 96 97 return DD_OK; 98 } 99 100 static HRGN get_window_region(HWND window) 101 { 102 POINT origin; 103 HRGN rgn; 104 HDC dc; 105 106 if (!(dc = GetDC(window))) 107 { 108 WARN("Failed to get dc.\n"); 109 return NULL; 110 } 111 112 if (!(rgn = CreateRectRgn(0, 0, 0, 0))) 113 { 114 ERR("Failed to create region.\n"); 115 ReleaseDC(window, dc); 116 return NULL; 117 } 118 119 if (GetRandomRgn(dc, rgn, SYSRGN) != 1) 120 { 121 ERR("Failed to get window region.\n"); 122 DeleteObject(rgn); 123 ReleaseDC(window, dc); 124 return NULL; 125 } 126 127 if (GetVersion() & 0x80000000) 128 { 129 GetDCOrgEx(dc, &origin); 130 OffsetRgn(rgn, origin.x, origin.y); 131 } 132 133 ReleaseDC(window, dc); 134 return rgn; 135 } 136 137 /***************************************************************************** 138 * IDirectDrawClipper::GetClipList 139 * 140 * Retrieve a copy of the clip list 141 * 142 * Arguments: 143 * rect: Rectangle to be used to clip the clip list or NULL for the 144 * entire clip list. 145 * clip_list: structure for the resulting copy of the clip list. 146 * If NULL, fills Size up to the number of bytes necessary to hold 147 * the entire clip. 148 * clip_list_size: Size of resulting clip list; size of the buffer at clip_list 149 * or, if clip_list is NULL, receives the required size of the buffer 150 * in bytes. 151 * 152 * RETURNS 153 * Either DD_OK or DDERR_* 154 ************************************************************************/ 155 static HRESULT WINAPI ddraw_clipper_GetClipList(IDirectDrawClipper *iface, RECT *rect, 156 RGNDATA *clip_list, DWORD *clip_list_size) 157 { 158 struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface); 159 HRGN region; 160 161 TRACE("iface %p, rect %s, clip_list %p, clip_list_size %p.\n", 162 iface, wine_dbgstr_rect(rect), clip_list, clip_list_size); 163 164 wined3d_mutex_lock(); 165 166 if (clipper->window) 167 { 168 if (!(region = get_window_region(clipper->window))) 169 { 170 wined3d_mutex_unlock(); 171 WARN("Failed to get window region.\n"); 172 return E_FAIL; 173 } 174 } 175 else 176 { 177 if (!(region = clipper->region)) 178 { 179 wined3d_mutex_unlock(); 180 WARN("No clip list set.\n"); 181 return DDERR_NOCLIPLIST; 182 } 183 } 184 185 if (rect) 186 { 187 HRGN clip_region; 188 189 if (!(clip_region = CreateRectRgnIndirect(rect))) 190 { 191 wined3d_mutex_unlock(); 192 ERR("Failed to create region.\n"); 193 if (clipper->window) 194 DeleteObject(region); 195 return E_FAIL; 196 } 197 198 if (CombineRgn(clip_region, region, clip_region, RGN_AND) == ERROR) 199 { 200 wined3d_mutex_unlock(); 201 ERR("Failed to combine regions.\n"); 202 DeleteObject(clip_region); 203 if (clipper->window) 204 DeleteObject(region); 205 return E_FAIL; 206 } 207 208 if (clipper->window) 209 DeleteObject(region); 210 region = clip_region; 211 } 212 213 *clip_list_size = GetRegionData(region, *clip_list_size, clip_list); 214 if (rect || clipper->window) 215 DeleteObject(region); 216 217 wined3d_mutex_unlock(); 218 return DD_OK; 219 } 220 221 /***************************************************************************** 222 * IDirectDrawClipper::SetClipList 223 * 224 * Sets or deletes (if region is NULL) the clip list 225 * 226 * This implementation is a stub and returns DD_OK always to make the app 227 * happy. 228 * 229 * PARAMS 230 * region Pointer to a LRGNDATA structure or NULL 231 * flags not used, must be 0 232 * RETURNS 233 * Either DD_OK or DDERR_* 234 *****************************************************************************/ 235 static HRESULT WINAPI ddraw_clipper_SetClipList(IDirectDrawClipper *iface, RGNDATA *region, DWORD flags) 236 { 237 struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface); 238 239 TRACE("iface %p, region %p, flags %#x.\n", iface, region, flags); 240 241 wined3d_mutex_lock(); 242 243 if (clipper->window) 244 { 245 wined3d_mutex_unlock(); 246 return DDERR_CLIPPERISUSINGHWND; 247 } 248 249 if (clipper->region) 250 DeleteObject(clipper->region); 251 if (!region) 252 clipper->region = NULL; 253 else if (!(clipper->region = ExtCreateRegion(NULL, 0, region))) 254 { 255 wined3d_mutex_unlock(); 256 ERR("Failed to create region.\n"); 257 return E_FAIL; 258 } 259 260 wined3d_mutex_unlock(); 261 262 return DD_OK; 263 } 264 265 static HRESULT WINAPI ddraw_clipper_GetHWnd(IDirectDrawClipper *iface, HWND *window) 266 { 267 struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface); 268 269 TRACE("iface %p, window %p.\n", iface, window); 270 271 wined3d_mutex_lock(); 272 *window = clipper->window; 273 wined3d_mutex_unlock(); 274 275 return DD_OK; 276 } 277 278 static HRESULT WINAPI ddraw_clipper_Initialize(IDirectDrawClipper *iface, 279 IDirectDraw *ddraw, DWORD flags) 280 { 281 struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface); 282 283 TRACE("iface %p, ddraw %p, flags %#x.\n", iface, ddraw, flags); 284 285 wined3d_mutex_lock(); 286 if (clipper->initialized) 287 { 288 wined3d_mutex_unlock(); 289 return DDERR_ALREADYINITIALIZED; 290 } 291 292 clipper->initialized = TRUE; 293 wined3d_mutex_unlock(); 294 295 return DD_OK; 296 } 297 298 static HRESULT WINAPI ddraw_clipper_IsClipListChanged(IDirectDrawClipper *iface, BOOL *changed) 299 { 300 FIXME("iface %p, changed %p stub!\n", iface, changed); 301 302 /* XXX What is safest? */ 303 *changed = FALSE; 304 305 return DD_OK; 306 } 307 308 static const struct IDirectDrawClipperVtbl ddraw_clipper_vtbl = 309 { 310 ddraw_clipper_QueryInterface, 311 ddraw_clipper_AddRef, 312 ddraw_clipper_Release, 313 ddraw_clipper_GetClipList, 314 ddraw_clipper_GetHWnd, 315 ddraw_clipper_Initialize, 316 ddraw_clipper_IsClipListChanged, 317 ddraw_clipper_SetClipList, 318 ddraw_clipper_SetHWnd, 319 }; 320 321 HRESULT ddraw_clipper_init(struct ddraw_clipper *clipper) 322 { 323 clipper->IDirectDrawClipper_iface.lpVtbl = &ddraw_clipper_vtbl; 324 clipper->ref = 1; 325 326 return DD_OK; 327 } 328 329 struct ddraw_clipper *unsafe_impl_from_IDirectDrawClipper(IDirectDrawClipper *iface) 330 { 331 if (!iface) 332 return NULL; 333 assert(iface->lpVtbl == &ddraw_clipper_vtbl); 334 335 return impl_from_IDirectDrawClipper(iface); 336 } 337