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.

9693 lines
260 KiB

  1. //
  2. // MWND.CPP
  3. // Main WB Window
  4. //
  5. // Copyright Microsoft 1998-
  6. //
  7. // PRECOMP
  8. #include "precomp.h"
  9. #include <dde.h>
  10. #include "version.h"
  11. static const TCHAR s_cszHtmlHelpFile[] = TEXT("nmwhiteb.chm");
  12. // Class name
  13. TCHAR szMainClassName[] = "Wb32MainWindowClass";
  14. //
  15. // Scroll accelerators
  16. //
  17. typedef struct tagSCROLL
  18. {
  19. UINT uiMenuId;
  20. UINT uiMessage;
  21. UINT uiScrollCode;
  22. }
  23. SCROLL;
  24. static const SCROLL s_MenuToScroll[] =
  25. {
  26. { IDM_PAGEUP, WM_VSCROLL, SB_PAGEUP },
  27. { IDM_PAGEDOWN, WM_VSCROLL, SB_PAGEDOWN },
  28. { IDM_SHIFTPAGEUP, WM_HSCROLL, SB_PAGEUP },
  29. { IDM_SHIFTPAGEDOWN, WM_HSCROLL, SB_PAGEDOWN },
  30. { IDM_HOME, WM_HSCROLL, SB_TOP },
  31. { IDM_HOME, WM_VSCROLL, SB_TOP },
  32. { IDM_END, WM_HSCROLL, SB_BOTTOM },
  33. { IDM_END, WM_VSCROLL, SB_BOTTOM },
  34. { IDM_LINEUP, WM_VSCROLL, SB_LINEUP },
  35. { IDM_LINEDOWN, WM_VSCROLL, SB_LINEDOWN },
  36. { IDM_SHIFTLINEUP, WM_HSCROLL, SB_LINEUP },
  37. { IDM_SHIFTLINEDOWN, WM_HSCROLL, SB_LINEDOWN }
  38. };
  39. // tooltip data
  40. // check codes
  41. #define NA 0 // dont't check checked state
  42. #define TB 1 // check toolbar for checked state
  43. #define BT 2 // check tipped wnd (a button) for checked state
  44. typedef struct
  45. {
  46. UINT nID;
  47. UINT nCheck;
  48. UINT nUpTipID;
  49. UINT nDownTipID;
  50. }
  51. TIPIDS;
  52. TIPIDS g_tipIDsArray[] =
  53. {
  54. {IDM_SELECT, TB, IDS_HINT_SELECT, IDS_HINT_SELECT},
  55. {IDM_ERASER, TB, IDS_HINT_ERASER, IDS_HINT_ERASER},
  56. {IDM_TEXT, TB, IDS_HINT_TEXT, IDS_HINT_TEXT},
  57. {IDM_HIGHLIGHT, TB, IDS_HINT_HIGHLIGHT, IDS_HINT_HIGHLIGHT},
  58. {IDM_PEN, TB, IDS_HINT_PEN, IDS_HINT_PEN},
  59. {IDM_LINE, TB, IDS_HINT_LINE, IDS_HINT_LINE},
  60. {IDM_BOX, TB, IDS_HINT_BOX, IDS_HINT_BOX},
  61. {IDM_FILLED_BOX, TB, IDS_HINT_FBOX, IDS_HINT_FBOX},
  62. {IDM_ELLIPSE, TB, IDS_HINT_ELLIPSE, IDS_HINT_ELLIPSE},
  63. {IDM_FILLED_ELLIPSE, TB, IDS_HINT_FELLIPSE, IDS_HINT_FELLIPSE},
  64. {IDM_ZOOM, TB, IDS_HINT_ZOOM_UP, IDS_HINT_ZOOM_DOWN},
  65. {IDM_REMOTE, TB, IDS_HINT_REMOTE_UP, IDS_HINT_REMOTE_DOWN},
  66. {IDM_LOCK, TB, IDS_HINT_LOCK_UP, IDS_HINT_LOCK_DOWN},
  67. {IDM_SYNC, TB, IDS_HINT_SYNC_UP, IDS_HINT_SYNC_DOWN},
  68. {IDM_GRAB_AREA, TB, IDS_HINT_GRAB_AREA, IDS_HINT_GRAB_AREA},
  69. {IDM_GRAB_WINDOW, TB, IDS_HINT_GRAB_WINDOW, IDS_HINT_GRAB_WINDOW},
  70. {IDM_WIDTH_1, NA, IDS_HINT_WIDTH_1, IDS_HINT_WIDTH_1},
  71. {IDM_WIDTH_2, NA, IDS_HINT_WIDTH_2, IDS_HINT_WIDTH_2},
  72. {IDM_WIDTH_3, NA, IDS_HINT_WIDTH_3, IDS_HINT_WIDTH_3},
  73. {IDM_WIDTH_4, NA, IDS_HINT_WIDTH_4, IDS_HINT_WIDTH_4},
  74. {IDM_PAGE_FIRST, BT, IDS_HINT_PAGE_FIRST, IDS_HINT_PAGE_FIRST},
  75. {IDM_PAGE_PREV, BT, IDS_HINT_PAGE_PREVIOUS, IDS_HINT_PAGE_PREVIOUS},
  76. {IDM_PAGE_ANY, NA, IDS_HINT_PAGE_ANY, IDS_HINT_PAGE_ANY},
  77. {IDM_PAGE_NEXT, BT, IDS_HINT_PAGE_NEXT, IDS_HINT_PAGE_NEXT},
  78. {IDM_PAGE_LAST, BT, IDS_HINT_PAGE_LAST, IDS_HINT_PAGE_LAST},
  79. {IDM_PAGE_INSERT_AFTER, BT, IDS_HINT_PAGE_INSERT, IDS_HINT_PAGE_INSERT}
  80. };
  81. ////////////
  82. //
  83. //
  84. // Function: WbMainWindow constructor
  85. //
  86. // Purpose: Create the main Whiteboard window. An exception is thrown
  87. // if an error occurs during construction.
  88. //
  89. //
  90. WbMainWindow::WbMainWindow(void)
  91. {
  92. OSVERSIONINFO OsData;
  93. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::WbMainWindow");
  94. //
  95. // Initialize member vars first!
  96. //
  97. m_hwnd = NULL;
  98. ZeroMemory(m_ToolArray, sizeof(m_ToolArray));
  99. m_hwndToolTip = NULL;
  100. ZeroMemory(&m_tiLastHit, sizeof(m_tiLastHit));
  101. m_nLastHit = -1;
  102. m_bInitOk = FALSE;
  103. m_bDisplayingError = FALSE;
  104. g_pwbCore = NULL;
  105. m_dwDomain = 0;
  106. m_bTimerActive = FALSE;
  107. m_bSyncUpdateNeeded = FALSE;
  108. m_hPageClip = WB_PAGE_HANDLE_NULL;
  109. m_hGraphicClip = NULL;
  110. m_pDelayedGraphicClip = NULL;
  111. m_pDelayedDataClip = NULL;
  112. m_bToolBarOn = FALSE;
  113. // Load the main accelerator table
  114. m_hAccelTable =
  115. ::LoadAccelerators(g_hInstance, MAKEINTRESOURCE(MAINACCELTABLE));
  116. m_hwndPageSortDlg = NULL;
  117. m_hwndQuerySaveDlg = NULL;
  118. m_hwndWaitForEventDlg = NULL;
  119. m_hwndWaitForLockDlg = NULL;
  120. m_hwndInitDlg = NULL;
  121. m_hwndSB = NULL;
  122. m_bStatusBarOn = TRUE;
  123. m_pCurrentTool = NULL;
  124. m_uiSavedLockType = WB_LOCK_TYPE_NONE;
  125. ZeroMemory(m_strFileName, sizeof(m_strFileName));
  126. m_hCurrentPage = WB_PAGE_HANDLE_NULL;
  127. // Load the alternative accelerator table for the pages edit
  128. // field and text editor
  129. m_hAccelPagesGroup =
  130. ::LoadAccelerators(g_hInstance, MAKEINTRESOURCE(PAGESGROUPACCELTABLE));
  131. m_hAccelTextEdit =
  132. ::LoadAccelerators(g_hInstance, MAKEINTRESOURCE(TEXTEDITACCELTABLE));
  133. m_pLocalUser = NULL;
  134. m_pLockOwner = NULL;
  135. // Show that we are not yet in a call
  136. m_uiState = STARTING;
  137. m_uiSubState = SUBSTATE_IDLE;
  138. // We are not currently displaying a menu
  139. m_hContextMenuBar = NULL;
  140. m_hContextMenu = NULL;
  141. m_hGrobjContextMenuBar = NULL;
  142. m_hGrobjContextMenu = NULL;
  143. m_bPromptingJoinCall = FALSE;
  144. m_bInSaveDialog = FALSE;
  145. m_bJoinCallPending = FALSE;
  146. m_dwPendingDomain = 0;
  147. m_bPendingCallKeepContents = FALSE;
  148. m_dwJoinDomain = 0;
  149. m_bCallActive = FALSE;
  150. m_hInitMenu = NULL;
  151. m_numRemoteUsers = 0;
  152. m_bSelectAllInProgress = FALSE;
  153. m_bUnlockStateSettled = TRUE;
  154. m_bQuerySysShutdown = FALSE;
  155. // figure out if we're on Win95
  156. m_bIsWin95 = FALSE;
  157. OsData.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  158. if( GetVersionEx( &OsData ) )
  159. {
  160. if( OsData.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
  161. m_bIsWin95 = TRUE;
  162. }
  163. m_cancelModeSent = FALSE;
  164. //
  165. // We only do this once for the lifetime of the DLL. There is no
  166. // way really to clean up registered window messages, and each register
  167. // bumps up a ref count. If we registered each time WB was started up
  168. // during one session of CONF, we'd overflow the refcount.
  169. //
  170. if (!g_uConfShutdown)
  171. {
  172. g_uConfShutdown = ::RegisterWindowMessage( NM_ENDSESSION_MSG_NAME );
  173. }
  174. }
  175. //
  176. // Open()
  177. // Do Main window initialization (stuff that can fail). After this,
  178. // the run code will try to join the current domain and do message loop
  179. // stuff.
  180. //
  181. BOOL WbMainWindow::Open(int iCommand)
  182. {
  183. WNDCLASSEX wc;
  184. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::Open");
  185. //
  186. // CREATE OTHER GLOBALS
  187. //
  188. // Start the Whiteboard Core
  189. if (!CreateWBObject(WbMainWindowEventHandler, &g_pwbCore))
  190. {
  191. ERROR_OUT(("WBP_Start failed"));
  192. DefaultExceptionHandler(WBFE_RC_WB, UT_RC_NO_MEM);
  193. return FALSE;
  194. }
  195. if (!InitToolArray())
  196. {
  197. ERROR_OUT(("Can't create tools; failing to start up"));
  198. return(FALSE);
  199. }
  200. g_pUsers = new WbUserList;
  201. if (!g_pUsers)
  202. {
  203. ERROR_OUT(("Can't create g_pUsers"));
  204. return(FALSE);
  205. }
  206. g_pIcons = new DCWbColorToIconMap();
  207. if (!g_pIcons)
  208. {
  209. ERROR_OUT(("Can't create g_pIcons"));
  210. return(FALSE);
  211. }
  212. //
  213. // Init comon controls
  214. //
  215. InitCommonControls();
  216. //
  217. // CREATE THE MAIN FRAME WINDOW
  218. //
  219. ASSERT(!m_hwnd);
  220. // Get the class info for it, and change the name.
  221. ZeroMemory(&wc, sizeof(wc));
  222. wc.cbSize = sizeof(wc);
  223. wc.style = CS_DBLCLKS; // CS_HREDRAW | CS_VREDRAW?
  224. wc.lpfnWndProc = WbMainWindowProc;
  225. wc.hInstance = g_hInstance;
  226. wc.hIcon = ::LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_APP));
  227. wc.hCursor = ::LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
  228. wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
  229. wc.lpszMenuName = MAKEINTRESOURCE(MAINMENU);
  230. wc.lpszClassName = szMainClassName;
  231. if (!::RegisterClassEx(&wc))
  232. {
  233. ERROR_OUT(("Can't register private frame window class"));
  234. return(FALSE);
  235. }
  236. // Create the main drawing window.
  237. if (!::CreateWindowEx(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE, szMainClassName,
  238. NULL, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  239. CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, g_hInstance, this))
  240. {
  241. // Could not create the main window
  242. ERROR_OUT(("Failed to create main window"));
  243. return(FALSE);
  244. }
  245. ASSERT(m_hwnd);
  246. // Create the pop-up context menu
  247. if (!CreateContextMenus())
  248. {
  249. ERROR_OUT(("Failed to create context menus"));
  250. return(FALSE);
  251. }
  252. // Register the the main window for Drag/Drop messages.
  253. DragAcceptFiles(m_hwnd, TRUE);
  254. //
  255. // CREATE THE CHILD WINDOWS
  256. //
  257. // Create the drawing pane
  258. // (the Create call throws an exception on error)
  259. RECT clientRect;
  260. RECT drawingAreaRect;
  261. ::GetClientRect(m_hwnd, &clientRect);
  262. drawingAreaRect = clientRect;
  263. // Every control in the main window has a border on it, so increase the
  264. // client size by 1 to force these borders to be drawn under the inside
  265. // black line in the window frame. This prevents a 2 pel wide border
  266. // being drawn
  267. ::InflateRect(&clientRect, 1, 1);
  268. SIZE sizeAG;
  269. m_AG.GetNaturalSize(&sizeAG);
  270. //
  271. // The drawing area is the top part of the client. The attributes group
  272. // and status bar are below it.
  273. //
  274. drawingAreaRect.bottom -= (STATUSBAR_HEIGHT
  275. + GetSystemMetrics(SM_CYBORDER)
  276. + sizeAG.cy);
  277. if (!m_drawingArea.Create(m_hwnd, &drawingAreaRect))
  278. {
  279. ERROR_OUT(("Failed to create drawing area"));
  280. return(FALSE);
  281. }
  282. if (!m_TB.Create(m_hwnd))
  283. {
  284. ERROR_OUT(("Failed to create tool window"));
  285. return(FALSE);
  286. }
  287. // Lock the drawing area initially. This prevents the user attempting
  288. // to make changes before we are in a call.
  289. LockDrawingArea();
  290. // disable remote pointer while we are initing (bug 4767)
  291. m_TB.Disable(IDM_REMOTE);
  292. m_hwndSB = ::CreateWindowEx(0, STATUSCLASSNAME, NULL,
  293. WS_CHILD | WS_VISIBLE | CCS_NOPARENTALIGN | CCS_NOMOVEY |
  294. CCS_NORESIZE | SBARS_SIZEGRIP,
  295. clientRect.left, clientRect.bottom - STATUSBAR_HEIGHT,
  296. (clientRect.right - clientRect.left), STATUSBAR_HEIGHT,
  297. m_hwnd, 0, g_hInstance, NULL);
  298. if (!m_hwndSB)
  299. {
  300. ERROR_OUT(("Failed to create status bar window"));
  301. return(FALSE);
  302. }
  303. //
  304. // Create the attributes group
  305. // The attributes group is on the bottom, underneath the
  306. // drawing area, above the status bar.
  307. //
  308. RECT rectAG;
  309. rectAG.left = clientRect.left;
  310. rectAG.right = clientRect.right;
  311. rectAG.top = drawingAreaRect.bottom;
  312. rectAG.bottom = rectAG.top + sizeAG.cy;
  313. if (!m_AG.Create(m_hwnd, &rectAG))
  314. {
  315. ERROR_OUT(("Failed to create attributes group window"));
  316. return(FALSE);
  317. }
  318. //
  319. // Create the widths group.
  320. // The widths group is on the left side, underneath the tools group
  321. //
  322. SIZE sizeWG;
  323. RECT rectWG;
  324. // The widths group is on the left side, underneath the toolbar
  325. m_WG.GetNaturalSize(&sizeWG);
  326. rectWG.left = 0;
  327. rectWG.right = rectWG.left + sizeWG.cx;
  328. rectWG.bottom = rectAG.top;
  329. rectWG.top = rectWG.bottom - sizeWG.cy;
  330. if (!m_WG.Create(m_hwnd, &rectWG))
  331. {
  332. ERROR_OUT(("Failed to create widths group window"));
  333. return(FALSE);
  334. }
  335. // The main window is created with the status bar visible. So make sure
  336. // that the relevant menu item is checked. This is subject to change
  337. // depending on options in the Open member function.
  338. CheckMenuItem(IDM_STATUS_BAR_TOGGLE);
  339. // Initialize the color, width and tool menus
  340. InitializeMenus();
  341. m_currentMenuTool = IDM_SELECT;
  342. m_pCurrentTool = m_ToolArray[TOOL_INDEX(IDM_SELECT)];
  343. m_hwndToolTip = ::CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
  344. WS_POPUP | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT,
  345. CW_USEDEFAULT, CW_USEDEFAULT, m_hwnd, NULL, g_hInstance, NULL);
  346. if (!m_hwndToolTip)
  347. {
  348. ERROR_OUT(("Unable to create tooltip window"));
  349. return(FALSE);
  350. }
  351. // Add a dead-area tooltip
  352. TOOLINFO ti;
  353. ZeroMemory(&ti, sizeof(ti));
  354. ti.cbSize = sizeof(TOOLINFO);
  355. ti.uFlags = TTF_IDISHWND;
  356. ti.hwnd = m_hwnd;
  357. ti.uId = (UINT_PTR)m_hwnd;
  358. ::SendMessage(m_hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
  359. // Ensure the page buttons are disabled while starting
  360. UpdatePageButtons();
  361. // If this is the first time we have created a clipboard object,
  362. // register the private Whiteboard formats.
  363. if (g_ClipboardFormats[CLIPBOARD_PRIVATE_SINGLE_OBJ] == 0)
  364. {
  365. g_ClipboardFormats[CLIPBOARD_PRIVATE_SINGLE_OBJ] =
  366. (int) ::RegisterClipboardFormat("DCGWbClipFormat");
  367. }
  368. if (g_ClipboardFormats[CLIPBOARD_PRIVATE_MULTI_OBJ] == 0)
  369. {
  370. g_ClipboardFormats[CLIPBOARD_PRIVATE_MULTI_OBJ] =
  371. (int) ::RegisterClipboardFormat("DCGWbMultiObjClipFormat");
  372. }
  373. // There is no deleted graphic yet
  374. m_LastDeletedGraphic.BurnTrash();
  375. m_bInitOk = TRUE;
  376. BOOL bSuccess = TRUE; // indicates whether window opened successfully
  377. // Get the position of the window from options
  378. RECT rectWindow;
  379. RECT rectDefault;
  380. ::SetRectEmpty(&rectDefault);
  381. OPT_GetWindowRectOption(OPT_MAIN_MAINWINDOWRECT, &rectWindow, &rectDefault);
  382. if (!::IsRectEmpty(&rectWindow))
  383. {
  384. ::MoveWindow(m_hwnd, rectWindow.left, rectWindow.top,
  385. rectWindow.right - rectWindow.left,
  386. rectWindow.bottom - rectWindow.top, FALSE );
  387. }
  388. // Check whether the help bar is to be visible
  389. if (!OPT_GetBooleanOption(OPT_MAIN_STATUSBARVISIBLE, DFLT_MAIN_STATUSBARVISIBLE))
  390. {
  391. // Update the window to turn the help bar off
  392. OnStatusBarToggle();
  393. }
  394. //
  395. // Position the toolbar
  396. //
  397. // Hide the tool bar before moving it (otherwise we get some
  398. // problems redrawing it).
  399. ::ShowWindow(m_TB.m_hwnd, SW_HIDE);
  400. // Resize the window panes to allow room for the tools
  401. if (m_bToolBarOn)
  402. {
  403. ResizePanes();
  404. ::ShowWindow(m_TB.m_hwnd, SW_SHOW);
  405. }
  406. // Move the focus back from the tool window to the main window
  407. ::SetFocus(m_hwnd);
  408. // Check whether the tool window is to be visible
  409. if (OPT_GetBooleanOption(OPT_MAIN_TOOLBARVISIBLE, DFLT_MAIN_TOOLBARVISIBLE))
  410. {
  411. // Display the tool window, and check the associated menu item
  412. OnToolBarToggle();
  413. }
  414. // Set up the variable saving the maximized/minimized state of
  415. // the window and the extra style necessary for displaying the
  416. // window correctly initially.
  417. if (OPT_GetBooleanOption(OPT_MAIN_MAXIMIZED, DFLT_MAIN_MAXIMIZED))
  418. {
  419. m_uiWindowSize = SIZEFULLSCREEN;
  420. iCommand = SW_SHOWMAXIMIZED;
  421. }
  422. else if (OPT_GetBooleanOption(OPT_MAIN_MINIMIZED, DFLT_MAIN_MINIMIZED))
  423. {
  424. m_uiWindowSize = SIZEICONIC;
  425. iCommand = SW_SHOWMINIMIZED;
  426. }
  427. else
  428. {
  429. // Default
  430. m_uiWindowSize = SIZENORMAL;
  431. iCommand = SW_SHOWNORMAL;
  432. }
  433. UpdateWindowTitle();
  434. ::ShowWindow(m_hwnd, iCommand);
  435. ::UpdateWindow(m_hwnd);
  436. // Update the tool window
  437. ::UpdateWindow(m_TB.m_hwnd);
  438. // Select the tool
  439. m_currentMenuTool = IDM_SELECT;
  440. m_pCurrentTool = m_ToolArray[TOOL_INDEX(IDM_SELECT)];
  441. ::PostMessage(m_hwnd, WM_COMMAND, m_currentMenuTool, 0L);
  442. // Return value indicating success or failure
  443. return(bSuccess);
  444. }
  445. //
  446. //
  447. // Function: WbMainWindow destructor
  448. //
  449. // Purpose: Tidy up main window on destruction.
  450. //
  451. //
  452. WbMainWindow::~WbMainWindow()
  453. {
  454. //
  455. // Destroy the tooltip window
  456. //
  457. if (m_hwndToolTip)
  458. {
  459. ::DestroyWindow(m_hwndToolTip);
  460. m_hwndToolTip = NULL;
  461. }
  462. // Make sure the clipboard discards its saved graphic
  463. // before the drawingArea gets deleted.
  464. CLP_FreeDelayedGraphic();
  465. if (m_hGrobjContextMenuBar != NULL)
  466. {
  467. ::DestroyMenu(m_hGrobjContextMenuBar);
  468. m_hGrobjContextMenuBar = NULL;
  469. }
  470. m_hGrobjContextMenu = NULL;
  471. if (m_hContextMenuBar != NULL)
  472. {
  473. ::DestroyMenu(m_hContextMenuBar);
  474. m_hContextMenuBar = NULL;
  475. }
  476. m_hContextMenu = NULL;
  477. POSITION position = m_pageToPosition.GetHeadPosition();
  478. PAGE_POSITION * pPoint;
  479. while (position)
  480. {
  481. pPoint = (PAGE_POSITION*)m_pageToPosition.GetNext(position);
  482. delete pPoint;
  483. }
  484. m_pageToPosition.EmptyList();
  485. if (g_pwbCore)
  486. {
  487. //
  488. //We must call an explicit stop function, rather than 'delete'
  489. // because we need to pass in the event proc
  490. //
  491. g_pwbCore->WBP_Stop(WbMainWindowEventHandler);
  492. g_pwbCore = NULL;
  493. }
  494. DestroyToolArray();
  495. // Destroy our window
  496. if (m_hwnd != NULL)
  497. {
  498. ::DestroyWindow(m_hwnd);
  499. m_hwnd = NULL;
  500. }
  501. // Deregister our class
  502. ::UnregisterClass(szMainClassName, g_hInstance);
  503. //
  504. // Free the palette
  505. //
  506. if (g_hRainbowPaletteDisplay)
  507. {
  508. DeletePalette(g_hRainbowPaletteDisplay);
  509. g_hRainbowPaletteDisplay = NULL;
  510. }
  511. g_bPalettesInitialized = FALSE;
  512. g_bUsePalettes = FALSE;
  513. if (g_pIcons)
  514. {
  515. delete g_pIcons;
  516. g_pIcons = NULL;
  517. }
  518. if (g_pUsers)
  519. {
  520. delete g_pUsers;
  521. g_pUsers = NULL;
  522. }
  523. }
  524. //
  525. // JoinDomain()
  526. // Attach to the empty domain or current call
  527. //
  528. BOOL WbMainWindow::JoinDomain(void)
  529. {
  530. BOOL bSuccess;
  531. CM_STATUS cmStatus;
  532. // If there is a call available - join it.
  533. if (CMS_GetStatus(&cmStatus))
  534. {
  535. m_bCallActive = TRUE;
  536. // Get the domain ID of the call
  537. m_dwJoinDomain = (DWORD) cmStatus.callID;
  538. // Join the call
  539. bSuccess = JoinCall(FALSE);
  540. }
  541. else
  542. {
  543. // No call available so join the local domain
  544. // Set the domain ID to "no call"
  545. m_dwJoinDomain = (DWORD) OM_NO_CALL;
  546. // Join the call
  547. bSuccess = JoinCall(FALSE);
  548. }
  549. // Wait for the call to be joined, if not abandoned
  550. if (bSuccess)
  551. {
  552. bSuccess = WaitForJoinCallComplete();
  553. }
  554. // take down init dlg
  555. KillInitDlg();
  556. return(bSuccess);
  557. }
  558. //
  559. // KillInitDlg()
  560. // Take down the init dialog
  561. //
  562. void WbMainWindow::KillInitDlg(void)
  563. {
  564. if (m_hwndInitDlg != NULL )
  565. {
  566. ::DestroyWindow(m_hwndInitDlg);
  567. m_hwndInitDlg = NULL;
  568. ::EnableWindow(m_hwnd, TRUE);
  569. }
  570. }
  571. //
  572. // OnToolHitTest()
  573. // This handles tooltips for child windows.
  574. //
  575. int WbMainWindow::OnToolHitTest(POINT pt, TOOLINFO* pTI) const
  576. {
  577. HWND hwnd;
  578. int status;
  579. int nHit = -1;
  580. ASSERT(!IsBadWritePtr(pTI, sizeof(TOOLINFO)));
  581. hwnd = ::ChildWindowFromPointEx(m_hwnd, pt, CWP_SKIPINVISIBLE);
  582. if (hwnd == m_AG.m_hwnd)
  583. {
  584. ::MapWindowPoints(m_hwnd, m_AG.m_hwnd, &pt, 1);
  585. hwnd = ::ChildWindowFromPointEx(m_AG.m_hwnd, pt, CWP_SKIPINVISIBLE);
  586. if (hwnd != NULL)
  587. {
  588. nHit = ::GetDlgCtrlID(hwnd);
  589. pTI->hwnd = m_hwnd;
  590. pTI->uId = (UINT_PTR)hwnd;
  591. pTI->uFlags |= TTF_IDISHWND;
  592. pTI->lpszText = LPSTR_TEXTCALLBACK;
  593. return(nHit);
  594. }
  595. }
  596. else if (hwnd == m_WG.m_hwnd)
  597. {
  598. int iItem;
  599. ::MapWindowPoints(m_hwnd, m_WG.m_hwnd, &pt, 1);
  600. iItem = m_WG.ItemFromPoint(pt.x, pt.y);
  601. pTI->hwnd = m_WG.m_hwnd;
  602. pTI->uId = iItem;
  603. // Since the area isn't a window, we must fill in the rect ourself
  604. m_WG.GetItemRect(iItem, &pTI->rect);
  605. pTI->lpszText = LPSTR_TEXTCALLBACK;
  606. return(iItem);
  607. }
  608. else if (hwnd == m_TB.m_hwnd)
  609. {
  610. RECT rect;
  611. TBBUTTON button;
  612. int i;
  613. for (i = 0; i < TOOLBAR_MAXBUTTON; i++)
  614. {
  615. if (::SendMessage(m_TB.m_hwnd, TB_GETITEMRECT, i, (LPARAM)&rect) &&
  616. ::PtInRect(&rect, pt) &&
  617. ::SendMessage(m_TB.m_hwnd, TB_GETBUTTON, i, (LPARAM)&button) &&
  618. !(button.fsStyle & TBSTYLE_SEP))
  619. {
  620. nHit = button.idCommand;
  621. pTI->hwnd = m_TB.m_hwnd;
  622. pTI->uId = nHit;
  623. pTI->rect = rect;
  624. pTI->lpszText = LPSTR_TEXTCALLBACK;
  625. // found matching rect, return the ID of the button
  626. return(nHit);
  627. }
  628. }
  629. }
  630. return(-1);
  631. }
  632. //
  633. // WbMainWindowProc()
  634. // Frame window message handler
  635. //
  636. LRESULT WbMainWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  637. {
  638. LRESULT lResult = 0;
  639. WbMainWindow * pMain;
  640. pMain = (WbMainWindow *)::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  641. switch (message)
  642. {
  643. case WM_NCCREATE:
  644. pMain = (WbMainWindow *)((LPCREATESTRUCT)lParam)->lpCreateParams;
  645. ASSERT(pMain);
  646. pMain->m_hwnd = hwnd;
  647. ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pMain);
  648. goto DefWndProc;
  649. break;
  650. case WM_DESTROY:
  651. ShutDownHelp();
  652. break;
  653. case WM_NCDESTROY:
  654. pMain->m_hwnd = NULL;
  655. break;
  656. case WM_MOVE:
  657. pMain->OnMove();
  658. break;
  659. case WM_SIZE:
  660. pMain->OnSize((UINT)wParam, LOWORD(lParam), HIWORD(lParam));
  661. break;
  662. case WM_ACTIVATE:
  663. if (GET_WM_ACTIVATE_STATE(wParam, lParam) == WA_INACTIVE)
  664. {
  665. // Cancel the tooltip if it's around
  666. if (pMain->m_hwndToolTip)
  667. ::SendMessage(pMain->m_hwndToolTip, TTM_ACTIVATE, FALSE, 0);
  668. }
  669. goto DefWndProc;
  670. break;
  671. case WM_SETFOCUS:
  672. pMain->OnSetFocus();
  673. break;
  674. case WM_CANCELMODE:
  675. pMain->OnCancelMode();
  676. break;
  677. case WM_TIMER:
  678. pMain->OnTimer(wParam);
  679. break;
  680. case WM_INITMENUPOPUP:
  681. pMain->OnInitMenuPopup((HMENU)wParam, LOWORD(lParam), HIWORD(lParam));
  682. break;
  683. case WM_MENUSELECT:
  684. pMain->OnMenuSelect(GET_WM_MENUSELECT_CMD(wParam, lParam),
  685. GET_WM_MENUSELECT_FLAGS(wParam, lParam),
  686. GET_WM_MENUSELECT_HMENU(wParam, lParam));
  687. break;
  688. case WM_MEASUREITEM:
  689. pMain->OnMeasureItem((int)wParam, (LPMEASUREITEMSTRUCT)lParam);
  690. break;
  691. case WM_DRAWITEM:
  692. pMain->OnDrawItem((int)wParam, (LPDRAWITEMSTRUCT)lParam);
  693. break;
  694. case WM_QUERYNEWPALETTE:
  695. lResult = pMain->OnQueryNewPalette();
  696. break;
  697. case WM_PALETTECHANGED:
  698. pMain->OnPaletteChanged((HWND)wParam);
  699. break;
  700. case WM_HELP:
  701. pMain->OnCommand(IDM_HELP, 0, NULL);
  702. break;
  703. case WM_CLOSE:
  704. pMain->OnClose();
  705. break;
  706. case WM_QUERYENDSESSION:
  707. lResult = pMain->OnQueryEndSession();
  708. break;
  709. case WM_ENDSESSION:
  710. pMain->OnEndSession((BOOL)wParam);
  711. break;
  712. case WM_SYSCOLORCHANGE:
  713. pMain->OnSysColorChange();
  714. break;
  715. case WM_USER_PRIVATE_PARENTNOTIFY:
  716. pMain->OnParentNotify(GET_WM_PARENTNOTIFY_MSG(wParam, lParam));
  717. break;
  718. case WM_GETMINMAXINFO:
  719. if (pMain)
  720. pMain->OnGetMinMaxInfo((LPMINMAXINFO)lParam);
  721. break;
  722. case WM_RENDERALLFORMATS:
  723. pMain->OnRenderAllFormats();
  724. break;
  725. case WM_RENDERFORMAT:
  726. pMain->CLP_RenderFormat((int)wParam);
  727. break;
  728. case WM_COMMAND:
  729. pMain->OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam);
  730. break;
  731. case WM_NOTIFY:
  732. pMain->OnNotify((UINT)wParam, (NMHDR *)lParam);
  733. break;
  734. case WM_DROPFILES:
  735. pMain->OnDropFiles((HDROP)wParam);
  736. break;
  737. case WM_USER_GOTO_USER_POSITION:
  738. pMain->OnGotoUserPosition(lParam);
  739. break;
  740. case WM_USER_GOTO_USER_POINTER:
  741. pMain->OnGotoUserPointer(lParam);
  742. break;
  743. case WM_USER_JOIN_CALL:
  744. pMain->OnJoinCall((BOOL)wParam, lParam);
  745. break;
  746. case WM_USER_DISPLAY_ERROR:
  747. pMain->OnDisplayError(wParam, lParam);
  748. break;
  749. case WM_USER_UPDATE_ATTRIBUTES:
  750. pMain->m_AG.DisplayTool(pMain->m_pCurrentTool);
  751. break;
  752. case WM_USER_JOIN_PENDING_CALL:
  753. pMain->OnJoinPendingCall();
  754. break;
  755. default:
  756. if (message == g_uConfShutdown)
  757. {
  758. lResult = pMain->OnConfShutdown(wParam, lParam);
  759. }
  760. else
  761. {
  762. DefWndProc:
  763. lResult = DefWindowProc(hwnd, message, wParam, lParam);
  764. }
  765. break;
  766. }
  767. return(lResult);
  768. }
  769. //
  770. // OnCommand()
  771. // Command dispatcher for the main window
  772. //
  773. void WbMainWindow::OnCommand(UINT cmd, UINT code, HWND hwndCtl)
  774. {
  775. switch (cmd)
  776. {
  777. //
  778. // FILE MENU
  779. //
  780. case IDM_NEW:
  781. OnNew();
  782. break;
  783. case IDM_OPEN:
  784. OnOpen();
  785. break;
  786. case IDM_SAVE:
  787. OnSave(FALSE);
  788. break;
  789. case IDM_SAVE_AS:
  790. OnSave(TRUE);
  791. break;
  792. case IDM_PRINT:
  793. OnPrint();
  794. break;
  795. case IDM_EXIT:
  796. ::PostMessage(m_hwnd, WM_CLOSE, 0, 0);
  797. break;
  798. //
  799. // EDIT MENU
  800. //
  801. case IDM_DELETE:
  802. OnDelete();
  803. break;
  804. case IDM_UNDELETE:
  805. OnUndelete();
  806. break;
  807. case IDM_CUT:
  808. OnCut();
  809. break;
  810. case IDM_COPY:
  811. OnCopy();
  812. break;
  813. case IDM_PASTE:
  814. OnPaste();
  815. break;
  816. case IDM_SELECTALL:
  817. OnSelectAll();
  818. break;
  819. case IDM_BRING_TO_TOP:
  820. m_drawingArea.BringToTopSelection();
  821. break;
  822. case IDM_SEND_TO_BACK:
  823. m_drawingArea.SendToBackSelection();
  824. break;
  825. case IDM_CLEAR_PAGE:
  826. OnClearPage();
  827. break;
  828. case IDM_DELETE_PAGE:
  829. OnDeletePage();
  830. break;
  831. case IDM_PAGE_INSERT_BEFORE:
  832. OnInsertPageBefore();
  833. break;
  834. case IDM_PAGE_INSERT_AFTER:
  835. OnInsertPageAfter();
  836. break;
  837. case IDM_PAGE_SORTER:
  838. OnPageSorter();
  839. break;
  840. //
  841. // VIEW MENU
  842. //
  843. case IDM_TOOL_BAR_TOGGLE:
  844. OnToolBarToggle();
  845. break;
  846. case IDM_STATUS_BAR_TOGGLE:
  847. OnStatusBarToggle();
  848. break;
  849. case IDM_ZOOM:
  850. OnZoom();
  851. break;
  852. //
  853. // TOOLS MENU
  854. //
  855. case IDM_SELECT:
  856. case IDM_PEN:
  857. case IDM_HIGHLIGHT:
  858. case IDM_TEXT:
  859. case IDM_ERASER:
  860. case IDM_LINE:
  861. case IDM_BOX:
  862. case IDM_FILLED_BOX:
  863. case IDM_ELLIPSE:
  864. case IDM_FILLED_ELLIPSE:
  865. OnSelectTool(cmd);
  866. break;
  867. case IDM_REMOTE:
  868. OnRemotePointer();
  869. break;
  870. case IDM_GRAB_AREA:
  871. OnGrabArea();
  872. break;
  873. case IDM_GRAB_WINDOW:
  874. OnGrabWindow();
  875. break;
  876. case IDM_SYNC:
  877. OnSync();
  878. break;
  879. case IDM_LOCK:
  880. OnLock();
  881. break;
  882. //
  883. // OPTIONS MENU
  884. //
  885. case IDM_COLOR:
  886. OnSelectColor();
  887. break;
  888. case IDM_EDITCOLOR:
  889. m_AG.OnEditColors();
  890. break;
  891. case IDM_FONT:
  892. OnChooseFont();
  893. break;
  894. case IDM_WIDTH_1:
  895. case IDM_WIDTH_2:
  896. case IDM_WIDTH_3:
  897. case IDM_WIDTH_4:
  898. OnSelectWidth(cmd);
  899. break;
  900. //
  901. // HELP MENU
  902. //
  903. case IDM_ABOUT:
  904. OnAbout();
  905. break;
  906. case IDM_HELP:
  907. ShowHelp();
  908. break;
  909. //
  910. // PAGE BAR
  911. //
  912. case IDM_PAGE_FIRST:
  913. OnFirstPage();
  914. break;
  915. case IDM_PAGE_PREV:
  916. OnPrevPage();
  917. break;
  918. case IDM_PAGE_GOTO:
  919. OnGotoPage();
  920. break;
  921. case IDM_PAGE_NEXT:
  922. OnNextPage();
  923. break;
  924. case IDM_PAGE_LAST:
  925. OnLastPage();
  926. break;
  927. //
  928. // SCROLLING
  929. //
  930. case IDM_PAGEUP:
  931. case IDM_PAGEDOWN:
  932. case IDM_SHIFTPAGEUP:
  933. case IDM_SHIFTPAGEDOWN:
  934. case IDM_HOME:
  935. case IDM_END:
  936. case IDM_LINEUP:
  937. case IDM_LINEDOWN:
  938. case IDM_SHIFTLINEUP:
  939. case IDM_SHIFTLINEDOWN:
  940. OnScrollAccelerator(cmd);
  941. break;
  942. }
  943. }
  944. //
  945. // WinHelp() wrapper
  946. //
  947. void WbMainWindow::ShowHelp(void)
  948. {
  949. HWND hwndCapture;
  950. // Get the main window out of any mode
  951. ::SendMessage(m_hwnd, WM_CANCELMODE, 0, 0);
  952. // Cancel any other tracking
  953. if (hwndCapture = ::GetCapture())
  954. ::SendMessage(hwndCapture, WM_CANCELMODE, 0, 0);
  955. // finally, run the Windows Help engine
  956. ShowNmHelp(s_cszHtmlHelpFile);
  957. }
  958. //
  959. //
  960. // Function: OnJoinCall
  961. //
  962. // Purpose: Join a call - displaying a dialog informing the user of
  963. // progress.
  964. //
  965. //
  966. void WbMainWindow::OnJoinCall(BOOL bKeep, LPARAM lParam)
  967. {
  968. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnJoinCall");
  969. // cancel the load if there's one in progress
  970. if ( (m_uiState == IN_CALL)
  971. && (m_uiSubState == SUBSTATE_LOADING))
  972. {
  973. CancelLoad();
  974. }
  975. // Get the parameters for JoinCall
  976. m_dwJoinDomain = (DWORD) lParam;
  977. // Start the process of joining the call
  978. BOOL bSuccess = JoinCall(bKeep);
  979. // Wait for the join call to complete, if not abandoned
  980. if (bSuccess)
  981. {
  982. bSuccess = WaitForJoinCallComplete();
  983. if (bSuccess)
  984. {
  985. TRACE_MSG(("Joined call OK"));
  986. }
  987. else
  988. {
  989. // WaitForJoinCallComplete displays appropriate error message
  990. TRACE_MSG(("Failed to join call"));
  991. // get into a good state
  992. Recover();
  993. }
  994. }
  995. // take down init dlg
  996. KillInitDlg();
  997. }
  998. //
  999. //
  1000. // Function: JoinCall
  1001. //
  1002. // Purpose: Join a call - displaying a dialog informing the user of
  1003. // progress.
  1004. //
  1005. //
  1006. BOOL WbMainWindow::JoinCall(BOOL bKeep)
  1007. {
  1008. BOOL bSuccess = TRUE;
  1009. UINT uiReturn;
  1010. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::JoinCall");
  1011. // We must not already be in a real call when we get here
  1012. if ((m_uiState == IN_CALL) && (m_dwDomain != OM_NO_CALL))
  1013. {
  1014. ERROR_OUT(("In a call already"));
  1015. }
  1016. //
  1017. // Prompt the user to save the current contents unless we are in
  1018. // application start-up (when there can be no contents to save) or we
  1019. // are keeping the contents (when there is no need to save).
  1020. //
  1021. if ((m_uiState != STARTING) && !bKeep)
  1022. {
  1023. //
  1024. // Close the page sorter dialog if it's up.
  1025. //
  1026. if (m_hwndPageSortDlg != NULL)
  1027. {
  1028. ::SendMessage(m_hwndPageSortDlg, WM_COMMAND,
  1029. MAKELONG(IDOK, BN_CLICKED), 0);
  1030. ASSERT(m_hwndPageSortDlg == NULL);
  1031. }
  1032. TRACE_MSG(("Not in STARTING state - check whether save wanted"));
  1033. if (m_hwndQuerySaveDlg != NULL)
  1034. {
  1035. ::SendMessage(m_hwndQuerySaveDlg, WM_COMMAND,
  1036. MAKELONG(IDCANCEL, BN_CLICKED), 0);
  1037. ASSERT(m_hwndQuerySaveDlg == NULL);
  1038. }
  1039. // flag that we are joining a call
  1040. m_bPromptingJoinCall = TRUE;
  1041. // ask the user whether to save changes (if required)
  1042. int iDoNew = QuerySaveRequired(FALSE);
  1043. // remove any save as dialog that is already up.
  1044. if (m_bInSaveDialog)
  1045. {
  1046. m_bPromptingJoinCall = FALSE;
  1047. CancelSaveDialog();
  1048. m_bPromptingJoinCall = TRUE;
  1049. }
  1050. if (iDoNew == IDYES)
  1051. {
  1052. TRACE_MSG(("User has elected to save the changes"));
  1053. // Save the changes
  1054. iDoNew = OnSave(FALSE);
  1055. }
  1056. if (!m_bPromptingJoinCall) // received end call notification
  1057. // (during save-as or query-save)
  1058. {
  1059. TRACE_MSG(("Call ended - abandon JoinCall"));
  1060. return(FALSE);
  1061. }
  1062. // flag we're no longer in a state where the join call can be
  1063. // cancelled
  1064. m_bPromptingJoinCall = FALSE;
  1065. //
  1066. // Reset the file name to Untitled, since we are receiving new
  1067. // contents
  1068. //
  1069. ZeroMemory(m_strFileName, sizeof(m_strFileName));
  1070. UpdateWindowTitle();
  1071. // if we have the lock then release it
  1072. if (WB_GotLock())
  1073. {
  1074. // Release the lock
  1075. g_pwbCore->WBP_Unlock();
  1076. // Set the locked check mark
  1077. UncheckMenuItem(IDM_LOCK);
  1078. // Pop up the lock button
  1079. m_TB.PopUp(IDM_LOCK);
  1080. }
  1081. if(m_pLocalUser != NULL)
  1082. {
  1083. // if the remote pointer is active then turn it off
  1084. DCWbGraphicPointer* pPointer = m_pLocalUser->GetPointer();
  1085. if (pPointer->IsActive())
  1086. {
  1087. OnRemotePointer();
  1088. }
  1089. }
  1090. // if sync is turned on then turn it off
  1091. Unsync();
  1092. // If we are not keeping the contents then the only valid current
  1093. // page is the first page.
  1094. g_pwbCore->WBP_PageHandle(WB_PAGE_HANDLE_NULL, PAGE_FIRST, &m_hCurrentPage);
  1095. }
  1096. //PUTBACK BY RAND - the progress timer meter is kinda the heart beat
  1097. // of this thing which I ripped out when I removed the
  1098. // progress meter. I put it back to fix 1476.
  1099. if (m_bTimerActive)
  1100. {
  1101. ::KillTimer(m_hwnd, TIMERID_PROGRESS_METER);
  1102. m_bTimerActive = FALSE;
  1103. }
  1104. //
  1105. // lock the drawing area until the joining of the call has succeeded
  1106. //
  1107. TRACE_MSG(("Locking drawing area"));
  1108. LockDrawingArea();
  1109. //
  1110. // Give the drawing area a null page during the joining process. This
  1111. // prevents the drawing area attempting to draw the objects in the page
  1112. // during the process of joining the call.
  1113. //
  1114. TRACE_MSG(("Detaching drawing area"));
  1115. m_drawingArea.Detach();
  1116. // Show that we are no longer in a call, but joining a new one
  1117. TRACE_MSG(("m_uiState %d", m_uiState));
  1118. if (m_uiState != STARTING)
  1119. {
  1120. m_uiState = JOINING;
  1121. UpdatePageButtons();
  1122. }
  1123. // put up init dlg
  1124. if (m_bCallActive)
  1125. {
  1126. ::UpdateWindow(m_hwnd);
  1127. //
  1128. // Our init dialog doesn't have a proc, since it has no UI to
  1129. // interact with. We destroy it when we are done. So, do the
  1130. // init stuff here.
  1131. //
  1132. m_hwndInitDlg = ::CreateDialogParam(g_hInstance,
  1133. MAKEINTRESOURCE(IM_INITIALIZING), m_hwnd, NULL, 0);
  1134. if (!m_hwndInitDlg)
  1135. {
  1136. ERROR_OUT(("Couldn't create startup screen for WB"));
  1137. }
  1138. else
  1139. {
  1140. RECT rcMovie;
  1141. HWND hwndMovieParent;
  1142. HWND hwndMovie;
  1143. // Get the rectangle to create the animation control in
  1144. hwndMovieParent = ::GetDlgItem(m_hwndInitDlg, IDC_INITIALIZING_ANIMATION);
  1145. ::GetClientRect(hwndMovieParent, &rcMovie);
  1146. hwndMovie = ::CreateWindowEx(0, ANIMATE_CLASS, NULL,
  1147. WS_CHILD | WS_VISIBLE | ACS_TRANSPARENT | ACS_CENTER,
  1148. rcMovie.left, rcMovie.top,
  1149. rcMovie.right - rcMovie.left, rcMovie.bottom - rcMovie.top,
  1150. hwndMovieParent, (HMENU)IDC_INITIALIZING_ANIMATION,
  1151. g_hInstance, NULL);
  1152. if (hwndMovie != NULL)
  1153. {
  1154. ::SendMessage(hwndMovie, ACM_OPEN, 0, (LPARAM)
  1155. MAKEINTRESOURCE(WBMOVIE));
  1156. }
  1157. // Disable the main window while the dialog is up.
  1158. ::EnableWindow(m_hwnd, FALSE);
  1159. ::ShowWindow(m_hwndInitDlg, SW_SHOW);
  1160. ::UpdateWindow(m_hwndInitDlg);
  1161. if (hwndMovie != NULL)
  1162. {
  1163. ::SendMessage(hwndMovie, ACM_PLAY, 0xFFFF,
  1164. MAKELPARAM(0, 0xFFFF));
  1165. }
  1166. }
  1167. }
  1168. //
  1169. // Start joining the call. Throws an exception on error.
  1170. //
  1171. ASSERT(g_pUsers);
  1172. g_pUsers->Clear();
  1173. uiReturn = g_pwbCore->WBP_JoinCall(bKeep, m_dwJoinDomain);
  1174. if (uiReturn != 0)
  1175. {
  1176. bSuccess = FALSE;
  1177. }
  1178. return(bSuccess);
  1179. }
  1180. //
  1181. //
  1182. // Function: WaitForJoinCallComplete
  1183. //
  1184. // Purpose: Join a call - displaying a dialog informing the user of
  1185. // progress.
  1186. //
  1187. //
  1188. BOOL WbMainWindow::WaitForJoinCallComplete(void)
  1189. {
  1190. BOOL bResult = FALSE;
  1191. TMDLG tmdlg;
  1192. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::WaitForJoinCallComplete");
  1193. //
  1194. // Bring up a dialog to wait for call joining to complete. This turns
  1195. // the asynchronous registration process into a synchronous process as
  1196. // far as this routine is concerned.
  1197. //
  1198. //
  1199. // Set the window title to show we're no longer registering/joining a
  1200. // call.
  1201. //
  1202. UpdateWindowTitle();
  1203. ASSERT(m_hwndWaitForEventDlg == NULL);
  1204. //
  1205. // This is the data we use in the timed dialog
  1206. //
  1207. ZeroMemory(&tmdlg, sizeof(tmdlg));
  1208. tmdlg.bVisible = FALSE;
  1209. tmdlg.bLockNotEvent = FALSE;
  1210. tmdlg.uiMaxDisplay = MAIN_REGISTRATION_TIMEOUT;
  1211. ::DialogBoxParam(g_hInstance, MAKEINTRESOURCE(INVISIBLEDIALOG),
  1212. m_hwnd, TimedDlgProc, (LPARAM)&tmdlg);
  1213. ASSERT(m_hwndWaitForEventDlg == NULL);
  1214. //
  1215. // Set the window title to show we're no longer registering/joining a
  1216. // call.
  1217. //
  1218. UpdateWindowTitle();
  1219. if (m_uiState != IN_CALL)
  1220. {
  1221. //
  1222. // We failed to join the call
  1223. //
  1224. WARNING_OUT(("User cancelled or joincall failed, m_uiState %d", m_uiState));
  1225. //
  1226. // We must display an error inline here because we will close
  1227. // shortly
  1228. //
  1229. OnDisplayError(WBFE_RC_JOIN_CALL_FAILED, 0);
  1230. }
  1231. else
  1232. {
  1233. bResult = TRUE;
  1234. }
  1235. return(bResult);
  1236. }
  1237. //
  1238. // TimedDlgProc()
  1239. // This puts up a visible or invisible dialog which only goes away when
  1240. // an event occurs or a certain amount of time has passed. We store the
  1241. // DialogBoxParam parameter, a TMDLG pointer, in our user data. That is
  1242. // from the stack of the DialogBoxParam() caller, so it is valid until that
  1243. // function returns, which won't be until a bit after the dialog has been
  1244. // destroyed.
  1245. //
  1246. INT_PTR CALLBACK TimedDlgProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  1247. {
  1248. BOOL fHandled = FALSE;
  1249. TMDLG * ptm;
  1250. switch (uMessage)
  1251. {
  1252. case WM_INITDIALOG:
  1253. ptm = (TMDLG *)lParam;
  1254. ASSERT(!IsBadWritePtr(ptm, sizeof(TMDLG)));
  1255. ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)ptm);
  1256. //
  1257. // Set the WbMainWindow hwnd
  1258. //
  1259. if (ptm->bLockNotEvent)
  1260. {
  1261. g_pMain->m_hwndWaitForLockDlg = hwnd;
  1262. }
  1263. else
  1264. {
  1265. g_pMain->m_hwndWaitForEventDlg = hwnd;
  1266. }
  1267. //
  1268. // Set max timer
  1269. //
  1270. ::SetTimer(hwnd, TIMERID_MAXDISPLAY, ptm->uiMaxDisplay, NULL);
  1271. //
  1272. // Change the cursor if invisible
  1273. //
  1274. if (!ptm->bVisible)
  1275. ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
  1276. fHandled = TRUE;
  1277. break;
  1278. case WM_TIMER:
  1279. ASSERT(wParam == TIMERID_MAXDISPLAY);
  1280. // End the dialog--since we timed out, it acts like cancel
  1281. ::SendMessage(hwnd, WM_COMMAND, MAKELONG(IDCANCEL, BN_CLICKED), 0);
  1282. fHandled = TRUE;
  1283. break;
  1284. case WM_COMMAND:
  1285. switch (GET_WM_COMMAND_ID(wParam, lParam))
  1286. {
  1287. case IDOK:
  1288. case IDCANCEL:
  1289. if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED)
  1290. {
  1291. ptm = (TMDLG *)::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1292. ASSERT(!IsBadWritePtr(ptm, sizeof(TMDLG)));
  1293. // Clear out the HWND variable
  1294. if (ptm->bLockNotEvent)
  1295. {
  1296. g_pMain->m_hwndWaitForLockDlg = NULL;
  1297. }
  1298. else
  1299. {
  1300. g_pMain->m_hwndWaitForEventDlg = NULL;
  1301. }
  1302. // Restore the cursor
  1303. if (!ptm->bVisible)
  1304. ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
  1305. ::KillTimer(hwnd, TIMERID_MAXDISPLAY);
  1306. ::EndDialog(hwnd, GET_WM_COMMAND_ID(wParam, lParam));
  1307. }
  1308. break;
  1309. }
  1310. fHandled = TRUE;
  1311. break;
  1312. //
  1313. // Don't let these dialogs be killed by any other means than our
  1314. // getting an event or timing out.
  1315. //
  1316. case WM_CLOSE:
  1317. fHandled = TRUE;
  1318. break;
  1319. }
  1320. return(fHandled);
  1321. }
  1322. //
  1323. // FilterMessage()
  1324. //
  1325. // This does tooltip message filtering, then translates accelerators.
  1326. //
  1327. BOOL WbMainWindow::FilterMessage(MSG* pMsg)
  1328. {
  1329. BOOL bResult = FALSE;
  1330. if ((pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) ||
  1331. (pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONDBLCLK) ||
  1332. (pMsg->message == WM_RBUTTONDOWN || pMsg->message == WM_RBUTTONDBLCLK) ||
  1333. (pMsg->message == WM_MBUTTONDOWN || pMsg->message == WM_MBUTTONDBLCLK) ||
  1334. (pMsg->message == WM_NCLBUTTONDOWN || pMsg->message == WM_NCLBUTTONDBLCLK) ||
  1335. (pMsg->message == WM_NCRBUTTONDOWN || pMsg->message == WM_NCRBUTTONDBLCLK) ||
  1336. (pMsg->message == WM_NCMBUTTONDOWN || pMsg->message == WM_NCMBUTTONDBLCLK))
  1337. {
  1338. // Cancel any tooltip up
  1339. ::SendMessage(m_hwndToolTip, TTM_ACTIVATE, FALSE, 0);
  1340. }
  1341. // handle tooltip messages (some messages cancel, some may cause it to popup)
  1342. if ((pMsg->message == WM_MOUSEMOVE || pMsg->message == WM_NCMOUSEMOVE ||
  1343. pMsg->message == WM_LBUTTONUP || pMsg->message == WM_RBUTTONUP ||
  1344. pMsg->message == WM_MBUTTONUP) &&
  1345. (GetKeyState(VK_LBUTTON) >= 0 && GetKeyState(VK_RBUTTON) >= 0 &&
  1346. GetKeyState(VK_MBUTTON) >= 0))
  1347. {
  1348. #if 0
  1349. //
  1350. // If this mouse move isn't for a descendant of the main window, skip
  1351. // it. For example, when the tooltip is shown, it gets a mousemove
  1352. // to itself, which if we didn't check for it, would cause us to
  1353. // immediately dismiss this!
  1354. //
  1355. HWND hwndTmp = pMsg->hwnd;
  1356. while (hwndTmp && (::GetWindowLong(hwndTmp, GWL_STYLE) & WS_CHILD))
  1357. {
  1358. hwndTmp = ::GetParent(hwndTmp);
  1359. }
  1360. if (hwndTmp != m_hwnd)
  1361. {
  1362. // This is not for us, it's for another top level window in
  1363. // our app.
  1364. goto DoneToolTipFiltering;
  1365. }
  1366. #endif
  1367. // determine which tool was hit
  1368. POINT pt;
  1369. pt = pMsg->pt;
  1370. ::ScreenToClient(m_hwnd, &pt);
  1371. TOOLINFO tiHit;
  1372. ZeroMemory(&tiHit, sizeof(tiHit));
  1373. tiHit.cbSize = sizeof(TOOLINFO);
  1374. int nHit = OnToolHitTest(pt, &tiHit);
  1375. if (m_nLastHit != nHit)
  1376. {
  1377. if (nHit != -1)
  1378. {
  1379. // add new tool and activate the tip
  1380. if (!::SendMessage(m_hwndToolTip, TTM_ADDTOOL, 0, (LPARAM)&tiHit))
  1381. {
  1382. ERROR_OUT(("TTM_ADDTOOL failed"));
  1383. }
  1384. if (::GetActiveWindow() == m_hwnd)
  1385. {
  1386. // allow the tooltip to popup when it should
  1387. ::SendMessage(m_hwndToolTip, TTM_ACTIVATE, TRUE, 0);
  1388. // bring the tooltip window above other popup windows
  1389. ::SetWindowPos(m_hwndToolTip, HWND_TOP, 0, 0, 0, 0,
  1390. SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE);
  1391. }
  1392. }
  1393. // relay mouse event before deleting old tool
  1394. ::SendMessage(m_hwndToolTip, TTM_RELAYEVENT, 0, (LPARAM)pMsg);
  1395. // now safe to delete the old tool
  1396. if (m_tiLastHit.cbSize != 0)
  1397. ::SendMessage(m_hwndToolTip, TTM_DELTOOL, 0, (LPARAM)&m_tiLastHit);
  1398. m_nLastHit = nHit;
  1399. m_tiLastHit = tiHit;
  1400. }
  1401. else
  1402. {
  1403. // relay mouse events through the tooltip
  1404. if (nHit != -1)
  1405. ::SendMessage(m_hwndToolTip, TTM_RELAYEVENT, 0, (LPARAM)pMsg);
  1406. }
  1407. }
  1408. #if 0
  1409. DoneToolTipFiltering:
  1410. #endif
  1411. // Assume we will use the main accelerator table
  1412. HACCEL hAccelTable = m_hAccelTable;
  1413. // If this window has focus, just continue
  1414. HWND hwndFocus = ::GetFocus();
  1415. if (hwndFocus && (hwndFocus != m_hwnd))
  1416. {
  1417. // Check whether an edit field in the pages group has the focus
  1418. if (m_AG.IsChildEditField(hwndFocus))
  1419. {
  1420. hAccelTable = m_hAccelPagesGroup;
  1421. }
  1422. // Check whether text editor has the focus and is active
  1423. else if ( (hwndFocus == m_drawingArea.m_hwnd)
  1424. && (m_drawingArea.TextEditActive()))
  1425. {
  1426. // Let editbox do its own acceleration.
  1427. hAccelTable = NULL;
  1428. }
  1429. }
  1430. return ( (hAccelTable != NULL)
  1431. && ::TranslateAccelerator(m_hwnd, hAccelTable, pMsg));
  1432. }
  1433. //
  1434. //
  1435. // Function: OnDisplayError
  1436. //
  1437. // Purpose: Display an error message
  1438. //
  1439. //
  1440. void WbMainWindow::OnDisplayError(WPARAM uiFEReturnCode, LPARAM uiDCGReturnCode)
  1441. {
  1442. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnDisplayError");
  1443. // Only continue if we are not currently displaying an error
  1444. if (!m_bDisplayingError)
  1445. {
  1446. // Show that we are currently displaying an error message
  1447. m_bDisplayingError = TRUE;
  1448. // Display the error
  1449. ::ErrorMessage((UINT)uiFEReturnCode, (UINT)uiDCGReturnCode);
  1450. // Show that we are no longer displaying an error
  1451. m_bDisplayingError = FALSE;
  1452. }
  1453. }
  1454. //
  1455. //
  1456. // Function: OnTimer
  1457. //
  1458. // Purpose: Process a timer event. These are used to update the progress
  1459. // meter and the sync position.
  1460. //
  1461. //
  1462. void WbMainWindow::OnTimer(UINT_PTR idTimer)
  1463. {
  1464. TRACE_TIMER(("WbMainWindow::OnTimer"));
  1465. //
  1466. // Only do anything if the timer has not been switched off (this may be an
  1467. // old timer message left in the queue when we stopped the timer).
  1468. //
  1469. if (m_bTimerActive)
  1470. {
  1471. //
  1472. // Check for sync position update needed
  1473. //
  1474. // Check whether an update is flagged
  1475. if (m_bSyncUpdateNeeded)
  1476. {
  1477. TRACE_TIMER(("Updating sync position"));
  1478. // Check whether the local user is still synced
  1479. if ((m_uiState == IN_CALL) &&
  1480. (m_pLocalUser != NULL) &&
  1481. (m_pLocalUser->IsSynced()) &&
  1482. (!WB_ContentsLocked()))
  1483. {
  1484. RECT rcVis;
  1485. // Update the local user's position information
  1486. m_drawingArea.GetVisibleRect(&rcVis);
  1487. m_pLocalUser->SetVisibleRect(&rcVis);
  1488. // Write the sync position from the local user's current position
  1489. m_pLocalUser->PutSyncPosition();
  1490. }
  1491. // Show that the update has been done
  1492. m_bSyncUpdateNeeded = FALSE;
  1493. }
  1494. }
  1495. }
  1496. //
  1497. //
  1498. // Function: OnPaletteChanged
  1499. //
  1500. // Purpose: The palette has changed.
  1501. //
  1502. //
  1503. void WbMainWindow::OnPaletteChanged(HWND hwndPalette)
  1504. {
  1505. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnPaletteChanged");
  1506. if ((hwndPalette != m_hwnd) &&
  1507. (hwndPalette != m_drawingArea.m_hwnd))
  1508. {
  1509. // Tell the drawing area to realize its palette
  1510. m_drawingArea.RealizePalette( TRUE );
  1511. }
  1512. }
  1513. //
  1514. //
  1515. // Function: OnQueryNewPalette
  1516. //
  1517. // Purpose: We are getting focus and must realize our palette
  1518. //
  1519. //
  1520. LRESULT WbMainWindow::OnQueryNewPalette(void)
  1521. {
  1522. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnQueryNewPalette");
  1523. // Tell the drawing area to realize its palette
  1524. m_drawingArea.RealizePalette( FALSE );
  1525. return TRUE;
  1526. }
  1527. //
  1528. //
  1529. // Function: WbMainWindowEventHandler
  1530. //
  1531. // Purpose: Event handler for WbMainWindow objects. This is a class
  1532. // wide function. The client data passed to it is a pointer
  1533. // to the instance of WbMainWindow for which the event is
  1534. // intended.
  1535. //
  1536. //
  1537. BOOL CALLBACK WbMainWindowEventHandler
  1538. (
  1539. LPVOID utHandle,
  1540. UINT event,
  1541. UINT_PTR param1,
  1542. UINT_PTR param2
  1543. )
  1544. {
  1545. if (g_pMain->m_hwnd != NULL)
  1546. {
  1547. return(g_pMain->EventHandler(event, param1, param2));
  1548. }
  1549. else
  1550. {
  1551. return(FALSE);
  1552. }
  1553. }
  1554. //
  1555. //
  1556. // Function: EventHandler
  1557. //
  1558. // Purpose: Handler for DC-Groupware events for this object
  1559. //
  1560. //
  1561. BOOL WbMainWindow::EventHandler(UINT Event, UINT_PTR param1, UINT_PTR param2)
  1562. {
  1563. BOOL processed;
  1564. switch (Event)
  1565. {
  1566. case CMS_NEW_CALL:
  1567. case CMS_END_CALL:
  1568. case ALS_LOCAL_LOAD:
  1569. case ALS_REMOTE_LOAD_RESULT:
  1570. case WBP_EVENT_JOIN_CALL_OK:
  1571. case WBP_EVENT_JOIN_CALL_FAILED:
  1572. case WBP_EVENT_NETWORK_LOST:
  1573. case WBP_EVENT_ERROR:
  1574. case WBP_EVENT_PAGE_CLEAR_IND:
  1575. case WBP_EVENT_PAGE_ORDER_UPDATED:
  1576. case WBP_EVENT_PAGE_DELETE_IND:
  1577. case WBP_EVENT_CONTENTS_LOCKED:
  1578. case WBP_EVENT_PAGE_ORDER_LOCKED:
  1579. case WBP_EVENT_UNLOCKED:
  1580. case WBP_EVENT_LOCK_FAILED:
  1581. case WBP_EVENT_GRAPHIC_ADDED:
  1582. case WBP_EVENT_GRAPHIC_MOVED:
  1583. case WBP_EVENT_GRAPHIC_UPDATE_IND:
  1584. case WBP_EVENT_GRAPHIC_REPLACE_IND:
  1585. case WBP_EVENT_GRAPHIC_DELETE_IND:
  1586. case WBP_EVENT_PERSON_JOINED:
  1587. case WBP_EVENT_PERSON_LEFT:
  1588. case WBP_EVENT_PERSON_UPDATE:
  1589. case WBP_EVENT_PERSON_REPLACE:
  1590. case WBP_EVENT_SYNC_POSITION_UPDATED:
  1591. case WBP_EVENT_LOAD_COMPLETE:
  1592. case WBP_EVENT_LOAD_FAILED:
  1593. // Process the Event
  1594. ProcessEvents(Event, param1, param2);
  1595. processed = TRUE;
  1596. break;
  1597. default:
  1598. processed = FALSE;
  1599. break;
  1600. }
  1601. return(processed);
  1602. }
  1603. //
  1604. //
  1605. // Function: PopupContextMenu
  1606. //
  1607. // Purpose: Popup the context menu for the drawing area. This is called
  1608. // by the drawing area window on a right mouse click.
  1609. //
  1610. //
  1611. void WbMainWindow::PopupContextMenu(int x, int y)
  1612. {
  1613. POINT surfacePos;
  1614. RECT clientRect;
  1615. DCWbGraphic * pGraphic;
  1616. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::PopupContextMenu");
  1617. surfacePos.x = x;
  1618. surfacePos.y = y;
  1619. // figure out which popup menu to use (bug 426)
  1620. if (m_pCurrentTool->ToolType() == TOOLTYPE_SELECT)
  1621. {
  1622. m_drawingArea.ClientToSurface(&surfacePos);
  1623. if( (pGraphic = m_drawingArea.GetHitObject( surfacePos )) != NULL )
  1624. {
  1625. // we clicked over an object, see if its already selected
  1626. if( !m_drawingArea.IsSelected( pGraphic ) )
  1627. {
  1628. // object is not already selected, zap current selection and then select it
  1629. m_drawingArea.ClearSelection();
  1630. m_drawingArea.SelectGraphic( pGraphic );
  1631. }
  1632. else
  1633. {
  1634. // plug leak by deleteing pGraphic
  1635. delete pGraphic;
  1636. }
  1637. }
  1638. if( m_drawingArea.GraphicSelected() )
  1639. {
  1640. // selector tool is active, and one or more objects are selected
  1641. m_hInitMenu = m_hGrobjContextMenu;
  1642. }
  1643. else
  1644. {
  1645. // no current selection, show drawing menu
  1646. m_hInitMenu = m_hContextMenu;
  1647. }
  1648. }
  1649. else
  1650. {
  1651. // no objects selected, use drawing menu
  1652. m_hInitMenu = m_hContextMenu;
  1653. }
  1654. // set up current menu state
  1655. SetMenuStates(m_hInitMenu);
  1656. // pop it up
  1657. ::GetClientRect(m_drawingArea.m_hwnd, &clientRect);
  1658. ::MapWindowPoints(m_drawingArea.m_hwnd, NULL, (LPPOINT)&clientRect.left, 2);
  1659. ::TrackPopupMenu(m_hInitMenu, TPM_RIGHTALIGN | TPM_RIGHTBUTTON,
  1660. x + clientRect.left,
  1661. y + clientRect.top,
  1662. 0,
  1663. m_hwnd,
  1664. NULL);
  1665. // reset m_hInitMenu to indicate the popup menu isn't being shown anymore
  1666. m_hInitMenu = NULL;
  1667. }
  1668. //
  1669. //
  1670. // Function: ProcessEvents
  1671. //
  1672. // Purpose: Process events that have been queued internally
  1673. //
  1674. //
  1675. void WbMainWindow::ProcessEvents(UINT Event, UINT_PTR param1, UINT_PTR param2)
  1676. {
  1677. HWND hwndLastPopup;
  1678. TRACE_EVENT(("WbMainWindow::ProcessEvents"));
  1679. //
  1680. // If we are closing, ignore it.
  1681. //
  1682. if (m_uiState == CLOSING)
  1683. {
  1684. TRACE_EVENT(("ProcessEvents: ignored because WB is closing"));
  1685. return;
  1686. }
  1687. //
  1688. // If we are busy drawing, we postpone it until later when we can
  1689. // handle it.
  1690. //
  1691. // If the page sorter dialog is up, it gets notified by the appropriate
  1692. // event handler after the fact.
  1693. //
  1694. if (m_drawingArea.IsBusy())
  1695. {
  1696. TRACE_EVENT(("Reposting event %x, param1 %d param2 %d", Event, param1, param2));
  1697. g_pwbCore->WBP_PostEvent(200, Event, param1, param2);
  1698. return;
  1699. }
  1700. TRACE_EVENT(("Event %x, m_uiState %d", Event, m_uiState));
  1701. //
  1702. // Process according to the event type.
  1703. //
  1704. switch (Event)
  1705. {
  1706. case CMS_NEW_CALL:
  1707. OnCMSNewCall((BOOL)param1, (DWORD)param2);
  1708. break;
  1709. case CMS_END_CALL:
  1710. OnCMSEndCall();
  1711. break;
  1712. case ALS_LOCAL_LOAD:
  1713. switch (m_uiState)
  1714. {
  1715. case IN_CALL:
  1716. case ERROR_STATE:
  1717. // show the main window normal/minimized as necessary
  1718. hwndLastPopup = ::GetLastActivePopup(m_hwnd);
  1719. if (::IsIconic(m_hwnd))
  1720. ::ShowWindow(m_hwnd, SW_RESTORE);
  1721. else
  1722. ::ShowWindow(m_hwnd, SW_SHOW);
  1723. ::SetForegroundWindow(hwndLastPopup);
  1724. if (param2)
  1725. {
  1726. if (m_uiState == IN_CALL)
  1727. LoadCmdLine((LPCSTR)param2);
  1728. ::GlobalFree((HGLOBAL)param2);
  1729. }
  1730. break;
  1731. default:
  1732. TRACE_MSG(("Joining a call so try load later",
  1733. (LPCTSTR)param2));
  1734. g_pwbCore->WBP_PostEvent(400, Event, param1, param2);
  1735. break;
  1736. }
  1737. break;
  1738. case ALS_REMOTE_LOAD_RESULT:
  1739. OnALSLoadResult((UINT)param1);
  1740. break;
  1741. case WBP_EVENT_JOIN_CALL_OK:
  1742. OnWBPJoinCallOK();
  1743. break;
  1744. case WBP_EVENT_JOIN_CALL_FAILED:
  1745. OnWBPJoinCallFailed();
  1746. break;
  1747. case WBP_EVENT_NETWORK_LOST:
  1748. OnWBPNetworkLost();
  1749. break;
  1750. case WBP_EVENT_ERROR:
  1751. OnWBPError();
  1752. break;
  1753. case WBP_EVENT_PAGE_CLEAR_IND:
  1754. OnWBPPageClearInd((WB_PAGE_HANDLE) param1);
  1755. break;
  1756. case WBP_EVENT_PAGE_ORDER_UPDATED:
  1757. OnWBPPageOrderUpdated();
  1758. break;
  1759. case WBP_EVENT_PAGE_DELETE_IND:
  1760. OnWBPPageDeleteInd((WB_PAGE_HANDLE) param1);
  1761. break;
  1762. case WBP_EVENT_CONTENTS_LOCKED:
  1763. OnWBPContentsLocked((POM_OBJECT) param2);
  1764. break;
  1765. case WBP_EVENT_PAGE_ORDER_LOCKED:
  1766. OnWBPPageOrderLocked((POM_OBJECT) param2);
  1767. break;
  1768. case WBP_EVENT_UNLOCKED:
  1769. OnWBPUnlocked((POM_OBJECT) param2);
  1770. break;
  1771. case WBP_EVENT_LOCK_FAILED:
  1772. OnWBPLockFailed();
  1773. break;
  1774. case WBP_EVENT_GRAPHIC_ADDED:
  1775. OnWBPGraphicAdded((WB_PAGE_HANDLE) param1, (WB_GRAPHIC_HANDLE) param2);
  1776. break;
  1777. case WBP_EVENT_GRAPHIC_MOVED:
  1778. OnWBPGraphicMoved((WB_PAGE_HANDLE) param1, (WB_GRAPHIC_HANDLE) param2);
  1779. break;
  1780. case WBP_EVENT_GRAPHIC_UPDATE_IND:
  1781. OnWBPGraphicUpdateInd((WB_PAGE_HANDLE) param1, (WB_GRAPHIC_HANDLE) param2);
  1782. break;
  1783. case WBP_EVENT_GRAPHIC_REPLACE_IND:
  1784. OnWBPGraphicReplaceInd((WB_PAGE_HANDLE) param1, (WB_GRAPHIC_HANDLE) param2);
  1785. break;
  1786. case WBP_EVENT_GRAPHIC_DELETE_IND:
  1787. OnWBPGraphicDeleteInd((WB_PAGE_HANDLE) param1, (WB_GRAPHIC_HANDLE) param2);
  1788. break;
  1789. case WBP_EVENT_PERSON_JOINED:
  1790. OnWBPUserJoined((POM_OBJECT) param2);
  1791. break;
  1792. case WBP_EVENT_PERSON_LEFT:
  1793. OnWBPUserLeftInd((POM_OBJECT) param2);
  1794. break;
  1795. case WBP_EVENT_PERSON_UPDATE:
  1796. OnWBPUserUpdateInd((POM_OBJECT) param2, FALSE);
  1797. break;
  1798. case WBP_EVENT_PERSON_REPLACE:
  1799. OnWBPUserUpdateInd((POM_OBJECT) param2, TRUE);
  1800. break;
  1801. case WBP_EVENT_SYNC_POSITION_UPDATED:
  1802. OnWBPSyncPositionUpdated();
  1803. break;
  1804. case WBP_EVENT_LOAD_COMPLETE:
  1805. OnWBPLoadComplete();
  1806. break;
  1807. case WBP_EVENT_LOAD_FAILED:
  1808. OnWBPLoadFailed();
  1809. break;
  1810. default:
  1811. WARNING_OUT(("Unrecognized event %x", Event));
  1812. break;
  1813. }
  1814. }
  1815. //
  1816. //
  1817. // Function: OnCMSNewCall
  1818. //
  1819. // Purpose: Handler for CMS_NEW_CALL
  1820. //
  1821. //
  1822. void WbMainWindow::OnCMSNewCall(BOOL fTopProvider, DWORD _m_dwDomain)
  1823. {
  1824. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnCMSNewCall");
  1825. //
  1826. // If we created the call
  1827. //
  1828. if (fTopProvider)
  1829. {
  1830. // Join the call, keep existing contents
  1831. if (m_uiState == IN_CALL)
  1832. {
  1833. //
  1834. // Join the call but keep any existing messages.
  1835. //
  1836. ::PostMessage(m_hwnd, WM_USER_JOIN_CALL, 1, (LONG) _m_dwDomain);
  1837. }
  1838. else
  1839. {
  1840. m_bJoinCallPending = TRUE;
  1841. m_dwPendingDomain = _m_dwDomain;
  1842. m_bPendingCallKeepContents = TRUE;
  1843. }
  1844. }
  1845. else
  1846. {
  1847. CM_STATUS status;
  1848. CMS_GetStatus(&status);
  1849. if (!(status.attendeePermissions & NM_PERMIT_USEOLDWBATALL))
  1850. {
  1851. WARNING_OUT(("OLD WB: not joining call, not permitted"));
  1852. return;
  1853. }
  1854. if (m_uiState == IN_CALL)
  1855. {
  1856. //
  1857. // Join the call, throwing away our current contents (after
  1858. // prompting the user to save them first).
  1859. //
  1860. ::PostMessage(m_hwnd, WM_USER_JOIN_CALL, 0, (LONG) _m_dwDomain);
  1861. }
  1862. else
  1863. {
  1864. m_bJoinCallPending = TRUE;
  1865. m_dwPendingDomain = _m_dwDomain;
  1866. m_bPendingCallKeepContents = FALSE;
  1867. }
  1868. }
  1869. //
  1870. // Get the call status correct.
  1871. //
  1872. m_bCallActive = TRUE;
  1873. UpdateWindowTitle();
  1874. }
  1875. //
  1876. //
  1877. // Function: OnJoinPendingCall
  1878. //
  1879. // Purpose: Handler for WM_USER_JOIN_PENDING_CALL
  1880. //
  1881. //
  1882. void WbMainWindow::OnJoinPendingCall(void)
  1883. {
  1884. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnJoinPendingCall");
  1885. //
  1886. // If there's still a pending call (haven't received an end-call message
  1887. // between posting the WM_USER_JOIN_PENDING_CALL and getting here).
  1888. //
  1889. if (m_bJoinCallPending)
  1890. {
  1891. //
  1892. // Post a message to join the call
  1893. //
  1894. ::PostMessage(m_hwnd, WM_USER_JOIN_CALL,
  1895. m_bPendingCallKeepContents,
  1896. (LONG) m_dwPendingDomain);
  1897. // cancel call-pending status
  1898. m_bJoinCallPending = FALSE;
  1899. }
  1900. }
  1901. //
  1902. //
  1903. // Function: OnCMSEndCall
  1904. //
  1905. // Purpose: Handler for CMS_END_CALL
  1906. //
  1907. //
  1908. void WbMainWindow::OnCMSEndCall(void)
  1909. {
  1910. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnCMSEndCall");
  1911. //
  1912. // Flag to cancel any current join-call processing, and destroy any
  1913. // associated dialogs.
  1914. //
  1915. if (m_bPromptingJoinCall)
  1916. {
  1917. m_bPromptingJoinCall = FALSE;
  1918. if (m_hwndQuerySaveDlg != NULL)
  1919. {
  1920. ::SendMessage(m_hwndQuerySaveDlg, WM_COMMAND,
  1921. MAKELONG(IDCANCEL, BN_CLICKED), 0);
  1922. ASSERT(m_hwndQuerySaveDlg == NULL);
  1923. }
  1924. }
  1925. //
  1926. // Show that we are no longer in a call
  1927. //
  1928. m_dwDomain = OM_NO_CALL;
  1929. //
  1930. // If currently in the process of joining a call, then set the domain
  1931. // we're joining to NO_CALL and join the local (singleton) domain.
  1932. // Get the call status correct.
  1933. //
  1934. m_bCallActive = FALSE;
  1935. TRACE_MSG(("m_uiState %d", m_uiState));
  1936. m_dwDomain = OM_NO_CALL;
  1937. //
  1938. // Show there is no call pending
  1939. //
  1940. m_bJoinCallPending = FALSE;
  1941. //
  1942. // Update the window title with "not in call"
  1943. //
  1944. UpdateWindowTitle();
  1945. }
  1946. //
  1947. //
  1948. // Function: OnWBPJoinCallOK
  1949. //
  1950. // Purpose: Handler for WBP_EVENT_JOIN_CALL_OK
  1951. //
  1952. //
  1953. void WbMainWindow::OnWBPJoinCallOK(void)
  1954. {
  1955. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPJoinCallOK");
  1956. //
  1957. // Record that we have joined the call, but the drawing area is not yet
  1958. // ready for input (because we have not yet attached to a page).
  1959. //
  1960. m_uiState = JOINED;
  1961. //
  1962. // Get the local user
  1963. //
  1964. m_pLocalUser = WB_LocalUser();
  1965. if (!m_pLocalUser)
  1966. {
  1967. ERROR_OUT(("Can't join call; can't create local user object, m_pLocalUser!"));
  1968. m_uiState = ERROR_STATE;
  1969. }
  1970. else
  1971. {
  1972. //
  1973. // Get the first user in the call
  1974. //
  1975. WbUser* pUser = WB_GetFirstUser();
  1976. //
  1977. // Loop through all available users
  1978. //
  1979. while (pUser != NULL)
  1980. {
  1981. //
  1982. // Make updates necessary for a user joining
  1983. //
  1984. UserJoined(pUser);
  1985. //
  1986. // Get the next user
  1987. //
  1988. pUser = WB_GetNextUser(pUser);
  1989. }
  1990. //
  1991. // If the registration dialog is up - cancel it
  1992. //
  1993. m_uiState = IN_CALL; // have to set m_uiState before zapping
  1994. // m_hwndWaitForEventDlg or it will
  1995. // think the call failed now (the
  1996. // delay has been removed from
  1997. // EndDialogDelayed() (bug 3881)
  1998. }
  1999. if (m_hwndWaitForEventDlg != NULL)
  2000. {
  2001. TRACE_MSG(("Joined call OK - end dialog"));
  2002. ::SendMessage(m_hwndWaitForEventDlg, WM_COMMAND, MAKELONG(IDOK, BN_CLICKED), 0);
  2003. ASSERT(m_hwndWaitForEventDlg == NULL);
  2004. }
  2005. if (!m_pLocalUser)
  2006. {
  2007. //
  2008. // BAIL out, we can't join the call
  2009. return;
  2010. }
  2011. //
  2012. // Now complete the join call processing
  2013. //
  2014. TRACE_MSG(("Successfully joined the call"));
  2015. m_dwDomain = m_dwJoinDomain;
  2016. //
  2017. // If we have never attached to a page before (ie at start up), attach
  2018. // to the first available page in the drawing area. If we are joining
  2019. // a call then we reattach to the current page
  2020. //
  2021. if (m_hCurrentPage == WB_PAGE_HANDLE_NULL)
  2022. {
  2023. TRACE_MSG(("Attach to first page"));
  2024. g_pwbCore->WBP_PageHandle(WB_PAGE_HANDLE_NULL, PAGE_FIRST, &m_hCurrentPage);
  2025. }
  2026. else
  2027. {
  2028. TRACE_DEBUG(("Just joined new call, reattach to the current page."));
  2029. }
  2030. m_drawingArea.Attach(m_hCurrentPage);
  2031. // Display the initial status
  2032. UpdateStatus();
  2033. ::SetTimer(m_hwnd, TIMERID_PROGRESS_METER, MAIN_PROGRESS_TIMER, NULL);
  2034. m_bTimerActive = TRUE;
  2035. //
  2036. // Unlock the drawing area, allowing user updates (unless its already
  2037. // locked by someone else)
  2038. //
  2039. if (!WB_ContentsLocked())
  2040. {
  2041. UnlockDrawingArea();
  2042. }
  2043. // Set the substate (also updates page buttons)
  2044. SetSubstate(SUBSTATE_IDLE);
  2045. //
  2046. // If we aren't synced, then sync now.
  2047. // Set the window title to show we're no longer registering/joining a
  2048. // call
  2049. //
  2050. Sync();
  2051. UpdateWindowTitle();
  2052. //
  2053. // If we were joining the local domain, and a join call message arrived
  2054. // in the meantime, then join that call now.
  2055. //
  2056. if ((m_bJoinCallPending) && (m_dwJoinDomain == OM_NO_CALL))
  2057. {
  2058. ::PostMessage(m_hwnd, WM_USER_JOIN_PENDING_CALL, 0, 0L);
  2059. }
  2060. }
  2061. //
  2062. //
  2063. // Function: OnWBPJoinCallFailed
  2064. //
  2065. // Purpose: Handler for WBP_EVENT_JOIN_CALL_FAILED
  2066. //
  2067. //
  2068. void WbMainWindow::OnWBPJoinCallFailed(void)
  2069. {
  2070. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPJoinCallFailed");
  2071. //
  2072. // If we have just failed to join a new call (not a single domain) it
  2073. // may be because the call ended before we had time to join it
  2074. // completely - try joining the single domain.
  2075. //
  2076. if ((m_uiState == STARTING) && (m_dwJoinDomain != OM_NO_CALL))
  2077. {
  2078. WARNING_OUT(("Failed to join call on startup, try local domain"));
  2079. m_dwJoinDomain = OM_NO_CALL;
  2080. m_bCallActive = FALSE;
  2081. JoinCall(FALSE);
  2082. }
  2083. else
  2084. {
  2085. //
  2086. // Tell the registration dialog to finish
  2087. //
  2088. if (m_hwndWaitForEventDlg != NULL)
  2089. {
  2090. WARNING_OUT(("Failed to join call - end dialog"));
  2091. ::SendMessage(m_hwndWaitForEventDlg, WM_COMMAND, MAKELONG(IDOK, BN_CLICKED), 0);
  2092. ASSERT(m_hwndWaitForEventDlg == NULL);
  2093. }
  2094. m_uiState = ERROR_STATE;
  2095. }
  2096. }
  2097. //
  2098. //
  2099. // Function: OnWBPNetworkLost
  2100. //
  2101. // Purpose: Handler for WBP_EVENT_NETWORK_LOST
  2102. //
  2103. //
  2104. void WbMainWindow::OnWBPNetworkLost(void)
  2105. {
  2106. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPNetworkLost");
  2107. //
  2108. // We have lost contact with the other people in the call.
  2109. // Treat as if we got an end call (we should get an end call too, but
  2110. // other intervening events might occur (such as trying to join a
  2111. // call).
  2112. //
  2113. OnCMSEndCall();
  2114. }
  2115. //
  2116. //
  2117. // Function: OnWBPError
  2118. //
  2119. // Purpose: Handler for WBP_EVENT_ERROR
  2120. //
  2121. //
  2122. void WbMainWindow::OnWBPError(void)
  2123. {
  2124. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPError");
  2125. // Inform the user of the error.
  2126. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, 0);
  2127. }
  2128. //
  2129. //
  2130. // Function: OnWBPPageClearInd
  2131. //
  2132. // Purpose: Handler for WBP_EVENT_PAGE_CLEAR_IND
  2133. //
  2134. //
  2135. void WbMainWindow::OnWBPPageClearInd(WB_PAGE_HANDLE hPage)
  2136. {
  2137. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPPageClearInd");
  2138. // Confirm the clearing of the page. This is OK even if the page being
  2139. // cleared is the current page because we already know that the drawing
  2140. // area is not busy (otherwise we would not be here).
  2141. // If there's an object on the page which has been copied to the
  2142. // clipboard with delayed rendering, then save it
  2143. if (CLP_LastCopiedPage() == hPage)
  2144. {
  2145. CLP_SaveDelayedGraphic();
  2146. }
  2147. // If it is the current page being cleared
  2148. if (m_hCurrentPage == hPage)
  2149. {
  2150. m_drawingArea.PageCleared();
  2151. }
  2152. // If there is a last deleted graphic
  2153. // and it belongs to the page being cleared.
  2154. if ((m_LastDeletedGraphic.GotTrash()) &&
  2155. (m_LastDeletedGraphic.Page() == hPage))
  2156. {
  2157. // Free the last deleted graphic
  2158. m_LastDeletedGraphic.BurnTrash();
  2159. }
  2160. g_pwbCore->WBP_PageClearConfirm(hPage);
  2161. //
  2162. // Notify the page sorter AFTER the page has been cleared
  2163. //
  2164. if (m_hwndPageSortDlg != NULL)
  2165. {
  2166. ::SendMessage(m_hwndPageSortDlg, WM_PS_PAGECLEARIND, (WPARAM)hPage, 0);
  2167. }
  2168. }
  2169. //
  2170. //
  2171. // Function: OnWBPPageOrderUpdated
  2172. //
  2173. // Purpose: Handler for WBP_EVENT_PAGE_ORDER_UPDATED
  2174. //
  2175. //
  2176. void WbMainWindow::OnWBPPageOrderUpdated(void)
  2177. {
  2178. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPPageOrderUpdated");
  2179. m_drawingArea.CancelDrawingMode();
  2180. // The page order has changed, we just need to update the number of the
  2181. // current page in the pages group.
  2182. UpdateStatus();
  2183. //
  2184. // Notify the page sorter AFTER the page order has been updated
  2185. //
  2186. if (m_hwndPageSortDlg != NULL)
  2187. {
  2188. ::SendMessage(m_hwndPageSortDlg, WM_PS_PAGEORDERUPD, 0, 0);
  2189. }
  2190. }
  2191. //
  2192. //
  2193. // Function: OnWBPPageDeleteInd
  2194. //
  2195. // Purpose: Handler for WBP_EVENT_PAGE_DELETE_IND
  2196. //
  2197. //
  2198. void WbMainWindow::OnWBPPageDeleteInd(WB_PAGE_HANDLE hPage)
  2199. {
  2200. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPPageDeleteInd");
  2201. //
  2202. // Notify the page sorter BEFORE the page is deleted
  2203. //
  2204. if (m_hwndPageSortDlg != NULL)
  2205. {
  2206. ::SendMessage(m_hwndPageSortDlg, WM_PS_PAGEDELIND, (WPARAM)hPage, 0);
  2207. }
  2208. m_drawingArea.CancelDrawingMode();
  2209. // Remove it from the page-position map
  2210. PAGE_POSITION *mapob;
  2211. POSITION savedPos;
  2212. POSITION position = m_pageToPosition.GetHeadPosition();
  2213. BOOL bFound = FALSE;
  2214. while (position && !bFound)
  2215. {
  2216. savedPos = position;
  2217. mapob = (PAGE_POSITION *)m_pageToPosition.GetNext(position);
  2218. if ( mapob->hPage == hPage)
  2219. {
  2220. bFound = TRUE;
  2221. }
  2222. }
  2223. if(bFound)
  2224. {
  2225. m_pageToPosition.RemoveAt(savedPos);
  2226. delete mapob;
  2227. }
  2228. // A page has been deleted. If it is the current page we must attach
  2229. // a different page to the drawing area. In any case we should confirm
  2230. // the delete.
  2231. // If there's an object on the page which has been copied to the
  2232. // clipboard with delayed rendering, then save it
  2233. if (CLP_LastCopiedPage() == hPage)
  2234. {
  2235. CLP_SaveDelayedGraphic();
  2236. }
  2237. if (hPage == m_hCurrentPage)
  2238. {
  2239. // Check whether we are deleting the last page
  2240. WB_PAGE_HANDLE hNewPage;
  2241. g_pwbCore->WBP_PageHandle(WB_PAGE_HANDLE_NULL, PAGE_LAST, &hNewPage);
  2242. if (hNewPage == hPage)
  2243. {
  2244. // We are deleting the last page, so go back one
  2245. hNewPage = PG_GetPreviousPage(hPage);
  2246. }
  2247. else
  2248. {
  2249. // We are not deleting the last page, so go forward one
  2250. hNewPage = PG_GetNextPage(hPage);
  2251. }
  2252. // Check that we got a different page to the one being deleted
  2253. ASSERT(hNewPage != hPage);
  2254. // Lock the drawing area - this ensures we are no longer editing
  2255. // any text etc.
  2256. LockDrawingArea();
  2257. // Move to the new page
  2258. GotoPage(hNewPage);
  2259. // Unlock the drawing area (unless we're doing a new, in which case we
  2260. // leave it locked - it will become unlocked when the new completes)
  2261. if ( (!WB_ContentsLocked())
  2262. && (m_uiState == IN_CALL)
  2263. && (m_uiSubState != SUBSTATE_NEW_IN_PROGRESS))
  2264. {
  2265. UnlockDrawingArea();
  2266. }
  2267. }
  2268. // If there is a last deleted graphic
  2269. if ((m_LastDeletedGraphic.GotTrash()) &&
  2270. (m_LastDeletedGraphic.Page() == hPage))
  2271. {
  2272. // Free the last deleted graphic
  2273. m_LastDeletedGraphic.BurnTrash();
  2274. }
  2275. // if the remote pointer is on the deleted page then turn it off
  2276. ASSERT(m_pLocalUser);
  2277. DCWbGraphicPointer* pPointer = m_pLocalUser->GetPointer();
  2278. if ( (pPointer->IsActive())
  2279. && (pPointer->Page() == hPage))
  2280. {
  2281. OnRemotePointer();
  2282. }
  2283. // Let the core delete the page
  2284. g_pwbCore->WBP_PageDeleteConfirm(hPage);
  2285. // if this is last page to be deleted, then the file/new is complete
  2286. if ((m_uiSubState == SUBSTATE_NEW_IN_PROGRESS)
  2287. && (g_pwbCore->WBP_ContentsCountPages() == 1))
  2288. {
  2289. SetSubstate(SUBSTATE_IDLE);
  2290. ReleasePageOrderLock();
  2291. if (!WB_ContentsLocked())
  2292. {
  2293. UnlockDrawingArea();
  2294. }
  2295. }
  2296. // Update the status (there is a new number of pages)
  2297. UpdateStatus();
  2298. }
  2299. //
  2300. //
  2301. // Function: OnWBPContentsLocked
  2302. //
  2303. // Purpose: Handler for WBP_EVENT_CONTENTS_LOCKED
  2304. //
  2305. //
  2306. void WbMainWindow::OnWBPContentsLocked(POM_OBJECT hUser)
  2307. {
  2308. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPContentsLocked");
  2309. //
  2310. // Notify page sorter dialog that the lock status has changed
  2311. //
  2312. if (m_hwndPageSortDlg != NULL)
  2313. {
  2314. ::SendMessage(m_hwndPageSortDlg, WM_PS_LOCKCHANGE, 0, 0);
  2315. }
  2316. if (m_uiState != IN_CALL)
  2317. {
  2318. TRACE_MSG(("Lock indication received out of call - ignored"));
  2319. }
  2320. else
  2321. {
  2322. ASSERT(m_pLocalUser);
  2323. if (m_pLocalUser->Handle() == hUser)
  2324. {
  2325. // We have acquired the lock
  2326. // Set the locked check mark
  2327. CheckMenuItem(IDM_LOCK);
  2328. // Tell the tool bar of the new selection
  2329. m_TB.PushDown(IDM_LOCK);
  2330. }
  2331. else
  2332. {
  2333. //
  2334. // A remote user has acquired the lock:
  2335. // If we're not synced, then sync now.
  2336. //
  2337. Sync();
  2338. // Tell the drawing area it is now locked
  2339. LockDrawingArea();
  2340. // ensure the page button enable/disable state is correct
  2341. UpdatePageButtons();
  2342. }
  2343. }
  2344. //
  2345. // If the lock dialog is up - cancel it.
  2346. //
  2347. if (m_hwndWaitForLockDlg != NULL)
  2348. {
  2349. ::SendMessage(m_hwndWaitForLockDlg, WM_COMMAND, MAKELONG(IDOK, BN_CLICKED), 0);
  2350. ASSERT(m_hwndWaitForLockDlg == NULL);
  2351. }
  2352. }
  2353. //
  2354. //
  2355. // Function: OnWBPPageOrderLocked
  2356. //
  2357. // Purpose: Handler for WBP_EVENT_PAGE_ORDER_LOCKED
  2358. //
  2359. //
  2360. void WbMainWindow::OnWBPPageOrderLocked(POM_OBJECT)
  2361. {
  2362. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPPageOrderLocked");
  2363. // If the lock dialog is up - cancel it
  2364. if (m_hwndWaitForLockDlg != NULL)
  2365. {
  2366. ::SendMessage(m_hwndWaitForLockDlg, WM_COMMAND, MAKELONG(IDOK, BN_CLICKED), 0);
  2367. ASSERT(m_hwndWaitForLockDlg == NULL);
  2368. }
  2369. // Update the page sorter
  2370. if (m_hwndPageSortDlg != NULL)
  2371. {
  2372. ::SendMessage(m_hwndPageSortDlg, WM_PS_LOCKCHANGE, 0, 0);
  2373. }
  2374. if (!WB_GotLock())
  2375. {
  2376. EnableToolbar( FALSE );
  2377. UpdatePageButtons();
  2378. }
  2379. }
  2380. //
  2381. //
  2382. // Function: OnWBPUnlocked
  2383. //
  2384. // Purpose: Handler for WBP_EVENT_UNLOCKED
  2385. //
  2386. //
  2387. void WbMainWindow::OnWBPUnlocked(POM_OBJECT hUser)
  2388. {
  2389. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPUnlocked");
  2390. // Update the page sorter if it's around
  2391. if (m_hwndPageSortDlg != NULL)
  2392. {
  2393. ::SendMessage(m_hwndPageSortDlg, WM_PS_LOCKCHANGE, 0, 0);
  2394. }
  2395. // Uncheck the lock menu item
  2396. UncheckMenuItem(IDM_LOCK);
  2397. // Tell the tool bar of the change
  2398. m_TB.PopUp(IDM_LOCK);
  2399. // If a remote user is releasing the lock, and we're in a state where
  2400. // it's safe to unlock the drawing area...
  2401. if ((m_pLocalUser != NULL) &&
  2402. (m_pLocalUser->Handle() != hUser) &&
  2403. (m_uiState == IN_CALL))
  2404. {
  2405. // Tell the drawing area it is no longer locked
  2406. UnlockDrawingArea();
  2407. }
  2408. // ensure the page button enable/disable state is correct
  2409. UpdatePageButtons();
  2410. m_bUnlockStateSettled = TRUE; //Allow page operations now
  2411. }
  2412. //
  2413. //
  2414. // Function: OnWBPLockFailed
  2415. //
  2416. // Purpose: Handler for WBP_EVENT_LOCK_FAILED
  2417. //
  2418. //
  2419. void WbMainWindow::OnWBPLockFailed(void)
  2420. {
  2421. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPLockFailed");
  2422. // If the lock dialog is up - kill it
  2423. if (m_hwndWaitForLockDlg != NULL)
  2424. {
  2425. ::SendMessage(m_hwndWaitForLockDlg, WM_COMMAND, MAKELONG(IDOK, BN_CLICKED), 0);
  2426. ASSERT(m_hwndWaitForLockDlg == NULL);
  2427. }
  2428. }
  2429. //
  2430. //
  2431. // Function: OnWBPGraphicAdded
  2432. //
  2433. // Purpose: Handler for WBP_EVENT_GRAPHIC_ADDED
  2434. //
  2435. //
  2436. void WbMainWindow::OnWBPGraphicAdded
  2437. (
  2438. WB_PAGE_HANDLE hPage,
  2439. WB_GRAPHIC_HANDLE hGraphic
  2440. )
  2441. {
  2442. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPGraphicAdded");
  2443. // We only need to take action if the page to which the graphic has
  2444. // been added is the current page.
  2445. if (hPage == m_hCurrentPage && (!(hGraphic->flags & DELETED)))
  2446. {
  2447. // Retrieve the graphic that has been added
  2448. DCWbGraphic* pGraphic = DCWbGraphic::ConstructGraphic(hPage, hGraphic);
  2449. // Tell the drawing area of the new graphic
  2450. m_drawingArea.GraphicAdded(pGraphic);
  2451. // Free the graphic
  2452. delete pGraphic;
  2453. }
  2454. }
  2455. //
  2456. //
  2457. // Function: OnWBPGraphicMoved
  2458. //
  2459. // Purpose: Handler for WBP_EVENT_GRAPHIC_MOVED
  2460. //
  2461. //
  2462. void WbMainWindow::OnWBPGraphicMoved
  2463. (
  2464. WB_PAGE_HANDLE hPage,
  2465. WB_GRAPHIC_HANDLE hGraphic
  2466. )
  2467. {
  2468. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPGraphicMoved");
  2469. // We only need to take action if the graphic belongs to the current page
  2470. if (hPage == m_hCurrentPage && (!(hGraphic->flags & DELETED)))
  2471. {
  2472. // Retrieve the graphic that has been moved
  2473. DCWbGraphic* pGraphic = DCWbGraphic::ConstructGraphic(hPage, hGraphic);
  2474. if( NULL != pGraphic )
  2475. {
  2476. // Tell the drawing area of the new graphic
  2477. m_drawingArea.GraphicUpdated(pGraphic, TRUE, FALSE);
  2478. // set paint to draw only objects above this object inclusive
  2479. if (pGraphic->IsGraphicTool() == enumGraphicText)
  2480. {
  2481. m_drawingArea.SetStartPaintGraphic( NULL );
  2482. // this optimization screws up text
  2483. // so short it out if this is text
  2484. // (text draws transparently and background
  2485. // isn't repainted properly if this is active)
  2486. }
  2487. else
  2488. {
  2489. m_drawingArea.SetStartPaintGraphic( hGraphic );
  2490. // not text so optimize by drawing only this
  2491. // object and everthing above it
  2492. }
  2493. // Free the graphic
  2494. delete pGraphic;
  2495. }
  2496. }
  2497. }
  2498. //
  2499. //
  2500. // Function: OnWBPGraphicUpdateInd
  2501. //
  2502. // Purpose: Handler for WBP_EVENT_GRAPHIC_UPDATE_IND
  2503. //
  2504. //
  2505. void WbMainWindow::OnWBPGraphicUpdateInd
  2506. (
  2507. WB_PAGE_HANDLE hPage,
  2508. WB_GRAPHIC_HANDLE hGraphic
  2509. )
  2510. {
  2511. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPGraphicUpdateInd");
  2512. if(hGraphic->flags & DELETED)
  2513. {
  2514. return;
  2515. }
  2516. PWB_GRAPHIC pOldHeader;
  2517. PWB_GRAPHIC pOldHeaderCopy;
  2518. DCWbGraphic* pOldGraphic;
  2519. PWB_GRAPHIC pNewHeader;
  2520. DCWbGraphic* pNewGraphic;
  2521. if (hPage != m_hCurrentPage)
  2522. {
  2523. // nothing visual has changed, confirm and we're done
  2524. g_pwbCore->WBP_GraphicUpdateConfirm(hPage, hGraphic);
  2525. return;
  2526. }
  2527. // Retrieve the original graphic and make a copy
  2528. // Get the page of the update
  2529. pOldHeader = PG_GetData(hPage, hGraphic);
  2530. pOldHeaderCopy = (PWB_GRAPHIC) new BYTE[ pOldHeader->length ];
  2531. if( pOldHeaderCopy == NULL )
  2532. {
  2533. ERROR_OUT( ("Can't copy pOldHeader, can't update drawing") );
  2534. g_pwbCore->WBP_GraphicRelease(hPage, hGraphic, pOldHeader );
  2535. g_pwbCore->WBP_GraphicUpdateConfirm(hPage, hGraphic);
  2536. return;
  2537. }
  2538. CopyMemory( (PVOID)pOldHeaderCopy, (CONST VOID *)pOldHeader, pOldHeader->length );
  2539. // confirm and get the new one
  2540. g_pwbCore->WBP_GraphicRelease(hPage, hGraphic, pOldHeader );
  2541. g_pwbCore->WBP_GraphicUpdateConfirm(hPage, hGraphic);
  2542. pNewHeader = PG_GetData(hPage, hGraphic);
  2543. // This update might affect painting. See if old and new are visually different
  2544. if( HasGraphicChanged( pOldHeaderCopy, (const PWB_GRAPHIC)pNewHeader ) )
  2545. {
  2546. // they're different, invalidate/erase old graphic's bounding rect
  2547. pOldGraphic = DCWbGraphic::ConstructGraphic(hPage, hGraphic, pOldHeaderCopy );
  2548. m_drawingArea.GraphicUpdated( pOldGraphic, FALSE, TRUE );
  2549. // draw new graphic (don't need to erase)
  2550. pNewGraphic = DCWbGraphic::ConstructGraphic(hPage, hGraphic, pNewHeader );
  2551. g_pwbCore->WBP_GraphicRelease(hPage, hGraphic, pNewHeader );
  2552. m_drawingArea.GraphicUpdated( pNewGraphic, TRUE, FALSE );
  2553. // If the graphic is selected, ensure the attributes bar is up to date
  2554. if (m_drawingArea.GraphicSelected())
  2555. {
  2556. DCWbGraphic* pSelectedGraphic = m_drawingArea.GetSelection();
  2557. if ((pSelectedGraphic != NULL) &&
  2558. (pSelectedGraphic->Handle() == hGraphic))
  2559. {
  2560. m_pCurrentTool->SelectGraphic(pNewGraphic);
  2561. OnUpdateAttributes();
  2562. }
  2563. }
  2564. delete pOldGraphic;
  2565. delete pNewGraphic;
  2566. }
  2567. else
  2568. {
  2569. g_pwbCore->WBP_GraphicRelease(hPage, hGraphic, pNewHeader);
  2570. }
  2571. delete [] pOldHeaderCopy;
  2572. }
  2573. //
  2574. //
  2575. // Function: OnWBPGraphicReplaceInd
  2576. //
  2577. // Purpose: Handler for WBP_EVENT_GRAPHIC_REPLACE_IND
  2578. //
  2579. //
  2580. void WbMainWindow::OnWBPGraphicReplaceInd
  2581. (
  2582. WB_PAGE_HANDLE hPage,
  2583. WB_GRAPHIC_HANDLE hGraphic
  2584. )
  2585. {
  2586. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPGraphicReplaceInd");
  2587. if(hGraphic->flags & DELETED)
  2588. {
  2589. return;
  2590. }
  2591. // Retrieve the graphic that has been replaced
  2592. DCWbGraphic* pGraphic = DCWbGraphic::ConstructGraphic(hPage, hGraphic);
  2593. if (pGraphic->IsGraphicTool() == enumGraphicFreeHand)
  2594. {
  2595. // Confirm the replace - the graphic reads its new details
  2596. pGraphic->ReplaceConfirm();
  2597. // Only redraw the graphic if it is on the current page
  2598. if (hPage == m_hCurrentPage)
  2599. {
  2600. // Redraw the graphic
  2601. m_drawingArea.GraphicFreehandUpdated(pGraphic);
  2602. }
  2603. }
  2604. else
  2605. {
  2606. // We make two updates to the drawing area - one with the graphic in its
  2607. // current state and one after the update is confirmed. The first one
  2608. // invalidates the rectangle that the graphic now occupies. The second one
  2609. // invalidates the new rectangle. This ensures that the graphic is
  2610. // correctly redrawn.
  2611. // If the graphic is on the current page...
  2612. if (hPage == m_hCurrentPage)
  2613. {
  2614. // Update the drawing area for the old version of the graphic
  2615. m_drawingArea.GraphicUpdated(pGraphic, FALSE);
  2616. }
  2617. // Confirm the replace - the graphic reads its new details
  2618. pGraphic->ReplaceConfirm();
  2619. // If the graphic is on the current page...
  2620. if (hPage == m_hCurrentPage)
  2621. {
  2622. // Update the drawing area for the new version of the graphic
  2623. m_drawingArea.GraphicUpdated(pGraphic, TRUE);
  2624. }
  2625. }
  2626. // If the graphic is selected, ensure the attributes bar is up to date
  2627. if (m_drawingArea.GraphicSelected())
  2628. {
  2629. DCWbGraphic* pSelectedGraphic = m_drawingArea.GetSelection();
  2630. if ((pSelectedGraphic != NULL) &&
  2631. (pSelectedGraphic->Handle() == hGraphic))
  2632. {
  2633. m_pCurrentTool->SelectGraphic(pGraphic);
  2634. OnUpdateAttributes();
  2635. }
  2636. }
  2637. // Free the graphic
  2638. delete pGraphic;
  2639. }
  2640. //
  2641. //
  2642. // Function: OnWBPGraphicDeleteInd
  2643. //
  2644. // Purpose: Handler for WBP_EVENT_GRAPHIC_DELETE_IND
  2645. //
  2646. //
  2647. void WbMainWindow::OnWBPGraphicDeleteInd
  2648. (
  2649. WB_PAGE_HANDLE hPage,
  2650. WB_GRAPHIC_HANDLE hGraphic
  2651. )
  2652. {
  2653. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPGraphicDeleteInd");
  2654. // if the graphic was copied into the clipboard and was delayed,
  2655. // then save it in case we are asked to render it later
  2656. if ( (CLP_LastCopiedPage() == hPage)
  2657. && (CLP_LastCopiedGraphic() == hGraphic))
  2658. {
  2659. CLP_SaveDelayedGraphic();
  2660. }
  2661. // Retrieve the graphic that is to be deleted
  2662. DCWbGraphic* pGraphic = DCWbGraphic::ConstructGraphic(hPage, hGraphic);
  2663. // If the graphic is on the current page...
  2664. if (hPage == m_hCurrentPage)
  2665. {
  2666. // Update the drawing area
  2667. m_drawingArea.GraphicDeleted(pGraphic);
  2668. }
  2669. // Confirm the delete
  2670. g_pwbCore->WBP_GraphicDeleteConfirm(hPage, hGraphic);
  2671. // Free the graphic
  2672. delete pGraphic;
  2673. }
  2674. //
  2675. //
  2676. // Function: UserJoined
  2677. //
  2678. // Purpose: Make updates necessary for a new user joining the call
  2679. //
  2680. //
  2681. void WbMainWindow::UserJoined(WbUser* pUser)
  2682. {
  2683. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::UserJoined");
  2684. // Get the user's remote pointer
  2685. ASSERT(pUser);
  2686. DCWbGraphicPointer* pPointer = pUser->GetPointer();
  2687. // If the pointer is active and on the current page...
  2688. ASSERT(pPointer);
  2689. if ( (pPointer->IsActive())
  2690. && (pPointer->Page() == m_hCurrentPage))
  2691. {
  2692. // Update the drawing area
  2693. m_drawingArea.PointerUpdated(pPointer);
  2694. }
  2695. }
  2696. //
  2697. //
  2698. // Function: OnWBPUserJoined
  2699. //
  2700. // Purpose: Handler for WBP_EVENT_PERSON_JOINED
  2701. //
  2702. //
  2703. void WbMainWindow::OnWBPUserJoined(POM_OBJECT hUser)
  2704. {
  2705. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPUserJoined");
  2706. // Create a user object from the handle
  2707. WbUser* pUser = WB_GetUser(hUser);
  2708. if (!pUser)
  2709. {
  2710. WARNING_OUT(("Can't handle OnWBPUserJoined; can't create user object for 0x%08x", hUser));
  2711. }
  2712. else
  2713. {
  2714. // Make the necessary updates
  2715. UserJoined(pUser);
  2716. }
  2717. // Update the title bar to reflect the number of users. Do this here,
  2718. // rather than in UserJoined because we go through this function for
  2719. // remote users only, but through UserJoined for the local user too.
  2720. UpdateWindowTitle();
  2721. }
  2722. //
  2723. //
  2724. // Function: OnWBPUserLeftInd
  2725. //
  2726. // Purpose: Handler for WBP_EVENT_PERSON_LEFT
  2727. //
  2728. //
  2729. void WbMainWindow::OnWBPUserLeftInd(POM_OBJECT hUser)
  2730. {
  2731. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPUserLeft");
  2732. // Create a user object from the handle
  2733. WbUser* pUser = WB_GetUser(hUser);
  2734. if (!pUser)
  2735. {
  2736. WARNING_OUT(("Can't handle OnWBPUserLeftInd; can't get user object for 0x%08x", hUser));
  2737. }
  2738. else
  2739. {
  2740. // Get the user's remote pointer
  2741. DCWbGraphicPointer* pPointer = pUser->GetPointer();
  2742. ASSERT(pPointer);
  2743. // If the pointer is on the current page...
  2744. if (pPointer->Page() == m_hCurrentPage)
  2745. {
  2746. // Update the drawing area
  2747. m_drawingArea.PointerRemoved(pPointer);
  2748. }
  2749. }
  2750. // Confirm the update.
  2751. g_pwbCore->WBP_PersonLeftConfirm(hUser);
  2752. //
  2753. // Get this dude out of our list
  2754. //
  2755. if (pUser != NULL)
  2756. {
  2757. ASSERT(g_pUsers);
  2758. POSITION position = g_pUsers->GetHeadPosition();
  2759. WbUser * pRemovedUser;
  2760. while (position)
  2761. {
  2762. POSITION savedPosition = position;
  2763. pRemovedUser = (WbUser*)g_pUsers->GetNext(position);
  2764. if (pRemovedUser == pUser)
  2765. {
  2766. g_pUsers->RemoveAt(savedPosition);
  2767. position = NULL;
  2768. }
  2769. }
  2770. delete pUser;
  2771. }
  2772. // Update the title bar to reflect the number of users
  2773. UpdateWindowTitle();
  2774. }
  2775. //
  2776. //
  2777. // Function: OnWBPUserUpdateInd
  2778. //
  2779. // Purpose: Handler for WBP_EVENT_PERSON_UPDATE
  2780. //
  2781. //
  2782. void WbMainWindow::OnWBPUserUpdateInd(POM_OBJECT hUser, BOOL bReplace)
  2783. {
  2784. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPUserUpdateInd");
  2785. BOOL bActiveOld, bActiveNew;
  2786. WB_PAGE_HANDLE hPointerPageOld, hPointerPageNew;
  2787. POINT pointOld, pointNew;
  2788. WB_PAGE_HANDLE hUserPageOld, hUserPageNew;
  2789. BOOL syncOld, syncNew;
  2790. DCWbGraphicPointer * pPointer = NULL;
  2791. // Get the user object associated with the handle, and the remote pointer
  2792. WbUser* pUser = WB_GetUser(hUser);
  2793. if (!pUser)
  2794. {
  2795. WARNING_OUT(("Can't handle OnWBPUserUpdatedInd; can't get user object for 0x%08x", hUser));
  2796. }
  2797. else
  2798. {
  2799. pPointer = pUser->GetPointer();
  2800. ASSERT(pPointer);
  2801. //
  2802. // Save the interesting bits of the user's state before the change.
  2803. //
  2804. bActiveOld = pPointer->IsActive();
  2805. hPointerPageOld = pPointer->Page();
  2806. pPointer->GetPosition(&pointOld);
  2807. hUserPageOld = pUser->Page();
  2808. syncOld = pUser->IsSynced();
  2809. }
  2810. //
  2811. // Confirm the change
  2812. //
  2813. if (bReplace)
  2814. {
  2815. g_pwbCore->WBP_PersonReplaceConfirm(hUser);
  2816. }
  2817. else
  2818. {
  2819. g_pwbCore->WBP_PersonUpdateConfirm(hUser);
  2820. }
  2821. if (pUser != NULL)
  2822. {
  2823. pUser->Refresh();
  2824. //
  2825. // We do nothing for the local user; since we made the updates locally,
  2826. // we should have already accounted for them.
  2827. //
  2828. if (pUser == m_pLocalUser)
  2829. {
  2830. return;
  2831. }
  2832. //
  2833. // Get the state after the change.
  2834. //
  2835. pPointer = pUser->GetPointer();
  2836. ASSERT(pPointer);
  2837. bActiveNew = pPointer->IsActive();
  2838. hPointerPageNew = pPointer->Page();
  2839. pPointer->GetPosition(&pointNew);
  2840. hUserPageNew = pUser->Page();
  2841. syncNew = pUser->IsSynced();
  2842. // Check whether anything in the pointer has changed
  2843. if ( (bActiveNew != bActiveOld)
  2844. || (hPointerPageNew != hPointerPageOld)
  2845. || (!EqualPoint(pointNew, pointOld)))
  2846. {
  2847. // Check that at least one of the pages is the current page
  2848. if ( (hPointerPageNew == m_hCurrentPage)
  2849. || (hPointerPageOld == m_hCurrentPage))
  2850. {
  2851. m_drawingArea.PointerUpdated(pPointer);
  2852. }
  2853. }
  2854. if (syncOld != syncNew)
  2855. {
  2856. // ensure the page button enable/disable state is correct
  2857. UpdatePageButtons();
  2858. }
  2859. }
  2860. }
  2861. //
  2862. //
  2863. // Function: OnWBPSyncPositionUpdated
  2864. //
  2865. // Purpose: Handler for WBP_EVENT_SYNC_POSITION_UPDATED
  2866. //
  2867. //
  2868. void WbMainWindow::OnWBPSyncPositionUpdated(void)
  2869. {
  2870. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPSyncPositionUpdated");
  2871. //
  2872. // Dont do anythig if we don't have a local user.
  2873. //
  2874. if (m_pLocalUser == NULL)
  2875. {
  2876. ERROR_OUT(("Got a WBP_EVENT_SYNC_POSITION_UPDATED event and pLocaUser is NULL "));
  2877. return;
  2878. }
  2879. // If the local user is synced, change the current page/position
  2880. if (m_pLocalUser->IsSynced())
  2881. {
  2882. GotoSyncPosition();
  2883. }
  2884. }
  2885. //
  2886. //
  2887. // Function: OnSize
  2888. //
  2889. // Purpose: The window has been resized.
  2890. //
  2891. //
  2892. void WbMainWindow::OnSize(UINT nType, int cx, int cy )
  2893. {
  2894. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnSize");
  2895. // Only process this message if the window is not minimized
  2896. if (nType != SIZE_MINIMIZED)
  2897. {
  2898. // Hide the statusbar to avoid drawing problems
  2899. if (m_bStatusBarOn)
  2900. {
  2901. ::ShowWindow(m_hwndSB, SW_HIDE);
  2902. }
  2903. // Resize the subpanes of the window
  2904. ResizePanes();
  2905. // Show it again
  2906. if (m_bStatusBarOn)
  2907. {
  2908. ::ShowWindow(m_hwndSB, SW_SHOW);
  2909. }
  2910. }
  2911. // The user's view has changed
  2912. PositionUpdated();
  2913. // If the status has changed, set the option
  2914. if (m_uiWindowSize != nType)
  2915. {
  2916. m_uiWindowSize = nType;
  2917. // Write the new option values to file
  2918. OPT_SetBooleanOption(OPT_MAIN_MAXIMIZED,
  2919. (m_uiWindowSize == SIZE_MAXIMIZED));
  2920. OPT_SetBooleanOption(OPT_MAIN_MINIMIZED,
  2921. (m_uiWindowSize == SIZE_MINIMIZED));
  2922. }
  2923. // If this is setting the window to a new normal size,
  2924. // save the new position.
  2925. if (nType == SIZE_RESTORED)
  2926. {
  2927. SaveWindowPosition();
  2928. }
  2929. }
  2930. //
  2931. //
  2932. // Function: SaveWindowPosition
  2933. //
  2934. // Purpose: Save the current window position to the options file.
  2935. //
  2936. //
  2937. void WbMainWindow::SaveWindowPosition(void)
  2938. {
  2939. RECT rectWindow;
  2940. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::SaveWindowPosition");
  2941. // Get the new window rectangle
  2942. ::GetWindowRect(m_hwnd, &rectWindow);
  2943. // Write the new option values to file
  2944. OPT_SetWindowRectOption(OPT_MAIN_MAINWINDOWRECT, &rectWindow);
  2945. }
  2946. //
  2947. //
  2948. // Function: OnMove
  2949. //
  2950. // Purpose: The window has been moved.
  2951. //
  2952. //
  2953. void WbMainWindow::OnMove(void)
  2954. {
  2955. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnMove");
  2956. // If we are not maximized
  2957. if (!::IsZoomed(m_hwnd) && !::IsIconic(m_hwnd))
  2958. {
  2959. // Save the new position of the window
  2960. SaveWindowPosition();
  2961. }
  2962. }
  2963. //
  2964. //
  2965. // Function: ResizePanes
  2966. //
  2967. // Purpose: Resize the subpanes of the main window.
  2968. //
  2969. //
  2970. void WbMainWindow::ResizePanes(void)
  2971. {
  2972. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::ResizePanes");
  2973. //
  2974. //
  2975. // The client area is organized as follows:
  2976. //
  2977. // -------------------------------------
  2978. // | | |
  2979. // | T | |
  2980. // | o | Drawing Area |
  2981. // | o | |
  2982. // | l | |
  2983. // | s | |
  2984. // |---| |
  2985. // | W | |
  2986. // | i | |
  2987. // | d | |
  2988. // | t | |
  2989. // | h | |
  2990. // | s | |
  2991. // |-----------------------------------|
  2992. // | Attributes (colors) | Pages |
  2993. // |-----------------------------------|
  2994. // | Status |
  2995. // -------------------------------------
  2996. //
  2997. //
  2998. RECT clientRect;
  2999. RECT rectStatusBar;
  3000. RECT rectToolBar;
  3001. RECT rectWG;
  3002. RECT rectAG;
  3003. RECT rectDraw;
  3004. SIZE size;
  3005. SIZE sizeAG;
  3006. // Get the client rectangle
  3007. ::GetClientRect(m_hwnd, &clientRect);
  3008. rectStatusBar = clientRect;
  3009. // Resize the help bar and progress meter
  3010. if (m_bStatusBarOn)
  3011. {
  3012. rectStatusBar.top = rectStatusBar.bottom - STATUSBAR_HEIGHT;
  3013. ::MoveWindow(m_hwndSB, rectStatusBar.left, rectStatusBar.top,
  3014. rectStatusBar.right - rectStatusBar.left,
  3015. rectStatusBar.bottom - rectStatusBar.top, TRUE);
  3016. }
  3017. else
  3018. {
  3019. // Status bar is off - set it's height to zero
  3020. rectStatusBar.top = rectStatusBar.bottom;
  3021. }
  3022. // Resize the tool and width windows
  3023. m_TB.GetNaturalSize(&size);
  3024. rectToolBar.left = 0;
  3025. rectToolBar.right = rectToolBar.left + size.cx;
  3026. rectToolBar.top = 0;
  3027. rectToolBar.bottom = rectToolBar.top + size.cy;
  3028. m_WG.GetNaturalSize(&size);
  3029. rectWG.left = rectToolBar.left;
  3030. rectWG.top = rectToolBar.bottom;
  3031. rectWG.bottom = rectWG.top + size.cy;
  3032. if (!m_bToolBarOn)
  3033. {
  3034. // Toolbar is either off or floating - set its width to zero
  3035. rectToolBar.right = rectToolBar.left;
  3036. }
  3037. rectWG.right = rectToolBar.right;
  3038. // Position attribute group
  3039. m_AG.GetNaturalSize(&sizeAG);
  3040. ::MoveWindow(m_AG.m_hwnd, rectToolBar.left, rectStatusBar.top - sizeAG.cy,
  3041. clientRect.right - rectToolBar.left, sizeAG.cy, TRUE);
  3042. // finish fiddling with tools and widths bars
  3043. if (m_bToolBarOn)
  3044. {
  3045. //
  3046. // We make the toolbar, which includes the width bar, extend all
  3047. // down the left side.
  3048. //
  3049. rectToolBar.bottom = rectStatusBar.top - sizeAG.cy;
  3050. rectWG.left += TOOLBAR_MARGINX;
  3051. rectWG.right -= 2*TOOLBAR_MARGINX;
  3052. ::MoveWindow(m_TB.m_hwnd, rectToolBar.left,
  3053. rectToolBar.top, rectToolBar.right - rectToolBar.left,
  3054. rectToolBar.bottom - rectToolBar.top, TRUE);
  3055. ::MoveWindow(m_WG.m_hwnd, rectWG.left, rectWG.top,
  3056. rectWG.right - rectWG.left, rectWG.bottom - rectWG.top, TRUE);
  3057. ::BringWindowToTop(m_WG.m_hwnd);
  3058. }
  3059. // Resize the drawing pane
  3060. rectDraw = clientRect;
  3061. rectDraw.bottom = rectStatusBar.top - sizeAG.cy;
  3062. rectDraw.left = rectToolBar.right;
  3063. ::MoveWindow(m_drawingArea.m_hwnd, rectDraw.left, rectDraw.top,
  3064. rectDraw.right - rectDraw.left, rectDraw.bottom - rectDraw.top, TRUE);
  3065. // Check to see if Width group is overlapping Attributes group. This can happen if
  3066. // the menu bar has wrapped because the window isn't wide enough (bug 424)
  3067. RECT crWidthWnd;
  3068. RECT crAttrWnd;
  3069. ::GetWindowRect(m_WG.m_hwnd, &crWidthWnd);
  3070. ::GetWindowRect(m_AG.m_hwnd, &crAttrWnd);
  3071. if (crAttrWnd.top < crWidthWnd.bottom)
  3072. {
  3073. // the menu bar has wrapped and our height placements are wrong. Adjust window
  3074. // by difference and try again
  3075. RECT crMainWnd;
  3076. ::GetWindowRect(m_hwnd, &crMainWnd);
  3077. crMainWnd.bottom += (crWidthWnd.bottom - crAttrWnd.top + ::GetSystemMetrics(SM_CYFIXEDFRAME));
  3078. ::MoveWindow(m_hwnd, crMainWnd.left, crMainWnd.top,
  3079. crMainWnd.right - crMainWnd.left, crMainWnd.bottom - crMainWnd.top,
  3080. FALSE);
  3081. // this is going to recurse but the adjustment will happen only once.....
  3082. }
  3083. }
  3084. //
  3085. //
  3086. // Function: WbMainWindow::OnGetMinMaxInfo
  3087. //
  3088. // Purpose: Set the minimum and maximum tracking sizes of the window
  3089. //
  3090. //
  3091. void WbMainWindow::OnGetMinMaxInfo(LPMINMAXINFO lpmmi)
  3092. {
  3093. if (m_TB.m_hwnd == NULL)
  3094. return; // not ready to do this yet
  3095. SIZE csFrame;
  3096. SIZE csSeparator;
  3097. SIZE csAG;
  3098. SIZE csToolBar;
  3099. SIZE csWidthBar;
  3100. SIZE csStatusBar;
  3101. RECT rectStatusBar;
  3102. SIZE csMaxSize;
  3103. SIZE csScrollBars;
  3104. csFrame.cx = ::GetSystemMetrics(SM_CXSIZEFRAME);
  3105. csFrame.cy = ::GetSystemMetrics(SM_CYSIZEFRAME);
  3106. csSeparator.cx = ::GetSystemMetrics(SM_CXEDGE);
  3107. csSeparator.cy = ::GetSystemMetrics(SM_CYEDGE);
  3108. csScrollBars.cx = ::GetSystemMetrics(SM_CXVSCROLL);
  3109. csScrollBars.cy = ::GetSystemMetrics(SM_CYHSCROLL);
  3110. m_AG.GetNaturalSize(&csAG);
  3111. m_TB.GetNaturalSize(&csToolBar);
  3112. m_WG.GetNaturalSize(&csWidthBar);
  3113. csStatusBar.cx = 0;
  3114. if (m_bStatusBarOn)
  3115. {
  3116. csStatusBar.cy = STATUSBAR_HEIGHT;
  3117. }
  3118. else
  3119. {
  3120. csStatusBar.cy = 0;
  3121. }
  3122. // Set the minimum width and height of the window
  3123. lpmmi->ptMinTrackSize.x =
  3124. csFrame.cx + csAG.cx + csFrame.cx;
  3125. lpmmi->ptMinTrackSize.y =
  3126. csFrame.cy +
  3127. GetSystemMetrics( SM_CYCAPTION ) +
  3128. GetSystemMetrics( SM_CYMENU ) +
  3129. csToolBar.cy +
  3130. csWidthBar.cy +
  3131. csSeparator.cy +
  3132. csAG.cy +
  3133. csSeparator.cy +
  3134. csStatusBar.cy +
  3135. csFrame.cy ;
  3136. //
  3137. // Retrieves the size of the work area on the primary display monitor. The work
  3138. // area is the portion of the screen not obscured by the system taskbar or by
  3139. // application desktop toolbars
  3140. //
  3141. RECT rcWorkArea;
  3142. ::SystemParametersInfo( SPI_GETWORKAREA, 0, (&rcWorkArea), NULL );
  3143. csMaxSize.cx = rcWorkArea.right - rcWorkArea.left;
  3144. csMaxSize.cy = rcWorkArea.bottom - rcWorkArea.top;
  3145. lpmmi->ptMaxPosition.x = 0;
  3146. lpmmi->ptMaxPosition.y = 0;
  3147. lpmmi->ptMaxSize.x = csMaxSize.cx;
  3148. lpmmi->ptMaxSize.y = csMaxSize.cy;
  3149. lpmmi->ptMaxTrackSize.x = csMaxSize.cx;
  3150. lpmmi->ptMaxTrackSize.y = csMaxSize.cy;
  3151. }
  3152. //
  3153. //
  3154. // Function: WbMainWindow::CreateContextMenus
  3155. //
  3156. // Purpose: Create the pop-up context menus: used within the application
  3157. // drawing area.
  3158. //
  3159. //
  3160. BOOL WbMainWindow::CreateContextMenus(void)
  3161. {
  3162. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::CreateContextMenus");
  3163. m_hContextMenuBar = ::LoadMenu(g_hInstance, MAKEINTRESOURCE(CONTEXTMENU));
  3164. if (!m_hContextMenuBar)
  3165. {
  3166. ERROR_OUT(("Failed to create context menu"));
  3167. DefaultExceptionHandler(WBFE_RC_WINDOWS, 0);
  3168. return FALSE;
  3169. }
  3170. m_hContextMenu = ::GetSubMenu(m_hContextMenuBar, 0);
  3171. m_hGrobjContextMenuBar = ::LoadMenu(g_hInstance, MAKEINTRESOURCE(GROBJMENU));
  3172. if (!m_hGrobjContextMenuBar)
  3173. {
  3174. ERROR_OUT(("Failed to create grobj context menu"));
  3175. DefaultExceptionHandler(WBFE_RC_WINDOWS, 0);
  3176. return FALSE;
  3177. }
  3178. m_hGrobjContextMenu = ::GetSubMenu(m_hGrobjContextMenuBar, 0);
  3179. // make parts of m_hGrobjContextMenu be owner draw
  3180. ::ModifyMenu(m_hGrobjContextMenu, IDM_WIDTH_1, MF_ENABLED | MF_OWNERDRAW,
  3181. IDM_WIDTH_1, NULL);
  3182. ::ModifyMenu(m_hGrobjContextMenu, IDM_WIDTH_2, MF_ENABLED | MF_OWNERDRAW,
  3183. IDM_WIDTH_2, NULL);
  3184. ::ModifyMenu(m_hGrobjContextMenu, IDM_WIDTH_3, MF_ENABLED | MF_OWNERDRAW,
  3185. IDM_WIDTH_3, NULL);
  3186. ::ModifyMenu(m_hGrobjContextMenu, IDM_WIDTH_4, MF_ENABLED | MF_OWNERDRAW,
  3187. IDM_WIDTH_4, NULL);
  3188. return TRUE;
  3189. }
  3190. //
  3191. //
  3192. // Function: WbMainWindow::InitializeMenus
  3193. //
  3194. // Purpose: Initialise the menus: set up owner-drawn menu items and
  3195. // those read from options file.
  3196. //
  3197. //
  3198. void WbMainWindow::InitializeMenus(void)
  3199. {
  3200. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::InitializeMenus");
  3201. // Make the width menu ownerdraw
  3202. HMENU hMenu = GetMenuWithItem(::GetMenu(m_hwnd), IDM_WIDTH_1);
  3203. if (hMenu != NULL)
  3204. {
  3205. // Change each entry to be ownerdraw (loop until failure)
  3206. int iIndex;
  3207. UINT uiId;
  3208. int iCount = ::GetMenuItemCount(hMenu);
  3209. for (iIndex = 0; iIndex < iCount; iIndex++)
  3210. {
  3211. uiId = ::GetMenuItemID(hMenu, iIndex);
  3212. ::ModifyMenu(hMenu, iIndex,
  3213. MF_BYPOSITION
  3214. | MF_ENABLED
  3215. | MF_OWNERDRAW,
  3216. uiId,
  3217. NULL);
  3218. }
  3219. }
  3220. }
  3221. //
  3222. //
  3223. // Function: WbMainWindow::OnMeasureItem
  3224. //
  3225. // Purpose: Return the size of an item in the widths menu
  3226. //
  3227. //
  3228. void WbMainWindow::OnMeasureItem
  3229. (
  3230. int nIDCtl,
  3231. LPMEASUREITEMSTRUCT measureStruct
  3232. )
  3233. {
  3234. // Check that this is for a color menu item
  3235. if ( (measureStruct->itemID >= IDM_WIDTHS_START)
  3236. && (measureStruct->itemID < IDM_WIDTHS_END))
  3237. {
  3238. measureStruct->itemWidth = ::GetSystemMetrics(SM_CXMENUCHECK) +
  3239. (2 * CHECKMARK_BORDER_X) + COLOR_MENU_WIDTH;
  3240. measureStruct->itemHeight = ::GetSystemMetrics(SM_CYMENUCHECK) +
  3241. (2 * CHECKMARK_BORDER_Y);
  3242. }
  3243. }
  3244. //
  3245. //
  3246. // Function: WbMainWindow::OnDrawItem
  3247. //
  3248. // Purpose: Draw an item in the color menu
  3249. //
  3250. //
  3251. void WbMainWindow::OnDrawItem
  3252. (
  3253. int nIDCtl,
  3254. LPDRAWITEMSTRUCT drawStruct
  3255. )
  3256. {
  3257. COLORREF crMenuBackground;
  3258. COLORREF crMenuText;
  3259. HPEN hOldPen;
  3260. HBRUSH hOldBrush;
  3261. COLORREF crOldBkgnd;
  3262. COLORREF crOldText;
  3263. int nOldBkMode;
  3264. HBITMAP hbmp = NULL;
  3265. BITMAP bitmap;
  3266. UINT uiCheckWidth;
  3267. UINT uiCheckHeight;
  3268. RECT rect;
  3269. RECT rectCheck;
  3270. RECT rectLine;
  3271. HDC hMemDC;
  3272. UINT uiWidthIndex;
  3273. UINT uiWidth;
  3274. HPEN hPenMenu;
  3275. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnDrawItem");
  3276. // Check that this is a width menu item
  3277. if( (drawStruct->itemID < IDM_WIDTHS_START) ||
  3278. (drawStruct->itemID >= IDM_WIDTHS_END) )
  3279. {
  3280. return;
  3281. }
  3282. // get menu item colors
  3283. if( (drawStruct->itemState & ODS_SELECTED) ||
  3284. ((drawStruct->itemState & (ODS_SELECTED |ODS_CHECKED)) ==
  3285. (ODS_SELECTED |ODS_CHECKED))
  3286. )
  3287. {
  3288. crMenuBackground = COLOR_HIGHLIGHT;
  3289. crMenuText = COLOR_HIGHLIGHTTEXT;
  3290. }
  3291. else if( drawStruct->itemState & ODS_GRAYED)
  3292. {
  3293. crMenuBackground = COLOR_MENU;
  3294. crMenuText = COLOR_GRAYTEXT;
  3295. }
  3296. else
  3297. {
  3298. crMenuBackground = COLOR_MENU;
  3299. crMenuText = COLOR_MENUTEXT;
  3300. }
  3301. hPenMenu = ::CreatePen(PS_SOLID, 0, ::GetSysColor(crMenuBackground));
  3302. if (!hPenMenu)
  3303. {
  3304. TRACE_MSG(("Failed to create penMenu"));
  3305. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WINDOWS, 0);
  3306. goto bail_out;
  3307. }
  3308. rect = drawStruct->rcItem;
  3309. // Fill the whole box with current menu background color
  3310. hOldPen = SelectPen(drawStruct->hDC, hPenMenu);
  3311. hOldBrush = SelectBrush(drawStruct->hDC, GetSysColorBrush(crMenuBackground));
  3312. ::Rectangle(drawStruct->hDC, rect.left, rect.top, rect.right, rect.bottom);
  3313. SelectBrush(drawStruct->hDC, hOldBrush);
  3314. SelectPen(drawStruct->hDC, hOldPen);
  3315. if( (hbmp = (HBITMAP)LoadImage( NULL, MAKEINTRESOURCE( OBM_CHECK ), IMAGE_BITMAP,
  3316. 0,0, 0 ))
  3317. == NULL )
  3318. {
  3319. TRACE_MSG(("Failed to create check image"));
  3320. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WINDOWS, 0);
  3321. goto bail_out;
  3322. }
  3323. // Get the width and height of the bitmap (allowing some border)
  3324. ::GetObject(hbmp, sizeof(BITMAP), &bitmap);
  3325. uiCheckWidth = bitmap.bmWidth + (2 * CHECKMARK_BORDER_X);
  3326. uiCheckHeight = bitmap.bmHeight;
  3327. // Draw in a checkmark (if needed)
  3328. if (drawStruct->itemState & ODS_CHECKED)
  3329. {
  3330. hMemDC = ::CreateCompatibleDC(drawStruct->hDC);
  3331. if (!hMemDC)
  3332. {
  3333. ERROR_OUT(("Failed to create memDC"));
  3334. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WINDOWS, 0);
  3335. goto bail_out;
  3336. }
  3337. crOldBkgnd = ::SetBkColor(drawStruct->hDC, GetSysColor( crMenuBackground ) );
  3338. crOldText = ::SetTextColor(drawStruct->hDC, GetSysColor( crMenuText ) );
  3339. nOldBkMode = ::SetBkMode(drawStruct->hDC, OPAQUE );
  3340. HBITMAP hOld = SelectBitmap(hMemDC, hbmp);
  3341. if (hOld != NULL)
  3342. {
  3343. rectCheck = rect;
  3344. rectCheck.top += ((rectCheck.bottom - rectCheck.top)/2 - uiCheckHeight/2);
  3345. rectCheck.right = rectCheck.left + uiCheckWidth;
  3346. rectCheck.bottom = rectCheck.top + uiCheckHeight;
  3347. ::BitBlt(drawStruct->hDC, rectCheck.left,
  3348. rectCheck.top,
  3349. rectCheck.right - rectCheck.left,
  3350. rectCheck.bottom - rectCheck.top,
  3351. hMemDC,
  3352. 0,
  3353. 0,
  3354. SRCCOPY);
  3355. SelectBitmap(hMemDC, hOld);
  3356. }
  3357. ::SetBkMode(drawStruct->hDC, nOldBkMode);
  3358. ::SetTextColor(drawStruct->hDC, crOldText);
  3359. ::SetBkColor(drawStruct->hDC, crOldBkgnd);
  3360. ::DeleteDC(hMemDC);
  3361. }
  3362. DeleteBitmap(hbmp);
  3363. // Allow room for the checkmark to the left of the color
  3364. rect.left += uiCheckWidth;
  3365. uiWidthIndex = drawStruct->itemID - IDM_WIDTHS_START;
  3366. uiWidth = g_PenWidths[uiWidthIndex];
  3367. // If pens are very wide they can be larger than the allowed rectangle.
  3368. // So we reduce the clipping rectangle here. We save the DC so that we
  3369. // can restore it - getting the clip region back.
  3370. if (::SaveDC(drawStruct->hDC) == 0)
  3371. {
  3372. ERROR_OUT(("Failed to save DC"));
  3373. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WINDOWS, 0);
  3374. goto bail_out;
  3375. }
  3376. if (::IntersectClipRect(drawStruct->hDC, rect.left, rect.top,
  3377. rect.right, rect.bottom) == ERROR)
  3378. {
  3379. ERROR_OUT(("Failed to set clip rect"));
  3380. ::RestoreDC(drawStruct->hDC, -1);
  3381. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WINDOWS, 0);
  3382. goto bail_out;
  3383. }
  3384. hOldPen = SelectPen(drawStruct->hDC, hPenMenu);
  3385. hOldBrush = SelectBrush(drawStruct->hDC, GetSysColorBrush(crMenuText));
  3386. rectLine.left = rect.left;
  3387. rectLine.top = rect.top + ((rect.bottom - rect.top) / 2) - uiWidth/2;
  3388. rectLine.right= rect.right - ((rect.right - rect.left) / 6);
  3389. rectLine.bottom = rectLine.top + uiWidth + 2;
  3390. ::Rectangle(drawStruct->hDC, rectLine.left, rectLine.top,
  3391. rectLine.right, rectLine.bottom);
  3392. SelectBrush(drawStruct->hDC, hOldBrush);
  3393. SelectPen(drawStruct->hDC, hOldPen);
  3394. ::RestoreDC(drawStruct->hDC, -1);
  3395. bail_out:
  3396. if (hPenMenu != NULL)
  3397. {
  3398. ::DeletePen(hPenMenu);
  3399. }
  3400. }
  3401. //
  3402. //
  3403. // Function: OnSetFocus
  3404. //
  3405. // Purpose: The window is getting the focus
  3406. //
  3407. //
  3408. void WbMainWindow::OnSetFocus(void)
  3409. {
  3410. // We pass the focus on to the main drawing area
  3411. ::SetFocus(m_drawingArea.m_hwnd);
  3412. }
  3413. //
  3414. //
  3415. // Function: UpdateStatus
  3416. //
  3417. // Purpose: Set the text in the status bar
  3418. //
  3419. //
  3420. void WbMainWindow::UpdateStatus()
  3421. {
  3422. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::UpdateStatus");
  3423. //
  3424. // Update the current and last page numbers
  3425. //
  3426. m_AG.SetCurrentPageNumber(g_pwbCore->WBP_PageNumberFromHandle(m_hCurrentPage));
  3427. m_AG.SetLastPageNumber(g_pwbCore->WBP_ContentsCountPages());
  3428. //
  3429. // Update the user information with the page.
  3430. //
  3431. if (m_pLocalUser != NULL)
  3432. {
  3433. m_pLocalUser->SetPage(m_hCurrentPage);
  3434. }
  3435. }
  3436. //
  3437. //
  3438. // Function: SetMenuState
  3439. //
  3440. // Purpose: Sets menu contents to their correct enabled/disabled state
  3441. //
  3442. //
  3443. void WbMainWindow::SetMenuStates(HMENU hInitMenu)
  3444. {
  3445. BOOL bLocked;
  3446. BOOL bPageOrderLocked;
  3447. BOOL bPresentationMode;
  3448. UINT uiEnable;
  3449. UINT uiCountPages;
  3450. BOOL bIdle;
  3451. BOOL bSelected;
  3452. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::SetMenuStates");
  3453. //
  3454. // Check menu exists
  3455. //
  3456. if (hInitMenu == NULL)
  3457. {
  3458. WARNING_OUT(("Menu doesn't exist"));
  3459. return;
  3460. }
  3461. HMENU hMainMenu = ::GetMenu(m_hwnd);
  3462. // Get the window's main menu and check that the menu
  3463. // now being popped up is one on the top-level. (We do not
  3464. // seem to be able to associate the index number passed with
  3465. // sub-menus easily.)
  3466. if ((hInitMenu != m_hContextMenu) && (hInitMenu != m_hGrobjContextMenu))
  3467. {
  3468. BOOL bTopLevel = FALSE;
  3469. int nCount = ::GetMenuItemCount(hMainMenu);
  3470. for (int nNext = 0; nNext < nCount; nNext++)
  3471. {
  3472. HMENU hNextMenu = ::GetSubMenu(hMainMenu, nNext);
  3473. if (hNextMenu != NULL)
  3474. {
  3475. if (hNextMenu == hInitMenu)
  3476. {
  3477. bTopLevel = TRUE;
  3478. break;
  3479. }
  3480. }
  3481. }
  3482. // not a top level, so leave the function now
  3483. if (!bTopLevel)
  3484. {
  3485. TRACE_DEBUG(("Not top-level menu"));
  3486. return;
  3487. }
  3488. }
  3489. // Get the lock and selection states:
  3490. // If we are joining a call, we cannot assume that the contents
  3491. // and user/client details have been created yet, so just set the
  3492. // locked state to true.
  3493. bIdle = IsIdle();
  3494. bSelected = m_drawingArea.GraphicSelected();
  3495. TRACE_DEBUG(("m_uiState %d", m_uiState));
  3496. if ((m_uiState == STARTING) || (m_uiState == JOINING))
  3497. {
  3498. TRACE_DEBUG(("Not initilalised yet"));
  3499. bLocked = TRUE;
  3500. bPageOrderLocked = TRUE;
  3501. bPresentationMode = TRUE;
  3502. uiCountPages = 1;
  3503. }
  3504. else
  3505. {
  3506. //
  3507. // Note that bLocked and bPageOrderLocked are always true when
  3508. // we're not in idle state.
  3509. //
  3510. uiCountPages = g_pwbCore->WBP_ContentsCountPages();
  3511. bLocked = (WB_Locked() || !bIdle);
  3512. bPageOrderLocked = (WB_Locked() || !bIdle);
  3513. bPresentationMode = (((m_uiState == IN_CALL) &&
  3514. (WB_PresentationMode()))
  3515. || (!bIdle));
  3516. }
  3517. //
  3518. // Functions which are disabled when contents is locked
  3519. //
  3520. uiEnable = MF_BYCOMMAND | (bLocked ? MF_GRAYED : MF_ENABLED);
  3521. ::EnableMenuItem(hInitMenu, IDM_OPEN, uiEnable);
  3522. ::EnableMenuItem(hInitMenu, IDM_SAVE, uiEnable);
  3523. ::EnableMenuItem(hInitMenu, IDM_SAVE_AS, uiEnable);
  3524. ::EnableMenuItem(hInitMenu, IDM_PRINT, uiEnable);
  3525. ::EnableMenuItem(hInitMenu, IDM_GRAB_AREA, uiEnable);
  3526. ::EnableMenuItem(hInitMenu, IDM_GRAB_WINDOW, uiEnable);
  3527. ::EnableMenuItem(hInitMenu, IDM_SELECTALL, uiEnable);
  3528. ::EnableMenuItem(hInitMenu, IDM_SELECT, uiEnable);
  3529. ::EnableMenuItem(hInitMenu, IDM_PEN, uiEnable);
  3530. ::EnableMenuItem(hInitMenu, IDM_HIGHLIGHT, uiEnable);
  3531. // Don't allow editing in zoom mode
  3532. if( m_drawingArea.Zoomed() )
  3533. ::EnableMenuItem(hInitMenu, IDM_TEXT, MF_GRAYED);
  3534. else
  3535. ::EnableMenuItem(hInitMenu, IDM_TEXT, uiEnable);
  3536. ::EnableMenuItem(hInitMenu, IDM_CLEAR_PAGE, uiEnable);
  3537. ::EnableMenuItem(hInitMenu, IDM_ERASER, uiEnable);
  3538. ::EnableMenuItem(hInitMenu, IDM_LINE, uiEnable);
  3539. ::EnableMenuItem(hInitMenu, IDM_BOX, uiEnable);
  3540. ::EnableMenuItem(hInitMenu, IDM_FILLED_BOX, uiEnable);
  3541. ::EnableMenuItem(hInitMenu, IDM_ELLIPSE, uiEnable);
  3542. ::EnableMenuItem(hInitMenu, IDM_FILLED_ELLIPSE, uiEnable);
  3543. ::EnableMenuItem(hInitMenu, IDM_ZOOM, uiEnable);
  3544. // So toolbar will follow menu (MFC-auto-update is broken for this)
  3545. EnableToolbar( !bLocked );
  3546. //
  3547. // File/New is disabled if page order is locked, or not in a call,
  3548. // or a new is already in progress.
  3549. //
  3550. ::EnableMenuItem(hInitMenu, IDM_NEW, MF_BYCOMMAND |
  3551. (bPageOrderLocked ? MF_GRAYED : MF_ENABLED));
  3552. //
  3553. // Paste enabled only if not locked, and there's something in the
  3554. // clipboard
  3555. //
  3556. uiEnable = MF_BYCOMMAND | MF_ENABLED;
  3557. if ( (CLP_AcceptableClipboardFormat() == NULL)
  3558. || (bLocked))
  3559. {
  3560. // No acceptable format available, or the contents
  3561. // are locked by another user - gray the Paste command.
  3562. uiEnable = MF_BYCOMMAND | MF_GRAYED;
  3563. }
  3564. ::EnableMenuItem(hInitMenu, IDM_PASTE, uiEnable);
  3565. //
  3566. // Functions which require a graphic to be selected
  3567. //
  3568. uiEnable = MF_BYCOMMAND | MF_ENABLED;
  3569. if( !m_drawingArea.TextEditActive() )
  3570. {
  3571. if (!bSelected || bLocked)
  3572. {
  3573. // No acceptable format available - gray the menu item
  3574. uiEnable = MF_BYCOMMAND | MF_GRAYED;
  3575. }
  3576. }
  3577. ::EnableMenuItem(hInitMenu, IDM_CUT, uiEnable);
  3578. // don't do textedit delete for now
  3579. if( m_drawingArea.TextEditActive() )
  3580. ::EnableMenuItem(hInitMenu, IDM_DELETE, MF_BYCOMMAND | MF_GRAYED);
  3581. else
  3582. ::EnableMenuItem(hInitMenu, IDM_DELETE, uiEnable);
  3583. ::EnableMenuItem(hInitMenu, IDM_BRING_TO_TOP, uiEnable);
  3584. ::EnableMenuItem(hInitMenu, IDM_SEND_TO_BACK, uiEnable);
  3585. //
  3586. // Can copy even if contents are locked
  3587. //
  3588. //COMMENT BY RAND - To fix 556 I changed !bIdle to bIdle like the current
  3589. // 16bit code does.
  3590. ::EnableMenuItem(hInitMenu, IDM_COPY, MF_BYCOMMAND |
  3591. (m_drawingArea.TextEditActive()||(bSelected && bIdle)
  3592. ? MF_ENABLED : MF_GRAYED)); //CHANGED BY RAND for 556
  3593. //
  3594. // Object to undelete?
  3595. //
  3596. ::EnableMenuItem(hInitMenu, IDM_UNDELETE, MF_BYCOMMAND |
  3597. ((m_LastDeletedGraphic.GotTrash() &&
  3598. (m_LastDeletedGraphic.Page() == m_hCurrentPage) &&
  3599. (!bLocked)) ? MF_ENABLED : MF_GRAYED));
  3600. //
  3601. // Page functions depend on number of pages
  3602. //
  3603. ::EnableMenuItem(hInitMenu, IDM_DELETE_PAGE, MF_BYCOMMAND |
  3604. ((bPageOrderLocked ||
  3605. (uiCountPages == 1)||
  3606. (!m_bUnlockStateSettled))
  3607. ? MF_GRAYED : MF_ENABLED));
  3608. uiEnable = MF_BYCOMMAND | MF_ENABLED;
  3609. if ((bPageOrderLocked) ||
  3610. (uiCountPages == WB_MAX_PAGES)||
  3611. (!m_bUnlockStateSettled))
  3612. {
  3613. uiEnable = MF_BYCOMMAND | MF_GRAYED;
  3614. }
  3615. ::EnableMenuItem(hInitMenu, IDM_PAGE_INSERT_BEFORE, uiEnable);
  3616. ::EnableMenuItem(hInitMenu, IDM_PAGE_INSERT_AFTER, uiEnable);
  3617. //
  3618. // Can't bring up page sorter if locked
  3619. //
  3620. ::EnableMenuItem(hInitMenu, IDM_PAGE_SORTER, MF_BYCOMMAND |
  3621. (bPresentationMode ? MF_GRAYED : MF_ENABLED));
  3622. // Enable page controls
  3623. m_AG.EnablePageCtrls(!bPresentationMode);
  3624. //
  3625. // Lock enabled only if not already locked
  3626. //
  3627. ::EnableMenuItem(hInitMenu, IDM_LOCK, MF_BYCOMMAND |
  3628. (bPageOrderLocked ? MF_GRAYED : MF_ENABLED));
  3629. //
  3630. // Enable sync if not in "presentation" mode
  3631. //
  3632. ::EnableMenuItem(hInitMenu, IDM_SYNC, MF_BYCOMMAND |
  3633. (((!bPresentationMode) && bIdle) ? MF_ENABLED : MF_GRAYED));
  3634. //
  3635. // Gray font/color/widths if inappropriate for current tool.
  3636. //
  3637. ::EnableMenuItem(hInitMenu, IDM_FONT, MF_BYCOMMAND |
  3638. (!bLocked && m_pCurrentTool->HasFont() ? MF_ENABLED : MF_GRAYED));
  3639. ::EnableMenuItem(hInitMenu, IDM_EDITCOLOR, MF_BYCOMMAND |
  3640. (!bLocked && m_pCurrentTool->HasColor() ? MF_ENABLED : MF_GRAYED));
  3641. // enable width menu (bug 433)
  3642. HMENU hOptionsMenu = ::GetSubMenu(hMainMenu, MENUPOS_OPTIONS);
  3643. uiEnable = (!bLocked && m_pCurrentTool->HasWidth())?MF_ENABLED:MF_GRAYED;
  3644. if (hOptionsMenu == hInitMenu )
  3645. ::EnableMenuItem(hOptionsMenu, OPTIONSPOS_WIDTH, MF_BYPOSITION | uiEnable );
  3646. UINT i;
  3647. UINT uIdmCurWidth = 0;
  3648. if( uiEnable == MF_ENABLED )
  3649. uIdmCurWidth = m_pCurrentTool->GetWidthIndex() + IDM_WIDTH_1;
  3650. // set width state(bug 426)
  3651. for( i=IDM_WIDTH_1; i<=IDM_WIDTH_4; i++ )
  3652. {
  3653. ::EnableMenuItem(hInitMenu, i, uiEnable );
  3654. if( uiEnable == MF_ENABLED )
  3655. {
  3656. if( uIdmCurWidth == i )
  3657. ::CheckMenuItem(hInitMenu, i, MF_CHECKED );
  3658. else
  3659. ::CheckMenuItem(hInitMenu, i, MF_UNCHECKED );
  3660. }
  3661. }
  3662. }
  3663. //
  3664. //
  3665. // Function: OnInitMenuPopup
  3666. //
  3667. // Purpose: Process a WM_INITMENUPOPUP event
  3668. //
  3669. //
  3670. void WbMainWindow::OnInitMenuPopup
  3671. (
  3672. HMENU hMenu,
  3673. UINT uiIndex,
  3674. BOOL bSystemMenu
  3675. )
  3676. {
  3677. // 1/2 of fix for strange MFC4.2 build bug that clogs up DCL's message pipe.
  3678. // The other 1/2 and a better comment are in LoadFile().
  3679. if( m_bIsWin95 )
  3680. {
  3681. if( GetSubState() == SUBSTATE_LOADING )
  3682. {
  3683. ::SetFocus(m_drawingArea.m_hwnd);
  3684. return;
  3685. }
  3686. }
  3687. // Ignore the event if it relates to the system menu
  3688. if (!bSystemMenu)
  3689. {
  3690. if (hMenu)
  3691. {
  3692. SetMenuStates(hMenu);
  3693. m_hInitMenu = hMenu;
  3694. }
  3695. else
  3696. {
  3697. m_hInitMenu = NULL;
  3698. }
  3699. // Save the last menu we handled, so that we can alter its state
  3700. // if necessary whilst it is still visible
  3701. }
  3702. }
  3703. //
  3704. //
  3705. // Function : OnMenuSelect
  3706. //
  3707. // Purpose : Update the text in the help bar
  3708. //
  3709. //
  3710. void WbMainWindow::OnMenuSelect(UINT uiItemID, UINT uiFlags, HMENU hSysMenu)
  3711. {
  3712. UINT firstMenuId;
  3713. UINT statusId;
  3714. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnMenuSelect");
  3715. //
  3716. // Work out the help ID for the menu item. We have to store this now
  3717. // because when the user presses F1 from a menu item, we can't tell
  3718. // which item it was.
  3719. //
  3720. if (uiFlags == (UINT)-1)
  3721. {
  3722. //
  3723. // The menu has been dismissed
  3724. //
  3725. m_hInitMenu = NULL;
  3726. statusId = IDS_DEFAULT;
  3727. if( hSysMenu == 0 )
  3728. {
  3729. // Menu was dismissed, check cursor loc.
  3730. DCWbGraphic *pGraphic;
  3731. POINT surfacePos;
  3732. ::GetCursorPos( &surfacePos );
  3733. ::ScreenToClient(m_drawingArea.m_hwnd, &surfacePos);
  3734. m_drawingArea.ClientToSurface(&surfacePos );
  3735. if( (pGraphic = m_drawingArea.GetHitObject( surfacePos )) == NULL )
  3736. {
  3737. // we clicked dead air, don't lose current selection (bug 426)
  3738. m_drawingArea.SetLClickIgnore( TRUE );
  3739. }
  3740. else
  3741. delete pGraphic; // plug leak
  3742. }
  3743. }
  3744. else if ((uiFlags & MF_POPUP) && (uiFlags & MF_SYSMENU))
  3745. {
  3746. //
  3747. // System menu selected
  3748. //
  3749. statusId = IDS_MENU_SYSTEM;
  3750. }
  3751. else if (uiFlags & MF_POPUP)
  3752. {
  3753. // get popup menu handle and first item (bug NM4db:463)
  3754. HMENU hPopup = ::GetSubMenu( hSysMenu, uiItemID );
  3755. firstMenuId = ::GetMenuItemID( hPopup, 0 );
  3756. // figure out which popup it is so we can display the right help text
  3757. switch (firstMenuId)
  3758. {
  3759. case IDM_NEW:
  3760. statusId = IDS_MENU_FILE;
  3761. break;
  3762. case IDM_DELETE:
  3763. statusId = IDS_MENU_EDIT;
  3764. break;
  3765. case IDM_TOOL_BAR_TOGGLE:
  3766. statusId = IDS_MENU_VIEW;
  3767. break;
  3768. case IDM_EDITCOLOR:
  3769. // The first item in the options menu is the color popup
  3770. // menu - popup menus have Id -1
  3771. statusId = IDS_MENU_OPTIONS;
  3772. break;
  3773. case IDM_TOOLS_START:
  3774. statusId = IDS_MENU_TOOLS;
  3775. break;
  3776. case IDM_HELP:
  3777. statusId = IDS_MENU_HELP;
  3778. break;
  3779. case IDM_WIDTH_1: // (added for bug NM4db:463)
  3780. statusId = IDS_MENU_WIDTH;
  3781. break;
  3782. default:
  3783. statusId = IDS_DEFAULT;
  3784. break;
  3785. }
  3786. }
  3787. else
  3788. {
  3789. //
  3790. // A normal menu item has been selected
  3791. //
  3792. statusId = uiItemID;
  3793. }
  3794. // Set the new help text
  3795. TCHAR szStatus[256];
  3796. if (::LoadString(g_hInstance, statusId, szStatus, 256))
  3797. {
  3798. ::SetWindowText(m_hwndSB, szStatus);
  3799. }
  3800. }
  3801. //
  3802. //
  3803. // Function: OnParentNotfiy
  3804. //
  3805. // Purpose: Process a message coming from a child window
  3806. //
  3807. //
  3808. void WbMainWindow::OnParentNotify(UINT uiMessage)
  3809. {
  3810. switch (uiMessage)
  3811. {
  3812. // Scroll message from the drawing area. These are sent when the user
  3813. // scrolls the area using the scroll bars. We queue an update of the
  3814. // current sync position.
  3815. case WM_HSCROLL:
  3816. case WM_VSCROLL:
  3817. // The user's view has changed
  3818. PositionUpdated();
  3819. break;
  3820. }
  3821. }
  3822. //
  3823. //
  3824. // Function: QuerySaveRequired
  3825. //
  3826. // Purpose: Check whether the drawing pane contents are to be saved
  3827. // before a destructive function is performed.
  3828. //
  3829. //
  3830. int WbMainWindow::QuerySaveRequired(BOOL bCancelBtn)
  3831. {
  3832. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::QuerySaveRequired");
  3833. // Default the response to "no save required"
  3834. int iResult = IDNO;
  3835. //
  3836. // If we are already displaying a "Save As" dialog, dismiss it.
  3837. //
  3838. if (m_hwndQuerySaveDlg != NULL)
  3839. {
  3840. ::SendMessage(m_hwndQuerySaveDlg, WM_COMMAND,
  3841. MAKELONG(IDCANCEL, BN_CLICKED), 0);
  3842. ASSERT(m_hwndQuerySaveDlg == NULL);
  3843. }
  3844. // If any of the pages has changed - ask the user if they want to
  3845. // save the contents of the Whiteboard.
  3846. if (g_pwbCore->WBP_ContentsChanged())
  3847. {
  3848. ::SetForegroundWindow(m_hwnd); //bring us to the top first
  3849. // SetForegroundWindow() does not work properly in Memphis when its called during a
  3850. // SendMessage handler, specifically, when conf calls me to shutdown. The window activation
  3851. // state is messed up or something and my window does not pop to the top. So I have to
  3852. // force my window to the top using SetWindowPos. But even after that the titlebar is not
  3853. // highlighted properly. I tried combinations of SetActiveWindow, SetFocus, etc but to no
  3854. // avail. But, at least the dialog is visible so you can clear it thus fixing the
  3855. // bug (NM4db:2103). SetForegroundWindow() works ok for Win95 and NT here without
  3856. // having to use SetWindowPos (it doesn't hurt anyting to do it anyway so I didn't
  3857. // do a platform check).
  3858. ::SetWindowPos(m_hwnd, HWND_TOPMOST, 0,0, 0,0, SWP_NOMOVE | SWP_NOSIZE ); // force to top
  3859. ::SetWindowPos(m_hwnd, HWND_NOTOPMOST, 0,0, 0,0, SWP_NOMOVE | SWP_NOSIZE ); // let go of topmost
  3860. //
  3861. // Display a dialog box with the relevant question
  3862. // LOWORD of user data is "cancel command is allowed"
  3863. // HIWORD of user data is "disable cancel button"
  3864. //
  3865. iResult = (int)DialogBoxParam(g_hInstance,
  3866. bCancelBtn ? MAKEINTRESOURCE(QUERYSAVEDIALOGCANCEL)
  3867. : MAKEINTRESOURCE(QUERYSAVEDIALOG),
  3868. m_hwnd,
  3869. QuerySaveDlgProc,
  3870. MAKELONG(bCancelBtn, FALSE));
  3871. }
  3872. return iResult;
  3873. }
  3874. //
  3875. // QuerySaveDlgProc()
  3876. // Handler for query save dialogs. We save some flags in GWL_USER
  3877. //
  3878. INT_PTR CALLBACK QuerySaveDlgProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  3879. {
  3880. BOOL fHandled = FALSE;
  3881. switch (uMessage)
  3882. {
  3883. case WM_INITDIALOG:
  3884. //
  3885. // Save away our HWND so this dialog can be cancelled if necessary
  3886. //
  3887. g_pMain->m_hwndQuerySaveDlg = hwnd;
  3888. // Remember the flags we passed
  3889. ::SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
  3890. // Should the cancel button be disabled?
  3891. if (HIWORD(lParam))
  3892. ::EnableWindow(::GetDlgItem(hwnd, IDCANCEL), FALSE);
  3893. // Bring us to the front
  3894. ::SetForegroundWindow(hwnd);
  3895. fHandled = TRUE;
  3896. break;
  3897. case WM_CLOSE:
  3898. // Even if the cancel button is disabled, kill the dialog
  3899. ::PostMessage(hwnd, WM_COMMAND, IDCANCEL, 0);
  3900. fHandled = TRUE;
  3901. break;
  3902. case WM_COMMAND:
  3903. switch (GET_WM_COMMAND_ID(wParam, lParam))
  3904. {
  3905. case IDCANCEL:
  3906. //
  3907. // If a dialog doesn't have a cancel button or it's
  3908. // disabled and the user pressed the close btn, we can
  3909. // get here.
  3910. //
  3911. if (!LOWORD(::GetWindowLongPtr(hwnd, GWLP_USERDATA)))
  3912. wParam = MAKELONG(IDNO, HIWORD(wParam));
  3913. // FALL THRU
  3914. case IDYES:
  3915. case IDNO:
  3916. if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED)
  3917. {
  3918. g_pMain->m_hwndQuerySaveDlg = NULL;
  3919. ::EndDialog(hwnd, GET_WM_COMMAND_ID(wParam, lParam));
  3920. break;
  3921. }
  3922. break;
  3923. }
  3924. fHandled = TRUE;
  3925. break;
  3926. }
  3927. return(fHandled);
  3928. }
  3929. //
  3930. //
  3931. // Function: OnNew
  3932. //
  3933. // Purpose: Clear the workspace and associated filenames
  3934. //
  3935. //
  3936. void WbMainWindow::OnNew(void)
  3937. {
  3938. int iDoNew;
  3939. if( UsersMightLoseData( NULL, NULL ) ) // bug NM4db:418
  3940. return;
  3941. // check state before proceeding - if we're already doing a new, then abort
  3942. if ( (m_uiState != IN_CALL)
  3943. || (m_uiSubState == SUBSTATE_NEW_IN_PROGRESS))
  3944. {
  3945. // post an error message indicating the whiteboard is busy
  3946. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, WB_RC_BUSY);
  3947. goto OnNewCleanup;
  3948. }
  3949. // if we're currently loading, then cancel the load and proceed (don't
  3950. // prompt to save).
  3951. else if (m_uiSubState == SUBSTATE_LOADING)
  3952. {
  3953. // cancel load, not releasing the page order lock, because
  3954. // we need it immediately afterwards
  3955. CancelLoad(FALSE);
  3956. iDoNew = IDNO;
  3957. }
  3958. // otherwise prompt to save if necessary
  3959. else
  3960. {
  3961. // Get confirmation for the new
  3962. iDoNew = QuerySaveRequired(TRUE);
  3963. }
  3964. if (iDoNew == IDYES)
  3965. {
  3966. // Save the changes
  3967. iDoNew = OnSave(FALSE);
  3968. }
  3969. // If the user did not cancel the operation, clear the drawing area
  3970. if (iDoNew != IDCANCEL)
  3971. {
  3972. // Go to the first page, as this won't be deleted - stops flashing
  3973. // with locking contents for each page delete
  3974. OnFirstPage();
  3975. GotoPosition(0, 0);
  3976. // lock the drawing area
  3977. LockDrawingArea();
  3978. // Save the current lock status
  3979. SaveLock();
  3980. // Get the Page Order Lock (with an invisible dialog)
  3981. BOOL bGotLock = GetLock(WB_LOCK_TYPE_PAGE_ORDER, SW_HIDE);
  3982. if (!bGotLock)
  3983. {
  3984. RestoreLock();
  3985. }
  3986. else
  3987. {
  3988. UINT uiReturn;
  3989. // Remove all the pages
  3990. uiReturn = g_pwbCore->WBP_ContentsDelete();
  3991. if (uiReturn != 0)
  3992. {
  3993. DefaultExceptionHandler(WBFE_RC_WB, uiReturn);
  3994. return;
  3995. }
  3996. // if there is only one page, the new is implemented just as a page-
  3997. // clear, so we don't need to go into NEW_IN_PROGRESS substate.
  3998. if (g_pwbCore->WBP_ContentsCountPages() > 1)
  3999. {
  4000. // set substate to show we're doing a new
  4001. SetSubstate(SUBSTATE_NEW_IN_PROGRESS);
  4002. }
  4003. else
  4004. {
  4005. // Restore the lock status
  4006. RestoreLock();
  4007. }
  4008. // Clear the associated file name
  4009. ZeroMemory(m_strFileName, sizeof(m_strFileName));
  4010. // Update the window title with no file name
  4011. UpdateWindowTitle();
  4012. }
  4013. }
  4014. OnNewCleanup:
  4015. // unlock the drawing area if the new is not asynchronous
  4016. if ( (m_uiSubState != SUBSTATE_NEW_IN_PROGRESS)
  4017. && (!WB_ContentsLocked()))
  4018. {
  4019. UnlockDrawingArea();
  4020. }
  4021. return;
  4022. }
  4023. //
  4024. //
  4025. // Function: OnNextPage
  4026. //
  4027. // Purpose: Move to the next worksheet in the pages list
  4028. //
  4029. //
  4030. void WbMainWindow::OnNextPage(void)
  4031. {
  4032. // ignore this command if in presentation mode
  4033. if ( (m_uiState == IN_CALL)
  4034. && (!WB_PresentationMode()))
  4035. {
  4036. // Go to the next page
  4037. GotoPage(PG_GetNextPage(m_hCurrentPage));
  4038. }
  4039. }
  4040. //
  4041. //
  4042. // Function: OnPrevPage
  4043. //
  4044. // Purpose: Move to the previous worksheet in the pages list
  4045. //
  4046. //
  4047. void WbMainWindow::OnPrevPage(void)
  4048. {
  4049. // ignore this command if in presentation mode
  4050. if ( (m_uiState == IN_CALL)
  4051. && (!WB_PresentationMode()))
  4052. {
  4053. // Go to the previous page
  4054. GotoPage(PG_GetPreviousPage(m_hCurrentPage));
  4055. }
  4056. }
  4057. //
  4058. //
  4059. // Function: OnFirstPage
  4060. //
  4061. // Purpose: Move to the first worksheet in the pages list
  4062. //
  4063. //
  4064. void WbMainWindow::OnFirstPage(void)
  4065. {
  4066. // ignore this command if in presentation mode
  4067. if ( (m_uiState == IN_CALL)
  4068. && (!WB_PresentationMode()))
  4069. {
  4070. // Go to the first page
  4071. WB_PAGE_HANDLE hPage;
  4072. g_pwbCore->WBP_PageHandle(WB_PAGE_HANDLE_NULL, PAGE_FIRST, &hPage);
  4073. GotoPage(hPage);
  4074. }
  4075. }
  4076. //
  4077. //
  4078. // Function: OnLastPage
  4079. //
  4080. // Purpose: Move to the last worksheet in the pages list
  4081. //
  4082. //
  4083. void WbMainWindow::OnLastPage(void)
  4084. {
  4085. // ignore this command if in presentation mode
  4086. if ( (m_uiState == IN_CALL)
  4087. && (!WB_PresentationMode()))
  4088. {
  4089. // Go to the last page
  4090. WB_PAGE_HANDLE hPage;
  4091. g_pwbCore->WBP_PageHandle(WB_PAGE_HANDLE_NULL, PAGE_LAST, &hPage);
  4092. GotoPage(hPage);
  4093. }
  4094. }
  4095. //
  4096. //
  4097. // Function: OnGotoPage
  4098. //
  4099. // Purpose: Move to the specified page (if it exists)
  4100. //
  4101. //
  4102. void WbMainWindow::OnGotoPage(void)
  4103. {
  4104. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnGotoPage");
  4105. // ignore this command if in presentation mode
  4106. if ( (m_uiState == IN_CALL)
  4107. && (!WB_PresentationMode()))
  4108. {
  4109. // Get the requested page number from the pages group
  4110. UINT uiPageNumber = m_AG.GetCurrentPageNumber();
  4111. // Goto the page
  4112. GotoPageNumber(uiPageNumber);
  4113. }
  4114. }
  4115. //
  4116. //
  4117. // Function: GotoPage
  4118. //
  4119. // Purpose: Move to the specified page
  4120. //
  4121. //
  4122. void WbMainWindow::GotoPage(WB_PAGE_HANDLE hPageNew)
  4123. {
  4124. BOOL inEditField;
  4125. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::GotoPage");
  4126. inEditField = m_AG.IsChildEditField(::GetFocus());
  4127. // If we are changing page
  4128. if (hPageNew != m_hCurrentPage)
  4129. {
  4130. m_drawingArea.CancelDrawingMode();
  4131. // Attach the new page to the drawing area
  4132. m_hCurrentPage = hPageNew;
  4133. m_drawingArea.Attach(m_hCurrentPage);
  4134. // Update the local user information with the new page
  4135. if (m_pLocalUser != NULL)
  4136. m_pLocalUser->SetPage(m_hCurrentPage);
  4137. // Show that we need to update the sync position
  4138. m_bSyncUpdateNeeded = TRUE;
  4139. PAGE_POSITION *mapob = NULL;
  4140. POSITION position = m_pageToPosition.GetHeadPosition();
  4141. BOOL bFound = FALSE;
  4142. while (position && !bFound)
  4143. {
  4144. mapob = (PAGE_POSITION *)m_pageToPosition.GetNext(position);
  4145. if ( mapob && mapob->hPage == hPageNew)
  4146. {
  4147. bFound = TRUE;
  4148. }
  4149. }
  4150. if (!bFound)
  4151. {
  4152. // page not in map, so go to the top-left
  4153. //CHANGED BY RAND - to fix memory leak
  4154. GotoPosition( 0, 0);
  4155. }
  4156. else
  4157. {
  4158. if(mapob)
  4159. {
  4160. GotoPosition(mapob->position.x, mapob->position.y);
  4161. }
  4162. }
  4163. }
  4164. // Update the status display
  4165. UpdateStatus();
  4166. // set the focus back to the drawing area
  4167. if (!inEditField)
  4168. {
  4169. ::SetFocus(m_drawingArea.m_hwnd);
  4170. }
  4171. }
  4172. //
  4173. //
  4174. // Function: GotoPageNumber
  4175. //
  4176. // Purpose: Move to the specified page
  4177. //
  4178. //
  4179. void WbMainWindow::GotoPageNumber(UINT uiPageNumber)
  4180. {
  4181. GotoPage(PG_GetPageNumber(uiPageNumber));
  4182. }
  4183. //
  4184. //
  4185. // Function: GotoPosition
  4186. //
  4187. // Purpose: Move to the specified position within the page
  4188. //
  4189. //
  4190. void WbMainWindow::GotoPosition(int x, int y)
  4191. {
  4192. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::GotoPosition");
  4193. // Move the drawing area to the new position
  4194. m_drawingArea.GotoPosition(x, y);
  4195. // The user's view has changed
  4196. PositionUpdated();
  4197. }
  4198. //
  4199. //
  4200. // Function: GotoSyncPosition
  4201. //
  4202. // Purpose: Move to the the current sync position
  4203. //
  4204. //
  4205. void WbMainWindow::GotoSyncPosition(void)
  4206. {
  4207. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::GotoSyncPosition");
  4208. //
  4209. // Get the local user to determine the new position.
  4210. //
  4211. if (!m_pLocalUser)
  4212. {
  4213. ERROR_OUT(("Skipping GotoSyncPosition; no local user object"));
  4214. return;
  4215. }
  4216. m_pLocalUser->GetSyncPosition();
  4217. //
  4218. // If the page is different to where we are currently, get the number
  4219. // of the page and select the current page
  4220. //
  4221. if (m_pLocalUser->Page() != m_hCurrentPage)
  4222. {
  4223. GotoPageNumber(g_pwbCore->WBP_PageNumberFromHandle(m_pLocalUser->Page()));
  4224. }
  4225. // Get the requested position from the user
  4226. RECT rectVisibleUser;
  4227. m_pLocalUser->GetVisibleRect(&rectVisibleUser);
  4228. // Scroll to the required position
  4229. GotoPosition(rectVisibleUser.left, rectVisibleUser.top);
  4230. // Make sure we are zoomed / not zoomed as appropriate
  4231. if ((m_pLocalUser->GetZoom()) != m_drawingArea.Zoomed())
  4232. {
  4233. OnZoom();
  4234. }
  4235. //
  4236. // Reset the sync position update flag that will have been turned on by
  4237. // the calls above. We do not want to change the current sync position
  4238. // when we are merely changing our position to match that set by
  4239. // another user in the call.
  4240. //
  4241. m_bSyncUpdateNeeded = FALSE;
  4242. // Inform the other users that we have changed position
  4243. m_pLocalUser->Update();
  4244. }
  4245. //
  4246. //
  4247. // Function: OnGotoUserPosition
  4248. //
  4249. // Purpose: Move to the the current position of the specified user
  4250. //
  4251. //
  4252. void WbMainWindow::OnGotoUserPosition(LPARAM lParam)
  4253. {
  4254. UINT uiPageNumber = 1;
  4255. WB_PAGE_HANDLE hPage;
  4256. WbUser * pUser;
  4257. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnGotoUserPosition");
  4258. //
  4259. // If the drawing area is busy, ignore this command. This is unlikely
  4260. // since this command is generated by selecting a menu entry on a user
  4261. // icon. The user should not therefore be drawing on the page by the
  4262. // time we get the message.
  4263. //
  4264. if (m_drawingArea.IsBusy())
  4265. {
  4266. TRACE_DEBUG(("drawing area is busy just now.."));
  4267. return;
  4268. }
  4269. //
  4270. // Get a user object (throws an exception if the handle specified is no
  4271. // longer valid).
  4272. //
  4273. pUser = WB_GetUser((POM_OBJECT) lParam);
  4274. if (!pUser)
  4275. {
  4276. WARNING_OUT(("Can't handle OnGotoUserPosition; can't get user object for 0x%08x", lParam));
  4277. return;
  4278. }
  4279. //
  4280. // Get the requested page from the user.
  4281. //
  4282. hPage = pUser->Page();
  4283. //
  4284. // Quit if the requested page is not valid locally.
  4285. //
  4286. if (hPage == WB_PAGE_HANDLE_NULL)
  4287. {
  4288. TRACE_DEBUG(("Page is not valid locally"));
  4289. return;
  4290. }
  4291. //
  4292. // Don't go to user's position if it's on another page and we're in
  4293. // presentation mode (this shouldn't normally happen, since we should
  4294. // all be on the same page, but there is a window at the start-up of
  4295. // presentation mode.
  4296. //
  4297. if ( (hPage == m_hCurrentPage) ||
  4298. (!WB_PresentationMode()) )
  4299. {
  4300. //
  4301. // If the page is different to where we are currently, get the
  4302. // number of the page and select the current page.
  4303. //
  4304. if (hPage != m_hCurrentPage)
  4305. {
  4306. uiPageNumber = g_pwbCore->WBP_PageNumberFromHandle(hPage);
  4307. GotoPageNumber(uiPageNumber);
  4308. }
  4309. //
  4310. // Get the requested position from the user and scroll to it.
  4311. //
  4312. RECT rectVisibleUser;
  4313. pUser->GetVisibleRect(&rectVisibleUser);
  4314. GotoPosition(rectVisibleUser.left, rectVisibleUser.top);
  4315. //
  4316. // Zoom/unzoom if the sync zoom state is different to our current
  4317. // zoom state.
  4318. //
  4319. if ( (m_pLocalUser->GetZoom()) != (m_drawingArea.Zoomed()) )
  4320. {
  4321. TRACE_DEBUG(("Change zoom state"));
  4322. OnZoom();
  4323. }
  4324. }
  4325. }
  4326. //
  4327. //
  4328. // Function: OnGotoUserPointer
  4329. //
  4330. // Purpose: Move to the pointer position of the specified user
  4331. //
  4332. //
  4333. void WbMainWindow::OnGotoUserPointer(LPARAM lParam)
  4334. {
  4335. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnGotoUserPointer");
  4336. // If the drawing area is busy, ignore this command.
  4337. // This is unlikely since this command is generated by selecting
  4338. // a menu entry on a user icon. The user should not therefore be
  4339. // drawing on the page by the time we get the message.
  4340. if (!m_drawingArea.IsBusy())
  4341. {
  4342. // Get a user object (throws an exception if the
  4343. // handle specified is no longer valid).
  4344. WbUser* pUser = WB_GetUser((POM_OBJECT) lParam);
  4345. if (!pUser)
  4346. {
  4347. WARNING_OUT(("Can't handle OnGotoUserPointer; can't get user object for 0x%08x", lParam));
  4348. return;
  4349. }
  4350. DCWbGraphicPointer* pPointer = pUser->GetPointer();
  4351. ASSERT(pPointer != NULL);
  4352. // Continue only if the user is using the pointer
  4353. if (pPointer->IsActive())
  4354. {
  4355. // Get the requested page from the user
  4356. WB_PAGE_HANDLE hPage = pPointer->Page();
  4357. // Check that the requested page is valid locally
  4358. if (hPage != WB_PAGE_HANDLE_NULL)
  4359. {
  4360. // If the pointer is on a different page, change to the
  4361. // correct page.
  4362. if (hPage != m_hCurrentPage)
  4363. {
  4364. GotoPageNumber(g_pwbCore->WBP_PageNumberFromHandle(hPage));
  4365. }
  4366. // Move within the page if the pointer is not wholly visible
  4367. // in the drawing area window.
  4368. RECT rectPointer;
  4369. RECT rcVis;
  4370. RECT rcT;
  4371. pPointer->GetBoundsRect(&rectPointer);
  4372. m_drawingArea.GetVisibleRect(&rcVis);
  4373. ::IntersectRect(&rcT, &rcVis, &rectPointer);
  4374. if (!::EqualRect(&rcT, &rectPointer))
  4375. {
  4376. // Adjust the position so that the pointer is shown
  4377. // in the centre of the window.
  4378. POINT position;
  4379. SIZE size;
  4380. position.x = rectPointer.left;
  4381. position.y = rectPointer.top;
  4382. size.cx = (rcVis.right - rcVis.left) - (rectPointer.right - rectPointer.left);
  4383. size.cy = (rcVis.bottom - rcVis.top) - (rectPointer.bottom - rectPointer.top);
  4384. position.x += -size.cx / 2;
  4385. position.y += -size.cy / 2;
  4386. // Scroll to the required position
  4387. GotoPosition(position.x, position.y);
  4388. }
  4389. }
  4390. }
  4391. }
  4392. }
  4393. //
  4394. //
  4395. // Function: LoadFile
  4396. //
  4397. // Purpose: Load a metafile into the application. Errors are reported
  4398. // to the caller by the return code.
  4399. //
  4400. //
  4401. void WbMainWindow::LoadFile
  4402. (
  4403. LPCSTR szLoadFileName
  4404. )
  4405. {
  4406. UINT uRes;
  4407. // Check we're in idle state
  4408. if (!IsIdle())
  4409. {
  4410. // post an error message indicating the whiteboard is busy
  4411. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, WB_RC_BUSY);
  4412. goto UserPointerCleanup;
  4413. }
  4414. if (*szLoadFileName)
  4415. {
  4416. // Change the cursor to "wait"
  4417. ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
  4418. // Save the current lock
  4419. SaveLock();
  4420. // Get the Page Order Lock (with an invisible dialog)
  4421. BOOL bGotLock = GetLock(WB_LOCK_TYPE_PAGE_ORDER, SW_HIDE);
  4422. if (!bGotLock)
  4423. {
  4424. RestoreLock();
  4425. goto UserPointerCleanup;
  4426. }
  4427. // Load the file
  4428. uRes = g_pwbCore->WBP_ContentsLoad(szLoadFileName);
  4429. if (uRes != 0)
  4430. {
  4431. DefaultExceptionHandler(WBFE_RC_WB, uRes);
  4432. return;
  4433. }
  4434. // Set the window title to the new file name
  4435. lstrcpy(m_strFileName, szLoadFileName);
  4436. // Update the window title with the new file name
  4437. UpdateWindowTitle();
  4438. // Set the state to say that we are loading a file
  4439. SetSubstate(SUBSTATE_LOADING);
  4440. }
  4441. UserPointerCleanup:
  4442. // Restore the cursor
  4443. ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
  4444. }
  4445. //
  4446. //
  4447. // Function: OnDropFiles
  4448. //
  4449. // Purpose: Files have been dropped onto the Whiteboard window
  4450. //
  4451. //
  4452. void WbMainWindow::OnDropFiles(HDROP hDropInfo)
  4453. {
  4454. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnDropFiles");
  4455. UINT uiFilesDropped = 0;
  4456. UINT eachfile;
  4457. // Get the total number of files dropped
  4458. uiFilesDropped = ::DragQueryFile(hDropInfo, (UINT) -1, NULL, (UINT) 0);
  4459. // release mouse capture in case we report any errors (message boxes
  4460. // won't repsond to mouse clicks if we don't)
  4461. ReleaseCapture();
  4462. if( UsersMightLoseData( NULL, NULL ) ) // bug NM4db:418
  4463. goto bail_out;
  4464. // Don't prompt to save file if we're already loading
  4465. int iOnSave;
  4466. if( m_uiSubState != SUBSTATE_LOADING )
  4467. {
  4468. // Check whether there are changes to be saved
  4469. iOnSave = QuerySaveRequired(TRUE);
  4470. }
  4471. else
  4472. {
  4473. goto bail_out;
  4474. }
  4475. if( iOnSave == IDYES )
  4476. {
  4477. // User wants to save the drawing area contents
  4478. int iResult = OnSave(TRUE);
  4479. if( iResult == IDOK )
  4480. {
  4481. // Update the window title with the new file name
  4482. UpdateWindowTitle();
  4483. }
  4484. else
  4485. {
  4486. // cancelled out of save, so cancel the open operation
  4487. goto bail_out;
  4488. }
  4489. }
  4490. // see if user canceled the whole drop
  4491. if( iOnSave == IDCANCEL )
  4492. goto bail_out;
  4493. for (eachfile = 0; eachfile < uiFilesDropped; eachfile++)
  4494. {
  4495. // Retrieve each file name
  4496. char szDropFileName[256];
  4497. ::DragQueryFile(hDropInfo, eachfile,
  4498. szDropFileName, 256);
  4499. TRACE_MSG(("Loading file: %s", szDropFileName));
  4500. // Load the file
  4501. // If this is a valid whiteboard file, the action is simply to load it
  4502. if (g_pwbCore->WBP_ValidateFile(szDropFileName, NULL) == 0)
  4503. {
  4504. LoadFile(szDropFileName);
  4505. }
  4506. else
  4507. {
  4508. ::Message(NULL, IDS_MSG_CAPTION,IDS_MSG_BAD_FILE_FORMAT);
  4509. }
  4510. }
  4511. bail_out:
  4512. ::DragFinish(hDropInfo);
  4513. }
  4514. //
  4515. //
  4516. // Function: OnOpen
  4517. //
  4518. // Purpose: Load a metafile into the application.
  4519. //
  4520. //
  4521. void WbMainWindow::OnOpen(void)
  4522. {
  4523. int iOnSave;
  4524. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnOpen");
  4525. if( UsersMightLoseData( NULL, NULL ) ) // bug NM4db:418
  4526. return;
  4527. // Check we're in idle state
  4528. if ( (m_uiState != IN_CALL) || (m_uiSubState == SUBSTATE_NEW_IN_PROGRESS))
  4529. {
  4530. // post an error message indicating the whiteboard is busy
  4531. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, WB_RC_BUSY);
  4532. return;
  4533. }
  4534. // Don't prompt to save file if we're already loading
  4535. if (m_uiSubState != SUBSTATE_LOADING)
  4536. {
  4537. // Check whether there are changes to be saved
  4538. iOnSave = QuerySaveRequired(TRUE);
  4539. }
  4540. else
  4541. {
  4542. iOnSave = IDNO;
  4543. }
  4544. if (iOnSave == IDYES)
  4545. {
  4546. // User wants to save the drawing area contents
  4547. int iResult = OnSave(TRUE);
  4548. if (iResult == IDOK)
  4549. {
  4550. UpdateWindowTitle();
  4551. }
  4552. else
  4553. {
  4554. // cancelled out of Save As, so cancel the open operation
  4555. iOnSave = IDCANCEL;
  4556. }
  4557. }
  4558. // Only continue if the user has not cancelled the operation
  4559. if (iOnSave != IDCANCEL)
  4560. {
  4561. OPENFILENAME ofn;
  4562. TCHAR szFileName[_MAX_PATH];
  4563. TCHAR szFileTitle[64];
  4564. TCHAR strLoadFilter[2*_MAX_PATH];
  4565. TCHAR strDefaultExt[_MAX_PATH];
  4566. TCHAR strDefaultPath[2*_MAX_PATH];
  4567. TCHAR * pStr;
  4568. UINT strSize = 0;
  4569. UINT totalSize;
  4570. // Build the filter for loadable files
  4571. pStr = strLoadFilter;
  4572. totalSize = 2*_MAX_PATH;
  4573. // These must be NULL separated, with a double NULL at the end
  4574. strSize = ::LoadString(g_hInstance, IDS_FILTER_WHT, pStr, totalSize) + 1;
  4575. pStr += strSize;
  4576. ASSERT(totalSize > strSize);
  4577. totalSize -= strSize;
  4578. strSize = ::LoadString(g_hInstance, IDS_FILTER_WHT_SPEC, pStr, totalSize) + 1;
  4579. pStr += strSize;
  4580. ASSERT(totalSize > strSize);
  4581. totalSize -= strSize;
  4582. strSize = ::LoadString(g_hInstance, IDS_FILTER_ALL, pStr, totalSize) + 1;
  4583. pStr += strSize;
  4584. ASSERT(totalSize > strSize);
  4585. totalSize -= strSize;
  4586. strSize = ::LoadString(g_hInstance, IDS_FILTER_ALL_SPEC, pStr, totalSize) + 1;
  4587. pStr += strSize;
  4588. ASSERT(totalSize > strSize);
  4589. totalSize -= strSize;
  4590. *pStr = 0;
  4591. //
  4592. // Setup the OPENFILENAME struct
  4593. //
  4594. ZeroMemory(&ofn, sizeof(ofn));
  4595. ofn.lStructSize = sizeof(ofn);
  4596. ofn.hwndOwner = m_hwnd;
  4597. // No file name supplied to begin with
  4598. szFileName[0] = 0;
  4599. ofn.lpstrFile = szFileName;
  4600. ofn.nMaxFile = _MAX_PATH;
  4601. // Default Extension: .WHT
  4602. ::LoadString(g_hInstance, IDS_EXT_WHT, strDefaultExt, sizeof(strDefaultExt));
  4603. ofn.lpstrDefExt = strDefaultExt;
  4604. // Default file title is empty
  4605. szFileTitle[0] = 0;
  4606. ofn.lpstrFileTitle = szFileTitle;
  4607. ofn.nMaxFileTitle = 64;
  4608. // Open flags
  4609. ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_EXPLORER;
  4610. ofn.hInstance = g_hInstance;
  4611. // Filter
  4612. ofn.lpstrFilter = strLoadFilter;
  4613. // Default path
  4614. if (GetDefaultPath(strDefaultPath, sizeof(strDefaultPath)))
  4615. ofn.lpstrInitialDir = strDefaultPath;
  4616. // Get user input, continue only if the user selects the OK button
  4617. if (::GetOpenFileName(&ofn))
  4618. {
  4619. // Change the cursor to "wait"
  4620. ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
  4621. // if we're currently loading a file, cancel it, not releasing
  4622. // the page order lock, because we need it immediately afterwards
  4623. if (m_uiSubState == SUBSTATE_LOADING)
  4624. {
  4625. CancelLoad(FALSE);
  4626. }
  4627. // Load the file
  4628. LoadFile(ofn.lpstrFile);
  4629. }
  4630. }
  4631. }
  4632. //
  4633. //
  4634. // Function: GetFileName
  4635. //
  4636. // Purpose: Get a file name for saving the contents
  4637. //
  4638. //
  4639. int WbMainWindow::GetFileName(void)
  4640. {
  4641. OPENFILENAME ofn;
  4642. int iResult;
  4643. TCHAR szFileTitle[64];
  4644. TCHAR strSaveFilter[2*_MAX_PATH];
  4645. TCHAR strDefaultExt[_MAX_PATH];
  4646. TCHAR strDefaultPath[2 * _MAX_PATH];
  4647. TCHAR szFileName[2*_MAX_PATH];
  4648. TCHAR * pStr;
  4649. UINT strSize = 0;
  4650. UINT totalSize;
  4651. //
  4652. // If we are already displaying a "Save As" dialog, dismiss it and create
  4653. // a new one. This can happen if Win95 shuts down whilst WB is
  4654. // displaying the "Save As" dialog and the use selects "Yes" when asked
  4655. // whether they want to save the contents - a second "Save As dialog
  4656. // appears on top of the first.
  4657. //
  4658. if (m_bInSaveDialog)
  4659. {
  4660. CancelSaveDialog();
  4661. }
  4662. // Build the filter for save files
  4663. pStr = strSaveFilter;
  4664. totalSize = 2*_MAX_PATH;
  4665. // These must be NULL separated, with a double NULL at the end
  4666. strSize = ::LoadString(g_hInstance, IDS_FILTER_WHT, pStr, totalSize) + 1;
  4667. pStr += strSize;
  4668. ASSERT(totalSize > strSize);
  4669. totalSize -= strSize;
  4670. strSize = ::LoadString(g_hInstance, IDS_FILTER_WHT_SPEC, pStr, totalSize) + 1;
  4671. pStr += strSize;
  4672. ASSERT(totalSize > strSize);
  4673. totalSize -= strSize;
  4674. strSize = ::LoadString(g_hInstance, IDS_FILTER_ALL, pStr, totalSize) + 1;
  4675. pStr += strSize;
  4676. ASSERT(totalSize > strSize);
  4677. totalSize -= strSize;
  4678. strSize = ::LoadString(g_hInstance, IDS_FILTER_ALL_SPEC, pStr, totalSize) + 1;
  4679. pStr += strSize;
  4680. ASSERT(totalSize > strSize);
  4681. totalSize -= strSize;
  4682. *pStr = 0;
  4683. //
  4684. // Setup the OPENFILENAME struct
  4685. //
  4686. ZeroMemory(&ofn, sizeof(ofn));
  4687. ofn.lStructSize = sizeof(ofn);
  4688. ofn.hwndOwner = m_hwnd;
  4689. lstrcpy(szFileName, m_strFileName);
  4690. ofn.lpstrFile = szFileName;
  4691. ofn.nMaxFile = _MAX_PATH;
  4692. // Build the default extension string
  4693. ::LoadString(g_hInstance, IDS_EXT_WHT, strDefaultExt, sizeof(strDefaultExt));
  4694. ofn.lpstrDefExt = strDefaultExt;
  4695. szFileTitle[0] = 0;
  4696. ofn.lpstrFileTitle = szFileTitle;
  4697. ofn.nMaxFileTitle = 64;
  4698. // Save flags
  4699. ofn.Flags = OFN_HIDEREADONLY | OFN_NOREADONLYRETURN |
  4700. OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
  4701. ofn.hInstance = g_hInstance;
  4702. // Filter
  4703. ofn.lpstrFilter = strSaveFilter;
  4704. // Default path
  4705. if (GetDefaultPath(strDefaultPath, sizeof(strDefaultPath)))
  4706. ofn.lpstrInitialDir = strDefaultPath;
  4707. m_bInSaveDialog = TRUE;
  4708. if (::GetSaveFileName(&ofn))
  4709. {
  4710. // The user selected OK
  4711. iResult = IDOK;
  4712. lstrcpy(m_strFileName, szFileName);
  4713. }
  4714. else
  4715. {
  4716. iResult = IDCANCEL;
  4717. }
  4718. m_bInSaveDialog = FALSE;
  4719. return iResult;
  4720. }
  4721. //
  4722. //
  4723. // Function: OnSave
  4724. //
  4725. // Purpose: Save the contents of the Whiteboard using the current file
  4726. // name (or prompting for a new name if there is no current).
  4727. //
  4728. //
  4729. int WbMainWindow::OnSave(BOOL bPrompt)
  4730. {
  4731. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnSave");
  4732. int iResult = IDOK;
  4733. // save the old file name in case there's an error
  4734. TCHAR *strOldName;
  4735. UINT fileNameSize = lstrlen(m_strFileName);
  4736. strOldName = new TCHAR[fileNameSize+1];
  4737. if (!strOldName)
  4738. {
  4739. ERROR_OUT(("OnSave: failed to allocate strOldName TCHAR array, fail"));
  4740. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, WB_RC_BUSY);
  4741. return(iResult);
  4742. }
  4743. else
  4744. {
  4745. lstrcpy(strOldName, m_strFileName);
  4746. }
  4747. BOOL bNewName = FALSE;
  4748. if (!IsIdle())
  4749. {
  4750. // post an error message indicating the whiteboard is busy
  4751. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, WB_RC_BUSY);
  4752. return(iResult);
  4753. }
  4754. // Check whether there is a filename available for use
  4755. if (!fileNameSize || bPrompt)
  4756. {
  4757. // Get user input, continue only if the user selects the OK button
  4758. iResult = GetFileName();
  4759. if (iResult == IDOK)
  4760. {
  4761. // entering a blank file name is treated as cancelling the save
  4762. if (!lstrlen(m_strFileName))
  4763. {
  4764. lstrcpy(m_strFileName, strOldName);
  4765. iResult = IDCANCEL;
  4766. }
  4767. else
  4768. {
  4769. // flag that we've changed the contents file name
  4770. bNewName = TRUE;
  4771. }
  4772. }
  4773. }
  4774. // Now save the file
  4775. if ((iResult == IDOK) && lstrlen(m_strFileName))
  4776. {
  4777. WIN32_FIND_DATA findFileData;
  4778. HANDLE hFind;
  4779. // Get attributes
  4780. hFind = ::FindFirstFile(m_strFileName, &findFileData);
  4781. if (hFind != INVALID_HANDLE_VALUE)
  4782. {
  4783. ::FindClose(hFind);
  4784. // This is a read-only file; we can't change its contents
  4785. if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
  4786. {
  4787. WARNING_OUT(("Dest file %s is read only", m_strFileName));
  4788. ::Message(NULL, IDS_SAVE, IDS_SAVE_READ_ONLY);
  4789. // If the file name was changed for this save then undo
  4790. // the change
  4791. if (bNewName)
  4792. {
  4793. lstrcpy(m_strFileName, strOldName);
  4794. bNewName = FALSE;
  4795. }
  4796. // Change the return code to indicate no save was made
  4797. iResult = IDCANCEL;
  4798. return(iResult);
  4799. }
  4800. }
  4801. // Change the cursor to "wait"
  4802. ::SetCursor(::LoadCursor(NULL,IDC_WAIT));
  4803. // Write the file
  4804. if (g_pwbCore->WBP_ContentsSave(m_strFileName) != 0)
  4805. {
  4806. // Show that an error occurred saving the file.
  4807. WARNING_OUT(("Error saving file"));
  4808. ::Message(NULL, IDS_SAVE, IDS_SAVE_ERROR);
  4809. // If the file name was changed for this save then undo
  4810. // the change
  4811. if (bNewName)
  4812. {
  4813. lstrcpy(m_strFileName, strOldName);
  4814. bNewName = FALSE;
  4815. }
  4816. // Change the return code to indicate no save was made
  4817. iResult = IDCANCEL;
  4818. }
  4819. // Restore the cursor
  4820. ::SetCursor(::LoadCursor(NULL,IDC_ARROW));
  4821. }
  4822. // if the contents file name has changed as a result of the save then
  4823. // update the window title
  4824. if (bNewName)
  4825. {
  4826. UpdateWindowTitle();
  4827. }
  4828. delete [] strOldName;
  4829. return(iResult);
  4830. }
  4831. //
  4832. // CancelSaveDialog()
  4833. // This cancels the save as dialog if up and we need to kill it to continue.
  4834. // We walk back up the owner chain in case the save dialog puts up help or
  4835. // other owned windows.
  4836. //
  4837. void WbMainWindow::CancelSaveDialog(void)
  4838. {
  4839. WBFINDDIALOG wbf;
  4840. ASSERT(m_bInSaveDialog);
  4841. wbf.hwndOwner = m_hwnd;
  4842. wbf.hwndDialog = NULL;
  4843. EnumThreadWindows(::GetCurrentThreadId(), WbFindCurrentDialog, (LPARAM)&wbf);
  4844. if (wbf.hwndDialog)
  4845. {
  4846. // Found it!
  4847. ::SendMessage(wbf.hwndDialog, WM_COMMAND, IDCANCEL, 0);
  4848. }
  4849. m_bInSaveDialog = FALSE;
  4850. }
  4851. BOOL CALLBACK WbFindCurrentDialog(HWND hwndNext, LPARAM lParam)
  4852. {
  4853. WBFINDDIALOG * pwbf = (WBFINDDIALOG *)lParam;
  4854. // Is this a dialog, owned by the main window?
  4855. if ((::GetClassLong(hwndNext, GCW_ATOM) == 0x8002) &&
  4856. (::GetWindow(hwndNext, GW_OWNER) == pwbf->hwndOwner))
  4857. {
  4858. pwbf->hwndDialog = hwndNext;
  4859. return(FALSE);
  4860. }
  4861. return(TRUE);
  4862. }
  4863. //
  4864. //
  4865. // Function: OnClose
  4866. //
  4867. // Purpose: Close the Whiteboard
  4868. //
  4869. //
  4870. void WbMainWindow::OnClose()
  4871. {
  4872. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnClose");
  4873. int iOnSave = IDOK;
  4874. KillInitDlg();
  4875. m_drawingArea.CancelDrawingMode();
  4876. m_drawingArea.RemoveMarker(NULL);
  4877. m_drawingArea.GetMarker()->DeleteAllMarkers( NULL );
  4878. m_AG.SaveSettings();
  4879. // If we got here, by way of OnDestroy from the DCL cores or
  4880. // by system shutdown, then assume that user responded already to the
  4881. // save-changes dialog that would have poped up during conf's global shutdown
  4882. // message. We don't need to ask 'em again. What tangled webs......
  4883. if ((!m_bQuerySysShutdown) && (IsIdle()))
  4884. {
  4885. // Check whether there are changes to be saved
  4886. iOnSave = QuerySaveRequired(TRUE);
  4887. if (iOnSave == IDYES)
  4888. {
  4889. // User wants to save the drawing area contents
  4890. iOnSave = OnSave(TRUE);
  4891. }
  4892. }
  4893. // If the exit was not cancelled, close the application
  4894. if (iOnSave != IDCANCEL)
  4895. {
  4896. // Mark state as closing - stops any queued events being processed
  4897. m_uiState = CLOSING;
  4898. //PUTBACK BY RAND - the progress timer meter is kinda the heart beat
  4899. // of this thing which I ripped out when I removed the
  4900. // progress meter. I put it back to fix 1476.
  4901. if (m_bTimerActive)
  4902. {
  4903. ::KillTimer(m_hwnd, TIMERID_PROGRESS_METER);
  4904. m_bTimerActive = FALSE;
  4905. }
  4906. m_drawingArea.ShutDownDC();
  4907. // Close the application
  4908. ::PostQuitMessage(0);
  4909. }
  4910. }
  4911. //
  4912. //
  4913. // Function: OnClearPage
  4914. //
  4915. // Purpose: Clear the Whiteboard drawing area. The user is prompted to
  4916. // choose clearing of foreground, background or both.
  4917. //
  4918. //
  4919. void WbMainWindow::OnClearPage(void)
  4920. {
  4921. int iResult;
  4922. BOOL bWasPosted;
  4923. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnClearPage");
  4924. if( UsersMightLoseData( &bWasPosted, NULL ) ) // bug NM4db:418
  4925. return;
  4926. if( bWasPosted )
  4927. iResult = IDYES;
  4928. else
  4929. iResult = ::Message(NULL, IDS_CLEAR_CAPTION, IDS_CLEAR_MESSAGE, MB_YESNO | MB_ICONQUESTION);
  4930. if (iResult == IDYES)
  4931. {
  4932. TRACE_MSG(("User requested clear of page"));
  4933. // lock the drawing area
  4934. LockDrawingArea();
  4935. // Save the current lock status
  4936. SaveLock();
  4937. // Get the Page Order Lock (with an invisible dialog)
  4938. BOOL bGotLock = GetLock(WB_LOCK_TYPE_PAGE_ORDER, SW_HIDE);
  4939. if( bGotLock )
  4940. {
  4941. // clear only if we got the page lock (NM4db:470)
  4942. m_drawingArea.Clear();
  4943. GotoPosition(0, 0);
  4944. }
  4945. RestoreLock();
  4946. UnlockDrawingArea();
  4947. }
  4948. }
  4949. //
  4950. //
  4951. // Function: OnDelete
  4952. //
  4953. // Purpose: Delete the current selection
  4954. //
  4955. //
  4956. void WbMainWindow::OnDelete()
  4957. {
  4958. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnDelete");
  4959. DCWbGraphic* pGraphicCopy = NULL;
  4960. // cleanup select logic in case object context menu called us (bug 426)
  4961. m_drawingArea.SetLClickIgnore( FALSE );
  4962. // If the user currently has a graphic selected
  4963. if (m_drawingArea.GraphicSelected())
  4964. {
  4965. m_LastDeletedGraphic.BurnTrash();
  4966. // Delete the currently selected graphic and add to m_LastDeletedGraphic
  4967. m_drawingArea.DeleteSelection();
  4968. }
  4969. }
  4970. //
  4971. //
  4972. // Function: OnUndelete
  4973. //
  4974. // Purpose: Undo the last delete operation
  4975. //
  4976. //
  4977. void WbMainWindow::OnUndelete()
  4978. {
  4979. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnUndelete");
  4980. // If there is a deleted graphic to restore
  4981. if ( m_LastDeletedGraphic.GotTrash() )
  4982. {
  4983. // If the deleted graphic belongs to the current page
  4984. if (m_LastDeletedGraphic.Page() == m_hCurrentPage)
  4985. {
  4986. // Add the graphic back into the current page
  4987. m_LastDeletedGraphic.AddToPageLast(m_hCurrentPage);
  4988. // if the current tool is a select tool then select the new
  4989. // graphic, otherwise forget it.
  4990. if (m_pCurrentTool->ToolType() == TOOLTYPE_SELECT)
  4991. {
  4992. m_LastDeletedGraphic.SelectTrash();
  4993. m_LastDeletedGraphic.EmptyTrash();
  4994. }
  4995. else
  4996. {
  4997. // Free the local copy
  4998. m_LastDeletedGraphic.BurnTrash();
  4999. }
  5000. }
  5001. }
  5002. }
  5003. void WbMainWindow::OnSelectAll( void )
  5004. {
  5005. // turn off any selections
  5006. // cleanup select logic in case object context menu called us (bug 426)
  5007. m_drawingArea.SetLClickIgnore( FALSE );
  5008. // inhibit normal select-tool action
  5009. m_bSelectAllInProgress = TRUE;
  5010. //put us in select-tool mode first
  5011. OnSelectTool(IDM_SELECT);
  5012. // back to normal
  5013. m_bSelectAllInProgress = FALSE;
  5014. // now, select everything
  5015. m_drawingArea.SelectMarkerFromRect( NULL );
  5016. }
  5017. //
  5018. //
  5019. // Function: DoCopy
  5020. //
  5021. // Purpose: Copy the current selection to the clipboard
  5022. //
  5023. //
  5024. BOOL WbMainWindow::DoCopy(BOOL bRenderNow)
  5025. {
  5026. BOOL bResult = FALSE;
  5027. DCWbGraphicMarker *pMarker;
  5028. DCWbGraphic* pGraphic = m_drawingArea.GetSelection();
  5029. if (pGraphic != NULL)
  5030. {
  5031. pMarker = m_drawingArea.GetMarker();
  5032. if( pMarker->GetNumMarkers() > 1 )
  5033. {
  5034. // more objs than just pGraphic, do a multi-object-to-clipboard
  5035. // operation.
  5036. pGraphic = pMarker;
  5037. }
  5038. //else if == 1 then pMarker contains just pGraphic already
  5039. // so we do a single-object-to-clipboard operation.
  5040. // Copy the graphic (or multiple marker objects) to the clipboard
  5041. bResult = CLP_Copy(pGraphic, bRenderNow);
  5042. // If an error occurred during the copy, report it now
  5043. if (!bResult)
  5044. {
  5045. ::Message(NULL, IDS_COPY, IDS_COPY_ERROR);
  5046. }
  5047. }
  5048. return bResult;
  5049. }
  5050. //
  5051. //
  5052. // Function: OnCut
  5053. //
  5054. // Purpose: Cut the current selection
  5055. //
  5056. //
  5057. void WbMainWindow::OnCut()
  5058. {
  5059. // cleanup select logic in case object context menu called us (bug 426)
  5060. m_drawingArea.SetLClickIgnore( FALSE );
  5061. if (m_drawingArea.TextEditActive())
  5062. {
  5063. m_drawingArea.TextEditCut();
  5064. return;
  5065. }
  5066. if (DoCopy(TRUE))
  5067. {
  5068. // Graphic copied to the clipboard OK - delete it
  5069. m_drawingArea.DeleteSelection();
  5070. }
  5071. }
  5072. //
  5073. // OnCopy()
  5074. // Purpose: Copy the current selection to the clipboard
  5075. //
  5076. //
  5077. void WbMainWindow::OnCopy(void)
  5078. {
  5079. // cleanup select logic in case object context menu called us (bug 426)
  5080. m_drawingArea.SetLClickIgnore( FALSE );
  5081. if( m_drawingArea.TextEditActive() )
  5082. {
  5083. m_drawingArea.TextEditCopy();
  5084. return;
  5085. }
  5086. DoCopy(TRUE);
  5087. }
  5088. //
  5089. //
  5090. // Function: OnPaste
  5091. //
  5092. // Purpose: Paste the contents of the clipboard into the drawing pane
  5093. //
  5094. //
  5095. void WbMainWindow::OnPaste()
  5096. {
  5097. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnPaste");
  5098. // cleanup select logic in case object context menu called us (bug 426)
  5099. m_drawingArea.SetLClickIgnore( FALSE );
  5100. if (m_drawingArea.TextEditActive())
  5101. {
  5102. m_drawingArea.TextEditPaste();
  5103. return;
  5104. }
  5105. // Get the data from the clipboard
  5106. DCWbGraphic* pGraphic = CLP_Paste();
  5107. if (pGraphic != NULL)
  5108. {
  5109. TRACE_MSG(("Got graphic object from clipboard OK"));
  5110. //CHANGED BY RAND - have to handle marker sperately,
  5111. // marker objects are already added to
  5112. // m_hCurrentPage and positioned
  5113. if( pGraphic->IsGraphicTool() == enumGraphicMarker)
  5114. {
  5115. ((DCWbGraphicMarker *)pGraphic)->Update();
  5116. if( m_pCurrentTool->ToolType() == TOOLTYPE_SELECT )
  5117. {
  5118. // marker is already setup, just draw it
  5119. m_drawingArea.PutMarker(NULL);
  5120. }
  5121. else
  5122. {
  5123. // don't select anything, dump marker
  5124. m_drawingArea.RemoveMarker(NULL);
  5125. }
  5126. }
  5127. else // not a marker, deal with single object
  5128. {
  5129. RECT rcVis;
  5130. // Position the graphic at the top left of the visible area of the
  5131. // drawing area
  5132. m_drawingArea.GetVisibleRect(&rcVis);
  5133. pGraphic->MoveTo(rcVis.left, rcVis.top);
  5134. // Add the graphic to the page
  5135. pGraphic->AddToPageLast(m_hCurrentPage);
  5136. // if the current tool is a select tool then select the new
  5137. // object, otherwise forget it.
  5138. if( m_pCurrentTool->ToolType() == TOOLTYPE_SELECT )
  5139. m_drawingArea.SelectGraphic(pGraphic);
  5140. else
  5141. {
  5142. // Free the graphic
  5143. delete pGraphic;
  5144. }
  5145. }
  5146. }
  5147. else
  5148. {
  5149. TRACE_MSG(("Could not get graphic from clipboard"));
  5150. // display error message instead of throwing exception
  5151. ::Message(NULL, IDS_PASTE, IDS_PASTE_ERROR);
  5152. }
  5153. }
  5154. //
  5155. //
  5156. // Function: OnRenderAllFormats
  5157. //
  5158. // Purpose: Render all formats of the graphic last copied to the
  5159. // CLP_
  5160. //
  5161. //
  5162. void WbMainWindow::OnRenderAllFormats(void)
  5163. {
  5164. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnRenderAllFormats");
  5165. //
  5166. // only render something if we have not done it already
  5167. //
  5168. if (CLP_LastCopiedPage() != WB_PAGE_HANDLE_NULL)
  5169. {
  5170. if (!CLP_RenderAllFormats())
  5171. {
  5172. // An error occurred rendering the formats
  5173. ERROR_OUT(("Error rendering all formats"));
  5174. }
  5175. }
  5176. }
  5177. //
  5178. //
  5179. // Function: CheckMenuItem
  5180. //
  5181. // Purpose: Check an item on the application menus (main and context
  5182. // menu.)
  5183. //
  5184. //
  5185. void WbMainWindow::CheckMenuItem(UINT uiId)
  5186. {
  5187. CheckMenuItemRecursive(::GetMenu(m_hwnd), uiId, MF_BYCOMMAND | MF_CHECKED);
  5188. CheckMenuItemRecursive(m_hContextMenu, uiId, MF_BYCOMMAND | MF_CHECKED);
  5189. CheckMenuItemRecursive(m_hGrobjContextMenu, uiId, MF_BYCOMMAND | MF_CHECKED); // bug 426
  5190. }
  5191. //
  5192. //
  5193. // Function: UncheckMenuItem
  5194. //
  5195. // Purpose: Uncheck an item on the application menus (main and context
  5196. // menus.)
  5197. //
  5198. //
  5199. void WbMainWindow::UncheckMenuItem(UINT uiId)
  5200. {
  5201. CheckMenuItemRecursive(::GetMenu(m_hwnd), uiId, MF_BYCOMMAND | MF_UNCHECKED);
  5202. CheckMenuItemRecursive(m_hContextMenu, uiId, MF_BYCOMMAND | MF_UNCHECKED);
  5203. CheckMenuItemRecursive(m_hGrobjContextMenu, uiId, MF_BYCOMMAND | MF_UNCHECKED); // bug 426
  5204. }
  5205. //
  5206. //
  5207. // Function: CheckMenuItemRecursive
  5208. //
  5209. // Purpose: Check or uncheck an item on the any of the Whiteboard menus.
  5210. // This function recursively searches through the menus until
  5211. // it finds the specified item. The menu item Ids must be
  5212. // unique for this function to work.
  5213. //
  5214. //
  5215. BOOL WbMainWindow::CheckMenuItemRecursive(HMENU hMenu,
  5216. UINT uiId,
  5217. BOOL bCheck)
  5218. {
  5219. UINT uiNumItems = ::GetMenuItemCount(hMenu);
  5220. // Attempt to check the menu item
  5221. UINT uiCheck = MF_BYCOMMAND | (bCheck ? MF_CHECKED : MF_UNCHECKED);
  5222. // A return code of -1 from CheckMenuItem implies that
  5223. // the menu item was not found
  5224. BOOL bChecked = ((::CheckMenuItem(hMenu, uiId, uiCheck) == -1) ? FALSE : TRUE);
  5225. if (bChecked)
  5226. {
  5227. //
  5228. // If this item is on the active menu, ensure it's redrawn now
  5229. //
  5230. if (hMenu == m_hInitMenu)
  5231. {
  5232. InvalidateActiveMenu();
  5233. }
  5234. }
  5235. else
  5236. {
  5237. UINT uiPos;
  5238. HMENU hSubMenu;
  5239. // Recurse through the submenus of the specified menu
  5240. for (uiPos = 0; uiPos < uiNumItems; uiPos++)
  5241. {
  5242. // Assume that the next item is a submenu
  5243. // and try to get a pointer to it
  5244. hSubMenu = ::GetSubMenu(hMenu, (int)uiPos);
  5245. // NULL return implies the item is a not submenu
  5246. if (hSubMenu != NULL)
  5247. {
  5248. // Item is a submenu, make recursive call to search it
  5249. bChecked = CheckMenuItemRecursive(hSubMenu, uiId, bCheck);
  5250. if (bChecked)
  5251. {
  5252. // We have found the item
  5253. break;
  5254. }
  5255. }
  5256. }
  5257. }
  5258. return bChecked;
  5259. }
  5260. //
  5261. //
  5262. // Function: GetMenuWithItem
  5263. //
  5264. // Purpose: Return the menu which contains the specified item.
  5265. //
  5266. //
  5267. HMENU WbMainWindow::GetMenuWithItem(HMENU hMenu, UINT uiID)
  5268. {
  5269. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::GetMenuWithItem");
  5270. ASSERT(hMenu != NULL);
  5271. HMENU hMenuResult = NULL;
  5272. // Get the number ofitems in the menu
  5273. UINT uiNumItems = ::GetMenuItemCount(hMenu);
  5274. UINT uiPos;
  5275. UINT uiNextID;
  5276. // Look for the item through the menu
  5277. for (uiPos = 0; uiPos < uiNumItems; uiPos++)
  5278. {
  5279. // Get the ID of the item at this position
  5280. uiNextID = ::GetMenuItemID(hMenu, uiPos);
  5281. if (uiNextID == uiID)
  5282. {
  5283. // We have found the item
  5284. hMenuResult = hMenu;
  5285. break;
  5286. }
  5287. }
  5288. // If we have not yet found the item
  5289. if (hMenuResult == NULL)
  5290. {
  5291. // Look through each of the submenus of the current menu
  5292. HMENU hSubMenu;
  5293. for (uiPos = 0; uiPos < uiNumItems; uiPos++)
  5294. {
  5295. // Get the ID of the item at this position
  5296. uiNextID = ::GetMenuItemID(hMenu, uiPos);
  5297. // If the item is a submenu
  5298. if (uiNextID == -1)
  5299. {
  5300. // Get the submenu
  5301. hSubMenu = ::GetSubMenu(hMenu, (int) uiPos);
  5302. // Search the submenu
  5303. hMenuResult = GetMenuWithItem(hSubMenu, uiID);
  5304. if (hMenuResult != NULL)
  5305. {
  5306. // We have found the menu with the requested item
  5307. break;
  5308. }
  5309. }
  5310. }
  5311. }
  5312. return hMenuResult;
  5313. }
  5314. //
  5315. //
  5316. // Function: OnScrollAccelerator
  5317. //
  5318. // Purpose: Called when a scroll accelerator is used
  5319. //
  5320. //
  5321. void WbMainWindow::OnScrollAccelerator(UINT uiMenuId)
  5322. {
  5323. int iScroll;
  5324. // Locate the scroll messages to be sent in the conversion table
  5325. for (iScroll = 0; iScroll < ARRAYSIZE(s_MenuToScroll); iScroll++)
  5326. {
  5327. if (s_MenuToScroll[iScroll].uiMenuId == uiMenuId)
  5328. {
  5329. // Found it;
  5330. break;
  5331. }
  5332. }
  5333. // Send the messages
  5334. if (iScroll < ARRAYSIZE(s_MenuToScroll))
  5335. {
  5336. while ((s_MenuToScroll[iScroll].uiMenuId == uiMenuId) && (iScroll < ARRAYSIZE(s_MenuToScroll)))
  5337. {
  5338. // Tell the drawing pane to scroll
  5339. ::PostMessage(m_drawingArea.m_hwnd, s_MenuToScroll[iScroll].uiMessage,
  5340. s_MenuToScroll[iScroll].uiScrollCode, 0);
  5341. iScroll++;
  5342. }
  5343. // Indicate that scrolling has completed (in both directions)
  5344. ::PostMessage(m_drawingArea.m_hwnd, WM_HSCROLL, SB_ENDSCROLL, 0L);
  5345. ::PostMessage(m_drawingArea.m_hwnd, WM_VSCROLL, SB_ENDSCROLL, 0L);
  5346. }
  5347. }
  5348. //
  5349. //
  5350. // Function: OnZoom
  5351. //
  5352. // Purpose: Zoom or unzoom the drawing area
  5353. //
  5354. //
  5355. void WbMainWindow::OnZoom()
  5356. {
  5357. // If the drawing area is currently zoomed
  5358. if (m_drawingArea.Zoomed())
  5359. {
  5360. // Remove the zoomed check mark
  5361. UncheckMenuItem(IDM_ZOOM);
  5362. // Tell the tool bar of the new selection
  5363. m_TB.PopUp(IDM_ZOOM);
  5364. // Inform the local user of the zoom state
  5365. if (m_pLocalUser != NULL)
  5366. m_pLocalUser->Unzoom();
  5367. }
  5368. else
  5369. {
  5370. // Set the zoomed check mark
  5371. CheckMenuItem(IDM_ZOOM);
  5372. // Tell the tool bar of the new selection
  5373. m_TB.PushDown(IDM_ZOOM);
  5374. // Inform the local user of the zoom state
  5375. if (m_pLocalUser != NULL)
  5376. m_pLocalUser->Zoom();
  5377. }
  5378. // Zoom/unzoom the drawing area
  5379. m_drawingArea.Zoom();
  5380. // Restore the focus to the drawing area
  5381. ::SetFocus(m_drawingArea.m_hwnd);
  5382. }
  5383. //
  5384. //
  5385. // Function: OnSelectTool
  5386. //
  5387. // Purpose: Select the current tool
  5388. //
  5389. //
  5390. void WbMainWindow::OnSelectTool(UINT uiMenuId)
  5391. {
  5392. UINT uiIndex;
  5393. UncheckMenuItem(m_currentMenuTool);
  5394. CheckMenuItem( uiMenuId);
  5395. // Save the new menu Id
  5396. m_currentMenuTool = uiMenuId;
  5397. // Tell the tool bar of the new selection
  5398. m_TB.PushDown(m_currentMenuTool);
  5399. // Get the new tool
  5400. m_pCurrentTool = m_ToolArray[TOOL_INDEX(m_currentMenuTool)];
  5401. // Set the current attributes
  5402. if( !m_bSelectAllInProgress )
  5403. {
  5404. m_AG.SetChoiceColor(m_pCurrentTool->GetColor() );
  5405. ::SendMessage(m_hwnd, WM_COMMAND, IDM_COLOR, 0L);
  5406. ::SendMessage(m_hwnd, WM_COMMAND, IDM_WIDTHS_START + m_pCurrentTool->GetWidthIndex(), 0L);//CHANGED BY RAND
  5407. }
  5408. // Report the change of tool to the attributes group
  5409. m_AG.DisplayTool(m_pCurrentTool);
  5410. // Select the new tool into the drawing area
  5411. m_drawingArea.SelectTool(m_pCurrentTool);
  5412. // Restore the focus to the drawing area
  5413. ::SetFocus(m_drawingArea.m_hwnd);
  5414. }
  5415. //
  5416. //
  5417. // Function: OnSelectColor
  5418. //
  5419. // Purpose: Set the current color
  5420. //
  5421. //
  5422. void WbMainWindow::OnSelectColor(void)
  5423. {
  5424. // Tell the attributes group of the new selection and get the
  5425. // new color value selected ino the current tool.
  5426. m_AG.SelectColor(m_pCurrentTool);
  5427. // Select the changed tool into the drawing area
  5428. m_drawingArea.SelectTool(m_pCurrentTool);
  5429. // If we are using a select tool, change the color of the selected object
  5430. if (m_pCurrentTool->ToolType() == TOOLTYPE_SELECT)
  5431. {
  5432. // If there is an object marked for changing
  5433. if (m_drawingArea.GraphicSelected())
  5434. {
  5435. // Update the object
  5436. m_drawingArea.SetSelectionColor(m_pCurrentTool->GetColor());
  5437. }
  5438. }
  5439. // if currently editing a text object then change its color
  5440. if ( (m_pCurrentTool->ToolType() == TOOLTYPE_TEXT)
  5441. && (m_drawingArea.TextEditActive()))
  5442. {
  5443. m_drawingArea.SetSelectionColor(m_pCurrentTool->GetColor());
  5444. }
  5445. // Restore the focus to the drawing area
  5446. ::SetFocus(m_drawingArea.m_hwnd);
  5447. }
  5448. //
  5449. //
  5450. // Function: OnSelectWidth
  5451. //
  5452. // Purpose: Set the current nib width
  5453. //
  5454. //
  5455. void WbMainWindow::OnSelectWidth(UINT uiMenuId)
  5456. {
  5457. // cleanup select logic in case object context menu called us (bug 426)
  5458. m_drawingArea.SetLClickIgnore( FALSE );
  5459. // Move the check mark on the menu
  5460. UncheckMenuItem(m_currentMenuWidth);
  5461. CheckMenuItem(uiMenuId);
  5462. // Save the new pen width
  5463. m_currentMenuWidth = uiMenuId;
  5464. // Tell the attributes display of the new selection
  5465. m_WG.PushDown(uiMenuId - IDM_WIDTHS_START);
  5466. if (m_pCurrentTool != NULL)
  5467. {
  5468. m_pCurrentTool->SetWidthIndex(uiMenuId - IDM_WIDTHS_START);
  5469. }
  5470. // Tell the drawing pane of the new selection
  5471. m_drawingArea.SelectTool(m_pCurrentTool);
  5472. // If we are using a select tool, change the color of the selected object
  5473. if (m_pCurrentTool->ToolType() == TOOLTYPE_SELECT)
  5474. {
  5475. // If there is an object marked for changing
  5476. if (m_drawingArea.GraphicSelected())
  5477. {
  5478. // Update the object
  5479. m_drawingArea.SetSelectionWidth(m_pCurrentTool->GetWidth());
  5480. }
  5481. }
  5482. // Restore the focus to the drawing area
  5483. ::SetFocus(m_drawingArea.m_hwnd);
  5484. }
  5485. //
  5486. //
  5487. // Function: OnChooseFont
  5488. //
  5489. // Purpose: Let the user select a font
  5490. //
  5491. //
  5492. void WbMainWindow::OnChooseFont(void)
  5493. {
  5494. HDC hdc;
  5495. LOGFONT lfont;
  5496. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnChooseFont");
  5497. // cleanup select logic in case object context menu called us (bug 426)
  5498. m_drawingArea.SetLClickIgnore( FALSE );
  5499. // It is only really sensible to be here when a text tool is selected.
  5500. // This is achieved by graying the Font selection menu entry when
  5501. // anything other than a text tool is in use.
  5502. // Get the font details from the current tool
  5503. ::GetObject(m_pCurrentTool->GetFont(), sizeof(LOGFONT), &lfont);
  5504. lfont.lfClipPrecision |= CLIP_DFA_OVERRIDE;
  5505. //
  5506. // The Font dialog is passed a LOGFONT structure which it uses to
  5507. // initialize all of its fields (face name, weight etc).
  5508. //
  5509. // The face name passed in the LOGFONT structure is checked by the dialog
  5510. // against the facenames of all available fonts. If the name does not
  5511. // match one of the available fonts, no name is displayed.
  5512. //
  5513. // WB stores the LOGFONT structure specifying the font used for a text
  5514. // object in the object. This LOGFONT is selected into a DC where the
  5515. // GDIs font mapper decides which physical font most closely matches the
  5516. // required logical font. On boxes where the original font is not
  5517. // supported the font is substituted for the closest matching font
  5518. // available.
  5519. //
  5520. // So, if we pass the LOGFONT structure for a font which is not supported
  5521. // into the Font dialog, no facename is displayed. To bypass this we
  5522. //
  5523. // - select the logical font into a DC
  5524. //
  5525. // - determine the textmetrics and get the face name of the physical font
  5526. // chosen by the Font Mapper
  5527. //
  5528. // - use these textmetrics to create a LOGFONT structure which matches
  5529. // the substituted font!
  5530. //
  5531. // The resulting LOGFONT will have the correct weight, dimensions and
  5532. // facename for the substituted font.
  5533. //
  5534. hdc = ::CreateCompatibleDC(NULL);
  5535. if (hdc != NULL)
  5536. {
  5537. TEXTMETRIC tm;
  5538. HFONT hFont;
  5539. HFONT hOldFont;
  5540. hFont = ::CreateFontIndirect(&lfont);
  5541. //
  5542. // Get the face name and text metrics of the selected font.
  5543. //
  5544. hOldFont = SelectFont(hdc, hFont);
  5545. if (hOldFont == NULL)
  5546. {
  5547. WARNING_OUT(("Failed to select font into DC"));
  5548. }
  5549. else
  5550. {
  5551. ::GetTextMetrics(hdc, &tm);
  5552. ::GetTextFace(hdc, LF_FACESIZE, lfont.lfFaceName);
  5553. //
  5554. // Restore the old font back into the DC.
  5555. //
  5556. SelectFont(hdc, hOldFont);
  5557. //
  5558. // Create a LOGFONT structure which matches the Text metrics
  5559. // of the font used by the DC so that the font dialog manages
  5560. // to initialise all of its fields properly, even for
  5561. // substituted fonts...
  5562. //
  5563. lfont.lfHeight = tm.tmHeight;
  5564. lfont.lfWidth = tm.tmAveCharWidth;
  5565. lfont.lfWeight = tm.tmWeight;
  5566. lfont.lfItalic = tm.tmItalic;
  5567. lfont.lfUnderline = tm.tmUnderlined;
  5568. lfont.lfStrikeOut = tm.tmStruckOut;
  5569. lfont.lfCharSet = tm.tmCharSet;
  5570. //ADDED BY RAND - to make lfHeight be a char height. This makes
  5571. // the font dlg show the same pt size that is
  5572. // displayed in the sample font toolbar
  5573. if( lfont.lfHeight > 0 )
  5574. {
  5575. lfont.lfHeight = -(lfont.lfHeight - tm.tmInternalLeading);
  5576. }
  5577. }
  5578. ::DeleteDC(hdc);
  5579. if (hFont != NULL)
  5580. {
  5581. ::DeleteFont(hFont);
  5582. }
  5583. }
  5584. else
  5585. {
  5586. WARNING_OUT(("Failed to get DC to select font into"));
  5587. }
  5588. CHOOSEFONT cf;
  5589. TCHAR szStyleName[64];
  5590. ZeroMemory(&cf, sizeof(cf));
  5591. ZeroMemory(szStyleName, sizeof(szStyleName));
  5592. cf.lStructSize = sizeof(cf);
  5593. cf.lpszStyle = szStyleName;
  5594. cf.rgbColors = m_pCurrentTool->GetColor() & 0x00ffffff; // blow off palette bits (NM4db:2304)
  5595. cf.Flags = CF_EFFECTS | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS |
  5596. CF_NOVERTFONTS;
  5597. cf.lpLogFont = &lfont;
  5598. cf.hwndOwner = m_hwnd;
  5599. // Call up the ChooseFont dialog from COM DLG
  5600. if (::ChooseFont(&cf))
  5601. {
  5602. lfont.lfClipPrecision |= CLIP_DFA_OVERRIDE;
  5603. //ADDED BY RAND - set color selected in dialog.
  5604. m_pCurrentTool->SetColor(cf.rgbColors);
  5605. m_AG.DisplayTool( m_pCurrentTool );
  5606. ::SendMessage(m_hwnd, WM_COMMAND,
  5607. (WPARAM)MAKELONG( IDM_COLOR, BN_CLICKED ),
  5608. (LPARAM)0 );
  5609. // Inform the drawing pane of the new selection
  5610. HFONT hNewFont;
  5611. hNewFont = ::CreateFontIndirect(&lfont);
  5612. if (!hNewFont)
  5613. {
  5614. ERROR_OUT(("Failed to create font"));
  5615. DefaultExceptionHandler(WBFE_RC_WINDOWS, 0);
  5616. return;
  5617. }
  5618. //
  5619. // We need to set the text editor font after inserting it in the DC
  5620. // and querying the metrics, otherwise we may get a font with different
  5621. // metrics in zoomed mode
  5622. //
  5623. HFONT hNewFont2;
  5624. HDC hDC = m_drawingArea.GetCachedDC();
  5625. TEXTMETRIC textMetrics;
  5626. m_drawingArea.PrimeFont(hDC, hNewFont, &textMetrics);
  5627. lfont.lfHeight = textMetrics.tmHeight;
  5628. lfont.lfWidth = textMetrics.tmAveCharWidth;
  5629. lfont.lfPitchAndFamily = textMetrics.tmPitchAndFamily;
  5630. ::GetTextFace(hDC, sizeof(lfont.lfFaceName),
  5631. lfont.lfFaceName);
  5632. TRACE_MSG(("Font face name %s", lfont.lfFaceName));
  5633. // Inform the drawing pane of the new selection
  5634. hNewFont2 = ::CreateFontIndirect(&lfont);
  5635. if (!hNewFont2)
  5636. {
  5637. ERROR_OUT(("Failed to create font"));
  5638. DefaultExceptionHandler(WBFE_RC_WINDOWS, 0);
  5639. return;
  5640. }
  5641. m_drawingArea.SetSelectionColor(cf.rgbColors);
  5642. m_drawingArea.SetSelectionFont(hNewFont2);
  5643. if (m_pCurrentTool != NULL)
  5644. {
  5645. m_pCurrentTool->SetFont(hNewFont2);
  5646. }
  5647. m_drawingArea.SelectTool(m_pCurrentTool);
  5648. //
  5649. // discard the new font
  5650. //
  5651. m_drawingArea.UnPrimeFont( hDC );
  5652. // Delete the fonts we created--everybody above makes copies
  5653. ::DeleteFont(hNewFont2);
  5654. ::DeleteFont(hNewFont);
  5655. }
  5656. // Restore the focus to the drawing area
  5657. ::SetFocus(m_drawingArea.m_hwnd);
  5658. }
  5659. //
  5660. //
  5661. // Function: OnToolBarToggle
  5662. //
  5663. // Purpose: Let the user toggle the tool bar on/off
  5664. //
  5665. //
  5666. void WbMainWindow::OnToolBarToggle(void)
  5667. {
  5668. RECT rectWnd;
  5669. // Toggle the flag
  5670. m_bToolBarOn = !m_bToolBarOn;
  5671. // Make the necessary updates
  5672. if (m_bToolBarOn)
  5673. {
  5674. // The tool bar was hidden, so show it
  5675. ::ShowWindow(m_TB.m_hwnd, SW_SHOW);
  5676. // The tool window is fixed so we must resize the other panes in
  5677. // the window to make room for it
  5678. ResizePanes();
  5679. // Check the associated menu item
  5680. CheckMenuItem(IDM_TOOL_BAR_TOGGLE);
  5681. }
  5682. else
  5683. {
  5684. // The tool bar was visible, so hide it
  5685. ::ShowWindow(m_TB.m_hwnd, SW_HIDE);
  5686. // Uncheck the associated menu item
  5687. UncheckMenuItem(IDM_TOOL_BAR_TOGGLE);
  5688. ResizePanes();
  5689. }
  5690. // Make sure things reflect current tool
  5691. m_AG.DisplayTool(m_pCurrentTool);
  5692. // Write the new option value to the options file
  5693. OPT_SetBooleanOption(OPT_MAIN_TOOLBARVISIBLE,
  5694. m_bToolBarOn);
  5695. ::GetWindowRect(m_hwnd, &rectWnd);
  5696. ::MoveWindow(m_hwnd, rectWnd.left, rectWnd.top,
  5697. rectWnd.right - rectWnd.left, rectWnd.bottom - rectWnd.top, TRUE);
  5698. }
  5699. //
  5700. //
  5701. // Function: OnStatusBarToggle
  5702. //
  5703. // Purpose: Let the user toggle the help bar on/off
  5704. //
  5705. //
  5706. void WbMainWindow::OnStatusBarToggle(void)
  5707. {
  5708. RECT rectWnd;
  5709. // Toggle the flag
  5710. m_bStatusBarOn = !m_bStatusBarOn;
  5711. // Make the necessary updates
  5712. if (m_bStatusBarOn)
  5713. {
  5714. // Resize the panes to give room for the help bar
  5715. ResizePanes();
  5716. // The help bar was hidden, so show it
  5717. ::ShowWindow(m_hwndSB, SW_SHOW);
  5718. // Check the associated menu item
  5719. CheckMenuItem(IDM_STATUS_BAR_TOGGLE);
  5720. }
  5721. else
  5722. {
  5723. // The help bar was visible, so hide it
  5724. ::ShowWindow(m_hwndSB, SW_HIDE);
  5725. // Uncheck the associated menu item
  5726. UncheckMenuItem(IDM_STATUS_BAR_TOGGLE);
  5727. // Resize the panes to take up the help bar space
  5728. ResizePanes();
  5729. }
  5730. // Write the new option value to the options file
  5731. OPT_SetBooleanOption(OPT_MAIN_STATUSBARVISIBLE, m_bStatusBarOn);
  5732. ::GetWindowRect(m_hwnd, &rectWnd);
  5733. ::MoveWindow(m_hwnd, rectWnd.left, rectWnd.top,
  5734. rectWnd.right - rectWnd.left, rectWnd.bottom - rectWnd.top, TRUE);
  5735. }
  5736. //
  5737. //
  5738. // Function: OnAbout
  5739. //
  5740. // Purpose: Show the about box for the Whiteboard application. This
  5741. // method is called whenever a WM_COMMAND with IDM_ABOUT
  5742. // is issued by Windows.
  5743. //
  5744. //
  5745. void WbMainWindow::OnAbout()
  5746. {
  5747. ::DialogBoxParam(g_hInstance, MAKEINTRESOURCE(ABOUTBOX), m_hwnd,
  5748. AboutDlgProc, 0);
  5749. }
  5750. INT_PTR AboutDlgProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  5751. {
  5752. BOOL fHandled = FALSE;
  5753. switch (uMessage)
  5754. {
  5755. case WM_INITDIALOG:
  5756. {
  5757. TCHAR szFormat[256];
  5758. TCHAR szVersion[512];
  5759. ::GetDlgItemText(hwnd, IDC_ABOUTVERSION, szFormat, 256);
  5760. wsprintf(szVersion, szFormat, VER_PRODUCTRELEASE_STR,
  5761. VER_PRODUCTVERSION_STR);
  5762. ::SetDlgItemText(hwnd, IDC_ABOUTVERSION, szVersion);
  5763. fHandled = TRUE;
  5764. break;
  5765. }
  5766. case WM_COMMAND:
  5767. switch (GET_WM_COMMAND_ID(wParam, lParam))
  5768. {
  5769. case IDOK:
  5770. case IDCANCEL:
  5771. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  5772. {
  5773. case BN_CLICKED:
  5774. ::EndDialog(hwnd, IDCANCEL);
  5775. break;
  5776. }
  5777. break;
  5778. }
  5779. fHandled = TRUE;
  5780. break;
  5781. }
  5782. return(fHandled);
  5783. }
  5784. //
  5785. //
  5786. // Function: SelectWindow
  5787. //
  5788. // Purpose: Let the user select a window for grabbing
  5789. //
  5790. //
  5791. HWND WbMainWindow::SelectWindow(void)
  5792. {
  5793. POINT mousePos; // Mouse position
  5794. HWND hwndSelected = NULL; // Window clicked on
  5795. MSG msg; // Current message
  5796. // Load the grabbing cursors
  5797. HCURSOR hGrabCursor = ::LoadCursor(g_hInstance, MAKEINTRESOURCE( GRABCURSOR ) );
  5798. // Capture the mouse
  5799. UT_CaptureMouse(m_hwnd);
  5800. // Ensure we receive all keyboard messages.
  5801. ::SetFocus(m_hwnd);
  5802. // Reset the CancelMode state
  5803. ResetCancelMode();
  5804. // Change to the grab cursor
  5805. HCURSOR hOldCursor = ::SetCursor(hGrabCursor);
  5806. // Trap all mouse messages until a WM_LBUTTONUP is received
  5807. for ( ; ; )
  5808. {
  5809. // Wait for the next message
  5810. ::WaitMessage();
  5811. // Cancel if we have been sent a WM_CANCELMODE message
  5812. if (CancelModeSent())
  5813. {
  5814. break;
  5815. }
  5816. // If it is a mouse message, process it
  5817. if (::PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
  5818. {
  5819. if (msg.message == WM_LBUTTONUP)
  5820. {
  5821. // Get mouse position
  5822. mousePos.x = (short)LOWORD(msg.lParam);
  5823. mousePos.y = (short)HIWORD(msg.lParam);
  5824. // Convert to screen coordinates
  5825. ::ClientToScreen(m_hwnd, &mousePos);
  5826. // Get the window under the mouse
  5827. hwndSelected = ::WindowFromPoint(mousePos);
  5828. // Leave the loop
  5829. break;
  5830. }
  5831. }
  5832. // Cancel if ESCAPE is pressed.
  5833. // or if another window receives the focus
  5834. else if (::PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
  5835. {
  5836. if (msg.wParam == VK_ESCAPE)
  5837. {
  5838. break;
  5839. }
  5840. }
  5841. }
  5842. // Release the mouse
  5843. UT_ReleaseMouse(m_hwnd);
  5844. // Restore the cursor
  5845. ::SetCursor(hOldCursor);
  5846. return(hwndSelected);
  5847. }
  5848. //
  5849. //
  5850. // Function: OnGrabWindow
  5851. //
  5852. // Purpose: Allows the user to grab a bitmap of a window
  5853. //
  5854. //
  5855. void WbMainWindow::OnGrabWindow(void)
  5856. {
  5857. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnGrabWindow");
  5858. if (::DialogBoxParam(g_hInstance, MAKEINTRESOURCE(WARNSELECTWINDOW),
  5859. m_hwnd, WarnSelectWindowDlgProc, 0) != IDOK)
  5860. {
  5861. // User cancelled; bail out
  5862. return;
  5863. }
  5864. // Hide the application windows
  5865. ::ShowWindow(m_hwnd, SW_HIDE);
  5866. // Get window selection from the user
  5867. HWND hwndSelected = SelectWindow();
  5868. if (hwndSelected != NULL)
  5869. {
  5870. // Walk back to the find the 'real' window ancestor
  5871. HWND hwndParent;
  5872. // The following piece of code attempts to find the frame window
  5873. // enclosing the selected window. This allows us to bring the
  5874. // enclosing window to the top, bringing the child window with it.
  5875. DWORD dwStyle;
  5876. while ((hwndParent = ::GetParent(hwndSelected)) != NULL)
  5877. {
  5878. // If we have reached a stand-alone window, stop the search
  5879. dwStyle = ::GetWindowLong(hwndSelected, GWL_STYLE);
  5880. if ( ((dwStyle & WS_POPUP) == WS_POPUP)
  5881. || ((dwStyle & WS_THICKFRAME) == WS_THICKFRAME)
  5882. || ((dwStyle & WS_DLGFRAME) == WS_DLGFRAME))
  5883. {
  5884. break;
  5885. }
  5886. // Move up to the parent window
  5887. hwndSelected = hwndParent;
  5888. }
  5889. // Bring the selected window to the top
  5890. ::BringWindowToTop(hwndSelected);
  5891. ::UpdateWindow(hwndSelected);
  5892. // Get an image copy of the window
  5893. RECT areaRect;
  5894. ::GetWindowRect(hwndSelected, &areaRect);
  5895. DCWbGraphicDIB dib;
  5896. dib.FromScreenArea(&areaRect);
  5897. // Add the new grabbed bitmap
  5898. AddCapturedImage(dib);
  5899. // Force the selection tool to be selected
  5900. ::PostMessage(m_hwnd, WM_COMMAND, IDM_TOOLS_START, 0L);
  5901. }
  5902. // Show the windows again
  5903. ::ShowWindow(m_hwnd, SW_SHOW);
  5904. // Restore the focus to the drawing area
  5905. ::SetFocus(m_drawingArea.m_hwnd);
  5906. }
  5907. //
  5908. // WarnSelectWindowDlgProc()
  5909. // This puts up the warning/explanation dialog. We use the default settings
  5910. // or whatever the user chose last time this dialog was up.
  5911. //
  5912. INT_PTR CALLBACK WarnSelectWindowDlgProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  5913. {
  5914. BOOL fHandled = FALSE;
  5915. switch (uMessage)
  5916. {
  5917. case WM_INITDIALOG:
  5918. {
  5919. if (OPT_GetBooleanOption( OPT_MAIN_SELECTWINDOW_NOTAGAIN,
  5920. DFLT_MAIN_SELECTWINDOW_NOTAGAIN))
  5921. {
  5922. // End this right away, the user doesn't want a warning
  5923. ::EndDialog(hwnd, IDOK);
  5924. }
  5925. fHandled = TRUE;
  5926. break;
  5927. }
  5928. case WM_COMMAND:
  5929. switch (GET_WM_COMMAND_ID(wParam, lParam))
  5930. {
  5931. case IDOK:
  5932. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  5933. {
  5934. case BN_CLICKED:
  5935. //
  5936. // Update settings -- note that we don't have to write out
  5937. // FALSE--we wouldn't be in the dialog in the first place
  5938. // if the current setting weren't already FALSE.
  5939. //
  5940. if (::IsDlgButtonChecked(hwnd, IDC_SWWARN_NOTAGAIN))
  5941. {
  5942. OPT_SetBooleanOption(OPT_MAIN_SELECTWINDOW_NOTAGAIN, TRUE);
  5943. }
  5944. ::EndDialog(hwnd, IDOK);
  5945. break;
  5946. }
  5947. break;
  5948. case IDCANCEL:
  5949. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  5950. {
  5951. case BN_CLICKED:
  5952. ::EndDialog(hwnd, IDCANCEL);
  5953. break;
  5954. }
  5955. break;
  5956. }
  5957. fHandled = TRUE;
  5958. break;
  5959. }
  5960. return(fHandled);
  5961. }
  5962. //
  5963. //
  5964. // Function: ShowAllWindows
  5965. //
  5966. // Purpose: Show or hide the main window and associated windows
  5967. //
  5968. //
  5969. void WbMainWindow::ShowAllWindows(int iShow)
  5970. {
  5971. // Show/hide the main window
  5972. ::ShowWindow(m_hwnd, iShow);
  5973. // Show/hide the tool window
  5974. if (m_bToolBarOn)
  5975. {
  5976. ::ShowWindow(m_TB.m_hwnd, iShow);
  5977. }
  5978. }
  5979. //
  5980. //
  5981. // Function: OnGrabArea
  5982. //
  5983. // Purpose: Allows the user to grab a bitmap of an area of the screen
  5984. //
  5985. //
  5986. void WbMainWindow::OnGrabArea(void)
  5987. {
  5988. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnGrabArea");
  5989. if (::DialogBoxParam(g_hInstance, MAKEINTRESOURCE(WARNSELECTAREA),
  5990. m_hwnd, WarnSelectAreaDlgProc, 0) != IDOK)
  5991. {
  5992. // User cancelled, so bail out
  5993. return;
  5994. }
  5995. // Hide the application windows
  5996. ::ShowWindow(m_hwnd, SW_HIDE);
  5997. // Load the grabbing cursors
  5998. HCURSOR hGrabCursor = ::LoadCursor(g_hInstance, MAKEINTRESOURCE( PENCURSOR ) );
  5999. // Capture the mouse
  6000. UT_CaptureMouse(m_hwnd);
  6001. // Ensure we receive all keyboard messages.
  6002. ::SetFocus(m_hwnd);
  6003. // Reset the CancelMode status
  6004. ResetCancelMode();
  6005. // Change to the grab cursor
  6006. HCURSOR hOldCursor = ::SetCursor(hGrabCursor);
  6007. // Let the user select the area to be grabbed
  6008. RECT rect;
  6009. int tmp;
  6010. GetGrabArea(&rect);
  6011. // Normalize coords
  6012. if (rect.right < rect.left)
  6013. {
  6014. tmp = rect.left;
  6015. rect.left = rect.right;
  6016. rect.right = tmp;
  6017. }
  6018. if (rect.bottom < rect.top)
  6019. {
  6020. tmp = rect.top;
  6021. rect.top = rect.bottom;
  6022. rect.bottom = tmp;
  6023. }
  6024. DCWbGraphicDIB dib;
  6025. if (!::IsRectEmpty(&rect))
  6026. {
  6027. // Get a bitmap copy of the screen area
  6028. dib.FromScreenArea(&rect);
  6029. }
  6030. // Show the windows again now - if we do it later we get the bitmap to
  6031. // be added re-drawn twice (once on the window show and once when the
  6032. // graphic added indication arrives).
  6033. ::ShowWindow(m_hwnd, SW_SHOW);
  6034. ::UpdateWindow(m_hwnd);
  6035. if (!::IsRectEmpty(&rect))
  6036. {
  6037. // Add the bitmap
  6038. AddCapturedImage(dib);
  6039. // Force the selection tool to be selected
  6040. ::PostMessage(m_hwnd, WM_COMMAND, IDM_TOOLS_START, 0L);
  6041. }
  6042. // Release the mouse
  6043. UT_ReleaseMouse(m_hwnd);
  6044. // Restore the cursor
  6045. ::SetCursor(hOldCursor);
  6046. // Restore the focus to the drawing area
  6047. ::SetFocus(m_drawingArea.m_hwnd);
  6048. }
  6049. //
  6050. // WarnSelectArea dialog handler
  6051. //
  6052. INT_PTR CALLBACK WarnSelectAreaDlgProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  6053. {
  6054. BOOL fHandled = FALSE;
  6055. switch (uMessage)
  6056. {
  6057. case WM_INITDIALOG:
  6058. if (OPT_GetBooleanOption(OPT_MAIN_SELECTAREA_NOTAGAIN,
  6059. DFLT_MAIN_SELECTAREA_NOTAGAIN))
  6060. {
  6061. // End this right away, the user doesn't want a warning
  6062. ::EndDialog(hwnd, IDOK);
  6063. }
  6064. fHandled = TRUE;
  6065. break;
  6066. case WM_COMMAND:
  6067. switch (GET_WM_COMMAND_ID(wParam, lParam))
  6068. {
  6069. case IDOK:
  6070. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  6071. {
  6072. case BN_CLICKED:
  6073. //
  6074. // Update settings -- note that we don't have to write out
  6075. // FALSE--we wouldn't be in the dialog in the first place
  6076. // if the current setting weren't already FALSE.
  6077. //
  6078. if (::IsDlgButtonChecked(hwnd, IDC_SAWARN_NOTAGAIN))
  6079. {
  6080. OPT_SetBooleanOption(OPT_MAIN_SELECTAREA_NOTAGAIN, TRUE);
  6081. }
  6082. ::EndDialog(hwnd, IDOK);
  6083. break;
  6084. }
  6085. break;
  6086. case IDCANCEL:
  6087. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  6088. {
  6089. case BN_CLICKED:
  6090. ::EndDialog(hwnd, IDCANCEL);
  6091. break;
  6092. }
  6093. }
  6094. fHandled = TRUE;
  6095. break;
  6096. }
  6097. return(fHandled);
  6098. }
  6099. //
  6100. //
  6101. // Function: GetGrabArea
  6102. //
  6103. // Purpose: Allows the user to grab a bitmap of an area of the screen
  6104. //
  6105. //
  6106. void WbMainWindow::GetGrabArea(LPRECT lprect)
  6107. {
  6108. POINT mousePos; // Mouse position
  6109. MSG msg; // Current message
  6110. BOOL tracking = FALSE; // Flag indicating mouse button is down
  6111. HDC hDC = NULL;
  6112. POINT grabStartPoint; // Start point (when mouse button is pressed)
  6113. POINT grabEndPoint; // End point (when mouse button is released)
  6114. POINT grabCurrPoint; // Current mouse position
  6115. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::GetGrabArea");
  6116. // Set the result to an empty rectangle
  6117. ::SetRectEmpty(lprect);
  6118. // Create the rectangle to be used for tracking
  6119. DCWbGraphicTrackingRectangle rectangle;
  6120. rectangle.SetColor(RGB(0, 0, 0));
  6121. rectangle.SetPenWidth(1);
  6122. rectangle.SetPenStyle(PS_DOT);
  6123. // Get the DC for tracking
  6124. HWND hDesktopWnd = ::GetDesktopWindow();
  6125. hDC = ::GetWindowDC(hDesktopWnd);
  6126. if (hDC == NULL)
  6127. {
  6128. WARNING_OUT(("NULL desktop DC"));
  6129. goto GrabAreaCleanup;
  6130. }
  6131. // Trap all mouse messages until a WM_LBUTTONUP is received
  6132. for ( ; ; )
  6133. {
  6134. // Wait for the next message
  6135. ::WaitMessage();
  6136. // Cancel if we have been sent a WM_CANCELMODE message
  6137. if (CancelModeSent())
  6138. {
  6139. TRACE_MSG(("canceling grab"));
  6140. // Erase the last tracking rectangle
  6141. if (!EqualPoint(grabStartPoint, grabEndPoint))
  6142. {
  6143. rectangle.SetRectPts(grabStartPoint, grabEndPoint);
  6144. rectangle.Draw(hDC);
  6145. }
  6146. break;
  6147. }
  6148. // If it is a mouse message, process it
  6149. if (::PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
  6150. {
  6151. // Get mouse position
  6152. TRACE_MSG( ("msg = %x, lParam = %0x", msg.message, msg.lParam) );
  6153. mousePos.x = (short)LOWORD(msg.lParam);
  6154. mousePos.y = (short)HIWORD(msg.lParam);
  6155. TRACE_MSG( ("mousePos = %d,%d", mousePos.x, mousePos.y) );
  6156. // Convert to screen coordinates
  6157. ::ClientToScreen(m_hwnd, &mousePos);
  6158. grabCurrPoint = mousePos;
  6159. switch (msg.message)
  6160. {
  6161. // Starting the grab
  6162. case WM_LBUTTONDOWN:
  6163. // Save the starting position
  6164. TRACE_MSG(("grabbing start position"));
  6165. grabStartPoint = mousePos;
  6166. grabEndPoint = mousePos;
  6167. tracking = TRUE;
  6168. break;
  6169. // Completing the rectangle
  6170. case WM_LBUTTONUP:
  6171. {
  6172. tracking = FALSE;
  6173. // Check that there is an area to capture
  6174. TRACE_MSG(("grabbing end position"));
  6175. if (EqualPoint(grabStartPoint, grabCurrPoint))
  6176. {
  6177. TRACE_MSG(("start == end, skipping grab"));
  6178. goto GrabAreaCleanup;
  6179. }
  6180. // Erase the last tracking rectangle
  6181. if (!EqualPoint(grabStartPoint, grabEndPoint))
  6182. {
  6183. rectangle.SetRectPts(grabStartPoint, grabEndPoint);
  6184. rectangle.Draw(hDC);
  6185. }
  6186. // Update the rectangle object
  6187. rectangle.SetRectPts(grabStartPoint, grabCurrPoint);
  6188. *lprect = *rectangle.GetRect();
  6189. // We are done
  6190. goto GrabAreaCleanup;
  6191. }
  6192. break;
  6193. // Continuing the rectangle
  6194. case WM_MOUSEMOVE:
  6195. if (tracking)
  6196. {
  6197. TRACE_MSG(("tracking grab"));
  6198. // Erase the last tracking rectangle
  6199. if (!EqualPoint(grabStartPoint, grabEndPoint))
  6200. {
  6201. rectangle.SetRectPts(grabStartPoint, grabEndPoint);
  6202. rectangle.Draw(hDC);
  6203. }
  6204. // Draw the new rectangle
  6205. if (!EqualPoint(grabStartPoint, grabCurrPoint))
  6206. {
  6207. // Save the new box end point
  6208. grabEndPoint = grabCurrPoint;
  6209. // Draw the rectangle
  6210. TRACE_MSG( ("grabStartPoint = %d,%d",
  6211. grabStartPoint.x, grabStartPoint.y) );
  6212. TRACE_MSG( ("grabEndPoint = %d,%d",
  6213. grabEndPoint.x, grabEndPoint.y) );
  6214. rectangle.SetRectPts(grabStartPoint, grabEndPoint);
  6215. rectangle.Draw(hDC);
  6216. }
  6217. }
  6218. break;
  6219. }
  6220. }
  6221. // Cancel if ESCAPE is pressed.
  6222. else if (::PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
  6223. {
  6224. if( ((msg.message == WM_KEYUP)||(msg.message == WM_SYSKEYUP))&&
  6225. (msg.wParam == VK_ESCAPE) )
  6226. {
  6227. TRACE_MSG(("grab cancelled by ESC"));
  6228. // Erase the last tracking rectangle
  6229. if (!EqualPoint(grabStartPoint, grabEndPoint))
  6230. {
  6231. rectangle.SetRectPts(grabStartPoint, grabEndPoint);
  6232. rectangle.Draw(hDC);
  6233. }
  6234. break;
  6235. }
  6236. }
  6237. }
  6238. GrabAreaCleanup:
  6239. // Release the device context (if we have it)
  6240. if (hDC != NULL)
  6241. {
  6242. ::ReleaseDC(hDesktopWnd, hDC);
  6243. }
  6244. }
  6245. //
  6246. //
  6247. // Function: AddCapturedImage
  6248. //
  6249. // Purpose: Add a bitmap to the contents (adding a new page for it
  6250. // if necessary).
  6251. //
  6252. //
  6253. void WbMainWindow::AddCapturedImage(DCWbGraphicDIB& dib)
  6254. {
  6255. // Position the grabbed object at the top left of the currently visible
  6256. // area.
  6257. RECT rcVis;
  6258. m_drawingArea.GetVisibleRect(&rcVis);
  6259. dib.MoveTo(rcVis.left, rcVis.top);
  6260. // Add the new grabbed bitmap
  6261. dib.AddToPageLast(m_hCurrentPage);
  6262. }
  6263. //
  6264. //
  6265. // Function: OnPrint
  6266. //
  6267. // Purpose: Print the contents of the drawing pane
  6268. //
  6269. //
  6270. void WbMainWindow::OnPrint()
  6271. {
  6272. BOOL bPrintError = FALSE;
  6273. PRINTDLG pd;
  6274. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnPrint");
  6275. if (!IsIdle())
  6276. {
  6277. // post an error message indicating the whiteboard is busy
  6278. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, WB_RC_BUSY);
  6279. return;
  6280. }
  6281. //
  6282. // Initialize the PRINTDLG structure
  6283. //
  6284. ZeroMemory(&pd, sizeof(pd));
  6285. pd.lStructSize = sizeof(pd);
  6286. pd.hInstance = g_hInstance;
  6287. pd.hwndOwner = m_hwnd;
  6288. pd.Flags = PD_ALLPAGES | PD_RETURNDC | PD_PAGENUMS |
  6289. PD_HIDEPRINTTOFILE | PD_NOSELECTION;
  6290. pd.nMinPage = 1;
  6291. pd.nMaxPage = (WORD)g_pwbCore->WBP_ContentsCountPages();
  6292. pd.nFromPage = pd.nMinPage;
  6293. pd.nToPage = pd.nMaxPage;
  6294. // Put up the COMMDLG print dialog
  6295. if (::PrintDlg(&pd))
  6296. {
  6297. int nStartPage, nEndPage;
  6298. // Get the start and end page numbers to be printed
  6299. if (pd.Flags & PD_PAGENUMS)
  6300. {
  6301. nStartPage = pd.nFromPage;
  6302. nEndPage = pd.nToPage;
  6303. }
  6304. else
  6305. {
  6306. nStartPage = pd.nMinPage;
  6307. nEndPage = pd.nMaxPage;
  6308. }
  6309. // Check whether any pages are to be printed
  6310. if (nStartPage <= pd.nMaxPage)
  6311. {
  6312. // Ensure that the start and end pages lie within range.
  6313. nStartPage = max(nStartPage, pd.nMinPage);
  6314. nEndPage = min(nEndPage, pd.nMaxPage);
  6315. // Get the printer and output port names.
  6316. // These are written to the dialog for the user to see
  6317. // in the OnInitDialog member.
  6318. TCHAR szDeviceName[2*_MAX_PATH];
  6319. LPDEVNAMES lpDev;
  6320. // Device name
  6321. if (pd.hDevNames == NULL)
  6322. {
  6323. szDeviceName[0] = 0;
  6324. }
  6325. else
  6326. {
  6327. lpDev = (LPDEVNAMES)::GlobalLock(pd.hDevNames);
  6328. wsprintf(szDeviceName, "%s %s",
  6329. (LPCTSTR)lpDev + lpDev->wDeviceOffset,
  6330. (LPCTSTR)lpDev + lpDev->wOutputOffset);
  6331. ::GlobalUnlock(pd.hDevNames);
  6332. }
  6333. //
  6334. // Tell the printer we are starting the print.
  6335. // Note that the printer object handles the cancellation dialog.
  6336. WbPrinter printer(szDeviceName);
  6337. TCHAR szJobName[_MAX_PATH];
  6338. ::LoadString(g_hInstance, IDS_PRINT_NAME, szJobName, _MAX_PATH);
  6339. int nPrintResult = printer.StartDoc(pd.hDC, szJobName, nStartPage);
  6340. if (nPrintResult < 0)
  6341. {
  6342. WARNING_OUT(("Print result %d", nPrintResult));
  6343. bPrintError = TRUE;
  6344. }
  6345. else
  6346. {
  6347. // Find out how many copies to print
  6348. int copyNum;
  6349. copyNum = 0;
  6350. while ((copyNum < pd.nCopies) && !bPrintError)
  6351. {
  6352. // Loop through all pages
  6353. int nPrintPage;
  6354. WB_PAGE_HANDLE hPage;
  6355. for (nPrintPage = nStartPage; nPrintPage <= nEndPage; nPrintPage++)
  6356. {
  6357. // Get the first page
  6358. hPage = PG_GetPageNumber((WORD) nPrintPage);
  6359. // Only print the page if there are some objects on it
  6360. if (g_pwbCore->WBP_PageCountGraphics(hPage) > 0)
  6361. {
  6362. // Tell the printer we are starting a new page
  6363. printer.StartPage(pd.hDC, nPrintPage);
  6364. if (!printer.Error())
  6365. {
  6366. RECT rectArea;
  6367. rectArea.left = 0;
  6368. rectArea.top = 0;
  6369. rectArea.right = DRAW_WIDTH;
  6370. rectArea.bottom = DRAW_HEIGHT;
  6371. // Print the page
  6372. PG_Print(hPage, pd.hDC, &rectArea);
  6373. // Inform the printer that the page is complete
  6374. printer.EndPage(pd.hDC);
  6375. }
  6376. else
  6377. {
  6378. bPrintError = TRUE;
  6379. break;
  6380. }
  6381. }
  6382. }
  6383. copyNum++;
  6384. }
  6385. // The print has completed
  6386. nPrintResult = printer.EndDoc(pd.hDC);
  6387. if (nPrintResult < 0)
  6388. {
  6389. WARNING_OUT(("Print result %d", nPrintResult));
  6390. bPrintError = TRUE;
  6391. }
  6392. // reset the error if the user cancelled the print
  6393. if (printer.Aborted())
  6394. {
  6395. WARNING_OUT(("User cancelled print"));
  6396. bPrintError = FALSE;
  6397. }
  6398. }
  6399. }
  6400. }
  6401. // Inform the user if an error occurred
  6402. if (bPrintError)
  6403. {
  6404. // display a message informing the user the job terminated
  6405. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_PRINTER, 0);
  6406. }
  6407. //
  6408. // Cleanup the hDevMode, hDevNames, and hdc blocks if allocated
  6409. //
  6410. if (pd.hDevMode != NULL)
  6411. {
  6412. ::GlobalFree(pd.hDevMode);
  6413. pd.hDevMode = NULL;
  6414. }
  6415. if (pd.hDevNames != NULL)
  6416. {
  6417. ::GlobalFree(pd.hDevNames);
  6418. pd.hDevNames = NULL;
  6419. }
  6420. if (pd.hDC != NULL)
  6421. {
  6422. ::DeleteDC(pd.hDC);
  6423. pd.hDC = NULL;
  6424. }
  6425. }
  6426. //
  6427. //
  6428. // Function: OnPageSorter
  6429. //
  6430. // Purpose: Re-order the pages
  6431. //
  6432. //
  6433. void WbMainWindow::OnPageSorter()
  6434. {
  6435. // don't call up page sorter if another user is presenting (has the contents
  6436. // locked and sync on)
  6437. if ( (m_uiState == IN_CALL)
  6438. && (!WB_PresentationMode()))
  6439. {
  6440. PAGESORT ps;
  6441. m_drawingArea.CancelDrawingMode();
  6442. // Save the lock state (in case the Page Sorter gets it)
  6443. SaveLock();
  6444. //
  6445. // Fill in the initial values
  6446. //
  6447. ZeroMemory(&ps, sizeof(ps));
  6448. ps.hCurPage = m_hCurrentPage;
  6449. ps.fPageOpsAllowed = (m_uiSubState == SUBSTATE_IDLE);
  6450. //
  6451. // Put up the dialog
  6452. //
  6453. ASSERT(m_hwndPageSortDlg == NULL);
  6454. ::DialogBoxParam(g_hInstance, MAKEINTRESOURCE(PAGESORTERDIALOG),
  6455. m_hwnd, PageSortDlgProc, (LPARAM)&ps);
  6456. ASSERT(m_hwndPageSortDlg == NULL);
  6457. // Restore the lock state
  6458. RestoreLock();
  6459. // Set up the new current page pointer
  6460. if ((ps.hCurPage != m_hCurrentPage) || ps.fChanged)
  6461. {
  6462. GotoPage((WB_PAGE_HANDLE)ps.hCurPage);
  6463. }
  6464. // Update the page number display,
  6465. // the number of the current page may have changed.
  6466. UpdateStatus();
  6467. }
  6468. }
  6469. //
  6470. //
  6471. // Function: OnInsertPageBefore
  6472. //
  6473. // Purpose: Insert a new page before the current page
  6474. //
  6475. //
  6476. void WbMainWindow::OnInsertPageBefore()
  6477. {
  6478. if (!m_bUnlockStateSettled)
  6479. {
  6480. // Disable insert button code so crazed users can't insert again before
  6481. // the conference wide page-lock status has settled. If we ask for the
  6482. // page-lock again before the last unlock has finished then something
  6483. // happens to the lock-event from the cores and we hang waiting for it
  6484. // (until our wait-timeout runs out). This arguably could be called a
  6485. // DCL core bug but I couldn't generate any convincing proof of that
  6486. // so I just fixed it on Whiteboard's end by preventing asking for the
  6487. // lock too soon.
  6488. //
  6489. // RestoreLock() will eventually set m_bUnlockStateSettled to TRUE (in
  6490. // OnWBPUnlocked() by way of the WBP_EVENT_UNLOCKED event)
  6491. MessageBeep( 0xffffffff );
  6492. return;
  6493. }
  6494. // check state before allowing action
  6495. if (!IsIdle())
  6496. {
  6497. // post an error message indicating the whiteboard is busy
  6498. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, WB_RC_BUSY);
  6499. return;
  6500. }
  6501. // Save the current lock status
  6502. SaveLock();
  6503. // Catch exceptions so that we can restore the lock state
  6504. // Get the Page Order Lock (with an invisible dialog)
  6505. BOOL bGotLock = GetLock(WB_LOCK_TYPE_PAGE_ORDER, SW_HIDE);
  6506. if (bGotLock)
  6507. {
  6508. UINT uiRet;
  6509. WB_PAGE_HANDLE hPage;
  6510. // Set flag to prevent any more inserts until
  6511. // we have completely released the page-lock
  6512. m_bUnlockStateSettled = FALSE;
  6513. // Add the new page to the list (throws an exception on failure)
  6514. uiRet = g_pwbCore->WBP_PageAddBefore(m_hCurrentPage, &hPage);
  6515. if (uiRet != 0)
  6516. {
  6517. DefaultExceptionHandler(WBFE_RC_WB, uiRet);
  6518. return;
  6519. }
  6520. // Go to the inserted page
  6521. GotoPage(hPage);
  6522. }
  6523. //CHANGED BY RAND
  6524. // Restore the lock status. This will eventually set m_bUnlockStateSettled
  6525. // to TRUE (in OnWBPUnlocked() by way of the WBP_EVENT_UNLOCKED event)
  6526. // and enable this function after the conference wide lock-status
  6527. // has settled.
  6528. RestoreLock();
  6529. }
  6530. //
  6531. //
  6532. // Function: InsertPageAfter
  6533. //
  6534. // Purpose: Insert a new page after the specified page.
  6535. //
  6536. //
  6537. void WbMainWindow::InsertPageAfter(WB_PAGE_HANDLE hPageAfter)
  6538. {
  6539. if (!m_bUnlockStateSettled)
  6540. {
  6541. // Disable insert button code so crazed users can't insert again before
  6542. // the conference wide page-lock status has settled. If we ask for the
  6543. // page-lock again before the last unlock has finished then something
  6544. // happens to the lock-event from the cores and we hang waiting for it
  6545. // (until our wait-timeout runs out). This arguably could be called a
  6546. // DCL core bug but I couldn't generate any convincing proof of that
  6547. // so I just fixed it on Whiteboard's end by preventing asking for the
  6548. // lock too soon.
  6549. //
  6550. // RestoreLock() will eventually set m_bUnlockStateSettled to TRUE (in
  6551. // OnWBPUnlocked() by way of the WBP_EVENT_UNLOCKED event)
  6552. MessageBeep( 0xffffffff );
  6553. return;
  6554. }
  6555. // check state before allowing action
  6556. if (!IsIdle())
  6557. {
  6558. // post an error message indicating the whiteboard is busy
  6559. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, WB_RC_BUSY);
  6560. return;
  6561. }
  6562. // Save the current lock status
  6563. SaveLock();
  6564. // Catch exceptions so that we can restore the lock state
  6565. BOOL bGotLock = GetLock(WB_LOCK_TYPE_PAGE_ORDER, SW_HIDE);
  6566. if (bGotLock)
  6567. {
  6568. UINT uiRet;
  6569. WB_PAGE_HANDLE hPage;
  6570. // Set flag to prevent any more inserts until
  6571. // we have completely released the page-lock
  6572. m_bUnlockStateSettled = FALSE;
  6573. uiRet = g_pwbCore->WBP_PageAddAfter(hPageAfter, &hPage);
  6574. if (uiRet != 0)
  6575. {
  6576. DefaultExceptionHandler(WBFE_RC_WB, uiRet);
  6577. return;
  6578. }
  6579. // Move to the added page
  6580. GotoPage(hPage);
  6581. }
  6582. //CHANGED BY RAND
  6583. // Restore the lock status. This will eventually set m_bUnlockStateSettled
  6584. // to TRUE (in OnWBPUnlocked() by way of the WBP_EVENT_UNLOCKED event)
  6585. // and enable this function after the conference wide lock-status
  6586. // has settled.
  6587. RestoreLock();
  6588. }
  6589. //
  6590. //
  6591. // Function: OnInsertPageAfter
  6592. //
  6593. // Purpose: Insert a new page after the current page
  6594. //
  6595. //
  6596. void WbMainWindow::OnInsertPageAfter()
  6597. {
  6598. // Insert the new page
  6599. InsertPageAfter(m_hCurrentPage);
  6600. }
  6601. //
  6602. //
  6603. // Function: OnDeletePage
  6604. //
  6605. // Purpose: Delete the current page
  6606. //
  6607. //
  6608. void WbMainWindow::OnDeletePage()
  6609. {
  6610. int iResult;
  6611. BOOL bWasPosted;
  6612. if (!m_bUnlockStateSettled)
  6613. {
  6614. // Disable delete button code so crazed users can't delete again before
  6615. // the conference wide page-lock status has settled. If we ask for the
  6616. // page-lock again before the last unlock has finished then something
  6617. // happens to the lock-event from the cores and we hang waiting for it
  6618. // (until our wait-timeout runs out). This arguably could be called a
  6619. // DCL core bug but I couldn't generate any convincing proof of that
  6620. // so I just fixed it on Whiteboard's end by preventing asking for the
  6621. // lock too soon.
  6622. //
  6623. // RestoreLock() will eventually set m_bUnlockStateSettled to TRUE (in
  6624. // OnWBPUnlocked() by way of the WBP_EVENT_UNLOCKED event)
  6625. MessageBeep( 0xffffffff );
  6626. return;
  6627. }
  6628. // check state
  6629. if (!IsIdle())
  6630. {
  6631. // post an error message indicating the whiteboard is busy
  6632. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, WB_RC_BUSY);
  6633. return;
  6634. }
  6635. // Display a message box with the relevant question
  6636. if( UsersMightLoseData( &bWasPosted, NULL ) ) // bug NM4db:418
  6637. return;
  6638. if( bWasPosted )
  6639. iResult = IDYES;
  6640. else
  6641. iResult = ::Message(NULL, IDS_DELETE_PAGE, IDS_DELETE_PAGE_MESSAGE, MB_YESNO | MB_ICONQUESTION);
  6642. // If the user wants to continue with the delete
  6643. if (iResult == IDYES)
  6644. {
  6645. // If this is the only page
  6646. if (g_pwbCore->WBP_ContentsCountPages() == 1)
  6647. {
  6648. // Just clear it. The core does handle this
  6649. // case but it is better not to get the lock unnecessarily, the
  6650. // lock is required to call the core delete page function.
  6651. m_drawingArea.Clear();
  6652. }
  6653. else
  6654. {
  6655. // Lock the drawing area - this ensures we cannot draw to a bad page
  6656. // It will normally be unlocked when we get the corresponding page
  6657. // delete indication
  6658. // - moved until after we have got the page order lock
  6659. //LockDrawingArea();
  6660. // Save the current lock status
  6661. SaveLock();
  6662. // Catch exceptions so that we can restore the lock state
  6663. // Get the Page Order Lock (with an invisible dialog)
  6664. BOOL bGotLock = GetLock(WB_LOCK_TYPE_PAGE_ORDER, SW_HIDE);
  6665. if (bGotLock)
  6666. {
  6667. UINT uiRet;
  6668. // Set flag to prevent any more inserts until
  6669. // we have completely released the page-lock
  6670. m_bUnlockStateSettled = FALSE;
  6671. // Lock the drawing area - this ensures we cannot draw to a bad page
  6672. // It will normally be unlocked when we get the corresponding page
  6673. // delete indication
  6674. LockDrawingArea();
  6675. // Delete the page. The page is not deleted immediately but a
  6676. // WBP_EVENT_PAGE_DELETED event is generated.
  6677. uiRet = g_pwbCore->WBP_PageDelete(m_hCurrentPage);
  6678. if (uiRet != 0)
  6679. {
  6680. DefaultExceptionHandler(WBFE_RC_WB, uiRet);
  6681. return;
  6682. }
  6683. }
  6684. //CHANGED BY RAND
  6685. // Restore the lock status. This will eventually set m_bUnlockStateSettled
  6686. // to TRUE (in OnWBPUnlocked() by way of the WBP_EVENT_UNLOCKED event)
  6687. // and enable this function after the conference wide lock-status
  6688. // has settled.
  6689. RestoreLock();
  6690. }
  6691. }
  6692. }
  6693. //
  6694. //
  6695. // Function: OnRemotePointer
  6696. //
  6697. // Purpose: Create a remote pointer
  6698. //
  6699. //
  6700. void WbMainWindow::OnRemotePointer(void)
  6701. {
  6702. if (!m_pLocalUser)
  6703. return;
  6704. DCWbGraphicPointer* pPointer = m_pLocalUser->GetPointer();
  6705. // This function toggles the presence of the user's remote pointer
  6706. ASSERT(pPointer != NULL);
  6707. if (pPointer->IsActive())
  6708. {
  6709. // Turn off the pointer in the user information
  6710. pPointer->SetInactive();
  6711. // Tell the drawing area of the change
  6712. m_drawingArea.PointerUpdated(pPointer);
  6713. // Set the check mark on the menu item
  6714. UncheckMenuItem(IDM_REMOTE);
  6715. // Pop up the sync button
  6716. m_TB.PopUp(IDM_REMOTE);
  6717. }
  6718. else
  6719. {
  6720. // Calculate a position at which to drop the pointer. The centre of the
  6721. // remote pointer is placed in the centre of the currently visible
  6722. // area of the surface (the centre of the drawing area window).
  6723. RECT rectVisible;
  6724. RECT rectPointer;
  6725. POINT ptCenter;
  6726. m_drawingArea.GetVisibleRect(&rectVisible);
  6727. pPointer->GetBoundsRect(&rectPointer);
  6728. ptCenter.x = (rectVisible.left + rectVisible.right) / 2;
  6729. ptCenter.x -= ((rectPointer.right - rectPointer.left) / 2);
  6730. ptCenter.y = (rectVisible.top + rectVisible.bottom) / 2;
  6731. ptCenter.y -= ((rectPointer.bottom - rectPointer.top) / 2);
  6732. // Turn on the pointer in the user information
  6733. pPointer->SetActive(m_hCurrentPage, ptCenter);
  6734. // Tell the drawing area of the change
  6735. m_drawingArea.PointerUpdated(pPointer);
  6736. // Set the synced check mark
  6737. CheckMenuItem(IDM_REMOTE);
  6738. // Pop up the sync button
  6739. m_TB.PushDown(IDM_REMOTE);
  6740. // Force the selection tool to be selected
  6741. ::PostMessage(m_hwnd, WM_COMMAND, IDM_TOOLS_START, 0L);
  6742. }
  6743. // Restore the focus to the drawing area
  6744. ::SetFocus(m_drawingArea.m_hwnd);
  6745. }
  6746. //
  6747. //
  6748. // Function: OnSync
  6749. //
  6750. // Purpose: Sync or unsync the Whiteboard with other users
  6751. //
  6752. //
  6753. void WbMainWindow::OnSync(void)
  6754. {
  6755. // disabled if in presentation mode (another user has lock & sync on)
  6756. if (!WB_PresentationMode())
  6757. {
  6758. if (m_pLocalUser != NULL)
  6759. {
  6760. // Determine whether we are currently synced
  6761. if (m_pLocalUser->IsSynced())
  6762. {
  6763. // currently synced, so unsync
  6764. Unsync();
  6765. }
  6766. else
  6767. {
  6768. // currently unsynced, so sync
  6769. Sync();
  6770. }
  6771. }
  6772. }
  6773. // Restore the focus to the drawing area
  6774. ::SetFocus(m_drawingArea.m_hwnd);
  6775. }
  6776. //
  6777. //
  6778. // Function: Sync
  6779. //
  6780. // Purpose: Sync the Whiteboard with other users
  6781. //
  6782. //
  6783. void WbMainWindow::Sync(void)
  6784. {
  6785. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::Sync");
  6786. //
  6787. // Dont do anything if the local user is already synced.
  6788. //
  6789. if (!m_pLocalUser || m_pLocalUser->IsSynced())
  6790. {
  6791. TRACE_DEBUG(("User already synced"));
  6792. return;
  6793. }
  6794. //
  6795. // Update the local user's position information, to make sure it's up
  6796. // to date.
  6797. //
  6798. RECT rcVisDraw;
  6799. RECT rcVisUser;
  6800. m_drawingArea.GetVisibleRect(&rcVisDraw);
  6801. m_pLocalUser->SetVisibleRect(&rcVisDraw);
  6802. //
  6803. // We are not currently synced - sync now (if we have the contents
  6804. // lock, or are the first to sync, it will put our sync position).
  6805. //
  6806. m_pLocalUser->Sync();
  6807. //
  6808. // Set the synced check mark and pop up the sync button.
  6809. //
  6810. CheckMenuItem(IDM_SYNC);
  6811. m_TB.PushDown(IDM_SYNC);
  6812. //
  6813. // If the sync position (or zoom state) chosen was not where we are
  6814. // now, move to the current sync position (we are joining a set of
  6815. // synced users).
  6816. //
  6817. m_drawingArea.GetVisibleRect(&rcVisDraw);
  6818. m_pLocalUser->GetVisibleRect(&rcVisUser);
  6819. if ( (m_pLocalUser->Page() != m_hCurrentPage) ||
  6820. (!::EqualRect(&rcVisUser, &rcVisDraw)) ||
  6821. (m_pLocalUser->GetZoom() != m_drawingArea.Zoomed()) ) //CHANGED BY RAND
  6822. {
  6823. TRACE_DEBUG(("Move to new sync pos/state"));
  6824. ::PostMessage(m_hwnd, WM_USER_GOTO_USER_POSITION, 0, (LPARAM)m_pLocalUser->Handle());
  6825. }
  6826. } // Sync
  6827. //
  6828. //
  6829. // Function: Unsync
  6830. //
  6831. // Purpose: Unsync the Whiteboard with other users
  6832. //
  6833. //
  6834. void WbMainWindow::Unsync(void)
  6835. {
  6836. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::Unsync");
  6837. //
  6838. // Dont do anythig if we are already unsynced.
  6839. //
  6840. if (!m_pLocalUser || !m_pLocalUser->IsSynced())
  6841. {
  6842. TRACE_DEBUG(("Already unsynced"));
  6843. return;
  6844. }
  6845. //
  6846. // Unsync.
  6847. // Set the synced check mark and pop up the sync button.
  6848. //
  6849. m_pLocalUser->Unsync();
  6850. UncheckMenuItem(IDM_SYNC);
  6851. m_TB.PopUp(IDM_SYNC);
  6852. } // Unsync
  6853. //
  6854. //
  6855. // Function: SaveLock
  6856. //
  6857. // Purpose: Save the current lock type
  6858. //
  6859. //
  6860. void WbMainWindow::SaveLock(void)
  6861. {
  6862. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::SaveLock");
  6863. m_uiSavedLockType = WB_LOCK_TYPE_NONE;
  6864. // If we have the contents lock
  6865. if (WB_GotContentsLock())
  6866. {
  6867. TRACE_MSG(("Saved contents lock"));
  6868. m_uiSavedLockType = WB_LOCK_TYPE_CONTENTS;
  6869. }
  6870. else
  6871. {
  6872. // If we have the page order lock
  6873. if (WB_GotLock())
  6874. {
  6875. TRACE_MSG(("Saved page order lock"));
  6876. m_uiSavedLockType = WB_LOCK_TYPE_PAGE_ORDER;
  6877. }
  6878. }
  6879. }
  6880. //
  6881. //
  6882. // Function: RestoreLock
  6883. //
  6884. // Purpose: Restore the current lock type (SaveLock must have been
  6885. // called previously.
  6886. //
  6887. //
  6888. void WbMainWindow::RestoreLock(void)
  6889. {
  6890. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::RestoreLock");
  6891. switch(m_uiSavedLockType)
  6892. {
  6893. case WB_LOCK_TYPE_CONTENTS:
  6894. // If we do not have the contents lock
  6895. if (!WB_GotContentsLock())
  6896. {
  6897. // Get the contents lock (with invisible dialog)
  6898. TRACE_MSG(("Restoring contents lock"));
  6899. GetLock(WB_LOCK_TYPE_CONTENTS, SW_HIDE);
  6900. }
  6901. // we really own the lock, clear settled flag so page buttons don't hang
  6902. m_bUnlockStateSettled = TRUE;
  6903. break;
  6904. case WB_LOCK_TYPE_PAGE_ORDER:
  6905. if (!WB_GotLock() || WB_GotContentsLock())
  6906. {
  6907. // Get the page order lock (with invisible dialog)
  6908. TRACE_MSG(("Restoring page order lock"));
  6909. GetLock(WB_LOCK_TYPE_PAGE_ORDER, SW_HIDE);
  6910. }
  6911. //ADDED BY RAND- we really own the lock, clear settled flag
  6912. // so page buttons don't hang
  6913. m_bUnlockStateSettled = TRUE;
  6914. break;
  6915. case WB_LOCK_TYPE_NONE:
  6916. // If we have the lock
  6917. if (WB_GotLock())
  6918. {
  6919. // Release the lock
  6920. TRACE_MSG(("Restoring no lock"));
  6921. // Let WBP_EVENT_LOCKED handle m_bUnlockStateSettled flag
  6922. g_pwbCore->WBP_Unlock();
  6923. }
  6924. break;
  6925. default:
  6926. // We have saved an invalid lock type
  6927. ERROR_OUT(("Bad saved lock type"));
  6928. //ADDED BY RAND- somethings broken, clear settled flag
  6929. // so page buttons don't hang
  6930. m_bUnlockStateSettled = TRUE;
  6931. break;
  6932. }
  6933. }
  6934. //
  6935. //
  6936. // Function: GetLock
  6937. //
  6938. // Purpose: Get the Page Order Lock (synchronously)
  6939. //
  6940. //
  6941. BOOL WbMainWindow::GetLock(UINT uiLockType, UINT uiHide)
  6942. {
  6943. BOOL bGotRequiredLock = FALSE;
  6944. BOOL bCancelled = FALSE;
  6945. UINT uiDialogReturn = 0;
  6946. UINT lDialogDelay = 1;
  6947. UINT lTimeout = 0;
  6948. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::GetLock");
  6949. switch(uiLockType)
  6950. {
  6951. case WB_LOCK_TYPE_PAGE_ORDER:
  6952. TRACE_DEBUG(("WB_LOCK_TYPE_PAGE_ORDER"));
  6953. if (WB_GotLock())
  6954. {
  6955. TRACE_DEBUG(("Already got it"));
  6956. bGotRequiredLock = TRUE;
  6957. goto RestoreLockCleanup;
  6958. }
  6959. break;
  6960. case WB_LOCK_TYPE_CONTENTS:
  6961. TRACE_DEBUG(("WB_LOCK_TYPE_CONTENTS"));
  6962. if (WB_GotContentsLock())
  6963. {
  6964. TRACE_DEBUG(("Already got it"));
  6965. bGotRequiredLock = TRUE;
  6966. goto RestoreLockCleanup;
  6967. }
  6968. break;
  6969. default:
  6970. ERROR_OUT(("Invalid lock type requested"));
  6971. break;
  6972. }
  6973. if (WB_Locked())
  6974. {
  6975. TRACE_DEBUG(("Contents already locked"));
  6976. goto RestoreLockCleanup;
  6977. }
  6978. // check for any object locks
  6979. BOOL bAnObjectIsLocked;
  6980. WB_PAGE_HANDLE hPage;
  6981. DCWbGraphic* pGraphic;
  6982. bAnObjectIsLocked = FALSE;
  6983. hPage = m_drawingArea.Page();
  6984. if (hPage != WB_PAGE_HANDLE_NULL)
  6985. {
  6986. WB_GRAPHIC_HANDLE hStart;
  6987. pGraphic = PG_First(hPage, &hStart);
  6988. while (pGraphic != NULL)
  6989. {
  6990. // get object lock
  6991. bAnObjectIsLocked = pGraphic->Locked();
  6992. // Release the current graphic
  6993. delete pGraphic;
  6994. // check object lock
  6995. if( bAnObjectIsLocked )
  6996. break;
  6997. // Get the next one
  6998. pGraphic = PG_Next(hPage, &hStart, NULL);
  6999. }
  7000. }
  7001. if( bAnObjectIsLocked )
  7002. {
  7003. Message(NULL, IDS_LOCK, IDS_OBJECTSARELOCKED);
  7004. return( FALSE );
  7005. }
  7006. //
  7007. // If we get this far then we need to get the lock.
  7008. //
  7009. if (uiLockType == WB_LOCK_TYPE_PAGE_ORDER)
  7010. {
  7011. g_pwbCore->WBP_PageOrderLock();
  7012. }
  7013. else
  7014. {
  7015. g_pwbCore->WBP_ContentsLock();
  7016. }
  7017. //
  7018. // Bring up a dialog to wait for the response. This dialog is
  7019. // cancelled by the event handler code when the lock response event is
  7020. // received.
  7021. //
  7022. ASSERT(m_hwndWaitForLockDlg == NULL);
  7023. TMDLG tmdlg;
  7024. ZeroMemory(&tmdlg, sizeof(tmdlg));
  7025. tmdlg.bLockNotEvent = TRUE;
  7026. tmdlg.uiMaxDisplay = MAIN_LOCK_TIMEOUT;
  7027. if (uiHide == SW_SHOW)
  7028. {
  7029. tmdlg.bVisible = TRUE;
  7030. uiDialogReturn = (UINT)::DialogBoxParam(g_hInstance, MAKEINTRESOURCE(LOCKDIALOG),
  7031. m_hwnd, TimedDlgProc, (LPARAM)&tmdlg);
  7032. }
  7033. else
  7034. {
  7035. tmdlg.bVisible = FALSE;
  7036. uiDialogReturn = (UINT)::DialogBoxParam(g_hInstance, MAKEINTRESOURCE(INVISIBLEDIALOG),
  7037. m_hwnd, TimedDlgProc, (LPARAM)&tmdlg);
  7038. }
  7039. ASSERT(m_hwndWaitForLockDlg == NULL);
  7040. if (uiDialogReturn == IDCANCEL)
  7041. {
  7042. // The user cancelled the lock request or it timed out
  7043. TRACE_MSG(("User cancelled lock request"));
  7044. bCancelled = TRUE;
  7045. //
  7046. // If we havent already got the lock then unlock here.
  7047. //
  7048. if (!WB_GotLock())
  7049. {
  7050. TRACE_DEBUG(("Havent got lock confirmation yet - cancel it"));
  7051. g_pwbCore->WBP_Unlock();
  7052. }
  7053. goto RestoreLockCleanup;
  7054. }
  7055. switch(uiLockType)
  7056. {
  7057. case WB_LOCK_TYPE_PAGE_ORDER:
  7058. if (WB_GotLock())
  7059. {
  7060. bGotRequiredLock = TRUE;
  7061. }
  7062. break;
  7063. case WB_LOCK_TYPE_CONTENTS:
  7064. if (WB_GotContentsLock())
  7065. {
  7066. bGotRequiredLock = TRUE;
  7067. }
  7068. break;
  7069. default:
  7070. // can't get here - trapped at top.
  7071. ERROR_OUT(("Invalid lock type - internal error"));
  7072. break;
  7073. }
  7074. RestoreLockCleanup:
  7075. if (!bGotRequiredLock)
  7076. {
  7077. if( !bCancelled )
  7078. {
  7079. // post error only if user didn't cancel (bug NM4db:429)
  7080. TRACE_MSG(("Failed to get the lock"));
  7081. // post an error message indicating the failure to get the lock
  7082. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, WB_RC_LOCKED);
  7083. }
  7084. }
  7085. return(bGotRequiredLock);
  7086. }
  7087. //
  7088. //
  7089. // Function: OnLock
  7090. //
  7091. // Purpose: Lock or unlock the Whiteboard
  7092. //
  7093. //
  7094. void WbMainWindow::OnLock(void)
  7095. {
  7096. // If we have the lock, this is an unlock request
  7097. if (WB_GotContentsLock())
  7098. {
  7099. // if currently loading or doing a new, then restore page order lock
  7100. if (!IsIdle())
  7101. {
  7102. GetLock(WB_LOCK_TYPE_PAGE_ORDER, SW_HIDE);
  7103. }
  7104. else
  7105. {
  7106. // Release the lock
  7107. g_pwbCore->WBP_Unlock();
  7108. }
  7109. // Set the locked check mark
  7110. UncheckMenuItem(IDM_LOCK);
  7111. // Pop up the lock button
  7112. m_TB.PopUp(IDM_LOCK);
  7113. }
  7114. else
  7115. {
  7116. // If another user has the lock.
  7117. // We should not usually get here if another user has the lock because
  7118. // the Lock menu entry (and button) will be grayed.
  7119. if (WB_ContentsLocked())
  7120. {
  7121. // Display a message
  7122. Message(NULL, IDS_LOCK, IDS_LOCK_ERROR);
  7123. }
  7124. else
  7125. {
  7126. // Save the current lock state (in case the user cancels the request)
  7127. SaveLock();
  7128. // Catch exceptions raised during the lock request
  7129. // Request the lock
  7130. BOOL bGotLock = GetLock(WB_LOCK_TYPE_CONTENTS, SW_SHOW);
  7131. if (!bGotLock)
  7132. {
  7133. RestoreLock();
  7134. }
  7135. else
  7136. {
  7137. // Turn sync on and write our sync position
  7138. Sync();
  7139. m_pLocalUser->PutSyncPosition();
  7140. }
  7141. }
  7142. }
  7143. // Restore the focus to the drawing area
  7144. ::SetFocus(m_drawingArea.m_hwnd);
  7145. }
  7146. //
  7147. //
  7148. // Function : OnWBPLoadComplete
  7149. //
  7150. // Purpose : Finished loading a file
  7151. //
  7152. //
  7153. void WbMainWindow::OnWBPLoadComplete(void)
  7154. {
  7155. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPLoadComplete");
  7156. if (m_uiSubState == SUBSTATE_LOADING)
  7157. {
  7158. TRACE_MSG(("Load has completed OK"));
  7159. SetSubstate(SUBSTATE_IDLE);
  7160. if (WB_GotLock())
  7161. {
  7162. }
  7163. ReleasePageOrderLock();
  7164. }
  7165. else
  7166. {
  7167. TRACE_MSG(("Unexpected WBP_EVENT_LOAD_COMPLETE event ignored"));
  7168. }
  7169. }
  7170. //
  7171. //
  7172. // Function : OnWBPLoadFailed
  7173. //
  7174. // Purpose : Finished loading a file
  7175. //
  7176. //
  7177. void WbMainWindow::OnWBPLoadFailed(void)
  7178. {
  7179. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnWBPLoadFailed");
  7180. if (m_uiSubState == SUBSTATE_LOADING)
  7181. {
  7182. ::PostMessage(m_hwnd, WM_USER_DISPLAY_ERROR, WBFE_RC_WB, WB_RC_BAD_FILE_FORMAT);
  7183. TRACE_MSG(("Load has failed - tell the user about it..."));
  7184. SetSubstate(SUBSTATE_IDLE);
  7185. ReleasePageOrderLock();
  7186. }
  7187. else
  7188. {
  7189. TRACE_MSG(("Unexpected WBP_EVENT_LOAD_FAILED event ignored"));
  7190. }
  7191. }
  7192. //
  7193. //
  7194. // Function: GetWindowTitle
  7195. //
  7196. // Purpose: Return a string for the window title
  7197. //
  7198. //
  7199. TCHAR * WbMainWindow::GetWindowTitle()
  7200. {
  7201. // Calculate the size we will need
  7202. int strSize=0;
  7203. if( m_pLockOwner != NULL )
  7204. {
  7205. strSize = lstrlen(m_pLockOwner->Name());
  7206. }
  7207. // This is the worst scenario, the total size would be less than 2*_MAX_FNAME
  7208. // but we give a lot of space for localization.
  7209. int totalSize = 2*(_MAX_FNAME)
  7210. + strSize + 1
  7211. +3*(_MAX_FNAME); // account for the following strings, the total is probably < 200
  7212. // IDS_UNTITLED
  7213. // IDS_TITLE_SEPARATOR
  7214. // IDS_DEFAULT
  7215. // IDS_IN_CALL
  7216. // IDS_IN_CALL_OTHERS
  7217. // IDS_JOINING
  7218. // IDS_INITIALIZING
  7219. // IDS_NOT_IN_CALL
  7220. // IDS_LOCKEDTITLE
  7221. TCHAR *pTitle = new TCHAR[totalSize];
  7222. if (!pTitle)
  7223. {
  7224. ERROR_OUT(("GetWindowTitle: failed to allocate TCHAR array"));
  7225. return(NULL);
  7226. }
  7227. TCHAR inUseBy[_MAX_PATH];
  7228. TCHAR *pStartTitle = pTitle;
  7229. // Set title to either the "Untitled" string, or the loaded file name
  7230. if( (!lstrlen(m_strFileName))||
  7231. (GetFileTitle( m_strFileName, pTitle, 2*_MAX_FNAME ) != 0) )
  7232. {
  7233. strSize = ::LoadString(g_hInstance, IDS_UNTITLED, pTitle, totalSize );
  7234. pTitle+=strSize;
  7235. ASSERT(totalSize>strSize);
  7236. totalSize -=strSize;
  7237. }
  7238. else
  7239. {
  7240. strSize = lstrlen(pTitle);
  7241. pTitle +=strSize;;
  7242. ASSERT(totalSize>strSize);
  7243. totalSize -=strSize;
  7244. }
  7245. // Get the separator from resources
  7246. strSize = ::LoadString(g_hInstance, IDS_TITLE_SEPARATOR, pTitle, totalSize);
  7247. pTitle+=strSize;;
  7248. ASSERT(totalSize>strSize);
  7249. totalSize -=strSize;
  7250. // Get the application title from options
  7251. strSize = ::LoadString(g_hInstance, IDS_DEFAULT, pTitle, totalSize );
  7252. pTitle+=strSize;
  7253. ASSERT(totalSize>strSize);
  7254. totalSize -=strSize;
  7255. // Add either "In Call" or "Not in Call", or "Initialising" or
  7256. // "Joining a call"
  7257. strSize = ::LoadString(g_hInstance, IDS_TITLE_SEPARATOR, pTitle, totalSize);
  7258. pTitle+=strSize;
  7259. ASSERT(totalSize>strSize);
  7260. totalSize -=strSize;
  7261. if ((m_uiState == IN_CALL) && m_bCallActive)
  7262. {
  7263. UINT count;
  7264. count = g_pwbCore->WBP_PersonCountInCall();
  7265. strSize = ::LoadString(g_hInstance, IDS_IN_CALL, inUseBy, totalSize);
  7266. strSize=wsprintf(pTitle, inUseBy, (count-1));
  7267. pTitle+=strSize;
  7268. ASSERT(totalSize>strSize);
  7269. totalSize -=strSize;
  7270. }
  7271. else if ((m_uiState == JOINING) ||
  7272. ((m_uiState == JOINED) && !m_bCallActive) ||
  7273. ((m_uiState == IN_CALL) && (m_dwDomain != OM_NO_CALL) && !m_bCallActive))
  7274. {
  7275. strSize = ::LoadString(g_hInstance, IDS_JOINING, pTitle, totalSize );
  7276. pTitle+=strSize;
  7277. ASSERT(totalSize>strSize);
  7278. totalSize -=strSize;
  7279. }
  7280. else if (m_uiState == STARTING)
  7281. {
  7282. strSize = ::LoadString(g_hInstance, IDS_INITIALIZING, pTitle, totalSize);
  7283. pTitle+=strSize;
  7284. ASSERT(totalSize>strSize);
  7285. totalSize -=strSize;
  7286. }
  7287. else
  7288. {
  7289. strSize = ::LoadString(g_hInstance, IDS_NOT_IN_CALL, pTitle, totalSize);
  7290. pTitle+=strSize;
  7291. ASSERT(totalSize>strSize);
  7292. totalSize -=strSize;
  7293. }
  7294. // add lock info
  7295. if( m_pLockOwner != NULL )
  7296. {
  7297. strSize = ::LoadString(g_hInstance, IDS_LOCKEDTITLE, pTitle, totalSize);
  7298. ASSERT(totalSize>strSize);
  7299. pTitle+=strSize;
  7300. lstrcpy(pTitle, m_pLockOwner->Name());
  7301. }
  7302. // Return the complete title string
  7303. return pStartTitle;
  7304. }
  7305. LRESULT WbMainWindow::OnConfShutdown( WPARAM, LPARAM )
  7306. {
  7307. if (OnQueryEndSession())
  7308. {
  7309. ::SendMessage(m_hwnd, WM_CLOSE, 0, 0); // do close immediately
  7310. // :
  7311. // DON'T DO ANYTHING else at this point except for exit.
  7312. return( 0 );// tell conf ok to shutdown
  7313. }
  7314. else
  7315. return( (LRESULT)g_cuEndSessionAbort ); // don't shutdown
  7316. }
  7317. //
  7318. //
  7319. // Function: OnQueryEndSession
  7320. //
  7321. // Purpose: Ensure user is prompted to save changes when windows is
  7322. // ended.
  7323. //
  7324. //
  7325. LRESULT WbMainWindow::OnQueryEndSession(void)
  7326. {
  7327. HWND hwndPopup;
  7328. if ((hwndPopup = ::GetLastActivePopup(m_hwnd)) != m_hwnd)
  7329. {
  7330. Message(NULL, IDS_DEFAULT, IDS_CANTCLOSE );
  7331. ::BringWindowToTop(hwndPopup);
  7332. return( FALSE );
  7333. }
  7334. // If changes are required then prompt the user to save
  7335. int iDoNew = IDOK;
  7336. if (IsIdle())
  7337. {
  7338. iDoNew = QuerySaveRequired(TRUE);
  7339. if (iDoNew == IDYES)
  7340. {
  7341. // Save the changes
  7342. iDoNew = OnSave(FALSE);
  7343. }
  7344. }
  7345. // remember what we did so OnClose can act appropriately
  7346. m_bQuerySysShutdown = (iDoNew != IDCANCEL);
  7347. // If the user did not cancel, let windows exit
  7348. return( m_bQuerySysShutdown );
  7349. }
  7350. //
  7351. //
  7352. // Function: Recover
  7353. //
  7354. // Purpose: Ensure the whiteboard is not left partly registered.
  7355. //
  7356. //
  7357. //
  7358. void WbMainWindow::Recover()
  7359. {
  7360. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::Recover");
  7361. // If the error occurred during start-up, then quit immediately
  7362. if (m_uiState == STARTING)
  7363. {
  7364. TRACE_MSG(("error during startup - exiting"));
  7365. ::PostMessage(m_hwnd, WM_CLOSE, FALSE, 0L);
  7366. }
  7367. else
  7368. {
  7369. // ensure the drawing area is locked while we are in a bad state
  7370. LockDrawingArea();
  7371. // disable remote pointer while we are handling this join failure (bug 4767)
  7372. m_TB.Disable(IDM_REMOTE);
  7373. // set state to starting - ensures we don't get in an infinite loop,
  7374. // because if an error occurs then we will quit if we try to recover
  7375. m_uiState = STARTING;
  7376. TRACE_MSG(("Attempting to recover after join call failure - state set to STARTING"));
  7377. // state changed: update page buttons
  7378. UpdatePageButtons();
  7379. // see if there is a call active
  7380. CM_STATUS cmStatus;
  7381. // if there's a call available, try to join it
  7382. if (!CMS_GetStatus(&cmStatus))
  7383. cmStatus.callID = OM_NO_CALL;
  7384. ::PostMessage(m_hwnd, WM_USER_JOIN_CALL, FALSE, (LONG)cmStatus.callID);
  7385. }
  7386. }
  7387. //
  7388. //
  7389. // Function: UnlockDrawingArea
  7390. //
  7391. // Purpose: Unlock the drawing area and enable the appropriate buttons
  7392. //
  7393. //
  7394. //
  7395. void WbMainWindow::UnlockDrawingArea()
  7396. {
  7397. m_drawingArea.Unlock();
  7398. // Enable tool-bar buttons that can now be used
  7399. if (WB_Locked() || !IsIdle())
  7400. {
  7401. EnableToolbar( FALSE );
  7402. }
  7403. else
  7404. {
  7405. EnableToolbar( TRUE );
  7406. }
  7407. //
  7408. // Show the tool attributes group.
  7409. //
  7410. m_AG.DisplayTool(m_pCurrentTool);
  7411. }
  7412. //
  7413. //
  7414. // Function: LockDrawingArea
  7415. //
  7416. // Purpose: Lock the drawing area and enable the appropriate buttons
  7417. //
  7418. //
  7419. //
  7420. void WbMainWindow::LockDrawingArea()
  7421. {
  7422. m_drawingArea.Lock();
  7423. // Disable tool-bar buttons that cannot be used while locked
  7424. if (WB_Locked() || !IsIdle())
  7425. {
  7426. EnableToolbar( FALSE );
  7427. }
  7428. else
  7429. {
  7430. EnableToolbar( TRUE );
  7431. }
  7432. //
  7433. // Hide the tool attributes
  7434. //
  7435. if (m_WG.m_hwnd != NULL)
  7436. {
  7437. ::ShowWindow(m_WG.m_hwnd, SW_HIDE);
  7438. }
  7439. m_AG.Hide();
  7440. }
  7441. void WbMainWindow::EnableToolbar( BOOL bEnable )
  7442. {
  7443. if (bEnable)
  7444. {
  7445. m_TB.Enable(IDM_SELECT);
  7446. // don't allow text editing in zoom mode
  7447. if( m_drawingArea.Zoomed() )
  7448. m_TB.Disable(IDM_TEXT);
  7449. else
  7450. m_TB.Enable(IDM_TEXT);
  7451. m_TB.Enable(IDM_PEN);
  7452. m_TB.Enable(IDM_HIGHLIGHT);
  7453. m_TB.Enable(IDM_LINE);
  7454. m_TB.Enable(IDM_ZOOM);
  7455. m_TB.Enable(IDM_BOX);
  7456. m_TB.Enable(IDM_FILLED_BOX);
  7457. m_TB.Enable(IDM_ELLIPSE);
  7458. m_TB.Enable(IDM_FILLED_ELLIPSE);
  7459. m_TB.Enable(IDM_ERASER);
  7460. m_TB.Enable(IDM_GRAB_AREA);
  7461. m_TB.Enable(IDM_GRAB_WINDOW);
  7462. m_TB.Enable(IDM_LOCK);
  7463. m_TB.Enable(IDM_SYNC);
  7464. // enable remote pointer incase it was disabled handling
  7465. // join failures (bug 4767)
  7466. m_TB.Enable(IDM_REMOTE);
  7467. }
  7468. else
  7469. {
  7470. m_TB.Disable(IDM_SELECT);
  7471. m_TB.Disable(IDM_PEN);
  7472. m_TB.Disable(IDM_HIGHLIGHT);
  7473. m_TB.Disable(IDM_TEXT);
  7474. m_TB.Disable(IDM_LINE);
  7475. m_TB.Disable(IDM_ZOOM);
  7476. m_TB.Disable(IDM_BOX);
  7477. m_TB.Disable(IDM_FILLED_BOX);
  7478. m_TB.Disable(IDM_ELLIPSE);
  7479. m_TB.Disable(IDM_FILLED_ELLIPSE);
  7480. m_TB.Disable(IDM_ERASER);
  7481. m_TB.Disable(IDM_GRAB_AREA);
  7482. m_TB.Disable(IDM_GRAB_WINDOW);
  7483. m_TB.Disable(IDM_LOCK);
  7484. m_TB.Disable(IDM_SYNC);
  7485. }
  7486. }
  7487. //
  7488. //
  7489. // Function: UpdatePageButtons
  7490. //
  7491. // Purpose: Enable or disable the page buttons, according to the current
  7492. // state.
  7493. //
  7494. //
  7495. //
  7496. void WbMainWindow::UpdatePageButtons()
  7497. {
  7498. // Disable page buttons if not in a call, or doing a new, or another user
  7499. // has the lock and is synced.
  7500. if ( (m_uiState != IN_CALL) ||
  7501. (m_uiSubState == SUBSTATE_NEW_IN_PROGRESS) ||
  7502. (WB_PresentationMode()))
  7503. {
  7504. m_AG.EnablePageCtrls(FALSE);
  7505. // when the page buttons are disabled, we do not allow the page sorter
  7506. // dialog to be displayed
  7507. if (m_hwndPageSortDlg != NULL)
  7508. {
  7509. ::SendMessage(m_hwndPageSortDlg, WM_COMMAND, MAKELONG(IDOK, BN_CLICKED),
  7510. 0);
  7511. ASSERT(m_hwndPageSortDlg == NULL);
  7512. }
  7513. }
  7514. else
  7515. {
  7516. m_AG.EnablePageCtrls(TRUE);
  7517. }
  7518. if (WB_Locked() || !IsIdle() )
  7519. {
  7520. EnableToolbar( FALSE );
  7521. }
  7522. else
  7523. {
  7524. EnableToolbar( TRUE );
  7525. }
  7526. //
  7527. // If the page sorter is up, inform it of the state change
  7528. //
  7529. if (m_hwndPageSortDlg != NULL)
  7530. {
  7531. ::SendMessage(m_hwndPageSortDlg, WM_PS_ENABLEPAGEOPS,
  7532. (m_uiSubState == SUBSTATE_IDLE), 0);
  7533. }
  7534. //
  7535. // Enable the insert-page button if the page order's not locked
  7536. //
  7537. m_AG.EnableInsert( ((m_uiState == IN_CALL) &&
  7538. (m_uiSubState == SUBSTATE_IDLE) &&
  7539. (g_pwbCore->WBP_ContentsCountPages() < WB_MAX_PAGES) &&
  7540. (!WB_Locked())));
  7541. //
  7542. // Ensure the currently active menu (if any) is correctly enabled
  7543. //
  7544. InvalidateActiveMenu();
  7545. }
  7546. //
  7547. //
  7548. // Function: InvalidateActiveMenu
  7549. //
  7550. // Purpose: If a menu is currently active, gray items according to
  7551. // the current state, and force it to redraw.
  7552. //
  7553. //
  7554. void WbMainWindow::InvalidateActiveMenu()
  7555. {
  7556. if (m_hInitMenu != NULL)
  7557. {
  7558. // A menu is displayed, so set the state appropriately and force a
  7559. // repaint to show the new state
  7560. SetMenuStates(m_hInitMenu);
  7561. ::RedrawWindow(::GetTopWindow(::GetDesktopWindow()),
  7562. NULL, NULL,
  7563. RDW_FRAME | RDW_INVALIDATE | RDW_ERASE |
  7564. RDW_ERASENOW | RDW_ALLCHILDREN);
  7565. }
  7566. }
  7567. //
  7568. //
  7569. // Function: CancelLoad
  7570. //
  7571. // Purpose: Cancel any load in progress
  7572. //
  7573. //
  7574. void WbMainWindow::CancelLoad(BOOL bReleaseLock)
  7575. {
  7576. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::CancelLoad");
  7577. // Cancel the load
  7578. g_pwbCore->WBP_CancelLoad();
  7579. // reset file name to untitled
  7580. ZeroMemory(m_strFileName, sizeof(m_strFileName));
  7581. UpdateWindowTitle();
  7582. // reset the whiteboard substate
  7583. SetSubstate(SUBSTATE_IDLE);
  7584. if (bReleaseLock)
  7585. {
  7586. ReleasePageOrderLock();
  7587. }
  7588. }
  7589. //
  7590. //
  7591. // Function: ReleasePageOrderLock
  7592. //
  7593. // Purpose: Releases the page order lock, unless the user has got the
  7594. // contents locked, in which case it has no effect. Called
  7595. // after asynchronous functions requiring the page order lock
  7596. // (file/new, file/open) have completed.
  7597. //
  7598. //
  7599. void WbMainWindow::ReleasePageOrderLock()
  7600. {
  7601. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::ReleasePageOrderLock");
  7602. //
  7603. // Only release the page order lock if:
  7604. // - the contents are not also locked (if they are then releasing
  7605. // the page order lock has no effect).
  7606. // - we actually have the page order locked in the first place.
  7607. //
  7608. if ( (!WB_GotContentsLock()) &&
  7609. (WB_GotLock()) )
  7610. {
  7611. g_pwbCore->WBP_Unlock();
  7612. }
  7613. }
  7614. //
  7615. //
  7616. // Function: IsIdle
  7617. //
  7618. // Purpose: Returns true if the main window is idle (in a call and not
  7619. // loading a file/performing a new)
  7620. //
  7621. //
  7622. BOOL WbMainWindow::IsIdle()
  7623. {
  7624. return((m_uiState == IN_CALL) && (m_uiSubState == SUBSTATE_IDLE));
  7625. }
  7626. //
  7627. //
  7628. // Function: SetSubstate
  7629. //
  7630. // Purpose: Sets the substate, informing the page sorter dialog of the
  7631. // change, if necessary.
  7632. //
  7633. //
  7634. void WbMainWindow::SetSubstate(UINT newSubState)
  7635. {
  7636. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::SetSubstate");
  7637. // substate only valid if in a call
  7638. if ( (m_uiState != IN_CALL)
  7639. || (newSubState != m_uiSubState))
  7640. {
  7641. m_uiSubState = newSubState;
  7642. // Trace the substate change
  7643. switch (m_uiSubState)
  7644. {
  7645. case SUBSTATE_IDLE:
  7646. TRACE_DEBUG(("set substate to IDLE"));
  7647. break;
  7648. case SUBSTATE_LOADING:
  7649. TRACE_DEBUG(("set substate to LOADING"));
  7650. break;
  7651. case SUBSTATE_NEW_IN_PROGRESS:
  7652. TRACE_DEBUG(("set substate to NEW_IN_PROGRESS"));
  7653. break;
  7654. default:
  7655. ERROR_OUT(("Unknown substate %hd",m_uiSubState));
  7656. break;
  7657. }
  7658. // update the page buttons (may have become enabled/disabled)
  7659. UpdatePageButtons();
  7660. }
  7661. }
  7662. //
  7663. //
  7664. // Function: PositionUpdated
  7665. //
  7666. // Purpose: Called when the drawing area position has changed.
  7667. // change, if necessary.
  7668. //
  7669. //
  7670. void WbMainWindow::PositionUpdated()
  7671. {
  7672. RECT rectDraw;
  7673. m_drawingArea.GetVisibleRect(&rectDraw);
  7674. if (m_pLocalUser != NULL)
  7675. {
  7676. // Set the new position from the drawing area
  7677. m_pLocalUser->SetVisibleRect(&rectDraw);
  7678. // Show that an update of the sync position is pending
  7679. m_bSyncUpdateNeeded = TRUE;
  7680. }
  7681. // If the current page is a valid one then store the user's position on
  7682. // that page.
  7683. if (m_hCurrentPage != WB_PAGE_HANDLE_NULL)
  7684. {
  7685. // Store position of this page
  7686. WORD pageIndex = (WORD)m_hCurrentPage;
  7687. PAGE_POSITION *mapob;
  7688. POSITION position = m_pageToPosition.GetHeadPosition();
  7689. BOOL bFound = FALSE;
  7690. while (position && !bFound)
  7691. {
  7692. mapob = (PAGE_POSITION *)m_pageToPosition.GetNext(position);
  7693. if ( mapob->hPage == pageIndex)
  7694. {
  7695. bFound = TRUE;
  7696. }
  7697. }
  7698. // If we're replacing an existing entry, then free the old entry.
  7699. if (bFound)
  7700. {
  7701. mapob->position.x = rectDraw.left;
  7702. mapob->position.y = rectDraw.top;
  7703. }
  7704. else
  7705. {
  7706. mapob = new PAGE_POSITION;
  7707. if (!mapob)
  7708. {
  7709. ERROR_OUT(("PositionUpdated failing; couldn't allocate PAGE_POSITION object"));
  7710. }
  7711. else
  7712. {
  7713. mapob->hPage = pageIndex;
  7714. mapob->position.x = rectDraw.left;
  7715. mapob->position.y = rectDraw.top;
  7716. m_pageToPosition.AddTail(mapob);
  7717. }
  7718. }
  7719. }
  7720. }
  7721. //
  7722. //
  7723. // Function : OnALSLoadResult
  7724. //
  7725. // Purpose : Deal with an ALS_LOAD_RESULT event
  7726. //
  7727. //
  7728. void WbMainWindow::OnALSLoadResult(UINT reason)
  7729. {
  7730. int errorMsg = 0;
  7731. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnALSLoadResult");
  7732. switch (reason)
  7733. {
  7734. case AL_LOAD_FAIL_NO_FP:
  7735. WARNING_OUT(("Remote WB load failed - no FP"));
  7736. errorMsg = IDS_MSG_LOAD_FAIL_NO_FP;
  7737. break;
  7738. case AL_LOAD_FAIL_NO_EXE:
  7739. WARNING_OUT(("Remote WB load failed - no exe"));
  7740. errorMsg = IDS_MSG_LOAD_FAIL_NO_EXE;
  7741. break;
  7742. case AL_LOAD_FAIL_BAD_EXE:
  7743. WARNING_OUT(("Remote WB load failed - bad exe"));
  7744. errorMsg = IDS_MSG_LOAD_FAIL_BAD_EXE;
  7745. break;
  7746. case AL_LOAD_FAIL_LOW_MEM:
  7747. WARNING_OUT(("Remote WB load failed - low mem"));
  7748. errorMsg = IDS_MSG_LOAD_FAIL_LOW_MEM;
  7749. break;
  7750. default:
  7751. WARNING_OUT(("Bad ALSLoadResult reason %d", reason));
  7752. break;
  7753. }
  7754. if (errorMsg)
  7755. {
  7756. //
  7757. // Put up an error message
  7758. //
  7759. Message(NULL, IDS_MSG_CAPTION, errorMsg);
  7760. }
  7761. }
  7762. //
  7763. //
  7764. // Function : OnEndSession
  7765. //
  7766. // Purpose : Called when Windows is exiting
  7767. //
  7768. //
  7769. void WbMainWindow::OnEndSession(BOOL bEnding)
  7770. {
  7771. if (bEnding)
  7772. {
  7773. ::PostQuitMessage(0);
  7774. }
  7775. else
  7776. {
  7777. m_bQuerySysShutdown = FALSE; // never mind, cancel OnClose special handling
  7778. }
  7779. }
  7780. //
  7781. // Function: OnCancelMode()
  7782. //
  7783. // Purpose: Called whenever a WM_CANCELMODE message is sent to the frame
  7784. // window.
  7785. // WM_CANCELMODE is sent when another app or dialog receives the
  7786. // input focus. The frame simply records that a WM_CANCELMODE
  7787. // message has been sent. This fact is used by the SelectWindow
  7788. // code to determine if it should cancel the selecting of a
  7789. // window
  7790. //
  7791. //
  7792. void WbMainWindow::OnCancelMode()
  7793. {
  7794. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::OnCancelMode");
  7795. m_cancelModeSent = TRUE;
  7796. //
  7797. // Note: Not passed to the default handler as the default action on
  7798. // WM_CANCELMODE is to release mouse capture - we shall do this
  7799. // explicitly.
  7800. //
  7801. // blow off any dragging that might be in progress (bug 573)
  7802. POINT pt;
  7803. ::GetCursorPos( &pt );
  7804. ::ScreenToClient(m_drawingArea.m_hwnd, &pt);
  7805. ::SendMessage(m_drawingArea.m_hwnd, WM_LBUTTONUP, 0, MAKELONG( pt.x, pt.y ) );
  7806. }
  7807. void WbMainWindow::LoadCmdLine(LPCSTR szFilename)
  7808. {
  7809. int iOnSave;
  7810. if (szFilename && *szFilename)
  7811. {
  7812. if( UsersMightLoseData( NULL, NULL ) ) // bug NM4db:418
  7813. return;
  7814. // Don't prompt to save file if we're already loading
  7815. if (m_uiSubState != SUBSTATE_LOADING )
  7816. {
  7817. // Check whether there are changes to be saved
  7818. iOnSave = QuerySaveRequired(TRUE);
  7819. }
  7820. else
  7821. {
  7822. return;
  7823. }
  7824. if (iOnSave == IDYES)
  7825. {
  7826. // User wants to save the drawing area contents
  7827. int iResult = OnSave(TRUE);
  7828. if( iResult == IDOK )
  7829. {
  7830. UpdateWindowTitle();
  7831. }
  7832. else
  7833. {
  7834. // cancelled out of save, so cancel the open operation
  7835. return;
  7836. }
  7837. }
  7838. // load filename
  7839. if( iOnSave != IDCANCEL )
  7840. LoadFile(szFilename);
  7841. }
  7842. }
  7843. //
  7844. // OnNotify()
  7845. // Handles TTN_NEEDTEXTA and TTN_NEEDTEXTW
  7846. //
  7847. void WbMainWindow::OnNotify(UINT id, NMHDR * pNM)
  7848. {
  7849. UINT nID;
  7850. HWND hwnd = NULL;
  7851. POINT ptCurPos;
  7852. UINT nTipStringID;
  7853. if (!pNM)
  7854. return;
  7855. if (pNM->code == TTN_NEEDTEXTA)
  7856. {
  7857. TOOLTIPTEXTA *pTA = (TOOLTIPTEXTA *)pNM;
  7858. // get id and hwnd
  7859. if( pTA->uFlags & TTF_IDISHWND )
  7860. {
  7861. // idFrom is actually the HWND of the tool
  7862. hwnd = (HWND)pNM->idFrom;
  7863. nID = ::GetDlgCtrlID(hwnd);
  7864. }
  7865. else
  7866. {
  7867. nID = (UINT)pNM->idFrom;
  7868. }
  7869. // get tip string id
  7870. nTipStringID = GetTipId(hwnd, nID);
  7871. if (nTipStringID == 0)
  7872. return;
  7873. // give it to em
  7874. pTA->lpszText = MAKEINTRESOURCE( nTipStringID );
  7875. pTA->hinst = g_hInstance;
  7876. }
  7877. else if (pNM->code == TTN_NEEDTEXTW)
  7878. {
  7879. TOOLTIPTEXTW *pTW = (TOOLTIPTEXTW *)pNM;
  7880. // get id and hwnd
  7881. if( pTW->uFlags & TTF_IDISHWND )
  7882. {
  7883. // idFrom is actually the HWND of the tool
  7884. hwnd = (HWND)pNM->idFrom;
  7885. nID = ::GetDlgCtrlID(hwnd);
  7886. }
  7887. else
  7888. {
  7889. nID = (UINT)pNM->idFrom;
  7890. }
  7891. // get tip string id
  7892. nTipStringID = GetTipId(hwnd, nID );
  7893. if (nTipStringID == 0)
  7894. return;
  7895. // give it to em
  7896. pTW->lpszText = (LPWSTR) MAKEINTRESOURCE( nTipStringID );
  7897. pTW->hinst = g_hInstance;
  7898. }
  7899. }
  7900. //
  7901. // GetTipId()
  7902. // Finds the tooltip for a control in Whiteboard
  7903. //
  7904. UINT WbMainWindow::GetTipId(HWND hwndTip, UINT nID)
  7905. {
  7906. WbTool * pTool;
  7907. BOOL bCheckedState;
  7908. int nTipID;
  7909. int nTipStringID;
  7910. int i;
  7911. // find tip stuff relevant for nID
  7912. nTipID = -1;
  7913. for( i=0; i<((sizeof g_tipIDsArray)/(sizeof (TIPIDS) )); i++ )
  7914. {
  7915. if( g_tipIDsArray[i].nID == nID )
  7916. {
  7917. nTipID = i;
  7918. break;
  7919. }
  7920. }
  7921. // valid?
  7922. if( nTipID < 0 )
  7923. return( 0 );
  7924. // get checked state
  7925. switch( g_tipIDsArray[ nTipID ].nCheck )
  7926. {
  7927. case TB:
  7928. bCheckedState =
  7929. (::SendMessage(m_TB.m_hwnd, TB_ISBUTTONCHECKED, nID, 0) != 0);
  7930. break;
  7931. case BT:
  7932. if (hwndTip != NULL)
  7933. {
  7934. bCheckedState =
  7935. (::SendMessage(hwndTip, BM_GETSTATE, 0, 0) & 0x0003) == 1;
  7936. }
  7937. else
  7938. bCheckedState = FALSE;
  7939. break;
  7940. case NA:
  7941. default:
  7942. bCheckedState = FALSE;
  7943. break;
  7944. }
  7945. // get tip string id
  7946. if( bCheckedState )
  7947. nTipStringID = g_tipIDsArray[ nTipID ].nDownTipID;
  7948. else
  7949. nTipStringID = g_tipIDsArray[ nTipID ].nUpTipID;
  7950. // done
  7951. return( nTipStringID );
  7952. }
  7953. // gets default path if no saves or opens have been done yet
  7954. // Returns FALSE if last default should be reused
  7955. BOOL WbMainWindow::GetDefaultPath(LPTSTR csDefaultPath , UINT size)
  7956. {
  7957. DWORD dwType;
  7958. DWORD dwBufLen = size;
  7959. HKEY hDefaultKey = NULL;
  7960. BOOL bRet =FALSE;
  7961. if( !lstrlen(m_strFileName) )
  7962. {
  7963. // a name has not been picked yet in this session, use path
  7964. // to "My Documents"
  7965. if( (RegOpenKeyEx( HKEY_CURRENT_USER,
  7966. "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
  7967. 0,
  7968. KEY_READ,
  7969. &hDefaultKey )
  7970. != ERROR_SUCCESS) ||
  7971. (RegQueryValueEx( hDefaultKey,
  7972. "Personal",
  7973. NULL,
  7974. &dwType,
  7975. (BYTE *)csDefaultPath,
  7976. &dwBufLen )
  7977. != ERROR_SUCCESS))
  7978. {
  7979. // reg failed, use desktop
  7980. LPITEMIDLIST pidl;
  7981. if(SUCCEEDED (SHGetSpecialFolderLocation(GetDesktopWindow(),CSIDL_DESKTOPDIRECTORY,&pidl)))
  7982. {
  7983. bRet= SHGetPathFromIDList(pidl,csDefaultPath);
  7984. }
  7985. if( hDefaultKey != NULL )
  7986. RegCloseKey( hDefaultKey );
  7987. }
  7988. else
  7989. {
  7990. bRet = TRUE;
  7991. }
  7992. }
  7993. return bRet;
  7994. }
  7995. void WbMainWindow::OnSysColorChange( void )
  7996. {
  7997. if (m_drawingArea.Page() != WB_PAGE_HANDLE_NULL)
  7998. {
  7999. PG_ReinitPalettes();
  8000. ::InvalidateRect(m_hwnd, NULL, TRUE );
  8001. ::UpdateWindow(m_hwnd);
  8002. }
  8003. m_TB.RecolorButtonImages();
  8004. m_AG.RecolorButtonImages();
  8005. }
  8006. //
  8007. // posts a do-you-wana-do-that message if other users are in the conference
  8008. //
  8009. BOOL WbMainWindow::UsersMightLoseData( BOOL *pbWasPosted, HWND hwnd )
  8010. {
  8011. if ( (m_uiState == IN_CALL) && m_bCallActive )
  8012. {
  8013. UINT count;
  8014. count = g_pwbCore->WBP_PersonCountInCall();
  8015. if (count > 1)
  8016. {
  8017. if( pbWasPosted != NULL )
  8018. *pbWasPosted = TRUE;
  8019. return( ::Message(hwnd, IDS_DEFAULT, IDS_MSG_USERSMIGHTLOSE, MB_YESNO | MB_ICONEXCLAMATION ) != IDYES );
  8020. }
  8021. }
  8022. if( pbWasPosted != NULL )
  8023. *pbWasPosted = FALSE;
  8024. return( FALSE );
  8025. }
  8026. BOOL WbMainWindow::HasGraphicChanged( PWB_GRAPHIC pOldHeaderCopy, const PWB_GRAPHIC pNewHeader )
  8027. {
  8028. MLZ_EntryOut(ZONE_FUNCTION, "WbMainWindow::HasGraphicChanged");
  8029. // If nothing is different but the lock state and some misc in a WBP_EVENT_GRAPHIC_UPDATE_IND then
  8030. // the graphics are visually the same.
  8031. //
  8032. // NOTE: This does not check ZORDER. ZORDER changes are handled by WBP_EVENT_GRAPHIC_MOVED
  8033. // if objects aren't the same length, they are different
  8034. if( pOldHeaderCopy->length != pNewHeader->length )
  8035. return( TRUE );
  8036. // temporarialy set pOldHeaderCopy's locked state + misc to same as pNewHeader so we can do an
  8037. // object compare.
  8038. UINT uOldLocked = pOldHeaderCopy->locked;
  8039. pOldHeaderCopy->locked = pNewHeader->locked;
  8040. OM_OBJECT_ID oldlockPersonID = pOldHeaderCopy->lockPersonID;
  8041. pOldHeaderCopy->lockPersonID = pNewHeader->lockPersonID;
  8042. UINT oldloadedFromFile = pOldHeaderCopy->loadedFromFile;
  8043. pOldHeaderCopy->loadedFromFile = pNewHeader->loadedFromFile;
  8044. NET_UID oldloadingClientID = pOldHeaderCopy->loadingClientID;
  8045. pOldHeaderCopy->loadingClientID = pNewHeader->loadingClientID;
  8046. // compare objects
  8047. BOOL bChanged = FALSE;
  8048. if( memcmp( pOldHeaderCopy, pNewHeader, pOldHeaderCopy->length ) != 0 )
  8049. bChanged = TRUE;
  8050. // restore lock state + misc
  8051. pOldHeaderCopy->locked = (TSHR_UINT8)uOldLocked;
  8052. pOldHeaderCopy->lockPersonID = oldlockPersonID;
  8053. pOldHeaderCopy->loadedFromFile = (TSHR_UINT16)oldloadedFromFile;
  8054. pOldHeaderCopy->loadingClientID = oldloadingClientID;
  8055. return( bChanged );
  8056. }
  8057. void WbMainWindow::UpdateWindowTitle(void)
  8058. {
  8059. TCHAR *pTitle = GetWindowTitle();
  8060. if (pTitle != NULL)
  8061. {
  8062. ::SetWindowText(m_hwnd, pTitle);
  8063. delete pTitle;
  8064. }
  8065. }
  8066.