Source code of Windows XP (NT5)
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.

5871 lines
164 KiB

  1. #include "precomp.h"
  2. #include <version.h>
  3. #include <nmhelp.h>
  4. //
  5. // VIEW.CPP
  6. // The frame, widgets, and client area that presents the shared apps/desktop
  7. // for a remote host.
  8. //
  9. // Copyright(c) Microsoft 1997-
  10. //
  11. //
  12. // NOTE:
  13. // The client of the shared view frame represents the virtual desktop (VD)
  14. // of the host. For 3.0 hosts, the VD is the same as the screen. But for
  15. // 2.x hosts, the VD is the union of the screen size of all hosts. Hence
  16. // the recalculation every time someone starts sharing or changes screen
  17. // size, and the extra fun this entails for existing shared 2.x views.
  18. //
  19. #define MLZ_FILE_ZONE ZONE_CORE
  20. // Help file
  21. static const TCHAR s_cszHtmlHelpFile[] = TEXT("conf.chm");
  22. //
  23. // VIEW_Init()
  24. //
  25. BOOL VIEW_Init(void)
  26. {
  27. BOOL rc = FALSE;
  28. WNDCLASSEX wc;
  29. DebugEntry(VIEW_Init);
  30. //
  31. // Register the frame window class.
  32. // NOTE: Change CS_NOCLOSE if/when we ever let you close the view
  33. // of a person's shared apps.
  34. //
  35. wc.cbSize = sizeof(wc);
  36. wc.style = CS_DBLCLKS | CS_NOCLOSE;
  37. wc.lpfnWndProc = VIEWFrameWindowProc;
  38. wc.cbClsExtra = 0;
  39. wc.cbWndExtra = 0;
  40. wc.hInstance = g_asInstance;
  41. wc.hIcon = NULL;
  42. wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
  43. wc.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
  44. wc.lpszMenuName = NULL;
  45. wc.lpszClassName = VIEW_FRAME_CLASS_NAME;
  46. wc.hIconSm = NULL;
  47. if (!RegisterClassEx(&wc))
  48. {
  49. ERROR_OUT(("Failed to register AS Frame class"));
  50. DC_QUIT;
  51. }
  52. //
  53. // Register the view window class. This sits in the client area of
  54. // the frame along with the statusbar, tray, etc. It displays
  55. // the remote host's shared contents.
  56. //
  57. wc.cbSize = sizeof(wc);
  58. wc.style = CS_DBLCLKS | CS_NOCLOSE;
  59. wc.lpfnWndProc = VIEWClientWindowProc;
  60. wc.cbClsExtra = 0;
  61. wc.cbWndExtra = 0;
  62. wc.hInstance = g_asInstance;
  63. wc.hIcon = NULL;
  64. wc.hCursor = NULL;
  65. wc.hbrBackground = NULL;
  66. wc.lpszMenuName = NULL;
  67. wc.lpszClassName = VIEW_CLIENT_CLASS_NAME;
  68. wc.hIconSm = NULL;
  69. if (!RegisterClassEx(&wc))
  70. {
  71. ERROR_OUT(("Failed to register AS Client class"));
  72. DC_QUIT;
  73. }
  74. //
  75. // Register the window bar class. This hugs the bottom of
  76. // frames for shared apps (not desktop) and acts like a tray
  77. // surrogate. It allows controllers to minimize, restore, and
  78. // activate shared windows that may not be on screen currently
  79. // and therefore not in the view area.
  80. //
  81. // It also is handy reference for what top level windows are shared
  82. // currently.
  83. //
  84. wc.cbSize = sizeof(wc);
  85. wc.style = 0;
  86. wc.lpfnWndProc = VIEWWindowBarProc;
  87. wc.cbClsExtra = 0;
  88. wc.cbWndExtra = 0;
  89. wc.hInstance = g_asInstance;
  90. wc.hIcon = NULL;
  91. wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
  92. wc.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
  93. wc.lpszMenuName = NULL;
  94. wc.lpszClassName = VIEW_WINDOWBAR_CLASS_NAME;
  95. wc.hIconSm = NULL;
  96. if (!RegisterClassEx(&wc))
  97. {
  98. ERROR_OUT(("Failed to register AS WindowBar class"));
  99. DC_QUIT;
  100. }
  101. //
  102. // Register the window bar items class. This is a child of the window
  103. // bar and contains the actual items.
  104. //
  105. wc.cbSize = sizeof(wc);
  106. wc.style = 0;
  107. wc.lpfnWndProc = VIEWWindowBarItemsProc;
  108. wc.cbClsExtra = 0;
  109. wc.cbWndExtra = 0;
  110. wc.hInstance = g_asInstance;
  111. wc.hIcon = NULL;
  112. wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
  113. wc.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
  114. wc.lpszMenuName = NULL;
  115. wc.lpszClassName = VIEW_WINDOWBARITEMS_CLASS_NAME;
  116. wc.hIconSm = NULL;
  117. if (!RegisterClassEx(&wc))
  118. {
  119. ERROR_OUT(("Failed to register AS WindowBarItems class"));
  120. DC_QUIT;
  121. }
  122. //
  123. // Register the full screen exit button class. This is a child of the
  124. // the view client when present.
  125. //
  126. wc.cbSize = sizeof(wc);
  127. wc.style = 0;
  128. wc.lpfnWndProc = VIEWFullScreenExitProc;
  129. wc.cbClsExtra = 0;
  130. wc.cbWndExtra = 0;
  131. wc.hInstance = g_asInstance;
  132. wc.hIcon = NULL;
  133. wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
  134. wc.hbrBackground = NULL;
  135. wc.lpszMenuName = NULL;
  136. wc.lpszClassName = VIEW_FULLEXIT_CLASS_NAME;
  137. wc.hIconSm = NULL;
  138. if (!RegisterClassEx(&wc))
  139. {
  140. ERROR_OUT(("Failed to register AS full screen exit class"));
  141. DC_QUIT;
  142. }
  143. rc = TRUE;
  144. DC_EXIT_POINT:
  145. DebugExitBOOL(VIEW_Init, rc);
  146. return(rc);
  147. }
  148. //
  149. // VIEW_Term()
  150. //
  151. void VIEW_Term(void)
  152. {
  153. DebugEntry(VIEW_Term);
  154. //
  155. // Free all resources we created (or may have created in window class
  156. // case).
  157. //
  158. UnregisterClass(VIEW_FULLEXIT_CLASS_NAME, g_asInstance);
  159. UnregisterClass(VIEW_WINDOWBARITEMS_CLASS_NAME, g_asInstance);
  160. UnregisterClass(VIEW_WINDOWBAR_CLASS_NAME, g_asInstance);
  161. UnregisterClass(VIEW_CLIENT_CLASS_NAME, g_asInstance);
  162. UnregisterClass(VIEW_FRAME_CLASS_NAME, g_asInstance);
  163. DebugExitVOID(VIEW_Term);
  164. }
  165. //
  166. // VIEW_ShareStarting()
  167. // Creates share resources
  168. //
  169. BOOL ASShare::VIEW_ShareStarting(void)
  170. {
  171. BOOL rc = FALSE;
  172. HBITMAP hbmpT;
  173. TEXTMETRIC tm;
  174. HDC hdc;
  175. HFONT hfnOld;
  176. char szRestore[256];
  177. SIZE extent;
  178. DebugEntry(ASShare::VIEW_ShareStarting);
  179. ASSERT(m_viewVDSize.x == 0);
  180. ASSERT(m_viewVDSize.y == 0);
  181. //
  182. // Get NODROP cursor
  183. //
  184. m_viewNotInControl = ::LoadCursor(NULL, IDC_NO);
  185. //
  186. // Get MOUSEWHEEL lines metric
  187. //
  188. SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
  189. &m_viewMouseWheelScrollLines, 0);
  190. //
  191. // Create a pattern brush from the obscured bitmap
  192. //
  193. hbmpT = LoadBitmap(g_asInstance, MAKEINTRESOURCE(IDB_OBSCURED));
  194. m_viewObscuredBrush = CreatePatternBrush(hbmpT);
  195. DeleteBitmap(hbmpT);
  196. if (!m_viewObscuredBrush)
  197. {
  198. ERROR_OUT(( "Failed to create obscured bitmap brush"));
  199. DC_QUIT;
  200. }
  201. //
  202. // NOTE THAT since the icons are VGA colors, we don't need to recreate
  203. // our brush on a SYSCOLOR change.
  204. //
  205. // Get the full screen cancel icon
  206. m_viewFullScreenExitIcon = (HICON)LoadImage(g_asInstance,
  207. MAKEINTRESOURCE(IDI_CANCELFULLSCREEN), IMAGE_ICON,
  208. GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
  209. LR_DEFAULTCOLOR);
  210. m_viewEdgeCX = ::GetSystemMetrics(SM_CXEDGE);
  211. m_viewEdgeCY = ::GetSystemMetrics(SM_CYEDGE);
  212. //
  213. // Get metrics of GUI_FONT, the one we use in the window bar and
  214. // status bar.
  215. //
  216. LoadString(g_asInstance, IDS_RESTORE, szRestore, sizeof(szRestore));
  217. hdc = ::GetDC(NULL);
  218. hfnOld = (HFONT)::SelectObject(hdc, ::GetStockObject(DEFAULT_GUI_FONT));
  219. ::GetTextMetrics(hdc, &tm);
  220. ::GetTextExtentPoint(hdc, szRestore, lstrlen(szRestore), &extent);
  221. ::SelectObject(hdc, hfnOld);
  222. ::ReleaseDC(NULL, hdc);
  223. //
  224. // Calculate size of full screen button
  225. // Edge on left + margin on left + sm icon + margin + text + margin on
  226. // right + edge on right == 5 edges + sm icon + text
  227. //
  228. m_viewFullScreenCX = extent.cx + 5*m_viewEdgeCX + GetSystemMetrics(SM_CXSMICON);
  229. m_viewFullScreenCY = max(GetSystemMetrics(SM_CYSMICON), extent.cy) + 4*m_viewEdgeCY;
  230. //
  231. // Calculate size of items on window bar
  232. //
  233. m_viewItemCX = 4*m_viewEdgeCX + ::GetSystemMetrics(SM_CXSMICON) +
  234. m_viewEdgeCX + VIEW_MAX_ITEM_CHARS * tm.tmAveCharWidth;
  235. m_viewItemCY = max(::GetSystemMetrics(SM_CYSMICON), tm.tmHeight) +
  236. 2*m_viewEdgeCY + 2*m_viewEdgeCY;
  237. //
  238. // Calculate the width & height of the items scroll buttons. We want
  239. // to make sure it fits, but isn't ungainly.
  240. //
  241. m_viewItemScrollCX = ::GetSystemMetrics(SM_CXHSCROLL);
  242. m_viewItemScrollCX = 2 * min(m_viewItemScrollCX, m_viewItemCY);
  243. m_viewItemScrollCY = ::GetSystemMetrics(SM_CYHSCROLL);
  244. m_viewItemScrollCY = min(m_viewItemScrollCY, m_viewItemCY);
  245. //
  246. // Calculate height of active window bar. We leave a CYEDGE gap on the
  247. // top. between it and the sunken border around the view client.
  248. //
  249. m_viewWindowBarCY = m_viewItemCY + m_viewEdgeCY;
  250. //
  251. // Calculate height of status bar. It's height of GUIFONT plus edge
  252. // space.
  253. //
  254. m_viewStatusBarCY = tm.tmHeight + 4*m_viewEdgeCY;
  255. rc = TRUE;
  256. DC_EXIT_POINT:
  257. DebugExitBOOL(ASShare::VIEW_ShareStarting, rc);
  258. return(rc);
  259. }
  260. //
  261. // VIEW_ShareEnded()
  262. // Cleans up resources for share
  263. //
  264. void ASShare::VIEW_ShareEnded(void)
  265. {
  266. DebugEntry(ASShare::VIEW_ShareEnded);
  267. //
  268. // Destroy the full screen cancel icon
  269. //
  270. if (m_viewFullScreenExitIcon != NULL)
  271. {
  272. DestroyIcon(m_viewFullScreenExitIcon);
  273. m_viewFullScreenExitIcon = NULL;
  274. }
  275. if (m_viewObscuredBrush != NULL)
  276. {
  277. DeleteBrush(m_viewObscuredBrush);
  278. m_viewObscuredBrush = NULL;
  279. }
  280. DebugExitVOID(ASShre::VIEW_ShareEnded);
  281. }
  282. //
  283. // VIEW_PartyLeftShare()
  284. //
  285. // This is called when somebody leaves a share. We need this to
  286. // simulate what back-level systems did to calculate the virtual desktop
  287. // size. They didn't recalc when someone stopped shared, that person's
  288. // screne size counted until they left the share.
  289. //
  290. void ASShare::VIEW_PartyLeftShare(ASPerson * pasPerson)
  291. {
  292. DebugEntry(ASShare::VIEW_PartyLeftShare);
  293. ValidatePerson(pasPerson);
  294. // If this dude ever shared, now remove him from the VD total
  295. if (pasPerson->viewExtent.x != 0)
  296. {
  297. pasPerson->viewExtent.x = 0;
  298. pasPerson->viewExtent.y = 0;
  299. VIEW_RecalcVD();
  300. }
  301. DebugExitVOID(ASShare::VIEW_PartyLeftShare);
  302. }
  303. //
  304. // VIEW_HostStarting()
  305. //
  306. // Called when we start to host.
  307. //
  308. BOOL ASHost::VIEW_HostStarting(void)
  309. {
  310. DebugEntry(ASHost:VIEW_HostStarting);
  311. m_pShare->VIEW_RecalcExtent(m_pShare->m_pasLocal);
  312. m_pShare->VIEW_RecalcVD();
  313. DebugExitBOOL(ASHost::VIEW_HostStarting, TRUE);
  314. return(TRUE);
  315. }
  316. //
  317. // VIEW_ViewStarting()
  318. // Called when someone in the meeting starts to share. For all in the
  319. // conference, we keep a running tally of the VD, but use it only for
  320. // 2.x views. For remotes only, we create a view of their desktop.
  321. //
  322. BOOL ASShare::VIEW_ViewStarting(ASPerson * pasHost)
  323. {
  324. BOOL rc = FALSE;
  325. HWND hwnd;
  326. RECT rcSize;
  327. DebugEntry(ASShare::VIEW_ViewStarting);
  328. ValidateView(pasHost);
  329. //
  330. // First, calculate the extents, and the VD size.
  331. //
  332. VIEW_RecalcExtent(pasHost);
  333. VIEW_RecalcVD();
  334. //
  335. // Next, create scratch regions
  336. //
  337. pasHost->m_pView->m_viewExtentRgn = CreateRectRgn(0, 0, 0, 0);
  338. pasHost->m_pView->m_viewScreenRgn = CreateRectRgn(0, 0, 0, 0);
  339. pasHost->m_pView->m_viewPaintRgn = CreateRectRgn(0, 0, 0, 0);
  340. pasHost->m_pView->m_viewScratchRgn = CreateRectRgn(0, 0, 0, 0);
  341. if (!pasHost->m_pView->m_viewExtentRgn || !pasHost->m_pView->m_viewScreenRgn || !pasHost->m_pView->m_viewPaintRgn || !pasHost->m_pView->m_viewScratchRgn)
  342. {
  343. ERROR_OUT(("ViewStarting: Couldn't create scratch regions"));
  344. DC_QUIT;
  345. }
  346. ASSERT(pasHost->m_pView->m_viewFrame == NULL);
  347. ASSERT(pasHost->m_pView->m_viewClient == NULL);
  348. ASSERT(pasHost->m_pView->m_viewSharedRgn == NULL);
  349. ASSERT(pasHost->m_pView->m_viewObscuredRgn == NULL);
  350. ASSERT(pasHost->m_pView->m_viewPos.x == 0);
  351. ASSERT(pasHost->m_pView->m_viewPos.y == 0);
  352. ASSERT(pasHost->m_pView->m_viewPage.x == 0);
  353. ASSERT(pasHost->m_pView->m_viewPage.y == 0);
  354. ASSERT(!pasHost->m_pView->m_viewStatusBarOn);
  355. ASSERT(!pasHost->m_pView->m_viewWindowBarOn);
  356. ASSERT(!pasHost->m_pView->m_viewFullScreen);
  357. pasHost->m_pView->m_viewStatusBarOn = TRUE;
  358. if (pasHost->hetCount != HET_DESKTOPSHARED)
  359. {
  360. pasHost->m_pView->m_viewWindowBarOn = TRUE;
  361. }
  362. //
  363. // Calculate the ideal size for this window.
  364. //
  365. VIEWFrameGetSize(pasHost, &rcSize);
  366. //
  367. // Create the frame. This will in turn create its children.
  368. //
  369. pasHost->m_pView->m_viewMenuBar = ::LoadMenu(g_asInstance,
  370. MAKEINTRESOURCE(IDM_FRAME));
  371. if (!pasHost->m_pView->m_viewMenuBar)
  372. {
  373. ERROR_OUT(("ViewStarting: couldn't load frame menu"));
  374. DC_QUIT;
  375. }
  376. //
  377. // Do once-only capabilities/menu stuff.
  378. //
  379. //
  380. // SEND CTRL+ALT+DEL:
  381. // Append Ctrl+Alt+Del after separator to control menu, if this
  382. // is a view of a service host on NT.
  383. //
  384. if (pasHost->hetCount == HET_DESKTOPSHARED)
  385. {
  386. //
  387. // Remove applications submenu
  388. //
  389. DeleteMenu(pasHost->m_pView->m_viewMenuBar, IDSM_WINDOW,
  390. MF_BYPOSITION);
  391. if ((pasHost->cpcCaps.general.typeFlags & AS_SERVICE) &&
  392. (pasHost->cpcCaps.general.OS == CAPS_WINDOWS) &&
  393. (pasHost->cpcCaps.general.OSVersion == CAPS_WINDOWS_NT))
  394. {
  395. HMENU hSubMenu;
  396. MENUITEMINFO mii;
  397. CHAR szMenu[32];
  398. hSubMenu = GetSubMenu(pasHost->m_pView->m_viewMenuBar, IDSM_CONTROL);
  399. ZeroMemory(&mii, sizeof(mii));
  400. // Separator
  401. mii.cbSize = sizeof(mii);
  402. mii.fMask = MIIM_TYPE;
  403. mii.fType = MFT_SEPARATOR;
  404. InsertMenuItem(hSubMenu, -1, TRUE, &mii);
  405. // Send Ctrl-Alt-Del command
  406. mii.fMask = MIIM_ID | MIIM_STATE | MIIM_TYPE;
  407. mii.fType = MFT_STRING;
  408. mii.fState = MFS_ENABLED;
  409. mii.wID = CMD_CTRLALTDEL;
  410. LoadString(g_asInstance, IDS_CMD_CTRLALTDEL, szMenu,
  411. sizeof(szMenu));
  412. mii.dwTypeData = szMenu;
  413. mii.cch = lstrlen(szMenu);
  414. InsertMenuItem(hSubMenu, -1, TRUE, &mii);
  415. }
  416. }
  417. //
  418. // FULL SCREEN:
  419. // We only enable Full Screen for 3.0 hosts (since with 2.x desktop
  420. // scrolling the view area can change) who have screen sizes identical
  421. // to ours.
  422. //
  423. if ((pasHost->cpcCaps.general.version >= CAPS_VERSION_30) &&
  424. (pasHost->cpcCaps.screen.capsScreenWidth ==
  425. m_pasLocal->cpcCaps.screen.capsScreenWidth) &&
  426. (pasHost->cpcCaps.screen.capsScreenHeight ==
  427. m_pasLocal->cpcCaps.screen.capsScreenHeight))
  428. {
  429. ::EnableMenuItem(pasHost->m_pView->m_viewMenuBar, CMD_VIEWFULLSCREEN,
  430. MF_ENABLED | MF_BYCOMMAND);
  431. }
  432. if (m_pasLocal->m_caControlledBy)
  433. {
  434. WARNING_OUT(("VIEWStarting: currently controlled, create view hidden"));
  435. }
  436. //
  437. // If we are currently controlled, create the frame invisible since
  438. // we hid all the visible ones when we started being this way.
  439. //
  440. hwnd = CreateWindowEx(
  441. WS_EX_WINDOWEDGE,
  442. VIEW_FRAME_CLASS_NAME, // See RegisterClass() call.
  443. NULL,
  444. WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX |
  445. WS_MAXIMIZEBOX | WS_CLIPCHILDREN | (!m_pasLocal->m_caControlledBy ? WS_VISIBLE : 0),
  446. CW_USEDEFAULT,
  447. CW_USEDEFAULT,
  448. pasHost->viewExtent.x >= m_pasLocal->cpcCaps.screen.capsScreenWidth ?
  449. CW_USEDEFAULT : rcSize.right - rcSize.left,
  450. pasHost->viewExtent.y >= m_pasLocal->cpcCaps.screen.capsScreenHeight ?
  451. CW_USEDEFAULT : rcSize.bottom - rcSize.top,
  452. NULL,
  453. pasHost->m_pView->m_viewMenuBar,
  454. g_asInstance,
  455. pasHost // Pass in person ptr
  456. );
  457. if (hwnd == NULL)
  458. {
  459. ERROR_OUT(("ViewStarting: couldn't create frame window"));
  460. DC_QUIT;
  461. }
  462. //
  463. // OK, now we've created this frame window. Go through the sizing
  464. // process again to make sure the scrollbars are OK.
  465. //
  466. VIEWClientExtentChange(pasHost, FALSE);
  467. if (!m_pasLocal->m_caControlledBy)
  468. {
  469. SetForegroundWindow(hwnd);
  470. UpdateWindow(hwnd);
  471. }
  472. #ifdef _DEBUG
  473. TRACE_OUT(("TIME TO SEE SOMETHING: %08d MS",
  474. ::GetTickCount() - g_asSession.scShareTime));
  475. g_asSession.scShareTime = 0;
  476. #endif // DEBUG
  477. rc = TRUE;
  478. DC_EXIT_POINT:
  479. DebugExitBOOL(ASShare::VIEW_ViewStarting, rc);
  480. return(rc);
  481. }
  482. //
  483. // VIEW_ViewEnded()
  484. //
  485. // Called when someone we are viewing stops hosting, so we can clean up.
  486. //
  487. void ASShare::VIEW_ViewEnded(ASPerson * pasHost)
  488. {
  489. DebugEntry(ASShare::VIEW_ViewEnded);
  490. ValidateView(pasHost);
  491. if (pasHost->m_pView->m_viewInformDlg != NULL)
  492. {
  493. SendMessage(pasHost->m_pView->m_viewInformDlg, WM_COMMAND, IDCANCEL, 0);
  494. ASSERT(!pasHost->m_pView->m_viewInformDlg);
  495. ASSERT(!pasHost->m_pView->m_viewInformMsg);
  496. ASSERT(IsWindowEnabled(pasHost->m_pView->m_viewFrame));
  497. }
  498. if (pasHost->m_pView->m_viewFrame != NULL)
  499. {
  500. //
  501. // The frame is the parent of the view, toolbar, etc. Those
  502. // should all be NULL when we return.
  503. //
  504. DestroyWindow(pasHost->m_pView->m_viewFrame);
  505. ASSERT(pasHost->m_pView->m_viewFrame == NULL);
  506. }
  507. ASSERT(pasHost->m_pView->m_viewClient == NULL);
  508. if (pasHost->m_pView->m_viewMenuBar != NULL)
  509. {
  510. ::DestroyMenu(pasHost->m_pView->m_viewMenuBar);
  511. pasHost->m_pView->m_viewMenuBar = NULL;
  512. }
  513. if (pasHost->m_pView->m_viewSharedRgn != NULL)
  514. {
  515. DeleteRgn(pasHost->m_pView->m_viewSharedRgn);
  516. pasHost->m_pView->m_viewSharedRgn = NULL;
  517. }
  518. if (pasHost->m_pView->m_viewObscuredRgn != NULL)
  519. {
  520. DeleteRgn(pasHost->m_pView->m_viewObscuredRgn);
  521. pasHost->m_pView->m_viewObscuredRgn = NULL;
  522. }
  523. //
  524. // Destroy scratch regions
  525. //
  526. if (pasHost->m_pView->m_viewScratchRgn != NULL)
  527. {
  528. DeleteRgn(pasHost->m_pView->m_viewScratchRgn);
  529. pasHost->m_pView->m_viewScratchRgn = NULL;
  530. }
  531. if (pasHost->m_pView->m_viewPaintRgn != NULL)
  532. {
  533. DeleteRgn(pasHost->m_pView->m_viewPaintRgn);
  534. pasHost->m_pView->m_viewPaintRgn = NULL;
  535. }
  536. if (pasHost->m_pView->m_viewScreenRgn != NULL)
  537. {
  538. DeleteRgn(pasHost->m_pView->m_viewScreenRgn);
  539. pasHost->m_pView->m_viewScreenRgn = NULL;
  540. }
  541. if (pasHost->m_pView->m_viewExtentRgn != NULL)
  542. {
  543. DeleteRgn(pasHost->m_pView->m_viewExtentRgn);
  544. pasHost->m_pView->m_viewExtentRgn = NULL;
  545. }
  546. pasHost->m_pView->m_viewPos.x = 0;
  547. pasHost->m_pView->m_viewPos.y = 0;
  548. pasHost->m_pView->m_viewPage.x = 0;
  549. pasHost->m_pView->m_viewPage.y = 0;
  550. pasHost->m_pView->m_viewPgSize.x = 0;
  551. pasHost->m_pView->m_viewPgSize.y = 0;
  552. pasHost->m_pView->m_viewLnSize.x = 0;
  553. pasHost->m_pView->m_viewLnSize.y = 0;
  554. DebugExitVOID(ASShare::VIEW_ViewEnded);
  555. }
  556. //
  557. // VIEW_InControl()
  558. //
  559. // Called when we start/stop controlling this host. We enable the
  560. // toolbar, statusbar, tray, etc., and change the cursor from being the
  561. // nodrop.
  562. //
  563. void ASShare::VIEW_InControl
  564. (
  565. ASPerson * pasHost,
  566. BOOL fStart
  567. )
  568. {
  569. POINT ptCursor;
  570. DebugEntry(ASShare::VIEW_InControl);
  571. //
  572. // We're changing our state, and that affects the contents of our
  573. // menu bar. So cancel out of menu mode, and spare problems/faults/
  574. // inapplicable commands.
  575. //
  576. if (pasHost->m_pView->m_viewInMenuMode)
  577. {
  578. SendMessage(pasHost->m_pView->m_viewFrame, WM_CANCELMODE, 0, 0);
  579. ASSERT(!pasHost->m_pView->m_viewInMenuMode);
  580. }
  581. //
  582. // If starting in control and a message is up, kill it. Then bring our
  583. // window to the front.
  584. //
  585. if (fStart)
  586. {
  587. if (pasHost->m_pView->m_viewInformDlg != NULL)
  588. {
  589. SendMessage(pasHost->m_pView->m_viewInformDlg, WM_COMMAND, IDCANCEL, 0);
  590. ASSERT(!pasHost->m_pView->m_viewInformDlg);
  591. ASSERT(!pasHost->m_pView->m_viewInformMsg);
  592. ASSERT(IsWindowEnabled(pasHost->m_pView->m_viewFrame));
  593. }
  594. SetForegroundWindow(pasHost->m_pView->m_viewFrame);
  595. }
  596. //
  597. // App Sharing (not desktop sharing) stuff
  598. //
  599. if (pasHost->hetCount && (pasHost->hetCount != HET_DESKTOPSHARED))
  600. {
  601. //
  602. // Enable/disable window bar
  603. //
  604. ASSERT(IsWindow(pasHost->m_pView->m_viewWindowBar));
  605. ::EnableWindow(::GetDlgItem(pasHost->m_pView->m_viewWindowBar,
  606. IDVIEW_ITEMS), fStart);
  607. //
  608. // Enable/Disable Applications submenu
  609. //
  610. EnableMenuItem(pasHost->m_pView->m_viewMenuBar, IDSM_WINDOW,
  611. (fStart ? MF_ENABLED : MF_GRAYED) | MF_BYPOSITION);
  612. if (!pasHost->m_pView->m_viewFullScreen)
  613. {
  614. DrawMenuBar(pasHost->m_pView->m_viewFrame);
  615. }
  616. }
  617. //
  618. // Change title bar
  619. //
  620. VIEW_HostStateChange(pasHost);
  621. //
  622. // Turn off/on shadow cursors
  623. //
  624. CM_UpdateShadowCursor(pasHost, fStart, pasHost->cmPos.x, pasHost->cmPos.y,
  625. pasHost->cmHotSpot.x, pasHost->cmHotSpot.y);
  626. //
  627. // This will reset cursor image:
  628. // * from nodrop to shared if in control
  629. // * from shared to nodrop if not in control
  630. //
  631. // This will also, if in control, cause a mousemove to get sent to the
  632. // host we're controlling so his cursor pos is synced with ours, if the
  633. // mouse is over the frame client area.
  634. //
  635. GetCursorPos(&ptCursor);
  636. SetCursorPos(ptCursor.x, ptCursor.y);
  637. DebugExitVOID(ASShare::VIEW_InControl);
  638. }
  639. //
  640. // VIEW_PausedInControl()
  641. //
  642. // Updates status bar etc. when control is paused.
  643. //
  644. void ASShare::VIEW_PausedInControl
  645. (
  646. ASPerson * pasHost,
  647. BOOL fPaused
  648. )
  649. {
  650. DebugEntry(ASShare::VIEW_PausedInControl);
  651. ValidatePerson(pasHost);
  652. ASSERT(pasHost->m_caControlledBy == m_pasLocal);
  653. //
  654. // Update status bar
  655. //
  656. //
  657. // Disable/Enable window menu
  658. //
  659. //
  660. // Put shadow cursors on/off
  661. //
  662. //
  663. // Jiggle cursor
  664. //
  665. DebugExitVOID(ASShare::VIEW_PausedInControl);
  666. }
  667. //
  668. // VIEW_HostStateChange()
  669. //
  670. // Called when a host's state has changed, via broadcast notification or
  671. // local operations.
  672. //
  673. // We update the titlebar and commands.
  674. //
  675. void ASShare::VIEW_HostStateChange
  676. (
  677. ASPerson * pasHost
  678. )
  679. {
  680. char szFormat[256];
  681. char szTitleText[256];
  682. char szOtherPart[128];
  683. DebugEntry(ASShare::VIEW_HostStateChange);
  684. ValidatePerson(pasHost);
  685. //
  686. // If this person isn't hosting anymore, don't do anything. We're
  687. // cleaning up after him.
  688. //
  689. if (!pasHost->hetCount)
  690. {
  691. DC_QUIT;
  692. }
  693. //
  694. // Make up trailing string
  695. //
  696. if (pasHost->m_caControlledBy)
  697. {
  698. LoadString(g_asInstance, IDS_TITLE_INCONTROL, szFormat, sizeof(szFormat));
  699. wsprintf(szOtherPart, szFormat, pasHost->m_caControlledBy->scName);
  700. }
  701. else if (pasHost->m_caAllowControl)
  702. {
  703. LoadString(g_asInstance, IDS_TITLE_CONTROLLABLE, szOtherPart, sizeof(szOtherPart));
  704. }
  705. else
  706. {
  707. szOtherPart[0] = 0;
  708. }
  709. if (pasHost->hetCount == HET_DESKTOPSHARED)
  710. {
  711. LoadString(g_asInstance, IDS_TITLE_SHAREDDESKTOP, szFormat, sizeof(szFormat));
  712. }
  713. else
  714. {
  715. ASSERT(pasHost->hetCount);
  716. LoadString(g_asInstance, IDS_TITLE_SHAREDPROGRAMS, szFormat, sizeof(szFormat));
  717. }
  718. wsprintf(szTitleText, szFormat, pasHost->scName, szOtherPart);
  719. ::SetWindowText(pasHost->m_pView->m_viewFrame, szTitleText);
  720. DC_EXIT_POINT:
  721. DebugExitVOID(ASShare::VIEW_HostStateChange);
  722. }
  723. //
  724. // VIEW_UpdateStatus()
  725. //
  726. // Updates the PERMANENT status of this frame. When we go into menu mode,
  727. // the strings shown are temporary only, not saved. When we come out of
  728. // menu mode, we put back the temporary status.
  729. //
  730. void ASShare::VIEW_UpdateStatus
  731. (
  732. ASPerson * pasHost,
  733. UINT idsStatus
  734. )
  735. {
  736. DebugEntry(ASShare::VIEW_UpdateStatus);
  737. ValidatePerson(pasHost);
  738. pasHost->m_pView->m_viewStatus = idsStatus;
  739. VIEWFrameSetStatus(pasHost, idsStatus);
  740. DebugExitVOID(ASShare::VIEW_UpdateStatus);
  741. }
  742. void ASShare::VIEWFrameSetStatus
  743. (
  744. ASPerson * pasHost,
  745. UINT idsStatus
  746. )
  747. {
  748. char szStatus[256];
  749. DebugEntry(ASShare::VIEWFrameSetStatus);
  750. if (idsStatus != IDS_STATUS_NONE)
  751. {
  752. LoadString(g_asInstance, idsStatus, szStatus, sizeof(szStatus));
  753. }
  754. else
  755. {
  756. szStatus[0] = 0;
  757. }
  758. ::SetWindowText(pasHost->m_pView->m_viewStatusBar, szStatus);
  759. DebugExitVOID(ASShare::VIEWFrameSetStatus);
  760. }
  761. //
  762. // VIEW_Message()
  763. //
  764. // Puts up a message to inform the end user of something.
  765. //
  766. void ASShare::VIEW_Message
  767. (
  768. ASPerson * pasHost,
  769. UINT ids
  770. )
  771. {
  772. DebugEntry(ASShare::VIEW_Message);
  773. ValidateView(pasHost);
  774. if (!pasHost->m_pView)
  775. {
  776. WARNING_OUT(("Can't show VIEW message; [%d] not hosting", pasHost->mcsID));
  777. DC_QUIT;
  778. }
  779. if (pasHost->m_pView->m_viewInformDlg)
  780. {
  781. // Kill the previous one
  782. TRACE_OUT(("Killing previous informational mesage for [%d]",
  783. pasHost->mcsID));
  784. SendMessage(pasHost->m_pView->m_viewInformDlg, WM_COMMAND, IDCANCEL, 0);
  785. ASSERT(!pasHost->m_pView->m_viewInformDlg);
  786. ASSERT(!pasHost->m_pView->m_viewInformMsg);
  787. }
  788. if (m_pasLocal->m_caControlledBy)
  789. {
  790. WARNING_OUT(("VIEW_Message: ignoring, view is hidden since we're controlled"));
  791. }
  792. else
  793. {
  794. pasHost->m_pView->m_viewInformMsg = ids;
  795. pasHost->m_pView->m_viewInformDlg = CreateDialogParam(g_asInstance,
  796. ((ids != IDS_ABOUT) ? MAKEINTRESOURCE(IDD_INFORM) : MAKEINTRESOURCE(IDD_ABOUT)),
  797. pasHost->m_pView->m_viewFrame, VIEWDlgProc, (LPARAM)pasHost);
  798. if (!pasHost->m_pView->m_viewInformDlg)
  799. {
  800. ERROR_OUT(("Failed to create inform message box for [%d]",
  801. pasHost->mcsID));
  802. pasHost->m_pView->m_viewInformMsg = 0;
  803. }
  804. }
  805. DC_EXIT_POINT:
  806. DebugExitVOID(ASShare::VIEW_Message);
  807. }
  808. //
  809. // VIEWStartControlled()
  810. //
  811. // If we are about to start being controlled, we hide all the frames
  812. // to get them out of the way AND prevent hangs caused by modal loop code
  813. // in Win9x title bar dragging.
  814. //
  815. void ASShare::VIEWStartControlled(BOOL fStart)
  816. {
  817. ASPerson * pasT;
  818. DebugEntry(ASShare::VIEWStartControlled);
  819. for (pasT = m_pasLocal; pasT != NULL; pasT = pasT->pasNext)
  820. {
  821. if (pasT->m_pView)
  822. {
  823. if (fStart)
  824. {
  825. ASSERT(IsWindowVisible(pasT->m_pView->m_viewFrame));
  826. ShowOwnedPopups(pasT->m_pView->m_viewFrame, FALSE);
  827. SetWindowPos(pasT->m_pView->m_viewFrame, NULL, 0, 0, 0, 0,
  828. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER |
  829. SWP_HIDEWINDOW);
  830. }
  831. else
  832. {
  833. ASSERT(!IsWindowVisible(pasT->m_pView->m_viewFrame));
  834. SetWindowPos(pasT->m_pView->m_viewFrame, NULL, 0, 0, 0, 0,
  835. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER |
  836. SWP_SHOWWINDOW);
  837. ShowOwnedPopups(pasT->m_pView->m_viewFrame, TRUE);
  838. }
  839. }
  840. }
  841. DebugEntry(ASShare::VIEWStartControlled);
  842. }
  843. //
  844. // VIEW_DlgProc()
  845. //
  846. // Handles informing user dialog
  847. //
  848. INT_PTR CALLBACK VIEWDlgProc
  849. (
  850. HWND hwnd,
  851. UINT message,
  852. WPARAM wParam,
  853. LPARAM lParam
  854. )
  855. {
  856. return(g_asSession.pShare->VIEW_DlgProc(hwnd, message, wParam, lParam));
  857. }
  858. BOOL ASShare::VIEW_DlgProc
  859. (
  860. HWND hwnd,
  861. UINT message,
  862. WPARAM wParam,
  863. LPARAM lParam
  864. )
  865. {
  866. BOOL rc = TRUE;
  867. ASPerson * pasHost;
  868. DebugEntry(VIEW_DlgProc);
  869. pasHost = (ASPerson *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  870. if (pasHost)
  871. {
  872. ValidateView(pasHost);
  873. }
  874. switch (message)
  875. {
  876. case WM_INITDIALOG:
  877. {
  878. char szT[256];
  879. char szRes[512];
  880. RECT rc;
  881. RECT rcOwner;
  882. pasHost = (ASPerson *)lParam;
  883. ValidateView(pasHost);
  884. pasHost->m_pView->m_viewInformDlg = hwnd;
  885. SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
  886. ASSERT(pasHost->m_pView->m_viewInformMsg);
  887. if (pasHost->m_pView->m_viewInformMsg == IDS_ABOUT)
  888. {
  889. // About box
  890. GetDlgItemText(hwnd, CTRL_ABOUTVERSION, szT, sizeof(szT));
  891. wsprintf(szRes, szT, VER_PRODUCTRELEASE_STR,
  892. VER_PRODUCTVERSION_STR);
  893. SetDlgItemText(hwnd, CTRL_ABOUTVERSION, szRes);
  894. }
  895. else
  896. {
  897. HDC hdc;
  898. HFONT hfn;
  899. // Set title.
  900. if ((pasHost->m_pView->m_viewInformMsg >= IDS_ERR_TAKECONTROL_FIRST) &&
  901. (pasHost->m_pView->m_viewInformMsg <= IDS_ERR_TAKECONTROL_LAST))
  902. {
  903. LoadString(g_asInstance, IDS_TITLE_TAKECONTROL_FAILED,
  904. szT, sizeof(szT));
  905. SetWindowText(hwnd, szT);
  906. }
  907. // Set message
  908. LoadString(g_asInstance, pasHost->m_pView->m_viewInformMsg,
  909. szT, sizeof(szT));
  910. wsprintf(szRes, szT, pasHost->scName);
  911. SetDlgItemText(hwnd, CTRL_INFORM, szRes);
  912. // Center the message vertically
  913. GetWindowRect(GetDlgItem(hwnd, CTRL_INFORM), &rcOwner);
  914. MapWindowPoints(NULL, hwnd, (LPPOINT)&rcOwner, 2);
  915. rc = rcOwner;
  916. hdc = GetDC(hwnd);
  917. hfn = (HFONT)SendDlgItemMessage(hwnd, CTRL_INFORM, WM_GETFONT, 0, 0);
  918. hfn = SelectFont(hdc, hfn);
  919. DrawText(hdc, szRes, -1, &rc, DT_NOCLIP | DT_EXPANDTABS |
  920. DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
  921. SelectFont(hdc, hfn);
  922. ReleaseDC(hwnd, hdc);
  923. ASSERT((rc.bottom - rc.top) <= (rcOwner.bottom - rcOwner.top));
  924. SetWindowPos(GetDlgItem(hwnd, CTRL_INFORM), NULL,
  925. rcOwner.left,
  926. ((rcOwner.top + rcOwner.bottom) - (rc.bottom - rc.top)) / 2,
  927. (rcOwner.right - rcOwner.left),
  928. rc.bottom - rc.top,
  929. SWP_NOACTIVATE | SWP_NOZORDER);
  930. }
  931. // Disable owner
  932. EnableWindow(pasHost->m_pView->m_viewFrame, FALSE);
  933. // Show window, centered around owner midpoint
  934. GetWindowRect(pasHost->m_pView->m_viewFrame, &rcOwner);
  935. GetWindowRect(hwnd, &rc);
  936. SetWindowPos(hwnd, NULL,
  937. ((rcOwner.left + rcOwner.right) - (rc.right - rc.left)) / 2,
  938. ((rcOwner.top + rcOwner.bottom) - (rc.bottom - rc.top)) / 2,
  939. 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
  940. ShowWindow(hwnd, SW_SHOWNORMAL);
  941. UpdateWindow(hwnd);
  942. break;
  943. }
  944. case WM_COMMAND:
  945. {
  946. switch (GET_WM_COMMAND_ID(wParam, lParam))
  947. {
  948. case IDOK:
  949. case IDCANCEL:
  950. {
  951. ASSERT(!IsWindowEnabled(pasHost->m_pView->m_viewFrame));
  952. EnableWindow(pasHost->m_pView->m_viewFrame, TRUE);
  953. DestroyWindow(hwnd);
  954. break;
  955. }
  956. }
  957. break;
  958. }
  959. case WM_DESTROY:
  960. {
  961. if (pasHost)
  962. {
  963. pasHost->m_pView->m_viewInformDlg = NULL;
  964. pasHost->m_pView->m_viewInformMsg = 0;
  965. }
  966. SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL);
  967. break;
  968. }
  969. default:
  970. {
  971. rc = FALSE;
  972. break;
  973. }
  974. }
  975. DebugExitBOOL(VIEW_DlgProc, rc);
  976. return(rc);
  977. }
  978. //
  979. // VIEW_RecalcExtent()
  980. //
  981. // This recalculates the extent of the view of the host.
  982. //
  983. void ASShare::VIEW_RecalcExtent(ASPerson * pasHost)
  984. {
  985. DebugEntry(ASShare::VIEW_RecalcExtent);
  986. TRACE_OUT(("VIEW_RecalcExtent: New view extent (%04d, %04d) for [%d] version %x",
  987. pasHost->viewExtent.x, pasHost->viewExtent.y,
  988. pasHost->mcsID, pasHost->cpcCaps.general.version));
  989. //
  990. // Compute the extent of the view:
  991. // For 2.x dudes, it's the VD size (union of all hosts)
  992. // For 3.0 dudes, it's the host screen size
  993. //
  994. // REMOVE THIS WHEN 2.X COMPAT IS GONE
  995. //
  996. if (pasHost->cpcCaps.general.version >= CAPS_VERSION_30)
  997. {
  998. pasHost->viewExtent.x = pasHost->cpcCaps.screen.capsScreenWidth;
  999. pasHost->viewExtent.y = pasHost->cpcCaps.screen.capsScreenHeight;
  1000. }
  1001. else
  1002. {
  1003. //
  1004. // We do this so that the window is created the right size in the
  1005. // first place. Then in VIEW_RecalcVD nothing will happen to it,
  1006. // because the extent won't alter.
  1007. //
  1008. pasHost->viewExtent.x = max(m_viewVDSize.x, pasHost->cpcCaps.screen.capsScreenWidth);
  1009. pasHost->viewExtent.y = max(m_viewVDSize.y, pasHost->cpcCaps.screen.capsScreenHeight);
  1010. }
  1011. DebugExitVOID(ASShare::VIEW_RecalcExtent);
  1012. }
  1013. //
  1014. // VIEW_RecalcVD()
  1015. // This recalculates the virtual desktop size when a remote starts/stops
  1016. // sharing, or if a host's screen changes size. The VD is the union of
  1017. // all the screen sizes of those hosting. 2.x nodes work in a virtual
  1018. // desktop, and may scroll over. For each 2.x view, we want the client to
  1019. // represent the VD, but with only the stuff on screen on the host to be
  1020. // interactable.
  1021. //
  1022. void ASShare::VIEW_RecalcVD(void)
  1023. {
  1024. POINT ptVDNew;
  1025. ASPerson * pas;
  1026. DebugEntry(ASShare::VIEW_RecalcVD);
  1027. //
  1028. // First, loop through all the hosts and recompute the VD.
  1029. //
  1030. ptVDNew.x = 0;
  1031. ptVDNew.y = 0;
  1032. for (pas = m_pasLocal; pas != NULL; pas = pas->pasNext)
  1033. {
  1034. //
  1035. // NOTE:
  1036. // For local dudes, we won't have an HWND. Use viewExtent, if
  1037. // we don't think the person is sharing, it will be zero.
  1038. //
  1039. if (pas->viewExtent.x != 0)
  1040. {
  1041. TRACE_OUT(("VIEW_RecalcVD: Found host [%d], screen size (%04d, %04d)",
  1042. pas->mcsID, pas->cpcCaps.screen.capsScreenWidth, pas->cpcCaps.screen.capsScreenHeight));
  1043. ptVDNew.x = max(ptVDNew.x, pas->cpcCaps.screen.capsScreenWidth);
  1044. ptVDNew.y = max(ptVDNew.y, pas->cpcCaps.screen.capsScreenHeight);
  1045. TRACE_OUT(("VIEW_RecalcVD: Computed VD size now (%04d, %04d)",
  1046. ptVDNew.x, ptVDNew.y));
  1047. }
  1048. }
  1049. //
  1050. // If the VD size didn't change, we're done.
  1051. //
  1052. if ((ptVDNew.x != m_viewVDSize.x) || (ptVDNew.y != m_viewVDSize.y))
  1053. {
  1054. TRACE_OUT(("VIEW_RecalcVD: VD size changed from (%04d, %04d) to (%04d, %04d)",
  1055. m_viewVDSize.x, m_viewVDSize.y, ptVDNew.x, ptVDNew.y));
  1056. m_viewVDSize = ptVDNew;
  1057. //
  1058. // Now loop through all the 2.x hosts, and update their extent, then
  1059. // have them do the resize voodoo so the scrollbar pos isn't out of
  1060. // range, etc.
  1061. //
  1062. // NOTE: Since us, the local guy, is not 2.x we can skip ourselves.
  1063. //
  1064. ValidatePerson(m_pasLocal);
  1065. for (pas = m_pasLocal->pasNext; pas != NULL; pas = pas->pasNext)
  1066. {
  1067. if ((pas->cpcCaps.general.version < CAPS_VERSION_30) && (pas->m_pView != NULL))
  1068. {
  1069. ASSERT(m_viewVDSize.x != 0);
  1070. ASSERT(m_viewVDSize.y != 0);
  1071. // Potential resize/range change
  1072. if ((pas->viewExtent.x != m_viewVDSize.x) ||
  1073. (pas->viewExtent.y != m_viewVDSize.y))
  1074. {
  1075. TRACE_OUT(("VIEW_RecalcVD: Found 2.x host [%d], must update old extent (%04d, %04d)",
  1076. pas->mcsID, pas->viewExtent.x, pas->viewExtent.y));
  1077. VIEW_RecalcExtent(pas);
  1078. VIEWClientExtentChange(pas, TRUE);
  1079. }
  1080. }
  1081. }
  1082. }
  1083. DebugExitVOID(ASShare::VIEW_RecalcVD);
  1084. }
  1085. //
  1086. // VIEW_IsPointShared()
  1087. // This determines, given a point relative to the client of the view for
  1088. // the remote on this system, if it is in a shared area.
  1089. //
  1090. BOOL ASShare::VIEW_IsPointShared
  1091. (
  1092. ASPerson * pasHost,
  1093. POINT ptLocal
  1094. )
  1095. {
  1096. BOOL rc = FALSE;
  1097. RECT rcClient;
  1098. DebugEntry(ASShare::VIEW_IsPointShared);
  1099. ValidateView(pasHost);
  1100. //
  1101. // Convert to client coords, and adjust for scrolling offset. That
  1102. // result is the equivalent point on the host desktop.
  1103. //
  1104. GetClientRect(pasHost->m_pView->m_viewClient, &rcClient);
  1105. if (!PtInRect(&rcClient, ptLocal))
  1106. {
  1107. TRACE_OUT(("VIEW_IsPointShared: point not in client area"));
  1108. return(FALSE);
  1109. }
  1110. //
  1111. // The obscured and shared areas are saved in frame client coords,
  1112. // so we don't need to account for the scroll position all the time.
  1113. // When the scroll position changes the regions are updated.
  1114. //
  1115. //
  1116. // NOTE that this order works for both desktop and app sharing
  1117. //
  1118. if ((pasHost->m_pView->m_viewObscuredRgn != NULL) &&
  1119. PtInRegion(pasHost->m_pView->m_viewObscuredRgn, ptLocal.x, ptLocal.y))
  1120. {
  1121. rc = FALSE;
  1122. }
  1123. else if ((pasHost->m_pView->m_viewSharedRgn != NULL) &&
  1124. !PtInRegion(pasHost->m_pView->m_viewSharedRgn, ptLocal.x, ptLocal.y))
  1125. {
  1126. rc = FALSE;
  1127. }
  1128. else
  1129. {
  1130. //
  1131. // 2.x hosts may be scrolled over. If so, shared stuff offscreen
  1132. // is also considered to be obscured.
  1133. //
  1134. RECT rcScreen;
  1135. //
  1136. // Compute what part of the VD, in local client coords, is visible
  1137. // on the remote's screen.
  1138. //
  1139. SetRect(&rcScreen, 0, 0, pasHost->cpcCaps.screen.capsScreenWidth, pasHost->cpcCaps.screen.capsScreenHeight);
  1140. OffsetRect(&rcScreen,
  1141. pasHost->m_pView->m_dsScreenOrigin.x - pasHost->m_pView->m_viewPos.x,
  1142. pasHost->m_pView->m_dsScreenOrigin.y - pasHost->m_pView->m_viewPos.y);
  1143. if (!PtInRect(&rcScreen, ptLocal))
  1144. {
  1145. TRACE_OUT(("VIEW_IsPointShared: point is in shared stuff but not visible on remote screen"));
  1146. rc = FALSE;
  1147. }
  1148. else
  1149. {
  1150. rc = TRUE;
  1151. }
  1152. }
  1153. DebugExitBOOL(AShare::VIEW_IsPointShared, rc);
  1154. return(rc);
  1155. }
  1156. //
  1157. // VIEW_ScreenChanged()
  1158. //
  1159. void ASShare::VIEW_ScreenChanged(ASPerson * pasPerson)
  1160. {
  1161. DebugEntry(ASShare::VIEW_ScreenChanged);
  1162. ValidatePerson(pasPerson);
  1163. //
  1164. // Recompute the extent
  1165. //
  1166. VIEW_RecalcExtent(pasPerson);
  1167. VIEWClientExtentChange(pasPerson, TRUE);
  1168. VIEW_RecalcVD();
  1169. DebugExitVOID(ASShare::VIEW_ScreenChanged);
  1170. }
  1171. //
  1172. // VIEW_SetHostRegions()
  1173. // This sets the new shared & obscured areas.
  1174. //
  1175. // Note that this routine takes responsibility for the regions pass in; it
  1176. // will delete them and/or the old ones if necessary.
  1177. //
  1178. void ASShare::VIEW_SetHostRegions
  1179. (
  1180. ASPerson * pasHost,
  1181. HRGN rgnShared,
  1182. HRGN rgnObscured
  1183. )
  1184. {
  1185. DebugEntry(ASShare::VIEW_SetHostRegions);
  1186. ValidateView(pasHost);
  1187. //
  1188. // Return immediately if either region handle is bogus. This can happen
  1189. // when we are running low on memory.
  1190. //
  1191. if (!rgnShared || !rgnObscured)
  1192. {
  1193. ERROR_OUT(("Bad host regions for person [%u]", pasHost->mcsID));
  1194. if (rgnShared != NULL)
  1195. {
  1196. DeleteRgn(rgnShared);
  1197. }
  1198. if (rgnObscured != NULL)
  1199. {
  1200. DeleteRgn(rgnObscured);
  1201. }
  1202. }
  1203. else
  1204. {
  1205. HRGN hrgnInvalid;
  1206. #ifdef _DEBUG
  1207. RECT rcT;
  1208. ::GetRgnBox(rgnShared, &rcT);
  1209. TRACE_OUT(("Shared region {%04d, %04d, %04d, %04d} for host [%d]",
  1210. rcT.left, rcT.top, rcT.right, rcT.bottom, pasHost->mcsID));
  1211. ::GetRgnBox(rgnObscured, &rcT);
  1212. TRACE_OUT(("Obscured region {%04d, %04d, %04d, %04d} for host [%d]",
  1213. rcT.left, rcT.top, rcT.right, rcT.bottom, pasHost->mcsID));
  1214. #endif // _DEBUG
  1215. //
  1216. // Update the current shared, obscured areas. Adjust for the
  1217. // scroll position so these are saved in client-relative coords.
  1218. //
  1219. OffsetRgn(rgnShared, -pasHost->m_pView->m_viewPos.x, -pasHost->m_pView->m_viewPos.y);
  1220. OffsetRgn(rgnObscured, -pasHost->m_pView->m_viewPos.x, -pasHost->m_pView->m_viewPos.y);
  1221. //
  1222. // The invalid area is whatever changed in the obscured area and
  1223. // the shared area. In other words, the union - the intersection.
  1224. //
  1225. hrgnInvalid = NULL;
  1226. if (pasHost->m_pView->m_viewSharedRgn != NULL)
  1227. {
  1228. HRGN hrgnU;
  1229. HRGN hrgnI;
  1230. ASSERT(pasHost->m_pView->m_viewObscuredRgn != NULL);
  1231. //
  1232. // If we're in a low memory situation, just invalidate everything
  1233. // and hope it can be repainted.
  1234. //
  1235. hrgnU = CreateRectRgn(0, 0, 0, 0);
  1236. hrgnI = CreateRectRgn(0, 0, 0, 0);
  1237. if (!hrgnU || !hrgnI)
  1238. goto SkipMinimalInvalidate;
  1239. hrgnInvalid = CreateRectRgn(0, 0, 0, 0);
  1240. if (!hrgnInvalid)
  1241. goto SkipMinimalInvalidate;
  1242. //
  1243. // WE'RE GOING TO DO THE SAME THING FOR BOTH SHARED AND
  1244. // OBSCURED REGIONS.
  1245. //
  1246. // Get the union of the old and new shared regions
  1247. UnionRgn(hrgnU, pasHost->m_pView->m_viewSharedRgn, rgnShared);
  1248. // Get the intersection of the old and new shared regions
  1249. IntersectRgn(hrgnI, pasHost->m_pView->m_viewSharedRgn, rgnShared);
  1250. //
  1251. // The intersection is what used to be shared and is still shared.
  1252. // The rest is changing, it needs to be repainted. That's the
  1253. // union minus the intersection.
  1254. //
  1255. SubtractRgn(hrgnU, hrgnU, hrgnI);
  1256. #ifdef _DEBUG
  1257. GetRgnBox(hrgnU, &rcT);
  1258. TRACE_OUT(("VIEW_SetHostRegions: Shared area change {%04d, %04d, %04d, %04d}",
  1259. rcT.left, rcT.top, rcT.right, rcT.bottom));
  1260. #endif // _DEBUG
  1261. // Add this to the invalidate total
  1262. UnionRgn(hrgnInvalid, hrgnInvalid, hrgnU);
  1263. //
  1264. // REPEAT FOR THE OBSCURED REGION
  1265. //
  1266. UnionRgn(hrgnU, pasHost->m_pView->m_viewObscuredRgn, rgnObscured);
  1267. IntersectRgn(hrgnI, pasHost->m_pView->m_viewObscuredRgn, rgnObscured);
  1268. SubtractRgn(hrgnU, hrgnU, hrgnI);
  1269. #ifdef _DEBUG
  1270. GetRgnBox(hrgnU, &rcT);
  1271. TRACE_OUT(("VIEW_SetHostRegions: Obscured area change {%04d, %04d, %04d, %04d}",
  1272. rcT.left, rcT.top, rcT.right, rcT.bottom));
  1273. #endif // _DEBUG
  1274. UnionRgn(hrgnInvalid, hrgnInvalid, hrgnU);
  1275. SkipMinimalInvalidate:
  1276. //
  1277. // Clean up scratch regions
  1278. //
  1279. if (hrgnI != NULL)
  1280. DeleteRgn(hrgnI);
  1281. if (hrgnU != NULL)
  1282. DeleteRgn(hrgnU);
  1283. DeleteRgn(pasHost->m_pView->m_viewSharedRgn);
  1284. pasHost->m_pView->m_viewSharedRgn = rgnShared;
  1285. DeleteRgn(pasHost->m_pView->m_viewObscuredRgn);
  1286. pasHost->m_pView->m_viewObscuredRgn = rgnObscured;
  1287. //
  1288. // DO NOT CALL VIEW_InvalidateRgn here, that expects a region in
  1289. // screen coords of pasHost. We have a region that is
  1290. // client coords relative. So just call InvalidateRgn() directly.
  1291. //
  1292. InvalidateRgn(pasHost->m_pView->m_viewClient, hrgnInvalid, FALSE);
  1293. if (hrgnInvalid != NULL)
  1294. DeleteRgn(hrgnInvalid);
  1295. }
  1296. else
  1297. {
  1298. RECT rcBound;
  1299. // The shared & obscured regions are both NULL or both non-NULL
  1300. ASSERT(pasHost->m_pView->m_viewObscuredRgn == NULL);
  1301. pasHost->m_pView->m_viewSharedRgn = rgnShared;
  1302. pasHost->m_pView->m_viewObscuredRgn = rgnObscured;
  1303. //
  1304. // This is the first SWL packet we've received. Snap the
  1305. // scrollbars to the start of the total shared area. This avoids
  1306. // having the view come up, but look empty because the shared
  1307. // apps are out of the range. We do this even if the user
  1308. // scrolled around in the window already.
  1309. //
  1310. // The total shared area is the union of the real shared +
  1311. // obscured shared areas. Convert back to remote VD coords!
  1312. //
  1313. UnionRgn(pasHost->m_pView->m_viewScratchRgn, rgnShared, rgnObscured);
  1314. GetRgnBox(pasHost->m_pView->m_viewScratchRgn, &rcBound);
  1315. OffsetRect(&rcBound, pasHost->m_pView->m_viewPos.x, pasHost->m_pView->m_viewPos.y);
  1316. //
  1317. // Is any part of what was shared within the extent of the view?
  1318. // If not, we can't do anything--there's nothing to show.
  1319. //
  1320. if ((rcBound.right <= 0) ||
  1321. (rcBound.left >= pasHost->viewExtent.x) ||
  1322. (rcBound.bottom <= 0) ||
  1323. (rcBound.top >= pasHost->viewExtent.y))
  1324. {
  1325. TRACE_OUT(("VIEW_SetHostRegions: Can't snap to shared area; none is visible"));
  1326. }
  1327. else
  1328. {
  1329. //
  1330. // Use top left corner of bounds
  1331. // VIEWClientScroll() will pin position w/in range
  1332. //
  1333. VIEWClientScroll(pasHost, rcBound.left, rcBound.top);
  1334. }
  1335. InvalidateRgn(pasHost->m_pView->m_viewClient, NULL, FALSE);
  1336. }
  1337. }
  1338. DebugExitVOID(ASShare::VIEW_SetHostRegions);
  1339. }
  1340. //
  1341. // VIEW_InvalidateRect()
  1342. // Repaints the given rect. This is for EXTERNAL code which passes in VD
  1343. // coords. We convert to client coordinates by accounting for the scroll
  1344. // position.
  1345. //
  1346. void ASShare::VIEW_InvalidateRect
  1347. (
  1348. ASPerson * pasPerson,
  1349. LPRECT lprc
  1350. )
  1351. {
  1352. DebugEntry(ASShare::VIEW_InvalidateRect);
  1353. ValidateView(pasPerson);
  1354. //
  1355. // Convert to client coords
  1356. //
  1357. if (lprc != NULL)
  1358. {
  1359. OffsetRect(lprc, -pasPerson->m_pView->m_viewPos.x, -pasPerson->m_pView->m_viewPos.y);
  1360. }
  1361. InvalidateRect(pasPerson->m_pView->m_viewClient, lprc, FALSE);
  1362. //
  1363. // Convert back so caller doesn't get a modified lprc
  1364. //
  1365. if (lprc != NULL)
  1366. {
  1367. OffsetRect(lprc, pasPerson->m_pView->m_viewPos.x, pasPerson->m_pView->m_viewPos.y);
  1368. }
  1369. DebugExitVOID(ASShare::VIEW_InvalidateRect);
  1370. }
  1371. //
  1372. // VIEW_InvalidateRgn()
  1373. // Repaints the given region. This is for EXTERNAL code which passes in VD
  1374. // coords. We convert to client coordinates by accounting fo the scroll
  1375. // position.
  1376. //
  1377. void ASShare::VIEW_InvalidateRgn
  1378. (
  1379. ASPerson * pasHost,
  1380. HRGN rgnInvalid
  1381. )
  1382. {
  1383. #ifdef _DEBUG
  1384. //
  1385. // Make sure we the invalid region goes back to the caller unaltered,
  1386. // even though we modify it temporarily here to avoid a copy.
  1387. //
  1388. RECT rcBoundBefore;
  1389. RECT rcBoundAfter;
  1390. #endif // _DEBUG
  1391. DebugEntry(ASShare::VIEW_InvalidateRgn);
  1392. ValidatePerson(pasHost);
  1393. //
  1394. // Adjust the region if the frame view is scrolled over.
  1395. //
  1396. if (rgnInvalid != NULL)
  1397. {
  1398. #ifdef _DEBUG
  1399. GetRgnBox(rgnInvalid, &rcBoundBefore);
  1400. #endif // _DEBUG
  1401. OffsetRgn(rgnInvalid, -pasHost->m_pView->m_viewPos.x, -pasHost->m_pView->m_viewPos.y);
  1402. #ifdef _DEBUG
  1403. TRACE_OUT(("VIEW_InvalidateRgn: Invalidating area {%04d, %04d, %04d, %04d}",
  1404. rcBoundBefore.left, rcBoundBefore.top, rcBoundBefore.right, rcBoundBefore.bottom));
  1405. #endif // _DEBUG
  1406. }
  1407. else
  1408. {
  1409. TRACE_OUT(("VIEW_InvalidateRgn: Invalidating entire client area"));
  1410. }
  1411. InvalidateRgn(pasHost->m_pView->m_viewClient, rgnInvalid, FALSE);
  1412. if (rgnInvalid != NULL)
  1413. {
  1414. OffsetRgn(rgnInvalid, pasHost->m_pView->m_viewPos.x, pasHost->m_pView->m_viewPos.y);
  1415. #ifdef _DEBUG
  1416. GetRgnBox(rgnInvalid, &rcBoundAfter);
  1417. ASSERT(EqualRect(&rcBoundBefore, &rcBoundAfter));
  1418. #endif // _DEBUG
  1419. }
  1420. DebugExitVOID(ASShare::VIEW_InvalidateRgn);
  1421. }
  1422. //
  1423. // VIEWClientExtentChange()
  1424. //
  1425. void ASShare::VIEWClientExtentChange(ASPerson * pasHost, BOOL fRedraw)
  1426. {
  1427. RECT rcl;
  1428. SCROLLINFO si;
  1429. DebugEntry(ASShare::VIEWClientExtentChange);
  1430. ValidatePerson(pasHost);
  1431. if (!pasHost->m_pView)
  1432. DC_QUIT;
  1433. #ifdef _DEBUG
  1434. //
  1435. // The client area (page size) shouldn't have changed. Only the
  1436. // extent has.
  1437. //
  1438. GetClientRect(pasHost->m_pView->m_viewClient, &rcl);
  1439. ASSERT(pasHost->m_pView->m_viewPage.x == rcl.right - rcl.left);
  1440. ASSERT(pasHost->m_pView->m_viewPage.y == rcl.bottom - rcl.top);
  1441. #endif // _DEBUG
  1442. pasHost->m_pView->m_viewPgSize.x = pasHost->viewExtent.x / 8;
  1443. pasHost->m_pView->m_viewPgSize.y = pasHost->viewExtent.y / 8;
  1444. pasHost->m_pView->m_viewLnSize.x = pasHost->viewExtent.x / 64;
  1445. pasHost->m_pView->m_viewLnSize.y = pasHost->viewExtent.y / 64;
  1446. //
  1447. // Move the scroll position to the origin.
  1448. //
  1449. //
  1450. // Clip the current scroll pos if we need to, now that the extent
  1451. // has changed size.
  1452. //
  1453. VIEWClientScroll(pasHost, pasHost->m_pView->m_viewPos.x, pasHost->m_pView->m_viewPos.y);
  1454. si.cbSize = sizeof(SCROLLINFO);
  1455. si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE|SIF_DISABLENOSCROLL;
  1456. // Set vertical info. Is vert pos out of range now?
  1457. si.nMin = 0;
  1458. si.nMax = pasHost->viewExtent.y - 1;
  1459. si.nPage = pasHost->m_pView->m_viewPage.y;
  1460. si.nPos = pasHost->m_pView->m_viewPos.y;
  1461. ASSERT(si.nPos <= si.nMax);
  1462. TRACE_OUT(("VIEWClientExtentChange: Setting VERT scroll info:"));
  1463. TRACE_OUT(("VIEWClientExtentChange: nMin %04d", si.nMin));
  1464. TRACE_OUT(("VIEWClientExtentChange: nMax %04d", si.nMax));
  1465. TRACE_OUT(("VIEWClientExtentChange: nPage %04d", si.nPage));
  1466. TRACE_OUT(("VIEWClientExtentChange: nPos %04d", si.nPos));
  1467. SetScrollInfo(pasHost->m_pView->m_viewClient, SB_VERT, &si, TRUE );
  1468. // Set horizontal (x) information
  1469. si.nMin = 0;
  1470. si.nMax = pasHost->viewExtent.x - 1;
  1471. si.nPage = pasHost->m_pView->m_viewPage.x;
  1472. si.nPos = pasHost->m_pView->m_viewPos.x;
  1473. ASSERT(si.nPos <= si.nMax);
  1474. TRACE_OUT(("VIEWClientExtentChange: Setting HORZ scroll info:"));
  1475. TRACE_OUT(("VIEWClientExtentChange: nMin %04d", si.nMin));
  1476. TRACE_OUT(("VIEWClientExtentChange: nMax %04d", si.nMax));
  1477. TRACE_OUT(("VIEWClientExtentChange: nPage %04d", si.nPage));
  1478. TRACE_OUT(("VIEWClientExtentChange: nPos %04d", si.nPos));
  1479. SetScrollInfo(pasHost->m_pView->m_viewClient, SB_HORZ, &si, TRUE );
  1480. if (fRedraw)
  1481. {
  1482. // Is the frame window too big now?
  1483. if ( (pasHost->m_pView->m_viewPage.x > pasHost->viewExtent.x) ||
  1484. (pasHost->m_pView->m_viewPage.y > pasHost->viewExtent.y) )
  1485. {
  1486. TRACE_OUT(("VIEWClientExtentChange: client size (%04d, %04d) now bigger than view extent (%04d, %04d)",
  1487. pasHost->m_pView->m_viewPage.x, pasHost->m_pView->m_viewPage.y,
  1488. pasHost->viewExtent.x, pasHost->viewExtent.y));
  1489. //
  1490. // Calculate the ideal size for this window.
  1491. //
  1492. VIEWFrameGetSize(pasHost, &rcl);
  1493. SetWindowPos( pasHost->m_pView->m_viewFrame,
  1494. NULL, 0, 0, rcl.right - rcl.left, rcl.bottom - rcl.top,
  1495. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  1496. }
  1497. TRACE_OUT(("VIEWClientExtentChange: Invalidating client area"));
  1498. VIEW_InvalidateRgn(pasHost, NULL);
  1499. }
  1500. DC_EXIT_POINT:
  1501. DebugExitVOID(ASShare::VIEWClientExtentChange);
  1502. }
  1503. //
  1504. // VIEWFrameWindowProc()
  1505. //
  1506. LRESULT CALLBACK VIEWFrameWindowProc
  1507. (
  1508. HWND hwnd,
  1509. UINT message,
  1510. WPARAM wParam,
  1511. LPARAM lParam
  1512. )
  1513. {
  1514. return(g_asSession.pShare->VIEW_FrameWindowProc(hwnd, message, wParam, lParam));
  1515. }
  1516. LRESULT ASShare::VIEW_FrameWindowProc
  1517. (
  1518. HWND hwnd,
  1519. UINT message,
  1520. WPARAM wParam,
  1521. LPARAM lParam
  1522. )
  1523. {
  1524. LRESULT rc = 0;
  1525. ASPerson * pasHost;
  1526. DebugEntry(VIEW_FrameWindowProc);
  1527. pasHost = (ASPerson *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1528. if (pasHost)
  1529. {
  1530. ValidateView(pasHost);
  1531. }
  1532. switch (message)
  1533. {
  1534. case WM_NCCREATE:
  1535. {
  1536. // Get the passed in host pointer, and set in our window long
  1537. pasHost = (ASPerson *)((LPCREATESTRUCT)lParam)->lpCreateParams;
  1538. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)pasHost);
  1539. pasHost->m_pView->m_viewFrame = hwnd;
  1540. //
  1541. // Set the window icon
  1542. //
  1543. SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)
  1544. ((pasHost->hetCount == HET_DESKTOPSHARED) ?
  1545. g_hetDeskIcon : g_hetASIcon));
  1546. goto DefWndProc;
  1547. break;
  1548. }
  1549. case WM_NCDESTROY:
  1550. {
  1551. if (pasHost != NULL)
  1552. {
  1553. pasHost->m_pView->m_viewFrame = NULL;
  1554. }
  1555. goto DefWndProc;
  1556. break;
  1557. }
  1558. case WM_CREATE:
  1559. {
  1560. // Set title
  1561. VIEW_HostStateChange(pasHost);
  1562. if (!VIEWFrameCreate(pasHost))
  1563. {
  1564. ERROR_OUT(("VIEWFrameWindowProc: errors in creation handling for [%d]", pasHost->mcsID));
  1565. rc = -1;
  1566. }
  1567. break;
  1568. }
  1569. case WM_DESTROY:
  1570. {
  1571. //
  1572. // Clear menu bar; we always destroy it ourself.
  1573. //
  1574. ::SetMenu(hwnd, NULL);
  1575. break;
  1576. }
  1577. case WM_ACTIVATE:
  1578. {
  1579. //
  1580. // If we're switching back to the view of the host we're in
  1581. // control of, update the key states.
  1582. //
  1583. if (wParam)
  1584. {
  1585. SetFocus(pasHost->m_pView->m_viewClient);
  1586. }
  1587. else
  1588. {
  1589. //
  1590. // If we're full screen but are deactivating, kick out of
  1591. // full screenmode.
  1592. //
  1593. if (pasHost->m_pView->m_viewFullScreen)
  1594. {
  1595. // Do this later, so title bar state isn't messed up
  1596. ::PostMessage(hwnd, WM_COMMAND, MAKELONG(CMD_VIEWFULLSCREEN, 0), 0);
  1597. }
  1598. }
  1599. break;
  1600. }
  1601. case WM_ENTERMENULOOP:
  1602. {
  1603. pasHost->m_pView->m_viewInMenuMode = TRUE;
  1604. break;
  1605. }
  1606. case WM_EXITMENULOOP:
  1607. {
  1608. pasHost->m_pView->m_viewInMenuMode = FALSE;
  1609. break;
  1610. }
  1611. case WM_COMMAND:
  1612. {
  1613. VIEWFrameCommand(pasHost, wParam, lParam);
  1614. break;
  1615. }
  1616. case WM_INITMENU:
  1617. {
  1618. if ((HMENU)wParam == pasHost->m_pView->m_viewMenuBar)
  1619. {
  1620. VIEWFrameInitMenuBar(pasHost);
  1621. }
  1622. break;
  1623. }
  1624. case WM_MENUSELECT:
  1625. {
  1626. VIEWFrameOnMenuSelect(pasHost, wParam, lParam);
  1627. break;
  1628. }
  1629. case WM_PALETTECHANGED:
  1630. //
  1631. // The system palette has changed - repaint the window.
  1632. //
  1633. VIEW_InvalidateRgn(pasHost, NULL);
  1634. //
  1635. // The system palette has changed. If we are not the
  1636. // window that triggered this message then realize our
  1637. // palette now to set up our new palette mapping.
  1638. //
  1639. if ((HWND)wParam == hwnd)
  1640. {
  1641. //
  1642. // If this window caused the change return without
  1643. // realizing our logical palette or we could end up in
  1644. // an infinite loop.
  1645. //
  1646. break;
  1647. }
  1648. TRACE_OUT(("Palette changed - fall through to realize palette (%x)",
  1649. hwnd));
  1650. //
  1651. // Do not break here but FALL THROUGH to the code which
  1652. // realizes the remote palette into this window. This allows
  1653. // the window to grab some color entries for itself in the new
  1654. // system palette.
  1655. //
  1656. case WM_QUERYNEWPALETTE:
  1657. rc = FALSE;
  1658. if (message == WM_QUERYNEWPALETTE)
  1659. {
  1660. TRACE_OUT(( "WM_QUERYNEWPALETTE hwnd(%x)", hwnd));
  1661. }
  1662. if (g_usrPalettized)
  1663. {
  1664. HDC hdc;
  1665. HPALETTE hPalOld;
  1666. UINT cChangedEntries;
  1667. //
  1668. // Realize this window's palette, and force a repaint
  1669. // if necessary.
  1670. //
  1671. hdc = GetDC(hwnd);
  1672. hPalOld = SelectPalette(hdc, pasHost->pmPalette, FALSE);
  1673. cChangedEntries = RealizePalette(hdc);
  1674. SelectPalette(hdc, hPalOld, FALSE);
  1675. ReleaseDC(hwnd, hdc);
  1676. rc = (cChangedEntries > 0);
  1677. if (rc)
  1678. {
  1679. // Have to repaint this window
  1680. VIEW_InvalidateRgn(pasHost, NULL);
  1681. }
  1682. }
  1683. break;
  1684. case WM_GETMINMAXINFO:
  1685. {
  1686. RECT rc;
  1687. LPMINMAXINFO lpmmi = (LPMINMAXINFO) lParam;
  1688. int cx,cy;
  1689. if (!pasHost)
  1690. {
  1691. // We're not created yet; bail.
  1692. break;
  1693. }
  1694. //
  1695. // Calculate the ideal maximized size for this window
  1696. //
  1697. VIEWFrameGetSize(pasHost, &rc);
  1698. //
  1699. // If it's bigger than the local screen, clip it.
  1700. //
  1701. cx = min(rc.right - rc.left, m_pasLocal->cpcCaps.screen.capsScreenWidth);
  1702. cy = min(rc.bottom - rc.top, m_pasLocal->cpcCaps.screen.capsScreenHeight);
  1703. lpmmi->ptMaxSize.x = cx;
  1704. lpmmi->ptMaxSize.y = cy;
  1705. lpmmi->ptMaxTrackSize.x = cx;
  1706. lpmmi->ptMaxTrackSize.y = cy;
  1707. //
  1708. // Make sure that we don't size this window too narrow. Keep
  1709. // space for borders and one window bar button + scroll ctl.
  1710. //
  1711. lpmmi->ptMinTrackSize.x = 2*::GetSystemMetrics(SM_CXSIZEFRAME) +
  1712. (m_viewItemCX + m_viewEdgeCX) + m_viewItemScrollCX;
  1713. //
  1714. // And prevent sizing too short. Keep space for borders, menu
  1715. // bar, status bar, and window bar
  1716. //
  1717. lpmmi->ptMinTrackSize.y = 2*::GetSystemMetrics(SM_CYSIZEFRAME) +
  1718. ::GetSystemMetrics(SM_CYCAPTION) + ::GetSystemMetrics(SM_CYMENU);
  1719. if (pasHost->m_pView->m_viewWindowBarOn)
  1720. {
  1721. lpmmi->ptMinTrackSize.y += m_viewWindowBarCY + m_viewEdgeCY;
  1722. }
  1723. if (pasHost->m_pView->m_viewStatusBarOn)
  1724. {
  1725. lpmmi->ptMinTrackSize.y += m_viewStatusBarCY + m_viewEdgeCY;
  1726. }
  1727. break;
  1728. }
  1729. case WM_SIZE:
  1730. {
  1731. if (wParam != SIZE_MINIMIZED)
  1732. {
  1733. VIEWFrameResize(pasHost);
  1734. }
  1735. break;
  1736. }
  1737. default:
  1738. DefWndProc:
  1739. rc = DefWindowProc(hwnd, message, wParam, lParam);
  1740. break;
  1741. }
  1742. DebugExitDWORD(ASShare::VIEW_FrameWindowProc, rc);
  1743. return(rc);
  1744. }
  1745. //
  1746. // VIEWFrameCreate()
  1747. //
  1748. BOOL ASShare::VIEWFrameCreate(ASPerson * pasPerson)
  1749. {
  1750. RECT rect;
  1751. BOOL rc = FALSE;
  1752. DebugEntry(VIEWFrameCreate);
  1753. ValidateView(pasPerson);
  1754. //
  1755. // Creates the children which lie in the frame's client:
  1756. // * the toolbar hugs the top
  1757. // * the statusbar hugs the bottom
  1758. // * the tray hugs the left underneath the toolbar and above the
  1759. // statusbar
  1760. // * the view fills in what's left
  1761. //
  1762. GetClientRect(pasPerson->m_pView->m_viewFrame, &rect);
  1763. //
  1764. // Create the statusbar (hugs bottom)
  1765. //
  1766. pasPerson->m_pView->m_viewStatusBar = ::CreateWindowEx(0, STATUSCLASSNAME,
  1767. NULL, WS_CHILD | WS_VISIBLE | CCS_NOPARENTALIGN | CCS_NOMOVEY | CCS_NORESIZE |
  1768. SBARS_SIZEGRIP,
  1769. rect.left, rect.bottom - m_viewStatusBarCY, rect.right - rect.left,
  1770. m_viewStatusBarCY, pasPerson->m_pView->m_viewFrame, NULL, g_asInstance,
  1771. NULL);
  1772. if (!pasPerson->m_pView->m_viewStatusBar)
  1773. {
  1774. ERROR_OUT(("Couldn't create statusbar for frame of person [%d]", pasPerson->mcsID));
  1775. DC_QUIT;
  1776. }
  1777. rect.bottom -= m_viewStatusBarCY + m_viewEdgeCY;
  1778. //
  1779. // Create the tray (hugs top of status bar, bottom of view)
  1780. // BUT NOT FOR DESKTOP SHARING
  1781. //
  1782. if (pasPerson->hetCount != HET_DESKTOPSHARED)
  1783. {
  1784. pasPerson->m_pView->m_viewWindowBar = ::CreateWindowEx(0,
  1785. VIEW_WINDOWBAR_CLASS_NAME, NULL,
  1786. WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE | WS_CHILD,
  1787. rect.left, rect.bottom - m_viewWindowBarCY,
  1788. rect.right - rect.left, m_viewWindowBarCY,
  1789. pasPerson->m_pView->m_viewFrame, NULL, g_asInstance, pasPerson);
  1790. if (!pasPerson->m_pView->m_viewWindowBar)
  1791. {
  1792. ERROR_OUT(("VIEWFrameCreate: Failed to create window bar"));
  1793. DC_QUIT;
  1794. }
  1795. // Subtract tray space + an edge above it of margin
  1796. rect.bottom -= m_viewWindowBarCY + m_viewEdgeCY;
  1797. }
  1798. //
  1799. // Create the view (takes up rest of client)
  1800. //
  1801. if (!CreateWindowEx(WS_EX_CLIENTEDGE,
  1802. VIEW_CLIENT_CLASS_NAME, NULL,
  1803. WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE | WS_CHILD |
  1804. WS_VSCROLL | WS_HSCROLL,
  1805. rect.left, rect.top,
  1806. rect.right - rect.left, rect.bottom - rect.top,
  1807. pasPerson->m_pView->m_viewFrame,
  1808. NULL, g_asInstance, pasPerson))
  1809. {
  1810. ERROR_OUT(("VIEWFrameCreate: Failed to create view"));
  1811. DC_QUIT;
  1812. }
  1813. rc = TRUE;
  1814. DC_EXIT_POINT:
  1815. DebugExitBOOL(ASShare::VIEWFrameCreate, rc);
  1816. return(rc);
  1817. }
  1818. //
  1819. // VIEWFrameResize()
  1820. // Repositions the child windows when the frame is resized.
  1821. //
  1822. void ASShare::VIEWFrameResize(ASPerson * pasPerson)
  1823. {
  1824. RECT rect;
  1825. DebugEntry(ASShare::VIEWFrameResize);
  1826. ValidateView(pasPerson);
  1827. GetClientRect(pasPerson->m_pView->m_viewFrame, &rect);
  1828. //
  1829. // Move the statusbar
  1830. //
  1831. if ((pasPerson->m_pView->m_viewStatusBar != NULL) &&
  1832. (pasPerson->m_pView->m_viewStatusBarOn))
  1833. {
  1834. MoveWindow(pasPerson->m_pView->m_viewStatusBar, rect.left,
  1835. rect.bottom - m_viewStatusBarCY, rect.right - rect.left,
  1836. m_viewStatusBarCY, TRUE);
  1837. rect.bottom -= m_viewStatusBarCY + m_viewEdgeCY;
  1838. }
  1839. //
  1840. // Move the tray
  1841. //
  1842. if ((pasPerson->m_pView->m_viewWindowBar != NULL) &&
  1843. (pasPerson->m_pView->m_viewWindowBarOn))
  1844. {
  1845. MoveWindow(pasPerson->m_pView->m_viewWindowBar, rect.left,
  1846. rect.bottom - m_viewWindowBarCY, rect.right - rect.left,
  1847. m_viewWindowBarCY, TRUE);
  1848. rect.bottom -= m_viewWindowBarCY + m_viewEdgeCY;
  1849. }
  1850. //
  1851. // Move the view
  1852. //
  1853. MoveWindow(pasPerson->m_pView->m_viewClient, rect.left, rect.top,
  1854. rect.right - rect.left, rect.bottom - rect.top, TRUE);
  1855. DebugExitVOID(ASShare::VIEWFrameResize);
  1856. }
  1857. //
  1858. // VIEWFrameResizeChanged()
  1859. //
  1860. // Called when the widgets of the frame (the status bar, the window bar, etc.)
  1861. // come or go. We may need to shrink the window, if the view is going
  1862. // to end up being bigger than the host's desktop.
  1863. //
  1864. void ASShare::VIEWFrameResizeChanged(ASPerson * pasHost)
  1865. {
  1866. RECT rcView;
  1867. DebugEntry(ASShare::VIEWFrameResizeChanged);
  1868. // Get current view size
  1869. GetClientRect(pasHost->m_pView->m_viewClient, &rcView);
  1870. //
  1871. // The view area can't be bigger than the remote's desktop area
  1872. //
  1873. if ((rcView.bottom - rcView.top) >= pasHost->viewExtent.y)
  1874. {
  1875. RECT rcWindowCur;
  1876. RECT rcWindowMax;
  1877. // Get current frame size
  1878. GetWindowRect(pasHost->m_pView->m_viewFrame, &rcWindowCur);
  1879. // Get maximum frame size
  1880. VIEWFrameGetSize(pasHost, &rcWindowMax);
  1881. // Resize vertically to just hold everything
  1882. SetWindowPos(pasHost->m_pView->m_viewFrame, NULL, 0, 0,
  1883. rcWindowCur.right - rcWindowCur.left,
  1884. rcWindowMax.bottom - rcWindowMax.top,
  1885. SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
  1886. }
  1887. else
  1888. {
  1889. // We can stay the same size, and just shuffle the pieces around
  1890. VIEWFrameResize(pasHost);
  1891. }
  1892. DebugExitVOID(ASShare::VIEWFrameResizeChanged);
  1893. }
  1894. //
  1895. // VIEWFrameCommand()
  1896. //
  1897. // Handles commands from menus/accelerators for frame views
  1898. //
  1899. void ASShare::VIEWFrameCommand
  1900. (
  1901. ASPerson* pasHost,
  1902. WPARAM wParam,
  1903. LPARAM lParam
  1904. )
  1905. {
  1906. UINT cmd;
  1907. MENUITEMINFO mi;
  1908. DebugEntry(ASShare::VIEWFrameCommand);
  1909. ValidateView(pasHost);
  1910. cmd = GET_WM_COMMAND_ID(wParam, lParam);
  1911. switch (cmd)
  1912. {
  1913. case CMD_TAKECONTROL:
  1914. {
  1915. CA_TakeControl(pasHost);
  1916. break;
  1917. }
  1918. case CMD_CANCELCONTROL:
  1919. {
  1920. CA_CancelTakeControl(pasHost, TRUE);
  1921. break;
  1922. }
  1923. case CMD_RELEASECONTROL:
  1924. {
  1925. CA_ReleaseControl(pasHost, TRUE);
  1926. break;
  1927. }
  1928. case CMD_CTRLALTDEL:
  1929. {
  1930. AWC_SendMsg(pasHost->mcsID, AWC_MSG_SAS, 0, 0);
  1931. break;
  1932. }
  1933. case CMD_VIEWSTATUSBAR:
  1934. {
  1935. ASSERT(::IsWindow(pasHost->m_pView->m_viewStatusBar));
  1936. // Toggle show/hide of status bar, then resize
  1937. if (pasHost->m_pView->m_viewStatusBarOn)
  1938. {
  1939. pasHost->m_pView->m_viewStatusBarOn = FALSE;
  1940. ::ShowWindow(pasHost->m_pView->m_viewStatusBar, SW_HIDE);
  1941. }
  1942. else
  1943. {
  1944. pasHost->m_pView->m_viewStatusBarOn = TRUE;
  1945. ::ShowWindow(pasHost->m_pView->m_viewStatusBar, SW_SHOW);
  1946. }
  1947. VIEWFrameResizeChanged(pasHost);
  1948. break;
  1949. }
  1950. case CMD_VIEWWINDOWBAR:
  1951. {
  1952. ASSERT(::IsWindow(pasHost->m_pView->m_viewWindowBar));
  1953. // Toggle show/hide of window bar, then resize
  1954. if (pasHost->m_pView->m_viewWindowBarOn)
  1955. {
  1956. pasHost->m_pView->m_viewWindowBarOn = FALSE;
  1957. ::ShowWindow(pasHost->m_pView->m_viewWindowBar, SW_HIDE);
  1958. }
  1959. else
  1960. {
  1961. pasHost->m_pView->m_viewWindowBarOn = TRUE;
  1962. ::ShowWindow(pasHost->m_pView->m_viewWindowBar, SW_SHOW);
  1963. }
  1964. VIEWFrameResizeChanged(pasHost);
  1965. break;
  1966. }
  1967. case CMD_VIEWFULLSCREEN:
  1968. {
  1969. VIEWFrameFullScreen(pasHost, (pasHost->m_pView->m_viewFullScreen == 0));
  1970. break;
  1971. }
  1972. case CMD_HELPTOPICS:
  1973. {
  1974. VIEWFrameHelp(pasHost);
  1975. break;
  1976. }
  1977. case CMD_HELPABOUT:
  1978. {
  1979. VIEWFrameAbout(pasHost);
  1980. break;
  1981. }
  1982. default:
  1983. {
  1984. if ((cmd >= CMD_APPSTART) && (cmd < CMD_APPMAX))
  1985. {
  1986. if ((pasHost->m_caControlledBy == m_pasLocal) &&
  1987. !pasHost->m_caControlPaused)
  1988. {
  1989. //
  1990. // This is a request to activate a host window.
  1991. // Get the item data, the remote HWND, then look to see
  1992. // if it's still on the tray.
  1993. //
  1994. ZeroMemory(&mi, sizeof(mi));
  1995. mi.cbSize = sizeof(mi);
  1996. mi.fMask = MIIM_DATA;
  1997. GetMenuItemInfo(GetSubMenu(pasHost->m_pView->m_viewMenuBar,
  1998. IDSM_WINDOW), cmd, FALSE, &mi);
  1999. if (!mi.dwItemData)
  2000. {
  2001. ERROR_OUT(("No item data for command %d", cmd));
  2002. }
  2003. else
  2004. {
  2005. PWNDBAR_ITEM pItem;
  2006. COM_BasedListFind(LIST_FIND_FROM_FIRST,
  2007. &(pasHost->m_pView->m_viewWindowBarItems),
  2008. (void**)&pItem, FIELD_OFFSET(WNDBAR_ITEM, chain),
  2009. FIELD_OFFSET(WNDBAR_ITEM, winIDRemote),
  2010. mi.dwItemData, FIELD_SIZE(WNDBAR_ITEM, winIDRemote));
  2011. if (pItem)
  2012. {
  2013. VIEWWindowBarDoActivate(pasHost, pItem);
  2014. }
  2015. }
  2016. }
  2017. }
  2018. else if ((cmd >= CMD_FORWARDCONTROLSTART) && (cmd < CMD_FORWARDCONTROLMAX))
  2019. {
  2020. if ((pasHost->m_caControlledBy == m_pasLocal) &&
  2021. !pasHost->m_caControlPaused)
  2022. {
  2023. //
  2024. // This is a request to pass control. Get the item data,
  2025. // the remote's MCS ID, then look to see if this person is
  2026. // still in the share. If so, pass control to them.
  2027. //
  2028. ZeroMemory(&mi, sizeof(mi));
  2029. mi.cbSize = sizeof(mi);
  2030. mi.fMask = MIIM_DATA;
  2031. GetMenuItemInfo(GetSubMenu(GetSubMenu(pasHost->m_pView->m_viewMenuBar,
  2032. IDSM_CONTROL), POS_FORWARDCONTROLCMD), cmd, FALSE, &mi);
  2033. if (!mi.dwItemData)
  2034. {
  2035. ERROR_OUT(("No item data for command %d", cmd));
  2036. }
  2037. else
  2038. {
  2039. ASPerson * pasT;
  2040. if (SC_ValidateNetID((MCSID)mi.dwItemData, &pasT))
  2041. {
  2042. CA_PassControl(pasHost, pasT);
  2043. }
  2044. }
  2045. }
  2046. }
  2047. else
  2048. {
  2049. ERROR_OUT(("Unrecognized WM_COMMAND id"));
  2050. }
  2051. break;
  2052. }
  2053. }
  2054. DebugExitVOID(ASShare::VIEWFrameCommand);
  2055. }
  2056. //
  2057. // ASShare::VIEWFrameInitMenuBar()
  2058. //
  2059. void ASShare::VIEWFrameInitMenuBar(ASPerson* pasHost)
  2060. {
  2061. HMENU hMenu;
  2062. HMENU hSubMenu;
  2063. int iItem;
  2064. MENUITEMINFO mi;
  2065. UINT cmd;
  2066. UINT ids;
  2067. UINT flags;
  2068. char szItem[256];
  2069. DebugEntry(ASShare::VIEWFrameInitMenu);
  2070. ValidateView(pasHost);
  2071. hMenu = pasHost->m_pView->m_viewMenuBar;
  2072. ASSERT(hMenu);
  2073. //
  2074. // CONTROL MENU
  2075. //
  2076. cmd = CMD_TAKECONTROL;
  2077. ids = IDS_CMD_TAKECONTROL;
  2078. flags = MF_ENABLED;
  2079. if (pasHost->m_caControlledBy == m_pasLocal)
  2080. {
  2081. ASSERT(pasHost->m_caAllowControl);
  2082. cmd = CMD_RELEASECONTROL;
  2083. ids = IDS_CMD_RELEASECONTROL;
  2084. //
  2085. // If the remote is unattended and we're in control, no releasing.
  2086. //
  2087. if (pasHost->cpcCaps.general.typeFlags & AS_UNATTENDED)
  2088. flags = MF_GRAYED;
  2089. }
  2090. else if ((m_caWaitingForReplyFrom == pasHost) &&
  2091. (m_caWaitingForReplyMsg == CA_REPLY_REQUEST_TAKECONTROL))
  2092. {
  2093. ASSERT(pasHost->m_caAllowControl);
  2094. cmd = CMD_CANCELCONTROL;
  2095. ids = IDS_CMD_CANCELCONTROL;
  2096. }
  2097. else if (!pasHost->m_caAllowControl || pasHost->m_caControlledBy)
  2098. {
  2099. //
  2100. // Host isn't allowing control, or somebody else is in control right
  2101. // now.
  2102. //
  2103. flags = MF_GRAYED;
  2104. }
  2105. flags |= MF_STRING | MF_BYPOSITION;
  2106. ::LoadString(g_asInstance, ids, szItem, sizeof(szItem));
  2107. hSubMenu = GetSubMenu(hMenu, IDSM_CONTROL);
  2108. ModifyMenu(hSubMenu, POS_CONTROLCMD, flags, cmd, szItem);
  2109. //
  2110. // If we're in control, and there's another 3.0 dude in the conference,
  2111. // enable PassControl and build the popup.
  2112. //
  2113. EnableMenuItem(hSubMenu, POS_FORWARDCONTROLCMD, MF_GRAYED | MF_BYPOSITION);
  2114. if ((pasHost->m_caControlledBy == m_pasLocal) &&
  2115. !pasHost->m_caControlPaused &&
  2116. (pasHost->cpcCaps.general.version >= CAPS_VERSION_30))
  2117. {
  2118. ASPerson * pasT;
  2119. HMENU hPassMenu;
  2120. hPassMenu = GetSubMenu(hSubMenu, POS_FORWARDCONTROLCMD);
  2121. ASSERT(IsMenu(hPassMenu));
  2122. //
  2123. // Delete existing items.
  2124. //
  2125. iItem = GetMenuItemCount(hPassMenu);
  2126. while (iItem > 0)
  2127. {
  2128. iItem--;
  2129. DeleteMenu(hPassMenu, iItem, MF_BYPOSITION);
  2130. }
  2131. //
  2132. // Add items for the other 3.0 nodes besides us & the host.
  2133. //
  2134. iItem = CMD_FORWARDCONTROLSTART;
  2135. pasT = m_pasLocal->pasNext;
  2136. while (pasT != NULL)
  2137. {
  2138. if ((pasT != pasHost) &&
  2139. (pasT->cpcCaps.general.version >= CAPS_VERSION_30))
  2140. {
  2141. //
  2142. // This dude is a candidate. We must store the MCS IDs since the
  2143. // any person could go away while we're in menu mode.
  2144. //
  2145. ZeroMemory(&mi, sizeof(mi));
  2146. mi.cbSize = sizeof(mi);
  2147. mi.fMask = MIIM_ID | MIIM_STATE | MIIM_TYPE | MIIM_DATA;
  2148. mi.fType = MFT_STRING;
  2149. mi.fState = MFS_ENABLED;
  2150. mi.wID = iItem;
  2151. mi.dwItemData = pasT->mcsID;
  2152. mi.dwTypeData = pasT->scName;
  2153. mi.cch = lstrlen(pasT->scName);
  2154. //
  2155. // Append this to the menu
  2156. //
  2157. InsertMenuItem(hPassMenu, -1, TRUE, &mi);
  2158. iItem++;
  2159. }
  2160. pasT = pasT->pasNext;
  2161. }
  2162. //
  2163. // Enable the Pass Control submenu if there's somebody on the
  2164. // menu.
  2165. //
  2166. if (iItem != CMD_FORWARDCONTROLSTART)
  2167. {
  2168. EnableMenuItem(hSubMenu, POS_FORWARDCONTROLCMD, MF_ENABLED | MF_BYPOSITION);
  2169. }
  2170. }
  2171. //
  2172. // APPLICATIONS MENU
  2173. //
  2174. if ((pasHost->hetCount != HET_DESKTOPSHARED) &&
  2175. (pasHost->m_caControlledBy == m_pasLocal) &&
  2176. !pasHost->m_caControlPaused)
  2177. {
  2178. PWNDBAR_ITEM pItem;
  2179. hSubMenu = GetSubMenu(hMenu, IDSM_WINDOW);
  2180. //
  2181. // Delete existing items.
  2182. //
  2183. iItem = GetMenuItemCount(hSubMenu);
  2184. while (iItem > 0)
  2185. {
  2186. iItem--;
  2187. DeleteMenu(hSubMenu, iItem, MF_BYPOSITION);
  2188. }
  2189. //
  2190. // Add window bar items.
  2191. //
  2192. iItem = CMD_APPSTART;
  2193. pItem = (PWNDBAR_ITEM)COM_BasedListFirst(&(pasHost->m_pView->m_viewWindowBarItems),
  2194. FIELD_OFFSET(WNDBAR_ITEM, chain));
  2195. while (pItem && (iItem < CMD_APPMAX))
  2196. {
  2197. ZeroMemory(&mi, sizeof(mi));
  2198. mi.cbSize = sizeof(mi);
  2199. mi.fMask = MIIM_ID | MIIM_STATE | MIIM_TYPE | MIIM_DATA;
  2200. mi.fType = MFT_STRING;
  2201. mi.fState = MFS_ENABLED;
  2202. if (pItem == pasHost->m_pView->m_viewWindowBarActiveItem)
  2203. {
  2204. mi.fState |= MFS_CHECKED;
  2205. }
  2206. mi.wID = iItem;
  2207. mi.dwItemData = pItem->winIDRemote;
  2208. mi.dwTypeData = pItem->szText;
  2209. mi.cch = lstrlen(pItem->szText);
  2210. //
  2211. // Append this to the menu
  2212. //
  2213. InsertMenuItem(hSubMenu, -1, TRUE, &mi);
  2214. iItem++;
  2215. pItem = (PWNDBAR_ITEM)COM_BasedListNext(&(pasHost->m_pView->m_viewWindowBarItems),
  2216. pItem, FIELD_OFFSET(WNDBAR_ITEM, chain));
  2217. }
  2218. if (iItem == CMD_APPSTART)
  2219. {
  2220. char szBlank[128];
  2221. //
  2222. // Append a disabled, blank item
  2223. //
  2224. ZeroMemory(&mi, sizeof(mi));
  2225. mi.cbSize = sizeof(mi);
  2226. mi.fMask = MIIM_ID | MIIM_STATE | MIIM_TYPE;
  2227. mi.fType = MFT_STRING;
  2228. mi.fState = MFS_DISABLED;
  2229. mi.wID = iItem;
  2230. LoadString(g_asInstance, IDS_CMD_BLANKPROGRAM, szBlank, sizeof(szBlank));
  2231. mi.dwTypeData = szBlank;
  2232. mi.cch = lstrlen(szBlank);
  2233. InsertMenuItem(hSubMenu, -1, TRUE, &mi);
  2234. }
  2235. }
  2236. //
  2237. // VIEW MENU
  2238. //
  2239. // Status bar
  2240. ASSERT(::IsWindow(pasHost->m_pView->m_viewStatusBar));
  2241. if (pasHost->m_pView->m_viewStatusBarOn)
  2242. {
  2243. ::CheckMenuItem(hMenu, CMD_VIEWSTATUSBAR, MF_CHECKED | MF_BYCOMMAND);
  2244. }
  2245. else
  2246. {
  2247. ::CheckMenuItem(hMenu, CMD_VIEWSTATUSBAR, MF_UNCHECKED | MF_BYCOMMAND);
  2248. }
  2249. // Window bar
  2250. if (!pasHost->m_pView->m_viewWindowBar)
  2251. {
  2252. ::EnableMenuItem(hMenu, CMD_VIEWWINDOWBAR, MF_GRAYED | MF_BYCOMMAND);
  2253. }
  2254. else if (pasHost->m_pView->m_viewWindowBarOn)
  2255. {
  2256. ::CheckMenuItem(hMenu, CMD_VIEWWINDOWBAR, MF_CHECKED | MF_BYCOMMAND);
  2257. }
  2258. else
  2259. {
  2260. ::CheckMenuItem(hMenu, CMD_VIEWWINDOWBAR, MF_UNCHECKED | MF_BYCOMMAND);
  2261. }
  2262. DebugExitVOID(ASShare::VIEWFrameInitMenu);
  2263. }
  2264. //
  2265. // VIEWFrameOnMenuSelect()
  2266. //
  2267. void ASShare::VIEWFrameOnMenuSelect
  2268. (
  2269. ASPerson * pasHost,
  2270. WPARAM wParam,
  2271. LPARAM lParam
  2272. )
  2273. {
  2274. HMENU hMenu;
  2275. int uItem;
  2276. UINT flags;
  2277. UINT idsStatus = IDS_STATUS_NONE;
  2278. DebugEntry(ASShare::VIEWFrameOnMenuSelect);
  2279. //
  2280. // Extract the params out (menuselect is messy)
  2281. //
  2282. hMenu = (HMENU)lParam;
  2283. uItem = (int)LOWORD(wParam);
  2284. if ((short)HIWORD(wParam) == -1)
  2285. {
  2286. flags = 0xFFFFFFFF;
  2287. }
  2288. else
  2289. {
  2290. flags = HIWORD(wParam);
  2291. }
  2292. if ((LOWORD(flags) == 0xFFFF) && !hMenu)
  2293. {
  2294. // Menu mode is ending. Put back original status.
  2295. idsStatus = pasHost->m_pView->m_viewStatus;
  2296. DC_QUIT;
  2297. }
  2298. if (!(flags & MF_POPUP))
  2299. {
  2300. if (flags & MF_SEPARATOR)
  2301. {
  2302. // No status
  2303. }
  2304. else if (flags & MF_SYSMENU)
  2305. {
  2306. // No status
  2307. }
  2308. else if ((uItem >= CMD_APPSTART) && (uItem < CMD_APPMAX))
  2309. {
  2310. // One of an unbounded set of items in the Window popup
  2311. idsStatus = IDS_STATUS_CMDS_APP;
  2312. }
  2313. else if ((uItem >= CMD_FORWARDCONTROLSTART) && (uItem < CMD_FORWARDCONTROLMAX))
  2314. {
  2315. // One of an unbounded set of items in the Forward Control popup
  2316. idsStatus = IDS_STATUS_CMDS_FORWARD;
  2317. }
  2318. else
  2319. {
  2320. // A normal command, just add offset to CMD id
  2321. idsStatus = uItem + IDS_STATUS_CMD_START;
  2322. }
  2323. }
  2324. else
  2325. {
  2326. // This is a popup menu
  2327. if (hMenu == pasHost->m_pView->m_viewMenuBar)
  2328. {
  2329. // It's a popup from the top level menu bar. uItem is the index
  2330. switch (uItem)
  2331. {
  2332. case IDSM_CONTROL:
  2333. idsStatus = IDS_STATUS_MENU_CONTROL;
  2334. break;
  2335. case IDSM_VIEW:
  2336. idsStatus = IDS_STATUS_MENU_VIEW;
  2337. break;
  2338. case IDSM_WINDOW:
  2339. idsStatus = IDS_STATUS_MENU_WINDOW;
  2340. break;
  2341. case IDSM_HELP:
  2342. idsStatus = IDS_STATUS_MENU_HELP;
  2343. break;
  2344. default:
  2345. ERROR_OUT(("AS: Unknown submenu index %d of frame", uItem));
  2346. break;
  2347. }
  2348. }
  2349. else if (hMenu == GetSubMenu(pasHost->m_pView->m_viewMenuBar, IDSM_CONTROL))
  2350. {
  2351. // This is a popup off the Control menu. The only one we have is Forward
  2352. idsStatus = IDS_STATUS_MENU_FORWARDCONTROL;
  2353. }
  2354. else if (flags & MF_SYSMENU)
  2355. {
  2356. // System menu
  2357. }
  2358. }
  2359. DC_EXIT_POINT:
  2360. VIEWFrameSetStatus(pasHost, idsStatus);
  2361. DebugEntry(ASShare::VIEWFrameOnMenuSelect);
  2362. }
  2363. //
  2364. // VIEWFrameHelp()
  2365. //
  2366. void ASShare::VIEWFrameHelp(ASPerson * pasHost)
  2367. {
  2368. DebugEntry(ASShare::VIEWFrameHelp);
  2369. ShowNmHelp(s_cszHtmlHelpFile);
  2370. DebugExitVOID(ASShare::VIEWFrameHelp);
  2371. }
  2372. //
  2373. // VIEWFrameAbout()
  2374. //
  2375. void ASShare::VIEWFrameAbout(ASPerson * pasHost)
  2376. {
  2377. DebugEntry(ASShare::VIEWFrameAbout);
  2378. //
  2379. // We make use of the standard centered-disabled-goes-away properly
  2380. // VIEW_Message() stuff.
  2381. //
  2382. VIEW_Message(pasHost, IDS_ABOUT);
  2383. DebugExitVOID(ASShare::VIEWFrameAbout);
  2384. }
  2385. //
  2386. // VIEWFrameGetSize()
  2387. // This returns back a rectangle for the ideal size of the frame. It will
  2388. // fit the view, menu, tools, tray, status, etc.
  2389. //
  2390. void ASShare::VIEWFrameGetSize(ASPerson * pasPerson, LPRECT lprc)
  2391. {
  2392. DebugEntry(ASShare::VIEWFrameGetSize);
  2393. ValidateView(pasPerson);
  2394. VIEWClientGetSize(pasPerson, lprc);
  2395. //
  2396. // Add in space for tray.
  2397. // NOTE that for DESKTOP SHARING we don't have a tray
  2398. //
  2399. if (pasPerson->m_pView->m_viewWindowBarOn)
  2400. {
  2401. lprc->bottom += m_viewWindowBarCY + m_viewEdgeCY;
  2402. }
  2403. //
  2404. // Add in space for statusbar if it's on, etc.
  2405. //
  2406. if (pasPerson->m_pView->m_viewStatusBarOn)
  2407. {
  2408. lprc->bottom += m_viewStatusBarCY + m_viewEdgeCY;
  2409. }
  2410. if (!pasPerson->m_pView->m_viewFullScreen)
  2411. {
  2412. //
  2413. // Adjust for frame styles including menu bar.
  2414. //
  2415. AdjustWindowRectEx(lprc, WS_OVERLAPPEDWINDOW, TRUE, WS_EX_WINDOWEDGE);
  2416. }
  2417. DebugExitVOID(ASShare::VIEWFrameGetSize);
  2418. }
  2419. //
  2420. // VIEWFrameFullScreen()
  2421. //
  2422. // This puts into or out of screen mode. We remove all the frame goop
  2423. // including scrollbars, so that the view area is identical to the screen.
  2424. //
  2425. void ASShare::VIEWFrameFullScreen(ASPerson * pasPerson, BOOL fFull)
  2426. {
  2427. LONG lStyle;
  2428. RECT rcNew;
  2429. DebugEntry(ASShare::VIEWFrameFullScreen);
  2430. //
  2431. // Turn redraw OFF
  2432. //
  2433. ::SendMessage(pasPerson->m_pView->m_viewFrame, WM_SETREDRAW, FALSE, 0);
  2434. if (fFull)
  2435. {
  2436. //
  2437. // We're going into full screen mode.
  2438. //
  2439. ASSERT(!pasPerson->m_pView->m_viewFullScreen);
  2440. pasPerson->m_pView->m_viewFullScreen = TRUE;
  2441. //
  2442. // Save old window rect
  2443. //
  2444. ::GetWindowRect(pasPerson->m_pView->m_viewFrame,
  2445. &pasPerson->m_pView->m_viewSavedWindowRect);
  2446. //
  2447. // Save old scroll pos and set to the origin. Do this BEFORE
  2448. // clearing style bits.
  2449. //
  2450. pasPerson->m_pView->m_viewSavedPos = pasPerson->m_pView->m_viewPos;
  2451. VIEWClientScroll(pasPerson, 0, 0);
  2452. //
  2453. // Save current status bar state before turning it off temporarily.
  2454. //
  2455. if (pasPerson->m_pView->m_viewStatusBarOn)
  2456. {
  2457. pasPerson->m_pView->m_viewSavedStatusBarOn = TRUE;
  2458. pasPerson->m_pView->m_viewStatusBarOn = FALSE;
  2459. ::ShowWindow(pasPerson->m_pView->m_viewStatusBar, SW_HIDE);
  2460. }
  2461. else
  2462. {
  2463. pasPerson->m_pView->m_viewSavedStatusBarOn = FALSE;
  2464. }
  2465. //
  2466. // Save current window bar state before turning it off temporarily.
  2467. //
  2468. if (pasPerson->m_pView->m_viewWindowBarOn)
  2469. {
  2470. pasPerson->m_pView->m_viewSavedWindowBarOn = TRUE;
  2471. pasPerson->m_pView->m_viewWindowBarOn = FALSE;
  2472. ::ShowWindow(pasPerson->m_pView->m_viewWindowBar, SW_HIDE);
  2473. }
  2474. else
  2475. {
  2476. pasPerson->m_pView->m_viewSavedWindowBarOn = FALSE;
  2477. }
  2478. //
  2479. // Remove all frame and client bits.
  2480. //
  2481. lStyle = ::GetWindowLong(pasPerson->m_pView->m_viewFrame, GWL_EXSTYLE);
  2482. lStyle &= ~WS_EX_WINDOWEDGE;
  2483. ::SetWindowLong(pasPerson->m_pView->m_viewFrame, GWL_EXSTYLE, lStyle);
  2484. lStyle = ::GetWindowLong(pasPerson->m_pView->m_viewFrame, GWL_STYLE);
  2485. lStyle &= ~(WS_CAPTION | WS_THICKFRAME);
  2486. lStyle |= WS_POPUP;
  2487. ::SetWindowLong(pasPerson->m_pView->m_viewFrame, GWL_STYLE, lStyle);
  2488. lStyle = ::GetWindowLong(pasPerson->m_pView->m_viewClient, GWL_EXSTYLE);
  2489. lStyle &= ~WS_EX_CLIENTEDGE;
  2490. ::SetWindowLong(pasPerson->m_pView->m_viewClient, GWL_EXSTYLE, lStyle);
  2491. lStyle = ::GetWindowLong(pasPerson->m_pView->m_viewClient, GWL_STYLE);
  2492. lStyle &= ~(WS_HSCROLL | WS_VSCROLL);
  2493. ::SetWindowLong(pasPerson->m_pView->m_viewClient, GWL_STYLE, lStyle);
  2494. //
  2495. // Remove the menu bar
  2496. //
  2497. ::SetMenu(pasPerson->m_pView->m_viewFrame, NULL);
  2498. //
  2499. // Set up to size window the size of the screen.
  2500. //
  2501. rcNew.left = 0;
  2502. rcNew.top = 0;
  2503. rcNew.right = m_pasLocal->cpcCaps.screen.capsScreenWidth;
  2504. rcNew.bottom = m_pasLocal->cpcCaps.screen.capsScreenHeight;
  2505. //
  2506. // Create the moveable escape-out button in the lower right corner.
  2507. //
  2508. ::CreateWindowEx(0, VIEW_FULLEXIT_CLASS_NAME, NULL,
  2509. WS_CHILD | WS_VISIBLE,
  2510. rcNew.right - m_viewFullScreenCX - 2*m_viewEdgeCX,
  2511. rcNew.top + 2*m_viewEdgeCY,
  2512. m_viewFullScreenCX, m_viewFullScreenCY,
  2513. pasPerson->m_pView->m_viewClient,
  2514. (HMENU)0,
  2515. g_asInstance,
  2516. pasPerson);
  2517. }
  2518. else
  2519. {
  2520. //
  2521. // We're coming out of full screen mode.
  2522. //
  2523. //
  2524. // Destroy the escape-out button
  2525. //
  2526. ::DestroyWindow(::GetDlgItem(pasPerson->m_pView->m_viewClient, 0));
  2527. //
  2528. // Put back the menu bar. Do this BEFORE clearing the full screen bit
  2529. //
  2530. ::SetMenu(pasPerson->m_pView->m_viewFrame, pasPerson->m_pView->m_viewMenuBar);
  2531. ASSERT(pasPerson->m_pView->m_viewFullScreen);
  2532. pasPerson->m_pView->m_viewFullScreen = FALSE;
  2533. //
  2534. // Put back old status bar state.
  2535. //
  2536. if (pasPerson->m_pView->m_viewSavedStatusBarOn)
  2537. {
  2538. pasPerson->m_pView->m_viewStatusBarOn = TRUE;
  2539. ::ShowWindow(pasPerson->m_pView->m_viewStatusBar, SW_SHOW);
  2540. }
  2541. //
  2542. // Put back old window bar state.
  2543. //
  2544. if (pasPerson->m_pView->m_viewSavedWindowBarOn)
  2545. {
  2546. pasPerson->m_pView->m_viewWindowBarOn = TRUE;
  2547. ::ShowWindow(pasPerson->m_pView->m_viewWindowBar, SW_SHOW);
  2548. }
  2549. //
  2550. // Add back all frame and client bits.
  2551. //
  2552. lStyle = ::GetWindowLong(pasPerson->m_pView->m_viewFrame, GWL_EXSTYLE);
  2553. lStyle |= WS_EX_WINDOWEDGE;
  2554. ::SetWindowLong(pasPerson->m_pView->m_viewFrame, GWL_EXSTYLE, lStyle);
  2555. lStyle = ::GetWindowLong(pasPerson->m_pView->m_viewFrame, GWL_STYLE);
  2556. lStyle &= ~(WS_POPUP);
  2557. lStyle |= (WS_CAPTION | WS_THICKFRAME);
  2558. ::SetWindowLong(pasPerson->m_pView->m_viewFrame, GWL_STYLE, lStyle);
  2559. lStyle = ::GetWindowLong(pasPerson->m_pView->m_viewClient, GWL_EXSTYLE);
  2560. lStyle |= WS_EX_CLIENTEDGE;
  2561. ::SetWindowLong(pasPerson->m_pView->m_viewClient, GWL_EXSTYLE, lStyle);
  2562. lStyle = ::GetWindowLong(pasPerson->m_pView->m_viewClient, GWL_STYLE);
  2563. lStyle |= (WS_HSCROLL | WS_VSCROLL);
  2564. ::SetWindowLong(pasPerson->m_pView->m_viewClient, GWL_STYLE, lStyle);
  2565. //
  2566. // Put back old scroll pos AFTER style bits restore.
  2567. //
  2568. VIEWClientScroll(pasPerson, pasPerson->m_pView->m_viewSavedPos.x,
  2569. pasPerson->m_pView->m_viewSavedPos.y);
  2570. //
  2571. // Restore the window back to where it started.
  2572. //
  2573. rcNew = pasPerson->m_pView->m_viewSavedWindowRect;
  2574. }
  2575. //
  2576. // Resize, reframe, and repaint from scratch.
  2577. //
  2578. ::SendMessage(pasPerson->m_pView->m_viewFrame, WM_SETREDRAW, TRUE, 0);
  2579. ::SetWindowPos(pasPerson->m_pView->m_viewFrame, NULL, rcNew.left,
  2580. rcNew.top, rcNew.right - rcNew.left, rcNew.bottom - rcNew.top,
  2581. SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_NOCOPYBITS);
  2582. DebugExitVOID(ASShare::VIEWFrameFullScreen);
  2583. }
  2584. //
  2585. // VIEWClientGetSize()
  2586. // This returns back a rectangle for the ideal size of the view part of the
  2587. // frame client. It will fit the extent of what we're viewing on the remote
  2588. // plus scrollbars.
  2589. //
  2590. void ASShare::VIEWClientGetSize(ASPerson * pasPerson, LPRECT lprc)
  2591. {
  2592. DebugEntry(ASShare::VIEWClientGetSize);
  2593. ValidateView(pasPerson);
  2594. lprc->left = 0;
  2595. lprc->top = 0;
  2596. lprc->right = pasPerson->viewExtent.x;
  2597. lprc->bottom = pasPerson->viewExtent.y;
  2598. if (!pasPerson->m_pView->m_viewFullScreen)
  2599. {
  2600. AdjustWindowRectEx(lprc, WS_CHILD, FALSE, WS_EX_CLIENTEDGE);
  2601. lprc->right += GetSystemMetrics(SM_CXVSCROLL);
  2602. lprc->bottom += GetSystemMetrics(SM_CYHSCROLL);
  2603. }
  2604. DebugExitVOID(ASShare::VIEWClientGetSize);
  2605. }
  2606. //
  2607. // VIEWClientWindowProc()
  2608. // Handles messages for the view window, a child in the client of the frame
  2609. // which displays the contents of the remote host's shared apps.
  2610. //
  2611. LRESULT CALLBACK VIEWClientWindowProc
  2612. (
  2613. HWND hwnd,
  2614. UINT message,
  2615. WPARAM wParam,
  2616. LPARAM lParam
  2617. )
  2618. {
  2619. return(g_asSession.pShare->VIEW_ViewWindowProc(hwnd, message, wParam, lParam));
  2620. }
  2621. LRESULT ASShare::VIEW_ViewWindowProc
  2622. (
  2623. HWND hwnd,
  2624. UINT message,
  2625. WPARAM wParam,
  2626. LPARAM lParam
  2627. )
  2628. {
  2629. LRESULT rc = 0;
  2630. RECT rcl;
  2631. POINT mousePos;
  2632. SCROLLINFO si;
  2633. ASPerson * pasPerson;
  2634. DebugEntry(ASShare::VIEW_ViewWindowProc);
  2635. pasPerson = (ASPerson *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  2636. if (pasPerson)
  2637. {
  2638. ValidateView(pasPerson);
  2639. }
  2640. switch (message)
  2641. {
  2642. case WM_NCCREATE:
  2643. {
  2644. // Get the passed in host pointer, and set in our window long
  2645. pasPerson = (ASPerson *)((LPCREATESTRUCT)lParam)->lpCreateParams;
  2646. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)pasPerson);
  2647. pasPerson->m_pView->m_viewClient = hwnd;
  2648. goto DefWndProc;
  2649. break;
  2650. }
  2651. case WM_NCDESTROY:
  2652. {
  2653. if (pasPerson != NULL)
  2654. {
  2655. pasPerson->m_pView->m_viewClient = NULL;
  2656. }
  2657. goto DefWndProc;
  2658. break;
  2659. }
  2660. case WM_ERASEBKGND:
  2661. {
  2662. //
  2663. // BOGUS LAURABU: Paint on erase then validate for faster
  2664. // response.
  2665. //
  2666. rc = TRUE;
  2667. break;
  2668. }
  2669. case WM_PAINT:
  2670. {
  2671. VIEWClientPaint(pasPerson);
  2672. break;
  2673. }
  2674. case WM_SETFOCUS:
  2675. {
  2676. pasPerson->m_pView->m_viewFocus = TRUE;
  2677. pasPerson->m_pView->m_viewMouseWheelDelta = 0;
  2678. break;
  2679. }
  2680. case WM_KILLFOCUS:
  2681. {
  2682. pasPerson->m_pView->m_viewFocus = FALSE;
  2683. pasPerson->m_pView->m_viewMouseWheelDelta = 0;
  2684. break;
  2685. }
  2686. case WM_LBUTTONDOWN:
  2687. case WM_RBUTTONDOWN:
  2688. case WM_MBUTTONDOWN:
  2689. {
  2690. VIEWClientMouseDown(pasPerson, message, wParam, lParam);
  2691. break;
  2692. }
  2693. case WM_LBUTTONUP:
  2694. case WM_RBUTTONUP:
  2695. case WM_MBUTTONUP:
  2696. {
  2697. VIEWClientMouseUp(pasPerson, message, wParam, lParam, TRUE);
  2698. break;
  2699. }
  2700. case WM_MOUSEMOVE:
  2701. {
  2702. VIEWClientMouseMove(pasPerson, message, wParam, lParam);
  2703. break;
  2704. }
  2705. case WM_MOUSEWHEEL:
  2706. {
  2707. //
  2708. // We've handled it no matter what, don't pass it up the chain.
  2709. //
  2710. rc = TRUE;
  2711. //
  2712. // If we're not controlling this dude, try to use the mousewheel
  2713. // to scroll.
  2714. //
  2715. if ((pasPerson->m_caControlledBy != m_pasLocal) ||
  2716. pasPerson->m_caControlPaused)
  2717. {
  2718. VIEWClientMouseWheel(pasPerson, wParam, lParam);
  2719. break;
  2720. }
  2721. //
  2722. // FALL THROUGH
  2723. // Otherwise, we send the MOUSEWHEEL message to the host.
  2724. //
  2725. }
  2726. case WM_LBUTTONDBLCLK:
  2727. case WM_RBUTTONDBLCLK:
  2728. case WM_MBUTTONDBLCLK:
  2729. {
  2730. VIEWClientMouseMsg(pasPerson, message, wParam, lParam);
  2731. break;
  2732. }
  2733. case WM_TIMER:
  2734. {
  2735. if (wParam == IDT_AUTOSCROLL)
  2736. {
  2737. VIEWClientAutoScroll(pasPerson);
  2738. }
  2739. break;
  2740. }
  2741. case WM_CAPTURECHANGED:
  2742. {
  2743. //
  2744. // Check if capture got stolen away from us, if we think the
  2745. // buttons are down fake a button up.
  2746. //
  2747. if (pasPerson->m_pView->m_viewMouseFlags != 0)
  2748. {
  2749. VIEWClientCaptureStolen(pasPerson);
  2750. }
  2751. break;
  2752. }
  2753. case WM_KEYDOWN:
  2754. {
  2755. WPARAM wScrollNotify;
  2756. UINT uMsg;
  2757. if ((pasPerson->m_caControlledBy == m_pasLocal) &&
  2758. !pasPerson->m_caControlPaused)
  2759. {
  2760. goto KeyInput;
  2761. }
  2762. if (pasPerson->m_pView->m_viewFullScreen)
  2763. {
  2764. if (wParam == VK_ESCAPE)
  2765. {
  2766. //
  2767. // Kick out of full screen mode.
  2768. //
  2769. VIEWFrameFullScreen(pasPerson, FALSE);
  2770. }
  2771. goto DefWndProc;
  2772. }
  2773. //
  2774. // UP, DOWN, LEFT, and RIGHT are unambiguous about which
  2775. // scrollbar is intended.
  2776. //
  2777. // For the others, unmodified is vertical and SHIFT is
  2778. // horizontal.
  2779. //
  2780. if (::GetKeyState(VK_SHIFT) < 0)
  2781. {
  2782. uMsg = WM_HSCROLL;
  2783. }
  2784. else
  2785. {
  2786. uMsg = WM_VSCROLL;
  2787. }
  2788. switch (wParam)
  2789. {
  2790. //
  2791. // These aren't ambiguous, we know which scrollbar is meant
  2792. // by the direction.
  2793. //
  2794. case VK_UP:
  2795. wScrollNotify = SB_LINEUP;
  2796. uMsg = WM_VSCROLL;
  2797. break;
  2798. case VK_DOWN:
  2799. wScrollNotify = SB_LINEDOWN;
  2800. uMsg = WM_VSCROLL;
  2801. break;
  2802. case VK_LEFT:
  2803. wScrollNotify = SB_LINEUP;
  2804. uMsg = WM_HSCROLL;
  2805. break;
  2806. case VK_RIGHT:
  2807. wScrollNotify = SB_LINEDOWN;
  2808. uMsg = WM_HSCROLL;
  2809. break;
  2810. //
  2811. // These are ambiguous, hence the SHIFT key as a
  2812. // modifier.
  2813. //
  2814. case VK_PRIOR:
  2815. wScrollNotify = SB_PAGEUP;
  2816. break;
  2817. case VK_NEXT:
  2818. wScrollNotify = SB_PAGEDOWN;
  2819. break;
  2820. case VK_HOME:
  2821. wScrollNotify = SB_TOP;
  2822. break;
  2823. case VK_END:
  2824. wScrollNotify = SB_BOTTOM;
  2825. break;
  2826. default:
  2827. goto DefWndProc;
  2828. break;
  2829. }
  2830. SendMessage(hwnd, uMsg, MAKELONG(wScrollNotify, 0), 0L);
  2831. break;
  2832. }
  2833. case WM_SYSKEYDOWN:
  2834. {
  2835. if ((pasPerson->m_caControlledBy == m_pasLocal) &&
  2836. !pasPerson->m_caControlPaused)
  2837. {
  2838. goto KeyInput;
  2839. }
  2840. //
  2841. // ALT-ENTER toggles full screen state, if it's available
  2842. //
  2843. if ((wParam == VK_RETURN) &&
  2844. !(::GetMenuState(pasPerson->m_pView->m_viewMenuBar,
  2845. CMD_VIEWFULLSCREEN, MF_BYCOMMAND) & MF_DISABLED))
  2846. {
  2847. VIEWFrameFullScreen(pasPerson,
  2848. (pasPerson->m_pView->m_viewFullScreen == 0));
  2849. }
  2850. goto DefWndProc;
  2851. break;
  2852. }
  2853. case WM_KEYUP:
  2854. case WM_SYSKEYUP:
  2855. {
  2856. //
  2857. // If we're controlling this node, pass it along. Otherwise,
  2858. // call DefWindowProc() so key accels like Alt+Space for system
  2859. // menu will kick in.
  2860. //
  2861. if ((pasPerson->m_caControlledBy == m_pasLocal) &&
  2862. !pasPerson->m_caControlPaused)
  2863. {
  2864. KeyInput:
  2865. IM_OutgoingKeyboardInput(pasPerson, (UINT)wParam, (UINT)lParam);
  2866. }
  2867. else
  2868. {
  2869. goto DefWndProc;
  2870. }
  2871. break;
  2872. }
  2873. case WM_SETCURSOR:
  2874. {
  2875. if ((LOWORD(lParam) == HTCLIENT) && ((HWND)wParam == hwnd))
  2876. {
  2877. HCURSOR hCursor;
  2878. POINT cursorPoint;
  2879. if ((pasPerson->m_caControlledBy == m_pasLocal) &&
  2880. !pasPerson->m_caControlPaused)
  2881. {
  2882. hCursor = m_cmArrowCursor;
  2883. //
  2884. // Only set the remote cursor if we're over shared space.
  2885. //
  2886. if (pasPerson->m_pView->m_viewFocus)
  2887. {
  2888. GetCursorPos(&cursorPoint);
  2889. ScreenToClient(hwnd, &cursorPoint);
  2890. if (VIEW_IsPointShared(pasPerson, cursorPoint))
  2891. {
  2892. hCursor = pasPerson->cmhRemoteCursor;
  2893. }
  2894. }
  2895. }
  2896. else
  2897. {
  2898. // NoDrop
  2899. hCursor = m_viewNotInControl;
  2900. }
  2901. SetCursor(hCursor);
  2902. rc = TRUE;
  2903. }
  2904. else
  2905. {
  2906. // Let defwindowproc handle it
  2907. goto DefWndProc;
  2908. }
  2909. break;
  2910. }
  2911. case WM_SIZE:
  2912. {
  2913. //
  2914. // If we're in full screen mode, there are no scrollbars.
  2915. //
  2916. if (!pasPerson->m_pView->m_viewFullScreen)
  2917. {
  2918. int xNewPos;
  2919. int yNewPos;
  2920. xNewPos = pasPerson->m_pView->m_viewPos.x;
  2921. yNewPos = pasPerson->m_pView->m_viewPos.y;
  2922. GetClientRect(hwnd, &rcl);
  2923. pasPerson->m_pView->m_viewPage.x = rcl.right - rcl.left;
  2924. pasPerson->m_pView->m_viewPage.y = rcl.bottom - rcl.top;
  2925. TRACE_OUT(("WM_SIZE: Set page size (%04d, %04d)",
  2926. pasPerson->m_pView->m_viewPage.x, pasPerson->m_pView->m_viewPage.y));
  2927. //
  2928. // Scroll window if necessary.
  2929. //
  2930. si.cbSize = sizeof(SCROLLINFO);
  2931. si.fMask = SIF_PAGE|SIF_DISABLENOSCROLL;
  2932. // Set new HORIZONTAL proportional scroll button size
  2933. si.nPage = pasPerson->m_pView->m_viewPage.x;
  2934. SetScrollInfo(hwnd, SB_HORZ, &si, TRUE );
  2935. // Set new VERTICAL proportional scroll button size
  2936. si.nPage = pasPerson->m_pView->m_viewPage.y;
  2937. SetScrollInfo(hwnd, SB_VERT, &si, TRUE );
  2938. //
  2939. // This will make sure the scroll pos is pinned properly
  2940. //
  2941. VIEWClientScroll(pasPerson, pasPerson->m_pView->m_viewPos.x, pasPerson->m_pView->m_viewPos.y);
  2942. }
  2943. break;
  2944. }
  2945. case WM_HSCROLL:
  2946. {
  2947. int xNewPos; // new position
  2948. switch (GET_WM_HSCROLL_CODE(wParam, lParam))
  2949. {
  2950. case SB_PAGEUP:
  2951. xNewPos = pasPerson->m_pView->m_viewPos.x - pasPerson->m_pView->m_viewPgSize.x;
  2952. break;
  2953. case SB_PAGEDOWN:
  2954. xNewPos = pasPerson->m_pView->m_viewPos.x + pasPerson->m_pView->m_viewPgSize.x;
  2955. break;
  2956. case SB_LINEUP:
  2957. xNewPos = pasPerson->m_pView->m_viewPos.x - pasPerson->m_pView->m_viewLnSize.x;
  2958. break;
  2959. case SB_LINEDOWN:
  2960. xNewPos = pasPerson->m_pView->m_viewPos.x + pasPerson->m_pView->m_viewLnSize.x;
  2961. break;
  2962. case SB_TOP:
  2963. xNewPos = 0;
  2964. break;
  2965. case SB_BOTTOM:
  2966. xNewPos = pasPerson->viewExtent.x;
  2967. break;
  2968. case SB_THUMBTRACK:
  2969. case SB_THUMBPOSITION:
  2970. xNewPos = GET_WM_HSCROLL_POS(wParam, lParam);
  2971. break;
  2972. default:
  2973. xNewPos = pasPerson->m_pView->m_viewPos.x;
  2974. break;
  2975. }
  2976. //
  2977. // This will pin the desired scroll pos in the range, and if
  2978. // nothing has changed, won't scroll.
  2979. //
  2980. VIEWClientScroll(pasPerson, xNewPos, pasPerson->m_pView->m_viewPos.y);
  2981. break;
  2982. }
  2983. case WM_VSCROLL:
  2984. {
  2985. int yNewPos; // new position
  2986. switch (GET_WM_VSCROLL_CODE(wParam, lParam))
  2987. {
  2988. case SB_PAGEUP:
  2989. yNewPos = pasPerson->m_pView->m_viewPos.y - pasPerson->m_pView->m_viewPgSize.y;
  2990. break;
  2991. case SB_PAGEDOWN:
  2992. yNewPos = pasPerson->m_pView->m_viewPos.y + pasPerson->m_pView->m_viewPgSize.y;
  2993. break;
  2994. case SB_LINEUP:
  2995. yNewPos = pasPerson->m_pView->m_viewPos.y - pasPerson->m_pView->m_viewLnSize.y;
  2996. break;
  2997. case SB_LINEDOWN:
  2998. yNewPos = pasPerson->m_pView->m_viewPos.y + pasPerson->m_pView->m_viewLnSize.y;
  2999. break;
  3000. case SB_TOP:
  3001. yNewPos = 0;
  3002. break;
  3003. case SB_BOTTOM:
  3004. yNewPos = pasPerson->viewExtent.y;
  3005. break;
  3006. case SB_THUMBTRACK:
  3007. case SB_THUMBPOSITION:
  3008. yNewPos = GET_WM_VSCROLL_POS(wParam, lParam);
  3009. break;
  3010. default:
  3011. yNewPos = pasPerson->m_pView->m_viewPos.y;
  3012. break;
  3013. }
  3014. //
  3015. // This will pin the desired scroll pos in the range, and if
  3016. // nothing has changed, won't scroll.
  3017. //
  3018. VIEWClientScroll(pasPerson, pasPerson->m_pView->m_viewPos.x, yNewPos);
  3019. break;
  3020. }
  3021. default:
  3022. DefWndProc:
  3023. rc = DefWindowProc(hwnd, message, wParam, lParam);
  3024. break;
  3025. }
  3026. DebugExitDWORD(ASShare::VIEW_ViewWindowProc, rc);
  3027. return(rc);
  3028. }
  3029. //
  3030. // VIEWClientPaint()
  3031. //
  3032. // This paints the client area of the view frame. We paint
  3033. // (1) The obscured area, in the obscured pattern
  3034. // * parts of shared regions that are covered up
  3035. // * parts of shared regions that are offscreen/off the VD
  3036. // (2) The shared area, from the bitmap
  3037. // (3) The deadspace, in COLOR_APPWORKSPACE
  3038. //
  3039. void ASShare::VIEWClientPaint(ASPerson * pasPerson)
  3040. {
  3041. PAINTSTRUCT ps;
  3042. HDC hdcView;
  3043. HPALETTE hOldPal;
  3044. HPALETTE hOldPal2;
  3045. RECT rcT;
  3046. DebugEntry(ASShare::VIEWClientPaint);
  3047. ValidateView(pasPerson);
  3048. hdcView = BeginPaint(pasPerson->m_pView->m_viewClient, &ps);
  3049. if (hdcView == NULL)
  3050. {
  3051. WARNING_OUT(( "Failed to get hdc for frame window %08X", pasPerson->m_pView->m_viewClient));
  3052. DC_QUIT;
  3053. }
  3054. if (IsRectEmpty(&ps.rcPaint))
  3055. {
  3056. TRACE_OUT(("Nothing to paint but got WM_PAINT message"));
  3057. DC_QUIT;
  3058. }
  3059. TRACE_OUT(("VIEWClientPaint: Painting total client area {%04d, %04d, %04d, %04d}",
  3060. ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom));
  3061. //
  3062. // In desktop sharing, viewSharedRgn is NULL
  3063. //
  3064. if (pasPerson->m_pView->m_viewSharedRgn != NULL)
  3065. {
  3066. POINT ptOrigin;
  3067. HBRUSH hbrT;
  3068. //
  3069. // First, create paint area region
  3070. //
  3071. SetRectRgn(pasPerson->m_pView->m_viewPaintRgn, ps.rcPaint.left, ps.rcPaint.top,
  3072. ps.rcPaint.right, ps.rcPaint.bottom);
  3073. //
  3074. // Second, compute the VD area not currently on screen. Do this
  3075. // in CLIENT coords.
  3076. //
  3077. SetRectRgn(pasPerson->m_pView->m_viewExtentRgn,
  3078. -pasPerson->m_pView->m_viewPos.x,
  3079. -pasPerson->m_pView->m_viewPos.y,
  3080. -pasPerson->m_pView->m_viewPos.x + pasPerson->viewExtent.x,
  3081. -pasPerson->m_pView->m_viewPos.y + pasPerson->viewExtent.y);
  3082. SetRectRgn(pasPerson->m_pView->m_viewScreenRgn,
  3083. -pasPerson->m_pView->m_viewPos.x + pasPerson->m_pView->m_dsScreenOrigin.x,
  3084. -pasPerson->m_pView->m_viewPos.y + pasPerson->m_pView->m_dsScreenOrigin.y,
  3085. -pasPerson->m_pView->m_viewPos.x + pasPerson->m_pView->m_dsScreenOrigin.x + pasPerson->cpcCaps.screen.capsScreenWidth,
  3086. -pasPerson->m_pView->m_viewPos.y + pasPerson->m_pView->m_dsScreenOrigin.y + pasPerson->cpcCaps.screen.capsScreenHeight);
  3087. SubtractRgn(pasPerson->m_pView->m_viewExtentRgn, pasPerson->m_pView->m_viewExtentRgn, pasPerson->m_pView->m_viewScreenRgn);
  3088. //
  3089. // pasPerson->m_pView->m_viewExtentRgn is now the offscreen parts of the VD, and therefore
  3090. // any shared areas lying in them should be treated as obscured.
  3091. //
  3092. //
  3093. // Now, compute the real obscured area. It's the covered up bits
  3094. // plus open parts of shared stuff not currently on screen.
  3095. //
  3096. IntersectRgn(pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewExtentRgn, pasPerson->m_pView->m_viewSharedRgn);
  3097. UnionRgn(pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewObscuredRgn);
  3098. // Calc what part of the obscured region to actually paint
  3099. IntersectRgn(pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewPaintRgn);
  3100. if (GetRgnBox(pasPerson->m_pView->m_viewScratchRgn, &rcT) > NULLREGION)
  3101. {
  3102. TRACE_OUT(("VIEWClientPaint: Painting obscured client area {%04d, %04d, %04d, %04d}",
  3103. rcT.left, rcT.top, rcT.right, rcT.bottom));
  3104. //
  3105. // Remove this area so we have what's left to paint.
  3106. //
  3107. SubtractRgn(pasPerson->m_pView->m_viewPaintRgn, pasPerson->m_pView->m_viewPaintRgn, pasPerson->m_pView->m_viewScratchRgn);
  3108. //
  3109. // We do NOT want to use FillRgn; it ignores the brush origin.
  3110. // So we select this in as the clip region and PatBlt instead.
  3111. //
  3112. SelectClipRgn(hdcView, pasPerson->m_pView->m_viewScratchRgn);
  3113. #ifdef _DEBUG
  3114. //
  3115. // NOTE: Do NOT move this--we're using ptOrigin for scratch.
  3116. //
  3117. GetDCOrgEx(hdcView, &ptOrigin);
  3118. TRACE_OUT(("VIEWClientPaint: Setting brush origin to {%04d, %04d}, screen {%04d, %04d}",
  3119. -pasPerson->m_pView->m_viewPos.x, -pasPerson->m_pView->m_viewPos.y,
  3120. ptOrigin.x - pasPerson->m_pView->m_viewPos.x,
  3121. ptOrigin.y - pasPerson->m_pView->m_viewPos.y));
  3122. #endif
  3123. //
  3124. // Align the brush with where the view's real origin would be, in
  3125. // client coords. We do that by accounting for being scrolled over.
  3126. //
  3127. SetBrushOrgEx(hdcView, -pasPerson->m_pView->m_viewPos.x,
  3128. -pasPerson->m_pView->m_viewPos.y, &ptOrigin);
  3129. UnrealizeObject(m_viewObscuredBrush);
  3130. hbrT = SelectBrush(hdcView, m_viewObscuredBrush);
  3131. PatBlt(hdcView,
  3132. rcT.left, rcT.top,
  3133. rcT.right - rcT.left,
  3134. rcT.bottom - rcT.top,
  3135. PATCOPY);
  3136. SelectBrush(hdcView, hbrT);
  3137. SetBrushOrgEx(hdcView, ptOrigin.x, ptOrigin.y, NULL);
  3138. SelectClipRgn(hdcView, NULL);
  3139. }
  3140. //
  3141. // Paint the deadspace area, set up clipping for app sharing.
  3142. // This also works for desktop sharing, where there are no obscured or
  3143. // shared regions, the whole area paints.
  3144. //
  3145. //
  3146. // The deadspace is whatever's left over in the paint region
  3147. // (already subtracted the obscured region) after subtracting the
  3148. // shared area
  3149. //
  3150. SubtractRgn(pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewPaintRgn, pasPerson->m_pView->m_viewSharedRgn);
  3151. if (GetRgnBox(pasPerson->m_pView->m_viewScratchRgn, &rcT) > NULLREGION)
  3152. {
  3153. TRACE_OUT(("VIEWClientPaint: Painting dead client area {%04d, %04d, %04d, %04d}",
  3154. rcT.left, rcT.top, rcT.right, rcT.bottom));
  3155. FillRgn(hdcView, pasPerson->m_pView->m_viewScratchRgn, GetSysColorBrush(COLOR_APPWORKSPACE));
  3156. }
  3157. //
  3158. // Compute what part of the shared area needs painting (the part
  3159. // that lies on the remote screen actually).
  3160. //
  3161. IntersectRgn(pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewSharedRgn, pasPerson->m_pView->m_viewScreenRgn);
  3162. IntersectRgn(pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewPaintRgn);
  3163. // Now select in the piece of what we're painting as the clip region
  3164. SelectClipRgn(hdcView, pasPerson->m_pView->m_viewScratchRgn);
  3165. }
  3166. //
  3167. // Blt the shared region
  3168. //
  3169. if (GetClipBox(hdcView, &rcT) > NULLREGION)
  3170. {
  3171. TRACE_OUT(("VIEWClientPaint: Painting shared client area {%04x, %04x, %04x, %04x}",
  3172. rcT.left, rcT.top, rcT.right, rcT.bottom));
  3173. if (g_usrPalettized)
  3174. {
  3175. ASSERT(pasPerson->pmPalette != NULL);
  3176. //
  3177. // Select and realize the current remote palette into the
  3178. // screen and shadow bitmap DCs.
  3179. //
  3180. hOldPal = SelectPalette(pasPerson->m_pView->m_usrDC, pasPerson->pmPalette, FALSE);
  3181. RealizePalette(pasPerson->m_pView->m_usrDC);
  3182. hOldPal2 = SelectPalette( hdcView, pasPerson->pmPalette, FALSE);
  3183. RealizePalette(hdcView);
  3184. }
  3185. //
  3186. // The host bitmap is in screen coords, not VD coords, so
  3187. // adjust for being scrolled over...
  3188. //
  3189. BitBlt(hdcView,
  3190. rcT.left, rcT.top, rcT.right - rcT.left, rcT.bottom - rcT.top,
  3191. pasPerson->m_pView->m_usrDC,
  3192. rcT.left + pasPerson->m_pView->m_viewPos.x - pasPerson->m_pView->m_dsScreenOrigin.x,
  3193. rcT.top + pasPerson->m_pView->m_viewPos.y - pasPerson->m_pView->m_dsScreenOrigin.y,
  3194. SRCCOPY);
  3195. if (g_usrPalettized)
  3196. {
  3197. ASSERT(pasPerson->pmPalette != NULL);
  3198. SelectPalette(pasPerson->m_pView->m_usrDC, hOldPal, FALSE);
  3199. SelectPalette(hdcView, hOldPal2, FALSE);
  3200. }
  3201. }
  3202. //
  3203. // Deselect the clip region, or we won't be able to draw shadow cursors
  3204. // that lie outside the shared area.
  3205. //
  3206. if (pasPerson->m_pView->m_viewSharedRgn != NULL)
  3207. {
  3208. SelectClipRgn(hdcView, NULL);
  3209. }
  3210. //
  3211. // Draw the shadow cursor.
  3212. //
  3213. CM_DrawShadowCursor(pasPerson, hdcView);
  3214. DC_EXIT_POINT:
  3215. if (hdcView != NULL)
  3216. EndPaint(pasPerson->m_pView->m_viewClient, &ps);
  3217. DebugExitVOID(ASShare::VIEWClientPaint);
  3218. }
  3219. //
  3220. // VIEWClientScroll()
  3221. //
  3222. // This is the common place where the scroll position is altered. If
  3223. // necessary the contents are scrolled over, the regions (always in client
  3224. // coords) are adjusted, and new info about our origin is sent to remotes.
  3225. //
  3226. // We first make sure the scroll position is pinned properly within the
  3227. // range.
  3228. //
  3229. // The return value is whether scrolling happened or not.
  3230. //
  3231. BOOL ASShare::VIEWClientScroll
  3232. (
  3233. ASPerson * pasPerson,
  3234. int xNew,
  3235. int yNew
  3236. )
  3237. {
  3238. int dx;
  3239. int dy;
  3240. DebugEntry(ASShare::VIEWClientScroll);
  3241. //
  3242. // First, pin the requested new position within the range
  3243. //
  3244. //
  3245. // Pin x pos
  3246. //
  3247. if (xNew < 0)
  3248. xNew = 0;
  3249. if (xNew + pasPerson->m_pView->m_viewPage.x > pasPerson->viewExtent.x)
  3250. xNew = pasPerson->viewExtent.x - pasPerson->m_pView->m_viewPage.x;
  3251. //
  3252. // Pin y pos
  3253. //
  3254. if (yNew < 0)
  3255. yNew = 0;
  3256. if (yNew + pasPerson->m_pView->m_viewPage.y > pasPerson->viewExtent.y)
  3257. yNew = pasPerson->viewExtent.y - pasPerson->m_pView->m_viewPage.y;
  3258. //
  3259. // How much are we going to scroll by?
  3260. //
  3261. dx = pasPerson->m_pView->m_viewPos.x - xNew;
  3262. dy = pasPerson->m_pView->m_viewPos.y - yNew;
  3263. // Updates
  3264. if (dx || dy)
  3265. {
  3266. //
  3267. // Adjust regions
  3268. //
  3269. if (pasPerson->m_pView->m_viewObscuredRgn != NULL)
  3270. OffsetRgn(pasPerson->m_pView->m_viewObscuredRgn, dx, dy);
  3271. if (pasPerson->m_pView->m_viewSharedRgn != NULL)
  3272. OffsetRgn(pasPerson->m_pView->m_viewSharedRgn, dx, dy);
  3273. pasPerson->m_pView->m_viewPos.x = xNew;
  3274. pasPerson->m_pView->m_viewPos.y = yNew;
  3275. ScrollWindowEx(pasPerson->m_pView->m_viewClient,
  3276. dx,
  3277. dy,
  3278. NULL,
  3279. NULL,
  3280. NULL,
  3281. NULL,
  3282. SW_SCROLLCHILDREN | SW_INVALIDATE);
  3283. if (dx)
  3284. {
  3285. SetScrollPos(pasPerson->m_pView->m_viewClient, SB_HORZ, xNew, TRUE);
  3286. }
  3287. if (dy)
  3288. {
  3289. SetScrollPos(pasPerson->m_pView->m_viewClient, SB_VERT, yNew, TRUE);
  3290. }
  3291. }
  3292. DebugExitBOOL(ASShare::VIEWClientScroll, (dx || dy));
  3293. return(dx || dy);
  3294. }
  3295. //
  3296. // VIEWClientMouseDown()
  3297. //
  3298. void ASShare::VIEWClientMouseDown
  3299. (
  3300. ASPerson * pasPerson,
  3301. UINT message,
  3302. WPARAM wParam,
  3303. LPARAM lParam
  3304. )
  3305. {
  3306. DebugEntry(ASShare::VIEWClientMouseDown);
  3307. ValidateView(pasPerson);
  3308. //
  3309. // On the first button down, set capture so all mouse messages come
  3310. // to us until capture is released or stolen.
  3311. //
  3312. if (!pasPerson->m_pView->m_viewMouseFlags)
  3313. {
  3314. //
  3315. // If this is RBUTTONDOWN, track the Collaborate pop up...
  3316. //
  3317. ASSERT(!pasPerson->m_pView->m_viewMouseOutside);
  3318. SetCapture(pasPerson->m_pView->m_viewClient);
  3319. }
  3320. //
  3321. // Remember what button is down.
  3322. //
  3323. switch (message)
  3324. {
  3325. case WM_LBUTTONDOWN:
  3326. pasPerson->m_pView->m_viewMouseFlags |= MK_LBUTTON;
  3327. break;
  3328. case WM_RBUTTONDOWN:
  3329. pasPerson->m_pView->m_viewMouseFlags |= MK_RBUTTON;
  3330. break;
  3331. case WM_MBUTTONDOWN:
  3332. pasPerson->m_pView->m_viewMouseFlags |= MK_MBUTTON;
  3333. break;
  3334. }
  3335. //
  3336. // Save the current mouse position
  3337. //
  3338. pasPerson->m_pView->m_viewMouse.x = GET_X_LPARAM(lParam);
  3339. pasPerson->m_pView->m_viewMouse.y = GET_Y_LPARAM(lParam);
  3340. VIEWClientMouseMsg(pasPerson, message, wParam, lParam);
  3341. DebugExitVOID(ASShare::VIEWClientMouseDown);
  3342. }
  3343. //
  3344. // VIEWClientMouseUp()
  3345. //
  3346. void ASShare::VIEWClientMouseUp
  3347. (
  3348. ASPerson * pasPerson,
  3349. UINT message,
  3350. WPARAM wParam,
  3351. LPARAM lParam,
  3352. BOOL fReleaseCapture
  3353. )
  3354. {
  3355. DebugEntry(ASShare::VIEWClientMouseUp);
  3356. switch (message)
  3357. {
  3358. case WM_LBUTTONUP:
  3359. if (pasPerson->m_pView->m_viewMouseFlags & MK_LBUTTON)
  3360. pasPerson->m_pView->m_viewMouseFlags &= ~MK_LBUTTON;
  3361. else
  3362. fReleaseCapture = FALSE; // From dbl-click
  3363. break;
  3364. case WM_RBUTTONUP:
  3365. if (pasPerson->m_pView->m_viewMouseFlags & MK_RBUTTON)
  3366. pasPerson->m_pView->m_viewMouseFlags &= ~MK_RBUTTON;
  3367. else
  3368. fReleaseCapture = FALSE; // From dbl-click
  3369. break;
  3370. case WM_MBUTTONUP:
  3371. if (pasPerson->m_pView->m_viewMouseFlags & MK_MBUTTON)
  3372. pasPerson->m_pView->m_viewMouseFlags &= ~MK_MBUTTON;
  3373. else
  3374. fReleaseCapture = FALSE; // From dbl-click
  3375. break;
  3376. }
  3377. //
  3378. // Should we release capture?
  3379. // We don't just want to release capture on a button up. The user may
  3380. // press one button down then another; we don't want to release capture
  3381. // until all buttons are up.
  3382. //
  3383. if (!pasPerson->m_pView->m_viewMouseFlags)
  3384. {
  3385. if (pasPerson->m_pView->m_viewMouseOutside)
  3386. {
  3387. pasPerson->m_pView->m_viewMouseOutside = FALSE;
  3388. KillTimer(pasPerson->m_pView->m_viewClient, IDT_AUTOSCROLL);
  3389. }
  3390. if (fReleaseCapture)
  3391. ReleaseCapture();
  3392. }
  3393. //
  3394. // Save the current mouse position
  3395. //
  3396. pasPerson->m_pView->m_viewMouse.x = GET_X_LPARAM(lParam);
  3397. pasPerson->m_pView->m_viewMouse.y = GET_Y_LPARAM(lParam);
  3398. VIEWClientMouseMsg(pasPerson, message, wParam, lParam);
  3399. DebugExitVOID(ASShare::VIEWClientMouseUp);
  3400. }
  3401. //
  3402. // VIEWClientCaptureStolen()
  3403. // Called when capture gets stolen away from us, like by Alt-Tab.
  3404. //
  3405. void ASShare::VIEWClientCaptureStolen(ASPerson * pasPerson)
  3406. {
  3407. DebugEntry(ASShare::VIEWClientCaptureStolen);
  3408. //
  3409. // We need to fake a button up for each button we think is down.
  3410. // Use the current cursor pos.
  3411. //
  3412. if (pasPerson->m_pView->m_viewMouseFlags & MK_MBUTTON)
  3413. {
  3414. VIEWClientMouseUp(pasPerson, WM_MBUTTONUP, pasPerson->m_pView->m_viewMouseFlags,
  3415. MAKELPARAM(pasPerson->m_pView->m_viewMouse.x, pasPerson->m_pView->m_viewMouse.y),
  3416. FALSE);
  3417. }
  3418. if (pasPerson->m_pView->m_viewMouseFlags & MK_RBUTTON)
  3419. {
  3420. VIEWClientMouseUp(pasPerson, WM_RBUTTONUP, pasPerson->m_pView->m_viewMouseFlags,
  3421. MAKELPARAM(pasPerson->m_pView->m_viewMouse.x, pasPerson->m_pView->m_viewMouse.y),
  3422. FALSE);
  3423. }
  3424. if (pasPerson->m_pView->m_viewMouseFlags & MK_LBUTTON)
  3425. {
  3426. VIEWClientMouseUp(pasPerson, WM_LBUTTONUP, pasPerson->m_pView->m_viewMouseFlags,
  3427. MAKELPARAM(pasPerson->m_pView->m_viewMouse.x, pasPerson->m_pView->m_viewMouse.y),
  3428. FALSE);
  3429. }
  3430. DebugExitVOID(ASShare::VIEWClientCaptureStolen);
  3431. }
  3432. //
  3433. // VIEWClientMouseMove()
  3434. //
  3435. void ASShare::VIEWClientMouseMove
  3436. (
  3437. ASPerson * pasPerson,
  3438. UINT message,
  3439. WPARAM wParam,
  3440. LPARAM lParam
  3441. )
  3442. {
  3443. RECT rcClient;
  3444. DebugEntry(ASShare::VIEWClientMouseMove);
  3445. if (!pasPerson->m_pView->m_viewFocus)
  3446. {
  3447. // Ignore mouse moves over windows that don't have the focus
  3448. DC_QUIT;
  3449. }
  3450. //
  3451. // Save the current mouse position
  3452. //
  3453. pasPerson->m_pView->m_viewMouse.x = GET_X_LPARAM(lParam);
  3454. pasPerson->m_pView->m_viewMouse.y = GET_Y_LPARAM(lParam);
  3455. GetClientRect(pasPerson->m_pView->m_viewClient, &rcClient);
  3456. //
  3457. // If any button is down, check whether we should kick in
  3458. // autoscroll detection.
  3459. //
  3460. if (pasPerson->m_pView->m_viewMouseFlags)
  3461. {
  3462. // Is the mouse inside or outside the client for the first time?
  3463. if (PtInRect(&rcClient, pasPerson->m_pView->m_viewMouse))
  3464. {
  3465. //
  3466. // Was the mouse outside the client before? If so, kill our
  3467. // autoscroll timer, we're not dragging outside.
  3468. //
  3469. if (pasPerson->m_pView->m_viewMouseOutside)
  3470. {
  3471. pasPerson->m_pView->m_viewMouseOutside = FALSE;
  3472. KillTimer(pasPerson->m_pView->m_viewClient, IDT_AUTOSCROLL);
  3473. }
  3474. }
  3475. else
  3476. {
  3477. //
  3478. // Is the first time the mouse is outside the client? If so,
  3479. // set our autoscroll timer to the default value. When it goes
  3480. // off, the autoscroll code will scroll by some multiple of
  3481. // how far away the mouse is from the client.
  3482. //
  3483. if (!pasPerson->m_pView->m_viewMouseOutside)
  3484. {
  3485. //
  3486. // The Windows scrollbar code uses 1/8 of the double-click
  3487. // time, so we do also.
  3488. //
  3489. pasPerson->m_pView->m_viewMouseOutside = TRUE;
  3490. SetTimer(pasPerson->m_pView->m_viewClient, IDT_AUTOSCROLL,
  3491. GetDoubleClickTime() / 8, NULL);
  3492. }
  3493. //
  3494. // LAURABU BOGUS!
  3495. // When IM_Periodic goop is gone for controlling, do NOT
  3496. // pass along mouse outside messages. Only the autoscroll
  3497. // timer will fake a mouse move in this case. Either that,
  3498. // or clip the position to the nearest client area equivalent.
  3499. //
  3500. }
  3501. }
  3502. VIEWClientMouseMsg(pasPerson, message, wParam, lParam);
  3503. DC_EXIT_POINT:
  3504. DebugExitVOID(ASShare::VIEWClientMouseMove);
  3505. }
  3506. //
  3507. // VIEWClientMouseMsg()
  3508. //
  3509. void ASShare::VIEWClientMouseMsg
  3510. (
  3511. ASPerson * pasPerson,
  3512. UINT message,
  3513. WPARAM wParam,
  3514. LPARAM lParam
  3515. )
  3516. {
  3517. POINT mousePos;
  3518. DebugEntry(ASShare::VIEWClientMouseMsg);
  3519. //
  3520. // Extract the mouse position from <lParam> and package it
  3521. // in a POINT structure. These coordinates are relative to our
  3522. // client area. So convert to remote's desktop by adjusting for
  3523. // scroll position.
  3524. //
  3525. // Be careful when converting the LOWORD and HIWORD values
  3526. // because the positions are signed values.
  3527. //
  3528. mousePos.x = GET_X_LPARAM(lParam) + pasPerson->m_pView->m_viewPos.x;
  3529. mousePos.y = GET_Y_LPARAM(lParam) + pasPerson->m_pView->m_viewPos.y;
  3530. //
  3531. // These coords represent the SCREEN coords on the host.
  3532. //
  3533. if (pasPerson->m_caControlledBy == m_pasLocal)
  3534. {
  3535. if (!pasPerson->m_caControlPaused)
  3536. {
  3537. IM_OutgoingMouseInput(pasPerson, &mousePos, message, (UINT)wParam);
  3538. }
  3539. }
  3540. else if (pasPerson->m_caAllowControl && !pasPerson->m_caControlledBy &&
  3541. (message == WM_LBUTTONDBLCLK))
  3542. {
  3543. //
  3544. // If we're already waiting for control of this person, don't bother
  3545. // trying to take control again.
  3546. //
  3547. if ((m_caWaitingForReplyFrom != pasPerson) &&
  3548. (m_caWaitingForReplyMsg != CA_REPLY_REQUEST_TAKECONTROL))
  3549. {
  3550. CA_TakeControl(pasPerson);
  3551. }
  3552. }
  3553. DebugExitVOID(ASShare::VIEWClientMouse);
  3554. }
  3555. //
  3556. // VIEWClientMouseWheel()
  3557. //
  3558. // Unbelievably complicated, messy, nonsensical Intellimouse wheel handling
  3559. // to scroll the client. Since the Intellimouse makes no distinction for
  3560. // which direction to scroll in, we basically have to guess. We don't want
  3561. // to be unpredictable and decide which direction to scroll based on how
  3562. // much is visible in each dimenion.
  3563. //
  3564. // So instead, we assume horizontal. If the horizontal scrollbar is disabled,
  3565. // then we try vertical. If that's disabled, we do nothing.
  3566. //
  3567. // We do NOT handle zoom and datazoom flavors.
  3568. //
  3569. // Note that this code comes from the listbox/sample source.
  3570. //
  3571. void ASShare::VIEWClientMouseWheel
  3572. (
  3573. ASPerson * pasHost,
  3574. WPARAM wParam,
  3575. LPARAM lParam
  3576. )
  3577. {
  3578. int cDetants;
  3579. DebugEntry(ASShare::VIEWClientMouseWheel);
  3580. //
  3581. // The LOWORD of wParam has key state information.
  3582. // The HIWORD of wParam is the number of mouse wheel clicks.
  3583. //
  3584. //
  3585. // We don't do zoom/datazoom
  3586. //
  3587. if (wParam & (MK_SHIFT | MK_CONTROL))
  3588. {
  3589. DC_QUIT;
  3590. }
  3591. pasHost->m_pView->m_viewMouseWheelDelta -= (int)(short)HIWORD(wParam);
  3592. cDetants = pasHost->m_pView->m_viewMouseWheelDelta / WHEEL_DELTA;
  3593. if (cDetants && (m_viewMouseWheelScrollLines > 0))
  3594. {
  3595. POINT ptPos;
  3596. pasHost->m_pView->m_viewMouseWheelDelta %= WHEEL_DELTA;
  3597. //
  3598. // The basic idea is that we scroll some number of lines, the
  3599. // number being cDetants.
  3600. //
  3601. ptPos = pasHost->m_pView->m_viewPos;
  3602. //
  3603. // To be consistent with other apps, and with our keyboard
  3604. // accelerators, try the vertical direction first.
  3605. //
  3606. if (pasHost->m_pView->m_viewPage.y < pasHost->viewExtent.y)
  3607. {
  3608. ptPos.y += cDetants * pasHost->m_pView->m_viewLnSize.y;
  3609. }
  3610. else if (pasHost->m_pView->m_viewPage.x < pasHost->viewExtent.x)
  3611. {
  3612. ptPos.x += cDetants * pasHost->m_pView->m_viewLnSize.x;
  3613. }
  3614. else
  3615. {
  3616. // Nothing to scroll, the whole view fits in the client area.
  3617. }
  3618. VIEWClientScroll(pasHost, ptPos.x, ptPos.y);
  3619. }
  3620. DC_EXIT_POINT:
  3621. DebugExitVOID(ASShare::VIEWClientMouseWheel);
  3622. }
  3623. //
  3624. // VIEWClientAutoScroll()
  3625. //
  3626. void ASShare::VIEWClientAutoScroll(ASPerson * pasPerson)
  3627. {
  3628. int dx;
  3629. int dy;
  3630. RECT rcClient;
  3631. DebugEntry(ASShare::VIEWClientAutoScroll);
  3632. ValidateView(pasPerson);
  3633. ASSERT(pasPerson->m_pView->m_viewMouseOutside);
  3634. //
  3635. // Do scrolling. The amount is dependent on how far outside the
  3636. // client area we are.
  3637. //
  3638. GetClientRect(pasPerson->m_pView->m_viewClient, &rcClient);
  3639. // Horizontal scrolling?
  3640. if (pasPerson->m_pView->m_viewMouse.x < rcClient.left)
  3641. {
  3642. dx = pasPerson->m_pView->m_viewMouse.x - rcClient.left;
  3643. }
  3644. else if (pasPerson->m_pView->m_viewMouse.x >= rcClient.right)
  3645. {
  3646. dx = pasPerson->m_pView->m_viewMouse.x - rcClient.right + 1;
  3647. }
  3648. else
  3649. {
  3650. dx = 0;
  3651. }
  3652. // Vertical scrolling?
  3653. if (pasPerson->m_pView->m_viewMouse.y < rcClient.top)
  3654. {
  3655. dy = pasPerson->m_pView->m_viewMouse.y - rcClient.top;
  3656. }
  3657. else if (pasPerson->m_pView->m_viewMouse.y >= rcClient.bottom)
  3658. {
  3659. dy = pasPerson->m_pView->m_viewMouse.y - rcClient.bottom + 1;
  3660. }
  3661. else
  3662. {
  3663. dy = 0;
  3664. }
  3665. // For every 32 pixel blocks outside the client, scroll one line amount
  3666. if (dx)
  3667. dx = MulDiv(pasPerson->m_pView->m_viewLnSize.x, dx, 32);
  3668. if (dy)
  3669. dy = MulDiv(pasPerson->m_pView->m_viewLnSize.y, dy, 32);
  3670. // Do scrolling.
  3671. if (VIEWClientScroll(pasPerson, pasPerson->m_pView->m_viewPos.x + dx,
  3672. pasPerson->m_pView->m_viewPos.y + dy))
  3673. {
  3674. //
  3675. // The scroll position actually changed. So fake a mouse move
  3676. // to the current location so that the remote's
  3677. // cursor will be in the same spot as ours. If our scroll pos has
  3678. // changed, we're mapping to a different place on the remote.
  3679. //
  3680. VIEWClientMouseMsg(pasPerson, WM_MOUSEMOVE, pasPerson->m_pView->m_viewMouseFlags,
  3681. MAKELPARAM(pasPerson->m_pView->m_viewMouse.x, pasPerson->m_pView->m_viewMouse.y));
  3682. }
  3683. DebugExitVOID(ASShare::VIEWClientAutoScroll);
  3684. }
  3685. //
  3686. // VIEW_SyncCursorPos()
  3687. //
  3688. // This is called when we see a CM_SYNC pos packet broadcasted from a
  3689. // host. It means that we should sync our cursor to the corresponding
  3690. // position in our view. This happens when the cursor is moved by
  3691. // an app, constrained by clipping, or we're too out of whack because it's
  3692. // taking too long.
  3693. //
  3694. // This will only do something if the frame is active and our cursor is
  3695. // currently over the client area. If we need to, we will scroll the
  3696. // client over to make the corresponding point visible.
  3697. //
  3698. void ASShare::VIEW_SyncCursorPos
  3699. (
  3700. ASPerson * pasHost,
  3701. int xRemote,
  3702. int yRemote
  3703. )
  3704. {
  3705. POINT ptCursor;
  3706. RECT rcClient;
  3707. int xNewPos;
  3708. int yNewPos;
  3709. int xMargin;
  3710. int yMargin;
  3711. DebugEntry(ASShare::VIEW_SyncCursorPos);
  3712. ValidateView(pasHost);
  3713. if (!pasHost->m_pView->m_viewFocus)
  3714. {
  3715. // The frame isn't active, do nothing
  3716. DC_QUIT;
  3717. }
  3718. //
  3719. // Is our mouse currently over the client area?
  3720. //
  3721. GetCursorPos(&ptCursor);
  3722. ScreenToClient(pasHost->m_pView->m_viewClient, &ptCursor);
  3723. GetClientRect(pasHost->m_pView->m_viewClient, &rcClient);
  3724. if (!PtInRect(&rcClient, ptCursor))
  3725. {
  3726. // No sense in snapping cursor
  3727. DC_QUIT;
  3728. }
  3729. //
  3730. // Is the remote point in range of our view? If not, we must scroll it.
  3731. //
  3732. // The margin is the page size if there's room, nothing if not
  3733. xMargin = pasHost->m_pView->m_viewPgSize.x;
  3734. if (xMargin >= rcClient.right - rcClient.left)
  3735. xMargin = 0;
  3736. xNewPos = pasHost->m_pView->m_viewPos.x;
  3737. if ((xRemote < pasHost->m_pView->m_viewPos.x) ||
  3738. (xRemote >= pasHost->m_pView->m_viewPos.x + (rcClient.right - rcClient.left)))
  3739. {
  3740. //
  3741. // Scroll over more than just enough to pin the point on the left
  3742. // side.
  3743. //
  3744. xNewPos = xRemote - xMargin;
  3745. }
  3746. yMargin = pasHost->m_pView->m_viewPgSize.y;
  3747. if (yMargin >= rcClient.bottom - rcClient.top)
  3748. yMargin = 0;
  3749. yNewPos = pasHost->m_pView->m_viewPos.y;
  3750. if ((yRemote < pasHost->m_pView->m_viewPos.y) ||
  3751. (yRemote >= yNewPos + (rcClient.bottom - rcClient.top)))
  3752. {
  3753. //
  3754. // Scroll over more than just enough to pin the point on the top
  3755. // side.
  3756. //
  3757. yNewPos = yRemote - yMargin;
  3758. }
  3759. VIEWClientScroll(pasHost, xNewPos, yNewPos);
  3760. ptCursor.x = xRemote - pasHost->m_pView->m_viewPos.x;
  3761. ptCursor.y = yRemote - pasHost->m_pView->m_viewPos.y;
  3762. ClientToScreen(pasHost->m_pView->m_viewClient, &ptCursor);
  3763. SetCursorPos(ptCursor.x, ptCursor.y);
  3764. DC_EXIT_POINT:
  3765. DebugExitVOID(ASShare::VIEW_SyncCursorPos);
  3766. }
  3767. //
  3768. // VIEWWindowBarProc()
  3769. //
  3770. LRESULT CALLBACK VIEWWindowBarProc
  3771. (
  3772. HWND hwnd,
  3773. UINT message,
  3774. WPARAM wParam,
  3775. LPARAM lParam
  3776. )
  3777. {
  3778. return(g_asSession.pShare->VIEW_WindowBarProc(hwnd, message, wParam, lParam));
  3779. }
  3780. LRESULT ASShare::VIEW_WindowBarProc
  3781. (
  3782. HWND hwnd,
  3783. UINT message,
  3784. WPARAM wParam,
  3785. LPARAM lParam
  3786. )
  3787. {
  3788. LRESULT rc = 0;
  3789. ASPerson * pasHost;
  3790. DebugEntry(ASShare::VIEW_WindowBarProc);
  3791. pasHost = (ASPerson *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  3792. if (pasHost)
  3793. {
  3794. ValidateView(pasHost);
  3795. }
  3796. switch (message)
  3797. {
  3798. case WM_NCCREATE:
  3799. {
  3800. // Get & save the person this view is for.
  3801. pasHost = (ASPerson *)((LPCREATESTRUCT)lParam)->lpCreateParams;
  3802. ValidateView(pasHost);
  3803. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)pasHost);
  3804. pasHost->m_pView->m_viewWindowBar = hwnd;
  3805. goto DefWndProc;
  3806. break;
  3807. }
  3808. case WM_NCDESTROY:
  3809. {
  3810. if (pasHost != NULL)
  3811. {
  3812. pasHost->m_pView->m_viewWindowBar = NULL;
  3813. }
  3814. goto DefWndProc;
  3815. break;
  3816. }
  3817. case WM_CREATE:
  3818. {
  3819. if (!VIEWWindowBarCreate(pasHost, hwnd))
  3820. {
  3821. ERROR_OUT(("VIEWWndBarProc: couldn't create more item"));
  3822. rc = -1;
  3823. }
  3824. break;
  3825. }
  3826. case WM_SIZE:
  3827. {
  3828. VIEWWindowBarResize(pasHost, hwnd);
  3829. break;
  3830. }
  3831. case WM_HSCROLL:
  3832. {
  3833. VIEWWindowBarItemsScroll(pasHost, wParam, lParam);
  3834. break;
  3835. }
  3836. default:
  3837. DefWndProc:
  3838. {
  3839. rc = DefWindowProc(hwnd, message, wParam, lParam);
  3840. break;
  3841. }
  3842. }
  3843. DebugExitDWORD(ASShare::VIEW_WindowBarProc, rc);
  3844. return(rc);
  3845. }
  3846. //
  3847. // VIEWWindowBarCreate()
  3848. // Handles creation for the window bar. We make the next/prev buttons on
  3849. // the right side, which stay there always. They are disabled if all the
  3850. // window bar items fit, and one or both are enabled if not.
  3851. //
  3852. BOOL ASShare::VIEWWindowBarCreate
  3853. (
  3854. ASPerson * pasHost,
  3855. HWND hwndBar
  3856. )
  3857. {
  3858. BOOL rc = FALSE;
  3859. RECT rect;
  3860. DebugEntry(ASShare::VIEWWindowBarCreate);
  3861. ::GetClientRect(hwndBar, &rect);
  3862. rect.top += m_viewEdgeCY;
  3863. rect.right -= m_viewItemScrollCX;
  3864. //
  3865. // Create the scrollbar, vertically centered, right-justified.
  3866. //
  3867. if (!::CreateWindowEx(0, "ScrollBar", NULL,
  3868. WS_CHILD | WS_VISIBLE | SBS_HORZ | WS_CLIPSIBLINGS | WS_DISABLED,
  3869. rect.right,
  3870. (rect.top + rect.bottom - m_viewItemScrollCY) / 2,
  3871. m_viewItemScrollCX, m_viewItemScrollCY,
  3872. hwndBar, (HMENU)IDVIEW_SCROLL,
  3873. g_asInstance, NULL))
  3874. {
  3875. ERROR_OUT(("VIEWWindowBarCreate: Unable to create scroll ctrl"));
  3876. DC_QUIT;
  3877. }
  3878. //
  3879. // Create the windowbar, an integral number of items wide (including
  3880. // trailing margin).
  3881. //
  3882. pasHost->m_pView->m_viewWindowBarItemFitCount =
  3883. (rect.right - rect.left) / (m_viewItemCX + m_viewEdgeCX);
  3884. if (!::CreateWindowEx(0, VIEW_WINDOWBARITEMS_CLASS_NAME, NULL,
  3885. WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CLIPSIBLINGS,
  3886. rect.left, rect.top,
  3887. pasHost->m_pView->m_viewWindowBarItemFitCount * (m_viewItemCX + m_viewEdgeCX),
  3888. m_viewItemCY,
  3889. hwndBar, (HMENU)IDVIEW_ITEMS,
  3890. g_asInstance, pasHost))
  3891. {
  3892. ERROR_OUT(("VIEWWindowBarCreate: Unable to create window bar item list"));
  3893. DC_QUIT;
  3894. }
  3895. rc = TRUE;
  3896. DC_EXIT_POINT:
  3897. DebugExitBOOL(ASShare::VIEWWindowBarCreate, rc);
  3898. return(rc);
  3899. }
  3900. //
  3901. // VIEWWindowBarResize()
  3902. //
  3903. // This is called when the window bar is resized, due to the frame being
  3904. // sized horizontally.
  3905. //
  3906. // It right-justifies the scroll control, then resizes the window list to
  3907. // hold however many integral items fit across.
  3908. //
  3909. void ASShare::VIEWWindowBarResize
  3910. (
  3911. ASPerson * pasHost,
  3912. HWND hwndBar
  3913. )
  3914. {
  3915. RECT rc;
  3916. DebugEntry(ASShare::VIEWWindowBarResize);
  3917. ValidateView(pasHost);
  3918. //
  3919. // Recalculate the page size, the # of items that fit across.
  3920. // If it's different, invalidate the right side of the window bar client.
  3921. // Move the scrollbar control, and update the scroll info.
  3922. //
  3923. // What might change is the number that fit across.
  3924. ::GetClientRect(hwndBar, &rc);
  3925. rc.top += m_viewEdgeCY;
  3926. rc.right -= m_viewItemScrollCX;
  3927. // Move the scroll control, right justified.
  3928. ::MoveWindow(::GetDlgItem(hwndBar, IDVIEW_SCROLL), rc.right,
  3929. (rc.top + rc.bottom - m_viewItemScrollCY) / 2,
  3930. m_viewItemScrollCX, m_viewItemScrollCY, TRUE);
  3931. //
  3932. // Resize the window items list to fit an integral # of items again.
  3933. //
  3934. pasHost->m_pView->m_viewWindowBarItemFitCount =
  3935. (rc.right - rc.left) / (m_viewItemCX + m_viewEdgeCX);
  3936. ::MoveWindow(::GetDlgItem(hwndBar, IDVIEW_ITEMS), rc.left, rc.top,
  3937. pasHost->m_pView->m_viewWindowBarItemFitCount * (m_viewItemCX + m_viewEdgeCX),
  3938. m_viewItemCY, TRUE);
  3939. //
  3940. // Update the scroll page and pos if necessary.
  3941. //
  3942. VIEWWindowBarItemsScroll(pasHost, GET_WM_HSCROLL_MPS(SB_ENDSCROLL, 0, NULL));
  3943. DebugExitVOID(ASShare::VIEWWindowBarResize);
  3944. }
  3945. //
  3946. // VIEW_WindowBarUpdateItem()
  3947. //
  3948. // This is ONLY called for items, in the new SWL packet, that are window
  3949. // bar items. We don't call it with non-windowbar items. When done
  3950. // looping through the SWL entries, we can then remove the items on the
  3951. // window bar that were NOT seen in the new SWL packet.
  3952. //
  3953. // We will either create a new item on the window bar, or update an existing
  3954. // one. In the first case, that is always a change. In the latter, there's
  3955. // a change only if the item text changed.
  3956. //
  3957. BOOL ASShare::VIEW_WindowBarUpdateItem
  3958. (
  3959. ASPerson * pasHost,
  3960. PSWLWINATTRIBUTES pWinNew,
  3961. LPSTR pText
  3962. )
  3963. {
  3964. PWNDBAR_ITEM pItem;
  3965. BOOL viewAnyChanges = FALSE;
  3966. DebugEntry(ASView::VIEW_WindowBarUpdateItem);
  3967. ValidateView(pasHost);
  3968. ASSERT(pWinNew->flags & SWL_FLAG_WINDOW_HOSTED);
  3969. ASSERT(pWinNew->flags & SWL_FLAG_WINDOW_TASKBAR);
  3970. //
  3971. // NOTE:
  3972. // aswlLast holds the _previous_ attributes for the windows, from
  3973. // the previous SWL packet. pWinNew holds the _new_ attributes for
  3974. // the window, from the SWL packet being processed, and these
  3975. // haven't taken effect yet.
  3976. //
  3977. // Does this new item already exist on the tray?
  3978. COM_BasedListFind(LIST_FIND_FROM_FIRST, &(pasHost->m_pView->m_viewWindowBarItems),
  3979. (void**)&pItem, FIELD_OFFSET(WNDBAR_ITEM, chain),
  3980. FIELD_OFFSET(WNDBAR_ITEM, winIDRemote),
  3981. pWinNew->winID, FIELD_SIZE(WNDBAR_ITEM, winIDRemote));
  3982. if (pItem)
  3983. {
  3984. //
  3985. // Update this item, and mark it as seen.
  3986. //
  3987. ASSERT(pItem->winIDRemote == pWinNew->winID);
  3988. pItem->flags = pWinNew->flags | SWL_FLAG_INTERNAL_SEEN;
  3989. //
  3990. // Is anything going to result in a visual change? That's only
  3991. // the text currently. And we only display VIEW_MAX_ITEM_CHARS at
  3992. // most, an end ellipsis if there's too much.
  3993. //
  3994. //
  3995. // NOTE that the items are always created with maximum space for
  3996. // text, since we cannot realloc.
  3997. //
  3998. if (lstrcmp(pItem->szText, pText))
  3999. {
  4000. lstrcpyn(pItem->szText, pText, sizeof(pItem->szText));
  4001. viewAnyChanges = TRUE;
  4002. }
  4003. }
  4004. else
  4005. {
  4006. //
  4007. // Create a new item.
  4008. //
  4009. //
  4010. // A WNDBAR_ITEM also includes maximum space for text that we will
  4011. // store.
  4012. //
  4013. pItem = (PWNDBAR_ITEM) new WNDBAR_ITEM;
  4014. if (!pItem)
  4015. {
  4016. ERROR_OUT(("VIEW_WindowBarUpdateItem: no memory to create new item for remote hwnd 0x%08x",
  4017. pWinNew->winID));
  4018. }
  4019. else
  4020. {
  4021. ::ZeroMemory(pItem, sizeof(*pItem));
  4022. SET_STAMP(pItem, WNDITEM);
  4023. pItem->winIDRemote = pWinNew->winID;
  4024. //
  4025. // Add SEEN to the flags; when we're done we'll remove items we haven't
  4026. // seen.
  4027. //
  4028. pItem->flags = pWinNew->flags | SWL_FLAG_INTERNAL_SEEN;
  4029. lstrcpyn(pItem->szText, pText, sizeof(pItem->szText));
  4030. // Append to end of list
  4031. COM_BasedListInsertBefore(&(pasHost->m_pView->m_viewWindowBarItems),
  4032. &(pItem->chain));
  4033. // Success!
  4034. pasHost->m_pView->m_viewWindowBarItemCount++;
  4035. viewAnyChanges = TRUE;
  4036. }
  4037. }
  4038. DebugExitBOOL(ASShare::VIEW_UpdateWindowItem, viewAnyChanges);
  4039. return(viewAnyChanges);
  4040. }
  4041. //
  4042. // VIEW_WindowBarEndUpdateItems()
  4043. //
  4044. // This turns redraw on and invalidates the window bar so it will repaint.
  4045. //
  4046. void ASShare::VIEW_WindowBarEndUpdateItems
  4047. (
  4048. ASPerson * pasHost,
  4049. BOOL viewAnyChanges
  4050. )
  4051. {
  4052. PWNDBAR_ITEM pItem;
  4053. PWNDBAR_ITEM pNext;
  4054. DebugEntry(ASShare::VIEW_WindowBarEndUpdateItems);
  4055. ValidateView(pasHost);
  4056. //
  4057. // Walk the window bar item list. Keep the ones marked as seen, but
  4058. // remove the ones we haven't seen.
  4059. //
  4060. pItem = (PWNDBAR_ITEM)COM_BasedListFirst(&(pasHost->m_pView->m_viewWindowBarItems),
  4061. FIELD_OFFSET(WNDBAR_ITEM, chain));
  4062. while (pItem)
  4063. {
  4064. pNext = (PWNDBAR_ITEM)COM_BasedListNext(&(pasHost->m_pView->m_viewWindowBarItems),
  4065. pItem, FIELD_OFFSET(WNDBAR_ITEM, chain));
  4066. //
  4067. // If this item wasn't seen (existing & still existing, or new)
  4068. // during processing, it's gone. Delete it.
  4069. //
  4070. if (pItem->flags & SWL_FLAG_INTERNAL_SEEN)
  4071. {
  4072. //
  4073. // This was just added or is still around, keep it.
  4074. // But of course clear the flag, so we are clear for
  4075. // processing the next SWL packet.
  4076. //
  4077. pItem->flags &= ~SWL_FLAG_INTERNAL_SEEN;
  4078. }
  4079. else
  4080. {
  4081. //
  4082. // Remove it.
  4083. //
  4084. // We're killing the active item, clear it out.
  4085. if (pItem == pasHost->m_pView->m_viewWindowBarActiveItem)
  4086. {
  4087. pasHost->m_pView->m_viewWindowBarActiveItem = NULL;
  4088. }
  4089. COM_BasedListRemove(&(pItem->chain));
  4090. delete pItem;
  4091. --pasHost->m_pView->m_viewWindowBarItemCount;
  4092. ASSERT(pasHost->m_pView->m_viewWindowBarItemCount >= 0);
  4093. //
  4094. // Something changed in our list
  4095. //
  4096. viewAnyChanges = TRUE;
  4097. }
  4098. pItem = pNext;
  4099. }
  4100. //
  4101. // No need to check for changes here--they would only occur if
  4102. // an item was removed in the middle, caused by Destroy which we already
  4103. // account for, or if items were appended to the end, which we account
  4104. // for in Update.
  4105. //
  4106. if (viewAnyChanges)
  4107. {
  4108. // Turn off redraw on window list
  4109. ::SendDlgItemMessage(pasHost->m_pView->m_viewWindowBar, IDVIEW_ITEMS,
  4110. WM_SETREDRAW, FALSE, 0);
  4111. // Adjust pos
  4112. VIEWWindowBarItemsScroll(pasHost, GET_WM_HSCROLL_MPS(SB_ENDSCROLL, 0, NULL));
  4113. // Figure out active window again.
  4114. VIEW_WindowBarChangedActiveWindow(pasHost);
  4115. // Turn back on redraw
  4116. ::SendDlgItemMessage(pasHost->m_pView->m_viewWindowBar, IDVIEW_ITEMS,
  4117. WM_SETREDRAW, TRUE, 0);
  4118. // Repaint the items.
  4119. ::InvalidateRect(::GetDlgItem(pasHost->m_pView->m_viewWindowBar, IDVIEW_ITEMS),
  4120. NULL, TRUE);
  4121. }
  4122. else
  4123. {
  4124. //
  4125. // ALWAYS do this -- our real SWL list has changed, regardless of whether
  4126. // the window bar has. And therefore we may have a different ancestor
  4127. // relationship.
  4128. //
  4129. VIEW_WindowBarChangedActiveWindow(pasHost);
  4130. }
  4131. DebugExitVOID(ASShare::VIEW_EndUpdateWindowList);
  4132. }
  4133. //
  4134. // VIEW_WindowBarChangedActiveWindow()
  4135. //
  4136. // This is called when the active window has changed, as discovered via an
  4137. // AWC packet from the host, or when we get a new SWL packet and the shared
  4138. // list is different so the window bar items may have changed.
  4139. //
  4140. // It's quite common for the active window to be (a) nothing, meaning no
  4141. // shared app window is active or (b) not something relating to what's on
  4142. // the window bar currently. The latter is a transitory condition, caused
  4143. // because SWL packets come before AWC packets.
  4144. //
  4145. void ASShare::VIEW_WindowBarChangedActiveWindow(ASPerson * pasHost)
  4146. {
  4147. PWNDBAR_ITEM pItem;
  4148. PSWLWINATTRIBUTES pWin;
  4149. int iWin;
  4150. UINT_PTR activeWinID;
  4151. TSHR_UINT32 ownerWinID;
  4152. DebugEntry(ASShare::VIEW_WindowBarChangedActiveWindow);
  4153. ValidateView(pasHost);
  4154. //
  4155. // Map this remote window to the closest window bar item in the
  4156. // ancestor hierarchy.
  4157. //
  4158. pItem = NULL;
  4159. activeWinID = pasHost->awcActiveWinID;
  4160. while (activeWinID != 0)
  4161. {
  4162. //
  4163. // Is this on the window bar?
  4164. //
  4165. COM_BasedListFind(LIST_FIND_FROM_FIRST,
  4166. &(pasHost->m_pView->m_viewWindowBarItems),
  4167. (void**)&pItem, FIELD_OFFSET(WNDBAR_ITEM, chain),
  4168. FIELD_OFFSET(WNDBAR_ITEM, winIDRemote),
  4169. activeWinID, FIELD_SIZE(WNDBAR_ITEM, winIDRemote));
  4170. if (pItem)
  4171. {
  4172. // Yes.
  4173. TRACE_OUT(("VIEW_UpdateActiveWindow: Window 0x%08x found", activeWinID));
  4174. break;
  4175. }
  4176. //
  4177. // Try to go up the chain to this window's owner. Find this item,
  4178. // then grab the owner of it, and try again.
  4179. //
  4180. ownerWinID = 0;
  4181. for (iWin = 0, pWin = pasHost->m_pView->m_aswlLast;
  4182. iWin < pasHost->m_pView->m_swlCount;
  4183. iWin++, pWin++)
  4184. {
  4185. if (pWin->winID == activeWinID)
  4186. {
  4187. // Found it.
  4188. ownerWinID = pWin->ownerWinID;
  4189. break;
  4190. }
  4191. }
  4192. activeWinID = ownerWinID;
  4193. }
  4194. //
  4195. // Now see if the active item is different.
  4196. //
  4197. VIEWWindowBarChangeActiveItem(pasHost, pItem);
  4198. DebugExitVOID(ASShare::VIEW_WindowBarChangedActiveWindow);
  4199. }
  4200. //
  4201. // VIEWWindowBarFirstVisibleItem()
  4202. //
  4203. // This returns a pointer to the first visible item. We must loop through
  4204. // the invisible items first. Since this doesn't happen with a lot of
  4205. // frequence, and the size of the list is rarely that big, this is fine.
  4206. //
  4207. // We return NULL if the list is empty.
  4208. //
  4209. PWNDBAR_ITEM ASShare::VIEWWindowBarFirstVisibleItem(ASPerson * pasHost)
  4210. {
  4211. PWNDBAR_ITEM pItem;
  4212. int iItem;
  4213. ValidateView(pasHost);
  4214. if (!pasHost->m_pView->m_viewWindowBarItemCount)
  4215. {
  4216. pItem = NULL;
  4217. DC_QUIT;
  4218. }
  4219. ASSERT(pasHost->m_pView->m_viewWindowBarItemFirst < pasHost->m_pView->m_viewWindowBarItemCount);
  4220. pItem = (PWNDBAR_ITEM)COM_BasedListFirst(&(pasHost->m_pView->m_viewWindowBarItems),
  4221. FIELD_OFFSET(WNDBAR_ITEM, chain));
  4222. for (iItem = 0; iItem < pasHost->m_pView->m_viewWindowBarItemFirst; iItem++)
  4223. {
  4224. ASSERT(pItem);
  4225. pItem = (PWNDBAR_ITEM)COM_BasedListNext(&(pasHost->m_pView->m_viewWindowBarItems),
  4226. pItem, FIELD_OFFSET(WNDBAR_ITEM, chain));
  4227. }
  4228. ASSERT(pItem);
  4229. DC_EXIT_POINT:
  4230. DebugExitPVOID(ASShare::VIEWWindowBarFirstVisibleItem, pItem);
  4231. return(pItem);
  4232. }
  4233. //
  4234. // VIEWWindowBarChangeActiveItem()
  4235. //
  4236. // Updates the active item on the window bar. This happens when either
  4237. // we get a new AWC packet telling us there's a new active window on the host,
  4238. // or when we get a SWL packet, which may have added/removed items. This
  4239. // also happens when one is clicked on and the user is in control of the host.
  4240. //
  4241. void ASShare::VIEWWindowBarChangeActiveItem
  4242. (
  4243. ASPerson * pasHost,
  4244. PWNDBAR_ITEM pItem
  4245. )
  4246. {
  4247. DebugEntry(ASShare::VIEWWindowBarChangeActiveItem);
  4248. //
  4249. // If it's the active one already, nothing to do.
  4250. //
  4251. if (pItem == pasHost->m_pView->m_viewWindowBarActiveItem)
  4252. {
  4253. TRACE_OUT(("VIEWWindowBarChangeActiveItem: activating current item, nothing to do"));
  4254. DC_QUIT;
  4255. }
  4256. //
  4257. // Now make the visual change
  4258. //
  4259. if (pasHost->m_pView->m_viewWindowBarActiveItem)
  4260. {
  4261. VIEWWindowBarItemsInvalidate(pasHost, pasHost->m_pView->m_viewWindowBarActiveItem);
  4262. }
  4263. pasHost->m_pView->m_viewWindowBarActiveItem = pItem;
  4264. if (pItem)
  4265. {
  4266. VIEWWindowBarItemsInvalidate(pasHost, pItem);
  4267. }
  4268. DC_EXIT_POINT:
  4269. DebugExitVOID(ASShare::VIEWWindowBarChangeActiveItem);
  4270. }
  4271. //
  4272. // VIEWWindowBarItemsScroll()
  4273. //
  4274. // This is called when the end user presses a scroll button to shuffle over
  4275. // the visible window bar items. And also when items are added/removed
  4276. // so that scroll stuff is adjusted.
  4277. //
  4278. void ASShare::VIEWWindowBarItemsScroll
  4279. (
  4280. ASPerson * pasHost,
  4281. WPARAM wParam,
  4282. LPARAM lParam
  4283. )
  4284. {
  4285. int oldPos;
  4286. int newPos;
  4287. SCROLLINFO si;
  4288. DebugEntry(ASShare::VIEWWindowBarItemsScroll);
  4289. ValidateView(pasHost);
  4290. oldPos = pasHost->m_pView->m_viewWindowBarItemFirst;
  4291. switch (GET_WM_HSCROLL_CODE(wParam, lParam))
  4292. {
  4293. case SB_LINEUP:
  4294. case SB_PAGEUP:
  4295. newPos = oldPos - 1;
  4296. break;
  4297. case SB_LINEDOWN:
  4298. case SB_PAGEDOWN:
  4299. newPos = oldPos + 1;
  4300. break;
  4301. case SB_TOP:
  4302. newPos = 0;
  4303. break;
  4304. case SB_BOTTOM:
  4305. newPos = pasHost->m_pView->m_viewWindowBarItemCount;
  4306. break;
  4307. case SB_THUMBTRACK:
  4308. case SB_THUMBPOSITION:
  4309. newPos = GET_WM_HSCROLL_POS(wParam, lParam);
  4310. break;
  4311. default:
  4312. newPos = oldPos;
  4313. break;
  4314. }
  4315. //
  4316. // Pin position into range, taking care to show the maximum number
  4317. // of items that will fit in the space.
  4318. //
  4319. if (newPos + pasHost->m_pView->m_viewWindowBarItemFitCount >
  4320. pasHost->m_pView->m_viewWindowBarItemCount)
  4321. {
  4322. newPos = pasHost->m_pView->m_viewWindowBarItemCount -
  4323. pasHost->m_pView->m_viewWindowBarItemFitCount;
  4324. }
  4325. if (newPos < 0)
  4326. newPos = 0;
  4327. //
  4328. // Has the position changed?
  4329. //
  4330. if (newPos != oldPos)
  4331. {
  4332. pasHost->m_pView->m_viewWindowBarItemFirst = newPos;
  4333. //
  4334. // Scroll the item area over. This will do nothing if redraw is off.
  4335. // Conveniently!
  4336. //
  4337. ::ScrollWindowEx(::GetDlgItem(pasHost->m_pView->m_viewWindowBar, IDVIEW_ITEMS),
  4338. (oldPos - newPos) * (m_viewItemCX + m_viewEdgeCX),
  4339. 0,
  4340. NULL, NULL, NULL, NULL,
  4341. SW_INVALIDATE | SW_ERASE);
  4342. }
  4343. //
  4344. // If nothing's changed, no big deal.
  4345. //
  4346. ::ZeroMemory(&si, sizeof(si));
  4347. si.cbSize = sizeof(SCROLLINFO);
  4348. si.fMask = SIF_DISABLENOSCROLL | SIF_POS | SIF_PAGE | SIF_RANGE;
  4349. si.nMin = 0;
  4350. si.nMax = pasHost->m_pView->m_viewWindowBarItemCount - 1;
  4351. si.nPage = pasHost->m_pView->m_viewWindowBarItemFitCount;
  4352. si.nPos = pasHost->m_pView->m_viewWindowBarItemFirst;
  4353. ::SetScrollInfo(::GetDlgItem(pasHost->m_pView->m_viewWindowBar, IDVIEW_SCROLL),
  4354. SB_CTL, &si, TRUE);
  4355. DebugExitVOID(ASShare::VIEWWindowBarItemsScroll);
  4356. }
  4357. //
  4358. // VIEWWindowBarItemsProc()
  4359. //
  4360. LRESULT CALLBACK VIEWWindowBarItemsProc
  4361. (
  4362. HWND hwnd,
  4363. UINT message,
  4364. WPARAM wParam,
  4365. LPARAM lParam
  4366. )
  4367. {
  4368. return(g_asSession.pShare->VIEW_WindowBarItemsProc(hwnd, message, wParam, lParam));
  4369. }
  4370. LRESULT ASShare::VIEW_WindowBarItemsProc
  4371. (
  4372. HWND hwnd,
  4373. UINT message,
  4374. WPARAM wParam,
  4375. LPARAM lParam
  4376. )
  4377. {
  4378. LRESULT rc = 0;
  4379. ASPerson * pasHost;
  4380. DebugEntry(ASShare::VIEW_WindowBarItemsProc);
  4381. pasHost = (ASPerson *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  4382. if (pasHost)
  4383. {
  4384. ValidateView(pasHost);
  4385. }
  4386. switch (message)
  4387. {
  4388. case WM_NCCREATE:
  4389. {
  4390. // Get & save the person this view is for.
  4391. pasHost = (ASPerson *)((LPCREATESTRUCT)lParam)->lpCreateParams;
  4392. ValidateView(pasHost);
  4393. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)pasHost);
  4394. COM_BasedListInit(&(pasHost->m_pView->m_viewWindowBarItems));
  4395. goto DefWndProc;
  4396. break;
  4397. }
  4398. case WM_NCDESTROY:
  4399. {
  4400. if (pasHost != NULL)
  4401. {
  4402. // Loop through the items, killing the head, until done.
  4403. PWNDBAR_ITEM pItem;
  4404. while (pItem = (PWNDBAR_ITEM)COM_BasedListFirst(
  4405. &(pasHost->m_pView->m_viewWindowBarItems),
  4406. FIELD_OFFSET(WNDBAR_ITEM, chain)))
  4407. {
  4408. COM_BasedListRemove(&(pItem->chain));
  4409. delete pItem;
  4410. }
  4411. //
  4412. // Zero these out for safety. Yes, we're about to free
  4413. // m_pView altogether, so find out if we're referencing
  4414. // stuff that's gone.
  4415. //
  4416. pasHost->m_pView->m_viewWindowBarItemCount = 0;
  4417. pasHost->m_pView->m_viewWindowBarActiveItem = NULL;
  4418. }
  4419. goto DefWndProc;
  4420. break;
  4421. }
  4422. case WM_ENABLE:
  4423. {
  4424. // Repaint the items, disabled or pressable.
  4425. ::InvalidateRect(hwnd, NULL, FALSE);
  4426. break;
  4427. }
  4428. case WM_PAINT:
  4429. {
  4430. VIEWWindowBarItemsPaint(pasHost, hwnd);
  4431. break;
  4432. }
  4433. case WM_LBUTTONDOWN:
  4434. {
  4435. VIEWWindowBarItemsClick(pasHost, hwnd,
  4436. GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  4437. break;
  4438. }
  4439. default:
  4440. DefWndProc:
  4441. {
  4442. rc = DefWindowProc(hwnd, message, wParam, lParam);
  4443. break;
  4444. }
  4445. }
  4446. DebugExitDWORD(ASShare::VIEW_WindowBarItemsProc, rc);
  4447. return(rc);
  4448. }
  4449. //
  4450. // VIEWWindowBarItemsPaint()
  4451. //
  4452. void ASShare::VIEWWindowBarItemsPaint
  4453. (
  4454. ASPerson * pasHost,
  4455. HWND hwndItems
  4456. )
  4457. {
  4458. HFONT hfnT;
  4459. COLORREF clrText;
  4460. int bkMode;
  4461. PWNDBAR_ITEM pItem;
  4462. PAINTSTRUCT ps;
  4463. int xT;
  4464. RECT rcItem;
  4465. DebugEntry(ASShare::VIEWWindowBarItemsPaint);
  4466. ValidateView(pasHost);
  4467. ::BeginPaint(hwndItems, &ps);
  4468. //
  4469. // Skip over the visible items to the left of the paint area.
  4470. //
  4471. xT = 0;
  4472. pItem = VIEWWindowBarFirstVisibleItem(pasHost);
  4473. while (pItem && (xT + m_viewItemCX < ps.rcPaint.left))
  4474. {
  4475. pItem = (PWNDBAR_ITEM)COM_BasedListNext(&(pasHost->m_pView->m_viewWindowBarItems),
  4476. pItem, FIELD_OFFSET(WNDBAR_ITEM, chain));
  4477. xT += m_viewItemCX + m_viewEdgeCX;
  4478. }
  4479. //
  4480. // Setup painting objects, etc.
  4481. //
  4482. hfnT = SelectFont(ps.hdc, ::GetStockObject(DEFAULT_GUI_FONT));
  4483. if ((pasHost->m_caControlledBy != m_pasLocal) || pasHost->m_caControlPaused)
  4484. {
  4485. clrText = ::GetSysColor(COLOR_GRAYTEXT);
  4486. }
  4487. else
  4488. {
  4489. clrText = ::GetSysColor(COLOR_BTNTEXT);
  4490. }
  4491. clrText = ::SetTextColor(ps.hdc, clrText);
  4492. bkMode = ::SetBkMode(ps.hdc, TRANSPARENT);
  4493. //
  4494. // Now paint the visible items within the paint area.
  4495. //
  4496. while (pItem && (xT < ps.rcPaint.right))
  4497. {
  4498. rcItem.left = xT;
  4499. rcItem.top = 0;
  4500. rcItem.right = rcItem.left + m_viewItemCX;
  4501. rcItem.bottom = rcItem.top + m_viewItemCY;
  4502. //
  4503. // Draw button area, pressed in & checked for current tray item.
  4504. //
  4505. DrawFrameControl(ps.hdc, &rcItem, DFC_BUTTON,
  4506. DFCS_BUTTONPUSH | DFCS_ADJUSTRECT |
  4507. ((pItem == pasHost->m_pView->m_viewWindowBarActiveItem) ? (DFCS_PUSHED | DFCS_CHECKED) : 0));
  4508. // Subtract some margin.
  4509. ::InflateRect(&rcItem, -m_viewEdgeCX, -m_viewEdgeCY);
  4510. if (pItem == pasHost->m_pView->m_viewWindowBarActiveItem)
  4511. {
  4512. // Offset one for pushed effect
  4513. ::OffsetRect(&rcItem, 1, 1);
  4514. }
  4515. //
  4516. // Draw icon
  4517. //
  4518. ::DrawIconEx(ps.hdc, rcItem.left,
  4519. (rcItem.top + rcItem.bottom - ::GetSystemMetrics(SM_CYSMICON)) / 2,
  4520. g_hetASIconSmall,
  4521. ::GetSystemMetrics(SM_CXSMICON),
  4522. ::GetSystemMetrics(SM_CYSMICON),
  4523. 0, NULL, DI_NORMAL);
  4524. rcItem.left += ::GetSystemMetrics(SM_CXSMICON) + m_viewEdgeCX;
  4525. //
  4526. // Draw item text
  4527. //
  4528. ::DrawText(ps.hdc, pItem->szText, -1, &rcItem, DT_NOCLIP | DT_EXPANDTABS |
  4529. DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
  4530. pItem = (PWNDBAR_ITEM)COM_BasedListNext(&(pasHost->m_pView->m_viewWindowBarItems),
  4531. pItem, FIELD_OFFSET(WNDBAR_ITEM, chain));
  4532. xT += m_viewItemCX + m_viewEdgeCX;
  4533. }
  4534. ::SetBkMode(ps.hdc, bkMode);
  4535. ::SetTextColor(ps.hdc, clrText);
  4536. SelectFont(ps.hdc, hfnT);
  4537. ::EndPaint(hwndItems, &ps);
  4538. DebugExitVOID(ASShare::VIEWWindowBarItemsPaint);
  4539. }
  4540. //
  4541. // VIEWWindowBarItemsClick()
  4542. //
  4543. // Handles a left click on the window bar area. When we are in control, this
  4544. // will try to activate/restore the remote window the clicked item represents.
  4545. //
  4546. void ASShare::VIEWWindowBarItemsClick
  4547. (
  4548. ASPerson * pasHost,
  4549. HWND hwndItems,
  4550. int x,
  4551. int y
  4552. )
  4553. {
  4554. RECT rc;
  4555. PWNDBAR_ITEM pItemT;
  4556. DebugEntry(ASShare::VIEWWindowBarClick);
  4557. ValidateView(pasHost);
  4558. //
  4559. // If we're not in control of this host, or there aren't any items, we're
  4560. // done.
  4561. //
  4562. if ((pasHost->m_caControlledBy != m_pasLocal) ||
  4563. pasHost->m_caControlPaused ||
  4564. (!pasHost->m_pView->m_viewWindowBarItemCount))
  4565. {
  4566. DC_QUIT;
  4567. }
  4568. ::GetClientRect(hwndItems, &rc);
  4569. //
  4570. // Start at first visible item.
  4571. //
  4572. pItemT = VIEWWindowBarFirstVisibleItem(pasHost);
  4573. while (pItemT && (rc.left < rc.right))
  4574. {
  4575. // Is x in range?
  4576. if ((x >= rc.left) && (x < rc.left + m_viewItemCX))
  4577. {
  4578. // YES! We've found the item. If it's different than the
  4579. // current one, send a packet to the host.
  4580. //
  4581. // LAURABU BUGBUG:
  4582. // Should we do this always? Is it possible to have an active
  4583. // item whose z-order would change if the active button was
  4584. // pressed again?
  4585. //
  4586. // We're trying to avoid sending a ton of requests from somebody
  4587. // who clicks repeatedly on the same button, when we haven't
  4588. // received an AWC notification back.
  4589. //
  4590. VIEWWindowBarDoActivate(pasHost, pItemT);
  4591. break;
  4592. }
  4593. pItemT = (PWNDBAR_ITEM)COM_BasedListNext(&(pasHost->m_pView->m_viewWindowBarItems),
  4594. pItemT, FIELD_OFFSET(WNDBAR_ITEM, chain));
  4595. rc.left += m_viewItemCX + m_viewEdgeCX;
  4596. }
  4597. DC_EXIT_POINT:
  4598. DebugExitVOID(ASShare::VIEWWindowBarItemsClick);
  4599. }
  4600. //
  4601. // VIEWWindowBarDoActivate()
  4602. //
  4603. // Sends command to remote host requesting the window be activated and
  4604. // maybe unminimized.
  4605. //
  4606. // This is used when clicking on a button or choosing the window's item in
  4607. // the Applications menu.
  4608. //
  4609. void ASShare::VIEWWindowBarDoActivate
  4610. (
  4611. ASPerson * pasHost,
  4612. PWNDBAR_ITEM pItem
  4613. )
  4614. {
  4615. DebugEntry(ASShare::VIEWWindowBarDoActivate);
  4616. ValidateView(pasHost);
  4617. if (pItem != pasHost->m_pView->m_viewWindowBarActiveItem)
  4618. {
  4619. // Activate it. If we can't send an activate request,
  4620. // do not update the active item.
  4621. //
  4622. if (!AWC_SendMsg(pasHost->mcsID, AWC_MSG_ACTIVATE_WINDOW,
  4623. pItem->winIDRemote, 0))
  4624. {
  4625. ERROR_OUT(("VIEWWindowBarDoActivate: can't send AWC packet so failing"));
  4626. }
  4627. else
  4628. {
  4629. VIEWWindowBarChangeActiveItem(pasHost, pItem);
  4630. }
  4631. }
  4632. // Try to restore if minimized no matter what.
  4633. if (pItem->flags & SWL_FLAG_WINDOW_MINIMIZED)
  4634. {
  4635. AWC_SendMsg(pasHost->mcsID, AWC_MSG_RESTORE_WINDOW, pItem->winIDRemote, 0);
  4636. }
  4637. DebugExitVOID(ASShare::VIEWWindowBarDoActivate);
  4638. }
  4639. //
  4640. // VIEWWindowBarItemsInvalidate()
  4641. //
  4642. // This invalidates the window bar item, if it's visible in the window bar
  4643. // list currently.
  4644. //
  4645. void ASShare::VIEWWindowBarItemsInvalidate
  4646. (
  4647. ASPerson * pasHost,
  4648. PWNDBAR_ITEM pItem
  4649. )
  4650. {
  4651. PWNDBAR_ITEM pItemT;
  4652. RECT rc;
  4653. DebugEntry(ASShare::VIEWWindowBarItemsInvalidate);
  4654. ValidateView(pasHost);
  4655. ASSERT(pItem);
  4656. ::GetClientRect(::GetDlgItem(pasHost->m_pView->m_viewWindowBar, IDVIEW_ITEMS),
  4657. &rc);
  4658. //
  4659. // Start at the first visible item, and see if any in the visible range
  4660. // are this one. There will never be that many items visible across,
  4661. // it's not heinous to do this.
  4662. //
  4663. pItemT = VIEWWindowBarFirstVisibleItem(pasHost);
  4664. while (pItemT && (rc.left < rc.right))
  4665. {
  4666. if (pItemT == pItem)
  4667. {
  4668. // Found it, it's in the visible range. Invalidate it.
  4669. rc.right = rc.left + m_viewItemCX;
  4670. ::InvalidateRect(::GetDlgItem(pasHost->m_pView->m_viewWindowBar,
  4671. IDVIEW_ITEMS), &rc, TRUE);
  4672. break;
  4673. }
  4674. pItemT = (PWNDBAR_ITEM)COM_BasedListNext(&(pasHost->m_pView->m_viewWindowBarItems),
  4675. pItemT, FIELD_OFFSET(WNDBAR_ITEM, chain));
  4676. rc.left += m_viewItemCX + m_viewEdgeCX;
  4677. }
  4678. DebugExitVOID(ASShare::VIEWWindowBarItemsInvalidate);
  4679. }
  4680. //
  4681. // VIEWFullScreenExitProc()
  4682. //
  4683. // Window handler for full screen exit button.
  4684. //
  4685. LRESULT CALLBACK VIEWFullScreenExitProc
  4686. (
  4687. HWND hwnd,
  4688. UINT message,
  4689. WPARAM wParam,
  4690. LPARAM lParam
  4691. )
  4692. {
  4693. return(g_asSession.pShare->VIEW_FullScreenExitProc(hwnd, message, wParam, lParam));
  4694. }
  4695. //
  4696. // VIEW_FullScreenExitProc()
  4697. //
  4698. LRESULT ASShare::VIEW_FullScreenExitProc
  4699. (
  4700. HWND hwnd,
  4701. UINT message,
  4702. WPARAM wParam,
  4703. LPARAM lParam
  4704. )
  4705. {
  4706. LRESULT rc = 0;
  4707. ASPerson * pasHost;
  4708. DebugEntry(VIEW_FullScreenExitProc);
  4709. pasHost = (ASPerson *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  4710. if (pasHost)
  4711. {
  4712. ValidateView(pasHost);
  4713. }
  4714. switch (message)
  4715. {
  4716. case WM_NCCREATE:
  4717. {
  4718. // Get the passed in host pointer, and set in our window long
  4719. pasHost = (ASPerson *)((LPCREATESTRUCT)lParam)->lpCreateParams;
  4720. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)pasHost);
  4721. goto DefWndProc;
  4722. break;
  4723. }
  4724. case WM_NCDESTROY:
  4725. {
  4726. //
  4727. // Make sure tracking is stopped.
  4728. //
  4729. pasHost->m_pView->m_viewFullScreenExitTrack = FALSE;
  4730. break;
  4731. }
  4732. case WM_ERASEBKGND:
  4733. {
  4734. rc = TRUE;
  4735. break;
  4736. }
  4737. case WM_PAINT:
  4738. {
  4739. VIEWFullScreenExitPaint(pasHost, hwnd);
  4740. break;
  4741. }
  4742. case WM_LBUTTONDOWN:
  4743. {
  4744. //
  4745. // Start tracking to move or click button.
  4746. //
  4747. pasHost->m_pView->m_viewFullScreenExitTrack = TRUE;
  4748. pasHost->m_pView->m_viewFullScreenExitMove = FALSE;
  4749. // Original click, relative to our client
  4750. pasHost->m_pView->m_viewFullScreenExitStart.x =
  4751. GET_X_LPARAM(lParam);
  4752. pasHost->m_pView->m_viewFullScreenExitStart.y =
  4753. GET_Y_LPARAM(lParam);
  4754. // Set capture, and wait for moves/button up
  4755. SetCapture(hwnd);
  4756. break;
  4757. }
  4758. case WM_MOUSEMOVE:
  4759. {
  4760. if (pasHost->m_pView->m_viewFullScreenExitTrack)
  4761. {
  4762. POINT ptMove;
  4763. ptMove.x = GET_X_LPARAM(lParam);
  4764. ptMove.y = GET_Y_LPARAM(lParam);
  4765. //
  4766. // If we're not in move mode, see if this has pushed us over
  4767. // the tolerance.
  4768. //
  4769. if (!pasHost->m_pView->m_viewFullScreenExitMove)
  4770. {
  4771. if ((abs(ptMove.x - pasHost->m_pView->m_viewFullScreenExitStart.x) >
  4772. GetSystemMetrics(SM_CXDRAG)) ||
  4773. (abs(ptMove.y - pasHost->m_pView->m_viewFullScreenExitStart.y) >
  4774. GetSystemMetrics(SM_CYDRAG)))
  4775. {
  4776. //
  4777. // User has moved out of tolerance zone, must be
  4778. // dragging to move the button out of the way.
  4779. //
  4780. pasHost->m_pView->m_viewFullScreenExitMove = TRUE;
  4781. }
  4782. }
  4783. if (pasHost->m_pView->m_viewFullScreenExitMove)
  4784. {
  4785. RECT rcWindow;
  4786. //
  4787. // Move the button so that the cursor is over the
  4788. // same point as originally clicked on.
  4789. //
  4790. // Get our current position, in parent coordsinates.
  4791. GetWindowRect(hwnd, &rcWindow);
  4792. MapWindowPoints(NULL, GetParent(hwnd), (LPPOINT)&rcWindow, 2);
  4793. // Offset it by the amount of the move.
  4794. OffsetRect(&rcWindow,
  4795. ptMove.x - pasHost->m_pView->m_viewFullScreenExitStart.x,
  4796. ptMove.y - pasHost->m_pView->m_viewFullScreenExitStart.y);
  4797. SetWindowPos(hwnd, NULL, rcWindow.left, rcWindow.top, 0, 0,
  4798. SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
  4799. }
  4800. }
  4801. break;
  4802. }
  4803. case WM_LBUTTONUP:
  4804. {
  4805. if (pasHost->m_pView->m_viewFullScreenExitTrack)
  4806. {
  4807. //
  4808. // This will send us CAPTURECHANGED, causing us to clear
  4809. // the ExitTrack flag.
  4810. //
  4811. ReleaseCapture();
  4812. //
  4813. // If we never transitioned into move mode, then this was
  4814. // a click on the button.
  4815. //
  4816. if (!pasHost->m_pView->m_viewFullScreenExitMove)
  4817. {
  4818. //
  4819. // This was a click, send a command.
  4820. //
  4821. PostMessage(pasHost->m_pView->m_viewFrame, WM_COMMAND, CMD_VIEWFULLSCREEN, 0);
  4822. }
  4823. }
  4824. break;
  4825. }
  4826. case WM_CAPTURECHANGED:
  4827. {
  4828. //
  4829. // If we're tracking, something happened, so cancel out.
  4830. //
  4831. if (pasHost->m_pView->m_viewFullScreenExitTrack)
  4832. {
  4833. pasHost->m_pView->m_viewFullScreenExitTrack = FALSE;
  4834. }
  4835. break;
  4836. }
  4837. default:
  4838. DefWndProc:
  4839. rc = DefWindowProc(hwnd, message, wParam, lParam);
  4840. break;
  4841. }
  4842. DebugExitDWORD(VIEW_FullScreenExitProc, rc);
  4843. return(rc);
  4844. }
  4845. //
  4846. // VIEWFullScreenExitPaint()
  4847. //
  4848. // Paints the full screen button.
  4849. //
  4850. void ASShare::VIEWFullScreenExitPaint
  4851. (
  4852. ASPerson * pasHost,
  4853. HWND hwnd
  4854. )
  4855. {
  4856. RECT rc;
  4857. PAINTSTRUCT ps;
  4858. char szRestore[256];
  4859. HFONT hfnOld;
  4860. COLORREF txtColor;
  4861. COLORREF bkColor;
  4862. DebugEntry(ASShare::VIEWFullScreenExitPaint);
  4863. BeginPaint(hwnd, &ps);
  4864. GetClientRect(hwnd, &rc);
  4865. DrawFrameControl(ps.hdc, &rc, DFC_BUTTON, DFCS_BUTTONPUSH |
  4866. DFCS_ADJUSTRECT);
  4867. // Margin adjustments...
  4868. InflateRect(&rc, -m_viewEdgeCX, -m_viewEdgeCY);
  4869. DrawIconEx(ps.hdc, rc.left,
  4870. (rc.top + rc.bottom - GetSystemMetrics(SM_CYSMICON)) / 2,
  4871. m_viewFullScreenExitIcon,
  4872. GetSystemMetrics(SM_CXSMICON),
  4873. GetSystemMetrics(SM_CYSMICON),
  4874. 0, NULL, DI_NORMAL);
  4875. rc.left += GetSystemMetrics(SM_CXSMICON) + m_viewEdgeCX;
  4876. hfnOld = SelectFont(ps.hdc, GetStockObject(DEFAULT_GUI_FONT));
  4877. txtColor = SetTextColor(ps.hdc, GetSysColor(COLOR_BTNTEXT));
  4878. bkColor = SetBkColor(ps.hdc, GetSysColor(COLOR_BTNFACE));
  4879. LoadString(g_asInstance, IDS_RESTORE, szRestore, sizeof(szRestore));
  4880. DrawText(ps.hdc, szRestore, -1, &rc, DT_NOCLIP | DT_EXPANDTABS |
  4881. DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE);
  4882. SetBkColor(ps.hdc, bkColor);
  4883. SetTextColor(ps.hdc, txtColor);
  4884. SelectFont(ps.hdc, hfnOld);
  4885. EndPaint(hwnd, &ps);
  4886. DebugExitVOID(ASShare::VIEWFullScreenExitPaint);
  4887. }
  4888.