2022-12-31 08:35:58 +00:00
|
|
|
#include <imgui.h>
|
|
|
|
#include <imgui_stdlib.h>
|
|
|
|
|
2023-01-05 10:27:14 +00:00
|
|
|
#include "log.h"
|
2022-12-31 08:35:58 +00:00
|
|
|
#include "config.h"
|
2023-01-18 16:34:17 +00:00
|
|
|
#include "logcat_thread.h"
|
2022-12-31 08:35:58 +00:00
|
|
|
|
2023-01-04 16:40:35 +00:00
|
|
|
static inline void write_config_and_update_structures(const Config& config) {
|
|
|
|
try {
|
|
|
|
write_config(config);
|
|
|
|
} catch (const std::exception& e) {
|
2023-01-16 04:08:35 +00:00
|
|
|
log(std::string("Failed to write config: ") + e.what());
|
2023-01-05 10:27:14 +00:00
|
|
|
return;
|
2023-01-04 16:40:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-18 16:34:17 +00:00
|
|
|
static inline void check_for_logcat_items(LogcatThread& logcat_thread) {
|
|
|
|
LogcatThreadItem* logcat_thread_item;
|
|
|
|
|
|
|
|
while ((logcat_thread_item = logcat_thread.atomic_ring_buffer.get())) {
|
|
|
|
if (std::holds_alternative<std::string>(*logcat_thread_item)) {
|
2023-01-20 15:22:21 +00:00
|
|
|
log_raw(std::move(std::get<std::string>(*logcat_thread_item)), false);
|
2023-01-19 16:34:03 +00:00
|
|
|
} else if (std::holds_alternative<LogcatEntry>(*logcat_thread_item)) {
|
|
|
|
LogcatEntry logcat_entry = std::move(std::get<LogcatEntry>(*logcat_thread_item));
|
|
|
|
log("Received new logcat entry");
|
|
|
|
log(std::string(" - Buffer: ") + buffer_to(logcat_entry.buffer));
|
|
|
|
log(std::string(" - Time: ") + std::to_string(logcat_entry.time));
|
|
|
|
if (logcat_entry.user) {
|
|
|
|
log(std::string(" - User: ") + *logcat_entry.user);
|
|
|
|
}
|
|
|
|
log(std::string(" - PID: ") + std::to_string(logcat_entry.pid));
|
|
|
|
log(std::string(" - TID: ") + std::to_string(logcat_entry.tid));
|
|
|
|
log(std::string(" - Priority: ") + priority_to(logcat_entry.priority));
|
|
|
|
log(std::string(" - Tag: ") + logcat_entry.tag);
|
|
|
|
log(std::string(" - Message: ") + logcat_entry.message);
|
2023-01-18 16:34:17 +00:00
|
|
|
} else {
|
|
|
|
throw std::runtime_error("Cannot handle all possible logcat thread item variants");
|
|
|
|
}
|
|
|
|
logcat_thread.atomic_ring_buffer.increment_read();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-05 10:27:14 +00:00
|
|
|
|
2023-01-04 16:40:35 +00:00
|
|
|
static inline void settings_window(Config& config, float* config_write_timer, bool* show_settings_window) {
|
2022-12-31 08:35:58 +00:00
|
|
|
if (!ImGui::Begin("Settings", show_settings_window)) {
|
|
|
|
ImGui::End();
|
|
|
|
return;
|
|
|
|
}
|
2023-01-04 16:40:35 +00:00
|
|
|
// TODO actually have process control
|
2023-01-05 10:27:14 +00:00
|
|
|
ImGui::Text("Logcat command only takes effect when logcat is not running");
|
2023-01-15 14:17:31 +00:00
|
|
|
if (ImGui::InputTextWithHint("Logcat command", "adb logcat -Dv 'threadtime UTC epoch usec uid'", &config.logcat_command)) {
|
2023-01-04 16:40:35 +00:00
|
|
|
*config_write_timer = *config_write_timer > 0.0f ? *config_write_timer : 5.0f;
|
|
|
|
}
|
2023-01-08 16:12:22 +00:00
|
|
|
ImGui::Text("Font sizes only take effect when LogMeow is restarted");
|
|
|
|
#ifdef USE_FONTCONFIG
|
|
|
|
if (ImGui::InputFloat("Normal font size", &config.normal_font_size, 0.5f, 1.0f, "%.3f")) {
|
|
|
|
*config_write_timer = *config_write_timer > 0.0f ? *config_write_timer : 5.0f;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (ImGui::InputFloat("Monospace font size", &config.monospace_font_size, 0.5f, 1.0f, "%.3f")) {
|
|
|
|
*config_write_timer = *config_write_timer > 0.0f ? *config_write_timer : 5.0f;
|
|
|
|
}
|
2022-12-31 08:35:58 +00:00
|
|
|
ImGui::End();
|
|
|
|
}
|
|
|
|
|
2023-01-06 16:27:39 +00:00
|
|
|
static inline void logs_window(ImFont* monospace_font, bool* autoscrolling, bool* show_logs_window) {
|
2023-01-05 10:27:14 +00:00
|
|
|
if (!ImGui::Begin("LogMeow Logs", show_logs_window)) {
|
2022-12-31 08:35:58 +00:00
|
|
|
ImGui::End();
|
|
|
|
return;
|
|
|
|
}
|
2023-01-05 10:27:14 +00:00
|
|
|
|
|
|
|
if (ImGui::Button("Clear")) {
|
|
|
|
log_entries.clear();
|
2023-01-20 15:22:21 +00:00
|
|
|
log_entry_line_offsets = {0};
|
2022-12-31 08:35:58 +00:00
|
|
|
}
|
2023-01-05 10:27:14 +00:00
|
|
|
ImGui::SameLine();
|
|
|
|
if (ImGui::Button("Copy")) {
|
|
|
|
ImGui::SetClipboardText(log_entries.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::Separator();
|
2023-01-05 13:53:23 +00:00
|
|
|
// copied from imgui/imgui_demo.cpp: [SECTION] Example App: Debug Console / ShowExampleAppConsole()
|
2023-01-20 15:22:21 +00:00
|
|
|
// and [SECTION] Example App: Long Text / ShowExampleAppLongText()
|
|
|
|
// and [SECTION] Example App: Debug Log / ShowExampleAppLog()
|
2023-01-05 10:27:14 +00:00
|
|
|
if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar)) {
|
2023-01-06 16:27:39 +00:00
|
|
|
ImGui::PushFont(monospace_font);
|
2023-01-20 15:22:21 +00:00
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
|
|
|
|
|
|
|
|
ImGuiListClipper clipper;
|
|
|
|
clipper.Begin(static_cast<int>(log_entry_line_offsets.size()));
|
|
|
|
while (clipper.Step()) {
|
|
|
|
for (int i_u = clipper.DisplayStart; i_u < clipper.DisplayEnd; i_u++) {
|
|
|
|
// what'd we do if we log the error about an error failing to show logs
|
|
|
|
assert(i_u >= 0);
|
|
|
|
size_t i = static_cast<size_t>(i_u);
|
|
|
|
|
|
|
|
const char* start_offset = &log_entries[log_entry_line_offsets[i]];
|
|
|
|
const char* end_offset = log_entry_line_offsets.size() > i + 1
|
|
|
|
? &log_entries[log_entry_line_offsets[i + 1] - 1]
|
|
|
|
: &log_entries[log_entries.size()];
|
|
|
|
ImGui::TextUnformatted(start_offset, end_offset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
clipper.End();
|
|
|
|
|
|
|
|
ImGui::PopStyleVar();
|
2023-01-06 16:27:39 +00:00
|
|
|
ImGui::PopFont();
|
2023-01-05 13:53:23 +00:00
|
|
|
if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) {
|
2023-01-06 15:13:23 +00:00
|
|
|
*autoscrolling = true;
|
2023-01-05 13:53:23 +00:00
|
|
|
ImGui::SetScrollHereY(1.0f);
|
|
|
|
}
|
2023-01-05 10:27:14 +00:00
|
|
|
}
|
|
|
|
ImGui::EndChild();
|
2022-12-31 08:35:58 +00:00
|
|
|
ImGui::End();
|
|
|
|
}
|
|
|
|
|
2023-01-05 14:23:24 +00:00
|
|
|
static inline void main_window(bool latest_log_entries_read, bool* show_settings_window, bool* show_logs_window, bool* run_event_loop) {
|
2023-01-05 13:55:54 +00:00
|
|
|
if (!ImGui::Begin("LogMeow", run_event_loop)) {
|
2023-01-05 10:27:14 +00:00
|
|
|
ImGui::End();
|
2023-01-04 16:40:35 +00:00
|
|
|
return;
|
|
|
|
}
|
2023-01-05 14:23:24 +00:00
|
|
|
|
2023-01-05 10:27:14 +00:00
|
|
|
if (ImGui::Button("Settings")) {
|
|
|
|
*show_settings_window = true;
|
2022-12-31 08:35:58 +00:00
|
|
|
}
|
2023-01-05 14:23:24 +00:00
|
|
|
|
2023-01-04 16:40:35 +00:00
|
|
|
ImGui::SameLine();
|
2023-01-05 14:23:24 +00:00
|
|
|
if (!latest_log_entries_read) {
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(0.0f, 0.6f, 0.6f));
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(0.0f, 0.7f, 0.7f));
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(0.0f, 0.8f, 0.8f));
|
|
|
|
}
|
2023-01-05 10:27:14 +00:00
|
|
|
if (ImGui::Button("Logs")) {
|
|
|
|
*show_logs_window = true;
|
2023-01-04 16:40:35 +00:00
|
|
|
}
|
2023-01-05 14:23:24 +00:00
|
|
|
if (!latest_log_entries_read) {
|
|
|
|
ImGui::PopStyleColor(3);
|
|
|
|
}
|
|
|
|
|
2023-01-05 10:27:14 +00:00
|
|
|
ImGui::End();
|
2022-12-31 08:35:58 +00:00
|
|
|
}
|
|
|
|
|
2023-01-18 16:37:37 +00:00
|
|
|
#ifndef NDEBUG
|
2023-01-18 16:43:30 +00:00
|
|
|
static inline void debug_window(LogcatThread& logcat_thread) {
|
2022-12-31 08:35:58 +00:00
|
|
|
static bool show_demo_window = false;
|
2023-01-05 10:27:14 +00:00
|
|
|
static size_t add_log_entry_presses = 1;
|
2023-01-05 13:53:34 +00:00
|
|
|
static bool log_entry_every_second = false;
|
|
|
|
static float log_entry_every_second_delta;
|
2023-01-05 10:27:14 +00:00
|
|
|
|
2022-12-31 08:35:58 +00:00
|
|
|
if (show_demo_window) {
|
|
|
|
ImGui::ShowDemoWindow(&show_demo_window);
|
|
|
|
}
|
2023-01-05 09:05:09 +00:00
|
|
|
if (!ImGui::Begin("LogMeow Debug")) {
|
|
|
|
ImGui::End();
|
|
|
|
return;
|
|
|
|
}
|
2023-01-05 13:53:34 +00:00
|
|
|
|
2023-01-05 09:05:09 +00:00
|
|
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
|
|
ImGui::Checkbox("Show Dear ImGui Demo Window", &show_demo_window);
|
2023-01-05 13:53:34 +00:00
|
|
|
|
2023-01-05 10:27:14 +00:00
|
|
|
ImGui::Separator();
|
|
|
|
if (ImGui::Button("Add Log Entry")) {
|
2023-01-09 07:56:24 +00:00
|
|
|
log(std::string("Debug log entry #") + std::to_string(add_log_entry_presses++) + " (activated via manual button press)");
|
2023-01-05 13:53:34 +00:00
|
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
|
|
// returns true when it's pressed
|
|
|
|
if (ImGui::Checkbox("Add log entry every second", &log_entry_every_second)) {
|
|
|
|
log_entry_every_second_delta = 0.0f;
|
2023-01-05 10:27:14 +00:00
|
|
|
}
|
2023-01-16 03:57:07 +00:00
|
|
|
if (ImGui::Button("Add Log Entry with Newlines")) {
|
|
|
|
log("The following should have five spaces: \"\n\n\n\n\n\"");
|
|
|
|
}
|
2023-01-21 04:42:59 +00:00
|
|
|
if (ImGui::Button("Test user assert")) {
|
|
|
|
IM_ASSERT_USER_ERROR(0, "User assert tested");
|
|
|
|
}
|
2023-01-18 16:43:30 +00:00
|
|
|
if (ImGui::Button("Request log entry from Logcat thread")) {
|
|
|
|
logcat_thread.debug_log_request.test_and_set();
|
|
|
|
}
|
2023-01-16 03:57:07 +00:00
|
|
|
|
2023-01-05 13:53:34 +00:00
|
|
|
if (log_entry_every_second) {
|
|
|
|
log_entry_every_second_delta += ImGui::GetIO().DeltaTime;
|
|
|
|
if (log_entry_every_second_delta >= 1.0f) {
|
|
|
|
log_entry_every_second_delta = 0.0f;
|
2023-01-09 07:56:24 +00:00
|
|
|
log(std::string("Debug log entry #") + std::to_string(add_log_entry_presses++) + " (activated by add log entry every second)");
|
2023-01-05 13:53:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-05 09:05:09 +00:00
|
|
|
ImGui::End();
|
|
|
|
}
|
2023-01-18 16:37:37 +00:00
|
|
|
#endif
|
2023-01-05 09:05:09 +00:00
|
|
|
|
2023-01-18 16:34:17 +00:00
|
|
|
void event_loop(ImFont* monospace_font, Config& config, float* config_write_timer, LogcatThread& logcat_thread, bool* run_event_loop) {
|
2023-01-05 09:05:09 +00:00
|
|
|
static bool show_settings_window = false;
|
2023-01-05 10:27:14 +00:00
|
|
|
static bool show_logs_window = false;
|
2023-01-05 14:23:24 +00:00
|
|
|
static size_t log_entries_read = 0;
|
2023-01-05 09:05:09 +00:00
|
|
|
|
2023-01-18 16:34:17 +00:00
|
|
|
check_for_logcat_items(logcat_thread);
|
|
|
|
|
2023-01-18 16:37:37 +00:00
|
|
|
#ifndef NDEBUG
|
2023-01-18 16:43:30 +00:00
|
|
|
debug_window(logcat_thread);
|
2023-01-18 16:37:37 +00:00
|
|
|
#endif
|
2023-01-05 10:27:14 +00:00
|
|
|
|
2022-12-31 08:35:58 +00:00
|
|
|
if (show_settings_window) {
|
2023-01-04 16:40:35 +00:00
|
|
|
settings_window(config, config_write_timer, &show_settings_window);
|
|
|
|
}
|
|
|
|
if (*config_write_timer > 0.0f) {
|
|
|
|
*config_write_timer -= ImGui::GetIO().DeltaTime;
|
|
|
|
if (*config_write_timer <= 0.0f) {
|
|
|
|
write_config_and_update_structures(config);
|
|
|
|
}
|
2022-12-31 08:35:58 +00:00
|
|
|
}
|
|
|
|
|
2023-01-05 10:27:14 +00:00
|
|
|
if (show_logs_window) {
|
2023-01-06 15:13:23 +00:00
|
|
|
bool autoscrolling = false;
|
2023-01-06 16:27:39 +00:00
|
|
|
logs_window(monospace_font, &autoscrolling, &show_logs_window);
|
2023-01-06 15:13:23 +00:00
|
|
|
if (autoscrolling) {
|
2023-01-05 14:23:24 +00:00
|
|
|
log_entries_read = log_entries.size();
|
|
|
|
}
|
2023-01-05 10:27:14 +00:00
|
|
|
}
|
|
|
|
|
2023-01-05 14:23:24 +00:00
|
|
|
// log_entries must not be mutated until the show logs button
|
|
|
|
main_window(log_entries_read == log_entries.size(), &show_settings_window, &show_logs_window, run_event_loop);
|
2022-12-31 08:35:58 +00:00
|
|
|
}
|