Compare commits
No commits in common. "stable" and "v0.0.1" have entirely different histories.
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +0,0 @@
|
|||||||
.vs/
|
|
||||||
build/
|
|
||||||
*.aps
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
# Watchful Eye project CMakeLists.txt
|
|
||||||
cmake_minimum_required(VERSION 3.20)
|
|
||||||
|
|
||||||
project(watchful-eye)
|
|
||||||
|
|
||||||
add_subdirectory(WatchfulEye)
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
// Watchful Eye CMake presets
|
|
||||||
{
|
|
||||||
"version": 3,
|
|
||||||
|
|
||||||
"configurePresets": [
|
|
||||||
{
|
|
||||||
"name": "base",
|
|
||||||
"hidden": true,
|
|
||||||
"generator": "Ninja",
|
|
||||||
"binaryDir": "${sourceDir}/build/${presetName}",
|
|
||||||
"architecture": {
|
|
||||||
"value": "x64",
|
|
||||||
"strategy": "external"
|
|
||||||
},
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_C_COMPILER": "cl.exe",
|
|
||||||
"CMAKE_CXX_COMPILER": "cl.exe"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"name": "Debug",
|
|
||||||
"inherits": "base",
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_BUILD_TYPE": "Debug"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"name": "Release",
|
|
||||||
"inherits": "base",
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_BUILD_TYPE": "Release"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
"buildPresets": [
|
|
||||||
{
|
|
||||||
"name": "Debug",
|
|
||||||
"configurePreset": "Debug"
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"name": "Release",
|
|
||||||
"configurePreset": "Release"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
# Watchful Eye app CMakeLists.txt
|
|
||||||
add_executable(WatchfulEye WIN32 "src/main.cpp" "src/pch.h" "src/Application.h" "src/Application.cpp" "resource.rc" "src/resource.h")
|
|
||||||
|
|
||||||
set_property(TARGET WatchfulEye PROPERTY CXX_STANDARD 20)
|
|
||||||
|
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /entry:mainCRTStartup")
|
|
||||||
|
|
||||||
if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
|
|
||||||
set_property(TARGET WatchfulEye PROPERTY WIN32_EXECUTABLE FALSE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_precompile_headers(WatchfulEye PUBLIC "src/pch.h")
|
|
||||||
|
|
||||||
find_package(Git)
|
|
||||||
execute_process(COMMAND ${GIT_EXECUTABLE} describe OUTPUT_VARIABLE APPVERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
configure_file(src/version.h.in version.h)
|
|
||||||
target_include_directories(WatchfulEye PUBLIC "${PROJECT_BINARY_DIR}/WatchfulEye")
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 101 KiB |
@ -1,106 +0,0 @@
|
|||||||
// Microsoft Visual C++ generated resource script.
|
|
||||||
//
|
|
||||||
#include "src/resource.h"
|
|
||||||
#include "version.h"
|
|
||||||
|
|
||||||
#define APSTUDIO_READONLY_SYMBOLS
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Generated from the TEXTINCLUDE 2 resource.
|
|
||||||
//
|
|
||||||
#include <winres.h>
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
#undef APSTUDIO_READONLY_SYMBOLS
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
// English (United States) resources
|
|
||||||
|
|
||||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
|
||||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
|
||||||
#pragma code_page(1252)
|
|
||||||
|
|
||||||
#ifdef APSTUDIO_INVOKED
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// TEXTINCLUDE
|
|
||||||
//
|
|
||||||
|
|
||||||
1 TEXTINCLUDE
|
|
||||||
BEGIN
|
|
||||||
"src/resource.h\0"
|
|
||||||
END
|
|
||||||
|
|
||||||
2 TEXTINCLUDE
|
|
||||||
BEGIN
|
|
||||||
"#include <winres.h>\0"
|
|
||||||
END
|
|
||||||
|
|
||||||
3 TEXTINCLUDE
|
|
||||||
BEGIN
|
|
||||||
"\r\n"
|
|
||||||
"\0"
|
|
||||||
END
|
|
||||||
|
|
||||||
#endif // APSTUDIO_INVOKED
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Version
|
|
||||||
//
|
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
|
||||||
FILEFLAGSMASK 0x3fL
|
|
||||||
#ifdef _DEBUG
|
|
||||||
FILEFLAGS 0x1L
|
|
||||||
#else
|
|
||||||
FILEFLAGS 0x0L
|
|
||||||
#endif
|
|
||||||
FILEOS 0x40004L
|
|
||||||
FILETYPE 0x0L
|
|
||||||
FILESUBTYPE 0x0L
|
|
||||||
BEGIN
|
|
||||||
BLOCK "StringFileInfo"
|
|
||||||
BEGIN
|
|
||||||
BLOCK "040904b0"
|
|
||||||
BEGIN
|
|
||||||
VALUE "CompanyName", "Grayson Riffe"
|
|
||||||
VALUE "FileDescription", "Watchful Eye"
|
|
||||||
VALUE "InternalName", "WatchfulEye"
|
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2026"
|
|
||||||
VALUE "OriginalFilename", "WatchfulEye.exe"
|
|
||||||
VALUE "ProductName", "Watchful Eye"
|
|
||||||
VALUE "ProductVersion", APPVERSION
|
|
||||||
END
|
|
||||||
END
|
|
||||||
BLOCK "VarFileInfo"
|
|
||||||
BEGIN
|
|
||||||
VALUE "Translation", 0x409, 1200
|
|
||||||
END
|
|
||||||
END
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Icon
|
|
||||||
//
|
|
||||||
|
|
||||||
// Icon with lowest ID value placed first to ensure application icon
|
|
||||||
// remains consistent on all systems.
|
|
||||||
IDI_ICONMAIN ICON "res\\watchful-eye.ico"
|
|
||||||
|
|
||||||
#endif // English (United States) resources
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef APSTUDIO_INVOKED
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Generated from the TEXTINCLUDE 3 resource.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
#endif // not APSTUDIO_INVOKED
|
|
||||||
|
|
||||||
@ -1,369 +0,0 @@
|
|||||||
// Application class implementation
|
|
||||||
#include "pch.h"
|
|
||||||
|
|
||||||
#include "Application.h"
|
|
||||||
|
|
||||||
#include "resource.h"
|
|
||||||
|
|
||||||
#define WINDOW_WIDTH 450
|
|
||||||
#define WINDOW_HEIGHT 185
|
|
||||||
#define WINDOW_STYLE WS_POPUP
|
|
||||||
#define EX_WINDOW_STYLE WS_EX_TOOLWINDOW
|
|
||||||
|
|
||||||
#define WM_TRAYICON WM_USER // Tray icon window message
|
|
||||||
#define IDM_ABOUT 1001 // "About" menu identifier
|
|
||||||
#define IDM_EXIT 1002 // "Exit" menu identifier
|
|
||||||
#define IDT_UPDATE 1 // Update timer identifier
|
|
||||||
#define WM_UPDATE WM_USER + 1 // Update window message
|
|
||||||
|
|
||||||
// Enable visual styles
|
|
||||||
#pragma comment(linker, "\"/manifestdependency:type='win32' \
|
|
||||||
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
|
|
||||||
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
|
||||||
|
|
||||||
namespace watchfuleye {
|
|
||||||
Application::Application(const char* appName, const char* appVersion, unsigned int maximumMinutes, const char* driveToDetect)
|
|
||||||
: m_appName(appName)
|
|
||||||
, m_appVersion(appVersion)
|
|
||||||
, m_window(nullptr)
|
|
||||||
, m_running(true)
|
|
||||||
, m_active(false)
|
|
||||||
, m_overTime(false)
|
|
||||||
, m_maxMinutes(maximumMinutes)
|
|
||||||
, m_drive(driveToDetect)
|
|
||||||
, m_paintCounter(0)
|
|
||||||
, m_startTime()
|
|
||||||
, m_taskbarCreatedMessage(-1)
|
|
||||||
, m_region(nullptr)
|
|
||||||
, m_timeFont(nullptr)
|
|
||||||
, m_lowerFont(nullptr)
|
|
||||||
, m_greenBrush(nullptr)
|
|
||||||
, m_yellowBrush(nullptr)
|
|
||||||
, m_redBrush(nullptr)
|
|
||||||
, m_outlinePen(nullptr)
|
|
||||||
, m_offscreenDC(nullptr)
|
|
||||||
, m_offscreenBitmap(nullptr)
|
|
||||||
{
|
|
||||||
std::cout << std::format("{} {}\n", m_appName, m_appVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::run() {
|
|
||||||
// Create window
|
|
||||||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); // Don't mess with the window size
|
|
||||||
|
|
||||||
WNDCLASS wc = {};
|
|
||||||
|
|
||||||
std::string windowClassName = "WatchfulEyeWindow";
|
|
||||||
|
|
||||||
wc.lpszClassName = windowClassName.c_str();
|
|
||||||
wc.hCursor = LoadCursor(NULL, IDC_SIZEALL);
|
|
||||||
wc.lpfnWndProc = wndProc;
|
|
||||||
|
|
||||||
RegisterClass(&wc);
|
|
||||||
|
|
||||||
m_window = CreateWindowEx(EX_WINDOW_STYLE, windowClassName.c_str(), m_appName.c_str(), WINDOW_STYLE, 0, 0, 0, 0, nullptr, nullptr, nullptr, this);
|
|
||||||
|
|
||||||
// Create tray icon
|
|
||||||
createTrayIcon();
|
|
||||||
|
|
||||||
// Create drive query thread
|
|
||||||
std::thread queryThread(&Application::queryThreadFunction, this);
|
|
||||||
|
|
||||||
ShowWindow(m_window, SW_SHOW);
|
|
||||||
|
|
||||||
MSG msg = {};
|
|
||||||
while (GetMessage(&msg, nullptr, 0, 0)) {
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessage(&msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_running = false;
|
|
||||||
|
|
||||||
queryThread.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
LRESULT CALLBACK Application::wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
|
||||||
static Application* app = nullptr;
|
|
||||||
|
|
||||||
switch (msg) {
|
|
||||||
case WM_CREATE: {
|
|
||||||
app = reinterpret_cast<Application*>(reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams);
|
|
||||||
|
|
||||||
app->sizeWindow(hWnd);
|
|
||||||
|
|
||||||
// Round the window's corners
|
|
||||||
app->m_region = CreateRoundRectRgn(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 20, 20);
|
|
||||||
SetWindowRgn(hWnd, app->m_region, TRUE);
|
|
||||||
|
|
||||||
// Spawn in the lower right corner of the virtual screen (might be problematic in some cases)
|
|
||||||
int cornerX = GetSystemMetrics(SM_XVIRTUALSCREEN) + GetSystemMetrics(SM_CXVIRTUALSCREEN);
|
|
||||||
int cornerY = GetSystemMetrics(SM_YVIRTUALSCREEN) + GetSystemMetrics(SM_CYVIRTUALSCREEN);
|
|
||||||
|
|
||||||
// And set topmost flag
|
|
||||||
SetWindowPos(hWnd, HWND_TOPMOST, cornerX - 500, cornerY - 400, 0, 0, SWP_NOSIZE);
|
|
||||||
|
|
||||||
app->m_taskbarCreatedMessage = RegisterWindowMessage("TaskbarCreated");
|
|
||||||
|
|
||||||
// Set up UI
|
|
||||||
LOGFONT lFont = {};
|
|
||||||
strcpy(lFont.lfFaceName, "Consolas");
|
|
||||||
lFont.lfHeight = 35;
|
|
||||||
app->m_lowerFont = CreateFontIndirect(&lFont);
|
|
||||||
|
|
||||||
lFont.lfHeight = 180;
|
|
||||||
lFont.lfWeight = FW_BOLD;
|
|
||||||
app->m_timeFont = CreateFontIndirect(&lFont);
|
|
||||||
|
|
||||||
app->m_greenBrush = CreateSolidBrush(RGB(150, 255, 150));
|
|
||||||
app->m_yellowBrush = CreateSolidBrush(RGB(255, 255, 150));
|
|
||||||
app->m_redBrush = CreateSolidBrush(RGB(255, 150, 150));
|
|
||||||
|
|
||||||
app->m_outlinePen = CreatePen(PS_SOLID, 5, RGB(0, 0, 0));
|
|
||||||
|
|
||||||
// App will update (repaint) at 5 FPS
|
|
||||||
SendMessage(hWnd, WM_UPDATE, NULL, NULL);
|
|
||||||
SetTimer(hWnd, IDT_UPDATE, 200, nullptr);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_DPICHANGED: { // Prevents the window from resizing because of DPI changes
|
|
||||||
RECT* suggestedRECT = reinterpret_cast<RECT*>(lParam);
|
|
||||||
app->sizeWindow(hWnd, suggestedRECT->left, suggestedRECT->top);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_NCHITTEST: { // Allows the window to be moved by dragging from anywhere within it
|
|
||||||
LRESULT result = DefWindowProc(hWnd, msg, wParam, lParam);
|
|
||||||
if (result == HTCLIENT)
|
|
||||||
return HTCAPTION;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_SETCURSOR: { // Allows the cursor to change with the above WM_NCHITTEST code
|
|
||||||
if (LOWORD(lParam) == HTCAPTION)
|
|
||||||
lParam = MAKELPARAM(HTCLIENT, HIWORD(lParam));
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_TRAYICON: {
|
|
||||||
if (LOWORD(lParam) == WM_LBUTTONDOWN ||
|
|
||||||
LOWORD(lParam) == WM_RBUTTONDOWN) {
|
|
||||||
SetForegroundWindow(hWnd);
|
|
||||||
|
|
||||||
POINT cursor = {};
|
|
||||||
GetCursorPos(&cursor);
|
|
||||||
|
|
||||||
HMENU popupMenu = CreatePopupMenu();
|
|
||||||
AppendMenu(popupMenu, MF_STRING, IDM_ABOUT, "About");
|
|
||||||
AppendMenu(popupMenu, MF_STRING, IDM_EXIT, "Exit");
|
|
||||||
|
|
||||||
TrackPopupMenu(popupMenu, NULL, cursor.x, cursor.y, NULL, hWnd, nullptr);
|
|
||||||
|
|
||||||
DestroyMenu(popupMenu);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_COMMAND: {
|
|
||||||
if (HIWORD(wParam) == 0 && LOWORD(wParam) == IDM_ABOUT) {
|
|
||||||
MessageBox(hWnd, std::format("{} {}\nCopyright Grayson Riffe 2026\ngraysonriffe.com\n\n"
|
|
||||||
"\t{} is a simple countdown application\n"
|
|
||||||
"specifically designed for this electronics testing labratory.\n"
|
|
||||||
"Hopefully, it's working!", app->m_appName, app->m_appVersion,
|
|
||||||
app->m_appName).c_str(), std::format("About {}", app->m_appName).c_str(), MB_OK);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (HIWORD(wParam) == 0 && LOWORD(wParam) == IDM_EXIT) {
|
|
||||||
DestroyWindow(hWnd);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_TIMER: {
|
|
||||||
if (wParam == IDT_UPDATE) {
|
|
||||||
SendMessage(hWnd, WM_UPDATE, NULL, NULL);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_UPDATE: {
|
|
||||||
InvalidateRect(hWnd, nullptr, TRUE);
|
|
||||||
UpdateWindow(hWnd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_ERASEBKGND: { // Don't erase the background, it is already done in WM_PAINT
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_PAINT: {
|
|
||||||
PAINTSTRUCT ps = {};
|
|
||||||
HDC hDC = BeginPaint(hWnd, &ps);
|
|
||||||
|
|
||||||
RECT clientRect = {};
|
|
||||||
GetClientRect(hWnd, &clientRect);
|
|
||||||
|
|
||||||
// Create offscreen buffer if not already created
|
|
||||||
if (!app->m_offscreenDC) {
|
|
||||||
app->m_offscreenDC = CreateCompatibleDC(hDC);
|
|
||||||
app->m_offscreenBitmap = CreateCompatibleBitmap(hDC, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup RECTs
|
|
||||||
RECT timeRect = clientRect;
|
|
||||||
timeRect.top -= 25, timeRect.bottom -= 25;
|
|
||||||
|
|
||||||
RECT lowerRect = { .top = WINDOW_HEIGHT - 65, .right = WINDOW_WIDTH, .bottom = WINDOW_HEIGHT };
|
|
||||||
|
|
||||||
HANDLE prevBitmap = SelectObject(app->m_offscreenDC, app->m_offscreenBitmap);
|
|
||||||
|
|
||||||
// Fill background
|
|
||||||
HBRUSH backgroundBrush = nullptr;
|
|
||||||
|
|
||||||
if (!app->m_active)
|
|
||||||
backgroundBrush = app->m_greenBrush;
|
|
||||||
|
|
||||||
else if (app->m_overTime)
|
|
||||||
backgroundBrush = app->m_redBrush;
|
|
||||||
|
|
||||||
else
|
|
||||||
backgroundBrush = app->m_yellowBrush;
|
|
||||||
|
|
||||||
FillRect(app->m_offscreenDC, &clientRect, backgroundBrush);
|
|
||||||
|
|
||||||
// Draw outline
|
|
||||||
SelectObject(app->m_offscreenDC, GetStockObject(NULL_BRUSH));
|
|
||||||
SelectObject(app->m_offscreenDC, app->m_outlinePen);
|
|
||||||
|
|
||||||
RoundRect(app->m_offscreenDC, 1, 1, WINDOW_WIDTH - 2, WINDOW_HEIGHT - 2, 20, 20);
|
|
||||||
|
|
||||||
// Setup text options
|
|
||||||
SetTextColor(app->m_offscreenDC, RGB(0, 0, 0));
|
|
||||||
SetBkMode(app->m_offscreenDC, TRANSPARENT);
|
|
||||||
|
|
||||||
// Calculate time
|
|
||||||
Seconds elapsed = Duration(Clock::now() - app->m_startTime).count();
|
|
||||||
Seconds remaining = app->m_maxMinutes * 60;
|
|
||||||
if (app->m_active)
|
|
||||||
remaining -= elapsed;
|
|
||||||
|
|
||||||
if (!app->m_active || (app->m_active && !app->m_overTime)) { // Draw time
|
|
||||||
SelectObject(app->m_offscreenDC, app->m_timeFont);
|
|
||||||
unsigned int minutes = remaining % (3600) / 60, seconds = remaining % 60;
|
|
||||||
DrawText(app->m_offscreenDC, std::format("{:02}:{:02}", minutes, seconds).c_str(), -1, &timeRect, DT_SINGLELINE | DT_NOCLIP | DT_CENTER | DT_VCENTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!app->m_active) { // Ready (green)
|
|
||||||
SelectObject(app->m_offscreenDC, app->m_lowerFont);
|
|
||||||
DrawText(app->m_offscreenDC, "Ready", -1, &lowerRect, DT_SINGLELINE | DT_NOCLIP | DT_CENTER | DT_VCENTER);
|
|
||||||
}
|
|
||||||
else if (!app->m_overTime) { // Counting (yellow)
|
|
||||||
SelectObject(app->m_offscreenDC, app->m_lowerFont);
|
|
||||||
DrawText(app->m_offscreenDC, "Time Remaining on Tester", -1, &lowerRect, DT_SINGLELINE | DT_NOCLIP | DT_CENTER | DT_VCENTER);
|
|
||||||
}
|
|
||||||
else { // Over time (red)
|
|
||||||
SelectObject(app->m_offscreenDC, app->m_lowerFont);
|
|
||||||
DrawText(app->m_offscreenDC, "Please Eject Your USB", -1, &lowerRect, DT_SINGLELINE | DT_NOCLIP | DT_CENTER | DT_VCENTER);
|
|
||||||
|
|
||||||
if (app->m_paintCounter % 5 > 1) {
|
|
||||||
SelectObject(app->m_offscreenDC, app->m_timeFont);
|
|
||||||
DrawText(app->m_offscreenDC, "STOP", -1, &timeRect, DT_SINGLELINE | DT_NOCLIP | DT_CENTER | DT_VCENTER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (remaining <= 0)
|
|
||||||
app->m_overTime = true;
|
|
||||||
|
|
||||||
BitBlt(hDC, 0, 0, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top, app->m_offscreenDC, 0, 0, SRCCOPY);
|
|
||||||
|
|
||||||
SelectObject(app->m_offscreenDC, prevBitmap);
|
|
||||||
|
|
||||||
EndPaint(hWnd, &ps);
|
|
||||||
app->m_paintCounter++;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_CLOSE: {
|
|
||||||
// Do nothing
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_DESTROY: {
|
|
||||||
PostQuitMessage(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (app && msg == app->m_taskbarCreatedMessage) {
|
|
||||||
app->createTrayIcon();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::sizeWindow(const HWND& hWnd, int newXPos, int newYPos) {
|
|
||||||
RECT clientRect = { .right = WINDOW_WIDTH, .bottom = WINDOW_HEIGHT };
|
|
||||||
AdjustWindowRectExForDpi(&clientRect, WINDOW_STYLE, FALSE, EX_WINDOW_STYLE, GetDpiForWindow(hWnd));
|
|
||||||
SetWindowPos(hWnd, nullptr, newXPos, newYPos, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top, SWP_NOZORDER);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::createTrayIcon() {
|
|
||||||
NOTIFYICONDATA iconData = {};
|
|
||||||
iconData.cbSize = sizeof(iconData);
|
|
||||||
iconData.uVersion = NOTIFYICON_VERSION_4;
|
|
||||||
iconData.hWnd = m_window;
|
|
||||||
iconData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
|
|
||||||
iconData.uCallbackMessage = WM_TRAYICON;
|
|
||||||
iconData.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICONMAIN));
|
|
||||||
strcpy(iconData.szTip, m_appName.c_str());
|
|
||||||
Shell_NotifyIcon(NIM_ADD, &iconData);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::queryThreadFunction() {
|
|
||||||
char buff[100] = {};
|
|
||||||
|
|
||||||
while (m_running) {
|
|
||||||
bool driveDetected = QueryDosDevice(m_drive, buff, 100) > 0;
|
|
||||||
|
|
||||||
if (driveDetected && !m_active) {
|
|
||||||
m_active = true;
|
|
||||||
m_startTime = Clock::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!driveDetected && m_active) {
|
|
||||||
m_active = false;
|
|
||||||
m_overTime = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Application::~Application() {
|
|
||||||
DeleteObject(m_region);
|
|
||||||
|
|
||||||
DeleteObject(m_timeFont);
|
|
||||||
DeleteObject(m_lowerFont);
|
|
||||||
|
|
||||||
DeleteObject(m_greenBrush);
|
|
||||||
DeleteObject(m_yellowBrush);
|
|
||||||
DeleteObject(m_redBrush);
|
|
||||||
|
|
||||||
DeleteObject(m_offscreenBitmap);
|
|
||||||
DeleteDC(m_offscreenDC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
// Application class header
|
|
||||||
|
|
||||||
namespace watchfuleye {
|
|
||||||
class Application {
|
|
||||||
using Clock = std::chrono::high_resolution_clock;
|
|
||||||
using TimePoint = std::chrono::time_point<Clock>;
|
|
||||||
using Duration = std::chrono::duration<double, std::ratio<1, 1>>;
|
|
||||||
using Seconds = int;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Application(const char* appName, const char* appVersion, unsigned int maximumMinutes, const char* driveToDetect);
|
|
||||||
|
|
||||||
void run();
|
|
||||||
|
|
||||||
~Application();
|
|
||||||
private:
|
|
||||||
static LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
||||||
|
|
||||||
void sizeWindow(const HWND& hWnd, int newXPos = 0, int newYPos = 0);
|
|
||||||
|
|
||||||
void createTrayIcon();
|
|
||||||
|
|
||||||
void queryThreadFunction();
|
|
||||||
|
|
||||||
std::string m_appName, m_appVersion;
|
|
||||||
|
|
||||||
HWND m_window;
|
|
||||||
|
|
||||||
bool m_running; // Is the application running?
|
|
||||||
bool m_active; // Is the timer ticking?
|
|
||||||
bool m_overTime; // Are we out of time?
|
|
||||||
|
|
||||||
unsigned int m_maxMinutes;
|
|
||||||
const char* m_drive;
|
|
||||||
|
|
||||||
uint8_t m_paintCounter;
|
|
||||||
|
|
||||||
TimePoint m_startTime;
|
|
||||||
|
|
||||||
UINT m_taskbarCreatedMessage;
|
|
||||||
HRGN m_region;
|
|
||||||
HFONT m_timeFont, m_lowerFont;
|
|
||||||
HBRUSH m_greenBrush, m_yellowBrush, m_redBrush;
|
|
||||||
HPEN m_outlinePen;
|
|
||||||
HDC m_offscreenDC;
|
|
||||||
HBITMAP m_offscreenBitmap;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
// Watchful Eye main file
|
|
||||||
#include "pch.h"
|
|
||||||
|
|
||||||
#include "version.h"
|
|
||||||
#include "Application.h"
|
|
||||||
|
|
||||||
#define APPNAME "Watchful Eye"
|
|
||||||
|
|
||||||
// ======== Configuration ========
|
|
||||||
#define MAX_MINUTES 15
|
|
||||||
#define DRIVE_TO_DETECT "D:"
|
|
||||||
// ===============================
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
|
||||||
|
|
||||||
{
|
|
||||||
watchfuleye::Application app(APPNAME, APPVERSION, MAX_MINUTES, DRIVE_TO_DETECT);
|
|
||||||
app.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
// Watchful Eye precompiled header
|
|
||||||
|
|
||||||
// STD
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include <format>
|
|
||||||
#include <chrono>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
// Windows
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <Windows.h>
|
|
||||||
#include <shellapi.h>
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
//{{NO_DEPENDENCIES}}
|
|
||||||
// Microsoft Visual C++ generated include file.
|
|
||||||
// Used by C:\Users\Grayson\Documents\Visual Studio 18\Solutions\watchful-eye\WatchfulEye\resource.rc
|
|
||||||
//
|
|
||||||
#define IDI_ICONMAIN 101
|
|
||||||
|
|
||||||
// Next default values for new objects
|
|
||||||
//
|
|
||||||
#ifdef APSTUDIO_INVOKED
|
|
||||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
|
||||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
|
||||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
|
||||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
|
||||||
#define _APS_NEXT_SYMED_VALUE 101
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
// Version configured header file
|
|
||||||
#define APPVERSION "@APPVERSION@"
|
|
||||||
Loading…
x
Reference in New Issue
Block a user