Win32: Add support to convert mouse messages (WM_) to ui::Messages (using she::Events)

On Windows, instead of polling Allegro mouse position/buttons we can use
the mouse messages (WM_*) directly to generate she::Events. Those events
are received by the ui::Manager and converted to ui::Messages.
Maybe this is a possible fix for issue #133 (Wacom tablets don't work
properly).

Changes:
- Don't use jmouse_z() directly (new ui::MouseMessage::wheelDelta() member)
- Add ui::_internal_set_mouse_position() to change the jmouse_x/y(0)
  from the new mouse position received in she::Events. The same for
  ui::_internal_set_mouse_buttons().
- Modify the ui::Manager to generate mouse events in any case: using old
  Allegro 4 polling method, or from she::Events.
This commit is contained in:
David Capello 2014-04-17 22:23:12 -03:00
parent 2e9751fef1
commit dd2ce20e25
20 changed files with 473 additions and 196 deletions

View File

@ -215,6 +215,7 @@ if(WIN32)
shlwapi
psapi
wininet
comctl32
dbghelp
)

View File

@ -262,7 +262,7 @@ bool StandbyState::onMouseMove(Editor* editor, MouseMessage* msg)
bool StandbyState::onMouseWheel(Editor* editor, MouseMessage* msg)
{
int dz = jmouse_z(1) - jmouse_z(0);
int dz = -msg->wheelDelta();
WHEEL_ACTION wheelAction = WHEEL_NONE;
bool scrollBigSteps = false;

View File

@ -273,7 +273,7 @@ bool FileList::onProcessMessage(Message* msg)
View* view = View::getView(this);
if (view) {
gfx::Point scroll = view->getViewScroll();
scroll.y += (jmouse_z(1)-jmouse_z(0)) * 3*(2+getTextHeight()+2);
scroll.y += -static_cast<MouseMessage*>(msg)->wheelDelta() * 3*(2+getTextHeight()+2);
view->setViewScroll(scroll);
}
break;

View File

@ -255,7 +255,7 @@ bool PaletteView::onProcessMessage(Message* msg)
View* view = View::getView(this);
if (view) {
gfx::Point scroll = view->getViewScroll();
scroll.y += (jmouse_z(1)-jmouse_z(0)) * 3 * m_boxsize;
scroll.y += -static_cast<MouseMessage*>(msg)->wheelDelta() * 3 * m_boxsize;
view->setViewScroll(scroll);
}
break;

View File

@ -286,7 +286,7 @@ bool Tabs::onProcessMessage(Message* msg)
return true;
case kMouseWheelMessage: {
int dx = (jmouse_z(1) - jmouse_z(0)) * getBounds().w/6;
int dx = -static_cast<MouseMessage*>(msg)->wheelDelta() * getBounds().w/6;
// setScrollX(m_scrollX+dx);
m_begScrollX = m_scrollX;

View File

@ -739,7 +739,7 @@ bool Timeline::onProcessMessage(Message* msg)
case kMouseWheelMessage:
if (m_document) {
int dz = jmouse_z(1) - jmouse_z(0);
int dz = -static_cast<MouseMessage*>(msg)->wheelDelta();
int dx = 0;
int dy = 0;

View File

@ -254,7 +254,7 @@ bool ToolBar::onProcessMessage(Message* msg)
MouseMessage* mouseMsg2 = new MouseMessage(
kMouseDownMessage,
mouseMsg->buttons(),
mouseMsg->position());
mouseMsg->position(), 0);
mouseMsg2->addRecipient(strip);
getManager()->enqueueMessage(mouseMsg2);
}
@ -712,7 +712,7 @@ bool ToolBar::ToolStrip::onProcessMessage(Message* msg)
MouseMessage* mouseMsg2 = new MouseMessage(
kMouseDownMessage,
mouseMsg->buttons(),
mouseMsg->position());
mouseMsg->position(), 0);
mouseMsg2->addRecipient(bar);
getManager()->enqueueMessage(mouseMsg2);
}

View File

@ -13,7 +13,8 @@ namespace she {
enum Capabilities {
kMultipleDisplaysCapability = 1,
kCanResizeDisplayCapability = 2,
kDisplayScaleCapability = 4
kDisplayScaleCapability = 4,
kMouseEventsCapability = 8,
};
} // namespace she

View File

@ -8,6 +8,8 @@
#define SHE_EVENT_H_INCLUDED
#pragma once
#include "gfx/point.h"
#include <string>
#include <vector>
@ -18,6 +20,20 @@ namespace she {
enum Type {
None,
DropFiles,
MouseEnter,
MouseLeave,
MouseMove,
MouseDown,
MouseUp,
MouseWheel,
MouseDoubleClick,
};
enum MouseButton {
NoneButton,
LeftButton,
RightButton,
MiddleButton
};
typedef std::vector<std::string> Files;
@ -25,14 +41,23 @@ namespace she {
Event() : m_type(None) { }
int type() const { return m_type; }
void setType(Type type) { m_type = type; }
const Files& files() const { return m_files; }
gfx::Point position() const { return m_position; }
MouseButton button() const { return m_button; }
int delta() const { return m_delta; }
void setType(Type type) { m_type = type; }
void setFiles(const Files& files) { m_files = files; }
void setPosition(const gfx::Point& pos) { m_position = pos; }
void setButton(MouseButton button) { m_button = button; }
void setDelta(int delta) { m_delta = delta; }
private:
Type m_type;
Files m_files;
gfx::Point m_position;
MouseButton m_button;
int m_delta;
};
} // namespace she

View File

@ -11,6 +11,7 @@
#include "she.h"
#include "base/compiler_specific.h"
#include "base/concurrent_queue.h"
#include "base/string.h"
#include <allegro.h>
@ -19,6 +20,9 @@
#ifdef WIN32
#include <winalleg.h>
#include <windowsx.h>
#include <commctrl.h>
#if defined STRICT || defined __GNUC__
typedef WNDPROC wndproc_t;
#else
@ -36,6 +40,7 @@
#include <cassert>
#include <vector>
#include <list>
#define DISPLAY_FLAG_FULL_REFRESH 1
#define DISPLAY_FLAG_WINDOW_RESIZE 2
@ -153,20 +158,19 @@ public:
}
void getEvent(Event& event) {
if (m_events.size() > 0) {
event = m_events[0];
m_events.erase(m_events.begin());
}
else
if (!m_events.try_pop(event))
event.setType(Event::None);
}
void queueEvent(const Event& event) {
m_events.push_back(event);
m_events.push(event);
}
private:
std::vector<Event> m_events;
// We need a concurrent queue because events are generated in one
// thread (the thread created by Allegro 4 for the HWND), and
// consumed in the other thread (the main/program logic thread).
base::concurrent_queue<Event> m_events;
};
#if WIN32
@ -174,35 +178,137 @@ namespace {
Display* unique_display = NULL;
wndproc_t base_wndproc = NULL;
bool display_has_mouse = false;
int display_scale;
static void queue_event(Event& ev)
{
static_cast<Alleg4EventQueue*>(unique_display->getEventQueue())->queueEvent(ev);
}
static LRESULT CALLBACK wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg) {
case WM_DROPFILES:
{
HDROP hdrop = (HDROP)(wparam);
Event::Files files;
case WM_DROPFILES: {
HDROP hdrop = (HDROP)(wparam);
Event::Files files;
int count = DragQueryFile(hdrop, 0xFFFFFFFF, NULL, 0);
for (int index=0; index<count; ++index) {
int length = DragQueryFile(hdrop, index, NULL, 0);
if (length > 0) {
std::vector<TCHAR> str(length+1);
DragQueryFile(hdrop, index, &str[0], str.size());
files.push_back(base::to_utf8(&str[0]));
}
int count = DragQueryFile(hdrop, 0xFFFFFFFF, NULL, 0);
for (int index=0; index<count; ++index) {
int length = DragQueryFile(hdrop, index, NULL, 0);
if (length > 0) {
std::vector<TCHAR> str(length+1);
DragQueryFile(hdrop, index, &str[0], str.size());
files.push_back(base::to_utf8(&str[0]));
}
DragFinish(hdrop);
Event ev;
ev.setType(Event::DropFiles);
ev.setFiles(files);
static_cast<Alleg4EventQueue*>(unique_display->getEventQueue())
->queueEvent(ev);
}
DragFinish(hdrop);
Event ev;
ev.setType(Event::DropFiles);
ev.setFiles(files);
queue_event(ev);
break;
}
case WM_MOUSEMOVE: {
Event ev;
ev.setPosition(gfx::Point(
GET_X_LPARAM(lparam) / display_scale,
GET_Y_LPARAM(lparam) / display_scale));
if (!display_has_mouse) {
display_has_mouse = true;
ev.setType(Event::MouseEnter);
queue_event(ev);
// Track mouse to receive WM_MOUSELEAVE message.
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hwnd;
_TrackMouseEvent(&tme);
}
ev.setType(Event::MouseMove);
queue_event(ev);
break;
}
case WM_MOUSELEAVE: {
display_has_mouse = false;
Event ev;
ev.setType(Event::MouseLeave);
queue_event(ev);
break;
}
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN: {
Event ev;
ev.setType(Event::MouseDown);
ev.setPosition(gfx::Point(
GET_X_LPARAM(lparam) / display_scale,
GET_Y_LPARAM(lparam) / display_scale));
ev.setButton(
msg == WM_LBUTTONDOWN ? Event::LeftButton:
msg == WM_RBUTTONDOWN ? Event::RightButton:
msg == WM_MBUTTONDOWN ? Event::MiddleButton: Event::NoneButton);
queue_event(ev);
break;
}
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP: {
Event ev;
ev.setType(Event::MouseUp);
ev.setPosition(gfx::Point(
GET_X_LPARAM(lparam) / display_scale,
GET_Y_LPARAM(lparam) / display_scale));
ev.setButton(
msg == WM_LBUTTONUP ? Event::LeftButton:
msg == WM_RBUTTONUP ? Event::RightButton:
msg == WM_MBUTTONUP ? Event::MiddleButton: Event::NoneButton);
queue_event(ev);
break;
}
case WM_LBUTTONDBLCLK:
case WM_MBUTTONDBLCLK:
case WM_RBUTTONDBLCLK: {
Event ev;
ev.setType(Event::MouseDoubleClick);
ev.setPosition(gfx::Point(
GET_X_LPARAM(lparam) / display_scale,
GET_Y_LPARAM(lparam) / display_scale));
ev.setButton(
msg == WM_LBUTTONDBLCLK ? Event::LeftButton:
msg == WM_RBUTTONDBLCLK ? Event::RightButton:
msg == WM_MBUTTONDBLCLK ? Event::MiddleButton: Event::NoneButton);
queue_event(ev);
break;
}
case WM_MOUSEWHEEL: {
RECT rc;
::GetWindowRect(hwnd, &rc);
Event ev;
ev.setType(Event::MouseWheel);
ev.setPosition((gfx::Point(
GET_X_LPARAM(lparam),
GET_Y_LPARAM(lparam)) - gfx::Point(rc.left, rc.top))
/ display_scale);
ev.setDelta(((short)HIWORD(wparam)) / WHEEL_DELTA);
queue_event(ev);
break;
}
}
return ::CallWindowProc(base_wndproc, hwnd, msg, wparam, lparam);
@ -306,6 +412,7 @@ public:
void setScale(int scale) OVERRIDE {
ASSERT(scale >= 1);
display_scale = scale;
if (m_scale == scale)
return;
@ -403,7 +510,12 @@ public:
}
Capabilities capabilities() const {
return kCanResizeDisplayCapability;
return (Capabilities)
(kCanResizeDisplayCapability
#ifdef WIN32
| kMouseEventsCapability
#endif
);
}
Display* createDisplay(int width, int height, int scale) {

View File

@ -436,8 +436,7 @@ bool ComboBoxEntry::onProcessMessage(Message* msg)
releaseMouse();
MouseMessage mouseMsg2(kMouseDownMessage,
mouseMsg->buttons(),
mouseMsg->position());
mouseMsg->buttons(), mouseMsg->position(), 0);
pick->sendMessage(&mouseMsg2);
return true;
}

View File

@ -84,7 +84,7 @@ bool IntEntry::onProcessMessage(Message* msg)
MouseMessage mouseMsg2(kMouseDownMessage,
mouseMsg->buttons(),
mouseMsg->position());
mouseMsg->position(), 0);
m_slider->sendMessage(&mouseMsg2);
}
}
@ -93,7 +93,7 @@ bool IntEntry::onProcessMessage(Message* msg)
case kMouseWheelMessage:
if (isEnabled()) {
int oldValue = getValue();
int newValue = oldValue + jmouse_z(0) - jmouse_z(1);
int newValue = oldValue + static_cast<MouseMessage*>(msg)->wheelDelta();
newValue = MID(m_min, newValue, m_max);
if (newValue != oldValue) {
setValue(newValue);

View File

@ -185,7 +185,7 @@ bool ListBox::onProcessMessage(Message* msg)
View* view = View::getView(this);
if (view) {
gfx::Point scroll = view->getViewScroll();
scroll.y += (jmouse_z(1) - jmouse_z(0)) * getTextHeight()*3;
scroll.y += -static_cast<MouseMessage*>(msg)->wheelDelta() * getTextHeight()*3;
view->setViewScroll(scroll);
}
break;

View File

@ -17,6 +17,7 @@
#include "she/display.h"
#include "she/event.h"
#include "she/event_queue.h"
#include "she/system.h"
#include "ui/intern.h"
#include "ui/ui.h"
@ -65,6 +66,8 @@ struct Filter
typedef std::list<Message*> Messages;
typedef std::list<Filter*> Filters;
static bool mouse_events_from_she;
static int double_click_level;
static MouseButtons double_click_buttons;
static int double_click_ticks;
@ -114,6 +117,7 @@ Manager::Manager()
, m_clipboard(NULL)
, m_eventQueue(NULL)
, m_lockedWindow(NULL)
, m_mouseButtons(kButtonNone)
{
if (!m_defaultManager) {
// Hook the window close message
@ -145,8 +149,13 @@ Manager::Manager()
setVisible(true);
// Default manager is the first one (and is always visible).
if (!m_defaultManager)
if (!m_defaultManager) {
m_defaultManager = this;
mouse_events_from_she =
((she::Instance()->capabilities() & she::kMouseEventsCapability)
== she::kMouseEventsCapability);
}
}
Manager::~Manager()
@ -202,10 +211,6 @@ void Manager::run()
bool Manager::generateMessages()
{
Widget* widget;
Widget* window;
int c;
// Poll keyboard
poll_keyboard();
@ -223,7 +228,7 @@ bool Manager::generateMessages()
// New windows to show?
if (!new_windows.empty()) {
UI_FOREACH_WIDGET(new_windows, it) {
window = *it;
Widget* window = *it;
// Relayout
window->layout();
@ -246,56 +251,46 @@ bool Manager::generateMessages()
new_windows.clear();
}
if (!mouse_events_from_she)
generateMouseMessages();
// Generate Close message when the user press close button on the system window.
if (want_close_stage == STAGE_WANT_CLOSE) {
want_close_stage = STAGE_NORMAL;
Message* msg = new Message(kCloseAppMessage);
msg->broadcastToChildren(this);
enqueueMessage(msg);
}
generateKeyMessages();
generateMessagesFromSheEvents();
// Generate messages for timers
Timer::pollTimers();
// Generate redraw events.
flushRedraw();
if (!msg_queue.empty())
return true;
else
return false;
}
void Manager::generateMouseMessages()
{
// Update mouse status
bool mousemove = jmouse_poll();
if (mousemove || !mouse_widget) {
// Get the list of widgets to send mouse messages.
mouse_widgets_list.clear();
broadcastMouseMessage(mouse_widgets_list);
// Get the widget under the mouse
widget = NULL;
gfx::Point mousePos(gfx::Point(jmouse_x(0), jmouse_y(0)));
UI_FOREACH_WIDGET(mouse_widgets_list, it) {
widget = (*it)->pick(gfx::Point(jmouse_x(0), jmouse_y(0)));
if (widget)
break;
}
// Fixup "mouse" flag
if (widget != mouse_widget) {
if (!widget)
freeMouse();
else
setMouse(widget);
}
// Mouse movement
if (mousemove) {
Widget* dst;
// Reset double click status
double_click_level = DOUBLE_CLICK_NONE;
if (capture_widget)
dst = capture_widget;
else
dst = mouse_widget;
// Send the mouse movement message
enqueueMessage(newMouseMessage(kMouseMoveMessage, dst,
currentMouseButtons(0)));
generateSetCursorMessage();
}
}
if (mousemove || !mouse_widget)
handleMouseMove(mousePos, currentMouseButtons(0));
// Mouse wheel
if (jmouse_z(0) != jmouse_z(1)) {
enqueueMessage(newMouseMessage(kMouseWheelMessage,
capture_widget ? capture_widget:
mouse_widget,
currentMouseButtons(0)));
}
if (jmouse_z(0) != jmouse_z(1))
handleMouseWheel(mousePos, currentMouseButtons(0), jmouse_z(0) - jmouse_z(1));
// Mouse clicks
if (jmouse_b(0) != jmouse_b(1)) {
@ -359,63 +354,34 @@ bool Manager::generateMessages()
}
}
// Handle Z order: Send the window to top (only when you click in
// a window that aren't the desktop).
if (msgType == kMouseDownMessage && !capture_widget && mouse_widget) {
// The clicked window
Window* window = mouse_widget->getRoot();
Manager* win_manager = (window ? window->getManager(): NULL);
if ((window) &&
// We cannot change Z-order of desktop windows
(!window->isDesktop()) &&
// We cannot change Z order of foreground windows because a
// foreground window can launch other background windows
// which should be kept on top of the foreground one.
(!window->isForeground()) &&
// If the window is not already the top window of the manager.
(window != win_manager->getTopWindow())) {
base::ScopedValue<Widget*> scoped(m_lockedWindow, window, NULL);
// Put it in the top of the list
win_manager->removeChild(window);
if (window->isOnTop())
win_manager->insertChild(0, window);
else {
int pos = (int)win_manager->getChildren().size();
UI_FOREACH_WIDGET_BACKWARD(win_manager->getChildren(), it) {
if (static_cast<Window*>(*it)->isOnTop())
break;
--pos;
}
win_manager->insertChild(pos, window);
}
window->invalidate();
}
// Put the focus
setFocus(mouse_widget);
switch (msgType) {
case kMouseDownMessage:
handleMouseDown(mousePos, mouseButtons);
break;
case kMouseUpMessage:
handleMouseUp(mousePos, mouseButtons);
break;
case kDoubleClickMessage:
handleMouseDoubleClick(mousePos, mouseButtons);
break;
}
enqueueMessage(newMouseMessage(msgType,
capture_widget ? capture_widget:
mouse_widget,
mouseButtons));
}
}
// Generate Close message when the user press close button on the system window.
if (want_close_stage == STAGE_WANT_CLOSE) {
want_close_stage = STAGE_NORMAL;
Message* msg = new Message(kCloseAppMessage);
msg->broadcastToChildren(this);
enqueueMessage(msg);
}
void Manager::generateSetCursorMessage(const gfx::Point& mousePos)
{
Widget* dst = (capture_widget ? capture_widget: mouse_widget);
if (dst)
enqueueMessage(newMouseMessage(kSetCursorMessage, dst,
mousePos, currentMouseButtons(0)));
else
jmouse_set_cursor(kArrowCursor);
}
void Manager::generateKeyMessages()
{
// Generate kKeyDownMessage messages.
int c;
while (keypressed()) {
int scancode;
int unicode_char = ureadkey(&scancode);
@ -435,7 +401,7 @@ bool Manager::generateMessages()
enqueueMessage(msg);
}
for (c=0; c<KEY_MAX; c++) {
for (int c=0; c<KEY_MAX; c++) {
if (old_readed_key[c] != key[c]) {
KeyScancode scancode = static_cast<ui::KeyScancode>(c);
@ -466,7 +432,20 @@ bool Manager::generateMessages()
}
}
}
}
static MouseButtons mouse_buttons_from_she_to_ui(const she::Event& sheEvent)
{
switch (sheEvent.button()) {
case she::Event::LeftButton: return kButtonLeft; break;
case she::Event::RightButton: return kButtonRight; break;
case she::Event::MiddleButton: return kButtonMiddle; break;
default: return kButtonNone;
}
}
void Manager::generateMessagesFromSheEvents()
{
// Events from "she" layer.
she::Event sheEvent;
for (;;) {
@ -476,34 +455,179 @@ bool Manager::generateMessages()
switch (sheEvent.type()) {
case she::Event::DropFiles:
{
Message* msg = new DropFilesMessage(sheEvent.files());
msg->addRecipient(this);
enqueueMessage(msg);
}
case she::Event::DropFiles: {
Message* msg = new DropFilesMessage(sheEvent.files());
msg->addRecipient(this);
enqueueMessage(msg);
break;
}
case she::Event::MouseMove: {
if (!mouse_events_from_she)
continue;
_internal_set_mouse_position(sheEvent.position());
handleMouseMove(sheEvent.position(), m_mouseButtons);
break;
}
case she::Event::MouseDown: {
if (!mouse_events_from_she)
continue;
MouseButtons pressedButton = mouse_buttons_from_she_to_ui(sheEvent);
m_mouseButtons = (MouseButtons)((int)m_mouseButtons | (int)pressedButton);
_internal_set_mouse_buttons(m_mouseButtons);
handleMouseDown(sheEvent.position(), pressedButton);
break;
}
case she::Event::MouseUp: {
if (!mouse_events_from_she)
continue;
MouseButtons releasedButton = mouse_buttons_from_she_to_ui(sheEvent);
m_mouseButtons = (MouseButtons)((int)m_mouseButtons & ~(int)releasedButton);
_internal_set_mouse_buttons(m_mouseButtons);
handleMouseUp(sheEvent.position(), releasedButton);
break;
}
case she::Event::MouseDoubleClick: {
if (!mouse_events_from_she)
continue;
MouseButtons clickedButton = mouse_buttons_from_she_to_ui(sheEvent);
handleMouseUp(sheEvent.position(), clickedButton);
break;
}
case she::Event::MouseWheel: {
if (!mouse_events_from_she)
continue;
handleMouseWheel(sheEvent.position(), m_mouseButtons, sheEvent.delta());
break;
}
}
}
}
// Generate messages for timers
Timer::pollTimers();
void Manager::handleMouseMove(const gfx::Point& mousePos, MouseButtons mouseButtons)
{
// Get the list of widgets to send mouse messages.
mouse_widgets_list.clear();
broadcastMouseMessage(mouse_widgets_list);
// Generate redraw events.
flushRedraw();
// Get the widget under the mouse
Widget* widget = NULL;
UI_FOREACH_WIDGET(mouse_widgets_list, it) {
widget = (*it)->pick(mousePos);
if (widget)
break;
}
if (!msg_queue.empty())
return true;
else
return false;
// Fixup "mouse" flag
if (widget != mouse_widget) {
if (!widget)
freeMouse();
else
setMouse(widget);
}
// Reset double click status
double_click_level = DOUBLE_CLICK_NONE;
// Send the mouse movement message
Widget* dst = (capture_widget ? capture_widget: mouse_widget);
enqueueMessage(newMouseMessage(kMouseMoveMessage, dst, mousePos, mouseButtons));
generateSetCursorMessage(mousePos);
}
void Manager::handleMouseDown(const gfx::Point& mousePos, MouseButtons mouseButtons)
{
handleWindowZOrder();
enqueueMessage(newMouseMessage(kMouseDownMessage,
(capture_widget ? capture_widget: mouse_widget),
mousePos, mouseButtons));
}
void Manager::handleMouseUp(const gfx::Point& mousePos, MouseButtons mouseButtons)
{
enqueueMessage(newMouseMessage(kMouseUpMessage,
(capture_widget ? capture_widget: mouse_widget),
mousePos, mouseButtons));
}
void Manager::handleMouseDoubleClick(const gfx::Point& mousePos, MouseButtons mouseButtons)
{
enqueueMessage(newMouseMessage(kDoubleClickMessage,
(capture_widget ? capture_widget: mouse_widget),
mousePos, mouseButtons));
}
void Manager::handleMouseWheel(const gfx::Point& mousePos, MouseButtons mouseButtons, int delta)
{
enqueueMessage(newMouseMessage(kMouseWheelMessage,
(capture_widget ? capture_widget: mouse_widget),
mousePos, mouseButtons, delta));
}
// Handles Z order: Send the window to top (only when you click in a
// window that aren't the desktop).
void Manager::handleWindowZOrder()
{
if (capture_widget || !mouse_widget)
return;
// The clicked window
Window* window = mouse_widget->getRoot();
Manager* win_manager = (window ? window->getManager(): NULL);
if ((window) &&
// We cannot change Z-order of desktop windows
(!window->isDesktop()) &&
// We cannot change Z order of foreground windows because a
// foreground window can launch other background windows
// which should be kept on top of the foreground one.
(!window->isForeground()) &&
// If the window is not already the top window of the manager.
(window != win_manager->getTopWindow())) {
base::ScopedValue<Widget*> scoped(m_lockedWindow, window, NULL);
// Put it in the top of the list
win_manager->removeChild(window);
if (window->isOnTop())
win_manager->insertChild(0, window);
else {
int pos = (int)win_manager->getChildren().size();
UI_FOREACH_WIDGET_BACKWARD(win_manager->getChildren(), it) {
if (static_cast<Window*>(*it)->isOnTop())
break;
--pos;
}
win_manager->insertChild(pos, window);
}
window->invalidate();
}
// Put the focus
setFocus(mouse_widget);
}
void Manager::dispatchMessages()
{
// Add the "Queue Processing" message for the manager.
enqueueMessage(newMouseMessage(kQueueProcessingMessage, this,
currentMouseButtons(0)));
gfx::Point(jmouse_x(0), jmouse_y(0)), currentMouseButtons(0)));
pumpQueue();
}
@ -716,7 +840,7 @@ void Manager::setMouse(Widget* widget)
it = widget_parents.begin();
Message* msg = newMouseMessage(kMouseEnterMessage, NULL,
currentMouseButtons(0));
gfx::Point(jmouse_x(0), jmouse_y(0)), currentMouseButtons(0));
for (; it != widget_parents.end(); ++it) {
(*it)->flags |= JI_HASMOUSE;
@ -724,7 +848,7 @@ void Manager::setMouse(Widget* widget)
}
enqueueMessage(msg);
generateSetCursorMessage();
generateSetCursorMessage(gfx::Point(jmouse_x(0), jmouse_y(0)));
}
}
}
@ -1224,22 +1348,6 @@ void Manager::collectGarbage()
Internal routines
**********************************************************************/
// static
void Manager::generateSetCursorMessage()
{
Widget* dst;
if (capture_widget)
dst = capture_widget;
else
dst = mouse_widget;
if (dst)
enqueueMessage(newMouseMessage(kSetCursorMessage, dst,
currentMouseButtons(0)));
else
jmouse_set_cursor(kArrowCursor);
}
// static
void Manager::removeWidgetFromRecipients(Widget* widget, Message* msg)
{
@ -1276,13 +1384,10 @@ Widget* Manager::findMagneticWidget(Widget* widget)
}
// static
Message* Manager::newMouseMessage(MessageType type, Widget* widget,
MouseButtons buttons)
Message* Manager::newMouseMessage(MessageType type,
Widget* widget, gfx::Point mousePos, MouseButtons buttons, int delta)
{
Message* msg =
new MouseMessage(type, buttons,
gfx::Point(jmouse_x(0),
jmouse_y(0)));
Message* msg = new MouseMessage(type, buttons, mousePos, delta);
if (widget != NULL)
msg->addRecipient(widget);

View File

@ -92,14 +92,23 @@ namespace ui {
virtual LayoutIO* onGetLayoutIO();
private:
void generateMouseMessages();
void generateSetCursorMessage(const gfx::Point& mousePos);
void generateKeyMessages();
void generateMessagesFromSheEvents();
void handleMouseMove(const gfx::Point& mousePos, MouseButtons mouseButtons);
void handleMouseDown(const gfx::Point& mousePos, MouseButtons mouseButtons);
void handleMouseUp(const gfx::Point& mousePos, MouseButtons mouseButtons);
void handleMouseDoubleClick(const gfx::Point& mousePos, MouseButtons mouseButtons);
void handleMouseWheel(const gfx::Point& mousePos, MouseButtons mouseButtons, int delta);
void handleWindowZOrder();
void pumpQueue();
void generateSetCursorMessage();
static void removeWidgetFromRecipients(Widget* widget, Message* msg);
static bool someParentIsFocusStop(Widget* widget);
static Widget* findMagneticWidget(Widget* widget);
static Message* newMouseMessage(MessageType type, Widget* destination);
static Message* newMouseMessage(MessageType type, Widget* destination,
MouseButtons mouseButtons);
static Message* newMouseMessage(MessageType type,
Widget* widget, gfx::Point mousePos, MouseButtons buttons, int delta = 0);
static MouseButtons currentMouseButtons(int antique);
void broadcastKeyMsg(Message* msg);
@ -113,6 +122,9 @@ namespace ui {
// This member is used to make freeWidget() a no-op when we
// restack a window if the user clicks on it.
Widget* m_lockedWindow;
// Current pressed buttons.
MouseButtons m_mouseButtons;
};
} // namespace ui

View File

@ -101,20 +101,22 @@ namespace ui {
class MouseMessage : public Message
{
public:
MouseMessage(MessageType type, MouseButtons buttons, const gfx::Point& pos)
: Message(type), m_buttons(buttons), m_pos(pos) {
MouseMessage(MessageType type, MouseButtons buttons, const gfx::Point& pos, int delta)
: Message(type), m_buttons(buttons), m_pos(pos), m_delta(delta) {
}
MouseButtons buttons() const { return m_buttons; }
bool left() const { return (m_buttons & kButtonLeft) == kButtonLeft; }
bool right() const { return (m_buttons & kButtonRight) == kButtonRight; }
bool middle() const { return (m_buttons & kButtonMiddle) == kButtonMiddle; }
int wheelDelta() const { return m_delta; }
const gfx::Point& position() const { return m_pos; }
private:
MouseButtons m_buttons; // Pressed buttons
gfx::Point m_pos; // Mouse position
int m_delta; // Wheel axis variation
};
class TimerMessage : public Message

View File

@ -191,7 +191,7 @@ bool Slider::onProcessMessage(Message* msg)
case kMouseWheelMessage:
if (isEnabled()) {
int value = m_value + jmouse_z(0) - jmouse_z(1);
int value = m_value + static_cast<MouseMessage*>(msg)->wheelDelta();
value = MID(m_min, value, m_max);

View File

@ -22,7 +22,7 @@
#include "ui/widget.h"
#include <allegro.h>
#if defined(ALLEGRO_WINDOWS)
#if defined(WIN32)
#include <winalleg.h>
#elif defined(ALLEGRO_UNIX)
#include <xalleg.h>
@ -46,6 +46,7 @@ volatile int ji_clock = 0;
static CursorType mouse_cursor_type = kNoCursor;
static Cursor* mouse_cursor = NULL;
static she::Display* mouse_display = NULL;
static Overlay* mouse_cursor_overlay = NULL;
/* Mouse information (button and position). */
@ -125,6 +126,7 @@ void SetDisplay(she::Display* display)
CursorType cursor = jmouse_get_cursor();
jmouse_set_cursor(kNoCursor);
mouse_display = display;
ji_screen = (display ? reinterpret_cast<BITMAP*>(display->getSurface()->nativeHandle()): NULL);
ji_screen_w = (ji_screen ? ji_screen->w: 0);
ji_screen_h = (ji_screen ? ji_screen->h: 0);
@ -240,6 +242,21 @@ bool jmouse_poll()
return false;
}
void _internal_set_mouse_position(const gfx::Point& newPos)
{
moved = true;
m_x[1] = m_x[0];
m_y[1] = m_y[0];
m_x[0] = newPos.x;
m_y[0] = newPos.y;
}
void _internal_set_mouse_buttons(MouseButtons buttons)
{
m_b[1] = m_b[0];
m_b[0] = buttons;
}
gfx::Point get_mouse_position()
{
return gfx::Point(jmouse_x(0), jmouse_y(0));
@ -345,8 +362,8 @@ static void update_mouse_position()
m_y[0] = JI_SCREEN_H * mouse_y / SCREEN_H;
if (is_windowed_mode()) {
#ifdef ALLEGRO_WINDOWS
// This help us (in windows) to get mouse feedback when we capture
#ifdef WIN32
// This help us (on Windows) to get mouse feedback when we capture
// the mouse but we are outside the window.
POINT pt;
RECT rc;

View File

@ -57,6 +57,9 @@ namespace ui {
bool jmouse_poll();
void _internal_set_mouse_position(const gfx::Point& newPos);
void _internal_set_mouse_buttons(MouseButtons buttons);
gfx::Point get_mouse_position();
void set_mouse_position(const gfx::Point& newPos);

View File

@ -134,7 +134,7 @@ bool TextBox::onProcessMessage(Message* msg)
if (view) {
gfx::Point scroll = view->getViewScroll();
scroll.y += (jmouse_z(1) - jmouse_z(0)) * getTextHeight()*3;
scroll.y += -static_cast<MouseMessage*>(msg)->wheelDelta() * getTextHeight()*3;
view->setViewScroll(scroll);
}