diff --git a/CMakeLists.txt b/CMakeLists.txt index e309d477..a6f823d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,7 +223,6 @@ if(MW_USE_WAYLAND) Mw PRIVATE USE_WAYLAND - USE_DBUS ) message(STATUS "Wayland backend has been enabled") else() @@ -350,14 +349,10 @@ target_link_directories( PRIVATE ${LIBRARY_DIRS} ) -find_package(PkgConfig REQUIRED) -pkg_check_modules(DBUS REQUIRED dbus-1) -include_directories(${DBUS_INCLUDE_DIRS}) target_link_libraries( Mw PRIVATE ${LIBRARIES} - ${DBUS_LIBRARIES} ) if(MW_BUILD_OPENGL) diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 1b5ec529..2ba3ff0b 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -66,17 +66,11 @@ typedef struct _MwLLDBusFuncTable { DBusMessage* (*dbus_message_new_method_call)(const char* bus_name, const char* path, const char* iface, const char* method); void (*dbus_message_iter_init_append)(DBusMessage* message, DBusMessageIter* iter); dbus_bool_t (*dbus_message_iter_append_basic)(DBusMessageIter* iter, int type, const void* value); - void (*dbus_connection_flush)(DBusConnection* connection); - dbus_bool_t (*dbus_connection_read_write)(DBusConnection* connection, int timeout_milliseconds); DBusMessage* (*dbus_connection_send_with_reply_and_block)(DBusConnection* connection, DBusMessage* message, int timeout_milliseconds, DBusError* error); - DBusMessage* (*dbus_connection_pop_message)(DBusConnection* connection); - void (*dbus_bus_add_match)(DBusConnection* connection, const char* rule, DBusError* error); void (*dbus_message_unref)(DBusMessage* message); dbus_bool_t (*dbus_message_iter_init)(DBusMessage* message, DBusMessageIter* iter); - dbus_bool_t (*dbus_message_is_signal)(DBusMessage* message, const char* iface, const char* signal_name); int (*dbus_message_iter_get_arg_type)(DBusMessageIter* iter); void (*dbus_message_iter_recurse)(DBusMessageIter* iter, DBusMessageIter* sub); - void (*dbus_message_iter_next)(DBusMessageIter* iter); void (*dbus_connection_unref)(DBusConnection* connection); void (*dbus_message_iter_get_basic)(DBusMessageIter* iter, void* value); } MwLLDBusFuncTable; @@ -86,6 +80,7 @@ typedef struct _MwLLDBusContext { DBusError dbus_err; DBusMessage* dbus_msg; DBusMessage* dbus_reply; + DBusMessageIter dbus_args, dbus_variant, dbus_inner_variant; } MwLLDBusContext; typedef void (*MwLLDBusPortalPollListener)(MwLL handle, MwU32 new_value); diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 47be5ba3..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; @@ -448,7 +454,6 @@ struct _MwLLWayland { #endif MwBool dark_theme_detection; - MwU32 dark_theme; /* clipboard related stuff. * Note that unlike most interfaces, we don't keep zwp_primary_selection stuff in a wayland_protocol_t because we use wl_data_device as a fallback and want to have it share memory space.*/ diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 4cab7e62..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; @@ -651,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; @@ -976,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 */ @@ -1120,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; } @@ -1230,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; } @@ -1528,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); @@ -1553,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); @@ -1592,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; @@ -1774,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); @@ -1794,20 +1782,20 @@ 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) { - handle->wayland.dark_theme = (new_value == 1) ? 1 : 0; + wl_dark_theme = (new_value == 1) ? 1 : 0; - MwLLDispatch(handle, dark_theme, &handle->wayland.dark_theme); + MwLLDispatch(handle, dark_theme, &wl_dark_theme); } static void detect_dark_theme(MwLL handle) { - MwU32 value = 0; + MwU32 value = 0; MwLLDBusPortalGet(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); - handle->wayland.dark_theme = (value == 1) ? 1 : 0; + wl_dark_theme = (value == 1) ? 1 : 0; MwLLDBusPortalWatch(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings"); - MwLLDispatch(handle, dark_theme, &handle->wayland.dark_theme); + MwLLDispatch(handle, dark_theme, &wl_dark_theme); } #endif @@ -1823,7 +1811,6 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { if(!parent && wl_call_tbl.has_dbus) { wl_call_tbl.has_dbus = MwLLDBusNewContext(&wl_call_tbl.dbus, &r->wayland.dbus); r->wayland.dark_theme_detection = MwTRUE; - r->wayland.dark_theme = -1; } #endif @@ -1840,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) { @@ -1867,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) { @@ -1875,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); @@ -1888,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); @@ -1895,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; } @@ -2170,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); } @@ -2178,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) { @@ -2328,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); } @@ -2430,7 +2439,7 @@ static void MwLLShowImpl(MwLL handle, int show) { static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { (void)handle; (void)parent; - /* Wayland doesn't have "popups" in the Milsko sense per se. xdg_popup is closer to ToolWindow and as such is what we use there. So just like the Mac backend, this is just left alone. */ + /* Wayland doesn't have "popups" in the Milsko sense persay. xdg_popup is closer to ToolWindow and as such is what we use there. So just like the Mac backend, this is just left alone. */ } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { diff --git a/src/lowlevel.c b/src/lowlevel.c index 7dfeea16..935bf9b3 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -82,22 +82,16 @@ MwBool MwLLDBusFuncSetup(MwLLDBusFuncTable* tbl) { DBUS_FUNC(dbus_error_init); DBUS_FUNC(dbus_bus_get); - DBUS_FUNC(dbus_bus_add_match); DBUS_FUNC(dbus_error_is_set); DBUS_FUNC(dbus_error_free); DBUS_FUNC(dbus_message_new_method_call); - DBUS_FUNC(dbus_message_is_signal); DBUS_FUNC(dbus_message_iter_init_append); DBUS_FUNC(dbus_message_iter_append_basic); - DBUS_FUNC(dbus_connection_flush); - DBUS_FUNC(dbus_connection_pop_message); - DBUS_FUNC(dbus_connection_read_write); DBUS_FUNC(dbus_connection_send_with_reply_and_block); DBUS_FUNC(dbus_message_unref); DBUS_FUNC(dbus_message_iter_init); DBUS_FUNC(dbus_message_iter_get_arg_type); DBUS_FUNC(dbus_message_iter_recurse); - DBUS_FUNC(dbus_message_iter_next); DBUS_FUNC(dbus_connection_unref); DBUS_FUNC(dbus_message_iter_get_basic); @@ -127,8 +121,6 @@ MwBool MwLLDBusNewContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) { }; MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal, const char* namespace, const char* key, void* out) { - DBusMessageIter dbus_args, dbus_variant, dbus_inner_variant; - char arg_type; if(!ctx->dbus_conn) { return MwFALSE; } @@ -143,9 +135,9 @@ MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, co return MwFALSE; } - tbl->dbus_message_iter_init_append(ctx->dbus_msg, &dbus_args); - tbl->dbus_message_iter_append_basic(&dbus_args, 's', &namespace); - tbl->dbus_message_iter_append_basic(&dbus_args, 's', &key); + tbl->dbus_message_iter_init_append(ctx->dbus_msg, &ctx->dbus_args); + tbl->dbus_message_iter_append_basic(&ctx->dbus_args, 's', &namespace); + tbl->dbus_message_iter_append_basic(&ctx->dbus_args, 's', &key); ctx->dbus_reply = tbl->dbus_connection_send_with_reply_and_block(ctx->dbus_conn, ctx->dbus_msg, 100, &ctx->dbus_err); @@ -159,35 +151,25 @@ MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, co return MwFALSE; } - if(!tbl->dbus_message_iter_init(ctx->dbus_reply, &dbus_args)) { + if(!tbl->dbus_message_iter_init(ctx->dbus_reply, &ctx->dbus_args)) { fprintf(stderr, "[WARNING] Couldn't get %s::%s: Reply has no arguments\n", namespace, key); tbl->dbus_message_unref(ctx->dbus_reply); return MwFALSE; } - if((arg_type = tbl->dbus_message_iter_get_arg_type(&dbus_args)) != 'v') { - fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant, got: %c\n", namespace, key, arg_type); + if(tbl->dbus_message_iter_get_arg_type(&ctx->dbus_args) != 'v') { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant\n", namespace, key); tbl->dbus_message_unref(ctx->dbus_reply); return MwFALSE; } - tbl->dbus_message_iter_recurse(&dbus_args, &dbus_variant); + tbl->dbus_message_iter_recurse(&ctx->dbus_args, &ctx->dbus_variant); /* Some portals wrap the value in a second variant */ - arg_type = tbl->dbus_message_iter_get_arg_type(&dbus_variant); - if(arg_type == 'v') { - tbl->dbus_message_iter_recurse(&dbus_variant, &dbus_inner_variant); - if((arg_type = tbl->dbus_message_iter_get_arg_type(&dbus_inner_variant)) != 'u') { - fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 'u' (uint32) for 'value', got: %c\n", portal, arg_type); - tbl->dbus_message_unref(ctx->dbus_reply); - return MwFALSE; - } - tbl->dbus_message_iter_get_basic(&dbus_inner_variant, out); - } else if (arg_type == 'u') { - tbl->dbus_message_iter_get_basic(&dbus_variant, out); + if(tbl->dbus_message_iter_get_arg_type(&ctx->dbus_variant) == 'v') { + tbl->dbus_message_iter_recurse(&ctx->dbus_variant, &ctx->dbus_inner_variant); + tbl->dbus_message_iter_get_basic(&ctx->dbus_inner_variant, out); } else { - fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected variant or string, got: %c\n", namespace, key, arg_type); - tbl->dbus_message_unref(ctx->dbus_reply); - return MwFALSE; + tbl->dbus_message_iter_get_basic(&ctx->dbus_variant, out); } tbl->dbus_message_unref(ctx->dbus_msg); @@ -195,104 +177,66 @@ MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, co } MWDECL MwBool MwLLDBusPortalWatch(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal) { - char filter_string[2048]; if(!ctx->dbus_conn) { return MwFALSE; } + char filter_string[2048]; MwStringPrintIntoBuffer(filter_string, sizeof(filter_string), "type='%s',interface=%s", "signal", portal); - tbl->dbus_bus_add_match(ctx->dbus_conn, filter_string, &ctx->dbus_err); - tbl->dbus_connection_flush(ctx->dbus_conn); + 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 */ +// 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) { - DBusMessageIter args, msg_value, msg_value_inner; - const char* msg_namespace; - const char* msg_key; - MwU32 msg_value_content; - char arg_type; + DBusMessage* msg; + DBusMessageIter args, msg_value; + const char* msg_namespace; + const char* msg_key; + MwU32 msg_value_content; if(!ctx->dbus_conn) { return MwFALSE; } - tbl->dbus_connection_read_write(ctx->dbus_conn, 0); - tbl->dbus_connection_read_write(ctx->dbus_conn, 0); - ctx->dbus_reply = tbl->dbus_connection_pop_message(ctx->dbus_conn); + dbus_connection_read_write(ctx->dbus_conn, 0); + msg = dbus_connection_pop_message(ctx->dbus_conn); - if(tbl->dbus_error_is_set(&ctx->dbus_err)) { - fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Poll error: %s\n", portal, ctx->dbus_err.message); - tbl->dbus_error_free(&ctx->dbus_err); - return MwFALSE; - } - if(!ctx->dbus_reply) { + if (NULL == msg) { return MwFALSE; } - /* check if the message is a signal from the correct interface and with the correct name */ - if(tbl->dbus_message_is_signal(ctx->dbus_reply, portal, "SettingChanged")) { - /* read the parameters */ - if(!tbl->dbus_message_iter_init(ctx->dbus_reply, &args)) - fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged has no arguments\n", portal); + // 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 { - if((arg_type = tbl->dbus_message_iter_get_arg_type(&args)) != 's') { - fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 's' (string) for 'namespace', got: %c\n", portal, arg_type); - tbl->dbus_message_unref(ctx->dbus_reply); - return MwFALSE; - } - tbl->dbus_message_iter_get_basic(&args, &msg_namespace); + dbus_message_iter_get_basic(&args, &msg_namespace); - tbl->dbus_message_iter_next(&args); - if((arg_type = tbl->dbus_message_iter_get_arg_type(&args)) != 's') { - fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 's' (string) for 'key', got: %c\n", portal, arg_type); - tbl->dbus_message_unref(ctx->dbus_reply); - return MwFALSE; - } - tbl->dbus_message_iter_get_basic(&args, &msg_key); + 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 */ - tbl->dbus_message_iter_next(&args); - - if((arg_type = tbl->dbus_message_iter_get_arg_type(&args)) != 'v') { - fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant, got: %c\n", namespace, key, arg_type); - tbl->dbus_message_unref(ctx->dbus_reply); - return MwFALSE; - } - tbl->dbus_message_iter_recurse(&args, &msg_value); - - /* Some portals wrap the value in a second variant */ - arg_type = tbl->dbus_message_iter_get_arg_type(&msg_value); - if(arg_type == 'v') { - tbl->dbus_message_iter_recurse(&msg_value, &msg_value_inner); - if((arg_type = tbl->dbus_message_iter_get_arg_type(&msg_value_inner)) != 'u') { - fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 'u' (uint32) for 'value', got: %c\n", portal, arg_type); - tbl->dbus_message_unref(ctx->dbus_reply); - return MwFALSE; - } - tbl->dbus_message_iter_get_basic(&msg_value_inner, &msg_value_content); - } else if (arg_type == 'u') { - tbl->dbus_message_iter_get_basic(&msg_value, &msg_value_content); - } else { - fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected variant or string, got: %c\n", namespace, key, arg_type); - tbl->dbus_message_unref(ctx->dbus_reply); - return MwFALSE; - } + // 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 */ - tbl->dbus_message_unref(ctx->dbus_reply); - return MwTRUE; + // free the message + dbus_message_unref(msg); } void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) { 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); + } + } +}