diff --git a/CMakeLists.txt b/CMakeLists.txt index 948a83c8..a6f823d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -309,6 +309,8 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Retro") set_target_properties(Mw PROPERTIES LINK_FLAGS "-Wl,-gc-sections") endif() + list(APPEND LIBRARIES InterfaceLib WindowsLib ThreadsLib) + target_compile_definitions( Mw PRIVATE @@ -354,7 +356,7 @@ target_link_libraries( ) if(MW_BUILD_OPENGL) - target_compile_definitions( + target_compile_definitions( Mw PRIVATE MW_OPENGL diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index cbc67f9e..2ba3ff0b 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -83,11 +83,15 @@ typedef struct _MwLLDBusContext { DBusMessageIter dbus_args, dbus_variant, dbus_inner_variant; } MwLLDBusContext; +typedef void (*MwLLDBusPortalPollListener)(MwLL handle, MwU32 new_value); + /* setup the dbus func table. Returns false and prints a warning if dbus couldn't be found. */ MWDECL MwBool MwLLDBusFuncSetup(MwLLDBusFuncTable* tbl); MWDECL MwBool MwLLDBusNewContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx); MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal, const char* namespace, const char* key, void* out); +MWDECL MwBool MwLLDBusPortalWatch(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal); +MWDECL MwBool MwLLDBusPortalPoll(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, MwLL handle, const char* portal, const char* namespace, const char* key, MwLLDBusPortalPollListener); MWDECL void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx); #endif diff --git a/include/Mw/LowLevel/ClassicMacOS.h b/include/Mw/LowLevel/ClassicMacOS.h index 4b32f6cd..958b5e8b 100644 --- a/include/Mw/LowLevel/ClassicMacOS.h +++ b/include/Mw/LowLevel/ClassicMacOS.h @@ -13,9 +13,12 @@ struct _MwLLClassicMacOS { struct _MwLLCommon common; - WindowRef window; - EventRecord event; - Rect winRect; + MwLL parent; + + WindowRef window; + ControlHandle control; + EventRecord event; + Rect winRect; }; struct _MwLLClassicMacOSColor { diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 7debc887..7f9e7625 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -41,6 +41,7 @@ typedef struct wayland_call_table { MwBool has_dbus; #endif + int (*wl_display_dispatch)(struct wl_display* display); int (*wl_display_dispatch_pending)(struct wl_display* display); void (*wl_display_disconnect)(struct wl_display* display); void (*wl_display_cancel_read)(struct wl_display* display); @@ -58,6 +59,7 @@ typedef struct wayland_call_table { uint32_t flags, ...); struct wl_display* (*wl_display_connect)(const char* name); uint32_t (*wl_proxy_get_version)(struct wl_proxy* proxy); + struct wl_display* (*wl_display_connect_to_fd)(int fd); struct xkb_context* (*xkb_context_new)(enum xkb_context_flags flags); void (*xkb_context_unref)(struct xkb_context* context); @@ -156,6 +158,7 @@ MwInline int wayland_load_funcs() { return 1; \ }; + WAYLAND_FUNC(wl_display_dispatch) WAYLAND_FUNC(wl_display_dispatch_pending) WAYLAND_FUNC(wl_display_disconnect) WAYLAND_FUNC(wl_display_cancel_read) @@ -170,6 +173,7 @@ MwInline int wayland_load_funcs() { WAYLAND_FUNC(wl_proxy_marshal_flags) WAYLAND_FUNC(wl_display_connect) WAYLAND_FUNC(wl_proxy_get_version) + WAYLAND_FUNC(wl_display_connect_to_fd) #undef WAYLAND_FUNC @@ -235,6 +239,7 @@ MwInline int wayland_load_funcs() { return 0; } +#define wl_display_dispatch wl_call_tbl.wl_display_dispatch #define wl_display_dispatch_pending wl_call_tbl.wl_display_dispatch_pending #define wl_display_disconnect wl_call_tbl.wl_display_disconnect #define wl_display_cancel_read wl_call_tbl.wl_display_cancel_read @@ -249,6 +254,7 @@ MwInline int wayland_load_funcs() { #define wl_proxy_marshal_flags wl_call_tbl.wl_proxy_marshal_flags #define wl_display_connect wl_call_tbl.wl_display_connect #define wl_proxy_get_version wl_call_tbl.wl_proxy_get_version +#define wl_display_connect_to_fd wl_call_tbl.wl_display_connect_to_fd #define xkb_state_unref wl_call_tbl.xkb_state_unref #define xkb_context_new wl_call_tbl.xkb_context_new @@ -373,11 +379,11 @@ enum _MwLLWaylandType { }; typedef struct wl_clipboard_device_context { - union { + struct { struct wl_data_device* wl; struct zwp_primary_selection_device_v1* zwp; } device; - union { + struct { struct wl_data_offer* wl; struct zwp_primary_selection_offer_v1* zwp; } offer; @@ -409,13 +415,13 @@ struct _MwLLWayland { /* Map of Wayland interfaces to their relevant setup functions. */ struct { - const char* key; + char key[255]; wayland_protocol_callback_table_t* value; }* wl_protocol_setup_map; /* Map of Wayland interfaces to any information we keep about them once we've registered them. */ struct { - const char* key; + char key[255]; wayland_protocol_t* value; }* wl_protocol_map; diff --git a/include/Mw/Widget/Vulkan.h b/include/Mw/Widget/Vulkan.h index 0565022e..0b7db3ac 100644 --- a/include/Mw/Widget/Vulkan.h +++ b/include/Mw/Widget/Vulkan.h @@ -11,7 +11,7 @@ #ifndef __MW_WIDGET_VULKAN_H__ #define __MW_WIDGET_VULKAN_H__ -#if !defined(_WIN32) && !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) +#if defined(MW_VULKAN) && !defined(_WIN32) && !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) #error Vulkan is unsupported on the requested platform. #endif diff --git a/src/abstract/dynamic.c b/src/abstract/dynamic.c index d9558af6..ae31e82b 100644 --- a/src/abstract/dynamic.c +++ b/src/abstract/dynamic.c @@ -14,33 +14,39 @@ void MwDynamicClose(void* handle) { } #elif defined(CLASSIC_MAC_OS) void* MwDynamicOpen(const char* path) { - CFragConnectionID connID; - Ptr* addr; - unsigned char err[255]; + // CFragConnectionID connID; + // Ptr* addr; + // unsigned char err[255]; - if(GetSharedLibrary((ConstStr63Param)path, kPowerPCCFragArch, kPrivateCFragCopy, - &connID, addr, err)) { - printf("Error getting %s: %s\n", path, err); - return NULL; - }; - return connID; + // if(GetSharedLibrary((ConstStr63Param)path, kPowerPCCFragArch, kPrivateCFragCopy, + // &connID, addr, err)) { + // printf("Error getting %s: %s\n", path, err); + // return NULL; + // }; + // return connID; + printf("MwDynamicOpen not implemented yet.\n"); + getchar(); + return NULL; } void* MwDynamicSymbol(void* handle, const char* symbol) { - CFragConnectionID connID = (CFragConnectionID)handle; - Ptr* symAddr; - CFragSymbolClass* symClass; - OSErr err; - if((err = FindSymbol(connID, (ConstStr63Param)symbol, symAddr, symClass))) { - printf("Error getting %s: %d\n", symbol, err); - return NULL; - }; - return symAddr; + // CFragConnectionID connID = (CFragConnectionID)handle; + // Ptr* symAddr; + // CFragSymbolClass* symClass; + // OSErr err; + // if((err = FindSymbol(connID, (ConstStr63Param)symbol, symAddr, symClass))) { + // printf("Error getting %s: %d\n", symbol, err); + // return NULL; + // }; + // return symAddr; + printf("MwDynamicSymbol not implemented yet.\n"); + getchar(); + return NULL; } void MwDynamicClose(void* handle) { - CFragConnectionID connID = (CFragConnectionID)handle; - CloseConnection(&connID); + // CFragConnectionID connID = (CFragConnectionID)handle; + // CloseConnection(&connID); } #elif defined(__unix__) || defined(__APPLE__) void* MwDynamicOpen(const char* path) { diff --git a/src/backend/classicmacos.c b/src/backend/classicmacos.c index 4fa7ab37..d7db4331 100644 --- a/src/backend/classicmacos.c +++ b/src/backend/classicmacos.c @@ -1,12 +1,24 @@ #include +#include +#include #include "../../external/stb_ds.h" static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; - + r = malloc(sizeof(*r)); + memset(r, 0, sizeof(*r)); MwLLCreateCommon(r); + r->cmacos.parent = parent; + + if(x == MwDEFAULT) { + x = (qd.screenBits.bounds.right / 2) - (width / 2); + } + if(y == MwDEFAULT) { + y = (qd.screenBits.bounds.bottom / 2) - (height / 2); + } + /* todo: how do we set parent windows? If we can't, what is our equivalant to MacOS's NSViews, Wayland's subsurfaces, etc.? */ SetRect(&r->cmacos.winRect, x, y, width, height); r->cmacos.window = newcwindow(nil, &r->cmacos.winRect, "", true, @@ -23,24 +35,26 @@ static void MwLLDestroyImpl(MwLL handle) { } static void MwLLBeginDrawImpl(MwLL handle) { - (void)handle; } static void MwLLEndDrawImpl(MwLL handle) { - (void)handle; } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { int i; - PolyHandle p = OpenPoly(); + PolyHandle p; RGBColor col; - col.red = color->common.red; - col.green = color->common.green; - col.blue = color->common.blue; + SetPort(handle->cmacos.window); + BeginUpdate(handle->cmacos.window); + + p = OpenPoly(); + col.red = color->common.red * 0x101; + col.green = color->common.green * 0x101; + col.blue = color->common.blue * 0x101; - RGBBackColor(&col); RGBForeColor(&col); + PenMode(patCopy); for(i = 0; i < points_count; i++) { if(i == 0) { @@ -51,20 +65,24 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL } ClosePoly(); - PaintPoly(p); + FillCPoly(p, &qd.ltGray); KillPoly(p); + + EndUpdate(handle->cmacos.window); } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { RGBColor col; + SetPort(handle->cmacos.window); col.red = color->common.red; col.green = color->common.green; col.blue = color->common.blue; - RGBBackColor(&col); RGBForeColor(&col); + PenMode(patCopy); + MoveTo(points[0].x, points[0].y); LineTo(points[1].x, points[1].y); } @@ -103,10 +121,133 @@ static void MwLLFreeColorImpl(MwLLColor color) { } static int MwLLPendingImpl(MwLL handle) { - return GetNextEvent(everyEvent, &handle->cmacos.event); + YieldToAnyThread(); + return EventAvail(everyEvent, &handle->cmacos.event); } static void MwLLNextEventImpl(MwLL handle) { + EventRecord event; + GetNextEvent(everyEvent, &event); + + switch(event.what) { + case updateEvt: { + } + // MwLLDispatch(handle, draw, NULL); + break; + case osEvt: + break; + case mouseUp: { + // MwLLMouse m; + // m.button = MwLLMouseLeft; + // if(___curWindow->mouseButtonCallback != NULL) { + // int mods = MacModifiersToGLFWModifiers(event.modifiers); + + // if(___curWindow->keyStateMap[MK_LCTRL] == 1) { + // ___curWindow->mouseButtonCallback( + // ___curWindow, GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE, mods); + // } else { + // ___curWindow->mouseButtonCallback( + // ___curWindow, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE, mods); + // } + // } + } + case mouseDown: { + // // start with callback stuff + // if(___curWindow->mouseButtonCallback != NULL) { + // int mods = MacModifiersToGLFWModifiers(event.modifiers); + + // if(___curWindow->keyStateMap[MK_LCTRL] == 1) { + // ___curWindow->mouseButtonCallback( + // ___curWindow, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods); + // } else { + // ___curWindow->mouseButtonCallback( + // ___curWindow, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods); + // } + // } + + // then do system stuff + switch(FindWindow(event.where, &handle->cmacos.window)) { + case inDrag: + DragWindow(handle->cmacos.window, event.where, &qd.screenBits.bounds); + // if(___curWindow->windowPosCallback != NULL) { + // ___curWindow->windowPosCallback(___curWindow, event.where.h, + // event.where.v); + // } + break; + case inGrow: { + long growResult = + GrowWindow(handle->cmacos.window, event.where, &qd.screenBits.bounds); + + int width = growResult & 0xFFFF; + int height = growResult >> 16; + + SizeWindow(handle->cmacos.window, growResult & 0xFFFF, growResult >> 16, true); + + Rect rect; + GetWindowBounds(handle->cmacos.window, kWindowStructureRgn, &rect); + rect.right = width; + rect.bottom = height; + SetWindowBounds(handle->cmacos.window, kWindowStructureRgn, &rect); + + // ___curWindow->width = width; + // ___curWindow->height = height; + + // if(___curWindow->windowSizeCallback != NULL) { + // ___curWindow->windowSizeCallback(___curWindow, width, height); + // } + // if(___curWindow->windowSetFramebufferSizeCallback != NULL) { + // ___curWindow->windowSetFramebufferSizeCallback(___curWindow, + // width, height); + // } + } break; + + case inGoAway: { + if(TrackGoAway(handle->cmacos.window, event.where)) { + MwLLDispatch(handle, close, NULL); + // if(___curWindow->windowCloseCallback != NULL) { + // ___curWindow->windowCloseCallback(___curWindow); + // } + // ___curWindow->shouldClose = true; + } + } break; + } + } + case autoKey: + case keyDown: + case keyUp: { + // // key char stuff + // unsigned char ch = (event.message & charCodeMask); + // if(*___curWindow->charCallback != NULL) { + // ___curWindow->charCallback(___curWindow, ch); + // } + + // // key state map + // unsigned char key = (event.message & keyCodeMask) >> 8; + // ___curWindow->keyStateMap[key] = 0; + // if(event.what == keyDown || event.what == autoKey) { + // ___curWindow->keyStateMap[key] &= 1; + // } + + // if(*___curWindow->keyCallback != NULL) { + // int key = MacKeyToGLFWKey(event.message); + // int scancode = (event.message & adbAddrMask) >> 16; + + // int mods = MacModifiersToGLFWModifiers(event.modifiers); + + // int action; + // if(event.what == keyUp) { + // action = GLFW_RELEASE; + // } else { + // action = GLFW_PRESS; + // } + // ___curWindow->keyCallback(___curWindow, key, scancode, action, + // mods); + // } + } + } + + FlushEvents(everyEvent, -1); + YieldToAnyThread(); } static void MwLLSetTitleImpl(MwLL handle, const char* title) { @@ -167,14 +308,14 @@ static void MwLLFocusImpl(MwLL handle) { static void MwLLGrabPointerImpl(MwLL handle, int toggle) { } -static void MwLLSetClipboardImpl(MwLL handle, const char* text) { +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { /* TODO */ (void)handle; (void)text; } -static void MwLLGetClipboardImpl(MwLL handle) { +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { } static void MwLLMakeToolWindowImpl(MwLL handle) { diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 31eefb20..56601258 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -17,6 +17,8 @@ wayland_call_table_t wl_call_tbl; MwBool MwWaylandAlwaysRender = MwFALSE; +MwU32 wl_dark_theme = -1; + /* Standard procedure before most event callbacks in Wayland ("most" because the setup ones don't need this). Wait for the Mutex to be freed, if we're deadlocking for longer then a quarter of a second then do nothing with the event. */ #define WAYLAND_EVENT_OP_START(self) \ do { \ @@ -62,9 +64,7 @@ static void new_protocol(void* data, struct wl_registry* registry, wayland_protocol_callback_table_t* cb = shget(self->wayland.wl_protocol_setup_map, interface); if(cb != NULL) { - char* inter = malloc(strlen(interface) + 1); - strcpy(inter, interface); - shput(self->wayland.wl_protocol_map, inter, cb->setup(name, data)); + shput(self->wayland.wl_protocol_map, interface, cb->setup(name, data)); /* we don't care for adding this protocol, we just use it to know if the compositor will let us have transparent surfaces */ } else if(strcmp(interface, "wp_alpha_modifier_v1") == 0) { self->common.supports_transparency = MwTRUE; @@ -132,34 +132,6 @@ static void recursive_dispatch_move(MwLL handle, MwMouse* p) { } }; -/* Recursively dispatch a key event to a widget and its children */ -static void recursive_dispatch_key(MwLL handle, int* k) { - MwWidget h = (MwWidget)handle->common.user; - MwLLDispatch(handle, key, k); - if(h) { - int i; - for(i = 0; i < arrlen(h->children); i++) { - MwLLDispatch(h->children[i]->lowlevel, key, k); - if(arrlen(h->children[i]->children) > 0) { - recursive_dispatch_key(h->children[i]->lowlevel, k); - } - } - } -}; -/* Recursively dispatch a key released event to a widget and its children */ -static void recursive_dispatch_key_released(MwLL handle, int* k) { - MwWidget h = (MwWidget)handle->common.user; - MwLLDispatch(handle, key_released, k); - if(h) { - int i; - for(i = 0; i < arrlen(h->children); i++) { - MwLLDispatch(h->children[i]->lowlevel, key_released, k); - if(arrlen(h->children[i]->children) > 0) { - recursive_dispatch_key_released(h->children[i]->lowlevel, k); - } - } - } -}; static void wl_offer(void* data, struct wl_data_offer* wl_data_offer, const char* mime_type) { @@ -538,6 +510,12 @@ static void relative_pointer_motion(void* data, MwLL self = data; MwMouse p; + (void)pointer; + (void)timeHi; + (void)timeLo; + (void)dx; + (void)dy; + WAYLAND_EVENT_OP_START(self); p.point.x = wl_fixed_to_int(dxUnaccel); @@ -609,8 +587,6 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri inArea |= self->wayland.backbuffer.surface == curSurface; } if(inArea) { - int i; - switch(button) { case BTN_LEFT: p.button = MwMOUSE_LEFT; @@ -675,19 +651,24 @@ static void keyboard_keymap(void* data, MwLL self = data; (void)wl_keyboard; - if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + if(!self->wayland.parent) { + char* map_shm; + struct xkb_keymap* xkb_keymap; + struct xkb_state* xkb_state; + xkb_state = NULL; + assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); - char* map_shm = (char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + map_shm = (char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); assert(map_shm != MAP_FAILED); - struct xkb_keymap* xkb_keymap = xkb_keymap_new_from_string( + xkb_keymap = xkb_keymap_new_from_string( self->wayland.xkb_context, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); munmap(map_shm, size); close(fd); - struct xkb_state* xkb_state = xkb_state_new(xkb_keymap); + xkb_state = xkb_state_new(xkb_keymap); self->wayland.xkb_keymap = xkb_keymap; self->wayland.xkb_state = xkb_state; @@ -741,8 +722,8 @@ static void keyboard_key(void* data, MwU32 time, MwU32 key, MwU32 state) { - MwLL self = data; - MwBool inArea; + MwLL self = data; + MwBool inArea = 0; (void)wl_keyboard; (void)serial; @@ -760,7 +741,7 @@ static void keyboard_key(void* data, if(inArea) { xkb_layout_index_t layout; MwU32 levels; - xkb_level_index_t level; + xkb_level_index_t level = 0; const xkb_keysym_t* syms_out; MwU32 keycode = key + 8; MwU64 syms_num; @@ -785,9 +766,8 @@ static void keyboard_key(void* data, } for(i = 0; i < syms_num; i++) { - int sym = syms_out[i]; - int key = -1; - const char* name; + int sym = syms_out[i]; + int key = -1; switch(sym) { case XKB_KEY_BackSpace: @@ -1001,6 +981,7 @@ static wayland_protocol_t* wl_seat_setup(MwU32 name, MwLL ll) { static void wl_seat_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { (void)wayland; free(data->listener); + free(data); } /* wl_output setup function */ @@ -1145,6 +1126,8 @@ static int event_loop(MwLL handle) { if(wl_display_dispatch_pending(wayland->display) < 0) { wl_display_cancel_read(wayland->display); } + wl_display_flush(handle->wayland.display); + return 1; } @@ -1255,66 +1238,46 @@ static void update_buffer(MwLL self, struct _MwLLWaylandShmBuffer* buffer) { } static void buffer_setup(struct _MwLLWaylandShmBuffer* buffer, MwU32 width, MwU32 height) { - int stride = width * 4; - char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; - char temp_name_back[] = "/tmp/milsko-wl-shm-back-XXXXXX"; + int stride = width * 4; + char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; buffer->buf_size = width * height * 4; - buffer->fd = mkstemp(temp_name); - buffer->fd_back = mkstemp(temp_name_back); - + buffer->fd = mkstemp(temp_name); unlink(temp_name); - unlink(temp_name_back); if(posix_fallocate(buffer->fd, 0, buffer->buf_size) != 0) { printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); close(buffer->fd); return; } - if(posix_fallocate(buffer->fd_back, 0, buffer->buf_size) != 0) { - printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); - close(buffer->fd_back); - return; - } if(ftruncate(buffer->fd, buffer->buf_size) != 0) { printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); close(buffer->fd); return; } - if(ftruncate(buffer->fd_back, buffer->buf_size) != 0) { - printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); - close(buffer->fd_back); - return; - } buffer->buf = mmap(NULL, buffer->buf_size, PROT_WRITE, MAP_SHARED, buffer->fd, 0); - buffer->buf_back = mmap(NULL, buffer->buf_size, PROT_WRITE, MAP_SHARED, buffer->fd_back, 0); + buffer->buf_back = malloc(buffer->buf_size); fsync(buffer->fd); - fsync(buffer->fd_back); if(!(buffer->shm_pool = wl_shm_create_pool(buffer->shm, buffer->fd, buffer->buf_size))) { + close(buffer->fd); printf("failure setting up wl_shm: could not create pool.\n"); + return; } - if(!(buffer->shm_pool_back = wl_shm_create_pool(buffer->shm, buffer->fd_back, buffer->buf_size))) { - printf("failure setting up wl_shm: could not create pool.\n"); - } - buffer->shm_buffer = wl_shm_pool_create_buffer(buffer->shm_pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); - buffer->shm_buffer_back = wl_shm_pool_create_buffer(buffer->shm_pool_back, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); - buffer->setup = MwTRUE; + buffer->shm_buffer = wl_shm_pool_create_buffer(buffer->shm_pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); + buffer->setup = MwTRUE; } static void buffer_destroy(struct _MwLLWaylandShmBuffer* buffer) { - if(!buffer->setup) { - return; - } + close(buffer->fd); + if(buffer->buf) munmap(buffer->buf, buffer->buf_size); + if(buffer->buf_back) free(buffer->buf_back); if(buffer->shm_buffer) wl_buffer_destroy(buffer->shm_buffer); - if(buffer->shm_buffer_back) wl_buffer_destroy(buffer->shm_buffer_back); if(buffer->shm_pool) wl_shm_pool_destroy(buffer->shm_pool); if(buffer->shm_pool_back) wl_shm_pool_destroy(buffer->shm_pool_back); - close(buffer->fd); - close(buffer->fd_back); buffer->setup = MwFALSE; } @@ -1553,12 +1516,12 @@ static void destroy_toplevel(MwLL r) { xdg_toplevel_destroy(r->wayland.toplevel->xdg_top_level); - xkb_keymap_unref(r->wayland.xkb_keymap); - xkb_state_unref(r->wayland.xkb_state); xkb_context_unref(r->wayland.xkb_context); + xkb_keymap_unref(r->wayland.xkb_keymap); + free(r->wayland.toplevel); wl_registry_destroy(r->wayland.registry); @@ -1578,8 +1541,6 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { r->wayland.type = MWLL_WAYLAND_SUBLEVEL; - r->wayland.display = parent->wayland.display; - setup_callbacks(&r->wayland); r->wayland.registry = wl_display_get_registry(parent->wayland.display); @@ -1617,11 +1578,10 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { /* Sublevel setup function */ static void destroy_sublevel(MwLL r) { - backbuffer_destroy(&r->wayland); - framebuffer_destroy(&r->wayland); - wl_subsurface_destroy(r->wayland.sublevel->subsurface); + wl_registry_destroy(r->wayland.registry); + free(r->wayland.sublevel); r->wayland.configured = MwFALSE; @@ -1799,6 +1759,9 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh } } + framebuffer_destroy(&r->wayland); + backbuffer_destroy(&r->wayland); + framebuffer_setup(&r->wayland); backbuffer_setup(&r->wayland); @@ -1818,14 +1781,21 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh } #ifdef USE_DBUS +static void dark_theme_listener(MwLL handle, MwU32 new_value) { + wl_dark_theme = (new_value == 1) ? 1 : 0; + + MwLLDispatch(handle, dark_theme, &wl_dark_theme); +} + static void detect_dark_theme(MwLL handle) { MwU32 value = 0; - MwU32 dark_theme = 0; + MwLLDBusPortalGet(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); + wl_dark_theme = (value == 1) ? 1 : 0; - dark_theme = (value == 1) ? 1 : 0; + MwLLDBusPortalWatch(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings"); - MwLLDispatch(handle, dark_theme, &dark_theme); + MwLLDispatch(handle, dark_theme, &wl_dark_theme); } #endif @@ -1857,8 +1827,6 @@ static void MwLLDestroyImpl(MwLL handle) { int select_ret; event_loop(handle); - // wl_display_cancel_read(handle->wayland.display); - wl_flush(handle); if(pthread_mutex_timedlock(&handle->wayland.eventsMutex, &t) != 0) { @@ -1884,7 +1852,6 @@ static void MwLLDestroyImpl(MwLL handle) { } #endif - buffer_destroy(&handle->wayland.cursor); wl_region_destroy(handle->wayland.region); if(handle->wayland.supports_zwp) { @@ -1892,10 +1859,6 @@ static void MwLLDestroyImpl(MwLL handle) { } else { wl_data_source_destroy(handle->wayland.clipboard_source.wl); } - if(handle->wayland.icon != NULL) { - buffer_destroy(handle->wayland.icon); - wl_surface_destroy(handle->wayland.icon->surface); - } if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { destroy_toplevel(handle); @@ -1905,6 +1868,20 @@ static void MwLLDestroyImpl(MwLL handle) { destroy_popup(handle); } + if(handle->wayland.framebuffer.setup) { + framebuffer_destroy(&handle->wayland); + wl_surface_destroy(handle->wayland.framebuffer.surface); + } + if(handle->wayland.backbuffer.setup) { + backbuffer_destroy(&handle->wayland); + wl_surface_destroy(handle->wayland.backbuffer.surface); + } + buffer_destroy(&handle->wayland.cursor); + if(handle->wayland.icon != NULL) { + buffer_destroy(handle->wayland.icon); + wl_surface_destroy(handle->wayland.icon->surface); + } + for(i = 0; i < shlen(handle->wayland.wl_protocol_setup_map); i++) { void* ctx = shget(handle->wayland.wl_protocol_map, handle->wayland.wl_protocol_setup_map[i].key); @@ -1912,17 +1889,30 @@ static void MwLLDestroyImpl(MwLL handle) { handle->wayland.wl_protocol_setup_map[i].value->destroy(&handle->wayland, ctx); } shdel(handle->wayland.wl_protocol_map, handle->wayland.wl_protocol_setup_map[i].value); + free(handle->wayland.wl_protocol_setup_map[i].value); + free(ctx); } shfree(handle->wayland.wl_protocol_map); shfree(handle->wayland.wl_protocol_setup_map); - wl_keyboard_destroy(handle->wayland.keyboard); - wl_pointer_destroy(handle->wayland.pointer); + // wl_keyboard_destroy(handle->wayland.keyboard); + // wl_pointer_destroy(handle->wayland.pointer); + + if(handle->wayland.supports_zwp) { + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { + if(handle->wayland.clipboard_devices_zwp[i]->device.zwp) zwp_primary_selection_device_v1_destroy(handle->wayland.clipboard_devices_zwp[i]->device.zwp); + free(handle->wayland.clipboard_devices_zwp[i]); + } + } else { + printf("[WARNING] Primary clipboard requested for MwLLSetClipboard, but this Wayland compositor doesn't support it.\n"); + } + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_wl); i++) { + wl_data_device_destroy(handle->wayland.clipboard_devices_wl[i]->device.wl); + free(handle->wayland.clipboard_devices_wl[i]); + } wl_flush(handle); - // free(handle); - if(currentlyHeldWidget == handle) { currentlyHeldWidget = NULL; } @@ -1975,7 +1965,6 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { setup_popup(handle, handle->wayland.x, handle->wayland.y, handle->wayland.parent); } -refresh: region_setup(handle); framebuffer_destroy(&handle->wayland); @@ -2164,15 +2153,18 @@ static int MwLLPendingImpl(MwLL handle) { }; int pending = 0; - if(handle->wayland.dark_theme_detection) { - handle->wayland.dark_theme_detection = MwFALSE; #ifdef USE_DBUS - if(wl_call_tbl.has_dbus) { + if(wl_call_tbl.has_dbus) { + if(handle->wayland.dark_theme_detection) { + + handle->wayland.dark_theme_detection = MwFALSE; detect_dark_theme(handle); MwLLDispatch(handle, draw, NULL); + } else { + MwLLDBusPortalPoll(&wl_call_tbl.dbus, &handle->wayland.dbus, handle, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &dark_theme_listener); } -#endif } +#endif if(!handle->wayland.did_initial_resize) { recursive_dispatch_resize(handle); @@ -2185,6 +2177,7 @@ static int MwLLPendingImpl(MwLL handle) { wl_display_cancel_read(handle->wayland.display); } else { wl_display_read_events(handle->wayland.display); + wl_display_flush(handle->wayland.display); if((pending = wl_display_dispatch_pending(handle->wayland.display)) < 0) { wl_display_cancel_read(handle->wayland.display); } @@ -2193,6 +2186,7 @@ static int MwLLPendingImpl(MwLL handle) { if((pending = wl_display_dispatch_pending(handle->wayland.display)) < 0) { wl_display_cancel_read(handle->wayland.display); } + wl_display_flush(handle->wayland.display); } if(MwWaylandAlwaysRender) { @@ -2343,7 +2337,7 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { if(handle->wayland.configured) update_buffer(handle, handle->wayland.icon); - xdg_toplevel_icon_v1_add_buffer(icon, handle->wayland.icon->shm_buffer_back, 1); + xdg_toplevel_icon_v1_add_buffer(icon, handle->wayland.icon->shm_buffer, 1); xdg_toplevel_icon_manager_v1_set_icon(icon_manager, handle->wayland.toplevel->xdg_top_level, icon); } diff --git a/src/backend/x11.c b/src/backend/x11.c index cc76ed66..704bd7bd 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -72,7 +72,7 @@ static struct symtbl { char* (*XSetLocaleModifiers)(const char*); XIM (*XOpenIM)(Display*, struct _XrmHashBucketRec*, char*, char*); Status (*XCloseIM)(XIM); - XIC (*XCreateIC)(XIM, ...) _X_SENTINEL(0); + XIC (*XCreateIC)(XIM, ...); void (*XDestroyIC)(XIC); void (*XSetICFocus)(XIC); diff --git a/src/core.c b/src/core.c index 0c8360ef..6476ccbb 100644 --- a/src/core.c +++ b/src/core.c @@ -878,6 +878,9 @@ int MwLibraryInit(void) { #endif #ifdef USE_GDI MwLLGDICallInit, +#endif +#ifdef CLASSIC_MAC_OS + MwLLClassicMacOSCallInit, #endif NULL}; int i; @@ -900,6 +903,9 @@ int MwLibraryInit(void) { #endif #ifdef USE_GDI " GDI" +#endif +#ifdef CLASSIC_MAC_OS + " ClassicMacOS" #endif "\n"); diff --git a/src/lowlevel.c b/src/lowlevel.c index 2a874e6c..935bf9b3 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -176,6 +176,69 @@ MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, co return MwTRUE; } +MWDECL MwBool MwLLDBusPortalWatch(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal) { + if(!ctx->dbus_conn) { + return MwFALSE; + } + + char filter_string[2048]; + MwStringPrintIntoBuffer(filter_string, sizeof(filter_string), "type='%s',interface=%s", "signal", portal); + + dbus_bus_add_match(ctx->dbus_conn, filter_string, &ctx->dbus_err); + dbus_connection_flush(ctx->dbus_conn); + + return MwTRUE; +} + +// Technically this will swallow all other results, so this is not usable multiple times. +// TODO: Use a hashmap instead +MWDECL MwBool MwLLDBusPortalPoll(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, MwLL handle, const char* portal, const char* namespace, const char* key, MwLLDBusPortalPollListener listener) { + DBusMessage* msg; + DBusMessageIter args, msg_value; + const char* msg_namespace; + const char* msg_key; + MwU32 msg_value_content; + + if(!ctx->dbus_conn) { + return MwFALSE; + } + + dbus_connection_read_write(ctx->dbus_conn, 0); + msg = dbus_connection_pop_message(ctx->dbus_conn); + + if (NULL == msg) { + return MwFALSE; + } + + // check if the message is a signal from the correct interface and with the correct name + if (dbus_message_is_signal(msg, portal, "SettingChanged")) { + // read the parameters + if (!dbus_message_iter_init(msg, &args)) + fprintf(stderr, "[WARNING] Message has no arguments\n"); + else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) + fprintf(stderr, "[WARNING] Argument is not string\n"); + else { + dbus_message_iter_get_basic(&args, &msg_namespace); + + dbus_message_iter_next(&args); + dbus_message_iter_get_basic(&args, &msg_key); + + // Check that key and namespace match + if (strcmp(msg_namespace, namespace) == 0 && strcmp(msg_key, key) == 0) { + // Assuming the value is a basic type + dbus_message_iter_next(&args); + dbus_message_iter_recurse(&args, &msg_value); + dbus_message_iter_get_basic(&msg_value, &msg_value_content); + + listener(handle, msg_value_content); + } + } + } + + // free the message + dbus_message_unref(msg); +} + void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) { if(!tbl->lib) { return; diff --git a/tools/.gitignore b/tools/.gitignore new file mode 100644 index 00000000..0581170f --- /dev/null +++ b/tools/.gitignore @@ -0,0 +1,2 @@ +font +fuzzer diff --git a/tools/Makefile b/tools/Makefile index fbfc51a7..ef863683 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -6,7 +6,10 @@ LIBS = `freetype-config --libs` .PHONY: all clean .SUFFIXES: .c .o -all: font +all: fuzzer font + +fuzzer: fuzzer.o + $(CC) -g -L../src/ -Wl,-R../src -lMw -o $@ fuzzer.o font: font.o $(CC) $(LDFLAGS) -o $@ font.o $(LIBS) @@ -15,4 +18,4 @@ font: font.o $(CC) $(CFLAGS) -c -o $@ $< clean: - rm -f *.o font + rm -f *.o font fuzzer diff --git a/tools/fuzzer.c b/tools/fuzzer.c new file mode 100644 index 00000000..5b4224e9 --- /dev/null +++ b/tools/fuzzer.c @@ -0,0 +1,85 @@ +#include + +#define WIDGET_AMOUNT 1 + +int main() { + MwWidget window, widget; + + MwLibraryInit(); + + window = MwCreateWidget(MwWindowClass, "window", NULL, 0, 0, 400, 400); + + while(true) { + int r = rand() % WIDGET_AMOUNT; + MwClass cls; + switch(r) { + case 0: + cls = MwBoxClass; + break; + case 1: + cls = MwButtonClass; + break; + case 2: + cls = MwCheckBoxClass; + break; + case 3: + cls = MwComboBoxClass; + break; + case 4: + cls = MwEntryClass; + break; + case 5: + cls = MwFrameClass; + break; + case 6: + cls = MwImageClass; + break; + case 7: + cls = MwLabelClass; + break; + case 8: + cls = MwListBoxClass; + break; + case 9: + cls = MwMenuClass; + break; + case 10: + cls = MwNumberEntryClass; + break; + case 12: + cls = MwProgressBarClass; + break; + case 13: + cls = MwRadioBoxClass; + break; + case 14: + cls = MwScrollBarClass; + break; + case 15: + cls = MwSeparatorClass; + break; + // case 16: + // cls = MwSubMenuClass; + // break; + case 17: + cls = MwTreeViewClass; + break; + case 18: + cls = MwViewportClass; + break; + default: + cls = NULL; + break; + } + if(cls) { + widget = MwCreateWidget(cls, "Cls", window, 0, 0, 100, 100); + } + + if(MwPending(window)) { + MwStep(window); + } + if(cls) { + MwDestroyWidget(widget); + } + } +}