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)
7 // Copyright: (c) David Webster
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
29 #include "wx/cursor.h"
34 #include "wx/apptrait.h"
35 #include "wx/os2/private/timer.h"
36 #include "wx/evtloop.h"
38 #include "wx/os2/private.h" // includes <windows.h>
40 // ============================================================================
42 // ============================================================================
47 DosBeep(1000,1000); // 1kHz during 1 sec.
50 // ----------------------------------------------------------------------------
51 // functions to work with .INI files
52 // ----------------------------------------------------------------------------
54 // Sleep for nSecs seconds. Attempt a Windows implementation using timers.
55 static bool inTimer
= false;
57 class wxSleepTimer
: public wxTimer
67 // ---------------------------------------------------------------------------
68 // helper functions for showing a "busy" cursor
69 // ---------------------------------------------------------------------------
71 HCURSOR gs_wxBusyCursor
= 0; // new, busy cursor
72 HCURSOR gs_wxBusyCursorOld
= 0; // old cursor
73 static int gs_wxBusyCursorCount
= 0;
75 // Set the cursor to the busy cursor for all windows
76 void wxBeginBusyCursor(const wxCursor
* pCursor
)
78 if ( gs_wxBusyCursorCount
++ == 0 )
80 gs_wxBusyCursor
= (HCURSOR
)pCursor
->GetHCURSOR();
81 ::WinSetPointer(HWND_DESKTOP
, (HPOINTER
)gs_wxBusyCursor
);
83 //else: nothing to do, already set
86 // Restore cursor to normal
87 void wxEndBusyCursor()
89 wxCHECK_RET( gs_wxBusyCursorCount
> 0
90 ,wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()")
93 if (--gs_wxBusyCursorCount
== 0)
95 ::WinSetPointer(HWND_DESKTOP
, (HPOINTER
)gs_wxBusyCursorOld
);
96 gs_wxBusyCursorOld
= 0;
100 // true if we're between the above two calls
103 return (gs_wxBusyCursorCount
> 0);
106 // Check whether this window wants to process messages, e.g. Stop button
107 // in long calculations.
108 bool wxCheckForInterrupt( wxWindow
* pWnd
)
114 HWND hwndFilter
= NULLHANDLE
;
116 while(::WinPeekMsg(hab
, &vMsg
, hwndFilter
, 0, 0, PM_REMOVE
))
118 ::WinDispatchMsg(hab
, &vMsg
);
120 return true;//*** temporary?
124 wxFAIL_MSG(wxT("pWnd==NULL !!!"));
125 return false;//*** temporary?
129 // ----------------------------------------------------------------------------
131 // ----------------------------------------------------------------------------
133 // See also the wxGetMousePosition in window.cpp
134 // Deprecated: use wxPoint wxGetMousePosition() instead
135 void wxGetMousePosition(
142 ::WinQueryPointerPos(HWND_DESKTOP
, &vPt
);
147 // Return true if we have a colour display
148 bool wxColourDisplay()
155 hpsScreen
= ::WinGetScreenPS(HWND_DESKTOP
);
156 hdcScreen
= ::GpiQueryDevice(hpsScreen
);
157 ::DevQueryCaps(hdcScreen
, CAPS_COLORS
, 1L, &lColors
);
158 return(lColors
> 1L);
160 // I don't see how the PM display could not be color. Besides, this
161 // was leaking DCs and PSs!!! MN
166 // Returns depth of screen
173 static LONG nDepth
= 0;
175 // The screen colordepth ain't gonna change. No reason to query
178 hpsScreen
= ::WinGetScreenPS(HWND_DESKTOP
);
179 hdcScreen
= ::GpiQueryDevice(hpsScreen
);
180 ::DevQueryCaps(hdcScreen
, CAPS_COLOR_PLANES
, 1L, &lPlanes
);
181 ::DevQueryCaps(hdcScreen
, CAPS_COLOR_BITCOUNT
, 1L, &lBitsPerPixel
);
183 nDepth
= (int)(lPlanes
* lBitsPerPixel
);
184 ::DevCloseDC(hdcScreen
);
185 ::WinReleasePS(hpsScreen
);
190 // Get size of display
198 static LONG lWidth
= 0;
199 static LONG lHeight
= 0;
201 // The screen size ain't gonna change either so just cache the values
203 hpsScreen
= ::WinGetScreenPS(HWND_DESKTOP
);
204 hdcScreen
= ::GpiQueryDevice(hpsScreen
);
205 ::DevQueryCaps(hdcScreen
, CAPS_WIDTH
, 1L, &lWidth
);
206 ::DevQueryCaps(hdcScreen
, CAPS_HEIGHT
, 1L, &lHeight
);
207 ::DevCloseDC(hdcScreen
);
208 ::WinReleasePS(hpsScreen
);
211 *pWidth
= (int)lWidth
;
213 *pHeight
= (int)lHeight
;
216 void wxDisplaySizeMM(
224 hpsScreen
= ::WinGetScreenPS(HWND_DESKTOP
);
225 hdcScreen
= ::GpiQueryDevice(hpsScreen
);
228 ::DevQueryCaps( hdcScreen
229 ,CAPS_HORIZONTAL_RESOLUTION
234 ::DevQueryCaps( hdcScreen
235 ,CAPS_VERTICAL_RESOLUTION
239 ::DevCloseDC(hdcScreen
);
240 ::WinReleasePS(hpsScreen
);
243 void wxClientDisplayRect(int *x
, int *y
, int *width
, int *height
)
245 // This is supposed to return desktop dimensions minus any window
246 // manager panels, menus, taskbars, etc. If there is a way to do that
247 // for this platform please fix this function, otherwise it defaults
248 // to the entire desktop.
251 wxDisplaySize(width
, height
);
254 void wxGUIAppTraits::InitializeGui(unsigned long &ulHab
)
256 ulHab
= ::WinInitialize(0);
259 void wxGUIAppTraits::TerminateGui(unsigned long ulHab
)
261 ::WinTerminate(ulHab
);
264 wxPortId
wxGUIAppTraits::GetToolkitVersion(int *verMaj
, int *verMin
) const
266 // How to get version of PM ? I guess, just reusing the OS version is OK.
267 (void) wxGetOsVersion(verMaj
, verMin
);
271 wxTimerImpl
* wxGUIAppTraits::CreateTimerImpl(wxTimer
*timer
)
273 return new wxOS2TimerImpl(timer
);
276 wxEventLoopBase
* wxGUIAppTraits::CreateEventLoop()
278 return new wxEventLoop
;
281 // ---------------------------------------------------------------------------
282 // window information functions
283 // ---------------------------------------------------------------------------
285 wxString WXDLLEXPORT
wxGetWindowText( WXHWND hWnd
)
291 long lLen
= ::WinQueryWindowTextLength((HWND
)hWnd
) + 1;
292 ::WinQueryWindowText((HWND
)hWnd
, lLen
, (PSZ
)(wxChar
*)wxStringBuffer(vStr
, lLen
));
298 wxString WXDLLEXPORT
wxGetWindowClass( WXHWND hWnd
)
303 int nLen
= 256; // some starting value
307 int nCount
= ::WinQueryClassName((HWND
)hWnd
, nLen
, (PSZ
)(wxChar
*)wxStringBuffer(vStr
, nLen
));
311 // the class name might have been truncated, retry with larger
324 WXWORD WXDLLEXPORT
wxGetWindowId(
328 return ::WinQueryWindowUShort((HWND
)hWnd
, QWS_ID
);
339 vPoint
[0].x
= rRect
.xLeft
;
340 vPoint
[0].y
= rRect
.yBottom
;
341 ::GpiMove(hPS
, &vPoint
[0]);
342 if (dwStyle
& wxSIMPLE_BORDER
||
343 dwStyle
& wxSTATIC_BORDER
)
345 vPoint
[1].x
= rRect
.xRight
- 1;
346 vPoint
[1].y
= rRect
.yTop
- 1;
354 if (dwStyle
& wxSUNKEN_BORDER
)
356 LINEBUNDLE vLineBundle
;
358 vLineBundle
.lColor
= 0x00FFFFFF; // WHITE
359 vLineBundle
.usMixMode
= FM_OVERPAINT
;
360 vLineBundle
.fxWidth
= 2;
361 vLineBundle
.lGeomWidth
= 2;
362 vLineBundle
.usType
= LINETYPE_SOLID
;
363 vLineBundle
.usEnd
= 0;
364 vLineBundle
.usJoin
= 0;
367 ,LBB_COLOR
| LBB_MIX_MODE
| LBB_WIDTH
| LBB_GEOM_WIDTH
| LBB_TYPE
371 vPoint
[1].x
= rRect
.xRight
- 1;
372 vPoint
[1].y
= rRect
.yTop
- 1;
379 vPoint
[0].x
= rRect
.xLeft
+ 1;
380 vPoint
[0].y
= rRect
.yBottom
+ 1;
381 ::GpiMove(hPS
, &vPoint
[0]);
382 vPoint
[1].x
= rRect
.xRight
- 2;
383 vPoint
[1].y
= rRect
.yTop
- 2;
391 vLineBundle
.lColor
= 0x00000000; // BLACK
392 vLineBundle
.usMixMode
= FM_OVERPAINT
;
393 vLineBundle
.fxWidth
= 2;
394 vLineBundle
.lGeomWidth
= 2;
395 vLineBundle
.usType
= LINETYPE_SOLID
;
396 vLineBundle
.usEnd
= 0;
397 vLineBundle
.usJoin
= 0;
400 ,LBB_COLOR
| LBB_MIX_MODE
| LBB_WIDTH
| LBB_GEOM_WIDTH
| LBB_TYPE
404 vPoint
[0].x
= rRect
.xLeft
+ 2;
405 vPoint
[0].y
= rRect
.yBottom
+ 2;
406 ::GpiMove(hPS
, &vPoint
[0]);
407 vPoint
[1].x
= rRect
.xLeft
+ 2;
408 vPoint
[1].y
= rRect
.yTop
- 3;
409 ::GpiLine(hPS
, &vPoint
[1]);
410 vPoint
[1].x
= rRect
.xRight
- 3;
411 vPoint
[1].y
= rRect
.yTop
- 3;
412 ::GpiLine(hPS
, &vPoint
[1]);
414 vPoint
[0].x
= rRect
.xLeft
+ 3;
415 vPoint
[0].y
= rRect
.yBottom
+ 3;
416 ::GpiMove(hPS
, &vPoint
[0]);
417 vPoint
[1].x
= rRect
.xLeft
+ 3;
418 vPoint
[1].y
= rRect
.yTop
- 4;
419 ::GpiLine(hPS
, &vPoint
[1]);
420 vPoint
[1].x
= rRect
.xRight
- 4;
421 vPoint
[1].y
= rRect
.yTop
- 4;
422 ::GpiLine(hPS
, &vPoint
[1]);
424 if (dwStyle
& wxDOUBLE_BORDER
)
426 LINEBUNDLE vLineBundle
;
428 vLineBundle
.lColor
= 0x00FFFFFF; // WHITE
429 vLineBundle
.usMixMode
= FM_OVERPAINT
;
430 vLineBundle
.fxWidth
= 2;
431 vLineBundle
.lGeomWidth
= 2;
432 vLineBundle
.usType
= LINETYPE_SOLID
;
433 vLineBundle
.usEnd
= 0;
434 vLineBundle
.usJoin
= 0;
437 ,LBB_COLOR
| LBB_MIX_MODE
| LBB_WIDTH
| LBB_GEOM_WIDTH
| LBB_TYPE
441 vPoint
[1].x
= rRect
.xRight
- 1;
442 vPoint
[1].y
= rRect
.yTop
- 1;
449 vLineBundle
.lColor
= 0x00000000; // WHITE
450 vLineBundle
.usMixMode
= FM_OVERPAINT
;
451 vLineBundle
.fxWidth
= 2;
452 vLineBundle
.lGeomWidth
= 2;
453 vLineBundle
.usType
= LINETYPE_SOLID
;
454 vLineBundle
.usEnd
= 0;
455 vLineBundle
.usJoin
= 0;
458 ,LBB_COLOR
| LBB_MIX_MODE
| LBB_WIDTH
| LBB_GEOM_WIDTH
| LBB_TYPE
462 vPoint
[0].x
= rRect
.xLeft
+ 2;
463 vPoint
[0].y
= rRect
.yBottom
+ 2;
464 ::GpiMove(hPS
, &vPoint
[0]);
465 vPoint
[1].x
= rRect
.xRight
- 2;
466 vPoint
[1].y
= rRect
.yTop
- 2;
473 vLineBundle
.lColor
= 0x00FFFFFF; // BLACK
474 vLineBundle
.usMixMode
= FM_OVERPAINT
;
475 vLineBundle
.fxWidth
= 2;
476 vLineBundle
.lGeomWidth
= 2;
477 vLineBundle
.usType
= LINETYPE_SOLID
;
478 vLineBundle
.usEnd
= 0;
479 vLineBundle
.usJoin
= 0;
482 ,LBB_COLOR
| LBB_MIX_MODE
| LBB_WIDTH
| LBB_GEOM_WIDTH
| LBB_TYPE
486 vPoint
[0].x
= rRect
.xLeft
+ 3;
487 vPoint
[0].y
= rRect
.yBottom
+ 3;
488 ::GpiMove(hPS
, &vPoint
[0]);
489 vPoint
[1].x
= rRect
.xRight
- 3;
490 vPoint
[1].y
= rRect
.yTop
- 3;
498 if (dwStyle
& wxRAISED_BORDER
)
500 LINEBUNDLE vLineBundle
;
502 vLineBundle
.lColor
= 0x00000000; // BLACK
503 vLineBundle
.usMixMode
= FM_OVERPAINT
;
504 vLineBundle
.fxWidth
= 2;
505 vLineBundle
.lGeomWidth
= 2;
506 vLineBundle
.usType
= LINETYPE_SOLID
;
507 vLineBundle
.usEnd
= 0;
508 vLineBundle
.usJoin
= 0;
511 ,LBB_COLOR
| LBB_MIX_MODE
| LBB_WIDTH
| LBB_GEOM_WIDTH
| LBB_TYPE
515 vPoint
[1].x
= rRect
.xRight
- 1;
516 vPoint
[1].y
= rRect
.yTop
- 1;
523 vPoint
[0].x
= rRect
.xLeft
+ 1;
524 vPoint
[0].y
= rRect
.yBottom
+ 1;
525 ::GpiMove(hPS
, &vPoint
[0]);
526 vPoint
[1].x
= rRect
.xRight
- 2;
527 vPoint
[1].y
= rRect
.yTop
- 2;
535 vLineBundle
.lColor
= 0x00FFFFFF; // WHITE
536 vLineBundle
.usMixMode
= FM_OVERPAINT
;
537 vLineBundle
.fxWidth
= 2;
538 vLineBundle
.lGeomWidth
= 2;
539 vLineBundle
.usType
= LINETYPE_SOLID
;
540 vLineBundle
.usEnd
= 0;
541 vLineBundle
.usJoin
= 0;
544 ,LBB_COLOR
| LBB_MIX_MODE
| LBB_WIDTH
| LBB_GEOM_WIDTH
| LBB_TYPE
548 vPoint
[0].x
= rRect
.xLeft
+ 2;
549 vPoint
[0].y
= rRect
.yBottom
+ 2;
550 ::GpiMove(hPS
, &vPoint
[0]);
551 vPoint
[1].x
= rRect
.xLeft
+ 2;
552 vPoint
[1].y
= rRect
.yTop
- 3;
553 ::GpiLine(hPS
, &vPoint
[1]);
554 vPoint
[1].x
= rRect
.xRight
- 3;
555 vPoint
[1].y
= rRect
.yTop
- 3;
556 ::GpiLine(hPS
, &vPoint
[1]);
558 vPoint
[0].x
= rRect
.xLeft
+ 3;
559 vPoint
[0].y
= rRect
.yBottom
+ 3;
560 ::GpiMove(hPS
, &vPoint
[0]);
561 vPoint
[1].x
= rRect
.xLeft
+ 3;
562 vPoint
[1].y
= rRect
.yTop
- 4;
563 ::GpiLine(hPS
, &vPoint
[1]);
564 vPoint
[1].x
= rRect
.xRight
- 4;
565 vPoint
[1].y
= rRect
.yTop
- 4;
566 ::GpiLine(hPS
, &vPoint
[1]);
568 } // end of wxDrawBorder
572 , const wxFont
& rFont
580 if (hWnd
== NULLHANDLE
)
584 // The fonts available for Presentation Params are just a few
585 // outline fonts, the rest are available to the GPI, so we must
586 // map the families to one of these three
588 switch(rFont
.GetFamily())
591 strcpy(zFacename
, "Script");
595 strcpy(zFacename
, "WarpSans");
599 strcpy(zFacename
,"Times New Roman");
603 strcpy(zFacename
, "Courier New");
607 strcpy(zFacename
, "Courier New");
613 strcpy(zFacename
, "Helvetica");
617 switch(rFont
.GetWeight())
626 case wxFONTWEIGHT_MAX
:
627 strcpy(zWeight
, "Bold");
631 switch(rFont
.GetStyle())
635 strcpy(zStyle
, "Italic");
642 sprintf(zFont
, "%d.%s", rFont
.GetPointSize(), zFacename
);
643 if (zWeight
[0] != '\0')
646 strcat(zFont
, zWeight
);
648 if (zStyle
[0] != '\0')
651 strcat(zFont
, zStyle
);
653 ::WinSetPresParam(hWnd
, PP_FONTNAMESIZE
, strlen(zFont
) + 1, (PVOID
)zFont
);
654 } // end of wxOS2SetFont
656 // ---------------------------------------------------------------------------
657 // Helper for taking a regular bitmap and giving it a disabled look
658 // ---------------------------------------------------------------------------
659 wxBitmap
wxDisableBitmap(
664 wxMask
* pMask
= rBmp
.GetMask();
667 return(wxNullBitmap
);
669 DEVOPENSTRUC vDop
= {0L, "DISPLAY", NULL
, 0L, 0L, 0L, 0L, 0L, 0L};
670 SIZEL vSize
= {0, 0};
671 HDC hDC
= ::DevOpenDC(vHabmain
, OD_MEMORY
, "*", 5L, (PDEVOPENDATA
)&vDop
, NULLHANDLE
);
672 HPS hPS
= ::GpiCreatePS(vHabmain
, hDC
, &vSize
, PU_PELS
| GPIA_ASSOC
);
673 BITMAPINFOHEADER2 vHeader
;
677 HBITMAP hBitmap
= (HBITMAP
)rBmp
.GetHBITMAP();
678 HBITMAP hOldBitmap
= NULLHANDLE
;
679 HBITMAP hOldMask
= NULLHANDLE
;
680 HBITMAP hMask
= (HBITMAP
)rBmp
.GetMask()->GetMaskBitmap();
681 unsigned char* pucBits
; // buffer that will contain the bitmap data
682 unsigned char* pucData
; // pointer to use to traverse bitmap data
683 unsigned char* pucBitsMask
; // buffer that will contain the mask data
684 unsigned char* pucDataMask
; // pointer to use to traverse mask data
687 bool bpp16
= (wxDisplayDepth() == 16);
689 memset(&vHeader
, '\0', 16);
692 memset(&vInfo
, '\0', 16);
694 vInfo
.cx
= (ULONG
)rBmp
.GetWidth();
695 vInfo
.cy
= (ULONG
)rBmp
.GetHeight();
697 vInfo
.cBitCount
= 24; // Set to desired count going in
700 // Create the buffers for data....all wxBitmaps are 24 bit internally
702 int nBytesPerLine
= rBmp
.GetWidth() * 3;
703 int nSizeDWORD
= sizeof(DWORD
);
704 int nLineBoundary
= nBytesPerLine
% nSizeDWORD
;
710 // Bitmap must be in a double-word aligned address so we may
711 // have some padding to worry about
713 if (nLineBoundary
> 0)
715 nPadding
= nSizeDWORD
- nLineBoundary
;
716 nBytesPerLine
+= nPadding
;
718 pucBits
= (unsigned char *)malloc(nBytesPerLine
* rBmp
.GetHeight());
719 memset(pucBits
, '\0', (nBytesPerLine
* rBmp
.GetHeight()));
720 pucBitsMask
= (unsigned char *)malloc(nBytesPerLine
* rBmp
.GetHeight());
721 memset(pucBitsMask
, '\0', (nBytesPerLine
* rBmp
.GetHeight()));
724 // Extract the bitmap and mask data
726 if ((hOldBitmap
= ::GpiSetBitmap(hPS
, hBitmap
)) == HBM_ERROR
)
728 vError
= ::WinGetLastError(vHabmain
);
729 sError
= wxPMErrorToStr(vError
);
731 ::GpiQueryBitmapInfoHeader(hBitmap
, &vHeader
);
732 vInfo
.cBitCount
= 24;
733 if ((lScans
= ::GpiQueryBitmapBits( hPS
735 ,(LONG
)rBmp
.GetHeight()
740 vError
= ::WinGetLastError(vHabmain
);
741 sError
= wxPMErrorToStr(vError
);
743 if ((hOldMask
= ::GpiSetBitmap(hPS
, hMask
)) == HBM_ERROR
)
745 vError
= ::WinGetLastError(vHabmain
);
746 sError
= wxPMErrorToStr(vError
);
748 ::GpiQueryBitmapInfoHeader(hMask
, &vHeader
);
749 vInfo
.cBitCount
= 24;
750 if ((lScans
= ::GpiQueryBitmapBits( hPS
752 ,(LONG
)rBmp
.GetHeight()
757 vError
= ::WinGetLastError(vHabmain
);
758 sError
= wxPMErrorToStr(vError
);
760 if (( hMask
= ::GpiSetBitmap(hPS
, hOldMask
)) == HBM_ERROR
)
762 vError
= ::WinGetLastError(vHabmain
);
763 sError
= wxPMErrorToStr(vError
);
766 pucDataMask
= pucBitsMask
;
769 // Get the mask value
771 for (i
= 0; i
< rBmp
.GetHeight(); i
++)
773 for (j
= 0; j
< rBmp
.GetWidth(); j
++)
776 if (bpp16
&& *pucDataMask
== 0xF8) // 16 bit display gobblygook
781 else if (*pucDataMask
== 0xFF) // set to grey
788 *pucData
= ((unsigned char)(lColor
>> 16));
793 if (bpp16
&& *(pucDataMask
+ 1) == 0xFC) // 16 bit display gobblygook
798 else if (*(pucDataMask
+ 1) == 0xFF) // set to grey
805 *pucData
= ((unsigned char)(lColor
>> 8));
810 if (bpp16
&& *(pucDataMask
+ 2) == 0xF8) // 16 bit display gobblygook
815 else if (*(pucDataMask
+ 2) == 0xFF) // set to grey
822 *pucData
= ((unsigned char)lColor
);
827 for (j
= 0; j
< nPadding
; j
++)
835 // Create a new bitmap and set the modified bits
837 wxBitmap
vNewBmp( rBmp
.GetWidth()
841 HBITMAP hNewBmp
= (HBITMAP
)vNewBmp
.GetHBITMAP();
843 if ((hOldBitmap
= ::GpiSetBitmap(hPS
, hNewBmp
)) == HBM_ERROR
)
845 vError
= ::WinGetLastError(vHabmain
);
846 sError
= wxPMErrorToStr(vError
);
848 if ((lScansSet
= ::GpiSetBitmapBits( hPS
850 ,(LONG
)rBmp
.GetHeight()
856 vError
= ::WinGetLastError(vHabmain
);
857 sError
= wxPMErrorToStr(vError
);
861 pNewMask
= new wxMask(pMask
->GetMaskBitmap());
862 vNewBmp
.SetMask(pNewMask
);
864 ::GpiSetBitmap(hPS
, NULLHANDLE
);
869 return(wxNullBitmap
);
870 } // end of wxDisableBitmap
872 COLORREF
wxColourToRGB(
873 const wxColour
& rColor
876 return(OS2RGB(rColor
.Red(), rColor
.Green(), rColor
.Blue()));
877 } // end of wxColourToRGB