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.

413 lines
13 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: menudd.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Menu drag and drop - kernel
  7. *
  8. * History:
  9. * 10/29/96 GerardoB Created
  10. \***************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include "callback.h"
  14. /*
  15. * xxxClient* are callbacks from the kernel to call/load OLE functions
  16. * The other functions in this file are client calls into the kernel
  17. */
  18. /**************************************************************************\
  19. * xxxClientLoadOLE
  20. *
  21. * 11/06/96 GerardoB Created
  22. \**************************************************************************/
  23. NTSTATUS xxxClientLoadOLE (void)
  24. {
  25. NTSTATUS Status;
  26. PPROCESSINFO ppiCurrent = PpiCurrent();
  27. if (ppiCurrent->W32PF_Flags & W32PF_OLELOADED) {
  28. return STATUS_SUCCESS;
  29. }
  30. Status = xxxUserModeCallback(FI_CLIENTLOADOLE, NULL, 0, NULL, 0);
  31. if (NT_SUCCESS(Status)) {
  32. ppiCurrent->W32PF_Flags |= W32PF_OLELOADED;
  33. }
  34. return Status;
  35. }
  36. /**************************************************************************\
  37. * xxxClientRegisterDragDrop
  38. *
  39. * 10/28/96 GerardoB Created
  40. \**************************************************************************/
  41. NTSTATUS xxxClientRegisterDragDrop (HWND hwnd)
  42. {
  43. return xxxUserModeCallback(FI_CLIENTREGISTERDRAGDROP, &hwnd, sizeof(&hwnd), NULL, 0);
  44. }
  45. /**************************************************************************\
  46. * xxxClientRevokeDragDrop
  47. *
  48. * 10/28/96 GerardoB Created
  49. \**************************************************************************/
  50. NTSTATUS xxxClientRevokeDragDrop (HWND hwnd)
  51. {
  52. return xxxUserModeCallback(FI_CLIENTREVOKEDRAGDROP, &hwnd, sizeof(&hwnd), NULL, 0);
  53. }
  54. /**************************************************************************\
  55. * xxxMNSetGapState
  56. *
  57. * 11/15/96 GerardoB Created
  58. \**************************************************************************/
  59. void xxxMNSetGapState (ULONG_PTR uHitArea, UINT uIndex, UINT uFlags, BOOL fSet)
  60. {
  61. int yTop;
  62. PITEM pItem, pItemGap;
  63. PPOPUPMENU ppopup;
  64. RECT rc;
  65. TL tlHitArea;
  66. /*
  67. * Bail if there is nothing to do.
  68. */
  69. if (!(uFlags & MNGOF_GAP) || !IsMFMWFPWindow(uHitArea)) {
  70. return;
  71. }
  72. ppopup = ((PMENUWND)uHitArea)->ppopupmenu;
  73. pItem = MNGetpItem(ppopup, uIndex);
  74. /*
  75. * The menu window might be destroyed by now so pItem could be NULL.
  76. */
  77. if (pItem == NULL) {
  78. return;
  79. }
  80. /*
  81. * Mark the item and set the rectangle we need to redraw.
  82. * Drawing/erasing the insertion bar unhilites/hiltes the
  83. * item, so pItem needs to be redrawn completely. In additon,
  84. * we need to draw the insertion bar in the next/previous item.
  85. */
  86. rc.left = pItem->xItem;
  87. rc.right = pItem->xItem + pItem->cxItem;
  88. rc.top = pItem->yItem;
  89. rc.bottom = pItem->yItem + pItem->cyItem;
  90. if (uFlags & MNGOF_TOPGAP) {
  91. pItemGap = MNGetpItem(ppopup, uIndex - 1);
  92. if (fSet) {
  93. SetMFS(pItem, MFS_TOPGAPDROP);
  94. if (pItemGap != NULL) {
  95. SetMFS(pItemGap, MFS_BOTTOMGAPDROP);
  96. }
  97. } else {
  98. ClearMFS(pItem, MFS_TOPGAPDROP);
  99. if (pItemGap != NULL) {
  100. ClearMFS(pItemGap, MFS_BOTTOMGAPDROP);
  101. }
  102. }
  103. if (pItemGap != NULL) {
  104. rc.top -= SYSMET(CYDRAG);
  105. }
  106. } else {
  107. pItemGap = MNGetpItem(ppopup, uIndex + 1);
  108. if (fSet) {
  109. SetMFS(pItem, MFS_BOTTOMGAPDROP);
  110. if (pItemGap != NULL) {
  111. SetMFS(pItemGap, MFS_TOPGAPDROP);
  112. }
  113. } else {
  114. ClearMFS(pItem, MFS_BOTTOMGAPDROP);
  115. if (pItemGap != NULL) {
  116. ClearMFS(pItemGap, MFS_TOPGAPDROP);
  117. }
  118. }
  119. if (pItemGap != NULL) {
  120. rc.bottom += SYSMET(CYDRAG);
  121. }
  122. }
  123. /*
  124. * Adjust to "menu" coordinates (for scrollable menus)
  125. */
  126. yTop = MNGetToppItem(ppopup->spmenu)->yItem;
  127. rc.top -= yTop;
  128. rc.bottom -= yTop;
  129. /*
  130. * Invalidate this rect to repaint it later
  131. */
  132. ThreadLockAlways((PWND)uHitArea, &tlHitArea);
  133. xxxInvalidateRect((PWND)uHitArea, &rc, TRUE);
  134. ThreadUnlock(&tlHitArea);
  135. }
  136. /**************************************************************************\
  137. * xxxMNDragOver
  138. *
  139. * Menu windows involved in drag drop are registered as targets. This function
  140. * is called from the client side IDropTarget functions so the menu code can
  141. * update the selection given the mouse position
  142. *
  143. * 10/28/96 GerardoB Created
  144. \**************************************************************************/
  145. BOOL xxxMNDragOver(POINT * ppt, PMNDRAGOVERINFO pmndoi)
  146. {
  147. BOOL fRet;
  148. PMENUSTATE pMenuState;
  149. PWND pwnd;
  150. PPOPUPMENU ppopup;
  151. TL tlpwnd;
  152. /*
  153. * OLE always calls us in context (proxy/marshall stuff). So the
  154. * current thread must be in menu mode
  155. */
  156. pMenuState = PtiCurrent()->pMenuState;
  157. if (pMenuState == NULL) {
  158. RIPMSG0(RIP_WARNING, "xxxMNDragOver: Not in menu mode");
  159. return FALSE;
  160. }
  161. /*
  162. * This must be a drag and drop menu
  163. */
  164. UserAssert(pMenuState->fDragAndDrop);
  165. /*
  166. * We might have not initiated this DoDragDrop so make sure
  167. * the internal flag is set.
  168. */
  169. pMenuState->fInDoDragDrop = TRUE;
  170. /*
  171. * Get a window to call xxxCallHandleMenuMessages
  172. */
  173. pwnd = GetMenuStateWindow(pMenuState);
  174. if (pwnd == NULL) {
  175. RIPMSG0(RIP_WARNING, "xxxMNDragOver: Failed to get MenuStateWindow");
  176. return FALSE;
  177. }
  178. /*
  179. * We need this after calling back, so lock it
  180. */
  181. LockMenuState(pMenuState);
  182. /*
  183. * Update the selection and the dragging info
  184. * Use WM_NCMOUSEMOVE because the point is in screen coordinates already.
  185. */
  186. ThreadLockAlways(pwnd, &tlpwnd);
  187. xxxCallHandleMenuMessages(pMenuState, pwnd, WM_NCMOUSEMOVE, 0, MAKELONG(ppt->x, ppt->y));
  188. ThreadUnlock(&tlpwnd);
  189. /*
  190. * If we're on a popup, propagate the hit test info
  191. */
  192. if (pMenuState->uDraggingHitArea != MFMWFP_OFFMENU) {
  193. ppopup = ((PMENUWND)pMenuState->uDraggingHitArea)->ppopupmenu;
  194. pmndoi->hmenu = PtoH(ppopup->spmenu);
  195. pmndoi->uItemIndex = pMenuState->uDraggingIndex;
  196. pmndoi->hwndNotify = PtoH(ppopup->spwndNotify);
  197. pmndoi->dwFlags = pMenuState->uDraggingFlags;
  198. /*
  199. * Bottom gap of item N corresponds to N+1 gap
  200. */
  201. if (pmndoi->dwFlags & MNGOF_BOTTOMGAP) {
  202. UserAssert(pmndoi->uItemIndex != MFMWFP_NOITEM);
  203. (pmndoi->uItemIndex)++;
  204. }
  205. fRet = TRUE;
  206. } else {
  207. fRet = FALSE;
  208. }
  209. xxxUnlockMenuState(pMenuState);
  210. return fRet;;
  211. }
  212. /**************************************************************************\
  213. * xxxMNDragLeave
  214. *
  215. * 11/15/96 GerardoB Created
  216. \**************************************************************************/
  217. BOOL xxxMNDragLeave (VOID)
  218. {
  219. PMENUSTATE pMenuState;
  220. pMenuState = PtiCurrent()->pMenuState;
  221. if (pMenuState == NULL) {
  222. RIPMSG0(RIP_WARNING, "xxxMNDragLeave: Not in menu mode");
  223. return FALSE;
  224. }
  225. LockMenuState(pMenuState);
  226. /*
  227. * Clean up any present insertion bar state
  228. */
  229. xxxMNSetGapState(pMenuState->uDraggingHitArea,
  230. pMenuState->uDraggingIndex,
  231. pMenuState->uDraggingFlags,
  232. FALSE);
  233. /*
  234. * Forget the last dragging area
  235. */
  236. UnlockMFMWFPWindow(&pMenuState->uDraggingHitArea);
  237. pMenuState->uDraggingIndex = MFMWFP_NOITEM;
  238. pMenuState->uDraggingFlags = 0;
  239. /*
  240. * The DoDragDrop loop has left our window.
  241. */
  242. pMenuState->fInDoDragDrop = FALSE;
  243. xxxUnlockMenuState(pMenuState);
  244. return TRUE;
  245. }
  246. /**************************************************************************\
  247. * xxxMNUpdateDraggingInfo
  248. *
  249. * 10/28/96 GerardoB Created
  250. \**************************************************************************/
  251. void xxxMNUpdateDraggingInfo (PMENUSTATE pMenuState, ULONG_PTR uHitArea, UINT uIndex)
  252. {
  253. BOOL fCross;
  254. int y, iIndexDelta;
  255. PITEM pItem;
  256. PPOPUPMENU ppopup;
  257. TL tlLastHitArea;
  258. ULONG_PTR uLastHitArea;
  259. UINT uLastIndex, uLastFlags;
  260. /*
  261. * Remember current dragging area so we can detected when
  262. * crossing item/gap boundries.
  263. */
  264. UserAssert((pMenuState->uDraggingHitArea == 0) || IsMFMWFPWindow(pMenuState->uDraggingHitArea));
  265. ThreadLock((PWND)pMenuState->uDraggingHitArea, &tlLastHitArea);
  266. uLastHitArea = pMenuState->uDraggingHitArea;
  267. uLastIndex = pMenuState->uDraggingIndex;
  268. uLastFlags = pMenuState->uDraggingFlags & MNGOF_GAP;
  269. /*
  270. * Store new dragging area.
  271. */
  272. LockMFMWFPWindow(&pMenuState->uDraggingHitArea, uHitArea);
  273. pMenuState->uDraggingIndex = uIndex;
  274. /*
  275. * If we're not on a popup, done.
  276. */
  277. if (!IsMFMWFPWindow(pMenuState->uDraggingHitArea)) {
  278. pMenuState->uDraggingHitArea = MFMWFP_OFFMENU;
  279. pMenuState->uDraggingIndex = MFMWFP_NOITEM;
  280. ThreadUnlock(&tlLastHitArea);
  281. return;
  282. }
  283. /*
  284. * Get the popup and item we're on
  285. */
  286. ppopup = ((PMENUWND)pMenuState->uDraggingHitArea)->ppopupmenu;
  287. pItem = MNGetpItem(ppopup, pMenuState->uDraggingIndex);
  288. /*
  289. * Find out if we're on the gap, that is, the "virtual" space
  290. * between items. Some apps want to distinguish between a drop
  291. * ON the item and a drop BEFORE/AFTER the item; there is no
  292. * actual space between items so we define a virtual gap
  293. *
  294. */
  295. pMenuState->uDraggingFlags = 0;
  296. if (pItem != NULL) {
  297. /*
  298. * Map the point to client coordinates and then to "menu"
  299. * coordinates (to take care of scrollable menus)
  300. */
  301. y = pMenuState->ptMouseLast.y;
  302. y -= ((PWND)pMenuState->uDraggingHitArea)->rcClient.top;
  303. y += MNGetToppItem(ppopup->spmenu)->yItem;
  304. #if DBG
  305. if ((y < (int)pItem->yItem)
  306. || (y > (int)(pItem->yItem + pItem->cyItem))) {
  307. RIPMSG4(RIP_ERROR, "xxxMNUpdateDraggingInfo: y Point not in selected item. "
  308. "pwnd:%#lx ppopup:%#lx Index:%#lx pItem:%#lx",
  309. pMenuState->uDraggingHitArea, ppopup, pMenuState->uDraggingIndex, pItem);
  310. }
  311. #endif
  312. /*
  313. * Top/bottom gap check
  314. */
  315. if (y <= (int)(pItem->yItem + SYSMET(CYDRAG))) {
  316. pMenuState->uDraggingFlags = MNGOF_TOPGAP;
  317. } else if (y >= (int)(pItem->yItem + pItem->cyItem - SYSMET(CYDRAG))) {
  318. pMenuState->uDraggingFlags = MNGOF_BOTTOMGAP;
  319. }
  320. }
  321. /*
  322. * Have we crossed an item/gap boundary?
  323. * We don't cross a boundary when we move from the bottom
  324. * of an item to the top of the next, or, from the top
  325. * of an item to the bottom of the previous.
  326. * (Item N is on top of and previous to item N+1).
  327. */
  328. fCross = (uLastHitArea != pMenuState->uDraggingHitArea);
  329. if (!fCross) {
  330. iIndexDelta = (int)pMenuState->uDraggingIndex - (int)uLastIndex;
  331. switch (iIndexDelta) {
  332. case 0:
  333. /*
  334. * We're on the same item.
  335. */
  336. fCross = (uLastFlags != pMenuState->uDraggingFlags);
  337. break;
  338. case 1:
  339. /*
  340. * We've moved to the next item
  341. */
  342. fCross = !((pMenuState->uDraggingFlags == MNGOF_TOPGAP)
  343. && (uLastFlags == MNGOF_BOTTOMGAP));
  344. break;
  345. case -1:
  346. /*
  347. * We've moved to the previous item
  348. */
  349. fCross = !((pMenuState->uDraggingFlags == MNGOF_BOTTOMGAP)
  350. && (uLastFlags == MNGOF_TOPGAP));
  351. break;
  352. default:
  353. /*
  354. * We've skipped more than one item.
  355. */
  356. fCross = TRUE;
  357. }
  358. }
  359. if (fCross) {
  360. pMenuState->uDraggingFlags |= MNGOF_CROSSBOUNDARY;
  361. /*
  362. * Update the insertion bar state.
  363. */
  364. xxxMNSetGapState(uLastHitArea, uLastIndex, uLastFlags, FALSE);
  365. xxxMNSetGapState(pMenuState->uDraggingHitArea,
  366. pMenuState->uDraggingIndex,
  367. pMenuState->uDraggingFlags,
  368. TRUE);
  369. }
  370. ThreadUnlock(&tlLastHitArea);
  371. }