Path: blob/21.2-virgl/src/intel/tools/imgui/imgui_impl_gtk3.cpp
4547 views
// ImGui GLFW binding with OpenGL3 + shaders1// In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp.23// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.4// If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().5// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp.6// https://github.com/ocornut/imgui78#include <stdio.h>910#include "imgui/imgui.h"11#include "imgui_impl_gtk3.h"1213#include <gtk/gtk.h>1415#define ARRAY_SIZE(arg) (sizeof(arg) / sizeof((arg)[0]))1617#define EVENT_MASK \18((GdkEventMask) \19(GDK_STRUCTURE_MASK | \20GDK_FOCUS_CHANGE_MASK | \21GDK_EXPOSURE_MASK | \22GDK_PROPERTY_CHANGE_MASK | \23GDK_ENTER_NOTIFY_MASK | \24GDK_LEAVE_NOTIFY_MASK | \25GDK_KEY_PRESS_MASK | \26GDK_KEY_RELEASE_MASK | \27GDK_BUTTON_PRESS_MASK | \28GDK_BUTTON_RELEASE_MASK | \29GDK_POINTER_MOTION_MASK | \30GDK_SMOOTH_SCROLL_MASK | \31GDK_SCROLL_MASK))3233// Data34static GtkWidget* g_GtkGlArea = NULL;35static guint64 g_Time = 0;36static bool g_MousePressed[5] = { false, false, false, false, false };37static ImVec2 g_MousePosition = ImVec2(-1, -1);38static float g_MouseWheel = 0.0f;39static int g_NumRedraws = 0;40static guint g_RedrawTimeout = 0;4142static const char* ImGui_ImplGtk3_GetClipboardText(void* user_data)43{44static char *last_clipboard = NULL;4546g_clear_pointer(&last_clipboard, g_free);47last_clipboard = gtk_clipboard_wait_for_text(GTK_CLIPBOARD(user_data));48return last_clipboard;49}5051static void ImGui_ImplGtk3_SetClipboardText(void* user_data, const char* text)52{53gtk_clipboard_set_text(GTK_CLIPBOARD(user_data), text, -1);54}5556void ImGui_ImplGtk3_HandleEvent(GdkEvent *event)57{58ImGuiIO& io = ImGui::GetIO();5960GdkEventType type = gdk_event_get_event_type(event);61switch (type)62{63case GDK_MOTION_NOTIFY:64{65gdouble x = 0.0f, y = 0.0f;66if (gdk_event_get_coords(event, &x, &y))67g_MousePosition = ImVec2(x, y);68break;69}70case GDK_BUTTON_PRESS:71case GDK_BUTTON_RELEASE:72{73guint button = 0;74if (gdk_event_get_button(event, &button) && button > 0 && button <= 5)75{76if (type == GDK_BUTTON_PRESS)77g_MousePressed[button - 1] = true;78}79break;80}81case GDK_SCROLL:82{83gdouble x, y;84if (gdk_event_get_scroll_deltas(event, &x, &y))85g_MouseWheel = -y;86break;87}88case GDK_KEY_PRESS:89case GDK_KEY_RELEASE:90{91GdkEventKey *e = (GdkEventKey *) event;9293static const struct94{95enum ImGuiKey_ imgui;96guint gdk;97} gdk_key_to_imgui_key[] =98{99{ ImGuiKey_Tab, GDK_KEY_Tab },100{ ImGuiKey_Tab, GDK_KEY_ISO_Left_Tab },101{ ImGuiKey_LeftArrow, GDK_KEY_Left },102{ ImGuiKey_RightArrow, GDK_KEY_Right },103{ ImGuiKey_UpArrow, GDK_KEY_Up },104{ ImGuiKey_DownArrow, GDK_KEY_Down },105{ ImGuiKey_PageUp, GDK_KEY_Page_Up },106{ ImGuiKey_PageDown, GDK_KEY_Page_Down },107{ ImGuiKey_Home, GDK_KEY_Home },108{ ImGuiKey_End, GDK_KEY_End },109{ ImGuiKey_Delete, GDK_KEY_Delete },110{ ImGuiKey_Backspace, GDK_KEY_BackSpace },111{ ImGuiKey_Enter, GDK_KEY_Return },112{ ImGuiKey_Escape, GDK_KEY_Escape },113{ ImGuiKey_A, GDK_KEY_a },114{ ImGuiKey_C, GDK_KEY_c },115{ ImGuiKey_V, GDK_KEY_v },116{ ImGuiKey_X, GDK_KEY_x },117{ ImGuiKey_Y, GDK_KEY_y },118{ ImGuiKey_Z, GDK_KEY_z },119};120for (unsigned i = 0; i < ARRAY_SIZE(gdk_key_to_imgui_key); i++)121{122if (e->keyval == gdk_key_to_imgui_key[i].gdk)123io.KeysDown[gdk_key_to_imgui_key[i].imgui] = type == GDK_KEY_PRESS;124}125gunichar c = gdk_keyval_to_unicode(e->keyval);126if (g_unichar_isprint(c) && ImGuiKey_COUNT + c < ARRAY_SIZE(io.KeysDown))127io.KeysDown[ImGuiKey_COUNT + c] = type == GDK_KEY_PRESS;128129if (type == GDK_KEY_PRESS && e->string)130io.AddInputCharactersUTF8(e->string);131132struct {133bool *var;134GdkModifierType modifier;135guint keyvals[3];136} mods[] = {137{ &io.KeyCtrl, GDK_CONTROL_MASK,138{ GDK_KEY_Control_L, GDK_KEY_Control_R, 0 }, },139{ &io.KeyShift, GDK_SHIFT_MASK,140{ GDK_KEY_Shift_L, GDK_KEY_Shift_R, 0 }, },141{ &io.KeyAlt, GDK_MOD1_MASK,142{ GDK_KEY_Alt_L, GDK_KEY_Alt_R, 0 }, },143{ &io.KeySuper, GDK_SUPER_MASK,144{ GDK_KEY_Super_L, GDK_KEY_Super_R, 0 }, }145};146for (unsigned i = 0; i < ARRAY_SIZE(mods); i++)147{148*mods[i].var = (mods[i].modifier & e->state);149150bool match = false;151for (int j = 0; mods[i].keyvals[j] != 0; j++)152if (e->keyval == mods[i].keyvals[j])153match = true;154155if (match)156*mods[i].var = type == GDK_KEY_PRESS;157}158break;159}160default:161break;162}163164// We trigger 2 subsequent redraws for each event because of the165// way some ImGui widgets work. For example a Popup menu will only166// appear a frame after a click happened.167g_NumRedraws = 2;168169gtk_widget_queue_draw(g_GtkGlArea);170}171172static gboolean handle_gdk_event(GtkWidget *widget, GdkEvent *event, void *data)173{174ImGui_ImplGtk3_HandleEvent(event);175return TRUE;176}177178bool ImGui_ImplGtk3_Init(GtkWidget* gl_area, bool install_callbacks)179{180g_clear_pointer(&g_GtkGlArea, g_object_unref);181182g_GtkGlArea = GTK_WIDGET(g_object_ref(gl_area));183gtk_widget_realize(g_GtkGlArea);184gtk_widget_set_can_focus(g_GtkGlArea, TRUE);185gtk_widget_grab_focus(g_GtkGlArea);186187if (install_callbacks) {188gtk_widget_add_events(g_GtkGlArea, EVENT_MASK);189g_signal_connect(g_GtkGlArea, "event", G_CALLBACK(handle_gdk_event), NULL);190}191192ImGuiIO& io = ImGui::GetIO();193for (int i = 0; i < ImGuiKey_COUNT; i++)194{195io.KeyMap[i] = i;196}197198io.SetClipboardTextFn = ImGui_ImplGtk3_SetClipboardText;199io.GetClipboardTextFn = ImGui_ImplGtk3_GetClipboardText;200io.ClipboardUserData = gtk_widget_get_clipboard(g_GtkGlArea,201GDK_SELECTION_CLIPBOARD);202203return true;204}205206void ImGui_ImplGtk3_Shutdown()207{208g_clear_pointer(&g_GtkGlArea, g_object_unref);209if (g_RedrawTimeout)210g_source_remove(g_RedrawTimeout);211}212213static gboolean timeout_callback(gpointer data)214{215gtk_widget_queue_draw(g_GtkGlArea);216g_RedrawTimeout = 0;217return FALSE;218}219220static void kick_timeout_redraw(float timeout)221{222if (g_RedrawTimeout)223return;224g_RedrawTimeout = g_timeout_add(timeout * 1000, timeout_callback, NULL);225}226227void ImGui_ImplGtk3_NewFrame()228{229bool next_redraw = false;230if (g_NumRedraws > 0)231{232gtk_widget_queue_draw(g_GtkGlArea);233g_NumRedraws--;234next_redraw = true;235}236237ImGuiIO& io = ImGui::GetIO();238239// Setup display size (every frame to accommodate for window resizing)240io.DisplaySize = ImVec2((float)gtk_widget_get_allocated_width(g_GtkGlArea),241(float)gtk_widget_get_allocated_height(g_GtkGlArea));242int scale_factor = gtk_widget_get_scale_factor(g_GtkGlArea);243io.DisplayFramebufferScale = ImVec2(scale_factor, scale_factor);244245// Setup time step246guint64 current_time = g_get_monotonic_time();247io.DeltaTime = g_Time > 0 ? ((float)(current_time - g_Time) / 1000000) : (float)(1.0f/60.0f);248g_Time = current_time;249250// Setup inputs251if (gtk_widget_has_focus(g_GtkGlArea))252{253io.MousePos = g_MousePosition; // Mouse position in screen coordinates (set to -1,-1 if no mouse / on another screen, etc.)254}255else256{257io.MousePos = ImVec2(-1,-1);258}259260GdkWindow *window = gtk_widget_get_window(g_GtkGlArea);261GdkDevice *pointer = gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdk_display_get_default()));262GdkModifierType modifiers;263gdk_device_get_state(pointer, window, NULL, &modifiers);264265for (int i = 0; i < 3; i++)266{267io.MouseDown[i] = g_MousePressed[i] || (modifiers & (GDK_BUTTON1_MASK << i)) != 0;268g_MousePressed[i] = false;269}270271io.MouseWheel = g_MouseWheel;272g_MouseWheel = 0.0f;273274// Hide OS mouse cursor if ImGui is drawing it275GdkDisplay *display = gdk_window_get_display(window);276GdkCursor *cursor =277gdk_cursor_new_from_name(display, io.MouseDrawCursor ? "none" : "default");278gdk_window_set_cursor(window, cursor);279g_object_unref(cursor);280281if (!next_redraw && io.WantTextInput)282kick_timeout_redraw(0.2);283}284285286