diff --git a/examples/basic/clipboard.c b/examples/basic/clipboard.c index e6a7502..38084a1 100644 --- a/examples/basic/clipboard.c +++ b/examples/basic/clipboard.c @@ -1,6 +1,6 @@ #include -MwWidget window, instructions, text; +MwWidget window, instructions, text1, text2, cur_text; static void resize(MwWidget handle, void* user_data, void* call_data) { unsigned int w, h; @@ -17,9 +17,14 @@ static void resize(MwWidget handle, void* user_data, void* call_data) { MwNheight, h - 125 - 50 * 3, NULL); - MwVaApply(text, - MwNy, 200, - MwNwidth, w - 50 * 2, + MwVaApply(text1, + MwNy, 150, + MwNwidth, w - 25 * 2, + MwNheight, h - 125 - 50 * 3, + NULL); + MwVaApply(text2, + MwNy, 250, + MwNwidth, w - 25 * 2, MwNheight, h - 125 - 50 * 3, NULL); } @@ -30,14 +35,17 @@ static void clipboard(MwWidget handle, void* user_data, void* call_data) { (void)user_data; if(clipboard != NULL) { - MwVaApply(text, MwNtext, clipboard, NULL); - MwForceRender(text); + MwVaApply(cur_text, MwNtext, clipboard, NULL); + MwForceRender(cur_text); } - MwForceRender(window); } static void tick(MwWidget handle, void* user_data, void* call_data) { - MwGetClipboard(handle); + cur_text = text1; + MwGetClipboard(handle, MwClipboardMain); + cur_text = text2; + MwGetClipboard(handle, MwClipboardPrimary); + MwForceRender(window); } int main() { @@ -49,14 +57,19 @@ int main() { instructions = MwVaCreateWidget(MwLabelClass, "button", window, 50, 50, 300, 125, MwNtext, "clipboard contents will show up below.", NULL); - text = MwVaCreateWidget(MwLabelClass, "label", window, 50, 200, 300, 125, + text1 = MwVaCreateWidget(MwLabelClass, "label", window, 25, 150, 300, 75, MwNtext, "", NULL); + text2 = MwVaCreateWidget(MwLabelClass, "label2", window, 25, 250, 300, 75, + MwNtext, "", + NULL); + + cur_text = text1; MwAddUserHandler(window, MwNresizeHandler, resize, NULL); MwAddUserHandler(window, MwNclipboardHandler, clipboard, NULL); MwAddUserHandler(instructions, MwNclipboardHandler, clipboard, NULL); - MwAddUserHandler(text, MwNclipboardHandler, clipboard, NULL); + MwAddUserHandler(cur_text, MwNclipboardHandler, clipboard, NULL); MwAddUserHandler(window, MwNtickHandler, tick, NULL); resize(window, NULL, NULL); diff --git a/include/Mw/Core.h b/include/Mw/Core.h index 4d3e4b9..ad4cd19 100644 --- a/include/Mw/Core.h +++ b/include/Mw/Core.h @@ -362,10 +362,11 @@ MWDECL void MwGetScreenSize(MwWidget handle, MwRect* rect); MWDECL int MwGetCoordinateType(MwWidget handle); /*! - * @brief Queue to get clipboard content + * @brief Queue to get clipboard content. * @param handle Widget + * @param clipboard_type The Clipboard Type to get. See MwClipboardType. This is ignored on backends that aren't X11/Wayland, so if you're unsure, just use MwClipboardMain */ -MWDECL void MwGetClipboard(MwWidget handle); +MWDECL void MwGetClipboard(MwWidget handle, int clipboard_type); #ifdef __cplusplus } diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index d5a0b1b..abe81b6 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -234,8 +234,8 @@ MWDECL void (*MwLLEndStateChange)(MwLL handle); MWDECL void (*MwLLFocus)(MwLL handle); MWDECL void (*MwLLGrabPointer)(MwLL handle, int toggle); -MWDECL void (*MwLLSetClipboard)(MwLL handle, const char* text); -MWDECL void (*MwLLGetClipboard)(MwLL handle); +MWDECL void (*MwLLSetClipboard)(MwLL handle, const char* text, int clipboard_type); +MWDECL void (*MwLLGetClipboard)(MwLL handle, int clipboard_type); MWDECL void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point); MWDECL void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect); diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index ce1630c..a94d1c8 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -439,7 +439,7 @@ struct _MwLLWayland { /* 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.*/ - union { + struct { struct wl_data_device_manager* wl; struct zwp_primary_selection_device_manager_v1* zwp; } clipboard_manager; @@ -451,7 +451,8 @@ struct _MwLLWayland { MwBool supports_zwp; uint32_t clipboard_serial; - wl_clipboard_device_context_t** clipboard_devices; + wl_clipboard_device_context_t** clipboard_devices_wl; + wl_clipboard_device_context_t** clipboard_devices_zwp; struct wl_pointer* pointer; MwU32 pointer_serial; diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index 62380f0..bd0af3d 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -239,4 +239,12 @@ enum MwCoordinateType { MwCoordinatesLocal, }; +/* The clipboard type that MwGetClipboard should return */ +enum MwClipboardType { + /* the clipboard that is present on every platform that supports it */ + MwClipboardMain = 0, + /* the "primary" clipboard that Wayland stores to emulate X11's behavior. */ + MwClipboardPrimary, +}; + #endif diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 4cdc5b2..240e5b8 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1042,13 +1042,15 @@ static void MwLLGrabPointerImpl(MwLL handle, int toggle) { handle->cocoa.real->pointerLocked = toggle; } -static void MwLLSetClipboardImpl(MwLL handle, const char* text) { +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { (void)handle; (void)text; + (void)clipboard_type; } -static void MwLLGetClipboardImpl(MwLL handle) { +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { (void)handle; + (void)clipboard_type; } static void MwLLMakeToolWindowImpl(MwLL handle) { diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 5d89419..2941e5c 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -735,8 +735,9 @@ 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) { HGLOBAL hg; + (void)clipboard_type; if(OpenClipboard(handle->gdi.hWnd) != 0) { char* lock; @@ -753,7 +754,8 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text) { } } -static void MwLLGetClipboardImpl(MwLL handle) { +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { + (void)clipboard_type; handle->gdi.get_clipboard = 1; /* nishi: we do this to make clipboard api work similar to other backends */ } diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 8bb6f3e..7f6247f 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -266,7 +266,7 @@ struct zwp_primary_selection_device_v1_listener zwp_primary_selection_device_v1_ .selection = zwp_primary_selection_device_v1_selection, }; -static void wl_clipboard_read(wl_clipboard_device_context_t* ctx) { +static void wl_clipboard_read(wl_clipboard_device_context_t* ctx, int clipboard_type) { int fds[2]; fd_set set; char* buf = NULL; @@ -282,7 +282,7 @@ static void wl_clipboard_read(wl_clipboard_device_context_t* ctx) { timeout.tv_sec = 0; timeout.tv_usec = 100; - if(ctx->ll->wayland.supports_zwp) { + if(clipboard_type == MwClipboardPrimary) { zwp_primary_selection_offer_v1_receive(ctx->offer.zwp, "text/plain", fds[1]); } else if(ctx->offer.wl) { wl_data_offer_receive(ctx->offer.wl, "text/plain", fds[1]); @@ -427,7 +427,7 @@ static wayland_protocol_t* wl_data_device_manager_setup(MwU32 name, struct _MwLL static void wl_data_device_manager_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { (void)data; - if(wayland->clipboard_manager.wl != NULL && !wayland->supports_zwp) { + if(wayland->clipboard_manager.wl != NULL) { wl_data_device_manager_destroy(wayland->clipboard_manager.wl); wl_data_source_destroy(wayland->clipboard_source.wl); wayland->clipboard_manager.wl = NULL; @@ -436,10 +436,6 @@ static void wl_data_device_manager_interface_destroy(struct _MwLLWayland* waylan /* zwp_primary_selection_device_manager_v1 setup function */ static wayland_protocol_t* zwp_primary_selection_device_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) { - if(wayland->clipboard_manager.wl != NULL) { - wl_data_device_manager_interface_destroy(wayland, NULL); - } - wayland->clipboard_manager.zwp = wl_registry_bind(wayland->registry, name, &zwp_primary_selection_device_manager_v1_interface, 1); wayland->clipboard_source.zwp = zwp_primary_selection_device_manager_v1_create_source(wayland->clipboard_manager.zwp); @@ -621,10 +617,6 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri break; case BTN_MIDDLE: p.button = MwLLMouseMiddle; - for(i = 0; i < arrlen(self->wayland.clipboard_devices); i++) { - wl_clipboard_read( - self->wayland.clipboard_devices[i]); - } break; case BTN_RIGHT: p.button = MwLLMouseRight; @@ -840,14 +832,6 @@ static void keyboard_key(void* data, } if((self->wayland.mod_state & 4) == 4) { - /* clipboard paste */ - if(key == 'V') { - int i; - for(i = 0; i < arrlen(self->wayland.clipboard_devices); i++) { - wl_clipboard_read( - self->wayland.clipboard_devices[i]); - } - } key |= MwLLControlMask; } if((self->wayland.mod_state & 8) == 8) { @@ -913,8 +897,9 @@ wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) { /* `wl_seat.capabilities` callback */ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, MwU32 capabilities) { - MwLL self = data; - wl_clipboard_device_context_t* device_ctx = malloc(sizeof(wl_clipboard_device_context_t)); + MwLL self = data; + wl_clipboard_device_context_t* device_ctx_zwp = NULL; + wl_clipboard_device_context_t* device_ctx_wl = malloc(sizeof(wl_clipboard_device_context_t)); WAYLAND_EVENT_OP_START(self); @@ -930,21 +915,23 @@ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, if(self->wayland.clipboard_manager.wl != NULL) { if(self->wayland.supports_zwp) { - device_ctx->device.zwp = zwp_primary_selection_device_manager_v1_get_device(self->wayland.clipboard_manager.zwp, wl_seat); - } else { - device_ctx->device.wl = wl_data_device_manager_get_data_device(self->wayland.clipboard_manager.wl, wl_seat); + device_ctx_zwp = malloc(sizeof(wl_clipboard_device_context_t)); + device_ctx_zwp->device.zwp = zwp_primary_selection_device_manager_v1_get_device(self->wayland.clipboard_manager.zwp, wl_seat); + device_ctx_zwp->ll = self; + device_ctx_zwp->seat = wl_seat; + device_ctx_zwp->capabilities = capabilities; } - device_ctx->ll = self; - device_ctx->seat = wl_seat; - device_ctx->capabilities = capabilities; + device_ctx_wl->device.wl = wl_data_device_manager_get_data_device(self->wayland.clipboard_manager.wl, wl_seat); + device_ctx_wl->ll = self; + device_ctx_wl->seat = wl_seat; + device_ctx_wl->capabilities = capabilities; if(self->wayland.supports_zwp) { - zwp_primary_selection_device_v1_add_listener(device_ctx->device.zwp, &zwp_primary_selection_device_v1_listener, device_ctx); - } else { - wl_data_device_add_listener(device_ctx->device.wl, &wl_data_device_listener, device_ctx); + zwp_primary_selection_device_v1_add_listener(device_ctx_zwp->device.zwp, &zwp_primary_selection_device_v1_listener, device_ctx_zwp); + arrpush(self->wayland.clipboard_devices_zwp, device_ctx_zwp); } - - arrpush(self->wayland.clipboard_devices, device_ctx); + wl_data_device_add_listener(device_ctx_wl->device.wl, &wl_data_device_listener, device_ctx_wl); + arrpush(self->wayland.clipboard_devices_wl, device_ctx_wl); } WAYLAND_EVENT_OP_END(self); @@ -2471,33 +2458,48 @@ 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) { + int i; + if(handle->wayland.clipboard_buffer != NULL) { free(handle->wayland.clipboard_buffer); } handle->wayland.clipboard_buffer = malloc(strlen(text)); strcpy(handle->wayland.clipboard_buffer, text); - if(handle->wayland.supports_zwp) { - int i; - for(i = 0; i < arrlen(handle->wayland.clipboard_devices); i++) { - wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices[i]; - zwp_primary_selection_device_v1_set_selection(device->device.zwp, handle->wayland.clipboard_source.zwp, handle->wayland.keyboard_serial); + if(clipboard_type == MwClipboardPrimary) { + if(handle->wayland.supports_zwp) { + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { + wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices_zwp[i]; + zwp_primary_selection_device_v1_set_selection(device->device.zwp, handle->wayland.clipboard_source.zwp, handle->wayland.keyboard_serial); + } + } else { + printf("[WARNING] Primary clipboard requested for MwLLSetClipboard, but this Wayland compositor doesn't support it.\n"); } } else { - int i; - for(i = 0; i < arrlen(handle->wayland.clipboard_devices); i++) { - wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices[i]; + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_wl); i++) { + wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices_wl[i]; wl_data_device_set_selection(device->device.wl, handle->wayland.clipboard_source.wl, handle->wayland.keyboard_serial); } } } -static void MwLLGetClipboardImpl(MwLL handle) { +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { int i; - for(i = 0; i < arrlen(handle->wayland.clipboard_devices); i++) { - wl_clipboard_read( - handle->wayland.clipboard_devices[i]); + if(clipboard_type == MwClipboardPrimary) { + if(handle->wayland.supports_zwp) { + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { + wl_clipboard_read( + handle->wayland.clipboard_devices_zwp[i], clipboard_type); + } + } else { + printf("[WARNING] Primary clipboard requested for MwLLSetClipboard, but this Wayland compositor doesn't support it.\n"); + } + } else { + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_wl); i++) { + wl_clipboard_read( + handle->wayland.clipboard_devices_wl[i], clipboard_type); + } } return; } diff --git a/src/backend/x11.c b/src/backend/x11.c index ad97d68..4393317 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -1220,14 +1220,14 @@ 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) { if(handle->x11.clipboard_pending) return; XConvertSelection(handle->x11.display, handle->x11.clipboard, handle->x11.utf8_string, handle->x11.selection, handle->x11.window, CurrentTime); diff --git a/src/core.c b/src/core.c index cf45ddd..de2774d 100644 --- a/src/core.c +++ b/src/core.c @@ -958,6 +958,6 @@ int MwGetCoordinateType(MwWidget handle) { } } -void MwGetClipboard(MwWidget handle) { - MwLLGetClipboard(handle->lowlevel); +void MwGetClipboard(MwWidget handle, int clipboard_type) { + MwLLGetClipboard(handle->lowlevel, clipboard_type); } diff --git a/src/lowlevel.c b/src/lowlevel.c index 597a23a..534ecd2 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -45,8 +45,8 @@ void (*MwLLEndStateChange)(MwLL handle) = NULL; void (*MwLLFocus)(MwLL handle) = NULL; void (*MwLLGrabPointer)(MwLL handle, int toggle) = NULL; -void (*MwLLSetClipboard)(MwLL handle, const char* text) = NULL; -void (*MwLLGetClipboard)(MwLL handle) = NULL; +void (*MwLLSetClipboard)(MwLL handle, const char* text, int clipboard_type) = NULL; +void (*MwLLGetClipboard)(MwLL, int clipboard_type) = NULL; void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point) = NULL; void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect) = NULL; diff --git a/src/widget/entry.c b/src/widget/entry.c index bd7dbe1..a8d0941 100644 --- a/src/widget/entry.c +++ b/src/widget/entry.c @@ -113,7 +113,7 @@ static void key(MwWidget handle, int code) { } else if(code == MwLLKeyEnter) { MwDispatchUserHandler(handle, MwNactivateHandler, NULL); } else if(code == (MwLLControlMask | 'v')) { - MwLLGetClipboard(handle->lowlevel); + MwLLGetClipboard(handle->lowlevel, MwClipboardMain); } else if(!(code & MwLLKeyMask)) { int incr = 0; out = malloc(strlen(str) + 5 + 1); @@ -133,6 +133,20 @@ static void key(MwWidget handle, int code) { MwForceRender(handle); } +#if defined(USE_X11) || defined(USE_WAYLAND) +static void mouse_up(MwWidget handle, void* ptr) { + if(handle->lowlevel->common.type == MwLLBackendWayland || handle->lowlevel->common.type == MwLLBackendX11) { + MwLLMouse* mouse = ptr; + if(mouse->button == MwLLMouseMiddle) { + MwLLGetClipboard(handle->lowlevel, MwClipboardPrimary); + } + } + MwForceRender2(handle, NULL); +} +#else +#define mouse_up MwForceRender2 +#endif + static void prop_change(MwWidget handle, const char* prop) { if(strcmp(prop, MwNtext) == 0 || strcmp(prop, MwNhideInput) == 0) MwForceRender(handle); @@ -179,7 +193,7 @@ MwClassRec MwEntryClassRec = { NULL, /* parent_resize */ prop_change, /* prop_change */ NULL, /* mouse_move */ - MwForceRender2, /* mouse_up */ + mouse_up, /* mouse_up */ MwForceRender2, /* mouse_down */ key, /* key */ NULL, /* execute */