| 1119 | |
| 1120 | |
| 1121 | ResultType UserMenu::Display(bool aForceToForeground, int aX, int aY) |
| 1122 | // aForceToForeground defaults to true because when a menu is displayed spontaneously rather than |
| 1123 | // in response to the user right-clicking the tray icon, I believe that the OS will revert to its |
| 1124 | // behavior of "resisting" a window that tries to "steal focus". I believe this resistance does |
| 1125 | // not occur when the user clicks the icon because that click causes the task bar to get focus, |
| 1126 | // and it is likely that the OS allows other windows to steal focus from the task bar without |
| 1127 | // resistance. This is done because if the main window is *not* successfully activated prior to |
| 1128 | // displaying the menu, it might be impossible to dismiss the menu by clicking outside of it. |
| 1129 | { |
| 1130 | if (mMenuType != MENU_TYPE_POPUP) |
| 1131 | return g_script.RuntimeError(ERR_INVALID_MENU_TYPE); |
| 1132 | if (!mMenuItemCount) |
| 1133 | return OK; // Consider the display of an empty menu to be a success. |
| 1134 | if (!CreateHandle()) // Create if needed. No error msg since so rare. |
| 1135 | return FAIL; |
| 1136 | //if (!IsMenu(mMenu)) |
| 1137 | // mMenu = NULL; |
| 1138 | if (this == g_script.mTrayMenu) |
| 1139 | { |
| 1140 | // These are okay even if the menu items don't exist (perhaps because the user customized the menu): |
| 1141 | CheckMenuItem(mMenu, ID_TRAY_SUSPEND, g_IsSuspended ? MF_CHECKED : MF_UNCHECKED); |
| 1142 | CheckMenuItem(mMenu, ID_TRAY_PAUSE, g->IsPaused ? MF_CHECKED : MF_UNCHECKED); |
| 1143 | } |
| 1144 | |
| 1145 | POINT pt; |
| 1146 | if (aX == COORD_UNSPECIFIED || aY == COORD_UNSPECIFIED) |
| 1147 | GetCursorPos(&pt); |
| 1148 | if (!(aX == COORD_UNSPECIFIED && aY == COORD_UNSPECIFIED)) // At least one was specified. |
| 1149 | { |
| 1150 | // If one coordinate was omitted, pt contains the cursor position in SCREEN COORDINATES. |
| 1151 | // So don't do something like this, which would incorrectly offset the cursor position |
| 1152 | // by the window position if CoordMode != Screen: |
| 1153 | //CoordToScreen(pt, COORD_MODE_MENU); |
| 1154 | POINT origin = {0}; |
| 1155 | CoordToScreen(origin, COORD_MODE_MENU); |
| 1156 | if (aX != COORD_UNSPECIFIED) |
| 1157 | pt.x = aX + origin.x; |
| 1158 | if (aY != COORD_UNSPECIFIED) |
| 1159 | pt.y = aY + origin.y; |
| 1160 | } |
| 1161 | |
| 1162 | // UPDATE: For v1.0.35.14, must ensure one of the script's windows is active before showing the menu |
| 1163 | // because otherwise the menu cannot be dismissed via the escape key or by clicking outside the menu. |
| 1164 | // Testing shows that ensuring any of our thread's windows is active allows both the tray menu and |
| 1165 | // any popup or context menus to work correctly. |
| 1166 | // UPDATE: For v1.0.35.12, the script's main window (g_hWnd) is activated only for the tray menu because: |
| 1167 | // 1) Doing so for GUI context menus seems to prevent mouse clicks in the menu or elsewhere in the window. |
| 1168 | // 2) It would probably have other side effects for other uses of popup menus. |
| 1169 | HWND fore_win = GetForegroundWindow(); |
| 1170 | bool change_fore; |
| 1171 | if (change_fore = (!fore_win || GetWindowThreadProcessId(fore_win, NULL) != g_MainThreadID)) |
| 1172 | { |
| 1173 | // Always bring main window to foreground right before TrackPopupMenu(), even if window is hidden. |
| 1174 | // UPDATE: This is a problem because SetForegroundWindowEx() will restore the window if it's hidden, |
| 1175 | // but restoring also shows the window if it's hidden. Could re-hide it... but the question here |
| 1176 | // is can a minimized window be the foreground window? If not, how to explain why |
| 1177 | // SetForegroundWindow() always seems to work for the purpose of the tray menu? |
| 1178 | //if (aForceToForeground) |
no test coverage detected