GetOsVersion() is now wxGUIAppTraits method instead of a global function
[wxWidgets.git] / src / os2 / utils.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: utils.cpp
3 // Purpose: Various utilities
4 // Author: David Webster
5 // Modified by:
6 // Created: 09/17/99
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifndef WX_PRECOMP
16 #include "wx/setup.h"
17 #include "wx/utils.h"
18 #include "wx/app.h"
19 #include "wx/cursor.h"
20 #endif //WX_PRECOMP
21
22 #include "wx/os2/private.h"
23 #include "wx/timer.h"
24 #include "wx/intl.h"
25 #include "wx/apptrait.h"
26
27 #include <ctype.h>
28 #ifdef __EMX__
29 #include <dirent.h>
30 #endif
31
32 #include "wx/log.h"
33
34 #include <io.h>
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <stdarg.h>
41
42 #define PURE_32
43
44 #ifndef __EMX__
45 #include <upm.h>
46 #include <netcons.h>
47 #include <netbios.h>
48 #endif
49
50 static const wxChar WX_SECTION[] = _T("wxWindows");
51 static const wxChar eHOSTNAME[] = _T("HostName");
52 static const wxChar eUSERID[] = _T("UserId");
53 static const wxChar eUSERNAME[] = _T("UserName");
54
55 // For the following functions we SHOULD fill in support
56 // for Windows-NT (which I don't know) as I assume it begin
57 // a POSIX Unix (so claims MS) that it has some special
58 // functions beyond those provided by WinSock
59
60 // Get full hostname (eg. DoDo.BSn-Germany.crg.de)
61 bool wxGetHostName(
62 wxChar* zBuf
63 , int nMaxSize
64 )
65 {
66 #if wxUSE_NET_API
67 char zServer[256];
68 char zComputer[256];
69 unsigned long ulLevel = 0;
70 unsigned char* zBuffer = NULL;
71 unsigned long ulBuffer = 256;
72 unsigned long* pulTotalAvail = NULL;
73
74 NetBios32GetInfo( (const unsigned char*)zServer
75 ,(const unsigned char*)zComputer
76 ,ulLevel
77 ,zBuffer
78 ,ulBuffer
79 ,pulTotalAvail
80 );
81 strcpy(zBuf, zServer);
82 #else
83 wxChar* zSysname;
84 const wxChar* zDefaultHost = _T("noname");
85
86 if ((zSysname = wxGetenv(_T("SYSTEM_NAME"))) == NULL)
87 {
88 ULONG n = ::PrfQueryProfileString( HINI_PROFILE
89 ,(PSZ)WX_SECTION
90 ,(PSZ)eHOSTNAME
91 ,(PSZ)zDefaultHost
92 ,(void*)zBuf
93 ,(ULONG)nMaxSize - 1
94 );
95 }
96 else
97 wxStrncpy(zBuf, zSysname, nMaxSize - 1);
98 zBuf[nMaxSize] = _T('\0');
99 #endif
100 return *zBuf ? TRUE : FALSE;
101 }
102
103 // Get user ID e.g. jacs
104 bool wxGetUserId(
105 wxChar* zBuf
106 , int nType
107 )
108 {
109 #if defined(__VISAGECPP__)
110 long lrc;
111 // UPM procs return 0 on success
112 lrc = U32ELOCU((unsigned char*)zBuf, (unsigned long *)&nType);
113 if (lrc == 0) return TRUE;
114 #endif
115 return FALSE;
116 }
117
118 bool wxGetUserName(
119 wxChar* zBuf
120 , int nMaxSize
121 )
122 {
123 #ifdef USE_NET_API
124 wxGetUserId( zBuf
125 ,nMaxSize
126 );
127 #else
128 wxStrncpy(zBuf, _T("Unknown User"), nMaxSize);
129 #endif
130 return TRUE;
131 }
132
133 int wxKill(
134 long lPid
135 , wxSignal eSig
136 , wxKillError* peError
137 )
138 {
139 return((int)::DosKillProcess(0, (PID)lPid));
140 }
141
142 //
143 // Execute a program in an Interactive Shell
144 //
145 bool wxShell(
146 const wxString& rCommand
147 )
148 {
149 wxChar* zShell = _T("CMD.EXE");
150 wxString sInputs;
151 wxChar zTmp[255];
152 STARTDATA SData = {0};
153 PSZ PgmTitle = "Command Shell";
154 APIRET rc;
155 PID vPid = 0;
156 ULONG ulSessID = 0;
157 UCHAR achObjBuf[256] = {0}; //error data if DosStart fails
158 RESULTCODES vResult;
159
160 SData.Length = sizeof(STARTDATA);
161 SData.Related = SSF_RELATED_INDEPENDENT;
162 SData.FgBg = SSF_FGBG_FORE;
163 SData.TraceOpt = SSF_TRACEOPT_NONE;
164 SData.PgmTitle = PgmTitle;
165 SData.PgmName = zShell;
166
167 sInputs = "/C " + rCommand;
168 SData.PgmInputs = (BYTE*)sInputs.c_str();
169 SData.TermQ = 0;
170 SData.Environment = 0;
171 SData.InheritOpt = SSF_INHERTOPT_SHELL;
172 SData.SessionType = SSF_TYPE_WINDOWABLEVIO;
173 SData.IconFile = 0;
174 SData.PgmHandle = 0;
175 SData.PgmControl = SSF_CONTROL_VISIBLE | SSF_CONTROL_MAXIMIZE;
176 SData.InitXPos = 30;
177 SData.InitYPos = 40;
178 SData.InitXSize = 200;
179 SData.InitYSize = 140;
180 SData.Reserved = 0;
181 SData.ObjectBuffer = (char*)achObjBuf;
182 SData.ObjectBuffLen = (ULONG)sizeof(achObjBuf);
183
184 rc = ::DosStartSession(&SData, &ulSessID, &vPid);
185 if (rc == 0 || rc == 457) // NO_ERROR or SMG_START_IN_BACKGROUND
186 {
187 PTIB ptib;
188 PPIB ppib;
189
190 ::DosGetInfoBlocks(&ptib, &ppib);
191
192 ::DosWaitChild( DCWA_PROCESS
193 ,DCWW_WAIT
194 ,&vResult
195 ,&ppib->pib_ulpid
196 ,vPid
197 );
198 }
199 return (rc != 0);
200 }
201
202 // Shutdown or reboot the PC
203 bool wxShutdown(wxShutdownFlags wFlags)
204 {
205 // TODO
206 return FALSE;
207 }
208
209 // Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX)
210 long wxGetFreeMemory()
211 {
212 void* pMemptr = NULL;
213 ULONG lSize;
214 ULONG lMemFlags;
215 APIRET rc;
216
217 lMemFlags = PAG_FREE;
218 rc = ::DosQueryMem(pMemptr, &lSize, &lMemFlags);
219 if (rc != 0)
220 return -1L;
221 return (long)lSize;
222 }
223
224 // ----------------------------------------------------------------------------
225 // env vars
226 // ----------------------------------------------------------------------------
227
228 bool wxGetEnv(const wxString& var, wxString *value)
229 {
230 // wxGetenv is defined as getenv()
231 wxChar *p = wxGetenv(var);
232 if ( !p )
233 return FALSE;
234
235 if ( value )
236 {
237 *value = p;
238 }
239
240 return TRUE;
241 }
242
243 bool wxSetEnv(const wxString& variable, const wxChar *value)
244 {
245 #if defined(HAVE_SETENV)
246 return setenv(variable.mb_str(), value ? wxString(value).mb_str().data()
247 : NULL, 1 /* overwrite */) == 0;
248 #elif defined(HAVE_PUTENV)
249 wxString s = variable;
250 if ( value )
251 s << _T('=') << value;
252
253 // transform to ANSI
254 const char *p = s.mb_str();
255
256 // the string will be free()d by libc
257 char *buf = (char *)malloc(strlen(p) + 1);
258 strcpy(buf, p);
259
260 return putenv(buf) == 0;
261 #else // no way to set an env var
262 return FALSE;
263 #endif
264 }
265
266
267 // Sleep for nSecs seconds. Attempt a Windows implementation using timers.
268 static bool inTimer = FALSE;
269
270 class wxSleepTimer: public wxTimer
271 {
272 public:
273 inline void Notify()
274 {
275 inTimer = FALSE;
276 Stop();
277 }
278 };
279
280 static wxTimer* wxTheSleepTimer = NULL;
281
282 void wxUsleep(
283 unsigned long ulMilliseconds
284 )
285 {
286 ::DosSleep(ulMilliseconds/1000l);
287 }
288
289 void wxSleep(
290 int nSecs
291 )
292 {
293 ::DosSleep(1000 * nSecs);
294 }
295
296 // Consume all events until no more left
297 void wxFlushEvents()
298 {
299 // wxYield();
300 }
301
302 #if WXWIN_COMPATIBILITY_2_2
303
304 // Output a debug mess., in a system dependent fashion.
305 void wxDebugMsg(
306 const wxChar* zFmt ...
307 )
308 {
309 va_list vAp;
310 static wxChar zBuffer[512];
311
312 if (!wxTheApp->GetWantDebugOutput())
313 return ;
314 va_start(vAp, zFmt);
315 sprintf(zBuffer, zFmt, vAp) ;
316 va_end(vAp);
317 }
318
319 // Non-fatal error: pop up message box and (possibly) continue
320 void wxError(
321 const wxString& rMsg
322 , const wxString& rTitle
323 )
324 {
325 wxBuffer = new wxChar[256];
326 wxSprintf(wxBuffer, "%s\nContinue?", WXSTRINGCAST rMsg);
327 if (::WinMessageBox( HWND_DESKTOP
328 ,NULL
329 ,(PSZ)wxBuffer
330 ,(PSZ)WXSTRINGCAST rTitle
331 ,0
332 ,MB_ICONEXCLAMATION | MB_YESNO
333 ) == MBID_YES)
334 delete[] wxBuffer;
335 wxExit();
336 }
337
338 // Fatal error: pop up message box and abort
339 void wxFatalError(
340 const wxString& rMsg
341 , const wxString& rTitle
342 )
343 {
344 unsigned long ulRc;
345
346 ulRc = ::WinMessageBox( HWND_DESKTOP
347 ,NULL
348 ,WXSTRINGCAST rMsg
349 ,WXSTRINGCAST rTitle
350 ,0
351 ,MB_NOICON | MB_OK
352 );
353 DosExit(EXIT_PROCESS, ulRc);
354 }
355
356 #endif // WXWIN_COMPATIBILITY_2_2
357
358 // Emit a beeeeeep
359 void wxBell()
360 {
361 DosBeep(1000,1000); // 1kHz during 1 sec.
362 }
363
364 int wxGUIAppTraits::GetOSVersion(
365 int* pMajorVsn
366 , int* pMinorVsn
367 )
368 {
369 ULONG ulSysInfo[QSV_MAX] = {0};
370 APIRET ulrc;
371
372 ulrc = ::DosQuerySysInfo( 1L
373 ,QSV_MAX
374 ,(PVOID)ulSysInfo
375 ,sizeof(ULONG) * QSV_MAX
376 );
377 if (ulrc == 0L)
378 {
379 *pMajorVsn = ulSysInfo[QSV_VERSION_MAJOR];
380 *pMajorVsn = *pMajorVsn/10;
381 *pMinorVsn = ulSysInfo[QSV_VERSION_MINOR];
382 return wxWINDOWS_OS2;
383 }
384 return wxWINDOWS; // error if we get here, return generic value
385 }
386
387 // Reading and writing resources (eg WIN.INI, .Xdefaults)
388 #if wxUSE_RESOURCES
389 bool wxWriteResource(
390 const wxString& rSection
391 , const wxString& rEntry
392 , const wxString& rValue
393 , const wxString& rFile
394 )
395 {
396 HAB hab = 0;
397 HINI hIni = 0;
398
399 if (rFile != "")
400 {
401 hIni = ::PrfOpenProfile(hab, (PSZ)WXSTRINGCAST rFile);
402 if (hIni != 0L)
403 {
404 return (::PrfWriteProfileString( hIni
405 ,(PSZ)WXSTRINGCAST rSection
406 ,(PSZ)WXSTRINGCAST rEntry
407 ,(PSZ)WXSTRINGCAST rValue
408 ));
409 }
410 }
411 else
412 return (::PrfWriteProfileString( HINI_PROFILE
413 ,(PSZ)WXSTRINGCAST rSection
414 ,(PSZ)WXSTRINGCAST rEntry
415 ,(PSZ)WXSTRINGCAST rValue
416 ));
417 return FALSE;
418 }
419
420 bool wxWriteResource(
421 const wxString& rSection
422 , const wxString& rEntry
423 , float fValue
424 , const wxString& rFile
425 )
426 {
427 wxChar zBuf[50];
428
429 wxSprintf(zBuf, "%.4f", fValue);
430 return wxWriteResource( rSection
431 ,rEntry
432 ,zBuf
433 ,rFile
434 );
435 }
436
437 bool wxWriteResource(
438 const wxString& rSection
439 , const wxString& rEntry
440 , long lValue
441 , const wxString& rFile
442 )
443 {
444 wxChar zBuf[50];
445
446 wxSprintf(zBuf, "%ld", lValue);
447 return wxWriteResource( rSection
448 ,rEntry
449 ,zBuf
450 ,rFile
451 );
452 }
453
454 bool wxWriteResource(
455 const wxString& rSection
456 , const wxString& rEntry
457 , int lValue
458 , const wxString& rFile
459 )
460 {
461 wxChar zBuf[50];
462
463 wxSprintf(zBuf, "%d", lValue);
464 return wxWriteResource( rSection
465 ,rEntry
466 ,zBuf
467 ,rFile
468 );
469 }
470
471 bool wxGetResource(
472 const wxString& rSection
473 , const wxString& rEntry
474 , wxChar** ppValue
475 , const wxString& rFile
476 )
477 {
478 HAB hab = 0;
479 HINI hIni = 0;
480 wxChar zDefunkt[] = _T("$$default");
481 char zBuf[1000];
482
483 if (rFile != "")
484 {
485 hIni = ::PrfOpenProfile(hab, (PSZ)WXSTRINGCAST rFile);
486 if (hIni != 0L)
487 {
488 ULONG n = ::PrfQueryProfileString( hIni
489 ,(PSZ)WXSTRINGCAST rSection
490 ,(PSZ)WXSTRINGCAST rEntry
491 ,(PSZ)zDefunkt
492 ,(PVOID)zBuf
493 ,1000
494 );
495 if (zBuf == NULL)
496 return FALSE;
497 if (n == 0L || wxStrcmp(zBuf, zDefunkt) == 0)
498 return FALSE;
499 zBuf[n-1] = '\0';
500 }
501 else
502 return FALSE;
503 }
504 else
505 {
506 ULONG n = ::PrfQueryProfileString( HINI_PROFILE
507 ,(PSZ)WXSTRINGCAST rSection
508 ,(PSZ)WXSTRINGCAST rEntry
509 ,(PSZ)zDefunkt
510 ,(PVOID)zBuf
511 ,1000
512 );
513 if (zBuf == NULL)
514 return FALSE;
515 if (n == 0L || wxStrcmp(zBuf, zDefunkt) == 0)
516 return FALSE;
517 zBuf[n-1] = '\0';
518 }
519 strcpy((char*)*ppValue, zBuf);
520 return TRUE;
521 }
522
523 bool wxGetResource(
524 const wxString& rSection
525 , const wxString& rEntry
526 , float* pValue
527 , const wxString& rFile
528 )
529 {
530 wxChar* zStr = NULL;
531
532 zStr = new wxChar[1000];
533 bool bSucc = wxGetResource( rSection
534 ,rEntry
535 ,(wxChar **)&zStr
536 ,rFile
537 );
538
539 if (bSucc)
540 {
541 *pValue = (float)wxStrtod(zStr, NULL);
542 delete[] zStr;
543 return TRUE;
544 }
545 else
546 {
547 delete[] zStr;
548 return FALSE;
549 }
550 }
551
552 bool wxGetResource(
553 const wxString& rSection
554 , const wxString& rEntry
555 , long* pValue
556 , const wxString& rFile
557 )
558 {
559 wxChar* zStr = NULL;
560
561 zStr = new wxChar[1000];
562 bool bSucc = wxGetResource( rSection
563 ,rEntry
564 ,(wxChar **)&zStr
565 ,rFile
566 );
567
568 if (bSucc)
569 {
570 *pValue = wxStrtol(zStr, NULL, 10);
571 delete[] zStr;
572 return TRUE;
573 }
574 else
575 {
576 delete[] zStr;
577 return FALSE;
578 }
579 }
580
581 bool wxGetResource(
582 const wxString& rSection
583 , const wxString& rEntry
584 , int* pValue
585 , const wxString& rFile
586 )
587 {
588 wxChar* zStr = NULL;
589
590 zStr = new wxChar[1000];
591 bool bSucc = wxGetResource( rSection
592 ,rEntry
593 ,(wxChar **)&zStr
594 ,rFile
595 );
596
597 if (bSucc)
598 {
599 *pValue = (int)wxStrtol(zStr, NULL, 10);
600 delete[] zStr;
601 return TRUE;
602 }
603 else
604 {
605 delete[] zStr;
606 return FALSE;
607 }
608 }
609 #endif // wxUSE_RESOURCES
610
611 // ---------------------------------------------------------------------------
612 // helper functions for showing a "busy" cursor
613 // ---------------------------------------------------------------------------
614
615 HCURSOR gs_wxBusyCursor = 0; // new, busy cursor
616 HCURSOR gs_wxBusyCursorOld = 0; // old cursor
617 static int gs_wxBusyCursorCount = 0;
618
619 // Set the cursor to the busy cursor for all windows
620 void wxBeginBusyCursor(
621 wxCursor* pCursor
622 )
623 {
624 if ( gs_wxBusyCursorCount++ == 0 )
625 {
626 gs_wxBusyCursor = (HCURSOR)pCursor->GetHCURSOR();
627 ::WinSetPointer(HWND_DESKTOP, (HPOINTER)gs_wxBusyCursor);
628 }
629 //else: nothing to do, already set
630 }
631
632 // Restore cursor to normal
633 void wxEndBusyCursor()
634 {
635 wxCHECK_RET( gs_wxBusyCursorCount > 0
636 ,_T("no matching wxBeginBusyCursor() for wxEndBusyCursor()")
637 );
638
639 if (--gs_wxBusyCursorCount == 0)
640 {
641 ::WinSetPointer(HWND_DESKTOP, (HPOINTER)gs_wxBusyCursorOld);
642 gs_wxBusyCursorOld = 0;
643 }
644 }
645
646 // TRUE if we're between the above two calls
647 bool wxIsBusy()
648 {
649 return (gs_wxBusyCursorCount > 0);
650 }
651
652 // ---------------------------------------------------------------------------
653 const wxChar* wxGetHomeDir(
654 wxString* pStr
655 )
656 {
657 wxString& rStrDir = *pStr;
658
659 // OS/2 has no idea about home,
660 // so use the working directory instead?
661
662 // 256 was taken from os2def.h
663 #ifndef MAX_PATH
664 # define MAX_PATH 256
665 #endif
666
667 char zDirName[256];
668 ULONG ulDirLen;
669
670 ::DosQueryCurrentDir(0, zDirName, &ulDirLen);
671 rStrDir = zDirName;
672 return rStrDir.c_str();
673 }
674
675 // Hack for OS/2
676 wxChar* wxGetUserHome (
677 const wxString& rUser
678 )
679 {
680 wxChar* zHome;
681 wxString sUser1(rUser);
682
683 wxBuffer = new wxChar[256];
684 #ifndef __EMX__
685 if (sUser1 != _T(""))
686 {
687 wxChar zTmp[64];
688
689 if (wxGetUserId( zTmp
690 ,sizeof(zTmp)/sizeof(char)
691 ))
692 {
693 // Guests belong in the temp dir
694 if (wxStricmp(zTmp, _T("annonymous")) == 0)
695 {
696 if ((zHome = wxGetenv(_T("TMP"))) != NULL ||
697 (zHome = wxGetenv(_T("TMPDIR"))) != NULL ||
698 (zHome = wxGetenv(_T("TEMP"))) != NULL)
699 delete[] wxBuffer;
700 return *zHome ? zHome : (wxChar*)_T("\\");
701 }
702 if (wxStricmp(zTmp, WXSTRINGCAST sUser1) == 0)
703 sUser1 = _T("");
704 }
705 }
706 #endif
707 if (sUser1 == _T(""))
708 {
709 if ((zHome = wxGetenv(_T("HOME"))) != NULL)
710 {
711 wxStrcpy(wxBuffer, zHome);
712 wxUnix2DosFilename(wxBuffer);
713 wxStrcpy(zHome, wxBuffer);
714 delete[] wxBuffer;
715 return zHome;
716 }
717 }
718 delete[] wxBuffer;
719 return NULL; // No home known!
720 }
721
722 // Check whether this window wants to process messages, e.g. Stop button
723 // in long calculations.
724 bool wxCheckForInterrupt(
725 wxWindow* pWnd
726 )
727 {
728 if(pWnd)
729 {
730 QMSG vMsg;
731 HAB hab = 0;
732 HWND hwndFilter = NULLHANDLE;
733 HWND hwndWin= (HWND) pWnd->GetHWND();
734
735 while(::WinPeekMsg(hab, &vMsg, hwndFilter, 0, 0, PM_REMOVE))
736 {
737 ::WinDispatchMsg(hab, &vMsg);
738 }
739 return TRUE;//*** temporary?
740 }
741 else
742 {
743 wxFAIL_MSG(_T("pWnd==NULL !!!"));
744 return FALSE;//*** temporary?
745 }
746 }
747
748 void wxGetMousePosition(
749 int* pX
750 , int* pY
751 )
752 {
753 POINTL vPt;
754
755 ::WinQueryPointerPos(HWND_DESKTOP, &vPt);
756 *pX = vPt.x;
757 *pY = vPt.y;
758 };
759
760 // Return TRUE if we have a colour display
761 bool wxColourDisplay()
762 {
763 #if 0
764 HPS hpsScreen;
765 HDC hdcScreen;
766 LONG lColors;
767
768 hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
769 hdcScreen = ::GpiQueryDevice(hpsScreen);
770 ::DevQueryCaps(hdcScreen, CAPS_COLORS, 1L, &lColors);
771 return(lColors > 1L);
772 #else
773 // I don't see how the PM display could not be color. Besides, this
774 // was leaking DCs and PSs!!! MN
775 return TRUE;
776 #endif
777 }
778
779 // Returns depth of screen
780 int wxDisplayDepth()
781 {
782 HPS hpsScreen;
783 HDC hdcScreen;
784 LONG lPlanes;
785 LONG lBitsPerPixel;
786 static LONG nDepth = 0;
787
788 // The screen colordepth ain't gonna change. No reason to query
789 // it over and over!
790 if (!nDepth) {
791 hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
792 hdcScreen = ::GpiQueryDevice(hpsScreen);
793 ::DevQueryCaps(hdcScreen, CAPS_COLOR_PLANES, 1L, &lPlanes);
794 ::DevQueryCaps(hdcScreen, CAPS_COLOR_BITCOUNT, 1L, &lBitsPerPixel);
795
796 nDepth = (int)(lPlanes * lBitsPerPixel);
797 ::DevCloseDC(hdcScreen);
798 ::WinReleasePS(hpsScreen);
799 }
800 return (nDepth);
801 }
802
803 // Get size of display
804 void wxDisplaySize(
805 int* pWidth
806 , int* pHeight
807 )
808 {
809 HPS hpsScreen;
810 HDC hdcScreen;
811 static LONG lWidth = 0;
812 static LONG lHeight = 0;
813
814 // The screen size ain't gonna change either so just cache the values
815 if (!lWidth) {
816 hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
817 hdcScreen = ::GpiQueryDevice(hpsScreen);
818 ::DevQueryCaps(hdcScreen, CAPS_WIDTH, 1L, &lWidth);
819 ::DevQueryCaps(hdcScreen, CAPS_HEIGHT, 1L, &lHeight);
820 ::DevCloseDC(hdcScreen);
821 ::WinReleasePS(hpsScreen);
822 }
823 *pWidth = (int)lWidth;
824 *pHeight = (int)lHeight;
825 }
826
827 void wxDisplaySizeMM(
828 int* pWidth
829 , int* pHeight
830 )
831 {
832 HPS hpsScreen;
833 HDC hdcScreen;
834
835 hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
836 hdcScreen = ::GpiQueryDevice(hpsScreen);
837
838 if (pWidth)
839 ::DevQueryCaps( hdcScreen
840 ,CAPS_HORIZONTAL_RESOLUTION
841 ,1L
842 ,(PLONG)pWidth
843 );
844 if (pHeight)
845 ::DevQueryCaps( hdcScreen
846 ,CAPS_VERTICAL_RESOLUTION
847 ,1L
848 ,(PLONG)pHeight
849 );
850 ::DevCloseDC(hdcScreen);
851 ::WinReleasePS(hpsScreen);
852 }
853
854 void wxClientDisplayRect(int *x, int *y, int *width, int *height)
855 {
856 // This is supposed to return desktop dimensions minus any window
857 // manager panels, menus, taskbars, etc. If there is a way to do that
858 // for this platform please fix this function, otherwise it defaults
859 // to the entire desktop.
860 if (x) *x = 0;
861 if (y) *y = 0;
862 wxDisplaySize(width, height);
863 }
864
865
866 bool wxDirExists(
867 const wxString& rDir
868 )
869 {
870 return (::DosSetCurrentDir(WXSTRINGCAST rDir));
871 }
872
873 // ---------------------------------------------------------------------------
874 // window information functions
875 // ---------------------------------------------------------------------------
876
877 wxString WXDLLEXPORT wxGetWindowText(
878 WXHWND hWnd
879 )
880 {
881 wxString vStr;
882 long lLen = ::WinQueryWindowTextLength((HWND)hWnd) + 1;
883
884 ::WinQueryWindowText((HWND)hWnd, lLen, vStr.GetWriteBuf((int)lLen));
885 vStr.UngetWriteBuf();
886
887 return vStr;
888 }
889
890 wxString WXDLLEXPORT wxGetWindowClass(
891 WXHWND hWnd
892 )
893 {
894 wxString vStr;
895 int nLen = 256; // some starting value
896
897 for ( ;; )
898 {
899 int nCount = ::WinQueryClassName((HWND)hWnd, nLen, vStr.GetWriteBuf(nLen));
900
901 vStr.UngetWriteBuf();
902 if (nCount == nLen )
903 {
904 // the class name might have been truncated, retry with larger
905 // buffer
906 nLen *= 2;
907 }
908 else
909 {
910 break;
911 }
912 }
913 return vStr;
914 }
915
916 WXWORD WXDLLEXPORT wxGetWindowId(
917 WXHWND hWnd
918 )
919 {
920 return ::WinQueryWindowUShort((HWND)hWnd, QWS_ID);
921 }
922
923 wxString WXDLLEXPORT wxPMErrorToStr(
924 ERRORID vError
925 )
926 {
927 wxString sError;
928
929 //
930 // Remove the high order byte -- it is useless
931 //
932 vError &= 0x0000ffff;
933 switch(vError)
934 {
935 case PMERR_INVALID_HWND:
936 sError = wxT("Invalid window handle specified");
937 break;
938
939 case PMERR_INVALID_FLAG:
940 sError = wxT("Invalid flag bit set");
941 break;
942
943 case PMERR_NO_MSG_QUEUE:
944 sError = wxT("No message queue available");
945 break;
946
947 case PMERR_INVALID_PARM:
948 sError = wxT("Parameter contained invalid data");
949 break;
950
951 case PMERR_INVALID_PARAMETERS:
952 sError = wxT("Parameter value is out of range");
953 break;
954
955 case PMERR_PARAMETER_OUT_OF_RANGE:
956 sError = wxT("Parameter value is out of range");
957 break;
958
959 case PMERR_INVALID_INTEGER_ATOM:
960 sError = wxT("Not a valid atom");
961 break;
962
963 case PMERR_INVALID_HATOMTBL:
964 sError = wxT("Atom table handle is invalid");
965 break;
966
967 case PMERR_INVALID_ATOM_NAME:
968 sError = wxT("Not a valid atom name");
969 break;
970
971 case PMERR_ATOM_NAME_NOT_FOUND:
972 sError = wxT("Valid name format, but cannot find name in atom table");
973 break;
974
975 default:
976 sError = wxT("Unknown error");
977 }
978 return(sError);
979 } // end of wxPMErrorToStr
980
981 void wxDrawBorder(
982 HPS hPS
983 , RECTL& rRect
984 , WXDWORD dwStyle
985 )
986 {
987 POINTL vPoint[2];
988
989 vPoint[0].x = rRect.xLeft;
990 vPoint[0].y = rRect.yBottom;
991 ::GpiMove(hPS, &vPoint[0]);
992 if (dwStyle & wxSIMPLE_BORDER ||
993 dwStyle & wxSTATIC_BORDER)
994 {
995 vPoint[1].x = rRect.xRight - 1;
996 vPoint[1].y = rRect.yTop - 1;
997 ::GpiBox( hPS
998 ,DRO_OUTLINE
999 ,&vPoint[1]
1000 ,0L
1001 ,0L
1002 );
1003 }
1004 if (dwStyle & wxSUNKEN_BORDER)
1005 {
1006 LINEBUNDLE vLineBundle;
1007
1008 vLineBundle.lColor = 0x00FFFFFF; // WHITE
1009 vLineBundle.usMixMode = FM_OVERPAINT;
1010 vLineBundle.fxWidth = 2;
1011 vLineBundle.lGeomWidth = 2;
1012 vLineBundle.usType = LINETYPE_SOLID;
1013 vLineBundle.usEnd = 0;
1014 vLineBundle.usJoin = 0;
1015 ::GpiSetAttrs( hPS
1016 ,PRIM_LINE
1017 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
1018 ,0L
1019 ,&vLineBundle
1020 );
1021 vPoint[1].x = rRect.xRight - 1;
1022 vPoint[1].y = rRect.yTop - 1;
1023 ::GpiBox( hPS
1024 ,DRO_OUTLINE
1025 ,&vPoint[1]
1026 ,0L
1027 ,0L
1028 );
1029 vPoint[0].x = rRect.xLeft + 1;
1030 vPoint[0].y = rRect.yBottom + 1;
1031 ::GpiMove(hPS, &vPoint[0]);
1032 vPoint[1].x = rRect.xRight - 2;
1033 vPoint[1].y = rRect.yTop - 2;
1034 ::GpiBox( hPS
1035 ,DRO_OUTLINE
1036 ,&vPoint[1]
1037 ,0L
1038 ,0L
1039 );
1040
1041 vLineBundle.lColor = 0x00000000; // BLACK
1042 vLineBundle.usMixMode = FM_OVERPAINT;
1043 vLineBundle.fxWidth = 2;
1044 vLineBundle.lGeomWidth = 2;
1045 vLineBundle.usType = LINETYPE_SOLID;
1046 vLineBundle.usEnd = 0;
1047 vLineBundle.usJoin = 0;
1048 ::GpiSetAttrs( hPS
1049 ,PRIM_LINE
1050 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
1051 ,0L
1052 ,&vLineBundle
1053 );
1054 vPoint[0].x = rRect.xLeft + 2;
1055 vPoint[0].y = rRect.yBottom + 2;
1056 ::GpiMove(hPS, &vPoint[0]);
1057 vPoint[1].x = rRect.xLeft + 2;
1058 vPoint[1].y = rRect.yTop - 3;
1059 ::GpiLine(hPS, &vPoint[1]);
1060 vPoint[1].x = rRect.xRight - 3;
1061 vPoint[1].y = rRect.yTop - 3;
1062 ::GpiLine(hPS, &vPoint[1]);
1063
1064 vPoint[0].x = rRect.xLeft + 3;
1065 vPoint[0].y = rRect.yBottom + 3;
1066 ::GpiMove(hPS, &vPoint[0]);
1067 vPoint[1].x = rRect.xLeft + 3;
1068 vPoint[1].y = rRect.yTop - 4;
1069 ::GpiLine(hPS, &vPoint[1]);
1070 vPoint[1].x = rRect.xRight - 4;
1071 vPoint[1].y = rRect.yTop - 4;
1072 ::GpiLine(hPS, &vPoint[1]);
1073 }
1074 if (dwStyle & wxDOUBLE_BORDER)
1075 {
1076 LINEBUNDLE vLineBundle;
1077
1078 vLineBundle.lColor = 0x00FFFFFF; // WHITE
1079 vLineBundle.usMixMode = FM_OVERPAINT;
1080 vLineBundle.fxWidth = 2;
1081 vLineBundle.lGeomWidth = 2;
1082 vLineBundle.usType = LINETYPE_SOLID;
1083 vLineBundle.usEnd = 0;
1084 vLineBundle.usJoin = 0;
1085 ::GpiSetAttrs( hPS
1086 ,PRIM_LINE
1087 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
1088 ,0L
1089 ,&vLineBundle
1090 );
1091 vPoint[1].x = rRect.xRight - 1;
1092 vPoint[1].y = rRect.yTop - 1;
1093 ::GpiBox( hPS
1094 ,DRO_OUTLINE
1095 ,&vPoint[1]
1096 ,0L
1097 ,0L
1098 );
1099 vLineBundle.lColor = 0x00000000; // WHITE
1100 vLineBundle.usMixMode = FM_OVERPAINT;
1101 vLineBundle.fxWidth = 2;
1102 vLineBundle.lGeomWidth = 2;
1103 vLineBundle.usType = LINETYPE_SOLID;
1104 vLineBundle.usEnd = 0;
1105 vLineBundle.usJoin = 0;
1106 ::GpiSetAttrs( hPS
1107 ,PRIM_LINE
1108 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
1109 ,0L
1110 ,&vLineBundle
1111 );
1112 vPoint[0].x = rRect.xLeft + 2;
1113 vPoint[0].y = rRect.yBottom + 2;
1114 ::GpiMove(hPS, &vPoint[0]);
1115 vPoint[1].x = rRect.xRight - 2;
1116 vPoint[1].y = rRect.yTop - 2;
1117 ::GpiBox( hPS
1118 ,DRO_OUTLINE
1119 ,&vPoint[1]
1120 ,0L
1121 ,0L
1122 );
1123 vLineBundle.lColor = 0x00FFFFFF; // BLACK
1124 vLineBundle.usMixMode = FM_OVERPAINT;
1125 vLineBundle.fxWidth = 2;
1126 vLineBundle.lGeomWidth = 2;
1127 vLineBundle.usType = LINETYPE_SOLID;
1128 vLineBundle.usEnd = 0;
1129 vLineBundle.usJoin = 0;
1130 ::GpiSetAttrs( hPS
1131 ,PRIM_LINE
1132 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
1133 ,0L
1134 ,&vLineBundle
1135 );
1136 vPoint[0].x = rRect.xLeft + 3;
1137 vPoint[0].y = rRect.yBottom + 3;
1138 ::GpiMove(hPS, &vPoint[0]);
1139 vPoint[1].x = rRect.xRight - 3;
1140 vPoint[1].y = rRect.yTop - 3;
1141 ::GpiBox( hPS
1142 ,DRO_OUTLINE
1143 ,&vPoint[1]
1144 ,0L
1145 ,0L
1146 );
1147 }
1148 if (dwStyle & wxRAISED_BORDER)
1149 {
1150 LINEBUNDLE vLineBundle;
1151
1152 vLineBundle.lColor = 0x00000000; // BLACK
1153 vLineBundle.usMixMode = FM_OVERPAINT;
1154 vLineBundle.fxWidth = 2;
1155 vLineBundle.lGeomWidth = 2;
1156 vLineBundle.usType = LINETYPE_SOLID;
1157 vLineBundle.usEnd = 0;
1158 vLineBundle.usJoin = 0;
1159 ::GpiSetAttrs( hPS
1160 ,PRIM_LINE
1161 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
1162 ,0L
1163 ,&vLineBundle
1164 );
1165 vPoint[1].x = rRect.xRight - 1;
1166 vPoint[1].y = rRect.yTop - 1;
1167 ::GpiBox( hPS
1168 ,DRO_OUTLINE
1169 ,&vPoint[1]
1170 ,0L
1171 ,0L
1172 );
1173 vPoint[0].x = rRect.xLeft + 1;
1174 vPoint[0].y = rRect.yBottom + 1;
1175 ::GpiMove(hPS, &vPoint[0]);
1176 vPoint[1].x = rRect.xRight - 2;
1177 vPoint[1].y = rRect.yTop - 2;
1178 ::GpiBox( hPS
1179 ,DRO_OUTLINE
1180 ,&vPoint[1]
1181 ,0L
1182 ,0L
1183 );
1184
1185 vLineBundle.lColor = 0x00FFFFFF; // WHITE
1186 vLineBundle.usMixMode = FM_OVERPAINT;
1187 vLineBundle.fxWidth = 2;
1188 vLineBundle.lGeomWidth = 2;
1189 vLineBundle.usType = LINETYPE_SOLID;
1190 vLineBundle.usEnd = 0;
1191 vLineBundle.usJoin = 0;
1192 ::GpiSetAttrs( hPS
1193 ,PRIM_LINE
1194 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
1195 ,0L
1196 ,&vLineBundle
1197 );
1198 vPoint[0].x = rRect.xLeft + 2;
1199 vPoint[0].y = rRect.yBottom + 2;
1200 ::GpiMove(hPS, &vPoint[0]);
1201 vPoint[1].x = rRect.xLeft + 2;
1202 vPoint[1].y = rRect.yTop - 3;
1203 ::GpiLine(hPS, &vPoint[1]);
1204 vPoint[1].x = rRect.xRight - 3;
1205 vPoint[1].y = rRect.yTop - 3;
1206 ::GpiLine(hPS, &vPoint[1]);
1207
1208 vPoint[0].x = rRect.xLeft + 3;
1209 vPoint[0].y = rRect.yBottom + 3;
1210 ::GpiMove(hPS, &vPoint[0]);
1211 vPoint[1].x = rRect.xLeft + 3;
1212 vPoint[1].y = rRect.yTop - 4;
1213 ::GpiLine(hPS, &vPoint[1]);
1214 vPoint[1].x = rRect.xRight - 4;
1215 vPoint[1].y = rRect.yTop - 4;
1216 ::GpiLine(hPS, &vPoint[1]);
1217 }
1218 } // end of wxDrawBorder
1219
1220 void wxOS2SetFont(
1221 HWND hWnd
1222 , const wxFont& rFont
1223 )
1224 {
1225 char zFont[128];
1226 char zFacename[30];
1227 char zWeight[30];
1228 char zStyle[30];
1229
1230 if (hWnd == NULLHANDLE)
1231 return;
1232
1233 //
1234 // The fonts available for Presentation Params are just a few
1235 // outline fonts, the rest are available to the GPI, so we must
1236 // map the families to one of these three
1237 //
1238 switch(rFont.GetFamily())
1239 {
1240 case wxSCRIPT:
1241 strcpy(zFacename, "Script");
1242 break;
1243
1244 case wxDECORATIVE:
1245 strcpy(zFacename, "WarpSans");
1246 break;
1247
1248 case wxROMAN:
1249 strcpy(zFacename,"Times New Roman");
1250 break;
1251
1252 case wxTELETYPE:
1253 strcpy(zFacename, "Courier New");
1254 break;
1255
1256 case wxMODERN:
1257 strcpy(zFacename, "Courier New");
1258 break;
1259
1260 case wxDEFAULT:
1261 default:
1262 case wxSWISS:
1263 strcpy(zFacename, "Helvetica");
1264 break;
1265 }
1266
1267 switch(rFont.GetWeight())
1268 {
1269 default:
1270 case wxNORMAL:
1271 case wxLIGHT:
1272 zWeight[0] = '\0';
1273 break;
1274
1275 case wxBOLD:
1276 case wxFONTWEIGHT_MAX:
1277 strcpy(zWeight, "Bold");
1278 break;
1279 }
1280
1281 switch(rFont.GetStyle())
1282 {
1283 case wxITALIC:
1284 case wxSLANT:
1285 strcpy(zStyle, "Italic");
1286 break;
1287
1288 default:
1289 zStyle[0] = '\0';
1290 break;
1291 }
1292 sprintf(zFont, "%d.%s", rFont.GetPointSize(), zFacename);
1293 if (zWeight[0] != '\0')
1294 {
1295 strcat(zFont, " ");
1296 strcat(zFont, zWeight);
1297 }
1298 if (zStyle[0] != '\0')
1299 {
1300 strcat(zFont, " ");
1301 strcat(zFont, zStyle);
1302 }
1303 ::WinSetPresParam(hWnd, PP_FONTNAMESIZE, strlen(zFont) + 1, (PVOID)zFont);
1304 } // end of wxOS2SetFont
1305
1306 // ---------------------------------------------------------------------------
1307 // Helper for taking a regular bitmap and giving it a disabled look
1308 // ---------------------------------------------------------------------------
1309 wxBitmap wxDisableBitmap(
1310 const wxBitmap& rBmp
1311 , long lColor
1312 )
1313 {
1314 wxMask* pMask = rBmp.GetMask();
1315
1316 if (!pMask)
1317 return(wxNullBitmap);
1318
1319 DEVOPENSTRUC vDop = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
1320 SIZEL vSize = {0, 0};
1321 HDC hDC = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
1322 HPS hPS = ::GpiCreatePS(vHabmain, hDC, &vSize, PU_PELS | GPIA_ASSOC);
1323 BITMAPINFOHEADER2 vHeader;
1324 BITMAPINFO2 vInfo;
1325 ERRORID vError;
1326 wxString sError;
1327 HBITMAP hBitmap = (HBITMAP)rBmp.GetHBITMAP();
1328 HBITMAP hOldBitmap = NULLHANDLE;
1329 HBITMAP hOldMask = NULLHANDLE;
1330 HBITMAP hMask = (HBITMAP)rBmp.GetMask()->GetMaskBitmap();
1331 unsigned char* pucBits; // buffer that will contain the bitmap data
1332 unsigned char* pucData; // pointer to use to traverse bitmap data
1333 unsigned char* pucBitsMask; // buffer that will contain the mask data
1334 unsigned char* pucDataMask; // pointer to use to traverse mask data
1335 LONG lScans = 0L;
1336 LONG lScansSet = 0L;
1337 bool bpp16 = (wxDisplayDepth() == 16);
1338
1339 memset(&vHeader, '\0', 16);
1340 vHeader.cbFix = 16;
1341
1342 memset(&vInfo, '\0', 16);
1343 vInfo.cbFix = 16;
1344 vInfo.cx = (ULONG)rBmp.GetWidth();
1345 vInfo.cy = (ULONG)rBmp.GetHeight();
1346 vInfo.cPlanes = 1;
1347 vInfo.cBitCount = 24; // Set to desired count going in
1348
1349 //
1350 // Create the buffers for data....all wxBitmaps are 24 bit internally
1351 //
1352 int nBytesPerLine = rBmp.GetWidth() * 3;
1353 int nSizeDWORD = sizeof(DWORD);
1354 int nLineBoundary = nBytesPerLine % nSizeDWORD;
1355 int nPadding = 0;
1356 int i;
1357 int j;
1358
1359 //
1360 // Bitmap must be ina double-word alligned address so we may
1361 // have some padding to worry about
1362 //
1363 if (nLineBoundary > 0)
1364 {
1365 nPadding = nSizeDWORD - nLineBoundary;
1366 nBytesPerLine += nPadding;
1367 }
1368 pucBits = (unsigned char *)malloc(nBytesPerLine * rBmp.GetHeight());
1369 memset(pucBits, '\0', (nBytesPerLine * rBmp.GetHeight()));
1370 pucBitsMask = (unsigned char *)malloc(nBytesPerLine * rBmp.GetHeight());
1371 memset(pucBitsMask, '\0', (nBytesPerLine * rBmp.GetHeight()));
1372
1373 //
1374 // Extract the bitmap and mask data
1375 //
1376 if ((hOldBitmap = ::GpiSetBitmap(hPS, hBitmap)) == HBM_ERROR)
1377 {
1378 vError = ::WinGetLastError(vHabmain);
1379 sError = wxPMErrorToStr(vError);
1380 }
1381 ::GpiQueryBitmapInfoHeader(hBitmap, &vHeader);
1382 vInfo.cBitCount = 24;
1383 if ((lScans = ::GpiQueryBitmapBits( hPS
1384 ,0L
1385 ,(LONG)rBmp.GetHeight()
1386 ,(PBYTE)pucBits
1387 ,&vInfo
1388 )) == GPI_ALTERROR)
1389 {
1390 vError = ::WinGetLastError(vHabmain);
1391 sError = wxPMErrorToStr(vError);
1392 }
1393 if ((hOldMask = ::GpiSetBitmap(hPS, hMask)) == HBM_ERROR)
1394 {
1395 vError = ::WinGetLastError(vHabmain);
1396 sError = wxPMErrorToStr(vError);
1397 }
1398 ::GpiQueryBitmapInfoHeader(hMask, &vHeader);
1399 vInfo.cBitCount = 24;
1400 if ((lScans = ::GpiQueryBitmapBits( hPS
1401 ,0L
1402 ,(LONG)rBmp.GetHeight()
1403 ,(PBYTE)pucBitsMask
1404 ,&vInfo
1405 )) == GPI_ALTERROR)
1406 {
1407 vError = ::WinGetLastError(vHabmain);
1408 sError = wxPMErrorToStr(vError);
1409 }
1410 if (( hMask = ::GpiSetBitmap(hPS, hOldMask)) == HBM_ERROR)
1411 {
1412 vError = ::WinGetLastError(vHabmain);
1413 sError = wxPMErrorToStr(vError);
1414 }
1415 pucData = pucBits;
1416 pucDataMask = pucBitsMask;
1417
1418 //
1419 // Get the mask value
1420 //
1421 for (i = 0; i < rBmp.GetHeight(); i++)
1422 {
1423 for (j = 0; j < rBmp.GetWidth(); j++)
1424 {
1425 // Byte 1
1426 if (bpp16 && *pucDataMask == 0xF8) // 16 bit display gobblygook
1427 {
1428 *pucData = 0x7F;
1429 pucData++;
1430 }
1431 else if (*pucDataMask == 0xFF) // set to grey
1432 {
1433 *pucData = 0x7F;
1434 pucData++;
1435 }
1436 else
1437 {
1438 *pucData = ((unsigned char)(lColor >> 16));
1439 pucData++;
1440 }
1441
1442 // Byte 2
1443 if (bpp16 && *(pucDataMask + 1) == 0xFC) // 16 bit display gobblygook
1444 {
1445 *pucData = 0x7F;
1446 pucData++;
1447 }
1448 else if (*(pucDataMask + 1) == 0xFF) // set to grey
1449 {
1450 *pucData = 0x7F;
1451 pucData++;
1452 }
1453 else
1454 {
1455 *pucData = ((unsigned char)(lColor >> 8));
1456 pucData++;
1457 }
1458
1459 // Byte 3
1460 if (bpp16 && *(pucDataMask + 2) == 0xF8) // 16 bit display gobblygook
1461 {
1462 *pucData = 0x7F;
1463 pucData++;
1464 }
1465 else if (*(pucDataMask + 2) == 0xFF) // set to grey
1466 {
1467 *pucData = 0x7F;
1468 pucData++;
1469 }
1470 else
1471 {
1472 *pucData = ((unsigned char)lColor);
1473 pucData++;
1474 }
1475 pucDataMask += 3;
1476 }
1477 for (j = 0; j < nPadding; j++)
1478 {
1479 pucData++;
1480 pucDataMask++;
1481 }
1482 }
1483
1484 //
1485 // Create a new bitmap and set the modified bits
1486 //
1487 wxBitmap vNewBmp( rBmp.GetWidth()
1488 ,rBmp.GetHeight()
1489 ,24
1490 );
1491 HBITMAP hNewBmp = (HBITMAP)vNewBmp.GetHBITMAP();
1492
1493 if ((hOldBitmap = ::GpiSetBitmap(hPS, hNewBmp)) == HBM_ERROR)
1494 {
1495 vError = ::WinGetLastError(vHabmain);
1496 sError = wxPMErrorToStr(vError);
1497 }
1498 if ((lScansSet = ::GpiSetBitmapBits( hPS
1499 ,0L
1500 ,(LONG)rBmp.GetHeight()
1501 ,(PBYTE)pucBits
1502 ,&vInfo
1503 )) == GPI_ALTERROR)
1504
1505 {
1506 vError = ::WinGetLastError(vHabmain);
1507 sError = wxPMErrorToStr(vError);
1508 }
1509 wxMask* pNewMask;
1510
1511 pNewMask = new wxMask(pMask->GetMaskBitmap());
1512 vNewBmp.SetMask(pNewMask);
1513 free(pucBits);
1514 ::GpiSetBitmap(hPS, NULLHANDLE);
1515 ::GpiDestroyPS(hPS);
1516 ::DevCloseDC(hDC);
1517 if (vNewBmp.Ok())
1518 return(vNewBmp);
1519 return(wxNullBitmap);
1520 } // end of wxDisableBitmap
1521
1522 COLORREF wxColourToRGB(
1523 const wxColour& rColor
1524 )
1525 {
1526 return(OS2RGB(rColor.Red(), rColor.Green(), rColor.Blue()));
1527 } // end of wxColourToRGB