aboutsummaryrefslogtreecommitdiff
path: root/src/libui_sdl/libui
diff options
context:
space:
mode:
authorArisotura <thetotalworm@gmail.com>2019-06-04 15:53:08 +0200
committerGitHub <noreply@github.com>2019-06-04 15:53:08 +0200
commit97f4b5f70b67ea5cc142fbd1f3982c36b915a5d9 (patch)
treebd3fb3325db3743eef00cf3ddffafdeb644370a9 /src/libui_sdl/libui
parentf769d6e23f7635910e3f6659c6b55d8c6a8e96ff (diff)
parent3134c8fc66d1fbd5706930a3e3e64ce118406fe5 (diff)
Merge branch 'master' into fast-forward-hotkey
Diffstat (limited to 'src/libui_sdl/libui')
-rw-r--r--src/libui_sdl/libui/ui.h25
-rw-r--r--src/libui_sdl/libui/unix/CMakeLists.txt2
-rw-r--r--src/libui_sdl/libui/unix/area.c116
-rw-r--r--src/libui_sdl/libui/unix/draw.c4
-rw-r--r--src/libui_sdl/libui/unix/gl.c246
-rw-r--r--src/libui_sdl/libui/unix/main.c24
-rw-r--r--src/libui_sdl/libui/unix/uipriv_unix.h8
-rw-r--r--src/libui_sdl/libui/unix/window.c18
-rw-r--r--src/libui_sdl/libui/windows/CMakeLists.txt1
-rw-r--r--src/libui_sdl/libui/windows/area.cpp73
-rw-r--r--src/libui_sdl/libui/windows/area.hpp11
-rw-r--r--src/libui_sdl/libui/windows/areadraw.cpp27
-rw-r--r--src/libui_sdl/libui/windows/areaevents.cpp2
-rw-r--r--src/libui_sdl/libui/windows/areautil.cpp21
-rw-r--r--src/libui_sdl/libui/windows/draw.cpp5
-rw-r--r--src/libui_sdl/libui/windows/gl.cpp161
-rw-r--r--src/libui_sdl/libui/windows/window.cpp15
17 files changed, 724 insertions, 35 deletions
diff --git a/src/libui_sdl/libui/ui.h b/src/libui_sdl/libui/ui.h
index 5f40aff..e15c127 100644
--- a/src/libui_sdl/libui/ui.h
+++ b/src/libui_sdl/libui/ui.h
@@ -108,6 +108,8 @@ typedef struct uiWindow uiWindow;
#define uiWindow(this) ((uiWindow *) (this))
_UI_EXTERN char *uiWindowTitle(uiWindow *w);
_UI_EXTERN void uiWindowSetTitle(uiWindow *w, const char *title);
+_UI_EXTERN void uiWindowPosition(uiWindow *w, int *x, int *y);
+_UI_EXTERN void uiWindowSetPosition(uiWindow *w, int x, int y);
_UI_EXTERN void uiWindowContentSize(uiWindow *w, int *width, int *height);
_UI_EXTERN void uiWindowSetContentSize(uiWindow *w, int width, int height);
_UI_EXTERN int uiWindowMinimized(uiWindow *w);
@@ -326,6 +328,10 @@ _UI_ENUM(uiWindowResizeEdge) {
// TODO way to bring up the system menu instead?
};
+#define uiGLVersion(major, minor) ((major) | ((minor)<<16))
+#define uiGLVerMajor(ver) ((ver) & 0xFFFF)
+#define uiGLVerMinor(ver) ((ver) >> 16)
+
#define uiArea(this) ((uiArea *) (this))
// TODO give a better name
// TODO document the types of width and height
@@ -342,6 +348,7 @@ _UI_EXTERN void uiAreaBeginUserWindowMove(uiArea *a);
_UI_EXTERN void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge);
_UI_EXTERN void uiAreaSetBackgroundColor(uiArea *a, int r, int g, int b);
_UI_EXTERN uiArea *uiNewArea(uiAreaHandler *ah);
+_UI_EXTERN uiArea *uiNewGLArea(uiAreaHandler *ah, const unsigned int* req_versions);
_UI_EXTERN uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height);
struct uiAreaDrawParams {
@@ -509,7 +516,7 @@ _UI_EXTERN void uiDrawSave(uiDrawContext *c);
_UI_EXTERN void uiDrawRestore(uiDrawContext *c);
// bitmap API
-_UI_EXTERN uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height);
+_UI_EXTERN uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height, int alpha);
_UI_EXTERN void uiDrawBitmapUpdate(uiDrawBitmap* bmp, const void* data);
_UI_EXTERN void uiDrawBitmapDraw(uiDrawContext* c, uiDrawBitmap* bmp, uiRect* srcrect, uiRect* dstrect, int filter);
_UI_EXTERN void uiDrawFreeBitmap(uiDrawBitmap* bmp);
@@ -599,6 +606,22 @@ _UI_EXTERN void uiDrawTextLayoutSetColor(uiDrawTextLayout *layout, int startChar
_UI_EXTERN void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout);
+
+// OpenGL support
+
+typedef struct uiGLContext uiGLContext;
+
+_UI_EXTERN uiGLContext *uiAreaGetGLContext(uiArea* a);
+_UI_EXTERN void uiGLMakeContextCurrent(uiGLContext* ctx);
+_UI_EXTERN void uiGLBegin(uiGLContext* ctx);
+_UI_EXTERN void uiGLEnd(uiGLContext* ctx);
+_UI_EXTERN unsigned int uiGLGetVersion(uiGLContext* ctx);
+_UI_EXTERN void *uiGLGetProcAddress(const char* proc);
+_UI_EXTERN int uiGLGetFramebuffer(uiGLContext* ctx);
+_UI_EXTERN float uiGLGetFramebufferScale(uiGLContext* ctx);
+_UI_EXTERN void uiGLSwapBuffers(uiGLContext* ctx);
+
+
_UI_ENUM(uiModifiers) {
uiModifierCtrl = 1 << 0,
uiModifierAlt = 1 << 1,
diff --git a/src/libui_sdl/libui/unix/CMakeLists.txt b/src/libui_sdl/libui/unix/CMakeLists.txt
index 9300bcb..c69081e 100644
--- a/src/libui_sdl/libui/unix/CMakeLists.txt
+++ b/src/libui_sdl/libui/unix/CMakeLists.txt
@@ -43,6 +43,7 @@ list(APPEND _LIBUI_SOURCES
unix/text.c
unix/util.c
unix/window.c
+ unix/gl.c
)
set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE)
@@ -62,6 +63,7 @@ macro(_handle_static)
set(_oname libui-combined.o)
add_custom_command(
OUTPUT ${_oname}
+ DEPENDS ${_LIBUINAME}
COMMAND
ld -r --whole-archive ${_aname} -o ${_oname}
COMMAND
diff --git a/src/libui_sdl/libui/unix/area.c b/src/libui_sdl/libui/unix/area.c
index 2da9bab..5734b4b 100644
--- a/src/libui_sdl/libui/unix/area.c
+++ b/src/libui_sdl/libui/unix/area.c
@@ -28,6 +28,8 @@ struct areaWidgetClass {
GtkDrawingAreaClass parent_class;
};
+typedef struct uiGLContext uiGLContext;
+
struct uiArea {
uiUnixControl c;
GtkWidget *widget; // either swidget or areaWidget depending on whether it is scrolling
@@ -39,6 +41,10 @@ struct uiArea {
GtkWidget *areaWidget;
GtkDrawingArea *drawingArea;
areaWidget *area;
+
+ gboolean opengl;
+ uiGLContext *glContext;
+ unsigned int* req_versions;
int bgR, bgG, bgB;
@@ -57,6 +63,21 @@ struct uiArea {
G_DEFINE_TYPE(areaWidget, areaWidget, GTK_TYPE_DRAWING_AREA)
+int boub(GtkWidget* w) { return isAreaWidget(w); }
+void baba(GtkWidget* w)
+{
+ if (!isAreaWidget(w)) return;
+
+ areaWidget *aw = areaWidget(w);
+ uiArea *a = aw->a;
+ if (!a->opengl) return;
+
+ GdkGLContext* oldctx = gdk_gl_context_get_current();
+ uiGLMakeContextCurrent(a->glContext);
+ glFinish();
+ gdk_gl_context_make_current(oldctx);
+}
+
static void areaWidget_init(areaWidget *aw)
{
// for events
@@ -133,21 +154,28 @@ static gboolean areaWidget_draw(GtkWidget *w, cairo_t *cr)
loadAreaSize(a, &(dp.AreaWidth), &(dp.AreaHeight));
- cairo_clip_extents(cr, &clipX0, &clipY0, &clipX1, &clipY1);
- dp.ClipX = clipX0;
- dp.ClipY = clipY0;
- dp.ClipWidth = clipX1 - clipX0;
- dp.ClipHeight = clipY1 - clipY0;
-
- if (a->bgR != -1)
+ if (!a->opengl)
+ {
+ cairo_clip_extents(cr, &clipX0, &clipY0, &clipX1, &clipY1);
+ dp.ClipX = clipX0;
+ dp.ClipY = clipY0;
+ dp.ClipWidth = clipX1 - clipX0;
+ dp.ClipHeight = clipY1 - clipY0;
+
+ if (a->bgR != -1)
+ {
+ cairo_set_source_rgb(cr, a->bgR/255.0, a->bgG/255.0, a->bgB/255.0);
+ cairo_paint(cr);
+ }
+
+ // no need to save or restore the graphics state to reset transformations; GTK+ does that for us
+ (*(a->ah->Draw))(a->ah, a, &dp);
+ }
+ else
{
- cairo_set_source_rgb(cr, a->bgR/255.0, a->bgG/255.0, a->bgB/255.0);
- cairo_paint(cr);
+ areaDrawGL(w, &dp, cr, a->glContext);
}
- // no need to save or restore the graphics state to reset transformations; GTK+ does that for us
- (*(a->ah->Draw))(a->ah, a, &dp);
-
freeContext(dp.Context);
return FALSE;
}
@@ -598,7 +626,15 @@ static void areaWidget_class_init(areaWidgetClass *class)
// control implementation
-uiUnixControlAllDefaults(uiArea)
+uiUnixControlAllDefaultsExceptDestroy(uiArea)
+
+static void uiAreaDestroy(uiControl *c)
+{
+ uiArea* a = uiArea(c);
+ if (a->opengl && a->glContext) freeGLContext(a->glContext);
+ g_object_unref(uiArea(c)->widget);
+ uiFreeControl(c);
+}
void uiAreaSetBackgroundColor(uiArea *a, int r, int g, int b)
{
@@ -716,6 +752,7 @@ uiArea *uiNewArea(uiAreaHandler *ah)
a->ah = ah;
a->scrolling = FALSE;
+ a->opengl = FALSE;
a->areaWidget = GTK_WIDGET(g_object_new(areaWidgetType,
"libui-area", a,
@@ -730,6 +767,58 @@ uiArea *uiNewArea(uiAreaHandler *ah)
return a;
}
+void _areaCreateGLContext(GtkWidget* widget, gpointer data)
+{
+ uiArea* a = (uiArea*)data;
+
+ uiGLContext* ctx = NULL;
+ for (int i = 0; a->req_versions[i] && !ctx; i++)
+ {
+ int major = uiGLVerMajor(a->req_versions[i]);
+ int minor = uiGLVerMinor(a->req_versions[i]);
+
+ // we cannot support any version older than 3.2 via GDK
+ if ((major < 3) || (major == 3 && minor < 2))
+ break;
+
+ ctx = createGLContext(widget, major, minor);
+ }
+
+ a->glContext = ctx;
+}
+
+uiArea *uiNewGLArea(uiAreaHandler *ah, const unsigned int* req_versions)
+{
+ uiArea *a;
+
+ uiUnixNewControl(uiArea, a);
+
+ a->ah = ah;
+ a->scrolling = FALSE;
+ a->opengl = TRUE;
+
+ a->glContext = NULL;
+ a->req_versions = req_versions;
+ a->areaWidget = GTK_WIDGET(g_object_new(areaWidgetType,
+ "libui-area", a,
+ NULL));
+ a->area = areaWidget(a->areaWidget);
+
+ a->widget = a->areaWidget;
+
+ g_signal_connect(a->widget, "realize", G_CALLBACK(_areaCreateGLContext), a);
+
+ uiAreaSetBackgroundColor(a, -1, -1, -1);
+
+ return a;
+}
+
+uiGLContext *uiAreaGetGLContext(uiArea* a)
+{
+ if (!a) return NULL;
+ return a->glContext;
+}
+
uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height)
{
uiArea *a;
@@ -740,6 +829,7 @@ uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height)
a->scrolling = TRUE;
a->scrollWidth = width;
a->scrollHeight = height;
+ a->opengl = FALSE;
a->swidget = gtk_scrolled_window_new(NULL, NULL);
a->scontainer = GTK_CONTAINER(a->swidget);
diff --git a/src/libui_sdl/libui/unix/draw.c b/src/libui_sdl/libui/unix/draw.c
index e55397e..5befcd3 100644
--- a/src/libui_sdl/libui/unix/draw.c
+++ b/src/libui_sdl/libui/unix/draw.c
@@ -143,13 +143,13 @@ void uiDrawRestore(uiDrawContext *c)
// bitmap API
-uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height)
+uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height, int alpha)
{
uiDrawBitmap* bmp;
bmp = uiNew(uiDrawBitmap);
- bmp->bmp = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
+ bmp->bmp = cairo_image_surface_create(alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, width, height);
if (cairo_surface_status(bmp->bmp) != CAIRO_STATUS_SUCCESS)
implbug("error creating bitmap: %s",
cairo_status_to_string(cairo_surface_status(bmp->bmp)));
diff --git a/src/libui_sdl/libui/unix/gl.c b/src/libui_sdl/libui/unix/gl.c
new file mode 100644
index 0000000..e1665ee
--- /dev/null
+++ b/src/libui_sdl/libui/unix/gl.c
@@ -0,0 +1,246 @@
+// 26 may 2019
+#include "uipriv_unix.h"
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <EGL/egl.h>
+
+extern GThread* gtkthread;
+extern GMutex glmutex;
+
+struct uiGLContext
+{
+ GtkWidget* widget;
+ GdkWindow* window;
+
+ GdkGLContext *gctx;
+ int vermaj, vermin;
+
+ int width, height;
+ int scale;
+ GLuint renderbuffer[2][2];
+ GLuint framebuffer[2];
+ int backbuffer;
+};
+
+static void areaAllocRenderbuffer(uiGLContext* glctx);
+
+static PFNGLGENRENDERBUFFERSPROC _glGenRenderbuffers;
+static PFNGLDELETERENDERBUFFERSPROC _glDeleteRenderbuffers;
+static PFNGLBINDRENDERBUFFERPROC _glBindRenderbuffer;
+static PFNGLRENDERBUFFERSTORAGEPROC _glRenderbufferStorage;
+static PFNGLGETRENDERBUFFERPARAMETERIVPROC _glGetRenderbufferParameteriv;
+
+static PFNGLGENRENDERBUFFERSPROC _glGenFramebuffers;
+static PFNGLDELETERENDERBUFFERSPROC _glDeleteFramebuffers;
+static PFNGLBINDRENDERBUFFERPROC _glBindFramebuffer;
+static PFNGLFRAMEBUFFERTEXTUREPROC _glFramebufferTexture;
+static PFNGLFRAMEBUFFERRENDERBUFFERPROC _glFramebufferRenderbuffer;
+static PFNGLCHECKFRAMEBUFFERSTATUSPROC _glCheckFramebufferStatus;
+
+static int _procsLoaded = 0;
+
+static void _loadGLProcs(GdkGLContext* glctx)
+{
+ if (_procsLoaded) return;
+
+ _glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)uiGLGetProcAddress("glGenRenderbuffers");
+ _glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)uiGLGetProcAddress("glDeleteRenderbuffers");
+ _glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)uiGLGetProcAddress("glBindRenderbuffer");
+ _glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)uiGLGetProcAddress("glRenderbufferStorage");
+ _glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)uiGLGetProcAddress("glGetRenderbufferParameteriv");
+
+ _glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)uiGLGetProcAddress("glGenFramebuffers");
+ _glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)uiGLGetProcAddress("glDeleteFramebuffers");
+ _glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)uiGLGetProcAddress("glBindFramebuffer");
+ _glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)uiGLGetProcAddress("glFramebufferTexture");
+ _glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)uiGLGetProcAddress("glFramebufferRenderbuffer");
+ _glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)uiGLGetProcAddress("glCheckFramebufferStatus");
+
+ _procsLoaded = 1;
+}
+
+uiGLContext *createGLContext(GtkWidget* widget, int maj, int min)
+{
+ GdkWindow* gdkwin = gtk_widget_get_window(widget);
+
+ GError* err = NULL;
+ GdkGLContext* gctx = gdk_window_create_gl_context(gdkwin, &err);
+ if (err != NULL || gctx == NULL)
+ {
+ return NULL;
+ }
+
+ // TODO: make the set_use_es call conditional (#ifdef or smth) for older versions of gdk?
+ gdk_gl_context_set_use_es(gctx, FALSE);
+ gdk_gl_context_set_required_version(gctx, maj, min);
+
+ gboolean res = gdk_gl_context_realize(gctx, &err);
+ if (err != NULL || res == FALSE)
+ {
+ return NULL;
+ }
+
+ uiGLContext* ctx = uiNew(uiGLContext);
+
+ GtkAllocation allocation;
+ gtk_widget_get_allocation(widget, &allocation);
+ int window_scale = gdk_window_get_scale_factor(gdkwin);
+ ctx->width = allocation.width;
+ ctx->height = allocation.height;
+ ctx->scale = window_scale;
+
+ gdk_gl_context_make_current(gctx);
+ _loadGLProcs(gctx);
+ areaAllocRenderbuffer(ctx);
+ ctx->backbuffer = 0;
+
+ ctx->widget = widget;
+ ctx->window = gdkwin;
+ ctx->gctx = gctx;
+
+ return ctx;
+}
+
+void freeGLContext(uiGLContext* glctx)
+{
+ if (glctx == NULL) return;
+
+ gdk_gl_context_make_current(glctx->gctx);
+ _glDeleteRenderbuffers(4, &glctx->renderbuffer[0][0]);
+ _glDeleteFramebuffers(2, &glctx->framebuffer[0]);
+
+ gdk_gl_context_clear_current();
+ g_object_unref(glctx->gctx);
+ uiFree(glctx);
+}
+
+static void areaAllocRenderbuffer(uiGLContext* glctx)
+{
+ // TODO: create textures as a fallback if GL_RGB renderbuffer isn't supported?
+ // they say GL implementations aren't required to support a GL_RGB renderbuffer
+ // however, a GL_RGBA one would cause gdk_cairo_draw_from_gl() to fall back to glReadPixels()
+
+ _glGenRenderbuffers(4, &glctx->renderbuffer[0][0]);
+ _glGenFramebuffers(2, &glctx->framebuffer[0]);
+
+ _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][0]);
+ _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
+ //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][1]);
+ //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
+
+ _glBindFramebuffer(GL_FRAMEBUFFER, glctx->framebuffer[0]);
+ _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, glctx->renderbuffer[0][0]);
+ _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, glctx->renderbuffer[0][1]);
+
+ _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][0]);
+ _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
+ //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][1]);
+ //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
+
+ _glBindFramebuffer(GL_FRAMEBUFFER, glctx->framebuffer[1]);
+ _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, glctx->renderbuffer[1][0]);
+ _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, glctx->renderbuffer[1][1]);
+
+ //if (_glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+ // printf("FRAMEBUFFER IS BAD!! %04X\n", _glCheckFramebufferStatus(GL_FRAMEBUFFER));
+}
+
+static void areaReallocRenderbuffer(uiGLContext* glctx)
+{
+ _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][0]);
+ _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
+ //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][1]);
+ //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
+
+ _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][0]);
+ _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
+ //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][1]);
+ //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
+}
+
+void areaDrawGL(GtkWidget* widget, uiAreaDrawParams* dp, cairo_t* cr, uiGLContext* glctx)
+{
+ int window_scale = gdk_window_get_scale_factor(glctx->window);
+
+ if (glctx->width != dp->AreaWidth || glctx->height != dp->AreaHeight || glctx->scale != window_scale)
+ {
+ glctx->width = dp->AreaWidth;
+ glctx->height = dp->AreaHeight;
+ glctx->scale = window_scale;
+ areaReallocRenderbuffer(glctx);
+ }
+ else
+ {
+ gdk_cairo_draw_from_gl(cr, gtk_widget_get_window(widget),
+ glctx->renderbuffer[glctx->backbuffer][0], GL_RENDERBUFFER,
+ 1, 0, 0, glctx->width*glctx->scale, glctx->height*glctx->scale);
+ }
+}
+
+int uiGLGetFramebuffer(uiGLContext* ctx)
+{
+ return ctx->framebuffer[ctx->backbuffer];
+}
+
+float uiGLGetFramebufferScale(uiGLContext* ctx)
+{
+ return (float)ctx->scale;
+}
+
+void uiGLSwapBuffers(uiGLContext* ctx)
+{
+ ctx->backbuffer = ctx->backbuffer ? 0 : 1;
+}
+
+void uiGLMakeContextCurrent(uiGLContext* ctx)
+{
+ if (!ctx)
+ {
+ gdk_gl_context_clear_current();
+ return;
+ }
+
+ if (ctx->gctx == gdk_gl_context_get_current()) return;
+ gdk_gl_context_make_current(ctx->gctx);
+}
+
+void uiGLBegin(uiGLContext* ctx)
+{
+ if (g_thread_self() != gtkthread)
+ {
+ g_mutex_lock(&glmutex);
+ }
+}
+
+void uiGLEnd(uiGLContext* ctx)
+{
+ if (g_thread_self() != gtkthread)
+ {
+ g_mutex_unlock(&glmutex);
+ }
+}
+
+void *uiGLGetProcAddress(const char* proc)
+{
+ // TODO: consider using epoxy or something funny
+
+ void* ptr;
+
+ ptr = glXGetProcAddressARB((const GLubyte*)proc);
+ if (ptr) return ptr;
+
+ ptr = eglGetProcAddress(proc);
+ if (ptr) return ptr;
+
+ ptr = dlsym(NULL /* RTLD_DEFAULT */, proc);
+ if (ptr) return ptr;
+
+ return NULL;
+}
+unsigned int uiGLGetVersion(uiGLContext* ctx)
+{
+ if (!ctx) return 0;
+ return uiGLVersion(ctx->vermaj, ctx->vermin);
+}
+
diff --git a/src/libui_sdl/libui/unix/main.c b/src/libui_sdl/libui/unix/main.c
index 409b659..516bd76 100644
--- a/src/libui_sdl/libui/unix/main.c
+++ b/src/libui_sdl/libui/unix/main.c
@@ -5,6 +5,25 @@ uiInitOptions options;
// kind of a hack
GThread* gtkthread;
+GMutex glmutex;
+
+static void _eventfilter(GdkEvent* evt, gpointer data)
+{
+ if (evt->type == GDK_EXPOSE)
+ {
+ g_mutex_lock(&glmutex);
+ gtk_main_do_event(evt);
+ g_mutex_unlock(&glmutex);
+ return;
+ }
+
+ gtk_main_do_event(evt);
+}
+
+static void _eventfilterdestroy(gpointer data)
+{
+ printf("DELET\n");
+}
const char *uiInit(uiInitOptions *o)
{
@@ -21,6 +40,7 @@ const char *uiInit(uiInitOptions *o)
loadFutures();
gtkthread = g_thread_self();
+ g_mutex_init(&glmutex);
GList* iconlist = NULL;
iconlist = g_list_append(iconlist, gdk_pixbuf_new_from_resource("/org/kuriboland/melonDS/icon/melon_16x16.png", NULL));
@@ -31,6 +51,10 @@ const char *uiInit(uiInitOptions *o)
gtk_window_set_default_icon_list(iconlist);
+ g_mutex_init(&glmutex);
+
+ gdk_event_handler_set(_eventfilter, NULL, _eventfilterdestroy);
+
return NULL;
}
diff --git a/src/libui_sdl/libui/unix/uipriv_unix.h b/src/libui_sdl/libui/unix/uipriv_unix.h
index 33ff1e3..9b77188 100644
--- a/src/libui_sdl/libui/unix/uipriv_unix.h
+++ b/src/libui_sdl/libui/unix/uipriv_unix.h
@@ -5,7 +5,7 @@
#define GDK_VERSION_MAX_ALLOWED GDK_VERSION_3_10
#include <gtk/gtk.h>
#include <math.h>
-#include <dlfcn.h> // see drawtext.c
+#include <dlfcn.h> // see drawtext.c, gl.c
#include <langinfo.h>
#include <string.h>
#include <stdlib.h>
@@ -63,3 +63,9 @@ extern GtkCellRenderer *newCellRendererButton(void);
extern void loadFutures(void);
extern PangoAttribute *FUTURE_pango_attr_foreground_alpha_new(guint16 alpha);
extern gboolean FUTURE_gtk_widget_path_iter_set_object_name(GtkWidgetPath *path, gint pos, const char *name);
+
+// gl.c
+extern uiGLContext *createGLContext(GtkWidget* widget, int maj, int min);
+extern void freeGLContext(uiGLContext* glctx);
+extern void areaDrawGL(GtkWidget* widget, uiAreaDrawParams* dp, cairo_t* cr, uiGLContext* glctx);
+
diff --git a/src/libui_sdl/libui/unix/window.c b/src/libui_sdl/libui/unix/window.c
index 7da1134..6d5e2de 100644
--- a/src/libui_sdl/libui/unix/window.c
+++ b/src/libui_sdl/libui/unix/window.c
@@ -102,6 +102,23 @@ static void uiWindowDestroy(uiControl *c)
uiFreeControl(uiControl(w));
}
+void uiWindowSetPosition(uiWindow *w, int x, int y)
+{
+ if (!w) return;
+
+ gtk_window_move(w->window, x, y);
+}
+
+void uiWindowPosition(uiWindow *w, int *x, int *y)
+{
+ if (!w) return;
+
+ int xx, yy;
+ gtk_window_get_position(w->window, &xx, &yy);
+ if (x) *x = xx;
+ if (y) *y = yy;
+}
+
uiUnixControlDefaultHandle(uiWindow)
uiControl *uiWindowParent(uiControl *c)
@@ -442,3 +459,4 @@ uiWindow *uiNewWindow(const char *title, int width, int height, int maximized, i
return w;
}
+
diff --git a/src/libui_sdl/libui/windows/CMakeLists.txt b/src/libui_sdl/libui/windows/CMakeLists.txt
index 4695eb4..9d5313a 100644
--- a/src/libui_sdl/libui/windows/CMakeLists.txt
+++ b/src/libui_sdl/libui/windows/CMakeLists.txt
@@ -29,6 +29,7 @@ list(APPEND _LIBUI_SOURCES
windows/fontbutton.cpp
windows/fontdialog.cpp
windows/form.cpp
+ windows/gl.cpp
windows/graphemes.cpp
windows/grid.cpp
windows/group.cpp
diff --git a/src/libui_sdl/libui/windows/area.cpp b/src/libui_sdl/libui/windows/area.cpp
index 2185f25..72d5145 100644
--- a/src/libui_sdl/libui/windows/area.cpp
+++ b/src/libui_sdl/libui/windows/area.cpp
@@ -25,8 +25,11 @@ static LRESULT CALLBACK areaWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
}
// always recreate the render target if necessary
- if (a->rt == NULL)
- a->rt = makeHWNDRenderTarget(a->hwnd);
+ if (!a->openGL)
+ {
+ if (a->rt == NULL)
+ a->rt = makeHWNDRenderTarget(a->hwnd);
+ }
if (areaDoDraw(a, uMsg, wParam, lParam, &lResult) != FALSE)
return lResult;
@@ -34,12 +37,14 @@ static LRESULT CALLBACK areaWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
if (uMsg == WM_WINDOWPOSCHANGED) {
if ((wp->flags & SWP_NOSIZE) != 0)
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+ a->width = -1;
+ a->height = -1;
uiWindowsEnsureGetClientRect(a->hwnd, &client);
areaDrawOnResize(a, &client);
areaScrollOnResize(a, &client);
{
double w, h;
- loadAreaSize(a, a->rt, &w, &h);
+ loadAreaSize(a, &w, &h);
a->ah->Resize(a->ah, a, (int)w, (int)h);
}
return 0;
@@ -56,7 +61,15 @@ static LRESULT CALLBACK areaWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
// control implementation
-uiWindowsControlAllDefaults(uiArea)
+uiWindowsControlAllDefaultsExceptDestroy(uiArea)
+
+static void uiAreaDestroy(uiControl *c)
+{
+ uiArea* a = uiArea(c);
+ if (a->openGL && a->glcontext) freeGLContext(a->glcontext);
+ uiWindowsEnsureDestroyWindow(a->hwnd);
+ uiFreeControl(c);
+}
static void uiAreaMinimumSize(uiWindowsControl *c, int *width, int *height)
{
@@ -182,6 +195,9 @@ uiArea *uiNewArea(uiAreaHandler *ah)
uiWindowsNewControl(uiArea, a);
+ a->width = -1;
+ a->height = -1;
+
a->ah = ah;
a->scrolling = FALSE;
clickCounterReset(&(a->cc));
@@ -195,6 +211,50 @@ uiArea *uiNewArea(uiAreaHandler *ah)
uiAreaSetBackgroundColor(a, -1, -1, -1);
+ a->openGL = 0;
+
+ return a;
+}
+
+uiGLContext *uiAreaGetGLContext(uiArea* a)
+{
+ if (!a->openGL) userbug("trying to get GL context from non-GL area");
+
+ return a->glcontext;
+}
+
+uiArea *uiNewGLArea(uiAreaHandler *ah, const unsigned int* req_versions)
+{
+ uiArea *a;
+
+ uiWindowsNewControl(uiArea, a);
+
+ a->width = -1;
+ a->height = -1;
+
+ a->ah = ah;
+ a->scrolling = FALSE;
+ clickCounterReset(&(a->cc));
+
+ // a->hwnd is assigned in areaWndProc()
+ uiWindowsEnsureCreateControlHWND(0,
+ areaClass, L"",
+ 0,
+ hInstance, a,
+ FALSE);
+
+ uiAreaSetBackgroundColor(a, -1, -1, -1);
+
+ a->openGL = 1;
+
+ for (int i = 0; req_versions[i]; i++)
+ {
+ int major = uiGLVerMajor(req_versions[i]);
+ int minor = uiGLVerMinor(req_versions[i]);
+ a->glcontext = createGLContext(a, major, minor);
+ if (a->glcontext) break;
+ }
+
return a;
}
@@ -204,6 +264,9 @@ uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height)
uiWindowsNewControl(uiArea, a);
+ a->width = -1;
+ a->height = -1;
+
a->ah = ah;
a->scrolling = TRUE;
a->scrollWidth = width;
@@ -219,6 +282,8 @@ uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height)
uiAreaSetBackgroundColor(a, -1, -1, -1);
+ a->openGL = 0; // TODO, eventually???
+
// set initial scrolling parameters
areaUpdateScroll(a);
diff --git a/src/libui_sdl/libui/windows/area.hpp b/src/libui_sdl/libui/windows/area.hpp
index add62dd..cfc45a4 100644
--- a/src/libui_sdl/libui/windows/area.hpp
+++ b/src/libui_sdl/libui/windows/area.hpp
@@ -10,6 +10,8 @@ struct uiArea {
HWND hwnd;
uiAreaHandler *ah;
+ int width, height;
+
BOOL scrolling;
int scrollWidth;
int scrollHeight;
@@ -26,6 +28,9 @@ struct uiArea {
int bgR, bgG, bgB;
+ int openGL;
+ uiGLContext* glcontext;
+
ID2D1HwndRenderTarget *rt;
};
@@ -42,6 +47,10 @@ extern void areaUpdateScroll(uiArea *a);
extern BOOL areaDoEvents(uiArea *a, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult);
// areautil.cpp
-extern void loadAreaSize(uiArea *a, ID2D1RenderTarget *rt, double *width, double *height);
+extern void loadAreaSize(uiArea *a, double *width, double *height);
extern void pixelsToDIP(uiArea *a, double *x, double *y);
extern void dipToPixels(uiArea *a, double *x, double *y);
+
+// gl.cpp
+extern uiGLContext* createGLContext(uiArea* a, int vermajor, int verminor);
+extern void freeGLContext(uiGLContext* c);
diff --git a/src/libui_sdl/libui/windows/areadraw.cpp b/src/libui_sdl/libui/windows/areadraw.cpp
index a9ad477..f369255 100644
--- a/src/libui_sdl/libui/windows/areadraw.cpp
+++ b/src/libui_sdl/libui/windows/areadraw.cpp
@@ -6,6 +6,13 @@ static HRESULT doPaint(uiArea *a, ID2D1RenderTarget *rt, RECT *clip)
{
uiAreaHandler *ah = a->ah;
uiAreaDrawParams dp;
+
+ if (a->openGL)
+ {
+ //(*(ah->Draw))(ah, a, &dp);
+ return S_OK;
+ }
+
COLORREF bgcolorref;
D2D1_COLOR_F bgcolor;
D2D1_MATRIX_3X2_F scrollTransform;
@@ -13,7 +20,7 @@ static HRESULT doPaint(uiArea *a, ID2D1RenderTarget *rt, RECT *clip)
// no need to save or restore the graphics state to reset transformations; it's handled by resetTarget() in draw.c, called during the following
dp.Context = newContext(rt);
- loadAreaSize(a, rt, &(dp.AreaWidth), &(dp.AreaHeight));
+ loadAreaSize(a, &(dp.AreaWidth), &(dp.AreaHeight));
dp.ClipX = clip->left;
dp.ClipY = clip->top;
@@ -113,6 +120,9 @@ static void onWM_PAINT(uiArea *a)
static void onWM_PRINTCLIENT(uiArea *a, HDC dc)
{
+ // TODO????
+ if (a->openGL) return;
+
ID2D1DCRenderTarget *rt;
RECT client;
HRESULT hr;
@@ -143,13 +153,16 @@ BOOL areaDoDraw(uiArea *a, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lRe
// TODO only if the render target wasn't just created?
void areaDrawOnResize(uiArea *a, RECT *newClient)
{
- D2D1_SIZE_U size;
+ if (!a->openGL)
+ {
+ D2D1_SIZE_U size;
- size.width = newClient->right - newClient->left;
- size.height = newClient->bottom - newClient->top;
- // don't track the error; we'll get that in EndDraw()
- // see https://msdn.microsoft.com/en-us/library/windows/desktop/dd370994%28v=vs.85%29.aspx
- a->rt->Resize(&size);
+ size.width = newClient->right - newClient->left;
+ size.height = newClient->bottom - newClient->top;
+ // don't track the error; we'll get that in EndDraw()
+ // see https://msdn.microsoft.com/en-us/library/windows/desktop/dd370994%28v=vs.85%29.aspx
+ a->rt->Resize(&size);
+ }
// according to Rick Brewster, we must always redraw the entire client area after calling ID2D1RenderTarget::Resize() (see http://stackoverflow.com/a/33222983/3408572)
// we used to have a uiAreaHandler.RedrawOnResize() method to decide this; now you know why we don't anymore
diff --git a/src/libui_sdl/libui/windows/areaevents.cpp b/src/libui_sdl/libui/windows/areaevents.cpp
index 3ff7a47..46d6ab9 100644
--- a/src/libui_sdl/libui/windows/areaevents.cpp
+++ b/src/libui_sdl/libui/windows/areaevents.cpp
@@ -109,7 +109,7 @@ static void areaMouseEvent(uiArea *a, int down, int up, WPARAM wParam, LPARAM l
me.Y += a->vscrollpos;
}
- loadAreaSize(a, NULL, &(me.AreaWidth), &(me.AreaHeight));
+ loadAreaSize(a, &(me.AreaWidth), &(me.AreaHeight));
me.Down = down;
me.Up = up;
diff --git a/src/libui_sdl/libui/windows/areautil.cpp b/src/libui_sdl/libui/windows/areautil.cpp
index 212ea42..ea13221 100644
--- a/src/libui_sdl/libui/windows/areautil.cpp
+++ b/src/libui_sdl/libui/windows/areautil.cpp
@@ -2,20 +2,35 @@
#include "uipriv_windows.hpp"
#include "area.hpp"
-void loadAreaSize(uiArea *a, ID2D1RenderTarget *rt, double *width, double *height)
+// TODO: make those int rather than double
+void loadAreaSize(uiArea *a, double *width, double *height)
{
D2D1_SIZE_F size;
+ if (a->width != -1)
+ {
+ *width = (double)a->width;
+ *height = (double)a->height;
+ return;
+ }
+
*width = 0;
*height = 0;
if (!a->scrolling) {
- if (rt == NULL)
+ /*if (rt == NULL)
rt = a->rt;
size = realGetSize(rt);
*width = size.width;
*height = size.height;
- dipToPixels(a, width, height);
+ dipToPixels(a, width, height);*/
+ RECT rect;
+ GetWindowRect(a->hwnd, &rect);
+ *width = (double)(rect.right - rect.left);
+ *height = (double)(rect.bottom - rect.top);
}
+
+ a->width = (int)*width;
+ a->height = (int)*height;
}
void pixelsToDIP(uiArea *a, double *x, double *y)
diff --git a/src/libui_sdl/libui/windows/draw.cpp b/src/libui_sdl/libui/windows/draw.cpp
index 11a777d..9a815b9 100644
--- a/src/libui_sdl/libui/windows/draw.cpp
+++ b/src/libui_sdl/libui/windows/draw.cpp
@@ -522,7 +522,7 @@ void uiDrawRestore(uiDrawContext *c)
// bitmap API
-uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height)
+uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height, int alpha)
{
uiDrawBitmap* bmp;
HRESULT hr;
@@ -532,7 +532,8 @@ uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height)
D2D1_BITMAP_PROPERTIES bp2 = D2D1::BitmapProperties();
bp2.dpiX = 0;
bp2.dpiY = 0;
- bp2.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE);
+ bp2.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,
+ alpha ? D2D1_ALPHA_MODE_PREMULTIPLIED : D2D1_ALPHA_MODE_IGNORE);
//c->rt->BeginDraw();
diff --git a/src/libui_sdl/libui/windows/gl.cpp b/src/libui_sdl/libui/windows/gl.cpp
new file mode 100644
index 0000000..c621721
--- /dev/null
+++ b/src/libui_sdl/libui/windows/gl.cpp
@@ -0,0 +1,161 @@
+// 31 march 2019
+#include "uipriv_windows.hpp"
+#include "area.hpp"
+
+#include <GL/gl.h>
+#include <GL/wglext.h>
+
+struct uiGLContext
+{
+ uiArea* a;
+
+ HWND hwnd;
+ HDC dc;
+ HGLRC rc;
+
+ unsigned int version;
+};
+
+
+uiGLContext* createGLContext(uiArea* a, int vermajor, int verminor)
+{
+ uiGLContext* ctx;
+ BOOL res;
+
+ ctx = uiNew(uiGLContext);
+
+ ctx->a = a;
+ ctx->hwnd = a->hwnd;
+
+ PIXELFORMATDESCRIPTOR pfd;
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.nSize = sizeof(pfd);
+ pfd.nVersion = 1;
+ pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
+ pfd.iPixelType = PFD_TYPE_RGBA;
+ pfd.cColorBits = 24;
+ pfd.cAlphaBits = 8;
+ pfd.cDepthBits = 24;
+ pfd.cStencilBits = 8;
+ pfd.iLayerType = PFD_MAIN_PLANE;
+
+ ctx->dc = GetDC(ctx->hwnd);
+ if (!ctx->dc)
+ {
+ uiFree(ctx);
+ return NULL;
+ }
+
+ int pixelformat = ChoosePixelFormat(ctx->dc, &pfd);
+ res = SetPixelFormat(ctx->dc, pixelformat, &pfd);
+ if (!res)
+ {
+ ReleaseDC(ctx->hwnd, ctx->dc);
+ uiFree(ctx);
+ return NULL;
+ }
+
+ ctx->rc = wglCreateContext(ctx->dc);
+ if (!ctx->rc)
+ {
+ ReleaseDC(ctx->hwnd, ctx->dc);
+ uiFree(ctx);
+ return NULL;
+ }
+
+ wglMakeCurrent(ctx->dc, ctx->rc);
+
+ if (vermajor >= 3)
+ {
+ HGLRC (*wglCreateContextAttribsARB)(HDC,HGLRC,const int*);
+ HGLRC rc_better = NULL;
+
+ wglCreateContextAttribsARB = (HGLRC(*)(HDC,HGLRC,const int*))wglGetProcAddress("wglCreateContextAttribsARB");
+ if (wglCreateContextAttribsARB)
+ {
+ int attribs[15];
+ int i = 0;
+
+ attribs[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
+ attribs[i++] = vermajor;
+ attribs[i++] = WGL_CONTEXT_MINOR_VERSION_ARB;
+ attribs[i++] = verminor;
+
+ attribs[i] = 0;
+ rc_better = wglCreateContextAttribsARB(ctx->dc, NULL, attribs);
+ }
+
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(ctx->rc);
+
+ if (!rc_better)
+ {
+ ReleaseDC(ctx->hwnd, ctx->dc);
+ uiFree(ctx);
+ return NULL;
+ }
+
+ ctx->version = uiGLVersion(vermajor, verminor);
+ ctx->rc = rc_better;
+ wglMakeCurrent(ctx->dc, ctx->rc);
+ }
+
+ return ctx;
+}
+
+void freeGLContext(uiGLContext* ctx)
+{
+ if (ctx == NULL) return;
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(ctx->rc);
+ ReleaseDC(ctx->hwnd, ctx->dc);
+ uiFree(ctx);
+}
+
+void uiGLMakeContextCurrent(uiGLContext* ctx)
+{
+ if (ctx == NULL)
+ {
+ wglMakeCurrent(NULL, NULL);
+ return;
+ }
+
+ if (wglGetCurrentContext() == ctx->rc) return;
+ int res = wglMakeCurrent(ctx->dc, ctx->rc);
+}
+
+unsigned int uiGLGetVersion(uiGLContext* ctx)
+{
+ if (ctx == NULL) return 0;
+ return ctx->version;
+}
+
+void *uiGLGetProcAddress(const char* proc)
+{
+ return (void*)wglGetProcAddress(proc);
+}
+
+void uiGLBegin(uiGLContext* ctx)
+{
+}
+
+void uiGLEnd(uiGLContext* ctx)
+{
+}
+
+void uiGLSwapBuffers(uiGLContext* ctx)
+{
+ if (ctx == NULL) return;
+ SwapBuffers(ctx->dc);
+}
+
+int uiGLGetFramebuffer(uiGLContext* ctx)
+{
+ return 0;
+}
+
+float uiGLGetFramebufferScale(uiGLContext* ctx)
+{
+ // TODO
+ return 1;
+}
diff --git a/src/libui_sdl/libui/windows/window.cpp b/src/libui_sdl/libui/windows/window.cpp
index f52e2f6..18d1171 100644
--- a/src/libui_sdl/libui/windows/window.cpp
+++ b/src/libui_sdl/libui/windows/window.cpp
@@ -363,6 +363,21 @@ static void windowMonitorRect(HWND hwnd, RECT *r)
*r = mi.rcMonitor;
}
+void uiWindowPosition(uiWindow *w, int *x, int *y)
+{
+ RECT rect;
+ if (GetWindowRect(w->hwnd, &rect) == 0)
+ logLastError(L"error getting window position");
+ *x = rect.left;
+ *y = rect.top;
+}
+
+void uiWindowSetPosition(uiWindow *w, int x, int y)
+{
+ if (SetWindowPos(w->hwnd, NULL, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER) == 0)
+ logLastError(L"error moving window");
+}
+
void uiWindowContentSize(uiWindow *w, int *width, int *height)
{
RECT r;