source: trunk/src/helpers/shapewin.c@ 9

Last change on this file since 9 was 8, checked in by umoeller, 25 years ago

Initial checkin of helpers code which used to be in WarpIN.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 53.8 KB
Line 
1
2/*
3 *@@sourcefile shapewin.c:
4 * contains helper functions for "shaped" PM windows which
5 * can be non-rectangular in shape and have transparency.
6 *
7 * This file is new with V0.85.
8 *
9 * Usage: All PM programs.
10 *
11 * Function prefixes:
12 * -- shp* shape window functions
13 *
14 * This file consists of two parts:
15 *
16 * *** Part 1 ***
17 *
18 * The code in Part 1 implements the "Shape" window. This is used
19 * to display a bitmap on the screen with transparency.
20 *
21 * Really, it is not the "Shape" window which displays the bitmap.
22 * Since PM can only handle rectangular windows, as many subwindows
23 * as required are created, which are only managed by the (invisible)
24 * "Shape" window.
25 *
26 * See shp_fnwpShapeMgr for a window hierarchy.
27 *
28 * If you are not using the frame window functions in Part 2, the
29 * shape window class must be registered like this (the declarations
30 * are in shapewin.h):
31 *
32 + WinRegisterClass(
33 + hab, // anchor block handle
34 + SHAPE_WINDOW_CLASS, // class name (shapewin.h)
35 + shp_fnwpShapeMgr, // window procedure (in this file)
36 + 0L, // default window style
37 + sizeof(PVOID)) ; // class data size
38 *
39 * You can then create shape windows using WinCreateWindow():
40 + hwndShape = WinCreateWindow(
41 + hwndParent, // see remark (2)
42 + SHAPE_WINDOW_CLASS, // class name (shapewin.h)
43 + pszName, // doesn't matter
44 + flStyle, // can be 0
45 + x, y, cx, cy, // can all be 0; shape window
46 + // size depends on bitmap
47 + hwndOwner, // see remark (2)
48 + hwndInsertBehind, // should be HWND_TOP
49 + id,
50 + pCtlData, // *SHPCTLDATA, see remark (1)
51 + pPresParams); // NULL
52 *
53 * Remarks:
54 *
55 * 1) Shape windows _require_ a SHPCTLDATA structure for input with
56 * the pCtlData parameter of WinCreateWindow. This structure
57 * must contain the following:
58 + SHORT cx, cy ; // bitmap size
59 + HPS hpsMask; // HPS with bitmap selected into
60 + HPS hpsDraw; // HPS used for drawing the bitmap
61 *
62 * Note that the bitmap in hpsMask determines the drawing mask
63 * of the bitmap, while the bitmap in hpsDraw determines the
64 * bitmap to be drawn. You can use the same HPS (and thus
65 * the same bitmap) for both, but you can also use different
66 * ones.
67 *
68 * You _must_ select the bitmap(s) to be displayed into the HPS's,
69 * using GpiSetBitmap, or nothing will work. shpLoadBitmap
70 * in Part 2 of this file offers you a one-shot function for
71 * loading a bitmap either from resources or a PM 1.3 *.BMP
72 * file.
73 *
74 * Transparency is determined according to the most lower-left
75 * pixel of the bitmap in hpsMask. That is, all hpsDraw bitmap
76 * pixels which have the same color as hpsMask pixel (0, 0)
77 * will be made transparent.
78 *
79 * During window creation, the shape window analyzes the bitmap
80 * which was selected into hpsMask and creates lots of rectangular
81 * PM windows as neccessary. This is dependent of the
82 * "transparency" pixels of the bitmap.
83 *
84 * There is no limit for the size of the bitmap (in the HPS's).
85 * But you should be very careful with large bitmaps, because
86 * this can block the system forever. Shape windows are real
87 * CPU hogs. The number of PM subwindows created depends on the
88 * size of the bitmap and on the transparency. The calculations
89 * are line-based:
90 * -- each line is examined, and a PM window is created for
91 * each line of the input bitmap;
92 * -- if this line contains "transparency" pixels, more PM
93 * windows are created accordingly for that line.
94 * -- However, if several vertically adjacent subwindows have
95 * the same left and right coordinates, they are combined
96 * into one window.
97 *
98 * As a result, the more single transparent pixels you have,
99 * the more windows need to be created. The more rectangular
100 * transparent areas you have, the less windows need to be
101 * created.
102 *
103 * 2) The "Shape" window requires both a parent and an owner window.
104 * As always, the parent window determines the visibility, while
105 * the owner window requires a more abstract relationship. With
106 * shape windows, the owner window is important because all the
107 * input messages (for mouse and keyboard input) are forwarded
108 * to the owner.
109 *
110 * So it's best to set the parent to HWND_DESKTOP and specify
111 * a frame window for the owner. If you don't already have a
112 * frame window in your application, you can create an invisible
113 * frame window just for message handling. That's what the shp*
114 * functions in Part 2 of this file do (Akira Hatakeyama calls
115 * this the "Voodoo" feature).
116 *
117 * Never use the shape window itself as a top-level window,
118 * but one of your own windows instead, which own the shape
119 * window.
120 *
121 * Note that the keyboard and mouse input messages which are
122 * forwarded to the owner contain mouse coordinates relative
123 * to the rectangular shape subwindow which actually received
124 * the message, not relative to the frame window. So you better
125 * determine the real mouse position using WinQueryPointerPos().
126 *
127 * Note that the size of the shape window is defined once upon
128 * creation and cannot be changed later because this would conflict
129 * with all the subwindows which were created. For the same reason,
130 * you cannot alter the bitmap of the shape window after creation.
131 * You must create a second shape bitmap for that.
132 * Thus all the size parameters in WinSetWindowPos are swallowed and
133 * ignored.
134 *
135 * *** Part 2 ***
136 *
137 * This implements a proper invisible frame window for displaying
138 * shaped bitmap windows directly on the desktop.
139 * See shpCreateWindows for a working example.
140 *
141 * Note: Version numbering in this file relates to XWorkplace version
142 * numbering.
143 *
144 *@@header "helpers\shapewin.h"
145 */
146
147/*
148 * Credits:
149 * 1) Functions for shaped windows.
150 * This is based on the ShapeWin library 1.01 (SHAPEWIN.ZIP at
151 * Hobbes), (C) 1998, 1999 Software Research Associates, Inc.
152 * This has been written by Akira Hatakeyama (akira@sra.co.jp).
153 * Updated by Takayuki Suwa (jjsuwa@ibm.net).
154 * The original was placed under the GPL.
155 *
156 * Changes made by Ulrich M”ller (February 1999):
157 * -- some speedup (marked with *UM)
158 * -- renamed and commented out almost all of the functions
159 * and structures to make their use more lucid.
160 *
161 * 2) Functions for easily creating shape frame windows from a
162 * given HBITMAP. This has been written by me, after getting
163 * some inspiration from the sample programs in SHAPEWIN.ZIP.
164 *
165 * Copyright (C) 1998-2000
166 * Ulrich M”ller,
167 * Akira Hatakeyama,
168 * Takayuki Suwa.
169 * This file is part of the XWorkplace source package.
170 * XWorkplace is free software; you can redistribute it and/or modify
171 * it under the terms of the GNU General Public License as published
172 * by the Free Software Foundation, in version 2 as it comes in the
173 * "COPYING" file of the XWorkplace main distribution.
174 * This program is distributed in the hope that it will be useful,
175 * but WITHOUT ANY WARRANTY; without even the implied warranty of
176 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
177 * GNU General Public License for more details.
178 *
179 */
180
181#define OS2EMX_PLAIN_CHAR
182 // this is needed for "os2emx.h"; if this is defined,
183 // emx will define PSZ as _signed_ char, otherwise
184 // as unsigned char
185
186#define INCL_DOS
187#define INCL_DOSERRORS
188#define INCL_WIN
189#define INCL_WINSYS
190#define INCL_GPILOGCOLORTABLE
191#define INCL_GPIPRIMITIVES
192#define INCL_GPIBITMAPS
193#include <os2.h>
194
195#include <stdlib.h>
196#include <stdio.h>
197#include <string.h>
198
199#include "setup.h" // code generation and debugging options
200
201#include "helpers\gpih.h"
202#include "helpers\shapewin.h"
203
204#pragma hdrstop
205
206/*
207 *@@category: Helpers\PM helpers\Window classes\Shaped windows (transparency)
208 */
209
210/* ******************************************************************
211 * *
212 * Global variables *
213 * *
214 ********************************************************************/
215
216BOOL G_ShapeRegisteredRegion = FALSE;
217
218/* ******************************************************************
219 * *
220 * Part 1: Shape window functions *
221 * *
222 ********************************************************************/
223
224// forward declarations for structures, because
225// the structures are referenced from each other
226typedef struct _SHPWINCTLDATA *PSHPWINCTLDATA;
227typedef struct _SHPREGION *PSHPREGION;
228
229/*
230 * SHPWINCTLDATA:
231 * internal shape window control data.
232 * This is the shape-window-internal structure
233 * to allow the shape window to manage itself.
234 * This is created in WM_CREATE with the data
235 * passed in the mp1 and mp2 parameters
236 * (CREATESTRUCT and SHPCTLDATA).
237 * This is stored in a shape window's window words.
238 */
239
240typedef struct _SHPWINCTLDATA
241{
242 // common window parameters
243 // (copied from CREATESTRUCT in WM_CREATE)
244 HWND hwndShape ; // main shape window handle
245 HWND hwndParent; // shape window's parent (should be HWND_DESKTOP)
246 HWND hwndOwner ; // shape window's owner, to whom we'll forward all
247 // all the input messages
248 USHORT id ; // window ID
249 SHORT x ; // x - horz. position
250 SHORT y ; // y - vert. position
251 SHORT cx ; // horz. size
252 SHORT cy ; // vert. size
253 PSZ pszText ; // window text
254
255 // additional window parameters
256 HPS hpsDraw; // the input HPS with the bitmap
257 ULONG nRegion; // number of "regions"
258 PSHPREGION aRegion; // array of "regions"
259
260} SHPWINCTLDATA;
261
262/*
263 * SHPREGION:
264 * this is the structure for shape window
265 * "regions". Note that has nothing to do
266 * with GPI regions, but is simply a structure
267 * for each rectangular area in the shape
268 * window's bitmap which can be displayed
269 * as a rectangular PM window.
270 */
271
272typedef struct _SHPREGION
273{
274 PSHPWINCTLDATA pCtrl; // link to parent
275 HWND hwnd ; // drawing window
276 RECTL rect ; // rectangle of sub-bitmap
277} SHPREGION;
278
279/*
280 * SHPSPAN:
281 * this is a temporary structure used during
282 * the creation of SHPREGION's from the
283 * input bitmap.
284 */
285
286typedef struct _SHPSPAN {
287 ULONG nSize ;
288 ULONG nUsed ;
289 RECTL aSpan[1];
290} SHPSPAN, *PSHPSPAN;
291
292// the following defines how many SHPSPAN structures
293// will be initially created and afterwards for span
294// expansions by spanExpand
295#define SPAN_ALLOC_STEP 1024
296
297/*
298 * spanFree:
299 *
300 */
301
302void spanFree(PSHPSPAN pSpan)
303{
304 if (pSpan != NULL)
305 free(pSpan);
306}
307
308/*
309 * spanCreate:
310 * this creates SPAN_ALLOC_STEP SHPSPAN structures.
311 */
312
313PSHPSPAN spanCreate(void)
314{
315 PSHPSPAN pSpan;
316 int len ;
317
318 len = sizeof(SHPSPAN) + sizeof(RECTL) * SPAN_ALLOC_STEP;
319
320 if ((pSpan = (PSHPSPAN)malloc(len)) == NULL)
321 return NULL;
322
323 memset(pSpan, 0, len);
324 pSpan->nSize = SPAN_ALLOC_STEP;
325 pSpan->nUsed = 0 ;
326 return pSpan;
327}
328
329/*
330 * spanExpand:
331 * this expands the memory used for the SHPSPAN
332 * structures if more spans need to be appended.
333 * Another SPAN_ALLOC_STEP SHPSPAN structures are created.
334 */
335
336PSHPSPAN spanExpand(PSHPSPAN pOld)
337{
338 PSHPSPAN pNew;
339 int len ;
340
341 // TRACE("spanExpand\n");
342
343 len = sizeof(SHPSPAN) + sizeof(RECTL) * (pOld->nSize + SPAN_ALLOC_STEP);
344
345 if ((pNew = (PSHPSPAN)malloc(len)) == NULL)
346 return NULL;
347
348 memset(pNew, 0, len);
349 pNew->nSize = pOld->nSize + SPAN_ALLOC_STEP;
350 pNew->nUsed = pOld->nUsed;
351 memcpy(pNew->aSpan, pOld->aSpan, sizeof(RECTL) * pOld->nUsed);
352 spanFree(pOld);
353
354 return pNew;
355}
356
357/*
358 * spanAppend:
359 * this adds a new SHPSPAN to the list of spans.
360 *
361 */
362
363PSHPSPAN spanAppend(PSHPSPAN pSpan,
364 int y, // bottom y; top y = y+1
365 int x1, // left x
366 int x2) // right x
367{
368 int i;
369 PRECTL p;
370 PSHPSPAN pNew;
371
372 // TRACE("spanAppend %d (%d %d)\n", y, x1, x2);
373
374 /*
375 * check if continuous one
376 */
377
378 for (i = 0; i < pSpan->nUsed; i++) {
379 p = &pSpan->aSpan[i];
380 if (p->yTop == y && p->xLeft == x1 && p->xRight == x2)
381 {
382 p->yTop += 1;
383 return pSpan; // merged
384 }
385 }
386
387 /*
388 * if not enough space, expand
389 */
390
391 if ((pSpan->nUsed + 1) >= pSpan->nSize)
392 {
393 if ((pNew = spanExpand(pSpan)) == NULL)
394 return NULL;
395
396 pSpan = pNew;
397 }
398
399 /*
400 * append a rectangle
401 */
402
403 pSpan->aSpan[pSpan->nUsed].yTop = y + 1;
404 pSpan->aSpan[pSpan->nUsed].yBottom = y ;
405 pSpan->aSpan[pSpan->nUsed].xLeft = x1;
406 pSpan->aSpan[pSpan->nUsed].xRight = x2;
407 pSpan->nUsed += 1;
408
409 return pSpan;
410}
411
412#ifdef SHPDEBUG
413
414 /*
415 * ptisin:
416 *
417 */
418
419 BOOL ptisin(PSHPSPAN pSpan, int x, int y)
420 {
421 int i;
422
423 for (i = 0; i < pSpan->nUsed; i++)
424 {
425 if (y >= pSpan->aSpan[i].yTop) {
426 continue;
427 }
428 if (y < pSpan->aSpan[i].yBottom) {
429 continue;
430 }
431 if (x < pSpan->aSpan[i].xLeft) {
432 continue;
433 }
434 if (x >= pSpan->aSpan[i].xRight) {
435 continue;
436 }
437 return TRUE;
438 }
439 return FALSE;
440 }
441
442 /*
443 * dumpSpan:
444 *
445 */
446
447 void dumpSpan(PSHPSPAN pSpan)
448 {
449 int i, maxx, maxy, x, y;
450
451 TRACE("dumpSpan %d\n", pSpan->nUsed);
452
453 maxx = maxy = 0;
454
455 for (i = 0; i < pSpan->nUsed; i++)
456 {
457 if (pSpan->aSpan[i].yTop > maxy)
458 {
459 maxy = pSpan->aSpan[i].yTop;
460 }
461 if (pSpan->aSpan[i].xRight > maxx)
462 {
463 maxx = pSpan->aSpan[i].xRight;
464 }
465 }
466
467 for (y = maxy - 1; y >= 0; y--)
468 {
469 printf("%03d : ", y);
470 for (x = 0; x < maxx; x++)
471 {
472 if (ptisin(pSpan, x, y))
473 printf("#");
474 else
475 printf("_");
476 }
477 printf("\n");
478 }
479 }
480
481#endif // SHPDEBUG
482
483/*
484 * shprgnDraw:
485 * this gets called upon receiving WM_PAINT in
486 * shp_fnwpShapeRegion. We simply draw the
487 * subrectangle from the shape window's bitmap
488 * which corresponds to our region rectangle.
489 */
490
491void shprgnDraw(HPS hps, PSHPREGION pRgn)
492{
493 POINTL apt[3];
494
495 apt[0].x = 0;
496 apt[0].y = 0;
497 apt[1].x = (pRgn->rect.xRight - pRgn->rect.xLeft);
498 apt[1].y = (pRgn->rect.yTop - pRgn->rect.yBottom);
499 apt[2].x = pRgn->rect.xLeft ;
500 apt[2].y = pRgn->rect.yBottom;
501 GpiBitBlt(hps, pRgn->pCtrl->hpsDraw, 3, apt, ROP_SRCCOPY, 0);
502}
503
504/*
505 *@@ shp_fnwpShapeRegion:
506 * this is the window procedure for each of the
507 * shape window's rectangular subwindows.
508 *
509 * See shp_fnwpShapeMgr for a window hierarchy.
510 */
511
512MRESULT EXPENTRY shp_fnwpShapeRegion(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
513{
514 PSHPREGION pRgn;
515 HPS hps ;
516
517 pRgn = (PSHPREGION) WinQueryWindowPtr(hwnd, 0);
518
519 switch (msg)
520 {
521 /*
522 * WM_CREATE:
523 * store the SHPREGION pointer in our
524 * window words.
525 */
526
527 case WM_CREATE:
528 // TRACE("WM_CREATE\n");
529 pRgn = (PSHPREGION)PVOIDFROMMP(mp1);
530 WinSetWindowPtr(hwnd, 0, (PVOID) pRgn);
531 return (MRESULT) FALSE;
532
533 /*
534 * WM_PAINT:
535 * draw our subrectangle of the main bitmap.
536 */
537
538 case WM_PAINT:
539 // TRACE("WM_PAINT (%d %d) (%d %d)\n", pRgn->rect.yBottom, pRgn->rect.xLeft, pRgn->rect.yTop, pRgn->rect.xRight);
540 hps = WinBeginPaint(hwnd, NULLHANDLE, NULL);
541 shprgnDraw(hps, pRgn);
542 WinEndPaint(hps) ;
543 return (MRESULT) 0;
544
545 case WM_MOUSEMOVE :
546 case WM_BUTTON1DOWN :
547 case WM_BUTTON1UP :
548 case WM_BUTTON1CLICK :
549 case WM_BUTTON1DBLCLK:
550 case WM_BUTTON2DOWN :
551 case WM_BUTTON2UP :
552 case WM_BUTTON2CLICK :
553 case WM_BUTTON2DBLCLK:
554 case WM_BUTTON3DOWN :
555 case WM_BUTTON3UP :
556 case WM_BUTTON3CLICK :
557 case WM_BUTTON3DBLCLK:
558 case WM_CHAR :
559 case WM_VIOCHAR :
560 case WM_BEGINDRAG :
561 case WM_ENDDRAG :
562 case WM_SINGLESELECT :
563 case WM_OPEN :
564 case WM_CONTEXTMENU :
565 case WM_CONTEXTHELP :
566 case WM_TEXTEDIT :
567 case WM_BEGINSELECT :
568 case WM_ENDSELECT :
569 // forward all these to the shape window
570 return WinSendMsg(pRgn->pCtrl->hwndShape, msg, mp1, mp2);
571 }
572 return WinDefWindowProc(hwnd, msg, mp1, mp2);
573}
574
575/*
576 * shpmgrWMAdjustWindowPos:
577 * adjust the region windows' positions, visibility etc.
578 * by going thru the whole region windows list and
579 * repositioning all the windows.
580 * This gets called upon receiving WM_ADJUSTWINDOWPOS
581 * in shp_fnwpShapeMgr.
582 */
583
584int shpmgrWMAdjustWindowPos(PSHPWINCTLDATA pCtrl, PSWP pSwp)
585{
586 int i ;
587 PSHPREGION pRgn;
588 ULONG fl ;
589 // HPS hps ;
590
591 PSWP pswpArray;
592
593 // TRACE("shpmgrWMAdjustWindowPos - %d, %08x\n", pCtrl->nRegion, pSwp->fl);
594
595 if (pCtrl->nRegion == 0 || pCtrl->aRegion == NULL)
596 {
597 // TRACE("ShpDrawRegion - no region to open\n");
598 return -1;
599 }
600
601 if ((fl = pSwp->fl) & SWP_MOVE)
602 {
603 pCtrl->x = pSwp->x;
604 pCtrl->y = pSwp->y;
605 }
606
607 pswpArray = (PSWP) malloc(sizeof(SWP) * pCtrl->nRegion);
608
609 // go thru all the "regions" and adjust their sizes
610 for (i = 0, pRgn = pCtrl->aRegion;
611 i < pCtrl->nRegion;
612 i++, pRgn++)
613 {
614 pswpArray[i].fl = fl;
615 pswpArray[i].cy = (pRgn->rect.yTop - pRgn->rect.yBottom);
616 pswpArray[i].cx = (pRgn->rect.xRight - pRgn->rect.xLeft);
617 pswpArray[i].y = (pCtrl->y + pRgn->rect.yBottom);
618 pswpArray[i].x = (pCtrl->x + pRgn->rect.xLeft);
619 pswpArray[i].hwndInsertBehind = pSwp->hwndInsertBehind;
620 pswpArray[i].hwnd = pRgn->hwnd;
621 }
622
623 // set all window positions at once
624 WinSetMultWindowPos(WinQueryAnchorBlock(pCtrl->hwndShape),
625 &pswpArray[0],
626 pCtrl->nRegion);
627 free((void*) pswpArray);
628
629 // calling WinInvalidateRect is not neccessary,
630 // because the windows' update regions are already
631 // properly set by WinSetMultWindowPos (*UM)
632
633 /* for (i = 0, pRgn = pCtrl->aRegion;
634 i < pCtrl->nRegion;
635 i++, pRgn++)
636 {
637 if (fl & (SWP_MOVE | SWP_ZORDER)) {
638 WinInvalidateRect(pRgn->hwnd, NULL, FALSE);
639 }
640 } */
641 return 0;
642}
643
644/*
645 * shpmgrUpdateRegions:
646 * this gets called by shp_fnwpShapeMgr upon receiving
647 * SHAPEWIN_MSG_UPDATE.
648 */
649
650int shpmgrUpdateRegions(PSHPWINCTLDATA pCtrl, PRECTL pRect)
651{
652 RECTL rect, intern;
653 int i ;
654 PSHPREGION pRgn;
655 HAB hab ;
656 // HPS hps ;
657
658 // TRACE("shpmgrUpdateRegions\n");
659
660 hab = WinQueryAnchorBlock(pCtrl->hwndShape);
661
662 if (pRect == NULL) {
663 rect.xLeft = 0 ;
664 rect.yBottom = 0 ;
665 rect.xRight = pCtrl->cx;
666 rect.yTop = pCtrl->cy;
667 pRect = &rect;
668 }
669 for (i = 0, pRgn = pCtrl->aRegion; i < pCtrl->nRegion; i++, pRgn++)
670 {
671 if (WinIntersectRect(hab, &intern, pRect, &pRgn->rect) == FALSE) {
672 continue;
673 } else {
674 WinInvalidateRect(pRgn->hwnd, NULL, FALSE);
675 }
676 }
677 return 0;
678}
679
680/*
681 * shpmgrParseBitmap:
682 * this gets called from shpmgrWMCreate_Bitmap2Regions when the
683 * shape region windows need to be created.
684 * This function does the actual bitmap analysis and
685 * creates a large number of SHPSPAN structures according
686 * to the bitmaps, which can later be turned into
687 * PM windows.
688 * This happens during the processing of WM_CREATE in
689 * shp_fnwpShapeMgr.
690 * CPU usage: relatively low. Maybe 5% of the whole creation
691 * procedure.
692 *
693 *@@changed V0.9.1 (99-12-03): fixed memory leak
694 */
695
696PSHPSPAN shpmgrParseBitmap(HPS hps, PBITMAPINFOHEADER2 bmih2)
697{
698 int blen, hlen;
699 PUCHAR buf;
700 PBITMAPINFO2 pbmi;
701 PSHPSPAN pSpan, pNew;
702 int x, y, k;
703 LONG first, color;
704 BOOL inspan;
705 int left;
706
707 // TRACE("shpmgrParseBitmap\n");
708
709 hlen = sizeof(BITMAPINFO2) + sizeof(RGB) * 256;
710 blen = ((bmih2->cBitCount * bmih2->cx + 31) / 32) * bmih2->cPlanes * 4;
711
712 pbmi = (PBITMAPINFO2)malloc(hlen);
713 buf = (PUCHAR)malloc(blen);
714
715 if (pbmi == NULL || buf == NULL)
716 {
717 // TRACE("shpmgrParseBitmap - failed to alloc %d %d\n", hlen, blen);
718 if (pbmi)
719 free(pbmi);
720 if (buf)
721 free(buf);
722 return NULL;
723 }
724 memcpy(pbmi, bmih2, sizeof(BITMAPINFOHEADER2));
725
726 if ((pSpan = spanCreate()) == NULL)
727 {
728 // TRACE("shpmgrParseBitmap - failed to make\n");
729 free(pbmi);
730 free(buf);
731 return NULL;
732 }
733
734 first = -1;
735
736 for (y = 0; y < bmih2->cy; y++)
737 {
738
739 // TRACE("shpmgrParseBitmap - scan line %d\n", y); fflush(stdout);
740
741 GpiQueryBitmapBits(hps, y, 1, (PBYTE)buf, pbmi);
742
743 for (x = 0, inspan = FALSE; x < bmih2->cx; x++)
744 {
745 k = x * 3;
746 color = ((buf[k] << 16) | (buf[k+1] << 8) | buf[k+2]);
747
748 if (first < 0)
749 {
750 // first iteration: get the very first color (that
751 // is the pixel at (0, 0)), with which we will
752 // compare the others to determine the mask
753 first = color;
754 }
755
756 if (inspan == FALSE && color != first)
757 {
758 inspan = TRUE;
759 left = x;
760 }
761 else if (inspan == TRUE && color == first)
762 {
763 // transparent color found:
764 // create new span
765 inspan = FALSE;
766 if ((pNew = spanAppend(pSpan, y, left, x)) != NULL)
767 {
768 pSpan = pNew;
769 }
770 else
771 {
772 // TRACE("shpmgrParseBitmap - failed to extend\n");
773 break;
774 }
775 }
776 }
777 if (inspan == TRUE)
778 {
779 if ((pNew = spanAppend(pSpan, y, left, x)) != NULL)
780 pSpan = pNew;
781 else
782 // TRACE("shpmgrParseBitmap - failed to extend\n");
783 break;
784 }
785 }
786
787#ifdef SHPDEBUG
788 dumpSpan(pSpan);
789#endif
790
791 // fixed these memory leaks V0.9.1 (99-12-03)
792 if (pbmi)
793 free(pbmi);
794 if (buf)
795 free(buf);
796
797 return pSpan;
798}
799
800/*
801 * shpmgrWMCreate_Bitmap2Regions:
802 * this gets called from shpmgrWMCreate (WM_CREATE) to have a
803 * drawing region created from the bitmap which has been
804 * selected into the given HPS.
805 *
806 * First step in WM_CREATE.
807 */
808
809int shpmgrWMCreate_Bitmap2Regions(PSHPWINCTLDATA pCtrl, // in: shape control data
810 HPS hpsMask) // in: HPS with selected bitmap
811{
812 HAB hab;
813 HDC hdc;
814 HPS hps;
815 SIZEL siz;
816 HBITMAP hbm,
817 hbmPrevious;
818 BITMAPINFOHEADER2 bmi;
819 POINTL apt[3];
820 PSHPSPAN pSpan;
821 PSHPREGION pRegn;
822 int i;
823
824 // TRACE("shpmgrWMCreate_Bitmap2Regions\n");
825
826 hab = WinQueryAnchorBlock(pCtrl->hwndShape);
827
828 /*
829 * Create Memory DC & HPS
830 */
831
832 hdc = DevOpenDC(hab, OD_MEMORY, "*", 0, NULL, NULLHANDLE);
833 siz.cx = siz.cy = 0;
834 hps = GpiCreatePS(hab, hdc, &siz,
835 PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC);
836
837 /*
838 * Create Bitmap and relate to memory PS
839 */
840
841 memset(&bmi, 0, sizeof(bmi));
842
843 bmi.cbFix = sizeof(BITMAPINFOHEADER2);
844 bmi.cx = pCtrl->cx;
845 bmi.cy = pCtrl->cy;
846 bmi.cPlanes = 1 ;
847 bmi.cBitCount = 24;
848 bmi.ulCompression = 0 ;
849 bmi.cclrUsed = 0 ;
850 bmi.cclrImportant = 0 ;
851
852 hbm = GpiCreateBitmap(hps, &bmi, 0, NULL, NULL);
853
854 hbmPrevious = GpiSetBitmap(hps, hbm);
855
856 /*
857 * Copy in Mask Pattern
858 */
859
860 // TRACE("shpmgrWMCreate_Bitmap2Regions - copyin %d x %d mask pattern\n", bmi.cx, bmi.cy);
861
862 apt[0].x = 0; // Target
863 apt[0].y = 0;
864 apt[1].x = bmi.cx;
865 apt[1].y = bmi.cy;
866 apt[2].x = 0; // Source
867 apt[2].y = 0;
868
869 if (GpiBitBlt(hps, pCtrl->hpsDraw, 3, apt, ROP_SRCCOPY, 0) == GPI_ERROR) {
870 // TRACE("MakeRect - BitBlt Failed %08x, hdc %08x, hps %08x, hbm %08x\n",
871 // WinGetLastError(hab), hdc, hps, hbm);
872 }
873
874 /*
875 * Parse Mask Pattern
876 */
877
878 // call shpmgrParseBitmap; this does the actual creation of the
879 // "spans" by comparing all bitmap pixels to the (0, 0)
880 // pixel
881 if ((pSpan = shpmgrParseBitmap(hps, &bmi)) != NULL)
882 {
883 if ((pRegn = (PSHPREGION) malloc(sizeof(SHPREGION) * pSpan->nUsed)) == NULL)
884 {
885 // TRACE("shpmgrWMCreate_Bitmap2Regions - failed to alloc\n");
886 }
887 else
888 {
889 // mask created successfully:
890 pCtrl->nRegion = pSpan->nUsed;
891 pCtrl->aRegion = pRegn;
892
893 for (i = 0; i < pSpan->nUsed; i++)
894 {
895 pRegn[i].pCtrl = pCtrl;
896 pRegn[i].hwnd = NULLHANDLE;
897 pRegn[i].rect.xLeft = pSpan->aSpan[i].xLeft ;
898 pRegn[i].rect.xRight = pSpan->aSpan[i].xRight ;
899 pRegn[i].rect.yTop = pSpan->aSpan[i].yTop ;
900 pRegn[i].rect.yBottom = pSpan->aSpan[i].yBottom;
901 }
902 }
903 spanFree(pSpan);
904 }
905
906 /*
907 * dispose local resources
908 */
909
910 GpiSetBitmap(hps, hbmPrevious); // (*UM)
911 GpiDeleteBitmap(hbm);
912 GpiDestroyPS(hps);
913 DevCloseDC(hdc);
914
915 return 0;
916}
917
918/*
919 * shpmgrWMCreate_Regions2Windows:
920 * this gets called from shpmgrWMCreate (WM_CREATE) to convert
921 * all the "regions" that have been created by shpmgrWMCreate_Bitmap2Regions
922 * in pCtrl to individual rectangular PM windows.
923 *
924 * CPU usage: extremely high, because all the dull PM functions
925 * take so damn long. Calculating the "regions" isn't really
926 * difficult, but it's the PM windows which cause the CPU hog.
927 *
928 * Second step in WM_CREATE.
929 */
930
931int shpmgrWMCreate_Regions2Windows(PSHPWINCTLDATA pCtrl)
932{
933 int i ;
934 PSHPREGION pRgn;
935 ULONG flStyle;
936
937 // TRACE("shpmgrWMCreate_Regions2Windows %d regions\n", pCtrl->nRegion);
938
939 // check if any "regions" exist at all
940 if (pCtrl->nRegion == 0 || pCtrl->aRegion == NULL)
941 {
942 // TRACE("shpmgrWMCreate_Regions2Windows - no region to open\n");
943 return -1;
944 }
945
946 if (G_ShapeRegisteredRegion == FALSE)
947 {
948 // first call: register "shape region" class
949 WinRegisterClass(WinQueryAnchorBlock(pCtrl->hwndShape),
950 WC_SHAPE_REGION,
951 shp_fnwpShapeRegion,
952 CS_PARENTCLIP
953 // use parent's clipping region instead
954 // of the one of the region window
955 | CS_CLIPSIBLINGS
956 // don't allow the subwindows to paint
957 // over siblings (ie. windows with the
958 // same parent); this is neccessary if
959 // HWND_DESKTOP is the parent
960 | CS_SYNCPAINT,
961 // paint immediately
962 sizeof(PVOID));
963 G_ShapeRegisteredRegion = TRUE;
964 }
965
966 flStyle = 0;
967
968 // now go thru the "regions" list
969 for (i = 0, pRgn = pCtrl->aRegion;
970 i < pCtrl->nRegion;
971 i++, pRgn++)
972 {
973 // and create a window for each "region"
974 pRgn->hwnd = WinCreateWindow(
975 pCtrl->hwndParent, // copy parent window from shape window
976 // changed (*UM)
977 // HWND_DESKTOP, // Parent Window
978 WC_SHAPE_REGION, // window class
979 NULL, // window text
980 flStyle, // window style
981 (pCtrl->x + pRgn->rect.xLeft), // x
982 (pCtrl->y + pRgn->rect.yBottom), // y
983 (pRgn->rect.xRight - pRgn->rect.xLeft), // cx
984 (pRgn->rect.yTop - pRgn->rect.yBottom), // cy
985 pCtrl->hwndOwner, // Owner Window
986 HWND_TOP, // Z-Order
987 i, // Window ID
988 pRgn, // Control Data
989 NULL); // Pres. Param.
990 }
991 return 0;
992}
993
994/*
995 * shpmgrFreeRegion:
996 * cleanup during WM_DESTROY.
997 */
998
999int shpmgrFreeRegion(PSHPWINCTLDATA pCtrl)
1000{
1001 int i ;
1002 PSHPREGION pRgn;
1003
1004 for (i = 0, pRgn = pCtrl->aRegion;
1005 i < pCtrl->nRegion;
1006 i++, pRgn++)
1007 WinDestroyWindow(pRgn->hwnd);
1008
1009 free(pCtrl->aRegion);
1010
1011 return 0;
1012}
1013
1014/*
1015 * shpmgrWMCreate:
1016 * this initializes the "shape window".
1017 * This gets called upon receiving WM_CREATE in shp_fnwpShapeMgr.
1018 * The procedure is as follows:
1019 * 1) the bitmap in pData->hpsDraw is analyzed pixel by
1020 * pixel to create a number of "regions" from it
1021 * (which are not GPI regions, but an array of SHPREGION
1022 * structures. At least one of these structures is
1023 * created for each line. This is done by calling
1024 * shpmgrWMCreate_Bitmap2Regions.
1025 * 2) We then call shpmgrWMCreate_Regions2Windows to actually create
1026 * PM windows from all these structures.
1027 */
1028
1029PSHPWINCTLDATA shpmgrWMCreate(HWND hwnd, // in: shape window
1030 PCREATESTRUCT pWin, // in: create struct of WM_CREATE
1031 PSHPCTLDATA pData) // in: SHPCTLDATA struct (WM_CREATE mp1)
1032{
1033 PSHPWINCTLDATA pCtrl;
1034
1035 if (pData->hpsDraw == NULLHANDLE || pData->hpsMask == NULLHANDLE) {
1036 return NULL;
1037 }
1038
1039 // create new PSHPWINCTLDATA structure
1040 if ((pCtrl = (PSHPWINCTLDATA) malloc(sizeof(SHPWINCTLDATA))) == NULL) {
1041 return NULL;
1042 }
1043
1044 /*
1045 * Setup Common Window Parameters
1046 */
1047
1048 pCtrl->hwndShape = hwnd;
1049 pCtrl->hwndParent = pWin->hwndParent;
1050 pCtrl->hwndOwner = pWin->hwndOwner ;
1051 pCtrl->id = pWin->id;
1052 pCtrl->x = pWin->x ;
1053 pCtrl->y = pWin->y ;
1054 pCtrl->cx = pWin->cx;
1055 pCtrl->cy = pWin->cy;
1056
1057 /*
1058 * Setup Image Window's Control Data
1059 */
1060
1061 pCtrl->cx = pData->cx;
1062 pCtrl->cy = pData->cy;
1063 pCtrl->hpsDraw = pData->hpsDraw;
1064
1065 // now create "regions" from bitmap;
1066 // this will store the "regions" in pCtrl
1067 shpmgrWMCreate_Bitmap2Regions(pCtrl, pData->hpsMask);
1068
1069 // now create as many rectangular PM
1070 // windows as we have "regions" in pCtrl
1071 shpmgrWMCreate_Regions2Windows(pCtrl);
1072
1073 return pCtrl;
1074}
1075
1076/*
1077 * shpmgrWMDestroy:
1078 * this cleans up the shape's resources.
1079 * Gets called upon receiving WM_DESTROY in
1080 * shp_fnwpShapeMgr.
1081 */
1082
1083void shpmgrWMDestroy(PSHPWINCTLDATA pCtrl)
1084{
1085 if (pCtrl == NULL)
1086 return;
1087
1088 shpmgrFreeRegion(pCtrl);
1089 free(pCtrl);
1090}
1091
1092/*
1093 *@@ shp_fnwpShapeMgr:
1094 * this is the window procedure for the "shape window manager".
1095 * Register this procedure with WinRegisterWindowClass.
1096 *
1097 * This does the transformation of the bitmap into many
1098 * rectangular subwindows upon WM_CREATE, each of which
1099 * will use shp_fnwpShapeRegion as its window proc.
1100 *
1101 * There should be the following window hierarchy (the
1102 * lines signify ownership):
1103 *
1104 + Your owner window
1105 + |
1106 + +-- owns "shape manager" window (this window proc)
1107 + |
1108 + +-- lots of "region" windows (shp_fnwpShapeRegion)
1109 + +-- ...
1110 *
1111 * The "region" windows are owned by the "shape manager" window,
1112 * but have the same parent as the "shape manager" window.
1113 * Normally, this should be set to HWND_DESKTOP when creating the
1114 * "shape" window.
1115 *
1116 * This window procedure forwards the following messages
1117 * to its owner:
1118 * -- WM_MOUSEMOVE
1119 * -- all WM_BUTTONxxx messages
1120 * -- WM_CHAR
1121 * -- WM_VIOCHAR
1122 * -- WM_BEGINDRAG
1123 * -- WM_ENDDRAG
1124 * -- WM_SINGLESELECT
1125 * -- WM_OPEN
1126 * -- WM_CONTEXTMENU
1127 * -- WM_CONTEXTHELP
1128 * -- WM_TEXTEDIT
1129 * -- WM_BEGINSELECT
1130 * -- WM_ENDSELECT
1131 */
1132
1133MRESULT EXPENTRY shp_fnwpShapeMgr(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
1134{
1135 PSHPWINCTLDATA pCtrl;
1136 PSWP pswp ;
1137 // SHORT sx; // , sy;
1138
1139 pCtrl = (PSHPWINCTLDATA) WinQueryWindowPtr(hwnd, 0);
1140
1141 switch (msg)
1142 {
1143
1144 /*
1145 * WM_CREATE:
1146 * shape window is being created.
1147 * Parameters:
1148 * PSHPCTLDATA mp1
1149 * PCREATESTRUCT mp2
1150 * Shaped windows must have a SHPCTLDATA
1151 * structure in mp1.
1152 */
1153
1154 case WM_CREATE:
1155 // TRACE("WM_CREATE\n");
1156 pCtrl = shpmgrWMCreate(hwnd,
1157 (PCREATESTRUCT)PVOIDFROMMP(mp2),
1158 (PSHPCTLDATA)PVOIDFROMMP(mp1));
1159
1160 if (pCtrl == NULL)
1161 return (MRESULT) TRUE;
1162
1163 // store control data in window words
1164 WinSetWindowPtr(hwnd, 0, (PVOID) pCtrl);
1165 return (MRESULT) FALSE;
1166
1167 /*
1168 * WM_DESTROY:
1169 * clean up.
1170 */
1171
1172 case WM_DESTROY:
1173 // TRACE("WM_DESTORY\n");
1174 shpmgrWMDestroy(pCtrl);
1175 return (MRESULT) 0;
1176
1177 /*
1178 * WM_ADJUSTWINDOWPOS:
1179 * this needs to be manipulated to
1180 * adjust the positions of all the
1181 * subwindows instead.
1182 */
1183
1184 case WM_ADJUSTWINDOWPOS:
1185 // TRACE("WM_ADJUSTWINDOWPOS\n");
1186 pswp = (PSWP) PVOIDFROMMP(mp1);
1187 // DUMPSWP(pswp);
1188
1189 // enforce the size which we were given
1190 // in the beginning, because we cannot
1191 // change the size later
1192 pswp->cx = pCtrl->cx;
1193 pswp->cy = pCtrl->cy;
1194
1195 // adjust the sub-windows
1196 shpmgrWMAdjustWindowPos(pCtrl, pswp);
1197
1198 // never show ourselves
1199 pswp->fl &= ~SWP_SHOW;
1200 return (MRESULT) 0;
1201
1202 /*
1203 * SHAPEWIN_MSG_UPDATE:
1204 *
1205 */
1206
1207 case SHAPEWIN_MSG_UPDATE:
1208 shpmgrUpdateRegions(pCtrl, (PRECTL) PVOIDFROMMP(mp1));
1209 return (MRESULT) 0;
1210
1211 /*
1212 * WM_QUERYDLGCODE:
1213 *
1214 */
1215
1216 case WM_QUERYDLGCODE:
1217 // TRACE("WM_QUERYDLGCODE\n");
1218 return (MRESULT) DLGC_STATIC;
1219
1220 /*
1221 * WM_PAINT:
1222 * we just swallow this message because
1223 * there's no "shape window" to be painted;
1224 * instead, all the region windows get
1225 * their own WM_PAINT message
1226 */
1227
1228 case WM_PAINT:
1229 {
1230 // TRACE("WM_PAINT\n");
1231 /* HPS hps = WinBeginPaint(hwnd, NULLHANDLE, NULL);
1232
1233 POINTL apt[3];
1234 RECTL rclWin;
1235 WinQueryWindowRect(hwnd, &rclWin);
1236
1237 // lower left of target
1238 apt[0].x = 0;
1239 apt[0].y = 0;
1240 // upper right of target
1241 apt[1].x = rclWin.xRight;
1242 apt[1].y = rclWin.yTop;
1243 // lower left of source
1244 apt[2].x = 0;
1245 apt[2].y = 0;
1246 GpiBitBlt(hps,
1247 pCtrl->hpsDraw,
1248 3,
1249 apt,
1250 ROP_SRCCOPY,
1251 0); */
1252
1253 // delete update region to stop further
1254 // WM_PAINTs for this window;
1255 // this is faster than WiNBeginPaint
1256 WinValidateRect(hwnd, NULL, FALSE);
1257 // WinEndPaint(hps);
1258 return (MRESULT) 0;
1259 }
1260
1261 /*
1262 * all input-related messages:
1263 * forward these to the owner
1264 */
1265
1266 case WM_MOUSEMOVE :
1267 case WM_BUTTON1DOWN :
1268 case WM_BUTTON1UP :
1269 case WM_BUTTON1CLICK :
1270 case WM_BUTTON1DBLCLK:
1271 case WM_BUTTON2DOWN :
1272 case WM_BUTTON2UP :
1273 case WM_BUTTON2CLICK :
1274 case WM_BUTTON2DBLCLK:
1275 case WM_BUTTON3DOWN :
1276 case WM_BUTTON3UP :
1277 case WM_BUTTON3CLICK :
1278 case WM_BUTTON3DBLCLK:
1279 case WM_CHAR :
1280 case WM_VIOCHAR :
1281 case WM_BEGINDRAG :
1282 case WM_ENDDRAG :
1283 case WM_SINGLESELECT :
1284 case WM_OPEN :
1285 case WM_CONTEXTMENU :
1286 case WM_CONTEXTHELP :
1287 case WM_TEXTEDIT :
1288 case WM_BEGINSELECT :
1289 case WM_ENDSELECT :
1290 return WinSendMsg(pCtrl->hwndOwner, msg, mp1, mp2);
1291
1292 } // end switch (msg)
1293 return WinDefWindowProc(hwnd, msg, mp1, mp2);
1294}
1295
1296/* ******************************************************************
1297 * *
1298 * Part 2: Shape frame functions *
1299 * *
1300 ********************************************************************/
1301
1302MRESULT EXPENTRY fnwpShapeFrame(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
1303
1304/*
1305 *@@ shpLoadBitmap:
1306 * this creates a memory device context/presentation space
1307 * and loads and selects a bitmap into it.
1308 *
1309 * If pszBitmap == NULL, the bitmap is loaded from the
1310 * specified resources, otherwise we attempt to load the
1311 * bitmap file specified in pszBitmap (using gpihLoadBitmapFile).
1312 *
1313 * Output in the given SHAPEFRAME structure:
1314 * -- hab: as passed to this func
1315 * -- hdc: device context handle
1316 * -- hps: presentation space handle
1317 * -- hbm: bitmap handle
1318 * -- bmi: BITMAPINFOHEADER of hbmp
1319 * -- ptlLowerLeft: lower left corner is set so that
1320 * bitmap is centered on screen
1321 *
1322 * All other fields are neither read nor written to.
1323 * Returns TRUE if everything went OK.
1324 *
1325 * You can call this function directly before calling
1326 * shpCreateWindows.
1327 *
1328 * Pass the SHAPEFRAME structure to shpFreeBitmap to clean up.
1329 *
1330 *@@changed V0.9.0 [umoeller]: added default window positioning
1331 *@@changed V0.9.0 [umoeller]: removed GpiSetBitmap here
1332 */
1333
1334BOOL shpLoadBitmap(HAB hab, // in: anchor block
1335 PSZ pszBitmapFile, // in: OS/2 1.3 bmp file or NULL
1336 HMODULE hmodResource, // in: module handle from where the
1337 // resources should be loaded if
1338 // pszBitmapFile == NULL. This can be 0 for
1339 // the current EXE
1340 ULONG idResource, // in: bitmap resource ID in that module
1341 PSHAPEFRAME psb) // out: bitmap info
1342{
1343 SIZEL siz;
1344 BOOL brc;
1345
1346 psb->hab = hab;
1347
1348 psb->hdc = DevOpenDC(hab, OD_MEMORY, "*", 0, NULL, NULLHANDLE);
1349 if (psb->hdc)
1350 {
1351 siz.cx = siz.cy = 0;
1352 psb->hps = GpiCreatePS(hab, psb->hdc, &siz,
1353 PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC);
1354
1355 if (psb->hps)
1356 {
1357 if (pszBitmapFile)
1358 {
1359 // load bitmap file
1360 ULONG ulError;
1361 psb->hbm = gpihLoadBitmapFile(psb->hps,
1362 pszBitmapFile,
1363 &ulError);
1364 } else
1365 // load resource bitmap
1366 psb->hbm = GpiLoadBitmap(psb->hps,
1367 hmodResource,
1368 idResource,
1369 0, 0);
1370 if (psb->hbm)
1371 {
1372 SWP swpScreen;
1373 // store bitmap info in structure
1374 psb->bmi.cbFix = sizeof(psb->bmi);
1375 GpiQueryBitmapInfoHeader(psb->hbm, &psb->bmi);
1376
1377 // set ptlLowerLeft so that the bitmap
1378 // is centered on the screen
1379 WinQueryWindowPos(HWND_DESKTOP, &swpScreen);
1380 psb->ptlLowerLeft.x = (swpScreen.cx - psb->bmi.cx) / 2;
1381 psb->ptlLowerLeft.y = (swpScreen.cy - psb->bmi.cy) / 2;
1382
1383 brc = TRUE;
1384 }
1385 }
1386 }
1387 return (brc);
1388}
1389
1390/*
1391 *@@ shpFreeBitmap:
1392 * this cleans up resources allocated by shpLoadBitmap:
1393 * delete the bitmap, destroy the HPS and HDC.
1394 *
1395 *@@changed V0.9.3 (2000-04-11) [umoeller]: fixed major resource leak; the bitmap was never freed
1396 */
1397
1398VOID shpFreeBitmap(PSHAPEFRAME psb)
1399{
1400 if (psb->hbm != NULLHANDLE)
1401 {
1402 // unset bitmap in HPS; it cannot be deleted otherwise...
1403 GpiSetBitmap(psb->hps, NULLHANDLE); // V0.9.3 (2000-04-11) [umoeller]
1404 GpiDeleteBitmap(psb->hbm);
1405 psb->hbm = NULLHANDLE;
1406 }
1407 if (psb->hps != NULLHANDLE)
1408 {
1409 GpiDestroyPS(psb->hps);
1410 psb->hps = NULLHANDLE;
1411 }
1412 if (psb->hdc != NULLHANDLE)
1413 {
1414 DevCloseDC(psb->hdc);
1415 psb->hdc = NULLHANDLE;
1416 }
1417}
1418
1419/*
1420 *@@ shpCreateWindows:
1421 * this is a one-shot function for creating a
1422 * shaped window from a bitmap.
1423 *
1424 * Required fields in SHAPEFRAME for input (those
1425 * are all properly set by shpLoadBitmap):
1426 * -- hab: anchor block
1427 * -- hps: presentation space handle
1428 * -- hbm: bitmap handle
1429 * -- bmi: BITMAPINFOHEADER of hbmp
1430 * -- ptlLowerLeft: lower left corner of where
1431 * to position the shape window (new with V0.9.0).
1432 *
1433 * All other fields are ignored for input and only
1434 * set for output (and for the shape window later).
1435 *
1436 * You can use shpLoadBitmap to have all the fields
1437 * initialized, which will also set ptlLowerLeft
1438 * so that the shape window gets centered on the
1439 * Desktop.
1440 *
1441 * Otherwise you must initialize the above fields for
1442 * yourself.
1443 *
1444 * Obviously, this function uses the same HPS (and
1445 * thus bitmap) for both transparency and drawing.
1446 * If you wish to use two different bitmaps (one for
1447 * transparency, one for drawing), you cannot use
1448 * this function.
1449 *
1450 * Note that the windows are now (V0.9.0) also positioned
1451 * on the screen.
1452 *
1453 * Output in that structure:
1454 * -- hwndShapeFrame: invisible rectangular frame
1455 * window for the shape window
1456 * (fnwpShapeFrame, created here)
1457 * -- hwndShape: "shape" window
1458 * (shp_fnwpShapeMgr, created here)
1459 * -- pfnFrame: original window procedure of
1460 * WC_FRAME (hwndShapeFrame),
1461 * which is subclassed here
1462 * using fnwpShapeFrame
1463 * -- shpctrl: control data for hwndShape
1464 *
1465 * Returns TRUE if everything went OK.
1466 *
1467 * <B>Example</B> for creating a shaped window and
1468 * centering it on the screen:
1469 + SHAPEFRAME sb;
1470 + if (shpLoadBitmap(hab...,
1471 + szBitmapFile...,
1472 + 0, 0,
1473 + &sb))
1474 + {
1475 + // create shape (transparent) windows
1476 + if (shpCreateWindows(habQuickThread, &sb))
1477 + {
1478 * ...
1479 + }
1480 + }
1481 + ...
1482 + // cleanup
1483 + shpFreeBitmap(&sb);
1484 + WinDestroyWindow(sb.hwndShapeFrame) ;
1485 + WinDestroyWindow(sb.hwndShape);
1486 *
1487 *@@changed V0.9.0 [umoeller]: removed hab from function prototype
1488 *@@changed V0.9.0 [umoeller]: added window positioning
1489 *@@changed V0.9.0 [umoeller]: added GpiSetBitmap here (always forget that)
1490 */
1491
1492BOOL shpCreateWindows(PSHAPEFRAME psb)
1493{
1494 BOOL brc = FALSE;
1495
1496 if (psb->hbm)
1497 {
1498 // bitmap seems to be valid:
1499 FRAMECDATA fcd;
1500
1501 GpiSetBitmap(psb->hps, psb->hbm);
1502
1503 memset(&fcd, 0, sizeof(fcd));
1504 fcd.cb = sizeof(fcd);
1505
1506 // create invisible frame
1507 psb->hwndShapeFrame = WinCreateWindow(
1508 HWND_DESKTOP, // Parent window handle
1509 WC_FRAME, // Frame Window Class
1510 "XWorkplaceLogoShape", // title
1511 0, // Window Style
1512 0, 0, 0, 0, // Position & size
1513 NULLHANDLE, // Owner Window
1514 HWND_TOP, // Z-Order
1515 0, // Window ID
1516 &fcd, // Control Data
1517 NULL); // Presentation Parameter
1518
1519 if (psb->hwndShapeFrame)
1520 {
1521 // store the SHAPEFRAME structure in the frame's window words
1522 // so that the subclassed frame can access the data
1523 WinSetWindowULong(psb->hwndShapeFrame, QWL_USER, (ULONG)psb);
1524
1525 // subclass the frame window; store the original wnd proc in
1526 // the SHAPEFRAME structure
1527 psb->pfnFrame = WinSubclassWindow(psb->hwndShapeFrame, fnwpShapeFrame);
1528
1529 if ((psb->hwndShapeFrame) && (psb->hps))
1530 {
1531 // OK, no errors so far
1532
1533 // register shape window class; if this is already
1534 // registered, this won't hurt
1535 WinRegisterClass(psb->hab,
1536 WC_SHAPE_WINDOW,
1537 shp_fnwpShapeMgr,
1538 0L, // class style flags
1539 sizeof(PVOID));
1540
1541 // create shape manager window
1542 psb->shpctrl.cx = psb->bmi.cx;
1543 psb->shpctrl.cy = psb->bmi.cy;
1544 psb->shpctrl.hpsDraw = psb->hps;
1545 psb->shpctrl.hpsMask = psb->hps;
1546
1547 // create the "shape" window
1548 psb->hwndShape = WinCreateWindow(
1549 HWND_DESKTOP, // Parent Window
1550 WC_SHAPE_WINDOW, // Window Class
1551 NULL, // Window Text
1552 0, // Window Style;
1553 // no clip siblings!
1554 0, 0, 0, 0, // Pos & Size
1555 psb->hwndShapeFrame, // Owner Window
1556 HWND_TOP, // Z-Order
1557 0, // Window ID
1558 &psb->shpctrl, // Control Data
1559 NULL); // Pres. Param.
1560
1561 if (psb->hwndShape)
1562 {
1563 // no error: only then return TRUE
1564 brc = TRUE;
1565
1566 // and position the windows
1567 WinSetWindowPos(psb->hwndShapeFrame, NULLHANDLE,
1568 psb->ptlLowerLeft.x, psb->ptlLowerLeft.y,
1569 psb->bmi.cx, psb->bmi.cy,
1570 (SWP_MOVE | SWP_SIZE | SWP_HIDE));
1571 WinSetWindowPos(psb->hwndShape, NULLHANDLE,
1572 psb->ptlLowerLeft.x, psb->ptlLowerLeft.y,
1573 psb->bmi.cx, psb->bmi.cy,
1574 (SWP_MOVE | SWP_SIZE | SWP_SHOW));
1575 }
1576 }
1577 }
1578 }
1579
1580 return (brc);
1581}
1582
1583/*
1584 *@@ fnwpShapeFrame:
1585 * this is the window proc for subclassing the shape frame window
1586 * (shpCreateWindows above).
1587 * The shaped window proc (shp_fnwpShapeMgr) keeps forwarding messages
1588 * to its owner (which is the frame here), so we better handle
1589 * those messages.
1590 */
1591
1592MRESULT EXPENTRY fnwpShapeFrame(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
1593{
1594 MRESULT mrc;
1595
1596 // get the SHAPEFRAME structure from the window words,
1597 // which has been stored there by shpCreateWindows
1598 PSHAPEFRAME psb = (PSHAPEFRAME)WinQueryWindowULong(hwnd, QWL_USER);
1599
1600 // _Pmpf(("frame %08x %08x %08x", msg, mp1, mp2));
1601
1602 switch (msg)
1603 {
1604
1605 /*
1606 * WM_ADJUSTWINDOWPOS:
1607 * forward the data we get here to the shape
1608 * window (which will in turn reposition all
1609 * the region windows);
1610 * afterwards, always delete SHOW and set HIDE
1611 * for ourselves
1612 */
1613
1614 case WM_ADJUSTWINDOWPOS: {
1615 PSWP pswp = (PSWP) PVOIDFROMMP(mp1);
1616 POINTL ptl;
1617 WinQueryPointerPos(HWND_DESKTOP, &ptl);
1618 WinSetWindowPos(psb->hwndShape,
1619 pswp->hwndInsertBehind,
1620 // use current mouse position instead
1621 // of the original ones
1622 ptl.x,
1623 ptl.y,
1624 // pswp->x,
1625 // pswp->y,
1626 pswp->cx,
1627 pswp->cy,
1628 pswp->fl);
1629 pswp->fl &= ~SWP_SHOW;
1630 pswp->fl |= SWP_HIDE;
1631 mrc = (*psb->pfnFrame)(hwnd, msg, mp1, mp2);
1632 break; }
1633
1634 /* the shape window forwards these messages to us:
1635 WM_MOUSEMOVE
1636 WM_BUTTON1DOWN
1637 WM_BUTTON1UP
1638 WM_BUTTON1CLICK
1639 WM_BUTTON1DBLCLK
1640 WM_BUTTON2DOWN
1641 WM_BUTTON2UP
1642 WM_BUTTON2CLICK
1643 WM_BUTTON2DBLCLK
1644 WM_BUTTON3DOWN
1645 WM_BUTTON3UP
1646 WM_BUTTON3CLICK
1647 WM_BUTTON3DBLCLK
1648 WM_CHAR
1649 WM_VIOCHAR
1650 WM_BEGINDRAG
1651 WM_ENDDRAG
1652 WM_SINGLESELECT
1653 WM_OPEN
1654 WM_CONTEXTMENU
1655 WM_CONTEXTHELP
1656 WM_TEXTEDIT
1657 WM_BEGINSELECT
1658 WM_ENDSELECT */
1659
1660 /*
1661 * WM_SINGLESELECT:
1662 * if we are being clicked upon, bring the
1663 * shape window to top instead
1664 */
1665
1666 case WM_SINGLESELECT:
1667 WinSetWindowPos(psb->hwndShape, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER);
1668 mrc = 0;
1669 break;
1670
1671 /*
1672 * WM_BEGINDRAG:
1673 * if we are being dragged with MB2, forward
1674 * this to the shape window
1675 */
1676
1677 case WM_BEGINDRAG:
1678 WinSendMsg(psb->hwndShapeFrame, WM_TRACKFRAME,
1679 MPFROMSHORT(TF_MOVE /* | TF_SETPOINTERPOS*/ ), NULL);
1680 mrc = 0;
1681 break;
1682
1683 default:
1684 mrc = (*psb->pfnFrame)(hwnd, msg, mp1, mp2);
1685 }
1686
1687 return (mrc);
1688}
1689
1690/*
1691 *@@ shp2RegisterClasses:
1692 *
1693 *@@added V0.9.3 (2000-05-03) [umoeller]
1694 */
1695
1696BOOL shp2RegisterClasses(HAB hab)
1697{
1698 // register shape window class; if this is already
1699 // registered, this won't hurt
1700 return(WinRegisterClass(hab,
1701 WC_SHAPE_WINDOW,
1702 shp_fnwpShapeMgr,
1703 0L, // class style flags
1704 sizeof(PVOID)));
1705}
1706
1707
Note: See TracBrowser for help on using the repository browser.