mirror of
https://gitea.nishi.boats/pyrite-dev/milsko
synced 2026-01-04 08:30:51 +00:00
Compare commits
31 Commits
c8e7f58230
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30a100fd28 | ||
|
|
a148b3bedf | ||
|
|
bed668b84a | ||
|
|
6183a1ccda | ||
|
|
f32f6cefc0 | ||
|
|
f3683dece3 | ||
|
|
808495cccf | ||
|
|
6946c1eaf3 | ||
|
|
029e62d765 | ||
|
|
a03065ae52 | ||
|
|
324257c43f | ||
|
|
afecb04848 | ||
|
|
bed63dd245 | ||
|
|
67bd6029af | ||
|
|
72820e87f1 | ||
|
|
d3147ac087 | ||
|
|
4bdda59693 | ||
|
|
823c865791 | ||
|
|
3f9125d1ae | ||
|
|
549d235893 | ||
|
|
0daa527b1d | ||
|
|
0ca7f6ed8a | ||
|
|
e895e96941 | ||
|
|
0d79141a49 | ||
|
|
c80987ffe4 | ||
|
|
d3a7b0a01d | ||
|
|
e77c4f3c38 | ||
|
|
22b4737c33 | ||
|
|
509351a0a0 | ||
|
|
86effbdfd7 | ||
|
|
7b47524286 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,6 +5,7 @@ examples/*/*.exe
|
||||
!examples/*/
|
||||
!examples/*.*
|
||||
!examples/*/*.*
|
||||
*.exe
|
||||
*.o
|
||||
*.so
|
||||
*.dll
|
||||
|
||||
@@ -195,7 +195,6 @@ target_compile_definitions(
|
||||
_MILSKO
|
||||
)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(
|
||||
TARGETS Mw
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2025, Pyrite development team
|
||||
Copyright (c) 2025-2026, Pyrite development team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#define _MILSKO
|
||||
#include <Mw/Milsko.h>
|
||||
|
||||
MwWidget window, button, text;
|
||||
MwWidget window, instructions, text;
|
||||
|
||||
void resize(MwWidget handle, void* user_data, void* call_data) {
|
||||
unsigned int w, h, mh;
|
||||
@@ -12,7 +11,7 @@ void resize(MwWidget handle, void* user_data, void* call_data) {
|
||||
w = MwGetInteger(handle, MwNwidth);
|
||||
h = MwGetInteger(handle, MwNheight);
|
||||
|
||||
MwVaApply(button,
|
||||
MwVaApply(instructions,
|
||||
MwNy, 50 + mh,
|
||||
MwNwidth, w - 50 * 2,
|
||||
MwNheight, h - 125 - 50 * 3,
|
||||
@@ -24,40 +23,34 @@ void resize(MwWidget handle, void* user_data, void* call_data) {
|
||||
MwNheight, h - 125 - 50 * 3,
|
||||
NULL);
|
||||
}
|
||||
void clipboard(MwWidget handle, void* user_data, void* call_data) {
|
||||
char* clipboard = call_data;
|
||||
|
||||
void handler(MwWidget handle, void* user_data, void* call_data) {
|
||||
(void)handle;
|
||||
(void)user_data;
|
||||
(void)call_data;
|
||||
char* clipboard;
|
||||
|
||||
clipboard = MwLLGetClipboard(handle->lowlevel);
|
||||
|
||||
if(clipboard != NULL) {
|
||||
MwVaApply(text, MwNtext, clipboard);
|
||||
MwForceRender(text);
|
||||
}
|
||||
|
||||
resize(window, NULL, NULL);
|
||||
MwForceRender(window);
|
||||
}
|
||||
|
||||
int main() {
|
||||
MwMenu m, m2;
|
||||
|
||||
MwLibraryInit();
|
||||
|
||||
window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 400, 400,
|
||||
MwNtitle, "clipboard",
|
||||
NULL);
|
||||
button = MwVaCreateWidget(MwButtonClass, "button", window, 50, 50, 300, 125,
|
||||
MwNtext, "get clipboard contents",
|
||||
NULL);
|
||||
text = MwVaCreateWidget(MwLabelClass, "label", window, 50, 200, 300, 125,
|
||||
MwNtext, "",
|
||||
NULL);
|
||||
window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 400, 400,
|
||||
MwNtitle, "clipboard",
|
||||
NULL);
|
||||
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,
|
||||
MwNtext, "",
|
||||
NULL);
|
||||
|
||||
MwAddUserHandler(window, MwNresizeHandler, resize, NULL);
|
||||
MwAddUserHandler(button, MwNactivateHandler, handler, NULL);
|
||||
MwAddUserHandler(window, MwNclipboardHandler, clipboard, NULL);
|
||||
|
||||
resize(window, NULL, NULL);
|
||||
|
||||
|
||||
@@ -147,6 +147,7 @@ struct _MwLLHandler {
|
||||
void (*key_released)(MwLL handle, void* data);
|
||||
void (*focus_in)(MwLL handle, void* data);
|
||||
void (*focus_out)(MwLL handle, void* data);
|
||||
void (*clipboard)(MwLL handle, void* data);
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -203,7 +204,7 @@ MWDECL void (*MwLLFocus)(MwLL handle);
|
||||
MWDECL void (*MwLLGrabPointer)(MwLL handle, int toggle);
|
||||
|
||||
MWDECL void (*MwLLSetClipboard)(MwLL handle, const char* text);
|
||||
MWDECL char* (*MwLLGetClipboard)(MwLL handle);
|
||||
MWDECL void (*MwLLGetClipboard)(MwLL handle);
|
||||
|
||||
MWDECL void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point);
|
||||
MWDECL void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect);
|
||||
|
||||
@@ -21,6 +21,7 @@ struct _MwLLGDI {
|
||||
|
||||
int grabbed;
|
||||
int force_render;
|
||||
int get_clipboard;
|
||||
};
|
||||
|
||||
struct _MwLLGDIColor {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <wayland-client.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <cairo/cairo.h>
|
||||
#include <pthread.h>
|
||||
|
||||
MWDECL int MwLLWaylandCallInit(void);
|
||||
|
||||
@@ -97,6 +98,21 @@ enum _MwLLWaylandType {
|
||||
MWLL_WAYLAND_POPUP,
|
||||
};
|
||||
|
||||
typedef struct wl_clipboard_device_context {
|
||||
union {
|
||||
struct wl_data_device* wl;
|
||||
struct zwp_primary_selection_device_v1* zwp;
|
||||
} device;
|
||||
union {
|
||||
struct wl_data_offer* wl;
|
||||
struct zwp_primary_selection_offer_v1* zwp;
|
||||
} offer;
|
||||
|
||||
MwLL ll;
|
||||
struct wl_seat* seat;
|
||||
MwU32 capabilities;
|
||||
} wl_clipboard_device_context_t;
|
||||
|
||||
struct _MwLLWayland {
|
||||
struct _MwLLCommon common;
|
||||
|
||||
@@ -124,6 +140,8 @@ struct _MwLLWayland {
|
||||
wayland_protocol_t* value;
|
||||
}* wl_protocol_map;
|
||||
|
||||
MwBool always_render;
|
||||
|
||||
struct wl_display* display;
|
||||
struct wl_registry* registry;
|
||||
struct wl_compositor* compositor;
|
||||
@@ -131,12 +149,29 @@ struct _MwLLWayland {
|
||||
struct wl_region* region;
|
||||
struct wl_output* output;
|
||||
|
||||
struct wl_pointer* pointer;
|
||||
struct wl_keyboard* keyboard;
|
||||
MwU32 pointer_serial;
|
||||
/* 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.*/
|
||||
|
||||
MwBool events_pending;
|
||||
MwBool test;
|
||||
union {
|
||||
struct wl_data_device_manager* wl;
|
||||
struct zwp_primary_selection_device_manager_v1* zwp;
|
||||
} clipboard_manager;
|
||||
union {
|
||||
struct wl_data_source* wl;
|
||||
struct zwp_primary_selection_source_v1* zwp;
|
||||
} clipboard_source;
|
||||
char* clipboard_buffer;
|
||||
MwBool supports_zwp;
|
||||
|
||||
uint32_t clipboard_serial;
|
||||
wl_clipboard_device_context_t** clipboard_devices;
|
||||
|
||||
struct wl_pointer* pointer;
|
||||
MwU32 pointer_serial;
|
||||
struct wl_keyboard* keyboard;
|
||||
MwU32 keyboard_serial;
|
||||
|
||||
MwU64 events_pending;
|
||||
|
||||
MwU32 mod_state;
|
||||
|
||||
@@ -149,10 +184,20 @@ struct _MwLLWayland {
|
||||
|
||||
MwLL parent;
|
||||
|
||||
MwBool force_render;
|
||||
|
||||
MwBool disabled;
|
||||
|
||||
struct _MwLLWaylandShmBuffer framebuffer;
|
||||
struct _MwLLWaylandShmBuffer cursor;
|
||||
struct _MwLLWaylandShmBuffer* icon;
|
||||
|
||||
/*
|
||||
Events mutex. Any time a keyboard/mouse event happens, we try to lock this for 100 milliseconds, then give up if we can't do it. This is used in conjunction with some code in the MwLLDestroyImpl to make sure that destroy is NEVER interferes with an ongoing event.
|
||||
|
||||
IOI_XD: This sounds like a hilariously rare edge case, so it's almost funnier that this happened with 100% certainty for me and I spent day(s) trying to figure out what was happening. */
|
||||
pthread_mutex_t eventsMutex;
|
||||
|
||||
cairo_surface_t* cs;
|
||||
cairo_t* cairo;
|
||||
};
|
||||
|
||||
@@ -29,6 +29,7 @@ struct _MwLLX11 {
|
||||
GC gc;
|
||||
Colormap colormap;
|
||||
Atom wm_delete;
|
||||
Atom wm_protocols;
|
||||
XIM xim;
|
||||
XIC xic;
|
||||
|
||||
|
||||
@@ -71,5 +71,6 @@
|
||||
#define MwNdirectoryChosenHandler "CdirectoryChosen" /* char* */
|
||||
#define MwNcolorChosenHandler "CcolorChosen" /* MwRGB* */
|
||||
#define MwNdrawHandler "Cdraw" /* NULL */
|
||||
#define MwNclipboardHandler "Cclipboard" /* char* */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -39,6 +39,7 @@ typedef void (*MwHandlerChildrenProp)(MwWidget handle, MwWidget child, const cha
|
||||
typedef void (*MwHandlerKey)(MwWidget handle, int key);
|
||||
typedef void (*MwHandlerMouse)(MwWidget handle, void* ptr);
|
||||
typedef void (*MwHandlerExecute)(MwWidget handle, const char* name, void* out, va_list args);
|
||||
typedef void (*MwHandlerClipboardReceived)(MwWidget handle, const char* data);
|
||||
|
||||
typedef void (*MwUserHandler)(MwWidget handle, void* user_data, void* call_data);
|
||||
typedef void (*MwErrorHandler)(int code, const char* message, void* user_data);
|
||||
@@ -196,26 +197,26 @@ struct _MwListBoxPacket {
|
||||
};
|
||||
|
||||
struct _MwClass {
|
||||
MwHandlerWithStatus create;
|
||||
MwHandler destroy;
|
||||
MwHandler draw;
|
||||
MwHandler click;
|
||||
MwHandler parent_resize;
|
||||
MwHandlerProp prop_change;
|
||||
MwHandler mouse_move;
|
||||
MwHandlerMouse mouse_up;
|
||||
MwHandlerMouse mouse_down;
|
||||
MwHandlerKey key;
|
||||
MwHandlerExecute execute;
|
||||
MwHandler tick;
|
||||
MwHandler resize;
|
||||
MwHandler children_update;
|
||||
MwHandlerChildrenProp children_prop_change;
|
||||
void* reserved1;
|
||||
void* reserved2;
|
||||
void* reserved3;
|
||||
void* reserved4;
|
||||
void* reserved5;
|
||||
MwHandlerWithStatus create;
|
||||
MwHandler destroy;
|
||||
MwHandler draw;
|
||||
MwHandler click;
|
||||
MwHandler parent_resize;
|
||||
MwHandlerProp prop_change;
|
||||
MwHandler mouse_move;
|
||||
MwHandlerMouse mouse_up;
|
||||
MwHandlerMouse mouse_down;
|
||||
MwHandlerKey key;
|
||||
MwHandlerExecute execute;
|
||||
MwHandler tick;
|
||||
MwHandler resize;
|
||||
MwHandler children_update;
|
||||
MwHandlerChildrenProp children_prop_change;
|
||||
MwHandlerClipboardReceived clipboard;
|
||||
void* reserved1;
|
||||
void* reserved2;
|
||||
void* reserved3;
|
||||
void* reserved4;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,6 +29,16 @@ MwInline void MwSubMenuAppear(MwWidget handle, MwMenu menu, MwPoint* point, int
|
||||
MwVaWidgetExecute(handle, "mwSubMenuAppear", NULL, menu, point, diff_calc);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Calculates the size of submenu
|
||||
* @param handle Handle
|
||||
* @param menu Menu
|
||||
* @param rect Size
|
||||
*/
|
||||
MwInline void MwSubMenuGetSize(MwWidget handle, MwMenu menu, MwRect* rect) {
|
||||
MwVaWidgetExecute(handle, "mwSubMenuGetSize", NULL, menu, rect);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -122,6 +122,7 @@
|
||||
<handler name="directoryChosen" />
|
||||
<handler name="colorChosen" />
|
||||
<handler name="draw" />
|
||||
<handler name="clipboard" />
|
||||
</properties>
|
||||
<enumerations>
|
||||
<enumeration name="MwDIRECTION">
|
||||
@@ -544,6 +545,7 @@
|
||||
<property name="bold" />
|
||||
<property name="sevenSegment" />
|
||||
<property name="length" />
|
||||
<property name="leftPadding" />
|
||||
</properties>
|
||||
<functions>
|
||||
<function name="SetSevenSegment">
|
||||
@@ -640,6 +642,9 @@
|
||||
</functions>
|
||||
</widget>
|
||||
<widget name="SubMenu">
|
||||
<properties>
|
||||
<property name="leftPadding" />
|
||||
</properties>
|
||||
<functions>
|
||||
<function name="Appear">
|
||||
<arguments>
|
||||
|
||||
@@ -32,6 +32,10 @@ if (grep(/^wayland$/, @backends)) {
|
||||
add_cflags(`pkg-config --cflags cairo wayland-client xkbcommon`);
|
||||
add_libs(`pkg-config --libs cairo wayland-client xkbcommon`);
|
||||
|
||||
if (param_get("opengl")) {
|
||||
add_libs(`pkg-config --libs egl wayland-egl`);
|
||||
}
|
||||
|
||||
scan_wayland_protocol("stable", "xdg-shell", "");
|
||||
scan_wayland_protocol("stable", "tablet", "-v2");
|
||||
scan_wayland_protocol("staging", "xdg-toplevel-icon", "-v1");
|
||||
@@ -39,7 +43,7 @@ if (grep(/^wayland$/, @backends)) {
|
||||
scan_wayland_protocol("unstable", "xdg-decoration", "-unstable-v1");
|
||||
scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1");
|
||||
|
||||
$gl_libs = "-lEGL -lwayland-egl lGL -lGLU";
|
||||
$gl_libs = "-lGL -lGLU";
|
||||
}
|
||||
|
||||
if (param_get("stb-image")) {
|
||||
@@ -48,6 +52,7 @@ if (param_get("stb-image")) {
|
||||
if (param_get("stb-truetype")) {
|
||||
add_cflags("-DUSE_STB_TRUETYPE");
|
||||
}
|
||||
|
||||
if (param_get("freetype2")) {
|
||||
add_cflags("-DUSE_FREETYPE2");
|
||||
if ($cross) {
|
||||
|
||||
@@ -237,12 +237,13 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) {
|
||||
r->common.copy_buffer = 1;
|
||||
r->common.type = MwLLBackendGDI;
|
||||
|
||||
r->gdi.force_render = 0;
|
||||
r->gdi.grabbed = 0;
|
||||
r->gdi.hWnd = CreateWindow("milsko", "Milsko", parent == NULL ? (WS_OVERLAPPEDWINDOW) : (WS_CHILD | WS_VISIBLE), x == MwDEFAULT ? CW_USEDEFAULT : x, y == MwDEFAULT ? CW_USEDEFAULT : y, width, height, parent == NULL ? NULL : parent->gdi.hWnd, 0, wc.hInstance, NULL);
|
||||
r->gdi.hInstance = wc.hInstance;
|
||||
r->gdi.cursor = NULL;
|
||||
r->gdi.icon = NULL;
|
||||
r->gdi.get_clipboard = 1;
|
||||
r->gdi.force_render = 0;
|
||||
r->gdi.grabbed = 0;
|
||||
r->gdi.hWnd = CreateWindow("milsko", "Milsko", parent == NULL ? (WS_OVERLAPPEDWINDOW) : (WS_CHILD | WS_VISIBLE), x == MwDEFAULT ? CW_USEDEFAULT : x, y == MwDEFAULT ? CW_USEDEFAULT : y, width, height, parent == NULL ? NULL : parent->gdi.hWnd, 0, wc.hInstance, NULL);
|
||||
r->gdi.hInstance = wc.hInstance;
|
||||
r->gdi.cursor = NULL;
|
||||
r->gdi.icon = NULL;
|
||||
|
||||
u->ll = r;
|
||||
u->min_set = 0;
|
||||
@@ -383,6 +384,7 @@ static int MwLLPendingImpl(MwLL handle) {
|
||||
|
||||
(void)handle;
|
||||
|
||||
if(handle->gdi.get_clipboard) return 1;
|
||||
return PeekMessage(&msg, handle->gdi.hWnd, 0, 0, PM_NOREMOVE) ? 1 : 0;
|
||||
}
|
||||
|
||||
@@ -391,6 +393,24 @@ static void MwLLNextEventImpl(MwLL handle) {
|
||||
|
||||
(void)handle;
|
||||
|
||||
if(handle->gdi.get_clipboard) {
|
||||
HGLOBAL hg;
|
||||
if(OpenClipboard(handle->gdi.hWnd) != 0 && (hg = GetClipboardData(CF_TEXT)) != NULL) {
|
||||
char* txt = malloc(GlobalSize(hg));
|
||||
char* clp = GlobalLock(hg);
|
||||
|
||||
strcpy(txt, clp);
|
||||
|
||||
GlobalUnlock(hg);
|
||||
CloseClipboard();
|
||||
|
||||
MwLLDispatch(handle, clipboard, txt);
|
||||
|
||||
free(txt);
|
||||
}
|
||||
|
||||
handle->gdi.get_clipboard = 0;
|
||||
}
|
||||
while(PeekMessage(&msg, handle->gdi.hWnd, 0, 0, PM_NOREMOVE)) {
|
||||
GetMessage(&msg, handle->gdi.hWnd, 0, 0);
|
||||
TranslateMessage(&msg);
|
||||
@@ -697,21 +717,8 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text) {
|
||||
}
|
||||
}
|
||||
|
||||
static char* MwLLGetClipboardImpl(MwLL handle) {
|
||||
HGLOBAL hg;
|
||||
char* r = NULL;
|
||||
if(OpenClipboard(handle->gdi.hWnd) != 0 && (hg = GetClipboardData(CF_TEXT)) != NULL) {
|
||||
char* lock;
|
||||
|
||||
r = malloc(GlobalSize(hg));
|
||||
|
||||
lock = GlobalLock(hg);
|
||||
strcpy(r, lock);
|
||||
GlobalUnlock(hg);
|
||||
|
||||
CloseClipboard();
|
||||
}
|
||||
return r;
|
||||
static void MwLLGetClipboardImpl(MwLL handle) {
|
||||
handle->gdi.get_clipboard = 1; /* nishi: we do this to make clipboard api work similar to other backends */
|
||||
}
|
||||
|
||||
static void MwLLMakeToolWindowImpl(MwLL handle) {
|
||||
|
||||
@@ -10,11 +10,9 @@
|
||||
#include <unistd.h>
|
||||
|
||||
/* TODO:
|
||||
* - MwLLSetClipboardImpl
|
||||
* - MwLLGrabPointerImpl
|
||||
* - MwLLMakePopupImpl
|
||||
* - MwLLShowImpl
|
||||
* - MwLLDetachImpl
|
||||
*/
|
||||
|
||||
/* TODO: find out what FreeBSD and such wants us to include */
|
||||
@@ -47,7 +45,7 @@ static void new_protocol(void* data, struct wl_registry* registry,
|
||||
|
||||
wayland_protocol_callback_table_t* cb = shget(wayland->wl_protocol_setup_map, interface);
|
||||
if(cb != NULL) {
|
||||
char* inter = malloc(strlen(interface));
|
||||
char* inter = malloc(strlen(interface) + 1);
|
||||
strcpy(inter, interface);
|
||||
shput(wayland->wl_protocol_map, inter, cb->setup(name, data));
|
||||
} else {
|
||||
@@ -62,78 +60,278 @@ static void protocol_removed(void* data,
|
||||
printf("%d destroyed\n", name);
|
||||
};
|
||||
|
||||
static void offer_offer(void* data,
|
||||
struct zwp_primary_selection_offer_v1* zwp_primary_selection_offer_v1,
|
||||
const char* mime_type) {
|
||||
/* Flush Wayland events */
|
||||
static void wl_flush(MwLL handle) {
|
||||
struct pollfd pfd;
|
||||
int rc;
|
||||
|
||||
pfd.fd = wl_display_get_fd(handle->wayland.display);
|
||||
pfd.events = POLLIN;
|
||||
while(MwTRUE) {
|
||||
rc = wl_display_flush(handle->wayland.display);
|
||||
if(errno != EAGAIN || rc != -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(poll(&pfd, 1, -1) == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_offer(void* data,
|
||||
struct wl_data_offer* wl_data_offer,
|
||||
const char* mime_type) {
|
||||
wl_clipboard_device_context_t* self = data;
|
||||
wl_data_offer_accept(wl_data_offer, self->ll->wayland.clipboard_serial, mime_type);
|
||||
};
|
||||
|
||||
struct zwp_primary_selection_offer_v1_listener offer_listener = {
|
||||
.offer = offer_offer,
|
||||
struct wl_data_offer_listener offer_listener = {
|
||||
.offer = wl_offer,
|
||||
};
|
||||
|
||||
typedef struct primary_selection_device_context {
|
||||
struct zwp_primary_selection_device_v1* device;
|
||||
struct zwp_primary_selection_offer_v1* offer;
|
||||
} primary_selection_device_context_t;
|
||||
static void wl_data_device_data_offer(void* data,
|
||||
struct wl_data_device* wl_data_device,
|
||||
struct wl_data_offer* offer) {
|
||||
wl_clipboard_device_context_t* self = data;
|
||||
|
||||
typedef struct primary_selection_context {
|
||||
struct zwp_primary_selection_device_manager_v1* manager;
|
||||
/* stored seperately of the listeners because it's not a pointer and it gets assigned to data devices dynamically. */
|
||||
struct zwp_primary_selection_device_v1_listener listener;
|
||||
wl_data_offer_add_listener(offer, &offer_listener, data);
|
||||
|
||||
struct zwp_primary_selection_source_v1* source;
|
||||
primary_selection_device_context_t** devices;
|
||||
} primary_selection_context_t;
|
||||
|
||||
static void primary_selection_data_offer(void* data,
|
||||
struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1,
|
||||
struct zwp_primary_selection_offer_v1* offer) {
|
||||
struct primary_selection_device_context* self = data;
|
||||
zwp_primary_selection_offer_v1_add_listener(offer, &offer_listener, data);
|
||||
|
||||
self->offer = offer;
|
||||
self->offer.wl = offer;
|
||||
};
|
||||
static void primary_selection_selection(void* data,
|
||||
struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1,
|
||||
struct zwp_primary_selection_offer_v1* id) {
|
||||
|
||||
static void wl_data_device_enter(void* data,
|
||||
struct wl_data_device* wl_data_device,
|
||||
uint32_t serial,
|
||||
struct wl_surface* surface,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y,
|
||||
struct wl_data_offer* id) {
|
||||
MwLL self = data;
|
||||
self->wayland.clipboard_serial = serial;
|
||||
};
|
||||
static void wl_data_device_leave(void* data,
|
||||
struct wl_data_device* wl_data_device) {
|
||||
wl_data_device_destroy(wl_data_device);
|
||||
};
|
||||
static void wl_data_device_motion(void* data,
|
||||
struct wl_data_device* wl_data_device,
|
||||
uint32_t time,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y) {
|
||||
};
|
||||
static void wl_data_device_drop(void* data,
|
||||
struct wl_data_device* wl_data_device) {
|
||||
};
|
||||
|
||||
static void wl_data_device_selection(void* data,
|
||||
struct wl_data_device* wl_data_device,
|
||||
struct wl_data_offer* id) {
|
||||
};
|
||||
|
||||
struct wl_data_device_listener wl_data_device_listener = {
|
||||
.data_offer = wl_data_device_data_offer,
|
||||
.enter = wl_data_device_enter,
|
||||
.leave = wl_data_device_leave,
|
||||
.motion = wl_data_device_motion,
|
||||
.drop = wl_data_device_drop,
|
||||
.selection = wl_data_device_selection,
|
||||
};
|
||||
|
||||
static void zwp_primary_selection_device_v1_data_offer(void* data,
|
||||
struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1,
|
||||
struct zwp_primary_selection_offer_v1* offer) {
|
||||
wl_clipboard_device_context_t* self = data;
|
||||
|
||||
self->offer.zwp = offer;
|
||||
};
|
||||
|
||||
static void zwp_primary_selection_device_v1_selection(void* data,
|
||||
struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1,
|
||||
struct zwp_primary_selection_offer_v1* id) {
|
||||
};
|
||||
|
||||
struct zwp_primary_selection_device_v1_listener zwp_primary_selection_device_v1_listener = {
|
||||
.data_offer = zwp_primary_selection_device_v1_data_offer,
|
||||
.selection = zwp_primary_selection_device_v1_selection,
|
||||
};
|
||||
|
||||
static void wl_clipboard_read(wl_clipboard_device_context_t* ctx) {
|
||||
int fds[2];
|
||||
fd_set set;
|
||||
char* buf = NULL;
|
||||
struct timeval timeout;
|
||||
int rc = 0;
|
||||
int n;
|
||||
|
||||
if(pipe(fds) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
FD_ZERO(&set);
|
||||
FD_SET(fds[0], &set);
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 100;
|
||||
|
||||
if(ctx->ll->wayland.supports_zwp) {
|
||||
zwp_primary_selection_offer_v1_receive(ctx->offer.zwp, "text/plain", fds[1]);
|
||||
} else {
|
||||
wl_data_offer_receive(ctx->offer.wl, "text/plain", fds[1]);
|
||||
}
|
||||
close(fds[1]);
|
||||
|
||||
wl_flush(ctx->ll);
|
||||
wl_display_roundtrip(ctx->ll->wayland.display);
|
||||
|
||||
while(MwTRUE) {
|
||||
char ch;
|
||||
rc = select(fds[0] + 1, &set, NULL, NULL, &timeout);
|
||||
if(rc <= 0) {
|
||||
break;
|
||||
} else {
|
||||
char b;
|
||||
ssize_t n = read(fds[0], &b, sizeof(b));
|
||||
if(n <= 0) {
|
||||
break;
|
||||
}
|
||||
arrpush(buf, b);
|
||||
}
|
||||
}
|
||||
arrpush(buf, 0);
|
||||
close(fds[0]);
|
||||
|
||||
MwLLDispatch(ctx->ll, clipboard, buf);
|
||||
arrfree(buf);
|
||||
}
|
||||
|
||||
static void wl_data_source_listener_target(void* data,
|
||||
struct wl_data_source* wl_data_source,
|
||||
const char* mime_type) {
|
||||
};
|
||||
static void wl_data_source_listener_send(void* data,
|
||||
struct wl_data_source* wl_data_source,
|
||||
const char* mime_type,
|
||||
int32_t fd) {
|
||||
MwLL self = data;
|
||||
if(self->wayland.clipboard_buffer != NULL) {
|
||||
write(fd, self->wayland.clipboard_buffer, strlen(self->wayland.clipboard_buffer));
|
||||
close(fd);
|
||||
|
||||
self->wayland.events_pending = 1;
|
||||
}
|
||||
};
|
||||
static void wl_data_source_listener_cancelled(void* data,
|
||||
struct wl_data_source* wl_data_source);
|
||||
|
||||
struct wl_data_source_listener wl_data_source_listener = {
|
||||
.target = wl_data_source_listener_target,
|
||||
.send = wl_data_source_listener_send,
|
||||
.cancelled = wl_data_source_listener_cancelled,
|
||||
};
|
||||
|
||||
static void wl_data_source_listener_cancelled(void* data,
|
||||
struct wl_data_source* wl_data_source) {
|
||||
MwLL self = data;
|
||||
|
||||
wl_data_source_destroy(wl_data_source);
|
||||
|
||||
self->wayland.clipboard_source.wl = wl_data_device_manager_create_data_source(self->wayland.clipboard_manager.wl);
|
||||
|
||||
wl_data_source_offer(self->wayland.clipboard_source.wl, "text/plain");
|
||||
wl_data_source_offer(self->wayland.clipboard_source.wl, "text/plain;charset=utf-8");
|
||||
wl_data_source_offer(self->wayland.clipboard_source.wl, "TEXT");
|
||||
wl_data_source_offer(self->wayland.clipboard_source.wl, "STRING");
|
||||
wl_data_source_offer(self->wayland.clipboard_source.wl, "UTF8_STRING");
|
||||
|
||||
wl_data_source_add_listener(self->wayland.clipboard_source.wl, &wl_data_source_listener, self);
|
||||
};
|
||||
|
||||
static void zwp_primary_selection_source_v1_send(void* data,
|
||||
struct zwp_primary_selection_source_v1* wl_data_source,
|
||||
const char* mime_type,
|
||||
int32_t fd) {
|
||||
MwLL self = data;
|
||||
if(self->wayland.clipboard_buffer != NULL) {
|
||||
write(fd, self->wayland.clipboard_buffer, strlen(self->wayland.clipboard_buffer));
|
||||
close(fd);
|
||||
|
||||
self->wayland.events_pending = 1;
|
||||
}
|
||||
};
|
||||
static void zwp_primary_selection_source_v1_cancelled(void* data,
|
||||
struct zwp_primary_selection_source_v1* wl_data_source) {
|
||||
MwLL self = data;
|
||||
|
||||
zwp_primary_selection_source_v1_destroy(self->wayland.clipboard_source.zwp);
|
||||
|
||||
self->wayland.clipboard_source.zwp = zwp_primary_selection_device_manager_v1_create_source(self->wayland.clipboard_manager.zwp);
|
||||
|
||||
zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "text/plain");
|
||||
zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "text/plain;charset=utf-8");
|
||||
zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "TEXT");
|
||||
zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "STRING");
|
||||
zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "UTF8_STRING");
|
||||
};
|
||||
|
||||
struct zwp_primary_selection_source_v1_listener zwp_primary_selection_source_v1_listener = {
|
||||
.send = zwp_primary_selection_source_v1_send,
|
||||
.cancelled = zwp_primary_selection_source_v1_cancelled,
|
||||
};
|
||||
|
||||
/* wl_data_device_manager setup function */
|
||||
static wayland_protocol_t* wl_data_device_manager_setup(MwU32 name, struct _MwLLWayland* wayland) {
|
||||
wayland->clipboard_manager.wl = wl_registry_bind(wayland->registry, name, &wl_data_device_manager_interface, 2);
|
||||
|
||||
wayland->clipboard_source.wl = wl_data_device_manager_create_data_source(wayland->clipboard_manager.wl);
|
||||
|
||||
wl_data_source_offer(wayland->clipboard_source.wl, "text/plain");
|
||||
wl_data_source_offer(wayland->clipboard_source.wl, "text/plain;charset=utf-8");
|
||||
wl_data_source_offer(wayland->clipboard_source.wl, "TEXT");
|
||||
wl_data_source_offer(wayland->clipboard_source.wl, "STRING");
|
||||
wl_data_source_offer(wayland->clipboard_source.wl, "UTF8_STRING");
|
||||
|
||||
wl_data_source_add_listener(wayland->clipboard_source.wl, &wl_data_source_listener, wayland);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void wl_data_device_manager_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) {
|
||||
if(wayland->clipboard_manager.wl != NULL && !wayland->supports_zwp) {
|
||||
wl_data_device_manager_destroy(wayland->clipboard_manager.wl);
|
||||
wl_data_source_destroy(wayland->clipboard_source.wl);
|
||||
wayland->clipboard_manager.wl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* zwp_primary_selection_device_manager_v1 setup function */
|
||||
static wayland_protocol_t* zwp_primary_selection_device_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) {
|
||||
wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t));
|
||||
primary_selection_context_t* context = malloc(sizeof(primary_selection_context_t));
|
||||
if(wayland->clipboard_manager.wl != NULL) {
|
||||
wl_data_device_manager_interface_destroy(wayland, NULL);
|
||||
}
|
||||
|
||||
context->manager = wl_registry_bind(wayland->registry, name, &zwp_primary_selection_device_manager_v1_interface, 1);
|
||||
wayland->clipboard_manager.zwp = wl_registry_bind(wayland->registry, name, &zwp_primary_selection_device_manager_v1_interface, 1);
|
||||
|
||||
struct zwp_primary_selection_device_manager_v1* device;
|
||||
context->listener.data_offer = primary_selection_data_offer;
|
||||
context->listener.selection = primary_selection_selection;
|
||||
wayland->clipboard_source.zwp = zwp_primary_selection_device_manager_v1_create_source(wayland->clipboard_manager.zwp);
|
||||
|
||||
context->source = zwp_primary_selection_device_manager_v1_create_source(context->manager);
|
||||
zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "text/plain");
|
||||
zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "text/plain;charset=utf-8");
|
||||
zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "TEXT");
|
||||
zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "STRING");
|
||||
zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "UTF8_STRING");
|
||||
|
||||
context->devices = NULL;
|
||||
zwp_primary_selection_source_v1_add_listener(wayland->clipboard_source.zwp, &zwp_primary_selection_source_v1_listener, wayland);
|
||||
|
||||
proto->context = context;
|
||||
proto->listener = NULL;
|
||||
wayland->supports_zwp = MwTRUE;
|
||||
|
||||
return proto;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void zwp_primary_selection_device_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) {
|
||||
primary_selection_context_t* context = data->context;
|
||||
int i;
|
||||
return;
|
||||
|
||||
zwp_primary_selection_device_manager_v1_destroy(context->manager);
|
||||
zwp_primary_selection_device_manager_v1_destroy(wayland->clipboard_manager.zwp);
|
||||
|
||||
for(i = 0; i < arrlen(context->devices); i++) {
|
||||
primary_selection_device_context_t* device = context->devices[i];
|
||||
// zwp_primary_selection_device_v1_destroy(device->device);
|
||||
// zwp_primary_selection_offer_v1_destroy(device->offer);
|
||||
free(device);
|
||||
}
|
||||
arrfree(context->devices);
|
||||
|
||||
zwp_primary_selection_source_v1_destroy(context->source);
|
||||
zwp_primary_selection_source_v1_destroy(wayland->clipboard_source.zwp);
|
||||
|
||||
free(data->listener);
|
||||
}
|
||||
@@ -142,10 +340,18 @@ static void zwp_primary_selection_device_manager_v1_interface_destroy(struct _Mw
|
||||
static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial,
|
||||
struct wl_surface* surface, wl_fixed_t surface_x,
|
||||
wl_fixed_t surface_y) {
|
||||
MwLL self = data;
|
||||
MwLL self = data;
|
||||
struct timespec t;
|
||||
t.tv_nsec = 100;
|
||||
|
||||
if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) {
|
||||
return;
|
||||
};
|
||||
self->wayland.pointer_serial = serial;
|
||||
|
||||
wl_pointer_set_cursor(wl_pointer, serial, self->wayland.cursor.surface, 0, 0);
|
||||
|
||||
pthread_mutex_unlock(&self->wayland.eventsMutex);
|
||||
};
|
||||
|
||||
/* `wl_pointer.leave` callback */
|
||||
@@ -159,20 +365,35 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time
|
||||
MwLL self = data;
|
||||
MwLLMouse p;
|
||||
|
||||
struct timespec t;
|
||||
t.tv_nsec = 100;
|
||||
|
||||
if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) {
|
||||
return;
|
||||
};
|
||||
self->wayland.cur_mouse_pos.x = wl_fixed_to_double(surface_x);
|
||||
self->wayland.cur_mouse_pos.y = wl_fixed_to_double(surface_y);
|
||||
|
||||
p.point = self->wayland.cur_mouse_pos;
|
||||
MwLLDispatch(self, move, &p);
|
||||
self->wayland.events_pending = MwTRUE;
|
||||
|
||||
self->wayland.events_pending += 1;
|
||||
pthread_mutex_unlock(&self->wayland.eventsMutex);
|
||||
|
||||
/*timed_redraw(self, time, 50, &self->wayland.cooldown_timer);*/
|
||||
};
|
||||
|
||||
/* `wl_pointer.button` callback */
|
||||
static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 serial, MwU32 time, MwU32 button, MwU32 state) {
|
||||
MwLL self = data;
|
||||
MwLLMouse p;
|
||||
MwLL self = data;
|
||||
MwLLMouse p;
|
||||
struct timespec t;
|
||||
t.tv_nsec = 100;
|
||||
|
||||
if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) {
|
||||
return;
|
||||
};
|
||||
|
||||
p.point = self->wayland.cur_mouse_pos;
|
||||
if(p.point.x > self->wayland.x && p.point.x < self->wayland.x + self->wayland.ww && p.point.y > self->wayland.y && p.point.y < self->wayland.y + self->wayland.wh) {
|
||||
switch(button) {
|
||||
@@ -181,6 +402,10 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri
|
||||
break;
|
||||
case BTN_MIDDLE:
|
||||
p.button = MwLLMouseMiddle;
|
||||
for(int i = 0; i < arrlen(self->wayland.clipboard_devices); i++) {
|
||||
wl_clipboard_read(
|
||||
self->wayland.clipboard_devices[i]);
|
||||
}
|
||||
break;
|
||||
case BTN_RIGHT:
|
||||
p.button = MwLLMouseRight;
|
||||
@@ -196,8 +421,11 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri
|
||||
}
|
||||
}
|
||||
|
||||
MwLLDispatch(self, draw, NULL);
|
||||
self->wayland.events_pending = MwTRUE;
|
||||
if(!self->wayland.always_render) {
|
||||
MwLLDispatch(self, draw, NULL);
|
||||
self->wayland.events_pending += 1;
|
||||
}
|
||||
pthread_mutex_unlock(&self->wayland.eventsMutex);
|
||||
};
|
||||
|
||||
/* `wl_pointer.axis` callback */
|
||||
@@ -233,8 +461,6 @@ static void keyboard_keymap(void* data,
|
||||
close(fd);
|
||||
|
||||
struct xkb_state* xkb_state = xkb_state_new(xkb_keymap);
|
||||
xkb_keymap_unref(wayland->xkb_keymap);
|
||||
xkb_state_unref(wayland->xkb_state);
|
||||
|
||||
wayland->xkb_keymap = xkb_keymap;
|
||||
wayland->xkb_state = xkb_state;
|
||||
@@ -247,9 +473,19 @@ static void keyboard_enter(void* data,
|
||||
MwU32 serial,
|
||||
struct wl_surface* surface,
|
||||
struct wl_array* keys) {
|
||||
MwLL self = data;
|
||||
MwLL self = data;
|
||||
struct timespec t;
|
||||
t.tv_nsec = 100;
|
||||
|
||||
if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) {
|
||||
return;
|
||||
};
|
||||
|
||||
self->wayland.keyboard_serial = serial;
|
||||
|
||||
MwLLDispatch(self, focus_in, NULL);
|
||||
self->wayland.events_pending = MwTRUE;
|
||||
self->wayland.events_pending += 1;
|
||||
pthread_mutex_unlock(&self->wayland.eventsMutex);
|
||||
};
|
||||
|
||||
/* `wl_keyboard.leave` callback */
|
||||
@@ -257,9 +493,18 @@ static void keyboard_leave(void* data,
|
||||
struct wl_keyboard* wl_keyboard,
|
||||
MwU32 serial,
|
||||
struct wl_surface* surface) {
|
||||
MwLL self = data;
|
||||
MwLL self = data;
|
||||
struct timespec t;
|
||||
t.tv_nsec = 100;
|
||||
|
||||
if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) {
|
||||
return;
|
||||
};
|
||||
|
||||
MwLLDispatch(self, focus_out, NULL);
|
||||
self->wayland.events_pending = MwTRUE;
|
||||
self->wayland.events_pending += 1;
|
||||
|
||||
pthread_mutex_unlock(&self->wayland.eventsMutex);
|
||||
};
|
||||
|
||||
/* `wl_keyboard.key` callback */
|
||||
@@ -269,7 +514,13 @@ static void keyboard_key(void* data,
|
||||
MwU32 time,
|
||||
MwU32 key,
|
||||
MwU32 state) {
|
||||
MwLL self = data;
|
||||
MwLL self = data;
|
||||
struct timespec t;
|
||||
t.tv_nsec = 100;
|
||||
|
||||
if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) {
|
||||
return;
|
||||
};
|
||||
if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL) {
|
||||
struct _MwLLWaylandTopLevel* wayland = self->wayland.toplevel;
|
||||
xkb_layout_index_t layout;
|
||||
@@ -334,11 +585,19 @@ static void keyboard_key(void* data,
|
||||
key = sym;
|
||||
}
|
||||
if((self->wayland.mod_state & 4) == 4) {
|
||||
/* clipboard paste */
|
||||
if(key == 'V') {
|
||||
for(int 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) {
|
||||
key |= MwLLAltMask;
|
||||
}
|
||||
|
||||
if(state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
MwLLDispatch(self, key, &key);
|
||||
} else {
|
||||
@@ -346,7 +605,13 @@ static void keyboard_key(void* data,
|
||||
}
|
||||
}
|
||||
}
|
||||
self->wayland.events_pending = MwTRUE;
|
||||
|
||||
if(!self->wayland.always_render) {
|
||||
MwLLDispatch(self, draw, NULL);
|
||||
self->wayland.events_pending += 1;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&self->wayland.eventsMutex);
|
||||
};
|
||||
|
||||
/* `wl_keyboard.modifiers` callback */
|
||||
@@ -357,11 +622,19 @@ static void keyboard_modifiers(void* data,
|
||||
MwU32 mods_latched,
|
||||
MwU32 mods_locked,
|
||||
MwU32 group) {
|
||||
MwLL self = data;
|
||||
MwLL self = data;
|
||||
struct timespec t;
|
||||
t.tv_nsec = 100;
|
||||
|
||||
if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) {
|
||||
return;
|
||||
};
|
||||
|
||||
self->wayland.mod_state = 0;
|
||||
self->wayland.mod_state |= mods_depressed;
|
||||
self->wayland.mod_state |= mods_locked;
|
||||
|
||||
pthread_mutex_unlock(&self->wayland.eventsMutex);
|
||||
};
|
||||
|
||||
struct wl_keyboard_listener keyboard_listener = {
|
||||
@@ -379,7 +652,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;
|
||||
MwLL self = data;
|
||||
wl_clipboard_device_context_t* device_ctx = malloc(sizeof(wl_clipboard_device_context_t));
|
||||
|
||||
if(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
|
||||
self->wayland.keyboard = wl_seat_get_keyboard(wl_seat);
|
||||
wl_keyboard_add_listener(self->wayland.keyboard, &keyboard_listener, data);
|
||||
@@ -389,19 +664,23 @@ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat,
|
||||
wl_pointer_add_listener(self->wayland.pointer, &pointer_listener, data);
|
||||
}
|
||||
|
||||
/* primary selection support */
|
||||
if(WAYLAND_GET_INTERFACE(self->wayland, zwp_primary_selection_device_manager_v1) != NULL) {
|
||||
primary_selection_context_t* primary_selection = WAYLAND_GET_INTERFACE(self->wayland, zwp_primary_selection_device_manager_v1)->context;
|
||||
primary_selection_device_context_t* device_ctx = malloc(sizeof(primary_selection_device_context_t));
|
||||
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->ll = self;
|
||||
device_ctx->seat = wl_seat;
|
||||
device_ctx->capabilities = capabilities;
|
||||
|
||||
device_ctx->device =
|
||||
zwp_primary_selection_device_manager_v1_get_device(primary_selection->manager, wl_seat);
|
||||
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->device, &primary_selection->listener, device_ctx);
|
||||
|
||||
device_ctx->offer = NULL;
|
||||
|
||||
arrpush(primary_selection->devices, device_ctx);
|
||||
arrpush(self->wayland.clipboard_devices, device_ctx);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -466,7 +745,6 @@ static wayland_protocol_t* wl_output_setup(MwU32 name, MwLL ll) {
|
||||
}
|
||||
|
||||
static void wl_output_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) {
|
||||
// wl_output_destroy(wayland->output);
|
||||
}
|
||||
|
||||
/* wl_compositor setup function */
|
||||
@@ -477,7 +755,6 @@ static wayland_protocol_t* wl_compositor_setup(MwU32 name, struct _MwLLWayland*
|
||||
}
|
||||
|
||||
static void wl_compositor_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) {
|
||||
// wl_compositor_destroy(wayland->compositor);
|
||||
}
|
||||
|
||||
/* wl_subcompositor setup function */
|
||||
@@ -544,6 +821,11 @@ static void xdg_toplevel_configure(void* data,
|
||||
MwLL self = data;
|
||||
int i;
|
||||
|
||||
/* Yes, somehow this can get called before */
|
||||
if(!self->wayland.configured) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(width == 0 || height == 0) {
|
||||
width = self->wayland.ww;
|
||||
height = self->wayland.wh;
|
||||
@@ -565,6 +847,8 @@ static void xdg_toplevel_configure(void* data,
|
||||
MwLLDispatch(self, resize, NULL);
|
||||
MwLLDispatch(self, draw, NULL);
|
||||
|
||||
MwLLForceRender(self);
|
||||
|
||||
/*if(!self->wayland.egl_setup) {
|
||||
self->wayland.egl_setup = egl_setup(self, self->wayland.x, self->wayland.y, width, height);
|
||||
} else {
|
||||
@@ -612,7 +896,6 @@ static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland
|
||||
}
|
||||
|
||||
static void wl_shm_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) {
|
||||
// buffer_destroy(&wayland->framebuffer);
|
||||
}
|
||||
|
||||
static void update_buffer(struct _MwLLWaylandShmBuffer* buffer) {
|
||||
@@ -674,7 +957,8 @@ static void framebuffer_setup(struct _MwLLWayland* wayland) {
|
||||
|
||||
memset(wayland->framebuffer.buf, 255, wayland->framebuffer.buf_size);
|
||||
update_buffer(&wayland->framebuffer);
|
||||
wayland->events_pending = MwTRUE;
|
||||
|
||||
wayland->events_pending += 1;
|
||||
};
|
||||
static void framebuffer_destroy(struct _MwLLWayland* wayland) {
|
||||
buffer_destroy(&wayland->framebuffer);
|
||||
@@ -711,25 +995,6 @@ static void xdg_toplevel_icon_manager_v1_interface_destroy(struct _MwLLWayland*
|
||||
xdg_toplevel_icon_manager_v1_destroy(data->context);
|
||||
}
|
||||
|
||||
/* Flush Wayland events */
|
||||
static void wl_flush(MwLL handle) {
|
||||
struct pollfd pfd;
|
||||
int rc;
|
||||
|
||||
pfd.fd = wl_display_get_fd(handle->wayland.display);
|
||||
pfd.events = POLLIN;
|
||||
while(MwTRUE) {
|
||||
rc = wl_display_flush(handle->wayland.display);
|
||||
if(errno != EAGAIN || rc != -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(poll(&pfd, 1, -1) == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Standard Wayland event loop. */
|
||||
static int event_loop(MwLL handle) {
|
||||
struct pollfd fd;
|
||||
@@ -803,6 +1068,7 @@ static void setup_callbacks(struct _MwLLWayland* wayland) {
|
||||
WL_INTERFACE(wl_compositor);
|
||||
WL_INTERFACE(wl_seat);
|
||||
WL_INTERFACE(wl_output);
|
||||
WL_INTERFACE(wl_data_device_manager);
|
||||
WL_INTERFACE(zwp_primary_selection_device_manager_v1);
|
||||
if(wayland->type == MWLL_WAYLAND_TOPLEVEL) {
|
||||
WL_INTERFACE(xdg_wm_base);
|
||||
@@ -869,6 +1135,8 @@ static void setup_toplevel(MwLL r, int x, int y) {
|
||||
/* Perform the initial commit and wait for the first configure event */
|
||||
wl_surface_commit(r->wayland.framebuffer.surface);
|
||||
event_loop(r);
|
||||
while(!r->wayland.configured) {
|
||||
}
|
||||
|
||||
/* setup decorations if we can */
|
||||
if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) {
|
||||
@@ -893,6 +1161,8 @@ static void destroy_toplevel(MwLL r) {
|
||||
zxdg_decoration_manager_v1_destroy(dec->manager);
|
||||
}
|
||||
|
||||
wl_surface_destroy(r->wayland.framebuffer.surface);
|
||||
|
||||
wl_compositor_destroy(r->wayland.compositor);
|
||||
|
||||
xdg_surface_destroy(r->wayland.toplevel->xdg_surface);
|
||||
@@ -924,12 +1194,8 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) {
|
||||
|
||||
r->wayland.display = parent->wayland.display;
|
||||
|
||||
r->wayland.framebuffer.surface = wl_compositor_create_surface(compositor);
|
||||
|
||||
setup_callbacks(&r->wayland);
|
||||
|
||||
// printf("position %d %d\n", x, y);
|
||||
|
||||
r->wayland.registry = wl_display_get_registry(parent->wayland.display);
|
||||
r->wayland.display = parent->wayland.display;
|
||||
|
||||
@@ -940,6 +1206,8 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) {
|
||||
return;
|
||||
}
|
||||
|
||||
r->wayland.framebuffer.surface = wl_compositor_create_surface(compositor);
|
||||
|
||||
r->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(r->wayland.sublevel->subcompositor, r->wayland.framebuffer.surface, parent_surface);
|
||||
|
||||
wl_subsurface_set_position(r->wayland.sublevel->subsurface, x, y);
|
||||
@@ -985,11 +1253,14 @@ static void setup_popup(MwLL r) {
|
||||
struct xdg_surface* xdg_surface;
|
||||
MwLL topmost_parent = r->wayland.parent;
|
||||
|
||||
r->wayland.type = MWLL_WAYLAND_POPUP;
|
||||
|
||||
while(topmost_parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) {
|
||||
topmost_parent = topmost_parent->wayland.parent;
|
||||
}
|
||||
|
||||
r->wayland.type = MWLL_WAYLAND_POPUP;
|
||||
r->wayland.popup = malloc(sizeof(struct _MwLLWaylandPopup));
|
||||
memset(r->wayland.popup, 0, sizeof(struct _MwLLWaylandPopup));
|
||||
|
||||
setup_callbacks(&r->wayland);
|
||||
|
||||
@@ -1002,11 +1273,6 @@ static void setup_popup(MwLL r) {
|
||||
return;
|
||||
}
|
||||
|
||||
r->wayland.popup = calloc(sizeof(struct _MwLLWaylandPopup), 0);
|
||||
// r->wayland.popup->parent = parent;
|
||||
|
||||
r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor);
|
||||
|
||||
r->wayland.popup->xdg_wm_base = WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context;
|
||||
|
||||
r->wayland.popup->xdg_positioner = xdg_wm_base_create_positioner(r->wayland.popup->xdg_wm_base);
|
||||
@@ -1020,6 +1286,8 @@ static void setup_popup(MwLL r) {
|
||||
|
||||
xdg_surface = topmost_parent->wayland.toplevel->xdg_surface;
|
||||
|
||||
r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor);
|
||||
|
||||
r->wayland.popup->xdg_surface =
|
||||
xdg_wm_base_get_xdg_surface(r->wayland.popup->xdg_wm_base, r->wayland.framebuffer.surface);
|
||||
|
||||
@@ -1038,6 +1306,7 @@ static void setup_popup(MwLL r) {
|
||||
wl_surface_commit(r->wayland.framebuffer.surface);
|
||||
event_loop(r);
|
||||
}
|
||||
|
||||
/* Popup destroy function */
|
||||
static void destroy_popup(MwLL r) {
|
||||
xdg_popup_destroy(r->wayland.popup->xdg_popup);
|
||||
@@ -1048,8 +1317,6 @@ static void destroy_popup(MwLL r) {
|
||||
|
||||
wl_surface_destroy(r->wayland.framebuffer.surface);
|
||||
|
||||
// free(r->wayland.popup);
|
||||
|
||||
wl_registry_destroy(r->wayland.registry);
|
||||
}
|
||||
|
||||
@@ -1094,24 +1361,25 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) {
|
||||
}
|
||||
|
||||
static void MwLLDestroyImpl(MwLL handle) {
|
||||
int i;
|
||||
int i;
|
||||
struct timeval tv;
|
||||
int select_ret;
|
||||
|
||||
event_loop(handle);
|
||||
pthread_mutex_lock(&handle->wayland.eventsMutex);
|
||||
|
||||
MwLLDestroyCommon(handle);
|
||||
|
||||
buffer_destroy(&handle->wayland.framebuffer);
|
||||
event_loop(handle);
|
||||
|
||||
framebuffer_destroy(&handle->wayland);
|
||||
buffer_destroy(&handle->wayland.cursor);
|
||||
wl_region_destroy(handle->wayland.region);
|
||||
|
||||
if(WAYLAND_GET_INTERFACE(handle->wayland, zwp_primary_selection_device_manager_v1) != NULL) {
|
||||
primary_selection_context_t* primary_selection = WAYLAND_GET_INTERFACE(handle->wayland, zwp_primary_selection_device_manager_v1)->context;
|
||||
|
||||
for(i = 0; i < arrlen(primary_selection->devices); i++) {
|
||||
zwp_primary_selection_offer_v1_destroy(primary_selection->devices[i]->offer);
|
||||
}
|
||||
if(handle->wayland.supports_zwp) {
|
||||
zwp_primary_selection_source_v1_destroy(handle->wayland.clipboard_source.zwp);
|
||||
} 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);
|
||||
@@ -1129,6 +1397,7 @@ static void MwLLDestroyImpl(MwLL handle) {
|
||||
void* ctx = shget(handle->wayland.wl_protocol_map, handle->wayland.wl_protocol_setup_map[i].key);
|
||||
|
||||
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);
|
||||
}
|
||||
shfree(handle->wayland.wl_protocol_map);
|
||||
shfree(handle->wayland.wl_protocol_setup_map);
|
||||
@@ -1140,6 +1409,16 @@ static void MwLLDestroyImpl(MwLL handle) {
|
||||
wl_keyboard_destroy(handle->wayland.keyboard);
|
||||
}
|
||||
|
||||
/* sleep long enough that any active attempts to wait for the mutex will have given up and we can safely unlock/destroy it */
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 250;
|
||||
do {
|
||||
select_ret = select(1, NULL, NULL, NULL, &tv);
|
||||
} while((select_ret == -1) && (errno == EINTR));
|
||||
|
||||
pthread_mutex_unlock(&handle->wayland.eventsMutex);
|
||||
pthread_mutex_destroy(&handle->wayland.eventsMutex);
|
||||
|
||||
free(handle);
|
||||
}
|
||||
|
||||
@@ -1151,7 +1430,7 @@ static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsign
|
||||
}
|
||||
|
||||
static void MwLLSetXYImpl(MwLL handle, int x, int y) {
|
||||
if(handle->wayland.type != MWLL_WAYLAND_TOPLEVEL) {
|
||||
if(handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) {
|
||||
region_invalidate(handle);
|
||||
handle->wayland.x = x;
|
||||
handle->wayland.y = y;
|
||||
@@ -1164,6 +1443,7 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) {
|
||||
|
||||
static void MwLLSetWHImpl(MwLL handle, int w, int h) {
|
||||
region_invalidate(handle);
|
||||
|
||||
/* Prevent an integer underflow when the w/h is too low */
|
||||
if((w < 10 || h < 10)) {
|
||||
handle->wayland.ww = 10;
|
||||
@@ -1173,7 +1453,7 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) {
|
||||
handle->wayland.ww = w;
|
||||
handle->wayland.wh = h;
|
||||
|
||||
if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) {
|
||||
if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL && handle->wayland.configured) {
|
||||
xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, 0, 0, handle->wayland.ww, handle->wayland.wh);
|
||||
}
|
||||
|
||||
@@ -1200,7 +1480,8 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL
|
||||
}
|
||||
cairo_close_path(handle->wayland.cairo);
|
||||
cairo_fill(handle->wayland.cairo);
|
||||
handle->wayland.events_pending = MwTRUE;
|
||||
|
||||
handle->wayland.events_pending += 1;
|
||||
}
|
||||
|
||||
static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) {
|
||||
@@ -1218,7 +1499,8 @@ static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) {
|
||||
}
|
||||
cairo_close_path(handle->wayland.cairo);
|
||||
cairo_stroke(handle->wayland.cairo);
|
||||
handle->wayland.events_pending = MwTRUE;
|
||||
|
||||
handle->wayland.events_pending += 1;
|
||||
}
|
||||
|
||||
static void MwLLBeginDrawImpl(MwLL handle) {
|
||||
@@ -1226,7 +1508,8 @@ static void MwLLBeginDrawImpl(MwLL handle) {
|
||||
|
||||
static void MwLLEndDrawImpl(MwLL handle) {
|
||||
update_buffer(&handle->wayland.framebuffer);
|
||||
handle->wayland.events_pending = MwTRUE;
|
||||
|
||||
handle->wayland.events_pending += 1;
|
||||
}
|
||||
|
||||
static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) {
|
||||
@@ -1250,13 +1533,29 @@ static void MwLLFreeColorImpl(MwLLColor color) {
|
||||
}
|
||||
|
||||
static int MwLLPendingImpl(MwLL handle) {
|
||||
return handle->wayland.events_pending || wl_display_dispatch(handle->wayland.display);
|
||||
MwBool pending = MwFALSE;
|
||||
struct timespec timeout;
|
||||
int i;
|
||||
|
||||
if(handle->wayland.always_render) {
|
||||
return event_loop(handle);
|
||||
}
|
||||
|
||||
timeout.tv_nsec = 10;
|
||||
timeout.tv_sec = 0;
|
||||
|
||||
return handle->wayland.force_render || handle->wayland.events_pending || wl_display_dispatch_timeout(handle->wayland.display, &timeout);
|
||||
}
|
||||
|
||||
static void MwLLNextEventImpl(MwLL handle) {
|
||||
event_loop(handle);
|
||||
if(!handle->wayland.always_render) {
|
||||
event_loop(handle);
|
||||
}
|
||||
if(handle->wayland.events_pending) {
|
||||
handle->wayland.events_pending = MwFALSE;
|
||||
handle->wayland.events_pending = 0;
|
||||
}
|
||||
if(handle->wayland.force_render) {
|
||||
handle->wayland.force_render = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1336,7 +1635,8 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) {
|
||||
int i = 0;
|
||||
|
||||
if(handle->wayland.icon == NULL) {
|
||||
handle->wayland.icon = calloc(sizeof(struct _MwLLWaylandShmBuffer), 0);
|
||||
handle->wayland.icon = malloc(sizeof(struct _MwLLWaylandShmBuffer));
|
||||
memset(handle->wayland.icon, 0, sizeof(struct _MwLLWaylandShmBuffer));
|
||||
handle->wayland.icon->shm = handle->wayland.framebuffer.shm;
|
||||
}
|
||||
|
||||
@@ -1367,6 +1667,8 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) {
|
||||
static void MwLLForceRenderImpl(MwLL handle) {
|
||||
wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh);
|
||||
|
||||
handle->wayland.force_render = MwTRUE;
|
||||
|
||||
/*
|
||||
if(handle->wayland.egl_setup) {
|
||||
timed_redraw_by_epoch(handle, 25);
|
||||
@@ -1485,59 +1787,28 @@ static void MwLLGrabPointerImpl(MwLL handle, int toggle) {
|
||||
}
|
||||
|
||||
static void MwLLSetClipboardImpl(MwLL handle, const char* text) {
|
||||
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) {
|
||||
for(int 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);
|
||||
}
|
||||
} else {
|
||||
for(int i = 0; i < arrlen(handle->wayland.clipboard_devices); i++) {
|
||||
wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices[i];
|
||||
wl_data_device_set_selection(device->device.wl, handle->wayland.clipboard_source.wl, handle->wayland.keyboard_serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char* MwLLGetClipboardImpl(MwLL handle) {
|
||||
if(WAYLAND_GET_INTERFACE(handle->wayland, zwp_primary_selection_device_manager_v1) != NULL) {
|
||||
primary_selection_context_t* primary_selection = WAYLAND_GET_INTERFACE(handle->wayland, zwp_primary_selection_device_manager_v1)->context;
|
||||
int i, n = 0;
|
||||
int fds[2];
|
||||
struct timeval timeout;
|
||||
fd_set set;
|
||||
char* clip_buffer = NULL;
|
||||
|
||||
if(pipe(fds) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FD_ZERO(&set);
|
||||
FD_SET(fds[0], &set);
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 100;
|
||||
|
||||
for(i = 0; i < arrlen(primary_selection->devices); i++) {
|
||||
primary_selection_device_context_t* device = primary_selection->devices[i];
|
||||
size_t size = 0;
|
||||
char ch;
|
||||
int rc = 0;
|
||||
|
||||
zwp_primary_selection_offer_v1_receive(device->offer, "text/plain", fds[1]);
|
||||
|
||||
wl_flush(handle);
|
||||
|
||||
fcntl(fds[0], F_SETFL, O_NONBLOCK);
|
||||
|
||||
while(MwTRUE) {
|
||||
rc = select(fds[0] + 1, &set, NULL, NULL, &timeout);
|
||||
if(rc <= 0) {
|
||||
break;
|
||||
} else {
|
||||
read(fds[0], &ch, 1);
|
||||
arrpush(clip_buffer, ch);
|
||||
if(n++ >= 10240) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return clip_buffer;
|
||||
}
|
||||
|
||||
// zwp_primary_selection_source_v1_send();
|
||||
|
||||
// arrpush(primary_selection->devices, device);
|
||||
}
|
||||
return NULL;
|
||||
static void MwLLGetClipboardImpl(MwLL handle) {
|
||||
/* no-op */
|
||||
return;
|
||||
}
|
||||
|
||||
static void MwLLMakeToolWindowImpl(MwLL handle) {
|
||||
|
||||
@@ -209,8 +209,9 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) {
|
||||
r->x11.grabbed = 0;
|
||||
r->x11.force_render = 0;
|
||||
|
||||
r->x11.colormap = DefaultColormap(r->x11.display, XDefaultScreen(r->x11.display));
|
||||
r->x11.wm_delete = XInternAtom(r->x11.display, "WM_DELETE_WINDOW", False);
|
||||
r->x11.colormap = DefaultColormap(r->x11.display, XDefaultScreen(r->x11.display));
|
||||
r->x11.wm_delete = XInternAtom(r->x11.display, "WM_DELETE_WINDOW", False);
|
||||
r->x11.wm_protocols = XInternAtom(r->x11.display, "WM_PROTOCOLS", False);
|
||||
XSetWMProtocols(r->x11.display, r->x11.window, &r->x11.wm_delete, 1);
|
||||
|
||||
r->x11.gc = XCreateGC(r->x11.display, r->x11.window, 0, NULL);
|
||||
@@ -471,7 +472,7 @@ static void MwLLNextEventImpl(MwLL handle) {
|
||||
handle->x11.width = ev.xconfigure.width;
|
||||
handle->x11.height = ev.xconfigure.height;
|
||||
} else if(ev.type == ClientMessage) {
|
||||
if(ev.xclient.data.l[0] == (long)handle->x11.wm_delete) {
|
||||
if(ev.xclient.message_type == handle->x11.wm_protocols && ev.xclient.data.l[0] == (long)handle->x11.wm_delete) {
|
||||
MwLLDispatch(handle, close, NULL);
|
||||
}
|
||||
} else if(ev.type == FocusIn) {
|
||||
@@ -956,45 +957,10 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text) {
|
||||
(void)text;
|
||||
}
|
||||
|
||||
static char* MwLLGetClipboardImpl(MwLL handle) {
|
||||
Atom clip, target, prop;
|
||||
XEvent ev;
|
||||
XEvent* queue = NULL;
|
||||
char* r = NULL;
|
||||
static void MwLLGetClipboardImpl(MwLL handle) {
|
||||
/* TODO */
|
||||
|
||||
clip = XInternAtom(handle->x11.display, "CLIPBOARD", 0);
|
||||
target = XA_STRING;
|
||||
prop = XInternAtom(handle->x11.display, "XSEL_DATA", 0);
|
||||
|
||||
XConvertSelection(handle->x11.display, clip, target, prop, handle->x11.window, CurrentTime);
|
||||
|
||||
while(1) {
|
||||
XNextEvent(handle->x11.display, &ev);
|
||||
if(ev.type == SelectionNotify) {
|
||||
if(ev.xselection.selection == clip && ev.xselection.property != 0) {
|
||||
Atom t;
|
||||
unsigned long size, N;
|
||||
char* data;
|
||||
int format;
|
||||
|
||||
XGetWindowProperty(ev.xselection.display, ev.xselection.requestor, ev.xselection.property, 0, (~0L), 0, AnyPropertyType, &t, &format, &size, &N, (unsigned char**)&data);
|
||||
if(t == target) {
|
||||
r = MwStringDuplicate(data);
|
||||
XFree(data);
|
||||
}
|
||||
XDeleteProperty(ev.xselection.display, ev.xselection.requestor, ev.xselection.property);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while(arrlen(queue) > 0) {
|
||||
XPutBackEvent(handle->x11.display, &queue[0]);
|
||||
arrdel(queue, 0);
|
||||
}
|
||||
arrfree(queue);
|
||||
|
||||
return r;
|
||||
(void)handle;
|
||||
}
|
||||
|
||||
static void MwLLMakeToolWindowImpl(MwLL handle) {
|
||||
|
||||
13
src/core.c
13
src/core.c
@@ -107,6 +107,13 @@ static void llfocusouthandler(MwLL handle, void* data) {
|
||||
MwDispatchUserHandler(h, MwNfocusOutHandler, data);
|
||||
}
|
||||
|
||||
static void llclipboardhandler(MwLL handle, void* data) {
|
||||
MwWidget h = (MwWidget)handle->common.user;
|
||||
|
||||
MwDispatch3(h, clipboard, data);
|
||||
MwDispatchUserHandler(h, MwNclipboardHandler, data);
|
||||
}
|
||||
|
||||
MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height) {
|
||||
MwWidget h = malloc(sizeof(*h));
|
||||
|
||||
@@ -148,6 +155,7 @@ MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent,
|
||||
h->lowlevel->common.handler->key_released = llkeyrelhandler;
|
||||
h->lowlevel->common.handler->focus_in = llfocusinhandler;
|
||||
h->lowlevel->common.handler->focus_out = llfocusouthandler;
|
||||
h->lowlevel->common.handler->clipboard = llclipboardhandler;
|
||||
}
|
||||
|
||||
if(parent != NULL) arrput(parent->children, h);
|
||||
@@ -261,6 +269,8 @@ void MwDestroyWidget(MwWidget handle) {
|
||||
if(i == arrlen(handle->parent->destroy_queue)) {
|
||||
arrput(handle->parent->destroy_queue, handle);
|
||||
}
|
||||
|
||||
MwDispatch(handle->parent, children_update);
|
||||
}
|
||||
destroy_children(handle);
|
||||
handle->destroyed = 1;
|
||||
@@ -385,6 +395,9 @@ void MwSetInteger(MwWidget handle, const char* key, int n) {
|
||||
MwDispatch3(handle, prop_change, key);
|
||||
if(handle->parent != NULL) MwDispatch4(handle->parent, children_prop_change, handle, key);
|
||||
}
|
||||
if(strcmp(key, MwNforceInverted) == 0) {
|
||||
MwForceRender(handle);
|
||||
}
|
||||
}
|
||||
|
||||
void MwSetText(MwWidget handle, const char* key, const char* value) {
|
||||
|
||||
@@ -46,7 +46,7 @@ void (*MwLLFocus)(MwLL handle);
|
||||
void (*MwLLGrabPointer)(MwLL handle, int toggle);
|
||||
|
||||
void (*MwLLSetClipboard)(MwLL handle, const char* text);
|
||||
char* (*MwLLGetClipboard)(MwLL handle);
|
||||
void (*MwLLGetClipboard)(MwLL handle);
|
||||
|
||||
void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point);
|
||||
void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect);
|
||||
|
||||
@@ -47,6 +47,8 @@ static void layout(MwWidget handle) {
|
||||
int s = MwGetInteger(handle->children[i], MwNfixedSize);
|
||||
if(n == MwDEFAULT) n = 1;
|
||||
|
||||
if(handle->children[i]->destroyed) continue;
|
||||
|
||||
if(s != MwDEFAULT) {
|
||||
sz -= s + Margin;
|
||||
} else {
|
||||
@@ -60,6 +62,8 @@ static void layout(MwWidget handle) {
|
||||
int wsz;
|
||||
if(n == MwDEFAULT) n = 1;
|
||||
|
||||
if(handle->children[i]->destroyed) continue;
|
||||
|
||||
if(s != MwDEFAULT) {
|
||||
wsz = s;
|
||||
} else {
|
||||
@@ -110,7 +114,7 @@ MwClassRec MwBoxClassRec = {
|
||||
resize, /* resize */
|
||||
children_update, /* children_update */
|
||||
children_prop_change, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -107,7 +107,7 @@ MwClassRec MwButtonClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -53,7 +53,7 @@ MwClassRec MwCheckBoxClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -204,7 +204,7 @@ MwClassRec MwComboBoxClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -109,20 +109,7 @@ static void key(MwWidget handle, int code) {
|
||||
} else if(code == MwLLKeyEnter) {
|
||||
MwDispatchUserHandler(handle, MwNactivateHandler, NULL);
|
||||
} else if(code == (MwLLControlMask | 'v')) {
|
||||
char* c = MwLLGetClipboard(handle->lowlevel);
|
||||
if(c != NULL) {
|
||||
char* out = malloc(strlen(str) + strlen(c) + 1);
|
||||
|
||||
MwUTF8Copy(str, 0, out, 0, t->cursor);
|
||||
MwUTF8Copy(c, 0, out, t->cursor, MwUTF8Length(c));
|
||||
MwUTF8Copy(str, t->cursor, out, t->cursor + MwUTF8Length(c), MwUTF8Length(str) - t->cursor);
|
||||
|
||||
t->cursor += MwUTF8Length(c);
|
||||
|
||||
MwSetText(handle, MwNtext, out);
|
||||
free(out);
|
||||
free(c);
|
||||
}
|
||||
MwLLGetClipboard(handle->lowlevel);
|
||||
} else if(!(code & MwLLKeyMask)) {
|
||||
int incr = 0;
|
||||
out = malloc(strlen(str) + 5 + 1);
|
||||
@@ -157,6 +144,23 @@ static void prop_change(MwWidget handle, const char* prop) {
|
||||
}
|
||||
}
|
||||
|
||||
static void clipboard(MwWidget handle, const char* data) {
|
||||
MwEntry t = handle->internal;
|
||||
const char* str = MwGetText(handle, MwNtext);
|
||||
char* out = malloc(strlen(str) + strlen(data) + 1);
|
||||
|
||||
if(str == NULL) str = "";
|
||||
|
||||
MwUTF8Copy(str, 0, out, 0, t->cursor);
|
||||
MwUTF8Copy(data, 0, out, t->cursor, MwUTF8Length(data));
|
||||
MwUTF8Copy(str, t->cursor, out, t->cursor + MwUTF8Length(data), MwUTF8Length(str) - t->cursor);
|
||||
|
||||
t->cursor += MwUTF8Length(data);
|
||||
|
||||
MwSetText(handle, MwNtext, out);
|
||||
free(out);
|
||||
}
|
||||
|
||||
MwClassRec MwEntryClassRec = {
|
||||
create, /* create */
|
||||
destroy, /* destroy */
|
||||
@@ -173,7 +177,7 @@ MwClassRec MwEntryClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
clipboard, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -61,7 +61,7 @@ MwClassRec MwFrameClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -57,7 +57,7 @@ MwClassRec MwImageClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -15,6 +15,7 @@ static int create(MwWidget handle) {
|
||||
MwSetInteger(handle, MwNbold, 0);
|
||||
MwSetInteger(handle, MwNsevenSegment, 0);
|
||||
MwSetInteger(handle, MwNlength, 4);
|
||||
MwSetInteger(handle, MwNleftPadding, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -253,10 +254,11 @@ static void draw(MwWidget handle) {
|
||||
for(j = 1; j >= 0; j--) {
|
||||
MwLLColor cl = j == 1 ? shadow : text;
|
||||
for(cy = 1; cy < h - 1; cy++) {
|
||||
int c = (l_one - s_one) / 2 + s_one;
|
||||
int h = s_one / 2;
|
||||
int c = (l_one - h) / 2 + s_one;
|
||||
|
||||
int c1 = (c <= cy && cy <= (c + s_one)) ? 1 : 0;
|
||||
int c2 = ((s_one + l_one + c) <= cy && cy <= (s_one + l_one + c + s_one)) ? 1 : 0;
|
||||
int c1 = (c <= cy && cy <= (c + h)) ? 1 : 0;
|
||||
int c2 = ((s_one + l_one + c) <= cy && cy <= (s_one + l_one + c + h)) ? 1 : 0;
|
||||
|
||||
if(c1 || c2) {
|
||||
for(cx = x; cx < x + s_one; cx++) {
|
||||
@@ -309,6 +311,8 @@ static void draw(MwWidget handle) {
|
||||
|
||||
MwLLDestroyPixmap(px);
|
||||
} else {
|
||||
r.width -= MwGetInteger(handle, MwNleftPadding);
|
||||
|
||||
if(align == MwALIGNMENT_CENTER) {
|
||||
p.x = r.width / 2;
|
||||
} else if(align == MwALIGNMENT_BEGINNING) {
|
||||
@@ -318,6 +322,8 @@ static void draw(MwWidget handle) {
|
||||
}
|
||||
p.y = r.height / 2;
|
||||
|
||||
p.x += MwGetInteger(handle, MwNleftPadding);
|
||||
|
||||
p.x += 1;
|
||||
p.y += 1;
|
||||
MwDrawText(handle, &p, str, MwGetInteger(handle, MwNbold), MwALIGNMENT_CENTER, shadow);
|
||||
@@ -333,7 +339,7 @@ static void draw(MwWidget handle) {
|
||||
}
|
||||
|
||||
static void prop_change(MwWidget handle, const char* key) {
|
||||
if(strcmp(key, MwNtext) == 0 || strcmp(key, MwNalignment) == 0 || strcmp(key, MwNsevenSegment) == 0) MwForceRender(handle);
|
||||
if(strcmp(key, MwNtext) == 0 || strcmp(key, MwNalignment) == 0 || strcmp(key, MwNsevenSegment) == 0 || strcmp(key, MwNlength) == 0 || strcmp(key, MwNleftPadding) == 0) MwForceRender(handle);
|
||||
}
|
||||
|
||||
static void mwLabelSetSevenSegmentImpl(MwWidget handle, int index, unsigned char data) {
|
||||
@@ -369,7 +375,7 @@ MwClassRec MwLabelClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -608,7 +608,7 @@ MwClassRec MwListBoxClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -204,7 +204,7 @@ MwClassRec MwMenuClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -143,7 +143,7 @@ MwClassRec MwNumberEntryClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -42,6 +42,19 @@ typedef struct x11opengl {
|
||||
} x11opengl_t;
|
||||
#endif
|
||||
|
||||
#ifdef USE_WAYLAND
|
||||
#include <EGL/egl.h>
|
||||
#include <wayland-egl-core.h>
|
||||
|
||||
typedef struct waylandopengl {
|
||||
EGLNativeWindowType egl_window_native;
|
||||
EGLDisplay egl_display;
|
||||
EGLContext egl_context;
|
||||
EGLSurface egl_surface;
|
||||
EGLConfig egl_config;
|
||||
} waylandopengl_t;
|
||||
#endif
|
||||
|
||||
static int create(MwWidget handle) {
|
||||
void* r = NULL;
|
||||
#ifdef USE_GDI
|
||||
@@ -105,7 +118,90 @@ static int create(MwWidget handle) {
|
||||
#endif
|
||||
#ifdef USE_WAYLAND
|
||||
if(handle->lowlevel->common.type == MwLLBackendWayland) {
|
||||
/* todo */
|
||||
int err;
|
||||
EGLint numConfigs;
|
||||
EGLint majorVersion;
|
||||
EGLint minorVersion;
|
||||
EGLContext context;
|
||||
EGLSurface surface;
|
||||
EGLint fbAttribs[] =
|
||||
{
|
||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_DEPTH_SIZE, 24,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
|
||||
EGL_NONE};
|
||||
EGLint contextAttribs[] = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, 1,
|
||||
EGL_CONTEXT_MAJOR_VERSION, 1,
|
||||
EGL_CONTEXT_MINOR_VERSION, 1,
|
||||
EGL_NONE};
|
||||
EGLDisplay display;
|
||||
waylandopengl_t* o = r = malloc(sizeof(*o));
|
||||
MwLL topmost_parent = handle->lowlevel->wayland.parent;
|
||||
topmost_parent->wayland.always_render = MwTRUE;
|
||||
|
||||
while(topmost_parent->wayland.parent != NULL) {
|
||||
topmost_parent = topmost_parent->wayland.parent;
|
||||
topmost_parent->wayland.always_render = MwTRUE;
|
||||
}
|
||||
|
||||
display = eglGetDisplay((EGLNativeDisplayType)handle->lowlevel->wayland.display);
|
||||
if(display == EGL_NO_DISPLAY) {
|
||||
printf("ERROR: eglGetDisplay, %0X\n", eglGetError());
|
||||
return MwFALSE;
|
||||
}
|
||||
/* Initialize EGL */
|
||||
if(!eglInitialize(display, &majorVersion, &minorVersion)) {
|
||||
printf("ERROR: eglInitialize, %0X\n", eglGetError());
|
||||
return MwFALSE;
|
||||
}
|
||||
|
||||
/* Get configs */
|
||||
if((eglGetConfigs(display, NULL, 0, &numConfigs) != EGL_TRUE) || (numConfigs == 0)) {
|
||||
printf("ERROR: eglGetConfigs, %0X\n", eglGetError());
|
||||
return MwFALSE;
|
||||
}
|
||||
|
||||
/* Choose config */
|
||||
if((eglChooseConfig(display, fbAttribs, &o->egl_config, 1, &numConfigs) != EGL_TRUE) || (numConfigs != 1)) {
|
||||
printf("ERROR: eglChooseConfig, %0X\n", eglGetError());
|
||||
return MwFALSE;
|
||||
}
|
||||
|
||||
o->egl_window_native =
|
||||
(EGLNativeWindowType)wl_egl_window_create(handle->lowlevel->wayland.framebuffer.surface, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh);
|
||||
if(o->egl_window_native == EGL_NO_SURFACE) {
|
||||
printf("ERROR: wl_egl_window_create, EGL_NO_SURFACE\n");
|
||||
return MwFALSE;
|
||||
}
|
||||
|
||||
/* Create a surface */
|
||||
surface = eglCreateWindowSurface(display, o->egl_config, o->egl_window_native, NULL);
|
||||
if(surface == EGL_NO_SURFACE) {
|
||||
printf("ERROR: eglCreateWindowSurface, %0X\n", eglGetError());
|
||||
return MwFALSE;
|
||||
}
|
||||
|
||||
eglBindAPI(EGL_OPENGL_API);
|
||||
|
||||
/* Create a GL context */
|
||||
context = eglCreateContext(display, o->egl_config, EGL_NO_CONTEXT, contextAttribs);
|
||||
if(context == EGL_NO_CONTEXT) {
|
||||
printf("ERROR: eglCreateContext, %0X\n", eglGetError());
|
||||
return MwFALSE;
|
||||
}
|
||||
|
||||
if(!eglMakeCurrent(display, surface, surface, context)) {
|
||||
printf("ERROR: eglMakeCurrent (setup): %0X\n", eglGetError());
|
||||
}
|
||||
|
||||
o->egl_display = display;
|
||||
o->egl_surface = surface;
|
||||
o->egl_context = context;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -165,7 +261,11 @@ static void mwOpenGLMakeCurrentImpl(MwWidget handle) {
|
||||
#endif
|
||||
#ifdef USE_WAYLAND
|
||||
if(handle->lowlevel->common.type == MwLLBackendWayland) {
|
||||
/* todo */
|
||||
waylandopengl_t* o = handle->internal;
|
||||
|
||||
if(!eglMakeCurrent(o->egl_display, o->egl_surface, o->egl_surface, o->egl_context)) {
|
||||
printf("ERROR: eglMakeCurrent, %0X\n", eglGetError());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -187,7 +287,13 @@ static void mwOpenGLSwapBufferImpl(MwWidget handle) {
|
||||
#endif
|
||||
#ifdef USE_WAYLAND
|
||||
if(handle->lowlevel->common.type == MwLLBackendWayland) {
|
||||
/* todo */
|
||||
waylandopengl_t* o = handle->internal;
|
||||
eglSwapInterval(o->egl_display, 0);
|
||||
if(!eglSwapBuffers(o->egl_display, o->egl_surface)) {
|
||||
printf("ERROR: eglSwapBuffers, %0X\n", eglGetError());
|
||||
};
|
||||
wl_egl_window_resize((struct wl_egl_window*)o->egl_window_native, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh, 0, 0);
|
||||
MwLLForceRender(handle->lowlevel);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -209,7 +315,7 @@ static void* mwOpenGLGetProcAddressImpl(MwWidget handle, const char* name) {
|
||||
#endif
|
||||
#ifdef USE_WAYLAND
|
||||
if(handle->lowlevel->common.type == MwLLBackendWayland) {
|
||||
/* todo */
|
||||
return eglGetProcAddress(name);
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
@@ -244,7 +350,7 @@ MwClassRec MwOpenGLClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -61,7 +61,7 @@ MwClassRec MwProgressBarClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -62,7 +62,7 @@ MwClassRec MwRadioBoxClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -272,7 +272,7 @@ MwClassRec MwScrollBarClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -50,7 +50,7 @@ MwClassRec MwSeparatorClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -6,6 +6,7 @@ static int create(MwWidget handle) {
|
||||
MwLLBeginStateChange(handle->lowlevel);
|
||||
|
||||
MwSetDefault(handle);
|
||||
MwSetInteger(handle, MwNleftPadding, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -53,25 +54,27 @@ static void draw(MwWidget handle) {
|
||||
|
||||
rc.x = MwDefaultBorderWidth(handle) * 2;
|
||||
rc.y = p.y;
|
||||
rc.width = r.width - (rc.x * 2);
|
||||
rc.height = MwDefaultBorderWidth(handle) * 2;
|
||||
rc.width = r.width - (rc.x * 2) - MwGetInteger(handle, MwNleftPadding);
|
||||
rc.height = 2;
|
||||
|
||||
MwDrawFrame(handle, &rc, base, 1);
|
||||
rc.x += MwGetInteger(handle, MwNleftPadding);
|
||||
|
||||
p.y += MwDefaultBorderWidth(handle) * 2 + 1;
|
||||
MwDrawFrameEx(handle, &rc, base, 1, 1, 0, 0);
|
||||
|
||||
p.y += 2 + 1;
|
||||
} else {
|
||||
int tw = MwTextWidth(handle, menu->sub[i]->name);
|
||||
int th = MwTextHeight(handle, menu->sub[i]->name);
|
||||
|
||||
if(menu->sub[i]->wsub != NULL) {
|
||||
r.x = 0;
|
||||
r.x = MwGetInteger(handle, MwNleftPadding);
|
||||
r.y = p.y - 3;
|
||||
r.width = MwGetInteger(handle, MwNwidth);
|
||||
r.width = MwGetInteger(handle, MwNwidth) - MwGetInteger(handle, MwNleftPadding);
|
||||
r.height = th + 3 * 2;
|
||||
MwDrawWidgetBack(handle, &r, base, 0, MwTRUE);
|
||||
}
|
||||
|
||||
p.x = 5 + tw / 2;
|
||||
p.x = 5 + tw / 2 + MwGetInteger(handle, MwNleftPadding);
|
||||
|
||||
p.y += th / 2;
|
||||
MwDrawText(handle, &p, menu->sub[i]->name, menu->sub[i]->wsub != NULL ? 1 : 0, MwALIGNMENT_CENTER, text);
|
||||
@@ -116,7 +119,11 @@ static void click(MwWidget handle) {
|
||||
int th = MwTextHeight(handle, menu->sub[i]->name);
|
||||
rc.height = th;
|
||||
|
||||
if(rc.x <= handle->mouse_point.x && rc.y <= handle->mouse_point.y && handle->mouse_point.x <= (int)(rc.x + rc.width) && handle->mouse_point.y <= (int)(rc.y + rc.height)) {
|
||||
if(strcmp(menu->sub[i]->name, "----") == 0) {
|
||||
rc.height = 2 - 1;
|
||||
}
|
||||
|
||||
if(MwGetInteger(handle, MwNleftPadding) <= handle->mouse_point.x && rc.y <= handle->mouse_point.y && handle->mouse_point.y <= (int)(rc.y + rc.height)) {
|
||||
if(menu->sub[i]->wsub == NULL && arrlen(menu->sub[i]->sub) > 0) {
|
||||
MwPoint p;
|
||||
int j;
|
||||
@@ -160,51 +167,61 @@ static void click(MwWidget handle) {
|
||||
}
|
||||
|
||||
static void mwSubMenuAppearImpl(MwWidget handle, MwMenu menu, MwPoint* point, int diff_calc) {
|
||||
int i, w = 0, h = 0;
|
||||
MwRect rc;
|
||||
MwRect rc, sz;
|
||||
MwPoint p = *point;
|
||||
|
||||
MwSubMenuGetSize(handle, menu, &sz);
|
||||
|
||||
MwGetScreenSize(handle, &rc);
|
||||
|
||||
handle->internal = menu;
|
||||
|
||||
for(i = 0; i < arrlen(menu->sub); i++) {
|
||||
if(strcmp(menu->sub[i]->name, "----") == 0) {
|
||||
h += MwDefaultBorderWidth(handle) * 2 + 2;
|
||||
} else {
|
||||
int tw = MwTextWidth(handle, menu->sub[i]->name);
|
||||
h += MwTextHeight(handle, menu->sub[i]->name) + 3;
|
||||
if(tw > w) {
|
||||
w = tw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
w += 10 + 15;
|
||||
h += 3;
|
||||
|
||||
if(w < 150) w = 150;
|
||||
|
||||
if(diff_calc) {
|
||||
p.y = p.y - h;
|
||||
p.y = p.y - sz.height;
|
||||
}
|
||||
|
||||
MwLLMakeToolWindow(handle->lowlevel);
|
||||
MwLLDetach(handle->lowlevel, &p);
|
||||
|
||||
if(MwGetInteger(handle, MwNy) + h > rc.height) {
|
||||
if(MwGetInteger(handle, MwNy) + sz.height > rc.height) {
|
||||
MwVaApply(handle,
|
||||
MwNy, rc.height - h,
|
||||
MwNy, rc.height - sz.height,
|
||||
NULL);
|
||||
}
|
||||
MwLLEndStateChange(handle->lowlevel);
|
||||
|
||||
MwVaApply(handle,
|
||||
MwNwidth, w,
|
||||
MwNheight, h,
|
||||
MwNwidth, sz.width,
|
||||
MwNheight, sz.height,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void mwSubMenuGetSizeImpl(MwWidget handle, MwMenu menu, MwRect* rect) {
|
||||
int i;
|
||||
|
||||
rect->width = 0;
|
||||
rect->height = 0;
|
||||
|
||||
for(i = 0; i < arrlen(menu->sub); i++) {
|
||||
if(strcmp(menu->sub[i]->name, "----") == 0) {
|
||||
rect->height += 2 + 2;
|
||||
} else {
|
||||
int tw = MwTextWidth(handle, menu->sub[i]->name);
|
||||
rect->height += MwTextHeight(handle, menu->sub[i]->name) + 3;
|
||||
if(tw > rect->width) {
|
||||
rect->width = tw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rect->width += MwGetInteger(handle, MwNleftPadding);
|
||||
|
||||
rect->width += 10 + 15;
|
||||
rect->height += 3;
|
||||
|
||||
rect->width += 16;
|
||||
}
|
||||
|
||||
static void func_handler(MwWidget handle, const char* name, void* out, va_list va) {
|
||||
(void)out;
|
||||
|
||||
@@ -213,6 +230,10 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v
|
||||
MwPoint* point = va_arg(va, MwPoint*);
|
||||
int diff_calc = va_arg(va, int);
|
||||
mwSubMenuAppearImpl(handle, menu, point, diff_calc);
|
||||
} else if(strcmp(name, "mwSubMenuGetSize") == 0) {
|
||||
MwMenu menu = va_arg(va, MwMenu);
|
||||
MwRect* rect = va_arg(va, MwRect*);
|
||||
mwSubMenuGetSizeImpl(handle, menu, rect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +253,7 @@ MwClassRec MwSubMenuClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -496,7 +496,7 @@ MwClassRec MwTreeViewClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -191,7 +191,7 @@ MwClassRec MwViewportClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -524,7 +524,7 @@ MwClassRec MwVulkanClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -59,7 +59,7 @@ MwClassRec MwWindowClassRec = {
|
||||
NULL, /* resize */
|
||||
NULL, /* children_update */
|
||||
NULL, /* children_prop_change */
|
||||
NULL,
|
||||
NULL, /* clipboard */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
Reference in New Issue
Block a user