Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added power saving mode (docking branch) #4076

Open
wants to merge 2 commits into
base: docking
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions backends/imgui_impl_allegro5.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

#include <stdint.h> // uint64_t
#include <cstring> // memcpy
#include <math.h> // isinf
#include "imgui.h"
#include "imgui_impl_allegro5.h"

Expand Down Expand Up @@ -320,6 +321,24 @@ void ImGui_ImplAllegro5_Shutdown()
g_ClipboardTextData = NULL;
}

void ImGui_ImplAllegro5_WaitForEvent(ALLEGRO_EVENT_QUEUE* queue)
{
if (!(ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_EnablePowerSavingMode))
return;

int display_flags = al_get_display_flags(g_Display);
bool window_is_hidden = display_flags & ALLEGRO_MINIMIZED;
double waiting_time = window_is_hidden ? INFINITY : ImGui::GetEventWaitingTime();
if (waiting_time > 0.0)
{
if (isinf(waiting_time))
al_wait_for_event(queue, NULL);
else
al_wait_for_event_timed(queue, NULL, waiting_time);
}
}


// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - 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.
Expand All @@ -328,6 +347,8 @@ bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* ev)
{
ImGuiIO& io = ImGui::GetIO();

io.FrameCountSinceLastInput = 0;

switch (ev->type)
{
case ALLEGRO_EVENT_MOUSE_AXES:
Expand Down
2 changes: 2 additions & 0 deletions backends/imgui_impl_allegro5.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
#include "imgui.h" // IMGUI_IMPL_API

struct ALLEGRO_DISPLAY;
struct ALLEGRO_EVENT_QUEUE;
union ALLEGRO_EVENT;

IMGUI_IMPL_API bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display);
IMGUI_IMPL_API void ImGui_ImplAllegro5_Shutdown();
IMGUI_IMPL_API void ImGui_ImplAllegro5_NewFrame();
IMGUI_IMPL_API void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data);
IMGUI_IMPL_API void ImGui_ImplAllegro5_WaitForEvent(ALLEGRO_EVENT_QUEUE* queue);
IMGUI_IMPL_API bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* event);

// Use if you want to reset your rendering device without losing Dear ImGui state.
Expand Down
39 changes: 39 additions & 0 deletions backends/imgui_impl_glfw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
#include "imgui.h"
#include "imgui_impl_glfw.h"

#include <math.h> // isinf

// GLFW
#include <GLFW/glfw3.h>
#ifdef _WIN32
Expand Down Expand Up @@ -91,6 +93,7 @@ static bool g_WantUpdateMonitors = true;
// Chain GLFW callbacks for main viewport: our callbacks will call the user's previously installed callbacks, if any.
static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL;
static GLFWscrollfun g_PrevUserCallbackScroll = NULL;
static GLFWcursorposfun g_PrevUserCallbackCursorPos = NULL;
static GLFWkeyfun g_PrevUserCallbackKey = NULL;
static GLFWcharfun g_PrevUserCallbackChar = NULL;
static GLFWmonitorfun g_PrevUserCallbackMonitor = NULL;
Expand All @@ -115,6 +118,9 @@ void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int acti
if (g_PrevUserCallbackMousebutton != NULL && window == g_Window)
g_PrevUserCallbackMousebutton(window, button, action, mods);

ImGuiIO& io = ImGui::GetIO();
io.FrameCountSinceLastInput = 0;

if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed))
g_MouseJustPressed[button] = true;
}
Expand All @@ -125,16 +131,31 @@ void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yo
g_PrevUserCallbackScroll(window, xoffset, yoffset);

ImGuiIO& io = ImGui::GetIO();
io.FrameCountSinceLastInput = 0;
io.MouseWheelH += (float)xoffset;
io.MouseWheel += (float)yoffset;
}

void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double xpos, double ypos)
{
if (g_PrevUserCallbackCursorPos != NULL)
g_PrevUserCallbackCursorPos(window, xpos, ypos);

ImGuiIO& io = ImGui::GetIO();
io.FrameCountSinceLastInput = 0;

// Here, we just take note of the event without actually processing the cursor position.
// This is done in ImGui_ImplGlfw_NewFrame() / ImGui_ImplGlfw_UpdateMousePosAndButtons().
}

void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (g_PrevUserCallbackKey != NULL && window == g_Window)
g_PrevUserCallbackKey(window, key, scancode, action, mods);

ImGuiIO& io = ImGui::GetIO();
io.FrameCountSinceLastInput = 0;

if (action == GLFW_PRESS)
{
io.KeysDown[key] = true;
Expand Down Expand Up @@ -163,6 +184,7 @@ void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
g_PrevUserCallbackChar(window, c);

ImGuiIO& io = ImGui::GetIO();
io.FrameCountSinceLastInput = 0;
io.AddInputCharacter(c);
}

Expand Down Expand Up @@ -248,6 +270,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
g_InstalledCallbacks = true;
g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
g_PrevUserCallbackCursorPos = glfwSetCursorPosCallback(window, ImGui_ImplGlfw_CursorPosCallback);
g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
g_PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
Expand Down Expand Up @@ -306,6 +329,22 @@ void ImGui_ImplGlfw_Shutdown()
g_ClientApi = GlfwClientApi_Unknown;
}

void ImGui_ImplGlfw_WaitForEvent()
{
if (!(ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_EnablePowerSavingMode))
return;

bool window_is_hidden = !glfwGetWindowAttrib(g_Window, GLFW_VISIBLE) || glfwGetWindowAttrib(g_Window, GLFW_ICONIFIED);
double waiting_time = window_is_hidden ? INFINITY : ImGui::GetEventWaitingTime();
if (waiting_time > 0.0)
{
if (isinf(waiting_time))
glfwWaitEvents();
else
glfwWaitEventsTimeout(waiting_time);
}
}

static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
{
// Update buttons
Expand Down
1 change: 1 addition & 0 deletions backends/imgui_impl_glfw.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool in
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
IMGUI_IMPL_API void ImGui_ImplGlfw_WaitForEvent();

// GLFW callbacks
// - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any.
Expand Down
24 changes: 24 additions & 0 deletions backends/imgui_impl_sdl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
#include "TargetConditionals.h"
#endif

#include <math.h> // isinf

#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE SDL_VERSION_ATLEAST(2,0,4)
#define SDL_HAS_WINDOW_ALPHA SDL_VERSION_ATLEAST(2,0,5)
#define SDL_HAS_ALWAYS_ON_TOP SDL_VERSION_ATLEAST(2,0,5)
Expand Down Expand Up @@ -97,6 +99,26 @@ static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
SDL_SetClipboardText(text);
}

void ImGui_ImplSDL2_WaitForEvent()
{
if (!(ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_EnablePowerSavingMode))
return;

Uint32 window_flags = SDL_GetWindowFlags(g_Window);
bool window_is_hidden = window_flags & (SDL_WINDOW_HIDDEN | SDL_WINDOW_MINIMIZED);
double waiting_time = window_is_hidden ? INFINITY : ImGui::GetEventWaitingTime();
if (waiting_time > 0.0)
{
if (isinf(waiting_time))
SDL_WaitEvent(NULL);
else
{
const int waiting_time_ms = (int)(1000.0 * ImGui::GetEventWaitingTime());
SDL_WaitEventTimeout(NULL, waiting_time_ms);
}
}
}

// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - 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.
Expand All @@ -105,6 +127,8 @@ static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
{
ImGuiIO& io = ImGui::GetIO();
io.FrameCountSinceLastInput = 0;

switch (event->type)
{
case SDL_MOUSEWHEEL:
Expand Down
1 change: 1 addition & 0 deletions backends/imgui_impl_sdl.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window);
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame(SDL_Window* window);
IMGUI_IMPL_API void ImGui_ImplSDL2_WaitForEvent();
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);
18 changes: 18 additions & 0 deletions backends/imgui_impl_win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <math.h> // isinf
#include <tchar.h>
#include <dwmapi.h>

Expand Down Expand Up @@ -384,6 +385,20 @@ void ImGui_ImplWin32_NewFrame()
ImGui_ImplWin32_UpdateGamepads();
}

void ImGui_ImplWin32_WaitForEvent()
{
if (!(ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_EnablePowerSavingMode))
return;

BOOL window_is_hidden = !IsWindowVisible(g_hWnd) || IsIconic(g_hWnd);
double waiting_time = window_is_hidden ? INFINITE : ImGui::GetEventWaitingTime();
if (waiting_time > 0.0)
{
DWORD waiting_time_ms = isinf(waiting_time) ? INFINITE : (DWORD)(1000.0 * waiting_time);
::MsgWaitForMultipleObjectsEx(0, NULL, waiting_time_ms, QS_ALLINPUT, MWMO_INPUTAVAILABLE|MWMO_ALERTABLE);
}
}

// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions.
#ifndef WM_MOUSEHWHEEL
#define WM_MOUSEHWHEEL 0x020E
Expand All @@ -410,6 +425,9 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
return 0;

ImGuiIO& io = ImGui::GetIO();

io.FrameCountSinceLastInput = 0;

switch (msg)
{
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
Expand Down
1 change: 1 addition & 0 deletions backends/imgui_impl_win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd);
IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown();
IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame();
IMGUI_IMPL_API void ImGui_ImplWin32_WaitForEvent();

// Win32 message handler your application need to call.
// - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on <windows.h> from this helper.
Expand Down
3 changes: 0 additions & 3 deletions docs/TODO.txt
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- inputs/io: clarify/standardize/expose repeat rate and repeat delays (#1808)
- inputs/scrolling: support for smooth scrolling (#2462, #2569)

- misc: idle: expose "woken up" boolean (set by inputs) and/or animation time (for cursor blink) for backend to be able stop refreshing easily.
- misc: idle: if cursor blink if the _only_ visible animation, core imgui could rewrite vertex alpha to avoid CPU pass on ImGui:: calls.
- misc: idle: if cursor blink if the _only_ visible animation, could even expose a dirty rectangle that optionally can be leverage by some app to render in a smaller viewport, getting rid of much pixel shading cost.
- misc: no way to run a root-most GetID() with ImGui:: api since there's always a Debug window in the stack. (mentioned in #2960)
Expand All @@ -423,12 +422,10 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- demo: window size constraint: square demo is broken when resizing from edges (#1975), would need to rework the callback system to solve this

- examples: window minimize, maximize (#583)
- examples: provide a zero frame-rate/idle example.
- examples: dx11/dx12: try to use new swapchain blit models (#2970)
- backends: move to backends/ folder?
- backends: report it better when not able to create texture?
- backends: apple: example_apple should be using modern GL3.
- backends: glfw: could go idle when minimized? if (glfwGetWindowAttrib(window, GLFW_ICONIFIED)) { glfwWaitEvents(); continue; } // issue: DeltaTime will be super high on resume, perhaps provide a way to let impl know (#440)
- backends: opengl: rename imgui_impl_opengl2 to impl_opengl_legacy and imgui_impl_opengl3 to imgui_impl_opengl? (#1900)
- backends: opengl: could use a single vertex buffer and glBufferSubData for uploads?
- backends: opengl: explicitly disable GL_STENCIL_TEST in bindings.
Expand Down
2 changes: 2 additions & 0 deletions examples/example_allegro5/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ 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.
ImGui_ImplAllegro5_WaitForEvent(queue);
ALLEGRO_EVENT ev;
while (al_get_next_event(queue, &ev))
{
Expand Down Expand Up @@ -107,6 +108,7 @@ int main(int, char**)
ImGui::Text("counter = %d", counter);

ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Text("Frames since last input: %d", ImGui::GetIO().FrameCountSinceLastInput);
ImGui::End();
}

Expand Down
2 changes: 2 additions & 0 deletions examples/example_glfw_opengl3/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ 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.
ImGui_ImplGlfw_WaitForEvent();
glfwPollEvents();

// Start the Dear ImGui frame
Expand Down Expand Up @@ -198,6 +199,7 @@ int main(int, char**)
ImGui::Text("counter = %d", counter);

ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Text("Frames since last input: %d", ImGui::GetIO().FrameCountSinceLastInput);
ImGui::End();
}

Expand Down
2 changes: 2 additions & 0 deletions examples/example_sdl_opengl3/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ 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.
ImGui_ImplSDL2_WaitForEvent();
SDL_Event event;
while (SDL_PollEvent(&event))
{
Expand Down Expand Up @@ -203,6 +204,7 @@ int main(int, char**)
ImGui::Text("counter = %d", counter);

ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Text("Frames since last input: %d", ImGui::GetIO().FrameCountSinceLastInput);
ImGui::End();
}

Expand Down
5 changes: 4 additions & 1 deletion examples/example_win32_directx11/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ int main(int, char**)
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);

// Main loop
MSG msg;
ZeroMemory(&msg, sizeof(msg));
bool done = false;
while (!done)
{
Expand All @@ -103,7 +105,7 @@ 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.
MSG msg;
ImGui_ImplWin32_WaitForEvent();
while (::PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
::TranslateMessage(&msg);
Expand Down Expand Up @@ -143,6 +145,7 @@ int main(int, char**)
ImGui::Text("counter = %d", counter);

ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Text("Frames since last input: %d", ImGui::GetIO().FrameCountSinceLastInput);
ImGui::End();
}

Expand Down
19 changes: 19 additions & 0 deletions imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4012,6 +4012,23 @@ ImGuiKeyModFlags ImGui::GetMergedKeyModFlags()
return key_mod_flags;
}

double ImGui::GetEventWaitingTime()
{
ImGuiContext& g = *GImGui;

if ((g.IO.ConfigFlags & ImGuiConfigFlags_EnablePowerSavingMode) && g.IO.FrameCountSinceLastInput > 2)
return ImMax(0.0, g.MaxWaitBeforeNextFrame);

return 0.0;
}

void ImGui::SetMaxWaitBeforeNextFrame(double time)
{
ImGuiContext& g = *GImGui;

g.MaxWaitBeforeNextFrame = ImMin(g.MaxWaitBeforeNextFrame, time);
}

void ImGui::NewFrame()
{
IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
Expand Down Expand Up @@ -4039,6 +4056,7 @@ void ImGui::NewFrame()
g.TooltipOverrideCount = 0;
g.WindowsActiveCount = 0;
g.MenusIdSubmittedThisFrame.resize(0);
g.MaxWaitBeforeNextFrame = INFINITY;

// Calculate frame-rate for the user, as a purely luxurious feature
g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx];
Expand Down Expand Up @@ -4647,6 +4665,7 @@ void ImGui::EndFrame()
// End frame
g.WithinFrameScope = false;
g.FrameCountEnded = g.FrameCount;
g.IO.FrameCountSinceLastInput++;

// Initiate moving window + handle left-click and right-click focus
UpdateMouseMovingWindowEndFrame();
Expand Down
Loading