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