xW: add missing date change handling
This commit is contained in:
parent
100de5ac2d
commit
81bc578773
125
xW/xW.cpp
125
xW/xW.cpp
|
@ -100,6 +100,7 @@ struct {
|
||||||
HWND hwndInput; ///< edit: user input
|
HWND hwndInput; ///< edit: user input
|
||||||
|
|
||||||
HWND hwndLastFocused; ///< For Alt+Tab, e.g.
|
HWND hwndLastFocused; ///< For Alt+Tab, e.g.
|
||||||
|
HANDLE date_change_timer; ///< Waitable timer for day changes
|
||||||
|
|
||||||
HICON hicon; ///< Normal program icon
|
HICON hicon; ///< Normal program icon
|
||||||
HICON hiconHighlighted; ///< Highlighted program icon
|
HICON hiconHighlighted; ///< Highlighted program icon
|
||||||
|
@ -402,8 +403,7 @@ refresh_status()
|
||||||
status += L"🡇 ";
|
status += L"🡇 ";
|
||||||
|
|
||||||
status += g.buffer_current;
|
status += g.buffer_current;
|
||||||
auto b = buffer_by_name(g.buffer_current);
|
if (auto b = buffer_by_name(g.buffer_current)) {
|
||||||
if (b) {
|
|
||||||
if (!b->modes.empty())
|
if (!b->modes.empty())
|
||||||
status += L"(+" + b->modes + L")";
|
status += L"(+" + b->modes + L")";
|
||||||
if (b->hide_unimportant)
|
if (b->hide_unimportant)
|
||||||
|
@ -542,39 +542,81 @@ convert_buffer_line(Relay::EventData_BufferLine &line)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
buffer_print_line(std::vector<BufferLine>::const_iterator begin,
|
buffer_print_date_change(bool &sameline, const tm &last, const tm ¤t)
|
||||||
std::vector<BufferLine>::const_iterator line)
|
|
||||||
{
|
{
|
||||||
CHARRANGE cr = {};
|
if (last.tm_year == current.tm_year &&
|
||||||
cr.cpMin = cr.cpMax = GetWindowTextLength(g.hwndBuffer);
|
last.tm_mon == current.tm_mon &&
|
||||||
SendMessage(g.hwndBuffer, EM_EXSETSEL, 0, (LPARAM) &cr);
|
last.tm_mday == current.tm_mday)
|
||||||
|
return;
|
||||||
|
|
||||||
// The Rich Edit control makes the window cursor transparent
|
|
||||||
// each time you add an independent newline character. Avoid that.
|
|
||||||
// (Sadly, this also makes Windows 7 end lines with a bogus space that
|
|
||||||
// has the CHARFORMAT2 of what we flush that newline together with.)
|
|
||||||
bool sameline = !cr.cpMin;
|
|
||||||
|
|
||||||
time_t current_unix = line->when / 1000;
|
|
||||||
time_t last_unix = (line != begin)
|
|
||||||
? (line - 1)->when / 1000
|
|
||||||
: time(NULL);
|
|
||||||
|
|
||||||
tm current = {}, last = {};
|
|
||||||
(void) localtime_s(¤t, ¤t_unix);
|
|
||||||
(void) localtime_s(&last, &last_unix);
|
|
||||||
if (last.tm_year != current.tm_year ||
|
|
||||||
last.tm_mon != current.tm_mon ||
|
|
||||||
last.tm_mday != current.tm_mday) {
|
|
||||||
wchar_t buffer[64] = {};
|
wchar_t buffer[64] = {};
|
||||||
wcsftime(buffer, sizeof buffer, &L"\n%x\n"[sameline], ¤t);
|
wcsftime(buffer, sizeof buffer, &L"\n%x"[sameline], ¤t);
|
||||||
sameline = true;
|
sameline = false;
|
||||||
|
|
||||||
CHARFORMAT2 cf = default_charformat();
|
CHARFORMAT2 cf = default_charformat();
|
||||||
cf.dwEffects |= CFE_BOLD;
|
cf.dwEffects |= CFE_BOLD;
|
||||||
richedit_replacesel(g.hwndBuffer, &cf, buffer);
|
richedit_replacesel(g.hwndBuffer, &cf, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
buffer_reset_selection()
|
||||||
{
|
{
|
||||||
|
CHARRANGE cr = {};
|
||||||
|
cr.cpMin = cr.cpMax = GetWindowTextLength(g.hwndBuffer);
|
||||||
|
SendMessage(g.hwndBuffer, EM_EXSETSEL, 0, (LPARAM) &cr);
|
||||||
|
return cr.cpMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct tm
|
||||||
|
buffer_localtime(time_t time)
|
||||||
|
{
|
||||||
|
// This isn't critical, so let it fail quietly.
|
||||||
|
struct tm result = {};
|
||||||
|
(void) localtime_s(&result, &time);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
buffer_print_and_watch_trailing_date_changes()
|
||||||
|
{
|
||||||
|
time_t current_unix = time(NULL);
|
||||||
|
tm current = buffer_localtime(current_unix);
|
||||||
|
auto b = buffer_by_name(g.buffer_current);
|
||||||
|
if (b && !b->lines.empty()) {
|
||||||
|
tm last = buffer_localtime(b->lines.back().when / 1000);
|
||||||
|
bool sameline = !buffer_reset_selection();
|
||||||
|
buffer_print_date_change(sameline, last, current);
|
||||||
|
}
|
||||||
|
|
||||||
|
current.tm_sec = current.tm_min = current.tm_hour = 0;
|
||||||
|
current.tm_mday++;
|
||||||
|
current.tm_isdst = -1;
|
||||||
|
const time_t midnight = mktime(¤t);
|
||||||
|
if (midnight == (time_t) -1 || midnight < current_unix)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Note that after printing the first trailing update,
|
||||||
|
// follow-up updates may be duplicated if timer events arrive too early.
|
||||||
|
LARGE_INTEGER li = {};
|
||||||
|
li.QuadPart = (midnight - current_unix + 1) * -10000000LL;
|
||||||
|
SetWaitableTimer(g.date_change_timer, &li, 0, NULL, NULL, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
buffer_print_line(std::vector<BufferLine>::const_iterator begin,
|
||||||
|
std::vector<BufferLine>::const_iterator line)
|
||||||
|
{
|
||||||
|
tm current = buffer_localtime(line->when / 1000);
|
||||||
|
tm last = buffer_localtime(
|
||||||
|
line == begin ? time(NULL) : (line - 1)->when / 1000);
|
||||||
|
|
||||||
|
// The Rich Edit control makes the window cursor transparent
|
||||||
|
// each time you add an independent newline character. Avoid that.
|
||||||
|
// (Sadly, this also makes Windows 7 end lines with a bogus space that
|
||||||
|
// has the CHARFORMAT2 of what we flush that newline together with.)
|
||||||
|
bool sameline = !buffer_reset_selection();
|
||||||
|
buffer_print_date_change(sameline, last, current);
|
||||||
|
|
||||||
wchar_t buffer[64] = {};
|
wchar_t buffer[64] = {};
|
||||||
wcsftime(buffer, sizeof buffer, &L"\n%H:%M:%S"[sameline], ¤t);
|
wcsftime(buffer, sizeof buffer, &L"\n%H:%M:%S"[sameline], ¤t);
|
||||||
|
|
||||||
|
@ -585,7 +627,6 @@ buffer_print_line(std::vector<BufferLine>::const_iterator begin,
|
||||||
richedit_replacesel(g.hwndBuffer, &cf, buffer);
|
richedit_replacesel(g.hwndBuffer, &cf, buffer);
|
||||||
cf = default_charformat();
|
cf = default_charformat();
|
||||||
richedit_replacesel(g.hwndBuffer, &cf, L" ");
|
richedit_replacesel(g.hwndBuffer, &cf, L" ");
|
||||||
}
|
|
||||||
|
|
||||||
// Tabstops won't quite help us here, since we need it centred.
|
// Tabstops won't quite help us here, since we need it centred.
|
||||||
std::wstring prefix;
|
std::wstring prefix;
|
||||||
|
@ -673,6 +714,7 @@ refresh_buffer(const Buffer &b)
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buffer_print_and_watch_trailing_date_changes();
|
||||||
buffer_scroll_to_bottom();
|
buffer_scroll_to_bottom();
|
||||||
|
|
||||||
SendMessage(g.hwndBuffer, WM_SETREDRAW, (WPARAM) TRUE, 0);
|
SendMessage(g.hwndBuffer, WM_SETREDRAW, (WPARAM) TRUE, 0);
|
||||||
|
@ -1580,6 +1622,11 @@ window_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
case WM_SIZE:
|
case WM_SIZE:
|
||||||
process_resize(LOWORD(lParam), HIWORD(lParam));
|
process_resize(LOWORD(lParam), HIWORD(lParam));
|
||||||
return 0;
|
return 0;
|
||||||
|
case WM_TIMECHANGE:
|
||||||
|
_tzset();
|
||||||
|
if (auto b = buffer_by_name(g.buffer_current))
|
||||||
|
refresh_buffer(*b);
|
||||||
|
return 0;
|
||||||
case WM_ACTIVATE:
|
case WM_ACTIVATE:
|
||||||
if (LOWORD(wParam) == WA_INACTIVE)
|
if (LOWORD(wParam) == WA_INACTIVE)
|
||||||
g.hwndLastFocused = GetFocus();
|
g.hwndLastFocused = GetFocus();
|
||||||
|
@ -1847,20 +1894,38 @@ wWinMain(HINSTANCE hInstance, [[maybe_unused]] HINSTANCE hPrevInstance,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g.date_change_timer = CreateWaitableTimer(NULL, FALSE, NULL);
|
||||||
|
if (!g.date_change_timer) {
|
||||||
|
show_error_message(format_error_message(GetLastError()).c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
while (process_messages(accelerators)) {
|
while (process_messages(accelerators)) {
|
||||||
|
HANDLE handles[] = {g.date_change_timer, g.event};
|
||||||
|
DWORD count = 2 - !handles[1];
|
||||||
DWORD result = MsgWaitForMultipleObjects(
|
DWORD result = MsgWaitForMultipleObjects(
|
||||||
g.event != NULL, &g.event, FALSE, INFINITE, QS_ALLINPUT);
|
count, handles, FALSE, INFINITE, QS_ALLINPUT);
|
||||||
if (result == WAIT_FAILED) {
|
if (result == WAIT_FAILED) {
|
||||||
show_error_message(format_error_message(GetLastError()).c_str());
|
show_error_message(format_error_message(GetLastError()).c_str());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (g.event != NULL && result == WAIT_OBJECT_0 &&
|
if (result >= WAIT_OBJECT_0 + count)
|
||||||
!relay_process_socket_events(error)) {
|
continue;
|
||||||
|
|
||||||
|
auto signalled = handles[result];
|
||||||
|
if (signalled == g.date_change_timer) {
|
||||||
|
bool to_bottom = buffer_at_bottom();
|
||||||
|
buffer_print_and_watch_trailing_date_changes();
|
||||||
|
if (to_bottom)
|
||||||
|
buffer_scroll_to_bottom();
|
||||||
|
}
|
||||||
|
if (signalled == g.event && !relay_process_socket_events(error)) {
|
||||||
show_error_message(error.c_str());
|
show_error_message(error.c_str());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FreeAddrInfo(g.addresses);
|
FreeAddrInfo(g.addresses);
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
|
CloseHandle(g.date_change_timer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue