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.

479 lines
15 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: class.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains RegisterClass and the related window class management
  7. * functions.
  8. *
  9. * History:
  10. * 12-20-94 FritzS
  11. *
  12. \***************************************************************************/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. BOOL VisWindow(PWND,DWORD);
  16. /***************************************************************************\
  17. * xxxSetClassIconEnum
  18. \***************************************************************************/
  19. BOOL xxxSetClassIconEnum(
  20. PWND pwnd,
  21. LPARAM lParam)
  22. {
  23. CheckLock(pwnd);
  24. if (pwnd->pcls == (PCLS)lParam) {
  25. /*
  26. * If the window doesn't have a small icon or it comes from
  27. * WM_QUERYDRAGICON, redraw the title. In the WM_QUERYDRAGICON
  28. * case, get rid of the small icon so redrawing the title will
  29. * create it if necessary.
  30. */
  31. if (TestWF(pwnd, WFSMQUERYDRAGICON)) {
  32. DestroyWindowSmIcon(pwnd);
  33. }
  34. if (!_GetProp(pwnd, MAKEINTATOM(gpsi->atomIconSmProp),PROPF_INTERNAL)) {
  35. xxxRedrawTitle(pwnd, DC_ICON);
  36. }
  37. }
  38. return TRUE;
  39. }
  40. /***************************************************************************\
  41. * SetClassIcon
  42. *
  43. * Changes the big/small icon of a class. Called from SetClassWord().
  44. \***************************************************************************/
  45. PCURSOR xxxSetClassIcon(
  46. PWND pwnd,
  47. PCLS pcls,
  48. PCURSOR pCursor,
  49. int gcw)
  50. {
  51. PTHREADINFO pti = PtiCurrent();
  52. PCURSOR pCursorOld;
  53. HCURSOR hCursorOld;
  54. TL tlpwndChild;
  55. BOOL fRedraw;
  56. CheckLock(pwnd);
  57. /*
  58. * Save old icon.
  59. */
  60. pCursorOld = ((gcw == GCLP_HICON) ? pcls->spicn : pcls->spicnSm);
  61. if (pCursorOld != pCursor) {
  62. fRedraw = TRUE;
  63. hCursorOld = PtoH(pCursorOld);
  64. /*
  65. * Set new icon.
  66. */
  67. if (gcw == GCLP_HICON) {
  68. /*
  69. * Destroy private cached small icon first.
  70. */
  71. if (pcls->spicnSm && !DestroyClassSmIcon(pcls)) {
  72. fRedraw = FALSE;
  73. }
  74. Lock(&(pcls->spicn), pCursor);
  75. } else {
  76. /*
  77. * We don't allow apps to see the small icons we create from
  78. * their big icons. They can see their own. Saves memory
  79. * leak problems and is easier.
  80. */
  81. if (pcls->CSF_flags & CSF_CACHEDSMICON) {
  82. DestroyClassSmIcon(pcls);
  83. hCursorOld = NULL;
  84. }
  85. Lock(&(pcls->spicnSm), pCursor);
  86. }
  87. if (pcls->spicn && !pcls->spicnSm) {
  88. xxxCreateClassSmIcon(pcls);
  89. }
  90. if (fRedraw) {
  91. if (pcls->cWndReferenceCount > 1) {
  92. ThreadLock(pti->rpdesk->pDeskInfo->spwnd->spwndChild, &tlpwndChild);
  93. xxxInternalEnumWindow(pti->rpdesk->pDeskInfo->spwnd->spwndChild,
  94. xxxSetClassIconEnum,
  95. (LPARAM)pcls,
  96. BWL_ENUMLIST);
  97. ThreadUnlock(&tlpwndChild);
  98. } else {
  99. xxxSetClassIconEnum(pwnd, (LPARAM)pcls);
  100. }
  101. }
  102. /*
  103. * Revalidate the old cursor
  104. */
  105. if (hCursorOld != NULL) {
  106. pCursorOld = HMRevalidateHandleNoRip(hCursorOld);
  107. } else {
  108. pCursorOld = NULL;
  109. }
  110. }
  111. return pCursorOld;
  112. }
  113. /***************************************************************************\
  114. * DestroyClassSmIcon
  115. *
  116. * Destroys the small icon of a class if we've created a cached one.
  117. \***************************************************************************/
  118. BOOL DestroyClassSmIcon(
  119. PCLS pcls)
  120. {
  121. /*
  122. * If we don't have a cached icon, then no work.
  123. */
  124. if (pcls->CSF_flags & CSF_CACHEDSMICON) {
  125. if (pcls->spicnSm) {
  126. _DestroyCursor(pcls->spicnSm, CURSOR_ALWAYSDESTROY);
  127. Unlock(&pcls->spicnSm);
  128. }
  129. pcls->CSF_flags &= ~CSF_CACHEDSMICON;
  130. return TRUE;
  131. }
  132. return FALSE;
  133. }
  134. /***************************************************************************\
  135. * xxxCreateClassSmIcon
  136. *
  137. * Creates a cached class small icon from a class big icon.
  138. \***************************************************************************/
  139. VOID xxxCreateClassSmIcon(
  140. PCLS pcls)
  141. {
  142. PCURSOR pcur;
  143. UserAssert(pcls->cWndReferenceCount > 0);
  144. UserAssert(pcls->spicn);
  145. UserAssert(!pcls->spicnSm);
  146. pcur = xxxClientCopyImage(PtoH(pcls->spicn),
  147. pcls->spicn->rt == PTR_TO_ID(RT_ICON) ? IMAGE_ICON : IMAGE_CURSOR,
  148. SYSMET(CXSMICON),
  149. SYSMET(CYSMICON),
  150. LR_DEFAULTCOLOR | LR_COPYFROMRESOURCE);
  151. Lock(&pcls->spicnSm, pcur);
  152. if (pcls->spicnSm) {
  153. pcls->CSF_flags |= CSF_CACHEDSMICON;
  154. }
  155. }
  156. /***************************************************************************\
  157. * xxxSetWindowStyle
  158. *
  159. * Changes the style bits of a window. Called from SetWindowLong(). This
  160. * sends two messages, a changing and a changed. Upon receipt of a
  161. * WM_STYLECHANGING message, a window can muck with the style bits for
  162. * validation purposes. The WM_STYLECHANGED message is simply after the
  163. * fact.
  164. \***************************************************************************/
  165. LONG xxxSetWindowStyle(
  166. PWND pwnd,
  167. int gwl,
  168. DWORD styleNew)
  169. {
  170. STYLESTRUCT sty;
  171. BOOL fWasChild, fIsChild, fBefore, fAfter;
  172. CheckLock(pwnd);
  173. UserAssert(IsWinEventNotifyDeferredOK());
  174. sty.styleOld = ((gwl == GWL_STYLE) ? pwnd->style : pwnd->ExStyle);
  175. sty.styleNew = styleNew;
  176. /*
  177. * Note that we don't do validation before _and_ after. It is sufficient
  178. * to do our stuff at the end.
  179. */
  180. /*
  181. * We break Quicken 2.0 if we send the messages. That's why we version
  182. * switch them.
  183. *
  184. * Send a WM_STYLECHANGING message to the window, so it can muck with
  185. * the style bits. Like validate some stuff.
  186. */
  187. if (TestWF(pwnd, WFWIN40COMPAT)) {
  188. xxxSendMessage(pwnd, WM_STYLECHANGING, gwl, (LPARAM)(LPSTYLESTRUCT)&sty);
  189. }
  190. /*
  191. * Now do our own validation.
  192. */
  193. if (gwl == GWL_STYLE) {
  194. BOOL fWasVisWindow;
  195. /*
  196. * If this is an edit control that has ES_PASSWORD set and
  197. * the caller does not own it and is trying to reset it,
  198. * fail the call.
  199. */
  200. if (PpiCurrent() != GETPTI(pwnd)->ppi && IS_EDIT(pwnd) &&
  201. (sty.styleOld & ES_PASSWORD) && !(sty.styleNew & ES_PASSWORD)) {
  202. RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "Access denied in xxxSetWindowStyle");
  203. return 0;
  204. }
  205. /* Listbox ownerdraw style check was moved to the client side (client\ntstubs.c) */
  206. /*
  207. * Do proper validation on style bits.
  208. */
  209. if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) {
  210. sty.styleNew |= WS_CLIPSIBLINGS;
  211. }
  212. /*
  213. * If the clipping-ness is changing, invalidate the dc cache.
  214. */
  215. if ((sty.styleNew & (WS_CLIPCHILDREN | WS_CLIPSIBLINGS)) !=
  216. (sty.styleOld & (WS_CLIPCHILDREN | WS_CLIPSIBLINGS))) {
  217. /*
  218. * No need to DeferWinEventNotify() - pwnd is locked
  219. */
  220. zzzInvalidateDCCache(pwnd, IDC_DEFAULT);
  221. }
  222. /*
  223. * This breaks all Paradox dialogs 1.0-5.0 that have combos. They
  224. * enumerate all child windows, add on minimized, then sit in a peek
  225. * loop. After that they enumerate all child windows and remove
  226. * WS_MINIMIZE--except the code below won't let them.
  227. *
  228. * Result is weird painting and an inability to use the dialog any
  229. * more short of dismissing it
  230. *
  231. * Temp fix: Check for child window first.
  232. */
  233. /*
  234. * if this window is REALLY minimized (minimized bit is set and caption
  235. * present bit is removed), then don't allow app to remove the minimize
  236. * bit -- this fixes FoxBlow's attempt at being the OS -- jeffbog
  237. */
  238. if (!TestWF(pwnd, WFCHILD) &&
  239. TestWF(pwnd, WFMINIMIZED) &&
  240. !TestWF(pwnd, WFCPRESENT) &&
  241. !(sty.styleNew & WS_MINIMIZE)) {
  242. sty.styleNew |= WS_MINIMIZE;
  243. }
  244. /*
  245. * If we're changing the child bit, deal with spmenu appropriately.
  246. * If we're turning into a child, change spmenu to an id. If we're
  247. * turning into a top level window, turn spmenu into a menu.
  248. */
  249. fWasChild = TestwndChild(pwnd);
  250. pwnd->style = sty.styleNew;
  251. fIsChild = TestwndChild(pwnd);
  252. /*
  253. * If we turned into a top level window, change spmenu to NULL.
  254. * If we turned into a child from a top level window, unlock spmenu.
  255. */
  256. if (fWasChild && !fIsChild) {
  257. pwnd->spmenu = NULL;
  258. }
  259. if (!fWasChild && fIsChild) {
  260. ClrWF(pwnd, WFMPRESENT);
  261. UnlockWndMenu(pwnd, &pwnd->spmenu);
  262. }
  263. /*
  264. * If the visible, child, or minimized style is changing,
  265. * then update the cVisWindows count
  266. */
  267. fWasVisWindow = VisWindow(pwnd, sty.styleOld);
  268. if (fWasVisWindow != VisWindow(pwnd, sty.styleNew)) {
  269. if (fWasVisWindow) {
  270. DecVisWindows(pwnd);
  271. } else {
  272. IncVisWindows(pwnd);
  273. }
  274. }
  275. } else {
  276. /*
  277. * First, see if the app might be setting bits that it really
  278. * doesn't know about. If so, replace those bits with the
  279. * current values.
  280. */
  281. if (GetAppCompatFlags2(VER40) & GACF2_NO50EXSTYLEBITS) {
  282. sty.styleNew &= WS_EX_VALID40;
  283. } else {
  284. /*
  285. * Don't let aplications set unused extended bits.
  286. */
  287. if (sty.styleNew & ~WS_EX_ALLVALID) {
  288. RIPMSGF1(RIP_WARNING,
  289. "Trying to set reserved exStyle bits 0x%x",
  290. sty.styleNew);
  291. }
  292. sty.styleNew &= WS_EX_ALLVALID;
  293. }
  294. /*
  295. * Is someone trying to toggle the WS_EX_TOPMOST style bit?
  296. */
  297. if ((sty.styleOld & WS_EX_TOPMOST) != (sty.styleNew & WS_EX_TOPMOST)) {
  298. RIPMSG0(RIP_WARNING, "Can't change WS_EX_TOPMOST with SetWindowLong");
  299. /*
  300. * BACKWARDS COMPATIBILITY HACK
  301. * If stuff is getting stored in the high word, then it must be
  302. * Lotus 123-W sticking a FAR pointer in this field. So don't
  303. * modify it.
  304. */
  305. if (TestWF(pwnd, WFWIN40COMPAT) || !HIWORD(sty.styleNew)) {
  306. /*
  307. * Don't let the bit be flipped.
  308. */
  309. sty.styleNew &= ~WS_EX_TOPMOST;
  310. sty.styleNew |= (sty.styleOld & WS_EX_TOPMOST);
  311. }
  312. }
  313. /*
  314. * Check pwnd->ExStyle directly since sty.styleOld can now be
  315. * different from the real state of the window, because of the
  316. * callbacks in this function from the time sty.styleOld was
  317. * remembered and up to now. We must call the layering functions
  318. * based on the real state of the layering bit.
  319. */
  320. fBefore = (pwnd->ExStyle & WS_EX_LAYERED);
  321. fAfter = (sty.styleNew & WS_EX_LAYERED);
  322. if (fBefore && !fAfter) {
  323. UnsetLayeredWindow(pwnd);
  324. } else if (!fBefore && fAfter) {
  325. if (!xxxSetLayeredWindow(pwnd, TRUE)) {
  326. return 0;
  327. }
  328. }
  329. fBefore = (pwnd->ExStyle & WS_EX_COMPOSITED);
  330. fAfter = (sty.styleNew & WS_EX_COMPOSITED);
  331. if (!fBefore && fAfter) {
  332. /*
  333. * If we are turning WS_EX_COMPOSITED on, none of our parents
  334. * should already have WS_EX_COMPOSITED turned on. If any do,
  335. * since we were explicitely trying to turn this style on, fail
  336. * the call.
  337. */
  338. if (GetStyleWindow(pwnd->spwndParent, WEFCOMPOSITED) != NULL) {
  339. return 0;
  340. }
  341. }
  342. if (fBefore && !fAfter) {
  343. UnsetRedirectedWindow(pwnd, REDIRECT_COMPOSITED);
  344. } else if (!fBefore && fAfter) {
  345. if (!SetRedirectedWindow(pwnd, REDIRECT_COMPOSITED)) {
  346. return 0;
  347. }
  348. /*
  349. * We have successfully turned WS_EX_COMPOSITED on for ourself, so
  350. * need to ensure that none of our child have WS_EX_COMPOSITED also
  351. * turned on.
  352. */
  353. xxxTurnOffCompositing(pwnd, TRUE);
  354. }
  355. #ifdef REDIRECTION
  356. {
  357. BOOL fVisrgnChange = FALSE;
  358. fBefore = (pwnd->ExStyle & WS_EX_EXTREDIRECTED);
  359. fAfter = (sty.styleNew & WS_EX_EXTREDIRECTED);
  360. if (fBefore && !fAfter) {
  361. UnsetRedirectedWindow(pwnd, REDIRECT_EXTREDIRECTED);
  362. fVisrgnChange = TRUE;
  363. } else if (!fBefore && fAfter) {
  364. if (!SetRedirectedWindow(pwnd, REDIRECT_EXTREDIRECTED)) {
  365. return 0;
  366. }
  367. fVisrgnChange = TRUE;
  368. }
  369. if (fVisrgnChange) {
  370. BEGINATOMICCHECK();
  371. zzzInvalidateDCCache(pwnd, IDC_DEFAULT | IDC_NOMOUSE);
  372. ENDATOMICCHECK();
  373. }
  374. }
  375. #endif
  376. /*
  377. * The bits we use internally should be preserved
  378. */
  379. pwnd->ExStyle = sty.styleNew | (pwnd->ExStyle & ~WS_EX_ALLVALID);
  380. if ((sty.styleOld ^ sty.styleNew)
  381. & (WS_EX_LEFTSCROLLBAR | WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LAYOUTRTL)) {
  382. xxxRedrawFrame(pwnd);
  383. }
  384. }
  385. /*
  386. * See if we still need the 3D edge since the window styles changed.
  387. */
  388. if (NeedsWindowEdge(pwnd->style, pwnd->ExStyle, TestWF(pwnd, WFWIN40COMPAT))) {
  389. SetWF(pwnd, WEFWINDOWEDGE);
  390. } else {
  391. ClrWF(pwnd, WEFWINDOWEDGE);
  392. }
  393. /*
  394. * Send a WM_STYLECHANGED message.
  395. */
  396. if (TestWF(pwnd, WFWIN40COMPAT)) {
  397. xxxSendMessage(pwnd, WM_STYLECHANGED, gwl, (LPARAM)(LPSTYLESTRUCT)&sty);
  398. }
  399. return sty.styleOld;
  400. }
  401. /***************************************************************************\
  402. * VisWindow
  403. *
  404. * Based on style, determines if this is considered to be "visible" by
  405. * queue foreground styles.
  406. \***************************************************************************/
  407. BOOL VisWindow(
  408. PWND pwnd,
  409. DWORD style)
  410. {
  411. return (FTopLevel(pwnd) && !(style & WS_MINIMIZE) && (style & WS_VISIBLE));
  412. }