home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: WPS_PM
/
WPS_PM.zip
/
xfld085s.zip
/
helpers
/
winh.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-02-24
|
40KB
|
1,064 lines
/*
*@@sourcefile winh.c:
* contains Presentation Manager helper functions that are
* independent of a single application, i.e. these can be
* used w/out the rest of the XFolder source in any PM
* program.
*
* Function prefixes (new with V0.81):
* -- winh* Win (Presentation Manager) helper functions
*
*@@include #define INCL_WINWINDOWMGR
*@@include #define INCL_WINMESSAGEMGR
*@@include #define INCL_WINDIALOGS
*@@include #define INCL_WINSTDCNR
*@@include #define INCL_WININPUT
*@@include #define INCL_WINSYS
*@@include #define INCL_WINSHELLDATA
*@@include #include <os2.h>
*@@include #include "winh.h"
*/
/*
* Copyright (C) 1997-99 Ulrich Möller.
* This file is part of the XFolder source package.
* XFolder is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, in version 2 as it comes in the
* "COPYING" file of the XFolder main distribution.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define INCL_DOSDEVIOCTL
#define INCL_DOS
#define INCL_DOSERRORS
#define INCL_WIN
#define INCL_GPI
// spooler #include's
#define INCL_BASE
#define INCL_SPL
#define INCL_SPLDOSPRINT
#define INCL_SPLERRORS
#include <os2.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "dosh.h"
#include "winh.h"
#include "prfh.h"
#include "gpih.h"
#include "undoc.h"
// #define _PMPRINTF_
#include "pmprintf.h"
/*
*@@ winhInsertMenuItem:
* this inserts one one menu item into a given menu.
* Returns the return value of the MM_INSERTITEM msg:
* -- MIT_MEMERROR: space allocation for menu item failed
* -- MIT_ERROR: other error
* -- other: zero-based index of new item in menu.
*/
SHORT winhInsertMenuItem(HWND hwndMenu, // in: menu to insert item into
SHORT iPosition, // in: zero-based index of where to
// insert or MIT_END
SHORT sItemId, // in: ID of new menu item
PSZ pszItemTitle, // in: title of new menu item
SHORT afStyle, // in: MIS_* style flags
SHORT afAttr) // in: MIA_* attribute flags
{
MENUITEM mi;
SHORT src = MIT_ERROR;
mi.iPosition = iPosition;
mi.afStyle = afStyle;
mi.afAttribute = afAttr;
mi.id = sItemId;
mi.hwndSubMenu = 0;
mi.hItem = 0;
src = SHORT1FROMMR(WinSendMsg(hwndMenu, MM_INSERTITEM, (MPARAM)&mi, (MPARAM)pszItemTitle));
return (src);
}
/*
*@@ winhInsertSubmenu:
* this inserts a submenu into a given menu and, if
* sItemId != 0, inserts one item into this new submenu also.
* Returns the HWND of the new submenu.
*/
HWND winhInsertSubmenu(HWND hwndMenu, // in: menu to add submenu to
ULONG iPosition, // in: index where to add submenu or MIT_END
SHORT sMenuId, // in: menu ID of new submenu
PSZ pszSubmenuTitle, // in: title of new submenu
USHORT afMenuStyle, // in: MIS* style flags for submenu;
// MIS_SUBMENU will always be added
SHORT sItemId, // in: ID of first item to add to submenu;
// if 0, no first item is inserted
PSZ pszItemTitle, // in: title of this item
// (if sItemID != 0)
USHORT afItemStyle, // in: style flags for this item, e.g. MIS_TEXT
// (this is ignored if sItemID == 0)
USHORT afAttribute) // in: attributes for this item, e.g. MIA_DISABLED
// (this is ignored if sItemID == 0)
{
MENUITEM mi;
SHORT src = MIT_ERROR;
HWND hwndNewMenu;
// create new, empty menu
hwndNewMenu = WinCreateMenu(hwndMenu,
NULL); // no menu template
if (hwndNewMenu)
{
// add "submenu item" to this empty menu;
// for some reason, PM always needs submenus
// to be a menu item
mi.iPosition = iPosition;
mi.afStyle = afMenuStyle | MIS_SUBMENU;
mi.afAttribute = 0;
mi.id = sMenuId;
mi.hwndSubMenu = hwndNewMenu;
mi.hItem = 0;
src = SHORT1FROMMR(WinSendMsg(hwndMenu, MM_INSERTITEM, (MPARAM)&mi, (MPARAM)pszSubmenuTitle));
if ( (src != MIT_MEMERROR)
&& (src != MIT_ERROR)
)
{
// set the new menu's ID to the same as the
// submenu item
WinSetWindowUShort(hwndNewMenu, QWS_ID, sMenuId);
if (sItemId) {
// item id given: insert first menu item also
mi.iPosition = 0;
mi.afStyle = afItemStyle;
mi.afAttribute = afAttribute;
mi.id = sItemId;
mi.hwndSubMenu = 0;
mi.hItem = 0;
WinSendMsg(hwndNewMenu,
MM_INSERTITEM,
(MPARAM)&mi,
(MPARAM)pszItemTitle);
}
}
}
return (hwndNewMenu);
}
/*
*@@ winhInsertMenuSeparator:
* this inserts a separator into a given menu at
* the given position (which may be MIT_END);
* returns the position at which the item was
* inserted.
*/
SHORT winhInsertMenuSeparator(HWND hMenu, // in: menu to add separator to
SHORT iPosition, // in: index where to add separator or MIT_END
SHORT sId) // in: separator menu ID (doesn't really matter)
{
MENUITEM mi;
mi.iPosition = iPosition;
mi.afStyle = MIS_SEPARATOR; // append separator
mi.afAttribute = 0;
mi.id = sId;
mi.hwndSubMenu = 0;
mi.hItem = 0;
return (SHORT1FROMMR(WinSendMsg(hMenu,
MM_INSERTITEM,
(MPARAM)&mi,
(MPARAM)"")));
}
/*
*@@ winhMenuRemoveEllipse:
* removes a "..." substring from a menu item
* title, if found. This is useful if confirmations
* have been turned off for a certain menu item, which
* should be reflected in the menu.
*/
VOID winhMenuRemoveEllipse(HWND hwndMenu,
USHORT usItemId) // in: item to remove "..." from
{
CHAR szBuf[255];
CHAR *p;
WinSendMsg(hwndMenu, MM_QUERYITEMTEXT,
MPFROM2SHORT(usItemId, sizeof(szBuf)-1),
(MPARAM)&szBuf);
if (p = strstr(szBuf, "..."))
strcpy(p, p+3);
WinSendMsg(hwndMenu, MM_SETITEMTEXT,
MPFROMSHORT(usItemId),
(MPARAM)&szBuf);
}
/*
* winhSetDlgItemSpinData:
* sets a spin button's limits and data within a dialog window.
* This only works for decimal spin buttons.
*/
VOID winhSetDlgItemSpinData(HWND hwndDlg, // in: dlg window
ULONG idSpinButton, // in: item ID of spin button
ULONG min, // in: minimum allowed value
ULONG max, // in: maximum allowed value
ULONG current) // in: new current value
{
HWND hwndSpinButton = WinWindowFromID(hwndDlg, idSpinButton);
if (hwndSpinButton) {
WinSendMsg(hwndSpinButton,
SPBM_SETLIMITS, // Set limits message
(MPARAM)max, // Spin Button maximum setting
(MPARAM)min); // Spin Button minimum setting
WinSendMsg(hwndSpinButton,
SPBM_SETCURRENTVALUE, // Set current value message
(MPARAM)current,
(MPARAM)NULL);
}
}
/*
*@@ winhAdjustDlgItemSpinData:
* this can be called on a spin button control to
* have its current data snap to a grid. This only
* works for LONG integer values.
*
* For example, if you specify 100 for the grid and call
* this func after you have received SPBN_UP/DOWNARROW,
* the spin button's value will always in/decrease
* in steps of 100.
*
* This returns the "snapped" value to which the spin
* button was set.
*/
LONG winhAdjustDlgItemSpinData(HWND hwndDlg, // in: dlg window
USHORT usItemID, // in: item ID of spin button
LONG lGrid, // in: grid
USHORT usNotifyCode) // in: SPBN_UP* or *DOWNARROW of WM_CONTROL message
{
HWND hwndSpin = WinWindowFromID(hwndDlg, usItemID);
LONG lBottom, lTop, lValue;
// get value, which has already increased /
// decreased by 1
WinSendMsg(hwndSpin,
SPBM_QUERYVALUE,
(MPARAM)&lValue,
MPFROM2SHORT(0, SPBQ_ALWAYSUPDATE));
if ( (usNotifyCode == SPBN_UPARROW)
|| (usNotifyCode == SPBN_DOWNARROW)
)
{
// only if the up/down buttons were pressed,
// snap to the nearest grid; if the user
// manually enters something (SPBN_CHANGE),
// we'll accept that value
lValue = (lValue / lGrid) * lGrid;
// add /subtract grid
if (usNotifyCode == SPBN_UPARROW)
lValue += lGrid;
// else we'll have -= lGrid already
// balance with spin button limits
WinSendMsg(hwndSpin,
SPBM_QUERYLIMITS,
(MPARAM)&lTop,
(MPARAM)&lBottom);
if (lValue < lBottom)
lValue = lTop;
else if (lValue > lTop)
lValue = lBottom;
WinSendMsg(hwndSpin,
SPBM_SETCURRENTVALUE,
(MPARAM)(lValue),
MPNULL);
}
return (lValue);
}
/*
*@@ winhCnrScrollToRecord:
* scrolls a given container control to make a given
* record visible.
*
* Returns:
* -- 0: OK, scrolled
* -- 1: record rectangle query failed (error)
* -- 2: cnr viewport query failed (error)
* -- 3: record is already visible (scrolling not necessary)
* -- 4: cnrinfo query failed (error)
* -- 5: parent record rectangle query failed (error)
*
* Note: All messages are _sent_ to the container, not posted.
* Scrolling therefore occurs synchroneously before this
* function returns.
*
* This function an improved version of the one (W)(C) Dan Libby, found at
* http://zebra.asta.fh-weingarten.de/os2/Snippets/Howt6364.HTML
* Improvements (C) 1998 Ulrich Möller.
*/
ULONG winhCnrScrollToRecord(HWND hwndCnr, // in: container window
PRECORDCORE pRec, // in: record to scroll to
ULONG fsExtent,
// in: this determines what parts of pRec
// should be made visible. OR the following
// flags:
// -- CMA_ICON the icon rectangle
// -- CMA_TEXT the record text
// -- CMA_TREEICON the "+" sign in tree view
BOOL KeepParent)
// for tree views only: whether to keep
// the parent record of pRec visible when scrolling.
// If scrolling to pRec would make the parent
// record invisible, we instead scroll so that
// the parent record appears at the top of the
// container workspace (Win95 style).
{
QUERYRECORDRECT qRect, qRect2;
RECTL rclRecord, rclParentRecord, rclCnr, rclCnr2;
POINTL ptlRecord, ptlParentRecord;
CNRINFO CnrInfo;
HAB hab = WinQueryAnchorBlock(hwndCnr);
BOOL KeepParent2;
LONG lYOfs;
qRect.cb = sizeof(qRect);
qRect.pRecord = (PRECORDCORE)pRec;
qRect.fsExtent = fsExtent;
// query record location and size of container
if (!WinSendMsg(hwndCnr, CM_QUERYRECORDRECT, &rclRecord, &qRect))
return 1;
if (!WinSendMsg(hwndCnr, CM_QUERYVIEWPORTRECT, &rclCnr, MPFROM2SHORT(CMA_WINDOW, FALSE)) )
return 2;
// check if left bottom point of pRec is currently visible in container
ptlRecord.x = (rclRecord.xLeft);
ptlRecord.y = (rclRecord.yBottom);
// ptlRecord.x = (rclRecord.xLeft + rclRecord.xRight) / 2;
// ptlRecord.y = (rclRecord.yBottom + rclRecord.yTop) / 2;
if (WinPtInRect(hab, &rclCnr, &ptlRecord))
return 3;
if (KeepParent)
if (!WinSendMsg(hwndCnr, CM_QUERYCNRINFO, (MPARAM)&CnrInfo, (MPARAM)sizeof(CnrInfo)))
return 4;
else KeepParent2 = (CnrInfo.flWindowAttr & CV_TREE);
else KeepParent2 = FALSE;
// calculate offset to scroll to make pRec visible
lYOfs = (rclCnr.yBottom - rclRecord.yBottom) // this would suffice
+ (rclRecord.yTop - rclRecord.yBottom); // but we make the next rcl visible too
if (KeepParent2) {
qRect2.cb = sizeof(qRect2);
qRect2.pRecord = (PRECORDCORE)WinSendMsg(hwndCnr, CM_QUERYRECORD,
(MPARAM)pRec, MPFROM2SHORT(CMA_PARENT, CMA_ITEMORDER));
qRect2.fsExtent = fsExtent;
// now query PARENT record location and size of container
if (!WinSendMsg(hwndCnr, CM_QUERYRECORDRECT, &rclParentRecord, &qRect2))
return 5;
ptlParentRecord.x = (rclParentRecord.xLeft);
ptlParentRecord.y = (rclParentRecord.yTop);
// ptlParentRecord.x = (rclParentRecord.xLeft + rclParentRecord.xRight) / 2;
// ptlParentRecord.y = (rclParentRecord.yBottom + rclParentRecord.yTop) / 2;
rclCnr2 = rclCnr;
WinOffsetRect(hab, &rclCnr2, 0, -lYOfs);
// if ( (rclParentRecord.yBottom - rclRecord.yBottom) > (rclCnr.yTop - rclCnr.yBottom) )
if (!(WinPtInRect(hab, &rclCnr2, &ptlParentRecord)))
{
lYOfs = (rclCnr.yTop - rclParentRecord.yTop) // this would suffice
- (rclRecord.yTop - rclRecord.yBottom); // but we make the previous rcl visible too
}
}
if (!KeepParent2)
WinSendMsg(hwndCnr, CM_SCROLLWINDOW, (MPARAM)CMA_HORIZONTAL,
(MPARAM)(rclRecord.xLeft - rclCnr.xLeft));
WinSendMsg(hwndCnr, CM_SCROLLWINDOW,
(MPARAM)CMA_VERTICAL, (MPARAM)lYOfs);
return 0;
}
/*
*@@ winhCnrAllocRecord:
* this is a shortcut to allocating memory for
* a container record core. Returns the new recc.
*/
PRECORDCORE winhCnrAllocRecord(HWND hwndCnr, // in: cnr to allocate from
ULONG cbrecc)
// in: total size of your record core;
// if you're using the default recc's, this
// must be sizeof(RECORDCORE)
{
PRECORDCORE precc;
precc = (PRECORDCORE)WinSendMsg(hwndCnr, CM_ALLOCRECORD,
(MPARAM)(cbrecc-sizeof(RECORDCORE)),
(MPARAM)1);
precc->cb = cbrecc;
return (precc);
}
/*
*@@ winhCnrInsertRecord:
* shortcut to inserting a record core which has been
* allocated using winhCnrAllocRecord into a container.
* flRecordAttr should have the record attributes as
* specified in the RECORDCORE structure, which are:
* -- CRA_SELECTED record is selected
* -- CRA_CURSORED cursor (keyboard focus) is on the record
* -- CRA_SOURCE record has source emphasis (drag'n'drop)
* -- CRA_TARGET record has target emphasis (drag'n'drop)
* -- CRA_INUSE record has in-use emphasis
* -- CRA_FILTERED record has been filtered
* -- CRA_DROPONABLE record can be dropped something upon
* -- CRA_RECORDREADONLY record is read-only (no text edit)
* -- CRA_EXPANDED record is expanded (tree view)
* -- CRA_COLLAPSED record is collapsed (tree view)
* -- CRA_PICKED record picked (Lazy Drag)
*
* plus the following undocumented (haven't tested these):
* -- CRA_IGNORE
* -- CRA_DISABLED
* -- CRA_OWNERFREE
* -- CRA_OWNERDRAW
*
* This func returns precc.
*/
PRECORDCORE winhCnrInsertRecord(HWND hwndCnr, // in: container to insert into
PRECORDCORE preccParent,
// in: record core below which precc should
// be inserted (tree view only); if NULL, precc
// is inserted at "root" level
PRECORDCORE precc,
// in: record core to insert (allocated using
// winhCnrAllocRecord)
PSZ pszText,
// in: text for recc. in all views
ULONG flRecordAttr)
// in: CRA_* flags
{
RECORDINSERT ri;
if (precc) {
// RECORDCORE stuff
precc->flRecordAttr = flRecordAttr;
precc->preccNextRecord = NULL;
precc->pszIcon = pszText;
precc->pszText = pszText;
precc->pszName = pszText;
precc->pszTree = pszText;
// setup RECORDINSERT struct
ri.cb = sizeof(RECORDINSERT);
ri.pRecordOrder = (PRECORDCORE)CMA_END;
ri.pRecordParent = (PRECORDCORE)preccParent;
ri.zOrder = CMA_TOP;
ri.fInvalidateRecord = TRUE;
ri.cRecordsInsert = 1;
// printf(" Sending CM_INSERTRECORD\n");
WinSendMsg(hwndCnr, CM_INSERTRECORD, (MPARAM)precc, (MPARAM)&ri);
}
return (precc);
}
/*
*@@ winhSaveWindowPos:
* saves the position of a certain window. As opposed
* to the barely documented WinStoreWindowPos API, this
* one only saves one regular SWP structure for the given
* window. It does _not_ save minimized/maximized positions,
* presparams or anything about child windows.
* The window should still be visible on the screen
* when calling this function. Do not call it in WM_DESTROY,
* because then the SWP data is no longer valid.
* Returns TRUE if saving was successful.
*/
BOOL winhSaveWindowPos(HWND hwnd, // in: window to save
HINI hIni, // in: INI file (or HINI_USER/SYSTEM)
PSZ pszApp, // in: INI application name
PSZ pszKey) // in: INI key name
{
BOOL brc = FALSE;
SWP swp;
if (WinQueryWindowPos(hwnd, &swp))
{
brc = PrfWriteProfileData(hIni, pszApp, pszKey, &swp, sizeof(swp));
}
return (brc);
}
/*
*@@ winhRestoreWindowPos:
* this will retrieve a window position which was
* previously stored using winhSaveWindowPos.
* The window should not be visible to avoid flickering.
* "fl" must contain the SWP_flags as in WinSetWindowPos.
* Note that only the following may be used:
* -- SWP_MOVE reposition the window
* -- SWP_SIZE also resize the window to
* the stored position; this might
* lead to problems with different
* video resolutions, so be careful.
* -- SWP_SHOW make window visible too
* -- SWP_NOREDRAW changes are not redrawn
* -- SWP_NOADJUST do not send a WM_ADJUSTWINDOWPOS message
* before moving or sizing
* -- SWP_ACTIVATE activate window (make topmost)
* -- SWP_DEACTIVATE deactivate window (make bottommost)
*
* Do not specify any other SWP_* flags.
*
* If SWP_SIZE is not set, the window will be moved only
* (recommended).
*
* This function automatically checks for whether the
* window would be positioned outside the visible screen
* area and will adjust coordinates accordingly. This can
* happen when changing video resolutions.
*/
BOOL winhRestoreWindowPos(HWND hwnd, // in: window to save
HINI hIni, // in: INI file (or HINI_USER/SYSTEM)
PSZ pszApp, // in: INI application name
PSZ pszKey, // in: INI key name
ULONG fl) // in: "fl" parameter for WinSetWindowPos
{
BOOL brc = FALSE;
SWP swp, swpNow;
ULONG cbswp = sizeof(swp);
ULONG fl2 = fl;
if (PrfQueryProfileData(hIni, pszApp, pszKey, &swp, &cbswp))
{
ULONG ulScreenCX = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
ULONG ulScreenCY = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
brc = TRUE;
if ((fl & SWP_SIZE) == 0) {
// if no resize, we need to get the current position
brc = WinQueryWindowPos(hwnd, &swpNow);
swp.cx = swpNow.cx;
swp.cy = swpNow.cy;
}
if (brc) {
// check for full visibility
if ( (swp.x + swp.cx) > ulScreenCX)
swp.x = ulScreenCX - swp.cx;
if ( (swp.y + swp.cy) > ulScreenCY)
swp.y = ulScreenCY - swp.cy;
}
} else {
// window pos not found in INI: unset SWP_MOVE etc.
fl2 &= ~(SWP_MOVE | SWP_SIZE);
}
brc = WinSetWindowPos(hwnd,
NULLHANDLE, // insert-behind window
swp.x,
swp.y,
swp.cx,
swp.cy,
fl2); // SWP_* flags
return (brc);
}
/*
*@@ winhCenterWindow:
* centers a window within its parent window. If that's
* the PM desktop, it will be centered according to the
* whole screen.
* For dialog boxes, use WinCenteredDlgBox as a one-shot
* function.
*
* Note: When calling this function, the window should
* not be visible to avoid flickering.
* This func does not show the window either, so call
* WinShowWindow afterwards.
*/
void winhCenterWindow(HWND hwnd)
{
RECTL rclParent;
RECTL rclWindow;
WinQueryWindowRect(hwnd, &rclWindow);
WinQueryWindowRect(WinQueryWindow(hwnd, QW_PARENT), &rclParent);
rclWindow.xLeft = (rclParent.xRight - rclWindow.xRight) / 2;
rclWindow.yBottom = (rclParent.yTop - rclWindow.yTop ) / 2;
WinSetWindowPos(hwnd, NULLHANDLE, rclWindow.xLeft, rclWindow.yBottom,
0, 0, SWP_MOVE);
}
/*
*@@ winhCenteredDlgBox:
* just like WinDlgBox, but the dlg box is centered on the screen;
* you should mark the dlg template as not visible in the dlg
* editor, or display will flicker.
* As opposed to winhCenterWindow, this _does_ show the window.
*/
ULONG winhCenteredDlgBox(HWND hwndParent, HWND hwndOwner,
PFNWP pfnDlgProc, HMODULE hmod, ULONG idDlg, PVOID pCreateParams)
{
ULONG ulReply;
HWND hwndDlg = WinLoadDlg(hwndParent, hwndOwner, pfnDlgProc,
hmod, idDlg, pCreateParams);
winhCenterWindow(hwndDlg);
ulReply = WinProcessDlg(hwndDlg);
WinDestroyWindow(hwndDlg);
return (ulReply);
}
/*
*@@ winhQueryPresColor:
* returns the specified color. This is queried in the
* following order:
* 1) hwnd's pres params are searched for ulPP;
* 2) if this fails, PM_Colors in OS2.INI is searched
* for pszKeyName;
* 3) if this fails also, pszDefault is evaluated.
*
* The return value is always an RGB LONG.
* The following ulPP / pszKeyName pairs are useful:
* -- PP_FOREGROUNDCOLOR ("WindowText")
* Foreground color
* -- PP_BACKGROUNDCOLOR ("Window" or "DialogBackground")
* Background color
* -- PP_HILITEFOREGROUNDCOLOR ("HiliteForeground" or "MenuHiliteText")
* Highlighted foreground color, for example for selected menu
* -- PP_HILITEBACKGROUNDCOLOR ("HiliteBackground" or "MenuHilite")
* Highlighted background color
* -- PP_DISABLEDFOREGROUNDCOLOR
* Disabled foreground color
* -- PP_DISABLEDBACKGROUNDCOLOR
* Disabled background color
* -- PP_BORDERCOLOR ("WindowFrame")
* Border color
* -- PP_ACTIVECOLOR
* Active color
* -- PP_INACTIVECOLOR
* Inactive color
* -- PP_ACTIVETEXTFGNDCOLOR
* Active text foreground color
* -- PP_ACTIVETEXTBGNDCOLOR
* Active text background color
* -- PP_INACTIVETEXTFGNDCOLOR
* Inactive text foreground color
* -- PP_INACTIVETEXTBGNDCOLOR
* Inactive text background color
*/
LONG winhQueryPresColor(HWND hwnd, // in: window to query
ULONG ulPP, // in: PP_* index
PSZ pszKeyName, // in: INI key for PM_Colors
PSZ pszDefault) // in: e.g. "255 255 255"
{
ULONG ul, attrFound, abValue[32];
if (ulPP != (ULONG)-1)
if (ul = WinQueryPresParam(hwnd,
ulPP,
0,
&attrFound,
(ULONG)sizeof(abValue),
(PVOID)&abValue,
0))
return (abValue[0]);
return (prfhQueryColor(pszKeyName, pszDefault));
}
/*
*@@ winhCreateFakeDesktop:
* this routine creates and displays a frameless window over
* the whole screen to fool the user that all windows
* have been closed (which in fact might not be the
* case).
* This window's background color is set to the Desktop's
* (PM's one, not the WPS's one).
* Returns the hwnd of this window.
*/
HWND winhCreateFakeDesktop(HWND hwndSibling)
{
typedef struct _BACKGROUND {
ULONG cb; // Length of the aparam parameter, in bytes.
ULONG id; // Attribute type identity.
ULONG cb2; // Byte count of the ab parameter.
RGB rgb; // Attribute value.
} BACKGROUND;
RECTL R;
BACKGROUND background;
ULONG flStyle; // window style
LONG lDesktopColor;
/* create fake desktop window = empty window with
the size of full screen */
lDesktopColor = WinQuerySysColor(HWND_DESKTOP,
SYSCLR_BACKGROUND, 0);
flStyle = WS_VISIBLE;
R.xLeft = 0;
R.yBottom = 0;
R.xRight = WinQuerySysValue(HWND_DESKTOP,SV_CXSCREEN);
R.yTop = WinQuerySysValue(HWND_DESKTOP,SV_CYSCREEN);
background.cb = sizeof(background.id)
+ sizeof(background.cb)
+ sizeof(background.rgb);
background.id = PP_BACKGROUNDCOLOR;
background.cb2 = sizeof(RGB);
background.rgb.bBlue = (CHAR1FROMMP(lDesktopColor));
background.rgb.bGreen= (CHAR2FROMMP(lDesktopColor));
background.rgb.bRed = (CHAR3FROMMP(lDesktopColor));
return (WinCreateWindow(HWND_DESKTOP, // parent window
WC_FRAME, // class name
"", // window text
flStyle, // window style
0, 0, // position (x,y)
R.xRight,
R.yTop,
NULLHANDLE, // owner window
hwndSibling, // sibling window
1, // window id
NULL, // control data
&background)); // presentation parms
}
/*
*@@ winhQueryCnrFromFrame:
* find the handle of a frame window's container; we do this
* by enumerating all the frame's child windows and comparing
* their window classes to the WC_CONTAINER code.
* This is not terribly fast, so use this func economically.
* Returns NULLHANDLE if not found.
*/
HWND winhQueryCnrFromFrame(HWND hwndFrame)
{
HENUM henum;
CHAR szClassName[256];
HWND hwndCnr = NULLHANDLE,
hwndTemp = NULLHANDLE;
if (hwndFrame) {
henum = WinBeginEnumWindows(hwndFrame);
if (henum) {
do {
hwndTemp = WinGetNextWindow(henum);
if (hwndTemp) {
if (WinQueryClassName(hwndTemp, 250, szClassName))
if (strcmp(szClassName, "#37") == 0)
// unbelievable, this is PM's code for WC_CONTAINER...
hwndCnr = hwndTemp;
}
} while (hwndTemp);
}
WinEndEnumWindows(henum);
}
return hwndCnr;
}
/*
*@@ winhAssertWarp4Notebook:
* this takes hwndDlg as a notebook dialog page and
* goes thru all its controls. If a control with an
* ID <= udIdThreshold is found, this is assumed to
* be a button which is to be given the BS_NOTEBOOKBUTTON
* style. You should therefore give all your button
* controls which should be moved such an ID.
* You can also specify how many dialog units
* all the other controls will be moved downward in
* ulDownUnits; this is useful to fill up the space
* which was used by the buttons before moving them.
* Returns TRUE if anything was changed.
*
* This function is useful if you wish to create
* notebook pages using dlgedit.exe which are compatible
* with both Warp 3 and Warp 4. This should be executed
* in WM_INITDLG of the notebook dlg function if the app
* has determined that it is running on Warp 4.
*/
BOOL winhAssertWarp4Notebook(HWND hwndDlg,
USHORT usIdThreshold, // in: ID threshold
ULONG ulDownUnits) // in: dialog units or 0
{
BOOL brc = FALSE;
POINTL ptl;
HAB hab = WinQueryAnchorBlock(hwndDlg);
BOOL fIsVisible = WinIsWindowVisible(hwndDlg);
if (ulDownUnits) {
ptl.x = 0;
ptl.y = ulDownUnits;
WinMapDlgPoints(hwndDlg, &ptl, 1, TRUE);
}
WinEnableWindowUpdate(hwndDlg, FALSE);
if (doshIsWarp4()) {
HENUM henum = WinBeginEnumWindows(hwndDlg);
HWND hwndItem;
while (hwndItem = WinGetNextWindow(henum)) {
USHORT usId = WinQueryWindowUShort(hwndItem, QWS_ID);
_Pmpf(("hwndItem: 0x%lX, ID: 0x%lX", hwndItem, usId));
if (usId <= usIdThreshold) {
// pushbutton to change:
_Pmpf((" Setting bit"));
WinSetWindowBits(hwndItem, QWL_STYLE,
BS_NOTEBOOKBUTTON, BS_NOTEBOOKBUTTON);
brc = TRUE;
} else
// no pushbutton to change: move downwards
// if desired
if (ulDownUnits)
{
SWP swp;
_Pmpf(("Moving downwards %d pixels", ptl.y));
WinQueryWindowPos(hwndItem, &swp);
WinSetWindowPos(hwndItem, 0,
swp.x,
swp.y - ptl.y,
0, 0,
SWP_MOVE);
}
}
WinEndEnumWindows(henum);
}
if (fIsVisible)
WinShowWindow(hwndDlg, TRUE);
return (brc);
}
/*
*@@ winhQueryItemUnderMouse:
* this queries the menu item which corresponds
* to the given mouse coordinates.
* Returns the ID of the menu item and stores its
* rectangle in *prtlItem; returns (-1) upon errors.
*/
SHORT winhQueryItemUnderMouse(HWND hwndMenu, // in: menu handle
POINTL *pptlMouse, // in: mouse coordinates
RECTL *prtlItem) // out: rectangle of menu item
{
SHORT s, sItemId, sItemCount;
HAB habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);
sItemCount = SHORT1FROMMR(WinSendMsg(hwndMenu, MM_QUERYITEMCOUNT, MPNULL, MPNULL));
for (s = 0;
s <= sItemCount;
s++)
{
sItemId = SHORT1FROMMR(WinSendMsg(hwndMenu,
MM_ITEMIDFROMPOSITION,
(MPARAM)s, MPNULL));
WinSendMsg(hwndMenu, MM_QUERYITEMRECT,
MPFROM2SHORT(sItemId, FALSE),
(MPARAM)prtlItem);
if (WinPtInRect(habDesktop, prtlItem, pptlMouse))
return (sItemId);
}
/* sItemId = (SHORT)WinSendMsg(hwndMenu, MM_ITEMIDFROMPOSITION, (MPARAM)(sItemCount-1), MPNULL);
return (sItemId); */
return (-1); // error: no valid menu item
}
/*
*@@ winhDrawFormattedText:
* this func takes a rectangle and draws pszText into
* it, breaking the words as neccessary. The line spacing
* is determined from the font currently selected in hps.
* As opposed to WinDrawText, this can draw several lines
* at once.
* This returns the number of lines drawn.
*/
ULONG winhDrawFormattedText(HPS hps, // in: presentation space; its settings
// are used, but not altered
PRECTL prcl, // in/out: rectangle to use for drawing;
// both y coords are modified to return
// the space which was used for drawing
PSZ pszText, // in: text to draw
ULONG flCmd) // in: flags like in WinDrawText; I have
// only tested DT_TOP and DT_LEFT though.
// DT_WORDBREAK | DT_TEXTATTRS are always
// set.
// You can specify DT_QUERYEXTENT to only
// have prcl calculated without drawing.
{
PSZ p = pszText;
LONG lDrawn = 1,
lTotalDrawn = 0,
lLineCount = 0,
lOrigYTop = prcl->yTop;
ULONG ulTextLen = strlen(pszText),
ulCharHeight,
flCmd2;
// POINTL aptlText[TXTBOX_COUNT];
RECTL rcl2;
// printf("Entering winhDrawFormattedText\n");
flCmd2 = flCmd | DT_WORDBREAK | DT_TEXTATTRS;
ulCharHeight = gpihQueryLineSpacing(hps, pszText);
// _Pmpf((" ulCharHeight: %d\n", ulCharHeight));
while ( (lDrawn)
&& (lTotalDrawn < ulTextLen)
)
{
memcpy(&rcl2, prcl, sizeof(rcl2));
lDrawn = WinDrawText(hps,
ulTextLen-lTotalDrawn,
p,
&rcl2,
0, 0, // colors
flCmd2
);
p += lDrawn;
lTotalDrawn += lDrawn;
prcl->yTop -= ulCharHeight;
lLineCount++;
// printf(" lDrawn: %d, lTotalDrawn: %d\n", lDrawn, lTotalDrawn);
}
// printf(" LineCount: %d\n", lLineCount);
prcl->yBottom = prcl->yTop;
prcl->yTop = lOrigYTop;
return (lLineCount);
}
/*
*@@ winhKillTasklist:
* this will destroy the Tasklist (window list) window.
* Note: you will only be able to get it back after a
* reboot, not a WPS restart. Only for use at shutdown and such.
* This trick by Uri J. Stern at
* http://zebra.asta.fh-weingarten.de/os2/Snippets/Howt8881.HTML
*/
VOID winhKillTasklist(VOID)
{
SWBLOCK swblock;
HWND hwndTasklist;
// the tasklist has entry #0 in the SWBLOCK
WinQuerySwitchList(NULLHANDLE, &swblock, sizeof(SWBLOCK));
hwndTasklist = swblock.aswentry[0].swctl.hwnd;
WinPostMsg(hwndTasklist,
0x0454, // undocumented msg for killing tasklist
NULL, NULL);
}
/*
*@@ winhQueryPendingSpoolJobs:
* returns the number of pending print jobs in the spooler
* or 0 if none. Useful for testing before shutdown.
*/
ULONG winhQueryPendingSpoolJobs(VOID)
{
// BOOL rcPending = FALSE;
ULONG ulTotalJobCount = 0;
SPLERR splerr;
USHORT jobCount ;
ULONG cbBuf ;
ULONG cTotal;
ULONG cReturned ;
ULONG cbNeeded ;
ULONG ulLevel ;
ULONG i,j ;
PSZ pszComputerName ;
PBYTE pBuf = NULL;
PPRQINFO3 prq ;
PPRJINFO2 prj2 ;
ulLevel = 4L;
pszComputerName = (PSZ)NULL ;
splerr = SplEnumQueue(pszComputerName, ulLevel, pBuf, 0L, // cbBuf
&cReturned, &cTotal,
&cbNeeded, NULL);
if ( splerr == ERROR_MORE_DATA || splerr == NERR_BufTooSmall )
{
if (!DosAllocMem( (PPVOID)&pBuf, cbNeeded,
PAG_READ | PAG_WRITE | PAG_COMMIT) )
{
cbBuf = cbNeeded ;
splerr = SplEnumQueue(pszComputerName, ulLevel, pBuf, cbBuf,
&cReturned, &cTotal,
&cbNeeded, NULL);
if (splerr == NO_ERROR)
{
// set pointer to point to the beginning of the buffer
prq = (PPRQINFO3)pBuf ;
// cReturned has the count of the number of PRQINFO3 structures
for (i=0;i < cReturned ; i++)
{
// save the count of jobs; there are this many PRJINFO2
// structures following the PRQINFO3 structure
jobCount = prq->cJobs;
// _Pmpf(( "Job count in this queue is %d",jobCount ));
// increment the pointer past the PRQINFO3 structure
prq++;
// set a pointer to point to the first PRJINFO2 structure
prj2=(PPRJINFO2)prq;
for (j=0;j < jobCount ; j++)
{
// increment the pointer to point to the next structure
prj2++;
// increase the job count, which we'll return
ulTotalJobCount++;
} // endfor jobCount
// after doing all the job structures, prj2 points to the next
// queue structure; set the pointer for a PRQINFO3 structure
prq = (PPRQINFO3)prj2;
} //endfor cReturned
} // endif NO_ERROR
DosFreeMem(pBuf) ;
}
} // end if Q level given
return (ulTotalJobCount);
}