Skip to content
46 changes: 39 additions & 7 deletions Engine/system/api/macosapi.mm
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,28 @@ static NSPoint mousePos(NSPoint px, NSWindow* wnd, bool& inWindow) {
return mousePos(e,dummy);
}

static Tempest::Point mousePos(NSWindow* wnd, bool& inWindow) {
NSPoint p = [wnd mouseLocationOutsideOfEventStream];
NSPoint px = mousePos(p, wnd, inWindow);
return Tempest::Point{int(px.x), int(px.y)};
}

static void implShowCursor(SystemApi::Window *w, CursorShape show) {
static CursorShape current = CursorShape::Arrow;
if(current==show) {
// show/hie mechanism is ref couter based on Mac
// https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/QuartzDisplayServicesConceptual/Articles/MouseCursor.html
return;
}

current = show;
if(show==CursorShape::Hidden) {
CGDisplayHideCursor(kCGNullDirectDisplay);
return;
}
CGDisplayShowCursor(kCGNullDirectDisplay);
}

void Detail::ImplMacOSApi::onDisplayLink(void* hwnd) {
@autoreleasepool {
auto cb = reinterpret_cast<Tempest::Window*>(hwnd);
Expand All @@ -128,6 +150,20 @@ static NSPoint mousePos(NSPoint px, NSWindow* wnd, bool& inWindow) {
auto cb = reinterpret_cast<Tempest::Window*>(hwnd);
NSWindow* wnd = reinterpret_cast<NSWindow*>(w);

bool inWindow = true;
auto mpos = mousePos(wnd, inWindow);
if(inWindow) {
MouseEvent e( mpos.x,
mpos.y,
Event::ButtonNone,
Event::M_NoModifier,
0,
0,
Event::MouseMove );
MacOSApi::dispatchMouseMove(*cb, e);
}
implShowCursor(reinterpret_cast<SystemApi::Window*>(w), MacOSApi::cursorShape(*cb));

FocusEvent e(true, Event::UnknownReason);
MacOSApi::dispatchFocus(*cb, e);
}
Expand Down Expand Up @@ -367,11 +403,7 @@ - (void)dispatchRenderer{
}

void MacOSApi::implShowCursor(SystemApi::Window *w, CursorShape show) {
if(show==CursorShape::Hidden) {
CGDisplayHideCursor(kCGNullDirectDisplay);
return;
}
CGDisplayShowCursor(kCGNullDirectDisplay);
::implShowCursor(w, show);
}

void MacOSApi::implSetWindowTitle(Window* w, const char* utf8) {
Expand Down Expand Up @@ -601,7 +633,7 @@ MouseEvent e(p.x,p.y,
break;
}
default: break;
}
}

auto isDown = evt.modifierFlags & flag;
auto eType = (isDown ? Event::KeyDown : Event::KeyUp);
Expand All @@ -613,8 +645,8 @@ MouseEvent e(p.x,p.y,
return;
}
case NSEventTypeAppKitDefined:
break;
case NSEventTypeMouseEntered:
break;
case NSEventTypeMouseExited:
break;

Expand Down
16 changes: 15 additions & 1 deletion Engine/system/api/windowsapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,21 @@ long long WindowsApi::windowProc(void *_hWnd, uint32_t msg, const unsigned long
}

case WM_ACTIVATE:{
SetCursor(cb->cursorShape());
POINT mpos = {};
if(wParam==WA_ACTIVE && GetCursorPos(&mpos)) {

@Abendlied Abendlied Sep 20, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MouseEvent coordinate uses GetCursorPos which gives the coordinates for the screen, should we use window coordinates instead?
Can you check if this works on Windows doing Alt-Tabbing with non-fullscreen and not tight top left window?
If not, could we copy from WM_MOUSEMOVE and use getX_LPARAM and getY_LPARAM?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we use window coordinates instead?

Fixed - now it's cb-local. Tested with spacer (it has arrow cursor, on edge of resizable panels) - works.

If not, could we copy from WM_MOUSEMOVE and use getX_LPARAM and getY_LPARAM?

We can't - LPARAM has contextual meaning on windows.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you so much!
Works on X11 on my end.

Looks great now, ready for merge from my side.

mpos.x -= cb->x();
mpos.y -= cb->y();
MouseEvent e( mpos.x,
mpos.y,
Event::ButtonNone,
Event::M_NoModifier,
0,
0,
Event::MouseMove );
SystemApi::dispatchMouseMove(*cb, e);
}

SetCursor(SystemApi::cursorShape(*cb));
if(wParam==WA_INACTIVE) {
FocusEvent e(false, Event::UnknownReason);
SystemApi::dispatchFocus(*cb, e);
Expand Down
34 changes: 23 additions & 11 deletions Engine/system/api/x11api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ SystemApi::Window *X11Api::implCreateWindow(Tempest::Window *owner, uint32_t w,

XSetWindowAttributes swa={};
swa.colormap = cmap;
swa.event_mask = PointerMotionMask | ExposureMask |
swa.event_mask = PointerMotionMask | EnterWindowMask | ExposureMask |
ButtonPressMask | ButtonReleaseMask |
KeyPressMask | KeyReleaseMask |
FocusChangeMask | StructureNotifyMask |
Expand Down Expand Up @@ -598,6 +598,28 @@ void X11Api::implProcessEvents(SystemApi::AppCallBack &cb) {
}
break;
}
case EnterNotify: {
MouseEvent e( xev.xcrossing.x,
xev.xcrossing.y,
Event::ButtonNone,
Event::M_NoModifier,
0,
0,
Event::MouseMove );
SystemApi::dispatchMouseMove(cb,e);
implShowCursor(hWnd.ptr(),SystemApi::cursorShape(cb));
break;
}
case FocusIn: {
FocusEvent e(true, Event::UnknownReason);
SystemApi::dispatchFocus(cb, e);
break;
}
case FocusOut: {
FocusEvent e(false, Event::UnknownReason);
SystemApi::dispatchFocus(cb, e);
break;
}
case MotionNotify: {
if(activeCursorChange == 1) {
// FIXME: mouse behave crazy in OpenGothic
Expand Down Expand Up @@ -643,16 +665,6 @@ void X11Api::implProcessEvents(SystemApi::AppCallBack &cb) {
SystemApi::dispatchKeyUp (cb,e,scan);
break;
}
case FocusIn: {
FocusEvent e(true, Event::UnknownReason);
SystemApi::dispatchFocus(cb, e);
break;
}
case FocusOut: {
FocusEvent e(false, Event::UnknownReason);
SystemApi::dispatchFocus(cb, e);
break;
}
}

std::this_thread::yield();
Expand Down
4 changes: 4 additions & 0 deletions Engine/system/systemapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ void SystemApi::showCursor(SystemApi::Window *w, CursorShape show) {
return inst().implShowCursor(w,show);
}

CursorShape SystemApi::cursorShape(Tempest::Window& cb) {
return cb.resolvedCursor;
}

float SystemApi::uiScale(Window* w) {
return inst().implUiScale(w);
}
1 change: 1 addition & 0 deletions Engine/system/systemapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class SystemApi {

static void setCursorPosition(SystemApi::Window *w, int x, int y);
static void showCursor(SystemApi::Window *w, CursorShape c);
static CursorShape cursorShape(Tempest::Window& cb);

static void dispatchOverlayRender(Tempest::Window &w, Tempest::PaintEvent& e);
static void dispatchRender (Tempest::Window& cb);
Expand Down
1 change: 1 addition & 0 deletions Engine/ui/window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,6 @@ void Window::setCursorPosition(const Point& p) {
}

void Window::implShowCursor(CursorShape s) {
resolvedCursor = s;
SystemApi::showCursor(hwnd(),s);
}
4 changes: 3 additions & 1 deletion Engine/ui/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@ class Window : public Widget {
private:
void implShowCursor(CursorShape s);

SystemApi::Window* id=nullptr;
SystemApi::Window* id = nullptr;
CursorShape resolvedCursor = CursorShape::Arrow;

friend class Widget;
friend class UiOverlay;
friend class EventDispatcher;
friend class SystemApi;
};

}