/*
** Opens the context menu in given coordinates.
*/
void ContextMenu::ShowMenu(POINT pos, Skin* skin)
{
	static const MenuTemplate s_Menu[] =
	{
		MENU_ITEM(IDM_MANAGE, ID_STR_MANAGE),
		MENU_ITEM(IDM_ABOUT, ID_STR_ABOUT),
		MENU_ITEM(IDM_SHOW_HELP, ID_STR_HELP),
		MENU_SEPARATOR(),
		MENU_SUBMENU(ID_STR_SKINS,
			MENU_ITEM(IDM_OPENSKINSFOLDER, ID_STR_OPENFOLDER),
			MENU_ITEM(IDM_DISABLEDRAG, ID_STR_DISABLEDRAGGING),
			MENU_SEPARATOR(),
			MENU_ITEM_GRAYED(0, ID_STR_NOSKINS)),
		MENU_SUBMENU(ID_STR_FAVORITES,
			MENU_ITEM_GRAYED(0, ID_STR_NOFAVORITES)),
		MENU_SUBMENU(ID_STR_THEMES,
			MENU_ITEM_GRAYED(0, ID_STR_NOTHEMES)),
		MENU_SEPARATOR(),
		MENU_ITEM(IDM_EDITCONFIG, ID_STR_EDITSETTINGS),
		MENU_ITEM(IDM_REFRESH, ID_STR_REFRESHALL),
		MENU_SEPARATOR(),
		MENU_SUBMENU(ID_STR_LOGGING,
			MENU_ITEM(IDM_SHOWLOGFILE, ID_STR_SHOWLOGFILE),
			MENU_SEPARATOR(),
			MENU_ITEM(IDM_STARTLOG, ID_STR_STARTLOGGING),
			MENU_ITEM(IDM_STOPLOG, ID_STR_STOPLOGGING),
			MENU_SEPARATOR(),
			MENU_ITEM(IDM_DELETELOGFILE, ID_STR_DELETELOGFILE),
			MENU_ITEM(IDM_DEBUGLOG, ID_STR_DEBUGMODE)),
		MENU_SEPARATOR(),
		MENU_ITEM(IDM_QUIT, ID_STR_EXIT)
	};

	if (m_MenuActive || (skin && skin->IsClosing())) return;

	// Show context menu, if no actions were executed
	HMENU menu = MenuTemplate::CreateMenu(s_Menu, _countof(s_Menu), GetString);
	if (!menu) return;

	m_MenuActive = true;
	Rainmeter& rainmeter = GetRainmeter();

	SetMenuDefaultItem(menu, IDM_MANAGE, MF_BYCOMMAND);

	if (_waccess(GetLogger().GetLogFilePath().c_str(), 0) == -1)
	{
		EnableMenuItem(menu, IDM_SHOWLOGFILE, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(menu, IDM_DELETELOGFILE, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(menu, IDM_STOPLOG, MF_BYCOMMAND | MF_GRAYED);
	}
	else
	{
		EnableMenuItem(
			menu,
			(GetLogger().IsLogToFile()) ? IDM_STARTLOG : IDM_STOPLOG,
			MF_BYCOMMAND | MF_GRAYED);
	}

	if (rainmeter.m_Debug)
	{
		CheckMenuItem(menu, IDM_DEBUGLOG, MF_BYCOMMAND | MF_CHECKED);
	}

	HMENU allSkinsMenu = GetSubMenu(menu, 4);
	if (allSkinsMenu)
	{
		if (!rainmeter.m_SkinRegistry.IsEmpty())
		{
			// "Open folder" = 0, "Disable dragging" = 1, separator = 2
			DeleteMenu(allSkinsMenu, 3, MF_BYPOSITION);  // "No skins available" menuitem
			CreateAllSkinsMenu(allSkinsMenu);
		}

		if (rainmeter.m_DisableDragging)
		{
			CheckMenuItem(allSkinsMenu, IDM_DISABLEDRAG, MF_BYCOMMAND | MF_CHECKED);
		}
	}

	HMENU favoritesMenu = GetSubMenu(menu, 5);
	if (favoritesMenu)
	{
		if (!rainmeter.m_Favorites.empty())
		{
			DeleteMenu(favoritesMenu, 0, MF_BYPOSITION);  // "No skins available" menuitem
			CreateFavoritesMenu(favoritesMenu);
		}
	}

	HMENU layoutMenu = GetSubMenu(menu, 6);
	if (layoutMenu)
	{
		if (!rainmeter.m_Layouts.empty())
		{
			DeleteMenu(layoutMenu, 0, MF_BYPOSITION);  // "No layouts available" menuitem
			CreateLayoutMenu(layoutMenu);
		}
	}

	if (skin)
	{
		HMENU rainmeterMenu = menu;
		menu = CreateSkinMenu(skin, 0, allSkinsMenu);

		InsertMenu(menu, IDM_CLOSESKIN, MF_BYCOMMAND | MF_POPUP, (UINT_PTR)rainmeterMenu, L"Rainmeter");
		InsertMenu(menu, IDM_CLOSESKIN, MF_BYCOMMAND | MF_SEPARATOR, 0, nullptr);
	}
	else
	{
		InsertMenu(menu, 13, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr);

		// Create a menu for all active skins
		int index = 0;
		std::map<std::wstring, Skin*>::const_iterator iter = rainmeter.m_Skins.begin();
		for (; iter != rainmeter.m_Skins.end(); ++iter)
		{
			Skin* skin = ((*iter).second);
			HMENU skinMenu = CreateSkinMenu(skin, index, allSkinsMenu);
			InsertMenu(menu, 13, MF_BYPOSITION | MF_POPUP, (UINT_PTR)skinMenu, skin->GetFolderPath().c_str());
			++index;
		}

		// Add update notification item
		if (rainmeter.m_NewVersion)
		{
			InsertMenu(menu, 0, MF_BYPOSITION, IDM_NEW_VERSION, GetString(ID_STR_UPDATEAVAILABLE));
			HiliteMenuItem(rainmeter.GetTrayIcon()->GetWindow(), menu, 0, MF_BYPOSITION | MF_HILITE);
			InsertMenu(menu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr);
		}
	}

	HWND hWnd = WindowFromPoint(pos);
	if (hWnd != nullptr)
	{
		Skin* skin = rainmeter.GetSkin(hWnd);
		if (skin)
		{
			// Cancel the mouse event beforehand
			skin->SetMouseLeaveEvent(true);
		}
	}

	DisplayMenu(pos, menu, skin ? skin->GetWindow() : rainmeter.m_TrayIcon->GetWindow());
	DestroyMenu(menu);

	m_MenuActive = false;
}
Example #2
0
/*
** Opens the context menu in given coordinates.
*/
void ContextMenu::ShowMenu(POINT pos, MeterWindow* meterWindow)
{
	static const MenuTemplate s_Menu[] =
	{
		MENU_ITEM(IDM_MANAGE, ID_STR_MANAGE),
		MENU_ITEM(IDM_ABOUT, ID_STR_ABOUT),
		MENU_ITEM(IDM_SHOW_HELP, ID_STR_HELP),
		MENU_SEPARATOR(),
		MENU_SUBMENU(ID_STR_SKINS,
			MENU_ITEM_GRAYED(0, ID_STR_NOSKINS),
			MENU_SEPARATOR(),
			MENU_ITEM(IDM_OPENSKINSFOLDER, ID_STR_OPENFOLDER),
			MENU_ITEM(IDM_DISABLEDRAG, ID_STR_DISABLEDRAGGING)),
		MENU_SUBMENU(ID_STR_THEMES,
			MENU_ITEM_GRAYED(0, ID_STR_NOTHEMES)),
		MENU_SEPARATOR(),
		MENU_ITEM(IDM_EDITCONFIG, ID_STR_EDITSETTINGS),
		MENU_ITEM(IDM_REFRESH, ID_STR_REFRESHALL),
		MENU_SEPARATOR(),
		MENU_SUBMENU(ID_STR_LOGGING,
			MENU_ITEM(IDM_SHOWLOGFILE, ID_STR_SHOWLOGFILE),
			MENU_SEPARATOR(),
			MENU_ITEM(IDM_STARTLOG, ID_STR_STARTLOGGING),
			MENU_ITEM(IDM_STOPLOG, ID_STR_STOPLOGGING),
			MENU_SEPARATOR(),
			MENU_ITEM(IDM_DELETELOGFILE, ID_STR_DELETELOGFILE),
			MENU_ITEM(IDM_DEBUGLOG, ID_STR_DEBUGMODE)),
		MENU_SEPARATOR(),
		MENU_ITEM(IDM_QUIT, ID_STR_EXIT)
	};

	if (m_MenuActive || (meterWindow && meterWindow->IsClosing())) return;

	// Show context menu, if no actions were executed
	HMENU menu = MenuTemplate::CreateMenu(s_Menu, _countof(s_Menu), GetString);
	if (!menu) return;

	m_MenuActive = true;
	Rainmeter& rainmeter = GetRainmeter();

	SetMenuDefaultItem(menu, IDM_MANAGE, MF_BYCOMMAND);

	if (_waccess(GetLogger().GetLogFilePath().c_str(), 0) == -1)
	{
		EnableMenuItem(menu, IDM_SHOWLOGFILE, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(menu, IDM_DELETELOGFILE, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(menu, IDM_STOPLOG, MF_BYCOMMAND | MF_GRAYED);
	}
	else
	{
		EnableMenuItem(
			menu,
			(GetLogger().IsLogToFile()) ? IDM_STARTLOG : IDM_STOPLOG,
			MF_BYCOMMAND | MF_GRAYED);
	}

	if (rainmeter.m_Debug)
	{
		CheckMenuItem(menu, IDM_DEBUGLOG, MF_BYCOMMAND | MF_CHECKED);
	}

	HMENU allSkinsMenu = GetSubMenu(menu, 4);
	if (allSkinsMenu)
	{
		if (!rainmeter.m_SkinRegistry.IsEmpty())
		{
			DeleteMenu(allSkinsMenu, 0, MF_BYPOSITION);  // "No skins available" menuitem
			CreateAllSkinsMenu(allSkinsMenu);
		}

		if (rainmeter.m_DisableDragging)
		{
			CheckMenuItem(allSkinsMenu, IDM_DISABLEDRAG, MF_BYCOMMAND | MF_CHECKED);
		}
	}

	HMENU layoutMenu = GetSubMenu(menu, 5);
	if (layoutMenu)
	{
		if (!rainmeter.m_Layouts.empty())
		{
			DeleteMenu(layoutMenu, 0, MF_BYPOSITION);  // "No layouts available" menuitem
			CreateLayoutMenu(layoutMenu);
		}
	}

	if (meterWindow)
	{
		HMENU rainmeterMenu = menu;
		menu = CreateSkinMenu(meterWindow, 0, allSkinsMenu);

		InsertMenu(menu, IDM_CLOSESKIN, MF_BYCOMMAND | MF_POPUP, (UINT_PTR)rainmeterMenu, L"Rainmeter");
		InsertMenu(menu, IDM_CLOSESKIN, MF_BYCOMMAND | MF_SEPARATOR, 0, nullptr);
	}
	else
	{
		InsertMenu(menu, 12, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr);

		// Create a menu for all active skins
		int index = 0;
		std::map<std::wstring, MeterWindow*>::const_iterator iter = rainmeter.m_MeterWindows.begin();
		for (; iter != rainmeter.m_MeterWindows.end(); ++iter)
		{
			MeterWindow* mw = ((*iter).second);
			HMENU skinMenu = CreateSkinMenu(mw, index, allSkinsMenu);
			InsertMenu(menu, 12, MF_BYPOSITION | MF_POPUP, (UINT_PTR)skinMenu, mw->GetFolderPath().c_str());
			++index;
		}

		// Add update notification item
		if (rainmeter.m_NewVersion)
		{
			InsertMenu(menu, 0, MF_BYPOSITION, IDM_NEW_VERSION, GetString(ID_STR_UPDATEAVAILABLE));
			HiliteMenuItem(rainmeter.GetTrayWindow()->GetWindow(), menu, 0, MF_BYPOSITION | MF_HILITE);
			InsertMenu(menu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr);
		}
	}

	HWND hWnd = WindowFromPoint(pos);
	if (hWnd != nullptr)
	{
		MeterWindow* mw = rainmeter.GetMeterWindow(hWnd);
		if (mw)
		{
			// Cancel the mouse event beforehand
			mw->SetMouseLeaveEvent(true);
		}
	}

	// Set the window to foreground
	hWnd = meterWindow ? meterWindow->GetWindow() : rainmeter.m_TrayWindow->GetWindow();
	HWND hWndForeground = GetForegroundWindow();
	if (hWndForeground != hWnd)
	{
		const DWORD foregroundThreadID = GetWindowThreadProcessId(hWndForeground, nullptr);
		const DWORD currentThreadID = GetCurrentThreadId();
		AttachThreadInput(currentThreadID, foregroundThreadID, TRUE);
		SetForegroundWindow(hWnd);
		AttachThreadInput(currentThreadID, foregroundThreadID, FALSE);
	}

	// Show context menu
	TrackPopupMenu(
		menu,
		TPM_RIGHTBUTTON | TPM_LEFTALIGN | (*GetString(ID_STR_ISRTL) == L'1' ? TPM_LAYOUTRTL : 0),
		pos.x,
		pos.y,
		0,
		hWnd,
		nullptr);

	DestroyMenu(menu);

	m_MenuActive = false;
}