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 hwndLastFocused; ///< For Alt+Tab, e.g.
|
||||
HANDLE date_change_timer; ///< Waitable timer for day changes
|
||||
|
||||
HICON hicon; ///< Normal program icon
|
||||
HICON hiconHighlighted; ///< Highlighted program icon
|
||||
|
@ -402,8 +403,7 @@ refresh_status()
|
|||
status += L"🡇 ";
|
||||
|
||||
status += g.buffer_current;
|
||||
auto b = buffer_by_name(g.buffer_current);
|
||||
if (b) {
|
||||
if (auto b = buffer_by_name(g.buffer_current)) {
|
||||
if (!b->modes.empty())
|
||||
status += L"(+" + b->modes + L")";
|
||||
if (b->hide_unimportant)
|
||||
|
@ -542,39 +542,81 @@ convert_buffer_line(Relay::EventData_BufferLine &line)
|
|||
}
|
||||
|
||||
static void
|
||||
buffer_print_line(std::vector<BufferLine>::const_iterator begin,
|
||||
std::vector<BufferLine>::const_iterator line)
|
||||
buffer_print_date_change(bool &sameline, const tm &last, const tm ¤t)
|
||||
{
|
||||
CHARRANGE cr = {};
|
||||
cr.cpMin = cr.cpMax = GetWindowTextLength(g.hwndBuffer);
|
||||
SendMessage(g.hwndBuffer, EM_EXSETSEL, 0, (LPARAM) &cr);
|
||||
if (last.tm_year == current.tm_year &&
|
||||
last.tm_mon == current.tm_mon &&
|
||||
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] = {};
|
||||
wcsftime(buffer, sizeof buffer, &L"\n%x\n"[sameline], ¤t);
|
||||
sameline = true;
|
||||
wcsftime(buffer, sizeof buffer, &L"\n%x"[sameline], ¤t);
|
||||
sameline = false;
|
||||
|
||||
CHARFORMAT2 cf = default_charformat();
|
||||
cf.dwEffects |= CFE_BOLD;
|
||||
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] = {};
|
||||
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);
|
||||
cf = default_charformat();
|
||||
richedit_replacesel(g.hwndBuffer, &cf, L" ");
|
||||
}
|
||||
|
||||
// Tabstops won't quite help us here, since we need it centred.
|
||||
std::wstring prefix;
|
||||
|
@ -673,6 +714,7 @@ refresh_buffer(const Buffer &b)
|
|||
i++;
|
||||
}
|
||||
|
||||
buffer_print_and_watch_trailing_date_changes();
|
||||
buffer_scroll_to_bottom();
|
||||
|
||||
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:
|
||||
process_resize(LOWORD(lParam), HIWORD(lParam));
|
||||
return 0;
|
||||
case WM_TIMECHANGE:
|
||||
_tzset();
|
||||
if (auto b = buffer_by_name(g.buffer_current))
|
||||
refresh_buffer(*b);
|
||||
return 0;
|
||||
case WM_ACTIVATE:
|
||||
if (LOWORD(wParam) == WA_INACTIVE)
|
||||
g.hwndLastFocused = GetFocus();
|
||||
|
@ -1847,20 +1894,38 @@ wWinMain(HINSTANCE hInstance, [[maybe_unused]] HINSTANCE hPrevInstance,
|
|||
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)) {
|
||||
HANDLE handles[] = {g.date_change_timer, g.event};
|
||||
DWORD count = 2 - !handles[1];
|
||||
DWORD result = MsgWaitForMultipleObjects(
|
||||
g.event != NULL, &g.event, FALSE, INFINITE, QS_ALLINPUT);
|
||||
count, handles, FALSE, INFINITE, QS_ALLINPUT);
|
||||
if (result == WAIT_FAILED) {
|
||||
show_error_message(format_error_message(GetLastError()).c_str());
|
||||
return 1;
|
||||
}
|
||||
if (g.event != NULL && result == WAIT_OBJECT_0 &&
|
||||
!relay_process_socket_events(error)) {
|
||||
if (result >= WAIT_OBJECT_0 + count)
|
||||
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());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
FreeAddrInfo(g.addresses);
|
||||
WSACleanup();
|
||||
CloseHandle(g.date_change_timer);
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue