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.

4360 lines
122 KiB

  1. #include "precomp.h"
  2. #include <version.h>
  3. //
  4. // VIEW.CPP
  5. // The frame, widgets, and client area that presents the shared apps/desktop
  6. // for a remote host.
  7. //
  8. // Copyright(c) Microsoft 1997-
  9. //
  10. //
  11. // NOTE:
  12. // The client of the shared view frame represents the virtual desktop (VD)
  13. // of the host. For 3.0 hosts, the VD is the same as the screen. But for
  14. // 2.x hosts, the VD is the union of the screen size of all hosts. Hence
  15. // the recalculation every time someone starts sharing or changes screen
  16. // size, and the extra fun this entails for existing shared 2.x views.
  17. //
  18. #define MLZ_FILE_ZONE ZONE_CORE
  19. // Help file
  20. static const TCHAR s_cszHtmlHelpFile[] = TEXT("conf.chm");
  21. //
  22. // VIEW_Init()
  23. //
  24. BOOL VIEW_Init(void)
  25. {
  26. BOOL rc = FALSE;
  27. WNDCLASSEX wc;
  28. DebugEntry(VIEW_Init);
  29. //
  30. // Register the frame window class.
  31. // NOTE: Change CS_NOCLOSE if/when we ever let you close the view
  32. // of a person's shared apps.
  33. //
  34. wc.cbSize = sizeof(wc);
  35. wc.style = CS_DBLCLKS | CS_NOCLOSE;
  36. wc.lpfnWndProc = VIEWFrameWindowProc;
  37. wc.cbClsExtra = 0;
  38. wc.cbWndExtra = 0;
  39. wc.hInstance = g_asInstance;
  40. wc.hIcon = NULL;
  41. wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
  42. wc.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
  43. wc.lpszMenuName = NULL;
  44. wc.lpszClassName = VIEW_FRAME_CLASS_NAME;
  45. wc.hIconSm = NULL;
  46. if (!RegisterClassEx(&wc))
  47. {
  48. ERROR_OUT(("Failed to register AS Frame class"));
  49. DC_QUIT;
  50. }
  51. //
  52. // Register the view window class. This sits in the client area of
  53. // the frame along with the statusbar, tray, etc. It displays
  54. // the remote host's shared contents.
  55. //
  56. wc.cbSize = sizeof(wc);
  57. wc.style = CS_DBLCLKS | CS_NOCLOSE;
  58. wc.lpfnWndProc = VIEWClientWindowProc;
  59. wc.cbClsExtra = 0;
  60. wc.cbWndExtra = 0;
  61. wc.hInstance = g_asInstance;
  62. wc.hIcon = NULL;
  63. wc.hCursor = NULL;
  64. wc.hbrBackground = NULL;
  65. wc.lpszMenuName = NULL;
  66. wc.lpszClassName = VIEW_CLIENT_CLASS_NAME;
  67. wc.hIconSm = NULL;
  68. if (!RegisterClassEx(&wc))
  69. {
  70. ERROR_OUT(("Failed to register AS Client class"));
  71. DC_QUIT;
  72. }
  73. //
  74. // Register the full screen exit button class. This is a child of the
  75. // the view client when present.
  76. //
  77. wc.cbSize = sizeof(wc);
  78. wc.style = 0;
  79. wc.lpfnWndProc = VIEWFullScreenExitProc;
  80. wc.cbClsExtra = 0;
  81. wc.cbWndExtra = 0;
  82. wc.hInstance = g_asInstance;
  83. wc.hIcon = NULL;
  84. wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
  85. wc.hbrBackground = NULL;
  86. wc.lpszMenuName = NULL;
  87. wc.lpszClassName = VIEW_FULLEXIT_CLASS_NAME;
  88. wc.hIconSm = NULL;
  89. if (!RegisterClassEx(&wc))
  90. {
  91. ERROR_OUT(("Failed to register AS full screen exit class"));
  92. DC_QUIT;
  93. }
  94. rc = TRUE;
  95. DC_EXIT_POINT:
  96. DebugExitBOOL(VIEW_Init, rc);
  97. return(rc);
  98. }
  99. //
  100. // VIEW_Term()
  101. //
  102. void VIEW_Term(void)
  103. {
  104. DebugEntry(VIEW_Term);
  105. //
  106. // Free all resources we created (or may have created in window class
  107. // case).
  108. //
  109. UnregisterClass(VIEW_FULLEXIT_CLASS_NAME, g_asInstance);
  110. UnregisterClass(VIEW_CLIENT_CLASS_NAME, g_asInstance);
  111. UnregisterClass(VIEW_FRAME_CLASS_NAME, g_asInstance);
  112. DebugExitVOID(VIEW_Term);
  113. }
  114. //
  115. // VIEW_ShareStarting()
  116. // Creates share resources
  117. //
  118. BOOL ASShare::VIEW_ShareStarting(void)
  119. {
  120. BOOL rc = FALSE;
  121. HBITMAP hbmpT;
  122. TEXTMETRIC tm;
  123. HDC hdc;
  124. HFONT hfnOld;
  125. char szRestore[256];
  126. SIZE extent;
  127. DebugEntry(ASShare::VIEW_ShareStarting);
  128. ASSERT(m_viewVDSize.x == 0);
  129. ASSERT(m_viewVDSize.y == 0);
  130. //
  131. // Get NODROP cursor
  132. //
  133. m_viewNotInControl = ::LoadCursor(NULL, IDC_NO);
  134. //
  135. // Get MOUSEWHEEL lines metric
  136. //
  137. SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
  138. &m_viewMouseWheelScrollLines, 0);
  139. //
  140. // Create a pattern brush from the obscured bitmap
  141. //
  142. hbmpT = LoadBitmap(g_asInstance, MAKEINTRESOURCE(IDB_OBSCURED));
  143. m_viewObscuredBrush = CreatePatternBrush(hbmpT);
  144. DeleteBitmap(hbmpT);
  145. if (!m_viewObscuredBrush)
  146. {
  147. ERROR_OUT(( "Failed to create obscured bitmap brush"));
  148. DC_QUIT;
  149. }
  150. //
  151. // NOTE THAT since the icons are VGA colors, we don't need to recreate
  152. // our brush on a SYSCOLOR change.
  153. //
  154. // Get the full screen cancel icon
  155. m_viewFullScreenExitIcon = (HICON)LoadImage(g_asInstance,
  156. MAKEINTRESOURCE(IDI_CANCELFULLSCREEN), IMAGE_ICON,
  157. GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
  158. LR_DEFAULTCOLOR);
  159. m_viewEdgeCX = ::GetSystemMetrics(SM_CXEDGE);
  160. m_viewEdgeCY = ::GetSystemMetrics(SM_CYEDGE);
  161. //
  162. // Get metrics of GUI_FONT, the one we use in the window bar and
  163. // status bar.
  164. //
  165. LoadString(g_asInstance, IDS_RESTORE, szRestore, sizeof(szRestore));
  166. hdc = ::GetDC(NULL);
  167. hfnOld = (HFONT)::SelectObject(hdc, ::GetStockObject(DEFAULT_GUI_FONT));
  168. ::GetTextMetrics(hdc, &tm);
  169. ::GetTextExtentPoint(hdc, szRestore, lstrlen(szRestore), &extent);
  170. ::SelectObject(hdc, hfnOld);
  171. ::ReleaseDC(NULL, hdc);
  172. //
  173. // Calculate size of full screen button
  174. // Edge on left + margin on left + sm icon + margin + text + margin on
  175. // right + edge on right == 5 edges + sm icon + text
  176. //
  177. m_viewFullScreenCX = extent.cx + 5*m_viewEdgeCX + GetSystemMetrics(SM_CXSMICON);
  178. m_viewFullScreenCY = max(GetSystemMetrics(SM_CYSMICON), extent.cy) + 4*m_viewEdgeCY;
  179. //
  180. // Calculate size of items on window bar
  181. //
  182. m_viewItemCX = 4*m_viewEdgeCX + ::GetSystemMetrics(SM_CXSMICON) +
  183. m_viewEdgeCX + VIEW_MAX_ITEM_CHARS * tm.tmAveCharWidth;
  184. m_viewItemCY = max(::GetSystemMetrics(SM_CYSMICON), tm.tmHeight) +
  185. 2*m_viewEdgeCY + 2*m_viewEdgeCY;
  186. //
  187. // Calculate the width & height of the items scroll buttons. We want
  188. // to make sure it fits, but isn't ungainly.
  189. //
  190. m_viewItemScrollCX = ::GetSystemMetrics(SM_CXHSCROLL);
  191. m_viewItemScrollCX = 2 * min(m_viewItemScrollCX, m_viewItemCY);
  192. m_viewItemScrollCY = ::GetSystemMetrics(SM_CYHSCROLL);
  193. m_viewItemScrollCY = min(m_viewItemScrollCY, m_viewItemCY);
  194. //
  195. // Calculate height of status bar. It's height of GUIFONT plus edge
  196. // space.
  197. //
  198. m_viewStatusBarCY = tm.tmHeight + 4*m_viewEdgeCY;
  199. rc = TRUE;
  200. DC_EXIT_POINT:
  201. DebugExitBOOL(ASShare::VIEW_ShareStarting, rc);
  202. return(rc);
  203. }
  204. //
  205. // VIEW_ShareEnded()
  206. // Cleans up resources for share
  207. //
  208. void ASShare::VIEW_ShareEnded(void)
  209. {
  210. DebugEntry(ASShare::VIEW_ShareEnded);
  211. //
  212. // Destroy the full screen cancel icon
  213. //
  214. if (m_viewFullScreenExitIcon != NULL)
  215. {
  216. DestroyIcon(m_viewFullScreenExitIcon);
  217. m_viewFullScreenExitIcon = NULL;
  218. }
  219. if (m_viewObscuredBrush != NULL)
  220. {
  221. DeleteBrush(m_viewObscuredBrush);
  222. m_viewObscuredBrush = NULL;
  223. }
  224. DebugExitVOID(ASShre::VIEW_ShareEnded);
  225. }
  226. //
  227. // VIEW_PartyLeftShare()
  228. //
  229. // This is called when somebody leaves a share. We need this to
  230. // simulate what back-level systems did to calculate the virtual desktop
  231. // size. They didn't recalc when someone stopped shared, that person's
  232. // screne size counted until they left the share.
  233. //
  234. void ASShare::VIEW_PartyLeftShare(ASPerson * pasPerson)
  235. {
  236. DebugEntry(ASShare::VIEW_PartyLeftShare);
  237. ValidatePerson(pasPerson);
  238. // If this dude ever shared, now remove him from the VD total
  239. if (pasPerson->viewExtent.x != 0)
  240. {
  241. pasPerson->viewExtent.x = 0;
  242. pasPerson->viewExtent.y = 0;
  243. VIEW_RecalcVD();
  244. }
  245. DebugExitVOID(ASShare::VIEW_PartyLeftShare);
  246. }
  247. //
  248. // VIEW_HostStarting()
  249. //
  250. // Called when we start to host.
  251. //
  252. BOOL ASHost::VIEW_HostStarting(void)
  253. {
  254. DebugEntry(ASHost:VIEW_HostStarting);
  255. m_pShare->VIEW_RecalcExtent(m_pShare->m_pasLocal);
  256. m_pShare->VIEW_RecalcVD();
  257. DebugExitBOOL(ASHost::VIEW_HostStarting, TRUE);
  258. return(TRUE);
  259. }
  260. //
  261. // VIEW_ViewStarting()
  262. // Called when someone in the meeting starts to share. For all in the
  263. // conference, we keep a running tally of the VD, but use it only for
  264. // 2.x views. For remotes only, we create a view of their desktop.
  265. //
  266. BOOL ASShare::VIEW_ViewStarting(ASPerson * pasHost)
  267. {
  268. BOOL rc = FALSE;
  269. HWND hwnd;
  270. RECT rcSize;
  271. DebugEntry(ASShare::VIEW_ViewStarting);
  272. ValidateView(pasHost);
  273. //
  274. // First, calculate the extents, and the VD size.
  275. //
  276. VIEW_RecalcExtent(pasHost);
  277. VIEW_RecalcVD();
  278. //
  279. // Next, create scratch regions
  280. //
  281. pasHost->m_pView->m_viewExtentRgn = CreateRectRgn(0, 0, 0, 0);
  282. pasHost->m_pView->m_viewScreenRgn = CreateRectRgn(0, 0, 0, 0);
  283. pasHost->m_pView->m_viewPaintRgn = CreateRectRgn(0, 0, 0, 0);
  284. pasHost->m_pView->m_viewScratchRgn = CreateRectRgn(0, 0, 0, 0);
  285. if (!pasHost->m_pView->m_viewExtentRgn || !pasHost->m_pView->m_viewScreenRgn || !pasHost->m_pView->m_viewPaintRgn || !pasHost->m_pView->m_viewScratchRgn)
  286. {
  287. ERROR_OUT(("ViewStarting: Couldn't create scratch regions"));
  288. DC_QUIT;
  289. }
  290. ASSERT(pasHost->m_pView->m_viewFrame == NULL);
  291. ASSERT(pasHost->m_pView->m_viewClient == NULL);
  292. ASSERT(pasHost->m_pView->m_viewSharedRgn == NULL);
  293. ASSERT(pasHost->m_pView->m_viewObscuredRgn == NULL);
  294. ASSERT(pasHost->m_pView->m_viewPos.x == 0);
  295. ASSERT(pasHost->m_pView->m_viewPos.y == 0);
  296. ASSERT(pasHost->m_pView->m_viewPage.x == 0);
  297. ASSERT(pasHost->m_pView->m_viewPage.y == 0);
  298. ASSERT(!pasHost->m_pView->m_viewStatusBarOn);
  299. ASSERT(!pasHost->m_pView->m_viewFullScreen);
  300. pasHost->m_pView->m_viewStatusBarOn = TRUE;
  301. //
  302. // Calculate the ideal size for this window.
  303. //
  304. VIEWFrameGetSize(pasHost, &rcSize);
  305. //
  306. // Create the frame. This will in turn create its children.
  307. //
  308. pasHost->m_pView->m_viewMenuBar = ::LoadMenu(g_asInstance,
  309. MAKEINTRESOURCE(IDM_FRAME));
  310. if (!pasHost->m_pView->m_viewMenuBar)
  311. {
  312. ERROR_OUT(("ViewStarting: couldn't load frame menu"));
  313. DC_QUIT;
  314. }
  315. //
  316. // Do once-only capabilities/menu stuff.
  317. //
  318. //
  319. // SEND CTRL+ALT+DEL:
  320. // Append Ctrl+Alt+Del after separator to control menu, if this
  321. // is a view of a service host on NT.
  322. //
  323. if (pasHost->hetCount == HET_DESKTOPSHARED)
  324. {
  325. //
  326. // Remove applications submenu
  327. //
  328. DeleteMenu(pasHost->m_pView->m_viewMenuBar, IDSM_WINDOW,
  329. MF_BYPOSITION);
  330. if ((pasHost->cpcCaps.general.typeFlags & AS_SERVICE) &&
  331. (pasHost->cpcCaps.general.OS == CAPS_WINDOWS) &&
  332. (pasHost->cpcCaps.general.OSVersion == CAPS_WINDOWS_NT))
  333. {
  334. HMENU hSubMenu;
  335. MENUITEMINFO mii;
  336. CHAR szMenu[32];
  337. hSubMenu = GetSubMenu(pasHost->m_pView->m_viewMenuBar, IDSM_CONTROL);
  338. ZeroMemory(&mii, sizeof(mii));
  339. // Separator
  340. mii.cbSize = sizeof(mii);
  341. mii.fMask = MIIM_TYPE;
  342. mii.fType = MFT_SEPARATOR;
  343. InsertMenuItem(hSubMenu, -1, TRUE, &mii);
  344. // Send Ctrl-Alt-Del command
  345. mii.fMask = MIIM_ID | MIIM_STATE | MIIM_TYPE;
  346. mii.fType = MFT_STRING;
  347. mii.fState = MFS_ENABLED;
  348. mii.wID = CMD_CTRLALTDEL;
  349. LoadString(g_asInstance, IDS_CMD_CTRLALTDEL, szMenu,
  350. sizeof(szMenu));
  351. mii.dwTypeData = szMenu;
  352. mii.cch = lstrlen(szMenu);
  353. InsertMenuItem(hSubMenu, -1, TRUE, &mii);
  354. }
  355. }
  356. //
  357. // FULL SCREEN:
  358. // We only enable Full Screen for 3.0 hosts (since with 2.x desktop
  359. // scrolling the view area can change) who have screen sizes identical
  360. // to ours.
  361. //
  362. if (
  363. (pasHost->cpcCaps.screen.capsScreenWidth ==
  364. m_pasLocal->cpcCaps.screen.capsScreenWidth) &&
  365. (pasHost->cpcCaps.screen.capsScreenHeight ==
  366. m_pasLocal->cpcCaps.screen.capsScreenHeight))
  367. {
  368. ::EnableMenuItem(pasHost->m_pView->m_viewMenuBar, CMD_VIEWFULLSCREEN,
  369. MF_ENABLED | MF_BYCOMMAND);
  370. }
  371. if (m_pasLocal->m_caControlledBy)
  372. {
  373. WARNING_OUT(("VIEWStarting: currently controlled, create view hidden"));
  374. }
  375. //
  376. // If we are currently controlled, create the frame invisible since
  377. // we hid all the visible ones when we started being this way.
  378. //
  379. hwnd = CreateWindowEx(
  380. WS_EX_WINDOWEDGE,
  381. VIEW_FRAME_CLASS_NAME, // See RegisterClass() call.
  382. NULL,
  383. WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX |
  384. WS_MAXIMIZEBOX | WS_CLIPCHILDREN | (!m_pasLocal->m_caControlledBy ? WS_VISIBLE : 0),
  385. CW_USEDEFAULT,
  386. CW_USEDEFAULT,
  387. pasHost->viewExtent.x >= m_pasLocal->cpcCaps.screen.capsScreenWidth ?
  388. CW_USEDEFAULT : rcSize.right - rcSize.left,
  389. pasHost->viewExtent.y >= m_pasLocal->cpcCaps.screen.capsScreenHeight ?
  390. CW_USEDEFAULT : rcSize.bottom - rcSize.top,
  391. NULL,
  392. pasHost->m_pView->m_viewMenuBar,
  393. g_asInstance,
  394. pasHost // Pass in person ptr
  395. );
  396. if (hwnd == NULL)
  397. {
  398. ERROR_OUT(("ViewStarting: couldn't create frame window"));
  399. DC_QUIT;
  400. }
  401. //
  402. // OK, now we've created this frame window. Go through the sizing
  403. // process again to make sure the scrollbars are OK.
  404. //
  405. VIEWClientExtentChange(pasHost, FALSE);
  406. if (!m_pasLocal->m_caControlledBy)
  407. {
  408. SetForegroundWindow(hwnd);
  409. UpdateWindow(hwnd);
  410. }
  411. #ifdef _DEBUG
  412. TRACE_OUT(("TIME TO SEE SOMETHING: %08d MS",
  413. ::GetTickCount() - g_asSession.scShareTime));
  414. g_asSession.scShareTime = 0;
  415. #endif // DEBUG
  416. rc = TRUE;
  417. DC_EXIT_POINT:
  418. DebugExitBOOL(ASShare::VIEW_ViewStarting, rc);
  419. return(rc);
  420. }
  421. //
  422. // VIEW_ViewEnded()
  423. //
  424. // Called when someone we are viewing stops hosting, so we can clean up.
  425. //
  426. void ASShare::VIEW_ViewEnded(ASPerson * pasHost)
  427. {
  428. DebugEntry(ASShare::VIEW_ViewEnded);
  429. ValidateView(pasHost);
  430. if (pasHost->m_pView->m_viewInformDlg != NULL)
  431. {
  432. SendMessage(pasHost->m_pView->m_viewInformDlg, WM_COMMAND, IDCANCEL, 0);
  433. ASSERT(!pasHost->m_pView->m_viewInformDlg);
  434. ASSERT(!pasHost->m_pView->m_viewInformMsg);
  435. ASSERT(IsWindowEnabled(pasHost->m_pView->m_viewFrame));
  436. }
  437. if (pasHost->m_pView->m_viewFrame != NULL)
  438. {
  439. //
  440. // The frame is the parent of the view, toolbar, etc. Those
  441. // should all be NULL when we return.
  442. //
  443. DestroyWindow(pasHost->m_pView->m_viewFrame);
  444. ASSERT(pasHost->m_pView->m_viewFrame == NULL);
  445. }
  446. ASSERT(pasHost->m_pView->m_viewClient == NULL);
  447. if (pasHost->m_pView->m_viewMenuBar != NULL)
  448. {
  449. ::DestroyMenu(pasHost->m_pView->m_viewMenuBar);
  450. pasHost->m_pView->m_viewMenuBar = NULL;
  451. }
  452. if (pasHost->m_pView->m_viewSharedRgn != NULL)
  453. {
  454. DeleteRgn(pasHost->m_pView->m_viewSharedRgn);
  455. pasHost->m_pView->m_viewSharedRgn = NULL;
  456. }
  457. if (pasHost->m_pView->m_viewObscuredRgn != NULL)
  458. {
  459. DeleteRgn(pasHost->m_pView->m_viewObscuredRgn);
  460. pasHost->m_pView->m_viewObscuredRgn = NULL;
  461. }
  462. //
  463. // Destroy scratch regions
  464. //
  465. if (pasHost->m_pView->m_viewScratchRgn != NULL)
  466. {
  467. DeleteRgn(pasHost->m_pView->m_viewScratchRgn);
  468. pasHost->m_pView->m_viewScratchRgn = NULL;
  469. }
  470. if (pasHost->m_pView->m_viewPaintRgn != NULL)
  471. {
  472. DeleteRgn(pasHost->m_pView->m_viewPaintRgn);
  473. pasHost->m_pView->m_viewPaintRgn = NULL;
  474. }
  475. if (pasHost->m_pView->m_viewScreenRgn != NULL)
  476. {
  477. DeleteRgn(pasHost->m_pView->m_viewScreenRgn);
  478. pasHost->m_pView->m_viewScreenRgn = NULL;
  479. }
  480. if (pasHost->m_pView->m_viewExtentRgn != NULL)
  481. {
  482. DeleteRgn(pasHost->m_pView->m_viewExtentRgn);
  483. pasHost->m_pView->m_viewExtentRgn = NULL;
  484. }
  485. pasHost->m_pView->m_viewPos.x = 0;
  486. pasHost->m_pView->m_viewPos.y = 0;
  487. pasHost->m_pView->m_viewPage.x = 0;
  488. pasHost->m_pView->m_viewPage.y = 0;
  489. pasHost->m_pView->m_viewPgSize.x = 0;
  490. pasHost->m_pView->m_viewPgSize.y = 0;
  491. pasHost->m_pView->m_viewLnSize.x = 0;
  492. pasHost->m_pView->m_viewLnSize.y = 0;
  493. DebugExitVOID(ASShare::VIEW_ViewEnded);
  494. }
  495. //
  496. // VIEW_InControl()
  497. //
  498. // Called when we start/stop controlling this host. We enable the
  499. // toolbar, statusbar, tray, etc., and change the cursor from being the
  500. // nodrop.
  501. //
  502. void ASShare::VIEW_InControl
  503. (
  504. ASPerson * pasHost,
  505. BOOL fStart
  506. )
  507. {
  508. POINT ptCursor;
  509. DebugEntry(ASShare::VIEW_InControl);
  510. //
  511. // We're changing our state, and that affects the contents of our
  512. // menu bar. So cancel out of menu mode, and spare problems/faults/
  513. // inapplicable commands.
  514. //
  515. if (pasHost->m_pView->m_viewInMenuMode)
  516. {
  517. SendMessage(pasHost->m_pView->m_viewFrame, WM_CANCELMODE, 0, 0);
  518. ASSERT(!pasHost->m_pView->m_viewInMenuMode);
  519. }
  520. //
  521. // If starting in control and a message is up, kill it. Then bring our
  522. // window to the front.
  523. //
  524. if (fStart)
  525. {
  526. if (pasHost->m_pView->m_viewInformDlg != NULL)
  527. {
  528. SendMessage(pasHost->m_pView->m_viewInformDlg, WM_COMMAND, IDCANCEL, 0);
  529. ASSERT(!pasHost->m_pView->m_viewInformDlg);
  530. ASSERT(!pasHost->m_pView->m_viewInformMsg);
  531. ASSERT(IsWindowEnabled(pasHost->m_pView->m_viewFrame));
  532. }
  533. SetForegroundWindow(pasHost->m_pView->m_viewFrame);
  534. }
  535. //
  536. // Change title bar
  537. //
  538. VIEW_HostStateChange(pasHost);
  539. //
  540. // Turn off/on shadow cursors
  541. //
  542. CM_UpdateShadowCursor(pasHost, fStart, pasHost->cmPos.x, pasHost->cmPos.y,
  543. pasHost->cmHotSpot.x, pasHost->cmHotSpot.y);
  544. //
  545. // This will reset cursor image:
  546. // * from nodrop to shared if in control
  547. // * from shared to nodrop if not in control
  548. //
  549. // This will also, if in control, cause a mousemove to get sent to the
  550. // host we're controlling so his cursor pos is synced with ours, if the
  551. // mouse is over the frame client area.
  552. //
  553. GetCursorPos(&ptCursor);
  554. SetCursorPos(ptCursor.x, ptCursor.y);
  555. DebugExitVOID(ASShare::VIEW_InControl);
  556. }
  557. //
  558. // VIEW_HostStateChange()
  559. //
  560. // Called when a host's state has changed, via broadcast notification or
  561. // local operations.
  562. //
  563. // We update the titlebar and commands.
  564. //
  565. void ASShare::VIEW_HostStateChange
  566. (
  567. ASPerson * pasHost
  568. )
  569. {
  570. char szFormat[256];
  571. char szTitleText[256];
  572. char szOtherPart[128];
  573. DebugEntry(ASShare::VIEW_HostStateChange);
  574. ValidatePerson(pasHost);
  575. //
  576. // If this person isn't hosting anymore, don't do anything. We're
  577. // cleaning up after him.
  578. //
  579. if (!pasHost->hetCount)
  580. {
  581. DC_QUIT;
  582. }
  583. //
  584. // Make up trailing string
  585. //
  586. if (pasHost->m_caControlledBy)
  587. {
  588. LoadString(g_asInstance, IDS_TITLE_INCONTROL, szFormat, sizeof(szFormat));
  589. wsprintf(szOtherPart, szFormat, pasHost->m_caControlledBy->scName);
  590. }
  591. else if (pasHost->m_caAllowControl)
  592. {
  593. LoadString(g_asInstance, IDS_TITLE_CONTROLLABLE, szOtherPart, sizeof(szOtherPart));
  594. }
  595. else
  596. {
  597. szOtherPart[0] = 0;
  598. }
  599. if (pasHost->hetCount == HET_DESKTOPSHARED)
  600. {
  601. LoadString(g_asInstance, IDS_TITLE_SHAREDDESKTOP, szFormat, sizeof(szFormat));
  602. }
  603. else
  604. {
  605. ASSERT(pasHost->hetCount);
  606. LoadString(g_asInstance, IDS_TITLE_SHAREDPROGRAMS, szFormat, sizeof(szFormat));
  607. }
  608. wsprintf(szTitleText, szFormat, pasHost->scName, szOtherPart);
  609. ::SetWindowText(pasHost->m_pView->m_viewFrame, szTitleText);
  610. DC_EXIT_POINT:
  611. DebugExitVOID(ASShare::VIEW_HostStateChange);
  612. }
  613. //
  614. // VIEW_UpdateStatus()
  615. //
  616. // Updates the PERMANENT status of this frame. When we go into menu mode,
  617. // the strings shown are temporary only, not saved. When we come out of
  618. // menu mode, we put back the temporary status.
  619. //
  620. void ASShare::VIEW_UpdateStatus
  621. (
  622. ASPerson * pasHost,
  623. UINT idsStatus
  624. )
  625. {
  626. DebugEntry(ASShare::VIEW_UpdateStatus);
  627. ValidatePerson(pasHost);
  628. pasHost->m_pView->m_viewStatus = idsStatus;
  629. VIEWFrameSetStatus(pasHost, idsStatus);
  630. DebugExitVOID(ASShare::VIEW_UpdateStatus);
  631. }
  632. void ASShare::VIEWFrameSetStatus
  633. (
  634. ASPerson * pasHost,
  635. UINT idsStatus
  636. )
  637. {
  638. char szStatus[256];
  639. DebugEntry(ASShare::VIEWFrameSetStatus);
  640. if (idsStatus != IDS_STATUS_NONE)
  641. {
  642. LoadString(g_asInstance, idsStatus, szStatus, sizeof(szStatus));
  643. }
  644. else
  645. {
  646. szStatus[0] = 0;
  647. }
  648. ::SetWindowText(pasHost->m_pView->m_viewStatusBar, szStatus);
  649. DebugExitVOID(ASShare::VIEWFrameSetStatus);
  650. }
  651. //
  652. // VIEW_Message()
  653. //
  654. // Puts up a message to inform the end user of something.
  655. //
  656. void ASShare::VIEW_Message
  657. (
  658. ASPerson * pasHost,
  659. UINT ids
  660. )
  661. {
  662. DebugEntry(ASShare::VIEW_Message);
  663. ValidateView(pasHost);
  664. if (!pasHost->m_pView)
  665. {
  666. WARNING_OUT(("Can't show VIEW message; [%d] not hosting", pasHost->mcsID));
  667. DC_QUIT;
  668. }
  669. if (pasHost->m_pView->m_viewInformDlg)
  670. {
  671. // Kill the previous one
  672. TRACE_OUT(("Killing previous informational mesage for [%d]",
  673. pasHost->mcsID));
  674. SendMessage(pasHost->m_pView->m_viewInformDlg, WM_COMMAND, IDCANCEL, 0);
  675. ASSERT(!pasHost->m_pView->m_viewInformDlg);
  676. ASSERT(!pasHost->m_pView->m_viewInformMsg);
  677. }
  678. if (m_pasLocal->m_caControlledBy)
  679. {
  680. WARNING_OUT(("VIEW_Message: ignoring, view is hidden since we're controlled"));
  681. }
  682. else
  683. {
  684. pasHost->m_pView->m_viewInformMsg = ids;
  685. pasHost->m_pView->m_viewInformDlg = CreateDialogParam(g_asInstance,
  686. ((ids != IDS_ABOUT) ? MAKEINTRESOURCE(IDD_INFORM) : MAKEINTRESOURCE(IDD_ABOUT)),
  687. pasHost->m_pView->m_viewFrame, VIEWDlgProc, (LPARAM)pasHost);
  688. if (!pasHost->m_pView->m_viewInformDlg)
  689. {
  690. ERROR_OUT(("Failed to create inform message box for [%d]",
  691. pasHost->mcsID));
  692. pasHost->m_pView->m_viewInformMsg = 0;
  693. }
  694. }
  695. DC_EXIT_POINT:
  696. DebugExitVOID(ASShare::VIEW_Message);
  697. }
  698. //
  699. // VIEWStartControlled()
  700. //
  701. // If we are about to start being controlled, we hide all the frames
  702. // to get them out of the way AND prevent hangs caused by modal loop code
  703. // in Win9x title bar dragging.
  704. //
  705. void ASShare::VIEWStartControlled(BOOL fStart)
  706. {
  707. ASPerson * pasT;
  708. DebugEntry(ASShare::VIEWStartControlled);
  709. for (pasT = m_pasLocal; pasT != NULL; pasT = pasT->pasNext)
  710. {
  711. if (pasT->m_pView)
  712. {
  713. if (fStart)
  714. {
  715. ASSERT(IsWindowVisible(pasT->m_pView->m_viewFrame));
  716. ShowOwnedPopups(pasT->m_pView->m_viewFrame, FALSE);
  717. SetWindowPos(pasT->m_pView->m_viewFrame, NULL, 0, 0, 0, 0,
  718. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER |
  719. SWP_HIDEWINDOW);
  720. }
  721. else
  722. {
  723. ASSERT(!IsWindowVisible(pasT->m_pView->m_viewFrame));
  724. SetWindowPos(pasT->m_pView->m_viewFrame, NULL, 0, 0, 0, 0,
  725. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER |
  726. SWP_SHOWWINDOW);
  727. ShowOwnedPopups(pasT->m_pView->m_viewFrame, TRUE);
  728. }
  729. }
  730. }
  731. DebugEntry(ASShare::VIEWStartControlled);
  732. }
  733. //
  734. // VIEW_DlgProc()
  735. //
  736. // Handles informing user dialog
  737. //
  738. INT_PTR CALLBACK VIEWDlgProc
  739. (
  740. HWND hwnd,
  741. UINT message,
  742. WPARAM wParam,
  743. LPARAM lParam
  744. )
  745. {
  746. return(g_asSession.pShare->VIEW_DlgProc(hwnd, message, wParam, lParam));
  747. }
  748. BOOL ASShare::VIEW_DlgProc
  749. (
  750. HWND hwnd,
  751. UINT message,
  752. WPARAM wParam,
  753. LPARAM lParam
  754. )
  755. {
  756. BOOL rc = TRUE;
  757. ASPerson * pasHost;
  758. DebugEntry(VIEW_DlgProc);
  759. pasHost = (ASPerson *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  760. if (pasHost)
  761. {
  762. ValidateView(pasHost);
  763. }
  764. switch (message)
  765. {
  766. case WM_INITDIALOG:
  767. {
  768. char szT[256];
  769. char szRes[512];
  770. RECT rc;
  771. RECT rcOwner;
  772. pasHost = (ASPerson *)lParam;
  773. ValidateView(pasHost);
  774. pasHost->m_pView->m_viewInformDlg = hwnd;
  775. SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
  776. ASSERT(pasHost->m_pView->m_viewInformMsg);
  777. if (pasHost->m_pView->m_viewInformMsg == IDS_ABOUT)
  778. {
  779. // About box
  780. GetDlgItemText(hwnd, CTRL_ABOUTVERSION, szT, sizeof(szT));
  781. wsprintf(szRes, szT, VER_PRODUCTRELEASE_STR,
  782. VER_PRODUCTVERSION_STR);
  783. SetDlgItemText(hwnd, CTRL_ABOUTVERSION, szRes);
  784. }
  785. else
  786. {
  787. HDC hdc;
  788. HFONT hfn;
  789. // Set title.
  790. if ((pasHost->m_pView->m_viewInformMsg >= IDS_ERR_TAKECONTROL_FIRST) &&
  791. (pasHost->m_pView->m_viewInformMsg <= IDS_ERR_TAKECONTROL_LAST))
  792. {
  793. LoadString(g_asInstance, IDS_TITLE_TAKECONTROL_FAILED,
  794. szT, sizeof(szT));
  795. SetWindowText(hwnd, szT);
  796. }
  797. // Set message
  798. LoadString(g_asInstance, pasHost->m_pView->m_viewInformMsg,
  799. szT, sizeof(szT));
  800. wsprintf(szRes, szT, pasHost->scName);
  801. SetDlgItemText(hwnd, CTRL_INFORM, szRes);
  802. // Center the message vertically
  803. GetWindowRect(GetDlgItem(hwnd, CTRL_INFORM), &rcOwner);
  804. MapWindowPoints(NULL, hwnd, (LPPOINT)&rcOwner, 2);
  805. rc = rcOwner;
  806. hdc = GetDC(hwnd);
  807. hfn = (HFONT)SendDlgItemMessage(hwnd, CTRL_INFORM, WM_GETFONT, 0, 0);
  808. hfn = SelectFont(hdc, hfn);
  809. DrawText(hdc, szRes, -1, &rc, DT_NOCLIP | DT_EXPANDTABS |
  810. DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
  811. SelectFont(hdc, hfn);
  812. ReleaseDC(hwnd, hdc);
  813. ASSERT((rc.bottom - rc.top) <= (rcOwner.bottom - rcOwner.top));
  814. SetWindowPos(GetDlgItem(hwnd, CTRL_INFORM), NULL,
  815. rcOwner.left,
  816. ((rcOwner.top + rcOwner.bottom) - (rc.bottom - rc.top)) / 2,
  817. (rcOwner.right - rcOwner.left),
  818. rc.bottom - rc.top,
  819. SWP_NOACTIVATE | SWP_NOZORDER);
  820. }
  821. // Disable owner
  822. EnableWindow(pasHost->m_pView->m_viewFrame, FALSE);
  823. // Show window, centered around owner midpoint
  824. GetWindowRect(pasHost->m_pView->m_viewFrame, &rcOwner);
  825. GetWindowRect(hwnd, &rc);
  826. SetWindowPos(hwnd, NULL,
  827. ((rcOwner.left + rcOwner.right) - (rc.right - rc.left)) / 2,
  828. ((rcOwner.top + rcOwner.bottom) - (rc.bottom - rc.top)) / 2,
  829. 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
  830. ShowWindow(hwnd, SW_SHOWNORMAL);
  831. UpdateWindow(hwnd);
  832. break;
  833. }
  834. case WM_COMMAND:
  835. {
  836. switch (GET_WM_COMMAND_ID(wParam, lParam))
  837. {
  838. case IDOK:
  839. case IDCANCEL:
  840. {
  841. ASSERT(!IsWindowEnabled(pasHost->m_pView->m_viewFrame));
  842. EnableWindow(pasHost->m_pView->m_viewFrame, TRUE);
  843. DestroyWindow(hwnd);
  844. break;
  845. }
  846. }
  847. break;
  848. }
  849. case WM_DESTROY:
  850. {
  851. if (pasHost)
  852. {
  853. pasHost->m_pView->m_viewInformDlg = NULL;
  854. pasHost->m_pView->m_viewInformMsg = 0;
  855. }
  856. SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL);
  857. break;
  858. }
  859. default:
  860. {
  861. rc = FALSE;
  862. break;
  863. }
  864. }
  865. DebugExitBOOL(VIEW_DlgProc, rc);
  866. return(rc);
  867. }
  868. //
  869. // VIEW_RecalcExtent()
  870. //
  871. // This recalculates the extent of the view of the host.
  872. //
  873. void ASShare::VIEW_RecalcExtent(ASPerson * pasHost)
  874. {
  875. DebugEntry(ASShare::VIEW_RecalcExtent);
  876. TRACE_OUT(("VIEW_RecalcExtent: New view extent (%04d, %04d) for [%d] version %x",
  877. pasHost->viewExtent.x, pasHost->viewExtent.y,
  878. pasHost->mcsID, pasHost->cpcCaps.general.version));
  879. pasHost->viewExtent.x = pasHost->cpcCaps.screen.capsScreenWidth;
  880. pasHost->viewExtent.y = pasHost->cpcCaps.screen.capsScreenHeight;
  881. DebugExitVOID(ASShare::VIEW_RecalcExtent);
  882. }
  883. //
  884. // VIEW_RecalcVD()
  885. // This recalculates the virtual desktop size when a remote starts/stops
  886. // sharing, or if a host's screen changes size. The VD is the union of
  887. // all the screen sizes of those hosting. 2.x nodes work in a virtual
  888. // desktop, and may scroll over. For each 2.x view, we want the client to
  889. // represent the VD, but with only the stuff on screen on the host to be
  890. // interactable.
  891. //
  892. void ASShare::VIEW_RecalcVD(void)
  893. {
  894. POINT ptVDNew;
  895. ASPerson * pas;
  896. DebugEntry(ASShare::VIEW_RecalcVD);
  897. //
  898. // First, loop through all the hosts and recompute the VD.
  899. //
  900. ptVDNew.x = 0;
  901. ptVDNew.y = 0;
  902. for (pas = m_pasLocal; pas != NULL; pas = pas->pasNext)
  903. {
  904. //
  905. // NOTE:
  906. // For local dudes, we won't have an HWND. Use viewExtent, if
  907. // we don't think the person is sharing, it will be zero.
  908. //
  909. if (pas->viewExtent.x != 0)
  910. {
  911. TRACE_OUT(("VIEW_RecalcVD: Found host [%d], screen size (%04d, %04d)",
  912. pas->mcsID, pas->cpcCaps.screen.capsScreenWidth, pas->cpcCaps.screen.capsScreenHeight));
  913. ptVDNew.x = max(ptVDNew.x, pas->cpcCaps.screen.capsScreenWidth);
  914. ptVDNew.y = max(ptVDNew.y, pas->cpcCaps.screen.capsScreenHeight);
  915. TRACE_OUT(("VIEW_RecalcVD: Computed VD size now (%04d, %04d)",
  916. ptVDNew.x, ptVDNew.y));
  917. }
  918. }
  919. //
  920. // If the VD size didn't change, we're done.
  921. //
  922. if ((ptVDNew.x != m_viewVDSize.x) || (ptVDNew.y != m_viewVDSize.y))
  923. {
  924. TRACE_OUT(("VIEW_RecalcVD: VD size changed from (%04d, %04d) to (%04d, %04d)",
  925. m_viewVDSize.x, m_viewVDSize.y, ptVDNew.x, ptVDNew.y));
  926. m_viewVDSize = ptVDNew;
  927. //
  928. // Now loop through all the 2.x hosts, and update their extent, then
  929. // have them do the resize voodoo so the scrollbar pos isn't out of
  930. // range, etc.
  931. //
  932. // NOTE: Since us, the local guy, is not 2.x we can skip ourselves.
  933. //
  934. ValidatePerson(m_pasLocal);
  935. }
  936. DebugExitVOID(ASShare::VIEW_RecalcVD);
  937. }
  938. //
  939. // VIEW_IsPointShared()
  940. // This determines, given a point relative to the client of the view for
  941. // the remote on this system, if it is in a shared area.
  942. //
  943. BOOL ASShare::VIEW_IsPointShared
  944. (
  945. ASPerson * pasHost,
  946. POINT ptLocal
  947. )
  948. {
  949. BOOL rc = FALSE;
  950. RECT rcClient;
  951. DebugEntry(ASShare::VIEW_IsPointShared);
  952. ValidateView(pasHost);
  953. //
  954. // Convert to client coords, and adjust for scrolling offset. That
  955. // result is the equivalent point on the host desktop.
  956. //
  957. GetClientRect(pasHost->m_pView->m_viewClient, &rcClient);
  958. if (!PtInRect(&rcClient, ptLocal))
  959. {
  960. TRACE_OUT(("VIEW_IsPointShared: point not in client area"));
  961. return(FALSE);
  962. }
  963. //
  964. // The obscured and shared areas are saved in frame client coords,
  965. // so we don't need to account for the scroll position all the time.
  966. // When the scroll position changes the regions are updated.
  967. //
  968. //
  969. // NOTE that this order works for both desktop and app sharing
  970. //
  971. if ((pasHost->m_pView->m_viewObscuredRgn != NULL) &&
  972. PtInRegion(pasHost->m_pView->m_viewObscuredRgn, ptLocal.x, ptLocal.y))
  973. {
  974. rc = FALSE;
  975. }
  976. else if ((pasHost->m_pView->m_viewSharedRgn != NULL) &&
  977. !PtInRegion(pasHost->m_pView->m_viewSharedRgn, ptLocal.x, ptLocal.y))
  978. {
  979. rc = FALSE;
  980. }
  981. else
  982. {
  983. //
  984. // 2.x hosts may be scrolled over. If so, shared stuff offscreen
  985. // is also considered to be obscured.
  986. //
  987. RECT rcScreen;
  988. //
  989. // Compute what part of the VD, in local client coords, is visible
  990. // on the remote's screen.
  991. //
  992. SetRect(&rcScreen, 0, 0, pasHost->cpcCaps.screen.capsScreenWidth, pasHost->cpcCaps.screen.capsScreenHeight);
  993. OffsetRect(&rcScreen,
  994. pasHost->m_pView->m_dsScreenOrigin.x - pasHost->m_pView->m_viewPos.x,
  995. pasHost->m_pView->m_dsScreenOrigin.y - pasHost->m_pView->m_viewPos.y);
  996. if (!PtInRect(&rcScreen, ptLocal))
  997. {
  998. TRACE_OUT(("VIEW_IsPointShared: point is in shared stuff but not visible on remote screen"));
  999. rc = FALSE;
  1000. }
  1001. else
  1002. {
  1003. rc = TRUE;
  1004. }
  1005. }
  1006. DebugExitBOOL(AShare::VIEW_IsPointShared, rc);
  1007. return(rc);
  1008. }
  1009. //
  1010. // VIEW_ScreenChanged()
  1011. //
  1012. void ASShare::VIEW_ScreenChanged(ASPerson * pasPerson)
  1013. {
  1014. DebugEntry(ASShare::VIEW_ScreenChanged);
  1015. ValidatePerson(pasPerson);
  1016. //
  1017. // Recompute the extent
  1018. //
  1019. VIEW_RecalcExtent(pasPerson);
  1020. VIEWClientExtentChange(pasPerson, TRUE);
  1021. VIEW_RecalcVD();
  1022. DebugExitVOID(ASShare::VIEW_ScreenChanged);
  1023. }
  1024. //
  1025. // VIEW_SetHostRegions()
  1026. // This sets the new shared & obscured areas.
  1027. //
  1028. // Note that this routine takes responsibility for the regions pass in; it
  1029. // will delete them and/or the old ones if necessary.
  1030. //
  1031. void ASShare::VIEW_SetHostRegions
  1032. (
  1033. ASPerson * pasHost,
  1034. HRGN rgnShared,
  1035. HRGN rgnObscured
  1036. )
  1037. {
  1038. DebugEntry(ASShare::VIEW_SetHostRegions);
  1039. ValidateView(pasHost);
  1040. //
  1041. // Return immediately if either region handle is bogus. This can happen
  1042. // when we are running low on memory.
  1043. //
  1044. if (!rgnShared || !rgnObscured)
  1045. {
  1046. ERROR_OUT(("Bad host regions for person [%u]", pasHost->mcsID));
  1047. if (rgnShared != NULL)
  1048. {
  1049. DeleteRgn(rgnShared);
  1050. }
  1051. if (rgnObscured != NULL)
  1052. {
  1053. DeleteRgn(rgnObscured);
  1054. }
  1055. }
  1056. else
  1057. {
  1058. HRGN hrgnInvalid;
  1059. #ifdef _DEBUG
  1060. RECT rcT;
  1061. ::GetRgnBox(rgnShared, &rcT);
  1062. TRACE_OUT(("Shared region {%04d, %04d, %04d, %04d} for host [%d]",
  1063. rcT.left, rcT.top, rcT.right, rcT.bottom, pasHost->mcsID));
  1064. ::GetRgnBox(rgnObscured, &rcT);
  1065. TRACE_OUT(("Obscured region {%04d, %04d, %04d, %04d} for host [%d]",
  1066. rcT.left, rcT.top, rcT.right, rcT.bottom, pasHost->mcsID));
  1067. #endif // _DEBUG
  1068. //
  1069. // Update the current shared, obscured areas. Adjust for the
  1070. // scroll position so these are saved in client-relative coords.
  1071. //
  1072. OffsetRgn(rgnShared, -pasHost->m_pView->m_viewPos.x, -pasHost->m_pView->m_viewPos.y);
  1073. OffsetRgn(rgnObscured, -pasHost->m_pView->m_viewPos.x, -pasHost->m_pView->m_viewPos.y);
  1074. //
  1075. // The invalid area is whatever changed in the obscured area and
  1076. // the shared area. In other words, the union - the intersection.
  1077. //
  1078. hrgnInvalid = NULL;
  1079. if (pasHost->m_pView->m_viewSharedRgn != NULL)
  1080. {
  1081. HRGN hrgnU;
  1082. HRGN hrgnI;
  1083. ASSERT(pasHost->m_pView->m_viewObscuredRgn != NULL);
  1084. //
  1085. // If we're in a low memory situation, just invalidate everything
  1086. // and hope it can be repainted.
  1087. //
  1088. hrgnU = CreateRectRgn(0, 0, 0, 0);
  1089. hrgnI = CreateRectRgn(0, 0, 0, 0);
  1090. if (!hrgnU || !hrgnI)
  1091. goto SkipMinimalInvalidate;
  1092. hrgnInvalid = CreateRectRgn(0, 0, 0, 0);
  1093. if (!hrgnInvalid)
  1094. goto SkipMinimalInvalidate;
  1095. //
  1096. // WE'RE GOING TO DO THE SAME THING FOR BOTH SHARED AND
  1097. // OBSCURED REGIONS.
  1098. //
  1099. // Get the union of the old and new shared regions
  1100. UnionRgn(hrgnU, pasHost->m_pView->m_viewSharedRgn, rgnShared);
  1101. // Get the intersection of the old and new shared regions
  1102. IntersectRgn(hrgnI, pasHost->m_pView->m_viewSharedRgn, rgnShared);
  1103. //
  1104. // The intersection is what used to be shared and is still shared.
  1105. // The rest is changing, it needs to be repainted. That's the
  1106. // union minus the intersection.
  1107. //
  1108. SubtractRgn(hrgnU, hrgnU, hrgnI);
  1109. #ifdef _DEBUG
  1110. GetRgnBox(hrgnU, &rcT);
  1111. TRACE_OUT(("VIEW_SetHostRegions: Shared area change {%04d, %04d, %04d, %04d}",
  1112. rcT.left, rcT.top, rcT.right, rcT.bottom));
  1113. #endif // _DEBUG
  1114. // Add this to the invalidate total
  1115. UnionRgn(hrgnInvalid, hrgnInvalid, hrgnU);
  1116. //
  1117. // REPEAT FOR THE OBSCURED REGION
  1118. //
  1119. UnionRgn(hrgnU, pasHost->m_pView->m_viewObscuredRgn, rgnObscured);
  1120. IntersectRgn(hrgnI, pasHost->m_pView->m_viewObscuredRgn, rgnObscured);
  1121. SubtractRgn(hrgnU, hrgnU, hrgnI);
  1122. #ifdef _DEBUG
  1123. GetRgnBox(hrgnU, &rcT);
  1124. TRACE_OUT(("VIEW_SetHostRegions: Obscured area change {%04d, %04d, %04d, %04d}",
  1125. rcT.left, rcT.top, rcT.right, rcT.bottom));
  1126. #endif // _DEBUG
  1127. UnionRgn(hrgnInvalid, hrgnInvalid, hrgnU);
  1128. SkipMinimalInvalidate:
  1129. //
  1130. // Clean up scratch regions
  1131. //
  1132. if (hrgnI != NULL)
  1133. DeleteRgn(hrgnI);
  1134. if (hrgnU != NULL)
  1135. DeleteRgn(hrgnU);
  1136. DeleteRgn(pasHost->m_pView->m_viewSharedRgn);
  1137. pasHost->m_pView->m_viewSharedRgn = rgnShared;
  1138. DeleteRgn(pasHost->m_pView->m_viewObscuredRgn);
  1139. pasHost->m_pView->m_viewObscuredRgn = rgnObscured;
  1140. //
  1141. // DO NOT CALL VIEW_InvalidateRgn here, that expects a region in
  1142. // screen coords of pasHost. We have a region that is
  1143. // client coords relative. So just call InvalidateRgn() directly.
  1144. //
  1145. InvalidateRgn(pasHost->m_pView->m_viewClient, hrgnInvalid, FALSE);
  1146. if (hrgnInvalid != NULL)
  1147. DeleteRgn(hrgnInvalid);
  1148. }
  1149. else
  1150. {
  1151. RECT rcBound;
  1152. // The shared & obscured regions are both NULL or both non-NULL
  1153. ASSERT(pasHost->m_pView->m_viewObscuredRgn == NULL);
  1154. pasHost->m_pView->m_viewSharedRgn = rgnShared;
  1155. pasHost->m_pView->m_viewObscuredRgn = rgnObscured;
  1156. //
  1157. // This is the first SWL packet we've received. Snap the
  1158. // scrollbars to the start of the total shared area. This avoids
  1159. // having the view come up, but look empty because the shared
  1160. // apps are out of the range. We do this even if the user
  1161. // scrolled around in the window already.
  1162. //
  1163. // The total shared area is the union of the real shared +
  1164. // obscured shared areas. Convert back to remote VD coords!
  1165. //
  1166. UnionRgn(pasHost->m_pView->m_viewScratchRgn, rgnShared, rgnObscured);
  1167. GetRgnBox(pasHost->m_pView->m_viewScratchRgn, &rcBound);
  1168. OffsetRect(&rcBound, pasHost->m_pView->m_viewPos.x, pasHost->m_pView->m_viewPos.y);
  1169. //
  1170. // Is any part of what was shared within the extent of the view?
  1171. // If not, we can't do anything--there's nothing to show.
  1172. //
  1173. if ((rcBound.right <= 0) ||
  1174. (rcBound.left >= pasHost->viewExtent.x) ||
  1175. (rcBound.bottom <= 0) ||
  1176. (rcBound.top >= pasHost->viewExtent.y))
  1177. {
  1178. TRACE_OUT(("VIEW_SetHostRegions: Can't snap to shared area; none is visible"));
  1179. }
  1180. else
  1181. {
  1182. //
  1183. // Use top left corner of bounds
  1184. // VIEWClientScroll() will pin position w/in range
  1185. //
  1186. VIEWClientScroll(pasHost, rcBound.left, rcBound.top);
  1187. }
  1188. InvalidateRgn(pasHost->m_pView->m_viewClient, NULL, FALSE);
  1189. }
  1190. }
  1191. DebugExitVOID(ASShare::VIEW_SetHostRegions);
  1192. }
  1193. //
  1194. // VIEW_InvalidateRect()
  1195. // Repaints the given rect. This is for EXTERNAL code which passes in VD
  1196. // coords. We convert to client coordinates by accounting for the scroll
  1197. // position.
  1198. //
  1199. void ASShare::VIEW_InvalidateRect
  1200. (
  1201. ASPerson * pasPerson,
  1202. LPRECT lprc
  1203. )
  1204. {
  1205. DebugEntry(ASShare::VIEW_InvalidateRect);
  1206. ValidateView(pasPerson);
  1207. //
  1208. // Convert to client coords
  1209. //
  1210. if (lprc != NULL)
  1211. {
  1212. OffsetRect(lprc, -pasPerson->m_pView->m_viewPos.x, -pasPerson->m_pView->m_viewPos.y);
  1213. }
  1214. InvalidateRect(pasPerson->m_pView->m_viewClient, lprc, FALSE);
  1215. //
  1216. // Convert back so caller doesn't get a modified lprc
  1217. //
  1218. if (lprc != NULL)
  1219. {
  1220. OffsetRect(lprc, pasPerson->m_pView->m_viewPos.x, pasPerson->m_pView->m_viewPos.y);
  1221. }
  1222. DebugExitVOID(ASShare::VIEW_InvalidateRect);
  1223. }
  1224. //
  1225. // VIEW_InvalidateRgn()
  1226. // Repaints the given region. This is for EXTERNAL code which passes in VD
  1227. // coords. We convert to client coordinates by accounting fo the scroll
  1228. // position.
  1229. //
  1230. void ASShare::VIEW_InvalidateRgn
  1231. (
  1232. ASPerson * pasHost,
  1233. HRGN rgnInvalid
  1234. )
  1235. {
  1236. #ifdef _DEBUG
  1237. //
  1238. // Make sure we the invalid region goes back to the caller unaltered,
  1239. // even though we modify it temporarily here to avoid a copy.
  1240. //
  1241. RECT rcBoundBefore;
  1242. RECT rcBoundAfter;
  1243. #endif // _DEBUG
  1244. DebugEntry(ASShare::VIEW_InvalidateRgn);
  1245. ValidatePerson(pasHost);
  1246. //
  1247. // Adjust the region if the frame view is scrolled over.
  1248. //
  1249. if (rgnInvalid != NULL)
  1250. {
  1251. #ifdef _DEBUG
  1252. GetRgnBox(rgnInvalid, &rcBoundBefore);
  1253. #endif // _DEBUG
  1254. OffsetRgn(rgnInvalid, -pasHost->m_pView->m_viewPos.x, -pasHost->m_pView->m_viewPos.y);
  1255. #ifdef _DEBUG
  1256. TRACE_OUT(("VIEW_InvalidateRgn: Invalidating area {%04d, %04d, %04d, %04d}",
  1257. rcBoundBefore.left, rcBoundBefore.top, rcBoundBefore.right, rcBoundBefore.bottom));
  1258. #endif // _DEBUG
  1259. }
  1260. else
  1261. {
  1262. TRACE_OUT(("VIEW_InvalidateRgn: Invalidating entire client area"));
  1263. }
  1264. InvalidateRgn(pasHost->m_pView->m_viewClient, rgnInvalid, FALSE);
  1265. if (rgnInvalid != NULL)
  1266. {
  1267. OffsetRgn(rgnInvalid, pasHost->m_pView->m_viewPos.x, pasHost->m_pView->m_viewPos.y);
  1268. #ifdef _DEBUG
  1269. GetRgnBox(rgnInvalid, &rcBoundAfter);
  1270. ASSERT(EqualRect(&rcBoundBefore, &rcBoundAfter));
  1271. #endif // _DEBUG
  1272. }
  1273. DebugExitVOID(ASShare::VIEW_InvalidateRgn);
  1274. }
  1275. //
  1276. // VIEWClientExtentChange()
  1277. //
  1278. void ASShare::VIEWClientExtentChange(ASPerson * pasHost, BOOL fRedraw)
  1279. {
  1280. RECT rcl;
  1281. SCROLLINFO si;
  1282. DebugEntry(ASShare::VIEWClientExtentChange);
  1283. ValidatePerson(pasHost);
  1284. if (!pasHost->m_pView)
  1285. DC_QUIT;
  1286. #ifdef _DEBUG
  1287. //
  1288. // The client area (page size) shouldn't have changed. Only the
  1289. // extent has.
  1290. //
  1291. GetClientRect(pasHost->m_pView->m_viewClient, &rcl);
  1292. ASSERT(pasHost->m_pView->m_viewPage.x == rcl.right - rcl.left);
  1293. ASSERT(pasHost->m_pView->m_viewPage.y == rcl.bottom - rcl.top);
  1294. #endif // _DEBUG
  1295. pasHost->m_pView->m_viewPgSize.x = pasHost->viewExtent.x / 8;
  1296. pasHost->m_pView->m_viewPgSize.y = pasHost->viewExtent.y / 8;
  1297. pasHost->m_pView->m_viewLnSize.x = pasHost->viewExtent.x / 64;
  1298. pasHost->m_pView->m_viewLnSize.y = pasHost->viewExtent.y / 64;
  1299. //
  1300. // Move the scroll position to the origin.
  1301. //
  1302. //
  1303. // Clip the current scroll pos if we need to, now that the extent
  1304. // has changed size.
  1305. //
  1306. VIEWClientScroll(pasHost, pasHost->m_pView->m_viewPos.x, pasHost->m_pView->m_viewPos.y);
  1307. si.cbSize = sizeof(SCROLLINFO);
  1308. si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE|SIF_DISABLENOSCROLL;
  1309. // Set vertical info. Is vert pos out of range now?
  1310. si.nMin = 0;
  1311. si.nMax = pasHost->viewExtent.y - 1;
  1312. si.nPage = pasHost->m_pView->m_viewPage.y;
  1313. si.nPos = pasHost->m_pView->m_viewPos.y;
  1314. ASSERT(si.nPos <= si.nMax);
  1315. TRACE_OUT(("VIEWClientExtentChange: Setting VERT scroll info:"));
  1316. TRACE_OUT(("VIEWClientExtentChange: nMin %04d", si.nMin));
  1317. TRACE_OUT(("VIEWClientExtentChange: nMax %04d", si.nMax));
  1318. TRACE_OUT(("VIEWClientExtentChange: nPage %04d", si.nPage));
  1319. TRACE_OUT(("VIEWClientExtentChange: nPos %04d", si.nPos));
  1320. SetScrollInfo(pasHost->m_pView->m_viewClient, SB_VERT, &si, TRUE );
  1321. // Set horizontal (x) information
  1322. si.nMin = 0;
  1323. si.nMax = pasHost->viewExtent.x - 1;
  1324. si.nPage = pasHost->m_pView->m_viewPage.x;
  1325. si.nPos = pasHost->m_pView->m_viewPos.x;
  1326. ASSERT(si.nPos <= si.nMax);
  1327. TRACE_OUT(("VIEWClientExtentChange: Setting HORZ scroll info:"));
  1328. TRACE_OUT(("VIEWClientExtentChange: nMin %04d", si.nMin));
  1329. TRACE_OUT(("VIEWClientExtentChange: nMax %04d", si.nMax));
  1330. TRACE_OUT(("VIEWClientExtentChange: nPage %04d", si.nPage));
  1331. TRACE_OUT(("VIEWClientExtentChange: nPos %04d", si.nPos));
  1332. SetScrollInfo(pasHost->m_pView->m_viewClient, SB_HORZ, &si, TRUE );
  1333. if (fRedraw)
  1334. {
  1335. // Is the frame window too big now?
  1336. if ( (pasHost->m_pView->m_viewPage.x > pasHost->viewExtent.x) ||
  1337. (pasHost->m_pView->m_viewPage.y > pasHost->viewExtent.y) )
  1338. {
  1339. TRACE_OUT(("VIEWClientExtentChange: client size (%04d, %04d) now bigger than view extent (%04d, %04d)",
  1340. pasHost->m_pView->m_viewPage.x, pasHost->m_pView->m_viewPage.y,
  1341. pasHost->viewExtent.x, pasHost->viewExtent.y));
  1342. //
  1343. // Calculate the ideal size for this window.
  1344. //
  1345. VIEWFrameGetSize(pasHost, &rcl);
  1346. SetWindowPos( pasHost->m_pView->m_viewFrame,
  1347. NULL, 0, 0, rcl.right - rcl.left, rcl.bottom - rcl.top,
  1348. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  1349. }
  1350. TRACE_OUT(("VIEWClientExtentChange: Invalidating client area"));
  1351. VIEW_InvalidateRgn(pasHost, NULL);
  1352. }
  1353. DC_EXIT_POINT:
  1354. DebugExitVOID(ASShare::VIEWClientExtentChange);
  1355. }
  1356. //
  1357. // VIEWFrameWindowProc()
  1358. //
  1359. LRESULT CALLBACK VIEWFrameWindowProc
  1360. (
  1361. HWND hwnd,
  1362. UINT message,
  1363. WPARAM wParam,
  1364. LPARAM lParam
  1365. )
  1366. {
  1367. return(g_asSession.pShare->VIEW_FrameWindowProc(hwnd, message, wParam, lParam));
  1368. }
  1369. LRESULT ASShare::VIEW_FrameWindowProc
  1370. (
  1371. HWND hwnd,
  1372. UINT message,
  1373. WPARAM wParam,
  1374. LPARAM lParam
  1375. )
  1376. {
  1377. LRESULT rc = 0;
  1378. ASPerson * pasHost;
  1379. DebugEntry(VIEW_FrameWindowProc);
  1380. pasHost = (ASPerson *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1381. if (pasHost)
  1382. {
  1383. ValidateView(pasHost);
  1384. }
  1385. switch (message)
  1386. {
  1387. case WM_NCCREATE:
  1388. {
  1389. // Get the passed in host pointer, and set in our window long
  1390. pasHost = (ASPerson *)((LPCREATESTRUCT)lParam)->lpCreateParams;
  1391. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)pasHost);
  1392. pasHost->m_pView->m_viewFrame = hwnd;
  1393. //
  1394. // Set the window icon
  1395. //
  1396. SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)
  1397. ((pasHost->hetCount == HET_DESKTOPSHARED) ?
  1398. g_hetDeskIcon : g_hetASIcon));
  1399. goto DefWndProc;
  1400. break;
  1401. }
  1402. case WM_NCDESTROY:
  1403. {
  1404. if (pasHost != NULL)
  1405. {
  1406. pasHost->m_pView->m_viewFrame = NULL;
  1407. }
  1408. goto DefWndProc;
  1409. break;
  1410. }
  1411. case WM_CREATE:
  1412. {
  1413. // Set title
  1414. VIEW_HostStateChange(pasHost);
  1415. if (!VIEWFrameCreate(pasHost))
  1416. {
  1417. ERROR_OUT(("VIEWFrameWindowProc: errors in creation handling for [%d]", pasHost->mcsID));
  1418. rc = -1;
  1419. }
  1420. break;
  1421. }
  1422. case WM_DESTROY:
  1423. {
  1424. //
  1425. // Clear menu bar; we always destroy it ourself.
  1426. //
  1427. ::SetMenu(hwnd, NULL);
  1428. break;
  1429. }
  1430. case WM_ACTIVATE:
  1431. {
  1432. //
  1433. // If we're switching back to the view of the host we're in
  1434. // control of, update the key states.
  1435. //
  1436. if (wParam)
  1437. {
  1438. SetFocus(pasHost->m_pView->m_viewClient);
  1439. }
  1440. else
  1441. {
  1442. //
  1443. // If we're full screen but are deactivating, kick out of
  1444. // full screenmode.
  1445. //
  1446. if (pasHost->m_pView->m_viewFullScreen)
  1447. {
  1448. // Do this later, so title bar state isn't messed up
  1449. ::PostMessage(hwnd, WM_COMMAND, MAKELONG(CMD_VIEWFULLSCREEN, 0), 0);
  1450. }
  1451. }
  1452. break;
  1453. }
  1454. case WM_ENTERMENULOOP:
  1455. {
  1456. pasHost->m_pView->m_viewInMenuMode = TRUE;
  1457. break;
  1458. }
  1459. case WM_EXITMENULOOP:
  1460. {
  1461. pasHost->m_pView->m_viewInMenuMode = FALSE;
  1462. break;
  1463. }
  1464. case WM_COMMAND:
  1465. {
  1466. VIEWFrameCommand(pasHost, wParam, lParam);
  1467. break;
  1468. }
  1469. case WM_INITMENU:
  1470. {
  1471. if ((HMENU)wParam == pasHost->m_pView->m_viewMenuBar)
  1472. {
  1473. VIEWFrameInitMenuBar(pasHost);
  1474. }
  1475. break;
  1476. }
  1477. case WM_MENUSELECT:
  1478. {
  1479. VIEWFrameOnMenuSelect(pasHost, wParam, lParam);
  1480. break;
  1481. }
  1482. case WM_PALETTECHANGED:
  1483. //
  1484. // The system palette has changed - repaint the window.
  1485. //
  1486. VIEW_InvalidateRgn(pasHost, NULL);
  1487. //
  1488. // The system palette has changed. If we are not the
  1489. // window that triggered this message then realize our
  1490. // palette now to set up our new palette mapping.
  1491. //
  1492. if ((HWND)wParam == hwnd)
  1493. {
  1494. //
  1495. // If this window caused the change return without
  1496. // realizing our logical palette or we could end up in
  1497. // an infinite loop.
  1498. //
  1499. break;
  1500. }
  1501. TRACE_OUT(("Palette changed - fall through to realize palette (%x)",
  1502. hwnd));
  1503. //
  1504. // Do not break here but FALL THROUGH to the code which
  1505. // realizes the remote palette into this window. This allows
  1506. // the window to grab some color entries for itself in the new
  1507. // system palette.
  1508. //
  1509. case WM_QUERYNEWPALETTE:
  1510. rc = FALSE;
  1511. if (message == WM_QUERYNEWPALETTE)
  1512. {
  1513. TRACE_OUT(( "WM_QUERYNEWPALETTE hwnd(%x)", hwnd));
  1514. }
  1515. if (g_usrPalettized)
  1516. {
  1517. HDC hdc;
  1518. HPALETTE hPalOld;
  1519. UINT cChangedEntries;
  1520. //
  1521. // Realize this window's palette, and force a repaint
  1522. // if necessary.
  1523. //
  1524. hdc = GetDC(hwnd);
  1525. hPalOld = SelectPalette(hdc, pasHost->pmPalette, FALSE);
  1526. cChangedEntries = RealizePalette(hdc);
  1527. SelectPalette(hdc, hPalOld, FALSE);
  1528. ReleaseDC(hwnd, hdc);
  1529. rc = (cChangedEntries > 0);
  1530. if (rc)
  1531. {
  1532. // Have to repaint this window
  1533. VIEW_InvalidateRgn(pasHost, NULL);
  1534. }
  1535. }
  1536. break;
  1537. case WM_GETMINMAXINFO:
  1538. {
  1539. RECT rc;
  1540. LPMINMAXINFO lpmmi = (LPMINMAXINFO) lParam;
  1541. int cx,cy;
  1542. if (!pasHost)
  1543. {
  1544. // We're not created yet; bail.
  1545. break;
  1546. }
  1547. //
  1548. // Calculate the ideal maximized size for this window
  1549. //
  1550. VIEWFrameGetSize(pasHost, &rc);
  1551. //
  1552. // If it's bigger than the local screen, clip it.
  1553. //
  1554. cx = min(rc.right - rc.left, m_pasLocal->cpcCaps.screen.capsScreenWidth);
  1555. cy = min(rc.bottom - rc.top, m_pasLocal->cpcCaps.screen.capsScreenHeight);
  1556. lpmmi->ptMaxSize.x = cx;
  1557. lpmmi->ptMaxSize.y = cy;
  1558. lpmmi->ptMaxTrackSize.x = cx;
  1559. lpmmi->ptMaxTrackSize.y = cy;
  1560. //
  1561. // Make sure that we don't size this window too narrow. Keep
  1562. // space for borders and one window bar button + scroll ctl.
  1563. //
  1564. lpmmi->ptMinTrackSize.x = 2*::GetSystemMetrics(SM_CXSIZEFRAME) +
  1565. (m_viewItemCX + m_viewEdgeCX) + m_viewItemScrollCX;
  1566. //
  1567. // And prevent sizing too short. Keep space for borders, menu
  1568. // bar, status bar, and window bar
  1569. //
  1570. lpmmi->ptMinTrackSize.y = 2*::GetSystemMetrics(SM_CYSIZEFRAME) +
  1571. ::GetSystemMetrics(SM_CYCAPTION) + ::GetSystemMetrics(SM_CYMENU);
  1572. if (pasHost->m_pView->m_viewStatusBarOn)
  1573. {
  1574. lpmmi->ptMinTrackSize.y += m_viewStatusBarCY + m_viewEdgeCY;
  1575. }
  1576. break;
  1577. }
  1578. case WM_SIZE:
  1579. {
  1580. if (wParam != SIZE_MINIMIZED)
  1581. {
  1582. VIEWFrameResize(pasHost);
  1583. }
  1584. break;
  1585. }
  1586. default:
  1587. DefWndProc:
  1588. rc = DefWindowProc(hwnd, message, wParam, lParam);
  1589. break;
  1590. }
  1591. DebugExitDWORD(ASShare::VIEW_FrameWindowProc, rc);
  1592. return(rc);
  1593. }
  1594. //
  1595. // VIEWFrameCreate()
  1596. //
  1597. BOOL ASShare::VIEWFrameCreate(ASPerson * pasPerson)
  1598. {
  1599. RECT rect;
  1600. BOOL rc = FALSE;
  1601. DebugEntry(VIEWFrameCreate);
  1602. ValidateView(pasPerson);
  1603. //
  1604. // Creates the children which lie in the frame's client:
  1605. // * the toolbar hugs the top
  1606. // * the statusbar hugs the bottom
  1607. // * the tray hugs the left underneath the toolbar and above the
  1608. // statusbar
  1609. // * the view fills in what's left
  1610. //
  1611. GetClientRect(pasPerson->m_pView->m_viewFrame, &rect);
  1612. //
  1613. // Create the statusbar (hugs bottom)
  1614. //
  1615. pasPerson->m_pView->m_viewStatusBar = ::CreateWindowEx(0, STATUSCLASSNAME,
  1616. NULL, WS_CHILD | WS_VISIBLE | CCS_NOPARENTALIGN | CCS_NOMOVEY | CCS_NORESIZE |
  1617. SBARS_SIZEGRIP,
  1618. rect.left, rect.bottom - m_viewStatusBarCY, rect.right - rect.left,
  1619. m_viewStatusBarCY, pasPerson->m_pView->m_viewFrame, NULL, g_asInstance,
  1620. NULL);
  1621. if (!pasPerson->m_pView->m_viewStatusBar)
  1622. {
  1623. ERROR_OUT(("Couldn't create statusbar for frame of person [%d]", pasPerson->mcsID));
  1624. DC_QUIT;
  1625. }
  1626. rect.bottom -= m_viewStatusBarCY + m_viewEdgeCY;
  1627. //
  1628. // Create the view (takes up rest of client)
  1629. //
  1630. if (!CreateWindowEx(WS_EX_CLIENTEDGE,
  1631. VIEW_CLIENT_CLASS_NAME, NULL,
  1632. WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE | WS_CHILD |
  1633. WS_VSCROLL | WS_HSCROLL,
  1634. rect.left, rect.top,
  1635. rect.right - rect.left, rect.bottom - rect.top,
  1636. pasPerson->m_pView->m_viewFrame,
  1637. NULL, g_asInstance, pasPerson))
  1638. {
  1639. ERROR_OUT(("VIEWFrameCreate: Failed to create view"));
  1640. DC_QUIT;
  1641. }
  1642. rc = TRUE;
  1643. DC_EXIT_POINT:
  1644. DebugExitBOOL(ASShare::VIEWFrameCreate, rc);
  1645. return(rc);
  1646. }
  1647. //
  1648. // VIEWFrameResize()
  1649. // Repositions the child windows when the frame is resized.
  1650. //
  1651. void ASShare::VIEWFrameResize(ASPerson * pasPerson)
  1652. {
  1653. RECT rect;
  1654. DebugEntry(ASShare::VIEWFrameResize);
  1655. ValidateView(pasPerson);
  1656. GetClientRect(pasPerson->m_pView->m_viewFrame, &rect);
  1657. //
  1658. // Move the statusbar
  1659. //
  1660. if ((pasPerson->m_pView->m_viewStatusBar != NULL) &&
  1661. (pasPerson->m_pView->m_viewStatusBarOn))
  1662. {
  1663. MoveWindow(pasPerson->m_pView->m_viewStatusBar, rect.left,
  1664. rect.bottom - m_viewStatusBarCY, rect.right - rect.left,
  1665. m_viewStatusBarCY, TRUE);
  1666. rect.bottom -= m_viewStatusBarCY + m_viewEdgeCY;
  1667. }
  1668. //
  1669. // Move the view
  1670. //
  1671. MoveWindow(pasPerson->m_pView->m_viewClient, rect.left, rect.top,
  1672. rect.right - rect.left, rect.bottom - rect.top, TRUE);
  1673. DebugExitVOID(ASShare::VIEWFrameResize);
  1674. }
  1675. //
  1676. // VIEWFrameResizeChanged()
  1677. //
  1678. // Called when the widgets of the frame (the status bar, the window bar, etc.)
  1679. // come or go. We may need to shrink the window, if the view is going
  1680. // to end up being bigger than the host's desktop.
  1681. //
  1682. void ASShare::VIEWFrameResizeChanged(ASPerson * pasHost)
  1683. {
  1684. RECT rcView;
  1685. DebugEntry(ASShare::VIEWFrameResizeChanged);
  1686. // Get current view size
  1687. GetClientRect(pasHost->m_pView->m_viewClient, &rcView);
  1688. //
  1689. // The view area can't be bigger than the remote's desktop area
  1690. //
  1691. if ((rcView.bottom - rcView.top) >= pasHost->viewExtent.y)
  1692. {
  1693. RECT rcWindowCur;
  1694. RECT rcWindowMax;
  1695. // Get current frame size
  1696. GetWindowRect(pasHost->m_pView->m_viewFrame, &rcWindowCur);
  1697. // Get maximum frame size
  1698. VIEWFrameGetSize(pasHost, &rcWindowMax);
  1699. // Resize vertically to just hold everything
  1700. SetWindowPos(pasHost->m_pView->m_viewFrame, NULL, 0, 0,
  1701. rcWindowCur.right - rcWindowCur.left,
  1702. rcWindowMax.bottom - rcWindowMax.top,
  1703. SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
  1704. }
  1705. else
  1706. {
  1707. // We can stay the same size, and just shuffle the pieces around
  1708. VIEWFrameResize(pasHost);
  1709. }
  1710. DebugExitVOID(ASShare::VIEWFrameResizeChanged);
  1711. }
  1712. //
  1713. // VIEWFrameCommand()
  1714. //
  1715. // Handles commands from menus/accelerators for frame views
  1716. //
  1717. void ASShare::VIEWFrameCommand
  1718. (
  1719. ASPerson* pasHost,
  1720. WPARAM wParam,
  1721. LPARAM lParam
  1722. )
  1723. {
  1724. UINT cmd;
  1725. MENUITEMINFO mi;
  1726. DebugEntry(ASShare::VIEWFrameCommand);
  1727. ValidateView(pasHost);
  1728. cmd = GET_WM_COMMAND_ID(wParam, lParam);
  1729. switch (cmd)
  1730. {
  1731. case CMD_TAKECONTROL:
  1732. {
  1733. CA_TakeControl(pasHost);
  1734. break;
  1735. }
  1736. case CMD_CANCELCONTROL:
  1737. {
  1738. CA_CancelTakeControl(pasHost, TRUE);
  1739. break;
  1740. }
  1741. case CMD_RELEASECONTROL:
  1742. {
  1743. CA_ReleaseControl(pasHost, TRUE);
  1744. break;
  1745. }
  1746. case CMD_CTRLALTDEL:
  1747. {
  1748. AWC_SendMsg(pasHost->mcsID, AWC_MSG_SAS, 0, 0);
  1749. break;
  1750. }
  1751. case CMD_VIEWSTATUSBAR:
  1752. {
  1753. ASSERT(::IsWindow(pasHost->m_pView->m_viewStatusBar));
  1754. // Toggle show/hide of status bar, then resize
  1755. if (pasHost->m_pView->m_viewStatusBarOn)
  1756. {
  1757. pasHost->m_pView->m_viewStatusBarOn = FALSE;
  1758. ::ShowWindow(pasHost->m_pView->m_viewStatusBar, SW_HIDE);
  1759. }
  1760. else
  1761. {
  1762. pasHost->m_pView->m_viewStatusBarOn = TRUE;
  1763. ::ShowWindow(pasHost->m_pView->m_viewStatusBar, SW_SHOW);
  1764. }
  1765. VIEWFrameResizeChanged(pasHost);
  1766. break;
  1767. }
  1768. case CMD_VIEWFULLSCREEN:
  1769. {
  1770. VIEWFrameFullScreen(pasHost, (pasHost->m_pView->m_viewFullScreen == 0));
  1771. break;
  1772. }
  1773. case CMD_HELPTOPICS:
  1774. {
  1775. VIEWFrameHelp(pasHost);
  1776. break;
  1777. }
  1778. case CMD_HELPABOUT:
  1779. {
  1780. VIEWFrameAbout(pasHost);
  1781. break;
  1782. }
  1783. default:
  1784. {
  1785. if ((cmd >= CMD_FORWARDCONTROLSTART) && (cmd < CMD_FORWARDCONTROLMAX))
  1786. {
  1787. if ((pasHost->m_caControlledBy == m_pasLocal))
  1788. {
  1789. //
  1790. // This is a request to pass control. Get the item data,
  1791. // the remote's MCS ID, then look to see if this person is
  1792. // still in the share. If so, pass control to them.
  1793. //
  1794. ZeroMemory(&mi, sizeof(mi));
  1795. mi.cbSize = sizeof(mi);
  1796. mi.fMask = MIIM_DATA;
  1797. GetMenuItemInfo(GetSubMenu(GetSubMenu(pasHost->m_pView->m_viewMenuBar,
  1798. IDSM_CONTROL), POS_FORWARDCONTROLCMD), cmd, FALSE, &mi);
  1799. if (!mi.dwItemData)
  1800. {
  1801. ERROR_OUT(("No item data for command %d", cmd));
  1802. }
  1803. else
  1804. {
  1805. ASPerson * pasT;
  1806. if (SC_ValidateNetID((MCSID)mi.dwItemData, &pasT))
  1807. {
  1808. CA_PassControl(pasHost, pasT);
  1809. }
  1810. }
  1811. }
  1812. }
  1813. else
  1814. {
  1815. ERROR_OUT(("Unrecognized WM_COMMAND id"));
  1816. }
  1817. break;
  1818. }
  1819. }
  1820. DebugExitVOID(ASShare::VIEWFrameCommand);
  1821. }
  1822. //
  1823. // ASShare::VIEWFrameInitMenuBar()
  1824. //
  1825. void ASShare::VIEWFrameInitMenuBar(ASPerson* pasHost)
  1826. {
  1827. HMENU hMenu;
  1828. HMENU hSubMenu;
  1829. int iItem;
  1830. MENUITEMINFO mi;
  1831. UINT cmd;
  1832. UINT ids;
  1833. UINT flags;
  1834. char szItem[256];
  1835. DebugEntry(ASShare::VIEWFrameInitMenu);
  1836. ValidateView(pasHost);
  1837. hMenu = pasHost->m_pView->m_viewMenuBar;
  1838. ASSERT(hMenu);
  1839. //
  1840. // CONTROL MENU
  1841. //
  1842. cmd = CMD_TAKECONTROL;
  1843. ids = IDS_CMD_TAKECONTROL;
  1844. flags = MF_ENABLED;
  1845. if (pasHost->m_caControlledBy == m_pasLocal)
  1846. {
  1847. ASSERT(pasHost->m_caAllowControl);
  1848. cmd = CMD_RELEASECONTROL;
  1849. ids = IDS_CMD_RELEASECONTROL;
  1850. //
  1851. // If the remote is unattended and we're in control, no releasing.
  1852. //
  1853. if (pasHost->cpcCaps.general.typeFlags & AS_UNATTENDED)
  1854. flags = MF_GRAYED;
  1855. }
  1856. else if ((m_caWaitingForReplyFrom == pasHost) &&
  1857. (m_caWaitingForReplyMsg == CA_REPLY_REQUEST_TAKECONTROL))
  1858. {
  1859. ASSERT(pasHost->m_caAllowControl);
  1860. cmd = CMD_CANCELCONTROL;
  1861. ids = IDS_CMD_CANCELCONTROL;
  1862. }
  1863. else if (!pasHost->m_caAllowControl || pasHost->m_caControlledBy)
  1864. {
  1865. //
  1866. // Host isn't allowing control, or somebody else is in control right
  1867. // now.
  1868. //
  1869. flags = MF_GRAYED;
  1870. }
  1871. flags |= MF_STRING | MF_BYPOSITION;
  1872. ::LoadString(g_asInstance, ids, szItem, sizeof(szItem));
  1873. hSubMenu = GetSubMenu(hMenu, IDSM_CONTROL);
  1874. ModifyMenu(hSubMenu, POS_CONTROLCMD, flags, cmd, szItem);
  1875. //
  1876. // If we're in control, and there's another 3.0 dude in the conference,
  1877. // enable PassControl and build the popup.
  1878. //
  1879. EnableMenuItem(hSubMenu, POS_FORWARDCONTROLCMD, MF_GRAYED | MF_BYPOSITION);
  1880. if (pasHost->m_caControlledBy == m_pasLocal)
  1881. {
  1882. ASPerson * pasT;
  1883. HMENU hPassMenu;
  1884. hPassMenu = GetSubMenu(hSubMenu, POS_FORWARDCONTROLCMD);
  1885. ASSERT(IsMenu(hPassMenu));
  1886. //
  1887. // Delete existing items.
  1888. //
  1889. iItem = GetMenuItemCount(hPassMenu);
  1890. while (iItem > 0)
  1891. {
  1892. iItem--;
  1893. DeleteMenu(hPassMenu, iItem, MF_BYPOSITION);
  1894. }
  1895. //
  1896. // Add items for the other 3.0 nodes besides us & the host.
  1897. //
  1898. iItem = CMD_FORWARDCONTROLSTART;
  1899. pasT = m_pasLocal->pasNext;
  1900. while (pasT != NULL)
  1901. {
  1902. if (pasT != pasHost)
  1903. {
  1904. //
  1905. // This dude is a candidate. We must store the MCS IDs since the
  1906. // any person could go away while we're in menu mode.
  1907. //
  1908. ZeroMemory(&mi, sizeof(mi));
  1909. mi.cbSize = sizeof(mi);
  1910. mi.fMask = MIIM_ID | MIIM_STATE | MIIM_TYPE | MIIM_DATA;
  1911. mi.fType = MFT_STRING;
  1912. mi.fState = MFS_ENABLED;
  1913. mi.wID = iItem;
  1914. mi.dwItemData = pasT->mcsID;
  1915. mi.dwTypeData = pasT->scName;
  1916. mi.cch = lstrlen(pasT->scName);
  1917. //
  1918. // Append this to the menu
  1919. //
  1920. InsertMenuItem(hPassMenu, -1, TRUE, &mi);
  1921. iItem++;
  1922. }
  1923. pasT = pasT->pasNext;
  1924. }
  1925. //
  1926. // Enable the Pass Control submenu if there's somebody on the
  1927. // menu.
  1928. //
  1929. if (iItem != CMD_FORWARDCONTROLSTART)
  1930. {
  1931. EnableMenuItem(hSubMenu, POS_FORWARDCONTROLCMD, MF_ENABLED | MF_BYPOSITION);
  1932. }
  1933. }
  1934. //
  1935. // VIEW MENU
  1936. //
  1937. // Status bar
  1938. ASSERT(::IsWindow(pasHost->m_pView->m_viewStatusBar));
  1939. if (pasHost->m_pView->m_viewStatusBarOn)
  1940. {
  1941. ::CheckMenuItem(hMenu, CMD_VIEWSTATUSBAR, MF_CHECKED | MF_BYCOMMAND);
  1942. }
  1943. else
  1944. {
  1945. ::CheckMenuItem(hMenu, CMD_VIEWSTATUSBAR, MF_UNCHECKED | MF_BYCOMMAND);
  1946. }
  1947. DebugExitVOID(ASShare::VIEWFrameInitMenu);
  1948. }
  1949. //
  1950. // VIEWFrameOnMenuSelect()
  1951. //
  1952. void ASShare::VIEWFrameOnMenuSelect
  1953. (
  1954. ASPerson * pasHost,
  1955. WPARAM wParam,
  1956. LPARAM lParam
  1957. )
  1958. {
  1959. HMENU hMenu;
  1960. int uItem;
  1961. UINT flags;
  1962. UINT idsStatus = IDS_STATUS_NONE;
  1963. DebugEntry(ASShare::VIEWFrameOnMenuSelect);
  1964. //
  1965. // Extract the params out (menuselect is messy)
  1966. //
  1967. hMenu = (HMENU)lParam;
  1968. uItem = (int)LOWORD(wParam);
  1969. if ((short)HIWORD(wParam) == -1)
  1970. {
  1971. flags = 0xFFFFFFFF;
  1972. }
  1973. else
  1974. {
  1975. flags = HIWORD(wParam);
  1976. }
  1977. if ((LOWORD(flags) == 0xFFFF) && !hMenu)
  1978. {
  1979. // Menu mode is ending. Put back original status.
  1980. idsStatus = pasHost->m_pView->m_viewStatus;
  1981. DC_QUIT;
  1982. }
  1983. if (!(flags & MF_POPUP))
  1984. {
  1985. if (flags & MF_SEPARATOR)
  1986. {
  1987. // No status
  1988. }
  1989. else if (flags & MF_SYSMENU)
  1990. {
  1991. // No status
  1992. }
  1993. else if ((uItem >= CMD_APPSTART) && (uItem < CMD_APPMAX))
  1994. {
  1995. // One of an unbounded set of items in the Window popup
  1996. idsStatus = IDS_STATUS_CMDS_APP;
  1997. }
  1998. else if ((uItem >= CMD_FORWARDCONTROLSTART) && (uItem < CMD_FORWARDCONTROLMAX))
  1999. {
  2000. // One of an unbounded set of items in the Forward Control popup
  2001. idsStatus = IDS_STATUS_CMDS_FORWARD;
  2002. }
  2003. else
  2004. {
  2005. // A normal command, just add offset to CMD id
  2006. idsStatus = uItem + IDS_STATUS_CMD_START;
  2007. }
  2008. }
  2009. else
  2010. {
  2011. // This is a popup menu
  2012. if (hMenu == pasHost->m_pView->m_viewMenuBar)
  2013. {
  2014. // It's a popup from the top level menu bar. uItem is the index
  2015. switch (uItem)
  2016. {
  2017. case IDSM_CONTROL:
  2018. idsStatus = IDS_STATUS_MENU_CONTROL;
  2019. break;
  2020. case IDSM_VIEW:
  2021. idsStatus = IDS_STATUS_MENU_VIEW;
  2022. break;
  2023. case IDSM_WINDOW:
  2024. idsStatus = IDS_STATUS_MENU_WINDOW;
  2025. break;
  2026. case IDSM_HELP:
  2027. idsStatus = IDS_STATUS_MENU_HELP;
  2028. break;
  2029. default:
  2030. ERROR_OUT(("AS: Unknown submenu index %d of frame", uItem));
  2031. break;
  2032. }
  2033. }
  2034. else if (hMenu == GetSubMenu(pasHost->m_pView->m_viewMenuBar, IDSM_CONTROL))
  2035. {
  2036. // This is a popup off the Control menu. The only one we have is Forward
  2037. idsStatus = IDS_STATUS_MENU_FORWARDCONTROL;
  2038. }
  2039. else if (flags & MF_SYSMENU)
  2040. {
  2041. // System menu
  2042. }
  2043. }
  2044. DC_EXIT_POINT:
  2045. VIEWFrameSetStatus(pasHost, idsStatus);
  2046. DebugEntry(ASShare::VIEWFrameOnMenuSelect);
  2047. }
  2048. //
  2049. // VIEWFrameHelp()
  2050. //
  2051. void ASShare::VIEWFrameHelp(ASPerson * pasHost)
  2052. {
  2053. DebugEntry(ASShare::VIEWFrameHelp);
  2054. DebugExitVOID(ASShare::VIEWFrameHelp);
  2055. }
  2056. //
  2057. // VIEWFrameAbout()
  2058. //
  2059. void ASShare::VIEWFrameAbout(ASPerson * pasHost)
  2060. {
  2061. DebugEntry(ASShare::VIEWFrameAbout);
  2062. //
  2063. // We make use of the standard centered-disabled-goes-away properly
  2064. // VIEW_Message() stuff.
  2065. //
  2066. VIEW_Message(pasHost, IDS_ABOUT);
  2067. DebugExitVOID(ASShare::VIEWFrameAbout);
  2068. }
  2069. //
  2070. // VIEWFrameGetSize()
  2071. // This returns back a rectangle for the ideal size of the frame. It will
  2072. // fit the view, menu, tools, tray, status, etc.
  2073. //
  2074. void ASShare::VIEWFrameGetSize(ASPerson * pasPerson, LPRECT lprc)
  2075. {
  2076. DebugEntry(ASShare::VIEWFrameGetSize);
  2077. ValidateView(pasPerson);
  2078. VIEWClientGetSize(pasPerson, lprc);
  2079. //
  2080. // Add in space for statusbar if it's on, etc.
  2081. //
  2082. if (pasPerson->m_pView->m_viewStatusBarOn)
  2083. {
  2084. lprc->bottom += m_viewStatusBarCY + m_viewEdgeCY;
  2085. }
  2086. if (!pasPerson->m_pView->m_viewFullScreen)
  2087. {
  2088. //
  2089. // Adjust for frame styles including menu bar.
  2090. //
  2091. AdjustWindowRectEx(lprc, WS_OVERLAPPEDWINDOW, TRUE, WS_EX_WINDOWEDGE);
  2092. }
  2093. DebugExitVOID(ASShare::VIEWFrameGetSize);
  2094. }
  2095. //
  2096. // VIEWFrameFullScreen()
  2097. //
  2098. // This puts into or out of screen mode. We remove all the frame goop
  2099. // including scrollbars, so that the view area is identical to the screen.
  2100. //
  2101. void ASShare::VIEWFrameFullScreen(ASPerson * pasPerson, BOOL fFull)
  2102. {
  2103. LONG lStyle;
  2104. RECT rcNew;
  2105. DebugEntry(ASShare::VIEWFrameFullScreen);
  2106. //
  2107. // Turn redraw OFF
  2108. //
  2109. ::SendMessage(pasPerson->m_pView->m_viewFrame, WM_SETREDRAW, FALSE, 0);
  2110. if (fFull)
  2111. {
  2112. //
  2113. // We're going into full screen mode.
  2114. //
  2115. ASSERT(!pasPerson->m_pView->m_viewFullScreen);
  2116. pasPerson->m_pView->m_viewFullScreen = TRUE;
  2117. //
  2118. // Save old window rect
  2119. //
  2120. ::GetWindowRect(pasPerson->m_pView->m_viewFrame,
  2121. &pasPerson->m_pView->m_viewSavedWindowRect);
  2122. //
  2123. // Save old scroll pos and set to the origin. Do this BEFORE
  2124. // clearing style bits.
  2125. //
  2126. pasPerson->m_pView->m_viewSavedPos = pasPerson->m_pView->m_viewPos;
  2127. VIEWClientScroll(pasPerson, 0, 0);
  2128. //
  2129. // Save current status bar state before turning it off temporarily.
  2130. //
  2131. if (pasPerson->m_pView->m_viewStatusBarOn)
  2132. {
  2133. pasPerson->m_pView->m_viewSavedStatusBarOn = TRUE;
  2134. pasPerson->m_pView->m_viewStatusBarOn = FALSE;
  2135. ::ShowWindow(pasPerson->m_pView->m_viewStatusBar, SW_HIDE);
  2136. }
  2137. else
  2138. {
  2139. pasPerson->m_pView->m_viewSavedStatusBarOn = FALSE;
  2140. }
  2141. //
  2142. // Remove all frame and client bits.
  2143. //
  2144. lStyle = ::GetWindowLong(pasPerson->m_pView->m_viewFrame, GWL_EXSTYLE);
  2145. lStyle &= ~WS_EX_WINDOWEDGE;
  2146. ::SetWindowLong(pasPerson->m_pView->m_viewFrame, GWL_EXSTYLE, lStyle);
  2147. lStyle = ::GetWindowLong(pasPerson->m_pView->m_viewFrame, GWL_STYLE);
  2148. lStyle &= ~(WS_CAPTION | WS_THICKFRAME);
  2149. lStyle |= WS_POPUP;
  2150. ::SetWindowLong(pasPerson->m_pView->m_viewFrame, GWL_STYLE, lStyle);
  2151. lStyle = ::GetWindowLong(pasPerson->m_pView->m_viewClient, GWL_EXSTYLE);
  2152. lStyle &= ~WS_EX_CLIENTEDGE;
  2153. ::SetWindowLong(pasPerson->m_pView->m_viewClient, GWL_EXSTYLE, lStyle);
  2154. lStyle = ::GetWindowLong(pasPerson->m_pView->m_viewClient, GWL_STYLE);
  2155. lStyle &= ~(WS_HSCROLL | WS_VSCROLL);
  2156. ::SetWindowLong(pasPerson->m_pView->m_viewClient, GWL_STYLE, lStyle);
  2157. //
  2158. // Remove the menu bar
  2159. //
  2160. ::SetMenu(pasPerson->m_pView->m_viewFrame, NULL);
  2161. //
  2162. // Set up to size window the size of the screen.
  2163. //
  2164. rcNew.left = 0;
  2165. rcNew.top = 0;
  2166. rcNew.right = m_pasLocal->cpcCaps.screen.capsScreenWidth;
  2167. rcNew.bottom = m_pasLocal->cpcCaps.screen.capsScreenHeight;
  2168. //
  2169. // Create the moveable escape-out button in the lower right corner.
  2170. //
  2171. ::CreateWindowEx(0, VIEW_FULLEXIT_CLASS_NAME, NULL,
  2172. WS_CHILD | WS_VISIBLE,
  2173. rcNew.right - m_viewFullScreenCX - 2*m_viewEdgeCX,
  2174. rcNew.top + 2*m_viewEdgeCY,
  2175. m_viewFullScreenCX, m_viewFullScreenCY,
  2176. pasPerson->m_pView->m_viewClient,
  2177. (HMENU)0,
  2178. g_asInstance,
  2179. pasPerson);
  2180. }
  2181. else
  2182. {
  2183. //
  2184. // We're coming out of full screen mode.
  2185. //
  2186. //
  2187. // Destroy the escape-out button
  2188. //
  2189. ::DestroyWindow(::GetDlgItem(pasPerson->m_pView->m_viewClient, 0));
  2190. //
  2191. // Put back the menu bar. Do this BEFORE clearing the full screen bit
  2192. //
  2193. ::SetMenu(pasPerson->m_pView->m_viewFrame, pasPerson->m_pView->m_viewMenuBar);
  2194. ASSERT(pasPerson->m_pView->m_viewFullScreen);
  2195. pasPerson->m_pView->m_viewFullScreen = FALSE;
  2196. //
  2197. // Put back old status bar state.
  2198. //
  2199. if (pasPerson->m_pView->m_viewSavedStatusBarOn)
  2200. {
  2201. pasPerson->m_pView->m_viewStatusBarOn = TRUE;
  2202. ::ShowWindow(pasPerson->m_pView->m_viewStatusBar, SW_SHOW);
  2203. }
  2204. //
  2205. // Add back all frame and client bits.
  2206. //
  2207. lStyle = ::GetWindowLong(pasPerson->m_pView->m_viewFrame, GWL_EXSTYLE);
  2208. lStyle |= WS_EX_WINDOWEDGE;
  2209. ::SetWindowLong(pasPerson->m_pView->m_viewFrame, GWL_EXSTYLE, lStyle);
  2210. lStyle = ::GetWindowLong(pasPerson->m_pView->m_viewFrame, GWL_STYLE);
  2211. lStyle &= ~(WS_POPUP);
  2212. lStyle |= (WS_CAPTION | WS_THICKFRAME);
  2213. ::SetWindowLong(pasPerson->m_pView->m_viewFrame, GWL_STYLE, lStyle);
  2214. lStyle = ::GetWindowLong(pasPerson->m_pView->m_viewClient, GWL_EXSTYLE);
  2215. lStyle |= WS_EX_CLIENTEDGE;
  2216. ::SetWindowLong(pasPerson->m_pView->m_viewClient, GWL_EXSTYLE, lStyle);
  2217. lStyle = ::GetWindowLong(pasPerson->m_pView->m_viewClient, GWL_STYLE);
  2218. lStyle |= (WS_HSCROLL | WS_VSCROLL);
  2219. ::SetWindowLong(pasPerson->m_pView->m_viewClient, GWL_STYLE, lStyle);
  2220. //
  2221. // Put back old scroll pos AFTER style bits restore.
  2222. //
  2223. VIEWClientScroll(pasPerson, pasPerson->m_pView->m_viewSavedPos.x,
  2224. pasPerson->m_pView->m_viewSavedPos.y);
  2225. //
  2226. // Restore the window back to where it started.
  2227. //
  2228. rcNew = pasPerson->m_pView->m_viewSavedWindowRect;
  2229. }
  2230. //
  2231. // Resize, reframe, and repaint from scratch.
  2232. //
  2233. ::SendMessage(pasPerson->m_pView->m_viewFrame, WM_SETREDRAW, TRUE, 0);
  2234. ::SetWindowPos(pasPerson->m_pView->m_viewFrame, NULL, rcNew.left,
  2235. rcNew.top, rcNew.right - rcNew.left, rcNew.bottom - rcNew.top,
  2236. SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_NOCOPYBITS);
  2237. DebugExitVOID(ASShare::VIEWFrameFullScreen);
  2238. }
  2239. //
  2240. // VIEWClientGetSize()
  2241. // This returns back a rectangle for the ideal size of the view part of the
  2242. // frame client. It will fit the extent of what we're viewing on the remote
  2243. // plus scrollbars.
  2244. //
  2245. void ASShare::VIEWClientGetSize(ASPerson * pasPerson, LPRECT lprc)
  2246. {
  2247. DebugEntry(ASShare::VIEWClientGetSize);
  2248. ValidateView(pasPerson);
  2249. lprc->left = 0;
  2250. lprc->top = 0;
  2251. lprc->right = pasPerson->viewExtent.x;
  2252. lprc->bottom = pasPerson->viewExtent.y;
  2253. if (!pasPerson->m_pView->m_viewFullScreen)
  2254. {
  2255. AdjustWindowRectEx(lprc, WS_CHILD, FALSE, WS_EX_CLIENTEDGE);
  2256. lprc->right += GetSystemMetrics(SM_CXVSCROLL);
  2257. lprc->bottom += GetSystemMetrics(SM_CYHSCROLL);
  2258. }
  2259. DebugExitVOID(ASShare::VIEWClientGetSize);
  2260. }
  2261. //
  2262. // VIEWClientWindowProc()
  2263. // Handles messages for the view window, a child in the client of the frame
  2264. // which displays the contents of the remote host's shared apps.
  2265. //
  2266. LRESULT CALLBACK VIEWClientWindowProc
  2267. (
  2268. HWND hwnd,
  2269. UINT message,
  2270. WPARAM wParam,
  2271. LPARAM lParam
  2272. )
  2273. {
  2274. return(g_asSession.pShare->VIEW_ViewWindowProc(hwnd, message, wParam, lParam));
  2275. }
  2276. LRESULT ASShare::VIEW_ViewWindowProc
  2277. (
  2278. HWND hwnd,
  2279. UINT message,
  2280. WPARAM wParam,
  2281. LPARAM lParam
  2282. )
  2283. {
  2284. LRESULT rc = 0;
  2285. RECT rcl;
  2286. POINT mousePos;
  2287. SCROLLINFO si;
  2288. ASPerson * pasPerson;
  2289. DebugEntry(ASShare::VIEW_ViewWindowProc);
  2290. pasPerson = (ASPerson *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  2291. if (pasPerson)
  2292. {
  2293. ValidateView(pasPerson);
  2294. }
  2295. switch (message)
  2296. {
  2297. case WM_NCCREATE:
  2298. {
  2299. // Get the passed in host pointer, and set in our window long
  2300. pasPerson = (ASPerson *)((LPCREATESTRUCT)lParam)->lpCreateParams;
  2301. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)pasPerson);
  2302. pasPerson->m_pView->m_viewClient = hwnd;
  2303. goto DefWndProc;
  2304. break;
  2305. }
  2306. case WM_NCDESTROY:
  2307. {
  2308. if (pasPerson != NULL)
  2309. {
  2310. pasPerson->m_pView->m_viewClient = NULL;
  2311. }
  2312. goto DefWndProc;
  2313. break;
  2314. }
  2315. case WM_ERASEBKGND:
  2316. {
  2317. //
  2318. // BOGUS LAURABU: Paint on erase then validate for faster
  2319. // response.
  2320. //
  2321. rc = TRUE;
  2322. break;
  2323. }
  2324. case WM_PAINT:
  2325. {
  2326. VIEWClientPaint(pasPerson);
  2327. break;
  2328. }
  2329. case WM_SETFOCUS:
  2330. {
  2331. pasPerson->m_pView->m_viewFocus = TRUE;
  2332. pasPerson->m_pView->m_viewMouseWheelDelta = 0;
  2333. break;
  2334. }
  2335. case WM_KILLFOCUS:
  2336. {
  2337. pasPerson->m_pView->m_viewFocus = FALSE;
  2338. pasPerson->m_pView->m_viewMouseWheelDelta = 0;
  2339. break;
  2340. }
  2341. case WM_LBUTTONDOWN:
  2342. case WM_RBUTTONDOWN:
  2343. case WM_MBUTTONDOWN:
  2344. {
  2345. VIEWClientMouseDown(pasPerson, message, wParam, lParam);
  2346. break;
  2347. }
  2348. case WM_LBUTTONUP:
  2349. case WM_RBUTTONUP:
  2350. case WM_MBUTTONUP:
  2351. {
  2352. VIEWClientMouseUp(pasPerson, message, wParam, lParam, TRUE);
  2353. break;
  2354. }
  2355. case WM_MOUSEMOVE:
  2356. {
  2357. VIEWClientMouseMove(pasPerson, message, wParam, lParam);
  2358. break;
  2359. }
  2360. case WM_MOUSEWHEEL:
  2361. {
  2362. //
  2363. // We've handled it no matter what, don't pass it up the chain.
  2364. //
  2365. rc = TRUE;
  2366. //
  2367. // If we're not controlling this dude, try to use the mousewheel
  2368. // to scroll.
  2369. //
  2370. if ((pasPerson->m_caControlledBy != m_pasLocal))
  2371. {
  2372. VIEWClientMouseWheel(pasPerson, wParam, lParam);
  2373. break;
  2374. }
  2375. //
  2376. // FALL THROUGH
  2377. // Otherwise, we send the MOUSEWHEEL message to the host.
  2378. //
  2379. }
  2380. case WM_LBUTTONDBLCLK:
  2381. case WM_RBUTTONDBLCLK:
  2382. case WM_MBUTTONDBLCLK:
  2383. {
  2384. VIEWClientMouseMsg(pasPerson, message, wParam, lParam);
  2385. break;
  2386. }
  2387. case WM_TIMER:
  2388. {
  2389. if (wParam == IDT_AUTOSCROLL)
  2390. {
  2391. VIEWClientAutoScroll(pasPerson);
  2392. }
  2393. break;
  2394. }
  2395. case WM_CAPTURECHANGED:
  2396. {
  2397. //
  2398. // Check if capture got stolen away from us, if we think the
  2399. // buttons are down fake a button up.
  2400. //
  2401. if (pasPerson->m_pView->m_viewMouseFlags != 0)
  2402. {
  2403. VIEWClientCaptureStolen(pasPerson);
  2404. }
  2405. break;
  2406. }
  2407. case WM_KEYDOWN:
  2408. {
  2409. WPARAM wScrollNotify;
  2410. UINT uMsg;
  2411. if ((pasPerson->m_caControlledBy == m_pasLocal))
  2412. {
  2413. goto KeyInput;
  2414. }
  2415. if (pasPerson->m_pView->m_viewFullScreen)
  2416. {
  2417. if (wParam == VK_ESCAPE)
  2418. {
  2419. //
  2420. // Kick out of full screen mode.
  2421. //
  2422. VIEWFrameFullScreen(pasPerson, FALSE);
  2423. }
  2424. goto DefWndProc;
  2425. }
  2426. //
  2427. // UP, DOWN, LEFT, and RIGHT are unambiguous about which
  2428. // scrollbar is intended.
  2429. //
  2430. // For the others, unmodified is vertical and SHIFT is
  2431. // horizontal.
  2432. //
  2433. if (::GetKeyState(VK_SHIFT) < 0)
  2434. {
  2435. uMsg = WM_HSCROLL;
  2436. }
  2437. else
  2438. {
  2439. uMsg = WM_VSCROLL;
  2440. }
  2441. switch (wParam)
  2442. {
  2443. //
  2444. // These aren't ambiguous, we know which scrollbar is meant
  2445. // by the direction.
  2446. //
  2447. case VK_UP:
  2448. wScrollNotify = SB_LINEUP;
  2449. uMsg = WM_VSCROLL;
  2450. break;
  2451. case VK_DOWN:
  2452. wScrollNotify = SB_LINEDOWN;
  2453. uMsg = WM_VSCROLL;
  2454. break;
  2455. case VK_LEFT:
  2456. wScrollNotify = SB_LINEUP;
  2457. uMsg = WM_HSCROLL;
  2458. break;
  2459. case VK_RIGHT:
  2460. wScrollNotify = SB_LINEDOWN;
  2461. uMsg = WM_HSCROLL;
  2462. break;
  2463. //
  2464. // These are ambiguous, hence the SHIFT key as a
  2465. // modifier.
  2466. //
  2467. case VK_PRIOR:
  2468. wScrollNotify = SB_PAGEUP;
  2469. break;
  2470. case VK_NEXT:
  2471. wScrollNotify = SB_PAGEDOWN;
  2472. break;
  2473. case VK_HOME:
  2474. wScrollNotify = SB_TOP;
  2475. break;
  2476. case VK_END:
  2477. wScrollNotify = SB_BOTTOM;
  2478. break;
  2479. default:
  2480. goto DefWndProc;
  2481. break;
  2482. }
  2483. SendMessage(hwnd, uMsg, MAKELONG(wScrollNotify, 0), 0L);
  2484. break;
  2485. }
  2486. case WM_SYSKEYDOWN:
  2487. {
  2488. if ((pasPerson->m_caControlledBy == m_pasLocal))
  2489. {
  2490. goto KeyInput;
  2491. }
  2492. //
  2493. // ALT-ENTER toggles full screen state, if it's available
  2494. //
  2495. if ((wParam == VK_RETURN) &&
  2496. !(::GetMenuState(pasPerson->m_pView->m_viewMenuBar,
  2497. CMD_VIEWFULLSCREEN, MF_BYCOMMAND) & MF_DISABLED))
  2498. {
  2499. VIEWFrameFullScreen(pasPerson,
  2500. (pasPerson->m_pView->m_viewFullScreen == 0));
  2501. }
  2502. goto DefWndProc;
  2503. break;
  2504. }
  2505. case WM_KEYUP:
  2506. case WM_SYSKEYUP:
  2507. {
  2508. //
  2509. // If we're controlling this node, pass it along. Otherwise,
  2510. // call DefWindowProc() so key accels like Alt+Space for system
  2511. // menu will kick in.
  2512. //
  2513. if ((pasPerson->m_caControlledBy == m_pasLocal))
  2514. {
  2515. KeyInput:
  2516. IM_OutgoingKeyboardInput(pasPerson, (UINT)wParam, (UINT)lParam);
  2517. }
  2518. else
  2519. {
  2520. goto DefWndProc;
  2521. }
  2522. break;
  2523. }
  2524. case WM_SETCURSOR:
  2525. {
  2526. if ((LOWORD(lParam) == HTCLIENT) && ((HWND)wParam == hwnd))
  2527. {
  2528. HCURSOR hCursor;
  2529. POINT cursorPoint;
  2530. if ((pasPerson->m_caControlledBy == m_pasLocal))
  2531. {
  2532. hCursor = m_cmArrowCursor;
  2533. //
  2534. // Only set the remote cursor if we're over shared space.
  2535. //
  2536. if (pasPerson->m_pView->m_viewFocus)
  2537. {
  2538. GetCursorPos(&cursorPoint);
  2539. ScreenToClient(hwnd, &cursorPoint);
  2540. if (VIEW_IsPointShared(pasPerson, cursorPoint))
  2541. {
  2542. hCursor = pasPerson->cmhRemoteCursor;
  2543. }
  2544. }
  2545. }
  2546. else
  2547. {
  2548. // NoDrop
  2549. hCursor = m_viewNotInControl;
  2550. }
  2551. SetCursor(hCursor);
  2552. rc = TRUE;
  2553. }
  2554. else
  2555. {
  2556. // Let defwindowproc handle it
  2557. goto DefWndProc;
  2558. }
  2559. break;
  2560. }
  2561. case WM_SIZE:
  2562. {
  2563. //
  2564. // If we're in full screen mode, there are no scrollbars.
  2565. //
  2566. if (!pasPerson->m_pView->m_viewFullScreen)
  2567. {
  2568. int xNewPos;
  2569. int yNewPos;
  2570. xNewPos = pasPerson->m_pView->m_viewPos.x;
  2571. yNewPos = pasPerson->m_pView->m_viewPos.y;
  2572. GetClientRect(hwnd, &rcl);
  2573. pasPerson->m_pView->m_viewPage.x = rcl.right - rcl.left;
  2574. pasPerson->m_pView->m_viewPage.y = rcl.bottom - rcl.top;
  2575. TRACE_OUT(("WM_SIZE: Set page size (%04d, %04d)",
  2576. pasPerson->m_pView->m_viewPage.x, pasPerson->m_pView->m_viewPage.y));
  2577. //
  2578. // Scroll window if necessary.
  2579. //
  2580. si.cbSize = sizeof(SCROLLINFO);
  2581. si.fMask = SIF_PAGE|SIF_DISABLENOSCROLL;
  2582. // Set new HORIZONTAL proportional scroll button size
  2583. si.nPage = pasPerson->m_pView->m_viewPage.x;
  2584. SetScrollInfo(hwnd, SB_HORZ, &si, TRUE );
  2585. // Set new VERTICAL proportional scroll button size
  2586. si.nPage = pasPerson->m_pView->m_viewPage.y;
  2587. SetScrollInfo(hwnd, SB_VERT, &si, TRUE );
  2588. //
  2589. // This will make sure the scroll pos is pinned properly
  2590. //
  2591. VIEWClientScroll(pasPerson, pasPerson->m_pView->m_viewPos.x, pasPerson->m_pView->m_viewPos.y);
  2592. }
  2593. break;
  2594. }
  2595. case WM_HSCROLL:
  2596. {
  2597. int xNewPos; // new position
  2598. switch (GET_WM_HSCROLL_CODE(wParam, lParam))
  2599. {
  2600. case SB_PAGEUP:
  2601. xNewPos = pasPerson->m_pView->m_viewPos.x - pasPerson->m_pView->m_viewPgSize.x;
  2602. break;
  2603. case SB_PAGEDOWN:
  2604. xNewPos = pasPerson->m_pView->m_viewPos.x + pasPerson->m_pView->m_viewPgSize.x;
  2605. break;
  2606. case SB_LINEUP:
  2607. xNewPos = pasPerson->m_pView->m_viewPos.x - pasPerson->m_pView->m_viewLnSize.x;
  2608. break;
  2609. case SB_LINEDOWN:
  2610. xNewPos = pasPerson->m_pView->m_viewPos.x + pasPerson->m_pView->m_viewLnSize.x;
  2611. break;
  2612. case SB_TOP:
  2613. xNewPos = 0;
  2614. break;
  2615. case SB_BOTTOM:
  2616. xNewPos = pasPerson->viewExtent.x;
  2617. break;
  2618. case SB_THUMBTRACK:
  2619. case SB_THUMBPOSITION:
  2620. xNewPos = GET_WM_HSCROLL_POS(wParam, lParam);
  2621. break;
  2622. default:
  2623. xNewPos = pasPerson->m_pView->m_viewPos.x;
  2624. break;
  2625. }
  2626. //
  2627. // This will pin the desired scroll pos in the range, and if
  2628. // nothing has changed, won't scroll.
  2629. //
  2630. VIEWClientScroll(pasPerson, xNewPos, pasPerson->m_pView->m_viewPos.y);
  2631. break;
  2632. }
  2633. case WM_VSCROLL:
  2634. {
  2635. int yNewPos; // new position
  2636. switch (GET_WM_VSCROLL_CODE(wParam, lParam))
  2637. {
  2638. case SB_PAGEUP:
  2639. yNewPos = pasPerson->m_pView->m_viewPos.y - pasPerson->m_pView->m_viewPgSize.y;
  2640. break;
  2641. case SB_PAGEDOWN:
  2642. yNewPos = pasPerson->m_pView->m_viewPos.y + pasPerson->m_pView->m_viewPgSize.y;
  2643. break;
  2644. case SB_LINEUP:
  2645. yNewPos = pasPerson->m_pView->m_viewPos.y - pasPerson->m_pView->m_viewLnSize.y;
  2646. break;
  2647. case SB_LINEDOWN:
  2648. yNewPos = pasPerson->m_pView->m_viewPos.y + pasPerson->m_pView->m_viewLnSize.y;
  2649. break;
  2650. case SB_TOP:
  2651. yNewPos = 0;
  2652. break;
  2653. case SB_BOTTOM:
  2654. yNewPos = pasPerson->viewExtent.y;
  2655. break;
  2656. case SB_THUMBTRACK:
  2657. case SB_THUMBPOSITION:
  2658. yNewPos = GET_WM_VSCROLL_POS(wParam, lParam);
  2659. break;
  2660. default:
  2661. yNewPos = pasPerson->m_pView->m_viewPos.y;
  2662. break;
  2663. }
  2664. //
  2665. // This will pin the desired scroll pos in the range, and if
  2666. // nothing has changed, won't scroll.
  2667. //
  2668. VIEWClientScroll(pasPerson, pasPerson->m_pView->m_viewPos.x, yNewPos);
  2669. break;
  2670. }
  2671. default:
  2672. DefWndProc:
  2673. rc = DefWindowProc(hwnd, message, wParam, lParam);
  2674. break;
  2675. }
  2676. DebugExitDWORD(ASShare::VIEW_ViewWindowProc, rc);
  2677. return(rc);
  2678. }
  2679. //
  2680. // VIEWClientPaint()
  2681. //
  2682. // This paints the client area of the view frame. We paint
  2683. // (1) The obscured area, in the obscured pattern
  2684. // * parts of shared regions that are covered up
  2685. // * parts of shared regions that are offscreen/off the VD
  2686. // (2) The shared area, from the bitmap
  2687. // (3) The deadspace, in COLOR_APPWORKSPACE
  2688. //
  2689. void ASShare::VIEWClientPaint(ASPerson * pasPerson)
  2690. {
  2691. PAINTSTRUCT ps;
  2692. HDC hdcView;
  2693. HPALETTE hOldPal;
  2694. HPALETTE hOldPal2;
  2695. RECT rcT;
  2696. DebugEntry(ASShare::VIEWClientPaint);
  2697. ValidateView(pasPerson);
  2698. hdcView = BeginPaint(pasPerson->m_pView->m_viewClient, &ps);
  2699. if (hdcView == NULL)
  2700. {
  2701. WARNING_OUT(( "Failed to get hdc for frame window %08X", pasPerson->m_pView->m_viewClient));
  2702. DC_QUIT;
  2703. }
  2704. if (IsRectEmpty(&ps.rcPaint))
  2705. {
  2706. TRACE_OUT(("Nothing to paint but got WM_PAINT message"));
  2707. DC_QUIT;
  2708. }
  2709. TRACE_OUT(("VIEWClientPaint: Painting total client area {%04d, %04d, %04d, %04d}",
  2710. ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom));
  2711. //
  2712. // In desktop sharing, viewSharedRgn is NULL
  2713. //
  2714. if (pasPerson->m_pView->m_viewSharedRgn != NULL)
  2715. {
  2716. POINT ptOrigin;
  2717. HBRUSH hbrT;
  2718. //
  2719. // First, create paint area region
  2720. //
  2721. SetRectRgn(pasPerson->m_pView->m_viewPaintRgn, ps.rcPaint.left, ps.rcPaint.top,
  2722. ps.rcPaint.right, ps.rcPaint.bottom);
  2723. //
  2724. // Second, compute the VD area not currently on screen. Do this
  2725. // in CLIENT coords.
  2726. //
  2727. SetRectRgn(pasPerson->m_pView->m_viewExtentRgn,
  2728. -pasPerson->m_pView->m_viewPos.x,
  2729. -pasPerson->m_pView->m_viewPos.y,
  2730. -pasPerson->m_pView->m_viewPos.x + pasPerson->viewExtent.x,
  2731. -pasPerson->m_pView->m_viewPos.y + pasPerson->viewExtent.y);
  2732. SetRectRgn(pasPerson->m_pView->m_viewScreenRgn,
  2733. -pasPerson->m_pView->m_viewPos.x + pasPerson->m_pView->m_dsScreenOrigin.x,
  2734. -pasPerson->m_pView->m_viewPos.y + pasPerson->m_pView->m_dsScreenOrigin.y,
  2735. -pasPerson->m_pView->m_viewPos.x + pasPerson->m_pView->m_dsScreenOrigin.x + pasPerson->cpcCaps.screen.capsScreenWidth,
  2736. -pasPerson->m_pView->m_viewPos.y + pasPerson->m_pView->m_dsScreenOrigin.y + pasPerson->cpcCaps.screen.capsScreenHeight);
  2737. SubtractRgn(pasPerson->m_pView->m_viewExtentRgn, pasPerson->m_pView->m_viewExtentRgn, pasPerson->m_pView->m_viewScreenRgn);
  2738. //
  2739. // pasPerson->m_pView->m_viewExtentRgn is now the offscreen parts of the VD, and therefore
  2740. // any shared areas lying in them should be treated as obscured.
  2741. //
  2742. //
  2743. // Now, compute the real obscured area. It's the covered up bits
  2744. // plus open parts of shared stuff not currently on screen.
  2745. //
  2746. IntersectRgn(pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewExtentRgn, pasPerson->m_pView->m_viewSharedRgn);
  2747. UnionRgn(pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewObscuredRgn);
  2748. // Calc what part of the obscured region to actually paint
  2749. IntersectRgn(pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewPaintRgn);
  2750. if (GetRgnBox(pasPerson->m_pView->m_viewScratchRgn, &rcT) > NULLREGION)
  2751. {
  2752. TRACE_OUT(("VIEWClientPaint: Painting obscured client area {%04d, %04d, %04d, %04d}",
  2753. rcT.left, rcT.top, rcT.right, rcT.bottom));
  2754. //
  2755. // Remove this area so we have what's left to paint.
  2756. //
  2757. SubtractRgn(pasPerson->m_pView->m_viewPaintRgn, pasPerson->m_pView->m_viewPaintRgn, pasPerson->m_pView->m_viewScratchRgn);
  2758. //
  2759. // We do NOT want to use FillRgn; it ignores the brush origin.
  2760. // So we select this in as the clip region and PatBlt instead.
  2761. //
  2762. SelectClipRgn(hdcView, pasPerson->m_pView->m_viewScratchRgn);
  2763. #ifdef _DEBUG
  2764. //
  2765. // NOTE: Do NOT move this--we're using ptOrigin for scratch.
  2766. //
  2767. GetDCOrgEx(hdcView, &ptOrigin);
  2768. TRACE_OUT(("VIEWClientPaint: Setting brush origin to {%04d, %04d}, screen {%04d, %04d}",
  2769. -pasPerson->m_pView->m_viewPos.x, -pasPerson->m_pView->m_viewPos.y,
  2770. ptOrigin.x - pasPerson->m_pView->m_viewPos.x,
  2771. ptOrigin.y - pasPerson->m_pView->m_viewPos.y));
  2772. #endif
  2773. //
  2774. // Align the brush with where the view's real origin would be, in
  2775. // client coords. We do that by accounting for being scrolled over.
  2776. //
  2777. SetBrushOrgEx(hdcView, -pasPerson->m_pView->m_viewPos.x,
  2778. -pasPerson->m_pView->m_viewPos.y, &ptOrigin);
  2779. UnrealizeObject(m_viewObscuredBrush);
  2780. hbrT = SelectBrush(hdcView, m_viewObscuredBrush);
  2781. PatBlt(hdcView,
  2782. rcT.left, rcT.top,
  2783. rcT.right - rcT.left,
  2784. rcT.bottom - rcT.top,
  2785. PATCOPY);
  2786. SelectBrush(hdcView, hbrT);
  2787. SetBrushOrgEx(hdcView, ptOrigin.x, ptOrigin.y, NULL);
  2788. SelectClipRgn(hdcView, NULL);
  2789. }
  2790. //
  2791. // Paint the deadspace area, set up clipping for app sharing.
  2792. // This also works for desktop sharing, where there are no obscured or
  2793. // shared regions, the whole area paints.
  2794. //
  2795. //
  2796. // The deadspace is whatever's left over in the paint region
  2797. // (already subtracted the obscured region) after subtracting the
  2798. // shared area
  2799. //
  2800. SubtractRgn(pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewPaintRgn, pasPerson->m_pView->m_viewSharedRgn);
  2801. if (GetRgnBox(pasPerson->m_pView->m_viewScratchRgn, &rcT) > NULLREGION)
  2802. {
  2803. TRACE_OUT(("VIEWClientPaint: Painting dead client area {%04d, %04d, %04d, %04d}",
  2804. rcT.left, rcT.top, rcT.right, rcT.bottom));
  2805. FillRgn(hdcView, pasPerson->m_pView->m_viewScratchRgn, GetSysColorBrush(COLOR_APPWORKSPACE));
  2806. }
  2807. //
  2808. // Compute what part of the shared area needs painting (the part
  2809. // that lies on the remote screen actually).
  2810. //
  2811. IntersectRgn(pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewSharedRgn, pasPerson->m_pView->m_viewScreenRgn);
  2812. IntersectRgn(pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewScratchRgn, pasPerson->m_pView->m_viewPaintRgn);
  2813. // Now select in the piece of what we're painting as the clip region
  2814. SelectClipRgn(hdcView, pasPerson->m_pView->m_viewScratchRgn);
  2815. }
  2816. //
  2817. // Blt the shared region
  2818. //
  2819. if (GetClipBox(hdcView, &rcT) > NULLREGION)
  2820. {
  2821. TRACE_OUT(("VIEWClientPaint: Painting shared client area {%04x, %04x, %04x, %04x}",
  2822. rcT.left, rcT.top, rcT.right, rcT.bottom));
  2823. if (g_usrPalettized)
  2824. {
  2825. ASSERT(pasPerson->pmPalette != NULL);
  2826. //
  2827. // Select and realize the current remote palette into the
  2828. // screen and shadow bitmap DCs.
  2829. //
  2830. hOldPal = SelectPalette(pasPerson->m_pView->m_usrDC, pasPerson->pmPalette, FALSE);
  2831. RealizePalette(pasPerson->m_pView->m_usrDC);
  2832. hOldPal2 = SelectPalette( hdcView, pasPerson->pmPalette, FALSE);
  2833. RealizePalette(hdcView);
  2834. }
  2835. //
  2836. // The host bitmap is in screen coords, not VD coords, so
  2837. // adjust for being scrolled over...
  2838. //
  2839. BitBlt(hdcView,
  2840. rcT.left, rcT.top, rcT.right - rcT.left, rcT.bottom - rcT.top,
  2841. pasPerson->m_pView->m_usrDC,
  2842. rcT.left + pasPerson->m_pView->m_viewPos.x - pasPerson->m_pView->m_dsScreenOrigin.x,
  2843. rcT.top + pasPerson->m_pView->m_viewPos.y - pasPerson->m_pView->m_dsScreenOrigin.y,
  2844. SRCCOPY);
  2845. if (g_usrPalettized)
  2846. {
  2847. ASSERT(pasPerson->pmPalette != NULL);
  2848. SelectPalette(pasPerson->m_pView->m_usrDC, hOldPal, FALSE);
  2849. SelectPalette(hdcView, hOldPal2, FALSE);
  2850. }
  2851. }
  2852. //
  2853. // Deselect the clip region, or we won't be able to draw shadow cursors
  2854. // that lie outside the shared area.
  2855. //
  2856. if (pasPerson->m_pView->m_viewSharedRgn != NULL)
  2857. {
  2858. SelectClipRgn(hdcView, NULL);
  2859. }
  2860. //
  2861. // Draw the shadow cursor.
  2862. //
  2863. CM_DrawShadowCursor(pasPerson, hdcView);
  2864. DC_EXIT_POINT:
  2865. if (hdcView != NULL)
  2866. EndPaint(pasPerson->m_pView->m_viewClient, &ps);
  2867. DebugExitVOID(ASShare::VIEWClientPaint);
  2868. }
  2869. //
  2870. // VIEWClientScroll()
  2871. //
  2872. // This is the common place where the scroll position is altered. If
  2873. // necessary the contents are scrolled over, the regions (always in client
  2874. // coords) are adjusted, and new info about our origin is sent to remotes.
  2875. //
  2876. // We first make sure the scroll position is pinned properly within the
  2877. // range.
  2878. //
  2879. // The return value is whether scrolling happened or not.
  2880. //
  2881. BOOL ASShare::VIEWClientScroll
  2882. (
  2883. ASPerson * pasPerson,
  2884. int xNew,
  2885. int yNew
  2886. )
  2887. {
  2888. int dx;
  2889. int dy;
  2890. DebugEntry(ASShare::VIEWClientScroll);
  2891. //
  2892. // First, pin the requested new position within the range
  2893. //
  2894. //
  2895. // Pin x pos
  2896. //
  2897. if (xNew < 0)
  2898. xNew = 0;
  2899. if (xNew + pasPerson->m_pView->m_viewPage.x > pasPerson->viewExtent.x)
  2900. xNew = pasPerson->viewExtent.x - pasPerson->m_pView->m_viewPage.x;
  2901. //
  2902. // Pin y pos
  2903. //
  2904. if (yNew < 0)
  2905. yNew = 0;
  2906. if (yNew + pasPerson->m_pView->m_viewPage.y > pasPerson->viewExtent.y)
  2907. yNew = pasPerson->viewExtent.y - pasPerson->m_pView->m_viewPage.y;
  2908. //
  2909. // How much are we going to scroll by?
  2910. //
  2911. dx = pasPerson->m_pView->m_viewPos.x - xNew;
  2912. dy = pasPerson->m_pView->m_viewPos.y - yNew;
  2913. // Updates
  2914. if (dx || dy)
  2915. {
  2916. //
  2917. // Adjust regions
  2918. //
  2919. if (pasPerson->m_pView->m_viewObscuredRgn != NULL)
  2920. OffsetRgn(pasPerson->m_pView->m_viewObscuredRgn, dx, dy);
  2921. if (pasPerson->m_pView->m_viewSharedRgn != NULL)
  2922. OffsetRgn(pasPerson->m_pView->m_viewSharedRgn, dx, dy);
  2923. pasPerson->m_pView->m_viewPos.x = xNew;
  2924. pasPerson->m_pView->m_viewPos.y = yNew;
  2925. ScrollWindowEx(pasPerson->m_pView->m_viewClient,
  2926. dx,
  2927. dy,
  2928. NULL,
  2929. NULL,
  2930. NULL,
  2931. NULL,
  2932. SW_SCROLLCHILDREN | SW_INVALIDATE);
  2933. if (dx)
  2934. {
  2935. SetScrollPos(pasPerson->m_pView->m_viewClient, SB_HORZ, xNew, TRUE);
  2936. }
  2937. if (dy)
  2938. {
  2939. SetScrollPos(pasPerson->m_pView->m_viewClient, SB_VERT, yNew, TRUE);
  2940. }
  2941. }
  2942. DebugExitBOOL(ASShare::VIEWClientScroll, (dx || dy));
  2943. return(dx || dy);
  2944. }
  2945. //
  2946. // VIEWClientMouseDown()
  2947. //
  2948. void ASShare::VIEWClientMouseDown
  2949. (
  2950. ASPerson * pasPerson,
  2951. UINT message,
  2952. WPARAM wParam,
  2953. LPARAM lParam
  2954. )
  2955. {
  2956. DebugEntry(ASShare::VIEWClientMouseDown);
  2957. ValidateView(pasPerson);
  2958. //
  2959. // On the first button down, set capture so all mouse messages come
  2960. // to us until capture is released or stolen.
  2961. //
  2962. if (!pasPerson->m_pView->m_viewMouseFlags)
  2963. {
  2964. //
  2965. // If this is RBUTTONDOWN, track the Collaborate pop up...
  2966. //
  2967. ASSERT(!pasPerson->m_pView->m_viewMouseOutside);
  2968. SetCapture(pasPerson->m_pView->m_viewClient);
  2969. }
  2970. //
  2971. // Remember what button is down.
  2972. //
  2973. switch (message)
  2974. {
  2975. case WM_LBUTTONDOWN:
  2976. pasPerson->m_pView->m_viewMouseFlags |= MK_LBUTTON;
  2977. break;
  2978. case WM_RBUTTONDOWN:
  2979. pasPerson->m_pView->m_viewMouseFlags |= MK_RBUTTON;
  2980. break;
  2981. case WM_MBUTTONDOWN:
  2982. pasPerson->m_pView->m_viewMouseFlags |= MK_MBUTTON;
  2983. break;
  2984. }
  2985. //
  2986. // Save the current mouse position
  2987. //
  2988. pasPerson->m_pView->m_viewMouse.x = GET_X_LPARAM(lParam);
  2989. pasPerson->m_pView->m_viewMouse.y = GET_Y_LPARAM(lParam);
  2990. VIEWClientMouseMsg(pasPerson, message, wParam, lParam);
  2991. DebugExitVOID(ASShare::VIEWClientMouseDown);
  2992. }
  2993. //
  2994. // VIEWClientMouseUp()
  2995. //
  2996. void ASShare::VIEWClientMouseUp
  2997. (
  2998. ASPerson * pasPerson,
  2999. UINT message,
  3000. WPARAM wParam,
  3001. LPARAM lParam,
  3002. BOOL fReleaseCapture
  3003. )
  3004. {
  3005. DebugEntry(ASShare::VIEWClientMouseUp);
  3006. switch (message)
  3007. {
  3008. case WM_LBUTTONUP:
  3009. if (pasPerson->m_pView->m_viewMouseFlags & MK_LBUTTON)
  3010. pasPerson->m_pView->m_viewMouseFlags &= ~MK_LBUTTON;
  3011. else
  3012. fReleaseCapture = FALSE; // From dbl-click
  3013. break;
  3014. case WM_RBUTTONUP:
  3015. if (pasPerson->m_pView->m_viewMouseFlags & MK_RBUTTON)
  3016. pasPerson->m_pView->m_viewMouseFlags &= ~MK_RBUTTON;
  3017. else
  3018. fReleaseCapture = FALSE; // From dbl-click
  3019. break;
  3020. case WM_MBUTTONUP:
  3021. if (pasPerson->m_pView->m_viewMouseFlags & MK_MBUTTON)
  3022. pasPerson->m_pView->m_viewMouseFlags &= ~MK_MBUTTON;
  3023. else
  3024. fReleaseCapture = FALSE; // From dbl-click
  3025. break;
  3026. }
  3027. //
  3028. // Should we release capture?
  3029. // We don't just want to release capture on a button up. The user may
  3030. // press one button down then another; we don't want to release capture
  3031. // until all buttons are up.
  3032. //
  3033. if (!pasPerson->m_pView->m_viewMouseFlags)
  3034. {
  3035. if (pasPerson->m_pView->m_viewMouseOutside)
  3036. {
  3037. pasPerson->m_pView->m_viewMouseOutside = FALSE;
  3038. KillTimer(pasPerson->m_pView->m_viewClient, IDT_AUTOSCROLL);
  3039. }
  3040. if (fReleaseCapture)
  3041. ReleaseCapture();
  3042. }
  3043. //
  3044. // Save the current mouse position
  3045. //
  3046. pasPerson->m_pView->m_viewMouse.x = GET_X_LPARAM(lParam);
  3047. pasPerson->m_pView->m_viewMouse.y = GET_Y_LPARAM(lParam);
  3048. VIEWClientMouseMsg(pasPerson, message, wParam, lParam);
  3049. DebugExitVOID(ASShare::VIEWClientMouseUp);
  3050. }
  3051. //
  3052. // VIEWClientCaptureStolen()
  3053. // Called when capture gets stolen away from us, like by Alt-Tab.
  3054. //
  3055. void ASShare::VIEWClientCaptureStolen(ASPerson * pasPerson)
  3056. {
  3057. DebugEntry(ASShare::VIEWClientCaptureStolen);
  3058. //
  3059. // We need to fake a button up for each button we think is down.
  3060. // Use the current cursor pos.
  3061. //
  3062. if (pasPerson->m_pView->m_viewMouseFlags & MK_MBUTTON)
  3063. {
  3064. VIEWClientMouseUp(pasPerson, WM_MBUTTONUP, pasPerson->m_pView->m_viewMouseFlags,
  3065. MAKELPARAM(pasPerson->m_pView->m_viewMouse.x, pasPerson->m_pView->m_viewMouse.y),
  3066. FALSE);
  3067. }
  3068. if (pasPerson->m_pView->m_viewMouseFlags & MK_RBUTTON)
  3069. {
  3070. VIEWClientMouseUp(pasPerson, WM_RBUTTONUP, pasPerson->m_pView->m_viewMouseFlags,
  3071. MAKELPARAM(pasPerson->m_pView->m_viewMouse.x, pasPerson->m_pView->m_viewMouse.y),
  3072. FALSE);
  3073. }
  3074. if (pasPerson->m_pView->m_viewMouseFlags & MK_LBUTTON)
  3075. {
  3076. VIEWClientMouseUp(pasPerson, WM_LBUTTONUP, pasPerson->m_pView->m_viewMouseFlags,
  3077. MAKELPARAM(pasPerson->m_pView->m_viewMouse.x, pasPerson->m_pView->m_viewMouse.y),
  3078. FALSE);
  3079. }
  3080. DebugExitVOID(ASShare::VIEWClientCaptureStolen);
  3081. }
  3082. //
  3083. // VIEWClientMouseMove()
  3084. //
  3085. void ASShare::VIEWClientMouseMove
  3086. (
  3087. ASPerson * pasPerson,
  3088. UINT message,
  3089. WPARAM wParam,
  3090. LPARAM lParam
  3091. )
  3092. {
  3093. RECT rcClient;
  3094. DebugEntry(ASShare::VIEWClientMouseMove);
  3095. if (!pasPerson->m_pView->m_viewFocus)
  3096. {
  3097. // Ignore mouse moves over windows that don't have the focus
  3098. DC_QUIT;
  3099. }
  3100. //
  3101. // Save the current mouse position
  3102. //
  3103. pasPerson->m_pView->m_viewMouse.x = GET_X_LPARAM(lParam);
  3104. pasPerson->m_pView->m_viewMouse.y = GET_Y_LPARAM(lParam);
  3105. GetClientRect(pasPerson->m_pView->m_viewClient, &rcClient);
  3106. //
  3107. // If any button is down, check whether we should kick in
  3108. // autoscroll detection.
  3109. //
  3110. if (pasPerson->m_pView->m_viewMouseFlags)
  3111. {
  3112. // Is the mouse inside or outside the client for the first time?
  3113. if (PtInRect(&rcClient, pasPerson->m_pView->m_viewMouse))
  3114. {
  3115. //
  3116. // Was the mouse outside the client before? If so, kill our
  3117. // autoscroll timer, we're not dragging outside.
  3118. //
  3119. if (pasPerson->m_pView->m_viewMouseOutside)
  3120. {
  3121. pasPerson->m_pView->m_viewMouseOutside = FALSE;
  3122. KillTimer(pasPerson->m_pView->m_viewClient, IDT_AUTOSCROLL);
  3123. }
  3124. }
  3125. else
  3126. {
  3127. //
  3128. // Is the first time the mouse is outside the client? If so,
  3129. // set our autoscroll timer to the default value. When it goes
  3130. // off, the autoscroll code will scroll by some multiple of
  3131. // how far away the mouse is from the client.
  3132. //
  3133. if (!pasPerson->m_pView->m_viewMouseOutside)
  3134. {
  3135. //
  3136. // The Windows scrollbar code uses 1/8 of the double-click
  3137. // time, so we do also.
  3138. //
  3139. pasPerson->m_pView->m_viewMouseOutside = TRUE;
  3140. SetTimer(pasPerson->m_pView->m_viewClient, IDT_AUTOSCROLL,
  3141. GetDoubleClickTime() / 8, NULL);
  3142. }
  3143. //
  3144. // LAURABU BOGUS!
  3145. // When IM_Periodic goop is gone for controlling, do NOT
  3146. // pass along mouse outside messages. Only the autoscroll
  3147. // timer will fake a mouse move in this case. Either that,
  3148. // or clip the position to the nearest client area equivalent.
  3149. //
  3150. }
  3151. }
  3152. VIEWClientMouseMsg(pasPerson, message, wParam, lParam);
  3153. DC_EXIT_POINT:
  3154. DebugExitVOID(ASShare::VIEWClientMouseMove);
  3155. }
  3156. //
  3157. // VIEWClientMouseMsg()
  3158. //
  3159. void ASShare::VIEWClientMouseMsg
  3160. (
  3161. ASPerson * pasPerson,
  3162. UINT message,
  3163. WPARAM wParam,
  3164. LPARAM lParam
  3165. )
  3166. {
  3167. POINT mousePos;
  3168. DebugEntry(ASShare::VIEWClientMouseMsg);
  3169. //
  3170. // Extract the mouse position from <lParam> and package it
  3171. // in a POINT structure. These coordinates are relative to our
  3172. // client area. So convert to remote's desktop by adjusting for
  3173. // scroll position.
  3174. //
  3175. // Be careful when converting the LOWORD and HIWORD values
  3176. // because the positions are signed values.
  3177. //
  3178. mousePos.x = GET_X_LPARAM(lParam) + pasPerson->m_pView->m_viewPos.x;
  3179. mousePos.y = GET_Y_LPARAM(lParam) + pasPerson->m_pView->m_viewPos.y;
  3180. //
  3181. // These coords represent the SCREEN coords on the host.
  3182. //
  3183. if (pasPerson->m_caControlledBy == m_pasLocal)
  3184. {
  3185. IM_OutgoingMouseInput(pasPerson, &mousePos, message, (UINT)wParam);
  3186. }
  3187. else if (pasPerson->m_caAllowControl && !pasPerson->m_caControlledBy &&
  3188. (message == WM_LBUTTONDBLCLK))
  3189. {
  3190. //
  3191. // If we're already waiting for control of this person, don't bother
  3192. // trying to take control again.
  3193. //
  3194. if ((m_caWaitingForReplyFrom != pasPerson) &&
  3195. (m_caWaitingForReplyMsg != CA_REPLY_REQUEST_TAKECONTROL))
  3196. {
  3197. CA_TakeControl(pasPerson);
  3198. }
  3199. }
  3200. DebugExitVOID(ASShare::VIEWClientMouse);
  3201. }
  3202. //
  3203. // VIEWClientMouseWheel()
  3204. //
  3205. // Unbelievably complicated, messy, nonsensical Intellimouse wheel handling
  3206. // to scroll the client. Since the Intellimouse makes no distinction for
  3207. // which direction to scroll in, we basically have to guess. We don't want
  3208. // to be unpredictable and decide which direction to scroll based on how
  3209. // much is visible in each dimenion.
  3210. //
  3211. // So instead, we assume horizontal. If the horizontal scrollbar is disabled,
  3212. // then we try vertical. If that's disabled, we do nothing.
  3213. //
  3214. // We do NOT handle zoom and datazoom flavors.
  3215. //
  3216. // Note that this code comes from the listbox/sample source.
  3217. //
  3218. void ASShare::VIEWClientMouseWheel
  3219. (
  3220. ASPerson * pasHost,
  3221. WPARAM wParam,
  3222. LPARAM lParam
  3223. )
  3224. {
  3225. int cDetants;
  3226. DebugEntry(ASShare::VIEWClientMouseWheel);
  3227. //
  3228. // The LOWORD of wParam has key state information.
  3229. // The HIWORD of wParam is the number of mouse wheel clicks.
  3230. //
  3231. //
  3232. // We don't do zoom/datazoom
  3233. //
  3234. if (wParam & (MK_SHIFT | MK_CONTROL))
  3235. {
  3236. DC_QUIT;
  3237. }
  3238. pasHost->m_pView->m_viewMouseWheelDelta -= (int)(short)HIWORD(wParam);
  3239. cDetants = pasHost->m_pView->m_viewMouseWheelDelta / WHEEL_DELTA;
  3240. if (cDetants && (m_viewMouseWheelScrollLines > 0))
  3241. {
  3242. POINT ptPos;
  3243. pasHost->m_pView->m_viewMouseWheelDelta %= WHEEL_DELTA;
  3244. //
  3245. // The basic idea is that we scroll some number of lines, the
  3246. // number being cDetants.
  3247. //
  3248. ptPos = pasHost->m_pView->m_viewPos;
  3249. //
  3250. // To be consistent with other apps, and with our keyboard
  3251. // accelerators, try the vertical direction first.
  3252. //
  3253. if (pasHost->m_pView->m_viewPage.y < pasHost->viewExtent.y)
  3254. {
  3255. ptPos.y += cDetants * pasHost->m_pView->m_viewLnSize.y;
  3256. }
  3257. else if (pasHost->m_pView->m_viewPage.x < pasHost->viewExtent.x)
  3258. {
  3259. ptPos.x += cDetants * pasHost->m_pView->m_viewLnSize.x;
  3260. }
  3261. else
  3262. {
  3263. // Nothing to scroll, the whole view fits in the client area.
  3264. }
  3265. VIEWClientScroll(pasHost, ptPos.x, ptPos.y);
  3266. }
  3267. DC_EXIT_POINT:
  3268. DebugExitVOID(ASShare::VIEWClientMouseWheel);
  3269. }
  3270. //
  3271. // VIEWClientAutoScroll()
  3272. //
  3273. void ASShare::VIEWClientAutoScroll(ASPerson * pasPerson)
  3274. {
  3275. int dx;
  3276. int dy;
  3277. RECT rcClient;
  3278. DebugEntry(ASShare::VIEWClientAutoScroll);
  3279. ValidateView(pasPerson);
  3280. ASSERT(pasPerson->m_pView->m_viewMouseOutside);
  3281. //
  3282. // Do scrolling. The amount is dependent on how far outside the
  3283. // client area we are.
  3284. //
  3285. GetClientRect(pasPerson->m_pView->m_viewClient, &rcClient);
  3286. // Horizontal scrolling?
  3287. if (pasPerson->m_pView->m_viewMouse.x < rcClient.left)
  3288. {
  3289. dx = pasPerson->m_pView->m_viewMouse.x - rcClient.left;
  3290. }
  3291. else if (pasPerson->m_pView->m_viewMouse.x >= rcClient.right)
  3292. {
  3293. dx = pasPerson->m_pView->m_viewMouse.x - rcClient.right + 1;
  3294. }
  3295. else
  3296. {
  3297. dx = 0;
  3298. }
  3299. // Vertical scrolling?
  3300. if (pasPerson->m_pView->m_viewMouse.y < rcClient.top)
  3301. {
  3302. dy = pasPerson->m_pView->m_viewMouse.y - rcClient.top;
  3303. }
  3304. else if (pasPerson->m_pView->m_viewMouse.y >= rcClient.bottom)
  3305. {
  3306. dy = pasPerson->m_pView->m_viewMouse.y - rcClient.bottom + 1;
  3307. }
  3308. else
  3309. {
  3310. dy = 0;
  3311. }
  3312. // For every 32 pixel blocks outside the client, scroll one line amount
  3313. if (dx)
  3314. dx = MulDiv(pasPerson->m_pView->m_viewLnSize.x, dx, 32);
  3315. if (dy)
  3316. dy = MulDiv(pasPerson->m_pView->m_viewLnSize.y, dy, 32);
  3317. // Do scrolling.
  3318. if (VIEWClientScroll(pasPerson, pasPerson->m_pView->m_viewPos.x + dx,
  3319. pasPerson->m_pView->m_viewPos.y + dy))
  3320. {
  3321. //
  3322. // The scroll position actually changed. So fake a mouse move
  3323. // to the current location so that the remote's
  3324. // cursor will be in the same spot as ours. If our scroll pos has
  3325. // changed, we're mapping to a different place on the remote.
  3326. //
  3327. VIEWClientMouseMsg(pasPerson, WM_MOUSEMOVE, pasPerson->m_pView->m_viewMouseFlags,
  3328. MAKELPARAM(pasPerson->m_pView->m_viewMouse.x, pasPerson->m_pView->m_viewMouse.y));
  3329. }
  3330. DebugExitVOID(ASShare::VIEWClientAutoScroll);
  3331. }
  3332. //
  3333. // VIEW_SyncCursorPos()
  3334. //
  3335. // This is called when we see a CM_SYNC pos packet broadcasted from a
  3336. // host. It means that we should sync our cursor to the corresponding
  3337. // position in our view. This happens when the cursor is moved by
  3338. // an app, constrained by clipping, or we're too out of whack because it's
  3339. // taking too long.
  3340. //
  3341. // This will only do something if the frame is active and our cursor is
  3342. // currently over the client area. If we need to, we will scroll the
  3343. // client over to make the corresponding point visible.
  3344. //
  3345. void ASShare::VIEW_SyncCursorPos
  3346. (
  3347. ASPerson * pasHost,
  3348. int xRemote,
  3349. int yRemote
  3350. )
  3351. {
  3352. POINT ptCursor;
  3353. RECT rcClient;
  3354. int xNewPos;
  3355. int yNewPos;
  3356. int xMargin;
  3357. int yMargin;
  3358. DebugEntry(ASShare::VIEW_SyncCursorPos);
  3359. ValidateView(pasHost);
  3360. if (!pasHost->m_pView->m_viewFocus)
  3361. {
  3362. // The frame isn't active, do nothing
  3363. DC_QUIT;
  3364. }
  3365. //
  3366. // Is our mouse currently over the client area?
  3367. //
  3368. GetCursorPos(&ptCursor);
  3369. ScreenToClient(pasHost->m_pView->m_viewClient, &ptCursor);
  3370. GetClientRect(pasHost->m_pView->m_viewClient, &rcClient);
  3371. if (!PtInRect(&rcClient, ptCursor))
  3372. {
  3373. // No sense in snapping cursor
  3374. DC_QUIT;
  3375. }
  3376. //
  3377. // Is the remote point in range of our view? If not, we must scroll it.
  3378. //
  3379. // The margin is the page size if there's room, nothing if not
  3380. xMargin = pasHost->m_pView->m_viewPgSize.x;
  3381. if (xMargin >= rcClient.right - rcClient.left)
  3382. xMargin = 0;
  3383. xNewPos = pasHost->m_pView->m_viewPos.x;
  3384. if ((xRemote < pasHost->m_pView->m_viewPos.x) ||
  3385. (xRemote >= pasHost->m_pView->m_viewPos.x + (rcClient.right - rcClient.left)))
  3386. {
  3387. //
  3388. // Scroll over more than just enough to pin the point on the left
  3389. // side.
  3390. //
  3391. xNewPos = xRemote - xMargin;
  3392. }
  3393. yMargin = pasHost->m_pView->m_viewPgSize.y;
  3394. if (yMargin >= rcClient.bottom - rcClient.top)
  3395. yMargin = 0;
  3396. yNewPos = pasHost->m_pView->m_viewPos.y;
  3397. if ((yRemote < pasHost->m_pView->m_viewPos.y) ||
  3398. (yRemote >= yNewPos + (rcClient.bottom - rcClient.top)))
  3399. {
  3400. //
  3401. // Scroll over more than just enough to pin the point on the top
  3402. // side.
  3403. //
  3404. yNewPos = yRemote - yMargin;
  3405. }
  3406. VIEWClientScroll(pasHost, xNewPos, yNewPos);
  3407. ptCursor.x = xRemote - pasHost->m_pView->m_viewPos.x;
  3408. ptCursor.y = yRemote - pasHost->m_pView->m_viewPos.y;
  3409. ClientToScreen(pasHost->m_pView->m_viewClient, &ptCursor);
  3410. SetCursorPos(ptCursor.x, ptCursor.y);
  3411. DC_EXIT_POINT:
  3412. DebugExitVOID(ASShare::VIEW_SyncCursorPos);
  3413. }
  3414. //
  3415. // VIEWFullScreenExitProc()
  3416. //
  3417. // Window handler for full screen exit button.
  3418. //
  3419. LRESULT CALLBACK VIEWFullScreenExitProc
  3420. (
  3421. HWND hwnd,
  3422. UINT message,
  3423. WPARAM wParam,
  3424. LPARAM lParam
  3425. )
  3426. {
  3427. return(g_asSession.pShare->VIEW_FullScreenExitProc(hwnd, message, wParam, lParam));
  3428. }
  3429. //
  3430. // VIEW_FullScreenExitProc()
  3431. //
  3432. LRESULT ASShare::VIEW_FullScreenExitProc
  3433. (
  3434. HWND hwnd,
  3435. UINT message,
  3436. WPARAM wParam,
  3437. LPARAM lParam
  3438. )
  3439. {
  3440. LRESULT rc = 0;
  3441. ASPerson * pasHost;
  3442. DebugEntry(VIEW_FullScreenExitProc);
  3443. pasHost = (ASPerson *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  3444. if (pasHost)
  3445. {
  3446. ValidateView(pasHost);
  3447. }
  3448. switch (message)
  3449. {
  3450. case WM_NCCREATE:
  3451. {
  3452. // Get the passed in host pointer, and set in our window long
  3453. pasHost = (ASPerson *)((LPCREATESTRUCT)lParam)->lpCreateParams;
  3454. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)pasHost);
  3455. goto DefWndProc;
  3456. break;
  3457. }
  3458. case WM_NCDESTROY:
  3459. {
  3460. //
  3461. // Make sure tracking is stopped.
  3462. //
  3463. pasHost->m_pView->m_viewFullScreenExitTrack = FALSE;
  3464. break;
  3465. }
  3466. case WM_ERASEBKGND:
  3467. {
  3468. rc = TRUE;
  3469. break;
  3470. }
  3471. case WM_PAINT:
  3472. {
  3473. VIEWFullScreenExitPaint(pasHost, hwnd);
  3474. break;
  3475. }
  3476. case WM_LBUTTONDOWN:
  3477. {
  3478. //
  3479. // Start tracking to move or click button.
  3480. //
  3481. pasHost->m_pView->m_viewFullScreenExitTrack = TRUE;
  3482. pasHost->m_pView->m_viewFullScreenExitMove = FALSE;
  3483. // Original click, relative to our client
  3484. pasHost->m_pView->m_viewFullScreenExitStart.x =
  3485. GET_X_LPARAM(lParam);
  3486. pasHost->m_pView->m_viewFullScreenExitStart.y =
  3487. GET_Y_LPARAM(lParam);
  3488. // Set capture, and wait for moves/button up
  3489. SetCapture(hwnd);
  3490. break;
  3491. }
  3492. case WM_MOUSEMOVE:
  3493. {
  3494. if (pasHost->m_pView->m_viewFullScreenExitTrack)
  3495. {
  3496. POINT ptMove;
  3497. ptMove.x = GET_X_LPARAM(lParam);
  3498. ptMove.y = GET_Y_LPARAM(lParam);
  3499. //
  3500. // If we're not in move mode, see if this has pushed us over
  3501. // the tolerance.
  3502. //
  3503. if (!pasHost->m_pView->m_viewFullScreenExitMove)
  3504. {
  3505. if ((abs(ptMove.x - pasHost->m_pView->m_viewFullScreenExitStart.x) >
  3506. GetSystemMetrics(SM_CXDRAG)) ||
  3507. (abs(ptMove.y - pasHost->m_pView->m_viewFullScreenExitStart.y) >
  3508. GetSystemMetrics(SM_CYDRAG)))
  3509. {
  3510. //
  3511. // User has moved out of tolerance zone, must be
  3512. // dragging to move the button out of the way.
  3513. //
  3514. pasHost->m_pView->m_viewFullScreenExitMove = TRUE;
  3515. }
  3516. }
  3517. if (pasHost->m_pView->m_viewFullScreenExitMove)
  3518. {
  3519. RECT rcWindow;
  3520. //
  3521. // Move the button so that the cursor is over the
  3522. // same point as originally clicked on.
  3523. //
  3524. // Get our current position, in parent coordsinates.
  3525. GetWindowRect(hwnd, &rcWindow);
  3526. MapWindowPoints(NULL, GetParent(hwnd), (LPPOINT)&rcWindow, 2);
  3527. // Offset it by the amount of the move.
  3528. OffsetRect(&rcWindow,
  3529. ptMove.x - pasHost->m_pView->m_viewFullScreenExitStart.x,
  3530. ptMove.y - pasHost->m_pView->m_viewFullScreenExitStart.y);
  3531. SetWindowPos(hwnd, NULL, rcWindow.left, rcWindow.top, 0, 0,
  3532. SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
  3533. }
  3534. }
  3535. break;
  3536. }
  3537. case WM_LBUTTONUP:
  3538. {
  3539. if (pasHost->m_pView->m_viewFullScreenExitTrack)
  3540. {
  3541. //
  3542. // This will send us CAPTURECHANGED, causing us to clear
  3543. // the ExitTrack flag.
  3544. //
  3545. ReleaseCapture();
  3546. //
  3547. // If we never transitioned into move mode, then this was
  3548. // a click on the button.
  3549. //
  3550. if (!pasHost->m_pView->m_viewFullScreenExitMove)
  3551. {
  3552. //
  3553. // This was a click, send a command.
  3554. //
  3555. PostMessage(pasHost->m_pView->m_viewFrame, WM_COMMAND, CMD_VIEWFULLSCREEN, 0);
  3556. }
  3557. }
  3558. break;
  3559. }
  3560. case WM_CAPTURECHANGED:
  3561. {
  3562. //
  3563. // If we're tracking, something happened, so cancel out.
  3564. //
  3565. if (pasHost->m_pView->m_viewFullScreenExitTrack)
  3566. {
  3567. pasHost->m_pView->m_viewFullScreenExitTrack = FALSE;
  3568. }
  3569. break;
  3570. }
  3571. default:
  3572. DefWndProc:
  3573. rc = DefWindowProc(hwnd, message, wParam, lParam);
  3574. break;
  3575. }
  3576. DebugExitDWORD(VIEW_FullScreenExitProc, rc);
  3577. return(rc);
  3578. }
  3579. //
  3580. // VIEWFullScreenExitPaint()
  3581. //
  3582. // Paints the full screen button.
  3583. //
  3584. void ASShare::VIEWFullScreenExitPaint
  3585. (
  3586. ASPerson * pasHost,
  3587. HWND hwnd
  3588. )
  3589. {
  3590. RECT rc;
  3591. PAINTSTRUCT ps;
  3592. char szRestore[256];
  3593. HFONT hfnOld;
  3594. COLORREF txtColor;
  3595. COLORREF bkColor;
  3596. DebugEntry(ASShare::VIEWFullScreenExitPaint);
  3597. BeginPaint(hwnd, &ps);
  3598. GetClientRect(hwnd, &rc);
  3599. DrawFrameControl(ps.hdc, &rc, DFC_BUTTON, DFCS_BUTTONPUSH |
  3600. DFCS_ADJUSTRECT);
  3601. // Margin adjustments...
  3602. InflateRect(&rc, -m_viewEdgeCX, -m_viewEdgeCY);
  3603. DrawIconEx(ps.hdc, rc.left,
  3604. (rc.top + rc.bottom - GetSystemMetrics(SM_CYSMICON)) / 2,
  3605. m_viewFullScreenExitIcon,
  3606. GetSystemMetrics(SM_CXSMICON),
  3607. GetSystemMetrics(SM_CYSMICON),
  3608. 0, NULL, DI_NORMAL);
  3609. rc.left += GetSystemMetrics(SM_CXSMICON) + m_viewEdgeCX;
  3610. hfnOld = SelectFont(ps.hdc, GetStockObject(DEFAULT_GUI_FONT));
  3611. txtColor = SetTextColor(ps.hdc, GetSysColor(COLOR_BTNTEXT));
  3612. bkColor = SetBkColor(ps.hdc, GetSysColor(COLOR_BTNFACE));
  3613. LoadString(g_asInstance, IDS_RESTORE, szRestore, sizeof(szRestore));
  3614. DrawText(ps.hdc, szRestore, -1, &rc, DT_NOCLIP | DT_EXPANDTABS |
  3615. DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE);
  3616. SetBkColor(ps.hdc, bkColor);
  3617. SetTextColor(ps.hdc, txtColor);
  3618. SelectFont(ps.hdc, hfnOld);
  3619. EndPaint(hwnd, &ps);
  3620. DebugExitVOID(ASShare::VIEWFullScreenExitPaint);
  3621. }
  3622.