Add MessageLoop to avoid 100% CPU in foreground windows.

This commit is contained in:
David Capello 2012-07-09 18:31:06 -03:00
parent 5529c62c9f
commit 8e7b16c3b1
7 changed files with 83 additions and 31 deletions

View File

@ -27,6 +27,7 @@ add_library(ui-lib
manager.cpp manager.cpp
menu.cpp menu.cpp
message.cpp message.cpp
message_loop.cpp
paint_event.cpp paint_event.cpp
popup_window.cpp popup_window.cpp
preferred_size_event.cpp preferred_size_event.cpp

View File

@ -32,6 +32,7 @@
#include "ui/manager.h" #include "ui/manager.h"
#include "ui/menu.h" #include "ui/menu.h"
#include "ui/message.h" #include "ui/message.h"
#include "ui/message_loop.h"
#include "ui/paint_event.h" #include "ui/paint_event.h"
#include "ui/popup_window.h" #include "ui/popup_window.h"
#include "ui/preferred_size_event.h" #include "ui/preferred_size_event.h"

View File

@ -11,8 +11,6 @@
#include "ui/manager.h" #include "ui/manager.h"
#include "base/chrono.h"
#include "base/thread.h"
#include "ui/gui.h" #include "ui/gui.h"
#include "ui/intern.h" #include "ui/intern.h"
@ -186,27 +184,10 @@ Manager::~Manager()
void Manager::run() void Manager::run()
{ {
base::Chrono chrono; MessageLoop loop(this);
while (!jlist_empty(this->children)) { while (!jlist_empty(this->children))
chrono.reset(); loop.pumpMessages();
if (generateMessages()) {
dispatchMessages();
}
else if (!m_garbage.empty()) {
collectGarbage();
}
// If the dispatching of messages was faster than 10 milliseconds,
// it means that the process is not using a lot of CPU, so we can
// wait the difference to cover those 10 milliseconds
// sleeping. With this code we can avoid 100% CPU usage (a
// property of Allegro 4 polling nature).
double elapsedMSecs = chrono.elapsed() * 1000.0;
if (elapsedMSecs > 0.0 && elapsedMSecs < 10.0)
base::this_thread::sleep_for((10.0 - elapsedMSecs) / 1000.0);
}
} }
bool Manager::generateMessages() bool Manager::generateMessages()
@ -1196,6 +1177,9 @@ void Manager::invalidateDisplayRegion(const JRegion region)
void Manager::collectGarbage() void Manager::collectGarbage()
{ {
if (m_garbage.empty())
return;
for (WidgetsList::iterator for (WidgetsList::iterator
it = m_garbage.begin(), it = m_garbage.begin(),
end = m_garbage.end(); it != end; ++it) { end = m_garbage.end(); it != end; ++it) {

View File

@ -28,12 +28,11 @@ namespace ui {
// Returns true if there are messages in the queue to be // Returns true if there are messages in the queue to be
// distpatched through jmanager_dispatch_messages(). // distpatched through jmanager_dispatch_messages().
bool generateMessages(); bool generateMessages();
void dispatchMessages(); void dispatchMessages();
void enqueueMessage(Message* msg);
void addToGarbage(Widget* widget); void addToGarbage(Widget* widget);
void collectGarbage();
void enqueueMessage(Message* msg);
Window* getTopWindow(); Window* getTopWindow();
Window* getForegroundWindow(); Window* getForegroundWindow();
@ -72,7 +71,6 @@ namespace ui {
private: private:
void layoutManager(JRect rect); void layoutManager(JRect rect);
void pumpQueue(); void pumpQueue();
void collectGarbage();
void generateSetCursorMessage(); void generateSetCursorMessage();
static void removeWidgetFromDests(Widget* widget, Message* msg); static void removeWidgetFromDests(Widget* widget, Message* msg);
static bool someParentIsFocusStop(Widget* widget); static bool someParentIsFocusStop(Widget* widget);

43
src/ui/message_loop.cpp Normal file
View File

@ -0,0 +1,43 @@
// ASEPRITE gui library
// Copyright (C) 2001-2012 David Capello
//
// This source file is ditributed under a BSD-like license, please
// read LICENSE.txt for more information.
#include "config.h"
#include "ui/message_loop.h"
#include "base/chrono.h"
#include "base/thread.h"
#include "ui/manager.h"
namespace ui {
MessageLoop::MessageLoop(Manager* manager)
: m_manager(manager)
{
}
void MessageLoop::pumpMessages()
{
base::Chrono chrono;
if (m_manager->generateMessages()) {
m_manager->dispatchMessages();
}
else {
m_manager->collectGarbage();
}
// If the dispatching of messages was faster than 10 milliseconds,
// it means that the process is not using a lot of CPU, so we can
// wait the difference to cover those 10 milliseconds
// sleeping. With this code we can avoid 100% CPU usage (a
// property of Allegro 4 polling nature).
double elapsedMSecs = chrono.elapsed() * 1000.0;
if (elapsedMSecs > 0.0 && elapsedMSecs < 10.0)
base::this_thread::sleep_for((10.0 - elapsedMSecs) / 1000.0);
}
} // namespace ui

27
src/ui/message_loop.h Normal file
View File

@ -0,0 +1,27 @@
// ASEPRITE gui library
// Copyright (C) 2001-2012 David Capello
//
// This source file is ditributed under a BSD-like license, please
// read LICENSE.txt for more information.
#ifndef UI_MESSAGE_LOOP_H_INCLUDED
#define UI_MESSAGE_LOOP_H_INCLUDED
namespace ui {
class Manager;
class MessageLoop
{
public:
MessageLoop(Manager* manager);
void pumpMessages();
private:
Manager* m_manager;
};
} // namespace ui
#endif

View File

@ -233,14 +233,12 @@ void Window::openWindowInForeground()
{ {
openWindow(); openWindow();
Manager* manager = getManager(); MessageLoop loop(getManager());
m_is_foreground = true; m_is_foreground = true;
while (!(this->flags & JI_HIDDEN)) { while (!(this->flags & JI_HIDDEN))
if (manager->generateMessages()) loop.pumpMessages();
manager->dispatchMessages();
}
m_is_foreground = false; m_is_foreground = false;
} }