mirror of
https://github.com/chibicitiberiu/rainmeter-studio.git
synced 2024-02-24 04:33:31 +00:00
FileView: Added support for opening the properties or context menu for each item. A user-defined item can also be used on parent measures (in case someone wants to open the properties/context menu from another source - a "dummy" parent measure will be needed).
Usage: !CommandMeasure MeasureName ContextMenu !CommandMeasure MeasureName Properties
This commit is contained in:
parent
d0fd184063
commit
05d256ced3
@ -17,6 +17,8 @@
|
||||
*/
|
||||
|
||||
#include "PluginFileView.h"
|
||||
#include "../../Common/Platform.h"
|
||||
#include "../../Common/StringUtil.h"
|
||||
|
||||
#define MAX_LINE_LENGTH 4096
|
||||
#define INVALID_FILE L"/<>\\"
|
||||
@ -50,6 +52,7 @@ HRESULT SaveIcon(HICON hIcon, FILE* fp);
|
||||
|
||||
static std::vector<ParentMeasure*> g_ParentMeasures;
|
||||
static CRITICAL_SECTION g_CriticalSection;
|
||||
static std::string g_SysProperties;
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
@ -74,6 +77,15 @@ PLUGIN_EXPORT void Initialize(void** data, void* rm)
|
||||
{
|
||||
ChildMeasure* child = new ChildMeasure;
|
||||
*data = child;
|
||||
|
||||
if (g_SysProperties.empty())
|
||||
{
|
||||
std::wstring dir = RmReplaceVariables(rm, L"%WINDIR%");
|
||||
dir.append(L"\\system32\\control.exe");
|
||||
dir.append(Platform::IsAtLeastWinVista() ? L" system" : L" sysdm.cpl");
|
||||
|
||||
g_SysProperties = StringUtil::Narrow(dir);
|
||||
}
|
||||
}
|
||||
|
||||
PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
|
||||
@ -98,7 +110,7 @@ PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
|
||||
|
||||
if (!child->parent)
|
||||
{
|
||||
RmLog(LOG_ERROR, L"FileView.dll: Invalid Path");
|
||||
RmLogF(rm, LOG_ERROR, L"Invalid Path: \"%s\"", path.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -110,6 +122,8 @@ PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
|
||||
child->parent->skin = skin;
|
||||
child->parent->name = RmGetMeasureName(rm);
|
||||
child->parent->ownerChild = child;
|
||||
child->parent->hwnd = RmGetSkinWindow(rm);
|
||||
child->parent->rm = rm;
|
||||
g_ParentMeasures.push_back(child->parent);
|
||||
}
|
||||
|
||||
@ -495,20 +509,33 @@ PLUGIN_EXPORT void ExecuteBang(void* data, LPCWSTR args)
|
||||
return;
|
||||
}
|
||||
|
||||
auto runFile = [&](std::wstring& filename, std::wstring& dir)
|
||||
auto runFile = [&](std::wstring fileName, std::wstring dir, bool isProperty) -> void
|
||||
{
|
||||
std::wstring file = dir + filename;
|
||||
// Display computer system properties
|
||||
if (isProperty && dir.empty() && fileName.empty())
|
||||
{
|
||||
WinExec(g_SysProperties.c_str(), SW_SHOWNORMAL);
|
||||
return;
|
||||
}
|
||||
|
||||
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
||||
|
||||
std::wstring file = dir + fileName;
|
||||
SHELLEXECUTEINFO si = {sizeof(SHELLEXECUTEINFO)};
|
||||
|
||||
si.lpVerb = nullptr;
|
||||
si.lpVerb = isProperty ? L"properties" : nullptr;
|
||||
si.lpFile = file.c_str();
|
||||
si.nShow = SW_SHOWNORMAL;
|
||||
si.lpDirectory = dir.c_str();
|
||||
si.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_ASYNCOK;
|
||||
|
||||
if (isProperty) si.fMask |= SEE_MASK_INVOKEIDLIST;
|
||||
|
||||
ShellExecuteEx(&si);
|
||||
CoUninitialize();
|
||||
};
|
||||
|
||||
// Parent only commands
|
||||
if (parent->ownerChild == child)
|
||||
{
|
||||
if ((int)parent->files.size() > parent->count)
|
||||
@ -573,57 +600,110 @@ PLUGIN_EXPORT void ExecuteBang(void* data, LPCWSTR args)
|
||||
parent->needsIcons = true;
|
||||
parent->needsUpdating = true;
|
||||
}
|
||||
else if (_wcsicmp(args, L"CONTEXTMENU") == 0)
|
||||
{
|
||||
if (!ShowContextMenu(parent->hwnd, parent->path))
|
||||
{
|
||||
RmLogF(parent->rm, LOG_ERROR, L"Cannot open context menu for \"%s\"", parent->path.c_str());
|
||||
}
|
||||
}
|
||||
else if (_wcsicmp(args, L"PROPERTIES") == 0)
|
||||
{
|
||||
runFile(L"", parent->path, true);
|
||||
}
|
||||
else if (parent->recursiveType != RECURSIVE_FULL && _wcsicmp(args, L"PREVIOUSFOLDER") == 0)
|
||||
{
|
||||
std::vector<std::wstring> path = Tokenize(parent->path, L"\\");
|
||||
if (path.size() < 2)
|
||||
{
|
||||
parent->path.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
parent->path.clear();
|
||||
for (size_t i = 0; i < path.size() - 1; ++i)
|
||||
{
|
||||
parent->path += path[i];
|
||||
parent->path += L"\\";
|
||||
}
|
||||
}
|
||||
GetParentFolder(parent->path);
|
||||
|
||||
parent->indexOffset = 0;
|
||||
parent->needsUpdating = true;
|
||||
parent->needsIcons = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Special commands that allow for a user defined file/folder
|
||||
std::wstring arg = args;
|
||||
std::wstring::size_type pos = arg.find_first_of(L' ');
|
||||
if (pos != std::wstring::npos)
|
||||
{
|
||||
arg = arg.substr(pos);
|
||||
if (!arg.empty())
|
||||
{
|
||||
arg.erase(0, 1); // Skip the space
|
||||
|
||||
if (_wcsnicmp(args, L"CONTEXTMENU", 11) == 0)
|
||||
{
|
||||
if (!ShowContextMenu(parent->hwnd, arg))
|
||||
{
|
||||
RmLogF(parent->rm, LOG_ERROR, L"Cannot open context menu for \"%s\"", arg.c_str());
|
||||
}
|
||||
}
|
||||
else if (_wcsnicmp(args, L"PROPERTIES", 10) == 0)
|
||||
{
|
||||
runFile(arg, L"", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
RmLogF(parent->rm, LOG_WARNING, L"!CommandMeasure: Unknown path: %s", arg.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RmLogF(parent->rm, LOG_WARNING, L"!CommandMeasure: Unknown command: %s", args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&g_CriticalSection);
|
||||
return;
|
||||
}
|
||||
|
||||
// Child only commands
|
||||
int trueIndex = child->ignoreCount ? child->index : ((child->index % parent->count) + parent->indexOffset);
|
||||
if (!parent->files.empty() && trueIndex >= 0 && trueIndex < (int)parent->files.size())
|
||||
{
|
||||
if (_wcsicmp(args, L"OPEN") == 0)
|
||||
{
|
||||
runFile(parent->files[trueIndex].fileName, parent->files[trueIndex].path);
|
||||
runFile(parent->files[trueIndex].fileName, parent->files[trueIndex].path, false);
|
||||
}
|
||||
else if (_wcsicmp(args, L"CONTEXTMENU") == 0)
|
||||
{
|
||||
std::wstring path = parent->files[trueIndex].path;
|
||||
std::wstring fileName = parent->files[trueIndex].fileName;
|
||||
|
||||
if (_wcsicmp(fileName.c_str(), L"..") == 0)
|
||||
{
|
||||
path = parent->path;
|
||||
GetParentFolder(path);
|
||||
fileName = L"";
|
||||
}
|
||||
|
||||
path.append(fileName);
|
||||
|
||||
if (!ShowContextMenu(parent->hwnd, path))
|
||||
{
|
||||
RmLogF(parent->rm, LOG_ERROR, L"Cannot open context menu for \"%s\"", path.c_str());
|
||||
}
|
||||
}
|
||||
else if (_wcsicmp(args, L"PROPERTIES") == 0)
|
||||
{
|
||||
std::wstring path = parent->files[trueIndex].path;
|
||||
std::wstring fileName = parent->files[trueIndex].fileName;
|
||||
|
||||
if (_wcsicmp(fileName.c_str(), L"..") == 0)
|
||||
{
|
||||
path = parent->path;
|
||||
GetParentFolder(path);
|
||||
fileName = L"";
|
||||
}
|
||||
|
||||
runFile(fileName, path, true);
|
||||
}
|
||||
else if (parent->recursiveType != RECURSIVE_FULL && _wcsicmp(args, L"FOLLOWPATH") == 0)
|
||||
{
|
||||
if (_wcsicmp(parent->files[trueIndex].fileName.c_str(), L"..") == 0)
|
||||
{
|
||||
std::vector<std::wstring> path = Tokenize(parent->path, L"\\");
|
||||
if (path.size() < 2)
|
||||
{
|
||||
parent->path.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
parent->path.clear();
|
||||
for (size_t i = 0; i < path.size() - 1; ++i)
|
||||
{
|
||||
parent->path += path[i];
|
||||
parent->path += L"\\";
|
||||
}
|
||||
}
|
||||
GetParentFolder(parent->path);
|
||||
|
||||
parent->indexOffset = 0;
|
||||
parent->needsUpdating = true;
|
||||
@ -643,16 +723,20 @@ PLUGIN_EXPORT void ExecuteBang(void* data, LPCWSTR args)
|
||||
}
|
||||
else
|
||||
{
|
||||
runFile(parent->files[trueIndex].fileName, parent->files[trueIndex].path);
|
||||
runFile(parent->files[trueIndex].fileName, parent->files[trueIndex].path, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RmLogF(parent->rm, LOG_WARNING, L"!CommandMeasure: Unknown command: %s", args);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&g_CriticalSection);
|
||||
return;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&g_CriticalSection);
|
||||
RmLog(LOG_ERROR, L"FileView.dll: Invalid command");
|
||||
RmLogF(parent->rm, LOG_WARNING, L"!CommandMeasure: Unknown command: %s", args);
|
||||
}
|
||||
|
||||
PLUGIN_EXPORT void Finalize(void* data)
|
||||
|
@ -114,6 +114,8 @@ struct ParentMeasure
|
||||
int indexOffset;
|
||||
HANDLE thread;
|
||||
|
||||
void* rm;
|
||||
HWND hwnd;
|
||||
void* skin;
|
||||
LPCWSTR name;
|
||||
ChildMeasure* ownerChild;
|
||||
@ -139,6 +141,8 @@ struct ParentMeasure
|
||||
skin(nullptr),
|
||||
name(),
|
||||
ownerChild(nullptr),
|
||||
rm(),
|
||||
hwnd(),
|
||||
thread(nullptr),
|
||||
fileCount(0),
|
||||
folderCount(0),
|
||||
@ -188,6 +192,81 @@ std::vector<std::wstring> Tokenize(const std::wstring& str, const std::wstring&
|
||||
return tokens;
|
||||
}
|
||||
|
||||
void GetParentFolder(std::wstring& path)
|
||||
{
|
||||
std::vector<std::wstring> tokens = Tokenize(path, L"\\");
|
||||
if (tokens.size() < 2)
|
||||
{
|
||||
path.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
path.clear();
|
||||
for (size_t i = 0; i < tokens.size() - 1; ++i)
|
||||
{
|
||||
path += tokens[i];
|
||||
path += L"\\";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ShowContextMenu(HWND hwnd, std::wstring& path)
|
||||
{
|
||||
POINT pos;
|
||||
GetCursorPos(&pos);
|
||||
|
||||
// If the mouse is outside of the boundaries of
|
||||
// the skin, use the upper-left corner of the skin
|
||||
RECT rect;
|
||||
GetWindowRect(hwnd, &rect);
|
||||
if (pos.x < rect.left || pos.x > rect.right ||
|
||||
pos.y < rect.top || pos.y > rect.bottom)
|
||||
{
|
||||
pos.x = rect.left;
|
||||
pos.y = rect.top;
|
||||
}
|
||||
|
||||
ITEMIDLIST* id = nullptr;
|
||||
HRESULT result = SHParseDisplayName(path.c_str(), nullptr, &id, 0, nullptr);
|
||||
if (!SUCCEEDED(result) || !id)
|
||||
return false;
|
||||
|
||||
IShellFolder* iFolder = nullptr;
|
||||
LPCITEMIDLIST idChild = nullptr;
|
||||
result = SHBindToParent(id, IID_IShellFolder, (void**)&iFolder, &idChild);
|
||||
if (!SUCCEEDED(result) || !iFolder)
|
||||
return false;
|
||||
|
||||
IContextMenu* iMenu = nullptr;
|
||||
result = iFolder->GetUIObjectOf(hwnd, 1, (const ITEMIDLIST **)&idChild, IID_IContextMenu, nullptr, (void**)&iMenu);
|
||||
if (!SUCCEEDED(result) || !iFolder)
|
||||
return false;
|
||||
|
||||
HMENU hMenu = CreatePopupMenu();
|
||||
if (!hMenu)
|
||||
return false;
|
||||
|
||||
if (SUCCEEDED(iMenu->QueryContextMenu(hMenu, 0, 1, 0x7FFF, CMF_NORMAL)))
|
||||
{
|
||||
int iCmd = TrackPopupMenuEx(hMenu, TPM_RETURNCMD, pos.x, pos.y, hwnd, NULL);
|
||||
if (iCmd > 0)
|
||||
{
|
||||
CMINVOKECOMMANDINFOEX info = { 0 };
|
||||
info.cbSize = sizeof(info);
|
||||
info.fMask = CMIC_MASK_UNICODE | CMIC_MASK_ASYNCOK;
|
||||
info.hwnd = hwnd;
|
||||
info.lpVerb = MAKEINTRESOURCEA(iCmd - 1);
|
||||
info.lpVerbW = MAKEINTRESOURCEW(iCmd - 1);
|
||||
info.nShow = SW_SHOWNORMAL;
|
||||
|
||||
iMenu->InvokeCommand((LPCMINVOKECOMMANDINFO)&info);
|
||||
}
|
||||
}
|
||||
|
||||
DestroyMenu(hMenu);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*std::wstring UINT64_To_String(UINT64 value)
|
||||
{
|
||||
std::wstring result;
|
||||
|
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,0,2,0
|
||||
FILEVERSION 2,0,3,0
|
||||
PRODUCTVERSION PRODUCTVER
|
||||
FILEFLAGSMASK 0x17L
|
||||
#ifdef _DEBUG
|
||||
@ -23,7 +23,7 @@ VS_VERSION_INFO VERSIONINFO
|
||||
{
|
||||
BLOCK "040904E4"
|
||||
{
|
||||
VALUE "FileVersion", "2.0.2.0"
|
||||
VALUE "FileVersion", "2.0.3.0"
|
||||
VALUE "LegalCopyright", "© 2012 - Brian Ferguson"
|
||||
VALUE "ProductName", "Rainmeter"
|
||||
#ifdef _WIN64
|
||||
|
@ -36,6 +36,11 @@
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="PluginFileView.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Common\Common.vcxproj">
|
||||
<Project>{19312085-aa51-4bd6-be92-4b6098cca539}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <process.h>
|
||||
#include <Shellapi.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <ShlObj.h>
|
||||
|
||||
// STL
|
||||
#include <string>
|
||||
|
Loading…
Reference in New Issue
Block a user