diff options
-rw-r--r-- | xA/xA.go | 148 | ||||
-rw-r--r-- | xW/xW.cpp | 175 |
2 files changed, 182 insertions, 141 deletions
@@ -363,16 +363,18 @@ func bufferByName(name string) *buffer { return nil } -func bufferActivate(name string) { - relaySend(RelayCommandData{ - Variant: &RelayCommandDataBufferActivate{BufferName: name}, - }, nil) +func bufferAtBottom() bool { + return wRichScroll.Offset.Y >= + wRichScroll.Content.Size().Height-wRichScroll.Size().Height } -func bufferToggleUnimportant(name string) { - relaySend(RelayCommandData{ - Variant: &RelayCommandDataBufferToggleUnimportant{BufferName: name}, - }, nil) +func bufferScrollToBottom() { + // XXX: Doing it once is not reliable, something's amiss. + // (In particular, nothing happens when we switch from an empty buffer + // to a buffer than needs scrolling.) + wRichScroll.ScrollToBottom() + wRichScroll.ScrollToBottom() + refreshStatus() } func bufferPushLine(b *buffer, line bufferLine) { @@ -386,68 +388,20 @@ func bufferPushLine(b *buffer, line bufferLine) { } } -// --- Current buffer ---------------------------------------------------------- - -func bufferToggleLogFinish(err string, response *RelayResponseDataBufferLog) { - if response == nil { - showErrorMessage(err) - return - } - - wLog.SetText(string(response.Log)) - wLog.Show() - wRichScroll.Hide() -} - -func bufferToggleLog() { - if wLog.Visible() { - wRichScroll.Show() - wLog.Hide() - wLog.SetText("") - return - } - - name := bufferCurrent - relaySend(RelayCommandData{Variant: &RelayCommandDataBufferLog{ - BufferName: name, - }}, func(err string, response *RelayResponseData) { - if bufferCurrent == name { - bufferToggleLogFinish( - err, response.Variant.(*RelayResponseDataBufferLog)) - } - }) -} - -func bufferAtBottom() bool { - return wRichScroll.Offset.Y >= - wRichScroll.Content.Size().Height-wRichScroll.Size().Height -} - -func bufferScrollToBottom() { - // XXX: Doing it once is not reliable, something's amiss. - // (In particular, nothing happens when we switch from an empty buffer - // to a buffer than needs scrolling.) - wRichScroll.ScrollToBottom() - wRichScroll.ScrollToBottom() - refreshStatus() -} - // --- UI state refresh -------------------------------------------------------- func refreshIcon() { - highlighted := false + resource := resourceIconNormal for _, b := range buffers { if b.highlighted { - highlighted = true + resource = resourceIconHighlighted break } } - if highlighted { - wWindow.SetIcon(resourceIconHighlighted) - } else { - wWindow.SetIcon(resourceIconNormal) - } + // Prevent deadlocks (though it might have a race condition). + // https://github.com/fyne-io/fyne/issues/5266 + go func() { wWindow.SetIcon(resource) }() } func refreshTopic(topic []bufferLineItem) { @@ -515,6 +469,63 @@ func refreshStatus() { wStatus.SetText(status) } +func recheckHighlighted() { + // Corresponds to the logic toggling the bool on. + if b := bufferByName(bufferCurrent); b != nil && + b.highlighted && bufferAtBottom() && + inForeground && !wLog.Visible() { + b.highlighted = false + refreshIcon() + refreshBufferList() + } +} + +// --- Buffer actions ---------------------------------------------------------- + +func bufferActivate(name string) { + relaySend(RelayCommandData{ + Variant: &RelayCommandDataBufferActivate{BufferName: name}, + }, nil) +} + +func bufferToggleUnimportant(name string) { + relaySend(RelayCommandData{ + Variant: &RelayCommandDataBufferToggleUnimportant{BufferName: name}, + }, nil) +} + +func bufferToggleLogFinish(err string, response *RelayResponseDataBufferLog) { + if response == nil { + showErrorMessage(err) + return + } + + wLog.SetText(string(response.Log)) + wLog.Show() + wRichScroll.Hide() +} + +func bufferToggleLog() { + if wLog.Visible() { + wRichScroll.Show() + wLog.Hide() + wLog.SetText("") + + recheckHighlighted() + return + } + + name := bufferCurrent + relaySend(RelayCommandData{Variant: &RelayCommandDataBufferLog{ + BufferName: name, + }}, func(err string, response *RelayResponseData) { + if bufferCurrent == name { + bufferToggleLogFinish( + err, response.Variant.(*RelayResponseDataBufferLog)) + } + }) +} + // --- RichText formatting ----------------------------------------------------- func defaultBufferLineItem() bufferLineItem { return bufferLineItem{} } @@ -756,6 +767,7 @@ func refreshBuffer(b *buffer) { bufferPrintAndWatchTrailingDateChanges() wRichText.Refresh() bufferScrollToBottom() + recheckHighlighted() } // --- Event processing -------------------------------------------------------- @@ -1374,6 +1386,9 @@ func (l *customLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) { } if toBottom { bufferScrollToBottom() + } else { + recheckHighlighted() + refreshStatus() } } @@ -1497,11 +1512,7 @@ func main() { a.Lifecycle().SetOnEnteredForeground(func() { // TODO(p): Does this need locking? inForeground = true - if b := bufferByName(bufferCurrent); b != nil { - b.highlighted = false - refreshIcon() - refreshBufferList() - } + recheckHighlighted() }) a.Lifecycle().SetOnExitedForeground(func() { inForeground = false @@ -1542,7 +1553,10 @@ func main() { wRichText = widget.NewRichText() wRichText.Wrapping = fyne.TextWrapWord wRichScroll = container.NewVScroll(wRichText) - wRichScroll.OnScrolled = func(position fyne.Position) { refreshStatus() } + wRichScroll.OnScrolled = func(position fyne.Position) { + recheckHighlighted() + refreshStatus() + } wLog = newLogEntry() wLog.Wrapping = fyne.TextWrapWord wLog.Hide() @@ -255,73 +255,6 @@ buffer_by_name(const std::wstring &name) return nullptr; } -static void -buffer_activate(const std::wstring &name) -{ - auto activate = new Relay::CommandData_BufferActivate(); - activate->buffer_name = name; - relay_send(activate); -} - -static void -buffer_toggle_unimportant(const std::wstring &name) -{ - auto toggle = new Relay::CommandData_BufferToggleUnimportant(); - toggle->buffer_name = name; - relay_send(toggle); -} - -// --- Current buffer ---------------------------------------------------------- - -static void -buffer_toggle_log( - const std::wstring &error, const Relay::ResponseData_BufferLog *response) -{ - if (!response) { - show_error_message(error.c_str()); - return; - } - - std::wstring log; - if (!LibertyXDR::utf8_to_wstring( - response->log.data(), response->log.size(), log)) { - show_error_message(L"Invalid encoding."); - return; - } - - std::wstring filtered; - for (auto wch : log) { - if (wch == L'\n') - filtered += L"\r\n"; - else - filtered += wch; - } - - SetWindowText(g.hwndBufferLog, filtered.c_str()); - ShowWindow(g.hwndBuffer, SW_HIDE); - ShowWindow(g.hwndBufferLog, SW_SHOW); -} - -static void -buffer_toggle_log() -{ - if (IsWindowVisible(g.hwndBufferLog)) { - ShowWindow(g.hwndBufferLog, SW_HIDE); - ShowWindow(g.hwndBuffer, SW_SHOW); - SetWindowText(g.hwndBufferLog, L""); - return; - } - - auto log = new Relay::CommandData_BufferLog(); - log->buffer_name = g.buffer_current; - relay_send(log, [name = g.buffer_current](auto error, auto response) { - if (g.buffer_current != name) - return; - buffer_toggle_log(error, - dynamic_cast<const Relay::ResponseData_BufferLog *>(response)); - }); -} - static bool buffer_at_bottom() { @@ -354,6 +287,7 @@ refresh_icon() if (b.highlighted) icon = g.hiconHighlighted; + // XXX: This may not change the taskbar icon. SendMessage(g.hwndMain, WM_SETICON, ICON_SMALL, (LPARAM) icon); SendMessage(g.hwndMain, WM_SETICON, ICON_BIG, (LPARAM) icon); } @@ -430,6 +364,88 @@ refresh_status() SetWindowText(g.hwndStatus, status.c_str()); } +static void +recheck_highlighted() +{ + // Corresponds to the logic toggling the bool on. + auto b = buffer_by_name(g.buffer_current); + if (b && b->highlighted && buffer_at_bottom() && + !IsIconic(g.hwndMain) && !IsWindowVisible(g.hwndBufferLog)) { + b->highlighted = false; + refresh_icon(); + refresh_buffer_list(); + } +} + +// --- Buffer actions ---------------------------------------------------------- + +static void +buffer_activate(const std::wstring &name) +{ + auto activate = new Relay::CommandData_BufferActivate(); + activate->buffer_name = name; + relay_send(activate); +} + +static void +buffer_toggle_unimportant(const std::wstring &name) +{ + auto toggle = new Relay::CommandData_BufferToggleUnimportant(); + toggle->buffer_name = name; + relay_send(toggle); +} + +static void +buffer_toggle_log( + const std::wstring &error, const Relay::ResponseData_BufferLog *response) +{ + if (!response) { + show_error_message(error.c_str()); + return; + } + + std::wstring log; + if (!LibertyXDR::utf8_to_wstring( + response->log.data(), response->log.size(), log)) { + show_error_message(L"Invalid encoding."); + return; + } + + std::wstring filtered; + for (auto wch : log) { + if (wch == L'\n') + filtered += L"\r\n"; + else + filtered += wch; + } + + SetWindowText(g.hwndBufferLog, filtered.c_str()); + ShowWindow(g.hwndBuffer, SW_HIDE); + ShowWindow(g.hwndBufferLog, SW_SHOW); +} + +static void +buffer_toggle_log() +{ + if (IsWindowVisible(g.hwndBufferLog)) { + ShowWindow(g.hwndBufferLog, SW_HIDE); + ShowWindow(g.hwndBuffer, SW_SHOW); + SetWindowText(g.hwndBufferLog, L""); + + recheck_highlighted(); + return; + } + + auto log = new Relay::CommandData_BufferLog(); + log->buffer_name = g.buffer_current; + relay_send(log, [name = g.buffer_current](auto error, auto response) { + if (g.buffer_current != name) + return; + buffer_toggle_log(error, + dynamic_cast<const Relay::ResponseData_BufferLog *>(response)); + }); +} + // --- Rich Edit formatting ---------------------------------------------------- static COLORREF @@ -728,6 +744,7 @@ refresh_buffer(const Buffer &b) buffer_print_and_watch_trailing_date_changes(); buffer_scroll_to_bottom(); + // We will get a scroll event, so no need to recheck_highlighted() here. SendMessage(g.hwndBuffer, WM_SETREDRAW, (WPARAM) TRUE, 0); InvalidateRect(g.hwndBuffer, NULL, TRUE); @@ -749,8 +766,9 @@ relay_process_buffer_line(Buffer &b, Relay::EventData_BufferLine &m) // Retained mode is complicated. bool display = (!m.is_unimportant || !bc->hide_unimportant) && (b.buffer_name == g.buffer_current || m.leak_to_active); + // XXX: It would be great if it didn't autoscroll when focused. bool to_bottom = display && - buffer_at_bottom(); + (buffer_at_bottom() || GetFocus() == g.hwndBuffer); bool visible = display && to_bottom && !IsIconic(g.hwndMain) && @@ -1465,6 +1483,7 @@ richedit_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, { // Dragging the scrollbar doesn't result in EN_VSCROLL. LRESULT lResult = DefSubclassProc(hWnd, uMsg, wParam, lParam); + recheck_highlighted(); refresh_status(); return lResult; } @@ -1522,8 +1541,12 @@ process_resize(UINT w, UINT h) MoveWindow(g.hwndBufferList, 3, top, 150, h - top - bottom, FALSE); MoveWindow(g.hwndBuffer, 156, top, w - 159, h - top - bottom, FALSE); MoveWindow(g.hwndBufferLog, 156, top, w - 159, h - top - bottom, FALSE); - if (to_bottom) + if (to_bottom) { buffer_scroll_to_bottom(); + } else { + recheck_highlighted(); + refresh_status(); + } InvalidateRect(g.hwndMain, NULL, TRUE); } @@ -1685,8 +1708,10 @@ window_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } case WM_SYSCOMMAND: { + // We're not deiconified yet, so duplicate recheck_highlighted(). auto b = buffer_by_name(g.buffer_current); - if (b && wParam == SC_RESTORE) { + if (wParam == SC_RESTORE && b && b->highlighted && buffer_at_bottom() && + !IsWindowVisible(g.hwndBufferLog)) { b->highlighted = false; refresh_icon(); } @@ -1694,13 +1719,15 @@ window_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) break; } case WM_COMMAND: - if (!lParam) + if (!lParam) { process_accelerator(LOWORD(wParam)); - else if (lParam == (LPARAM) g.hwndBufferList) + } else if (lParam == (LPARAM) g.hwndBufferList) { process_bufferlist_notification(HIWORD(wParam)); - else if (lParam == (LPARAM) g.hwndBuffer && - HIWORD(wParam) == EN_VSCROLL) + } else if (lParam == (LPARAM) g.hwndBuffer && + HIWORD(wParam) == EN_VSCROLL) { + recheck_highlighted(); refresh_status(); + } return 0; case WM_NOTIFY: switch (((LPNMHDR) lParam)->code) { |