Mercurial > projects > ddmd
diff dbg/ui/CrashWindow.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | 2cc604139636 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dbg/ui/CrashWindow.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,369 @@ +/** + A window used to display the data from a CrashInfo struct generated by the + runtime's crash handler. + + TODO: + * Send report - need SMTP implementation + * Save report + + Authors: + Jeremie Pelletier + + License: + Public Domain +*/ +module dbg.ui.CrashWindow; + +import std.c.string; +import dlib.CrashHandler; +import dbg.Debug : SystemException; + +import std.stdio; + +private enum { + ReportWindowWidth = 640, + ReportWindowHeight = 480, + ReportWindowMinWidth = 320, + ReportWindowMinHeight = 240, + ReportWindowTitle = "Unhandled exception!" +} + +// ---------------------------------------------------------------------------- +// W i n 3 2 +// ---------------------------------------------------------------------------- + +version(Windows) { + +import win32.windows; + +private enum { + ID_LABEL = 100, + ID_SAVE_BTN = 101, + ID_SEND_BTN = 102, + ID_CLOSE_BTN = 103, + ID_REPORT = 104 +} + +enum CLEARTYPE_QUALITY = 5; +enum LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x20; + +/** + Create the crash window for the given crash information, the routine will + return when the window is closed. +*/ +void ShowCrashWindow(CrashInfo* crashInfo) +in { + assert(crashInfo); +} +body { + try { + + HINSTANCE inst = GetModuleHandle(null); + + WNDCLASSEXA wc; + wc.cbSize = WNDCLASSEX.sizeof; + wc.lpfnWndProc = &ReportWndProc; + wc.hInstance = inst; + wc.hIcon = cast(HICON)LoadImage(HINSTANCE.init, MAKEINTRESOURCE(OIC_ERROR), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); + wc.hCursor = cast(HCURSOR)LoadImage(HINSTANCE.init, MAKEINTRESOURCE(OCR_NORMAL), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE); + wc.hbrBackground = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); + wc.lpszClassName = "CrashWindowClass"; + + if(!RegisterClassExA(&wc)) SystemException(); + scope(exit) if(!UnregisterClassA("CrashWindowClass", inst)) SystemException(); + + RECT rc = void; + GetClientRect(GetDesktopWindow(), &rc); + + writeln(crashInfo.toString); + + HWND wnd = CreateWindowExA( + WS_EX_WINDOWEDGE, + "CrashWindowClass", ReportWindowTitle, + WS_OVERLAPPEDWINDOW | WS_VISIBLE, + (rc.right >> 1) - (ReportWindowWidth >> 1), (rc.bottom >> 1) - (ReportWindowHeight >> 1), + ReportWindowWidth, ReportWindowHeight, + HWND.init, HMENU.init, inst, cast(void*)crashInfo.toString.ptr + ); + if(!wnd) SystemException(); + + MSG msg = void; + while(GetMessage(&msg, HWND.init, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + } // try + catch(Throwable e) { + MessageBoxA(HWND.init, (e.toString ~ '\0').ptr, "Crash Window Error!", MB_ICONERROR | MB_OK); + } +} + +private: + +__gshared HWND saveButton, sendButton, closeButton, reportField; + +extern(Windows) +LRESULT ReportWndProc(HWND wnd, uint msg, WPARAM w, LPARAM l) { + try { + + switch(msg) { + case WM_CREATE: + HINSTANCE inst = cast(HINSTANCE).GetModuleHandle(null); + CREATESTRUCT* cs = cast(CREATESTRUCT*)l; + + LOGFONTA lf; + lf.lfHeight = 15; + lf.lfWeight = FW_REGULAR; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfQuality = CLEARTYPE_QUALITY; + lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + + HFONT font = .CreateFontIndirectA(&lf); + if(!font) SystemException(); + + HINSTANCE iconMod = LoadLibraryExA("shell32.dll", null, + DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); + + HWND CreateButton(string caption, uint id, ushort iconId) { + HWND ret = CreateWindowExA( + 0, "BUTTON", caption.ptr, WS_CHILD | WS_VISIBLE, + 0, 0, 0, 0, wnd, cast(HMENU)id, inst, null + ); + if(!ret) SystemException(); + + SendMessageA(ret, WM_SETFONT, cast(WPARAM)font, 0); + + if(iconMod) { + HANDLE icon = LoadImage(iconMod, MAKEINTRESOURCE(iconId), IMAGE_ICON, 24, 24, 0); + if(icon) SendMessageA(ret, BM_SETIMAGE, IMAGE_ICON, cast(uint)icon); + } + + return ret; + } + + saveButton = CreateButton("Save Report", ID_SAVE_BTN, 7); + sendButton = CreateButton("Send Report", ID_SEND_BTN, 27); + closeButton = CreateButton("Close", ID_CLOSE_BTN, 28); + + if(iconMod) FreeLibrary(cast(HMODULE)iconMod); + + enum ReportFont = "Courier New\0"; + lf.lfHeight = 14; + lf.lfFaceName[0 .. ReportFont.length] = ReportFont; + + font = CreateFontIndirectA(&lf); + if(!font) SystemException(); + + reportField = CreateWindowExA( + WS_EX_CLIENTEDGE, "EDIT", null, + WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE | + ES_READONLY | ES_MULTILINE | ES_AUTOVSCROLL, + 0, 0, 0, 0, wnd, cast(HMENU)ID_REPORT, inst, null + ); + if(!reportField) SystemException(); + + SendMessageA(reportField, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(5, 5)); + SendMessageA(reportField, WM_SETFONT, cast(WPARAM)font, 0); + SendMessageA(reportField, WM_SETTEXT, 0, cast(LPARAM)cs.lpCreateParams); + + break; + + case WM_DESTROY: + PostQuitMessage(0); + break; + + case WM_GETMINMAXINFO: + MINMAXINFO* mm = cast(MINMAXINFO*)l; + mm.ptMinTrackSize.x = ReportWindowMinWidth; + mm.ptMinTrackSize.y = ReportWindowMinHeight; + break; + + case WM_SIZE: + int width = LOWORD(l), halfWidth = width >> 1; + int height = HIWORD(l); + + enum { + BtnWidth = 125, + BtnHeight = 35, + NumBtns = 3, + Pad = 10, + ReportHPad = Pad * 2, + ReportVPad = BtnHeight + Pad * 3, + BtnVPad = BtnHeight + Pad, + BtnHalfWidth = (BtnWidth * NumBtns + (Pad * (NumBtns - 1))) >> 1 + } + + if(!MoveWindow(reportField, Pad, Pad, width - ReportHPad, height - ReportVPad, true)) + SystemException(); + + void Move(HWND wnd, int i) { + if(!MoveWindow(wnd, halfWidth - BtnHalfWidth + BtnWidth * i + Pad * i, + height - BtnVPad, BtnWidth, BtnHeight, true)) + SystemException(); + } + + Move(saveButton, 0); + Move(sendButton, 1); + Move(closeButton, 2); + + break; + + case WM_COMMAND: + if(HIWORD(w) != BN_CLICKED) break; + + int id = LOWORD(w); + + // GetSaveFileName fails on win7.. no idea why + if(id == ID_SAVE_BTN) { + /*char[256] path = void; + path[0 .. 11] = "Report.txt\0"; + + OPENFILENAMEA ofn; + ofn.lStructSize = OPENFILENAME.sizeof; + ofn.hwndOwner = wnd; + ofn.lpstrFilter = "Text File\0*.txt\0\0"; + ofn.lpstrFile = path.ptr; + ofn.nMaxFile = path.length; + ofn.Flags = OFN_OVERWRITEPROMPT; + + try { + if(!GetSaveFileNameA(&ofn)) SystemException(); + + uint len = strlen(path.ptr); + if(path[len-4 .. len] != ".txt") path[len .. len + 5] = ".txt\0"; + + HANDLE file = CreateFileA(path.ptr, GENERIC_WRITE, 0, + null, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, null); + + if(file == INVALID_HANDLE_VALUE) SystemException(); + scope(exit) if(!CloseHandle(file)) SystemException(); + + char* text; + SendMessageA(reportField, WM_GETTEXT, 0, cast(LPARAM)text); + len = strlen(text); + + uint written = void; + if(!WriteFile(file, text, len, &written, null)) + SystemException(); + + if(written != len) throw new SystemException("Couldn't write entire data."); + + id = ID_CLOSE_BTN; + } + catch(SystemException e) { + MessageBoxA(wnd, (e.toString ~ '\0').ptr, "Error!", MB_OK | MB_ICONERROR); + }*/ + + MessageBoxA(wnd, "TODO", "Error!", MB_OK | MB_ICONERROR); + } + + if(id == ID_SEND_BTN) + MessageBoxA(wnd, "TODO", "Error!", MB_OK | MB_ICONERROR); + + if(id == ID_CLOSE_BTN) + SendMessageA(wnd, WM_CLOSE, 0, 0); + + break; + + default: + return DefWindowProcA(wnd, msg, w, l); + } + + } // try + catch(Exception e) { + MessageBoxA(HWND.init, (e.toString ~ '\0').ptr, "Crash Window Handler Error!", MB_ICONERROR | MB_OK); + PostQuitMessage(0); + } + + return 0; +} + +} // version(Windows) + +else version(Gnome) { + +import std.c.stdio; + +import ext.Gnome.gtk; +import ext.Gnome.gobject; + +void ErrorGUI(in ErrorReport* report) { + int argc; + if(!gtk_init_check(&argc, null)) { + printf("gtk failed!\n"); + Pause; + } + + void SetSignal(A, B)(A* widget, string signal, B callback) { + g_signal_connect(cast(void*)widget, signal.ptr, cast(GCallback)callback, null); + } + + // Create the report window + GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(cast(GtkWindow*)window, ReportWindowTitle); + gtk_window_set_default_size(cast(GtkWindow*)window, ReportWindowWidth, ReportWindowHeight); + gtk_window_set_icon_name(cast(GtkWindow*)window, GTK_STOCK_DIALOG_ERROR); + + SetSignal(window, "destroy", >k_main_quit); + + // Create the root box + GtkWidget* vbox = gtk_vbox_new(false, 0); + gtk_container_add(cast(GtkContainer*)window, vbox); + + // Create the report edit + GtkWidget* view = gtk_text_view_new(); + gtk_text_view_set_editable(cast(GtkTextView*)view, false); + gtk_text_view_set_cursor_visible(cast(GtkTextView*)view, false); + + GtkTextBuffer* buffer = gtk_text_view_get_buffer(cast(GtkTextView*)view); + gtk_text_buffer_set_text(buffer, report.dumpText.ptr, -1); + + gtk_box_pack_start(cast(GtkBox*)vbox, view, true, true, 0); + + // Create the buttons box + GtkWidget* hbox = gtk_hbutton_box_new(); + gtk_box_set_spacing(cast(GtkBox*)hbox, 10); + gtk_button_box_set_layout(cast(GtkButtonBox*)hbox, GTK_BUTTONBOX_CENTER); + gtk_box_pack_start(cast(GtkBox*)vbox, hbox, false, true, 10); + + // Create the buttons + GtkWidget* CreateButton(B)(string label, string stockId, B callback) { + GtkWidget* button = gtk_button_new_with_label(label.ptr); + + GtkWidget* image = gtk_image_new_from_stock(stockId.ptr, GTK_ICON_SIZE_BUTTON); + gtk_button_set_image(cast(GtkButton*)button, image); + + gtk_container_add(cast(GtkContainer*)hbox, button); + + if(callback) SetSignal(button, "clicked", callback); + + return button; + } + + CreateButton("Save Report", GTK_STOCK_SAVE_AS, &OnClickSave); + CreateButton("Send Report", GTK_STOCK_CONNECT, &OnClickSend); + GtkWidget* close = CreateButton("Close", GTK_STOCK_CLOSE, null); + + g_signal_connect_swapped(cast(void*)close, "clicked", + cast(GCallback)(>k_widget_destroy), cast(void*)(window)); + + // Display the window and run the main loop + gtk_widget_show_all(window); + gtk_main(); +} + +extern(C): + +void OnClickSave(GtkButton* button, gpointer user_data) { + // TODO +} + +void OnClickSend(GtkButton* button, gpointer user_data) { + // TODO +} + +} // version(Gnome) +else static assert(0); \ No newline at end of file