From 90c7bc237c9cf964c16f0cb48c308a92a8193a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Ankarstr=C3=B6m?= Date: Fri, 2 Sep 2022 02:11:49 +0200 Subject: Use global Window object. This makes it easier to control initialization and maintain RAII. --- c/main.cpp | 167 +++++++++++++++++++++++++++++-------------------------------- 1 file changed, 78 insertions(+), 89 deletions(-) (limited to 'c/main.cpp') diff --git a/c/main.cpp b/c/main.cpp index 203a24d..58c0441 100644 --- a/c/main.cpp +++ b/c/main.cpp @@ -9,6 +9,7 @@ #include "datalistview.h" #include "episodelistview.h" #include "layout.h" +#include "main.h" #include "test.h" #include "util.h" @@ -24,56 +25,37 @@ * program. `extern' is used to access them from other files, when * need be. */ -/* Exit gracefully on uncaught exception. */ -static auto _ = SET_TERMINATE; - /* Looked-up constants. */ int g_dpi = 96; -/* Cursors. */ -HCURSOR g_hcArrow = LoadCursorW(nullptr, IDC_ARROW); -HCURSOR g_hcSizeNs = LoadCursorW(nullptr, IDC_SIZENS); - /* Fonts. */ HFONT g_hfNormal; HFONT g_hfBold; +/* Cursors. */ +HCURSOR g_hcArrow = LoadCursorW(nullptr, IDC_ARROW); +HCURSOR g_hcSizeNs = LoadCursorW(nullptr, IDC_SIZENS); + /* Menus. */ HMENU g_hMenuPopup; /* Windows. */ HWND g_hWndFocus; -HWND g_hWnd; HWND g_hWndStatus; -/* Child window objects. */ -DataListView* g_dlv; -EpisodeListView* g_elv; - -/* Layout handlers. */ -DlvDragger g_dragDlv; - -/* File views. */ -FileView g_fvCfg = FileView::Initialized(L"cfg.dat", 1); -CfgA& g_cfg = g_fvCfg.At(0); -FileView g_fvElv(L"elvdata.dat", g_cfg.cEp+128u); -FileView g_fvDlv(L"dlvdata.dat", g_cfg.cEp+128u); - /* Optional Windows functions. */ BOOL (__stdcall *IsThemeActive)(); HRESULT (__stdcall *SetWindowTheme)(HWND, const wchar_t*, const wchar_t*); +/* Main window object. */ +Window* g_window; + /* Initialize important global state on parent window creation. */ -static void InitializeMainWindow(HWND); +static void InitializeMainWindow(HWND) noexcept; /* Process parent window commands. */ static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); -static LRESULT CALLBACK HandleMsg(HWND, UINT, WPARAM, LPARAM); -/* Process main menu commands. */ -static void HandleMainMenu(HWND, WORD); /* Handle messages to Help > About dialog. */ -static INT_PTR CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM); -/* Try to style application according to current Windows theme. */ -static void UpdateTheme(); +INT_PTR CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain( _In_ const HINSTANCE hInstance, @@ -81,6 +63,9 @@ int WINAPI WinMain( _In_ char* const, _In_ const int nCmdShow) { + /* Exit gracefully on uncaught exception. */ + SET_TERMINATE; + setbuf(stdout, nullptr); LIBXML_TEST_VERSION; @@ -126,8 +111,8 @@ int WINAPI WinMain( /* Populate episode list view. */ /* TODO: Update tracked episodes. */ - g_elv->Update(); - g_elv->RestoreFocus(); + g_window->elv.Update(); + g_window->elv.RestoreFocus(); #ifdef _DEBUG RunTests(); @@ -143,7 +128,7 @@ int WINAPI WinMain( return 0; } -void InitializeMainWindow(const HWND hWnd) +static void InitializeMainWindow_(const HWND hWnd) { /* This code is run ONCE, at the creation of the top-level * window -- before WndProc! This is important, as it @@ -186,37 +171,58 @@ void InitializeMainWindow(const HWND hWnd) g_hMenuPopup = Require(LoadMenuW(nullptr, MAKEINTRESOURCE(IDR_POPUPMENU))); g_hMenuPopup = Require(GetSubMenu(g_hMenuPopup, 0)); - /* Create child windows. */ - g_dlv = new DataListView(hWnd); - g_elv = new EpisodeListView(hWnd); + g_window = new Window(hWnd); +} - /* The global main window handle must only be set AFTER - * successful initialization. */ - g_hWnd = hWnd; +void InitializeMainWindow(const HWND hWnd) noexcept +{ + try { + InitializeMainWindow_(hWnd); + } catch (...) { + ShowException(L"Initialization failed due to an error: %s"); + exit(1); + } } LRESULT CALLBACK WndProc(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam) { try { - return HandleMsg(hWnd, uMsg, wParam, lParam); + return g_window->WndProc(hWnd, uMsg, wParam, lParam); } catch (...) { ShowException(L"The action was cancelled due to an error: %s"); } return DefWindowProc(hWnd, uMsg, wParam, lParam); } -LRESULT CALLBACK HandleMsg(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam) +INT_PTR CALLBACK AboutDlgProc(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM) +{ + switch (uMsg) { + case WM_CLOSE: + EndDialog(hWnd, IDOK); + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + EndDialog(hWnd, IDOK); + return TRUE; + + default: + return FALSE; + } +} + +LRESULT CALLBACK Window::WndProc(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam) { switch (uMsg) { case WM_CREATE: UpdateTheme(); SetWindowPos(hWnd, nullptr, -1, -1, Dpi(510), Dpi(412), SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE); - SetFocus(g_elv->hWnd); + SetFocus(elv.hWnd); /* Set menu item checkmarks according to saved settings. */ - CheckMenuItem(GetMenu(hWnd), IDM_VIEW_WATCHED, g_cfg.bViewWatched? MF_CHECKED: MF_UNCHECKED); - CheckMenuItem(GetMenu(hWnd), IDM_VIEW_TV_ORIGINAL, g_cfg.bViewTVOriginal? MF_CHECKED: MF_UNCHECKED); - CheckMenuItem(GetMenu(hWnd), IDM_VIEW_OTHERS, g_cfg.limitToScreenwriter[0]? MF_UNCHECKED: MF_CHECKED); + CheckMenuItem(GetMenu(hWnd), IDM_VIEW_WATCHED, cfg.bViewWatched? MF_CHECKED: MF_UNCHECKED); + CheckMenuItem(GetMenu(hWnd), IDM_VIEW_TV_ORIGINAL, cfg.bViewTVOriginal? MF_CHECKED: MF_UNCHECKED); + CheckMenuItem(GetMenu(hWnd), IDM_VIEW_OTHERS, cfg.limitToScreenwriter[0]? MF_UNCHECKED: MF_CHECKED); return 0; case WM_CLOSE: @@ -224,7 +230,7 @@ LRESULT CALLBACK HandleMsg(const HWND hWnd, const UINT uMsg, const WPARAM wParam return 0; case WM_DESTROY: - g_elv->SaveFocus(); + elv.SaveFocus(); PostQuitMessage(0); return 0; @@ -270,14 +276,14 @@ LRESULT CALLBACK HandleMsg(const HWND hWnd, const UINT uMsg, const WPARAM wParam else { SetFocus(g_hWndFocus); /* TODO: Update tracked episodes. */ - g_elv->Redraw(); + elv.Redraw(); } return 0; case WM_NOTIFY: switch (reinterpret_cast(lParam)->idFrom) { case IDC_EPISODELISTVIEW: - return g_elv->HandleNotify(lParam); + return elv.HandleNotify(lParam); } return 0; @@ -289,7 +295,7 @@ LRESULT CALLBACK HandleMsg(const HWND hWnd, const UINT uMsg, const WPARAM wParam HandleMainMenu(hWnd, command); return 0; case IDG_CTX: - g_elv->HandleContextMenu(command); + elv.HandleContextMenu(command); return 0; default: return 0; @@ -309,13 +315,13 @@ LRESULT CALLBACK HandleMsg(const HWND hWnd, const UINT uMsg, const WPARAM wParam /*IDM_FILE_FETCH_SCREENWRITERS*/L"Fetch screenwriters from the web (may take a minute).", /*IDM_FILE_FETCH_CANCEL*/L"Stop fetching data from the web.", /*IDM_FILE_ABOUT*/L"Show information about Episode Browser.", - /*IDM_VIEW_WATCHED*/(g_cfg.bViewWatched? + /*IDM_VIEW_WATCHED*/(cfg.bViewWatched? L"Click to hide watched episodes.": L"Click to show watched episodes."), - /*IDM_VIEW_TV_ORIGINAL*/(g_cfg.bViewTVOriginal? + /*IDM_VIEW_TV_ORIGINAL*/(cfg.bViewTVOriginal? L"Click to hide TV original episodes.": L"Click to show TV original episodes."), - /*IDM_VIEW_OTHERS*/(g_cfg.limitToScreenwriter? + /*IDM_VIEW_OTHERS*/(cfg.limitToScreenwriter? L"Click to hide episodes by other screenwriters.": L"Click to show episodes by other screenwriters.") }; @@ -349,11 +355,11 @@ LRESULT CALLBACK HandleMsg(const HWND hWnd, const UINT uMsg, const WPARAM wParam } case WM_LBUTTONDOWN: - g_dragDlv.HandleLButtonDown(); + dragDlv.HandleLButtonDown(); return 0; case WM_SETCURSOR: - if (g_dragDlv.HandleSetCursor()) + if (dragDlv.HandleSetCursor()) return 1; else { /* Use default cursor. */ @@ -368,7 +374,7 @@ LRESULT CALLBACK HandleMsg(const HWND hWnd, const UINT uMsg, const WPARAM wParam } } -void HandleMainMenu(const HWND hWnd, const WORD command) +void Window::HandleMainMenu(const HWND hWnd, const WORD command) { switch (command) { case IDM_FILE_EXIT: @@ -376,7 +382,7 @@ void HandleMainMenu(const HWND hWnd, const WORD command) break; case IDM_FILE_REFRESH: - g_elv->Update(); + elv.Update(); break; case IDM_FILE_FETCH_DATA: @@ -402,61 +408,44 @@ void HandleMainMenu(const HWND hWnd, const WORD command) break; case IDM_VIEW_WATCHED: - CheckMenuItem(GetMenu(hWnd), IDM_VIEW_WATCHED, g_cfg.bViewWatched? MF_UNCHECKED: MF_CHECKED); - g_cfg.bViewWatched = !g_cfg.bViewWatched; - g_elv->Update(); - g_elv->EnsureFocusVisible(); + CheckMenuItem(GetMenu(hWnd), IDM_VIEW_WATCHED, cfg.bViewWatched? MF_UNCHECKED: MF_CHECKED); + cfg.bViewWatched = !cfg.bViewWatched; + elv.Update(); + elv.EnsureFocusVisible(); /* TODO: Remember last valid focus. In case of * non-existing focus, use the last valid focus. */ break; case IDM_VIEW_TV_ORIGINAL: - CheckMenuItem(GetMenu(hWnd), IDM_VIEW_TV_ORIGINAL, g_cfg.bViewTVOriginal? MF_UNCHECKED: MF_CHECKED); - g_cfg.bViewTVOriginal = !g_cfg.bViewTVOriginal; - g_elv->Update(); - g_elv->EnsureFocusVisible(); + CheckMenuItem(GetMenu(hWnd), IDM_VIEW_TV_ORIGINAL, cfg.bViewTVOriginal? MF_UNCHECKED: MF_CHECKED); + cfg.bViewTVOriginal = !cfg.bViewTVOriginal; + elv.Update(); + elv.EnsureFocusVisible(); break; case IDM_VIEW_OTHERS: - if (g_cfg.limitToScreenwriter[0]) { /* Show episodes by all screenwriters. */ + if (cfg.limitToScreenwriter[0]) { /* Show episodes by all screenwriters. */ CheckMenuItem(GetMenu(hWnd), IDM_VIEW_OTHERS, MF_CHECKED); - g_cfg.limitToScreenwriter[0] = 0; + cfg.limitToScreenwriter[0] = 0; } else { /* Hide episodes by other screenwriters than current. */ LVITEM lvi = {LVIF_PARAM, -1}; - if (g_elv->FindNextItem(&lvi, LVNI_FOCUSED) - && g_fvDlv.At(lvi.lParam-1).screenwriter[0]) { - Wcscpy(g_cfg.limitToScreenwriter, g_fvDlv.At(lvi.lParam-1).screenwriter); + if (elv.FindNextItem(&lvi, LVNI_FOCUSED) + && fvDlv.At(lvi.lParam-1).screenwriter[0]) { + Wcscpy(cfg.limitToScreenwriter, fvDlv.At(lvi.lParam-1).screenwriter); CheckMenuItem(GetMenu(hWnd), IDM_VIEW_OTHERS, MF_UNCHECKED); } } - g_elv->Update(); - g_elv->EnsureFocusVisible(); + elv.Update(); + elv.EnsureFocusVisible(); break; } } -INT_PTR CALLBACK AboutDlgProc(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM) -{ - switch (uMsg) { - case WM_CLOSE: - EndDialog(hWnd, IDOK); - return TRUE; - - case WM_COMMAND: - if (LOWORD(wParam) == IDOK) - EndDialog(hWnd, IDOK); - return TRUE; - - default: - return FALSE; - } -} - -void UpdateTheme() +void Window::UpdateTheme() { if (IsThemeActive) { const bool bThemeActive = IsThemeActive(); - g_dlv->UpdateTheme(bThemeActive); - g_elv->UpdateTheme(bThemeActive); + dlv.UpdateTheme(bThemeActive); + elv.UpdateTheme(bThemeActive); } } -- cgit v1.2.3