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.

587 lines
13 KiB

  1. //============================================================================
  2. // Copyright (c) 1996, Microsoft Corporation
  3. //
  4. // File: bubble.c
  5. //
  6. // History:
  7. // Abolade Gbadegesin Mar-1-1996 Created.
  8. //
  9. // This file contains code for the bubble-popup control.
  10. //============================================================================
  11. #include <windows.h>
  12. #include <windowsx.h>
  13. #include <commctrl.h>
  14. #include <debug.h>
  15. #include <nouiutil.h>
  16. #include <uiutil.h>
  17. #include "bpopup.h" // public declarations
  18. #include "bubble.h" // private declarations
  19. //----------------------------------------------------------------------------
  20. // Function: BubblePopup_Init
  21. //
  22. // This function is called to initialize the control class.
  23. // It registers the bubble-popup window class.
  24. //----------------------------------------------------------------------------
  25. BOOL
  26. BubblePopup_Init(
  27. IN HINSTANCE hinstance
  28. ) {
  29. //
  30. // if the window class is registered already, return
  31. //
  32. WNDCLASS wc;
  33. if (GetClassInfo(hinstance, WC_BUBBLEPOPUP, &wc)) { return TRUE; }
  34. //
  35. // set up the window class for registration
  36. //
  37. wc.lpfnWndProc = BP_WndProc;
  38. wc.hCursor = LoadCursor(hinstance, IDC_ARROW);
  39. wc.hIcon = NULL;
  40. wc.lpszMenuName = NULL;
  41. wc.hInstance = hinstance;
  42. wc.lpszClassName = WC_BUBBLEPOPUP;
  43. wc.hbrBackground = (HBRUSH)(COLOR_INFOBK + 1);
  44. wc.style = CS_HREDRAW | CS_VREDRAW;
  45. wc.cbWndExtra = sizeof(BPOPUP *);
  46. wc.cbClsExtra = 0;
  47. return RegisterClass(&wc);
  48. }
  49. //----------------------------------------------------------------------------
  50. // Function: BP_WndProc
  51. //
  52. // This is the window procedure for all windows in the BubblePopup class.
  53. //----------------------------------------------------------------------------
  54. LRESULT
  55. CALLBACK
  56. BP_WndProc(
  57. IN HWND hwnd,
  58. IN UINT uiMsg,
  59. IN WPARAM wParam,
  60. IN LPARAM lParam
  61. ) {
  62. BPOPUP *pbp;
  63. //
  64. // attempt to retrieve the private data pointer for the window
  65. // on WM_NCCREATE, this fails, so we allocate the data.
  66. //
  67. if ( NULL == hwnd)
  68. {
  69. return (LRESULT)FALSE;
  70. }
  71. pbp = BP_GetPtr(hwnd);
  72. if (pbp == NULL) {
  73. if (uiMsg != WM_NCCREATE) {
  74. return DefWindowProc(hwnd, uiMsg, wParam, lParam);
  75. }
  76. //
  77. // allocate a block of memory
  78. //
  79. pbp = (BPOPUP *)Malloc(sizeof(BPOPUP));
  80. if (pbp == NULL) { return (LRESULT)FALSE; }
  81. //
  82. // save the pointer in the window's private bytes
  83. //
  84. pbp->hwnd = hwnd;
  85. //
  86. //Reset Error code, because BP_SetPtr won't reset the error code when
  87. //it succeeds
  88. //
  89. SetLastError( 0 );
  90. if ((0 == BP_SetPtr(hwnd, pbp)) && (0 != GetLastError()))
  91. {
  92. Free(pbp);
  93. return (LRESULT)FALSE;
  94. }
  95. return DefWindowProc(hwnd, uiMsg, wParam, lParam);
  96. }
  97. //
  98. // if the window is being destroyed, free the block allocated
  99. // and set the private bytes pointer to NULL
  100. //
  101. if (uiMsg == WM_NCDESTROY) {
  102. Free(pbp);
  103. BP_SetPtr(hwnd, 0);
  104. return (LRESULT)0;
  105. }
  106. //
  107. // handle other messages
  108. //
  109. switch(uiMsg) {
  110. HANDLE_MSG(pbp, WM_CREATE, BP_OnCreate);
  111. HANDLE_MSG(pbp, WM_DESTROY, BP_OnDestroy);
  112. case WM_PAINT: {
  113. return BP_OnPaint(pbp);
  114. }
  115. case WM_WINDOWPOSCHANGED: {
  116. BP_ResizeClient(pbp);
  117. return 0;
  118. }
  119. case WM_LBUTTONDOWN:
  120. case WM_RBUTTONDOWN: {
  121. //
  122. // hide the window if it is showing
  123. //
  124. BP_OnDeactivate(pbp);
  125. return 0;
  126. }
  127. case WM_GETFONT: {
  128. return (LRESULT)pbp->hfont;
  129. }
  130. case WM_SETFONT: {
  131. BOOL bRet = BP_OnSetFont(pbp, (HFONT)wParam, (BOOL)LOWORD(lParam));
  132. BP_ResizeClient(pbp);
  133. if (pbp->dwFlags & BPFLAG_Activated) {
  134. InvalidateRect(pbp->hwnd, NULL, TRUE);
  135. UpdateWindow(pbp->hwnd);
  136. }
  137. return bRet;
  138. }
  139. case WM_SETTEXT: {
  140. //
  141. // change the text we're currently using,
  142. // and invalidate our client area
  143. //
  144. Free0(pbp->pszText);
  145. pbp->pszText = StrDup((PTSTR)lParam);
  146. BP_ResizeClient(pbp);
  147. if (pbp->dwFlags & BPFLAG_Activated) {
  148. InvalidateRect(pbp->hwnd, NULL, TRUE);
  149. UpdateWindow(pbp->hwnd);
  150. }
  151. return (pbp->pszText) ? TRUE : FALSE;
  152. }
  153. case WM_GETTEXT: {
  154. //
  155. // return the text we're currently using
  156. //
  157. PTSTR dst = (LPTSTR)lParam;
  158. PTSTR src = pbp->pszText;
  159. return lstrlen(lstrcpyn(dst, src ? src : TEXT(""), (int)wParam));
  160. }
  161. case WM_TIMER: {
  162. BP_OnDeactivate(pbp);
  163. return 0;
  164. }
  165. case BPM_SETTIMEOUT: {
  166. pbp->uiTimeout = (UINT)lParam;
  167. if (pbp->dwFlags & BPFLAG_Activated) {
  168. KillTimer(pbp->hwnd, pbp->ulpTimer);
  169. pbp->ulpTimer = SetTimer(
  170. pbp->hwnd, BP_TimerId, pbp->uiTimeout, NULL
  171. );
  172. }
  173. return 0;
  174. }
  175. case BPM_ACTIVATE: {
  176. return BP_OnActivate(pbp);
  177. }
  178. case BPM_DEACTIVATE: {
  179. return BP_OnDeactivate(pbp);
  180. }
  181. }
  182. return DefWindowProc(hwnd, uiMsg, wParam, lParam);
  183. }
  184. //----------------------------------------------------------------------------
  185. // Function: BP_OnCreate
  186. //
  187. // This function handles the creation of private data for a bubble-popup.
  188. //----------------------------------------------------------------------------
  189. BOOL
  190. BP_OnCreate(
  191. IN BPOPUP * pbp,
  192. IN CREATESTRUCT * pcs
  193. ) {
  194. //
  195. // initialize the structure members
  196. //
  197. pbp->iCtrlId = PtrToUlong(pcs->hMenu);
  198. pbp->pszText = (pcs->lpszName ? StrDup((PTSTR)pcs->lpszName) : NULL);
  199. pbp->dwFlags = 0;
  200. pbp->ulpTimer = 0;
  201. pbp->uiTimeout = 5000;
  202. //
  203. // we force the window to have the WS_POPUP style
  204. //
  205. SetWindowLong(pbp->hwnd, GWL_STYLE, WS_POPUP);
  206. //
  207. // set the WS_EX_TOOLWINDOW style to make sure
  208. // that this window doesn't show up in the tasklist
  209. //
  210. SetWindowLong(pbp->hwnd, GWL_EXSTYLE, pcs->dwExStyle | WS_EX_TOOLWINDOW);
  211. return BP_OnSetFont(pbp, NULL, FALSE);
  212. }
  213. //----------------------------------------------------------------------------
  214. // Function: BP_OnDestroy
  215. //
  216. // This function handles the deallocation of private data for a bubble-popup.
  217. //----------------------------------------------------------------------------
  218. VOID
  219. BP_OnDestroy(
  220. IN BPOPUP * pbp
  221. ) {
  222. //
  223. // if the font was created by this window, delete it
  224. //
  225. if (pbp->dwFlags & BPFLAG_FontCreated) { DeleteObject(pbp->hfont); }
  226. pbp->dwFlags = 0;
  227. pbp->hfont = NULL;
  228. }
  229. //----------------------------------------------------------------------------
  230. // Function: BP_OnSetFont
  231. //
  232. // This function handles the changing of the font in use by a bubble-popup.
  233. //----------------------------------------------------------------------------
  234. BOOL
  235. BP_OnSetFont(
  236. IN BPOPUP * pbp,
  237. IN HFONT hfont,
  238. IN BOOL bRedraw
  239. ) {
  240. if (pbp->dwFlags & BPFLAG_FontCreated) { DeleteObject(pbp->hfont); }
  241. pbp->dwFlags &= ~BPFLAG_FontCreated;
  242. pbp->hfont = NULL;
  243. if (!hfont) {
  244. //
  245. // (re)create the default font.
  246. //
  247. NONCLIENTMETRICS ncm;
  248. ncm.cbSize = sizeof(ncm);
  249. if (!SystemParametersInfo(
  250. SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0
  251. )) {
  252. TRACE1("error %d getting font info", GetLastError());
  253. return FALSE;
  254. }
  255. hfont = CreateFontIndirect(&ncm.lfStatusFont);
  256. if (!hfont) {
  257. TRACE("error creating bubble-popup font");
  258. return FALSE;
  259. }
  260. pbp->dwFlags |= BPFLAG_FontCreated;
  261. }
  262. pbp->hfont = hfont;
  263. if (bRedraw) { InvalidateRect(pbp->hwnd, NULL, TRUE); }
  264. return TRUE;
  265. }
  266. //----------------------------------------------------------------------------
  267. // Function: BP_OnGetRect
  268. //
  269. // This function recomputes the rectangle required to display
  270. // a bubble-popup's current text.
  271. //----------------------------------------------------------------------------
  272. VOID
  273. BP_OnGetRect(
  274. IN BPOPUP * pbp,
  275. IN RECT * prc
  276. ) {
  277. if (!pbp->pszText) { SetRectEmpty(prc); }
  278. else {
  279. HFONT hfontOld;
  280. HDC hdc = GetDC(pbp->hwnd);
  281. if (hdc)
  282. {
  283. //
  284. // select the font into the DC and compute the new rectangle
  285. //
  286. hfontOld = SelectObject(hdc, pbp->hfont);
  287. DrawText(hdc, pbp->pszText, -1, prc, DT_CALCRECT | DT_EXPANDTABS);
  288. if (hfontOld) { SelectObject(hdc, hfontOld); }
  289. ReleaseDC(pbp->hwnd, hdc);
  290. //
  291. // make space in the rectangle for the border
  292. //
  293. InflateRect(
  294. prc, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)
  295. );
  296. }
  297. }
  298. //
  299. // convert the rectangle to screen coordinates
  300. //
  301. MapWindowPoints(pbp->hwnd, NULL, (POINT *)prc, 2);
  302. }
  303. //----------------------------------------------------------------------------
  304. // Function: BP_ResizeClient
  305. //
  306. // When a change occurs (e.g. font-change, new text) this function is called
  307. // to resize the bubble-popup's window so the text still fits.
  308. //----------------------------------------------------------------------------
  309. VOID
  310. BP_ResizeClient(
  311. IN BPOPUP * pbp
  312. ) {
  313. RECT rc;
  314. //
  315. // find out what size the window needs to be to hold
  316. // the text it is currently set to display
  317. //
  318. BP_OnGetRect(pbp, &rc);
  319. //
  320. // resize the window so its client area is large enough
  321. // to hold DrawText's output
  322. //
  323. SetWindowPos(
  324. pbp->hwnd, HWND_TOPMOST, 0, 0, rc.right - rc.left,
  325. rc.bottom - rc.top, SWP_NOMOVE
  326. );
  327. }
  328. //----------------------------------------------------------------------------
  329. // Function: BP_OnPaint
  330. //
  331. // This function handles the painting of a bubble-popup window.
  332. //----------------------------------------------------------------------------
  333. DWORD
  334. BP_OnPaint(
  335. IN BPOPUP * pbp
  336. ) {
  337. HDC hdc;
  338. HBRUSH hbr;
  339. HFONT hfontOld;
  340. PAINTSTRUCT ps;
  341. RECT rc, rcText;
  342. if (!pbp->hfont || !pbp->pszText) { return (DWORD)-1; }
  343. hdc = BeginPaint(pbp->hwnd, &ps);
  344. GetClientRect(pbp->hwnd, &rc);
  345. rcText = rc;
  346. InflateRect(
  347. &rcText, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE)
  348. );
  349. hfontOld = SelectObject(hdc, pbp->hfont);
  350. SetTextColor(hdc, GetSysColor(COLOR_INFOTEXT));
  351. //
  352. // clear the window's background
  353. //
  354. hbr = CreateSolidBrush(GetSysColor(COLOR_INFOBK));
  355. if (hbr)
  356. {
  357. FillRect(hdc, &rc, hbr);
  358. DeleteObject(hbr);
  359. }
  360. //
  361. // draw our formatted text in the window
  362. //
  363. SetBkMode(hdc, TRANSPARENT);
  364. DrawText(hdc, pbp->pszText, -1, &rcText, DT_EXPANDTABS);
  365. //
  366. // draw a border around the window
  367. //
  368. DrawEdge(hdc, &rc, BDR_RAISEDOUTER, BF_RECT);
  369. if (hfontOld) { SelectObject(hdc, hfontOld); }
  370. EndPaint(pbp->hwnd, &ps);
  371. return 0;
  372. }
  373. BOOL
  374. BP_OnActivate(
  375. IN BPOPUP * pbp
  376. ) {
  377. if (pbp->dwFlags & BPFLAG_Activated) {
  378. KillTimer(pbp->hwnd, pbp->ulpTimer);
  379. }
  380. ShowWindow(pbp->hwnd, SW_SHOW);
  381. UpdateWindow(pbp->hwnd);
  382. pbp->ulpTimer = SetTimer(pbp->hwnd, BP_TimerId, pbp->uiTimeout, NULL);
  383. pbp->dwFlags |= BPFLAG_Activated;
  384. return TRUE;
  385. }
  386. BOOL
  387. BP_OnDeactivate(
  388. IN BPOPUP * pbp
  389. ) {
  390. if (pbp->ulpTimer) { KillTimer(pbp->hwnd, pbp->ulpTimer); pbp->ulpTimer = 0; }
  391. ShowWindow(pbp->hwnd, SW_HIDE);
  392. pbp->dwFlags &= ~BPFLAG_Activated;
  393. return TRUE;
  394. }