From 6dc4d6ca09d263da94b8fadfc182bec2488da983 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 11 Jun 2019 16:16:14 -0700 Subject: [PATCH] Add refresh callback to GLFW shell (#9280) In some cases, the window needs to be redrawn without a resize. This adds a callback for that case to trigger a repaint. Since there's no embedding API for repainting, trigger it with a window metrics event using the current window size. Fixes https://github.com/flutter/flutter/issues/30731 --- shell/platform/glfw/flutter_glfw.cc | 55 +++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/shell/platform/glfw/flutter_glfw.cc b/shell/platform/glfw/flutter_glfw.cc index 699f8cba7..24caf6af1 100644 --- a/shell/platform/glfw/flutter_glfw.cc +++ b/shell/platform/glfw/flutter_glfw.cc @@ -96,6 +96,10 @@ struct FlutterDesktopWindow { // The ratio of pixels per screen coordinate for the window. double pixels_per_screen_coordinate = 1.0; + + // Resizing triggers a window refresh, but the resize already updates Flutter. + // To avoid double messages, the refresh after each resize is skipped. + bool skip_next_window_refresh = false; }; // Struct for storing state of a Flutter engine instance. @@ -166,31 +170,53 @@ static double GetScreenCoordinatesPerInch() { return primary_monitor_mode->width / (primary_monitor_width_mm / 25.4); } +// Sends a window metrics update to the Flutter engine using the given +// framebuffer size and the current window information in |state|. +static void SendWindowMetrics(FlutterDesktopWindowControllerState* state, + int width, + int height) { + double dpi = state->window_wrapper->pixels_per_screen_coordinate * + state->monitor_screen_coordinates_per_inch; + + FlutterWindowMetricsEvent event = {}; + event.struct_size = sizeof(event); + event.width = width; + event.height = height; + // The Flutter pixel_ratio is defined as DPI/dp. Limit the ratio to a minimum + // of 1 to avoid rendering a smaller UI on standard resolution monitors. + event.pixel_ratio = std::max(dpi / kDpPerInch, 1.0); + FlutterEngineSendWindowMetricsEvent(state->engine, &event); +} + // When GLFW calls back to the window with a framebuffer size change, notify // FlutterEngine about the new window metrics. -// The Flutter pixel_ratio is defined as DPI/dp. static void GLFWFramebufferSizeCallback(GLFWwindow* window, int width_px, int height_px) { int width; glfwGetWindowSize(window, &width, nullptr); - - auto state = GetSavedWindowState(window); + auto* state = GetSavedWindowState(window); state->window_wrapper->pixels_per_screen_coordinate = width > 0 ? width_px / width : 1; - double dpi = state->window_wrapper->pixels_per_screen_coordinate * - state->monitor_screen_coordinates_per_inch; - // Limit the ratio to 1 to avoid rendering a smaller UI in standard resolution - // monitors. - double pixel_ratio = std::max(dpi / kDpPerInch, 1.0); + SendWindowMetrics(state, width_px, height_px); + state->window_wrapper->skip_next_window_refresh = true; +} - FlutterWindowMetricsEvent event = {}; - event.struct_size = sizeof(event); - event.width = width_px; - event.height = height_px; - event.pixel_ratio = pixel_ratio; - FlutterEngineSendWindowMetricsEvent(state->engine, &event); +// Indicates that the window needs to be redrawn. +void GLFWWindowRefreshCallback(GLFWwindow* window) { + auto* state = GetSavedWindowState(window); + if (state->window_wrapper->skip_next_window_refresh) { + state->window_wrapper->skip_next_window_refresh = false; + return; + } + // There's no engine API to request a redraw explicitly, so instead send a + // window metrics event with the current size to trigger it. + int width_px, height_px; + glfwGetFramebufferSize(window, &width_px, &height_px); + if (width_px > 0 && height_px > 0) { + SendWindowMetrics(state, width_px, height_px); + } } // Sends a pointer event to the Flutter engine based on the given data. @@ -589,6 +615,7 @@ FlutterDesktopWindowControllerRef FlutterDesktopCreateWindow( // Set up GLFW callbacks for the window. glfwSetFramebufferSizeCallback(window, GLFWFramebufferSizeCallback); + glfwSetWindowRefreshCallback(window, GLFWWindowRefreshCallback); GLFWAssignEventCallbacks(window); return state.release(); -- GitLab