From 985aed852a974e8a87b94a2e9974b3854833a0d4 Mon Sep 17 00:00:00 2001 From: martinfouilleul Date: Tue, 25 Jul 2023 13:40:25 +0200 Subject: [PATCH 1/8] [app] change mp_move_event to mp_mouse_event and mp_frame_event to mp_move_event. Transmit both window frame and contents rect in move/resize events --- src/input_state.c | 4 +- src/mp_app.h | 15 ++--- src/win32_app.c | 147 +++++++++++++++++++++++++--------------------- src/win32_app.h | 2 +- 4 files changed, 91 insertions(+), 77 deletions(-) diff --git a/src/input_state.c b/src/input_state.c index 1a1f385..074c805 100644 --- a/src/input_state.c +++ b/src/input_state.c @@ -136,11 +136,11 @@ void mp_input_process_event(mp_input_state* state, mp_event* event) break; case MP_EVENT_MOUSE_MOVE: - mp_update_mouse_move(state, event->move.x, event->move.y, event->move.deltaX, event->move.deltaY); + mp_update_mouse_move(state, event->mouse.x, event->mouse.y, event->mouse.deltaX, event->mouse.deltaY); break; case MP_EVENT_MOUSE_WHEEL: - mp_update_mouse_wheel(state, event->move.deltaX, event->move.deltaY); + mp_update_mouse_wheel(state, event->mouse.deltaX, event->mouse.deltaY); break; case MP_EVENT_MOUSE_BUTTON: diff --git a/src/mp_app.h b/src/mp_app.h index 237b598..e281b41 100644 --- a/src/mp_app.h +++ b/src/mp_app.h @@ -222,19 +222,20 @@ typedef struct mp_char_event // character input u8 seqLen; } mp_char_event; -typedef struct mp_move_event // mouse move/scroll +typedef struct mp_mouse_event // mouse move/scroll { f32 x; f32 y; f32 deltaX; f32 deltaY; mp_keymod_flags mods; -} mp_move_event; +} mp_mouse_event; -typedef struct mp_frame_event // window resize / move +typedef struct mp_move_event // window resize / move { - mp_rect rect; -} mp_frame_event; + mp_rect frame; + mp_rect contents; +} mp_move_event; typedef struct mp_event { @@ -246,8 +247,8 @@ typedef struct mp_event { mp_key_event key; mp_char_event character; - mp_move_event move; - mp_frame_event frame; + mp_mouse_event mouse; + mp_move_event move; str8_list paths; }; diff --git a/src/win32_app.c b/src/win32_app.c index c438847..8342131 100644 --- a/src/win32_app.c +++ b/src/win32_app.c @@ -240,13 +240,46 @@ static void process_wheel_event(mp_window_data* window, f32 x, f32 y) mp_event event = {0}; event.window = mp_window_handle_from_ptr(window); event.type = MP_EVENT_MOUSE_WHEEL; - event.move.deltaX = x/30.0f; - event.move.deltaY = -y/30.0f; - event.move.mods = mp_get_mod_keys(); + event.mouse.deltaX = x/30.0f; + event.mouse.deltaY = -y/30.0f; + event.mouse.mods = mp_get_mod_keys(); mp_queue_event(&event); } +void mg_win32_layer_set_frame(mp_layer* layer, mp_rect frame) +{ + layer->userFrame = frame; + + HWND parent = GetParent(layer->hWnd); + + RECT clientRect; + GetClientRect(parent, &clientRect); + POINT point = {0}; + ClientToScreen(layer->hWnd, &point); + + u32 dpi = GetDpiForWindow(layer->hWnd); + vec2 scale = (vec2){(float)dpi/96., (float)dpi/96.}; + + int parentWidth = (clientRect.right - clientRect.left)/scale.x; + int parentHeight = (clientRect.bottom - clientRect.top)/scale.y; + + int minX = Clamp(frame.x, 0, parentWidth); + int maxX = Clamp(frame.x + frame.w, 0, parentWidth); + int minY = Clamp(frame.y, 0, parentHeight); + int maxY = Clamp(frame.y + frame.h, 0, parentHeight); + + SetWindowPos(layer->hWnd, + HWND_TOP, + point.x + minX * scale.x, + point.y + minY * scale.y, + (maxX - minX) * scale.x, + (maxY - minY) * scale.y, + SWP_NOACTIVATE | SWP_NOZORDER); + + //TODO test if we should we guard against 0-width windows +} + static void win32_update_child_layers(mp_window_data* window) { RECT clientRect; @@ -254,26 +287,30 @@ static void win32_update_child_layers(mp_window_data* window) POINT point = {0}; ClientToScreen(window->win32.hWnd, &point); - int w = clientRect.right - clientRect.left; - int h = clientRect.bottom - clientRect.top; + u32 dpi = GetDpiForWindow(window->win32.hWnd); + vec2 scale = (vec2){(float)dpi/96., (float)dpi/96.}; + + int parentWidth = (clientRect.right - clientRect.left)/scale.x; + int parentHeight = (clientRect.bottom - clientRect.top)/scale.y; HWND insertAfter = window->win32.hWnd; for_list(&window->win32.layers, layer, mp_layer, listElt) { - mp_rect clipped = {0}; - clipped.x = Clamp(layer->frame.x, 0, w); - clipped.y = Clamp(layer->frame.y, 0, h); - clipped.w = Clamp(layer->frame.w, 0, w - layer->frame.x); - clipped.h = Clamp(layer->frame.h, 0, h - layer->frame.y); + mp_rect frame = layer->userFrame; + + int minX = Clamp(frame.x, 0, parentWidth); + int maxX = Clamp(frame.x + frame.w, 0, parentWidth); + int minY = Clamp(frame.y, 0, parentHeight); + int maxY = Clamp(frame.y + frame.h, 0, parentHeight); SetWindowPos(layer->hWnd, - insertAfter, - point.x + clipped.x, - point.y + clipped.y, - clipped.w, - clipped.h, - SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER); + insertAfter, + point.x + minX * scale.x, + point.y + minY * scale.y, + (maxX - minX) * scale.x, + (maxY - minY) * scale.y, + SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER); insertAfter = layer->hWnd; } @@ -321,30 +358,25 @@ LRESULT WinProc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam) } break; case WM_SIZING: - { - //TODO: take dpi into account - - RECT* rect = (RECT*)lParam; - - mp_event event = {0}; - event.window = mp_window_handle_from_ptr(mpWindow); - event.type = MP_EVENT_WINDOW_RESIZE; - event.frame.rect = (mp_rect){rect->left, rect->bottom, rect->bottom - rect->top, rect->right - rect->left}; - mp_queue_event(&event); - - win32_update_child_layers(mpWindow); - } break; - case WM_MOVING: { - //TODO: take dpi into account - RECT* rect = (RECT*)lParam; + u32 dpi = GetDpiForWindow(mpWindow->win32.hWnd); + f32 scaling = (f32)dpi/96.; + mp_event event = {0}; + event.type = message == WM_SIZING ? MP_EVENT_WINDOW_RESIZE : MP_EVENT_WINDOW_MOVE; event.window = mp_window_handle_from_ptr(mpWindow); - event.type = MP_EVENT_WINDOW_MOVE; - event.frame.rect = (mp_rect){rect->left, rect->bottom, rect->bottom - rect->top, rect->right - rect->left}; + + event.move.frame = (mp_rect){ + rect->left / scaling, + rect->bottom / scaling, + (rect->bottom - rect->top)/scaling, + (rect->right - rect->left)/scaling }; + + event.move.contents = mp_window_get_content_rect(event.window); + mp_queue_event(&event); win32_update_child_layers(mpWindow); @@ -429,15 +461,15 @@ LRESULT WinProc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam) mp_event event = {0}; event.window = mp_window_handle_from_ptr(mpWindow); event.type = MP_EVENT_MOUSE_MOVE; - event.move.x = LOWORD(lParam) / scaling; - event.move.y = HIWORD(lParam) / scaling; + event.mouse.x = LOWORD(lParam) / scaling; + event.mouse.y = HIWORD(lParam) / scaling; if(__mpApp.win32.mouseTracked || __mpApp.win32.mouseCaptureMask) { - event.move.deltaX = event.move.x - __mpApp.win32.lastMousePos.x; - event.move.deltaY = event.move.y - __mpApp.win32.lastMousePos.y; + event.mouse.deltaX = event.mouse.x - __mpApp.win32.lastMousePos.x; + event.mouse.deltaY = event.mouse.y - __mpApp.win32.lastMousePos.y; } - __mpApp.win32.lastMousePos = (vec2){event.move.x, event.move.y}; + __mpApp.win32.lastMousePos = (vec2){event.mouse.x, event.mouse.y}; if(!__mpApp.win32.mouseTracked) { @@ -452,8 +484,8 @@ LRESULT WinProc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam) mp_event enter = {.window = event.window, .type = MP_EVENT_MOUSE_ENTER, - .move.x = event.move.x, - .move.y = event.move.y}; + .mouse.x = event.mouse.x, + .mouse.y = event.mouse.y}; mp_queue_event(&enter); } @@ -937,35 +969,12 @@ vec2 mg_win32_surface_contents_scaling(mg_surface_data* surface) mp_rect mg_win32_surface_get_frame(mg_surface_data* surface) { - RECT rect = {0}; - GetClientRect(surface->layer.hWnd, &rect); - - vec2 scale = mg_win32_surface_contents_scaling(surface); - - mp_rect res = {rect.left/scale.x, - rect.bottom/scale.y, - (rect.right - rect.left)/scale.x, - (rect.bottom - rect.top)/scale.y}; - return(res); + return(surface->layer.userFrame); } void mg_win32_surface_set_frame(mg_surface_data* surface, mp_rect frame) { - HWND parent = GetParent(surface->layer.hWnd); - RECT parentContentRect; - - GetClientRect(parent, &parentContentRect); - int parentHeight = parentContentRect.bottom - parentContentRect.top; - - vec2 scale = mg_win32_surface_contents_scaling(surface); - - SetWindowPos(surface->layer.hWnd, - HWND_TOP, - frame.x * scale.x, - parentHeight - (frame.y + frame.h) * scale.y, - frame.w * scale.x, - frame.h * scale.y, - SWP_NOACTIVATE | SWP_NOZORDER); + mg_win32_layer_set_frame(&surface->layer, frame); } bool mg_win32_surface_get_hidden(mg_surface_data* surface) @@ -1053,6 +1062,11 @@ void mg_surface_init_for_window(mg_surface_data* surface, mp_window_data* window int width = parentRect.right - parentRect.left; int height = parentRect.bottom - parentRect.top; + u32 dpi = GetDpiForWindow(window->win32.hWnd); + vec2 scale = (vec2){(float)dpi/96., (float)dpi/96.}; + + surface->layer.userFrame = (mp_rect){0, 0, width / scale.x, height / scale.y}; + surface->layer.hWnd = CreateWindow("layer_window_class", "layer", WS_POPUP | WS_VISIBLE, point.x, point.y, width, height, @@ -1076,7 +1090,6 @@ void mg_surface_init_for_window(mg_surface_data* surface, mp_window_data* window log_error("couldn't enable blur behind\n"); } - surface->layer.frame = (mp_rect){0, 0, width, height}; surface->layer.parent = window; list_append(&window->win32.layers, &surface->layer.listElt); } diff --git a/src/win32_app.h b/src/win32_app.h index e6783e0..7124a88 100644 --- a/src/win32_app.h +++ b/src/win32_app.h @@ -28,7 +28,7 @@ typedef struct mp_layer { mp_window_data* parent; list_elt listElt; - mp_rect frame; + mp_rect userFrame; HWND hWnd; } mp_layer; From 3816e85592b5c68eeea4ed00001692f910a50c82 Mon Sep 17 00:00:00 2001 From: martinfouilleul Date: Tue, 25 Jul 2023 14:18:02 +0200 Subject: [PATCH 2/8] [win32, surface] always resize surface to parent window's client area --- examples/canvas/main.c | 3 ++ src/gl_canvas.c | 65 ++++++++++++++++++++---------- src/graphics.h | 3 +- src/graphics_surface.c | 35 ++++++----------- src/graphics_surface.h | 37 +----------------- src/win32_app.c | 89 ++++++++++-------------------------------- src/win32_app.h | 1 - 7 files changed, 84 insertions(+), 149 deletions(-) diff --git a/examples/canvas/main.c b/examples/canvas/main.c index eb5c0c9..1596add 100644 --- a/examples/canvas/main.c +++ b/examples/canvas/main.c @@ -161,6 +161,9 @@ int main() mg_set_color_rgba(0, 1, 1, 1); mg_clear(); + mg_set_color_rgba(1, 0, 1, 1); + mg_rectangle_fill(0, 0, 100, 100); + // head mg_set_color_rgba(1, 1, 0, 1); diff --git a/src/gl_canvas.c b/src/gl_canvas.c index cc1a635..bff7ea7 100644 --- a/src/gl_canvas.c +++ b/src/gl_canvas.c @@ -130,6 +130,10 @@ typedef struct mg_gl_canvas_backend mg_canvas_backend interface; mg_wgl_surface* surface; + int msaaCount; + vec2 frameSize; + + // gl stuff GLuint vao; GLuint pathSetup; @@ -155,17 +159,12 @@ typedef struct mg_gl_canvas_backend GLuint tileOpCountBuffer; GLuint screenTilesBuffer; GLuint rasterDispatchBuffer; - GLuint dummyVertexBuffer; - int msaaCount; - vec2 frameSize; - //encoding context int pathCount; int eltCount; - ///////////////// int pathBatchStart; int eltBatchStart; @@ -1201,10 +1200,28 @@ void mg_gl_render_batch(mg_gl_canvas_backend* backend, backend->eltBatchStart = backend->eltCount; } -///////////////////////////////////////////////////////////////////////// -//TODO -void mg_gl_canvas_resize(mg_gl_canvas_backend* backend, vec2 size); -///////////////////////////////////////////////////////////////////////// +void mg_gl_canvas_resize(mg_gl_canvas_backend* backend, vec2 size) +{ + int tileSize = MG_GL_TILE_SIZE; + int nTilesX = (int)(size.x + tileSize - 1)/tileSize; + int nTilesY = (int)(size.y + tileSize - 1)/tileSize; + + glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->screenTilesBuffer); + glBufferData(GL_SHADER_STORAGE_BUFFER, nTilesX*nTilesY*sizeof(mg_gl_screen_tile), 0, GL_DYNAMIC_COPY); + + if(backend->outTexture) + { + //NOTE: do we need to explicitly glDeleteTextures()? + glDeleteTextures(1, &backend->outTexture); + glGenTextures(1, &backend->outTexture); + glBindTexture(GL_TEXTURE_2D, backend->outTexture); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, size.x, size.y); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + + backend->frameSize = size; +} void mg_gl_canvas_render(mg_canvas_backend* interface, mg_color clearColor, @@ -1224,23 +1241,29 @@ void mg_gl_canvas_render(mg_canvas_backend* interface, backend->bufferSync[backend->bufferIndex] = 0; } - //TODO update screen tiles buffer size + //NOTE update screen tiles buffer size mg_wgl_surface* surface = backend->surface; - mp_rect frame = surface->interface.getFrame((mg_surface_data*)surface); + vec2 surfaceSize = surface->interface.getSize((mg_surface_data*)surface); vec2 contentsScaling = surface->interface.contentsScaling((mg_surface_data*)surface); - //TODO support scaling in both axes + //TODO support scaling in both axes? f32 scale = contentsScaling.x; - vec2 viewportSize = {frame.w * scale, frame.h * scale}; + vec2 viewportSize = {surfaceSize.x * scale, surfaceSize.y * scale}; int tileSize = MG_GL_TILE_SIZE; - int nTilesX = (int)(frame.w * scale + tileSize - 1)/tileSize; - int nTilesY = (int)(frame.h * scale + tileSize - 1)/tileSize; + int nTilesX = (int)(viewportSize.x + tileSize - 1)/tileSize; + int nTilesY = (int)(viewportSize.y + tileSize - 1)/tileSize; if(viewportSize.x != backend->frameSize.x || viewportSize.y != backend->frameSize.y) { - //TODO: mg_gl_canvas_resize(backend, viewportSize); + mg_gl_canvas_resize(backend, viewportSize); } + ///////////////////////////////////////////////////////////////////////////////////////////////////// + //TODO: the surface's frame and the underlying window/view rect are not necessarily the same. + // we should set the viewport to cover the whole surface's frame, so it might not start at (0, 0) + ///////////////////////////////////////////////////////////////////////////////////////////////////// + glViewport(0, 0, viewportSize.x, viewportSize.y); + //NOTE: clear screen and reset input buffer offsets glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); @@ -1544,12 +1567,14 @@ mg_canvas_backend* gl_canvas_backend_create(mg_wgl_surface* surface) } //NOTE: create out texture - mp_rect frame = surface->interface.getFrame((mg_surface_data*)surface); + vec2 size = surface->interface.getSize((mg_surface_data*)surface); vec2 scale = surface->interface.contentsScaling((mg_surface_data*)surface); + backend->frameSize = (vec2){size.x * scale.x, size.y * scale.y}; + glGenTextures(1, &backend->outTexture); glBindTexture(GL_TEXTURE_2D, backend->outTexture); - glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, frame.w*scale.x, frame.h*scale.y); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, backend->frameSize.x, backend->frameSize.y); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -1611,8 +1636,8 @@ mg_canvas_backend* gl_canvas_backend_create(mg_wgl_surface* surface) glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(int), 0, GL_DYNAMIC_COPY); int tileSize = MG_GL_TILE_SIZE; - int nTilesX = (int)(frame.w * scale.x + tileSize - 1)/tileSize; - int nTilesY = (int)(frame.h * scale.y + tileSize - 1)/tileSize; + int nTilesX = (int)(backend->frameSize.x + tileSize - 1)/tileSize; + int nTilesY = (int)(backend->frameSize.y + tileSize - 1)/tileSize; glGenBuffers(1, &backend->screenTilesBuffer); glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->screenTilesBuffer); diff --git a/src/graphics.h b/src/graphics.h index 2eac71a..3a9a875 100644 --- a/src/graphics.h +++ b/src/graphics.h @@ -105,9 +105,8 @@ MP_API void mg_surface_present(mg_surface surface); MP_API void mg_surface_deselect(void); MP_API void mg_surface_swap_interval(mg_surface surface, int swap); +MP_API vec2 mg_surface_get_size(mg_surface surface); MP_API vec2 mg_surface_contents_scaling(mg_surface surface); -MP_API mp_rect mg_surface_get_frame(mg_surface surface); -MP_API void mg_surface_set_frame(mg_surface surface, mp_rect frame); MP_API bool mg_surface_get_hidden(mg_surface surface); MP_API void mg_surface_set_hidden(mg_surface surface, bool hidden); diff --git a/src/graphics_surface.c b/src/graphics_surface.c index 5715f89..9acc7a9 100644 --- a/src/graphics_surface.c +++ b/src/graphics_surface.c @@ -263,6 +263,18 @@ void mg_surface_swap_interval(mg_surface surface, int swap) } } +vec2 mg_surface_get_size(mg_surface surface) +{ + DEBUG_ASSERT(__mgData.init); + vec2 size = {0}; + mg_surface_data* surfaceData = mg_surface_data_from_handle(surface); + if(surfaceData && surfaceData->getSize) + { + size = surfaceData->getSize(surfaceData); + } + return(size); +} + vec2 mg_surface_contents_scaling(mg_surface surface) { DEBUG_ASSERT(__mgData.init); @@ -275,29 +287,6 @@ vec2 mg_surface_contents_scaling(mg_surface surface) return(scaling); } - -void mg_surface_set_frame(mg_surface surface, mp_rect frame) -{ - DEBUG_ASSERT(__mgData.init); - mg_surface_data* surfaceData = mg_surface_data_from_handle(surface); - if(surfaceData && surfaceData->setFrame) - { - surfaceData->setFrame(surfaceData, frame); - } -} - -mp_rect mg_surface_get_frame(mg_surface surface) -{ - DEBUG_ASSERT(__mgData.init); - mp_rect res = {0}; - mg_surface_data* surfaceData = mg_surface_data_from_handle(surface); - if(surfaceData && surfaceData->getFrame) - { - res = surfaceData->getFrame(surfaceData); - } - return(res); -} - void mg_surface_set_hidden(mg_surface surface, bool hidden) { DEBUG_ASSERT(__mgData.init); diff --git a/src/graphics_surface.h b/src/graphics_surface.h index fed7d6c..0dca19b 100644 --- a/src/graphics_surface.h +++ b/src/graphics_surface.h @@ -26,9 +26,8 @@ typedef void (*mg_surface_prepare_proc)(mg_surface_data* surface); typedef void (*mg_surface_deselect_proc)(mg_surface_data* surface); typedef void (*mg_surface_present_proc)(mg_surface_data* surface); typedef void (*mg_surface_swap_interval_proc)(mg_surface_data* surface, int swap); +typedef vec2 (*mg_surface_get_size_proc)(mg_surface_data* surface); typedef vec2 (*mg_surface_contents_scaling_proc)(mg_surface_data* surface); -typedef mp_rect (*mg_surface_get_frame_proc)(mg_surface_data* surface); -typedef void (*mg_surface_set_frame_proc)(mg_surface_data* surface, mp_rect frame); typedef bool (*mg_surface_get_hidden_proc)(mg_surface_data* surface); typedef void (*mg_surface_set_hidden_proc)(mg_surface_data* surface, bool hidden); typedef void* (*mg_surface_native_layer_proc)(mg_surface_data* surface); @@ -45,9 +44,8 @@ typedef struct mg_surface_data mg_surface_present_proc present; mg_surface_deselect_proc deselect; mg_surface_swap_interval_proc swapInterval; + mg_surface_get_size_proc getSize; mg_surface_contents_scaling_proc contentsScaling; - mg_surface_get_frame_proc getFrame; - mg_surface_set_frame_proc setFrame; mg_surface_get_hidden_proc getHidden; mg_surface_set_hidden_proc setHidden; mg_surface_native_layer_proc nativeLayer; @@ -79,34 +77,6 @@ typedef struct mg_image_data } mg_image_data; -typedef struct mg_vertex_layout -{ - u32 maxVertexCount; - u32 maxIndexCount; - - char* posBuffer; - u32 posStride; - - char* cubicBuffer; - u32 cubicStride; - - char* shapeIndexBuffer; - u32 shapeIndexStride; - - char* colorBuffer; - u32 colorStride; - - char* clipBuffer; - u32 clipStride; - - char* uvTransformBuffer; - u32 uvTransformStride; - - char* indexBuffer; - u32 indexStride; - -} mg_vertex_layout; - typedef void (*mg_canvas_backend_destroy_proc)(mg_canvas_backend* backend); typedef void (*mg_canvas_backend_begin_proc)(mg_canvas_backend* backend, mg_color clearColor); typedef void (*mg_canvas_backend_end_proc)(mg_canvas_backend* backend); @@ -133,8 +103,6 @@ typedef void (*mg_canvas_backend_render_proc)(mg_canvas_backend* backend, typedef struct mg_canvas_backend { -// mg_vertex_layout vertexLayout; - mg_canvas_backend_destroy_proc destroy; mg_canvas_backend_begin_proc begin; mg_canvas_backend_end_proc end; @@ -144,7 +112,6 @@ typedef struct mg_canvas_backend mg_canvas_backend_image_destroy_proc imageDestroy; mg_canvas_backend_image_upload_region_proc imageUploadRegion; - mg_canvas_backend_render_proc render; } mg_canvas_backend; diff --git a/src/win32_app.c b/src/win32_app.c index 8342131..70fb48b 100644 --- a/src/win32_app.c +++ b/src/win32_app.c @@ -247,39 +247,6 @@ static void process_wheel_event(mp_window_data* window, f32 x, f32 y) mp_queue_event(&event); } -void mg_win32_layer_set_frame(mp_layer* layer, mp_rect frame) -{ - layer->userFrame = frame; - - HWND parent = GetParent(layer->hWnd); - - RECT clientRect; - GetClientRect(parent, &clientRect); - POINT point = {0}; - ClientToScreen(layer->hWnd, &point); - - u32 dpi = GetDpiForWindow(layer->hWnd); - vec2 scale = (vec2){(float)dpi/96., (float)dpi/96.}; - - int parentWidth = (clientRect.right - clientRect.left)/scale.x; - int parentHeight = (clientRect.bottom - clientRect.top)/scale.y; - - int minX = Clamp(frame.x, 0, parentWidth); - int maxX = Clamp(frame.x + frame.w, 0, parentWidth); - int minY = Clamp(frame.y, 0, parentHeight); - int maxY = Clamp(frame.y + frame.h, 0, parentHeight); - - SetWindowPos(layer->hWnd, - HWND_TOP, - point.x + minX * scale.x, - point.y + minY * scale.y, - (maxX - minX) * scale.x, - (maxY - minY) * scale.y, - SWP_NOACTIVATE | SWP_NOZORDER); - - //TODO test if we should we guard against 0-width windows -} - static void win32_update_child_layers(mp_window_data* window) { RECT clientRect; @@ -287,29 +254,19 @@ static void win32_update_child_layers(mp_window_data* window) POINT point = {0}; ClientToScreen(window->win32.hWnd, &point); - u32 dpi = GetDpiForWindow(window->win32.hWnd); - vec2 scale = (vec2){(float)dpi/96., (float)dpi/96.}; - - int parentWidth = (clientRect.right - clientRect.left)/scale.x; - int parentHeight = (clientRect.bottom - clientRect.top)/scale.y; + int clientWidth = (clientRect.right - clientRect.left); + int clientHeight = (clientRect.bottom - clientRect.top); HWND insertAfter = window->win32.hWnd; for_list(&window->win32.layers, layer, mp_layer, listElt) { - mp_rect frame = layer->userFrame; - - int minX = Clamp(frame.x, 0, parentWidth); - int maxX = Clamp(frame.x + frame.w, 0, parentWidth); - int minY = Clamp(frame.y, 0, parentHeight); - int maxY = Clamp(frame.y + frame.h, 0, parentHeight); - SetWindowPos(layer->hWnd, insertAfter, - point.x + minX * scale.x, - point.y + minY * scale.y, - (maxX - minX) * scale.x, - (maxY - minY) * scale.y, + point.x, + point.y, + clientWidth, + clientHeight, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER); insertAfter = layer->hWnd; @@ -967,14 +924,17 @@ vec2 mg_win32_surface_contents_scaling(mg_surface_data* surface) return(contentsScaling); } -mp_rect mg_win32_surface_get_frame(mg_surface_data* surface) +vec2 mg_win32_surface_get_size(mg_surface_data* surface) { - return(surface->layer.userFrame); -} - -void mg_win32_surface_set_frame(mg_surface_data* surface, mp_rect frame) -{ - mg_win32_layer_set_frame(&surface->layer, frame); + vec2 size = {0}; + RECT rect; + if(GetClientRect(surface->layer.hWnd, &rect)) + { + u32 dpi = GetDpiForWindow(surface->layer.hWnd); + f32 scale = (float)dpi/96.; + size = (vec2){(rect.right - rect.left)/scale, (rect.bottom - rect.top)/scale}; + } + return(size); } bool mg_win32_surface_get_hidden(mg_surface_data* surface) @@ -1039,8 +999,7 @@ LRESULT LayerWinProc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lPar void mg_surface_init_for_window(mg_surface_data* surface, mp_window_data* window) { surface->contentsScaling = mg_win32_surface_contents_scaling; - surface->getFrame = mg_win32_surface_get_frame; - surface->setFrame = mg_win32_surface_set_frame; + surface->getSize = mg_win32_surface_get_size; surface->getHidden = mg_win32_surface_get_hidden; surface->setHidden = mg_win32_surface_set_hidden; surface->nativeLayer = mg_win32_surface_native_layer; @@ -1059,17 +1018,12 @@ void mg_surface_init_for_window(mg_surface_data* surface, mp_window_data* window POINT point = {0}; ClientToScreen(window->win32.hWnd, &point); - int width = parentRect.right - parentRect.left; - int height = parentRect.bottom - parentRect.top; - - u32 dpi = GetDpiForWindow(window->win32.hWnd); - vec2 scale = (vec2){(float)dpi/96., (float)dpi/96.}; - - surface->layer.userFrame = (mp_rect){0, 0, width / scale.x, height / scale.y}; + int clientWidth = parentRect.right - parentRect.left; + int clientHeight = parentRect.bottom - parentRect.top; surface->layer.hWnd = CreateWindow("layer_window_class", "layer", WS_POPUP | WS_VISIBLE, - point.x, point.y, width, height, + point.x, point.y, clientWidth, clientHeight, window->win32.hWnd, 0, layerWindowClass.hInstance, @@ -1097,8 +1051,7 @@ void mg_surface_init_for_window(mg_surface_data* surface, mp_window_data* window void mg_surface_init_remote(mg_surface_data* surface, u32 width, u32 height) { surface->contentsScaling = mg_win32_surface_contents_scaling; - surface->getFrame = mg_win32_surface_get_frame; - surface->setFrame = mg_win32_surface_set_frame; + surface->getSize = mg_win32_surface_get_size; surface->getHidden = mg_win32_surface_get_hidden; surface->setHidden = mg_win32_surface_set_hidden; surface->nativeLayer = mg_win32_surface_native_layer; diff --git a/src/win32_app.h b/src/win32_app.h index 7124a88..2eb0e44 100644 --- a/src/win32_app.h +++ b/src/win32_app.h @@ -28,7 +28,6 @@ typedef struct mp_layer { mp_window_data* parent; list_elt listElt; - mp_rect userFrame; HWND hWnd; } mp_layer; From a4ae1cf214fc241ee4cd8e15e5edd87cda973dd9 Mon Sep 17 00:00:00 2001 From: martinfouilleul Date: Tue, 25 Jul 2023 15:55:09 +0200 Subject: [PATCH 3/8] [win32, surface] Fix auto-selecting surface when first creating one ; checking why smooth resize still doesn't work even though we receive events and draw in a separate thread --- examples/smooth_resize/build.bat | 4 + examples/smooth_resize/main.c | 256 +++++++++++++------------------ src/gl_canvas.c | 4 - src/graphics_surface.c | 2 + 4 files changed, 110 insertions(+), 156 deletions(-) create mode 100644 examples/smooth_resize/build.bat diff --git a/examples/smooth_resize/build.bat b/examples/smooth_resize/build.bat new file mode 100644 index 0000000..4f2c691 --- /dev/null +++ b/examples/smooth_resize/build.bat @@ -0,0 +1,4 @@ + +set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers /I ..\..\..\..\vcpkg\packages\pthreads_x64-windows\include + +cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib /LIBPATH:..\..\..\..\vcpkg\packages\pthreads_x64-windows\lib pthreadVC3.lib /out:../../bin/example_smooth_resize.exe diff --git a/examples/smooth_resize/main.c b/examples/smooth_resize/main.c index 645828d..276c0e4 100644 --- a/examples/smooth_resize/main.c +++ b/examples/smooth_resize/main.c @@ -6,6 +6,7 @@ * @revision: * *****************************************************************/ +#include #include #include #include @@ -13,45 +14,55 @@ #define _USE_MATH_DEFINES //NOTE: necessary for MSVC #include +#define MG_INCLUDE_GL_API #include"milepost.h" #include -#define LOG_SUBSYSTEM "Main" +unsigned int program; +const char* vshaderSource = + "#version 430\n" + "attribute vec4 vPosition;\n" + "uniform mat4 transform;\n" + "void main()\n" + "{\n" + " gl_Position = transform*vPosition;\n" + "}\n"; -mg_font create_font() +const char* fshaderSource = + "#version 430\n" + "precision mediump float;\n" + "void main()\n" + "{\n" + " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" + "}\n"; + +void compile_shader(GLuint shader, const char* source) { - //NOTE(martin): create font - str8 fontPath = path_executable_relative(mem_scratch(), STR8("../resources/OpenSansLatinSubset.ttf")); - char* fontPathCString = str8_to_cstring(mem_scratch(), fontPath); + glShaderSource(shader, 1, &source, 0); + glCompileShader(shader); - FILE* fontFile = fopen(fontPathCString, "r"); - if(!fontFile) + int err = glGetError(); + if(err) { - log_error("Could not load font file '%s': %s\n", fontPathCString, strerror(errno)); - return(mg_font_nil()); + printf("gl error: %i\n", err); } - unsigned char* fontData = 0; - fseek(fontFile, 0, SEEK_END); - u32 fontDataSize = ftell(fontFile); - rewind(fontFile); - fontData = (unsigned char*)malloc(fontDataSize); - fread(fontData, 1, fontDataSize, fontFile); - fclose(fontFile); - unicode_range ranges[5] = {UNICODE_RANGE_BASIC_LATIN, - UNICODE_RANGE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT, - UNICODE_RANGE_LATIN_EXTENDED_A, - UNICODE_RANGE_LATIN_EXTENDED_B, - UNICODE_RANGE_SPECIALS}; - - mg_font font = mg_font_create_from_memory(fontDataSize, fontData, 5, ranges); - free(fontData); - - return(font); + int status = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if(!status) + { + char buffer[256]; + int size = 0; + glGetShaderInfoLog(shader, 256, &size, buffer); + printf("shader error: %.*s\n", size, buffer); + } } +GLfloat vertices[] = { + -0.866/2, -0.5/2, 0, 0.866/2, -0.5/2, 0, 0, 0.5, 0}; + typedef struct app_data { mp_window window; @@ -59,13 +70,7 @@ typedef struct app_data mg_canvas canvas; mg_font font; - f32 x; - f32 y; - f32 dx; - f32 dy; - f32 speed; - f32 frameTime; - + GLuint vertexBuffer; } app_data; void process_event(app_data* app, mp_event event) @@ -79,33 +84,7 @@ void process_event(app_data* app, mp_event event) case MP_EVENT_WINDOW_RESIZE: { - mp_rect frame = {0, 0, event.frame.rect.w, event.frame.rect.h}; - mg_surface_set_frame(app->surface, frame); - } break; - - case MP_EVENT_KEYBOARD_KEY: - { - if(event.key.action == MP_KEY_PRESS || event.key.action == MP_KEY_REPEAT) - { - f32 factor = (event.key.mods & MP_KEYMOD_SHIFT) ? 10 : 1; - - if(event.key.code == MP_KEY_LEFT) - { - app->x-=0.3*factor; - } - else if(event.key.code == MP_KEY_RIGHT) - { - app->x+=0.3*factor; - } - else if(event.key.code == MP_KEY_UP) - { - app->y-=0.3*factor; - } - else if(event.key.code == MP_KEY_DOWN) - { - app->y+=0.3*factor; - } - } + log_info("resizing window!\n"); } break; default: @@ -115,95 +94,89 @@ void process_event(app_data* app, mp_event event) void update_and_render(app_data* app) { - mp_rect contentRect = mp_window_get_content_rect(app->window); - - if(app->x-200 < 0) - { - app->x = 200; - app->dx = app->speed; - } - if(app->x+200 > contentRect.w) - { - app->x = contentRect.w - 200; - app->dx = -app->speed; - } - if(app->y-200 < 0) - { - app->y = 200; - app->dy = app->speed; - } - if(app->y+200 > contentRect.h) - { - app->y = contentRect.h - 200; - app->dy = -app->speed; - } - app->x += app->dx; - app->y += app->dy; - - f64 startTime = mp_get_time(MP_CLOCK_MONOTONIC); - mg_surface_prepare(app->surface); - // background - mg_set_color_rgba(0, 1, 1, 1); - mg_clear(); + glClearColor(0.3, 0.3, 1, 1); + glClear(GL_COLOR_BUFFER_BIT); - // head - mg_set_color_rgba(1, 1, 0, 1); + static float alpha = 0; + //f32 aspect = frameSize.x/frameSize.y; + f32 aspect = 800/(f32)600; - mg_circle_fill(app->x, app->y, 200); + GLfloat matrix[] = {cosf(alpha)/aspect, sinf(alpha), 0, 0, + -sinf(alpha)/aspect, cosf(alpha), 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1}; - // smile - f32 frown = app->frameTime > 0.033 ? -100 : 0; + alpha += 2*M_PI/120; - mg_set_color_rgba(0, 0, 0, 1); - mg_set_width(20); - mg_move_to(app->x-100, app->y+100); - mg_cubic_to(app->x-50, app->y+150+frown, app->x+50, app->y+150+frown, app->x+100, app->y+100); - mg_stroke(); + glUniformMatrix4fv(0, 1, false, matrix); - // eyes - mg_ellipse_fill(app->x-70, app->y-50, 30, 50); - mg_ellipse_fill(app->x+70, app->y-50, 30, 50); - // text - mg_set_color_rgba(0, 0, 1, 1); - mg_set_font(app->font); - mg_set_font_size(12); - mg_move_to(50, 600-50); + glBindBuffer(GL_ARRAY_BUFFER, app->vertexBuffer); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(0); - str8 text = str8_pushf(mem_scratch(), - "Milepost vector graphics test program (frame time = %fs, fps = %f)...", - app->frameTime, - 1./app->frameTime); - mg_text_outlines(text); - mg_fill(); + glDrawArrays(GL_TRIANGLES, 0, 3); - printf("Milepost vector graphics test program (frame time = %fs, fps = %f)...\n", - app->frameTime, - 1./app->frameTime); - - mg_flush(); mg_surface_present(app->surface); mem_arena_clear(mem_scratch()); - app->frameTime = mp_get_time(MP_CLOCK_MONOTONIC) - startTime; } void* render(void* user) { app_data* app = (app_data*)user; - mg_canvas_prepare(app->canvas); + //NOTE: init shader and gl state + mg_surface_prepare(app->surface); + + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + glGenBuffers(1, &app->vertexBuffer); + + GLfloat vertices[] = { + -0.866/2, -0.5/2, 0, 0.866/2, -0.5/2, 0, 0, 0.5, 0}; + + glBindBuffer(GL_ARRAY_BUFFER, app->vertexBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + + unsigned int vshader = glCreateShader(GL_VERTEX_SHADER); + unsigned int fshader = glCreateShader(GL_FRAGMENT_SHADER); + program = glCreateProgram(); + + compile_shader(vshader, vshaderSource); + compile_shader(fshader, fshaderSource); + + glAttachShader(program, vshader); + glAttachShader(program, fshader); + glLinkProgram(program); + + int status = 0; + glGetProgramiv(program, GL_LINK_STATUS, &status); + if(!status) + { + char buffer[256]; + int size = 0; + glGetProgramInfoLog(program, 256, &size, buffer); + printf("link error: %.*s\n", size, buffer); + } + + glUseProgram(program); while(!mp_should_quit()) { - mp_event event = {0}; - while(mp_next_event(&event)) + mp_event* event = 0; + + while((event = mp_next_event(mem_scratch())) != 0) { - process_event(app, event); + process_event(app, *event); } update_and_render(app); + mem_arena_clear(mem_scratch()); } return(0); @@ -211,8 +184,6 @@ void* render(void* user) int main() { - LogLevel(LOG_LEVEL_WARNING); - mp_init(); mp_clock_init(); //TODO put that in mp_init()? @@ -220,19 +191,16 @@ int main() mp_window window = mp_window_create(windowRect, "test", 0); //NOTE: create surface - mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_DEFAULT); - mg_surface_swap_interval(surface, 0); - - //TODO: create canvas - mg_canvas canvas = mg_canvas_create(surface); - - if(mg_canvas_is_nil(canvas)) + mg_surface surface = mg_surface_create_for_window(window, MG_GL); + if(mg_surface_is_nil(surface)) { - printf("Error: couldn't create canvas\n"); + printf("Error: couldn't create surface\n"); return(-1); } - mg_font font = create_font(); + mg_surface_swap_interval(surface, 1); + mg_surface_deselect(); + // start app mp_window_bring_to_front(window); @@ -240,13 +208,7 @@ int main() //TODO: start thread app_data app = {.window = window, - .surface = surface, - .canvas = canvas, - .font = font, - .x = 400, - .y = 300, - .dx = 0, - .dy = 0}; + .surface = surface}; pthread_t renderThread; pthread_create(&renderThread, 0, render, &app); @@ -254,21 +216,11 @@ int main() while(!mp_should_quit()) { mp_pump_events(0); - /* - mp_event event = {0}; - while(mp_next_event(&event)) - { - process_event(&app, event); - } - update_and_render(&app); - //*/ } void* res; pthread_join(renderThread, &res); - mg_font_destroy(font); - mg_canvas_destroy(canvas); mg_surface_destroy(surface); mp_window_destroy(window); diff --git a/src/gl_canvas.c b/src/gl_canvas.c index bff7ea7..30c6b35 100644 --- a/src/gl_canvas.c +++ b/src/gl_canvas.c @@ -1258,10 +1258,6 @@ void mg_gl_canvas_render(mg_canvas_backend* interface, mg_gl_canvas_resize(backend, viewportSize); } - ///////////////////////////////////////////////////////////////////////////////////////////////////// - //TODO: the surface's frame and the underlying window/view rect are not necessarily the same. - // we should set the viewport to cover the whole surface's frame, so it might not start at (0, 0) - ///////////////////////////////////////////////////////////////////////////////////////////////////// glViewport(0, 0, viewportSize.x, viewportSize.y); //NOTE: clear screen and reset input buffer offsets diff --git a/src/graphics_surface.c b/src/graphics_surface.c index 9acc7a9..e3d3023 100644 --- a/src/graphics_surface.c +++ b/src/graphics_surface.c @@ -147,6 +147,7 @@ mg_surface mg_surface_create_for_window(mp_window window, mg_surface_api api) if(surface) { surfaceHandle = mg_surface_handle_alloc(surface); + mg_surface_prepare(surfaceHandle); } return(surfaceHandle); } @@ -174,6 +175,7 @@ mg_surface mg_surface_create_remote(u32 width, u32 height, mg_surface_api api) if(surface) { surfaceHandle = mg_surface_handle_alloc(surface); + mg_surface_prepare(surfaceHandle); } return(surfaceHandle); } From e7cce5e36fd522a20666e73e945a6aeca1f4ed8b Mon Sep 17 00:00:00 2001 From: Martin Fouilleul Date: Tue, 25 Jul 2023 17:02:11 +0200 Subject: [PATCH 4/8] [osx, surface] use autoresizeMask to resize surfaces to the parent window's client area --- src/mtl_renderer.m | 18 ++++++----- src/mtl_surface.m | 6 ++-- src/osx_app.m | 77 ++++++++++++++++++++++------------------------ 3 files changed, 50 insertions(+), 51 deletions(-) diff --git a/src/mtl_renderer.m b/src/mtl_renderer.m index 53d805a..8cd5811 100644 --- a/src/mtl_renderer.m +++ b/src/mtl_renderer.m @@ -1159,6 +1159,8 @@ void mg_mtl_canvas_resize(mg_mtl_canvas_backend* backend, vec2 size) backend->outTexture = [backend->surface->device newTextureWithDescriptor:texDesc]; + backend->surface->mtlLayer.drawableSize = (CGSize){size.x, size.y}; + backend->frameSize = size; } } @@ -1179,13 +1181,13 @@ void mg_mtl_canvas_render(mg_canvas_backend* interface, //NOTE: ensure screen tiles buffer is correct size mg_mtl_surface* surface = backend->surface; - mp_rect frame = surface->interface.getFrame((mg_surface_data*)surface); + vec2 frameSize = surface->interface.getSize((mg_surface_data*)surface); f32 scale = surface->mtlLayer.contentsScale; - vec2 viewportSize = {frame.w * scale, frame.h * scale}; + vec2 viewportSize = {frameSize.x * scale, frameSize.y * scale}; int tileSize = MG_MTL_TILE_SIZE; - int nTilesX = (int)(frame.w * scale + tileSize - 1)/tileSize; - int nTilesY = (int)(frame.h * scale + tileSize - 1)/tileSize; + int nTilesX = (int)(viewportSize.x * scale + tileSize - 1)/tileSize; + int nTilesY = (int)(viewportSize.y * scale + tileSize - 1)/tileSize; if(viewportSize.x != backend->frameSize.x || viewportSize.y != backend->frameSize.y) { @@ -1482,10 +1484,10 @@ mg_canvas_backend* mtl_canvas_backend_create(mg_mtl_surface* surface) backend->blitPipeline = [surface->device newRenderPipelineStateWithDescriptor: pipelineStateDescriptor error:&err]; //NOTE: create textures - mp_rect frame = surface->interface.getFrame((mg_surface_data*)surface); + vec2 size = surface->interface.getSize((mg_surface_data*)surface); f32 scale = surface->mtlLayer.contentsScale; - backend->frameSize = (vec2){frame.w*scale, frame.h*scale}; + backend->frameSize = (vec2){size.x*scale, size.y*scale}; MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init]; texDesc.textureType = MTLTextureType2D; @@ -1540,8 +1542,8 @@ mg_canvas_backend* mtl_canvas_backend_create(mg_mtl_surface* surface) options: bufferOptions]; int tileSize = MG_MTL_TILE_SIZE; - int nTilesX = (int)(frame.w * scale + tileSize - 1)/tileSize; - int nTilesY = (int)(frame.h * scale + tileSize - 1)/tileSize; + int nTilesX = (int)(backend->frameSize.x + tileSize - 1)/tileSize; + int nTilesY = (int)(backend->frameSize.y + tileSize - 1)/tileSize; backend->screenTilesBuffer = [surface->device newBufferWithLength: nTilesX*nTilesY*sizeof(mg_mtl_screen_tile) options: bufferOptions]; diff --git a/src/mtl_surface.m b/src/mtl_surface.m index c4811ba..179e6b5 100644 --- a/src/mtl_surface.m +++ b/src/mtl_surface.m @@ -116,6 +116,7 @@ void mg_mtl_surface_swap_interval(mg_surface_data* interface, int swap) } } +/* void mg_mtl_surface_set_frame(mg_surface_data* interface, mp_rect frame) { mg_mtl_surface* surface = (mg_mtl_surface*)interface; @@ -135,6 +136,7 @@ void mg_mtl_surface_set_frame(mg_surface_data* interface, mp_rect frame) CGSize drawableSize = (CGSize){.width = frame.w * scale.x, .height = frame.h * scale.y}; surface->mtlLayer.drawableSize = drawableSize; } +*/ //TODO fix that according to real scaling, depending on the monitor settings @@ -162,8 +164,6 @@ mg_surface_data* mg_mtl_surface_create_for_window(mp_window window) surface->interface.present = mg_mtl_surface_present; surface->interface.swapInterval = mg_mtl_surface_swap_interval; - surface->interface.setFrame = mg_mtl_surface_set_frame; - @autoreleasepool { //----------------------------------------------------------- @@ -203,7 +203,7 @@ mg_surface_data* mg_mtl_surface_create_for_window(mp_window window) [surface->mtlLayer setOpaque:NO]; - + surface->mtlLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; [surface->interface.layer.caLayer addSublayer: (CALayer*)surface->mtlLayer]; //----------------------------------------------------------- diff --git a/src/osx_app.m b/src/osx_app.m index affb7d7..f8cecdf 100644 --- a/src/osx_app.m +++ b/src/osx_app.m @@ -663,11 +663,18 @@ void mp_install_keyboard_layout_listener() mp_event event = {}; event.window = mp_window_handle_from_ptr(mpWindow); event.type = MP_EVENT_WINDOW_MOVE; - event.frame.rect.x = contentRect.origin.x; - event.frame.rect.y = contentRect.origin.y; - event.frame.rect.w = contentRect.size.width; - event.frame.rect.h = contentRect.size.height; + /////////////////////////////////////////////////// + //TODO make it relative to top-left corner! + /////////////////////////////////////////////////// + event.move.contents.x = contentRect.origin.x; + event.move.contents.y = contentRect.origin.y; + event.move.contents.w = contentRect.size.width; + event.move.contents.h = contentRect.size.height; + + /////////////////////////////////////////////////// + //TODO: add window frame! + /////////////////////////////////////////////////// mp_queue_event(&event); } @@ -680,10 +687,14 @@ void mp_install_keyboard_layout_listener() mp_event event = {}; event.window = mp_window_handle_from_ptr(mpWindow); event.type = MP_EVENT_WINDOW_RESIZE; - event.frame.rect.x = contentRect.origin.x; - event.frame.rect.y = contentRect.origin.y; - event.frame.rect.w = contentRect.size.width; - event.frame.rect.h = contentRect.size.height; + + /////////////////////////////////////////////////// + //TODO make it relative to top-left corner! + /////////////////////////////////////////////////// + event.move.contents.x = contentRect.origin.x; + event.move.contents.y = contentRect.origin.y; + event.move.contents.w = contentRect.size.width; + event.move.contents.h = contentRect.size.height; if(__mpApp.liveResizeCallback) { @@ -869,11 +880,11 @@ static void mp_process_mouse_button(NSEvent* nsEvent, mp_window_data* window, mp mp_event event = {}; event.type = MP_EVENT_MOUSE_MOVE; event.window = mp_window_handle_from_ptr(window); - event.move.x = p.x; - event.move.y = frame.size.height - p.y; - event.move.deltaX = [nsEvent deltaX]; - event.move.deltaY = [nsEvent deltaY]; - event.move.mods = mp_convert_osx_mods([nsEvent modifierFlags]); + event.mouse.x = p.x; + event.mouse.y = frame.size.height - p.y; + event.mouse.deltaX = [nsEvent deltaX]; + event.mouse.deltaY = [nsEvent deltaY]; + event.mouse.mods = mp_convert_osx_mods([nsEvent modifierFlags]); mp_queue_event(&event); } @@ -885,11 +896,11 @@ static void mp_process_mouse_button(NSEvent* nsEvent, mp_window_data* window, mp event.type = MP_EVENT_MOUSE_WHEEL; double factor = [nsEvent hasPreciseScrollingDeltas] ? 0.1 : 1.0; - event.move.x = 0; - event.move.y = 0; - event.move.deltaX = -[nsEvent scrollingDeltaX]*factor; - event.move.deltaY = -[nsEvent scrollingDeltaY]*factor; - event.move.mods = mp_convert_osx_mods([nsEvent modifierFlags]); + event.mouse.x = 0; + event.mouse.y = 0; + event.mouse.deltaX = -[nsEvent scrollingDeltaX]*factor; + event.mouse.deltaY = -[nsEvent scrollingDeltaY]*factor; + event.mouse.mods = mp_convert_osx_mods([nsEvent modifierFlags]); mp_queue_event(&event); } @@ -1678,26 +1689,13 @@ vec2 mg_osx_surface_contents_scaling(mg_surface_data* surface) return(res); }} -mp_rect mg_osx_surface_get_frame(mg_surface_data* surface) +vec2 mg_osx_surface_get_size(mg_surface_data* surface) {@autoreleasepool{ - CGRect frame = surface->layer.caLayer.frame; - mp_rect res = {frame.origin.x, - frame.origin.y, - frame.size.width, - frame.size.height}; + CGRect bounds = surface->layer.caLayer.bounds; + vec2 res = {bounds.size.width, bounds.size.height}; return(res); }} -void mg_osx_surface_set_frame(mg_surface_data* surface, mp_rect frame) -{@autoreleasepool{ - CGRect cgFrame = {{frame.x, frame.y}, {frame.w, frame.h}}; - - [CATransaction begin]; - [CATransaction setDisableActions:YES]; - [surface->layer.caLayer setFrame: cgFrame]; - [CATransaction commit]; -}} - bool mg_osx_surface_get_hidden(mg_surface_data* surface) {@autoreleasepool{ return([surface->layer.caLayer isHidden]); @@ -1721,8 +1719,7 @@ void mg_surface_init_for_window(mg_surface_data* surface, mp_window_data* window surface->nativeLayer = mg_osx_surface_native_layer; surface->contentsScaling = mg_osx_surface_contents_scaling; - surface->getFrame = mg_osx_surface_get_frame; - surface->setFrame = mg_osx_surface_set_frame; + surface->getSize = mg_osx_surface_get_size; surface->getHidden = mg_osx_surface_get_hidden; surface->setHidden = mg_osx_surface_set_hidden; @@ -1734,6 +1731,8 @@ void mg_surface_init_for_window(mg_surface_data* surface, mp_window_data* window surface->layer.caLayer.frame = (CGRect){{0, 0}, size}; surface->layer.caLayer.contentsScale = window->osx.nsView.layer.contentsScale; + surface->layer.caLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; + [window->osx.nsView.layer addSublayer: surface->layer.caLayer]; }} @@ -1758,8 +1757,7 @@ void mg_surface_init_remote(mg_surface_data* surface, u32 width, u32 height) surface->nativeLayer = mg_osx_surface_native_layer; surface->contentsScaling = mg_osx_surface_contents_scaling; - surface->getFrame = mg_osx_surface_get_frame; - surface->setFrame = mg_osx_surface_set_frame; + surface->getSize = mg_osx_surface_get_size; surface->getHidden = mg_osx_surface_get_hidden; surface->setHidden = mg_osx_surface_set_hidden; surface->remoteID = mg_osx_surface_remote_id; @@ -1786,8 +1784,7 @@ void mg_surface_init_host(mg_surface_data* surface, mp_window_data* window) surface->api = MG_HOST; surface->nativeLayer = mg_osx_surface_native_layer; surface->contentsScaling = mg_osx_surface_contents_scaling; - surface->getFrame = mg_osx_surface_get_frame; - surface->setFrame = mg_osx_surface_set_frame; + surface->getSize = mg_osx_surface_get_size; surface->getHidden = mg_osx_surface_get_hidden; surface->setHidden = mg_osx_surface_set_hidden; surface->hostConnect = mg_osx_surface_host_connect; From 06b5d30dc6fe8ac9c993d777d886d42bb0ccd0e6 Mon Sep 17 00:00:00 2001 From: Martin Fouilleul Date: Tue, 25 Jul 2023 18:05:55 +0200 Subject: [PATCH 5/8] [osx] correctly pass move/resize contents and frame rect relative to top-left instead of bottom left --- src/mp_app_internal.h | 2 - src/osx_app.m | 148 +++++++++++++++++++----------------------- 2 files changed, 65 insertions(+), 85 deletions(-) diff --git a/src/mp_app_internal.h b/src/mp_app_internal.h index e801a96..931934b 100644 --- a/src/mp_app_internal.h +++ b/src/mp_app_internal.h @@ -39,8 +39,6 @@ typedef struct mp_window_data list_elt freeListElt; u32 generation; - mp_rect contentRect; - mp_rect frameRect; mp_window_style style; bool shouldClose; //TODO could be in status flags diff --git a/src/osx_app.m b/src/osx_app.m index f8cecdf..1f1b8fd 100644 --- a/src/osx_app.m +++ b/src/osx_app.m @@ -26,44 +26,24 @@ // mp window struct and utility functions //-------------------------------------------------------------------- -static mp_rect mp_osx_to_user_screen_rect(mp_rect rect) +static mp_rect mp_osx_to_user_screen_rect(NSScreen* screen, mp_rect rect) { @autoreleasepool { - NSRect screenRect = [[NSScreen mainScreen] frame]; - rect.y = screenRect.size.height - rect.y - rect.h; + rect.y = screen.frame.size.height - rect.y - rect.h; } return(rect); } -static mp_rect mp_user_to_osx_screen_rect(mp_rect rect) +static mp_rect mp_user_to_osx_screen_rect(NSScreen* screen, mp_rect rect) { @autoreleasepool { - NSRect screenRect = [[NSScreen mainScreen] frame]; - rect.y = screenRect.size.height - rect.y - rect.h; + rect.y = screen.frame.size.height - rect.y - rect.h; } return(rect); } -static void mp_window_update_rect_cache(mp_window_data* window) -{ - @autoreleasepool - { - NSRect frame = [window->osx.nsWindow frame]; - window->frameRect = mp_osx_to_user_screen_rect((mp_rect){frame.origin.x, frame.origin.y, frame.size.width, frame.size.height}); - - const NSRect contentRect = [[window->osx.nsWindow contentView] frame]; - - window->contentRect = (mp_rect){ contentRect.origin.x, - contentRect.origin.y, - contentRect.size.width, - contentRect.size.height }; - - window->contentRect.y = window->frameRect.h - window->contentRect.y - window->contentRect.h; - } -} - static u32 mp_osx_get_window_style_mask(mp_window_style style) { u32 mask = 0; @@ -657,42 +637,43 @@ void mp_install_keyboard_layout_listener() - (void)windowDidMove:(NSNotification *)notification { const NSRect contentRect = [[mpWindow->osx.nsWindow contentView] frame]; - - mp_window_update_rect_cache(mpWindow); + const NSRect frameRect = [mpWindow->osx.nsWindow frame]; + NSScreen* screen = mpWindow->osx.nsWindow.screen; mp_event event = {}; event.window = mp_window_handle_from_ptr(mpWindow); event.type = MP_EVENT_WINDOW_MOVE; - /////////////////////////////////////////////////// - //TODO make it relative to top-left corner! - /////////////////////////////////////////////////// + event.move.frame.x = contentRect.origin.x; + event.move.frame.y = screen.frame.size.height - frameRect.origin.y - frameRect.size.height; + event.move.frame.w = contentRect.size.width; + event.move.frame.h = contentRect.size.height; + event.move.contents.x = contentRect.origin.x; - event.move.contents.y = contentRect.origin.y; + event.move.contents.y = frameRect.size.height - contentRect.origin.y - contentRect.size.height; event.move.contents.w = contentRect.size.width; event.move.contents.h = contentRect.size.height; - /////////////////////////////////////////////////// - //TODO: add window frame! - /////////////////////////////////////////////////// mp_queue_event(&event); } - (void)windowDidResize:(NSNotification *)notification { const NSRect contentRect = [[mpWindow->osx.nsWindow contentView] frame]; - - mp_window_update_rect_cache(mpWindow); + const NSRect frameRect = [mpWindow->osx.nsWindow frame]; + NSScreen* screen = mpWindow->osx.nsWindow.screen; mp_event event = {}; event.window = mp_window_handle_from_ptr(mpWindow); event.type = MP_EVENT_WINDOW_RESIZE; - /////////////////////////////////////////////////// - //TODO make it relative to top-left corner! - /////////////////////////////////////////////////// + event.move.frame.x = contentRect.origin.x; + event.move.frame.y = screen.frame.size.height - frameRect.origin.y - frameRect.size.height; + event.move.frame.w = contentRect.size.width; + event.move.frame.h = contentRect.size.height; + event.move.contents.x = contentRect.origin.x; - event.move.contents.y = contentRect.origin.y; + event.move.contents.y = frameRect.size.height - contentRect.origin.y - contentRect.size.height; event.move.contents.w = contentRect.size.width; event.move.contents.h = contentRect.size.height; @@ -1403,7 +1384,6 @@ mp_window mp_window_create(mp_rect contentRect, const char* title, mp_window_sty [window->osx.nsWindow makeFirstResponder:view]; [window->osx.nsWindow setAcceptsMouseMovedEvents:YES]; - mp_window_update_rect_cache(window); mp_window windowHandle = mp_window_handle_from_ptr(window); @@ -1560,22 +1540,22 @@ void mp_window_bring_to_front_and_focus(mp_window window) mp_rect mp_window_content_rect_for_frame_rect(mp_rect frameRect, mp_window_style style) {@autoreleasepool{ u32 mask = mp_osx_get_window_style_mask(style); - mp_rect nativeFrame = mp_user_to_osx_screen_rect(frameRect); + mp_rect nativeFrame = mp_user_to_osx_screen_rect([NSScreen mainScreen], frameRect); NSRect frame = NSMakeRect(nativeFrame.x, nativeFrame.y, nativeFrame.w, nativeFrame.h); NSRect content = [NSWindow contentRectForFrameRect:frame styleMask:mask]; mp_rect result = {content.origin.x, content.origin.y, content.size.width, content.size.height}; - result = mp_osx_to_user_screen_rect(result); + result = mp_osx_to_user_screen_rect([NSScreen mainScreen], result); return(result); }} mp_rect mp_window_frame_rect_for_content_rect(mp_rect contentRect, mp_window_style style) {@autoreleasepool{ uint32 mask = mp_osx_get_window_style_mask(style); - mp_rect nativeContent = mp_user_to_osx_screen_rect(contentRect); + mp_rect nativeContent = mp_user_to_osx_screen_rect([NSScreen mainScreen], contentRect); NSRect content = NSMakeRect(nativeContent.x, nativeContent.y, nativeContent.w, nativeContent.h); NSRect frame = [NSWindow frameRectForContentRect:content styleMask:mask]; mp_rect result = {frame.origin.x, frame.origin.y, frame.size.width, frame.size.height}; - result = mp_osx_to_user_screen_rect(result); + result = mp_osx_to_user_screen_rect([NSScreen mainScreen], result); return(result); }} @@ -1584,22 +1564,15 @@ mp_rect mp_window_get_content_rect(mp_window window) mp_window_data* windowData = mp_window_ptr_from_handle(window); if(windowData) { - return(windowData->contentRect); - } - else - { - return((mp_rect){}); - } -} + NSRect frameRect = windowData->osx.nsWindow.frame; + NSRect contentsRect = [windowData->osx.nsWindow contentView].frame; + + mp_rect rect = { + contentsRect.origin.x, + frameRect.size.height - contentsRect.origin.y - contentsRect.size.height, + contentsRect.size.width, + contentsRect.size.height}; -mp_rect mp_window_get_absolute_content_rect(mp_window window) -{ - mp_window_data* windowData = mp_window_ptr_from_handle(window); - if(windowData) - { - mp_rect rect = windowData->contentRect; - rect.x += windowData->frameRect.x; - rect.y += windowData->frameRect.y; return(rect); } else @@ -1613,7 +1586,12 @@ mp_rect mp_window_get_frame_rect(mp_window window) mp_window_data* windowData = mp_window_ptr_from_handle(window); if(windowData) { - return(windowData->frameRect); + NSRect frameRect = windowData->osx.nsWindow.frame; + NSScreen* screen = windowData->osx.nsWindow.screen; + + mp_rect osxRect = (mp_rect){frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height}; + mp_rect rect = mp_osx_to_user_screen_rect(screen, osxRect); + return(rect); } else { @@ -1621,33 +1599,34 @@ mp_rect mp_window_get_frame_rect(mp_window window) } } -void mp_window_set_content_rect(mp_window window, mp_rect contentRect) -{@autoreleasepool{ - mp_window_data* windowData = mp_window_ptr_from_handle(window); - if(windowData) - { - u32 mask = mp_osx_get_window_style_mask(windowData->style); - - mp_rect nativeRect = mp_user_to_osx_screen_rect(contentRect); - NSRect content = NSMakeRect(nativeRect.x, nativeRect.y, nativeRect.w, nativeRect.h); - NSRect frame = [NSWindow frameRectForContentRect:content styleMask:mask]; - - [windowData->osx.nsWindow setFrame:frame display:YES]; - - mp_window_update_rect_cache(windowData); - } -}} void mp_window_set_frame_rect(mp_window window, mp_rect frameRect) {@autoreleasepool{ mp_window_data* windowData = mp_window_ptr_from_handle(window); if(windowData) { - mp_rect nativeRect = mp_user_to_osx_screen_rect(frameRect); + NSScreen* screen = windowData->osx.nsWindow.screen; + mp_rect nativeRect = mp_user_to_osx_screen_rect(screen, frameRect); NSRect frame = NSMakeRect(nativeRect.x, nativeRect.y, nativeRect.w, nativeRect.h); [windowData->osx.nsWindow setFrame:frame display:YES]; + } +}} - mp_window_update_rect_cache(windowData); - NSRect contentRect = [[windowData->osx.nsWindow contentView] frame]; +void mp_window_set_content_rect(mp_window window, mp_rect contentRect) +{@autoreleasepool{ + +//TODO: this is a bit inconsistent that this takes a screen-relative rect, while mp_window_get_content_rect +// returns a rect relative to the window's frame. + + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + u32 mask = mp_osx_get_window_style_mask(windowData->style); + + mp_rect nativeRect = mp_user_to_osx_screen_rect(windowData->osx.nsWindow.screen, contentRect); + NSRect content = NSMakeRect(nativeRect.x, nativeRect.y, nativeRect.w, nativeRect.h); + NSRect frame = [NSWindow frameRectForContentRect:content styleMask:mask]; + + [windowData->osx.nsWindow setFrame:frame display:YES]; } }} @@ -1664,12 +1643,15 @@ void mp_window_set_content_size(mp_window window, int width, int height) mp_window_data* windowData = mp_window_ptr_from_handle(window); if(windowData) { - mp_rect frame = windowData->frameRect; - mp_rect content = mp_window_content_rect_for_frame_rect(frame, windowData->style); + mp_rect content = mp_window_get_content_rect(window); + mp_rect frame = mp_window_get_frame_rect(window); + + content.x += frame.x; + content.y += frame.y; content.w = width; content.h = height; - frame = mp_window_frame_rect_for_content_rect(content, windowData->style); - mp_window_set_frame_rect(window, frame); + + mp_window_set_content_rect(window, frame); } } From 1fd9d17e8282f87ce07be10db1fdc4ae198775f7 Mon Sep 17 00:00:00 2001 From: Martin Fouilleul Date: Wed, 26 Jul 2023 15:54:01 +0200 Subject: [PATCH 6/8] [osx] settle on consistent API for getting/setting window rect --- examples/simpleWindow/build.sh | 4 +- examples/simpleWindow/main.c | 40 +++--- src/mp_app.h | 13 +- src/osx_app.m | 217 ++++++++++++++------------------- 4 files changed, 126 insertions(+), 148 deletions(-) diff --git a/examples/simpleWindow/build.sh b/examples/simpleWindow/build.sh index 4c97e8e..67d5f3e 100755 --- a/examples/simpleWindow/build.sh +++ b/examples/simpleWindow/build.sh @@ -9,4 +9,6 @@ INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app" LIBS="-L$BINDIR -lmilepost -framework Carbon -framework Cocoa -framework Metal -framework QuartzCore" FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG" -clang -g $FLAGS -Wl,-dead_strip $LIBS $INCLUDES -o test main.c +clang -g $FLAGS -Wl,-dead_strip $LIBS $INCLUDES -o $BINDIR/example_simple_window main.c + +install_name_tool -add_rpath "@executable_path" $BINDIR/example_simple_window diff --git a/examples/simpleWindow/main.c b/examples/simpleWindow/main.c index c659847..a325a01 100644 --- a/examples/simpleWindow/main.c +++ b/examples/simpleWindow/main.c @@ -37,36 +37,44 @@ int main() case MP_EVENT_WINDOW_RESIZE: { - printf("resized, rect = {%f, %f, %f, %f}\n", - event->frame.rect.x, - event->frame.rect.y, - event->frame.rect.w, - event->frame.rect.h); + printf("resized, frame = {%f, %f, %f, %f}, content = {%f, %f, %f, %f}\n", + event->move.frame.x, + event->move.frame.y, + event->move.frame.w, + event->move.frame.h, + event->move.content.x, + event->move.content.y, + event->move.content.w, + event->move.content.h); } break; case MP_EVENT_WINDOW_MOVE: { - printf("moved, rect = {%f, %f, %f, %f}\n", - event->frame.rect.x, - event->frame.rect.y, - event->frame.rect.w, - event->frame.rect.h); + printf("moved, frame = {%f, %f, %f, %f}, content = {%f, %f, %f, %f}\n", + event->move.frame.x, + event->move.frame.y, + event->move.frame.w, + event->move.frame.h, + event->move.content.x, + event->move.content.y, + event->move.content.w, + event->move.content.h); } break; case MP_EVENT_MOUSE_MOVE: { printf("mouse moved, pos = {%f, %f}, delta = {%f, %f}\n", - event->move.x, - event->move.y, - event->move.deltaX, - event->move.deltaY); + event->mouse.x, + event->mouse.y, + event->mouse.deltaX, + event->mouse.deltaY); } break; case MP_EVENT_MOUSE_WHEEL: { printf("mouse wheel, delta = {%f, %f}\n", - event->move.deltaX, - event->move.deltaY); + event->mouse.deltaX, + event->mouse.deltaY); } break; case MP_EVENT_MOUSE_ENTER: diff --git a/src/mp_app.h b/src/mp_app.h index e281b41..ffe79fb 100644 --- a/src/mp_app.h +++ b/src/mp_app.h @@ -234,7 +234,7 @@ typedef struct mp_mouse_event // mouse move/scroll typedef struct mp_move_event // window resize / move { mp_rect frame; - mp_rect contents; + mp_rect content; } mp_move_event; typedef struct mp_event @@ -315,10 +315,15 @@ MP_API void mp_window_unfocus(mp_window window); MP_API void mp_window_send_to_back(mp_window window); MP_API void mp_window_bring_to_front(mp_window window); -MP_API mp_rect mp_window_get_content_rect(mp_window window); MP_API mp_rect mp_window_get_frame_rect(mp_window window); -MP_API void mp_window_set_content_rect(mp_window window, mp_rect contentRect); -MP_API void mp_window_set_frame_rect(mp_window window, mp_rect frameRect); +MP_API void mp_window_set_frame_rect(mp_window window, mp_rect rect); +MP_API void mp_window_set_frame_position(mp_window window, vec2 position); +MP_API void mp_window_set_frame_size(mp_window window, vec2 size); + +MP_API mp_rect mp_window_get_content_rect(mp_window window); +MP_API void mp_window_set_content_rect(mp_window window, mp_rect rect); +MP_API void mp_window_set_content_position(mp_window window, vec2 position); +MP_API void mp_window_set_content_size(mp_window window, vec2 size); MP_API void mp_window_center(mp_window window); diff --git a/src/osx_app.m b/src/osx_app.m index 1f1b8fd..39405fd 100644 --- a/src/osx_app.m +++ b/src/osx_app.m @@ -26,24 +26,6 @@ // mp window struct and utility functions //-------------------------------------------------------------------- -static mp_rect mp_osx_to_user_screen_rect(NSScreen* screen, mp_rect rect) -{ - @autoreleasepool - { - rect.y = screen.frame.size.height - rect.y - rect.h; - } - return(rect); -} - -static mp_rect mp_user_to_osx_screen_rect(NSScreen* screen, mp_rect rect) -{ - @autoreleasepool - { - rect.y = screen.frame.size.height - rect.y - rect.h; - } - return(rect); -} - static u32 mp_osx_get_window_style_mask(mp_window_style style) { u32 mask = 0; @@ -644,15 +626,15 @@ void mp_install_keyboard_layout_listener() event.window = mp_window_handle_from_ptr(mpWindow); event.type = MP_EVENT_WINDOW_MOVE; - event.move.frame.x = contentRect.origin.x; + event.move.frame.x = frameRect.origin.x; event.move.frame.y = screen.frame.size.height - frameRect.origin.y - frameRect.size.height; - event.move.frame.w = contentRect.size.width; - event.move.frame.h = contentRect.size.height; + event.move.frame.w = frameRect.size.width; + event.move.frame.h = frameRect.size.height; - event.move.contents.x = contentRect.origin.x; - event.move.contents.y = frameRect.size.height - contentRect.origin.y - contentRect.size.height; - event.move.contents.w = contentRect.size.width; - event.move.contents.h = contentRect.size.height; + event.move.content.x = frameRect.origin.x + contentRect.origin.x; + event.move.content.y = screen.frame.size.height - frameRect.origin.y - contentRect.origin.y - contentRect.size.height; + event.move.content.w = contentRect.size.width; + event.move.content.h = contentRect.size.height; mp_queue_event(&event); } @@ -667,15 +649,15 @@ void mp_install_keyboard_layout_listener() event.window = mp_window_handle_from_ptr(mpWindow); event.type = MP_EVENT_WINDOW_RESIZE; - event.move.frame.x = contentRect.origin.x; + event.move.frame.x = frameRect.origin.x; event.move.frame.y = screen.frame.size.height - frameRect.origin.y - frameRect.size.height; - event.move.frame.w = contentRect.size.width; - event.move.frame.h = contentRect.size.height; + event.move.frame.w = frameRect.size.width; + event.move.frame.h = frameRect.size.height; - event.move.contents.x = contentRect.origin.x; - event.move.contents.y = frameRect.size.height - contentRect.origin.y - contentRect.size.height; - event.move.contents.w = contentRect.size.width; - event.move.contents.h = contentRect.size.height; + event.move.content.x = frameRect.origin.x + contentRect.origin.x; + event.move.content.y = screen.frame.size.height - frameRect.origin.y - contentRect.origin.y - contentRect.size.height; + event.move.content.w = contentRect.size.width; + event.move.content.h = contentRect.size.height; if(__mpApp.liveResizeCallback) { @@ -1323,15 +1305,6 @@ str8 mp_clipboard_get_data_for_tag(mem_arena* arena, const char* tag) // Window public API //--------------------------------------------------------------- -/* -//TODO(martin): review include scheme -extern "C" { - mp_graphics_surface mp_metal_surface_create_for_window_ptr(mp_window_data* window); - mp_graphics_surface mp_graphics_surface_null_handle(); - mp_graphics_surface mp_graphics_surface_handle_from_ptr(mp_graphics_surface_data* surface); -} -*/ - mp_window mp_window_create(mp_rect contentRect, const char* title, mp_window_style style) {@autoreleasepool{ mp_window_data* window = mp_window_alloc(); @@ -1536,123 +1509,113 @@ void mp_window_bring_to_front_and_focus(mp_window window) mp_window_focus(window); } - -mp_rect mp_window_content_rect_for_frame_rect(mp_rect frameRect, mp_window_style style) -{@autoreleasepool{ - u32 mask = mp_osx_get_window_style_mask(style); - mp_rect nativeFrame = mp_user_to_osx_screen_rect([NSScreen mainScreen], frameRect); - NSRect frame = NSMakeRect(nativeFrame.x, nativeFrame.y, nativeFrame.w, nativeFrame.h); - NSRect content = [NSWindow contentRectForFrameRect:frame styleMask:mask]; - mp_rect result = {content.origin.x, content.origin.y, content.size.width, content.size.height}; - result = mp_osx_to_user_screen_rect([NSScreen mainScreen], result); - return(result); -}} - -mp_rect mp_window_frame_rect_for_content_rect(mp_rect contentRect, mp_window_style style) -{@autoreleasepool{ - uint32 mask = mp_osx_get_window_style_mask(style); - mp_rect nativeContent = mp_user_to_osx_screen_rect([NSScreen mainScreen], contentRect); - NSRect content = NSMakeRect(nativeContent.x, nativeContent.y, nativeContent.w, nativeContent.h); - NSRect frame = [NSWindow frameRectForContentRect:content styleMask:mask]; - mp_rect result = {frame.origin.x, frame.origin.y, frame.size.width, frame.size.height}; - result = mp_osx_to_user_screen_rect([NSScreen mainScreen], result); - return(result); -}} - -mp_rect mp_window_get_content_rect(mp_window window) -{ - mp_window_data* windowData = mp_window_ptr_from_handle(window); - if(windowData) - { - NSRect frameRect = windowData->osx.nsWindow.frame; - NSRect contentsRect = [windowData->osx.nsWindow contentView].frame; - - mp_rect rect = { - contentsRect.origin.x, - frameRect.size.height - contentsRect.origin.y - contentsRect.size.height, - contentsRect.size.width, - contentsRect.size.height}; - - return(rect); - } - else - { - return((mp_rect){}); - } -} - mp_rect mp_window_get_frame_rect(mp_window window) { + mp_rect rect = {0}; mp_window_data* windowData = mp_window_ptr_from_handle(window); if(windowData) { NSRect frameRect = windowData->osx.nsWindow.frame; NSScreen* screen = windowData->osx.nsWindow.screen; - mp_rect osxRect = (mp_rect){frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height}; - mp_rect rect = mp_osx_to_user_screen_rect(screen, osxRect); - return(rect); - } - else - { - return((mp_rect){}); + rect = (mp_rect){ + frameRect.origin.x, + screen.frame.size.height - frameRect.origin.y - frameRect.size.height, + frameRect.size.width, + frameRect.size.height + }; } + return(rect); } -void mp_window_set_frame_rect(mp_window window, mp_rect frameRect) +void mp_window_set_frame_rect(mp_window window, mp_rect rect) {@autoreleasepool{ mp_window_data* windowData = mp_window_ptr_from_handle(window); if(windowData) { NSScreen* screen = windowData->osx.nsWindow.screen; - mp_rect nativeRect = mp_user_to_osx_screen_rect(screen, frameRect); - NSRect frame = NSMakeRect(nativeRect.x, nativeRect.y, nativeRect.w, nativeRect.h); - [windowData->osx.nsWindow setFrame:frame display:YES]; + NSRect frameRect = { + rect.x, + screen.frame.size.height - rect.y - rect.h, + rect.w, + rect.h + }; + [windowData->osx.nsWindow setFrame:frameRect display:YES]; } }} -void mp_window_set_content_rect(mp_window window, mp_rect contentRect) -{@autoreleasepool{ - -//TODO: this is a bit inconsistent that this takes a screen-relative rect, while mp_window_get_content_rect -// returns a rect relative to the window's frame. - - mp_window_data* windowData = mp_window_ptr_from_handle(window); - if(windowData) - { - u32 mask = mp_osx_get_window_style_mask(windowData->style); - - mp_rect nativeRect = mp_user_to_osx_screen_rect(windowData->osx.nsWindow.screen, contentRect); - NSRect content = NSMakeRect(nativeRect.x, nativeRect.y, nativeRect.w, nativeRect.h); - NSRect frame = [NSWindow frameRectForContentRect:content styleMask:mask]; - - [windowData->osx.nsWindow setFrame:frame display:YES]; - } -}} - -void mp_window_set_frame_size(mp_window window, int width, int height) +void mp_window_set_frame_position(mp_window window, vec2 position) { mp_rect frame = mp_window_get_frame_rect(window); - frame.w = width; - frame.h = height; + frame.x = position.x; + frame.y = position.y; mp_window_set_frame_rect(window, frame); } -void mp_window_set_content_size(mp_window window, int width, int height) +void mp_window_set_frame_size(mp_window window, vec2 size) { + mp_rect frame = mp_window_get_frame_rect(window); + frame.w = size.x; + frame.h = size.y; + mp_window_set_frame_rect(window, frame); +} + +mp_rect mp_window_get_content_rect(mp_window window) +{@autoreleasepool{ mp_window_data* windowData = mp_window_ptr_from_handle(window); if(windowData) { - mp_rect content = mp_window_get_content_rect(window); - mp_rect frame = mp_window_get_frame_rect(window); + NSScreen* screen = [windowData->osx.nsWindow screen]; + NSView* view = [windowData->osx.nsWindow contentView]; + NSRect contentRect = [windowData->osx.nsWindow convertRectToScreen: view.frame]; - content.x += frame.x; - content.y += frame.y; - content.w = width; - content.h = height; + mp_rect rect = { + contentRect.origin.x, + screen.frame.size.height - contentRect.origin.y - contentRect.size.height, + contentRect.size.width, + contentRect.size.height}; - mp_window_set_content_rect(window, frame); + return(rect); } + else + { + return((mp_rect){}); + } +}} + +void mp_window_set_content_rect(mp_window window, mp_rect rect) +{@autoreleasepool{ + + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + NSScreen* screen = [windowData->osx.nsWindow screen]; + NSRect contentRect = { + rect.x, + screen.frame.size.height - rect.y - rect.h, + rect.w, + rect.h + }; + + NSRect frameRect = [windowData->osx.nsWindow frameRectForContentRect: contentRect]; + [windowData->osx.nsWindow setFrame:frameRect display:YES]; + } +}} + +void mp_window_set_content_position(mp_window window, vec2 position) +{ + mp_rect rect = mp_window_get_content_rect(window); + rect.x = position.x; + rect.y = position.y; + mp_window_set_content_rect(window, rect); +} + +void mp_window_set_content_size(mp_window window, vec2 size) +{ + mp_rect rect = mp_window_get_content_rect(window); + rect.w = size.x; + rect.h = size.y; + mp_window_set_content_rect(window, rect); } //-------------------------------------------------------------------- From 2c0d3268e71f023b8b233702ec3a7b433c83f55b Mon Sep 17 00:00:00 2001 From: martinfouilleul Date: Wed, 26 Jul 2023 16:50:45 +0200 Subject: [PATCH 7/8] [win32] update window rect API --- examples/simpleWindow/build.bat | 2 +- src/mp_app.c | 36 +++++++++ src/osx_app.m | 32 -------- src/win32_app.c | 129 +++++++++++++++++++++++++++----- 4 files changed, 149 insertions(+), 50 deletions(-) diff --git a/examples/simpleWindow/build.bat b/examples/simpleWindow/build.bat index 971b6e5..2f24fa7 100644 --- a/examples/simpleWindow/build.bat +++ b/examples/simpleWindow/build.bat @@ -1,2 +1,2 @@ set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext -cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib user32.lib opengl32.lib gdi32.lib /out:../../bin/example_window.exe +cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib user32.lib /out:../../bin/example_simple_window.exe diff --git a/src/mp_app.c b/src/mp_app.c index cb053c3..7cc9f68 100644 --- a/src/mp_app.c +++ b/src/mp_app.c @@ -179,3 +179,39 @@ mp_event* mp_next_event(mem_arena* arena) } return(event); } + +//--------------------------------------------------------------- +// window rects helpers +//--------------------------------------------------------------- + +void mp_window_set_content_position(mp_window window, vec2 position) +{ + mp_rect rect = mp_window_get_content_rect(window); + rect.x = position.x; + rect.y = position.y; + mp_window_set_content_rect(window, rect); +} + +void mp_window_set_content_size(mp_window window, vec2 size) +{ + mp_rect rect = mp_window_get_content_rect(window); + rect.w = size.x; + rect.h = size.y; + mp_window_set_content_rect(window, rect); +} + +void mp_window_set_frame_position(mp_window window, vec2 position) +{ + mp_rect frame = mp_window_get_frame_rect(window); + frame.x = position.x; + frame.y = position.y; + mp_window_set_frame_rect(window, frame); +} + +void mp_window_set_frame_size(mp_window window, vec2 size) +{ + mp_rect frame = mp_window_get_frame_rect(window); + frame.w = size.x; + frame.h = size.y; + mp_window_set_frame_rect(window, frame); +} diff --git a/src/osx_app.m b/src/osx_app.m index 39405fd..093f0d6 100644 --- a/src/osx_app.m +++ b/src/osx_app.m @@ -1544,22 +1544,6 @@ void mp_window_set_frame_rect(mp_window window, mp_rect rect) } }} -void mp_window_set_frame_position(mp_window window, vec2 position) -{ - mp_rect frame = mp_window_get_frame_rect(window); - frame.x = position.x; - frame.y = position.y; - mp_window_set_frame_rect(window, frame); -} - -void mp_window_set_frame_size(mp_window window, vec2 size) -{ - mp_rect frame = mp_window_get_frame_rect(window); - frame.w = size.x; - frame.h = size.y; - mp_window_set_frame_rect(window, frame); -} - mp_rect mp_window_get_content_rect(mp_window window) {@autoreleasepool{ mp_window_data* windowData = mp_window_ptr_from_handle(window); @@ -1602,22 +1586,6 @@ void mp_window_set_content_rect(mp_window window, mp_rect rect) } }} -void mp_window_set_content_position(mp_window window, vec2 position) -{ - mp_rect rect = mp_window_get_content_rect(window); - rect.x = position.x; - rect.y = position.y; - mp_window_set_content_rect(window, rect); -} - -void mp_window_set_content_size(mp_window window, vec2 size) -{ - mp_rect rect = mp_window_get_content_rect(window); - rect.w = size.x; - rect.h = size.y; - mp_window_set_content_rect(window, rect); -} - //-------------------------------------------------------------------- // platform surface //-------------------------------------------------------------------- diff --git a/src/win32_app.c b/src/win32_app.c index 70fb48b..34b83dc 100644 --- a/src/win32_app.c +++ b/src/win32_app.c @@ -319,20 +319,12 @@ LRESULT WinProc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam) { RECT* rect = (RECT*)lParam; - u32 dpi = GetDpiForWindow(mpWindow->win32.hWnd); - f32 scaling = (f32)dpi/96.; - mp_event event = {0}; event.type = message == WM_SIZING ? MP_EVENT_WINDOW_RESIZE : MP_EVENT_WINDOW_MOVE; event.window = mp_window_handle_from_ptr(mpWindow); - event.move.frame = (mp_rect){ - rect->left / scaling, - rect->bottom / scaling, - (rect->bottom - rect->top)/scaling, - (rect->right - rect->left)/scaling }; - - event.move.contents = mp_window_get_content_rect(event.window); + event.move.frame = mp_window_get_frame_rect(event.window); + event.move.content = mp_window_get_content_rect(event.window); mp_queue_event(&event); @@ -588,12 +580,24 @@ mp_window mp_window_create(mp_rect rect, const char* title, mp_window_style styl HMONITOR monitor = MonitorFromPoint((POINT){rect.x, rect.y}, MONITOR_DEFAULTTOPRIMARY); GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); - f32 dpiScalingX = (f32)dpiX/96.; - f32 dpiScalingY = (f32)dpiY/96.; + f32 scaleX = (f32)dpiX/96.; + f32 scaleY = (f32)dpiY/96.; + + RECT frame = { + rect.x * scaleX, + rect.y * scaleY, + (rect.x + rect.w)*scaleX, + (rect.y + rect.h)*scaleY + }; + + DWORD winStyle = WS_OVERLAPPEDWINDOW; + AdjustWindowRect(&frame, winStyle, FALSE); HWND windowHandle = CreateWindow("ApplicationWindowClass", "Test Window", - WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, - rect.w * dpiScalingX, rect.h * dpiScalingY, + winStyle, + frame.left, frame.top, + frame.right-frame.left, + frame.bottom-frame.top, 0, 0, windowClass.hInstance, 0); if(!windowHandle) @@ -797,23 +801,114 @@ void mp_window_bring_to_front(mp_window window) } } +mp_rect mp_window_get_frame_rect(mp_window window) +{ + mp_rect rect = {0}; + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + //NOTE: GetWindowRect() includes the drop shadow, which we don't want, so we call + // DwmGetWindowAttribute() instead. + // Note that contrary to what the GetWindowRect() docs suggests when mentionning + // this, DwmGetWindowAttributes() _does_ seem to adjust for DPI. + u32 dpi = GetDpiForWindow(windowData->win32.hWnd); + f32 scale = (float)dpi/96.; + + RECT frame; + HRESULT res = DwmGetWindowAttribute(windowData->win32.hWnd, + DWMWA_EXTENDED_FRAME_BOUNDS, + &frame, + sizeof(RECT)); + if(res == S_OK) + { + rect = (mp_rect){ + frame.left / scale, + frame.top / scale, + (frame.right - frame.left)/scale, + (frame.bottom - frame.top)/scale}; + } + } + return(rect); +} + +void mp_window_set_frame_rect(mp_window window, mp_rect rect) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + u32 dpi = GetDpiForWindow(windowData->win32.hWnd); + f32 scale = (float)dpi/96.; + + RECT frame = { + rect.x * scale, + rect.y * scale, + (rect.x + rect.w)*scale, + (rect.y + rect.h)*scale + }; + + SetWindowPos(windowData->win32.hWnd, + HWND_TOP, + frame.left, + frame.top, + frame.right - frame.left, + frame.bottom - frame.top, + SWP_NOZORDER|SWP_NOACTIVATE); + } +} + mp_rect mp_window_get_content_rect(mp_window window) { mp_rect rect = {0}; mp_window_data* windowData = mp_window_ptr_from_handle(window); if(windowData) { - RECT winRect; - if(GetClientRect(windowData->win32.hWnd, &winRect)) + RECT client; + if(GetClientRect(windowData->win32.hWnd, &client)) { u32 dpi = GetDpiForWindow(windowData->win32.hWnd); f32 scale = (float)dpi/96.; - rect = (mp_rect){0, 0, (winRect.right - winRect.left)/scale, (winRect.bottom - winRect.top)/scale}; + + POINT origin = {0, 0}; + ClientToScreen(windowData->win32.hWnd, &origin); + + rect = (mp_rect){ + origin.x/scale, + origin.y/scale, + (client.right - client.left)/scale, + (client.bottom - client.top)/scale}; } } return(rect); } +void mp_window_set_content_rect(mp_window window, mp_rect rect) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + u32 dpi = GetDpiForWindow(windowData->win32.hWnd); + f32 scale = (float)dpi/96.; + + RECT frame = { + rect.x * scale, + rect.y * scale, + (rect.x + rect.w)*scale, + (rect.y + rect.h)*scale}; + + DWORD style = GetWindowLong(windowData->win32.hWnd, GWL_STYLE); + BOOL menu = (GetMenu(windowData->win32.hWnd) != NULL); + AdjustWindowRect(&frame, style, menu); + + SetWindowPos(windowData->win32.hWnd, + HWND_TOP, + frame.left, + frame.top, + frame.right - frame.left, + frame.bottom - frame.top, + SWP_NOZORDER|SWP_NOACTIVATE); + } +} + //TODO: set content rect, center void mp_window_center(mp_window window) { From 0785b6b637ca5290c8a6f4218517515e9cb46935 Mon Sep 17 00:00:00 2001 From: martinfouilleul Date: Wed, 26 Jul 2023 17:35:58 +0200 Subject: [PATCH 8/8] [win32] - Take drop shadown into account when calling SetWindowPos (milepost window frame _excludes_ the drop shadow) - Fix mp_window_center() --- examples/simpleWindow/main.c | 2 ++ src/win32_app.c | 65 ++++++++++++++++++++++++++---------- 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/examples/simpleWindow/main.c b/examples/simpleWindow/main.c index a325a01..eddccde 100644 --- a/examples/simpleWindow/main.c +++ b/examples/simpleWindow/main.c @@ -22,6 +22,8 @@ int main() mp_window_bring_to_front(window); mp_window_focus(window); + mp_window_center(window); + while(!mp_should_quit()) { mp_pump_events(0); diff --git a/src/win32_app.c b/src/win32_app.c index 34b83dc..89b9f97 100644 --- a/src/win32_app.c +++ b/src/win32_app.c @@ -831,6 +831,27 @@ mp_rect mp_window_get_frame_rect(mp_window window) return(rect); } +mp_rect win32_get_drop_shadow_offsets(HWND hWnd) +{ + RECT frameIncludingShadow; + RECT frameExcludingShadow; + + GetWindowRect(hWnd, &frameIncludingShadow); + DwmGetWindowAttribute(hWnd, + DWMWA_EXTENDED_FRAME_BOUNDS, + &frameExcludingShadow, + sizeof(RECT)); + + mp_rect extents = { + .x = frameIncludingShadow.left - frameExcludingShadow.left, + .y = frameIncludingShadow.top - frameExcludingShadow.top, + .w = frameIncludingShadow.right - frameExcludingShadow.right, + .h = frameIncludingShadow.bottom- frameExcludingShadow.bottom + }; + + return(extents); +} + void mp_window_set_frame_rect(mp_window window, mp_rect rect) { mp_window_data* windowData = mp_window_ptr_from_handle(window); @@ -839,11 +860,14 @@ void mp_window_set_frame_rect(mp_window window, mp_rect rect) u32 dpi = GetDpiForWindow(windowData->win32.hWnd); f32 scale = (float)dpi/96.; + //NOTE compute the size of the drop shadow to add it in setwindowpos + mp_rect shadowOffsets = win32_get_drop_shadow_offsets(windowData->win32.hWnd); + RECT frame = { - rect.x * scale, - rect.y * scale, - (rect.x + rect.w)*scale, - (rect.y + rect.h)*scale + rect.x * scale + shadowOffsets.x, + rect.y * scale + shadowOffsets.y, + (rect.x + rect.w)*scale + shadowOffsets.w, + (rect.y + rect.h)*scale + shadowOffsets.h }; SetWindowPos(windowData->win32.hWnd, @@ -909,28 +933,35 @@ void mp_window_set_content_rect(mp_window window, mp_rect rect) } } -//TODO: set content rect, center void mp_window_center(mp_window window) { mp_window_data* windowData = mp_window_ptr_from_handle(window); if(windowData) { - RECT winRect; - GetWindowRect(windowData->win32.hWnd, &winRect); - HMONITOR monitor = MonitorFromPoint((POINT){winRect.left, winRect.top}, MONITOR_DEFAULTTOPRIMARY); - MONITORINFO monitorInfo = {.cbSize = sizeof(MONITORINFO)}; - GetMonitorInfoW(monitor, &monitorInfo); + mp_rect frame = mp_window_get_frame_rect(window); - int monW = monitorInfo.rcWork.right - monitorInfo.rcWork.left; - int monH = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top; - int winW = winRect.right - winRect.left; - int winH = winRect.bottom - winRect.top; + HMONITOR monitor = MonitorFromWindow(windowData->win32.hWnd, MONITOR_DEFAULTTOPRIMARY); + if(monitor) + { + MONITORINFO monitorInfo = {.cbSize = sizeof(MONITORINFO)}; + GetMonitorInfoW(monitor, &monitorInfo); - int winX = 0.5*(monW-winW); - int winY = 0.5*(monW-winW); + int dpiX, dpiY; + GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); + f32 scaleX = dpiX/96.; + f32 scaleY = dpiY/96.; - SetWindowPos(windowData->win32.hWnd, NULL, winX, winY, winW, winH, SWP_NOZORDER|SWP_NOACTIVATE); + f32 monX = monitorInfo.rcWork.left/scaleX; + f32 monY = monitorInfo.rcWork.top/scaleY; + f32 monW = (monitorInfo.rcWork.right - monitorInfo.rcWork.left)/scaleX; + f32 monH = (monitorInfo.rcWork.bottom - monitorInfo.rcWork.top)/scaleY; + + frame.x = monX + 0.5*(monW - frame.w); + frame.y = monY + 0.5*(monH - frame.h); + + mp_window_set_frame_rect(window, frame); + } } }