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.

649 lines
17 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: caret.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Caret code. Every thread has a caret in its queue structure.
  7. *
  8. * History:
  9. * 11-17-90 ScottLu Created.
  10. * 01-Feb-1991 mikeke Added Revalidation code (None)
  11. * 02-12-91 JimA Added access checks
  12. \***************************************************************************/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. /***************************************************************************\
  16. * UT_CaretSet
  17. *
  18. * Checks to see if the current queue has a caret. If pwnd != NULL, check
  19. * to see if the caret is for pwnd.
  20. *
  21. * History:
  22. * 11-17-90 ScottLu Ported.
  23. \***************************************************************************/
  24. BOOL UT_CaretSet(
  25. PWND pwnd)
  26. {
  27. PQ pq;
  28. PTHREADINFO ptiCurrent;
  29. /*
  30. * Current queue have a caret? If not, return FALSE.
  31. */
  32. ptiCurrent = PtiCurrent();
  33. pq = ptiCurrent->pq;
  34. if (pq->caret.spwnd == NULL) {
  35. RIPERR0(ERROR_ACCESS_DENIED,
  36. RIP_VERBOSE,
  37. "Access denied in UT_CaretSet to current queue's caret");
  38. return FALSE;
  39. }
  40. /*
  41. * If the current task does not own the caret, then return FALSE. We let
  42. * 32 bit multithreaded apps set the caret position from a second thread
  43. * for compatibility to our NT 3.1 BETAs.
  44. */
  45. if (pq->caret.tid != TIDq(ptiCurrent)) {
  46. PTHREADINFO ptiCursorOwner = PtiFromThreadId(pq->caret.tid);
  47. if ((ptiCurrent->TIF_flags & TIF_16BIT) ||
  48. ptiCursorOwner == NULL ||
  49. ptiCurrent->ppi != ptiCursorOwner->ppi) {
  50. RIPERR0(ERROR_ACCESS_DENIED,
  51. RIP_VERBOSE,
  52. "Access denied in UT_CaretSet");
  53. return FALSE;
  54. }
  55. }
  56. /*
  57. * If pwnd == NULL, we're just checking to see if current queue has
  58. * caret. It does, so return TRUE.
  59. */
  60. if (pwnd == NULL) {
  61. return TRUE;
  62. }
  63. /*
  64. * pwnd != NULL. Check to see if the caret is for pwnd. If so, return
  65. * TRUE.
  66. */
  67. if (pwnd == pq->caret.spwnd) {
  68. return TRUE;
  69. } else {
  70. return FALSE;
  71. }
  72. }
  73. /***************************************************************************\
  74. * UT_InvertCaret
  75. *
  76. * Invert the caret.
  77. *
  78. * History:
  79. * 11-17-90 ScottLu Ported.
  80. \***************************************************************************/
  81. VOID UT_InvertCaret(
  82. VOID)
  83. {
  84. HDC hdc;
  85. PWND pwnd;
  86. PQ pq;
  87. HBITMAP hbmSave;
  88. BOOL fRestore;
  89. pq = PtiCurrent()->pq;
  90. pwnd = pq->caret.spwnd;
  91. if (pwnd == NULL || !IsVisible(pwnd)) {
  92. pq->caret.fVisible = FALSE;
  93. return;
  94. }
  95. /*
  96. * Get a DC for this window and draw the caret.
  97. */
  98. hdc = _GetDC(pwnd);
  99. if (fRestore = (pwnd->hrgnUpdate ? TRUE : FALSE)) {
  100. GreSaveDC(hdc);
  101. if (TestWF(pwnd, WFWIN31COMPAT)) {
  102. _ExcludeUpdateRgn(hdc, pwnd);
  103. }
  104. }
  105. /*
  106. * If the caret bitmap is NULL, the caret is a white pattern invert.
  107. * If the caret bitmap is == 1, the caret is a gray pattern.
  108. * If the caret bitmap is > 1, the caret is really a bitmap.
  109. */
  110. if (pq->caret.hBitmap > (HBITMAP)1) {
  111. /*
  112. * The caret is a bitmap. SRCINVERT it onto the screen.
  113. */
  114. hbmSave = GreSelectBitmap(ghdcMem, pq->caret.hBitmap);
  115. GreBitBlt(hdc,
  116. pq->caret.x,
  117. pq->caret.y,
  118. pq->caret.cx,
  119. pq->caret.cy,
  120. ghdcMem,
  121. 0,
  122. 0,
  123. SRCINVERT,
  124. 0);
  125. GreSelectBitmap(ghdcMem, hbmSave);
  126. } else {
  127. POLYPATBLT PolyData;
  128. /*
  129. * The caret is a pattern (gray or white). PATINVERT it onto the
  130. * screen.
  131. */
  132. PolyData.x = pq->caret.x;
  133. PolyData.y = pq->caret.y;
  134. PolyData.cx = pq->caret.cx;
  135. PolyData.cy = pq->caret.cy;
  136. if (pq->caret.hBitmap == (HBITMAP)1) {
  137. PolyData.BrClr.hbr = gpsi->hbrGray;
  138. } else {
  139. PolyData.BrClr.hbr = ghbrWhite;
  140. }
  141. GrePolyPatBlt(hdc, PATINVERT, &PolyData, 1, PPB_BRUSH);
  142. }
  143. if (fRestore) {
  144. GreRestoreDC(hdc, -1);
  145. }
  146. _ReleaseDC(hdc);
  147. }
  148. /***************************************************************************\
  149. * zzzInternalDestroyCaret
  150. *
  151. * Internal routine for killing the caret for this thread.
  152. *
  153. * History:
  154. * 11-17-90 ScottLu Ported
  155. \***************************************************************************/
  156. VOID zzzInternalDestroyCaret(
  157. VOID)
  158. {
  159. PQ pq;
  160. PTHREADINFO ptiCurrent = PtiCurrent();
  161. PWND pwndCaret;
  162. TL tlpwndCaret;
  163. /*
  164. * Hide the caret, kill the timer, and null out the caret structure.
  165. */
  166. zzzInternalHideCaret();
  167. pq = ptiCurrent->pq;
  168. if (pq->caret.hTimer != 0) {
  169. _KillSystemTimer(pq->caret.spwnd, IDSYS_CARET);
  170. pq->caret.hTimer = 0;
  171. }
  172. pq->caret.hBitmap = NULL;
  173. pq->caret.iHideLevel = 0;
  174. pwndCaret = pq->caret.spwnd;
  175. if (pwndCaret != NULL) {
  176. ThreadLockWithPti(ptiCurrent, pwndCaret, &tlpwndCaret);
  177. Unlock(&pq->caret.spwnd);
  178. zzzWindowEvent(EVENT_OBJECT_DESTROY,
  179. pwndCaret,
  180. OBJID_CARET,
  181. INDEXID_CONTAINER,
  182. 0);
  183. ThreadUnlock(&tlpwndCaret);
  184. }
  185. }
  186. /***************************************************************************\
  187. * zzzDestroyCaret
  188. *
  189. * External api for destroying the caret of the current thread.
  190. *
  191. * History:
  192. * 11-17-90 ScottLu Ported.
  193. * 16-May-1991 mikeke Changed to return BOOL
  194. \***************************************************************************/
  195. BOOL zzzDestroyCaret(
  196. VOID)
  197. {
  198. if (UT_CaretSet(NULL)) {
  199. zzzInternalDestroyCaret();
  200. return TRUE;
  201. } else {
  202. return FALSE;
  203. }
  204. }
  205. /***************************************************************************\
  206. * xxxCreateCaret
  207. *
  208. * External api for creating the caret.
  209. *
  210. * History:
  211. * 11-17-90 ScottLu Ported.
  212. * 16-May-1991 mikeke Changed to return BOOL
  213. \***************************************************************************/
  214. BOOL xxxCreateCaret(
  215. PWND pwnd,
  216. HBITMAP hBitmap,
  217. int cx,
  218. int cy)
  219. {
  220. PQ pq;
  221. BITMAP bitmap;
  222. PTHREADINFO ptiCurrent = PtiCurrent();
  223. CheckLock(pwnd);
  224. UserAssert(IsWinEventNotifyDeferredOK());
  225. pq = ptiCurrent->pq;
  226. /*
  227. * Don't allow the app to create a caret in a window
  228. * from another queue.
  229. */
  230. if (GETPTI(pwnd)->pq != pq) {
  231. return FALSE;
  232. }
  233. /*
  234. * Defer WinEvent notifications to preserve pq.
  235. */
  236. DeferWinEventNotify();
  237. if (pq->caret.spwnd != NULL) {
  238. zzzInternalDestroyCaret();
  239. }
  240. Lock(&pq->caret.spwnd, pwnd);
  241. pq->caret.iHideLevel = 1;
  242. pq->caret.fOn = TRUE;
  243. pq->caret.fVisible = FALSE;
  244. pq->caret.tid = TIDq(ptiCurrent);
  245. if (cy == 0) {
  246. cy = SYSMET(CYBORDER);
  247. }
  248. if (cx == 0) {
  249. cx = SYSMET(CXBORDER);
  250. }
  251. if ((pq->caret.hBitmap = hBitmap) > (HBITMAP)1) {
  252. GreExtGetObjectW(hBitmap, sizeof(BITMAP), &bitmap);
  253. cy = bitmap.bmHeight;
  254. cx = bitmap.bmWidth;
  255. }
  256. pq->caret.cy = cy;
  257. pq->caret.cx = cx;
  258. if (gpsi->dtCaretBlink != -1 && !IsRemoteConnection()) {
  259. pq->caret.hTimer = _SetSystemTimer(pwnd,
  260. IDSYS_CARET,
  261. gpsi->dtCaretBlink,
  262. CaretBlinkProc);
  263. } else {
  264. pq->caret.hTimer = 0;
  265. }
  266. UserAssert(pwnd == pq->caret.spwnd);
  267. zzzEndDeferWinEventNotify();
  268. /*
  269. * It's best to force this routine to be an xxx routine: that way we can
  270. * force pwnd to be locked and force notifications from within this
  271. * routine and all of the callers are happy with this.
  272. */
  273. xxxWindowEvent(EVENT_OBJECT_CREATE, pwnd, OBJID_CARET, INDEXID_CONTAINER, 0);
  274. return TRUE;
  275. }
  276. /***************************************************************************\
  277. * zzzInternalShowCaret
  278. *
  279. * Internal routine for showing the caret for this thread.
  280. *
  281. * History:
  282. * 11-17-90 ScottLu Ported.
  283. \***************************************************************************/
  284. VOID zzzInternalShowCaret(
  285. VOID)
  286. {
  287. PQ pq = PtiCurrent()->pq;
  288. /*
  289. * If the caret hide level is aleady 0 (meaning it's ok to show) and the
  290. * caret is not physically on, try to invert now if it's turned on.
  291. */
  292. if (pq->caret.iHideLevel == 0) {
  293. if (!pq->caret.fVisible) {
  294. if ((pq->caret.fVisible = pq->caret.fOn) != 0) {
  295. UT_InvertCaret();
  296. }
  297. }
  298. return;
  299. }
  300. /*
  301. * Adjust the hide caret hide count. If we hit 0, we can show the caret.
  302. * Try to invert it if it's turned on.
  303. */
  304. if (--pq->caret.iHideLevel == 0) {
  305. if ((pq->caret.fVisible = pq->caret.fOn) != 0) {
  306. UT_InvertCaret();
  307. }
  308. zzzWindowEvent(EVENT_OBJECT_SHOW,
  309. pq->caret.spwnd,
  310. OBJID_CARET,
  311. INDEXID_CONTAINER,
  312. 0);
  313. }
  314. }
  315. /***************************************************************************\
  316. * zzzInternalHideCaret
  317. *
  318. * Internal routine for hiding the caret.
  319. *
  320. * History:
  321. * 11-17-90 ScottLu Created.
  322. \***************************************************************************/
  323. VOID zzzInternalHideCaret(
  324. VOID)
  325. {
  326. PQ pq = PtiCurrent()->pq;
  327. /*
  328. * If the caret is physically visible, invert it to turn off the bits.
  329. * Adjust the hide count upwards to remember this hide level.
  330. */
  331. if (pq->caret.fVisible) {
  332. UT_InvertCaret();
  333. }
  334. pq->caret.fVisible = FALSE;
  335. pq->caret.iHideLevel++;
  336. /*
  337. * Is the caret transitioning to being hidden? If so, iHideLevel is
  338. * going from 0 to 1.
  339. */
  340. if (pq->caret.iHideLevel == 1) {
  341. zzzWindowEvent(EVENT_OBJECT_HIDE,
  342. pq->caret.spwnd,
  343. OBJID_CARET,
  344. INDEXID_CONTAINER,
  345. 0);
  346. }
  347. }
  348. /***************************************************************************\
  349. * zzzShowCaret
  350. *
  351. * External routine for showing the caret.
  352. *
  353. * History:
  354. * 11-17-90 ScottLu Ported.
  355. * 16-May-1991 mikeke Changed to return BOOL
  356. \***************************************************************************/
  357. BOOL zzzShowCaret(
  358. PWND pwnd)
  359. {
  360. if (UT_CaretSet(pwnd)) {
  361. zzzInternalShowCaret();
  362. return TRUE;
  363. } else {
  364. return FALSE;
  365. }
  366. }
  367. /***************************************************************************\
  368. * zzzHideCaret
  369. *
  370. * External api to hide the caret.
  371. *
  372. * History:
  373. * 11-17-90 ScottLu Ported.
  374. * 16-May-1991 mikeke Changed to return BOOL
  375. \***************************************************************************/
  376. BOOL zzzHideCaret(
  377. PWND pwnd)
  378. {
  379. if (UT_CaretSet(pwnd)) {
  380. zzzInternalHideCaret();
  381. return TRUE;
  382. } else {
  383. return FALSE;
  384. }
  385. }
  386. /***************************************************************************\
  387. * CaretBlinkProc
  388. *
  389. * This routine gets called by DispatchMessage when it gets the WM_SYSTIMER
  390. * message - it blinks the caret.
  391. *
  392. * History:
  393. * 11-17-90 ScottLu Ported.
  394. \***************************************************************************/
  395. VOID CaretBlinkProc(
  396. PWND pwnd,
  397. UINT message,
  398. UINT_PTR id,
  399. LPARAM lParam)
  400. {
  401. PQ pq = PtiCurrent()->pq;
  402. UNREFERENCED_PARAMETER(message);
  403. UNREFERENCED_PARAMETER(id);
  404. UNREFERENCED_PARAMETER(lParam);
  405. /*
  406. * If this window doesn't even have a timer, just return. TRUE is
  407. * returned, which gets returned from DispatchMessage(). Why? Because
  408. * it is compatible with Win3.
  409. */
  410. if (pwnd != pq->caret.spwnd) {
  411. return;
  412. }
  413. if (gpsi->dtCaretBlink == -1 && pq->caret.fOn && pq->caret.fVisible) {
  414. /*
  415. * Kill the timer for performance.
  416. */
  417. _KillSystemTimer(pq->caret.spwnd, IDSYS_CARET);
  418. return;
  419. }
  420. /*
  421. * Flip the logical cursor state. If the hide level permits it, flip
  422. * the physical state and draw the caret.
  423. */
  424. pq->caret.fOn ^= 1;
  425. if (pq->caret.iHideLevel == 0) {
  426. pq->caret.fVisible ^= 1;
  427. UT_InvertCaret();
  428. }
  429. }
  430. /***************************************************************************\
  431. * _SetCaretBlinkTime
  432. *
  433. * Sets the system caret blink time.
  434. *
  435. * History:
  436. * 11-17-90 ScottLu Created.
  437. * 02-12-91 JimA Added access check
  438. * 16-May-1991 mikeke Changed to return BOOL
  439. \***************************************************************************/
  440. BOOL _SetCaretBlinkTime(
  441. UINT cmsBlink)
  442. {
  443. PQ pq;
  444. /*
  445. * Blow it off if the caller doesn't have the proper access rights.
  446. */
  447. if (!CheckWinstaWriteAttributesAccess()) {
  448. return FALSE;
  449. }
  450. /*
  451. * Blow it off if this value is under policy control.
  452. */
  453. if (CheckDesktopPolicy(NULL, (PCWSTR)STR_BLINK)) {
  454. return FALSE;
  455. }
  456. gpsi->dtCaretBlink = cmsBlink;
  457. pq = PtiCurrent()->pq;
  458. if (pq->caret.hTimer) {
  459. _KillSystemTimer(pq->caret.spwnd, IDSYS_CARET);
  460. if (gpsi->dtCaretBlink != -1 && !IsRemoteConnection()) {
  461. pq->caret.hTimer = _SetSystemTimer(pq->caret.spwnd,
  462. IDSYS_CARET,
  463. gpsi->dtCaretBlink,
  464. CaretBlinkProc);
  465. } else {
  466. pq->caret.hTimer = 0;
  467. }
  468. }
  469. return TRUE;
  470. }
  471. /***************************************************************************\
  472. * zzzSetCaretPos
  473. *
  474. * External routine for setting the caret pos.
  475. *
  476. * History:
  477. * 11-17-90 ScottLu Ported.
  478. * 02-12-91 JimA Added access check
  479. \***************************************************************************/
  480. BOOL zzzSetCaretPos(
  481. int x,
  482. int y)
  483. {
  484. PQ pq;
  485. /*
  486. * If this thread does not have the caret set, return FALSE.
  487. */
  488. if (!UT_CaretSet(NULL)) {
  489. RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "Access denied in zzzSetCaretPos");
  490. return FALSE;
  491. }
  492. /*
  493. * If the caret isn't changing position, do nothing (but return success).
  494. */
  495. pq = PtiCurrent()->pq;
  496. if (pq->caret.x == x && pq->caret.y == y) {
  497. return TRUE;
  498. }
  499. /*
  500. * For windows that have private DCs, we have to store the client coordinate
  501. * equivelent for the logical coordinate caret positioning.
  502. */
  503. if (pq->caret.spwnd != NULL && pq->caret.spwnd->pcls->style & CS_OWNDC) {
  504. RECT rcOwnDcCaret;
  505. HDC hdc;
  506. rcOwnDcCaret.left = x;
  507. rcOwnDcCaret.top = y;
  508. rcOwnDcCaret.right = x + pq->caret.cx;
  509. rcOwnDcCaret.bottom = y + pq->caret.cy;
  510. hdc = _GetDC(pq->caret.spwnd);
  511. GreLPtoDP(hdc, (LPPOINT)(&rcOwnDcCaret), 2);
  512. _ReleaseDC(hdc);
  513. pq->caret.xOwnDc = rcOwnDcCaret.left;
  514. pq->caret.yOwnDc = rcOwnDcCaret.top;
  515. pq->caret.cxOwnDc = rcOwnDcCaret.right - rcOwnDcCaret.left;
  516. pq->caret.cyOwnDc = rcOwnDcCaret.bottom - rcOwnDcCaret.top;
  517. }
  518. /*
  519. * If the caret is visible, turn it off while we move it.
  520. */
  521. if (pq->caret.fVisible) {
  522. UT_InvertCaret();
  523. }
  524. /*
  525. * Adjust to the new position.
  526. */
  527. pq->caret.x = x;
  528. pq->caret.y = y;
  529. /*
  530. * Set a new timer so it'll blink in the new position dtCaretBlink
  531. * milliseconds from now.
  532. */
  533. if (pq->caret.hTimer != 0) {
  534. _KillSystemTimer(pq->caret.spwnd, IDSYS_CARET);
  535. }
  536. if (gpsi->dtCaretBlink != -1 && !IsRemoteConnection()) {
  537. pq->caret.hTimer = _SetSystemTimer(pq->caret.spwnd,
  538. IDSYS_CARET,
  539. gpsi->dtCaretBlink,
  540. CaretBlinkProc);
  541. } else {
  542. pq->caret.hTimer = 0;
  543. }
  544. pq->caret.fOn = TRUE;
  545. /*
  546. * Draw it immediately now if the hide level permits it.
  547. */
  548. pq->caret.fVisible = FALSE;
  549. if (pq->caret.iHideLevel == 0) {
  550. pq->caret.fVisible = TRUE;
  551. UT_InvertCaret();
  552. }
  553. zzzWindowEvent(EVENT_OBJECT_LOCATIONCHANGE,
  554. pq->caret.spwnd,
  555. OBJID_CARET,
  556. INDEXID_CONTAINER,
  557. 0);
  558. return TRUE;
  559. }