651
static bool PointInTriangle(nux::Point const& p, nux::Point const& t0, nux::Point const& t1, nux::Point const& t2)
656
bool PointInTriangle(nux::Point const& p, nux::Point const& t0, nux::Point const& t1, nux::Point const& t2)
653
658
int s = t0.y * t2.x - t0.x * t2.y + (t2.y - t0.y) * p.x + (t0.x - t2.x) * p.y;
654
659
int t = t0.x * t1.y - t0.y * t1.x + (t0.y - t1.y) * p.x + (t1.x - t0.x) * p.y;
667
672
return s > 0 && t > 0 && (s + t) < A;
670
static double GetMouseVelocity(nux::Point const& p0, nux::Point const& p1, util::Timer &timer)
675
double GetMouseVelocity(nux::Point const& p0, nux::Point const& p1, Time time_delta)
674
auto millis = timer.ElapsedMicroSeconds();
679
683
dx = p0.x - p1.x;
680
684
dy = p0.y - p1.y;
682
speed = sqrt(dx * dx + dy * dy) / millis * 1000;
686
speed = sqrt(dx * dx + dy * dy) / time_delta;
690
} // anonymous namespace
687
bool PanelView::TrackMenuPointer()
692
void PanelView::OnActiveEntryEvent(XEvent const& e)
689
nux::Point const& mouse = nux::GetGraphicsDisplay()->GetMouseScreenCoord();
690
double speed = GetMouseVelocity(mouse, tracked_pointer_pos_, mouse_tracker_timer_);
692
mouse_tracker_timer_.Reset();
694
if (e.type != MotionNotify)
697
double scale = Settings::Instance().em(monitor_)->DPIScale();
698
nux::Point mouse(e.xmotion.x_root, e.xmotion.y_root);
699
double speed = GetMouseVelocity(mouse, tracked_pointer_pos_, e.xmotion.time - last_pointer_time_);
693
701
tracked_pointer_pos_ = mouse;
695
double scale = Settings::Instance().em(monitor_)->DPIScale();
696
if (speed > 0 && PointInTriangle(mouse,
697
nux::Point(triangle_top_corner_.x, std::max(triangle_top_corner_.y - TRIANGLE_THRESHOLD.CP(scale), 0)),
698
nux::Point(menu_geo_.x, menu_geo_.y),
699
nux::Point(menu_geo_.x + menu_geo_.width, menu_geo_.y)))
704
if (mouse != triangle_top_corner_)
706
triangle_top_corner_ = mouse;
707
OnMenuPointerMoved(mouse.x, mouse.y);
702
last_pointer_time_ = e.xmotion.time;
704
if (speed > SCRUB_VELOCITY_THRESHOLD &&
705
PointInTriangle(mouse, {mouse.x, std::max(mouse.y - TRIANGLE_THRESHOLD.CP(scale), 0)},
706
menu_geo_.GetPosition(), {menu_geo_.x + menu_geo_.width, menu_geo_.y}))
711
OnMenuPointerMoved(mouse.x, mouse.y);
713
714
void PanelView::OnEntryActivated(std::string const& panel, std::string const& entry_id, nux::Rect const& menu_geo)
715
716
if (!panel.empty() && panel != GetPanelName())
719
bool active = !entry_id.empty();
720
auto const& activation_cb = sigc::mem_fun(this, &PanelView::OnActiveEntryEvent);
718
721
menu_geo_ = menu_geo;
720
bool active = !entry_id.empty();
721
if (active && !track_menu_pointer_timeout_)
724
// Track menus being scrubbed at 60Hz (about every 16 millisec)
725
// It might sound ugly, but it's far nicer (and more responsive) than the
726
// code it replaces which used to capture motion events in another process
727
// (unity-panel-service) and send them to us over dbus.
728
// NOTE: The reason why we have to use a timer instead of tracking motion
729
// events is because the motion events will never be delivered to this
730
// process. All the motion events will go to unity-panel-service while
731
// scrubbing because the active panel menu has (needs) the pointer grab.
733
mouse_tracker_timer_.Reset();
734
triangle_top_corner_ = nux::GetGraphicsDisplay()->GetMouseScreenCoord();
735
track_menu_pointer_timeout_.reset(new glib::Timeout(16));
736
track_menu_pointer_timeout_->Run(sigc::mem_fun(this, &PanelView::TrackMenuPointer));
725
auto& im = input::Monitor::Get();
726
if (im.RegisterClient(input::Events::POINTER, activation_cb))
728
last_pointer_time_ = 0;
729
ActivateEntry(entry_id);
732
if (overlay_is_open_)
733
ubus_manager_.SendMessage(UBUS_OVERLAY_CLOSE_REQUEST);
740
track_menu_pointer_timeout_.reset();
737
input::Monitor::Get().UnregisterClient(activation_cb);
741
738
menu_view_->NotifyAllMenusClosed();
742
tracked_pointer_pos_ = {-1, -1};
745
if (overlay_is_open_)
746
ubus_manager_.SendMessage(UBUS_OVERLAY_CLOSE_REQUEST);
749
742
void PanelView::OnEntryShowMenu(std::string const& entry_id, unsigned xid,
750
743
int x, int y, unsigned button)
752
if (!track_menu_pointer_timeout_)
745
if (menu_geo_.IsNull())
754
747
// This is ugly... But Nux fault!
755
748
menu_view_->IgnoreLeaveEvents(true);