Mercurial > projects > ddmd
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", >k_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)(>k_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); |