mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-13 09:35:23 -04:00
Cleanup X11 message box code and get rid of global 'dpy' variable.
This commit is contained in:
parent
342777b962
commit
a335d7fa06
240
src/Window.c
240
src/Window.c
@ -448,7 +448,6 @@ void Window_DisableRawMouse(void) {
|
|||||||
#define WM_XBUTTONUP 0x020C
|
#define WM_XBUTTONUP 0x020C
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static cc_bool rawMouseInited, rawMouseSupported;
|
|
||||||
typedef BOOL (WINAPI *FUNC_RegisterRawInput)(PCRAWINPUTDEVICE devices, UINT numDevices, UINT size);
|
typedef BOOL (WINAPI *FUNC_RegisterRawInput)(PCRAWINPUTDEVICE devices, UINT numDevices, UINT size);
|
||||||
static FUNC_RegisterRawInput _registerRawInput;
|
static FUNC_RegisterRawInput _registerRawInput;
|
||||||
typedef UINT (WINAPI *FUNC_GetRawInputData)(HRAWINPUT hRawInput, UINT cmd, void* data, UINT* size, UINT headerSize);
|
typedef UINT (WINAPI *FUNC_GetRawInputData)(HRAWINPUT hRawInput, UINT cmd, void* data, UINT* size, UINT headerSize);
|
||||||
@ -910,6 +909,7 @@ void Window_FreeFramebuffer(Bitmap* bmp) {
|
|||||||
DeleteObject(draw_DIB);
|
DeleteObject(draw_DIB);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cc_bool rawMouseInited, rawMouseSupported;
|
||||||
static void InitRawMouse(void) {
|
static void InitRawMouse(void) {
|
||||||
RAWINPUTDEVICE rid;
|
RAWINPUTDEVICE rid;
|
||||||
_registerRawInput = (FUNC_RegisterRawInput)DynamicLib_GetFrom("USER32.DLL", "RegisterRawInputDevices");
|
_registerRawInput = (FUNC_RegisterRawInput)DynamicLib_GetFrom("USER32.DLL", "RegisterRawInputDevices");
|
||||||
@ -1531,138 +1531,138 @@ static void Cursor_DoSetVisible(cc_bool visible) {
|
|||||||
/*########################################################################################################################*
|
/*########################################################################################################################*
|
||||||
*-----------------------------------------------------X11 message box-----------------------------------------------------*
|
*-----------------------------------------------------X11 message box-----------------------------------------------------*
|
||||||
*#########################################################################################################################*/
|
*#########################################################################################################################*/
|
||||||
static Display* dpy;
|
struct X11MessageBox {
|
||||||
static unsigned long X11_Col(cc_uint8 r, cc_uint8 g, cc_uint8 b) {
|
Window win;
|
||||||
Colormap cmap = XDefaultColormap(dpy, DefaultScreen(dpy));
|
Display* dpy;
|
||||||
|
GC gc;
|
||||||
|
unsigned long white, black, background;
|
||||||
|
unsigned long btnBorder, highlight, shadow;
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned long X11_Col(struct X11MessageBox* m, cc_uint8 r, cc_uint8 g, cc_uint8 b) {
|
||||||
|
Colormap cmap = XDefaultColormap(m->dpy, DefaultScreen(m->dpy));
|
||||||
XColor col = { 0 };
|
XColor col = { 0 };
|
||||||
col.red = r << 8;
|
col.red = r << 8;
|
||||||
col.green = g << 8;
|
col.green = g << 8;
|
||||||
col.blue = b << 8;
|
col.blue = b << 8;
|
||||||
col.flags = DoRed | DoGreen | DoBlue;
|
col.flags = DoRed | DoGreen | DoBlue;
|
||||||
|
|
||||||
XAllocColor(dpy, cmap, &col);
|
XAllocColor(m->dpy, cmap, &col);
|
||||||
return col.pixel;
|
return col.pixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
static void X11MessageBox_Init(struct X11MessageBox* m) {
|
||||||
Window win;
|
m->black = BlackPixel(m->dpy, DefaultScreen(m->dpy));
|
||||||
GC gc;
|
m->white = WhitePixel(m->dpy, DefaultScreen(m->dpy));
|
||||||
unsigned long white, black, background;
|
m->background = X11_Col(m, 206, 206, 206);
|
||||||
unsigned long btnBorder, highlight, shadow;
|
|
||||||
} X11Window;
|
|
||||||
|
|
||||||
static void X11Window_Init(X11Window* w) {
|
m->btnBorder = X11_Col(m, 60, 60, 60);
|
||||||
w->black = BlackPixel(dpy, DefaultScreen(dpy));
|
m->highlight = X11_Col(m, 144, 144, 144);
|
||||||
w->white = WhitePixel(dpy, DefaultScreen(dpy));
|
m->shadow = X11_Col(m, 49, 49, 49);
|
||||||
w->background = X11_Col(206, 206, 206);
|
|
||||||
|
|
||||||
w->btnBorder = X11_Col(60, 60, 60);
|
m->win = XCreateSimpleWindow(m->dpy, DefaultRootWindow(m->dpy), 0, 0, 100, 100,
|
||||||
w->highlight = X11_Col(144, 144, 144);
|
0, m->black, m->background);
|
||||||
w->shadow = X11_Col(49, 49, 49);
|
XSelectInput(m->dpy, m->win, ExposureMask | StructureNotifyMask |
|
||||||
|
KeyReleaseMask | PointerMotionMask |
|
||||||
|
ButtonPressMask | ButtonReleaseMask );
|
||||||
|
|
||||||
w->win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 100, 100,
|
m->gc = XCreateGC(m->dpy, m->win, 0, NULL);
|
||||||
0, w->black, w->background);
|
XSetForeground(m->dpy, m->gc, m->black);
|
||||||
XSelectInput(dpy, w->win, ExposureMask | StructureNotifyMask |
|
XSetBackground(m->dpy, m->gc, m->background);
|
||||||
KeyReleaseMask | PointerMotionMask |
|
|
||||||
ButtonPressMask | ButtonReleaseMask );
|
|
||||||
|
|
||||||
w->gc = XCreateGC(dpy, w->win, 0, NULL);
|
|
||||||
XSetForeground(dpy, w->gc, w->black);
|
|
||||||
XSetBackground(dpy, w->gc, w->background);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void X11Window_Free(X11Window* w) {
|
static void X11MessageBox_Free(struct X11MessageBox* m) {
|
||||||
XFreeGC(dpy, w->gc);
|
XFreeGC(m->dpy, m->gc);
|
||||||
XDestroyWindow(dpy, w->win);
|
XDestroyWindow(m->dpy, m->win);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
struct X11Textbox {
|
||||||
int X, Y, Width, Height;
|
int x, y, width, height;
|
||||||
int LineHeight, Descent;
|
int lineHeight, descent;
|
||||||
const char* Text;
|
const char* text;
|
||||||
} X11Textbox;
|
};
|
||||||
|
|
||||||
static void X11Textbox_Measure(X11Textbox* t, XFontStruct* font) {
|
static void X11Textbox_Measure(struct X11Textbox* t, XFontStruct* font) {
|
||||||
String str = String_FromReadonly(t->Text), line;
|
String str = String_FromReadonly(t->text), line;
|
||||||
XCharStruct overall;
|
XCharStruct overall;
|
||||||
int direction, ascent, descent, lines = 0;
|
int direction, ascent, descent, lines = 0;
|
||||||
|
|
||||||
for (; str.length; lines++) {
|
for (; str.length; lines++) {
|
||||||
String_UNSAFE_SplitBy(&str, '\n', &line);
|
String_UNSAFE_SplitBy(&str, '\n', &line);
|
||||||
XTextExtents(font, line.buffer, line.length, &direction, &ascent, &descent, &overall);
|
XTextExtents(font, line.buffer, line.length, &direction, &ascent, &descent, &overall);
|
||||||
t->Width = max(overall.width, t->Width);
|
t->width = max(overall.width, t->width);
|
||||||
}
|
}
|
||||||
|
|
||||||
t->LineHeight = ascent + descent;
|
t->lineHeight = ascent + descent;
|
||||||
t->Descent = descent;
|
t->descent = descent;
|
||||||
t->Height = t->LineHeight * lines;
|
t->height = t->lineHeight * lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void X11Textbox_Draw(X11Textbox* t, X11Window* w) {
|
static void X11Textbox_Draw(struct X11Textbox* t, struct X11MessageBox* m) {
|
||||||
String str = String_FromReadonly(t->Text), line;
|
String str = String_FromReadonly(t->text), line;
|
||||||
int y = t->Y + t->LineHeight - t->Descent; /* TODO: is -Descent even right? */
|
int y = t->y + t->lineHeight - t->descent; /* TODO: is -descent even right? */
|
||||||
|
|
||||||
for (; str.length; y += t->LineHeight) {
|
for (; str.length; y += t->lineHeight) {
|
||||||
String_UNSAFE_SplitBy(&str, '\n', &line);
|
String_UNSAFE_SplitBy(&str, '\n', &line);
|
||||||
XDrawString(dpy, w->win, w->gc, t->X, y, line.buffer, line.length);
|
XDrawString(m->dpy, m->win, m->gc, t->x, y, line.buffer, line.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
struct X11Button {
|
||||||
int X, Y, Width, Height;
|
int x, y, width, height;
|
||||||
cc_bool Clicked;
|
cc_bool clicked;
|
||||||
X11Textbox Text;
|
struct X11Textbox text;
|
||||||
} X11Button;
|
};
|
||||||
|
|
||||||
static void X11Button_Draw(X11Button* b, X11Window* w) {
|
static void X11Button_Draw(struct X11Button* b, struct X11MessageBox* m) {
|
||||||
X11Textbox* t;
|
struct X11Textbox* t;
|
||||||
int begX, endX, begY, endY;
|
int begX, endX, begY, endY;
|
||||||
|
|
||||||
XSetForeground(dpy, w->gc, w->btnBorder);
|
XSetForeground(m->dpy, m->gc, m->btnBorder);
|
||||||
XDrawRectangle(dpy, w->win, w->gc, b->X, b->Y,
|
XDrawRectangle(m->dpy, m->win, m->gc, b->x, b->y,
|
||||||
b->Width, b->Height);
|
b->width, b->height);
|
||||||
|
|
||||||
t = &b->Text;
|
t = &b->text;
|
||||||
begX = b->X + 1; endX = b->X + b->Width - 1;
|
begX = b->x + 1; endX = b->x + b->width - 1;
|
||||||
begY = b->Y + 1; endY = b->Y + b->Height - 1;
|
begY = b->y + 1; endY = b->y + b->height - 1;
|
||||||
|
|
||||||
if (b->Clicked) {
|
if (b->clicked) {
|
||||||
XSetForeground(dpy, w->gc, w->highlight);
|
XSetForeground(m->dpy, m->gc, m->highlight);
|
||||||
XDrawRectangle(dpy, w->win, w->gc, begX, begY,
|
XDrawRectangle(m->dpy, m->win, m->gc, begX, begY,
|
||||||
endX - begX, endY - begY);
|
endX - begX, endY - begY);
|
||||||
} else {
|
} else {
|
||||||
XSetForeground(dpy, w->gc, w->white);
|
XSetForeground(m->dpy, m->gc, m->white);
|
||||||
XDrawLine(dpy, w->win, w->gc, begX, begY,
|
XDrawLine(m->dpy, m->win, m->gc, begX, begY,
|
||||||
endX - 1, begY);
|
endX - 1, begY);
|
||||||
XDrawLine(dpy, w->win, w->gc, begX, begY,
|
XDrawLine(m->dpy, m->win, m->gc, begX, begY,
|
||||||
begX, endY - 1);
|
begX, endY - 1);
|
||||||
|
|
||||||
XSetForeground(dpy, w->gc, w->highlight);
|
XSetForeground(m->dpy, m->gc, m->highlight);
|
||||||
XDrawLine(dpy, w->win, w->gc, begX + 1, endY - 1,
|
XDrawLine(m->dpy, m->win, m->gc, begX + 1, endY - 1,
|
||||||
endX - 1, endY - 1);
|
endX - 1, endY - 1);
|
||||||
XDrawLine(dpy, w->win, w->gc, endX - 1, begY + 1,
|
XDrawLine(m->dpy, m->win, m->gc, endX - 1, begY + 1,
|
||||||
endX - 1, endY - 1);
|
endX - 1, endY - 1);
|
||||||
|
|
||||||
XSetForeground(dpy, w->gc, w->shadow);
|
XSetForeground(m->dpy, m->gc, m->shadow);
|
||||||
XDrawLine(dpy, w->win, w->gc, begX, endY, endX, endY);
|
XDrawLine(m->dpy, m->win, m->gc, begX, endY, endX, endY);
|
||||||
XDrawLine(dpy, w->win, w->gc, endX, begY, endX, endY);
|
XDrawLine(m->dpy, m->win, m->gc, endX, begY, endX, endY);
|
||||||
}
|
}
|
||||||
|
|
||||||
XSetForeground(dpy, w->gc, w->black);
|
XSetForeground(m->dpy, m->gc, m->black);
|
||||||
t->X = b->X + b->Clicked + (b->Width - t->Width) / 2;
|
t->x = b->x + b->clicked + (b->width - t->width) / 2;
|
||||||
t->Y = b->Y + b->Clicked + (b->Height - t->Height) / 2;
|
t->y = b->y + b->clicked + (b->height - t->height) / 2;
|
||||||
X11Textbox_Draw(t, w);
|
X11Textbox_Draw(t, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int X11Button_Contains(X11Button* b, int x, int y) {
|
static int X11Button_Contains(struct X11Button* b, int x, int y) {
|
||||||
return x >= b->X && x < (b->X + b->Width) &&
|
return x >= b->x && x < (b->x + b->width) &&
|
||||||
y >= b->Y && y < (b->Y + b->Height);
|
y >= b->y && y < (b->y + b->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bool X11_FilterEvent(Display* d, XEvent* e, XPointer w) { return e->xany.window == (Window)w; }
|
static Bool X11_FilterEvent(Display* d, XEvent* e, XPointer w) { return e->xany.window == (Window)w; }
|
||||||
static void X11_MessageBox(const char* title, const char* text, X11Window* w) {
|
static void X11_MessageBox(const char* title, const char* text, struct X11MessageBox* m) {
|
||||||
X11Button ok = { 0 };
|
struct X11Button ok = { 0 };
|
||||||
X11Textbox body = { 0 };
|
struct X11Textbox body = { 0 };
|
||||||
|
|
||||||
Atom protocols[2];
|
Atom protocols[2];
|
||||||
XFontStruct* font;
|
XFontStruct* font;
|
||||||
@ -1671,59 +1671,59 @@ static void X11_MessageBox(const char* title, const char* text, X11Window* w) {
|
|||||||
int mouseX = -1, mouseY = -1, over;
|
int mouseX = -1, mouseY = -1, over;
|
||||||
XEvent e;
|
XEvent e;
|
||||||
|
|
||||||
X11Window_Init(w);
|
X11MessageBox_Init(m);
|
||||||
XMapWindow(dpy, w->win);
|
XMapWindow(m->dpy, m->win);
|
||||||
XStoreName(dpy, w->win, title);
|
XStoreName(m->dpy, m->win, title);
|
||||||
|
|
||||||
protocols[0] = XInternAtom(dpy, "WM_DELETE_WINDOW", false);
|
protocols[0] = XInternAtom(m->dpy, "WM_DELETE_WINDOW", false);
|
||||||
protocols[1] = XInternAtom(dpy, "_NET_WM_PING", false);
|
protocols[1] = XInternAtom(m->dpy, "_NET_WM_PING", false);
|
||||||
XSetWMProtocols(dpy, w->win, protocols, 2);
|
XSetWMProtocols(m->dpy, m->win, protocols, 2);
|
||||||
|
|
||||||
font = XQueryFont(dpy, XGContextFromGC(w->gc));
|
font = XQueryFont(m->dpy, XGContextFromGC(m->gc));
|
||||||
if (!font) return;
|
if (!font) return;
|
||||||
|
|
||||||
/* Compute size of widgets */
|
/* Compute size of widgets */
|
||||||
body.Text = text;
|
body.text = text;
|
||||||
X11Textbox_Measure(&body, font);
|
X11Textbox_Measure(&body, font);
|
||||||
ok.Text.Text = "OK";
|
ok.text.text = "OK";
|
||||||
X11Textbox_Measure(&ok.Text, font);
|
X11Textbox_Measure(&ok.text, font);
|
||||||
ok.Width = ok.Text.Width + 70;
|
ok.width = ok.text.width + 70;
|
||||||
ok.Height = ok.Text.Height + 10;
|
ok.height = ok.text.height + 10;
|
||||||
|
|
||||||
/* Compute size and position of window */
|
/* Compute size and position of window */
|
||||||
width = body.Width + 20;
|
width = body.width + 20;
|
||||||
height = body.Height + 20 + ok.Height + 20;
|
height = body.height + 20 + ok.height + 20;
|
||||||
x = DisplayWidth (dpy, DefaultScreen(dpy))/2 - width/2;
|
x = DisplayWidth (m->dpy, DefaultScreen(m->dpy))/2 - width/2;
|
||||||
y = DisplayHeight(dpy, DefaultScreen(dpy))/2 - height/2;
|
y = DisplayHeight(m->dpy, DefaultScreen(m->dpy))/2 - height/2;
|
||||||
XMoveResizeWindow(dpy, w->win, x, y, width, height);
|
XMoveResizeWindow(m->dpy, m->win, x, y, width, height);
|
||||||
|
|
||||||
/* Adjust bounds of widgets */
|
/* Adjust bounds of widgets */
|
||||||
body.X = 10; body.Y = 10;
|
body.x = 10; body.y = 10;
|
||||||
ok.X = width/2 - ok.Width/2;
|
ok.x = width/2 - ok.width/2;
|
||||||
ok.Y = height - ok.Height - 10;
|
ok.y = height - ok.height - 10;
|
||||||
|
|
||||||
/* This marks the window as popup window of the main window */
|
/* This marks the window as popup window of the main window */
|
||||||
/* http://tronche.com/gui/x/icccm/sec-4.html#WM_TRANSIENT_FOR */
|
/* http://tronche.com/gui/x/icccm/sec-4.html#WM_TRANSIENT_FOR */
|
||||||
/* Depending on WM, removes minimise and doesn't show in taskbar */
|
/* Depending on WM, removes minimise and doesn't show in taskbar */
|
||||||
if (win_handle) XSetTransientForHint(dpy, w->win, win_handle);
|
if (win_handle) XSetTransientForHint(m->dpy, m->win, win_handle);
|
||||||
|
|
||||||
XFreeFontInfo(NULL, font, 1);
|
XFreeFontInfo(NULL, font, 1);
|
||||||
XUnmapWindow(dpy, w->win); /* Make window non resizeable */
|
XUnmapWindow(m->dpy, m->win); /* Make window non resizeable */
|
||||||
|
|
||||||
hints.flags = PSize | PMinSize | PMaxSize;
|
hints.flags = PSize | PMinSize | PMaxSize;
|
||||||
hints.min_width = hints.max_width = hints.base_width = width;
|
hints.min_width = hints.max_width = hints.base_width = width;
|
||||||
hints.min_height = hints.max_height = hints.base_height = height;
|
hints.min_height = hints.max_height = hints.base_height = height;
|
||||||
|
|
||||||
XSetWMNormalHints(dpy, w->win, &hints);
|
XSetWMNormalHints(m->dpy, m->win, &hints);
|
||||||
XMapRaised(dpy, w->win);
|
XMapRaised(m->dpy, m->win);
|
||||||
XFlush(dpy);
|
XFlush(m->dpy);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* The naive solution is to use XNextEvent(dpy, &e) here. */
|
/* The naive solution is to use XNextEvent(m->dpy, &e) here. */
|
||||||
/* However this causes issues as that removes events that */
|
/* However this causes issues as that removes events that */
|
||||||
/* should have been delivered to the main game window. */
|
/* should have been delivered to the main game window. */
|
||||||
/* (e.g. breaks initial window resize with i3 WM) */
|
/* (e.g. breaks initial window resize with i3 WM) */
|
||||||
XIfEvent(dpy, &e, X11_FilterEvent, (XPointer)w->win);
|
XIfEvent(m->dpy, &e, X11_FilterEvent, (XPointer)m->win);
|
||||||
|
|
||||||
switch (e.type)
|
switch (e.type)
|
||||||
{
|
{
|
||||||
@ -1732,18 +1732,18 @@ static void X11_MessageBox(const char* title, const char* text, X11Window* w) {
|
|||||||
if (e.xbutton.button != Button1) break;
|
if (e.xbutton.button != Button1) break;
|
||||||
over = X11Button_Contains(&ok, mouseX, mouseY);
|
over = X11Button_Contains(&ok, mouseX, mouseY);
|
||||||
|
|
||||||
if (ok.Clicked && e.type == ButtonRelease) {
|
if (ok.clicked && e.type == ButtonRelease) {
|
||||||
if (over) return;
|
if (over) return;
|
||||||
}
|
}
|
||||||
ok.Clicked = e.type == ButtonPress && over;
|
ok.clicked = e.type == ButtonPress && over;
|
||||||
/* fallthrough to redraw window */
|
/* fallthrough to redraw window */
|
||||||
|
|
||||||
case Expose:
|
case Expose:
|
||||||
case MapNotify:
|
case MapNotify:
|
||||||
XClearWindow(dpy, w->win);
|
XClearWindow(m->dpy, m->win);
|
||||||
X11Textbox_Draw(&body, w);
|
X11Textbox_Draw(&body, m);
|
||||||
X11Button_Draw(&ok, w);
|
X11Button_Draw(&ok, m);
|
||||||
XFlush(dpy);
|
XFlush(m->dpy);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyRelease:
|
case KeyRelease:
|
||||||
@ -1764,22 +1764,22 @@ static void X11_MessageBox(const char* title, const char* text, X11Window* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void ShowDialogCore(const char* title, const char* msg) {
|
static void ShowDialogCore(const char* title, const char* msg) {
|
||||||
X11Window w = { 0 };
|
struct X11MessageBox m = { 0 };
|
||||||
dpy = win_display;
|
m.dpy = win_display;
|
||||||
|
|
||||||
/* Failing to create a display means can't display a message box. */
|
/* Failing to create a display means can't display a message box. */
|
||||||
/* However the user might have launched the game through terminal, */
|
/* However the user might have launched the game through terminal, */
|
||||||
/* so fallback to console instead of just dying from a segfault */
|
/* so fallback to console instead of just dying from a segfault */
|
||||||
if (!dpy) {
|
if (!m.dpy) {
|
||||||
Platform_LogConst("### MESSAGE ###");
|
Platform_LogConst("### MESSAGE ###");
|
||||||
Platform_LogConst(title);
|
Platform_LogConst(title);
|
||||||
Platform_LogConst(msg);
|
Platform_LogConst(msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
X11_MessageBox(title, msg, &w);
|
X11_MessageBox(title, msg, &m);
|
||||||
X11Window_Free(&w);
|
X11MessageBox_Free(&m);
|
||||||
XFlush(dpy); /* flush so window disappears immediately */
|
XFlush(m.dpy); /* flush so window disappears immediately */
|
||||||
}
|
}
|
||||||
|
|
||||||
static GC fb_gc;
|
static GC fb_gc;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user