diff --git a/examples/example_x11_vulkan/main.cpp b/examples/example_x11_vulkan/main.cpp index 2cf30712a169..e2d3912b2fac 100644 --- a/examples/example_x11_vulkan/main.cpp +++ b/examples/example_x11_vulkan/main.cpp @@ -405,19 +405,19 @@ int main(int, char**) init_info.CheckVkResultFn = check_vk_result; ImGui_ImplVulkan_Init(&init_info, wd->RenderPass); - // // Load Fonts - // // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. - // // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // // - Read 'docs/FONTS.md' for more instructions and details. - // // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - io.Fonts->AddFontDefault(); - // //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - // //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - // //io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f); - // //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); - // //IM_ASSERT(font != NULL); + // Load Fonts + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). + // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. + // - Read 'docs/FONTS.md' for more instructions and details. + // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //io.Fonts->AddFontDefault(); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); + //IM_ASSERT(font != NULL); // Upload Fonts { @@ -453,10 +453,6 @@ int main(int, char**) bool show_demo_window = true; bool show_another_window = false; ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); - wd->ClearValue.color.float32[0] = clear_color.x; - wd->ClearValue.color.float32[1] = clear_color.y; - wd->ClearValue.color.float32[2] = clear_color.z; - wd->ClearValue.color.float32[3] = clear_color.w; // Main loop bool done = false; @@ -475,106 +471,105 @@ int main(int, char**) // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. - xcb_generic_event_t *event; - event = xcb_poll_for_event(connection); - if(event) + xcb_generic_event_t* event = xcb_poll_for_event(connection); + if (event) { - if(!ImGui_ImplX11_Event(event)) + if (!ImGui_ImplX11_ProcessEvent(event)) { - switch (event->response_type & ~0x80) { - case XCB_EXPOSE: { + switch (event->response_type & ~0x80) + { + case XCB_EXPOSE: + { xcb_flush(connection); break; } - case XCB_CLIENT_MESSAGE: { - if(((xcb_client_message_event_t*)event)->data.data32[0] == wm_delete_window) + case XCB_CLIENT_MESSAGE: + { + if (((xcb_client_message_event_t*)event)->data.data32[0] == wm_delete_window) done = true; break; } - case XCB_CONFIGURE_NOTIFY: { - xcb_configure_notify_event_t *config = (xcb_configure_notify_event_t*)event; + case XCB_CONFIGURE_NOTIFY: + { + xcb_configure_notify_event_t* config = (xcb_configure_notify_event_t*)event; // Set DisplaySize here instead of checking in X11 NewFrame // Checking window size is request/response g_SwapChainResizeWidth = config->width; g_SwapChainResizeHeight = config->height; g_MainWindowData.FrameIndex = 0; - ImGui::GetIO().DisplaySize = ImVec2(config->width, config->height); + ImGui::GetIO().DisplaySize = ImVec2(config->width, config->height); // FIXME: Why isn't this processed in ImGui_ImplX11_ProcessEvent? break; } default: break; } } - // xcb allocates the memory for the event and specifies - // the user to free it + + // xcb allocates the memory for the event and specifies the user to free it free(event); + continue; } - else + + // Resize swap chain? + if (g_SwapChainRebuild && g_SwapChainResizeWidth > 0 && g_SwapChainResizeHeight > 0) { - // Resize swap chain? - if (g_SwapChainRebuild && g_SwapChainResizeWidth > 0 && g_SwapChainResizeHeight > 0) - { - g_SwapChainRebuild = false; - ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount); - ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, &g_MainWindowData, g_QueueFamily, g_Allocator, g_SwapChainResizeWidth, g_SwapChainResizeHeight, g_MinImageCount); - g_MainWindowData.FrameIndex = 0; - } - // Start the Dear ImGui frame - ImGui_ImplVulkan_NewFrame(); - ImGui_ImplX11_NewFrame(); - ImGui::NewFrame(); - // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). - if (show_demo_window) - ImGui::ShowDemoWindow(&show_demo_window); - - // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window. - { - static float f = 0.0f; - static int counter = 0; + g_SwapChainRebuild = false; + ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount); + ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, &g_MainWindowData, g_QueueFamily, g_Allocator, g_SwapChainResizeWidth, g_SwapChainResizeHeight, g_MinImageCount); + g_MainWindowData.FrameIndex = 0; + } - ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. + // Start the Dear ImGui frame + ImGui_ImplVulkan_NewFrame(); + ImGui_ImplX11_NewFrame(); + ImGui::NewFrame(); - ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) - ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state - ImGui::Checkbox("Another Window", &show_another_window); + // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). + if (show_demo_window) + ImGui::ShowDemoWindow(&show_demo_window); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f - if(ImGui::ColorEdit3("clear color", (float*)&clear_color)) // Edit 3 floats representing a color - { - wd->ClearValue.color.float32[0] = clear_color.x; - wd->ClearValue.color.float32[1] = clear_color.y; - wd->ClearValue.color.float32[2] = clear_color.z; - wd->ClearValue.color.float32[3] = clear_color.w; - }; - - if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) - counter++; - ImGui::SameLine(); - ImGui::Text("counter = %d", counter); - - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGui::End(); - } + // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window. + { + static float f = 0.0f; + static int counter = 0; - // 3. Show another simple window. - if (show_another_window) - { - ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) - ImGui::Text("Hello from another window!"); - if (ImGui::Button("Close Me")) - show_another_window = false; - ImGui::End(); - } + ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. - // Rendering - ImGui::Render(); - ImDrawData* draw_data = ImGui::GetDrawData(); - const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f); - if (!is_minimized) - { - FrameRender(wd, draw_data); - FramePresent(wd); - } + ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) + ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state + ImGui::Checkbox("Another Window", &show_another_window); + + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color + + if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) + counter++; + ImGui::SameLine(); + ImGui::Text("counter = %d", counter); + + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::End(); + } + + // 3. Show another simple window. + if (show_another_window) + { + ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) + ImGui::Text("Hello from another window!"); + if (ImGui::Button("Close Me")) + show_another_window = false; + ImGui::End(); + } + + // Rendering + ImGui::Render(); + ImDrawData* draw_data = ImGui::GetDrawData(); + const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f); + if (!is_minimized) + { + memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float)); + FrameRender(wd, draw_data); + FramePresent(wd); } } diff --git a/examples/imgui_impl_x11.cpp b/examples/imgui_impl_x11.cpp index 033f99ea8016..aa8c002d5099 100644 --- a/examples/imgui_impl_x11.cpp +++ b/examples/imgui_impl_x11.cpp @@ -1,5 +1,6 @@ // dear imgui: Platform Binding for X11 using xcb // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) + // This works as is with Vulkan. For OpenGL using GLX, you need a hybrid // of XLib and xcb using the X11/Xlib-xcb.h header. Use XLib to create the // GLX context, then use functions in Xlib-xcb.h to convert the XLib @@ -7,9 +8,10 @@ // Requires libxcb, libxcb-xfixes, libxcb-xkb1 and libxcb-keysyms1 // Implemented features: +// [X] Platform: Keyboard arrays indexed using XK symbols, e.g. ImGui::IsKeyPressed(XK_space). +// Missing features: // [ ] Platform: Clipboard support // [ ] Platform: Mouse cursor shape and visibility. -// [X] Platform: Keyboard arrays indexed using XK symbols, e.g. ImGui::IsKeyPressed(XK_space). // [ ] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. #include "imgui.h" @@ -25,19 +27,19 @@ // 2020-07-30 Initial implementation // X11 Data -static xcb_connection_t *g_Connection; -static xcb_drawable_t *g_Win; -static xcb_key_symbols_t *g_KeySyms; +static xcb_connection_t* g_Connection; +static xcb_drawable_t* g_Window; +static xcb_key_symbols_t* g_KeySyms; static timespec g_LastTime; static timespec g_CurrentTime; // Functions -bool ImGui_ImplX11_Init(xcb_connection_t *connection, xcb_drawable_t *win) +bool ImGui_ImplX11_Init(xcb_connection_t* connection, xcb_drawable_t* window) { g_Connection = connection; - g_Win = win; + g_Window = window; clock_gettime(CLOCK_MONOTONIC_RAW, &g_LastTime); // Setup back-end capabilities flags @@ -45,8 +47,8 @@ bool ImGui_ImplX11_Init(xcb_connection_t *connection, xcb_drawable_t *win) io.BackendPlatformName = "imgui_impl_x11"; // Set initial display size - xcb_generic_error_t *x_Err = nullptr; - xcb_get_geometry_reply_t *resp = xcb_get_geometry_reply(g_Connection, xcb_get_geometry(g_Connection, *g_Win), &x_Err); + xcb_generic_error_t* x_Err = nullptr; + xcb_get_geometry_reply_t* resp = xcb_get_geometry_reply(g_Connection, xcb_get_geometry(g_Connection, *g_Window), &x_Err); IM_ASSERT(!x_Err && "X error querying window geometry"); io.DisplaySize = ImVec2(resp->width, resp->height); @@ -54,13 +56,14 @@ bool ImGui_ImplX11_Init(xcb_connection_t *connection, xcb_drawable_t *win) g_KeySyms = xcb_key_symbols_alloc(connection); // Turn off auto key repeat for this session - // By defaut X does key repeat as down/up/down/up + // By default X does key repeat as down/up/down/up // Unfortunately unlike win32, X has no way of signaling the key event is a repeated key - // So it's still possible to get mised down/up inputs in the same frame + // So it's still possible to miss down/up inputs in the same frame xcb_xkb_use_extension_cookie_t extension_cookie = xcb_xkb_use_extension(connection, 1, 0); - xcb_xkb_use_extension_reply_t *extension_reply = xcb_xkb_use_extension_reply(connection, extension_cookie, &x_Err); + xcb_xkb_use_extension_reply_t* extension_reply = xcb_xkb_use_extension_reply(connection, extension_cookie, &x_Err); - if(!x_Err && extension_reply->supported) { + if (!x_Err && extension_reply->supported) + { xcb_discard_reply(connection, xcb_xkb_per_client_flags(connection, XCB_XKB_ID_USE_CORE_KBD, @@ -75,6 +78,7 @@ bool ImGui_ImplX11_Init(xcb_connection_t *connection, xcb_drawable_t *win) // Therefore we have to remove the high bits to pass this check. // There are some unusual key symbols in the 0xFE00 and 0xFD00 range. // If you really want to support those check for that in your own xcb event handler. + // FIXME: Similar issue as OSX binding. io.KeyMap[ImGuiKey_Tab] = XK_Tab - 0xFF00; io.KeyMap[ImGuiKey_LeftArrow] = XK_Left - 0xFF00; io.KeyMap[ImGuiKey_RightArrow] = XK_Right - 0xFF00; @@ -115,8 +119,7 @@ void ImGui_ImplX11_NewFrame() // Setup time step clock_gettime(CLOCK_MONOTONIC_RAW, &g_CurrentTime); - io.DeltaTime = (g_CurrentTime.tv_sec - g_LastTime.tv_sec) + - ((g_CurrentTime.tv_nsec - g_LastTime.tv_nsec) / 1000000000.0f); + io.DeltaTime = (g_CurrentTime.tv_sec - g_LastTime.tv_sec) + ((g_CurrentTime.tv_nsec - g_LastTime.tv_nsec) / 1000000000.0f); g_LastTime = g_CurrentTime; } @@ -124,20 +127,23 @@ void ImGui_ImplX11_NewFrame() // Call from your application's message handler. Returns true if // ImGui processed the event. You can use this for checking if you // need further processing for the event. -bool ImGui_ImplX11_Event(xcb_generic_event_t *event) +bool ImGui_ImplX11_ProcessEvent(xcb_generic_event_t* event) { if (ImGui::GetCurrentContext() == NULL) return false; ImGuiIO& io = ImGui::GetIO(); - switch (event->response_type & ~0x80) { - case XCB_MOTION_NOTIFY: { - xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t*)event; + switch (event->response_type & ~0x80) + { + case XCB_MOTION_NOTIFY: + { + xcb_motion_notify_event_t* e = (xcb_motion_notify_event_t*)event; io.MousePos = ImVec2(e->event_x, e->event_y); return true; } - case XCB_KEY_PRESS: { - xcb_key_press_event_t *e = (xcb_key_press_event_t *)event; + case XCB_KEY_PRESS: + { + xcb_key_press_event_t* e = (xcb_key_press_event_t*)event; // since imgui processes modifiers internally by checking io.KeyCtrl and the like // we don't need any other xcb key columns besides the shift modifier. // without using the shift modifier we will only get the lower case letter @@ -145,13 +151,14 @@ bool ImGui_ImplX11_Event(xcb_generic_event_t *event) uint32_t col = io.KeyShift ? 1 : 0; xcb_keysym_t k = xcb_key_press_lookup_keysym(g_KeySyms, e, col); - if(k < 0xFF) // latin-1 range + if (k < 0xFF) // latin-1 range { io.AddInputCharacter(k); } - else if(k >= XK_Shift_L && k <= XK_Hyper_R) // modifier keys + else if (k >= XK_Shift_L && k <= XK_Hyper_R) // modifier keys { - switch(k) { + switch(k) + { case XK_Shift_L: case XK_Shift_R: io.KeyShift = true; @@ -172,26 +179,31 @@ bool ImGui_ImplX11_Event(xcb_generic_event_t *event) break; } } - else if(k >= 0x1000100 && k <= 0x110ffff) // utf range + else if (k >= 0x1000100 && k <= 0x110ffff) // utf range { io.AddInputCharacterUTF16(k); } else + { io.KeysDown[k - 0xFF00] = 1; + } return true; } - case XCB_KEY_RELEASE: { - xcb_key_press_event_t *e = (xcb_key_press_event_t *)event; + case XCB_KEY_RELEASE: + { + xcb_key_press_event_t* e = (xcb_key_press_event_t*)event; xcb_keysym_t k = xcb_key_press_lookup_keysym(g_KeySyms, e, 0); - if(k < 0xff) { - if(k == XK_space) + if (k < 0xff) + { + if (k == XK_space) io.KeysDown[XK_space] = 0; } - else if(k >= XK_Shift_L && k <= XK_Hyper_R) // modifier keys + else if (k >= XK_Shift_L && k <= XK_Hyper_R) // modifier keys { - switch(k) { + switch(k) + { case XK_Shift_L: case XK_Shift_R: io.KeyShift = false; @@ -213,28 +225,32 @@ bool ImGui_ImplX11_Event(xcb_generic_event_t *event) } } else + { io.KeysDown[k - 0xFF00] = 0; + } return true; } - case XCB_BUTTON_PRESS: { - xcb_button_press_event_t *e = (xcb_button_press_event_t *)event; + case XCB_BUTTON_PRESS: + { + xcb_button_press_event_t* e = (xcb_button_press_event_t*)event; // Get exact coords of the event. It may be separate from the mouse cursor. // e.g. touch input io.MousePos = ImVec2(e->event_x, e->event_y); // X decided button 4 is mwheel up and 5 is mwheel down - if(e->detail == 4) + if (e->detail >= 1 && e->detail <= 3) + io.MouseDown[e->detail - 1] = true; + else if (e->detail == 4) io.MouseWheel += 1.0; - else if(e->detail == 5) + else if (e->detail == 5) io.MouseWheel -= 1.0; - else - io.MouseDown[e->detail - 1] = true; return true; } - case XCB_BUTTON_RELEASE: { - xcb_button_release_event_t *e = (xcb_button_release_event_t *)event; + case XCB_BUTTON_RELEASE: + { + xcb_button_release_event_t* e = (xcb_button_release_event_t*)event; io.MousePos = ImVec2(e->event_x, e->event_y); - if(e->detail != 4 || e->detail != 5) + if (e->detail >= 1 && e->detail <= 3) io.MouseDown[e->detail - 1] = false; return true; } diff --git a/examples/imgui_impl_x11.h b/examples/imgui_impl_x11.h index 664b75a0e167..d1ce6511339d 100644 --- a/examples/imgui_impl_x11.h +++ b/examples/imgui_impl_x11.h @@ -1,24 +1,25 @@ // dear imgui: Platform Binding for X11 using xcb // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) + // This works as is with Vulkan. For OpenGL using GLX, you need a hybrid // of XLib and xcb using the X11/Xlib-xcb.h header. Use XLib to create the -// GLX context. Then use functions in Xlib-xcb.h to convert the XLib +// GLX context, then use functions in Xlib-xcb.h to convert the XLib // structures to xcb, which you can then pass unmodified here. -// Requires libxcb, libxcb-xfixes and libxcb-keysyms1 +// Requires libxcb, libxcb-xfixes, libxcb-xkb1 and libxcb-keysyms1 // Implemented features: +// [X] Platform: Keyboard arrays indexed using XK symbols, e.g. ImGui::IsKeyPressed(XK_space). +// Missing features: // [ ] Platform: Clipboard support // [ ] Platform: Mouse cursor shape and visibility. -// [X] Platform: Keyboard arrays indexed using XK symbols, e.g. ImGui::IsKeyPressed(XK_space). // [ ] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. - #pragma once #include "../imgui.h" // IMGUI_IMPL_API #include #include -IMGUI_IMPL_API bool ImGui_ImplX11_Init(xcb_connection_t *connection, xcb_drawable_t *win); +IMGUI_IMPL_API bool ImGui_ImplX11_Init(xcb_connection_t* connection, xcb_drawable_t* window); IMGUI_IMPL_API void ImGui_ImplX11_Shutdown(); IMGUI_IMPL_API void ImGui_ImplX11_NewFrame(); -IMGUI_IMPL_API bool ImGui_ImplX11_Event(xcb_generic_event_t *event); +IMGUI_IMPL_API bool ImGui_ImplX11_ProcessEvent(xcb_generic_event_t* event);