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", &gtk_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)(&gtk_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