Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2751 lines
84 KiB

  1. // DeskMovr.cpp : Implementation of CDeskMovr
  2. #include "stdafx.h"
  3. #pragma hdrstop
  4. #include "deskmovr.h"
  5. #define DEFAULT_INTERVAL 200 // check every 1/5th of a second.
  6. #define DEFAULT_ENABLED TRUE
  7. #define DETECT_TIMER_ID 2323
  8. #ifndef SHDOC401_DLL
  9. #define ANIMATE_TIMER_ID 2324
  10. #define ANIMATE_TIMER_INTERVAL (60*1000)
  11. #endif
  12. #ifdef DEBUG
  13. const static TCHAR sz_DM1[] = TEXT("no dragable part");
  14. const static TCHAR sz_DM2[] = TEXT("caption menu button");
  15. const static TCHAR sz_DM3[] = TEXT("caption close button");
  16. const static TCHAR sz_DM4[] = TEXT("move the component");
  17. const static TCHAR sz_DM5[] = TEXT("resize width and height from bottom right corner");
  18. const static TCHAR sz_DM6[] = TEXT("resize width and height from top left corner");
  19. const static TCHAR sz_DM7[] = TEXT("resize width and height from top right corner");
  20. const static TCHAR sz_DM8[] = TEXT("resize width and height from bottom left corner");
  21. const static TCHAR sz_DM9[] = TEXT("resize from the top edge");
  22. const static TCHAR sz_DM10[] = TEXT("resize from the bottom edge");
  23. const static TCHAR sz_DM11[] = TEXT("resize from the left edge");
  24. const static TCHAR sz_DM12[] = TEXT("resize from the right edge");
  25. const LPCTSTR g_szDragModeStr[] = {
  26. sz_DM1,
  27. sz_DM2,
  28. sz_DM3,
  29. sz_DM4,
  30. sz_DM5,
  31. sz_DM6,
  32. sz_DM7,
  33. sz_DM8,
  34. sz_DM9,
  35. sz_DM10,
  36. sz_DM11,
  37. sz_DM12
  38. };
  39. #endif // DEBUG
  40. // Globals used to track cdeskmovr instances. Useful for optimizing the
  41. // detection code so we can turn off the timer when the mouse is not over our
  42. // window. We track the cdeskmovr instances only on the first thread that instantiates
  43. // us to keep the code simple, this should be the active desktop case.
  44. #define CDESKMOVR_TRACK_COUNT 16 // 2 is what we use now for the active desktop, but we need
  45. // extra slots in the array due to the fact that a new instance
  46. // is created before the old one is destroyed during refresh.
  47. // Make the array large to handle nested refreshes!
  48. HHOOK g_hMouseHook;
  49. HHOOK g_hKeyboardHook;
  50. DWORD g_dwHookThreadId;
  51. #ifndef SHDOC401_DLL
  52. BOOL g_fAnimTimer = FALSE;
  53. #endif
  54. typedef CDeskMovr *PDM;
  55. PDM g_apDM[CDESKMOVR_TRACK_COUNT];
  56. BOOL CombView_EnableAnimations(BOOL fEnable);
  57. DWORD g_fIgnoreTimers = 0;
  58. #define IGNORE_CONTEXTMENU_UP 0x0001
  59. #define IGNORE_CAPTURE_SET 0x0002
  60. #define GET_SKIP_COUNT (2 * ((GetDoubleClickTime() / m_lInterval) + 1))
  61. MAKE_CONST_BSTR(s_sstrNameMember, L"name");
  62. MAKE_CONST_BSTR(s_sstrHidden, L"hidden");
  63. MAKE_CONST_BSTR(s_sstrVisible, L"visible");
  64. MAKE_CONST_BSTR(s_sstrResizeableMember, L"resizeable");
  65. // These were declared in shellprv.h, so use DEFINE instead of MAKE
  66. DEFINE_CONST_BSTR(s_sstrIDMember, L"id");
  67. DEFINE_CONST_BSTR(s_sstrSubSRCMember, L"subscribed_url");
  68. DEFINE_CONST_BSTR(s_sstrSRCMember, L"src");
  69. #define CAPTION_ONLY (m_ItemState & (IS_FULLSCREEN | IS_SPLIT))
  70. #define ISNORMAL (m_ItemState & IS_NORMAL)
  71. #define ISFULLSCREEN (m_ItemState & IS_FULLSCREEN)
  72. #define ISSPLIT (m_ItemState & IS_SPLIT)
  73. #define CAPTIONBAR_HOTAREA(cyDefaultCaption, cyCurrentCaption) (((cyCurrentCaption == 0) && CAPTION_ONLY) ? (cyDefaultCaption / 2) : 3 * cyDefaultCaption)
  74. #define MAX_ID_LENGTH 5
  75. void ObtainSavedStateForElem( IHTMLElement *pielem,
  76. LPCOMPSTATEINFO pCompState, BOOL fRestoredState);
  77. DWORD g_aDMtoCSPushed[] = {0, CS_MENUPUSHED, CS_CLOSEPUSHED, CS_RESTOREPUSHED, CS_FULLSCREENPUSHED, CS_SPLITPUSHED};
  78. DWORD g_aDMtoCSTracked[] = {0, CS_MENUTRACKED, CS_CLOSETRACKED, CS_RESTORETRACKED, CS_FULLSCREENTRACKED, CS_SPLITTRACKED};
  79. DWORD g_aDMDCfromDragMode[] = {0, DMDC_MENU, DMDC_CLOSE, DMDC_RESTORE, DMDC_FULLSCREEN, DMDC_SPLIT};
  80. #define PUSHED(dm) (g_aDMtoCSPushed[(dm)])
  81. #define TRACKED(dm) (g_aDMtoCSTracked[(dm)])
  82. #define DMDCFROMDM(dm) (g_aDMDCfromDragMode[(dm)])
  83. // Trident will flash if you change the zindex, even if it's to the same index,
  84. // so we prevent the no-op call.
  85. HRESULT SafeZOrderSet(IHTMLStyle * pistyle, LONG lNewZIndex)
  86. {
  87. HRESULT hr = S_OK;
  88. VARIANT varZ;
  89. ASSERT(pistyle);
  90. pistyle->get_zIndex(&varZ);
  91. // Does the component need to be moved to the top?
  92. if ((VT_I4 != varZ.vt) || (varZ.lVal != lNewZIndex))
  93. {
  94. // Yes.
  95. varZ.vt = VT_I4;
  96. varZ.lVal = lNewZIndex;
  97. hr = pistyle->put_zIndex(varZ);
  98. }
  99. return hr;
  100. }
  101. // Keyboard hook is installed when first instance of deskmovr is created. Used to implement the keyboard
  102. // interface for accessing the deskmovr control. Hook is removed when there are no more deskmovr's
  103. // being tracked.
  104. LRESULT CALLBACK DeskMovr_KeyboardHook(int nCode, WPARAM wParam, LPARAM lParam)
  105. {
  106. LRESULT lRes;
  107. BOOL fHaveMover = FALSE;
  108. for (int i = 0; i < CDESKMOVR_TRACK_COUNT; i++) {
  109. if (g_apDM[i])
  110. {
  111. g_apDM[i]->OnKeyboardHook(wParam, lParam);
  112. fHaveMover = TRUE;
  113. }
  114. }
  115. lRes = CallNextHookEx(g_hKeyboardHook, nCode, wParam, lParam);
  116. if (!fHaveMover)
  117. {
  118. UnhookWindowsHookEx(g_hKeyboardHook);
  119. g_hKeyboardHook = NULL;
  120. }
  121. return lRes;
  122. }
  123. // Helper function used to track cdeskmovr intances so that we can turn off the
  124. // timer if the mouse leaves our window.
  125. void TrackMover(PDM pdm, BOOL fAdd)
  126. {
  127. if (!g_dwHookThreadId)
  128. g_dwHookThreadId = GetCurrentThreadId();
  129. if (!g_hKeyboardHook && fAdd)
  130. g_hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, DeskMovr_KeyboardHook, NULL, GetCurrentThreadId());
  131. if (!fAdd || (g_dwHookThreadId == GetCurrentThreadId())) {
  132. int i = 0;
  133. PDM pdmFind = fAdd ? NULL : pdm;
  134. PDM pdmAssign = fAdd ? pdm : NULL;
  135. while (i < CDESKMOVR_TRACK_COUNT) {
  136. if (g_apDM[i] == pdmFind) {
  137. g_apDM[i] = pdmAssign;
  138. break;
  139. }
  140. i++;
  141. }
  142. // If we ever fail to track a mover then we'll never be able to optimize
  143. // again. Shouldn't happen in practice for the case we care about.
  144. if (fAdd && (i >= CDESKMOVR_TRACK_COUNT))
  145. g_dwHookThreadId = 0xffffffff;
  146. ASSERT(!fAdd || (i < CDESKMOVR_TRACK_COUNT));
  147. }
  148. }
  149. #if 0
  150. void AnimateToTray(HWND hwnd, LONG lLeft, LONG lTop, LONG lWidth, LONG lHeight)
  151. {
  152. HWND hwndTray;
  153. if (hwndTray = FindWindow(c_szTrayClass, NULL))
  154. {
  155. RECT rcComp, rcTray;
  156. SetRect(&rcComp, lLeft, lTop, lLeft + lWidth, lTop + lHeight);
  157. MapWindowPoints(hwnd, NULL, (LPPOINT)&rcComp, 2);
  158. GetWindowRect(hwndTray, &rcTray);
  159. if ((rcTray.right - rcTray.left) > (rcTray.bottom - rcTray.top))
  160. rcTray.left = rcTray.right - GetSystemMetrics(SM_CXSMICON);
  161. else
  162. rcTray.top = rcTray.bottom - GetSystemMetrics(SM_CYSMICON);
  163. DrawAnimatedRects(hwnd, IDANI_CAPTION, (CONST RECT *)&rcComp, (CONST RECT *)&rcTray);
  164. }
  165. }
  166. #endif
  167. void AnimateComponent(HWND hwnd, LONG lLeftS, LONG lTopS, LONG lWidthS, LONG lHeightS,
  168. LONG lLeftD, LONG lTopD, LONG lWidthD, LONG lHeightD)
  169. {
  170. RECT rcSource, rcDest;
  171. SetRect(&rcSource, lLeftS, lTopS, lLeftS + lWidthS, lTopS + lHeightS);
  172. SetRect(&rcDest, lLeftD, lTopD, lLeftD + lWidthD, lTopD + lHeightD);
  173. // 98/10/02 vtan: Removed the mapping as not required.
  174. // MapWindowPoints(hwnd, NULL, (LPPOINT)&rcSource, 2);
  175. // MapWindowPoints(hwnd, NULL, (LPPOINT)&rcDest, 2);
  176. DrawAnimatedRects(hwnd, IDANI_CAPTION, (CONST RECT *)&rcSource, (CONST RECT *)&rcDest);
  177. }
  178. // Hook is installed when we detect we can turn our tracking timer off. The first
  179. // time we get a mouse event in the hook we reactivate all the movers and unhook
  180. // ourself.
  181. LRESULT CALLBACK DeskMovr_MouseHook(int nCode, WPARAM wParam, LPARAM lParam)
  182. {
  183. LRESULT lRes;
  184. #ifndef SHDOC401_DLL
  185. // If we are getting mouse messages then a portion of the window must be
  186. // visible so enable animations.
  187. CombView_EnableAnimations(TRUE);
  188. #endif
  189. for (int i = 0; i < CDESKMOVR_TRACK_COUNT; i++) {
  190. if (g_apDM[i])
  191. g_apDM[i]->SmartActivateMovr(ERROR_SUCCESS);
  192. }
  193. lRes = CallNextHookEx(g_hMouseHook, nCode, wParam, lParam);
  194. UnhookWindowsHookEx(g_hMouseHook);
  195. g_hMouseHook = NULL;
  196. return lRes;
  197. }
  198. /////////////////////////////////////////////////////////////////////////////
  199. // CDeskMovr
  200. CDeskMovr::CDeskMovr()
  201. : m_TimerWnd(_T("STATIC"), this, 1)
  202. {
  203. TraceMsg(TF_CUSTOM2, "CDeskMovr::CDeskMovr()");
  204. m_fEnabled = DEFAULT_ENABLED;
  205. m_lInterval = DEFAULT_INTERVAL;
  206. m_cxSMBorder = GetSystemMetrics(SM_CXBORDER);
  207. m_cySMBorder = GetSystemMetrics(SM_CYBORDER);
  208. m_cxBorder = m_cxSMBorder;
  209. m_cyBorder = m_cySMBorder;
  210. m_cyCaption = 0;
  211. m_dmCur = dmNull;
  212. m_dmTrack = dmNull;
  213. m_hcursor = LoadCursor(NULL, IDC_ARROW);
  214. m_CaptionState = 0;
  215. m_hwndParent;
  216. m_fTimer = FALSE;
  217. m_fCaptured = FALSE;
  218. m_uiTimerID = DETECT_TIMER_ID;
  219. m_pistyle = NULL;
  220. m_pistyleTarget = NULL;
  221. m_pielemTarget = NULL;
  222. m_iSrcTarget = -1;
  223. m_bstrTargetName = NULL;
  224. m_dx = m_dy = 0;
  225. m_top = m_left = m_width = m_height = 0;
  226. // Tell ATL that we don't want to be Windowless
  227. m_bWindowOnly = TRUE;
  228. // Track this instance
  229. TrackMover(this, TRUE);
  230. }
  231. CDeskMovr::~CDeskMovr(void)
  232. {
  233. TraceMsg(TF_CUSTOM2, "CDeskMovr::~CDeskMovr() m_bstrTargetName=%ls.", GEN_DEBUGSTRW(m_bstrTargetName));
  234. // clean up, detach from events, if necessary.
  235. DeactivateMovr(TRUE);
  236. if ( m_bstrTargetName != NULL )
  237. SysFreeString( m_bstrTargetName );
  238. TrackMover(this, FALSE);
  239. }
  240. HRESULT CDeskMovr::SmartActivateMovr(HRESULT hrPropagate)
  241. {
  242. if ((FALSE == m_nFreezeEvents) && m_fEnabled && !m_pielemTarget)
  243. {
  244. #ifndef SHDOC401_DLL
  245. // Release our animation timer if it exists and create our regular one
  246. if (g_fAnimTimer && (m_uiTimerID == ANIMATE_TIMER_ID))
  247. {
  248. m_TimerWnd.KillTimer(m_uiTimerID);
  249. m_uiTimerID = DETECT_TIMER_ID;
  250. g_fAnimTimer = FALSE;
  251. m_fTimer = m_TimerWnd.SetTimer(m_uiTimerID, m_lInterval) != 0;
  252. }
  253. #endif
  254. hrPropagate = ActivateMovr();
  255. if (!EVAL(SUCCEEDED(hrPropagate)))
  256. DeactivateMovr(FALSE); // Clean up mess.
  257. }
  258. return hrPropagate;
  259. }
  260. HRESULT CDeskMovr::FreezeEvents(BOOL fFreeze)
  261. {
  262. HRESULT hr = IOleControlImpl<CDeskMovr>::FreezeEvents(fFreeze);
  263. TraceMsg(TF_CUSTOM1, "CDeskMovr::FreezeEvents(fFreeze=%lx) m_nFreezeEvents=%lx; m_fEnabled=%lx, m_bstrTargetName=%ls", (DWORD)fFreeze, m_nFreezeEvents, m_fEnabled, GEN_DEBUGSTRW(m_bstrTargetName));
  264. m_nFreezeEvents = fFreeze;
  265. if (fFreeze)
  266. DeactivateMovr(FALSE);
  267. else
  268. hr = SmartActivateMovr(hr);
  269. return hr;
  270. }
  271. HRESULT CDeskMovr::Load(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog)
  272. {
  273. HRESULT hr;
  274. VARIANT var;
  275. ATLTRACE(_T("IPersistPropertyBagImpl::Load\n"));
  276. var.vt = VT_BOOL;
  277. hr = pPropBag->Read(L"Enabled", &var, NULL);
  278. if (SUCCEEDED(hr) && var.vt==VT_BOOL) {
  279. m_fEnabled = var.boolVal;
  280. }
  281. var.vt = VT_I4;
  282. hr = pPropBag->Read(L"Interval", &var, NULL);
  283. if (SUCCEEDED(hr) && var.vt==VT_I4) {
  284. m_lInterval = var.lVal;
  285. }
  286. var.vt = VT_BSTR;
  287. var.bstrVal = NULL;
  288. hr = pPropBag->Read(L"TargetName", &var, NULL);
  289. if (SUCCEEDED(hr) && var.vt==VT_BSTR) {
  290. m_bstrTargetName = var.bstrVal;
  291. }
  292. // This PARAM determines whether the control will be in the
  293. // windowed or windowless "layer" of the Trident layout.
  294. var.vt = VT_BOOL;
  295. hr = pPropBag->Read(L"WindowOnly", &var, NULL);
  296. if (SUCCEEDED(hr) && var.vt==VT_BOOL) {
  297. m_bWindowOnly = var.boolVal;
  298. }
  299. hr = _GetZOrderSlot(&m_zIndexTop, TRUE);
  300. ASSERT(SUCCEEDED(hr));
  301. hr = _GetZOrderSlot(&m_zIndexBottom, FALSE);
  302. ASSERT(SUCCEEDED(hr));
  303. return hr;
  304. }
  305. HRESULT CDeskMovr::Save(LPPROPERTYBAG pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
  306. {
  307. return E_NOTIMPL;
  308. }
  309. BOOL CDeskMovr::GetCaptionButtonRect(DragMode dm, LPRECT lprc)
  310. {
  311. BOOL fSuccess;
  312. *lprc = m_rectCaption;
  313. switch (dm) {
  314. case dmClose:
  315. lprc->left = m_rectCaption.right - (m_cyCaption + m_cxSMBorder);
  316. fSuccess = (lprc->left > (m_rectCaption.left + m_cyCaption));
  317. break;
  318. case dmMenu:
  319. lprc->right = lprc->left + (m_cyCaption + m_cxSMBorder);
  320. fSuccess = (m_rectCaption.right > (m_rectCaption.left + m_cyCaption));
  321. break;
  322. case dmRestore:
  323. if (ISNORMAL)
  324. return FALSE;
  325. else if (ISSPLIT)
  326. goto CalcSplit;
  327. else if (ISFULLSCREEN)
  328. goto CalcFullScreen;
  329. ASSERT(FALSE);
  330. case dmSplit:
  331. if (ISSPLIT || !m_fCanResizeX || !m_fCanResizeY)
  332. {
  333. return FALSE;
  334. }
  335. CalcSplit:
  336. lprc->left = m_rectCaption.right - (m_cyCaption + m_cxSMBorder);
  337. OffsetRect(lprc, -(lprc->right - lprc->left), 0);
  338. fSuccess = (lprc->left > (m_rectCaption.left + 2 * m_cyCaption));
  339. break;
  340. case dmFullScreen:
  341. if (ISFULLSCREEN || !m_fCanResizeX || !m_fCanResizeY)
  342. {
  343. return FALSE;
  344. }
  345. CalcFullScreen:
  346. lprc->left = m_rectCaption.right - (m_cyCaption + m_cxSMBorder);
  347. OffsetRect(lprc, -((lprc->right - lprc->left) * 2 - 2 * m_cxSMBorder), 0);
  348. fSuccess = (lprc->left > (m_rectCaption.left + 2 * m_cyCaption));
  349. break;
  350. default:
  351. ASSERT(FALSE);
  352. fSuccess = FALSE;
  353. break;
  354. }
  355. // Shrink the button within the caption and position it adjacent to the border
  356. if (fSuccess) {
  357. OffsetRect(lprc, ((dm == dmClose) ? m_cxSMBorder : -m_cxSMBorder), -m_cySMBorder);
  358. InflateRect(lprc, -m_cxSMBorder, -m_cySMBorder);
  359. lprc->bottom -= m_cySMBorder; // Take an extra border off the bottom
  360. }
  361. return fSuccess;
  362. }
  363. void CDeskMovr::DrawCaptionButton(HDC hdc, LPRECT lprc, UINT uType, UINT uState, BOOL fErase)
  364. {
  365. RECT rcT;
  366. HRGN hrgnWnd, hrgnRect;
  367. int iRet;
  368. if (fErase)
  369. FillRect(hdc, lprc, (HBRUSH)(COLOR_3DFACE + 1));
  370. rcT = *lprc;
  371. InflateRect(&rcT, -2*m_cxSMBorder, -2*m_cySMBorder);
  372. switch (uType) {
  373. case DMDC_CLOSE:
  374. uType = DFC_CAPTION;
  375. goto Draw;
  376. case DMDC_MENU:
  377. uType = DFC_SCROLL;
  378. Draw:
  379. // We need to clip the border of the outer edge in order to get the drawing effect we
  380. // want here...
  381. if (hrgnWnd = CreateRectRgn(0, 0, 0, 0)) {
  382. if ((iRet = GetClipRgn(hdc, hrgnWnd)) != -1) {
  383. if (hrgnRect = CreateRectRgnIndirect(&rcT)) {
  384. SelectClipRgn(hdc, hrgnRect);
  385. DeleteObject(hrgnRect);
  386. }
  387. }
  388. }
  389. DrawFrameControl(hdc, lprc, uType, uState);
  390. if (hrgnWnd != NULL)
  391. {
  392. SelectClipRgn(hdc, (iRet == 1) ? hrgnWnd : NULL);
  393. }
  394. if (hrgnWnd)
  395. DeleteObject(hrgnWnd);
  396. break;
  397. case DMDC_FULLSCREEN:
  398. case DMDC_SPLIT:
  399. case DMDC_RESTORE:
  400. {
  401. if (uState & DFCS_PUSHED)
  402. OffsetRect(&rcT, 1, 1);
  403. DrawEdge(hdc, &rcT, BDR_OUTER, BF_FLAT | BF_MONO | BF_RECT);
  404. #ifndef OLD_CODE
  405. switch (uType) {
  406. case DMDC_RESTORE:
  407. rcT.right = rcT.left + (rcT.right - rcT.left) * 3 / 4;
  408. rcT.bottom = rcT.top + (rcT.bottom - rcT.top) * 3 / 4;
  409. rcT.left += (rcT.right - rcT.left) / 2 + 1;
  410. rcT.top += (rcT.bottom - rcT.top) / 2 + 1;
  411. FillRect(hdc, &rcT, (HBRUSH)(COLOR_WINDOWFRAME + 1));
  412. break;
  413. case DMDC_SPLIT:
  414. rcT.top += m_cySMBorder;
  415. rcT.left += (rcT.right - rcT.left) * 3 / 10;
  416. DrawEdge(hdc, &rcT, BDR_OUTER, BF_FLAT | BF_MONO | BF_TOP | BF_LEFT);
  417. break;
  418. case DMDC_FULLSCREEN:
  419. rcT.top += m_cySMBorder;
  420. DrawEdge(hdc, &rcT, BDR_OUTER, BF_FLAT | BF_MONO | BF_TOP);
  421. break;
  422. }
  423. #else
  424. switch (uType) {
  425. case DMDC_RESTORE:
  426. rcT.right = rcT.left + (rcT.right - rcT.left) * 3 / 4;
  427. rcT.bottom = rcT.top + (rcT.bottom - rcT.top) * 3 / 4;
  428. rcT.left += (rcT.right - rcT.left) / 2 + 1;
  429. rcT.top += (rcT.bottom - rcT.top) / 2 + 1;
  430. break;
  431. case DMDC_SPLIT:
  432. rcT.left += (rcT.right - rcT.left) * 3 / 10;
  433. break;
  434. case DMDC_FULLSCREEN:
  435. break;
  436. }
  437. FillRect(hdc, &rcT, (HBRUSH)(COLOR_WINDOWFRAME + 1));
  438. #endif
  439. }
  440. break;
  441. }
  442. // DFCS_FLAT means no border to us
  443. if (!(uState & DFCS_FLAT))
  444. DrawEdge(hdc, lprc, ((uState & DFCS_PUSHED) ? BDR_SUNKENOUTER : BDR_RAISEDINNER), BF_RECT);
  445. }
  446. void CDeskMovr::DrawCaption(HDC hdc, UINT uDrawFlags, int x, int y)
  447. {
  448. RECT rect;
  449. UINT uState;
  450. DragMode dmT;
  451. // Draw the caption
  452. if (uDrawFlags & DMDC_CAPTION) {
  453. rect = m_rectCaption;
  454. OffsetRect(&rect, x, y);
  455. FillRect( hdc, &rect, (HBRUSH)(COLOR_3DFACE + 1) );
  456. }
  457. // Draw the caption frame controls
  458. for (dmT = dmMenu; dmT < dmMove; dmT = (DragMode)((int)dmT + 1))
  459. {
  460. if ((uDrawFlags & DMDCFROMDM(dmT)) && GetCaptionButtonRect(dmT, &rect))
  461. {
  462. if (dmT == dmMenu)
  463. uState = DFCS_SCROLLDOWN;
  464. else if (dmT == dmClose)
  465. uState = DFCS_CAPTIONCLOSE;
  466. else
  467. uState = 0;
  468. if ((dmT == dmClose) && SHRestricted(REST_NOCLOSEDESKCOMP))
  469. uState |= DFCS_INACTIVE | DFCS_FLAT;
  470. else
  471. {
  472. if (m_CaptionState & PUSHED(dmT))
  473. uState |= DFCS_PUSHED;
  474. if (!(m_CaptionState & (TRACKED(dmT) | PUSHED(dmT))))
  475. uState |= DFCS_FLAT;
  476. }
  477. OffsetRect(&rect, x, y);
  478. DrawCaptionButton(hdc, &rect, DMDCFROMDM(dmT), uState, !(uDrawFlags & DMDC_CAPTION));
  479. }
  480. }
  481. }
  482. HRESULT CDeskMovr::OnDraw(ATL_DRAWINFO& di)
  483. {
  484. RECT& rc = *(RECT*)di.prcBounds;
  485. RECT r;
  486. HBRUSH hbrush = (HBRUSH)(COLOR_3DFACE + 1);
  487. // top edge
  488. r.left = rc.left;
  489. r.top = rc.top;
  490. r.right = rc.right;
  491. r.bottom = rc.top + m_cyBorder;
  492. FillRect( di.hdcDraw, &r, hbrush );
  493. // left edge
  494. r.top = rc.top + m_cyBorder;
  495. r.right = rc.left + m_cxBorder;
  496. r.bottom = rc.bottom - m_cyBorder;
  497. FillRect( di.hdcDraw, &r, hbrush );
  498. // right edge
  499. r.right = rc.right;
  500. r.left = rc.right - m_cxBorder;
  501. FillRect( di.hdcDraw, &r, hbrush );
  502. // bottom edge
  503. r.left = rc.left;
  504. r.top = rc.bottom - m_cyBorder;
  505. r.right = rc.right;
  506. r.bottom = rc.bottom;
  507. FillRect( di.hdcDraw, &r, hbrush );
  508. if ( m_cyCaption != 0 ) {
  509. DrawCaption(di.hdcDraw, DMDC_ALL, rc.left, rc.top);
  510. }
  511. return S_OK;
  512. }
  513. HRESULT CDeskMovr::GetParentWindow(void)
  514. {
  515. HRESULT hr = S_OK;
  516. if (!m_hwndParent)
  517. {
  518. if (m_spInPlaceSite)
  519. hr = m_spInPlaceSite->GetWindow(&m_hwndParent);
  520. else
  521. {
  522. IOleInPlaceSiteWindowless * poipsw;
  523. ASSERT(m_spClientSite);
  524. if (m_spClientSite &&
  525. SUCCEEDED(hr = m_spClientSite->QueryInterface(IID_IOleInPlaceSiteWindowless, (void **)&poipsw)))
  526. {
  527. hr = poipsw->GetWindow(&m_hwndParent);
  528. poipsw->Release();
  529. }
  530. }
  531. if (!m_hwndParent)
  532. hr = S_FALSE; // We failed to get it.
  533. }
  534. return hr;
  535. }
  536. void CDeskMovr::DeactivateMovr(BOOL fDestroy)
  537. {
  538. TraceMsg(TF_CUSTOM2, "CDeskMovr::DeactivateMovr() m_fTimer=%lx, m_bstrTargetName=%ls", m_fTimer, GEN_DEBUGSTRW(m_bstrTargetName));
  539. if (fDestroy || (m_uiTimerID == DETECT_TIMER_ID)) {
  540. if (m_fTimer)
  541. {
  542. m_TimerWnd.KillTimer(m_uiTimerID);
  543. m_fTimer = FALSE;
  544. }
  545. if (m_TimerWnd.m_hWnd)
  546. m_TimerWnd.DestroyWindow();
  547. #ifndef SHDOC401_DLL
  548. if (m_uiTimerID == ANIMATE_TIMER_ID)
  549. g_fAnimTimer = FALSE;
  550. #endif
  551. }
  552. // DismissSelfNow();
  553. ATOMICRELEASE( m_pistyle );
  554. ATOMICRELEASE( m_pistyleTarget );
  555. ATOMICRELEASE( m_pielemTarget );
  556. _ChangeCapture(FALSE);
  557. }
  558. HRESULT CDeskMovr::ActivateMovr()
  559. {
  560. HRESULT hr;
  561. // flush out old interface pointers
  562. DeactivateMovr(FALSE);
  563. TraceMsg(TF_CUSTOM2, "CDeskMovr::ActivateMovr() m_fTimer=%lx, m_bstrTargetName=%ls", m_fTimer, GEN_DEBUGSTRW(m_bstrTargetName));
  564. if (m_fEnabled)
  565. {
  566. if (SUCCEEDED(hr = GetOurStyle()))
  567. {
  568. if ((m_bstrTargetName != NULL) && (m_lInterval > 0))
  569. {
  570. if (!m_TimerWnd.m_hWnd)
  571. {
  572. // create a new timer.
  573. RECT rc = {0, 0, 0 , 0};
  574. // We attempt to get our parent HWND (m_hwndParent) now.
  575. // If we fail (and we will sometimes), then we will get it later when
  576. // we need it and Trident is then ready.
  577. GetParentWindow();
  578. m_TimerWnd.Create(NULL, rc, _T("Timer"), WS_POPUP);
  579. }
  580. if (!m_fTimer)
  581. m_fTimer = m_TimerWnd.SetTimer(m_uiTimerID, m_lInterval) != 0;
  582. }
  583. else
  584. {
  585. #ifdef HIDE_ALL_HANDLES
  586. hr = S_FALSE;
  587. #else
  588. hr = E_FAIL;
  589. #endif
  590. }
  591. }
  592. }
  593. else
  594. {
  595. hr = E_FAIL;
  596. }
  597. return hr;
  598. }
  599. HRESULT CDeskMovr::GetOurStyle(void)
  600. {
  601. HRESULT hr;
  602. IOleControlSite *pictlsite = 0;
  603. IDispatch *pidisp = 0;
  604. // Reach up to get our extender, who is the custodian of our element style
  605. if (m_spClientSite &&
  606. EVAL(SUCCEEDED(hr = m_spClientSite->QueryInterface(IID_IOleControlSite, (LPVOID*)&pictlsite))) &&
  607. EVAL(SUCCEEDED(hr = pictlsite->GetExtendedControl(&pidisp))))
  608. {
  609. DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
  610. VARIANT var;
  611. VariantInit( &var );
  612. // Alas, all we have is IDispatch on our extender, so we'll have to use Invoke to get
  613. // the style object...
  614. hr = pidisp->Invoke( DISPID_IHTMLELEMENT_STYLE, IID_NULL,
  615. LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
  616. &dispparamsNoArgs, &var, NULL, NULL );
  617. if ( SUCCEEDED(hr) ) {
  618. if ( var.vt == VT_DISPATCH )
  619. hr = var.pdispVal->QueryInterface( IID_IHTMLStyle, (LPVOID*)&m_pistyle );
  620. else
  621. hr = E_FAIL; // Try VariantChangeType?????
  622. VariantClear( &var );
  623. }
  624. }
  625. ATOMICRELEASE( pictlsite );
  626. ATOMICRELEASE( pidisp );
  627. return hr;
  628. }
  629. void CDeskMovr::UpdateCaption(UINT uDrawFlags)
  630. {
  631. HDC hdc;
  632. int x = 0, y = 0;
  633. if (m_bWndLess) {
  634. if (!m_spInPlaceSite || !SUCCEEDED(m_spInPlaceSite->GetDC(NULL, 0, &hdc)))
  635. return;
  636. } else {
  637. hdc = ::GetDC(m_hWnd);
  638. }
  639. _MapPoints(&x, &y);
  640. DrawCaption(hdc, uDrawFlags, -x, -y);
  641. if (m_bWndLess) {
  642. m_spInPlaceSite->ReleaseDC(hdc);
  643. } else {
  644. ::ReleaseDC(m_hWnd, hdc);
  645. }
  646. }
  647. void CDeskMovr::CheckCaptionState(int x, int y)
  648. {
  649. DragMode dm, dmT;
  650. UINT uDrawFlags = 0;
  651. _MapPoints (&x, &y);
  652. POINT pt = { x, y };
  653. if (m_fCaptured)
  654. dm = dmNull;
  655. else
  656. dm = DragModeFromPoint( pt );
  657. if (dm >= dmMenu && dm < dmMove)
  658. {
  659. if (!(m_CaptionState & (PUSHED(dm) | TRACKED(dm))))
  660. {
  661. m_CaptionState |= TRACKED(dm);
  662. uDrawFlags |= DMDCFROMDM(dm);
  663. }
  664. }
  665. for (dmT = dmMenu; dmT < dmMove; dmT = (DragMode)((int)dmT + 1))
  666. {
  667. if (dm != dmT && (m_CaptionState & (PUSHED(dmT) | TRACKED(dmT))))
  668. {
  669. m_CaptionState &= ~(PUSHED(dmT) | TRACKED(dmT));
  670. uDrawFlags |= DMDCFROMDM(dmT);
  671. }
  672. }
  673. if (uDrawFlags)
  674. UpdateCaption(uDrawFlags);
  675. }
  676. //=--------------------------------------------------------------------------=
  677. // CDeskMovr::DoMouseDown [instance method]
  678. //=--------------------------------------------------------------------------=
  679. // Respond to mouse down messages in our control. Initiate move/resize.
  680. //
  681. // Parameters:
  682. // int - [in] mouse message key flags
  683. // int - [in] mouse x location in control coords
  684. // int - [in] mouse y location in control coords
  685. //
  686. // Output:
  687. // <none>
  688. //
  689. // Notes:
  690. BOOL CDeskMovr::HandleNonMoveSize(DragMode dm)
  691. {
  692. m_dmCur = dm;
  693. switch (dm) {
  694. case dmMenu:
  695. case dmClose:
  696. case dmRestore:
  697. case dmFullScreen:
  698. case dmSplit:
  699. if (m_dmCur != dmClose || !SHRestricted(REST_NOCLOSEDESKCOMP)) // Special case for Close, check restriction
  700. {
  701. m_CaptionState &= ~(TRACKED(m_dmCur));
  702. m_CaptionState |= PUSHED(m_dmCur);
  703. UpdateCaption(DMDCFROMDM(m_dmCur));
  704. // Perform the operation on the up-click of the mouse...
  705. }
  706. if (m_dmCur == dmMenu && EVAL(S_OK == GetParentWindow())) // Special case for Menu, invoke on the down click
  707. {
  708. _DisplayContextMenu();
  709. }
  710. return TRUE;
  711. break;
  712. default:
  713. return FALSE;
  714. break;
  715. }
  716. }
  717. LRESULT CDeskMovr::OnMouseDown( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  718. {
  719. int x = (short)LOWORD(lParam);
  720. int y = (short)HIWORD(lParam);
  721. _MapPoints(&x, &y);
  722. TraceMsg(TF_CUSTOM2, "CDeskMovr::OnMouseDown() Mouse=<%d,%d>, Inner=<%d,%d,%d,%d>, Caption=<%d,%d,%d,%d>, m_bstrTargetName=%ls",
  723. x, y, m_rectInner.left, m_rectInner.top, m_rectInner.right, m_rectInner.bottom,
  724. m_rectCaption.left, m_rectCaption.top, m_rectCaption.right, m_rectCaption.bottom, GEN_DEBUGSTRW(m_bstrTargetName));
  725. POINT pt = { x, y };
  726. m_dmCur = DragModeFromPoint( pt );
  727. if (HandleNonMoveSize(m_dmCur))
  728. return 0;
  729. switch ( m_dmCur ) {
  730. case dmMove:
  731. m_dx = -x;
  732. m_dy = -y;
  733. break;
  734. case dmSizeWHBR:
  735. m_dx = m_rectInner.right - x;
  736. m_dy = m_rectInner.bottom - y;
  737. break;
  738. case dmSizeWHTL:
  739. m_dx = m_rectInner.left - x;
  740. m_dy = m_rectInner.top + m_cyCaption - y;
  741. break;
  742. case dmSizeWHTR:
  743. m_dx = m_rectInner.right - x;
  744. m_dy = m_rectInner.top + m_cyCaption - y;
  745. break;
  746. case dmSizeWHBL:
  747. m_dx = m_rectInner.left - x;
  748. m_dy = m_rectInner.bottom - y;
  749. break;
  750. case dmSizeTop:
  751. m_dx = 0;
  752. m_dy = m_rectInner.top + m_cyCaption - y;
  753. break;
  754. case dmSizeBottom:
  755. m_dx = 0;
  756. m_dy = m_rectInner.bottom - y;
  757. break;
  758. case dmSizeLeft:
  759. m_dx = m_rectInner.left - x;
  760. m_dy = 0;
  761. break;
  762. case dmSizeRight:
  763. m_dx = m_rectInner.right - x;
  764. m_dy = 0;
  765. break;
  766. default:
  767. bHandled = FALSE;
  768. return 1;
  769. }
  770. #ifdef DEBUG
  771. TraceMsg(TF_CUSTOM2, "CDeskMovr::OnMouseDown() New DragMode=""%s""", g_szDragModeStr[m_dmCur]);
  772. #endif // DEBUG
  773. // NOTE: (seanf, 1/31/97) temporary defense against 17902. We really
  774. // shouldn't ever be in visible and non-targeted at the same time, but
  775. // the resize trick we pull in CDeskMovr::ActivateMovr() to get us
  776. // in-place active exposes a 1X1 pixel area, just big enough for StanTak
  777. // to click on when we don't have a target, which then kills us when
  778. // we try to move the non-existent target.
  779. if ( m_pielemTarget != NULL ) {
  780. _ChangeCapture(TRUE);
  781. if (m_fCaptured)
  782. {
  783. // Move the target to the top and put ourselves just under it
  784. VARIANT varZ;
  785. m_pistyleTarget->get_zIndex(&varZ);
  786. // Does the component need to be moved to the top?
  787. if (!CAPTION_ONLY && ((VT_I4 != varZ.vt) || (varZ.lVal != m_zIndexTop)))
  788. {
  789. // Yes.
  790. varZ.vt = VT_I4;
  791. varZ.lVal = ++m_zIndexTop;
  792. // Move the DeskMover ActiveX Control on top of everything.
  793. m_pistyle->put_zIndex(varZ);
  794. // Move the Desktop Item on top of the DeskMover
  795. varZ.lVal = ++m_zIndexTop;
  796. m_pistyleTarget->put_zIndex(varZ);
  797. }
  798. }
  799. #ifdef DEBUG
  800. if (!m_fCaptured)
  801. TraceMsg(TF_CUSTOM2, "CDeskMovr::OnMouseDown() Unable to get capture, tracking will fail!");
  802. #endif
  803. }
  804. return 0;
  805. }
  806. //=--------------------------------------------------------------------------=
  807. // CDeskMovr::DoMouseUp [instance method]
  808. //=--------------------------------------------------------------------------=
  809. // Respond to mouse down messages in our control. Terminate move/resize.
  810. //
  811. // Parameters:
  812. // int - [in] mouse message key flags
  813. // int - [in] mouse x location in control coords
  814. // int - [in] mouse y location in control coords
  815. // UINT - [in] from the DeskMovrParts enum
  816. //
  817. // Output:
  818. // <none>
  819. //
  820. // Notes:
  821. LRESULT CDeskMovr::OnMouseUp( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  822. {
  823. if ( m_fCaptured ) {
  824. PersistTargetPosition( m_pielemTarget, m_left, m_top, m_width, m_height, m_zIndexTop, FALSE, FALSE, m_ItemState );
  825. _ChangeCapture(FALSE);
  826. } else {
  827. int x = (short)LOWORD(lParam);
  828. int y = (short)HIWORD(lParam);
  829. _MapPoints(&x, &y);
  830. POINT pt = { x, y };
  831. DragMode dm = DragModeFromPoint( pt );
  832. if ((dm >= dmMenu) && (dm < dmMove) && (m_CaptionState & PUSHED(dm)))
  833. {
  834. m_CaptionState &= ~(PUSHED(dm));
  835. m_CaptionState |= TRACKED(dm);
  836. UpdateCaption(DMDCFROMDM(dm));
  837. switch ( dm ) {
  838. case dmClose:
  839. // AnimateToTray(m_hwndParent, m_left, m_top, m_width, m_height);
  840. IElemCloseDesktopComp(m_pielemTarget);
  841. break;
  842. case dmRestore:
  843. _HandleZoom(IDM_DCCM_RESTORE);
  844. break;
  845. case dmFullScreen:
  846. _HandleZoom(IDM_DCCM_FULLSCREEN);
  847. break;
  848. case dmSplit:
  849. _HandleZoom(IDM_DCCM_SPLIT);
  850. break;
  851. }
  852. if (dm != dmMenu)
  853. DismissSelfNow();
  854. }
  855. }
  856. return 0;
  857. }
  858. //=--------------------------------------------------------------------------=
  859. // CDeskMovrControl::DoMouseMove [instance method]
  860. //=--------------------------------------------------------------------------=
  861. // Respond to mouse move messages in our control and when moving/sizing.
  862. //
  863. // Parameters:
  864. //
  865. // Output:
  866. // <none>
  867. //
  868. // Notes:
  869. LRESULT CDeskMovr::OnPaint( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  870. {
  871. TraceMsg(TF_CUSTOM2, "CDeskMovr::OnPaint() uMsg=%lx, wParam=%lx, lParam=%lx, m_bstrTargetName=%ls", uMsg, wParam, lParam, GEN_DEBUGSTRW(m_bstrTargetName));
  872. return CComControl<CDeskMovr>::OnPaint( uMsg, wParam, lParam, bHandled );
  873. }
  874. //=--------------------------------------------------------------------------=
  875. // CDeskMovrControl::DoMouseMove [instance method]
  876. //=--------------------------------------------------------------------------=
  877. // Respond to mouse move messages in our control and when moving/sizing.
  878. //
  879. // Parameters:
  880. //
  881. // Output:
  882. // <none>
  883. //
  884. // Notes:
  885. LRESULT CDeskMovr::OnMouseMove( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  886. {
  887. CheckCaptionState((short)LOWORD(lParam), (short)HIWORD(lParam));
  888. if (m_fCaptured && EVAL(S_OK == GetParentWindow()))
  889. {
  890. // Okay, it's a hit on one of our gadgets.
  891. // We're only interested in mouse moves and mouse ups if we're in the
  892. // process of a drag or resize
  893. HRESULT hr;
  894. POINT ptDoc; // location in document window coords
  895. POINT ptScreen;
  896. HWND hwndParent = m_hwndParent;
  897. int x = (short)LOWORD(lParam);
  898. int y = (short)HIWORD(lParam);
  899. ptScreen.x = x;
  900. ptScreen.y = y;
  901. ptDoc = ptScreen;
  902. if ( !m_bWndLess )
  903. ::MapWindowPoints( m_hWnd, hwndParent, &ptDoc, 1 );
  904. if ( m_dmCur == dmMove )
  905. hr = MoveSelfAndTarget( ptDoc.x + m_dx + m_cxBorder, ptDoc.y + m_dy + m_cyBorder + m_cyCaption );
  906. else if ( m_dmCur > dmMove )
  907. hr = SizeSelfAndTarget( ptDoc );
  908. ASSERT(SUCCEEDED(hr));
  909. }
  910. // Set m_cSkipTimer so that we delay dismissing the mover...
  911. m_cSkipTimer = GET_SKIP_COUNT;
  912. return 0;
  913. }
  914. LRESULT CDeskMovr::OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  915. {
  916. HRESULT hr;
  917. IHTMLElement *pielem;
  918. POINT ptCursor;
  919. BOOL fDidWork = FALSE;
  920. #ifndef SHDOC401_DLL
  921. /*
  922. * Check our animation timer first. If we are able to disable animations then
  923. * blow away the timer. Otherwise reset the timer for 60 seconds and keep on
  924. * looking.
  925. */
  926. if (wParam == ANIMATE_TIMER_ID)
  927. {
  928. if (CombView_EnableAnimations(FALSE))
  929. {
  930. m_TimerWnd.SetTimer(ANIMATE_TIMER_ID, ANIMATE_TIMER_INTERVAL);
  931. }
  932. else
  933. {
  934. m_TimerWnd.KillTimer(m_uiTimerID);
  935. m_uiTimerID = DETECT_TIMER_ID;
  936. g_fAnimTimer = FALSE;
  937. m_fTimer = FALSE;
  938. }
  939. return 0;
  940. }
  941. #endif
  942. if (!m_fTimer || g_fIgnoreTimers || !GetCursorPos( &ptCursor ) || !m_pistyle)
  943. return 0;
  944. if (ptCursor.x == m_ptMouseCursor.x && ptCursor.y == m_ptMouseCursor.y)
  945. // Mouse stayed still from last time we did a timer so, do nothing
  946. return 0;
  947. pielem = NULL;
  948. if (S_OK == GetParentWindow())
  949. {
  950. HWND hwndParent = m_hwndParent;
  951. HWND hwndCursor = WindowFromPoint(ptCursor);
  952. if ((hwndCursor != hwndParent) && !::IsChild(hwndParent, hwndCursor))
  953. {
  954. // The mouse has drifted out of our window, so lose our target, if any
  955. if (m_iSrcTarget >= 0)
  956. {
  957. hr = MoveSelfToTarget( NULL, NULL );
  958. ASSERT(SUCCEEDED(hr));
  959. if (hr != S_FALSE)
  960. {
  961. fDidWork = TRUE;
  962. }
  963. }
  964. if (GetCurrentThreadId() == g_dwHookThreadId) {
  965. #ifndef SHDOC401_DLL
  966. // Set ourselves up so we can look to see if our animations can be turned off
  967. if (!g_fAnimTimer)
  968. {
  969. if (m_fTimer)
  970. m_TimerWnd.KillTimer(m_uiTimerID);
  971. if (g_fAnimTimer = (m_TimerWnd.SetTimer(ANIMATE_TIMER_ID, ANIMATE_TIMER_INTERVAL / 10) != 0))
  972. m_uiTimerID = ANIMATE_TIMER_ID;
  973. m_fTimer = g_fAnimTimer;
  974. }
  975. #endif
  976. DismissSelfNow();
  977. DeactivateMovr(FALSE);
  978. if (!g_hMouseHook)
  979. g_hMouseHook = SetWindowsHookEx(WH_MOUSE, DeskMovr_MouseHook, NULL, GetCurrentThreadId());
  980. }
  981. }
  982. else if (!(GetDesktopFlags() & COMPONENTS_LOCKED) && SUCCEEDED(hr = _IsInElement(hwndParent, &ptCursor, &pielem)))
  983. {
  984. // See if we need to do anything based on the element under the mouse pointer
  985. hr = _TrackElement(&ptCursor, pielem, &fDidWork);
  986. // we're done with this particular interface pointer
  987. pielem->Release();
  988. }
  989. else if (m_iSrcTarget != -1) {
  990. // Check to see if we should expand border to size border width
  991. if (TrackCaption ( &ptCursor ))
  992. {
  993. TrackTarget(NULL);
  994. }
  995. }
  996. }
  997. if (!fDidWork)
  998. m_ptMouseCursor = ptCursor;
  999. return 0;
  1000. }
  1001. LRESULT CDeskMovr::OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  1002. {
  1003. if (!m_bWndLess) {
  1004. RECT rc;
  1005. ::GetClientRect(m_hWnd, &rc);
  1006. FillRect((HDC)wParam, &rc, (HBRUSH)(COLOR_3DFACE + 1));
  1007. }
  1008. bHandled = TRUE;
  1009. return 0;
  1010. }
  1011. //
  1012. // DismissSelfNow - Little helper function to dismiss the mover immediately
  1013. //
  1014. // Normally dismissal of the mover is desired to be done on a delayed basis. However,
  1015. // there are situations such as when the user clicks on UI or capture is lost etc. where
  1016. // it is desirable to dismiss the mover immediately.
  1017. //
  1018. void CDeskMovr::DismissSelfNow(void)
  1019. {
  1020. HRESULT hr;
  1021. m_cSkipTimer = 0;
  1022. hr = MoveSelfToTarget(NULL, NULL);
  1023. ASSERT(SUCCEEDED(hr) && (hr != S_FALSE));
  1024. }
  1025. LRESULT CDeskMovr::OnCaptureChanged( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  1026. {
  1027. if ( m_fCaptured ) {
  1028. _ChangeCapture(FALSE);
  1029. PersistTargetPosition( m_pielemTarget, m_left, m_top, m_width, m_height, m_zIndexTop, FALSE, FALSE, m_ItemState );
  1030. DismissSelfNow();
  1031. }
  1032. return 0;
  1033. }
  1034. HRESULT CDeskMovr::InPlaceDeactivate(void)
  1035. {
  1036. DeactivateMovr(FALSE);
  1037. TraceMsg(TF_CUSTOM1, "CDeskMovr::InPlaceDeactivate()");
  1038. return CComControl<CDeskMovr>::IOleInPlaceObject_InPlaceDeactivate();
  1039. }
  1040. LRESULT CDeskMovr::OnSetCursor( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  1041. {
  1042. if (EVAL(S_OK == GetParentWindow()))
  1043. {
  1044. POINT ptCursor;
  1045. DragMode dm;
  1046. GetCursorPos( &ptCursor );
  1047. ::ScreenToClient( m_hwndParent, &ptCursor );
  1048. // Get ptCursor into deskmovr local coords
  1049. ptCursor.x -= m_left - (CAPTION_ONLY ? 0 : m_cxBorder);
  1050. ptCursor.y -= m_top - (CAPTION_ONLY ? 0 : (m_cyBorder + m_cyCaption));
  1051. dm = DragModeFromPoint(ptCursor);
  1052. m_hcursor = CursorFromDragMode(dm);
  1053. TraceMsg(TF_CUSTOM2, "CDeskMovr::OnSetCursor() Mouse=<%d,%d>, Inner=<%d,%d,%d,%d>, Caption=<%d,%d,%d,%d>, m_bstrTargetName=%ls",
  1054. ptCursor.x, ptCursor.y, m_rectInner.left, m_rectInner.top, m_rectInner.right, m_rectInner.bottom,
  1055. m_rectCaption.left, m_rectCaption.top, m_rectCaption.right, m_rectCaption.bottom, GEN_DEBUGSTRW(m_bstrTargetName));
  1056. #ifdef DEBUG
  1057. TraceMsg(TF_CUSTOM2, "CDeskMovr::OnSetCursor() New DragMode=""%s""", g_szDragModeStr[dm]);
  1058. #endif // DEBUG
  1059. if (EVAL(m_hcursor != NULL))
  1060. SetCursor( m_hcursor );
  1061. else
  1062. bHandled = FALSE;
  1063. }
  1064. return !bHandled;
  1065. }
  1066. void CDeskMovr::TrackTarget(POINT * pptDoc)
  1067. {
  1068. HRESULT hr = S_OK;
  1069. if ( m_fEnabled && m_pielemTarget != NULL ) {
  1070. LONG left, top;
  1071. POINT pt;
  1072. VARIANT varZ;
  1073. COMPSTATEINFO CompState;
  1074. varZ.vt = VT_I4;
  1075. CLEANUP_ON_FAILURE(hr = CSSOM_TopLeft(m_pielemTarget, &pt));
  1076. m_top = pt.y;
  1077. m_left = pt.x;
  1078. CLEANUP_ON_FAILURE(hr = m_pielemTarget->get_offsetHeight( &m_height ));
  1079. CLEANUP_ON_FAILURE(hr = m_pielemTarget->get_offsetWidth( &m_width ));
  1080. // Hack so we don't get weird painting effect of the window hopping to the new
  1081. // target with the old target's size.
  1082. if (!m_bWndLess && m_cyCaption == 0)
  1083. ::SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE);
  1084. // Get our rectangle synced with the target (so TrackCaption works properly)
  1085. SyncRectsToTarget();
  1086. // If we discover we want to display the size-border or caption
  1087. // right now then we need to recalculate our rects.
  1088. if (pptDoc && TrackCaption(pptDoc))
  1089. SyncRectsToTarget();
  1090. CLEANUP_ON_FAILURE(hr = m_pistyleTarget->get_zIndex( &varZ ));
  1091. if (!CAPTION_ONLY || (m_cxBorder == m_cxSMBorder))
  1092. --varZ.lVal;
  1093. else
  1094. ++varZ.lVal;
  1095. CLEANUP_ON_FAILURE(hr = SafeZOrderSet(m_pistyle, varZ.lVal));
  1096. // NTRAID94268-2000/03/14 (stephstm): If this is hosted in a window that
  1097. // has scrollbars, we don't correctly add the screen to document
  1098. // offset when changing the location of the component.
  1099. // This causes us to drag incorrectly.
  1100. // 98/10/02 #176729 vtan: Now uses the component left and top to
  1101. // position the caption. Offset the caption if the component is
  1102. // not zoomed. If zoomed then just draw over the component.
  1103. left = m_left;
  1104. top = m_top;
  1105. if (!CAPTION_ONLY)
  1106. {
  1107. left -= m_cxBorder;
  1108. top -= m_cyBorder;
  1109. top -= m_cyCaption;
  1110. }
  1111. hr = m_pistyle->put_pixelLeft(left);
  1112. hr = m_pistyle->put_pixelWidth( m_rectOuter.right );
  1113. hr = m_pistyle->put_pixelTop(top);
  1114. hr = m_pistyle->put_pixelHeight( m_rectOuter.bottom );
  1115. hr = m_pistyle->put_visibility((BSTR)s_sstrVisible.wsz);
  1116. // We need to persist the original state of the item out now if the item's current width/height is -1
  1117. // This occurs when we are fitting an image to it's default size, we need to make sure the
  1118. // original size real values so it works properly.
  1119. ObtainSavedStateForElem(m_pielemTarget, &CompState, FALSE);
  1120. if (m_bWndLess && CompState.dwWidth == COMPONENT_DEFAULT_WIDTH && CompState.dwHeight == COMPONENT_DEFAULT_HEIGHT)
  1121. PersistTargetPosition(m_pielemTarget, m_left, m_top, m_width, m_height, varZ.lVal, FALSE, TRUE, CompState.dwItemState);
  1122. }
  1123. CleanUp:
  1124. ASSERT(SUCCEEDED(hr));
  1125. }
  1126. BOOL CDeskMovr::TrackCaption( POINT *pptDoc )
  1127. {
  1128. int cyCaption, cyCaptionNew;
  1129. POINT ptMovr;
  1130. DragMode dmNew;
  1131. BOOL fRetVal = FALSE;
  1132. //TraceMsg(TF_CUSTOM2, "CDeskMovr::TrackCaption() Mouse=<%d,%d>", ptMovr.x, ptMovr.y);
  1133. if (pptDoc)
  1134. {
  1135. ptMovr = *pptDoc;
  1136. // need a hit test of some sort within the deskmovr to control border swelling
  1137. ptMovr.x -= m_left - m_cxBorder;
  1138. ptMovr.y -= m_top - (m_cyBorder + m_cyCaption);
  1139. dmNew = DragModeFromPoint( ptMovr );
  1140. cyCaption = GET_CYCAPTION;
  1141. if (dmNew == dmNull) {
  1142. BOOL fInner;
  1143. int iInflate;
  1144. RECT rc;
  1145. // Treat something near the size border as a size border hit
  1146. // so we expand to the size border as the user nears the edge.
  1147. fInner = PtInRect(&m_rectInner, ptMovr);
  1148. if (fInner) {
  1149. rc = m_rectInner;
  1150. iInflate = -cyCaption;
  1151. } else {
  1152. rc = m_rectOuter;
  1153. iInflate = cyCaption;
  1154. }
  1155. InflateRect(&rc, iInflate, iInflate);
  1156. if (fInner != PtInRect(&rc, ptMovr))
  1157. dmNew = dmSizeRight;
  1158. }
  1159. if ( (pptDoc->y >= m_top - (m_cyBorder + 2 * m_cyCaption) &&
  1160. pptDoc->y <= (m_top + CAPTIONBAR_HOTAREA(cyCaption, m_cyCaption)) ) )
  1161. cyCaptionNew = cyCaption;
  1162. else
  1163. cyCaptionNew = 0;
  1164. }
  1165. else
  1166. {
  1167. cyCaptionNew = GET_CYCAPTION;
  1168. dmNew = dmSizeRight;
  1169. }
  1170. if ( cyCaptionNew != m_cyCaption ||
  1171. (m_dmTrack != dmNew && !((m_dmTrack > dmMove) && (dmNew > dmMove))) ) {
  1172. m_cyCaption = cyCaptionNew;
  1173. if (m_cyCaption == 0)
  1174. m_CaptionState = 0;
  1175. m_dmTrack = dmNew;
  1176. fRetVal = TRUE;
  1177. } else
  1178. m_cyCaption = cyCaptionNew;
  1179. return fRetVal;
  1180. }
  1181. int CDeskMovr::CountActiveCaptions()
  1182. {
  1183. int iCount = 0;
  1184. if (g_dwHookThreadId == GetCurrentThreadId())
  1185. {
  1186. for (int i = 0; i < CDESKMOVR_TRACK_COUNT; i++) {
  1187. if (g_apDM[i] && g_apDM[i]->m_pistyleTarget)
  1188. iCount++;
  1189. }
  1190. }
  1191. return iCount;
  1192. }
  1193. HRESULT CDeskMovr::_TrackElement(POINT * ppt, IHTMLElement * pielem, BOOL * fDidWork)
  1194. {
  1195. HRESULT hr;
  1196. IHTMLElement *pTargElem = NULL;
  1197. LONG iSrcTarget = -1;
  1198. ASSERT(pielem);
  1199. if ( FFindTargetElement( pielem, &pTargElem ) )
  1200. {
  1201. hr = pTargElem->get_sourceIndex( &iSrcTarget );
  1202. ASSERT(SUCCEEDED(hr));
  1203. }
  1204. // If the m_iSrcTarget isn't the same as the SrcTarget under our cursor,
  1205. // then we should move on top of it.
  1206. if ( m_iSrcTarget != iSrcTarget )
  1207. {
  1208. *fDidWork = TRUE;
  1209. if ((CountActiveCaptions() > 1) && (-1 == iSrcTarget))
  1210. m_cSkipTimer = 0;
  1211. // Yes, we need to move on top of it.
  1212. hr = MoveSelfToTarget( pTargElem, ppt );
  1213. ASSERT(SUCCEEDED(hr));
  1214. if (hr != S_FALSE)
  1215. m_iSrcTarget = iSrcTarget;
  1216. }
  1217. else
  1218. {
  1219. // No, so that means we already have focus...
  1220. if (ppt && TrackCaption(ppt))
  1221. {
  1222. TrackTarget(NULL);
  1223. }
  1224. }
  1225. if ( pTargElem != NULL ) {
  1226. pTargElem->Release(); // MoveSelfToTarget will have secured our reference
  1227. }
  1228. hr = (m_iSrcTarget == -1) ? S_FALSE : S_OK;
  1229. return hr;
  1230. }
  1231. //=--------------------------------------------------------------------------=
  1232. // CDeskMovr::InitAttributes [instance method]
  1233. //=--------------------------------------------------------------------------=
  1234. // Finds out if the element is resizeable in X and Y direction and sets the
  1235. // BITBOOLs accordingly.
  1236. //
  1237. // Also determines what state the element is in and sets m_ItemState.
  1238. //
  1239. // Parameters:
  1240. // IHTMLElement* [in] - interface on event source element
  1241. //
  1242. // Output:
  1243. // HRESULT - various. S_OK if operation succeeded.
  1244. //
  1245. HRESULT CDeskMovr::InitAttributes(IHTMLElement *pielem)
  1246. {
  1247. HRESULT hr;
  1248. TCHAR szMember[MAX_ID_LENGTH];
  1249. ASSERT(pielem);
  1250. m_fCanResizeX = m_fCanResizeY = FALSE; //Assume "Can't resize!
  1251. // The resizeable member is not required to be specified, only override defaults if present.
  1252. if (SUCCEEDED(GetHTMLElementStrMember(pielem, szMember, SIZECHARS(szMember), (BSTR)(s_sstrResizeableMember.wsz))))
  1253. {
  1254. if(StrChr(szMember, TEXT('X')))
  1255. m_fCanResizeX = TRUE;
  1256. if(StrChr(szMember, TEXT('Y')))
  1257. m_fCanResizeY = TRUE;
  1258. }
  1259. // The ItemState is required, return failure if we fail to find the ID
  1260. if (SUCCEEDED(hr = GetHTMLElementStrMember(pielem, szMember, SIZECHARS(szMember), (BSTR)(s_sstrIDMember.wsz))))
  1261. m_ItemState = GetCurrentState(szMember);
  1262. return hr;
  1263. }
  1264. //=--------------------------------------------------------------------------=
  1265. // CDeskMovr::MoveSelfToTarget [instance method]
  1266. //=--------------------------------------------------------------------------=
  1267. // Handles Trident document events as mouse moves over the desktop.
  1268. //
  1269. // Parameters:
  1270. // IHTMLElement* [in] - interface on event source element
  1271. // POINT* [in] - location of mouse (to determine if caption should be displayed)
  1272. //
  1273. // Output:
  1274. // HRESULT - various. S_OK if operation succeeded.
  1275. //
  1276. HRESULT CDeskMovr::MoveSelfToTarget(IHTMLElement *pielem, POINT * pptDoc)
  1277. {
  1278. HRESULT hr = S_OK;
  1279. TraceMsg(TF_CUSTOM2, "CDeskMovr::MoveSelfToTarget(pielem=%lx) %s, m_bstrTargetName=%ls", pielem, (pielem ? "We are GETTING focus." : "We are LOOSING focus."), GEN_DEBUGSTRW(m_bstrTargetName));
  1280. if (!pielem)
  1281. {
  1282. // The m_cSkipTimer variable is used to allow the skipping of timer ticks when determining
  1283. // if the mover should be dismissed. By doing this it gives the user more time and thus
  1284. // a better chance to manipulate the target if they are prone to drifting the mouse
  1285. // outside the target by accident.
  1286. // Check the m_cSkipTimer before dismissing the mover.
  1287. if (!m_cSkipTimer)
  1288. {
  1289. _ChangeCapture(FALSE);
  1290. if (m_pistyle)
  1291. hr = m_pistyle->put_visibility((BSTR)s_sstrHidden.wsz);
  1292. ATOMICRELEASE( m_pistyleTarget );
  1293. ATOMICRELEASE( m_pielemTarget );
  1294. m_iSrcTarget = -1;
  1295. }
  1296. else
  1297. {
  1298. m_cSkipTimer--;
  1299. hr = S_FALSE;
  1300. }
  1301. // These are actions we want to happen right away.
  1302. m_hcursor = CursorFromDragMode(dmNull);
  1303. if (m_hcursor != NULL)
  1304. SetCursor(m_hcursor);
  1305. }
  1306. // These are actions we want to happen after the Desktop Item
  1307. // looses focus.
  1308. if (hr != S_FALSE)
  1309. {
  1310. m_cyCaption = 0;
  1311. m_cxBorder = m_cxSMBorder;
  1312. m_cyBorder = m_cySMBorder;
  1313. m_CaptionState = 0;
  1314. m_dmTrack = dmNull;
  1315. }
  1316. if (pielem)
  1317. {
  1318. ASSERT(m_pielemTarget != pielem);
  1319. // exchange our new target ( if any ) for the old target, if any...
  1320. ATOMICRELEASE( m_pistyleTarget );
  1321. ATOMICRELEASE( m_pielemTarget );
  1322. hr = pielem->get_style(&m_pistyleTarget);
  1323. if (SUCCEEDED(hr))
  1324. {
  1325. // We are gaining focus.
  1326. m_pielemTarget = pielem;
  1327. m_pielemTarget->AddRef();
  1328. EVAL(SUCCEEDED(InitAttributes(m_pielemTarget)));
  1329. if (!pptDoc)
  1330. TrackCaption(NULL);
  1331. TrackTarget(pptDoc);
  1332. // Set m_cSkipTimer so that we delay dismissing the mover...
  1333. m_cSkipTimer = GET_SKIP_COUNT;
  1334. if (!m_bWndLess && !m_hWnd)
  1335. {
  1336. // This is all a hack until trident fixes the UIDeactivate stuff, bug 243801
  1337. IOleInPlaceObject_InPlaceDeactivate();
  1338. InPlaceActivate(OLEIVERB_UIACTIVATE);
  1339. SetControlFocus(TRUE);
  1340. }
  1341. }
  1342. }
  1343. return hr;
  1344. }
  1345. //=--------------------------------------------------------------------------=
  1346. // CDeskMovrControl::MoveSelfAndTarget [instance method]
  1347. //=--------------------------------------------------------------------------=
  1348. // Moves the control and it's target to a new location.
  1349. //
  1350. // Parameters:
  1351. // LONG [in] - x location, in document coord's to move to
  1352. // LONG [in] - y location, in document coord's to move to
  1353. //
  1354. // Output:
  1355. // HRESULT - various. S_OK if operation succeeded.
  1356. //
  1357. // Notes:
  1358. // We read back the target's location so that we stay consistent with
  1359. // any constraint's Trident might impose on our movement.
  1360. HRESULT CDeskMovr::MoveSelfAndTarget( LONG x, LONG y )
  1361. {
  1362. HRESULT hr;
  1363. m_top = y;
  1364. CLEANUP_ON_FAILURE((hr = m_pistyle->put_pixelTop( y - m_cyBorder - m_cyCaption )));
  1365. CLEANUP_ON_FAILURE((hr = m_pistyleTarget->put_pixelTop( y )));
  1366. // read it back to catch Trident constraint.
  1367. //CLEANUP_ON_FAILURE((hr = m_pielemTarget->get_docTop( &m_top )));
  1368. //CLEANUP_ON_FAILURE((hr = m_pistyle->put_pixelTop( m_top )));
  1369. m_left = x;
  1370. CLEANUP_ON_FAILURE((hr = m_pistyle->put_pixelLeft( x - m_cxBorder )));
  1371. CLEANUP_ON_FAILURE((hr = m_pistyleTarget->put_pixelLeft( x )));
  1372. // read it back to catch Trident constraint.
  1373. //CLEANUP_ON_FAILURE((hr = m_pielemTarget->get_docLeft( &m_left )));
  1374. //CLEANUP_ON_FAILURE((hr = m_pistyle->put_pixelLeft( m_left )));
  1375. // if ( !m_bWndLess )
  1376. if (EVAL(S_OK == GetParentWindow()))
  1377. ::UpdateWindow(m_hwndParent);
  1378. CleanUp:
  1379. return hr;
  1380. }
  1381. BOOL CDeskMovr::FFindTargetElement( IHTMLElement *pielem, IHTMLElement **ppielem )
  1382. {
  1383. *ppielem = NULL;
  1384. if ( pielem != NULL )
  1385. {
  1386. IDeskMovr *pidm = NULL;
  1387. // If it is over the mover return the current target, otherwise
  1388. // find out which component if any we are over.
  1389. if ( m_pielemTarget != NULL &&
  1390. SUCCEEDED(pielem->QueryInterface(IID_IDeskMovr, (LPVOID*)&pidm)))
  1391. {
  1392. m_pielemTarget->AddRef();
  1393. *ppielem = m_pielemTarget;
  1394. ATOMICRELEASE(pidm);
  1395. } else {
  1396. HRESULT hr;
  1397. IHTMLElement *pielem2 = pielem;
  1398. pielem2->AddRef();
  1399. do
  1400. {
  1401. VARIANT var;
  1402. VariantInit( &var );
  1403. if ( SUCCEEDED(hr = pielem2->getAttribute( (BSTR)s_sstrNameMember.wsz, TRUE, &var)) ) {
  1404. if ( var.vt == VT_BSTR && var.bstrVal != NULL ) {
  1405. if ( StrCmpW( var.bstrVal, m_bstrTargetName ) == 0 )
  1406. hr = S_OK;
  1407. else
  1408. hr = S_FALSE;
  1409. } else
  1410. hr = S_FALSE; // Try VariantChangeType?????
  1411. } else
  1412. hr = S_FALSE; // not here, maybe in parent.
  1413. VariantClear( &var );
  1414. if ( hr == S_OK ) { // we found it
  1415. hr = pielem2->QueryInterface( IID_IHTMLElement, (LPVOID*)ppielem );
  1416. } else if ( hr == S_FALSE ) { // not this one, climb up
  1417. IHTMLElement *pielemParent = NULL;
  1418. pielem2->get_parentElement( &pielemParent );
  1419. pielem2->Release(); // we're through at this level
  1420. pielem2 = pielemParent; // may be null, which just means we've reached the top.
  1421. }
  1422. } while ( SUCCEEDED(hr) && *ppielem == NULL && pielem2 != NULL );
  1423. ATOMICRELEASE(pielem2);
  1424. }
  1425. }
  1426. return *ppielem != NULL;
  1427. }
  1428. //=--------------------------------------------------------------------------=
  1429. // CDeskMovr::DragModeFromPoint [instance method]
  1430. //=--------------------------------------------------------------------------=
  1431. // Moves the control and it's target to a new location.
  1432. //
  1433. // Parameters:
  1434. // POINT - point to test, in local coords
  1435. //
  1436. // Output:
  1437. // DragMode - drag mode associated with the point
  1438. //
  1439. // Notes:
  1440. // This is only a hit testing method. It does not alter state.
  1441. CDeskMovr::DragMode CDeskMovr::DragModeFromPoint( POINT pt )
  1442. {
  1443. enum DragMode dm = dmNull;
  1444. RECT rc;
  1445. if ( PtInRect( &m_rectInner, pt ) )
  1446. { // either no-hit, or on caption
  1447. if ( PtInRect( &m_rectCaption, pt ) ) {
  1448. DragMode dmT;
  1449. for (dmT = dmMenu; dmT < dmMove; dmT = (DragMode)((int)dmT + 1)) {
  1450. if (GetCaptionButtonRect(dmT, &rc) && PtInRect(&rc, pt)) {
  1451. dm = dmT;
  1452. break;
  1453. }
  1454. }
  1455. if ((dmT == dmMove) && !CAPTION_ONLY)
  1456. dm = dmMove;
  1457. }
  1458. } else {
  1459. if ( PtInRect( &m_rectOuter, pt ) ) {
  1460. if (!CAPTION_ONLY)
  1461. {
  1462. // a resize border hit
  1463. if ( pt.y <= m_sizeCorner.cy ) {
  1464. // upper edge or corners
  1465. if ( pt.x <= m_sizeCorner.cx )
  1466. dm = dmSizeWHTL;
  1467. else if ( pt.x >= m_rectOuter.right - m_sizeCorner.cx )
  1468. dm = dmSizeWHTR;
  1469. else
  1470. dm = dmSizeTop;
  1471. } else if ( pt.y >= m_rectOuter.bottom - m_sizeCorner.cy ) {
  1472. // bottom edge or corners
  1473. if ( pt.x <= m_sizeCorner.cx )
  1474. dm = dmSizeWHBL;
  1475. else if ( pt.x >= m_rectOuter.right - m_sizeCorner.cx )
  1476. dm = dmSizeWHBR;
  1477. else
  1478. dm = dmSizeBottom;
  1479. } else {
  1480. // side edge hit
  1481. if ( pt.x > m_rectInner.left )
  1482. dm = dmSizeRight;
  1483. else
  1484. dm = dmSizeLeft;
  1485. }
  1486. } else {
  1487. if (m_cyCaption == 0)
  1488. {
  1489. if(IS_BIDI_LOCALIZED_SYSTEM())
  1490. {
  1491. dm = dmSizeRight;
  1492. }
  1493. else
  1494. {
  1495. dm = dmSizeLeft;
  1496. }
  1497. }
  1498. else
  1499. dm = dmNull;
  1500. }
  1501. }
  1502. //Check if this element can be sized in both the directions.
  1503. if(!m_fCanResizeX)
  1504. {
  1505. if((dm != dmSizeTop) && (dm != dmSizeBottom))
  1506. dm = dmNull;
  1507. }
  1508. if(!m_fCanResizeY)
  1509. {
  1510. if((dm != dmSizeLeft) && (dm != dmSizeRight))
  1511. dm = dmNull;
  1512. }
  1513. }
  1514. return dm;
  1515. }
  1516. // Align our member RECTs with the dimensions of the target element.
  1517. void CDeskMovr::SyncRectsToTarget(void)
  1518. {
  1519. // do the swelling thang
  1520. if ( (m_dmTrack > dmMove) || m_cyCaption ) {
  1521. m_cxBorder = GET_CXSIZE;
  1522. m_cyBorder = GET_CYSIZE;
  1523. } else {
  1524. m_cxBorder = m_cxSMBorder;
  1525. m_cyBorder = m_cySMBorder;
  1526. }
  1527. m_rectOuter.top = m_rectOuter.left = 0;
  1528. if (CAPTION_ONLY)
  1529. {
  1530. if (m_cyCaption != 0)
  1531. {
  1532. // Displaying just caption
  1533. m_rectOuter.bottom = m_cyCaption + m_cyBorder;
  1534. m_rectOuter.right = m_width;
  1535. } else {
  1536. // Displaying just left size border
  1537. m_rectOuter.bottom = m_height;
  1538. if(IS_BIDI_LOCALIZED_SYSTEM())
  1539. {
  1540. m_rectOuter.right = m_width;
  1541. m_rectOuter.left = m_rectOuter.right - m_cxBorder;
  1542. }
  1543. else
  1544. {
  1545. m_rectOuter.right = m_cxBorder;
  1546. }
  1547. }
  1548. } else {
  1549. // Displaying caption and border
  1550. m_rectOuter.bottom = m_height + 2 * m_cyBorder + m_cyCaption;
  1551. m_rectOuter.right = m_width + 2 * m_cxBorder;
  1552. }
  1553. if (CAPTION_ONLY && m_cyCaption == 0)
  1554. {
  1555. // Displaying just left size border
  1556. SetRectEmpty(&m_rectInner);
  1557. SetRectEmpty(&m_rectCaption);
  1558. } else {
  1559. // Displaying caption and possibly border
  1560. m_rectInner = m_rectOuter;
  1561. InflateRect( &m_rectInner, -m_cxBorder, -m_cyBorder );
  1562. m_rectCaption = m_rectInner;
  1563. m_rectCaption.bottom = m_cyBorder + m_cyCaption;
  1564. }
  1565. if ( m_rectOuter.bottom > 2 * m_cyCaption )
  1566. m_sizeCorner.cy = GET_CYCAPTION;
  1567. else
  1568. m_sizeCorner.cy = m_rectOuter.bottom / 2;
  1569. if ( m_rectOuter.right > 2 * m_cyCaption )
  1570. m_sizeCorner.cx = GET_CYCAPTION;
  1571. else
  1572. m_sizeCorner.cx = m_rectOuter.right / 2;
  1573. }
  1574. HCURSOR CDeskMovr::CursorFromDragMode( DragMode dm )
  1575. {
  1576. ASSERT( dm >= 0 && dm < cDragModes );
  1577. switch (dm) {
  1578. case dmNull:
  1579. case dmMenu:
  1580. case dmClose:
  1581. case dmMove:
  1582. case dmRestore:
  1583. case dmFullScreen:
  1584. case dmSplit:
  1585. default:
  1586. return LoadCursor(NULL, IDC_ARROW);
  1587. case dmSizeWHBR:
  1588. case dmSizeWHTL:
  1589. return LoadCursor(NULL, IDC_SIZENWSE);
  1590. case dmSizeWHTR:
  1591. case dmSizeWHBL:
  1592. return LoadCursor(NULL, IDC_SIZENESW);
  1593. case dmSizeTop:
  1594. case dmSizeBottom:
  1595. return LoadCursor( NULL, IDC_SIZENS );
  1596. case dmSizeLeft:
  1597. case dmSizeRight:
  1598. return LoadCursor( NULL, IDC_SIZEWE );
  1599. }
  1600. }
  1601. //=--------------------------------------------------------------------------=
  1602. // CDeskMovr::SizeSelfAndTarget [instance method]
  1603. //=--------------------------------------------------------------------------=
  1604. // Resizes our control and its target element.
  1605. //
  1606. // Parameters:
  1607. // LONG [in] - new width
  1608. // LONG [in] - new height
  1609. //
  1610. // Output:
  1611. // HRESULT - various. S_OK if operation succeeded.
  1612. //
  1613. // Notes:
  1614. // We read back the target's dimensions so that we stay consistent with
  1615. // any constraint's Trident might impose on our sizing.
  1616. HRESULT CDeskMovr::SizeSelfAndTarget( POINT ptDoc )
  1617. {
  1618. HRESULT hr;
  1619. int topOld = m_top;
  1620. int leftOld = m_left;
  1621. int heightOld = m_height;
  1622. int widthOld = m_width;
  1623. int cyCaption = GET_CYCAPTION;
  1624. switch ( m_dmCur ) {
  1625. case dmSizeWHBR:
  1626. m_width = (ptDoc.x + m_dx) - m_left;
  1627. m_height = (ptDoc.y + m_dy) - m_top;
  1628. break;
  1629. case dmSizeWHTL:
  1630. m_top = ptDoc.y + m_dy;
  1631. m_height += topOld - m_top;
  1632. m_left = ptDoc.x + m_dx;
  1633. m_width += leftOld - m_left;
  1634. break;
  1635. case dmSizeWHTR:
  1636. m_top = ptDoc.y + m_dy;
  1637. m_height += topOld - m_top;
  1638. m_width = (ptDoc.x + m_dx) - m_left;
  1639. break;
  1640. case dmSizeWHBL:
  1641. m_height = (ptDoc.y + m_dy) - m_top;
  1642. m_left = ptDoc.x + m_dx;
  1643. m_width += leftOld - m_left;
  1644. break;
  1645. case dmSizeTop:
  1646. m_top = ptDoc.y + m_dy;
  1647. m_height += topOld - m_top;
  1648. break;
  1649. case dmSizeBottom:
  1650. m_height = (ptDoc.y + m_dy) - m_top;
  1651. break;
  1652. case dmSizeLeft:
  1653. m_left = ptDoc.x + m_dx;
  1654. m_width += leftOld - m_left;
  1655. break;
  1656. case dmSizeRight:
  1657. m_width = (ptDoc.x + m_dx) - m_left;
  1658. break;
  1659. default:
  1660. ASSERT(FALSE);
  1661. return E_FAIL;
  1662. }
  1663. // limit shrinkage to keep the handle accessible
  1664. if ( m_height < cyCaption ) {
  1665. m_height = cyCaption;
  1666. if ( m_top != topOld )
  1667. m_top = topOld + heightOld - m_height;
  1668. }
  1669. // limit shrinkage to keep the handle accessible
  1670. if ( m_width < (4 * cyCaption) ) {
  1671. m_width = 4 * cyCaption;
  1672. if ( m_left != leftOld )
  1673. m_left = leftOld + widthOld - m_width;
  1674. }
  1675. SyncRectsToTarget();
  1676. if ( m_top != topOld ) {
  1677. CLEANUP_ON_FAILURE((hr = m_pistyleTarget->put_pixelTop( m_top )));
  1678. CLEANUP_ON_FAILURE((hr = m_pistyle->put_pixelTop( m_top - (m_cyBorder + m_cyCaption) )));
  1679. }
  1680. if ( m_left != leftOld ) {
  1681. CLEANUP_ON_FAILURE((hr = m_pistyleTarget->put_pixelLeft( m_left )));
  1682. CLEANUP_ON_FAILURE((hr = m_pistyle->put_pixelLeft( m_left - (CAPTION_ONLY ? 0 : m_cxBorder) )));
  1683. }
  1684. CLEANUP_ON_FAILURE((hr = m_pistyleTarget->put_pixelHeight( m_height )));
  1685. // read it back to catch Trident constraint.
  1686. //CLEANUP_ON_FAILURE((hr = m_pielemTarget->get_docHeight( &m_height )));
  1687. CLEANUP_ON_FAILURE((hr = m_pistyle->put_pixelHeight( m_rectOuter.bottom )));
  1688. CLEANUP_ON_FAILURE((hr = m_pistyleTarget->put_pixelWidth( m_width )));
  1689. // read it back to catch Trident constraint.
  1690. //CLEANUP_ON_FAILURE((hr = m_pielemTarget->get_docWidth( &m_width )));
  1691. CLEANUP_ON_FAILURE((hr = m_pistyle->put_pixelWidth( m_rectOuter.right )));
  1692. if(IS_BIDI_LOCALIZED_SYSTEM() && CAPTION_ONLY)
  1693. {
  1694. CLEANUP_ON_FAILURE((hr = m_pistyle->put_pixelLeft(m_rectOuter.left )));
  1695. CLEANUP_ON_FAILURE((hr = m_pistyle->put_pixelWidth(m_rectOuter.right - m_rectOuter.left )));
  1696. }
  1697. if (EVAL(S_OK == GetParentWindow()))
  1698. ::UpdateWindow(m_hwndParent);
  1699. CleanUp:
  1700. return hr;
  1701. }
  1702. // IQuickActivate
  1703. HRESULT CDeskMovr::QuickActivate(QACONTAINER *pQACont, QACONTROL *pQACtrl)
  1704. {
  1705. HRESULT hr = IQuickActivate_QuickActivate(pQACont, pQACtrl);
  1706. if (pQACont)
  1707. {
  1708. ClearFlag(pQACtrl->dwViewStatus, VIEWSTATUS_OPAQUE);
  1709. }
  1710. return hr;
  1711. }
  1712. HRESULT CDeskMovr::_GetHTMLDoc(IOleClientSite * pocs, IHTMLDocument2 ** pphd2)
  1713. {
  1714. HRESULT hr;
  1715. IOleContainer * poc = NULL;
  1716. if (!EVAL(pocs) || !EVAL(pphd2))
  1717. return E_INVALIDARG;
  1718. *pphd2 = NULL;
  1719. hr = pocs->GetContainer(&poc);
  1720. if (SUCCEEDED(hr))
  1721. {
  1722. hr = poc->QueryInterface(IID_IHTMLDocument2, (LPVOID*) pphd2);
  1723. poc->Release();
  1724. }
  1725. return hr;
  1726. }
  1727. HRESULT CDeskMovr::_IsInElement(HWND hwndParent, POINT * ppt, IHTMLElement ** pphe)
  1728. {
  1729. HRESULT hr = E_FAIL;
  1730. ASSERT(pphe);
  1731. *pphe = NULL;
  1732. if (!ppt || ::ScreenToClient(hwndParent, ppt))
  1733. {
  1734. IHTMLDocument2 * phd2;
  1735. ASSERT(m_spClientSite);
  1736. hr = _GetHTMLDoc(m_spClientSite, &phd2);
  1737. if (SUCCEEDED(hr))
  1738. {
  1739. if (ppt)
  1740. hr = phd2->elementFromPoint(ppt->x, ppt->y, pphe);
  1741. else
  1742. hr = phd2->get_activeElement(pphe);
  1743. if (!*pphe && SUCCEEDED(hr))
  1744. hr = E_FAIL; // Sometimes Trident returns S_FALSE on error.
  1745. phd2->Release();
  1746. }
  1747. }
  1748. return hr;
  1749. }
  1750. HRESULT CDeskMovr::_EnumComponents(LPFNCOMPENUM lpfn, LPVOID lpvData, DWORD dwData)
  1751. {
  1752. HRESULT hr = E_FAIL;
  1753. IActiveDesktop * padt = NULL;
  1754. hr = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC, IID_IActiveDesktop, (LPVOID *)&padt);
  1755. if (SUCCEEDED(hr))
  1756. {
  1757. int nCount;
  1758. int nIndex;
  1759. hr = padt->GetDesktopItemCount(&nCount, 0);
  1760. if (EVAL(SUCCEEDED(hr)))
  1761. {
  1762. COMPONENT comp;
  1763. for (nIndex = 0; nIndex < nCount; nIndex++)
  1764. {
  1765. comp.dwSize = sizeof(COMPONENT);
  1766. hr = padt->GetDesktopItem(nIndex, &comp, 0);
  1767. if (EVAL(SUCCEEDED(hr)))
  1768. {
  1769. if ((hr = lpfn(&comp, lpvData, dwData)) != S_OK)
  1770. break;
  1771. }
  1772. }
  1773. }
  1774. padt->Release();
  1775. }
  1776. return hr;
  1777. }
  1778. HRESULT CDeskMovr::_EnumElements(LPFNELEMENUM lpfn, LPVOID lpvData, DWORD dwData)
  1779. {
  1780. HRESULT hr;
  1781. IHTMLDocument2 * phd2;
  1782. ASSERT(m_spClientSite);
  1783. if (SUCCEEDED(hr = _GetHTMLDoc(m_spClientSite, &phd2)))
  1784. {
  1785. IHTMLElementCollection * pelems;
  1786. if (SUCCEEDED(hr = phd2->get_all(&pelems)))
  1787. {
  1788. VARIANT varIndex;
  1789. VARIANT varDummy;
  1790. IDispatch * pidisp;
  1791. VariantInit(&varDummy);
  1792. varIndex.vt = VT_I4;
  1793. varIndex.lVal = 0;
  1794. // Note: This loop terminates when trident returns SUCCESS - but with a NULL pidisp.
  1795. while (SUCCEEDED(hr = pelems->item(varIndex, varDummy, &pidisp)) && pidisp)
  1796. {
  1797. IHTMLElement * pielem;
  1798. if (SUCCEEDED(hr = pidisp->QueryInterface(IID_IHTMLElement, (LPVOID *)&pielem)))
  1799. {
  1800. hr = lpfn(pielem, lpvData, dwData);
  1801. pielem->Release();
  1802. }
  1803. pidisp->Release();
  1804. if (hr != S_OK)
  1805. break;
  1806. varIndex.lVal++;
  1807. }
  1808. pelems->Release();
  1809. }
  1810. phd2->Release();
  1811. }
  1812. return hr;
  1813. }
  1814. HRESULT lpfnZOrderCB(COMPONENT * pcomp, LPVOID lpvData, DWORD dwData)
  1815. {
  1816. #define LPZORDERSLOT ((LONG *)lpvData)
  1817. if (dwData ? (pcomp->cpPos.izIndex > *LPZORDERSLOT) : (pcomp->cpPos.izIndex < *LPZORDERSLOT))
  1818. *LPZORDERSLOT = pcomp->cpPos.izIndex;
  1819. return S_OK;
  1820. }
  1821. HRESULT CDeskMovr::_GetZOrderSlot(LONG * plZOrderSlot, BOOL fTop)
  1822. {
  1823. HRESULT hr;
  1824. ASSERT(plZOrderSlot);
  1825. *plZOrderSlot = m_bWindowOnly ? 10000 : 5000;
  1826. hr = _EnumComponents(lpfnZOrderCB, (LPVOID)plZOrderSlot, (DWORD)fTop);
  1827. *plZOrderSlot += fTop ? 2 : -2; // Make sure we are above / below.
  1828. return hr;
  1829. }
  1830. //=--------------------------------------------------------------------------=
  1831. // PersistTargetPosition [helper function]
  1832. //=--------------------------------------------------------------------------=
  1833. // Update the registry entries that are the persistence of the desktop HTML.
  1834. //
  1835. // Parameters:
  1836. // <none>
  1837. //
  1838. // Output:
  1839. // <none>
  1840. //
  1841. // Notes:
  1842. // If we fail, we do it quietly.
  1843. //=--------------------------------------------------------------------------=
  1844. void PersistTargetPosition( IHTMLElement *pielem,
  1845. int left,
  1846. int top,
  1847. int width,
  1848. int height,
  1849. int zIndex,
  1850. BOOL fSaveState,
  1851. BOOL fSaveOriginal,
  1852. DWORD dwNewState)
  1853. {
  1854. // only do this persistence thing if we're in ( or completing ) an operation
  1855. TCHAR szID[MAX_ID_LENGTH];
  1856. BOOL fOK;
  1857. if (SUCCEEDED(GetHTMLElementStrMember(pielem, szID, SIZECHARS(szID), (BSTR)(s_sstrIDMember.wsz))))
  1858. {
  1859. bool bChangedPosition, bChangedSize;
  1860. COMPPOS compPos;
  1861. // 99/03/23 #266412 vtan: The user has moved the deskmovr to a new position
  1862. // make sure that it is within the work area of the display monitors.
  1863. // ValidateComponentPosition() will do this for us and tell us whether the
  1864. // the component got moved or resized.
  1865. compPos.dwSize = sizeof(compPos);
  1866. compPos.iLeft = left;
  1867. compPos.iTop = top;
  1868. compPos.dwWidth = width;
  1869. compPos.dwHeight = height;
  1870. ValidateComponentPosition(&compPos, dwNewState, COMP_TYPE_HTMLDOC, &bChangedPosition, &bChangedSize);
  1871. if (bChangedPosition || bChangedSize)
  1872. {
  1873. IHTMLStyle *pIStyle;
  1874. // If the component got moved or resized then tell the object model
  1875. // where the deskmovr is now.
  1876. left = compPos.iLeft;
  1877. top = compPos.iTop;
  1878. width = compPos.dwWidth;
  1879. height = compPos.dwHeight;
  1880. if (SUCCEEDED(pielem->get_style(&pIStyle)))
  1881. {
  1882. pIStyle->put_pixelLeft(left);
  1883. pIStyle->put_pixelTop(top);
  1884. pIStyle->put_pixelWidth(width);
  1885. pIStyle->put_pixelHeight(height);
  1886. pIStyle->Release();
  1887. }
  1888. }
  1889. fOK = UpdateDesktopPosition(szID, left, top, width, height, zIndex, fSaveState, fSaveOriginal, dwNewState);
  1890. }
  1891. TraceMsg(TF_CUSTOM2, "PersistTargetPosition(pielem=%s, <left=%d, top=%d, wid=%d, h=%d>)", szID, left, top, width, height);
  1892. }
  1893. void ObtainSavedStateForElem( IHTMLElement *pielem,
  1894. LPCOMPSTATEINFO pCompState, BOOL fRestoredState)
  1895. {
  1896. // only do this persistence thing if we're in ( or completing ) an operation
  1897. TCHAR szID[MAX_ID_LENGTH];
  1898. BOOL fOK;
  1899. if (SUCCEEDED(GetHTMLElementStrMember(pielem, szID, SIZECHARS(szID), (BSTR)(s_sstrIDMember.wsz))))
  1900. fOK = GetSavedStateInfo(szID, pCompState, fRestoredState);
  1901. TraceMsg(TF_CUSTOM2, "ObtainSavedStateForElem(pielem=%s, <left=%d, top=%d, wid=%d, h=%d>)", szID, pCompState->iLeft, pCompState->iTop, pCompState->dwWidth, pCompState->dwHeight);
  1902. }
  1903. // IOleObject
  1904. HRESULT CDeskMovr::GetMiscStatus(DWORD dwAspect, DWORD *pdwStatus)
  1905. {
  1906. if (dwAspect == DVASPECT_CONTENT)
  1907. {
  1908. *pdwStatus = OLEMISMOVR;
  1909. return S_OK;
  1910. }
  1911. else
  1912. {
  1913. return DV_E_DVASPECT;
  1914. }
  1915. // dead code
  1916. }
  1917. HRESULT CDeskMovr::SetClientSite(IOleClientSite * pClientSite)
  1918. {
  1919. if (!pClientSite)
  1920. DeactivateMovr(FALSE);
  1921. return CComControlBase::IOleObject_SetClientSite(pClientSite);
  1922. }
  1923. void HandleRestore(IHTMLElement * pielem, LONG lData)
  1924. {
  1925. VARIANT varZ;
  1926. COMPSTATEINFO csiRestore;
  1927. IHTMLStyle * pistyle;
  1928. if (SUCCEEDED(pielem->get_style(&pistyle)))
  1929. {
  1930. csiRestore.dwSize = sizeof(csiRestore);
  1931. ObtainSavedStateForElem(pielem, &csiRestore, TRUE); // TRUE => Get restored state!
  1932. pistyle->put_pixelLeft(csiRestore.iLeft);
  1933. pistyle->put_pixelTop(csiRestore.iTop);
  1934. pistyle->put_pixelWidth(csiRestore.dwWidth);
  1935. pistyle->put_pixelHeight(csiRestore.dwHeight);
  1936. varZ.vt = VT_I4;
  1937. varZ.lVal = lData;
  1938. pistyle->put_zIndex(varZ);
  1939. PersistTargetPosition(pielem, csiRestore.iLeft, csiRestore.iTop, csiRestore.dwWidth, csiRestore.dwHeight, varZ.lVal, FALSE, FALSE, IS_NORMAL);
  1940. pistyle->Release();
  1941. }
  1942. }
  1943. HRESULT lpfnRestoreCB(IHTMLElement * pielem, LPVOID lpvData, LONG lData)
  1944. {
  1945. HRESULT hres = S_OK;
  1946. TCHAR szID[MAX_ID_LENGTH];
  1947. if (SUCCEEDED(GetHTMLElementStrMember(pielem, szID, SIZECHARS(szID), (BSTR)(s_sstrIDMember.wsz))))
  1948. {
  1949. DWORD dwState = GetCurrentState(szID);
  1950. // Since there is only one in this state we can stop the enumeration if we
  1951. // find a fullscreen/split item on this work area.
  1952. if (dwState & (IS_FULLSCREEN | IS_SPLIT)) {
  1953. POINT pt;
  1954. if (SUCCEEDED(CSSOM_TopLeft(pielem, &pt)) && PtInRect((CONST RECT *)lpvData, pt))
  1955. {
  1956. HandleRestore(pielem, lData);
  1957. hres = S_FALSE;
  1958. }
  1959. }
  1960. }
  1961. return hres;
  1962. }
  1963. HRESULT CDeskMovr::_HandleZoom(LONG lCommand)
  1964. {
  1965. LONG x, y, cx, cy, zIndex;
  1966. VARIANT varZ;
  1967. DWORD dwOldItemState = m_ItemState, dwNewItemState;
  1968. IHTMLStyle * pistyleTarget = m_pistyleTarget;
  1969. IHTMLElement * pielemTarget = m_pielemTarget;
  1970. // Paranoia
  1971. if (!pistyleTarget || !pielemTarget)
  1972. {
  1973. ASSERT(FALSE);
  1974. return E_FAIL;
  1975. }
  1976. // Hold on to these guys during this call, they could go away when we yield
  1977. // like during the animation call below.
  1978. pistyleTarget->AddRef();
  1979. pielemTarget->AddRef();
  1980. if (lCommand == IDM_DCCM_RESTORE)
  1981. {
  1982. COMPSTATEINFO csi;
  1983. csi.dwSize = sizeof(csi);
  1984. // The "Restore" command toggles with the "Reset Original Size" command.
  1985. // Make sure we get the correct Restore or Reset position for the element.
  1986. ObtainSavedStateForElem(pielemTarget, &csi, !ISNORMAL);
  1987. if (ISNORMAL)
  1988. {
  1989. // This is the split case, dont move the item just resize it.
  1990. x = m_left;
  1991. y = m_top;
  1992. }
  1993. else
  1994. {
  1995. // 98/07/27 vtan #176721: The following checks restoration of a component
  1996. // position from zoomed to user-specified position. If the component
  1997. // is placed at the default position then it is positioned now using
  1998. // the standard positioning code.
  1999. if ((csi.iLeft == COMPONENT_DEFAULT_LEFT) &&
  2000. (csi.iTop == COMPONENT_DEFAULT_TOP) &&
  2001. (csi.dwWidth == COMPONENT_DEFAULT_WIDTH) &&
  2002. (csi.dwHeight == COMPONENT_DEFAULT_HEIGHT))
  2003. {
  2004. COMPPOS compPos;
  2005. GetNextComponentPosition(&compPos);
  2006. IncrementComponentsPositioned();
  2007. csi.iLeft = compPos.iLeft;
  2008. csi.iTop = compPos.iTop;
  2009. csi.dwWidth = compPos.dwWidth;
  2010. csi.dwHeight = compPos.dwHeight;
  2011. }
  2012. // Restore case, go ahead and move it.
  2013. x = csi.iLeft;
  2014. y = csi.iTop;
  2015. }
  2016. cx = csi.dwWidth;
  2017. cy = csi.dwHeight;
  2018. m_ItemState = (m_ItemState & ~IS_VALIDSIZESTATEBITS) | IS_NORMAL;
  2019. dwNewItemState = m_ItemState;
  2020. m_zIndexTop += 2;
  2021. zIndex = m_zIndexTop;
  2022. }
  2023. else
  2024. {
  2025. RECT rcZoom, rcWork;
  2026. GetZoomRect(lCommand == IDM_DCCM_FULLSCREEN, TRUE, m_left, m_top, m_width, m_height, &rcZoom, &rcWork);
  2027. x = rcZoom.left;
  2028. y = rcZoom.top;
  2029. cx = rcZoom.right - rcZoom.left;
  2030. cy = rcZoom.bottom - rcZoom.top;
  2031. if (lCommand == IDM_DCCM_FULLSCREEN)
  2032. {
  2033. m_ItemState = (m_ItemState & ~IS_VALIDSIZESTATEBITS) | IS_FULLSCREEN;
  2034. dwNewItemState = m_ItemState;
  2035. }
  2036. else
  2037. {
  2038. m_ItemState = (m_ItemState & ~IS_VALIDSIZESTATEBITS) | IS_SPLIT;
  2039. dwNewItemState = m_ItemState;
  2040. }
  2041. varZ.vt = VT_I4;
  2042. pistyleTarget->get_zIndex(&varZ);
  2043. // We currently only allow 1 component to be either split or full screen per monitor (WorkArea), so
  2044. // restore any other component that is currently in this state.
  2045. _EnumElements(lpfnRestoreCB, (LPVOID)&rcWork, varZ.lVal);
  2046. m_zIndexBottom -= 2;
  2047. zIndex = m_zIndexBottom;
  2048. }
  2049. // We want to do the animation call before we start moving the target, it looks better
  2050. // that way.
  2051. AnimateComponent(m_hwndParent, m_left, m_top, m_width, m_height, x, y, cx, cy);
  2052. pistyleTarget->put_pixelLeft(x);
  2053. pistyleTarget->put_pixelTop(y);
  2054. pistyleTarget->put_pixelWidth(cx);
  2055. pistyleTarget->put_pixelHeight(cy);
  2056. varZ.vt = VT_I4;
  2057. varZ.lVal = zIndex;
  2058. pistyleTarget->put_zIndex(varZ);
  2059. PersistTargetPosition(pielemTarget, x, y, cx, cy, zIndex,
  2060. (BOOL)((dwOldItemState & IS_NORMAL) && !(dwNewItemState & IS_NORMAL)),
  2061. FALSE, dwNewItemState);
  2062. pistyleTarget->Release();
  2063. pielemTarget->Release();
  2064. return S_OK;
  2065. }
  2066. /************************************************************************\
  2067. FUNCTION: CDeskMovr::_DisplayContextMenu
  2068. PARAMETERS:
  2069. x,y - Coordinates relative to the desktop window.
  2070. \************************************************************************/
  2071. HRESULT CDeskMovr::_DisplayContextMenu()
  2072. {
  2073. HRESULT hr = S_OK;
  2074. HMENU hmenuContext = LoadMenuPopup(MENU_DESKCOMP_CONTEXTMENU);
  2075. TraceMsg(TF_CUSTOM2, "CDeskMovr::DisplayContextMenu(), m_bstrTargetName=%ls", GEN_DEBUGSTRW(m_bstrTargetName));
  2076. if (hmenuContext)
  2077. {
  2078. int nSelection;
  2079. BOOL fSubscribe = FALSE;
  2080. BOOL fRemoveSubscribe = FALSE;
  2081. TCHAR szName[MAX_URL_STRING];
  2082. POINT point;
  2083. if (CAPTION_ONLY)
  2084. {
  2085. point.x = m_left + m_cxBorder;
  2086. point.y = m_top + (m_cyCaption + m_cyBorder) - 4 * m_cySMBorder;
  2087. } else {
  2088. point.x = m_left - m_cxSMBorder;
  2089. point.y = m_top - 4 * m_cySMBorder;
  2090. }
  2091. ::ClientToScreen(m_hwndParent, &point);
  2092. // This calculation needs to be revisited. The reason it's so
  2093. // ugle and HACKy is because to look good, we want the context menu
  2094. // to appear on top of the 3-D edge below the triangle.
  2095. if (SUCCEEDED(GetHTMLElementStrMember(m_pielemTarget, szName, SIZECHARS(szName), (BSTR)(s_sstrSubSRCMember.wsz))))
  2096. {
  2097. int nScheme = GetUrlScheme(szName);
  2098. if ((URL_SCHEME_FILE == nScheme) || (URL_SCHEME_INVALID == nScheme))
  2099. fRemoveSubscribe = TRUE;
  2100. }
  2101. // check to see if we need to turn some things off or on
  2102. // Mainly because we are disabling features Admins don't want users to have.
  2103. hr = IElemCheckForExistingSubscription(m_pielemTarget);
  2104. if (fRemoveSubscribe || FAILED(hr)) // This object/thing cannot be subscribed to. (Channel Changer, Orenge Blob).
  2105. {
  2106. MENUITEMINFO menuItemInfo;
  2107. DeleteMenu(hmenuContext, IDM_DCCM_OFFLINE, MF_BYCOMMAND);
  2108. DeleteMenu(hmenuContext, IDM_DCCM_SYNCHRONIZE, MF_BYCOMMAND);
  2109. DeleteMenu(hmenuContext, IDM_DCCM_PROPERTIES, MF_BYCOMMAND);
  2110. // Is the top item in the list a separator?
  2111. menuItemInfo.cbSize = sizeof(menuItemInfo);
  2112. menuItemInfo.fMask = MIIM_TYPE;
  2113. if ((GetMenuItemInfo(hmenuContext, 0, TRUE, &menuItemInfo) != FALSE) &&
  2114. (menuItemInfo.fType == MFT_SEPARATOR))
  2115. {
  2116. // Yes, it is, so remove it.
  2117. DeleteMenu(hmenuContext, 0, MF_BYPOSITION);
  2118. }
  2119. }
  2120. else if (S_FALSE == hr) // Not subscribed
  2121. {
  2122. DeleteMenu(hmenuContext, IDM_DCCM_SYNCHRONIZE, MF_BYCOMMAND);
  2123. DeleteMenu(hmenuContext, IDM_DCCM_PROPERTIES, MF_BYCOMMAND);
  2124. fSubscribe = TRUE;
  2125. }
  2126. else if (S_OK == hr)
  2127. {
  2128. if (SHRestricted2(REST_NoManualUpdates, NULL, 0))
  2129. DeleteMenu(hmenuContext, IDM_DCCM_SYNCHRONIZE, MF_BYCOMMAND);
  2130. if (SHRestricted(REST_NOEDITDESKCOMP))
  2131. DeleteMenu(hmenuContext, IDM_DCCM_PROPERTIES, MF_BYCOMMAND);
  2132. CheckMenuItem(hmenuContext, IDM_DCCM_OFFLINE, MF_BYCOMMAND |MF_CHECKED);
  2133. }
  2134. if (SHRestricted(REST_NOCLOSEDESKCOMP))
  2135. EnableMenuItem(hmenuContext, IDM_DCCM_CLOSE, MF_BYCOMMAND | MF_GRAYED);
  2136. // If policy is set to lock down active desktop, don't put up the
  2137. // menu that invokes the web-tab
  2138. if (SHRestricted(REST_NOACTIVEDESKTOPCHANGES) || SHRestricted(REST_NODISPBACKGROUND))
  2139. {
  2140. EnableMenuItem(hmenuContext, IDM_DCCM_CUSTOMIZE, MF_BYCOMMAND | MF_GRAYED);
  2141. }
  2142. if (ISNORMAL)
  2143. {
  2144. COMPSTATEINFO CompState;
  2145. LoadString(HINST_THISDLL, IDS_MENU_RESET, szName, ARRAYSIZE(szName));
  2146. ModifyMenu(hmenuContext, IDM_DCCM_RESTORE, MF_BYCOMMAND | MF_STRING, IDM_DCCM_RESTORE, szName);
  2147. ObtainSavedStateForElem(m_pielemTarget, &CompState, FALSE);
  2148. if ((CompState.dwWidth == COMPONENT_DEFAULT_WIDTH && CompState.dwHeight == COMPONENT_DEFAULT_HEIGHT) ||
  2149. (CompState.dwWidth == (DWORD)m_width && CompState.dwHeight == (DWORD)m_height))
  2150. EnableMenuItem(hmenuContext, IDM_DCCM_RESTORE, MF_BYCOMMAND | MF_GRAYED);
  2151. }
  2152. if (ISSPLIT || !m_fCanResizeX || !m_fCanResizeY)
  2153. EnableMenuItem(hmenuContext, IDM_DCCM_SPLIT, MF_BYCOMMAND | MF_GRAYED);
  2154. if (ISFULLSCREEN || !m_fCanResizeX || !m_fCanResizeY)
  2155. EnableMenuItem(hmenuContext, IDM_DCCM_FULLSCREEN, MF_BYCOMMAND | MF_GRAYED);
  2156. g_fIgnoreTimers |= IGNORE_CONTEXTMENU_UP;
  2157. nSelection = TrackPopupMenu(hmenuContext, TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, point.x, point.y, 0, m_hwndParent, NULL);
  2158. DestroyMenu(hmenuContext);
  2159. m_CaptionState &= ~CS_MENUPUSHED;
  2160. UpdateCaption(DMDC_MENU);
  2161. switch (nSelection)
  2162. {
  2163. case IDM_DCCM_OFFLINE:
  2164. if (fSubscribe)
  2165. hr = IElemSubscribeDialog(m_pielemTarget, m_hWnd);
  2166. else
  2167. hr = IElemUnsubscribe(m_pielemTarget);
  2168. break;
  2169. case IDM_DCCM_SYNCHRONIZE:
  2170. hr = IElemUpdate(m_pielemTarget);
  2171. break;
  2172. case IDM_DCCM_PROPERTIES: // Subscriptions Dialog (Don't let the name fool you)
  2173. TraceMsg(TF_CUSTOM2, "CDeskMovr::_DisplayContextMenu() IDM_DCCM_PROPERTIES m_bstrTargetName=%ls.", GEN_DEBUGSTRW(m_bstrTargetName));
  2174. hr = IElemGetSubscriptionsDialog(m_pielemTarget, NULL);
  2175. break;
  2176. case IDM_DCCM_CUSTOMIZE: // Show Display Control Panel set to Components Sheet
  2177. LoadString(HINST_THISDLL, IDS_COMPSETTINGS, szName, ARRAYSIZE(szName));
  2178. SHRunControlPanel(szName, NULL);
  2179. hr = S_OK;
  2180. break;
  2181. case IDM_DCCM_CLOSE:
  2182. ASSERT(!SHRestricted(REST_NOCLOSEDESKCOMP)); // We should never be able to get here.
  2183. TraceMsg(TF_CUSTOM2, "CDeskMovr::_DisplayContextMenu() IDM_DCCM_CLOSE m_bstrTargetName=%ls", GEN_DEBUGSTRW(m_bstrTargetName));
  2184. // AnimateToTray(m_hwndParent, m_left, m_top, m_width, m_height);
  2185. hr = IElemCloseDesktopComp(m_pielemTarget);
  2186. break;
  2187. case IDM_DCCM_RESTORE:
  2188. case IDM_DCCM_FULLSCREEN:
  2189. case IDM_DCCM_SPLIT:
  2190. hr = _HandleZoom(nSelection);
  2191. break;
  2192. case IDM_DCCM_OPEN:
  2193. {
  2194. BOOL fShowFrame = (GetKeyState(VK_SHIFT) < 0) ? !(m_fCanResizeX && m_fCanResizeY) : (m_fCanResizeX && m_fCanResizeY);
  2195. hr = IElemOpenInNewWindow(m_pielemTarget, m_spClientSite, fShowFrame, m_width, m_height);
  2196. }
  2197. break;
  2198. }
  2199. g_fIgnoreTimers &= ~IGNORE_CONTEXTMENU_UP;
  2200. if (nSelection)
  2201. DismissSelfNow();
  2202. }
  2203. return hr;
  2204. }
  2205. void CDeskMovr::_MapPoints(int * px, int * py)
  2206. {
  2207. if (m_bWndLess)
  2208. {
  2209. *px -= m_left - (CAPTION_ONLY ? 0 : m_cxBorder);
  2210. *py -= m_top - (CAPTION_ONLY ? 0 : (m_cyBorder + m_cyCaption));
  2211. }
  2212. }
  2213. void CDeskMovr::_ChangeCapture(BOOL fSet)
  2214. {
  2215. if (m_fCaptured != fSet)
  2216. {
  2217. m_fCaptured = fSet;
  2218. if (fSet)
  2219. {
  2220. ASSERT(m_spInPlaceSite);
  2221. if (m_bWndLess && m_spInPlaceSite)
  2222. {
  2223. m_fCaptured = SUCCEEDED(m_spInPlaceSite->SetCapture(TRUE));
  2224. }
  2225. else
  2226. {
  2227. ::SetCapture( m_hWnd );
  2228. m_fCaptured = (GetCapture() == m_hWnd);
  2229. }
  2230. if (m_fCaptured)
  2231. g_fIgnoreTimers |= IGNORE_CAPTURE_SET;
  2232. }
  2233. else
  2234. {
  2235. ASSERT(m_spInPlaceSite);
  2236. if (m_bWndLess && m_spInPlaceSite)
  2237. {
  2238. m_spInPlaceSite->SetCapture(FALSE);
  2239. }
  2240. else
  2241. {
  2242. ReleaseCapture();
  2243. }
  2244. g_fIgnoreTimers &= ~IGNORE_CAPTURE_SET;
  2245. }
  2246. }
  2247. }
  2248. // Called from our keyboard hook so that we can implement keyboard invocation and dismissal
  2249. // of the deskmovr.
  2250. void CDeskMovr::OnKeyboardHook(WPARAM wParam, LPARAM lParam)
  2251. {
  2252. IHTMLElement * pielem;
  2253. HWND hwndFocus = GetFocus();
  2254. if (!(g_fIgnoreTimers & IGNORE_CONTEXTMENU_UP) && SUCCEEDED(GetParentWindow()) && ((hwndFocus == m_hwndParent) || ::IsChild(m_hwndParent, hwndFocus)))
  2255. {
  2256. switch (wParam) {
  2257. case VK_MENU:
  2258. if (!m_pielemTarget && !(GetDesktopFlags() & COMPONENTS_LOCKED) && SUCCEEDED(SmartActivateMovr(ERROR_SUCCESS)) && SUCCEEDED(_IsInElement(NULL, NULL, &pielem)))
  2259. {
  2260. BOOL fDummy;
  2261. _TrackElement(NULL, pielem, &fDummy);
  2262. pielem->Release();
  2263. }
  2264. break;
  2265. case VK_ESCAPE:
  2266. case VK_TAB:
  2267. if ((lParam >= 0) && m_pielemTarget) // If key down, dismiss
  2268. DismissSelfNow();
  2269. break;
  2270. case VK_SPACE:
  2271. if (m_pielemTarget && (GET_CYCAPTION == m_cyCaption) && (HIWORD(lParam) & KF_ALTDOWN))
  2272. {
  2273. HandleNonMoveSize(dmMenu);
  2274. }
  2275. break;
  2276. }
  2277. }
  2278. }
  2279. STDAPI CDeskMovr_CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppunk)
  2280. {
  2281. return CComCreator< CComPolyObject< CDeskMovr > >::CreateInstance( (LPVOID)pUnkOuter, IID_IUnknown, (LPVOID*)ppunk );
  2282. }