Mercurial > projects > ddmd
view 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 source
/** 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);