Move wxBell() from base to core library.
[wxWidgets.git] / src / msw / utilsgui.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/utilsgui.cpp
3 // Purpose: Various utility functions only available in GUI
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 21.06.2003 (extracted from msw/utils.cpp)
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/cursor.h"
29 #include "wx/window.h"
30 #include "wx/utils.h"
31 #endif //WX_PRECOMP
32
33 #include "wx/dynlib.h"
34
35 #include "wx/msw/private.h" // includes <windows.h>
36 #include "wx/msw/registry.h"
37 #include <shellapi.h> // needed for SHELLEXECUTEINFO
38
39
40 // ============================================================================
41 // implementation
42 // ============================================================================
43
44 // Emit a beeeeeep
45 void wxBell()
46 {
47 ::MessageBeep((UINT)-1); // default sound
48 }
49
50 // ---------------------------------------------------------------------------
51 // helper functions for showing a "busy" cursor
52 // ---------------------------------------------------------------------------
53
54 static HCURSOR gs_wxBusyCursor = 0; // new, busy cursor
55 static HCURSOR gs_wxBusyCursorOld = 0; // old cursor
56 static int gs_wxBusyCursorCount = 0;
57
58 extern HCURSOR wxGetCurrentBusyCursor()
59 {
60 return gs_wxBusyCursor;
61 }
62
63 // Set the cursor to the busy cursor for all windows
64 void wxBeginBusyCursor(const wxCursor *cursor)
65 {
66 if ( gs_wxBusyCursorCount++ == 0 )
67 {
68 gs_wxBusyCursor = (HCURSOR)cursor->GetHCURSOR();
69 #ifndef __WXMICROWIN__
70 gs_wxBusyCursorOld = ::SetCursor(gs_wxBusyCursor);
71 #endif
72 }
73 //else: nothing to do, already set
74 }
75
76 // Restore cursor to normal
77 void wxEndBusyCursor()
78 {
79 wxCHECK_RET( gs_wxBusyCursorCount > 0,
80 wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()") );
81
82 if ( --gs_wxBusyCursorCount == 0 )
83 {
84 #ifndef __WXMICROWIN__
85 ::SetCursor(gs_wxBusyCursorOld);
86 #endif
87 gs_wxBusyCursorOld = 0;
88 }
89 }
90
91 // true if we're between the above two calls
92 bool wxIsBusy()
93 {
94 return gs_wxBusyCursorCount > 0;
95 }
96
97 // Check whether this window wants to process messages, e.g. Stop button
98 // in long calculations.
99 bool wxCheckForInterrupt(wxWindow *wnd)
100 {
101 wxCHECK( wnd, false );
102
103 MSG msg;
104 while ( ::PeekMessage(&msg, GetHwndOf(wnd), 0, 0, PM_REMOVE) )
105 {
106 ::TranslateMessage(&msg);
107 ::DispatchMessage(&msg);
108 }
109
110 return true;
111 }
112
113 // ----------------------------------------------------------------------------
114 // get display info
115 // ----------------------------------------------------------------------------
116
117 // See also the wxGetMousePosition in window.cpp
118 // Deprecated: use wxPoint wxGetMousePosition() instead
119 void wxGetMousePosition( int* x, int* y )
120 {
121 POINT pt;
122 wxGetCursorPosMSW( & pt );
123 if ( x ) *x = pt.x;
124 if ( y ) *y = pt.y;
125 }
126
127 // Return true if we have a colour display
128 bool wxColourDisplay()
129 {
130 #ifdef __WXMICROWIN__
131 // MICROWIN_TODO
132 return true;
133 #else
134 // this function is called from wxDC ctor so it is called a *lot* of times
135 // hence we optimize it a bit but doing the check only once
136 //
137 // this should be MT safe as only the GUI thread (holding the GUI mutex)
138 // can call us
139 static int s_isColour = -1;
140
141 if ( s_isColour == -1 )
142 {
143 ScreenHDC dc;
144 int noCols = ::GetDeviceCaps(dc, NUMCOLORS);
145
146 s_isColour = (noCols == -1) || (noCols > 2);
147 }
148
149 return s_isColour != 0;
150 #endif
151 }
152
153 // Returns depth of screen
154 int wxDisplayDepth()
155 {
156 ScreenHDC dc;
157 return GetDeviceCaps(dc, PLANES) * GetDeviceCaps(dc, BITSPIXEL);
158 }
159
160 // Get size of display
161 void wxDisplaySize(int *width, int *height)
162 {
163 #ifdef __WXMICROWIN__
164 RECT rect;
165 HWND hWnd = GetDesktopWindow();
166 ::GetWindowRect(hWnd, & rect);
167
168 if ( width )
169 *width = rect.right - rect.left;
170 if ( height )
171 *height = rect.bottom - rect.top;
172 #else // !__WXMICROWIN__
173 ScreenHDC dc;
174
175 if ( width )
176 *width = ::GetDeviceCaps(dc, HORZRES);
177 if ( height )
178 *height = ::GetDeviceCaps(dc, VERTRES);
179 #endif // __WXMICROWIN__/!__WXMICROWIN__
180 }
181
182 void wxDisplaySizeMM(int *width, int *height)
183 {
184 #ifdef __WXMICROWIN__
185 // MICROWIN_TODO
186 if ( width )
187 *width = 0;
188 if ( height )
189 *height = 0;
190 #else
191 ScreenHDC dc;
192
193 if ( width )
194 *width = ::GetDeviceCaps(dc, HORZSIZE);
195 if ( height )
196 *height = ::GetDeviceCaps(dc, VERTSIZE);
197 #endif
198 }
199
200 void wxClientDisplayRect(int *x, int *y, int *width, int *height)
201 {
202 #if defined(__WXMICROWIN__)
203 *x = 0; *y = 0;
204 wxDisplaySize(width, height);
205 #else
206 // Determine the desktop dimensions minus the taskbar and any other
207 // special decorations...
208 RECT r;
209
210 SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
211 if (x) *x = r.left;
212 if (y) *y = r.top;
213 if (width) *width = r.right - r.left;
214 if (height) *height = r.bottom - r.top;
215 #endif
216 }
217
218 // ---------------------------------------------------------------------------
219 // window information functions
220 // ---------------------------------------------------------------------------
221
222 wxString WXDLLEXPORT wxGetWindowText(WXHWND hWnd)
223 {
224 wxString str;
225
226 if ( hWnd )
227 {
228 int len = GetWindowTextLength((HWND)hWnd) + 1;
229 ::GetWindowText((HWND)hWnd, wxStringBuffer(str, len), len);
230 }
231
232 return str;
233 }
234
235 wxString WXDLLEXPORT wxGetWindowClass(WXHWND hWnd)
236 {
237 wxString str;
238
239 // MICROWIN_TODO
240 #ifndef __WXMICROWIN__
241 if ( hWnd )
242 {
243 int len = 256; // some starting value
244
245 for ( ;; )
246 {
247 int count = ::GetClassName((HWND)hWnd, wxStringBuffer(str, len), len);
248
249 if ( count == len )
250 {
251 // the class name might have been truncated, retry with larger
252 // buffer
253 len *= 2;
254 }
255 else
256 {
257 break;
258 }
259 }
260 }
261 #endif // !__WXMICROWIN__
262
263 return str;
264 }
265
266 int WXDLLEXPORT wxGetWindowId(WXHWND hWnd)
267 {
268 return ::GetWindowLong((HWND)hWnd, GWL_ID);
269 }
270
271 // ----------------------------------------------------------------------------
272 // Metafile helpers
273 // ----------------------------------------------------------------------------
274
275 void PixelToHIMETRIC(LONG *x, LONG *y, HDC hdcRef)
276 {
277 int iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE),
278 iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE),
279 iWidthPels = GetDeviceCaps(hdcRef, HORZRES),
280 iHeightPels = GetDeviceCaps(hdcRef, VERTRES);
281
282 *x *= (iWidthMM * 100);
283 *x /= iWidthPels;
284 *y *= (iHeightMM * 100);
285 *y /= iHeightPels;
286 }
287
288 void HIMETRICToPixel(LONG *x, LONG *y, HDC hdcRef)
289 {
290 int iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE),
291 iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE),
292 iWidthPels = GetDeviceCaps(hdcRef, HORZRES),
293 iHeightPels = GetDeviceCaps(hdcRef, VERTRES);
294
295 *x *= iWidthPels;
296 *x /= (iWidthMM * 100);
297 *y *= iHeightPels;
298 *y /= (iHeightMM * 100);
299 }
300
301 void HIMETRICToPixel(LONG *x, LONG *y)
302 {
303 HIMETRICToPixel(x, y, ScreenHDC());
304 }
305
306 void PixelToHIMETRIC(LONG *x, LONG *y)
307 {
308 PixelToHIMETRIC(x, y, ScreenHDC());
309 }
310
311 void wxDrawLine(HDC hdc, int x1, int y1, int x2, int y2)
312 {
313 #ifdef __WXWINCE__
314 POINT points[2];
315 points[0].x = x1;
316 points[0].y = y1;
317 points[1].x = x2;
318 points[1].y = y2;
319 Polyline(hdc, points, 2);
320 #else
321 MoveToEx(hdc, x1, y1, NULL); LineTo((HDC) hdc, x2, y2);
322 #endif
323 }
324
325
326 // ----------------------------------------------------------------------------
327 // Shell API wrappers
328 // ----------------------------------------------------------------------------
329
330 extern bool wxEnableFileNameAutoComplete(HWND hwnd)
331 {
332 #if wxUSE_DYNLIB_CLASS
333 typedef HRESULT (WINAPI *SHAutoComplete_t)(HWND, DWORD);
334
335 static SHAutoComplete_t s_pfnSHAutoComplete = NULL;
336 static bool s_initialized = false;
337
338 if ( !s_initialized )
339 {
340 s_initialized = true;
341
342 wxLogNull nolog;
343 wxDynamicLibrary dll(wxT("shlwapi.dll"));
344 if ( dll.IsLoaded() )
345 {
346 s_pfnSHAutoComplete =
347 (SHAutoComplete_t)dll.GetSymbol(wxT("SHAutoComplete"));
348 if ( s_pfnSHAutoComplete )
349 {
350 // won't be unloaded until the process termination, no big deal
351 dll.Detach();
352 }
353 }
354 }
355
356 if ( !s_pfnSHAutoComplete )
357 return false;
358
359 HRESULT hr = s_pfnSHAutoComplete(hwnd, 0x10 /* SHACF_FILESYS_ONLY */);
360 if ( FAILED(hr) )
361 {
362 wxLogApiError(wxT("SHAutoComplete"), hr);
363 return false;
364 }
365
366 return true;
367 #else
368 wxUnusedVar(hwnd);
369 return false;
370 #endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
371 }
372
373 // ----------------------------------------------------------------------------
374 // Launch document with default app
375 // ----------------------------------------------------------------------------
376
377 bool wxLaunchDefaultApplication(const wxString& document, int flags)
378 {
379 wxUnusedVar(flags);
380
381 WinStruct<SHELLEXECUTEINFO> sei;
382 sei.lpFile = document.t_str();
383 #ifdef __WXWINCE__
384 sei.nShow = SW_SHOWNORMAL; // SW_SHOWDEFAULT not defined under CE (#10216)
385 #else
386 sei.nShow = SW_SHOWDEFAULT;
387 #endif
388
389 // avoid Windows message box in case of error for consistency with
390 // wxLaunchDefaultBrowser() even if don't show the error ourselves in this
391 // function
392 sei.fMask = SEE_MASK_FLAG_NO_UI;
393
394 if ( ::ShellExecuteEx(&sei) )
395 return true;
396
397 return false;
398 }
399
400 // ----------------------------------------------------------------------------
401 // Launch default browser
402 // ----------------------------------------------------------------------------
403
404 bool wxDoLaunchDefaultBrowser(const wxString& url, const wxString& scheme, int flags)
405 {
406 wxUnusedVar(flags);
407
408 #if wxUSE_IPC
409 if ( flags & wxBROWSER_NEW_WINDOW )
410 {
411 // ShellExecuteEx() opens the URL in an existing window by default so
412 // we can't use it if we need a new window
413 wxRegKey key(wxRegKey::HKCR, scheme + wxT("\\shell\\open"));
414 if ( !key.Exists() )
415 {
416 // try the default browser, it must be registered at least for http URLs
417 key.SetName(wxRegKey::HKCR, wxT("http\\shell\\open"));
418 }
419
420 if ( key.Exists() )
421 {
422 wxRegKey keyDDE(key, wxT("DDEExec"));
423 if ( keyDDE.Exists() )
424 {
425 // we only know the syntax of WWW_OpenURL DDE request for IE,
426 // optimistically assume that all other browsers are compatible
427 // with it
428 static const wxChar *TOPIC_OPEN_URL = wxT("WWW_OpenURL");
429 wxString ddeCmd;
430 wxRegKey keyTopic(keyDDE, wxT("topic"));
431 bool ok = keyTopic.Exists() &&
432 keyTopic.QueryDefaultValue() == TOPIC_OPEN_URL;
433 if ( ok )
434 {
435 ddeCmd = keyDDE.QueryDefaultValue();
436 ok = !ddeCmd.empty();
437 }
438
439 if ( ok )
440 {
441 // for WWW_OpenURL, the index of the window to open the URL
442 // in is -1 (meaning "current") by default, replace it with
443 // 0 which means "new" (see KB article 160957)
444 ok = ddeCmd.Replace(wxT("-1"), wxT("0"),
445 false /* only first occurrence */) == 1;
446 }
447
448 if ( ok )
449 {
450 // and also replace the parameters: the topic should
451 // contain a placeholder for the URL
452 ok = ddeCmd.Replace(wxT("%1"), url, false) == 1;
453 }
454
455 if ( ok )
456 {
457 // try to send it the DDE request now but ignore the errors
458 wxLogNull noLog;
459
460 const wxString ddeServer = wxRegKey(keyDDE, wxT("application"));
461 if ( wxExecuteDDE(ddeServer, TOPIC_OPEN_URL, ddeCmd) )
462 return true;
463
464 // this is not necessarily an error: maybe browser is
465 // simply not running, but no matter, in any case we're
466 // going to launch it using ShellExecuteEx() below now and
467 // we shouldn't try to open a new window if we open a new
468 // browser anyhow
469 }
470 }
471 }
472 }
473 #endif // wxUSE_IPC
474
475 WinStruct<SHELLEXECUTEINFO> sei;
476 sei.lpFile = url.c_str();
477 sei.lpVerb = wxT("open");
478 sei.nShow = SW_SHOWNORMAL;
479 sei.fMask = SEE_MASK_FLAG_NO_UI; // we give error message ourselves
480
481 if ( ::ShellExecuteEx(&sei) )
482 return true;
483
484 return false;
485 }