mirror of https://gitlab.com/nakst/essence
update x11 backend
This commit is contained in:
parent
3595c43fd7
commit
9e1a09d208
|
@ -403,7 +403,8 @@ bool PerformanceTimerDrift() {
|
||||||
EsPrint("Performance timer: %F s.\n", performanceTime);
|
EsPrint("Performance timer: %F s.\n", performanceTime);
|
||||||
EsPrint("Main timer: %F s.\n", mainTime);
|
EsPrint("Main timer: %F s.\n", mainTime);
|
||||||
|
|
||||||
CHECK(EsCRTfabs(performanceTime - mainTime) / mainTime < 0.1); // Less than a 10% drift.
|
// TODO Improve the quality of the performance timer, if better timer sources are available, like the HPET.
|
||||||
|
CHECK(EsCRTfabs(performanceTime - mainTime) / mainTime < 0.2); // Less than a 20% drift.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <sys/statvfs.h>
|
#include <sys/statvfs.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
@ -37,6 +38,7 @@ struct Object {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Thread : Object {
|
struct Thread : Object {
|
||||||
|
uintptr_t parameters[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Process : Object {
|
struct Process : Object {
|
||||||
|
@ -262,11 +264,19 @@ bool MessagePost(_EsMessageWithObject *message) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *ThreadUser(void *object) {
|
||||||
|
Thread *thread = (Thread *) object;
|
||||||
|
((void (*)(uintptr_t, uintptr_t)) thread->parameters[0])(thread->parameters[1], thread->parameters[2]);
|
||||||
|
ReferenceClose(thread);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
uintptr_t _APISyscall(uintptr_t index, uintptr_t argument0, uintptr_t argument1, uintptr_t, uintptr_t argument2, uintptr_t argument3) {
|
uintptr_t _APISyscall(uintptr_t index, uintptr_t argument0, uintptr_t argument1, uintptr_t, uintptr_t argument2, uintptr_t argument3) {
|
||||||
// TODO.
|
// TODO.
|
||||||
|
|
||||||
if (index == ES_SYSCALL_THREAD_GET_ID) {
|
if (index == ES_SYSCALL_THREAD_GET_ID) {
|
||||||
return pthread_self();
|
// TODO.
|
||||||
|
return 0;
|
||||||
} else if (index == ES_SYSCALL_THREAD_SET_TLS) {
|
} else if (index == ES_SYSCALL_THREAD_SET_TLS) {
|
||||||
tls = argument0;
|
tls = argument0;
|
||||||
return ES_SUCCESS;
|
return ES_SUCCESS;
|
||||||
|
@ -422,22 +432,27 @@ uintptr_t _APISyscall(uintptr_t index, uintptr_t argument0, uintptr_t argument1,
|
||||||
} else if (index == ES_SYSCALL_WINDOW_SET_PROPERTY) {
|
} else if (index == ES_SYSCALL_WINDOW_SET_PROPERTY) {
|
||||||
uint8_t property = argument3;
|
uint8_t property = argument3;
|
||||||
UIWindow *window = (UIWindow *) HandleResolve(argument0, OBJECT_WINDOW);
|
UIWindow *window = (UIWindow *) HandleResolve(argument0, OBJECT_WINDOW);
|
||||||
|
pthread_mutex_lock(&windowsMutex);
|
||||||
|
|
||||||
if (property == ES_WINDOW_PROPERTY_OBJECT) {
|
if (property == ES_WINDOW_PROPERTY_OBJECT) {
|
||||||
pthread_mutex_lock(&windowsMutex);
|
|
||||||
window->apiObject = (void *) argument2;
|
window->apiObject = (void *) argument2;
|
||||||
_EsMessageWithObject m = {};
|
_EsMessageWithObject m = {};
|
||||||
m.object = window->apiObject;
|
m.object = window->apiObject;
|
||||||
m.message.type = ES_MSG_WINDOW_RESIZED;
|
m.message.type = ES_MSG_WINDOW_RESIZED;
|
||||||
m.message.windowResized.content = ES_RECT_2S(window->width, window->height);
|
m.message.windowResized.content = ES_RECT_2S(window->width, window->height);
|
||||||
MessagePost(&m);
|
MessagePost(&m);
|
||||||
pthread_mutex_unlock(&windowsMutex);
|
} else if (property == ES_WINDOW_PROPERTY_SOLID
|
||||||
|
|| property == ES_WINDOW_PROPERTY_MATERIAL
|
||||||
|
|| property == ES_WINDOW_PROPERTY_BLUR_BOUNDS
|
||||||
|
|| property == ES_WINDOW_PROPERTY_ALPHA) {
|
||||||
|
// TODO.
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Unimplemented window property %d.\n", property);
|
fprintf(stderr, "Unimplemented window property %d.\n", property);
|
||||||
exit(1);
|
exit(1);
|
||||||
return ES_ERROR_UNSUPPORTED_FEATURE;
|
return ES_ERROR_UNSUPPORTED_FEATURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&windowsMutex);
|
||||||
return ES_SUCCESS;
|
return ES_SUCCESS;
|
||||||
} else if (index == ES_SYSCALL_WINDOW_SET_CURSOR) {
|
} else if (index == ES_SYSCALL_WINDOW_SET_CURSOR) {
|
||||||
// TODO.
|
// TODO.
|
||||||
|
@ -487,8 +502,155 @@ uintptr_t _APISyscall(uintptr_t index, uintptr_t argument0, uintptr_t argument1,
|
||||||
|
|
||||||
pthread_mutex_unlock(&windowsMutex);
|
pthread_mutex_unlock(&windowsMutex);
|
||||||
return ES_SUCCESS;
|
return ES_SUCCESS;
|
||||||
|
} else if (index == ES_SYSCALL_WINDOW_CREATE) {
|
||||||
|
EsWindowStyle style = (EsWindowStyle) argument0;
|
||||||
|
void *apiObject = (void *) argument2;
|
||||||
|
|
||||||
|
UIWindow *window = (UIWindow *) EsHeapAllocate(sizeof(UIWindow), true);
|
||||||
|
window->type = OBJECT_WINDOW;
|
||||||
|
window->referenceCount = 1;
|
||||||
|
window->id = __sync_fetch_and_add(&objectIDAllocator, 1);
|
||||||
|
window->apiObject = apiObject;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&windowsMutex);
|
||||||
|
XSetWindowAttributes attributes = {};
|
||||||
|
attributes.override_redirect = style == ES_WINDOW_MENU;
|
||||||
|
window->window = XCreateWindow(ui.display, DefaultRootWindow(ui.display), 0, 0, 800, 600, 0, 0,
|
||||||
|
InputOutput, CopyFromParent, CWOverrideRedirect, &attributes);
|
||||||
|
XSelectInput(ui.display, window->window, SubstructureNotifyMask | ExposureMask | PointerMotionMask
|
||||||
|
| ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask
|
||||||
|
| EnterWindowMask | LeaveWindowMask | ButtonMotionMask | KeymapStateMask | FocusChangeMask);
|
||||||
|
XSetWMProtocols(ui.display, window->window, &ui.windowClosedID, 1);
|
||||||
|
window->image = XCreateImage(ui.display, ui.visual, 24, ZPixmap, 0, NULL, 10, 10, 32, 0);
|
||||||
|
window->xic = XCreateIC(ui.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, window->window,
|
||||||
|
XNFocusWindow, window->window, NULL);
|
||||||
|
windows.Add(window);
|
||||||
|
|
||||||
|
if (argument2 == ES_WINDOW_MENU) {
|
||||||
|
Atom properties[] = {
|
||||||
|
XInternAtom(ui.display, "_NET_WM_WINDOW_TYPE", true),
|
||||||
|
XInternAtom(ui.display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", true),
|
||||||
|
XInternAtom(ui.display, "_MOTIF_WM_HINTS", true),
|
||||||
|
};
|
||||||
|
|
||||||
|
XChangeProperty(ui.display, window->window, properties[0], XA_ATOM, 32, PropModeReplace, (uint8_t *) properties, 2);
|
||||||
|
XSetTransientForHint(ui.display, window->window, DefaultRootWindow(ui.display));
|
||||||
|
|
||||||
|
struct Hints {
|
||||||
|
int flags;
|
||||||
|
int functions;
|
||||||
|
int decorations;
|
||||||
|
int inputMode;
|
||||||
|
int status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Hints hints = { 0 };
|
||||||
|
hints.flags = 2;
|
||||||
|
XChangeProperty(ui.display, window->window, properties[2], properties[2], 32, PropModeReplace, (uint8_t *) &hints, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&windowsMutex);
|
||||||
|
|
||||||
|
return HandleOpen(window);
|
||||||
|
} else if (index == ES_SYSCALL_WINDOW_MOVE) {
|
||||||
|
UIWindow *window = (UIWindow *) HandleResolve(argument0, OBJECT_WINDOW);
|
||||||
|
EsRectangle point = *(EsRectangle *) argument1;
|
||||||
|
int width = ES_RECT_WIDTH(point), height = ES_RECT_HEIGHT(point);
|
||||||
|
pthread_mutex_lock(&windowsMutex);
|
||||||
|
|
||||||
|
if (argument3 & ES_WINDOW_MOVE_HIDDEN) {
|
||||||
|
// TODO.
|
||||||
|
} else {
|
||||||
|
XMapWindow(ui.display, window->window);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argument3 & ES_WINDOW_MOVE_MAXIMIZED) {
|
||||||
|
// TODO.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argument3 & ES_WINDOW_MOVE_ADJUST_TO_FIT_SCREEN) {
|
||||||
|
for (int i = 0; i < ScreenCount(ui.display); i++) {
|
||||||
|
Screen *screen = ScreenOfDisplay(ui.display, i);
|
||||||
|
|
||||||
|
int x, y;
|
||||||
|
Window child;
|
||||||
|
XTranslateCoordinates(ui.display, screen->root, DefaultRootWindow(ui.display), 0, 0, &x, &y, &child);
|
||||||
|
|
||||||
|
if (point.l >= x && point.l < x + screen->width
|
||||||
|
&& point.t >= y && point.t < y + screen->height) {
|
||||||
|
if (point.l + width > x + screen->width) point.l = x + screen->width - width;
|
||||||
|
if (point.t + height > y + screen->height) point.t = y + screen->height - height;
|
||||||
|
if (point.l < x) point.l = x;
|
||||||
|
if (point.t < y) point.t = y;
|
||||||
|
if (point.l + width > x + screen->width) width = x + screen->width - point.l;
|
||||||
|
if (point.t + height > y + screen->height) height = y + screen->height - point.t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XMoveResizeWindow(ui.display, window->window, point.l, point.t, width, height);
|
||||||
|
pthread_mutex_unlock(&windowsMutex);
|
||||||
|
return ES_SUCCESS;
|
||||||
|
} else if (index == ES_SYSCALL_THREAD_CREATE) {
|
||||||
|
Thread *threadObject = (Thread *) EsHeapAllocate(sizeof(Thread), true);
|
||||||
|
if (!threadObject) return ES_ERROR_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
|
threadObject->type = OBJECT_THREAD;
|
||||||
|
threadObject->referenceCount = 2;
|
||||||
|
threadObject->parameters[0] = argument0;
|
||||||
|
threadObject->parameters[1] = argument3;
|
||||||
|
threadObject->parameters[2] = argument1;
|
||||||
|
|
||||||
|
EsThreadInformation *thread = (EsThreadInformation *) argument2;
|
||||||
|
EsMemoryZero(thread, sizeof(EsThreadInformation));
|
||||||
|
|
||||||
|
pthread_t pthread;
|
||||||
|
pthread_create(&pthread, nullptr, ThreadUser, threadObject);
|
||||||
|
// TODO Handling errors.
|
||||||
|
// TODO Saving and closing this handle.
|
||||||
|
|
||||||
|
thread->tid = 0; // TODO.
|
||||||
|
thread->handle = HandleOpen(threadObject);
|
||||||
|
|
||||||
|
return ES_SUCCESS;
|
||||||
|
} else if (index == ES_SYSCALL_EVENT_SET) {
|
||||||
|
Event *event = (Event *) HandleResolve(argument0, OBJECT_EVENT);
|
||||||
|
int value;
|
||||||
|
sem_getvalue(&event->semaphore, &value);
|
||||||
|
assert(event->autoReset); // TODO Events with autoReset false.
|
||||||
|
assert(!value);
|
||||||
|
sem_post(&event->semaphore);
|
||||||
|
return ES_SUCCESS;
|
||||||
|
} else if (index == ES_SYSCALL_EVENT_RESET) {
|
||||||
|
Event *event = (Event *) HandleResolve(argument0, OBJECT_EVENT);
|
||||||
|
int value;
|
||||||
|
sem_getvalue(&event->semaphore, &value);
|
||||||
|
assert(event->autoReset); // TODO Events with autoReset false.
|
||||||
|
assert(!value);
|
||||||
|
return ES_SUCCESS;
|
||||||
|
} else if (index == ES_SYSCALL_WAIT) {
|
||||||
|
assert(argument1 == 1); // TODO Waiting on multiple object.
|
||||||
|
Object *object = HandleResolve(*(EsHandle *) argument0, 0);
|
||||||
|
assert(object->type == OBJECT_EVENT); // TODO Waiting on other object types.
|
||||||
|
Event *event = (Event *) object;
|
||||||
|
assert(event->autoReset); // TODO Events with autoReset false.
|
||||||
|
|
||||||
|
if ((int) argument2 == ES_WAIT_NO_TIMEOUT) {
|
||||||
|
while (sem_wait(&event->semaphore) == -1);
|
||||||
|
return ES_SUCCESS;
|
||||||
|
} else {
|
||||||
|
struct timespec t;
|
||||||
|
clock_gettime(CLOCK_REALTIME, &t);
|
||||||
|
uint64_t x = (uint64_t) t.tv_sec * 1000000000 + (uint64_t) t.tv_nsec + (uint64_t) argument2 * 1000000;
|
||||||
|
t.tv_sec = x / 1000000000, t.tv_nsec = x % 1000000000;
|
||||||
|
sem_timedwait(&event->semaphore, &t);
|
||||||
|
int s = -1;
|
||||||
|
while ((s = sem_timedwait(&event->semaphore, &t)) == -1 && errno == EINTR);
|
||||||
|
return s == -1 ? ES_ERROR_TIMEOUT_REACHED : 0;
|
||||||
|
}
|
||||||
} else if (index == ES_SYSCALL_PROCESS_CRASH) {
|
} else if (index == ES_SYSCALL_PROCESS_CRASH) {
|
||||||
assert(false);
|
assert(false); // Do an assertion failure so it can be caught by an attached debugger.
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Unimplemented system call '%s' (%ld).\n", EnumLookupNameFromValue(enumStrings_EsSyscallType, index), index);
|
fprintf(stderr, "Unimplemented system call '%s' (%ld).\n", EnumLookupNameFromValue(enumStrings_EsSyscallType, index), index);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -648,7 +810,8 @@ void *UIThread(void *) {
|
||||||
XMapRaised(ui.display, window->window);
|
XMapRaised(ui.display, window->window);
|
||||||
XSetWMProtocols(ui.display, window->window, &ui.windowClosedID, 1);
|
XSetWMProtocols(ui.display, window->window, &ui.windowClosedID, 1);
|
||||||
window->image = XCreateImage(ui.display, ui.visual, 24, ZPixmap, 0, NULL, 10, 10, 32, 0);
|
window->image = XCreateImage(ui.display, ui.visual, 24, ZPixmap, 0, NULL, 10, 10, 32, 0);
|
||||||
window->xic = XCreateIC(ui.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, window->window, XNFocusWindow, window->window, NULL);
|
window->xic = XCreateIC(ui.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, window->window,
|
||||||
|
XNFocusWindow, window->window, NULL);
|
||||||
windows.Add(window);
|
windows.Add(window);
|
||||||
|
|
||||||
_EsMessageWithObject m = {};
|
_EsMessageWithObject m = {};
|
||||||
|
|
Loading…
Reference in New Issue