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.
|
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 commit; // An *approximate* commit in pages. TODO Better memory usage tracking.
|
||||||
|
uint64_t reserve; // The number of reserved pages.
|
||||||
};
|
};
|
||||||
|
|
||||||
// A physical page of memory.
|
// 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;
|
outputRegion->itemNonGuard.thisItem = outputRegion;
|
||||||
space->usedRegionsNonGuard.InsertEnd(&outputRegion->itemNonGuard);
|
space->usedRegionsNonGuard.InsertEnd(&outputRegion->itemNonGuard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
space->reserve += pagesNeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
// EsPrint("Reserve: %x->%x\n", outputRegion->baseAddress, outputRegion->pageCount * K_PAGE_SIZE + outputRegion->baseAddress);
|
// EsPrint("Reserve: %x->%x\n", outputRegion->baseAddress, outputRegion->pageCount * K_PAGE_SIZE + outputRegion->baseAddress);
|
||||||
|
@ -977,6 +980,8 @@ void MMUnreserve(MMSpace *space, MMRegion *remove, bool unmapPages, bool guardRe
|
||||||
remove->pageCount, ES_FLAGS_DEFAULT);
|
remove->pageCount, ES_FLAGS_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
space->reserve += remove->pageCount;
|
||||||
|
|
||||||
if (space == coreMMSpace) {
|
if (space == coreMMSpace) {
|
||||||
remove->core.used = false;
|
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_START (1)
|
||||||
#define DEBUG_NONE (2)
|
#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();
|
LoadOptions();
|
||||||
|
|
||||||
switch (emulator) {
|
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 " :
|
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 "
|
IsOptionEnabled("Emulator.AHCI") ? "-drive file=bin/drive,if=none,id=mydisk,format=raw,media=disk,index=0 "
|
||||||
"-device ich9-ahci,id=ahci "
|
"-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 "
|
: "-drive file=bin/drive,if=none,id=mydisk,format=raw "
|
||||||
"-device nvme,drive=mydisk,serial=1234 ";
|
"-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);
|
snprintf(cdromFlags, sizeof(cdromFlags), " -cdrom %s ", cdromImage);
|
||||||
} else {
|
} else {
|
||||||
snprintf(cdromFlags, sizeof(cdromFlags), "-drive file=%s,if=none,id=mycdrom,format=raw,media=cdrom,index=1 "
|
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 {
|
} else {
|
||||||
cdromFlags[0] = 0;
|
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 "
|
" -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 "
|
" -netdev user,id=u1 -device e1000,netdev=u1 -object filter-dump,id=f1,netdev=u1,file=bin/net.dat "
|
||||||
" %s %s %s %s ",
|
" %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") : "",
|
debug ? (debug == DEBUG_NONE ? "-enable-kvm" : "-S") : "",
|
||||||
cores, audioFlags2, logFlags, usbFlags, usbFlags2);
|
cores, audioFlags2, logFlags, usbFlags, usbFlags2);
|
||||||
} break;
|
} break;
|
||||||
|
@ -973,7 +974,6 @@ void AddressToLine(const char *symbolFile) {
|
||||||
typedef struct BuildType {
|
typedef struct BuildType {
|
||||||
const char *name, *alias, *emulator;
|
const char *name, *alias, *emulator;
|
||||||
bool optimise, debug, smp, noCompile;
|
bool optimise, debug, smp, noCompile;
|
||||||
int memory;
|
|
||||||
} BuildType;
|
} BuildType;
|
||||||
|
|
||||||
BuildType buildTypes[] = {
|
BuildType buildTypes[] = {
|
||||||
|
@ -1020,8 +1020,7 @@ void DoCommand(const char *l) {
|
||||||
if (encounteredErrors) {
|
if (encounteredErrors) {
|
||||||
printf("Errors were encountered during the build.\n");
|
printf("Errors were encountered during the build.\n");
|
||||||
} else if (entry->emulator) {
|
} else if (entry->emulator) {
|
||||||
Run(entry->emulator[0] == 'q' ? EMULATOR_QEMU : EMULATOR_VIRTUALBOX,
|
Run(entry->emulator[0] == 'q' ? EMULATOR_QEMU : EMULATOR_VIRTUALBOX, entry->smp ? 3 : 1, LOG_NORMAL, entry->debug);
|
||||||
entry->memory ?: 1024, entry->smp ? 3 : 1, LOG_NORMAL, entry->debug);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -251,6 +251,7 @@ typedef struct Option {
|
||||||
OptionVariant defaultState;
|
OptionVariant defaultState;
|
||||||
OptionVariant state;
|
OptionVariant state;
|
||||||
bool useDefaultState;
|
bool useDefaultState;
|
||||||
|
const char *warning;
|
||||||
} Option;
|
} Option;
|
||||||
|
|
||||||
Option options[] = {
|
Option options[] = {
|
||||||
|
@ -262,9 +263,9 @@ Option options[] = {
|
||||||
{ "Driver.FAT", OPTION_TYPE_BOOL, { .b = true } },
|
{ "Driver.FAT", OPTION_TYPE_BOOL, { .b = true } },
|
||||||
{ "Driver.HDAudio", OPTION_TYPE_BOOL, { .b = false } },
|
{ "Driver.HDAudio", OPTION_TYPE_BOOL, { .b = false } },
|
||||||
{ "Driver.I8254x", OPTION_TYPE_BOOL, { .b = true } },
|
{ "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.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.NVMe", OPTION_TYPE_BOOL, { .b = true } },
|
||||||
{ "Driver.Networking", OPTION_TYPE_BOOL, { .b = true } },
|
{ "Driver.Networking", OPTION_TYPE_BOOL, { .b = true } },
|
||||||
{ "Driver.PCI", 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.stb_sprintf", OPTION_TYPE_BOOL, { .b = true } },
|
||||||
{ "Dependency.HarfBuzz", OPTION_TYPE_BOOL, { .b = true } },
|
{ "Dependency.HarfBuzz", OPTION_TYPE_BOOL, { .b = true } },
|
||||||
{ "Dependency.FreeType", 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.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.CDROMImage", OPTION_TYPE_STRING, { .s = NULL } },
|
||||||
{ "Emulator.USBImage", OPTION_TYPE_STRING, { .s = NULL } },
|
{ "Emulator.USBImage", OPTION_TYPE_STRING, { .s = NULL } },
|
||||||
{ "Emulator.USBHostVendor", OPTION_TYPE_STRING, { .s = NULL } },
|
{ "Emulator.USBHostVendor", OPTION_TYPE_STRING, { .s = NULL } },
|
||||||
{ "Emulator.USBHostProduct", OPTION_TYPE_STRING, { .s = NULL } },
|
{ "Emulator.USBHostProduct", OPTION_TYPE_STRING, { .s = NULL } },
|
||||||
{ "Emulator.RunWithSudo", OPTION_TYPE_BOOL, { .b = false } },
|
{ "Emulator.RunWithSudo", OPTION_TYPE_BOOL, { .b = false } },
|
||||||
{ "Emulator.Audio", 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.first_application", OPTION_TYPE_STRING, { .s = NULL } },
|
||||||
{ "General.wallpaper", 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++) {
|
for (uintptr_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
|
||||||
options[i].state = options[i].defaultState;
|
options[i].state = options[i].defaultState;
|
||||||
options[i].useDefaultState = true;
|
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)) {
|
while (s.buffer && EsINIParse(&s)) {
|
||||||
|
|
|
@ -38,14 +38,26 @@ int OptionTableMessage(UIElement *element, UIMessage message, int di, void *dp)
|
||||||
Option *option = options + index;
|
Option *option = options + index;
|
||||||
|
|
||||||
if (option->type == OPTION_TYPE_BOOL) {
|
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) {
|
} else if (option->type == OPTION_TYPE_STRING) {
|
||||||
UIDialogShow(element->window, 0, "New value: \n%t\n%f%b", &option->state.s, "OK");
|
UIDialogShow(element->window, 0, "New value: \n%t\n%f%b", &option->state.s, "OK");
|
||||||
|
option->useDefaultState = false;
|
||||||
} else {
|
} else {
|
||||||
// TODO.
|
// TODO.
|
||||||
|
option->useDefaultState = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
option->useDefaultState = false;
|
|
||||||
UITableResizeColumns(optionTable);
|
UITableResizeColumns(optionTable);
|
||||||
UIElementRefresh(element);
|
UIElementRefresh(element);
|
||||||
UILabelSetContent(unsavedChangedLabel, "You have unsaved changes!", -1);
|
UILabelSetContent(unsavedChangedLabel, "You have unsaved changes!", -1);
|
||||||
|
@ -91,10 +103,6 @@ void ActionSave(void *_unused) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
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();
|
LoadOptions();
|
||||||
|
|
||||||
UIInitialise();
|
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_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_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_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,
|
UI_MSG_USER,
|
||||||
} UIMessage;
|
} UIMessage;
|
||||||
|
@ -370,6 +371,7 @@ typedef struct UIWindow {
|
||||||
XImage *image;
|
XImage *image;
|
||||||
XIC xic;
|
XIC xic;
|
||||||
unsigned ctrlCode, shiftCode, altCode;
|
unsigned ctrlCode, shiftCode, altCode;
|
||||||
|
Window dragSource;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef UI_WINDOWS
|
#ifdef UI_WINDOWS
|
||||||
|
@ -392,6 +394,7 @@ typedef struct UIPanel {
|
||||||
#define UI_PANEL_MEDIUM_SPACING (1 << 5)
|
#define UI_PANEL_MEDIUM_SPACING (1 << 5)
|
||||||
#define UI_PANEL_SMALL_SPACING (1 << 6)
|
#define UI_PANEL_SMALL_SPACING (1 << 6)
|
||||||
#define UI_PANEL_SCROLL (1 << 7)
|
#define UI_PANEL_SCROLL (1 << 7)
|
||||||
|
#define UI_PANEL_BORDER (1 << 8)
|
||||||
UIElement e;
|
UIElement e;
|
||||||
struct UIScrollBar *scrollBar;
|
struct UIScrollBar *scrollBar;
|
||||||
UIRectangle border;
|
UIRectangle border;
|
||||||
|
@ -668,7 +671,8 @@ struct {
|
||||||
Display *display;
|
Display *display;
|
||||||
Visual *visual;
|
Visual *visual;
|
||||||
XIM xim;
|
XIM xim;
|
||||||
Atom windowClosedID;
|
Atom windowClosedID, primaryID, uriListID, plainTextID;
|
||||||
|
Atom dndEnterID, dndPositionID, dndStatusID, dndActionCopyID, dndDropID, dndSelectionID, dndFinishedID, dndAwareID;
|
||||||
Cursor cursors[UI_CURSOR_COUNT];
|
Cursor cursors[UI_CURSOR_COUNT];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1609,6 +1613,10 @@ int _UIPanelMessage(UIElement *element, UIMessage message, int di, void *dp) {
|
||||||
} else if (element->flags & UI_PANEL_WHITE) {
|
} else if (element->flags & UI_PANEL_WHITE) {
|
||||||
UIDrawBlock((UIPainter *) dp, element->bounds, ui.theme.panel2);
|
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) {
|
} else if (message == UI_MSG_MOUSE_WHEEL && panel->scrollBar) {
|
||||||
return UIElementMessage(&panel->scrollBar->e, message, di, dp);
|
return UIElementMessage(&panel->scrollBar->e, message, di, dp);
|
||||||
} else if (message == UI_MSG_SCROLLED) {
|
} else if (message == UI_MSG_SCROLLED) {
|
||||||
|
@ -3430,26 +3438,29 @@ const char *UIDialogShow(UIWindow *window, uint32_t flags, const char *format, .
|
||||||
} else if (format[i] == '%') {
|
} else if (format[i] == '%') {
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
if (format[i] == 'b') {
|
if (format[i] == 'b' /* button */) {
|
||||||
const char *label = va_arg(arguments, const char *);
|
const char *label = va_arg(arguments, const char *);
|
||||||
UIButton *button = UIButtonCreate(&row->e, 0, label, -1);
|
UIButton *button = UIButtonCreate(&row->e, 0, label, -1);
|
||||||
if (!focus) focus = &button->e;
|
if (!focus) focus = &button->e;
|
||||||
button->invoke = _UIDialogButtonInvoke;
|
button->invoke = _UIDialogButtonInvoke;
|
||||||
button->e.cp = (void *) label;
|
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 *);
|
const char *label = va_arg(arguments, const char *);
|
||||||
UILabelCreate(&row->e, 0, label, -1);
|
UILabelCreate(&row->e, 0, label, -1);
|
||||||
} else if (format[i] == 't') {
|
} else if (format[i] == 't' /* textbox */) {
|
||||||
char **buffer = va_arg(arguments, char **);
|
char **buffer = va_arg(arguments, char **);
|
||||||
UITextbox *textbox = UITextboxCreate(&row->e, UI_ELEMENT_H_FILL);
|
UITextbox *textbox = UITextboxCreate(&row->e, UI_ELEMENT_H_FILL);
|
||||||
if (!focus) focus = &textbox->e;
|
if (!focus) focus = &textbox->e;
|
||||||
if (*buffer) UITextboxReplace(textbox, *buffer, _UIStringLength(*buffer), false);
|
if (*buffer) UITextboxReplace(textbox, *buffer, _UIStringLength(*buffer), false);
|
||||||
textbox->e.cp = buffer;
|
textbox->e.cp = buffer;
|
||||||
textbox->e.messageUser = _UIDialogTextboxMessage;
|
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);
|
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);
|
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 {
|
} else {
|
||||||
int j = i;
|
int j = i;
|
||||||
|
@ -3462,7 +3473,7 @@ const char *UIDialogShow(UIWindow *window, uint32_t flags, const char *format, .
|
||||||
va_end(arguments);
|
va_end(arguments);
|
||||||
|
|
||||||
window->dialogOldFocus = window->focused;
|
window->dialogOldFocus = window->focused;
|
||||||
UIElementFocus(focus);
|
UIElementFocus(focus ? focus : window->dialog);
|
||||||
|
|
||||||
// Run the modal message loop.
|
// 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);
|
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;
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4276,7 +4290,19 @@ void UIInitialise() {
|
||||||
|
|
||||||
ui.display = XOpenDisplay(NULL);
|
ui.display = XOpenDisplay(NULL);
|
||||||
ui.visual = XDefaultVisual(ui.display, 0);
|
ui.visual = XDefaultVisual(ui.display, 0);
|
||||||
|
|
||||||
ui.windowClosedID = XInternAtom(ui.display, "WM_DELETE_WINDOW", 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_ARROW] = XCreateFontCursor(ui.display, XC_left_ptr);
|
||||||
ui.cursors[UI_CURSOR_TEXT] = XCreateFontCursor(ui.display, XC_xterm);
|
ui.cursors[UI_CURSOR_TEXT] = XCreateFontCursor(ui.display, XC_xterm);
|
||||||
|
@ -4394,8 +4420,6 @@ void UIWindowPack(UIWindow *window, int _width) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _UIProcessEvent(XEvent *event) {
|
bool _UIProcessEvent(XEvent *event) {
|
||||||
// printf("x11 event: %d\n", event->type);
|
|
||||||
|
|
||||||
if (event->type == ClientMessage && (Atom) event->xclient.data.l[0] == ui.windowClosedID) {
|
if (event->type == ClientMessage && (Atom) event->xclient.data.l[0] == ui.windowClosedID) {
|
||||||
UIWindow *window = _UIFindWindow(event->xclient.window);
|
UIWindow *window = _UIFindWindow(event->xclient.window);
|
||||||
if (!window) return false;
|
if (!window) return false;
|
||||||
|
@ -4514,6 +4538,107 @@ bool _UIProcessEvent(XEvent *event) {
|
||||||
UIWindow *window = _UIFindWindow(event->xfocus.window);
|
UIWindow *window = _UIFindWindow(event->xfocus.window);
|
||||||
if (!window) return false;
|
if (!window) return false;
|
||||||
window->ctrl = window->shift = window->alt = 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;
|
return false;
|
||||||
|
@ -4569,6 +4694,7 @@ bool _UIMessageLoopSingle(int *result) {
|
||||||
void UIWindowPostMessage(UIWindow *window, UIMessage message, void *_dp) {
|
void UIWindowPostMessage(UIWindow *window, UIMessage message, void *_dp) {
|
||||||
// HACK! Xlib doesn't seem to have a nice way to do this,
|
// HACK! Xlib doesn't seem to have a nice way to do this,
|
||||||
// so send a specially crafted key press event instead.
|
// so send a specially crafted key press event instead.
|
||||||
|
// TODO Maybe ClientMessage is what this should use?
|
||||||
uintptr_t dp = (uintptr_t) _dp;
|
uintptr_t dp = (uintptr_t) _dp;
|
||||||
XKeyEvent event = { 0 };
|
XKeyEvent event = { 0 };
|
||||||
event.display = ui.display;
|
event.display = ui.display;
|
||||||
|
|
Loading…
Reference in New Issue