LCOV - code coverage report
Current view: top level - src - GuiLayer_Linux.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 30 30
Test Date: 2026-03-01 21:30:38 Functions: 100.0 % 17 17
Branches: 50.0 % 4 2

             Branch data     Line data    Source code
       1                 :             : #include "GuiLayer.h"
       2                 :             : #include "GuiPlatform.h"
       3                 :             : #include "Version.h"
       4                 :             : #include "Config.h"
       5                 :             : #include <iostream>
       6                 :             : #include <vector>
       7                 :             : #include <algorithm>
       8                 :             : #include <mutex>
       9                 :             : #include <chrono>
      10                 :             : 
      11                 :             : #if defined(ENABLE_IMGUI) && !defined(HEADLESS_GUI)
      12                 :             : #include "imgui.h"
      13                 :             : #include "imgui_impl_glfw.h"
      14                 :             : #include "imgui_impl_opengl3.h"
      15                 :             : #include <GLFW/glfw3.h>
      16                 :             : #if defined(__APPLE__)
      17                 :             : #include <OpenGL/gl.h>
      18                 :             : #else
      19                 :             : #include <GL/gl.h>
      20                 :             : #endif
      21                 :             : 
      22                 :             : static GLFWwindow* g_window = nullptr;
      23                 :             : #endif
      24                 :             : 
      25                 :             : extern std::atomic<bool> g_running;
      26                 :             : 
      27                 :             : class LinuxGuiPlatform : public IGuiPlatform {
      28                 :             : public:
      29                 :           5 :     void SetAlwaysOnTop(bool enabled) override {
      30                 :             : #if defined(ENABLE_IMGUI) && !defined(HEADLESS_GUI)
      31                 :             :         if (g_window) {
      32                 :             :             glfwSetWindowAttrib(g_window, GLFW_FLOATING, enabled ? GLFW_TRUE : GLFW_FALSE);
      33                 :             :         }
      34                 :             : #else
      35                 :           5 :         m_always_on_top_mock = enabled;
      36                 :             : #endif
      37                 :           5 :     }
      38                 :             : 
      39                 :           2 :     void ResizeWindow(int x, int y, int w, int h) override {
      40                 :             : #if defined(ENABLE_IMGUI) && !defined(HEADLESS_GUI)
      41                 :             :         if (g_window) {
      42                 :             :             glfwSetWindowSize(g_window, w, h);
      43                 :             :         }
      44                 :             : #endif
      45                 :           2 :     }
      46                 :             : 
      47                 :           3 :     void SaveWindowGeometry(bool is_graph_mode) override {
      48                 :             : #if defined(ENABLE_IMGUI) && !defined(HEADLESS_GUI)
      49                 :             :         if (g_window) {
      50                 :             :             int x, y, w, h;
      51                 :             :             glfwGetWindowPos(g_window, &x, &y);
      52                 :             :             glfwGetWindowSize(g_window, &w, &h);
      53                 :             :             Config::win_pos_x = x;
      54                 :             :             Config::win_pos_y = y;
      55                 :             :             if (is_graph_mode) {
      56                 :             :                 Config::win_w_large = w;
      57                 :             :                 Config::win_h_large = h;
      58                 :             :             } else {
      59                 :             :                 Config::win_w_small = w;
      60                 :             :                 Config::win_h_small = h;
      61                 :             :             }
      62                 :             :         }
      63                 :             : #endif
      64                 :           3 :     }
      65                 :             : 
      66                 :           2 :     bool OpenPresetFileDialog(std::string& outPath) override {
      67                 :           2 :         std::cout << "[GUI] File Dialog not implemented on Linux yet." << std::endl;
      68                 :           2 :         return false;
      69                 :             :     }
      70                 :             : 
      71                 :           2 :     bool SavePresetFileDialog(std::string& outPath, const std::string& defaultName) override {
      72                 :           2 :         std::cout << "[GUI] File Dialog not implemented on Linux yet." << std::endl;
      73                 :           2 :         return false;
      74                 :             :     }
      75                 :             : 
      76                 :           2 :     void* GetWindowHandle() override {
      77                 :             : #if defined(ENABLE_IMGUI) && !defined(HEADLESS_GUI)
      78                 :             :         return (void*)g_window;
      79                 :             : #else
      80                 :           2 :         return nullptr;
      81                 :             : #endif
      82                 :             :     }
      83                 :             : 
      84                 :           5 :     bool GetAlwaysOnTopMock() override { return m_always_on_top_mock; }
      85                 :             : 
      86                 :             :     // Mock access for tests
      87                 :             :     bool m_always_on_top_mock = false;
      88                 :             : };
      89                 :             : 
      90                 :             : static LinuxGuiPlatform g_platform;
      91                 :          15 : IGuiPlatform& GetGuiPlatform() { return g_platform; }
      92                 :             : 
      93                 :             : // Compatibility Helpers
      94                 :           1 : void ResizeWindowPlatform(int x, int y, int w, int h) { GetGuiPlatform().ResizeWindow(x, y, w, h); }
      95                 :           2 : void SaveCurrentWindowGeometryPlatform(bool is_graph_mode) { GetGuiPlatform().SaveWindowGeometry(is_graph_mode); }
      96                 :           4 : void SetWindowAlwaysOnTopPlatform(bool enabled) { GetGuiPlatform().SetAlwaysOnTop(enabled); }
      97                 :           1 : bool OpenPresetFileDialogPlatform(std::string& outPath) { return GetGuiPlatform().OpenPresetFileDialog(outPath); }
      98                 :           1 : bool SavePresetFileDialogPlatform(std::string& outPath, const std::string& defaultName) { return GetGuiPlatform().SavePresetFileDialog(outPath, defaultName); }
      99                 :             : 
     100                 :             : #if defined(ENABLE_IMGUI) && !defined(HEADLESS_GUI)
     101                 :             : 
     102                 :             : static void glfw_error_callback(int error, const char* description) {
     103                 :             :     fprintf(stderr, "Glfw Error %d: %s\n", error, description);
     104                 :             : }
     105                 :             : 
     106                 :             : bool GuiLayer::Init() {
     107                 :             :     glfwSetErrorCallback(glfw_error_callback);
     108                 :             :     if (!glfwInit()) return false;
     109                 :             : 
     110                 :             :     // GL 3.0 + GLSL 130
     111                 :             :     const char* glsl_version = "#version 130";
     112                 :             :     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
     113                 :             :     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
     114                 :             : 
     115                 :             :     int start_w = Config::show_graphs ? Config::win_w_large : Config::win_w_small;
     116                 :             :     int start_h = Config::show_graphs ? Config::win_h_large : Config::win_h_small;
     117                 :             : 
     118                 :             :     std::string title = "lmuFFB v" + std::string(LMUFFB_VERSION);
     119                 :             :     g_window = glfwCreateWindow(start_w, start_h, title.c_str(), NULL, NULL);
     120                 :             :     if (g_window == NULL) return false;
     121                 :             : 
     122                 :             :     glfwMakeContextCurrent(g_window);
     123                 :             :     glfwSwapInterval(1); // Enable vsync
     124                 :             : 
     125                 :             :     if (Config::m_always_on_top) SetWindowAlwaysOnTopPlatform(true);
     126                 :             : 
     127                 :             :     IMGUI_CHECKVERSION();
     128                 :             :     ImGui::CreateContext();
     129                 :             :     ImGuiIO& io = ImGui::GetIO(); (void)io;
     130                 :             :     io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
     131                 :             : 
     132                 :             :     SetupGUIStyle();
     133                 :             : 
     134                 :             :     ImGui_ImplGlfw_InitForOpenGL(g_window, true);
     135                 :             :     ImGui_ImplOpenGL3_Init(glsl_version);
     136                 :             : 
     137                 :             :     return true;
     138                 :             : }
     139                 :             : 
     140                 :             : void GuiLayer::Shutdown(FFBEngine& engine) {
     141                 :             :     SaveCurrentWindowGeometryPlatform(Config::show_graphs);
     142                 :             :     Config::Save(engine);
     143                 :             : 
     144                 :             :     ImGui_ImplOpenGL3_Shutdown();
     145                 :             :     ImGui_ImplGlfw_Shutdown();
     146                 :             :     ImGui::DestroyContext();
     147                 :             : 
     148                 :             :     glfwDestroyWindow(g_window);
     149                 :             :     glfwTerminate();
     150                 :             : }
     151                 :             : 
     152                 :             : void* GuiLayer::GetWindowHandle() {
     153                 :             :     return (void*)g_window;
     154                 :             : }
     155                 :             : 
     156                 :             : bool GuiLayer::Render(FFBEngine& engine) {
     157                 :             :     if (glfwWindowShouldClose(g_window)) {
     158                 :             :         g_running = false;
     159                 :             :         return false;
     160                 :             :     }
     161                 :             : 
     162                 :             :     glfwPollEvents();
     163                 :             : 
     164                 :             :     ImGui_ImplOpenGL3_NewFrame();
     165                 :             :     ImGui_ImplGlfw_NewFrame();
     166                 :             :     ImGui::NewFrame();
     167                 :             : 
     168                 :             :     DrawTuningWindow(engine);
     169                 :             :     if (Config::show_graphs) DrawDebugWindow(engine);
     170                 :             : 
     171                 :             :     ImGui::Render();
     172                 :             :     int display_w, display_h;
     173                 :             :     glfwGetFramebufferSize(g_window, &display_w, &display_h);
     174                 :             :     glViewport(0, 0, display_w, display_h);
     175                 :             :     glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
     176                 :             :     glClear(GL_COLOR_BUFFER_BIT);
     177                 :             :     ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
     178                 :             : 
     179                 :             :     glfwSwapBuffers(g_window);
     180                 :             : 
     181                 :             :     return true; // Always return true to keep the main loop running at full speed
     182                 :             : }
     183                 :             : 
     184                 :             : #else
     185                 :             : // Stub Implementation for Headless Builds (or if IMGUI disabled)
     186                 :           1 : bool GuiLayer::Init() {
     187                 :           1 :     std::cout << "[GUI] Disabled (Headless Mode)" << std::endl;
     188                 :           1 :     return true;
     189                 :             : }
     190                 :           1 : void GuiLayer::Shutdown(FFBEngine& engine) {
     191   [ +  -  +  - ]:           1 :     Config::Save(engine);
     192                 :           1 : }
     193                 :          27 : bool GuiLayer::Render(FFBEngine& engine) { return true; }
     194                 :           1 : void* GuiLayer::GetWindowHandle() { return nullptr; }
     195                 :             : 
     196                 :             : #endif
        

Generated by: LCOV version 2.0-1