|
1 // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // code for the Windows-dependent derived class |
|
15 // |
|
16 // |
|
17 |
|
18 #include "../SERVER/w32cmd.h" |
|
19 #include <emulator.h> |
|
20 |
|
21 #include "_windows.h" |
|
22 |
|
23 #include "DEBLOGWN.H" |
|
24 |
|
25 |
|
26 // static container for sharing data between Symbian & Windows threads |
|
27 struct TSharedMemory |
|
28 { |
|
29 RSemaphore iStartSemaphore; |
|
30 struct HWND__* iHwnd; |
|
31 }; |
|
32 |
|
33 static struct TSharedMemory GSharedMemory; |
|
34 |
|
35 |
|
36 enum TWindowsUserMessage |
|
37 { |
|
38 EAppendText16, |
|
39 EAppendText8, |
|
40 }; |
|
41 |
|
42 // Constants |
|
43 const int KMaxLogLines = 1000; |
|
44 const int KAverageLogLineLength = 60; |
|
45 const int KWinTimerId = 1; |
|
46 |
|
47 |
|
48 EXPORT_C CDebugLogBase *CreateDebugLog(TBool aIsFirst, TDesC &aParams) |
|
49 { |
|
50 CDebugLogWin *device=new(ELeave) CDebugLogWin(); |
|
51 CDebugLog *log=NULL; |
|
52 TRAPD(err,log=new(ELeave) CDebugLog(device)); |
|
53 if (err!=KErrNone) |
|
54 { |
|
55 delete device; |
|
56 User::Leave(err); |
|
57 } |
|
58 TRAP(err,log->ConstructL(aIsFirst, aParams)); |
|
59 if (err!=KErrNone) |
|
60 { |
|
61 delete log; |
|
62 User::Leave(err); |
|
63 } |
|
64 return(log); |
|
65 } |
|
66 |
|
67 CDebugLogWin::CDebugLogWin() :iThreadCreated(EFalse) |
|
68 {} |
|
69 |
|
70 CDebugLogWin::~CDebugLogWin() |
|
71 { |
|
72 if (iThreadCreated) |
|
73 { |
|
74 if (GSharedMemory.iHwnd) |
|
75 { |
|
76 PostMessage(GSharedMemory.iHwnd, WM_CLOSE, 0, 0); |
|
77 } |
|
78 iThread.Close(); |
|
79 iThreadCreated = 0; |
|
80 GSharedMemory.iStartSemaphore.Close(); |
|
81 } |
|
82 } |
|
83 |
|
84 void CDebugLogWin::ConstructL(TBool , TDesC &) |
|
85 { |
|
86 _LIT(KLog,"DebugLog"); |
|
87 GSharedMemory.iStartSemaphore.CreateLocal(0); |
|
88 User::LeaveIfError(iThread.Create(KLog,logWinMain,KDefaultStackSize,KHeapSize,KHeapSize,(TAny *)123)); |
|
89 iThreadCreated=ETrue; |
|
90 iThread.Resume(); |
|
91 GSharedMemory.iStartSemaphore.Wait(); |
|
92 } |
|
93 |
|
94 void CDebugLogWin::WriteToLogL(const TDesC &aDes, const TDesC &aDes2) |
|
95 { |
|
96 TBuf<LogTBufSize*2+1> bufPlusZero; |
|
97 bufPlusZero.Copy(iTextBuf); |
|
98 bufPlusZero.Append(aDes); |
|
99 bufPlusZero.ZeroTerminate(); |
|
100 TInt32 bufferAddr = (TInt32)(bufPlusZero.Ptr()); |
|
101 // synchronously transfer string to debug window |
|
102 Emulator::Escape(); |
|
103 SendMessage(GSharedMemory.iHwnd, WM_USER + EAppendText16, 0, bufferAddr); |
|
104 Emulator::Reenter(); |
|
105 iTextBuf.Copy(aDes2); |
|
106 } |
|
107 |
|
108 void CDebugLogWin::WriteToLog8L(const TDesC8 &aDes, const TDesC8 &aDes2) |
|
109 { |
|
110 TBuf8<LogTBufSize*2+1> bufPlusZero; |
|
111 bufPlusZero.Copy(iTextBuf); |
|
112 bufPlusZero.Append(aDes); |
|
113 bufPlusZero.ZeroTerminate(); |
|
114 TInt32 bufferAddr = (TInt32)(bufPlusZero.Ptr()); |
|
115 // synchronously transfer string to debug window |
|
116 Emulator::Escape(); |
|
117 SendMessage(GSharedMemory.iHwnd, WM_USER + EAppendText8, 0, bufferAddr); |
|
118 Emulator::Reenter(); |
|
119 iTextBuf.Copy(aDes2); |
|
120 } |
|
121 |
|
122 TInt32 __stdcall WndProc(struct HWND__ *aHwnd, TUint aMessage, |
|
123 TUint wParam, TInt32 lParam) |
|
124 { |
|
125 static HWND hWndListBox; |
|
126 static HFONT hfont; |
|
127 static TBool timerSet = EFalse; |
|
128 |
|
129 switch (aMessage) |
|
130 { |
|
131 case WM_CREATE: |
|
132 { // Disable Close menu option |
|
133 HMENU menu = GetSystemMenu(aHwnd, FALSE); |
|
134 EnableMenuItem(menu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED); |
|
135 |
|
136 // create fixed pitch font for debug log |
|
137 LOGFONT lf; |
|
138 if (GetObject(hfont, sizeof(lf), &lf)) |
|
139 { |
|
140 lf.lfPitchAndFamily = FIXED_PITCH; |
|
141 lstrcpy(lf.lfFaceName, L"courier"); |
|
142 hfont = CreateFontIndirect(&lf); |
|
143 } |
|
144 else |
|
145 { |
|
146 hfont = CreateFont(16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, |
|
147 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, L"courier"); |
|
148 } |
|
149 |
|
150 HINSTANCE hinstance = ((LPCREATESTRUCT) lParam) -> hInstance; |
|
151 SendMessage(aHwnd, WM_SETFONT, (WPARAM) (hfont), 0); |
|
152 RECT clientRect; |
|
153 GetClientRect(aHwnd, &clientRect); |
|
154 |
|
155 hWndListBox = CreateWindowEx(WS_EX_CLIENTEDGE, |
|
156 L"listbox", |
|
157 NULL, |
|
158 WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_BORDER | LBS_NOINTEGRALHEIGHT, |
|
159 0, 0, |
|
160 clientRect.right, clientRect.bottom, |
|
161 aHwnd, (HMENU) 1, hinstance, NULL); |
|
162 SendMessage(hWndListBox, WM_SETFONT, (WPARAM) (hfont), 0); |
|
163 |
|
164 // preallocate string memory |
|
165 SendMessage(hWndListBox, LB_INITSTORAGE, KMaxLogLines + 20, KAverageLogLineLength); |
|
166 } |
|
167 return 0; |
|
168 |
|
169 case WM_USER+EAppendText16: |
|
170 { // send wide char string to ListBox |
|
171 int numRows = SendMessageW(hWndListBox, LB_ADDSTRING, 0, lParam); |
|
172 // if too many lines set a timer to delete some lines |
|
173 if (!timerSet && (numRows > KMaxLogLines) ) |
|
174 { // set a timer for 2s |
|
175 SetTimer(aHwnd, KWinTimerId, 2000, NULL); |
|
176 timerSet = ETrue; |
|
177 } |
|
178 |
|
179 // scroll ListBox so that newest line is visible |
|
180 SendMessage(hWndListBox, LB_SETTOPINDEX, numRows, 0); |
|
181 } |
|
182 return KErrNone; |
|
183 |
|
184 case WM_USER+EAppendText8: |
|
185 { // send narrow character string to ListBox |
|
186 int numRows = SendMessageA(hWndListBox, LB_ADDSTRING, 0, lParam); |
|
187 // if too many lines set a timer to delete some lines |
|
188 if (!timerSet && (numRows > KMaxLogLines) ) |
|
189 { // set a timer for 2s |
|
190 SetTimer(aHwnd, KWinTimerId, 2000, NULL); |
|
191 timerSet = ETrue; |
|
192 } |
|
193 |
|
194 // scroll ListBox so that newest line is visible |
|
195 SendMessage(hWndListBox, LB_SETTOPINDEX, numRows, 0); |
|
196 } |
|
197 return KErrNone; |
|
198 |
|
199 case WM_TIMER: |
|
200 { // too many rows in listbox, release some memory |
|
201 TInt numRows; |
|
202 do |
|
203 { |
|
204 numRows = SendMessage(hWndListBox, LB_DELETESTRING, 0, 0); |
|
205 } |
|
206 while (numRows > KMaxLogLines); |
|
207 KillTimer(aHwnd, KWinTimerId); |
|
208 timerSet = EFalse; |
|
209 |
|
210 // ensure newest line is visible (delete moves focus to line 0) |
|
211 SendMessage(hWndListBox, LB_SETTOPINDEX, numRows-1, 0); |
|
212 } |
|
213 break; |
|
214 |
|
215 case WM_SIZE: |
|
216 // forward to the ListBox, and make it repaint |
|
217 if ( (wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED) ) |
|
218 { |
|
219 int width = LOWORD(lParam); |
|
220 int height = HIWORD(lParam); |
|
221 MoveWindow(hWndListBox, 0, 0, width, height, TRUE); |
|
222 } |
|
223 return 0; |
|
224 |
|
225 case WM_DESTROY: |
|
226 PostQuitMessage(0); |
|
227 DeleteObject(hfont); |
|
228 return 0; |
|
229 |
|
230 case WM_SYSCOMMAND: |
|
231 if (wParam == SC_CLOSE) |
|
232 { // do not allow window to be closed with ALT-F4 (this would close the emulator) |
|
233 return 1; |
|
234 } |
|
235 break; |
|
236 } |
|
237 |
|
238 return DefWindowProc(aHwnd, aMessage, wParam, lParam); |
|
239 } |
|
240 |
|
241 TInt logWinMain(TAny *) |
|
242 { |
|
243 MSG msg; |
|
244 WNDCLASS wndclass; |
|
245 const TText *szAppName=_S("Window Server Log"); |
|
246 |
|
247 wndclass.style=CS_HREDRAW|CS_VREDRAW; |
|
248 wndclass.lpfnWndProc=WndProc; |
|
249 wndclass.cbClsExtra=0; |
|
250 wndclass.cbWndExtra=0; |
|
251 wndclass.hInstance=NULL; |
|
252 wndclass.hIcon=LoadIcon(NULL, IDI_APPLICATION); |
|
253 wndclass.hCursor=LoadCursor(NULL, IDC_ARROW); |
|
254 wndclass.hbrBackground=(HBRUSH)GetSysColorBrush(COLOR_BTNFACE); |
|
255 wndclass.lpszMenuName=NULL; |
|
256 wndclass.lpszClassName=(LPCTSTR)szAppName; |
|
257 |
|
258 RegisterClass(&wndclass); |
|
259 |
|
260 GSharedMemory.iHwnd = CreateWindow((LPCTSTR)szAppName, |
|
261 (LPCTSTR)szAppName, |
|
262 WS_OVERLAPPEDWINDOW, |
|
263 CW_USEDEFAULT, |
|
264 CW_USEDEFAULT, |
|
265 CW_USEDEFAULT, |
|
266 CW_USEDEFAULT, |
|
267 NULL, |
|
268 NULL, |
|
269 NULL, |
|
270 NULL); |
|
271 |
|
272 ShowWindow(GSharedMemory.iHwnd, SW_SHOWMINNOACTIVE); |
|
273 |
|
274 GSharedMemory.iStartSemaphore.Signal(); // allows logging to start now that the window, etc. has been set up |
|
275 |
|
276 // Must remove thread from Symbian scheduler before calling blocking Windows APIs (e.g. GetMessage) |
|
277 Emulator::Escape(); |
|
278 while (GetMessage(&msg, NULL, 0, 0)) |
|
279 { |
|
280 TranslateMessage(&msg); |
|
281 DispatchMessage(&msg); |
|
282 } |
|
283 // return to Symbian Scheduler |
|
284 Emulator::Reenter(); |
|
285 GSharedMemory.iHwnd = NULL; |
|
286 return msg.wParam; |
|
287 } |