Leaked source code of windows server 2003
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.

1514 lines
47 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: wndobj.cxx
  3. *
  4. * WNDOBJ support routines.
  5. *
  6. * Created: 22-Sep-1993 17:42:20
  7. * Author: Wendy Wu [wendywu]
  8. * Hock San Lee [hockl]
  9. *
  10. * Copyright (c) 1993-1999 Microsoft Corporation
  11. \**************************************************************************/
  12. #include "precomp.hxx"
  13. #if DBG
  14. long glDebugLevel = 0;
  15. #define DBGINFO(str) if (glDebugLevel >= 2) DbgPrint("GLSRVL: " str)
  16. #define DBGENTRY(str) if (glDebugLevel >= 8) DbgPrint("GLSRVL: " str)
  17. #else
  18. #define DBGINFO(str)
  19. #define DBGENTRY(str)
  20. #endif
  21. // Global tracking object (TRACKOBJ) pointer.
  22. // If this is non-null, we are tracking some WNDOBJs in the system.
  23. PTRACKOBJ gpto = (PTRACKOBJ)NULL;
  24. // Global that indicates whether to notify driver with the new WNDOBJ
  25. // states following a WNDOBJ creation. User has not changed the window
  26. // states but this is required to initialize the driver. The update is
  27. // done in the parent gdi functions (e.g. SetPixelFormat) that allow
  28. // the DDI to create a WNDOBJ.
  29. BOOL gbWndobjUpdate;
  30. // The following is a global uniqueness that gets bumped up anytime USER
  31. // changes anyone's VisRgn:
  32. ULONG giVisRgnUniqueness = 0;
  33. // Maximum region rectangle
  34. RECTL grclMax = {
  35. MIN_REGION_COORD,
  36. MIN_REGION_COORD,
  37. MAX_REGION_COORD,
  38. MAX_REGION_COORD
  39. };
  40. // Here is a brief description of the semaphore usage.
  41. //
  42. // There are 3 semaphores that this module uses/references.
  43. //
  44. // 1. User critical section.
  45. // The user critical section ensures that no window moves when a new
  46. // update occurs. It is only relevent to the display DCs to ensure a
  47. // consistent window client regions state. For example, GreSetClientRgn
  48. // assumes that no window can move until GreClientRgnUpdated is called.
  49. //
  50. // 2. Display devlock and DC/surface locks.
  51. // The display devlock must be entered when a WNDOBJ is being used or
  52. // updated. This prevents a WNDOBJ from being modified when it is
  53. // being used in the DDI. The display devlock applies to the display
  54. // DCs only. For memory and printer DCs, the surface is locked when
  55. // a WNDOBJ is used. This is the current GDI design to prevent a
  56. // different thread from deleting a surface while it is being used.
  57. // Note that this precludes any multi-thread access to the printer or
  58. // memory DCs.
  59. //
  60. // 3. Window object semaphore.
  61. // The window object semaphore is used to protect access to the window
  62. // object data structures. Note that a semaphore is used instead of
  63. // a mutex here to allow for process cleanup of the semaphore. The
  64. // process cleanup is done in the user process cleanup code.
  65. //
  66. // The above 3 semaphores must be entered in the given order. Otherwise,
  67. // a deadlock may occur.
  68. /******************************Member*Function*****************************\
  69. * VOID TRACKOBJ::vUpdateDrvDelta
  70. *
  71. * Update driver function for delta regions. fl must have
  72. * WOC_RGN_CLIENT_DELTA or WOC_RGN_SURFACE_DELTA set.
  73. * Note that if the delta is empty, we do not need to call the driver.
  74. * The compiler does not allow this function to be inline because or forward
  75. * reference.
  76. *
  77. * History:
  78. * Thu Jan 13 09:55:23 1994 -by- Hock San Lee [hockl]
  79. * Wrote it.
  80. \**************************************************************************/
  81. VOID TRACKOBJ::vUpdateDrvDelta(EWNDOBJ *pwo, FLONG fl)
  82. {
  83. ASSERTGDI(fl & (WOC_RGN_CLIENT_DELTA|WOC_RGN_SURFACE_DELTA),
  84. "TRACKOBJ::vUpdateDrvDelta, Bad flags\n");
  85. if (!pwo->erclExclude().bEmpty())
  86. (*pfn)((WNDOBJ *)pwo, fl);
  87. }
  88. /******************************Public*Function*****************************\
  89. * EngCreateWnd
  90. *
  91. * Create a WNDOBJ from a HWND. This function should only be called
  92. * when the calling thread has the usercrit and devlock in that order.
  93. * GDI will ensure that the thread acquires both locks before calling the
  94. * DDIs that allow EngCreateWnd to be called. The driver should only call
  95. * this function from those DDI entry points. Currently, GreSetPixelFormat
  96. * acquires both locks before calling DrvSetPixelFormat; GreExtEscape for
  97. * WNDOBJ_SETUP escape also acquires both locks before calling DrvEscape.
  98. *
  99. * This function allows tracking multiple surfaces (screen, bitmaps and
  100. * printers). For each display surface being tracked, it further allows
  101. * multiple TRACKOBJs to be created for each driver function. The TRACKOBJs
  102. * on a device surface are identified by unique pfn function pointers.
  103. * This allows a live video driver and an OpenGL driver to track windows
  104. * independently of each other. The only restriction is that a window on
  105. * a surface cannot be tracked by more than one TRACKOBJs on that surface.
  106. *
  107. * A WNDOBJ has an associated pixel format. Once a WNDOBJ is created with
  108. * a given pixel format, it cannot be set to a different pixel format. If
  109. * there is no pixel format associated with a WNDOBJ, e.g. live video,
  110. * it should be set to zero.
  111. *
  112. * The WNDOBJ created in this function does not have the current states
  113. * until the first driver update function is called. However, the driver
  114. * may immediately associate its own data with the WNDOBJ by calling the
  115. * WNDOBJ_vSetConsumer function.
  116. *
  117. * Once a WNDOBJ is created, it cannot be deleted by the driver. Gdi will
  118. * will notifiy the driver of the deletion when the window goes away or
  119. * when the associated surface is deleted.
  120. *
  121. * The given hwnd identifies the user window to be tracked. It must be 0
  122. * if the surface is a printer or memory bitmap.
  123. *
  124. * Returns the new WNDOBJ pointer if a WNDOBJ is created; 0 if an error
  125. * occurs; -1 if hwnd is already being tracked by this driver function.
  126. *
  127. * History:
  128. * Thu Jan 13 09:55:23 1994 -by- Hock San Lee [hockl]
  129. * Rewrote it.
  130. * 27-Sep-1993 -by- Wendy Wu [wendywu]
  131. * Wrote it.
  132. \**************************************************************************/
  133. // This is a private clean up class for this function.
  134. class WO_CLEANUP
  135. {
  136. private:
  137. BOOL bKeep; // TRUE if resouces should not be freed
  138. PTRACKOBJ pto;
  139. PEWNDOBJ pwoSurf;
  140. PEWNDOBJ pwoClient;
  141. PREGION prgnSurf;
  142. PREGION prgnClient;
  143. HSEMAPHORE hsemClient;
  144. public:
  145. WO_CLEANUP()
  146. {
  147. bKeep = FALSE;
  148. pto = (PTRACKOBJ)NULL;
  149. pwoSurf = (PEWNDOBJ)NULL;
  150. pwoClient = (PEWNDOBJ)NULL;
  151. prgnSurf = (PREGION)NULL;
  152. prgnClient = (PREGION)NULL;
  153. hsemClient = NULL;
  154. }
  155. VOID vSetTrackobj(PTRACKOBJ pto1) { pto = pto1; }
  156. VOID vSetSurfWndobj(PEWNDOBJ pwo) { pwoSurf = pwo; }
  157. VOID vSetClientWndobj(PEWNDOBJ pwo) { pwoClient = pwo; }
  158. VOID vSetSurfRegion(RGNMEMOBJ &rmo) { prgnSurf = rmo.prgnGet();}
  159. VOID vSetClientRegion(RGNMEMOBJ &rmo) { prgnClient = rmo.prgnGet();}
  160. VOID vSetClientSem(HSEMAPHORE hsem) { hsemClient = hsem; }
  161. PTRACKOBJ ptoGet() { return(pto); }
  162. VOID vKeepAll() { bKeep = TRUE; }
  163. ~WO_CLEANUP()
  164. {
  165. if (bKeep) return;
  166. DBGINFO("EngCreateWnd: no WNDOBJ created\n");
  167. if (pto) { pto->ident = 0; VFREEMEM(pto); }
  168. if (pwoSurf) { pwoSurf->ident = 0; VFREEMEM(pwoSurf); }
  169. if (pwoClient) { pwoClient->ident = 0; VFREEMEM(pwoClient); }
  170. if (prgnSurf) prgnSurf->vDeleteREGION();
  171. if (prgnClient) prgnClient->vDeleteREGION();
  172. if (hsemClient) GreDeleteSemaphore(hsemClient);
  173. }
  174. };
  175. WNDOBJ * APIENTRY EngCreateWnd
  176. (
  177. SURFOBJ *pso,
  178. HWND hwnd,
  179. WNDOBJCHANGEPROC pfn,
  180. FLONG fl,
  181. int iPixelFormat
  182. )
  183. {
  184. WO_CLEANUP cleanup; // prepare for clean up
  185. PEWNDOBJ pwoClient;
  186. PEWNDOBJ pwoSurf;
  187. PEWNDOBJ pwo;
  188. PTRACKOBJ pto;
  189. PEWNDOBJ pwoGenericSibling = NULL;
  190. DBGENTRY("EngCreateWnd\n");
  191. PSURFACE pSurf = SURFOBJ_TO_SURFACE(pso);
  192. // Assert that we are in user critical section and also hold the devlock.
  193. // This ensures that no one is updating the hwnd.
  194. if (!UserIsUserCritSecIn())
  195. {
  196. RIP("Driver may call EngCreateWnd only from WNDOBJ_SETUP escape\n"
  197. "(or from OpenGL MCD or ICD escapes)");
  198. return(NULL);
  199. }
  200. CHECKUSERCRITIN;
  201. if (hwnd)
  202. {
  203. CHECKDEVLOCKIN2(pSurf);
  204. }
  205. // Validate flags.
  206. #if ((WO_VALID_FLAGS & WO_INTERNAL_VALID_FLAGS) != 0)
  207. #error "bad WO_INTERNAL_VALID_FLAGS"
  208. #endif
  209. if ((fl & ~WO_VALID_FLAGS) != 0)
  210. return((WNDOBJ *)0);
  211. // If this is the first time we need to track window object, create the
  212. // semaphore for synchronization. We use a semaphore instead of mutex
  213. // so that we can perform process cleanup of the semaphore.
  214. // Enter the semphore for window object.
  215. SEMOBJ so(ghsemWndobj);
  216. // If the window is already being tracked by the same TRACKOBJ and the
  217. // pixel format is the same, return -1. If the window is being tracked
  218. // by a different TRACKOBJ, return 0. There may be multiple TRACKOBJs
  219. // on the same device surface but a window can be tracked by only one
  220. // TRACKOBJ. In addition, pixel format in a window cannot be modified
  221. // once it is set.
  222. for (pto = gpto; pto; pto = pto->ptoNext)
  223. {
  224. for (pwo = pto->pwo; pwo; pwo = pwo->pwoNext)
  225. {
  226. if (pwo->hwnd == hwnd)
  227. {
  228. KdPrint(("Failing EngCreateWnd -- hwnd already has a WNDOBJ\n"));
  229. if (pto->pfn == pfn && pwo->ipfd == iPixelFormat)
  230. return((WNDOBJ *)-1); // return -1
  231. else
  232. return((WNDOBJ *)0); // tracked by a diff TRACKOBJ
  233. }
  234. }
  235. }
  236. // If this is the first time we track a device surface for this driver
  237. // function, we have to allocate space for the TRACKOBJ. We determine
  238. // if this is a new TRACKOBJ by comparing the pfn with those of the
  239. // existing ones. This allows the live video, installable opengl, and
  240. // generic opengl windows to be tracked separately.
  241. for (pto = gpto; pto; pto = pto->ptoNext)
  242. if (pto->pSurface == pSurf && pto->pfn == pfn)
  243. break;
  244. if (!pto)
  245. {
  246. // Allocate a new TRACKOBJ.
  247. if (!(pto = (PTRACKOBJ) PALLOCMEM(sizeof(TRACKOBJ), 'dnwG')))
  248. return((WNDOBJ *)0);
  249. cleanup.vSetTrackobj(pto);
  250. pto->ident = TRACKOBJ_IDENTIFIER;
  251. // pto->ptoNext
  252. pto->pwoSurf = (PEWNDOBJ)NULL;
  253. pto->pwo = (PEWNDOBJ)NULL;
  254. pto->pSurface = pSurf;
  255. pto->pfn = pfn;
  256. pto->fl = fl;
  257. pto->erclSurf.left = 0;
  258. pto->erclSurf.top = 0;
  259. pto->erclSurf.right = pSurf->sizl().cx;
  260. pto->erclSurf.bottom = pSurf->sizl().cy;
  261. // Create a surface WNDOBJ for the TRACKOBJ if it requests WO_RGN_SURFACE or
  262. // WO_RGN_SURFACE_DELTA.
  263. if (fl & (WO_RGN_SURFACE|WO_RGN_SURFACE_DELTA))
  264. {
  265. if (!(pwoSurf = (PEWNDOBJ) PALLOCMEM(sizeof(EWNDOBJ), 'dnwG')))
  266. return((WNDOBJ *)0);
  267. cleanup.vSetSurfWndobj(pwoSurf);
  268. // Create a surface client region that is the entire surface.
  269. RGNMEMOBJ rmoSurf((BOOL)FALSE);
  270. if (!rmoSurf.bValid())
  271. return((WNDOBJ *)0);
  272. cleanup.vSetSurfRegion(rmoSurf);
  273. rmoSurf.vSet((RECTL *)&pto->erclSurf);
  274. // Initialize the surface WNDOBJ.
  275. pwoSurf->pto = pto; // pto used by vSetClip
  276. rmoSurf.prgnGet()->vStamp(); // init iUniq
  277. pwoSurf->vSetClip(rmoSurf.prgnGet(), pto->erclSurf);
  278. pwoSurf->pvConsumer = 0;
  279. pwoSurf->psoOwner = pSurf->pSurfobj();
  280. pwoSurf->ident = EWNDOBJ_IDENTIFIER;
  281. pwoSurf->pwoNext = (PEWNDOBJ)NULL; // no next pointer
  282. pwoSurf->hwnd = 0; // no hwnd
  283. pwoSurf->fl = fl | WO_SURFACE;
  284. pwoSurf->ipfd = 0; // no pixel format
  285. // Add WNDOBJ to the TRACKOBJ.
  286. pto->pwoSurf = pwoSurf;
  287. }
  288. }
  289. // The tracking flags must be consistent.
  290. if ((pto->fl & ~WO_INTERNAL_VALID_FLAGS) != fl)
  291. return((WNDOBJ *)0);
  292. // Allocate a new client WNDOBJ.
  293. if (!(pwoClient = (PEWNDOBJ) PALLOCMEM(sizeof(EWNDOBJ), 'dnwG')))
  294. return((WNDOBJ *)0);
  295. cleanup.vSetClientWndobj(pwoClient);
  296. // Create an empty window client region. The client region is still being
  297. // created. The driver window region update will be done in the parent gdi
  298. // function.
  299. ERECTL erclClient(0,0,0,0);
  300. RGNMEMOBJ rmoClient((BOOL)FALSE);
  301. if (!rmoClient.bValid())
  302. return((WNDOBJ *)0);
  303. cleanup.vSetClientRegion(rmoClient);
  304. rmoClient.vSet((RECTL *)&erclClient);
  305. // Initialize the per-WNDOBJ semaphore once per window.
  306. {
  307. pwoClient->hsem = GreCreateSemaphore();
  308. if (pwoClient->hsem == NULL)
  309. {
  310. return NULL;
  311. }
  312. cleanup.vSetClientSem(pwoClient->hsem);
  313. fl |= WO_HSEM_OWNER;
  314. }
  315. // Initialize the WNDOBJ.
  316. pwoClient->pto = pto; // pto used by vSetClip
  317. rmoClient.prgnGet()->vStamp(); // init iUniq
  318. pwoClient->vSetClip(rmoClient.prgnGet(), erclClient);
  319. pwoClient->pvConsumer = 0; // to be set by the driver
  320. pwoClient->psoOwner = pSurf->pSurfobj();
  321. pwoClient->ident = EWNDOBJ_IDENTIFIER;
  322. pwoClient->hwnd = hwnd;
  323. pwoClient->fl = fl;
  324. pwoClient->ipfd = iPixelFormat;
  325. // Add WNDOBJ to TRACKOBJ.
  326. pwoClient->pwoNext = pto->pwo;
  327. pto->pwo = pwoClient;
  328. ASSERTGDI(offsetof(EWNDOBJ, pvConsumer) == offsetof(WNDOBJ, pvConsumer),
  329. "EngCreateWnd: rclClient wrong offset\n");
  330. // Add TRACKOBJ to global linked list.
  331. if (cleanup.ptoGet())
  332. {
  333. pto->ptoNext = gpto;
  334. gpto = pto;
  335. }
  336. // If hwnd is given, attach the WNDOBJ to the window in user.
  337. // Otherwise, it is a printer surface or memory bitmap. Attach it to
  338. // the surface.
  339. if (hwnd)
  340. {
  341. UserAssociateHwnd(hwnd, (PVOID) pwoClient);
  342. }
  343. else
  344. {
  345. // Only one WNDOBJ per memory bitmap or printer surface.
  346. ASSERTGDI(!pSurf->pwo(),
  347. "EngCreateWnd: multiple WNDOBJs unexpected in memory DCs\n");
  348. pSurf->pwo(pwoClient);
  349. }
  350. // Inform the parent gdi function that it needs to update the new WNDOBJ
  351. // in the driver.
  352. pto->fl |= WO_NEW_WNDOBJ;
  353. pwoClient->fl |= WO_NEW_WNDOBJ;
  354. gbWndobjUpdate = TRUE;
  355. // Don't free the PDEV until the WNDOBJ is destroyed.
  356. PDEVOBJ po(pSurf->hdev());
  357. po.vReferencePdev();
  358. // Everything is golden. Keep the created objects and return the new WNDOBJ.
  359. cleanup.vKeepAll();
  360. return((WNDOBJ *)pwoClient);
  361. }
  362. /******************************Public*Function*****************************\
  363. * GreDeleteWnd
  364. *
  365. * This function is called when the window that is being tracked is deleted
  366. * in user, or when the device surface (printer or memory bitmap) that
  367. * is begin tracked is deleted. It deletes the WNDOBJ and notifies the
  368. * driver that the WNDOBJ is going away.
  369. *
  370. * This function does not update the driver with the new client regions
  371. * following the WNDOBJ deletion. It assumes that if the deletion is a
  372. * window, user will update or has updated the client regions; and if the
  373. * deleteion is a printer or memory bitmap, the TRACKOBJ is going away
  374. * and therefore no need to notify driver.
  375. *
  376. * If the deletion is a window, the calling thread must have the usercrit.
  377. *
  378. * History:
  379. * Thu Jan 13 09:55:23 1994 -by- Hock San Lee [hockl]
  380. * Wrote it.
  381. \**************************************************************************/
  382. VOID APIENTRY GreDeleteWnd(PVOID _pwoDelete)
  383. {
  384. PEWNDOBJ pwoDelete = (PEWNDOBJ)_pwoDelete;
  385. PEWNDOBJ pwo;
  386. PTRACKOBJ pto;
  387. DBGENTRY("GreDeleteWnd\n");
  388. // Validate pwoDelete.
  389. if (!pwoDelete->bValid())
  390. {
  391. ASSERTGDI(FALSE, "GreDeleteWnd: Invalid pwoDelete\n");
  392. return;
  393. }
  394. // If hwnd is non 0, the user calling thread must hold the usercrit.
  395. // This ensures that no one is updating the hwnd.
  396. if (pwoDelete->hwnd)
  397. {
  398. CHECKUSERCRITIN;
  399. CHECKDEVLOCKIN2(pwoDelete->pto->pSurface);
  400. }
  401. pto = pwoDelete->pto;
  402. // Acquire the device lock. Note that this may be different from the
  403. // device lock that USER is holding if the PDEV is marked as 'deleted':
  404. PDEVOBJ po(pto->pSurface->hdev());
  405. {
  406. DEVLOCKOBJ dlo(po);
  407. // Enter the semaphore for window object.
  408. ASSERTGDI(ghsemWndobj, "GreDeleteWnd: bad ghsemWndobj\n");
  409. SEMOBJ so(ghsemWndobj);
  410. // Notify driver that the WNDOBJ is going away.
  411. // Hold the WNDOBJ stable while doing so by grabbing the per-WNDOBJ semaphore.
  412. {
  413. SEMOBJ soClient(pwoDelete->hsem);
  414. pto->vUpdateDrv(pwoDelete, WOC_DELETE);
  415. }
  416. // Unlink pwoDelete from chain.
  417. if (pto->pwo == pwoDelete)
  418. pto->pwo = pwoDelete->pwoNext;
  419. else
  420. for (pwo = pto->pwo; pwo; pwo = pwo->pwoNext)
  421. {
  422. if (pwo->pwoNext == pwoDelete)
  423. {
  424. pwo->pwoNext = pwoDelete->pwoNext;
  425. break;
  426. }
  427. }
  428. // Free pwoDelete.
  429. pwoDelete->bDelete(); // delete RGNOBJ
  430. pwoDelete->ident = 0;
  431. VFREEMEM(pwoDelete); // free memory
  432. // Delete the tracking object if there are no more windows to track.
  433. if (pto->pwo == (PEWNDOBJ)NULL)
  434. {
  435. // Unlink pto from chain.
  436. if (pto == gpto)
  437. gpto = pto->ptoNext;
  438. else
  439. for (PTRACKOBJ ptoTmp = gpto; ptoTmp; ptoTmp = ptoTmp->ptoNext)
  440. {
  441. if (ptoTmp->ptoNext == pto)
  442. {
  443. ptoTmp->ptoNext = pto->ptoNext;
  444. break;
  445. }
  446. }
  447. // Delete the pwoSurf if it exists.
  448. if (pto->pwoSurf)
  449. {
  450. ASSERTGDI(pto->fl & (WO_RGN_SURFACE|WO_RGN_SURFACE_DELTA),
  451. "GreDeleteWnd: WO_RGN_SURFACE or WO_RGN_SURFACE_DELTA not set\n");
  452. pto->pwoSurf->bDelete(); // delete RGNOBJ
  453. pto->pwoSurf->ident = 0;
  454. VFREEMEM(pto->pwoSurf); // free memory
  455. }
  456. pto->ident = 0;
  457. VFREEMEM(pto);
  458. }
  459. // Inform the sprite code that a WNDOBJ has been deleted.
  460. vSpWndobjChange(po.hdev(), NULL);
  461. }
  462. // Remove the reference to the PDEV.
  463. po.vUnreferencePdev();
  464. }
  465. /******************************Public*Function*****************************\
  466. * EngDeleteWnd
  467. *
  468. * Driver-callable entry point to delete a WNDOBJ.
  469. *
  470. \**************************************************************************/
  471. VOID EngDeleteWnd(WNDOBJ* _pwoDelete)
  472. {
  473. EWNDOBJ* pwoDelete = (EWNDOBJ*)_pwoDelete;
  474. if (!UserIsUserCritSecIn())
  475. {
  476. RIP("Driver may call EngDeleteWnd only from WNDOBJ_SETUP escape\n"
  477. "(or from OpenGL MCD or ICD escapes)");
  478. }
  479. else
  480. {
  481. // Tell USER to disassociate this WNDOBJ from its window:
  482. if (pwoDelete->hwnd)
  483. {
  484. UserAssociateHwnd(pwoDelete->hwnd, NULL);
  485. }
  486. GreDeleteWnd(pwoDelete);
  487. }
  488. }
  489. /******************************Public*Routine******************************\
  490. * VOID vChangeWndObjs
  491. *
  492. * Transfers ownership of WNDOBJs between PDEVs.
  493. *
  494. * History:
  495. * 8-Feb-1996 -by- J. Andrew Goossen [andrewgo]
  496. * Wrote it.
  497. \**************************************************************************/
  498. VOID vChangeWndObjs(
  499. SURFACE* pSurfaceOld,
  500. HDEV hdevOld,
  501. SURFACE* pSurfaceNew,
  502. HDEV hdevNew)
  503. {
  504. TRACKOBJ* pto;
  505. EWNDOBJ* pwo;
  506. EWNDOBJ* pwoNext;
  507. CHECKUSERCRITIN;
  508. SEMOBJ so(ghsemWndobj);
  509. // Note that we shouldn't use pSurfaceOld->hdev() or pSurfaceNew->hdev()
  510. // becuase they haven't been updated yet:
  511. PDEVOBJ poOld(hdevOld);
  512. PDEVOBJ poNew(hdevNew);
  513. // Changing drivers. Delete all WNDOBJs belonging to the old
  514. // surface:
  515. for (pto = gpto; pto != NULL; pto = pto->ptoNext)
  516. {
  517. if (pto->pSurface == pSurfaceOld)
  518. {
  519. // For every WNDOBJ belonging to this TRACKOBJ, transfer
  520. // ownership to the new PDEV:
  521. for (pwo = pto->pwo; pwo != NULL; pwo = pwo->pwoNext)
  522. {
  523. ASSERTGDI(pwo->psoOwner == pSurfaceOld->pSurfobj(),
  524. "Old psoOwner mismatch");
  525. poNew.vReferencePdev();
  526. poOld.vUnreferencePdev();
  527. }
  528. }
  529. else if (pto->pSurface == pSurfaceNew)
  530. {
  531. for (pwo = pto->pwo; pwo != NULL; pwo = pwo->pwoNext)
  532. {
  533. ASSERTGDI(pwo->psoOwner == pSurfaceNew->pSurfobj(),
  534. "New psoOwner mismatch");
  535. poOld.vReferencePdev();
  536. poNew.vUnreferencePdev();
  537. }
  538. }
  539. }
  540. }
  541. /******************************Public*Routine******************************\
  542. * VOID vTransferWndObjs
  543. *
  544. * Transfers ownership of WNDOBJs from PDEV to other PDEV.
  545. *
  546. * History:
  547. * 2-16-1999 -by- Hideyuki Nagase [hideyukn]
  548. * Wrote it.
  549. \**************************************************************************/
  550. VOID vTransferWndObjs(
  551. SURFACE* pSurface,
  552. HDEV hdevOld,
  553. HDEV hdevNew)
  554. {
  555. TRACKOBJ* pto;
  556. EWNDOBJ* pwo;
  557. EWNDOBJ* pwoNext;
  558. CHECKUSERCRITIN;
  559. SEMOBJ so(ghsemWndobj);
  560. PDEVOBJ poOld(hdevOld);
  561. PDEVOBJ poNew(hdevNew);
  562. for (pto = gpto; pto != NULL; pto = pto->ptoNext)
  563. {
  564. if (pto->pSurface == pSurface)
  565. {
  566. for (pwo = pto->pwo; pwo != NULL; pwo = pwo->pwoNext)
  567. {
  568. ASSERTGDI(pwo->psoOwner == pSurface->pSurfobj(),
  569. "New psoOwner mismatch");
  570. KdPrint(("Transfer wndobj %x - hdevNew %x hdevOld %x \n",
  571. pwo,hdevNew,hdevOld));
  572. poNew.vReferencePdev();
  573. poOld.vUnreferencePdev();
  574. }
  575. }
  576. }
  577. }
  578. /******************************Public*Function*****************************\
  579. * vForceClientRgnUpdate
  580. *
  581. * This function is called by gdi to force an update of the new WNDOBJ
  582. * that is just created.
  583. *
  584. * This function should only be called when the calling thread has the
  585. * usercrit and devlock in that order. Currently, it is called from
  586. * GreSetPixelFormat and GreExtEscape for WNDOBJ_SETUP escape after
  587. * they detected that the driver has created a new WNDOBJ.
  588. *
  589. * History:
  590. * Thu Jan 13 09:55:23 1994 -by- Hock San Lee [hockl]
  591. * Wrote it.
  592. \**************************************************************************/
  593. VOID vForceClientRgnUpdate()
  594. {
  595. PTRACKOBJ pto;
  596. PEWNDOBJ pwo = (PEWNDOBJ)NULL;
  597. DBGENTRY("vForceClientRgnUpdate\n");
  598. // Assert that we are in user critical section and also hold the devlock.
  599. // This ensures that no one is updating the hwnd.
  600. CHECKUSERCRITIN;
  601. // Update the new WNDOBJ that was just created.
  602. // User has not changed the client regions because we are still in the
  603. // user critical section. We are updating the client regions ourselves.
  604. {
  605. // Enter the semphore for window object.
  606. SEMOBJ so(ghsemWndobj);
  607. // Find the newly created WNDOBJ.
  608. for (pto = gpto; pto; pto = pto->ptoNext)
  609. {
  610. if (!(pto->fl & WO_NEW_WNDOBJ))
  611. continue;
  612. pto->fl &= ~WO_NEW_WNDOBJ;
  613. pto->fl |= WO_NOTIFIED;
  614. for (pwo = pto->pwo; pwo; pwo = pwo->pwoNext)
  615. {
  616. if (!(pwo->fl & WO_NEW_WNDOBJ))
  617. continue;
  618. pwo->fl &= ~WO_NEW_WNDOBJ;
  619. pwo->fl |= WO_NOTIFIED;
  620. break; // found it
  621. }
  622. break; // found it
  623. }
  624. if (!pwo)
  625. {
  626. ASSERTGDI(FALSE, "vForceClientRgnUpdate: no new WNDOBJ found\n");
  627. return;
  628. }
  629. // We need to ensure that the caller holds the devlock before calling this
  630. // function. Otherwise, some other threads may be drawing into the wrong
  631. // client region. We do the check here because we don't have any pSurf
  632. // information earlier.
  633. if (pwo->hwnd)
  634. {
  635. CHECKDEVLOCKIN2(pto->pSurface);
  636. }
  637. // If hwnd exists, get the client region from user.
  638. HRGN hrgnClient;
  639. ERECTL erclClient;
  640. if (pwo->hwnd)
  641. {
  642. hrgnClient = UserGetClientRgn(pwo->hwnd,
  643. (LPRECT)&erclClient,
  644. pwo->fl & WO_RGN_WINDOW);
  645. }
  646. else
  647. {
  648. // If hwnd does not exist, this is a memory bitmap or printer surface.
  649. // The client region is the whole surface.
  650. erclClient = pto->erclSurf;
  651. hrgnClient = GreCreateRectRgnIndirect((LPRECT)&erclClient);
  652. }
  653. if (!hrgnClient)
  654. {
  655. ASSERTGDI(FALSE, "vForceClientRgnUpdate: hwnd has no rgn\n");
  656. return;
  657. }
  658. // Update client region in the WNDOBJ.
  659. GreSetRegionOwner(hrgnClient, OBJECT_OWNER_PUBLIC);
  660. RGNOBJAPI roClient(hrgnClient,FALSE);
  661. ASSERTGDI(roClient.bValid(), "vForceClientRgnUpdate: invalid hrgnClient\n");
  662. #ifdef OPENGL_MM
  663. // Under Multi-mon we need to adjust the client region and
  664. // client rectangle by the offset of the surface.
  665. // Additionally we need to clip the client region to the
  666. // surface of the TRACKOBJ.
  667. if (!(pwo->fl & WO_RGN_DESKTOP_COORD))
  668. {
  669. PDEVOBJ pdo(pwo->pto->pSurface->hdev());
  670. if (pdo.bValid())
  671. {
  672. if (pdo.bPrimary(pwo->pto->pSurface))
  673. {
  674. POINTL ptlOrigin;
  675. ptlOrigin.x = -pdo.pptlOrigin()->x;
  676. ptlOrigin.y = -pdo.pptlOrigin()->y;
  677. if ((ptlOrigin.x != 0) || (ptlOrigin.y != 0))
  678. {
  679. // offset the region and window rect if necessary
  680. roClient.bOffset(&ptlOrigin);
  681. erclClient += ptlOrigin; /* this offsets by ptl */
  682. }
  683. }
  684. }
  685. RGNMEMOBJTMP rmoTmp;
  686. RGNMEMOBJTMP rmoRcl;
  687. if (rmoTmp.bValid() && rmoRcl.bValid())
  688. {
  689. // this clips the client region to the pto surface
  690. rmoRcl.vSet((RECTL *) &pto->erclSurf);
  691. rmoTmp.bCopy(roClient);
  692. roClient.iCombine(rmoTmp, rmoRcl, RGN_AND);
  693. if (rmoTmp.iCombine(roClient,rmoRcl,RGN_AND) != ERROR)
  694. {
  695. roClient.bSwap(&rmoTmp);
  696. }
  697. }
  698. }
  699. #endif // OPENGL_MM
  700. // We're going to modify the WNDOBJ now. Grab the per-WNDOBJ semaphore to
  701. // keep it stable. Don't release until after the driver is called.
  702. SEMOBJ soClient(pwo->hsem);
  703. roClient.bSwap(pwo);
  704. pwo->prgn->vStamp(); // init iUniq
  705. pwo->vSetClip(pwo->prgn, erclClient);
  706. roClient.bDeleteRGNOBJAPI(); // delete handle too
  707. // Call driver with the new WNDOBJ.
  708. if (pto->fl & WO_RGN_CLIENT_DELTA)
  709. pto->vUpdateDrvDelta(pwo, WOC_RGN_CLIENT_DELTA);
  710. if (pto->fl & WO_RGN_CLIENT)
  711. pto->vUpdateDrv(pwo, WOC_RGN_CLIENT);
  712. // Let the sprite code know that there's a new WNDOBJ, now completely
  713. // formed.
  714. vSpWndobjChange(pto->pSurface->hdev(), pwo);
  715. }
  716. // Update the remaining window client regions.
  717. GreClientRgnUpdated(GCR_WNDOBJEXISTS);
  718. }
  719. /******************************Member*Function*****************************\
  720. * GreWindowInsteadOfClient
  721. *
  722. * Returns TRUE if the window area instead of the client area should be
  723. * used for the WNDOBJ regions.
  724. *
  725. \**************************************************************************/
  726. BOOL GreWindowInsteadOfClient(PVOID _pwo)
  727. {
  728. PEWNDOBJ pwo = (PEWNDOBJ) _pwo;
  729. return(pwo->fl & WO_RGN_WINDOW);
  730. }
  731. /******************************Member*Function*****************************\
  732. * GreClientRgnUpdated
  733. *
  734. * User calls this function after having updated all the vis/client
  735. * region changes and before releasing the devlock. We have to complete
  736. * the remaining client region update operation.
  737. *
  738. * Gdi calls vForceClientRgnUpdate and this function after a new WNDOBJ
  739. * is created to update the driver.
  740. *
  741. * This function should only be called when the calling thread has the
  742. * usercrit and devlock in that order.
  743. *
  744. * If the GCR_DELAYFINALUPDATE flag is specified, the caller must
  745. * subsequently call GreClientRgnDone. If the driver specified
  746. * the WO_DRAW_NOTIFY flag, the GCR_DELAYFINALUPDATE will suppress
  747. * the WOC_DRAWN notification until GreClientRgnDone is called (or
  748. * the next time GreClientRgnUpdated is called without
  749. * GCR_DELAYFINALUPDATE).
  750. *
  751. * History:
  752. * Thu Jan 13 09:55:23 1994 -by- Hock San Lee [hockl]
  753. * Rewrote it.
  754. * 11-Nov-1993 -by- Wendy Wu [wendywu]
  755. * Wrote it.
  756. \**************************************************************************/
  757. VOID APIENTRY GreClientRgnUpdated(FLONG flUpdate)
  758. {
  759. PTRACKOBJ pto;
  760. PEWNDOBJ pwo;
  761. DBGENTRY("GreClientRgnUpdated\n");
  762. // Since we are holding the DEVLOCK to the active display, we can
  763. // increment the VisRgn count here without doing an atomic increment.
  764. giVisRgnUniqueness++;
  765. // Go any further only if some WNDOBJs exist.
  766. if (!(flUpdate & GCR_WNDOBJEXISTS))
  767. {
  768. return;
  769. }
  770. // Assert that we are in user critical section and also hold the devlock.
  771. // This ensures that no one is updating the hwnd.
  772. CHECKUSERCRITIN;
  773. // Enter the semphore for window object.
  774. SEMOBJ so(ghsemWndobj);
  775. // The surface client regions have changed. Complete the remaining
  776. // client region update.
  777. for (pto = gpto; pto; pto = pto->ptoNext)
  778. {
  779. if (!(pto->fl & WO_NOTIFIED))
  780. continue;
  781. pto->fl &= ~WO_NOTIFIED;
  782. // We need to ensure that user holds the devlock before calling this function.
  783. // Otherwise, some other threads may be drawing into the wrong client region.
  784. // We do the check here because we don't have any pSurface information earlier.
  785. //
  786. // Also, we exclude the entire screen since we are going to touch windows all
  787. // over the place and end with calling driver with WOC_COMPLETE which
  788. // can have an effect anywhere on the screen.
  789. DEVEXCLUDEOBJ dxo;
  790. if (pto->pwo->hwnd)
  791. {
  792. RECTL rclSurf;
  793. HDEV hdev = pto->pSurface->hdev();
  794. PDEVOBJ po(hdev);
  795. CHECKDEVLOCKIN2(pto->pSurface);
  796. ASSERTGDI(po.bValid(), "GreClientRgnUpdated: invalid pdevobj\n");
  797. if (po.bValid() && !po.bDisabled())
  798. {
  799. rclSurf.left = 0;
  800. rclSurf.top = 0;
  801. rclSurf.right = pto->pSurface->sizl().cx;
  802. rclSurf.bottom = pto->pSurface->sizl().cy;
  803. dxo.vExclude(hdev, &rclSurf, (ECLIPOBJ *) NULL);
  804. }
  805. }
  806. // Traverse the chain and call the driver with un-changed windows if
  807. // the WO_RGN_UPDATE_ALL and WO_RGN_CLIENT flags are set.
  808. if ((pto->fl & (WO_RGN_CLIENT|WO_RGN_UPDATE_ALL))
  809. == (WO_RGN_CLIENT|WO_RGN_UPDATE_ALL))
  810. {
  811. for (pwo = pto->pwo; pwo; pwo = pwo->pwoNext)
  812. if (pwo->fl & WO_NOTIFIED)
  813. pwo->fl &= ~WO_NOTIFIED;
  814. else
  815. {
  816. // Make WNDOBJ stable by holding the per-WNDOBJ semaphore
  817. // while we call the driver.
  818. SEMOBJ soClient(pwo->hsem);
  819. pto->vUpdateDrv(pwo, WOC_RGN_CLIENT);
  820. }
  821. }
  822. // Update the surface WNDOBJ if requested.
  823. if (pto->fl & (WO_RGN_SURFACE|WO_RGN_SURFACE_DELTA))
  824. {
  825. PEWNDOBJ pwoSurf = pto->pwoSurf;
  826. RGNMEMOBJTMP rmoTmp((BOOL)FALSE);
  827. RGNMEMOBJTMP rmoSurfNew((BOOL)FALSE);
  828. if (rmoTmp.bValid() && rmoSurfNew.bValid())
  829. {
  830. // Construct the new surface region which is the entire surface minus
  831. // the combined client regions.
  832. rmoSurfNew.vSet(&pwoSurf->rclClient);
  833. for (pwo = pto->pwo; pwo; pwo = pwo->pwoNext)
  834. {
  835. RGNOBJ ro(pwo->prgn);
  836. if (rmoTmp.iCombine(rmoSurfNew, ro, RGN_DIFF) != ERROR)
  837. rmoSurfNew.bSwap(&rmoTmp);
  838. }
  839. // If WO_RGN_SURFACE_DELTA is set, update the driver with the new surface delta.
  840. if (pto->fl & WO_RGN_SURFACE_DELTA)
  841. {
  842. RGNOBJ roSurf(pwoSurf->prgn);
  843. if (rmoTmp.iCombine(rmoSurfNew, roSurf, RGN_DIFF) != ERROR)
  844. {
  845. pwoSurf->bSwap(&rmoTmp);
  846. pwoSurf->prgn->vStamp(); // new iUniq
  847. pwoSurf->vSetClip(pwoSurf->prgn, *(ERECTL *)&pwoSurf->rclClient);
  848. pto->vUpdateDrvDelta(pwoSurf, WOC_RGN_SURFACE_DELTA);
  849. }
  850. }
  851. // Save the new surface region.
  852. // The surface region may be the same as previous one here. This code can be
  853. // optimized a little.
  854. pwoSurf->bSwap(&rmoSurfNew);
  855. pwoSurf->prgn->vStamp(); // new iUniq
  856. pwoSurf->vSetClip(pwoSurf->prgn, *(ERECTL *)&pwoSurf->rclClient);
  857. // Give the driver the new surface region.
  858. if (pto->fl & WO_RGN_SURFACE)
  859. pto->vUpdateDrv(pwoSurf, WOC_RGN_SURFACE);
  860. }
  861. } // if (pto->fl & (WO_RGN_SURFACE|WO_RGN_SURFACE_DELTA))
  862. // Send down the WOC_CHANGED to signify notification complete.
  863. pto->vUpdateDrv((PEWNDOBJ)NULL, WOC_CHANGED);
  864. // Need WOC_DRAWN notification if requested. Notification is delayed
  865. // if GCR_DELAYFINALUPDATE is set. Delayed notification is signaled
  866. // by setting the WO_NEED_DRAW_NOTIFY flag in the trackobj and is
  867. // handled in GreClientRgnDone.
  868. if (pto->fl & WO_DRAW_NOTIFY)
  869. {
  870. if (flUpdate & GCR_DELAYFINALUPDATE)
  871. {
  872. pto->fl |= WO_NEED_DRAW_NOTIFY;
  873. }
  874. else
  875. {
  876. pto->vUpdateDrv((PEWNDOBJ)NULL, WOC_DRAWN);
  877. pto->fl &= ~WO_NEED_DRAW_NOTIFY;
  878. }
  879. }
  880. } // for (pto = gpto; pto; pto = pto->ptoNext)
  881. }
  882. /******************************Public*Routine******************************\
  883. * GreClientRgnDone
  884. *
  885. * If USER calls GreClientRgnUpdated with the GCR_DELAYFINALUPDATE flag
  886. * set, it must subsequently call this function to complete the update.
  887. *
  888. * If the driver calls EngCreateWnd with the WO_NEED_DRAW_NOTIFY flag,
  889. * the GreClientRgnUpdated function will complete the notification with
  890. * a WOC_CHANGED followed by a WOC_DRAWN. However, if the
  891. * GCR_DELAYFINALUPDATE flag is specified when calling GreClientRgnUpdated,
  892. * the WOC_DRAWN message is suppressed until GreClientRgnDone is called.
  893. *
  894. * If the driver does not call EngCreateWnd with the WO_NEED_DRAW_NOTIFY
  895. * flag, GreClientRgnDone will only send the WOC_CHANGED notification and
  896. * this function will have no effect.
  897. *
  898. * This function should only be called when the calling thread has the
  899. * usercrit and devlock in that order.
  900. *
  901. * Note: Currently this function does not do anything if GCR_WNDOBJEXISTS
  902. * is not set (GreClientRgnUpdated will update the vis rgn uniqneness and
  903. * so must be called even if there are not WNDOBJs). Therefore, for now
  904. * it is acceptable for the caller to skip GreClientRgnDone if no WNDOBJs
  905. * exist.
  906. *
  907. * History:
  908. * 19-Dec-1997 -by- Gilman Wong [gilmanw]
  909. * Wrote it.
  910. \**************************************************************************/
  911. VOID APIENTRY GreClientRgnDone(FLONG flUpdate)
  912. {
  913. PTRACKOBJ pto;
  914. PEWNDOBJ pwo;
  915. DBGENTRY("GreClientRgnDone\n");
  916. // Go any further only if some WNDOBJs exist.
  917. if (!(flUpdate & GCR_WNDOBJEXISTS))
  918. {
  919. return;
  920. }
  921. // Assert that we are in user critical section.
  922. // This ensures that no one is updating the hwnd.
  923. CHECKUSERCRITIN;
  924. // Enter the semphore for window object.
  925. SEMOBJ so(ghsemWndobj);
  926. // Check which tracking objects need WOC_DRAWN notification.
  927. for (pto = gpto; pto; pto = pto->ptoNext)
  928. {
  929. if (pto->pwo->hwnd)
  930. {
  931. CHECKDEVLOCKIN2(pto->pSurface);
  932. }
  933. if (pto->fl & WO_NEED_DRAW_NOTIFY)
  934. {
  935. pto->fl &= ~WO_NEED_DRAW_NOTIFY;
  936. pto->vUpdateDrv((PEWNDOBJ)NULL, WOC_DRAWN);
  937. }
  938. // Inform the sprite code of the change in the WNDOBJ.
  939. for (pwo = pto->pwo; pwo; pwo = pwo->pwoNext)
  940. {
  941. vSpWndobjChange(pto->pSurface->hdev(), pwo);
  942. }
  943. } // for (pto = gpto; pto; pto = pto->ptoNext)
  944. }
  945. /******************************Public*Function*****************************\
  946. * GreSetClientRgn
  947. *
  948. * User calls this function to update the client region in a WNDOBJ.
  949. * After all the regions have been updated, user must call GreClientRgnUpdated
  950. * to complete the update.
  951. *
  952. * User creates a new region to give to this function. This function must
  953. * delete the region before it returns!
  954. *
  955. * This function should only be called when the calling thread has the
  956. * usercrit and devlock in that order.
  957. *
  958. * History:
  959. * Thu Jan 13 09:55:23 1994 -by- Hock San Lee [hockl]
  960. * Wrote it.
  961. \**************************************************************************/
  962. VOID GreSetClientRgn(PVOID _pwoClient, HRGN hrgnClient, LPRECT prcClient)
  963. {
  964. PEWNDOBJ pwoClient = (PEWNDOBJ)_pwoClient;
  965. DBGENTRY("GreSetClientRgn\n");
  966. // Assert that we are in user critical section and also hold the devlock.
  967. // This ensures that no one is updating the hwnd.
  968. CHECKUSERCRITIN;
  969. if (pwoClient->hwnd)
  970. {
  971. CHECKDEVLOCKIN2(pwoClient->pto->pSurface);
  972. }
  973. // Validate hrgnClient.
  974. if (!hrgnClient)
  975. {
  976. ASSERTGDI(FALSE, "GreSetClientRgn: hrgnClient is NULL\n");
  977. return;
  978. }
  979. // Validate pwoClient.
  980. if (!pwoClient->bValid())
  981. {
  982. ASSERTGDI(FALSE, "GreSetClientRgn: Invalid pwoClient\n");
  983. bDeleteRegion(hrgnClient);
  984. return;
  985. }
  986. // The WNDOBJ should only be modified once per update. A complete
  987. // update includes a call to GreClientRgnUpdated.
  988. #if DBG
  989. if ((pwoClient->fl & (WO_RGN_CLIENT|WO_RGN_UPDATE_ALL))
  990. == (WO_RGN_CLIENT|WO_RGN_UPDATE_ALL))
  991. if (pwoClient->fl & WO_NOTIFIED)
  992. DbgPrint("GreSetClientRgn: WNDOBJ updated more than once!\n");
  993. #endif // DBG
  994. // Get new and old regions.
  995. GreSetRegionOwner(hrgnClient, OBJECT_OWNER_PUBLIC);
  996. RGNOBJAPI roClient(hrgnClient,FALSE);
  997. ASSERTGDI(roClient.bValid(), "GreSetClientRgn: invalid hrgnClient\n");
  998. RGNOBJ roOld(pwoClient->prgn);
  999. ERECTL erclClient(prcClient->left, prcClient->top,
  1000. prcClient->right, prcClient->bottom);
  1001. #ifdef OPENGL_MM
  1002. // Under Multi-mon we need to adjust the client region and
  1003. // client rectangle by the offset of the surface.
  1004. // Additionally we need to clip the client region to the
  1005. // surface of the TRACKOBJ.
  1006. if (!(pwoClient->fl & WO_RGN_DESKTOP_COORD))
  1007. {
  1008. PDEVOBJ pdo(pwoClient->pto->pSurface->hdev());
  1009. if (pdo.bValid())
  1010. {
  1011. if (pdo.bPrimary(pwoClient->pto->pSurface))
  1012. {
  1013. POINTL ptlOrigin;
  1014. ptlOrigin.x = -pdo.pptlOrigin()->x;
  1015. ptlOrigin.y = -pdo.pptlOrigin()->y;
  1016. if ((ptlOrigin.x != 0) || (ptlOrigin.y != 0))
  1017. {
  1018. // offset the region and window rect if necessary
  1019. roClient.bOffset(&ptlOrigin);
  1020. erclClient += ptlOrigin; /* this offsets by ptl */
  1021. }
  1022. }
  1023. }
  1024. RGNMEMOBJTMP rmoTmp;
  1025. RGNMEMOBJTMP rmoRcl;
  1026. if (rmoTmp.bValid() && rmoRcl.bValid())
  1027. {
  1028. // this clips the client region to the pto surface
  1029. rmoRcl.vSet((RECTL *) &pwoClient->pto->erclSurf);
  1030. rmoTmp.bCopy(roClient);
  1031. roClient.iCombine(rmoTmp,rmoRcl,RGN_AND);
  1032. if (rmoTmp.iCombine(roClient,rmoRcl,RGN_AND) != ERROR)
  1033. {
  1034. roClient.bSwap(&rmoTmp);
  1035. }
  1036. }
  1037. }
  1038. #endif // OPENGL_MM
  1039. // If the regions are equal, no need to notify driver here.
  1040. if (roOld.bEqual(roClient)
  1041. && ((ERECTL *)&pwoClient->rclClient)->bEqual(erclClient))
  1042. {
  1043. roClient.bDeleteRGNOBJAPI(); // delete handle too
  1044. return;
  1045. }
  1046. // Enter the semphore for window object.
  1047. SEMOBJ so(ghsemWndobj);
  1048. // Now the WNDOBJ is going to get updated. Hold the per-WNDOBJ semaphore
  1049. // and keep it until we are done modifying and the driver update call has
  1050. // been made.
  1051. SEMOBJ soClient(pwoClient->hsem);
  1052. // Give the driver the client region delta.
  1053. // The delta is valid for this call only!
  1054. if (pwoClient->fl & WO_RGN_CLIENT_DELTA)
  1055. {
  1056. RGNMEMOBJTMP rmoDiff((BOOL)FALSE);
  1057. if (rmoDiff.bValid() &&
  1058. (rmoDiff.iCombine(roClient, roOld, RGN_DIFF) != ERROR))
  1059. {
  1060. pwoClient->bSwap(&rmoDiff);
  1061. pwoClient->prgn->vStamp(); // new iUniq
  1062. pwoClient->vSetClip(pwoClient->prgn, erclClient);
  1063. pwoClient->pto->vUpdateDrvDelta(pwoClient, WOC_RGN_CLIENT_DELTA);
  1064. }
  1065. }
  1066. // Update the new client region in WNDOBJ.
  1067. roClient.bSwap(pwoClient);
  1068. pwoClient->prgn->vStamp(); // new iUniq
  1069. pwoClient->vSetClip(pwoClient->prgn, erclClient);
  1070. roClient.bDeleteRGNOBJAPI(); // delete handle too
  1071. // Give the driver the new client region.
  1072. if (pwoClient->fl & WO_RGN_CLIENT)
  1073. {
  1074. pwoClient->pto->vUpdateDrv(pwoClient, WOC_RGN_CLIENT);
  1075. }
  1076. // Mark that we have visited this WNDOBJ and TRACKOBJ.
  1077. pwoClient->fl |= WO_NOTIFIED;
  1078. pwoClient->pto->fl |= WO_NOTIFIED;
  1079. return;
  1080. }
  1081. /******************************Member*Function*****************************\
  1082. * WNDOBJ_cEnumStart
  1083. *
  1084. * Start the window client region enumeration for the window object.
  1085. *
  1086. * This function can be called from the wndobjchangeproc that is passed to
  1087. * EngCreateWnd. It can also be called from DDI function where a WNDOBJ
  1088. * is given.
  1089. *
  1090. * This function should only be called when the calling thread has the
  1091. * devlock to ensure that there is no client region change.
  1092. *
  1093. * In future, we may want to add the pvConsumer and WNDOBJ pointer to the
  1094. * CLIPOBJ that is passed to the existing DDI. In this way, the WNDOBJ
  1095. * is always available to the DDI instead of the selected few.
  1096. *
  1097. * History:
  1098. * Thu Jan 13 09:55:23 1994 -by- Hock San Lee [hockl]
  1099. * Rewrote it.
  1100. * 11-Nov-1993 -by- Wendy Wu [wendywu]
  1101. * Wrote it.
  1102. \**************************************************************************/
  1103. extern "C" ULONG WNDOBJ_cEnumStart(
  1104. WNDOBJ *pwo,
  1105. ULONG iType,
  1106. ULONG iDir,
  1107. ULONG cLimit)
  1108. {
  1109. DBGENTRY("WNDOBJ_cEnumStart\n");
  1110. ASSERTGDI(((PEWNDOBJ)pwo)->bValid(), "WNDOBJ_cEnumStart: Invalid pwo\n");
  1111. // We need to ensure that the caller holds the devlock before calling this
  1112. // function. Otherwise, some other threads may be drawing into the wrong
  1113. // client region.
  1114. if (((PEWNDOBJ)pwo)->hwnd)
  1115. {
  1116. CHECKDEVLOCKIN2(((PEWNDOBJ)pwo)->pto->pSurface);
  1117. }
  1118. return (*(XCLIPOBJ *)pwo).cEnumStart(TRUE, iType, iDir, cLimit);
  1119. }
  1120. /******************************Member*Function*****************************\
  1121. * WNDOBJ_bEnum
  1122. *
  1123. * Enumerate the client region object in the window object.
  1124. *
  1125. * This function can be called from the wndobjchangeproc that is passed to
  1126. * EngCreateWnd. It can also be called from DDI function where a WNDOBJ
  1127. * is given.
  1128. *
  1129. * This function should only be called when the calling thread has the
  1130. * devlock to ensure that there is no client region change.
  1131. *
  1132. * In future, we may want to add the pvConsumer and WNDOBJ pointer to the
  1133. * CLIPOBJ that is passed to the existing DDI. In this way, the WNDOBJ
  1134. * is always available to the DDI instead of the selected few.
  1135. *
  1136. * History:
  1137. * Thu Jan 13 09:55:23 1994 -by- Hock San Lee [hockl]
  1138. * Rewrote it.
  1139. * 11-Nov-1993 -by- Wendy Wu [wendywu]
  1140. * Wrote it.
  1141. \**************************************************************************/
  1142. extern "C" BOOL WNDOBJ_bEnum(
  1143. WNDOBJ *pwo,
  1144. ULONG cj,
  1145. ULONG *pul)
  1146. {
  1147. DBGENTRY("WNDOBJ_bEnum\n");
  1148. ASSERTGDI(((PEWNDOBJ)pwo)->bValid(), "WNDOBJ_bEnum: Invalid pwo\n");
  1149. // We need to ensure that the caller holds the devlock before calling this
  1150. // function. Otherwise, some other threads may be drawing into the wrong
  1151. // client region.
  1152. if (((PEWNDOBJ)pwo)->hwnd)
  1153. {
  1154. CHECKDEVLOCKIN2(((PEWNDOBJ)pwo)->pto->pSurface);
  1155. }
  1156. return (*(XCLIPOBJ *)pwo).bEnum(cj, (VOID *)pul);
  1157. }
  1158. /******************************Member*Function*****************************\
  1159. * WNDOBJ_vSetConsumer
  1160. *
  1161. * Set the driver pvConsumer value in the window object. It should be
  1162. * used to modify the existing pvConsumer value.
  1163. *
  1164. * This function can be called from the wndobjchangeproc that is passed to
  1165. * EngCreateWnd. It can also be called from DDI function where a WNDOBJ
  1166. * is given.
  1167. *
  1168. * This function should only be called when the calling thread has the
  1169. * devlock to ensure that there is no client region change.
  1170. *
  1171. * History:
  1172. * Thu Jan 13 09:55:23 1994 -by- Hock San Lee [hockl]
  1173. * Wrote it.
  1174. \**************************************************************************/
  1175. extern "C" VOID WNDOBJ_vSetConsumer(
  1176. WNDOBJ *_pwo,
  1177. PVOID pvConsumer)
  1178. {
  1179. PEWNDOBJ pwo = (PEWNDOBJ)_pwo;
  1180. DBGENTRY("WNDOBJ_vSetConsumer\n");
  1181. ASSERTGDI(pwo->bValid(), "WNDOBJ_vSetConsumer: Invalid pwo\n");
  1182. // We need to ensure that the caller holds the devlock before calling this
  1183. // function. Otherwise, some other threads may be drawing into the wrong
  1184. // client region.
  1185. if (pwo->hwnd)
  1186. {
  1187. CHECKDEVLOCKIN2(pwo->pto->pSurface);
  1188. }
  1189. // Do not allow changes to surface wndobj. One reason is that there is
  1190. // no delete notification for surface wndobj.
  1191. if (pwo == pwo->pto->pwoSurf)
  1192. {
  1193. KdPrint(("WNDOBJ_vSetConsumer: cannot modify surface wndobj!\n"));
  1194. return;
  1195. }
  1196. pwo->pvConsumer = pvConsumer;
  1197. }
  1198. /******************************Member*Function*****************************\
  1199. * EWNDOBJ::vOffset
  1200. *
  1201. * Offset the WNDOBJ by some vector.
  1202. \**************************************************************************/
  1203. VOID EWNDOBJ::vOffset(LONG x, LONG y)
  1204. {
  1205. if ((x != 0) || (y != 0))
  1206. {
  1207. EPOINTL eptl(x, y);
  1208. bOffset(&eptl);
  1209. *((ERECTL*) &rclBounds) += eptl;
  1210. *((ERECTL*) &rclClient) += eptl;
  1211. }
  1212. }