mirror of https://gitlab.com/nakst/essence
support for latest qemu; update luigi.h
This commit is contained in:
parent
7a9b3da442
commit
edd1b57db7
|
@ -78,6 +78,7 @@ struct MMSpace {
|
|||
|
||||
bool user; // Regions in the space may be accessed from userspace.
|
||||
uint64_t commit; // An *approximate* commit in pages. TODO Better memory usage tracking.
|
||||
uint64_t reserve; // The number of reserved pages.
|
||||
};
|
||||
|
||||
// A physical page of memory.
|
||||
|
@ -933,6 +934,8 @@ MMRegion *MMReserve(MMSpace *space, size_t bytes, unsigned flags, uintptr_t forc
|
|||
outputRegion->itemNonGuard.thisItem = outputRegion;
|
||||
space->usedRegionsNonGuard.InsertEnd(&outputRegion->itemNonGuard);
|
||||
}
|
||||
|
||||
space->reserve += pagesNeeded;
|
||||
}
|
||||
|
||||
// EsPrint("Reserve: %x->%x\n", outputRegion->baseAddress, outputRegion->pageCount * K_PAGE_SIZE + outputRegion->baseAddress);
|
||||
|
@ -976,6 +979,8 @@ void MMUnreserve(MMSpace *space, MMRegion *remove, bool unmapPages, bool guardRe
|
|||
MMArchUnmapPages(space, remove->baseAddress,
|
||||
remove->pageCount, ES_FLAGS_DEFAULT);
|
||||
}
|
||||
|
||||
space->reserve += remove->pageCount;
|
||||
|
||||
if (space == coreMMSpace) {
|
||||
remove->core.used = false;
|
||||
|
|
13
util/build.c
13
util/build.c
|
@ -375,7 +375,7 @@ void Build(bool enableOptimisations, bool compile) {
|
|||
#define DEBUG_START (1)
|
||||
#define DEBUG_NONE (2)
|
||||
|
||||
void Run(int emulator, int memory, int cores, int log, int debug) {
|
||||
void Run(int emulator, int cores, int log, int debug) {
|
||||
LoadOptions();
|
||||
|
||||
switch (emulator) {
|
||||
|
@ -386,7 +386,7 @@ void Run(int emulator, int memory, int cores, int log, int debug) {
|
|||
const char *driveFlags = IsOptionEnabled("Emulator.ATA") ? "-drive file=bin/drive,format=raw,media=disk,index=0 " :
|
||||
IsOptionEnabled("Emulator.AHCI") ? "-drive file=bin/drive,if=none,id=mydisk,format=raw,media=disk,index=0 "
|
||||
"-device ich9-ahci,id=ahci "
|
||||
"-device ide-drive,drive=mydisk,bus=ahci.0 "
|
||||
"-device ide-hd,drive=mydisk,bus=ahci.0 "
|
||||
: "-drive file=bin/drive,if=none,id=mydisk,format=raw "
|
||||
"-device nvme,drive=mydisk,serial=1234 ";
|
||||
|
||||
|
@ -397,7 +397,7 @@ void Run(int emulator, int memory, int cores, int log, int debug) {
|
|||
snprintf(cdromFlags, sizeof(cdromFlags), " -cdrom %s ", cdromImage);
|
||||
} else {
|
||||
snprintf(cdromFlags, sizeof(cdromFlags), "-drive file=%s,if=none,id=mycdrom,format=raw,media=cdrom,index=1 "
|
||||
"-device ide-drive,drive=mycdrom,bus=ahci.1", cdromImage);
|
||||
"-device ide-cd,drive=mycdrom,bus=ahci.1", cdromImage);
|
||||
}
|
||||
} else {
|
||||
cdromFlags[0] = 0;
|
||||
|
@ -432,7 +432,8 @@ void Run(int emulator, int memory, int cores, int log, int debug) {
|
|||
" -device qemu-xhci,id=xhci -device usb-kbd,bus=xhci.0,id=mykeyboard -device usb-mouse,bus=xhci.0,id=mymouse "
|
||||
" -netdev user,id=u1 -device e1000,netdev=u1 -object filter-dump,id=f1,netdev=u1,file=bin/net.dat "
|
||||
" %s %s %s %s ",
|
||||
audioFlags, IsOptionEnabled("Emulator.RunWithSudo") ? "sudo " : "", driveFlags, cdromFlags, memory,
|
||||
audioFlags, IsOptionEnabled("Emulator.RunWithSudo") ? "sudo " : "", driveFlags, cdromFlags,
|
||||
atoi(GetOptionString("Emulator.MemoryMB")),
|
||||
debug ? (debug == DEBUG_NONE ? "-enable-kvm" : "-S") : "",
|
||||
cores, audioFlags2, logFlags, usbFlags, usbFlags2);
|
||||
} break;
|
||||
|
@ -973,7 +974,6 @@ void AddressToLine(const char *symbolFile) {
|
|||
typedef struct BuildType {
|
||||
const char *name, *alias, *emulator;
|
||||
bool optimise, debug, smp, noCompile;
|
||||
int memory;
|
||||
} BuildType;
|
||||
|
||||
BuildType buildTypes[] = {
|
||||
|
@ -1020,8 +1020,7 @@ void DoCommand(const char *l) {
|
|||
if (encounteredErrors) {
|
||||
printf("Errors were encountered during the build.\n");
|
||||
} else if (entry->emulator) {
|
||||
Run(entry->emulator[0] == 'q' ? EMULATOR_QEMU : EMULATOR_VIRTUALBOX,
|
||||
entry->memory ?: 1024, entry->smp ? 3 : 1, LOG_NORMAL, entry->debug);
|
||||
Run(entry->emulator[0] == 'q' ? EMULATOR_QEMU : EMULATOR_VIRTUALBOX, entry->smp ? 3 : 1, LOG_NORMAL, entry->debug);
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
|
@ -251,6 +251,7 @@ typedef struct Option {
|
|||
OptionVariant defaultState;
|
||||
OptionVariant state;
|
||||
bool useDefaultState;
|
||||
const char *warning;
|
||||
} Option;
|
||||
|
||||
Option options[] = {
|
||||
|
@ -262,9 +263,9 @@ Option options[] = {
|
|||
{ "Driver.FAT", OPTION_TYPE_BOOL, { .b = true } },
|
||||
{ "Driver.HDAudio", OPTION_TYPE_BOOL, { .b = false } },
|
||||
{ "Driver.I8254x", OPTION_TYPE_BOOL, { .b = true } },
|
||||
{ "Driver.IDE", OPTION_TYPE_BOOL, { .b = false } },
|
||||
{ "Driver.IDE", OPTION_TYPE_BOOL, { .b = true } },
|
||||
{ "Driver.ISO9660", OPTION_TYPE_BOOL, { .b = true } },
|
||||
{ "Driver.NTFS", OPTION_TYPE_BOOL, { .b = false } },
|
||||
{ "Driver.NTFS", OPTION_TYPE_BOOL, { .b = false }, .warning = "The NTFS driver has not been updated to work with the new FS layer." },
|
||||
{ "Driver.NVMe", OPTION_TYPE_BOOL, { .b = true } },
|
||||
{ "Driver.Networking", OPTION_TYPE_BOOL, { .b = true } },
|
||||
{ "Driver.PCI", OPTION_TYPE_BOOL, { .b = true } },
|
||||
|
@ -289,15 +290,16 @@ Option options[] = {
|
|||
{ "Dependency.stb_sprintf", OPTION_TYPE_BOOL, { .b = true } },
|
||||
{ "Dependency.HarfBuzz", OPTION_TYPE_BOOL, { .b = true } },
|
||||
{ "Dependency.FreeType", OPTION_TYPE_BOOL, { .b = true } },
|
||||
{ "Emulator.AHCI", OPTION_TYPE_BOOL, { .b = false } },
|
||||
{ "Emulator.AHCI", OPTION_TYPE_BOOL, { .b = true } },
|
||||
{ "Emulator.ATA", OPTION_TYPE_BOOL, { .b = false } },
|
||||
{ "Emulator.NVMe", OPTION_TYPE_BOOL, { .b = true } },
|
||||
{ "Emulator.NVMe", OPTION_TYPE_BOOL, { .b = false }, .warning = "Recent versions of Qemu have trouble booting from NVMe drives." },
|
||||
{ "Emulator.CDROMImage", OPTION_TYPE_STRING, { .s = NULL } },
|
||||
{ "Emulator.USBImage", OPTION_TYPE_STRING, { .s = NULL } },
|
||||
{ "Emulator.USBHostVendor", OPTION_TYPE_STRING, { .s = NULL } },
|
||||
{ "Emulator.USBHostProduct", OPTION_TYPE_STRING, { .s = NULL } },
|
||||
{ "Emulator.RunWithSudo", OPTION_TYPE_BOOL, { .b = false } },
|
||||
{ "Emulator.Audio", OPTION_TYPE_BOOL, { .b = false } },
|
||||
{ "Emulator.MemoryMB", OPTION_TYPE_STRING, { .s = "1024" } },
|
||||
{ "General.first_application", OPTION_TYPE_STRING, { .s = NULL } },
|
||||
{ "General.wallpaper", OPTION_TYPE_STRING, { .s = NULL } },
|
||||
};
|
||||
|
@ -312,6 +314,10 @@ void LoadOptions() {
|
|||
for (uintptr_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
|
||||
options[i].state = options[i].defaultState;
|
||||
options[i].useDefaultState = true;
|
||||
|
||||
if (options[i].type == OPTION_TYPE_STRING && options[i].state.s) {
|
||||
options[i].state.s = strdup(options[i].state.s);
|
||||
}
|
||||
}
|
||||
|
||||
while (s.buffer && EsINIParse(&s)) {
|
||||
|
|
|
@ -38,14 +38,26 @@ int OptionTableMessage(UIElement *element, UIMessage message, int di, void *dp)
|
|||
Option *option = options + index;
|
||||
|
||||
if (option->type == OPTION_TYPE_BOOL) {
|
||||
option->state.b = !option->state.b;
|
||||
bool okay = true;
|
||||
|
||||
if (option->warning && !option->state.b) {
|
||||
if (UIDialogShow(element->window, 0, "Warning:\n%s\n%f%b%b", option->warning, "Enable", "Cancel")[0] == 'C') {
|
||||
okay = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (okay) {
|
||||
option->state.b = !option->state.b;
|
||||
option->useDefaultState = false;
|
||||
}
|
||||
} else if (option->type == OPTION_TYPE_STRING) {
|
||||
UIDialogShow(element->window, 0, "New value: \n%t\n%f%b", &option->state.s, "OK");
|
||||
option->useDefaultState = false;
|
||||
} else {
|
||||
// TODO.
|
||||
option->useDefaultState = false;
|
||||
}
|
||||
|
||||
option->useDefaultState = false;
|
||||
UITableResizeColumns(optionTable);
|
||||
UIElementRefresh(element);
|
||||
UILabelSetContent(unsavedChangedLabel, "You have unsaved changes!", -1);
|
||||
|
@ -91,10 +103,6 @@ void ActionSave(void *_unused) {
|
|||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
for (uintptr_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
|
||||
options[i].state = options[i].defaultState;
|
||||
}
|
||||
|
||||
LoadOptions();
|
||||
|
||||
UIInitialise();
|
||||
|
|
144
util/luigi.h
144
util/luigi.h
|
@ -164,6 +164,7 @@ typedef enum UIMessage {
|
|||
UI_MSG_CODE_DECORATE_LINE, // dp = pointer to UICodeDecorateLine
|
||||
UI_MSG_WINDOW_CLOSE, // return 1 to prevent default (process exit for UIWindow; close for UIMDIChild)
|
||||
UI_MSG_TAB_SELECTED, // sent to the tab that was selected (not the tab pane itself)
|
||||
UI_MSG_WINDOW_DROP_FILES, // di = count, dp = char ** of paths
|
||||
|
||||
UI_MSG_USER,
|
||||
} UIMessage;
|
||||
|
@ -370,6 +371,7 @@ typedef struct UIWindow {
|
|||
XImage *image;
|
||||
XIC xic;
|
||||
unsigned ctrlCode, shiftCode, altCode;
|
||||
Window dragSource;
|
||||
#endif
|
||||
|
||||
#ifdef UI_WINDOWS
|
||||
|
@ -392,6 +394,7 @@ typedef struct UIPanel {
|
|||
#define UI_PANEL_MEDIUM_SPACING (1 << 5)
|
||||
#define UI_PANEL_SMALL_SPACING (1 << 6)
|
||||
#define UI_PANEL_SCROLL (1 << 7)
|
||||
#define UI_PANEL_BORDER (1 << 8)
|
||||
UIElement e;
|
||||
struct UIScrollBar *scrollBar;
|
||||
UIRectangle border;
|
||||
|
@ -668,7 +671,8 @@ struct {
|
|||
Display *display;
|
||||
Visual *visual;
|
||||
XIM xim;
|
||||
Atom windowClosedID;
|
||||
Atom windowClosedID, primaryID, uriListID, plainTextID;
|
||||
Atom dndEnterID, dndPositionID, dndStatusID, dndActionCopyID, dndDropID, dndSelectionID, dndFinishedID, dndAwareID;
|
||||
Cursor cursors[UI_CURSOR_COUNT];
|
||||
#endif
|
||||
|
||||
|
@ -1608,6 +1612,10 @@ int _UIPanelMessage(UIElement *element, UIMessage message, int di, void *dp) {
|
|||
UIDrawBlock((UIPainter *) dp, element->bounds, ui.theme.panel1);
|
||||
} else if (element->flags & UI_PANEL_WHITE) {
|
||||
UIDrawBlock((UIPainter *) dp, element->bounds, ui.theme.panel2);
|
||||
}
|
||||
|
||||
if (element->flags & UI_PANEL_BORDER) {
|
||||
UIDrawBorder((UIPainter *) dp, element->bounds, ui.theme.border, UI_RECT_1((int) element->window->scale));
|
||||
}
|
||||
} else if (message == UI_MSG_MOUSE_WHEEL && panel->scrollBar) {
|
||||
return UIElementMessage(&panel->scrollBar->e, message, di, dp);
|
||||
|
@ -3430,26 +3438,29 @@ const char *UIDialogShow(UIWindow *window, uint32_t flags, const char *format, .
|
|||
} else if (format[i] == '%') {
|
||||
i++;
|
||||
|
||||
if (format[i] == 'b') {
|
||||
if (format[i] == 'b' /* button */) {
|
||||
const char *label = va_arg(arguments, const char *);
|
||||
UIButton *button = UIButtonCreate(&row->e, 0, label, -1);
|
||||
if (!focus) focus = &button->e;
|
||||
button->invoke = _UIDialogButtonInvoke;
|
||||
button->e.cp = (void *) label;
|
||||
} else if (format[i] == 's') {
|
||||
} else if (format[i] == 's' /* label from string */) {
|
||||
const char *label = va_arg(arguments, const char *);
|
||||
UILabelCreate(&row->e, 0, label, -1);
|
||||
} else if (format[i] == 't') {
|
||||
} else if (format[i] == 't' /* textbox */) {
|
||||
char **buffer = va_arg(arguments, char **);
|
||||
UITextbox *textbox = UITextboxCreate(&row->e, UI_ELEMENT_H_FILL);
|
||||
if (!focus) focus = &textbox->e;
|
||||
if (*buffer) UITextboxReplace(textbox, *buffer, _UIStringLength(*buffer), false);
|
||||
textbox->e.cp = buffer;
|
||||
textbox->e.messageUser = _UIDialogTextboxMessage;
|
||||
} else if (format[i] == 'f') {
|
||||
} else if (format[i] == 'f' /* horizontal fill */) {
|
||||
UISpacerCreate(&row->e, UI_ELEMENT_H_FILL, 0, 0);
|
||||
} else if (format[i] == 'l') {
|
||||
} else if (format[i] == 'l' /* horizontal line */) {
|
||||
UISpacerCreate(&row->e, UI_SPACER_LINE | UI_ELEMENT_H_FILL, 0, 1);
|
||||
} else if (format[i] == 'u' /* user */) {
|
||||
void (*callback)(UIElement *) = va_arg(arguments, void (*)(UIElement *));
|
||||
callback(&row->e);
|
||||
}
|
||||
} else {
|
||||
int j = i;
|
||||
|
@ -3462,7 +3473,7 @@ const char *UIDialogShow(UIWindow *window, uint32_t flags, const char *format, .
|
|||
va_end(arguments);
|
||||
|
||||
window->dialogOldFocus = window->focused;
|
||||
UIElementFocus(focus);
|
||||
UIElementFocus(focus ? focus : window->dialog);
|
||||
|
||||
// Run the modal message loop.
|
||||
|
||||
|
@ -4262,6 +4273,9 @@ UIWindow *UIWindowCreate(UIWindow *owner, uint32_t flags, const char *cTitle, in
|
|||
|
||||
window->xic = XCreateIC(ui.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, window->window, XNFocusWindow, window->window, NULL);
|
||||
|
||||
int dndVersion = 4;
|
||||
XChangeProperty(ui.display, window->window, ui.dndAwareID, XA_ATOM, 32 /* bits */, PropModeReplace, (uint8_t *) &dndVersion, 1);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
|
@ -4276,7 +4290,19 @@ void UIInitialise() {
|
|||
|
||||
ui.display = XOpenDisplay(NULL);
|
||||
ui.visual = XDefaultVisual(ui.display, 0);
|
||||
|
||||
ui.windowClosedID = XInternAtom(ui.display, "WM_DELETE_WINDOW", 0);
|
||||
ui.primaryID = XInternAtom(ui.display, "PRIMARY", 0);
|
||||
ui.dndEnterID = XInternAtom(ui.display, "XdndEnter", 0);
|
||||
ui.dndPositionID = XInternAtom(ui.display, "XdndPosition", 0);
|
||||
ui.dndStatusID = XInternAtom(ui.display, "XdndStatus", 0);
|
||||
ui.dndActionCopyID = XInternAtom(ui.display, "XdndActionCopy", 0);
|
||||
ui.dndDropID = XInternAtom(ui.display, "XdndDrop", 0);
|
||||
ui.dndSelectionID = XInternAtom(ui.display, "XdndSelection", 0);
|
||||
ui.dndFinishedID = XInternAtom(ui.display, "XdndFinished", 0);
|
||||
ui.dndAwareID = XInternAtom(ui.display, "XdndAware", 0);
|
||||
ui.uriListID = XInternAtom(ui.display, "text/uri-list", 0);
|
||||
ui.plainTextID = XInternAtom(ui.display, "text/plain", 0);
|
||||
|
||||
ui.cursors[UI_CURSOR_ARROW] = XCreateFontCursor(ui.display, XC_left_ptr);
|
||||
ui.cursors[UI_CURSOR_TEXT] = XCreateFontCursor(ui.display, XC_xterm);
|
||||
|
@ -4394,8 +4420,6 @@ void UIWindowPack(UIWindow *window, int _width) {
|
|||
}
|
||||
|
||||
bool _UIProcessEvent(XEvent *event) {
|
||||
// printf("x11 event: %d\n", event->type);
|
||||
|
||||
if (event->type == ClientMessage && (Atom) event->xclient.data.l[0] == ui.windowClosedID) {
|
||||
UIWindow *window = _UIFindWindow(event->xclient.window);
|
||||
if (!window) return false;
|
||||
|
@ -4514,6 +4538,107 @@ bool _UIProcessEvent(XEvent *event) {
|
|||
UIWindow *window = _UIFindWindow(event->xfocus.window);
|
||||
if (!window) return false;
|
||||
window->ctrl = window->shift = window->alt = false;
|
||||
} else if (event->type == ClientMessage && event->xclient.message_type == ui.dndEnterID) {
|
||||
UIWindow *window = _UIFindWindow(event->xclient.window);
|
||||
if (!window) return false;
|
||||
window->dragSource = (Window) event->xclient.data.l[0];
|
||||
} else if (event->type == ClientMessage && event->xclient.message_type == ui.dndPositionID) {
|
||||
UIWindow *window = _UIFindWindow(event->xclient.window);
|
||||
if (!window) return false;
|
||||
XClientMessageEvent m = { 0 };
|
||||
m.type = ClientMessage;
|
||||
m.display = event->xclient.display;
|
||||
m.window = (Window) event->xclient.data.l[0];
|
||||
m.message_type = ui.dndStatusID;
|
||||
m.format = 32;
|
||||
m.data.l[0] = window->window;
|
||||
m.data.l[1] = true;
|
||||
m.data.l[4] = ui.dndActionCopyID;
|
||||
XSendEvent(ui.display, m.window, False, NoEventMask, (XEvent *) &m);
|
||||
XFlush(ui.display);
|
||||
} else if (event->type == ClientMessage && event->xclient.message_type == ui.dndDropID) {
|
||||
UIWindow *window = _UIFindWindow(event->xclient.window);
|
||||
if (!window) return false;
|
||||
|
||||
// TODO Dropping text.
|
||||
|
||||
if (!XConvertSelection(ui.display, ui.dndSelectionID, ui.uriListID, ui.primaryID, window->window, event->xclient.data.l[2])) {
|
||||
XClientMessageEvent m = { 0 };
|
||||
m.type = ClientMessage;
|
||||
m.display = ui.display;
|
||||
m.window = window->dragSource;
|
||||
m.message_type = ui.dndFinishedID;
|
||||
m.format = 32;
|
||||
m.data.l[0] = window->window;
|
||||
m.data.l[1] = 0;
|
||||
m.data.l[2] = ui.dndActionCopyID;
|
||||
XSendEvent(ui.display, m.window, False, NoEventMask, (XEvent *) &m);
|
||||
XFlush(ui.display);
|
||||
}
|
||||
} else if (event->type == SelectionNotify) {
|
||||
UIWindow *window = _UIFindWindow(event->xselection.requestor);
|
||||
if (!window) return false;
|
||||
if (!window->dragSource) return false;
|
||||
|
||||
Atom type = None;
|
||||
int format = 0;
|
||||
uint64_t count = 0, bytesLeft = 0;
|
||||
uint8_t *data = NULL;
|
||||
XGetWindowProperty(ui.display, window->window, ui.primaryID, 0, 65536, False, AnyPropertyType, &type, &format, &count, &bytesLeft, &data);
|
||||
|
||||
if (format == 8 /* bits per character */) {
|
||||
if (event->xselection.target == ui.uriListID) {
|
||||
char *copy = (char *) UI_MALLOC(count);
|
||||
int fileCount = 0;
|
||||
|
||||
for (int i = 0; i < (int) count; i++) {
|
||||
copy[i] = data[i];
|
||||
|
||||
if (i && data[i - 1] == '\r' && data[i] == '\n') {
|
||||
fileCount++;
|
||||
}
|
||||
}
|
||||
|
||||
char **files = (char **) UI_MALLOC(sizeof(char *) * fileCount);
|
||||
fileCount = 0;
|
||||
|
||||
for (int i = 0; i < (int) count; i++) {
|
||||
char *s = copy + i;
|
||||
while (!(i && data[i - 1] == '\r' && data[i] == '\n' && i < (int) count)) i++;
|
||||
copy[i - 1] = 0;
|
||||
|
||||
if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e' && s[4] == ':' && s[5] == '/' && s[6] == '/') {
|
||||
files[fileCount++] = s + 7;
|
||||
}
|
||||
|
||||
// TODO Replace % codes in the URL.
|
||||
}
|
||||
|
||||
UIElementMessage(&window->e, UI_MSG_WINDOW_DROP_FILES, fileCount, files);
|
||||
|
||||
UI_FREE(files);
|
||||
UI_FREE(copy);
|
||||
} else if (event->xselection.target == ui.plainTextID) {
|
||||
// TODO.
|
||||
}
|
||||
}
|
||||
|
||||
XFree(data);
|
||||
|
||||
XClientMessageEvent m = { 0 };
|
||||
m.type = ClientMessage;
|
||||
m.display = ui.display;
|
||||
m.window = window->dragSource;
|
||||
m.message_type = ui.dndFinishedID;
|
||||
m.format = 32;
|
||||
m.data.l[0] = window->window;
|
||||
m.data.l[1] = true;
|
||||
m.data.l[2] = ui.dndActionCopyID;
|
||||
XSendEvent(ui.display, m.window, False, NoEventMask, (XEvent *) &m);
|
||||
XFlush(ui.display);
|
||||
|
||||
window->dragSource = 0; // Drag complete.
|
||||
_UIUpdate();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -4569,6 +4694,7 @@ bool _UIMessageLoopSingle(int *result) {
|
|||
void UIWindowPostMessage(UIWindow *window, UIMessage message, void *_dp) {
|
||||
// HACK! Xlib doesn't seem to have a nice way to do this,
|
||||
// so send a specially crafted key press event instead.
|
||||
// TODO Maybe ClientMessage is what this should use?
|
||||
uintptr_t dp = (uintptr_t) _dp;
|
||||
XKeyEvent event = { 0 };
|
||||
event.display = ui.display;
|
||||
|
|
Loading…
Reference in New Issue