1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/os2/utilsgui.cpp
3 // Purpose: Various utility functions only available in GUI
4 // Author: David Webster
6 // Created: 20.08.2003 (extracted from os2/utils.cpp)
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
30 #include "wx/cursor.h"
35 #include "wx/apptrait.h"
36 #include "wx/os2/private/timer.h"
37 #include "wx/evtloop.h"
39 #include "wx/os2/private.h" // includes <windows.h>
41 // ============================================================================
43 // ============================================================================
48 DosBeep(1000,1000); // 1kHz during 1 sec.
51 // ----------------------------------------------------------------------------
52 // functions to work with .INI files
53 // ----------------------------------------------------------------------------
55 // Sleep for nSecs seconds. Attempt a Windows implementation using timers.
56 static bool inTimer
= false;
58 class wxSleepTimer
: public wxTimer
68 // ---------------------------------------------------------------------------
69 // helper functions for showing a "busy" cursor
70 // ---------------------------------------------------------------------------
72 HCURSOR gs_wxBusyCursor
= 0; // new, busy cursor
73 HCURSOR gs_wxBusyCursorOld
= 0; // old cursor
74 static int gs_wxBusyCursorCount
= 0;
76 // Set the cursor to the busy cursor for all windows
77 void wxBeginBusyCursor(const wxCursor
* pCursor
)
79 if ( gs_wxBusyCursorCount
++ == 0 )
81 gs_wxBusyCursor
= (HCURSOR
)pCursor
->GetHCURSOR();
82 ::WinSetPointer(HWND_DESKTOP
, (HPOINTER
)gs_wxBusyCursor
);
84 //else: nothing to do, already set
87 // Restore cursor to normal
88 void wxEndBusyCursor()
90 wxCHECK_RET( gs_wxBusyCursorCount
> 0
91 ,wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()")
94 if (--gs_wxBusyCursorCount
== 0)
96 ::WinSetPointer(HWND_DESKTOP
, (HPOINTER
)gs_wxBusyCursorOld
);
97 gs_wxBusyCursorOld
= 0;
101 // true if we're between the above two calls
104 return (gs_wxBusyCursorCount
> 0);
107 // Check whether this window wants to process messages, e.g. Stop button
108 // in long calculations.
109 bool wxCheckForInterrupt( wxWindow
* pWnd
)
115 HWND hwndFilter
= NULLHANDLE
;
117 while(::WinPeekMsg(hab
, &vMsg
, hwndFilter
, 0, 0, PM_REMOVE
))
119 ::WinDispatchMsg(hab
, &vMsg
);
121 return true;//*** temporary?
125 wxFAIL_MSG(wxT("pWnd==NULL !!!"));
126 return false;//*** temporary?
130 // ----------------------------------------------------------------------------
132 // ----------------------------------------------------------------------------
134 // See also the wxGetMousePosition in window.cpp
135 // Deprecated: use wxPoint wxGetMousePosition() instead
136 void wxGetMousePosition(
143 ::WinQueryPointerPos(HWND_DESKTOP
, &vPt
);
148 // Return true if we have a colour display
149 bool wxColourDisplay()
156 hpsScreen
= ::WinGetScreenPS(HWND_DESKTOP
);
157 hdcScreen
= ::GpiQueryDevice(hpsScreen
);
158 ::DevQueryCaps(hdcScreen
, CAPS_COLORS
, 1L, &lColors
);
159 return(lColors
> 1L);
161 // I don't see how the PM display could not be color. Besides, this
162 // was leaking DCs and PSs!!! MN
167 // Returns depth of screen
174 static LONG nDepth
= 0;
176 // The screen colordepth ain't gonna change. No reason to query
179 hpsScreen
= ::WinGetScreenPS(HWND_DESKTOP
);
180 hdcScreen
= ::GpiQueryDevice(hpsScreen
);
181 ::DevQueryCaps(hdcScreen
, CAPS_COLOR_PLANES
, 1L, &lPlanes
);
182 ::DevQueryCaps(hdcScreen
, CAPS_COLOR_BITCOUNT
, 1L, &lBitsPerPixel
);
184 nDepth
= (int)(lPlanes
* lBitsPerPixel
);
185 ::DevCloseDC(hdcScreen
);
186 ::WinReleasePS(hpsScreen
);
191 // Get size of display
199 static LONG lWidth
= 0;
200 static LONG lHeight
= 0;
202 // The screen size ain't gonna change either so just cache the values
204 hpsScreen
= ::WinGetScreenPS(HWND_DESKTOP
);
205 hdcScreen
= ::GpiQueryDevice(hpsScreen
);
206 ::DevQueryCaps(hdcScreen
, CAPS_WIDTH
, 1L, &lWidth
);
207 ::DevQueryCaps(hdcScreen
, CAPS_HEIGHT
, 1L, &lHeight
);
208 ::DevCloseDC(hdcScreen
);
209 ::WinReleasePS(hpsScreen
);
212 *pWidth
= (int)lWidth
;
214 *pHeight
= (int)lHeight
;
217 void wxDisplaySizeMM(
225 hpsScreen
= ::WinGetScreenPS(HWND_DESKTOP
);
226 hdcScreen
= ::GpiQueryDevice(hpsScreen
);
229 ::DevQueryCaps( hdcScreen
230 ,CAPS_HORIZONTAL_RESOLUTION
235 ::DevQueryCaps( hdcScreen
236 ,CAPS_VERTICAL_RESOLUTION
240 ::DevCloseDC(hdcScreen
);
241 ::WinReleasePS(hpsScreen
);
244 void wxClientDisplayRect(int *x
, int *y
, int *width
, int *height
)
246 // This is supposed to return desktop dimensions minus any window
247 // manager panels, menus, taskbars, etc. If there is a way to do that
248 // for this platform please fix this function, otherwise it defaults
249 // to the entire desktop.
252 wxDisplaySize(width
, height
);
255 void wxGUIAppTraits::InitializeGui(unsigned long &ulHab
)
257 ulHab
= ::WinInitialize(0);
260 void wxGUIAppTraits::TerminateGui(unsigned long ulHab
)
262 ::WinTerminate(ulHab
);
265 wxPortId
wxGUIAppTraits::GetToolkitVersion(int *verMaj
, int *verMin
) const
267 // How to get version of PM ? I guess, just reusing the OS version is OK.
268 (void) wxGetOsVersion(verMaj
, verMin
);
272 wxTimerImpl
* wxGUIAppTraits::CreateTimerImpl(wxTimer
*timer
)
274 return new wxOS2TimerImpl(timer
);
277 wxEventLoopBase
* wxGUIAppTraits::CreateEventLoop()
279 return new wxEventLoop
;
282 // ---------------------------------------------------------------------------
283 // window information functions
284 // ---------------------------------------------------------------------------
286 wxString WXDLLEXPORT
wxGetWindowText( WXHWND hWnd
)
292 long lLen
= ::WinQueryWindowTextLength((HWND
)hWnd
) + 1;
293 ::WinQueryWindowText((HWND
)hWnd
, lLen
, (PSZ
)(wxChar
*)wxStringBuffer(vStr
, lLen
));
299 wxString WXDLLEXPORT
wxGetWindowClass( WXHWND hWnd
)
304 int nLen
= 256; // some starting value
308 int nCount
= ::WinQueryClassName((HWND
)hWnd
, nLen
, (PSZ
)(wxChar
*)wxStringBuffer(vStr
, nLen
));
312 // the class name might have been truncated, retry with larger
325 WXWORD WXDLLEXPORT
wxGetWindowId(
329 return ::WinQueryWindowUShort((HWND
)hWnd
, QWS_ID
);
340 vPoint
[0].x
= rRect
.xLeft
;
341 vPoint
[0].y
= rRect
.yBottom
;
342 ::GpiMove(hPS
, &vPoint
[0]);
343 if (dwStyle
& wxSIMPLE_BORDER
||
344 dwStyle
& wxSTATIC_BORDER
)
346 vPoint
[1].x
= rRect
.xRight
- 1;
347 vPoint
[1].y
= rRect
.yTop
- 1;
355 if (dwStyle
& wxSUNKEN_BORDER
)
357 LINEBUNDLE vLineBundle
;
359 vLineBundle
.lColor
= 0x00FFFFFF; // WHITE
360 vLineBundle
.usMixMode
= FM_OVERPAINT
;
361 vLineBundle
.fxWidth
= 2;
362 vLineBundle
.lGeomWidth
= 2;
363 vLineBundle
.usType
= LINETYPE_SOLID
;
364 vLineBundle
.usEnd
= 0;
365 vLineBundle
.usJoin
= 0;
368 ,LBB_COLOR
| LBB_MIX_MODE
| LBB_WIDTH
| LBB_GEOM_WIDTH
| LBB_TYPE
372 vPoint
[1].x
= rRect
.xRight
- 1;
373 vPoint
[1].y
= rRect
.yTop
- 1;
380 vPoint
[0].x
= rRect
.xLeft
+ 1;
381 vPoint
[0].y
= rRect
.yBottom
+ 1;
382 ::GpiMove(hPS
, &vPoint
[0]);
383 vPoint
[1].x
= rRect
.xRight
- 2;
384 vPoint
[1].y
= rRect
.yTop
- 2;
392 vLineBundle
.lColor
= 0x00000000; // BLACK
393 vLineBundle
.usMixMode
= FM_OVERPAINT
;
394 vLineBundle
.fxWidth
= 2;
395 vLineBundle
.lGeomWidth
= 2;
396 vLineBundle
.usType
= LINETYPE_SOLID
;
397 vLineBundle
.usEnd
= 0;
398 vLineBundle
.usJoin
= 0;
401 ,LBB_COLOR
| LBB_MIX_MODE
| LBB_WIDTH
| LBB_GEOM_WIDTH
| LBB_TYPE
405 vPoint
[0].x
= rRect
.xLeft
+ 2;
406 vPoint
[0].y
= rRect
.yBottom
+ 2;
407 ::GpiMove(hPS
, &vPoint
[0]);
408 vPoint
[1].x
= rRect
.xLeft
+ 2;
409 vPoint
[1].y
= rRect
.yTop
- 3;
410 ::GpiLine(hPS
, &vPoint
[1]);
411 vPoint
[1].x
= rRect
.xRight
- 3;
412 vPoint
[1].y
= rRect
.yTop
- 3;
413 ::GpiLine(hPS
, &vPoint
[1]);
415 vPoint
[0].x
= rRect
.xLeft
+ 3;
416 vPoint
[0].y
= rRect
.yBottom
+ 3;
417 ::GpiMove(hPS
, &vPoint
[0]);
418 vPoint
[1].x
= rRect
.xLeft
+ 3;
419 vPoint
[1].y
= rRect
.yTop
- 4;
420 ::GpiLine(hPS
, &vPoint
[1]);
421 vPoint
[1].x
= rRect
.xRight
- 4;
422 vPoint
[1].y
= rRect
.yTop
- 4;
423 ::GpiLine(hPS
, &vPoint
[1]);
425 if (dwStyle
& wxDOUBLE_BORDER
)
427 LINEBUNDLE vLineBundle
;
429 vLineBundle
.lColor
= 0x00FFFFFF; // WHITE
430 vLineBundle
.usMixMode
= FM_OVERPAINT
;
431 vLineBundle
.fxWidth
= 2;
432 vLineBundle
.lGeomWidth
= 2;
433 vLineBundle
.usType
= LINETYPE_SOLID
;
434 vLineBundle
.usEnd
= 0;
435 vLineBundle
.usJoin
= 0;
438 ,LBB_COLOR
| LBB_MIX_MODE
| LBB_WIDTH
| LBB_GEOM_WIDTH
| LBB_TYPE
442 vPoint
[1].x
= rRect
.xRight
- 1;
443 vPoint
[1].y
= rRect
.yTop
- 1;
450 vLineBundle
.lColor
= 0x00000000; // WHITE
451 vLineBundle
.usMixMode
= FM_OVERPAINT
;
452 vLineBundle
.fxWidth
= 2;
453 vLineBundle
.lGeomWidth
= 2;
454 vLineBundle
.usType
= LINETYPE_SOLID
;
455 vLineBundle
.usEnd
= 0;
456 vLineBundle
.usJoin
= 0;
459 ,LBB_COLOR
| LBB_MIX_MODE
| LBB_WIDTH
| LBB_GEOM_WIDTH
| LBB_TYPE
463 vPoint
[0].x
= rRect
.xLeft
+ 2;
464 vPoint
[0].y
= rRect
.yBottom
+ 2;
465 ::GpiMove(hPS
, &vPoint
[0]);
466 vPoint
[1].x
= rRect
.xRight
- 2;
467 vPoint
[1].y
= rRect
.yTop
- 2;
474 vLineBundle
.lColor
= 0x00FFFFFF; // BLACK
475 vLineBundle
.usMixMode
= FM_OVERPAINT
;
476 vLineBundle
.fxWidth
= 2;
477 vLineBundle
.lGeomWidth
= 2;
478 vLineBundle
.usType
= LINETYPE_SOLID
;
479 vLineBundle
.usEnd
= 0;
480 vLineBundle
.usJoin
= 0;
483 ,LBB_COLOR
| LBB_MIX_MODE
| LBB_WIDTH
| LBB_GEOM_WIDTH
| LBB_TYPE
487 vPoint
[0].x
= rRect
.xLeft
+ 3;
488 vPoint
[0].y
= rRect
.yBottom
+ 3;
489 ::GpiMove(hPS
, &vPoint
[0]);
490 vPoint
[1].x
= rRect
.xRight
- 3;
491 vPoint
[1].y
= rRect
.yTop
- 3;
499 if (dwStyle
& wxRAISED_BORDER
)
501 LINEBUNDLE vLineBundle
;
503 vLineBundle
.lColor
= 0x00000000; // BLACK
504 vLineBundle
.usMixMode
= FM_OVERPAINT
;
505 vLineBundle
.fxWidth
= 2;
506 vLineBundle
.lGeomWidth
= 2;
507 vLineBundle
.usType
= LINETYPE_SOLID
;
508 vLineBundle
.usEnd
= 0;
509 vLineBundle
.usJoin
= 0;
512 ,LBB_COLOR
| LBB_MIX_MODE
| LBB_WIDTH
| LBB_GEOM_WIDTH
| LBB_TYPE
516 vPoint
[1].x
= rRect
.xRight
- 1;
517 vPoint
[1].y
= rRect
.yTop
- 1;
524 vPoint
[0].x
= rRect
.xLeft
+ 1;
525 vPoint
[0].y
= rRect
.yBottom
+ 1;
526 ::GpiMove(hPS
, &vPoint
[0]);
527 vPoint
[1].x
= rRect
.xRight
- 2;
528 vPoint
[1].y
= rRect
.yTop
- 2;
536 vLineBundle
.lColor
= 0x00FFFFFF; // WHITE
537 vLineBundle
.usMixMode
= FM_OVERPAINT
;
538 vLineBundle
.fxWidth
= 2;
539 vLineBundle
.lGeomWidth
= 2;
540 vLineBundle
.usType
= LINETYPE_SOLID
;
541 vLineBundle
.usEnd
= 0;
542 vLineBundle
.usJoin
= 0;
545 ,LBB_COLOR
| LBB_MIX_MODE
| LBB_WIDTH
| LBB_GEOM_WIDTH
| LBB_TYPE
549 vPoint
[0].x
= rRect
.xLeft
+ 2;
550 vPoint
[0].y
= rRect
.yBottom
+ 2;
551 ::GpiMove(hPS
, &vPoint
[0]);
552 vPoint
[1].x
= rRect
.xLeft
+ 2;
553 vPoint
[1].y
= rRect
.yTop
- 3;
554 ::GpiLine(hPS
, &vPoint
[1]);
555 vPoint
[1].x
= rRect
.xRight
- 3;
556 vPoint
[1].y
= rRect
.yTop
- 3;
557 ::GpiLine(hPS
, &vPoint
[1]);
559 vPoint
[0].x
= rRect
.xLeft
+ 3;
560 vPoint
[0].y
= rRect
.yBottom
+ 3;
561 ::GpiMove(hPS
, &vPoint
[0]);
562 vPoint
[1].x
= rRect
.xLeft
+ 3;
563 vPoint
[1].y
= rRect
.yTop
- 4;
564 ::GpiLine(hPS
, &vPoint
[1]);
565 vPoint
[1].x
= rRect
.xRight
- 4;
566 vPoint
[1].y
= rRect
.yTop
- 4;
567 ::GpiLine(hPS
, &vPoint
[1]);
569 } // end of wxDrawBorder
573 , const wxFont
& rFont
581 if (hWnd
== NULLHANDLE
)
585 // The fonts available for Presentation Params are just a few
586 // outline fonts, the rest are available to the GPI, so we must
587 // map the families to one of these three
589 switch(rFont
.GetFamily())
592 strcpy(zFacename
, "Script");
596 strcpy(zFacename
, "WarpSans");
600 strcpy(zFacename
,"Times New Roman");
604 strcpy(zFacename
, "Courier New");
608 strcpy(zFacename
, "Courier New");
614 strcpy(zFacename
, "Helvetica");
618 switch(rFont
.GetWeight())
627 case wxFONTWEIGHT_MAX
:
628 strcpy(zWeight
, "Bold");
632 switch(rFont
.GetStyle())
636 strcpy(zStyle
, "Italic");
643 sprintf(zFont
, "%d.%s", rFont
.GetPointSize(), zFacename
);
644 if (zWeight
[0] != '\0')
647 strcat(zFont
, zWeight
);
649 if (zStyle
[0] != '\0')
652 strcat(zFont
, zStyle
);
654 ::WinSetPresParam(hWnd
, PP_FONTNAMESIZE
, strlen(zFont
) + 1, (PVOID
)zFont
);
655 } // end of wxOS2SetFont
657 // ---------------------------------------------------------------------------
658 // Helper for taking a regular bitmap and giving it a disabled look
659 // ---------------------------------------------------------------------------
660 wxBitmap
wxDisableBitmap(
665 wxMask
* pMask
= rBmp
.GetMask();
668 return(wxNullBitmap
);
670 DEVOPENSTRUC vDop
= {0L, "DISPLAY", NULL
, 0L, 0L, 0L, 0L, 0L, 0L};
671 SIZEL vSize
= {0, 0};
672 HDC hDC
= ::DevOpenDC(vHabmain
, OD_MEMORY
, "*", 5L, (PDEVOPENDATA
)&vDop
, NULLHANDLE
);
673 HPS hPS
= ::GpiCreatePS(vHabmain
, hDC
, &vSize
, PU_PELS
| GPIA_ASSOC
);
674 BITMAPINFOHEADER2 vHeader
;
678 HBITMAP hBitmap
= (HBITMAP
)rBmp
.GetHBITMAP();
679 HBITMAP hOldBitmap
= NULLHANDLE
;
680 HBITMAP hOldMask
= NULLHANDLE
;
681 HBITMAP hMask
= (HBITMAP
)rBmp
.GetMask()->GetMaskBitmap();
682 unsigned char* pucBits
; // buffer that will contain the bitmap data
683 unsigned char* pucData
; // pointer to use to traverse bitmap data
684 unsigned char* pucBitsMask
; // buffer that will contain the mask data
685 unsigned char* pucDataMask
; // pointer to use to traverse mask data
688 bool bpp16
= (wxDisplayDepth() == 16);
690 memset(&vHeader
, '\0', 16);
693 memset(&vInfo
, '\0', 16);
695 vInfo
.cx
= (ULONG
)rBmp
.GetWidth();
696 vInfo
.cy
= (ULONG
)rBmp
.GetHeight();
698 vInfo
.cBitCount
= 24; // Set to desired count going in
701 // Create the buffers for data....all wxBitmaps are 24 bit internally
703 int nBytesPerLine
= rBmp
.GetWidth() * 3;
704 int nSizeDWORD
= sizeof(DWORD
);
705 int nLineBoundary
= nBytesPerLine
% nSizeDWORD
;
711 // Bitmap must be in a double-word aligned address so we may
712 // have some padding to worry about
714 if (nLineBoundary
> 0)
716 nPadding
= nSizeDWORD
- nLineBoundary
;
717 nBytesPerLine
+= nPadding
;
719 pucBits
= (unsigned char *)malloc(nBytesPerLine
* rBmp
.GetHeight());
720 memset(pucBits
, '\0', (nBytesPerLine
* rBmp
.GetHeight()));
721 pucBitsMask
= (unsigned char *)malloc(nBytesPerLine
* rBmp
.GetHeight());
722 memset(pucBitsMask
, '\0', (nBytesPerLine
* rBmp
.GetHeight()));
725 // Extract the bitmap and mask data
727 if ((hOldBitmap
= ::GpiSetBitmap(hPS
, hBitmap
)) == HBM_ERROR
)
729 vError
= ::WinGetLastError(vHabmain
);
730 sError
= wxPMErrorToStr(vError
);
732 ::GpiQueryBitmapInfoHeader(hBitmap
, &vHeader
);
733 vInfo
.cBitCount
= 24;
734 if ((lScans
= ::GpiQueryBitmapBits( hPS
736 ,(LONG
)rBmp
.GetHeight()
741 vError
= ::WinGetLastError(vHabmain
);
742 sError
= wxPMErrorToStr(vError
);
744 if ((hOldMask
= ::GpiSetBitmap(hPS
, hMask
)) == HBM_ERROR
)
746 vError
= ::WinGetLastError(vHabmain
);
747 sError
= wxPMErrorToStr(vError
);
749 ::GpiQueryBitmapInfoHeader(hMask
, &vHeader
);
750 vInfo
.cBitCount
= 24;
751 if ((lScans
= ::GpiQueryBitmapBits( hPS
753 ,(LONG
)rBmp
.GetHeight()
758 vError
= ::WinGetLastError(vHabmain
);
759 sError
= wxPMErrorToStr(vError
);
761 if (( hMask
= ::GpiSetBitmap(hPS
, hOldMask
)) == HBM_ERROR
)
763 vError
= ::WinGetLastError(vHabmain
);
764 sError
= wxPMErrorToStr(vError
);
767 pucDataMask
= pucBitsMask
;
770 // Get the mask value
772 for (i
= 0; i
< rBmp
.GetHeight(); i
++)
774 for (j
= 0; j
< rBmp
.GetWidth(); j
++)
777 if (bpp16
&& *pucDataMask
== 0xF8) // 16 bit display gobblygook
782 else if (*pucDataMask
== 0xFF) // set to grey
789 *pucData
= ((unsigned char)(lColor
>> 16));
794 if (bpp16
&& *(pucDataMask
+ 1) == 0xFC) // 16 bit display gobblygook
799 else if (*(pucDataMask
+ 1) == 0xFF) // set to grey
806 *pucData
= ((unsigned char)(lColor
>> 8));
811 if (bpp16
&& *(pucDataMask
+ 2) == 0xF8) // 16 bit display gobblygook
816 else if (*(pucDataMask
+ 2) == 0xFF) // set to grey
823 *pucData
= ((unsigned char)lColor
);
828 for (j
= 0; j
< nPadding
; j
++)
836 // Create a new bitmap and set the modified bits
838 wxBitmap
vNewBmp( rBmp
.GetWidth()
842 HBITMAP hNewBmp
= (HBITMAP
)vNewBmp
.GetHBITMAP();
844 if ((hOldBitmap
= ::GpiSetBitmap(hPS
, hNewBmp
)) == HBM_ERROR
)
846 vError
= ::WinGetLastError(vHabmain
);
847 sError
= wxPMErrorToStr(vError
);
849 if ((lScansSet
= ::GpiSetBitmapBits( hPS
851 ,(LONG
)rBmp
.GetHeight()
857 vError
= ::WinGetLastError(vHabmain
);
858 sError
= wxPMErrorToStr(vError
);
862 pNewMask
= new wxMask(pMask
->GetMaskBitmap());
863 vNewBmp
.SetMask(pNewMask
);
865 ::GpiSetBitmap(hPS
, NULLHANDLE
);
870 return(wxNullBitmap
);
871 } // end of wxDisableBitmap
873 COLORREF
wxColourToRGB(
874 const wxColour
& rColor
877 return(OS2RGB(rColor
.Red(), rColor
.Green(), rColor
.Blue()));
878 } // end of wxColourToRGB