diff --git a/CMakeLists.txt b/CMakeLists.txt index 129c4f8a4..c0feed888 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -215,6 +215,7 @@ if(WIN32) shlwapi psapi wininet + comctl32 dbghelp ) diff --git a/src/app/ui/editor/standby_state.cpp b/src/app/ui/editor/standby_state.cpp index 6261da53f..9182547bb 100644 --- a/src/app/ui/editor/standby_state.cpp +++ b/src/app/ui/editor/standby_state.cpp @@ -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; diff --git a/src/app/ui/file_list.cpp b/src/app/ui/file_list.cpp index 687b9e15d..a37118d82 100644 --- a/src/app/ui/file_list.cpp +++ b/src/app/ui/file_list.cpp @@ -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(msg)->wheelDelta() * 3*(2+getTextHeight()+2); view->setViewScroll(scroll); } break; diff --git a/src/app/ui/palette_view.cpp b/src/app/ui/palette_view.cpp index 2aaa1cca1..534ab29f2 100644 --- a/src/app/ui/palette_view.cpp +++ b/src/app/ui/palette_view.cpp @@ -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(msg)->wheelDelta() * 3 * m_boxsize; view->setViewScroll(scroll); } break; diff --git a/src/app/ui/tabs.cpp b/src/app/ui/tabs.cpp index 96e9ea7fd..299cb6846 100644 --- a/src/app/ui/tabs.cpp +++ b/src/app/ui/tabs.cpp @@ -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(msg)->wheelDelta() * getBounds().w/6; // setScrollX(m_scrollX+dx); m_begScrollX = m_scrollX; diff --git a/src/app/ui/timeline.cpp b/src/app/ui/timeline.cpp index ce4590112..be2e5f53c 100644 --- a/src/app/ui/timeline.cpp +++ b/src/app/ui/timeline.cpp @@ -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(msg)->wheelDelta(); int dx = 0; int dy = 0; diff --git a/src/app/ui/toolbar.cpp b/src/app/ui/toolbar.cpp index 3fcd69b0f..74ec088aa 100644 --- a/src/app/ui/toolbar.cpp +++ b/src/app/ui/toolbar.cpp @@ -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); } diff --git a/src/she/capabilities.h b/src/she/capabilities.h index 1e4f30a00..927dbf9b8 100644 --- a/src/she/capabilities.h +++ b/src/she/capabilities.h @@ -13,7 +13,8 @@ namespace she { enum Capabilities { kMultipleDisplaysCapability = 1, kCanResizeDisplayCapability = 2, - kDisplayScaleCapability = 4 + kDisplayScaleCapability = 4, + kMouseEventsCapability = 8, }; } // namespace she diff --git a/src/she/event.h b/src/she/event.h index 73cbffa39..d7417cf70 100644 --- a/src/she/event.h +++ b/src/she/event.h @@ -8,6 +8,8 @@ #define SHE_EVENT_H_INCLUDED #pragma once +#include "gfx/point.h" + #include #include @@ -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 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 diff --git a/src/she/she_alleg4.cpp b/src/she/she_alleg4.cpp index f127786cf..018ee0b14 100644 --- a/src/she/she_alleg4.cpp +++ b/src/she/she_alleg4.cpp @@ -11,6 +11,7 @@ #include "she.h" #include "base/compiler_specific.h" +#include "base/concurrent_queue.h" #include "base/string.h" #include @@ -19,6 +20,9 @@ #ifdef WIN32 #include + #include + #include + #if defined STRICT || defined __GNUC__ typedef WNDPROC wndproc_t; #else @@ -36,6 +40,7 @@ #include #include +#include #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 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 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(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 0) { - std::vector 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 0) { + std::vector 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(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) { diff --git a/src/ui/combobox.cpp b/src/ui/combobox.cpp index 5ee57af06..044e39194 100644 --- a/src/ui/combobox.cpp +++ b/src/ui/combobox.cpp @@ -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; } diff --git a/src/ui/int_entry.cpp b/src/ui/int_entry.cpp index 2b702ce5a..9a674c25d 100644 --- a/src/ui/int_entry.cpp +++ b/src/ui/int_entry.cpp @@ -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(msg)->wheelDelta(); newValue = MID(m_min, newValue, m_max); if (newValue != oldValue) { setValue(newValue); diff --git a/src/ui/listbox.cpp b/src/ui/listbox.cpp index 02ecf22e1..00ecbcbaa 100644 --- a/src/ui/listbox.cpp +++ b/src/ui/listbox.cpp @@ -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(msg)->wheelDelta() * getTextHeight()*3; view->setViewScroll(scroll); } break; diff --git a/src/ui/manager.cpp b/src/ui/manager.cpp index 1ba953afa..0fc74a96c 100644 --- a/src/ui/manager.cpp +++ b/src/ui/manager.cpp @@ -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 Messages; typedef std::list 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 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(*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(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 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(*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); diff --git a/src/ui/manager.h b/src/ui/manager.h index 2e066961d..c1f08a267 100644 --- a/src/ui/manager.h +++ b/src/ui/manager.h @@ -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 diff --git a/src/ui/message.h b/src/ui/message.h index 08ea597a2..36bd885ed 100644 --- a/src/ui/message.h +++ b/src/ui/message.h @@ -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 diff --git a/src/ui/slider.cpp b/src/ui/slider.cpp index fa368eac2..02f61716e 100644 --- a/src/ui/slider.cpp +++ b/src/ui/slider.cpp @@ -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(msg)->wheelDelta(); value = MID(m_min, value, m_max); diff --git a/src/ui/system.cpp b/src/ui/system.cpp index bad107eb8..db5cf4c49 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -22,7 +22,7 @@ #include "ui/widget.h" #include -#if defined(ALLEGRO_WINDOWS) +#if defined(WIN32) #include #elif defined(ALLEGRO_UNIX) #include @@ -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(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; diff --git a/src/ui/system.h b/src/ui/system.h index 4f8b2cad8..2a053b413 100644 --- a/src/ui/system.h +++ b/src/ui/system.h @@ -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); diff --git a/src/ui/textbox.cpp b/src/ui/textbox.cpp index b99b19c11..b9c838500 100644 --- a/src/ui/textbox.cpp +++ b/src/ui/textbox.cpp @@ -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(msg)->wheelDelta() * getTextHeight()*3; view->setViewScroll(scroll); }