C client: Implement error dialog on linux

This commit is contained in:
UnknownShadow200 2018-09-09 13:44:18 +10:00
parent d5faaf9c26
commit eb007e91cd

View File

@ -2,6 +2,8 @@
#include "Platform.h" #include "Platform.h"
#include "Chat.h" #include "Chat.h"
#include "Window.h" #include "Window.h"
#include "Funcs.h"
static void ErrorHandler_FailCore(ReturnCode result, const char* raw_msg, void* ctx); static void ErrorHandler_FailCore(ReturnCode result, const char* raw_msg, void* ctx);
static void ErrorHandler_Backtrace(STRING_TRANSIENT String* str, void* ctx); static void ErrorHandler_Backtrace(STRING_TRANSIENT String* str, void* ctx);
static void ErrorHandler_Registers(STRING_TRANSIENT String* str, void* ctx); static void ErrorHandler_Registers(STRING_TRANSIENT String* str, void* ctx);
@ -119,12 +121,240 @@ static void ErrorHandler_Backtrace(STRING_TRANSIENT String* str, void* ctx) {
String_AppendConst(str, "\r\n"); String_AppendConst(str, "\r\n");
} }
#elif CC_BUILD_NIX #elif CC_BUILD_NIX
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
Display* dpy;
unsigned long X11_Col(UInt8 r, UInt8 g, UInt8 b) {
Colormap cmap = XDefaultColormap(dpy, DefaultScreen(dpy));
XColor col = { 0 };
col.red = r << 8;
col.green = g << 8;
col.blue = b << 8;
col.flags = DoRed | DoGreen | DoBlue;
XAllocColor(dpy, cmap, &col);
return col.pixel;
}
typedef struct {
Window win;
GC gc;
unsigned long white, black, background;
unsigned long btnBorder, highlight, shadow;
} X11Window;
static void X11Window_Init(X11Window* w) {
w->black = BlackPixel(dpy, DefaultScreen(dpy));
w->white = WhitePixel(dpy, DefaultScreen(dpy));
w->background = X11_Col(206, 206, 206);
w->btnBorder = X11_Col(60, 60, 60);
w->highlight = X11_Col(144, 144, 144);
w->shadow = X11_Col(49, 49, 49);
w->win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 100, 100,
0, w->black, w->background);
XSelectInput(dpy, w->win, ExposureMask | StructureNotifyMask |
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) {
XFreeGC(dpy, w->gc);
XDestroyWindow(dpy, w->win);
}
typedef struct {
int X, Y, Width, Height;
int LineHeight, Descent;
const char* Text;
} X11Textbox;
static void X11Textbox_Measure(X11Textbox* t, XFontStruct* font) {
String str = String_FromReadonly(t->Text);
int direction, ascent, descent, end, lines = 0;
XCharStruct overall;
for (end = 0; end >= 0; lines++) {
end = String_IndexOf(&str, '\n', 0);
Int32 len = end == -1 ? str.length : end;
XTextExtents(font, str.buffer, len, &direction, &ascent, &descent, &overall);
t->Width = max(overall.width, t->Width);
if (end >= 0) str = String_UNSAFE_SubstringAt(&str, end + 1);
}
t->LineHeight = ascent + descent;
t->Descent = descent;
t->Height = t->LineHeight * lines;
}
static void X11Textbox_Draw(X11Textbox* t, X11Window* w) {
String str = String_FromReadonly(t->Text);
int end, y = t->Y + t->LineHeight - t->Descent; /* TODO: is -Descent even right? */
for (end = 0; end >= 0; y += t->LineHeight) {
end = String_IndexOf(&str, '\n', 0);
Int32 len = end == -1 ? str.length : end;
XDrawString(dpy, w->win, w->gc, t->X, y, str.buffer, len);
if (end >= 0) str = String_UNSAFE_SubstringAt(&str, end + 1);
}
}
typedef struct {
int X, Y, Width, Height;
bool Clicked;
X11Textbox Text;
} X11Button;
static void X11Button_Draw(X11Button* b, X11Window* w) {
XSetForeground(dpy, w->gc, w->btnBorder);
XDrawRectangle(dpy, w->win, w->gc, b->X, b->Y,
b->Width, b->Height);
X11Textbox* t = &b->Text;
int begX = b->X + 1, endX = b->X + b->Width - 1;
int begY = b->Y + 1, endY = b->Y + b->Height - 1;
if (b->Clicked) {
XSetForeground(dpy, w->gc, w->highlight);
XDrawRectangle(dpy, w->win, w->gc, begX, begY,
endX - begX, endY - begY);
} else {
XSetForeground(dpy, w->gc, w->white);
XDrawLine(dpy, w->win, w->gc, begX, begY,
endX - 1, begY);
XDrawLine(dpy, w->win, w->gc, begX, begY,
begX, endY - 1);
XSetForeground(dpy, w->gc, w->highlight);
XDrawLine(dpy, w->win, w->gc, begX + 1, endY - 1,
endX - 1, endY - 1);
XDrawLine(dpy, w->win, w->gc, endX - 1, begY + 1,
endX - 1, endY - 1);
XSetForeground(dpy, w->gc, w->shadow);
XDrawLine(dpy, w->win, w->gc, begX, endY, endX, endY);
XDrawLine(dpy, w->win, w->gc, endX, begY, endX, endY);
}
XSetForeground(dpy, w->gc, w->black);
t->X = b->X + b->Clicked + (b->Width - t->Width) / 2;
t->Y = b->Y + b->Clicked + (b->Height - t->Height) / 2;
X11Textbox_Draw(t, w);
}
static int X11Button_Contains(X11Button* b, int x, int y) {
return x >= b->X && x < (b->X + b->Width) &&
y >= b->Y && y < (b->Y + b->Height);
}
static void X11_MessageBox(const char* title, const char* text, X11Window* w) {
X11Button ok = { 0 };
X11Textbox body = { 0 };
X11Window_Init(w);
XMapWindow(dpy, w->win);
XStoreName(dpy, w->win, title);
Atom wmDelete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
XSetWMProtocols(dpy, w->win, &wmDelete, 1);
XFontStruct* font = XQueryFont(dpy, XGContextFromGC(w->gc));
if (!font) return;
/* Compute size of widgets */
body.Text = text;
X11Textbox_Measure(&body, font);
ok.Text.Text = "OK";
X11Textbox_Measure(&ok.Text, font);
ok.Width = ok.Text.Width + 70;
ok.Height = ok.Text.Height + 10;
/* Compute size and position of window */
int width = body.Width + 20;
int height = body.Height + 20 + ok.Height + 20;
int x = DisplayWidth (dpy, DefaultScreen(dpy))/2 - width/2;
int y = DisplayHeight(dpy, DefaultScreen(dpy))/2 - height/2;
XMoveResizeWindow(dpy, w->win, x, y, width, height);
/* Adjust bounds of widgets */
body.X = 10; body.Y = 10;
ok.X = width/2 - ok.Width/2;
ok.Y = height - ok.Height - 10;
XFreeFontInfo(NULL, font, 1);
XUnmapWindow(dpy, w->win); /* Make window non resizeable */
XSizeHints hints = { 0 };
hints.flags = PSize | PMinSize | PMaxSize;
hints.min_width = hints.max_width = hints.base_width = width;
hints.min_height = hints.max_height = hints.base_height = height;
XSetWMNormalHints(dpy, w->win, &hints);
XMapRaised(dpy, w->win);
XFlush(dpy);
XEvent e;
int mouseX = -1, mouseY = -1;
for (;;) {
XNextEvent(dpy, &e);
switch (e.type)
{
case ButtonPress:
case ButtonRelease:
if (e.xbutton.button != Button1) break;
int over = X11Button_Contains(&ok, mouseX, mouseY);
if (ok.Clicked && e.type == ButtonRelease) {
if (over) return;
}
ok.Clicked = e.type == ButtonPress && over;
/* fallthrough to redraw window */
case Expose:
case MapNotify:
XClearWindow(dpy, w->win);
X11Textbox_Draw(&body, w);
X11Button_Draw(&ok, w);
XFlush(dpy);
break;
case KeyRelease:
if (XLookupKeysym(&e.xkey, 0) == XK_Escape) return;
break;
case ClientMessage:
if (e.xclient.data.l[0] == wmDelete) return;
break;
case MotionNotify:
mouseX = e.xmotion.x; mouseY = e.xmotion.y;
break;
}
}
}
void ErrorHandler_Init(const char* logFile) { void ErrorHandler_Init(const char* logFile) {
/* TODO: Implement this */ /* TODO: Implement this */
} }
void ErrorHandler_ShowDialog(const char* title, const char* msg) { void ErrorHandler_ShowDialog(const char* title, const char* msg) {
/* TODO: Implement this */ X11Window w = { 0 };
dpy = DisplayDevice_Meta[0];
X11_MessageBox(title, msg, &w);
X11Window_Free(&w);
} }
void ErrorHandler_Backtrace(STRING_TRANSIENT String* str, void* ctx) { void ErrorHandler_Backtrace(STRING_TRANSIENT String* str, void* ctx) {