Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5874 lines
169 KiB

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