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.

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