comparison dbg/ui/CrashWindow.d @ 0:10317f0c89a5

Initial commit
author korDen
date Sat, 24 Oct 2009 08:42:06 +0400
parents
children 2cc604139636
comparison
equal deleted inserted replaced
-1:000000000000 0:10317f0c89a5
1 /**
2 A window used to display the data from a CrashInfo struct generated by the
3 runtime's crash handler.
4
5 TODO:
6 * Send report - need SMTP implementation
7 * Save report
8
9 Authors:
10 Jeremie Pelletier
11
12 License:
13 Public Domain
14 */
15 module dbg.ui.CrashWindow;
16
17 import std.c.string;
18 import dlib.CrashHandler;
19 import dbg.Debug : SystemException;
20
21 import std.stdio;
22
23 private enum {
24 ReportWindowWidth = 640,
25 ReportWindowHeight = 480,
26 ReportWindowMinWidth = 320,
27 ReportWindowMinHeight = 240,
28 ReportWindowTitle = "Unhandled exception!"
29 }
30
31 // ----------------------------------------------------------------------------
32 // W i n 3 2
33 // ----------------------------------------------------------------------------
34
35 version(Windows) {
36
37 import win32.windows;
38
39 private enum {
40 ID_LABEL = 100,
41 ID_SAVE_BTN = 101,
42 ID_SEND_BTN = 102,
43 ID_CLOSE_BTN = 103,
44 ID_REPORT = 104
45 }
46
47 enum CLEARTYPE_QUALITY = 5;
48 enum LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x20;
49
50 /**
51 Create the crash window for the given crash information, the routine will
52 return when the window is closed.
53 */
54 void ShowCrashWindow(CrashInfo* crashInfo)
55 in {
56 assert(crashInfo);
57 }
58 body {
59 try {
60
61 HINSTANCE inst = GetModuleHandle(null);
62
63 WNDCLASSEXA wc;
64 wc.cbSize = WNDCLASSEX.sizeof;
65 wc.lpfnWndProc = &ReportWndProc;
66 wc.hInstance = inst;
67 wc.hIcon = cast(HICON)LoadImage(HINSTANCE.init, MAKEINTRESOURCE(OIC_ERROR), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
68 wc.hCursor = cast(HCURSOR)LoadImage(HINSTANCE.init, MAKEINTRESOURCE(OCR_NORMAL), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE);
69 wc.hbrBackground = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
70 wc.lpszClassName = "CrashWindowClass";
71
72 if(!RegisterClassExA(&wc)) SystemException();
73 scope(exit) if(!UnregisterClassA("CrashWindowClass", inst)) SystemException();
74
75 RECT rc = void;
76 GetClientRect(GetDesktopWindow(), &rc);
77
78 writeln(crashInfo.toString);
79
80 HWND wnd = CreateWindowExA(
81 WS_EX_WINDOWEDGE,
82 "CrashWindowClass", ReportWindowTitle,
83 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
84 (rc.right >> 1) - (ReportWindowWidth >> 1), (rc.bottom >> 1) - (ReportWindowHeight >> 1),
85 ReportWindowWidth, ReportWindowHeight,
86 HWND.init, HMENU.init, inst, cast(void*)crashInfo.toString.ptr
87 );
88 if(!wnd) SystemException();
89
90 MSG msg = void;
91 while(GetMessage(&msg, HWND.init, 0, 0)) {
92 TranslateMessage(&msg);
93 DispatchMessage(&msg);
94 }
95
96 } // try
97 catch(Throwable e) {
98 MessageBoxA(HWND.init, (e.toString ~ '\0').ptr, "Crash Window Error!", MB_ICONERROR | MB_OK);
99 }
100 }
101
102 private:
103
104 __gshared HWND saveButton, sendButton, closeButton, reportField;
105
106 extern(Windows)
107 LRESULT ReportWndProc(HWND wnd, uint msg, WPARAM w, LPARAM l) {
108 try {
109
110 switch(msg) {
111 case WM_CREATE:
112 HINSTANCE inst = cast(HINSTANCE).GetModuleHandle(null);
113 CREATESTRUCT* cs = cast(CREATESTRUCT*)l;
114
115 LOGFONTA lf;
116 lf.lfHeight = 15;
117 lf.lfWeight = FW_REGULAR;
118 lf.lfCharSet = DEFAULT_CHARSET;
119 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
120 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
121 lf.lfQuality = CLEARTYPE_QUALITY;
122 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
123
124 HFONT font = .CreateFontIndirectA(&lf);
125 if(!font) SystemException();
126
127 HINSTANCE iconMod = LoadLibraryExA("shell32.dll", null,
128 DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
129
130 HWND CreateButton(string caption, uint id, ushort iconId) {
131 HWND ret = CreateWindowExA(
132 0, "BUTTON", caption.ptr, WS_CHILD | WS_VISIBLE,
133 0, 0, 0, 0, wnd, cast(HMENU)id, inst, null
134 );
135 if(!ret) SystemException();
136
137 SendMessageA(ret, WM_SETFONT, cast(WPARAM)font, 0);
138
139 if(iconMod) {
140 HANDLE icon = LoadImage(iconMod, MAKEINTRESOURCE(iconId), IMAGE_ICON, 24, 24, 0);
141 if(icon) SendMessageA(ret, BM_SETIMAGE, IMAGE_ICON, cast(uint)icon);
142 }
143
144 return ret;
145 }
146
147 saveButton = CreateButton("Save Report", ID_SAVE_BTN, 7);
148 sendButton = CreateButton("Send Report", ID_SEND_BTN, 27);
149 closeButton = CreateButton("Close", ID_CLOSE_BTN, 28);
150
151 if(iconMod) FreeLibrary(cast(HMODULE)iconMod);
152
153 enum ReportFont = "Courier New\0";
154 lf.lfHeight = 14;
155 lf.lfFaceName[0 .. ReportFont.length] = ReportFont;
156
157 font = CreateFontIndirectA(&lf);
158 if(!font) SystemException();
159
160 reportField = CreateWindowExA(
161 WS_EX_CLIENTEDGE, "EDIT", null,
162 WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE |
163 ES_READONLY | ES_MULTILINE | ES_AUTOVSCROLL,
164 0, 0, 0, 0, wnd, cast(HMENU)ID_REPORT, inst, null
165 );
166 if(!reportField) SystemException();
167
168 SendMessageA(reportField, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(5, 5));
169 SendMessageA(reportField, WM_SETFONT, cast(WPARAM)font, 0);
170 SendMessageA(reportField, WM_SETTEXT, 0, cast(LPARAM)cs.lpCreateParams);
171
172 break;
173
174 case WM_DESTROY:
175 PostQuitMessage(0);
176 break;
177
178 case WM_GETMINMAXINFO:
179 MINMAXINFO* mm = cast(MINMAXINFO*)l;
180 mm.ptMinTrackSize.x = ReportWindowMinWidth;
181 mm.ptMinTrackSize.y = ReportWindowMinHeight;
182 break;
183
184 case WM_SIZE:
185 int width = LOWORD(l), halfWidth = width >> 1;
186 int height = HIWORD(l);
187
188 enum {
189 BtnWidth = 125,
190 BtnHeight = 35,
191 NumBtns = 3,
192 Pad = 10,
193 ReportHPad = Pad * 2,
194 ReportVPad = BtnHeight + Pad * 3,
195 BtnVPad = BtnHeight + Pad,
196 BtnHalfWidth = (BtnWidth * NumBtns + (Pad * (NumBtns - 1))) >> 1
197 }
198
199 if(!MoveWindow(reportField, Pad, Pad, width - ReportHPad, height - ReportVPad, true))
200 SystemException();
201
202 void Move(HWND wnd, int i) {
203 if(!MoveWindow(wnd, halfWidth - BtnHalfWidth + BtnWidth * i + Pad * i,
204 height - BtnVPad, BtnWidth, BtnHeight, true))
205 SystemException();
206 }
207
208 Move(saveButton, 0);
209 Move(sendButton, 1);
210 Move(closeButton, 2);
211
212 break;
213
214 case WM_COMMAND:
215 if(HIWORD(w) != BN_CLICKED) break;
216
217 int id = LOWORD(w);
218
219 // GetSaveFileName fails on win7.. no idea why
220 if(id == ID_SAVE_BTN) {
221 /*char[256] path = void;
222 path[0 .. 11] = "Report.txt\0";
223
224 OPENFILENAMEA ofn;
225 ofn.lStructSize = OPENFILENAME.sizeof;
226 ofn.hwndOwner = wnd;
227 ofn.lpstrFilter = "Text File\0*.txt\0\0";
228 ofn.lpstrFile = path.ptr;
229 ofn.nMaxFile = path.length;
230 ofn.Flags = OFN_OVERWRITEPROMPT;
231
232 try {
233 if(!GetSaveFileNameA(&ofn)) SystemException();
234
235 uint len = strlen(path.ptr);
236 if(path[len-4 .. len] != ".txt") path[len .. len + 5] = ".txt\0";
237
238 HANDLE file = CreateFileA(path.ptr, GENERIC_WRITE, 0,
239 null, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, null);
240
241 if(file == INVALID_HANDLE_VALUE) SystemException();
242 scope(exit) if(!CloseHandle(file)) SystemException();
243
244 char* text;
245 SendMessageA(reportField, WM_GETTEXT, 0, cast(LPARAM)text);
246 len = strlen(text);
247
248 uint written = void;
249 if(!WriteFile(file, text, len, &written, null))
250 SystemException();
251
252 if(written != len) throw new SystemException("Couldn't write entire data.");
253
254 id = ID_CLOSE_BTN;
255 }
256 catch(SystemException e) {
257 MessageBoxA(wnd, (e.toString ~ '\0').ptr, "Error!", MB_OK | MB_ICONERROR);
258 }*/
259
260 MessageBoxA(wnd, "TODO", "Error!", MB_OK | MB_ICONERROR);
261 }
262
263 if(id == ID_SEND_BTN)
264 MessageBoxA(wnd, "TODO", "Error!", MB_OK | MB_ICONERROR);
265
266 if(id == ID_CLOSE_BTN)
267 SendMessageA(wnd, WM_CLOSE, 0, 0);
268
269 break;
270
271 default:
272 return DefWindowProcA(wnd, msg, w, l);
273 }
274
275 } // try
276 catch(Exception e) {
277 MessageBoxA(HWND.init, (e.toString ~ '\0').ptr, "Crash Window Handler Error!", MB_ICONERROR | MB_OK);
278 PostQuitMessage(0);
279 }
280
281 return 0;
282 }
283
284 } // version(Windows)
285
286 else version(Gnome) {
287
288 import std.c.stdio;
289
290 import ext.Gnome.gtk;
291 import ext.Gnome.gobject;
292
293 void ErrorGUI(in ErrorReport* report) {
294 int argc;
295 if(!gtk_init_check(&argc, null)) {
296 printf("gtk failed!\n");
297 Pause;
298 }
299
300 void SetSignal(A, B)(A* widget, string signal, B callback) {
301 g_signal_connect(cast(void*)widget, signal.ptr, cast(GCallback)callback, null);
302 }
303
304 // Create the report window
305 GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
306 gtk_window_set_title(cast(GtkWindow*)window, ReportWindowTitle);
307 gtk_window_set_default_size(cast(GtkWindow*)window, ReportWindowWidth, ReportWindowHeight);
308 gtk_window_set_icon_name(cast(GtkWindow*)window, GTK_STOCK_DIALOG_ERROR);
309
310 SetSignal(window, "destroy", &gtk_main_quit);
311
312 // Create the root box
313 GtkWidget* vbox = gtk_vbox_new(false, 0);
314 gtk_container_add(cast(GtkContainer*)window, vbox);
315
316 // Create the report edit
317 GtkWidget* view = gtk_text_view_new();
318 gtk_text_view_set_editable(cast(GtkTextView*)view, false);
319 gtk_text_view_set_cursor_visible(cast(GtkTextView*)view, false);
320
321 GtkTextBuffer* buffer = gtk_text_view_get_buffer(cast(GtkTextView*)view);
322 gtk_text_buffer_set_text(buffer, report.dumpText.ptr, -1);
323
324 gtk_box_pack_start(cast(GtkBox*)vbox, view, true, true, 0);
325
326 // Create the buttons box
327 GtkWidget* hbox = gtk_hbutton_box_new();
328 gtk_box_set_spacing(cast(GtkBox*)hbox, 10);
329 gtk_button_box_set_layout(cast(GtkButtonBox*)hbox, GTK_BUTTONBOX_CENTER);
330 gtk_box_pack_start(cast(GtkBox*)vbox, hbox, false, true, 10);
331
332 // Create the buttons
333 GtkWidget* CreateButton(B)(string label, string stockId, B callback) {
334 GtkWidget* button = gtk_button_new_with_label(label.ptr);
335
336 GtkWidget* image = gtk_image_new_from_stock(stockId.ptr, GTK_ICON_SIZE_BUTTON);
337 gtk_button_set_image(cast(GtkButton*)button, image);
338
339 gtk_container_add(cast(GtkContainer*)hbox, button);
340
341 if(callback) SetSignal(button, "clicked", callback);
342
343 return button;
344 }
345
346 CreateButton("Save Report", GTK_STOCK_SAVE_AS, &OnClickSave);
347 CreateButton("Send Report", GTK_STOCK_CONNECT, &OnClickSend);
348 GtkWidget* close = CreateButton("Close", GTK_STOCK_CLOSE, null);
349
350 g_signal_connect_swapped(cast(void*)close, "clicked",
351 cast(GCallback)(&gtk_widget_destroy), cast(void*)(window));
352
353 // Display the window and run the main loop
354 gtk_widget_show_all(window);
355 gtk_main();
356 }
357
358 extern(C):
359
360 void OnClickSave(GtkButton* button, gpointer user_data) {
361 // TODO
362 }
363
364 void OnClickSend(GtkButton* button, gpointer user_data) {
365 // TODO
366 }
367
368 } // version(Gnome)
369 else static assert(0);