1///////////////////////////////////////////////////////////////////////////////
2// Name:        src/os2/utilsgui.cpp
3// Purpose:     Various utility functions only available in GUI
4// Author:      David Webster
5// Modified by:
6// Created:     20.08.2003 (extracted from os2/utils.cpp)
7// RCS-ID:      $Id: utilsgui.cpp 41127 2006-09-10 12:25:54Z VZ $
8// Copyright:   (c) David Webster
9// License:     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/utils.h"
29    #include "wx/app.h"
30    #include "wx/cursor.h"
31    #include "wx/font.h"
32    #include "wx/timer.h"
33#endif //WX_PRECOMP
34
35#include "wx/apptrait.h"
36
37#include "wx/os2/private.h"     // includes <windows.h>
38
39// ============================================================================
40// implementation
41// ============================================================================
42
43// ----------------------------------------------------------------------------
44// functions to work with .INI files
45// ----------------------------------------------------------------------------
46
47// Sleep for nSecs seconds. Attempt a Windows implementation using timers.
48static bool inTimer = false;
49
50class wxSleepTimer: public wxTimer
51{
52public:
53    inline void Notify()
54    {
55        inTimer = false;
56        Stop();
57    }
58};
59
60// Reading and writing resources (eg WIN.INI, .Xdefaults)
61#if wxUSE_RESOURCES
62bool wxWriteResource( const wxString& rSection,
63                      const wxString& rEntry,
64                      const wxString& rValue,
65                      const wxString& rFile )
66{
67    HAB  hab = 0;
68    HINI hIni = 0;
69
70    if (!rFile.empty())
71    {
72        hIni = ::PrfOpenProfile(hab, (PSZ)WXSTRINGCAST rFile);
73        if (hIni != 0L)
74        {
75            return (::PrfWriteProfileString( hIni
76                                            ,(PSZ)WXSTRINGCAST rSection
77                                            ,(PSZ)WXSTRINGCAST rEntry
78                                            ,(PSZ)WXSTRINGCAST rValue
79                                           ));
80        }
81    }
82    else
83        return (::PrfWriteProfileString( HINI_PROFILE
84                                        ,(PSZ)WXSTRINGCAST rSection
85                                        ,(PSZ)WXSTRINGCAST rEntry
86                                        ,(PSZ)WXSTRINGCAST rValue
87                                       ));
88    return false;
89}
90
91bool wxWriteResource(
92  const wxString&                   rSection
93, const wxString&                   rEntry
94, float                             fValue
95, const wxString&                   rFile
96)
97{
98    wxChar                          zBuf[50];
99
100    wxSprintf(zBuf, "%.4f", fValue);
101    return wxWriteResource( rSection
102                           ,rEntry
103                           ,zBuf
104                           ,rFile
105                          );
106}
107
108bool wxWriteResource(
109  const wxString&                   rSection
110, const wxString&                   rEntry
111, long                              lValue
112, const wxString&                   rFile
113)
114{
115    wxChar                          zBuf[50];
116
117    wxSprintf(zBuf, "%ld", lValue);
118    return wxWriteResource( rSection
119                           ,rEntry
120                           ,zBuf
121                           ,rFile
122                          );
123}
124
125bool wxWriteResource( const wxString& rSection,
126                      const wxString& rEntry,
127                      int lValue,
128                      const wxString& rFile )
129{
130    wxChar zBuf[50];
131
132    wxSprintf(zBuf, "%d", lValue);
133    return wxWriteResource( rSection, rEntry, zBuf, rFile );
134}
135
136bool wxGetResource( const wxString& rSection,
137                    const wxString& rEntry,
138                    wxChar** ppValue,
139                    const wxString& rFile )
140{
141    HAB    hab = 0;
142    HINI   hIni = 0;
143    wxChar zDefunkt[] = _T("$$default");
144    char   zBuf[1000];
145
146    if (!rFile.empty())
147    {
148        hIni = ::PrfOpenProfile(hab, (PSZ)WXSTRINGCAST rFile);
149        if (hIni != 0L)
150        {
151            ULONG n = ::PrfQueryProfileString( hIni
152                                              ,(PSZ)WXSTRINGCAST rSection
153                                              ,(PSZ)WXSTRINGCAST rEntry
154                                              ,(PSZ)zDefunkt
155                                              ,(PVOID)zBuf
156                                              ,1000
157                                             );
158            if (zBuf == NULL)
159                return false;
160            if (n == 0L || wxStrcmp(zBuf, zDefunkt) == 0)
161                return false;
162            zBuf[n-1] = '\0';
163        }
164        else
165            return false;
166    }
167    else
168    {
169        ULONG n = ::PrfQueryProfileString( HINI_PROFILE
170                                          ,(PSZ)WXSTRINGCAST rSection
171                                          ,(PSZ)WXSTRINGCAST rEntry
172                                          ,(PSZ)zDefunkt
173                                          ,(PVOID)zBuf
174                                          ,1000
175                                         );
176        if (zBuf == NULL)
177            return false;
178        if (n == 0L || wxStrcmp(zBuf, zDefunkt) == 0)
179            return false;
180        zBuf[n-1] = '\0';
181    }
182    strcpy((char*)*ppValue, zBuf);
183    return true;
184}
185
186bool wxGetResource( const wxString& rSection,
187                    const wxString& rEntry,
188                    float* pValue,
189                    const wxString& rFile )
190{
191    wxChar* zStr = NULL;
192
193    zStr = new wxChar[1000];
194    bool bSucc = wxGetResource( rSection, rEntry, (wxChar **)&zStr, rFile );
195
196    if (bSucc)
197    {
198        *pValue = (float)wxStrtod(zStr, NULL);
199    }
200
201    delete[] zStr;
202    return bSucc;
203}
204
205bool wxGetResource( const wxString& rSection,
206                    const wxString& rEntry,
207                    long* pValue,
208                    const wxString& rFile )
209{
210    wxChar* zStr = NULL;
211
212    zStr = new wxChar[1000];
213    bool bSucc = wxGetResource( rSection, rEntry, (wxChar **)&zStr, rFile );
214
215    if (bSucc)
216    {
217        *pValue = wxStrtol(zStr, NULL, 10);
218    }
219
220    delete[] zStr;
221    return bSucc;
222}
223
224bool wxGetResource( const wxString& rSection,
225                    const wxString& rEntry,
226                    int* pValue,
227                    const wxString& rFile )
228{
229    wxChar* zStr = NULL;
230
231    zStr = new wxChar[1000];
232    bool bSucc = wxGetResource( rSection, rEntry, (wxChar **)&zStr, rFile );
233
234    if (bSucc)
235    {
236        *pValue = (int)wxStrtol(zStr, NULL, 10);
237    }
238
239    delete[] zStr;
240    return bSucc;
241}
242#endif // wxUSE_RESOURCES
243
244// ---------------------------------------------------------------------------
245// helper functions for showing a "busy" cursor
246// ---------------------------------------------------------------------------
247
248HCURSOR gs_wxBusyCursor = 0;     // new, busy cursor
249HCURSOR gs_wxBusyCursorOld = 0;  // old cursor
250static int gs_wxBusyCursorCount = 0;
251
252// Set the cursor to the busy cursor for all windows
253void wxBeginBusyCursor(const wxCursor* pCursor)
254{
255    if ( gs_wxBusyCursorCount++ == 0 )
256    {
257        gs_wxBusyCursor = (HCURSOR)pCursor->GetHCURSOR();
258        ::WinSetPointer(HWND_DESKTOP, (HPOINTER)gs_wxBusyCursor);
259    }
260    //else: nothing to do, already set
261}
262
263// Restore cursor to normal
264void wxEndBusyCursor()
265{
266    wxCHECK_RET( gs_wxBusyCursorCount > 0
267                ,_T("no matching wxBeginBusyCursor() for wxEndBusyCursor()")
268               );
269
270    if (--gs_wxBusyCursorCount == 0)
271    {
272        ::WinSetPointer(HWND_DESKTOP, (HPOINTER)gs_wxBusyCursorOld);
273        gs_wxBusyCursorOld = 0;
274    }
275}
276
277// true if we're between the above two calls
278bool wxIsBusy()
279{
280    return (gs_wxBusyCursorCount > 0);
281}
282
283// Check whether this window wants to process messages, e.g. Stop button
284// in long calculations.
285bool wxCheckForInterrupt( wxWindow* pWnd )
286{
287    if(pWnd)
288    {
289        QMSG vMsg;
290        HAB  hab = 0;
291        HWND hwndFilter = NULLHANDLE;
292
293        while(::WinPeekMsg(hab, &vMsg, hwndFilter, 0, 0, PM_REMOVE))
294        {
295            ::WinDispatchMsg(hab, &vMsg);
296        }
297        return true;//*** temporary?
298    }
299    else
300    {
301        wxFAIL_MSG(_T("pWnd==NULL !!!"));
302        return false;//*** temporary?
303    }
304}
305
306// ----------------------------------------------------------------------------
307// get display info
308// ----------------------------------------------------------------------------
309
310// See also the wxGetMousePosition in window.cpp
311// Deprecated: use wxPoint wxGetMousePosition() instead
312void wxGetMousePosition(
313  int*                              pX
314, int*                              pY
315)
316{
317    POINTL                          vPt;
318
319    ::WinQueryPointerPos(HWND_DESKTOP, &vPt);
320    *pX = vPt.x;
321    *pY = vPt.y;
322};
323
324// Return true if we have a colour display
325bool wxColourDisplay()
326{
327#if 0
328    HPS                             hpsScreen;
329    HDC                             hdcScreen;
330    LONG                            lColors;
331
332    hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
333    hdcScreen = ::GpiQueryDevice(hpsScreen);
334    ::DevQueryCaps(hdcScreen, CAPS_COLORS, 1L, &lColors);
335    return(lColors > 1L);
336#else
337    // I don't see how the PM display could not be color. Besides, this
338    // was leaking DCs and PSs!!!  MN
339    return true;
340#endif
341}
342
343// Returns depth of screen
344int wxDisplayDepth()
345{
346    HPS                             hpsScreen;
347    HDC                             hdcScreen;
348    LONG                            lPlanes;
349    LONG                            lBitsPerPixel;
350    static LONG                     nDepth = 0;
351
352    // The screen colordepth ain't gonna change. No reason to query
353    // it over and over!
354    if (!nDepth) {
355        hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
356        hdcScreen = ::GpiQueryDevice(hpsScreen);
357        ::DevQueryCaps(hdcScreen, CAPS_COLOR_PLANES, 1L, &lPlanes);
358        ::DevQueryCaps(hdcScreen, CAPS_COLOR_BITCOUNT, 1L, &lBitsPerPixel);
359
360        nDepth = (int)(lPlanes * lBitsPerPixel);
361        ::DevCloseDC(hdcScreen);
362        ::WinReleasePS(hpsScreen);
363    }
364    return (nDepth);
365}
366
367// Get size of display
368void wxDisplaySize(
369  int*                              pWidth
370, int*                              pHeight
371)
372{
373    HPS                             hpsScreen;
374    HDC                             hdcScreen;
375    static LONG                     lWidth  = 0;
376    static LONG                     lHeight = 0;
377
378    // The screen size ain't gonna change either so just cache the values
379    if (!lWidth) {
380        hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
381        hdcScreen = ::GpiQueryDevice(hpsScreen);
382        ::DevQueryCaps(hdcScreen, CAPS_WIDTH, 1L, &lWidth);
383        ::DevQueryCaps(hdcScreen, CAPS_HEIGHT, 1L, &lHeight);
384        ::DevCloseDC(hdcScreen);
385        ::WinReleasePS(hpsScreen);
386    }
387    if (pWidth)
388        *pWidth = (int)lWidth;
389    if (pHeight)
390        *pHeight = (int)lHeight;
391}
392
393void wxDisplaySizeMM(
394  int*                              pWidth
395, int*                              pHeight
396)
397{
398    HPS                             hpsScreen;
399    HDC                             hdcScreen;
400
401    hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
402    hdcScreen = ::GpiQueryDevice(hpsScreen);
403
404    if (pWidth)
405        ::DevQueryCaps( hdcScreen
406                       ,CAPS_HORIZONTAL_RESOLUTION
407                       ,1L
408                       ,(PLONG)pWidth
409                      );
410    if (pHeight)
411        ::DevQueryCaps( hdcScreen
412                       ,CAPS_VERTICAL_RESOLUTION
413                       ,1L
414                       ,(PLONG)pHeight
415                      );
416    ::DevCloseDC(hdcScreen);
417    ::WinReleasePS(hpsScreen);
418}
419
420void wxClientDisplayRect(int *x, int *y, int *width, int *height)
421{
422    // This is supposed to return desktop dimensions minus any window
423    // manager panels, menus, taskbars, etc.  If there is a way to do that
424    // for this platform please fix this function, otherwise it defaults
425    // to the entire desktop.
426    if (x) *x = 0;
427    if (y) *y = 0;
428    wxDisplaySize(width, height);
429}
430
431void wxGUIAppTraits::InitializeGui(unsigned long &ulHab)
432{
433    ulHab = ::WinInitialize(0);
434}
435
436void wxGUIAppTraits::TerminateGui(unsigned long ulHab)
437{
438    ::WinTerminate(ulHab);
439}
440
441wxPortId wxGUIAppTraits::GetToolkitVersion(int *verMaj, int *verMin) const
442{
443    // How to get version of PM ? I guess, just reusing the OS version is OK.
444    (void) wxGetOsVersion(verMaj, verMin);
445    return wxPORT_OS2;
446}
447
448
449// ---------------------------------------------------------------------------
450// window information functions
451// ---------------------------------------------------------------------------
452
453wxString WXDLLEXPORT wxGetWindowText( WXHWND hWnd )
454{
455    wxString vStr;
456
457    if ( hWnd )
458    {
459        long lLen = ::WinQueryWindowTextLength((HWND)hWnd) + 1;
460        ::WinQueryWindowText((HWND)hWnd, lLen, (PSZ)(wxChar*)wxStringBuffer(vStr, lLen));
461    }
462
463    return vStr;
464}
465
466wxString WXDLLEXPORT wxGetWindowClass( WXHWND hWnd )
467{
468    wxString vStr;
469    if ( hWnd )
470    {
471        int nLen = 256; // some starting value
472
473    for ( ;; )
474    {
475        int                     nCount = ::WinQueryClassName((HWND)hWnd, nLen, (PSZ)(wxChar*)wxStringBuffer(vStr, nLen));
476
477        if (nCount == nLen )
478        {
479            // the class name might have been truncated, retry with larger
480            // buffer
481            nLen *= 2;
482        }
483        else
484        {
485            break;
486        }
487        }
488    }
489    return vStr;
490}
491
492WXWORD WXDLLEXPORT wxGetWindowId(
493  WXHWND                            hWnd
494)
495{
496    return ::WinQueryWindowUShort((HWND)hWnd, QWS_ID);
497}
498
499void wxDrawBorder(
500  HPS                               hPS
501, RECTL&                            rRect
502, WXDWORD                           dwStyle
503)
504{
505    POINTL                          vPoint[2];
506
507    vPoint[0].x = rRect.xLeft;
508    vPoint[0].y = rRect.yBottom;
509    ::GpiMove(hPS, &vPoint[0]);
510    if (dwStyle & wxSIMPLE_BORDER ||
511        dwStyle & wxSTATIC_BORDER)
512    {
513        vPoint[1].x = rRect.xRight - 1;
514        vPoint[1].y = rRect.yTop - 1;
515        ::GpiBox( hPS
516                 ,DRO_OUTLINE
517                 ,&vPoint[1]
518                 ,0L
519                 ,0L
520                );
521    }
522    if (dwStyle & wxSUNKEN_BORDER)
523    {
524        LINEBUNDLE                      vLineBundle;
525
526        vLineBundle.lColor     = 0x00FFFFFF; // WHITE
527        vLineBundle.usMixMode  = FM_OVERPAINT;
528        vLineBundle.fxWidth    = 2;
529        vLineBundle.lGeomWidth = 2;
530        vLineBundle.usType     = LINETYPE_SOLID;
531        vLineBundle.usEnd      = 0;
532        vLineBundle.usJoin     = 0;
533        ::GpiSetAttrs( hPS
534                      ,PRIM_LINE
535                      ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
536                      ,0L
537                      ,&vLineBundle
538                     );
539        vPoint[1].x = rRect.xRight - 1;
540        vPoint[1].y = rRect.yTop - 1;
541        ::GpiBox( hPS
542                 ,DRO_OUTLINE
543                 ,&vPoint[1]
544                 ,0L
545                 ,0L
546                );
547       vPoint[0].x = rRect.xLeft + 1;
548       vPoint[0].y = rRect.yBottom + 1;
549       ::GpiMove(hPS, &vPoint[0]);
550        vPoint[1].x = rRect.xRight - 2;
551        vPoint[1].y = rRect.yTop - 2;
552        ::GpiBox( hPS
553                 ,DRO_OUTLINE
554                 ,&vPoint[1]
555                 ,0L
556                 ,0L
557                );
558
559        vLineBundle.lColor     = 0x00000000; // BLACK
560        vLineBundle.usMixMode  = FM_OVERPAINT;
561        vLineBundle.fxWidth    = 2;
562        vLineBundle.lGeomWidth = 2;
563        vLineBundle.usType     = LINETYPE_SOLID;
564        vLineBundle.usEnd      = 0;
565        vLineBundle.usJoin     = 0;
566        ::GpiSetAttrs( hPS
567                      ,PRIM_LINE
568                      ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
569                      ,0L
570                      ,&vLineBundle
571                     );
572        vPoint[0].x = rRect.xLeft + 2;
573        vPoint[0].y = rRect.yBottom + 2;
574        ::GpiMove(hPS, &vPoint[0]);
575        vPoint[1].x = rRect.xLeft + 2;
576        vPoint[1].y = rRect.yTop - 3;
577        ::GpiLine(hPS, &vPoint[1]);
578        vPoint[1].x = rRect.xRight - 3;
579        vPoint[1].y = rRect.yTop - 3;
580        ::GpiLine(hPS, &vPoint[1]);
581
582        vPoint[0].x = rRect.xLeft + 3;
583        vPoint[0].y = rRect.yBottom + 3;
584        ::GpiMove(hPS, &vPoint[0]);
585        vPoint[1].x = rRect.xLeft + 3;
586        vPoint[1].y = rRect.yTop - 4;
587        ::GpiLine(hPS, &vPoint[1]);
588        vPoint[1].x = rRect.xRight - 4;
589        vPoint[1].y = rRect.yTop - 4;
590        ::GpiLine(hPS, &vPoint[1]);
591    }
592    if (dwStyle & wxDOUBLE_BORDER)
593    {
594        LINEBUNDLE                      vLineBundle;
595
596        vLineBundle.lColor     = 0x00FFFFFF; // WHITE
597        vLineBundle.usMixMode  = FM_OVERPAINT;
598        vLineBundle.fxWidth    = 2;
599        vLineBundle.lGeomWidth = 2;
600        vLineBundle.usType     = LINETYPE_SOLID;
601        vLineBundle.usEnd      = 0;
602        vLineBundle.usJoin     = 0;
603        ::GpiSetAttrs( hPS
604                      ,PRIM_LINE
605                      ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
606                      ,0L
607                      ,&vLineBundle
608                     );
609        vPoint[1].x = rRect.xRight - 1;
610        vPoint[1].y = rRect.yTop - 1;
611        ::GpiBox( hPS
612                 ,DRO_OUTLINE
613                 ,&vPoint[1]
614                 ,0L
615                 ,0L
616                );
617        vLineBundle.lColor     = 0x00000000; // WHITE
618        vLineBundle.usMixMode  = FM_OVERPAINT;
619        vLineBundle.fxWidth    = 2;
620        vLineBundle.lGeomWidth = 2;
621        vLineBundle.usType     = LINETYPE_SOLID;
622        vLineBundle.usEnd      = 0;
623        vLineBundle.usJoin     = 0;
624        ::GpiSetAttrs( hPS
625                      ,PRIM_LINE
626                      ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
627                      ,0L
628                      ,&vLineBundle
629                     );
630        vPoint[0].x = rRect.xLeft + 2;
631        vPoint[0].y = rRect.yBottom + 2;
632        ::GpiMove(hPS, &vPoint[0]);
633        vPoint[1].x = rRect.xRight - 2;
634        vPoint[1].y = rRect.yTop - 2;
635        ::GpiBox( hPS
636                 ,DRO_OUTLINE
637                 ,&vPoint[1]
638                 ,0L
639                 ,0L
640                );
641        vLineBundle.lColor     = 0x00FFFFFF; // BLACK
642        vLineBundle.usMixMode  = FM_OVERPAINT;
643        vLineBundle.fxWidth    = 2;
644        vLineBundle.lGeomWidth = 2;
645        vLineBundle.usType     = LINETYPE_SOLID;
646        vLineBundle.usEnd      = 0;
647        vLineBundle.usJoin     = 0;
648        ::GpiSetAttrs( hPS
649                      ,PRIM_LINE
650                      ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
651                      ,0L
652                      ,&vLineBundle
653                     );
654        vPoint[0].x = rRect.xLeft + 3;
655        vPoint[0].y = rRect.yBottom + 3;
656        ::GpiMove(hPS, &vPoint[0]);
657        vPoint[1].x = rRect.xRight - 3;
658        vPoint[1].y = rRect.yTop - 3;
659        ::GpiBox( hPS
660                 ,DRO_OUTLINE
661                 ,&vPoint[1]
662                 ,0L
663                 ,0L
664                );
665    }
666    if (dwStyle & wxRAISED_BORDER)
667    {
668        LINEBUNDLE                      vLineBundle;
669
670        vLineBundle.lColor     = 0x00000000; // BLACK
671        vLineBundle.usMixMode  = FM_OVERPAINT;
672        vLineBundle.fxWidth    = 2;
673        vLineBundle.lGeomWidth = 2;
674        vLineBundle.usType     = LINETYPE_SOLID;
675        vLineBundle.usEnd      = 0;
676        vLineBundle.usJoin     = 0;
677        ::GpiSetAttrs( hPS
678                      ,PRIM_LINE
679                      ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
680                      ,0L
681                      ,&vLineBundle
682                     );
683        vPoint[1].x = rRect.xRight - 1;
684        vPoint[1].y = rRect.yTop - 1;
685        ::GpiBox( hPS
686                 ,DRO_OUTLINE
687                 ,&vPoint[1]
688                 ,0L
689                 ,0L
690                );
691       vPoint[0].x = rRect.xLeft + 1;
692       vPoint[0].y = rRect.yBottom + 1;
693       ::GpiMove(hPS, &vPoint[0]);
694        vPoint[1].x = rRect.xRight - 2;
695        vPoint[1].y = rRect.yTop - 2;
696        ::GpiBox( hPS
697                 ,DRO_OUTLINE
698                 ,&vPoint[1]
699                 ,0L
700                 ,0L
701                );
702
703        vLineBundle.lColor     = 0x00FFFFFF; // WHITE
704        vLineBundle.usMixMode  = FM_OVERPAINT;
705        vLineBundle.fxWidth    = 2;
706        vLineBundle.lGeomWidth = 2;
707        vLineBundle.usType     = LINETYPE_SOLID;
708        vLineBundle.usEnd      = 0;
709        vLineBundle.usJoin     = 0;
710        ::GpiSetAttrs( hPS
711                      ,PRIM_LINE
712                      ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
713                      ,0L
714                      ,&vLineBundle
715                     );
716        vPoint[0].x = rRect.xLeft + 2;
717        vPoint[0].y = rRect.yBottom + 2;
718        ::GpiMove(hPS, &vPoint[0]);
719        vPoint[1].x = rRect.xLeft + 2;
720        vPoint[1].y = rRect.yTop - 3;
721        ::GpiLine(hPS, &vPoint[1]);
722        vPoint[1].x = rRect.xRight - 3;
723        vPoint[1].y = rRect.yTop - 3;
724        ::GpiLine(hPS, &vPoint[1]);
725
726        vPoint[0].x = rRect.xLeft + 3;
727        vPoint[0].y = rRect.yBottom + 3;
728        ::GpiMove(hPS, &vPoint[0]);
729        vPoint[1].x = rRect.xLeft + 3;
730        vPoint[1].y = rRect.yTop - 4;
731        ::GpiLine(hPS, &vPoint[1]);
732        vPoint[1].x = rRect.xRight - 4;
733        vPoint[1].y = rRect.yTop - 4;
734        ::GpiLine(hPS, &vPoint[1]);
735    }
736} // end of wxDrawBorder
737
738void wxOS2SetFont(
739  HWND                              hWnd
740, const wxFont&                     rFont
741)
742{
743    char                            zFont[128];
744    char                            zFacename[30];
745    char                            zWeight[30];
746    char                            zStyle[30];
747
748    if (hWnd == NULLHANDLE)
749        return;
750
751    //
752    // The fonts available for Presentation Params are just a few
753    // outline fonts, the rest are available to the GPI, so we must
754    // map the families to one of these three
755    //
756    switch(rFont.GetFamily())
757    {
758        case wxSCRIPT:
759            strcpy(zFacename, "Script");
760            break;
761
762        case wxDECORATIVE:
763            strcpy(zFacename, "WarpSans");
764            break;
765
766        case wxROMAN:
767            strcpy(zFacename,"Times New Roman");
768            break;
769
770        case wxTELETYPE:
771            strcpy(zFacename, "Courier New");
772            break;
773
774        case wxMODERN:
775            strcpy(zFacename, "Courier New");
776            break;
777
778        case wxDEFAULT:
779        default:
780        case wxSWISS:
781            strcpy(zFacename, "Helvetica");
782            break;
783    }
784
785    switch(rFont.GetWeight())
786    {
787        default:
788        case wxNORMAL:
789        case wxLIGHT:
790            zWeight[0] = '\0';
791            break;
792
793        case wxBOLD:
794        case wxFONTWEIGHT_MAX:
795            strcpy(zWeight, "Bold");
796            break;
797    }
798
799    switch(rFont.GetStyle())
800    {
801        case wxITALIC:
802        case wxSLANT:
803            strcpy(zStyle, "Italic");
804            break;
805
806        default:
807            zStyle[0] = '\0';
808            break;
809    }
810    sprintf(zFont, "%d.%s", rFont.GetPointSize(), zFacename);
811    if (zWeight[0] != '\0')
812    {
813        strcat(zFont, " ");
814        strcat(zFont, zWeight);
815    }
816    if (zStyle[0] != '\0')
817    {
818        strcat(zFont, " ");
819        strcat(zFont, zStyle);
820    }
821    ::WinSetPresParam(hWnd, PP_FONTNAMESIZE, strlen(zFont) + 1, (PVOID)zFont);
822} // end of wxOS2SetFont
823
824// ---------------------------------------------------------------------------
825// Helper for taking a regular bitmap and giving it a disabled look
826// ---------------------------------------------------------------------------
827wxBitmap wxDisableBitmap(
828  const wxBitmap&                   rBmp
829, long                              lColor
830)
831{
832    wxMask*                         pMask = rBmp.GetMask();
833
834    if (!pMask)
835        return(wxNullBitmap);
836
837    DEVOPENSTRUC                    vDop  = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
838    SIZEL                           vSize = {0, 0};
839    HDC                             hDC   = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
840    HPS                             hPS   = ::GpiCreatePS(vHabmain, hDC, &vSize, PU_PELS | GPIA_ASSOC);
841    BITMAPINFOHEADER2               vHeader;
842    BITMAPINFO2                     vInfo;
843    ERRORID                         vError;
844    wxString                        sError;
845    HBITMAP                         hBitmap =  (HBITMAP)rBmp.GetHBITMAP();
846    HBITMAP                         hOldBitmap = NULLHANDLE;
847    HBITMAP                         hOldMask   = NULLHANDLE;
848    HBITMAP                         hMask = (HBITMAP)rBmp.GetMask()->GetMaskBitmap();
849    unsigned char*                  pucBits;     // buffer that will contain the bitmap data
850    unsigned char*                  pucData;     // pointer to use to traverse bitmap data
851    unsigned char*                  pucBitsMask; // buffer that will contain the mask data
852    unsigned char*                  pucDataMask; // pointer to use to traverse mask data
853    LONG                            lScans = 0L;
854    LONG                            lScansSet = 0L;
855    bool                            bpp16 = (wxDisplayDepth() == 16);
856
857    memset(&vHeader, '\0', 16);
858    vHeader.cbFix           = 16;
859
860    memset(&vInfo, '\0', 16);
861    vInfo.cbFix           = 16;
862    vInfo.cx              = (ULONG)rBmp.GetWidth();
863    vInfo.cy              = (ULONG)rBmp.GetHeight();
864    vInfo.cPlanes         = 1;
865    vInfo.cBitCount       = 24; // Set to desired count going in
866
867    //
868    // Create the buffers for data....all wxBitmaps are 24 bit internally
869    //
870    int                             nBytesPerLine = rBmp.GetWidth() * 3;
871    int                             nSizeDWORD    = sizeof(DWORD);
872    int                             nLineBoundary = nBytesPerLine % nSizeDWORD;
873    int                             nPadding = 0;
874    int                             i;
875    int                             j;
876
877    //
878    // Bitmap must be in a double-word aligned address so we may
879    // have some padding to worry about
880    //
881    if (nLineBoundary > 0)
882    {
883        nPadding     = nSizeDWORD - nLineBoundary;
884        nBytesPerLine += nPadding;
885    }
886    pucBits = (unsigned char *)malloc(nBytesPerLine * rBmp.GetHeight());
887    memset(pucBits, '\0', (nBytesPerLine * rBmp.GetHeight()));
888    pucBitsMask = (unsigned char *)malloc(nBytesPerLine * rBmp.GetHeight());
889    memset(pucBitsMask, '\0', (nBytesPerLine * rBmp.GetHeight()));
890
891    //
892    // Extract the bitmap and mask data
893    //
894    if ((hOldBitmap = ::GpiSetBitmap(hPS, hBitmap)) == HBM_ERROR)
895    {
896        vError = ::WinGetLastError(vHabmain);
897        sError = wxPMErrorToStr(vError);
898    }
899    ::GpiQueryBitmapInfoHeader(hBitmap, &vHeader);
900    vInfo.cBitCount = 24;
901    if ((lScans = ::GpiQueryBitmapBits( hPS
902                                       ,0L
903                                       ,(LONG)rBmp.GetHeight()
904                                       ,(PBYTE)pucBits
905                                       ,&vInfo
906                                      )) == GPI_ALTERROR)
907    {
908        vError = ::WinGetLastError(vHabmain);
909        sError = wxPMErrorToStr(vError);
910    }
911    if ((hOldMask = ::GpiSetBitmap(hPS, hMask)) == HBM_ERROR)
912    {
913        vError = ::WinGetLastError(vHabmain);
914        sError = wxPMErrorToStr(vError);
915    }
916    ::GpiQueryBitmapInfoHeader(hMask, &vHeader);
917    vInfo.cBitCount = 24;
918    if ((lScans = ::GpiQueryBitmapBits( hPS
919                                       ,0L
920                                       ,(LONG)rBmp.GetHeight()
921                                       ,(PBYTE)pucBitsMask
922                                       ,&vInfo
923                                      )) == GPI_ALTERROR)
924    {
925        vError = ::WinGetLastError(vHabmain);
926        sError = wxPMErrorToStr(vError);
927    }
928    if (( hMask = ::GpiSetBitmap(hPS, hOldMask)) == HBM_ERROR)
929    {
930        vError = ::WinGetLastError(vHabmain);
931        sError = wxPMErrorToStr(vError);
932    }
933    pucData     = pucBits;
934    pucDataMask = pucBitsMask;
935
936    //
937    // Get the mask value
938    //
939    for (i = 0; i < rBmp.GetHeight(); i++)
940    {
941        for (j = 0; j < rBmp.GetWidth(); j++)
942        {
943            // Byte 1
944            if (bpp16 && *pucDataMask == 0xF8) // 16 bit display gobblygook
945            {
946                *pucData = 0x7F;
947                pucData++;
948            }
949            else if (*pucDataMask == 0xFF) // set to grey
950            {
951                *pucData = 0x7F;
952                pucData++;
953            }
954            else
955            {
956                *pucData = ((unsigned char)(lColor >> 16));
957                pucData++;
958            }
959
960            // Byte 2
961            if (bpp16 && *(pucDataMask + 1) == 0xFC) // 16 bit display gobblygook
962            {
963                *pucData = 0x7F;
964                pucData++;
965            }
966            else if (*(pucDataMask + 1) == 0xFF) // set to grey
967            {
968                *pucData = 0x7F;
969                pucData++;
970            }
971            else
972            {
973                *pucData = ((unsigned char)(lColor >> 8));
974                pucData++;
975            }
976
977            // Byte 3
978            if (bpp16 && *(pucDataMask + 2) == 0xF8) // 16 bit display gobblygook
979            {
980                *pucData = 0x7F;
981                pucData++;
982            }
983            else if (*(pucDataMask + 2) == 0xFF) // set to grey
984            {
985                *pucData = 0x7F;
986                pucData++;
987            }
988            else
989            {
990                *pucData = ((unsigned char)lColor);
991                pucData++;
992            }
993            pucDataMask += 3;
994        }
995        for (j = 0; j < nPadding; j++)
996        {
997            pucData++;
998            pucDataMask++;
999        }
1000    }
1001
1002    //
1003    // Create a new bitmap and set the modified bits
1004    //
1005    wxBitmap                        vNewBmp( rBmp.GetWidth()
1006                                            ,rBmp.GetHeight()
1007                                            ,24
1008                                           );
1009    HBITMAP                         hNewBmp = (HBITMAP)vNewBmp.GetHBITMAP();
1010
1011    if ((hOldBitmap = ::GpiSetBitmap(hPS, hNewBmp)) == HBM_ERROR)
1012    {
1013        vError = ::WinGetLastError(vHabmain);
1014        sError = wxPMErrorToStr(vError);
1015    }
1016    if ((lScansSet = ::GpiSetBitmapBits( hPS
1017                                        ,0L
1018                                        ,(LONG)rBmp.GetHeight()
1019                                        ,(PBYTE)pucBits
1020                                        ,&vInfo
1021                                       )) == GPI_ALTERROR)
1022
1023    {
1024        vError = ::WinGetLastError(vHabmain);
1025        sError = wxPMErrorToStr(vError);
1026    }
1027    wxMask*                         pNewMask;
1028
1029    pNewMask = new wxMask(pMask->GetMaskBitmap());
1030    vNewBmp.SetMask(pNewMask);
1031    free(pucBits);
1032    ::GpiSetBitmap(hPS, NULLHANDLE);
1033    ::GpiDestroyPS(hPS);
1034    ::DevCloseDC(hDC);
1035    if (vNewBmp.Ok())
1036        return(vNewBmp);
1037    return(wxNullBitmap);
1038} // end of wxDisableBitmap
1039
1040COLORREF wxColourToRGB(
1041  const wxColour&                   rColor
1042)
1043{
1044    return(OS2RGB(rColor.Red(), rColor.Green(), rColor.Blue()));
1045} // end of wxColourToRGB
1046