home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / usbd0906.zip / usb_20020906.zip / usbcalls / samples / fmradio / widget.cpp < prev    next >
C/C++ Source or Header  |  2001-11-13  |  62KB  |  1,840 lines

  1.  
  2. /*
  3.  *@@sourcefile ____sample.c:
  4.  *      code template for an XCenter widget.
  5.  *
  6.  *      This is an example of an XCenter widget plugin.
  7.  *      This code is compiled into a separate widget
  8.  *      plugin DLL, which  (as with all widget plugins)
  9.  *      must be put into the plugins/xcenter directory
  10.  *      of the XWorkplace installation directory.
  11.  *
  12.  *      This dummy widget only displays a small rectangle
  13.  *      with a 3D frame. This can be taken as a template
  14.  *      for implementing something more useful.
  15.  *
  16.  *      This code might look terribly complex even though
  17.  *      it does close to nothing. However, this gives you
  18.  *      a good impression about how to structure a widget
  19.  *      class in order to be able to extend it later.
  20.  *
  21.  *      In this template, we have basic support for
  22.  *      setup strings. The widget does save colors and
  23.  *      fonts dropped on it in its setup string.
  24.  *
  25.  *      This template does _not_ contain a settings dialog
  26.  *      though. If you want to implement such a thing,
  27.  *      take a look at the window list widget (w_winlist.c).
  28.  *
  29.  *      Of course, you are free not to use this code and
  30.  *      rewrite everything from scratch.
  31.  *
  32.  *      Any XCenter widget plugin DLL must export the
  33.  *      following procedures by ordinal:
  34.  *
  35.  *      -- Ordinal 1 (WgtInitModule): this must
  36.  *         return the widgets which this DLL provides.
  37.  *
  38.  *      -- Ordinal 2 (WgtUnInitModule): this must
  39.  *         clean up global DLL data.
  40.  *
  41.  *      Unless you start your own threads in your widget,
  42.  *      you can safely compile the widget with the VAC
  43.  *      subsystem libraries to reduce the DLL's size.
  44.  *      You can also import functions from XFLDR.DLL
  45.  *      to avoid code duplication.
  46.  *
  47.  *      This is all new with V0.9.7.
  48.  *
  49.  *@@added V0.9.7 (2000-12-31) [umoeller]
  50.  *@@header "shared\center.h"
  51.  */
  52.  
  53. /*
  54.  *      Copyright (C) 2000 Ulrich Möller.
  55.  *      This file is part of the XWorkplace source package.
  56.  *      XWorkplace is free software; you can redistribute it and/or modify
  57.  *      it under the terms of the GNU General Public License as published
  58.  *      by the Free Software Foundation, in version 2 as it comes in the
  59.  *      "COPYING" file of the XWorkplace main distribution.
  60.  *      This program is distributed in the hope that it will be useful,
  61.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  62.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  63.  *      GNU General Public License for more details.
  64.  */
  65.  
  66. #pragma strings(readonly)
  67.  
  68. /*
  69.  *  Suggested #include order:
  70.  *  1)  os2.h
  71.  *  2)  C library headers
  72.  *  3)  setup.h (code generation and debugging options)
  73. cd src\widgets *  4)  headers in helpers\
  74.  *  5)  at least one SOM implementation header (*.ih)
  75.  *  6)  dlgids.h, headers in shared\ (as needed)
  76.  *  7)  headers in implementation dirs (e.g. filesys\, as needed)
  77.  *  8)  #pragma hdrstop and then more SOM headers which crash with precompiled headers
  78.  */
  79.  
  80. #define INCL_DOSMODULEMGR
  81. #define INCL_DOSERRORS
  82. #define INCL_DOSSEMAPHORES
  83. #define INCL_DOSPROCESS
  84. #define INCL_WINWINDOWMGR
  85. #define INCL_WINFRAMEMGR
  86. #define INCL_WINDIALOGS
  87. #define INCL_WININPUT
  88. #define INCL_WINSWITCHLIST
  89. #define INCL_WINRECTANGLES
  90. #define INCL_WINPOINTERS
  91. #define INCL_WINSYS
  92. #define INCL_WINLISTBOXES
  93. #define INCL_WINENTRYFIELDS
  94.  
  95. #define INCL_GPIPRIMITIVES
  96. #define INCL_GPILOGCOLORTABLE
  97. #include <os2.h>
  98.  
  99. // C library headers
  100. #include <stdio.h>
  101. #include <stdlib.h>
  102. #include <string.h>
  103. #include <float.h>
  104. #include <setjmp.h>             // needed for except.h
  105. #include <assert.h>             // needed for except.h
  106.  
  107. // generic headers
  108. #define DONT_REPLACE_MALLOC         // in case mem debug is enabled
  109. #include "setup.h"                      // code generation and debugging options
  110.  
  111. // disable wrappers, because we're not linking statically
  112. #ifdef WINH_STANDARDWRAPPERS
  113.   #undef WINH_STANDARDWRAPPERS
  114. #endif
  115.  
  116. // headers in /helpers
  117. #include "helpers\dosh.h"               // Control Program helper routines
  118. #include "helpers\gpih.h"               // GPI helper routines
  119. #include "helpers\prfh.h"               // INI file helper routines;
  120. // this include is required for some
  121. // of the structures in shared\center.h
  122. #include "helpers\winh.h"               // PM helper routines
  123. #include "helpers\xstring.h"            // extended string helpers
  124. #include "helpers\comctl.h"             // For Tooltip
  125.  
  126. // XWorkplace implementation headers
  127. #include "shared\center.h"              // public XCenter interfaces
  128. #include "shared\common.h"              // the majestic XWorkplace include file
  129. #include "widget.h"
  130. #define USB_BIND_DYNAMIC 1
  131. #include "..\..\usbcalls.h"
  132. #pragma hdrstop                     // VAC++ keeps crashing otherwise
  133.  
  134. /* ******************************************************************
  135.  *
  136.  *   Private definitions
  137.  *
  138.  ********************************************************************/
  139.  
  140. /* ******************************************************************
  141.  *
  142.  *   XCenter widget class definition
  143.  *
  144.  ********************************************************************/
  145.  
  146. /*
  147.  *      This contains the name of the PM window class and
  148.  *      the XCENTERWIDGETCLASS definition(s) for the widget
  149.  *      class(es) in this DLL.
  150.  */
  151.  
  152. #define WNDCLASS_WIDGET_RADIO "XWPCenterRadioWidget"
  153.  
  154. static XCENTERWIDGETCLASS G_WidgetClasses[]
  155. = {
  156.   WNDCLASS_WIDGET_RADIO,     // PM window class name
  157.   0,                          // additional flag, not used here
  158.   "RadioControlWidget",       // internal widget class name
  159.   "USB-Radio",                // widget class name displayed to user
  160.   WGTF_UNIQUEPERXCENTER | WGTF_TRAYABLE | WGTF_TOOLTIP,      // widget class flags
  161.   NULL                        // no settings dialog
  162. };
  163.  
  164. /* ******************************************************************
  165.  *
  166.  *   Function imports from XFLDR.DLL
  167.  *
  168.  ********************************************************************/
  169.  
  170. /*
  171.  *      To reduce the size of the widget DLL, it can
  172.  *      be compiled with the VAC subsystem libraries.
  173.  *      In addition, instead of linking frequently
  174.  *      used helpers against the DLL again, you can
  175.  *      import them from XFLDR.DLL, whose module handle
  176.  *      is given to you in the INITMODULE export.
  177.  *
  178.  *      Note that importing functions from XFLDR.DLL
  179.  *      is _not_ a requirement. We only do this to
  180.  *      avoid duplicate code.
  181.  *
  182.  *      For each funtion that you need, add a global
  183.  *      function pointer variable and an entry to
  184.  *      the G_aImports array. These better match.
  185.  *
  186.  *      The actual imports are then made by WgtInitModule.
  187.  */
  188.  
  189. // resolved function pointers from XFLDR.DLL
  190. PCMNQUERYDEFAULTFONT pcmnQueryDefaultFont = NULL;
  191.  
  192. PCTRDISPLAYHELP pctrDisplayHelp = NULL;
  193. PCTRFREESETUPVALUE pctrFreeSetupValue = NULL;
  194. PCTRPARSECOLORSTRING pctrParseColorString = NULL;
  195. PCTRSCANSETUPSTRING pctrScanSetupString = NULL;
  196. PCTRSETSETUPSTRING pctrSetSetupString = NULL;
  197.  
  198. PGPIHDRAW3DFRAME pgpihDraw3DFrame = NULL;
  199. PGPIHSWITCHTORGB pgpihSwitchToRGB = NULL;
  200.  
  201. PWINHFREE pwinhFree = NULL;
  202. PWINHQUERYPRESCOLOR pwinhQueryPresColor = NULL;
  203. PWINHQUERYWINDOWFONT pwinhQueryWindowFont = NULL;
  204. PWINHSETWINDOWFONT pwinhSetWindowFont = NULL;
  205.  
  206. PXSTRCAT pxstrcat = NULL;
  207. PXSTRCLEAR pxstrClear = NULL;
  208. PXSTRINIT pxstrInit = NULL;
  209.  
  210. RESOLVEFUNCTION G_aImports[] =
  211. {
  212.   "cmnQueryDefaultFont", (PFN*)&pcmnQueryDefaultFont,
  213.  
  214.   "ctrDisplayHelp", (PFN*)&pctrDisplayHelp,
  215.   "ctrFreeSetupValue", (PFN*)&pctrFreeSetupValue,
  216.   "ctrParseColorString", (PFN*)&pctrParseColorString,
  217.   "ctrScanSetupString", (PFN*)&pctrScanSetupString,
  218.   "ctrSetSetupString", (PFN*)&pctrSetSetupString,
  219.  
  220.   "gpihDraw3DFrame", (PFN*)&pgpihDraw3DFrame,
  221.   "gpihSwitchToRGB", (PFN*)&pgpihSwitchToRGB,
  222.  
  223.   "winhFree", (PFN*)&pwinhFree,
  224.   "winhQueryPresColor", (PFN*)&pwinhQueryPresColor,
  225.   "winhQueryWindowFont", (PFN*)&pwinhQueryWindowFont,
  226.   "winhSetWindowFont", (PFN*)&pwinhSetWindowFont,
  227.  
  228.   "xstrcat", (PFN*)&pxstrcat,
  229.   "xstrClear", (PFN*)&pxstrClear,
  230.   "xstrInit", (PFN*)&pxstrInit
  231. };
  232.  
  233. /* ******************************************************************
  234.  *
  235.  *   Private widget instance data
  236.  *
  237.  ********************************************************************/
  238.  
  239. /*
  240.  *@@ RADIOSETUP:
  241.  *      instance data to which setup strings correspond.
  242.  *      This is also a member of SAMPLEPRIVATE.
  243.  *
  244.  *      Putting these settings into a separate structure
  245.  *      is no requirement, but comes in handy if you
  246.  *      want to use the same setup string routines on
  247.  *      both the open widget window and a settings dialog.
  248.  */
  249.  
  250. typedef struct _RADIOSETUP
  251. {
  252.   BOOL fTurnOn;           // Is the Radio switched On
  253.   BOOL fOnOnAttach;       // Turn on the Radio when pluged in
  254.   ULONG ulCurrentFreq;    // Current Freq the Radio is on or set to when pluged in/switched on
  255.   ULONG ulStoredFreq[4];  // Station storage
  256. } RADIOSETUP, *PRADIOSETUP;
  257.  
  258. #define  RADIO_STEREO   0x00000001
  259. #define  RADIO_SCANUP   0x00000010
  260. #define  RADIO_SCANDOWN 0x00000020
  261. #define  RADIO_SCAN     0x00000030
  262. #define  RADIO_TUNEUP   0x00000100
  263. #define  RADIO_TUNEDOWN 0x00000200
  264. #define  RADIO_TUNE     0x00000300
  265. #define  RADIO_USBCHECK 0x00001000
  266. typedef struct _DIGITSET
  267. {
  268.   HBITMAP hDigit[11];
  269.   ULONG ulHeight;
  270.   ULONG ulWidth;
  271. }DIGITSET, *PDIGITSET;
  272.  
  273. #define OFF 0
  274. #define ON  1
  275. #define MOUSE_OVER 2
  276. typedef struct _SKINITEM
  277. {
  278.   ULONG ulFlags;
  279.   HBITMAP hBmp[3];
  280.   SIZEL  Size;
  281.   POINTL ptlPos;
  282. }SKINITEM, *PSKINITEM;
  283.  
  284. enum ITEMNAMES
  285. {
  286.   Power    = 0,
  287.   Stereo   = 1,
  288.   UsbPres  = 2,
  289.   ScanUp   = 3,
  290.   ScanDown = 4,
  291.   TuneUp   = 5,
  292.   TuneDown = 6,
  293.   Station1 = 7,
  294.   Station2 = 8,
  295.   Station3 = 9,
  296.   Station4 = 10,
  297.   Station1Set = 11,
  298.   Station2Set = 12,
  299.   Station3Set = 13,
  300.   Station4Set = 14,
  301.   MHz         = 15
  302. };
  303.  
  304. typedef struct _RADIOSKIN
  305. {
  306.   ULONG ulType;
  307.   HBITMAP hBackground;
  308.   SKINITEM HundretDigit;
  309.   DIGITSET NormalDigits;
  310.   POINTL   ptlNormalDigitPos[2];
  311.   DIGITSET SmallDigits;
  312.   POINTL   ptlSmallDigitPos[2];
  313.   SKINITEM SItems[16];
  314. }RADIOSKIN, *PRADIOSKIN;
  315.  
  316. /*
  317.  *@@ RADIOPRIVATE:
  318.  *      more window data for the widget.
  319.  *
  320.  *      An instance of this is created on WM_CREATE in
  321.  *      fnwpSampleWidget and stored in XCENTERWIDGET.pUser.
  322.  */
  323.  
  324. typedef struct _RADIOPRIVATE
  325. {
  326.   // reverse ptr to general widget data ptr; we need
  327.   // that all the time and don't want to pass it on
  328.   // the stack with each function call
  329.   PXCENTERWIDGET pWidget;
  330.  
  331.  
  332.   RADIOSETUP Setup;   // widget settings that correspond to a setup string
  333.   HEV hRadioPluged;   // Event Set When an USB Radio Is pluged in;
  334.   HEV hRadioUnpluged; // Event Set When an USB Radio is Unpluged
  335.   HEV hEvtFreqChange; // Freq Changed Set Device and Display
  336.   HMUX hMuxWait;      // MuxWait used for the thread
  337.   TID  hMonThread;    // Thread ID of the notify handler
  338.   TID  hFreqThread;   // Thread ID of the Freq Thread
  339.   USBNOTIFY NotifyID; // Id Returned from UsbRegisterDeviceNotification
  340.   USBHANDLE hDevice;  // Handle of the USBDevice;
  341.   ULONG ulState;      // State of the Radio
  342.   ULONG ulScanStart;  // Memorises the start Freq when user presses one of the scan buttons
  343.   ULONG ulStation;    // Current Selected Station;
  344.   ULONG ulNumRadios;  // Number of Radios Attached to the PC
  345.   PRADIOSKIN pSkin;  // SkinInfo
  346.   BOOL fTooltipShowing; // Is there a Tooltip?
  347. } RADIOPRIVATE, *PRADIOPRIVATE;
  348.  
  349. typedef struct _USBCALLS
  350. {
  351.   HMODULE                        hDLL;
  352.   PUSBREGISTERDEVICENOTIFICATION pUsbRegisterDeviceNotification;
  353.   PUSBDEREGISTERNOTIFICATION     pUsbDeregisterNotification;
  354.   PUSBOPEN                       pUsbOpen;
  355.   PUSBCLOSE                      pUsbClose;
  356.   PUSBCTRLMESSAGE                pUsbCtrlMessage;
  357. }USBCALLS, *PUSBCALLS;
  358.  
  359. HMODULE g_hResDLL;
  360. USBCALLS g_USBFuncs;
  361.  
  362. void QueryBitmapDimension( HBITMAP hBmp, PSIZEL pSize)
  363. {
  364.   BITMAPINFOHEADER2 BmpInfo;
  365.   BOOL rc;
  366.  
  367.   BmpInfo.cbFix = sizeof(BITMAPINFOHEADER2);
  368.   rc = GpiQueryBitmapInfoHeader( hBmp, &BmpInfo);
  369.   if(!rc)
  370.   {
  371.     pSize->cx = 0;
  372.     pSize->cy = 0;
  373.   }
  374.   else
  375.   {
  376.     pSize->cx = BmpInfo.cx;
  377.     pSize->cy = BmpInfo.cy;
  378.   }
  379. }
  380.  
  381. void LoadSkin(HPS hps,PSZ *pszSkinname, PRADIOPRIVATE pRadio)
  382. {
  383.   ULONG i;
  384.   if (pRadio->pSkin)
  385.     free(pRadio->pSkin);
  386.  
  387.   pRadio->pSkin = (PRADIOSKIN) malloc(sizeof(RADIOSKIN));
  388.   // @@ToDo Use the spzSkinName to load a skin from a real resource file.
  389.   pRadio->pSkin->hBackground = GpiLoadBitmap(hps, g_hResDLL, ID_BmpBackground,0,0);
  390.   pRadio->pSkin->SItems[Power].ptlPos.x = 6;
  391.   pRadio->pSkin->SItems[Power].ptlPos.y = 17;
  392.   pRadio->pSkin->SItems[Power].hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpPowerOff ,0,0);
  393.   pRadio->pSkin->SItems[Power].hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpPowerOn ,0,0);
  394.   QueryBitmapDimension( pRadio->pSkin->SItems[Power].hBmp[0],
  395.                         &pRadio->pSkin->SItems[Power].Size );
  396.   pRadio->pSkin->SItems[Stereo].ptlPos.x = 13;
  397.   pRadio->pSkin->SItems[Stereo].ptlPos.y = 17;
  398.   pRadio->pSkin->SItems[Stereo].hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStereoOff ,0,0);
  399.   pRadio->pSkin->SItems[Stereo].hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStereoOn ,0,0);
  400.   QueryBitmapDimension( pRadio->pSkin->SItems[Stereo].hBmp[0],
  401.                         &pRadio->pSkin->SItems[Stereo].Size );
  402.   pRadio->pSkin->SItems[Station1].ptlPos.x = 38;
  403.   pRadio->pSkin->SItems[Station1].ptlPos.y = 17;
  404.   pRadio->pSkin->SItems[Station1].hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStation1Off ,0,0);
  405.   pRadio->pSkin->SItems[Station1].hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStation1On ,0,0);
  406.   QueryBitmapDimension( pRadio->pSkin->SItems[Station1].hBmp[0],
  407.                         &pRadio->pSkin->SItems[Station1].Size );
  408.   pRadio->pSkin->SItems[Station2].ptlPos.x = 47;
  409.   pRadio->pSkin->SItems[Station2].ptlPos.y = 17;
  410.   pRadio->pSkin->SItems[Station2].hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStation2Off ,0,0);
  411.   pRadio->pSkin->SItems[Station2].hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStation2On ,0,0);
  412.   QueryBitmapDimension( pRadio->pSkin->SItems[Station2].hBmp[0],
  413.                         &pRadio->pSkin->SItems[Station2].Size );
  414.   pRadio->pSkin->SItems[Station1Set].ptlPos.x = 38;
  415.   pRadio->pSkin->SItems[Station1Set].ptlPos.y = 14;
  416.   pRadio->pSkin->SItems[Station1Set].hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStoreEmtpy ,0,0);
  417.   pRadio->pSkin->SItems[Station1Set].hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStoreUsed ,0,0);
  418.   QueryBitmapDimension( pRadio->pSkin->SItems[Station1Set].hBmp[0],
  419.                         &pRadio->pSkin->SItems[Station1Set].Size );
  420.   pRadio->pSkin->SItems[Station2Set].ptlPos.x = 47;
  421.   pRadio->pSkin->SItems[Station2Set].ptlPos.y = 14;
  422.   pRadio->pSkin->SItems[Station2Set].hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStoreEmtpy ,0,0);
  423.   pRadio->pSkin->SItems[Station2Set].hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStoreUsed ,0,0);
  424.   QueryBitmapDimension( pRadio->pSkin->SItems[Station2Set].hBmp[0],
  425.                         &pRadio->pSkin->SItems[Station2Set].Size );
  426.  
  427.   pRadio->pSkin->SItems[ScanDown].ptlPos.x = 6;
  428.   pRadio->pSkin->SItems[ScanDown].ptlPos.y = 5;
  429.   pRadio->pSkin->SItems[ScanDown].hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpScanDownOff ,0,0);
  430.   pRadio->pSkin->SItems[ScanDown].hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpScanDownOn ,0,0);
  431.   QueryBitmapDimension( pRadio->pSkin->SItems[ScanDown].hBmp[0],
  432.                         &pRadio->pSkin->SItems[ScanDown].Size );
  433.   pRadio->pSkin->SItems[TuneDown].ptlPos.x = 16;
  434.   pRadio->pSkin->SItems[TuneDown].ptlPos.y = 5;
  435.   pRadio->pSkin->SItems[TuneDown].hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpTuneDownOff ,0,0);
  436.   pRadio->pSkin->SItems[TuneDown].hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpTuneDownOn ,0,0);
  437.   QueryBitmapDimension( pRadio->pSkin->SItems[TuneDown].hBmp[0],
  438.                         &pRadio->pSkin->SItems[TuneDown].Size );
  439.   pRadio->pSkin->SItems[TuneUp].ptlPos.x = 22;
  440.   pRadio->pSkin->SItems[TuneUp].ptlPos.y = 5;
  441.   pRadio->pSkin->SItems[TuneUp].hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpTuneUpOff ,0,0);
  442.   pRadio->pSkin->SItems[TuneUp].hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpTuneUpOn ,0,0);
  443.   QueryBitmapDimension( pRadio->pSkin->SItems[TuneUp].hBmp[0],
  444.                         &pRadio->pSkin->SItems[TuneUp].Size );
  445.   pRadio->pSkin->SItems[ScanUp].ptlPos.x = 28;
  446.   pRadio->pSkin->SItems[ScanUp].ptlPos.y = 5;
  447.   pRadio->pSkin->SItems[ScanUp].hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpScanUpOff ,0,0);
  448.   pRadio->pSkin->SItems[ScanUp].hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpScanUpOn ,0,0);
  449.   QueryBitmapDimension( pRadio->pSkin->SItems[ScanUp].hBmp[0],
  450.                         &pRadio->pSkin->SItems[ScanUp].Size );
  451.  
  452.   pRadio->pSkin->SItems[Station3].ptlPos.x = 38;
  453.   pRadio->pSkin->SItems[Station3].ptlPos.y = 8;
  454.   pRadio->pSkin->SItems[Station3].hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStation3Off ,0,0);
  455.   pRadio->pSkin->SItems[Station3].hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStation3On ,0,0);
  456.   QueryBitmapDimension( pRadio->pSkin->SItems[Station3].hBmp[0],
  457.                         &pRadio->pSkin->SItems[Station3].Size );
  458.   pRadio->pSkin->SItems[Station4].ptlPos.x = 47;
  459.   pRadio->pSkin->SItems[Station4].ptlPos.y = 8;
  460.   pRadio->pSkin->SItems[Station4].hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStation4Off ,0,0);
  461.   pRadio->pSkin->SItems[Station4].hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStation4On ,0,0);
  462.   QueryBitmapDimension( pRadio->pSkin->SItems[Station4].hBmp[0],
  463.                         &pRadio->pSkin->SItems[Station4].Size );
  464.   pRadio->pSkin->SItems[Station3Set].ptlPos.x = 38;
  465.   pRadio->pSkin->SItems[Station3Set].ptlPos.y = 5;
  466.   pRadio->pSkin->SItems[Station3Set].hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStoreEmtpy ,0,0);
  467.   pRadio->pSkin->SItems[Station3Set].hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStoreUsed ,0,0);
  468.   QueryBitmapDimension( pRadio->pSkin->SItems[Station3Set].hBmp[0],
  469.                         &pRadio->pSkin->SItems[Station3Set].Size );
  470.   pRadio->pSkin->SItems[Station4Set].ptlPos.x = 47;
  471.   pRadio->pSkin->SItems[Station4Set].ptlPos.y = 5;
  472.   pRadio->pSkin->SItems[Station4Set].hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStoreEmtpy ,0,0);
  473.   pRadio->pSkin->SItems[Station4Set].hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpStoreUsed ,0,0);
  474.   QueryBitmapDimension( pRadio->pSkin->SItems[Station4Set].hBmp[0],
  475.                         &pRadio->pSkin->SItems[Station4Set].Size );
  476.  
  477.   pRadio->pSkin->HundretDigit.ptlPos.x = 56;
  478.   pRadio->pSkin->HundretDigit.ptlPos.y = 7;
  479.   pRadio->pSkin->HundretDigit.hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpNDigit100Off ,0,0);
  480.   pRadio->pSkin->HundretDigit.hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpNDigit100 ,0,0);
  481.   pRadio->pSkin->ptlNormalDigitPos[0].x = 59;
  482.   pRadio->pSkin->ptlNormalDigitPos[0].y = 7;
  483.   pRadio->pSkin->ptlNormalDigitPos[1].x = 69;
  484.   pRadio->pSkin->ptlNormalDigitPos[1].y = 7;
  485.   for (i=0;i<11;i++)
  486.   {
  487.     pRadio->pSkin->NormalDigits.hDigit[i] = GpiLoadBitmap(hps, g_hResDLL, ID_BmpNDigit0 + i ,0,0);
  488.   }
  489.   pRadio->pSkin->ptlSmallDigitPos[0].x = 79;
  490.   pRadio->pSkin->ptlSmallDigitPos[0].y = 11;
  491.   pRadio->pSkin->ptlSmallDigitPos[1].x = 87;
  492.   pRadio->pSkin->ptlSmallDigitPos[1].y = 11;
  493.   for (i=0;i<11;i++)
  494.   {
  495.     pRadio->pSkin->SmallDigits.hDigit[i] = GpiLoadBitmap(hps, g_hResDLL, ID_BmpSDigit0 + i ,0,0);
  496.   }
  497.  
  498.   pRadio->pSkin->SItems[UsbPres].ptlPos.x = 95;
  499.   pRadio->pSkin->SItems[UsbPres].ptlPos.y = 5;
  500.   pRadio->pSkin->SItems[UsbPres].hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpUsbAbsent ,0,0);
  501.   pRadio->pSkin->SItems[UsbPres].hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpUsbPresent ,0,0);
  502.   QueryBitmapDimension( pRadio->pSkin->SItems[UsbPres].hBmp[0],
  503.                         &pRadio->pSkin->SItems[UsbPres].Size );
  504.  
  505.   pRadio->pSkin->SItems[MHz].ptlPos.x = 95;
  506.   pRadio->pSkin->SItems[MHz].ptlPos.y = 14;
  507.   pRadio->pSkin->SItems[MHz].hBmp[0]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpMhzOff ,0,0);
  508.   pRadio->pSkin->SItems[MHz].hBmp[1]  = GpiLoadBitmap(hps, g_hResDLL, ID_BmpMhzOn ,0,0);
  509.   QueryBitmapDimension( pRadio->pSkin->SItems[MHz].hBmp[0],
  510.                         &pRadio->pSkin->SItems[MHz].Size );
  511.  
  512. }
  513.  
  514. LONG GetSkinItemFromPos(PPOINTL pptlPos, PRADIOPRIVATE pRadio)
  515. {
  516.   LONG lItem;
  517.   for(lItem = Power; lItem <=MHz;lItem++)
  518.   {
  519.     if( (pptlPos->x >= pRadio->pSkin->SItems[lItem].ptlPos.x) &&
  520.         (pptlPos->x <= (pRadio->pSkin->SItems[lItem].ptlPos.x + 
  521.                         pRadio->pSkin->SItems[lItem].Size.cx)) &&
  522.         (pptlPos->y >= pRadio->pSkin->SItems[lItem].ptlPos.y) &&
  523.         (pptlPos->y <= (pRadio->pSkin->SItems[lItem].ptlPos.y + 
  524.                         pRadio->pSkin->SItems[lItem].Size.cy)) )
  525.       return lItem;
  526.   }
  527.   return -1; // No Item Found
  528. }
  529.  
  530. BOOL LoadUSBDLL()
  531. {
  532.   APIRET rc;
  533.   char szError[260];
  534.   if (!g_USBFuncs.hDLL)
  535.   {
  536.     rc = DosLoadModule(szError, sizeof(szError),"USBCALLS.DLL",&g_USBFuncs.hDLL);
  537.     if (!rc)
  538.     {
  539.       rc = DosQueryProcAddr( g_USBFuncs.hDLL,
  540.                              0, "UsbRegisterDeviceNotification",
  541.                              (PFN*)&g_USBFuncs.pUsbRegisterDeviceNotification);
  542.       if (!rc)
  543.         rc = DosQueryProcAddr( g_USBFuncs.hDLL,
  544.                                0, "UsbDeregisterNotification",
  545.                                (PFN*)&g_USBFuncs.pUsbDeregisterNotification);
  546.       if (!rc)
  547.         rc = DosQueryProcAddr( g_USBFuncs.hDLL,
  548.                                0, "UsbOpen",
  549.                                (PFN*)&g_USBFuncs.pUsbOpen);
  550.       if (!rc)
  551.         rc = DosQueryProcAddr( g_USBFuncs.hDLL,
  552.                                0, "UsbClose",
  553.                                (PFN*)&g_USBFuncs.pUsbClose);
  554.       if (!rc)
  555.         rc = DosQueryProcAddr( g_USBFuncs.hDLL,
  556.                                0, "UsbCtrlMessage",
  557.                                (PFN*)&g_USBFuncs.pUsbCtrlMessage);
  558.       if (rc)
  559.         DosFreeModule( g_USBFuncs.hDLL );
  560.     }
  561.   }
  562.   return(g_USBFuncs.hDLL!=NULL);
  563. }
  564.  
  565.  
  566. APIRET RadioSetFreq(ULONG ulNewFreq)
  567. {
  568.   double dFreq;
  569.   ULONG ulFreq;
  570.   dFreq = ulNewFreq / 100.0;
  571.   USBHANDLE Handle;
  572.   APIRET rc;
  573.   UCHAR ucData[8];
  574. /*
  575.   if(japan)
  576.   {
  577.     ulFreq = ((dFreq-10.7)*80);
  578.   }
  579.   else
  580. */
  581.   {
  582.     ulFreq = ((dFreq+10.7)*80);
  583.   }
  584.   rc = g_USBFuncs.pUsbOpen( &Handle,
  585.                             0x04b4,
  586.                             0x1002,
  587.                             USB_ANY_PRODUCTVERSION,
  588.                             USB_OPEN_FIRST_UNUSED);
  589.   if (!rc)
  590.   {
  591.     rc = g_USBFuncs.pUsbCtrlMessage( Handle,
  592.                                      0xC0, 0x01,
  593.                                      ulFreq>>8,ulFreq,
  594.                                      1,(UCHAR*)&ucData,
  595.                                      0);
  596.  
  597.     g_USBFuncs.pUsbClose(Handle);
  598.   }
  599.   return(rc);
  600. }
  601.  
  602. BOOL RadioGetStereo()
  603. {
  604.   USBHANDLE Handle;
  605.   APIRET rc;
  606.   UCHAR ucData[8];
  607.   BOOL fStereo = FALSE;
  608.   rc = g_USBFuncs.pUsbOpen( &Handle,
  609.                             0x04b4,
  610.                             0x1002,
  611.                             USB_ANY_PRODUCTVERSION,
  612.                             USB_OPEN_FIRST_UNUSED);
  613.   if (!rc)
  614.   {
  615.     rc = g_USBFuncs.pUsbCtrlMessage( Handle,
  616.                                      0xC0, 0x00,
  617.                                      0, 0x00,
  618.                                      1,(UCHAR*)&ucData,
  619.                                      0);
  620.     fStereo = (ucData[0]&0x01)==0x00;
  621.  
  622.     g_USBFuncs.pUsbClose(Handle);
  623.   }
  624.   return(fStereo);
  625. }
  626.  
  627. APIRET RadioPower(BOOL fTurnOn)
  628. {
  629.   USBHANDLE Handle;
  630.   APIRET rc;
  631.   UCHAR ucData[8];
  632.   BOOL fStereo = FALSE;
  633.   rc = g_USBFuncs.pUsbOpen( &Handle,
  634.                             0x04b4,
  635.                             0x1002,
  636.                             USB_ANY_PRODUCTVERSION,
  637.                             USB_OPEN_FIRST_UNUSED);
  638.   if (!rc)
  639.   {
  640.     rc = g_USBFuncs.pUsbCtrlMessage( Handle,
  641.                                      0xC0, 0x02,
  642.                                      fTurnOn?1:0, 0,
  643.                                      1,(UCHAR*)&ucData,
  644.                                      0);
  645.     g_USBFuncs.pUsbClose(Handle);
  646.   }
  647.   return(rc);
  648. }
  649.  
  650. /* ******************************************************************
  651.  *
  652.  *   Widget setup management
  653.  *
  654.  ********************************************************************/
  655.  
  656. /*
  657.  *      This section contains shared code to manage the
  658.  *      widget's settings. This can translate a widget
  659.  *      setup string into the fields of a binary setup
  660.  *      structure and vice versa. This code is used by
  661.  *      an open widget window, but could be shared with
  662.  *      a settings dialog, if you implement one.
  663.  */
  664.  
  665. /*
  666.  *@@ WgtClearSetup:
  667.  *      cleans up the data in the specified setup
  668.  *      structure, but does not free the structure
  669.  *      itself.
  670.  */
  671.  
  672. VOID WgtClearSetup(PRADIOSETUP pSetup)
  673. {
  674.   if (pSetup)
  675.   {
  676.     pSetup->fTurnOn        = FALSE;
  677.     pSetup->fOnOnAttach    = TRUE;
  678.     pSetup->ulCurrentFreq   = 88.0;
  679.     pSetup->ulStoredFreq[0] = 0;
  680.     pSetup->ulStoredFreq[1] = 0;
  681.     pSetup->ulStoredFreq[2] = 0;
  682.     pSetup->ulStoredFreq[3] = 0;
  683.   }
  684. }
  685.  
  686. /*
  687.  *@@ WgtScanSetup:
  688.  *      scans the given setup string and translates
  689.  *      its data into the specified binary setup
  690.  *      structure.
  691.  *
  692.  *      NOTE: It is assumed that pSetup is zeroed
  693.  *      out. We do not clean up previous data here.
  694.  */
  695.  
  696. VOID WgtScanSetup(const char *pcszSetupString,
  697.                   PRADIOSETUP pSetup)
  698. {
  699.   PSZ p;
  700.   char szStation[] = "STATION-0";
  701.   // On Off setting
  702.   p = pctrScanSetupString( pcszSetupString,
  703.                            "RADIO_POWER");
  704.   if (p!=NULL)
  705.   {
  706.     pSetup->fTurnOn = stricmp(p,"ON")==0;
  707.     pctrFreeSetupValue(p);
  708.   }
  709.   else
  710.     // default to Off
  711.     pSetup->fTurnOn = FALSE;
  712.  
  713.   // turn of if a USB radio is attached
  714.   p = pctrScanSetupString(pcszSetupString,
  715.                           "ONONATTACH");
  716.   if (p!=NULL)
  717.   {
  718.     pSetup->fOnOnAttach = stricmp(p,"YES")==0;
  719.     pctrFreeSetupValue(p);
  720.   }
  721.   else
  722.     pSetup->fOnOnAttach = FALSE;
  723.  
  724.   // font:
  725.   // we set the font presparam, which automatically
  726.   // affects the cached presentation spaces
  727.   p = pctrScanSetupString(pcszSetupString,
  728.                           "FREQENCY");
  729.   if (p!=NULL)
  730.   {
  731.     ULONG NewFreq = atol(p);
  732.     if ( NewFreq >=8800 && NewFreq<=10800)
  733.       pSetup->ulCurrentFreq = NewFreq;
  734.     pctrFreeSetupValue(p);
  735.   }
  736.   else
  737.     pSetup->ulCurrentFreq = 10760;
  738.  
  739.   for (char i=0;i<4;i++)
  740.   {
  741.     szStation[strlen(szStation)] = '0'+i;
  742.     p = pctrScanSetupString(pcszSetupString,
  743.                             szStation);
  744.     if (p!=NULL)
  745.     {
  746.       ULONG NewFreq = atol(p);
  747.       if ( NewFreq >=8800 && NewFreq<=10800)
  748.         pSetup->ulStoredFreq[i] = NewFreq;
  749.       else
  750.         pSetup->ulStoredFreq[i] = 0;
  751.       pctrFreeSetupValue(p);
  752.     }
  753.     else
  754.       pSetup->ulStoredFreq[i] = 0;
  755.  
  756.   }
  757.  
  758. }
  759.  
  760. /*
  761.  *@@ WgtSaveSetup:
  762.  *      composes a new setup string.
  763.  *      The caller must invoke xstrClear on the
  764.  *      string after use.
  765.  */
  766.  
  767. VOID WgtSaveSetup(PXSTRING pstrSetup,       // out: setup string (is cleared first)
  768.                   PRADIOSETUP pSetup)
  769. {
  770.   char szStation[] = "STATION-0";
  771.   CHAR    szTemp[100];
  772.  
  773.   pxstrInit(pstrSetup, 200);
  774.  
  775.   sprintf(szTemp, "RADIO_POWER=%s;",
  776.           pSetup->fTurnOn?"ON":"OFF");
  777.   pxstrcat(pstrSetup, szTemp, 0);
  778.  
  779.   sprintf(szTemp, "ONONATTACH=%s;",
  780.           pSetup->fOnOnAttach?"YES":"NO");
  781.   pxstrcat(pstrSetup, szTemp, 0);
  782.  
  783.   sprintf(szTemp, "FREQENCY=%d;",
  784.           pSetup->ulCurrentFreq);
  785.   pxstrcat(pstrSetup, szTemp, 0);
  786.  
  787.   for (char i=0;i<4;i++)
  788.   {
  789.     szStation[strlen(szStation)] = '0'+i;
  790.     if ( pSetup->ulStoredFreq[i] >=8800 &&
  791.          pSetup->ulStoredFreq[i] <=10800)
  792.     {
  793.       sprintf(szTemp, "%s=%d;",
  794.               szStation,
  795.               pSetup->ulStoredFreq[i]);
  796.       pxstrcat(pstrSetup, szTemp, 0);
  797.     }
  798.   }
  799. }
  800.  
  801. void ProcessRadioUnpluged(PRADIOPRIVATE pRadio)
  802. {
  803.   pRadio->ulNumRadios--;
  804.   if (!pRadio->ulNumRadios)
  805.   {
  806.     DosBeep(440,50);
  807.     DosBeep(220,50);
  808.     pRadio->ulState = RADIO_USBCHECK;
  809.     pRadio->Setup.fTurnOn = FALSE;
  810.   }
  811.   WinInvalidateRegion(pRadio->pWidget->hwndWidget, NULL, TRUE);
  812. }
  813.  
  814. void ProcessRadioPluged(PRADIOPRIVATE pRadio)
  815. {
  816.   APIRET rc;
  817.   if (!pRadio->ulNumRadios)
  818.   {
  819.     if (pRadio->Setup.fOnOnAttach)
  820.     {
  821.       DosBeep(220,50);
  822.       DosBeep(440,50);
  823.       pRadio->Setup.fTurnOn = TRUE;
  824.       DosPostEventSem(pRadio->hEvtFreqChange);
  825.     }
  826.   }
  827.   pRadio->ulNumRadios++;
  828.   WinInvalidateRegion(pRadio->pWidget->hwndWidget, NULL, TRUE);
  829. }
  830.  
  831. void _Optlink NotifyThread(void* args)
  832. {
  833.   PRADIOPRIVATE pRadio = (PRADIOPRIVATE)args;
  834.   ULONG ulWhich;
  835.   ULONG ulCnt;
  836.   pRadio->ulState |= RADIO_USBCHECK;
  837.   while (pRadio->ulState  & RADIO_USBCHECK)
  838.   {
  839.     DosWaitMuxWaitSem(pRadio->hMuxWait,SEM_INDEFINITE_WAIT,&ulWhich);
  840.     if (!pRadio->ulState)
  841.       break;
  842.     if (ulWhich)
  843.     {
  844.       ProcessRadioUnpluged(pRadio);
  845.       DosResetEventSem(pRadio->hRadioPluged, &ulCnt);
  846.     }
  847.     else
  848.     {
  849.       ProcessRadioPluged(pRadio);
  850.       DosResetEventSem(pRadio->hRadioPluged, &ulCnt);
  851.     }
  852.   }
  853.   g_USBFuncs.pUsbDeregisterNotification(pRadio->NotifyID);
  854.   DosCloseMutexSem(pRadio->hMuxWait);
  855.   DosCloseEventSem(pRadio->hRadioPluged);
  856.   DosCloseEventSem(pRadio->hRadioUnpluged);
  857.  
  858. }
  859.  
  860. void _Optlink FreqThread(void* args)
  861. {
  862.   PRADIOPRIVATE pRadio = (PRADIOPRIVATE)args;
  863.   ULONG ulCnt;
  864.   while (pRadio->ulState  & RADIO_USBCHECK)
  865.   {
  866.     DosWaitEventSem(pRadio->hEvtFreqChange, SEM_INDEFINITE_WAIT);
  867.     if (!pRadio->ulState)
  868.       break;
  869.     do
  870.     {
  871.       if (pRadio->ulState & RADIO_SCANUP ||
  872.           pRadio->ulState & RADIO_TUNEUP)
  873.       {
  874.         pRadio->Setup.ulCurrentFreq += 5;
  875.         if(pRadio->Setup.ulCurrentFreq > 10800)
  876.           pRadio->Setup.ulCurrentFreq = 8800;
  877.       }
  878.       else
  879.         if (pRadio->ulState & RADIO_SCANDOWN ||
  880.             pRadio->ulState & RADIO_TUNEDOWN)
  881.         {
  882.           pRadio->Setup.ulCurrentFreq -= 5;
  883.           if(pRadio->Setup.ulCurrentFreq < 8800)
  884.             pRadio->Setup.ulCurrentFreq = 10800;
  885.         }
  886.       if( pRadio->Setup.ulCurrentFreq == pRadio->ulScanStart)
  887.         pRadio->ulState &= ~RADIO_SCAN;
  888.  
  889.       if(pRadio->ulNumRadios &&
  890.          pRadio->Setup.fTurnOn)
  891.       {
  892.         XSTRING strSetup;
  893.  
  894.         RadioSetFreq(pRadio->Setup.ulCurrentFreq);
  895.         WinInvalidateRect(pRadio->pWidget->hwndWidget,NULL, FALSE);
  896.         DosSleep(80);
  897.         if(RadioGetStereo())
  898.         {
  899.           pRadio->ulState |= RADIO_STEREO;
  900.           pRadio->ulState &= ~RADIO_SCAN;  // End Scanning if we tuned in.
  901.         }
  902.         else
  903.           pRadio->ulState &= ~RADIO_STEREO;
  904.         WgtSaveSetup(&strSetup,
  905.                      &pRadio->Setup);
  906.         //pData->pctrSetSetupString(pData->hSettings,
  907.         //                          strSetup.psz);
  908.         pxstrClear(&strSetup);
  909.       }
  910.       pRadio->ulState &= ~RADIO_TUNE;      
  911.       WinInvalidateRect(pRadio->pWidget->hwndWidget,NULL, FALSE);
  912.     }
  913.     while(pRadio->ulState & RADIO_SCAN);
  914.     DosResetEventSem(pRadio->hEvtFreqChange, &ulCnt);
  915.   }
  916.   DosCloseEventSem(pRadio->hEvtFreqChange);
  917. }
  918.  
  919. /* ******************************************************************
  920.  *
  921.  *   Widget settings dialog
  922.  *
  923.  ********************************************************************/
  924.  
  925. // None currently. To see how a setup dialog can be done,
  926. // see the window list widget (w_winlist.c).
  927.  
  928. /* ******************************************************************
  929.  *
  930.  *   Callbacks stored in XCENTERWIDGETCLASS
  931.  *
  932.  ********************************************************************/
  933.  
  934. // If you implement a settings dialog, you must write a
  935. // "show settings dlg" function and store its function pointer
  936. // in XCENTERWIDGETCLASS.
  937.  
  938. /* ******************************************************************
  939.  *
  940.  *   PM window class implementation
  941.  *
  942.  ********************************************************************/
  943.  
  944. /*
  945.  *      This code has the actual PM window class.
  946.  *
  947.  */
  948.  
  949. /*
  950.  *@@ WgtCreate:
  951.  *      implementation for WM_CREATE.
  952.  */
  953.  
  954. MRESULT WgtCreate(HWND hwnd,
  955.                   PXCENTERWIDGET pWidget)
  956. {
  957.   MRESULT mrc = 0;
  958.   APIRET rc;
  959.   // PSZ p;
  960.   PRADIOPRIVATE pRadio = (PRADIOPRIVATE)malloc(sizeof(RADIOPRIVATE));
  961.   memset(pRadio, 0, sizeof(RADIOPRIVATE));
  962.   // link the two together
  963.   pWidget->pUser = pRadio;
  964.   pRadio->pWidget = pWidget;
  965.  
  966.   // initialize binary setup structure from setup string
  967.   WgtScanSetup(pWidget->pcszSetupString,
  968.                &pRadio->Setup);
  969.  
  970.   rc = DosCreateEventSem(NULL,&pRadio->hEvtFreqChange,0,FALSE);
  971.   if(!rc)
  972.   {
  973.     pRadio->ulState = RADIO_USBCHECK;
  974.     pRadio->hFreqThread = _beginthread(FreqThread,NULL,8192,pRadio);
  975.     LoadUSBDLL();
  976.     if (g_USBFuncs.hDLL)
  977.     {
  978.       rc =DosCreateEventSem(NULL,&pRadio->hRadioPluged,0,FALSE);
  979.       if (!rc)
  980.       {
  981.         rc = DosCreateEventSem(NULL,&pRadio->hRadioUnpluged,0,FALSE);
  982.         if (rc)
  983.           DosCloseEventSem(pRadio->hRadioPluged);
  984.         else
  985.         {
  986.           SEMRECORD aSems[2];
  987.           aSems[0].hsemCur = (HSEM)pRadio->hRadioPluged;
  988.           aSems[0].ulUser  = 0;
  989.           aSems[1].hsemCur = (HSEM)pRadio->hRadioUnpluged;
  990.           aSems[1].ulUser  = 1;
  991.           rc = DosCreateMuxWaitSem(NULL, &pRadio->hMuxWait, 2, (PSEMRECORD)&aSems, DCMW_WAIT_ANY);
  992.           if (!rc)
  993.           {
  994.             pRadio->hMonThread = _beginthread(NotifyThread,NULL,8192,pRadio);
  995.             rc= g_USBFuncs.pUsbRegisterDeviceNotification( &pRadio->NotifyID,
  996.                                                            pRadio->hRadioPluged,
  997.                                                            pRadio->hRadioUnpluged,
  998.                                                            0x04b4, 0x1002, USB_ANY_PRODUCTVERSION
  999.                                                          );
  1000.           }
  1001.           else
  1002.           {
  1003.             DosCloseEventSem(pRadio->hRadioPluged);
  1004.             DosCloseEventSem(pRadio->hRadioUnpluged);
  1005.           }
  1006.         }
  1007.       }
  1008.       
  1009.     }
  1010.   }
  1011.   HPS hps =WinGetPS(hwnd);
  1012.   LoadSkin(hps,NULL, pRadio);
  1013.   WinReleasePS(hwnd);
  1014.   // if you want the context menu help to be enabled,
  1015.   // add your help library here; if these fields are
  1016.   // left NULL, the "Help" context menu item is disabled
  1017.  
  1018.   // pWidget->pcszHelpLibrary = pcmnQueryHelpLibrary();
  1019.   // pWidget->ulHelpPanelID = ID_XSH_WIDGET_WINLIST_MAIN;
  1020.  
  1021.   return(mrc);
  1022. }
  1023.  
  1024. /*
  1025.  *@@ MwgtControl:
  1026.  *      implementation for WM_CONTROL.
  1027.  *
  1028.  *      The XCenter communicates with widgets thru
  1029.  *      WM_CONTROL messages. At the very least, the
  1030.  *      widget should respond to XN_QUERYSIZE because
  1031.  *      otherwise it will be given some dumb default
  1032.  *      size.
  1033.  *
  1034.  *@@added V0.9.7 (2000-12-14) [umoeller]
  1035.  */
  1036.  
  1037. char szTTip[200];
  1038.  
  1039. BOOL WgtControl(HWND hwnd, MPARAM mp1, MPARAM mp2)
  1040. {
  1041.   BOOL brc = FALSE;
  1042.  
  1043.   // get widget data from QWL_USER (stored there by WM_CREATE)
  1044.   PXCENTERWIDGET pWidget = (PXCENTERWIDGET)WinQueryWindowPtr(hwnd, QWL_USER);
  1045.   if (pWidget)
  1046.   {
  1047.     // get private data from that widget data
  1048.     PRADIOPRIVATE pRadio = (PRADIOPRIVATE)pWidget->pUser;
  1049.     if (pRadio)
  1050.     {
  1051.       USHORT  usID = SHORT1FROMMP(mp1),
  1052.                      usNotifyCode = SHORT2FROMMP(mp1);
  1053.  
  1054.       // is this from the XCenter client?
  1055.       switch (usID)
  1056.       {
  1057.         case ID_XCENTER_CLIENT:
  1058.           {
  1059.             // yes:
  1060.  
  1061.             switch (usNotifyCode)
  1062.             {
  1063.               /*
  1064.                * XN_QUERYSIZE:
  1065.                *      XCenter wants to know our size.
  1066.                */
  1067.               
  1068.               case XN_QUERYSIZE:
  1069.                 {
  1070.                   PSIZEL pszl = (PSIZEL)mp2;
  1071.                   // @@ToDo Get the size from the bitmapdimensions.
  1072.                   pszl->cx = 118;      // desired width
  1073.                   pszl->cy = 31;      // desired minimum height
  1074.                   brc = TRUE;
  1075.                   break;}
  1076.  
  1077.                 /*
  1078.                  * XN_SETUPCHANGED:
  1079.                  *      XCenter has a new setup string for
  1080.                  *      us in mp2.
  1081.                  *
  1082.                  *      NOTE: This only comes in with settings
  1083.                  *      dialogs. Since we don't have one, this
  1084.                  *      really isn't necessary.
  1085.                  */
  1086.  
  1087.               case XN_SETUPCHANGED:
  1088.                 {
  1089.                   const char *pcszNewSetupString = (const char*)mp2;
  1090.  
  1091.                   // reinitialize the setup data
  1092.                   WgtClearSetup(&pRadio->Setup);
  1093.                   WgtScanSetup(pcszNewSetupString, &pRadio->Setup);
  1094.  
  1095.                   WinInvalidateRect(pWidget->hwndWidget, NULL, FALSE);
  1096.                   break;
  1097.                 }
  1098.             }
  1099.           }
  1100.         case ID_XCENTER_TOOLTIP:
  1101.           {
  1102.             switch (usNotifyCode)
  1103.             {
  1104.               case TTN_NEEDTEXT:
  1105.               {
  1106.                 POINTL ptlTTip;
  1107.                 WinQueryPointerPos(HWND_DESKTOP,&ptlTTip);
  1108.                 WinMapWindowPoints( HWND_DESKTOP,
  1109.                                     pRadio->pWidget->hwndWidget,
  1110.                                     &ptlTTip,1);
  1111.                 switch (GetSkinItemFromPos(&ptlTTip,pRadio))
  1112.                 {
  1113.                   case Power:     
  1114.                     strcpy(szTTip,"Power");
  1115.                     break;
  1116.                   case Stereo:    
  1117.                     strcpy(szTTip,"Stereo Indicator\nOn,Radio is Tuned");
  1118.                     break;
  1119.                   case UsbPres:   
  1120.                     strcpy(szTTip,"USB Support Indicator");
  1121.                     break;
  1122.                   case ScanUp:    
  1123.                     strcpy(szTTip,"Scan Up");
  1124.                     break;
  1125.                   case ScanDown:  
  1126.                     strcpy(szTTip,"Scan Down");
  1127.                     break;
  1128.                   case TuneUp:    
  1129.                     strcpy(szTTip,"Tune Up");
  1130.                     break;
  1131.                   case TuneDown:  
  1132.                     strcpy(szTTip,"Tune Down");
  1133.                     break;
  1134.                   case Station1:  
  1135.                   case Station2:  
  1136.                   case Station3:  
  1137.                   case Station4:  
  1138.                     strcpy(szTTip,"Station Storage");
  1139.                     break;
  1140.                   case Station1Set:
  1141.                   case Station2Set:
  1142.                   case Station3Set:
  1143.                   case Station4Set:
  1144.                     strcpy(szTTip,"Station Store usage");
  1145.                     break;
  1146.                   case MHz:
  1147.                     strcpy(szTTip,"Radio presence indicator");
  1148.                     break;
  1149.                   default:
  1150.                     strcpy(szTTip,"USB Radio");
  1151.                     break;
  1152.                 }
  1153.                 PTOOLTIPTEXT pttt = (PTOOLTIPTEXT)mp2;
  1154.                 pttt->pszText = szTTip;
  1155.                 pttt->ulFormat = TTFMT_PSZ;
  1156.               }
  1157.               break;
  1158.               case TTN_SHOW:
  1159.               {
  1160.                 pRadio->fTooltipShowing = TRUE;
  1161.               }
  1162.               break;
  1163.               case TTN_POP:
  1164.                 pRadio->fTooltipShowing = FALSE;
  1165.               break;
  1166.             }
  1167.           }
  1168.       }
  1169.     } // end if (pRadio)
  1170.   } // end if (pWidget)
  1171.  
  1172.   return(brc);
  1173. }
  1174.  
  1175. VOID WgtPaint(HWND hwnd,
  1176.               PXCENTERWIDGET pWidget);
  1177.  
  1178. BOOL WgtButtonclick(HWND hwnd, MPARAM mp1, MPARAM mp2)
  1179. {
  1180.   BOOL brc = FALSE;
  1181.   POINTL ptlPos;
  1182. // get widget data from QWL_USER (stored there by WM_CREATE)
  1183.   PXCENTERWIDGET pWidget = (PXCENTERWIDGET)WinQueryWindowPtr(hwnd, QWL_USER);
  1184.   if(pWidget)
  1185.   {
  1186.     PRADIOPRIVATE pRadio = (PRADIOPRIVATE)pWidget->pUser;
  1187.     if(pRadio)
  1188.     {
  1189.       WinQueryPointerPos( HWND_DESKTOP, &ptlPos);
  1190.       WinMapWindowPoints( HWND_DESKTOP,
  1191.                           pRadio->pWidget->hwndWidget,
  1192.                           &ptlPos,1);
  1193.       LONG lItem = GetSkinItemFromPos(&ptlPos,pRadio);
  1194.       switch (lItem)
  1195.       {
  1196.         case Power: 
  1197.           if(pRadio->ulNumRadios)
  1198.           {
  1199.             if(pRadio->Setup.fTurnOn)
  1200.               RadioPower(FALSE);
  1201.             pRadio->Setup.fTurnOn = !pRadio->Setup.fTurnOn;
  1202.             DosPostEventSem(pRadio->hEvtFreqChange);
  1203.           }
  1204.           brc = TRUE;
  1205.           break;
  1206.         case UsbPres:   
  1207.           if(!g_USBFuncs.hDLL && LoadUSBDLL())
  1208.           {
  1209.             WinInvalidateRect(hwnd, NULL, TRUE);
  1210.           }
  1211.           brc = TRUE;
  1212.           break;
  1213.         case ScanUp:    
  1214.           if(pRadio->Setup.fTurnOn)
  1215.           {
  1216.             if(pRadio->ulState & RADIO_TUNE)
  1217.             {
  1218.               DosBeep(440,10);
  1219.             }
  1220.             else
  1221.             {
  1222.               if(pRadio->ulState & RADIO_SCAN)
  1223.               {
  1224.                 pRadio->ulState &= ~RADIO_SCAN;
  1225.               }
  1226.               pRadio->ulState |= RADIO_SCANUP;
  1227.               pRadio->ulScanStart = pRadio->Setup.ulCurrentFreq;
  1228.               DosPostEventSem(pRadio->hEvtFreqChange);
  1229.             }
  1230.           }
  1231.           brc = TRUE;
  1232.           break;
  1233.         case ScanDown:  
  1234.           if(pRadio->Setup.fTurnOn)
  1235.           {
  1236.             if(pRadio->ulState & RADIO_TUNE)
  1237.             {
  1238.               DosBeep(440,10);
  1239.             }
  1240.             else
  1241.             {
  1242.               if(pRadio->ulState & RADIO_SCAN)
  1243.               {
  1244.                 pRadio->ulState &= ~RADIO_SCAN;
  1245.               }
  1246.               pRadio->ulState |= RADIO_SCANDOWN;
  1247.               pRadio->ulScanStart = pRadio->Setup.ulCurrentFreq;
  1248.               DosPostEventSem(pRadio->hEvtFreqChange);
  1249.             }
  1250.           }
  1251.           brc = TRUE;
  1252.           break;
  1253.         case TuneUp:    
  1254.           if(pRadio->Setup.fTurnOn)
  1255.           {
  1256.             if(pRadio->ulState & RADIO_SCAN)
  1257.             {
  1258.               pRadio->ulState &= ~RADIO_SCAN;
  1259.             }
  1260.             pRadio->ulState |= RADIO_TUNEUP;
  1261.             DosPostEventSem(pRadio->hEvtFreqChange);
  1262.           }
  1263.           brc = TRUE;
  1264.           break;
  1265.         case TuneDown:  
  1266.           if(pRadio->Setup.fTurnOn)
  1267.           {
  1268.             if(pRadio->ulState & RADIO_SCAN)
  1269.             {
  1270.               pRadio->ulState &= ~RADIO_SCAN;
  1271.             }
  1272.             pRadio->ulState |= RADIO_TUNEDOWN;
  1273.             DosPostEventSem(pRadio->hEvtFreqChange);
  1274.           }
  1275.           brc = TRUE;
  1276.           break;
  1277.         case Station1:  
  1278.         case Station2:  
  1279.         case Station3:  
  1280.         case Station4:  
  1281.           if(pRadio->Setup.fTurnOn)
  1282.           {
  1283.             if( (pRadio->Setup.ulStoredFreq[lItem-Station1]>=8800) &&
  1284.                 (pRadio->Setup.ulStoredFreq[lItem-Station1]<=10800) )
  1285.             {
  1286.               pRadio->Setup.ulCurrentFreq =
  1287.                 pRadio->Setup.ulStoredFreq[lItem-Station1];
  1288.               DosPostEventSem(pRadio->hEvtFreqChange);
  1289.             }
  1290.           }
  1291.           break;
  1292.         case Station1Set:
  1293.         case Station2Set:
  1294.         case Station3Set:
  1295.         case Station4Set:
  1296.           if(pRadio->Setup.fTurnOn)
  1297.           {
  1298.             pRadio->Setup.ulStoredFreq[lItem-Station1Set] = 
  1299.               pRadio->Setup.ulCurrentFreq;
  1300.             WinInvalidateRect(hwnd, NULL, TRUE);
  1301.           }
  1302.           break;
  1303.         case MHz:
  1304.           break;
  1305.         default:
  1306.           break;
  1307.       }
  1308.     }
  1309.   }
  1310.   return brc;
  1311. }
  1312.  
  1313. VOID DrawFreq(HPS hps, POINTL *ptlStart, PRADIOPRIVATE pRadio)
  1314. {
  1315.   // Freq Display
  1316.   ULONG ulFreq;
  1317.   POINTL ptlPos;
  1318.   ldiv_t calc;
  1319.   ptlPos.x = ptlStart->x + pRadio->pSkin->HundretDigit.ptlPos.x;
  1320.   ptlPos.y = ptlStart->y + pRadio->pSkin->HundretDigit.ptlPos.y;
  1321.  
  1322.   ulFreq = (pRadio->Setup.ulCurrentFreq>10800)?8800:
  1323.            (pRadio->Setup.ulCurrentFreq<8800)?8800:
  1324.            pRadio->Setup.ulCurrentFreq;
  1325.  
  1326.   WinDrawBitmap( hps, 
  1327.                  pRadio->pSkin->HundretDigit.hBmp[ulFreq>10000?ON:OFF],
  1328.                  NULL, &ptlPos,0,0, DBM_NORMAL);
  1329.   if (ulFreq>10000)
  1330.     ulFreq -=10000;
  1331.  
  1332.   ptlPos.x = ptlStart->x + pRadio->pSkin->ptlNormalDigitPos[0].x;
  1333.   ptlPos.y = ptlStart->y + pRadio->pSkin->ptlNormalDigitPos[0].y;
  1334.   calc = ldiv(ulFreq,1000);
  1335.   WinDrawBitmap( hps, 
  1336.                  pRadio->pSkin->NormalDigits.hDigit[calc.quot],
  1337.                  NULL, &ptlPos,0,0, DBM_NORMAL);
  1338.  
  1339.   ulFreq -= calc.quot*1000;
  1340.   ptlPos.x = ptlStart->x + pRadio->pSkin->ptlNormalDigitPos[1].x;
  1341.   ptlPos.y = ptlStart->y + pRadio->pSkin->ptlNormalDigitPos[1].y;
  1342.   calc = ldiv(ulFreq,100);
  1343.   WinDrawBitmap( hps, 
  1344.                  pRadio->pSkin->NormalDigits.hDigit[calc.quot],
  1345.                  NULL, &ptlPos,0,0, DBM_NORMAL);
  1346.  
  1347.   ulFreq -= calc.quot*100;
  1348.   ptlPos.x = ptlStart->x + pRadio->pSkin->ptlSmallDigitPos[0].x;
  1349.   ptlPos.y = ptlStart->y + pRadio->pSkin->ptlSmallDigitPos[0].y;
  1350.   calc = ldiv(ulFreq,10);
  1351.   WinDrawBitmap( hps, 
  1352.                  pRadio->pSkin->SmallDigits.hDigit[calc.quot],
  1353.                  NULL, &ptlPos,0,0, DBM_NORMAL);
  1354.  
  1355.   ulFreq -= calc.quot*10;
  1356.   ptlPos.y = ptlStart->y + pRadio->pSkin->ptlSmallDigitPos[1].y;
  1357.   ptlPos.x = ptlStart->x + pRadio->pSkin->ptlSmallDigitPos[1].x;
  1358.   WinDrawBitmap( hps, 
  1359.                  pRadio->pSkin->SmallDigits.hDigit[ulFreq],
  1360.                  NULL, &ptlPos,0,0, DBM_NORMAL);
  1361.  
  1362.   ptlPos.y = ptlStart->y + pRadio->pSkin->SItems[MHz].ptlPos.y;
  1363.   ptlPos.x = ptlStart->x + pRadio->pSkin->SItems[MHz].ptlPos.x;
  1364.   WinDrawBitmap( hps, 
  1365.                  pRadio->pSkin->SItems[MHz].hBmp[ON],
  1366.                  NULL, &ptlPos,0,0, DBM_NORMAL);
  1367. }
  1368.  
  1369. void DrawStereo(HPS hps, POINTL *ptlStart ,PRADIOPRIVATE pRadio)
  1370. {
  1371.   POINTL ptlPos;
  1372.   ptlPos.x = ptlStart->x + pRadio->pSkin->SItems[Stereo].ptlPos.x;
  1373.   ptlPos.y = ptlStart->y + pRadio->pSkin->SItems[Stereo].ptlPos.y;
  1374.   WinDrawBitmap( hps, 
  1375.                  pRadio->pSkin->SItems[Stereo].hBmp[(pRadio->ulState & RADIO_STEREO)?ON:OFF],
  1376.                  NULL, &ptlPos,0,0, DBM_NORMAL);
  1377. }
  1378.  
  1379. void DrawStations(HPS hps, POINTL *ptlStart ,PRADIOPRIVATE pRadio)
  1380. {
  1381.   POINTL ptlPos;
  1382.   USHORT i;
  1383.   for (i=0;i<4;i++)
  1384.   {
  1385.     ptlPos.x = ptlStart->x + pRadio->pSkin->SItems[Station1+i].ptlPos.x;
  1386.     ptlPos.y = ptlStart->y + pRadio->pSkin->SItems[Station1+i].ptlPos.y;
  1387.     WinDrawBitmap( hps, 
  1388.                    pRadio->Setup.fTurnOn?
  1389.                      pRadio->pSkin->SItems[Station1+i].hBmp[(pRadio->Setup.ulStoredFreq[i] == pRadio->Setup.ulCurrentFreq)?ON:OFF]:
  1390.                      pRadio->pSkin->SItems[Station1+i].hBmp[OFF],
  1391.                    NULL, &ptlPos,0,0, DBM_NORMAL);
  1392.     ptlPos.x = ptlStart->x + pRadio->pSkin->SItems[Station1Set+i].ptlPos.x;
  1393.     ptlPos.y = ptlStart->y + pRadio->pSkin->SItems[Station1Set+i].ptlPos.y;
  1394.     WinDrawBitmap( hps, 
  1395.                    pRadio->Setup.fTurnOn?
  1396.                      pRadio->pSkin->SItems[Station1Set+i].hBmp[(pRadio->Setup.ulStoredFreq[i] != 0)?ON:OFF]:
  1397.                      pRadio->pSkin->SItems[Station1Set+i].hBmp[OFF],
  1398.                    NULL, &ptlPos,0,0, DBM_NORMAL);
  1399.   }
  1400. }
  1401.  
  1402. void DrawControls(HPS hps, POINTL *ptlStart ,PRADIOPRIVATE pRadio)
  1403. {
  1404.   POINTL ptlPos;
  1405.   ptlPos.x = ptlStart->x + pRadio->pSkin->SItems[Power].ptlPos.x;
  1406.   ptlPos.y = ptlStart->y + pRadio->pSkin->SItems[Power].ptlPos.y;
  1407.   WinDrawBitmap( hps, 
  1408.                  pRadio->pSkin->SItems[Power].hBmp[ON],
  1409.                  NULL, &ptlPos,0,0, DBM_NORMAL);
  1410.   ptlPos.x = ptlStart->x + pRadio->pSkin->SItems[ScanDown].ptlPos.x;
  1411.   ptlPos.y = ptlStart->y + pRadio->pSkin->SItems[ScanDown].ptlPos.y;
  1412.   WinDrawBitmap( hps, 
  1413.                  pRadio->pSkin->SItems[ScanDown].hBmp[ON],
  1414.                  NULL, &ptlPos,0,0, DBM_NORMAL);
  1415.   ptlPos.x = ptlStart->x + pRadio->pSkin->SItems[TuneDown].ptlPos.x;
  1416.   ptlPos.y = ptlStart->y + pRadio->pSkin->SItems[TuneDown].ptlPos.y;
  1417.   WinDrawBitmap( hps, 
  1418.                  pRadio->pSkin->SItems[TuneDown].hBmp[ON],
  1419.                  NULL, &ptlPos,0,0, DBM_NORMAL);
  1420.   ptlPos.x = ptlStart->x + pRadio->pSkin->SItems[TuneUp].ptlPos.x;
  1421.   ptlPos.y = ptlStart->y + pRadio->pSkin->SItems[TuneUp].ptlPos.y;
  1422.   WinDrawBitmap( hps, 
  1423.                  pRadio->pSkin->SItems[TuneUp].hBmp[ON],
  1424.                  NULL, &ptlPos,0,0, DBM_NORMAL);
  1425.   ptlPos.x = ptlStart->x + pRadio->pSkin->SItems[ScanUp].ptlPos.x;
  1426.   ptlPos.y = ptlStart->y + pRadio->pSkin->SItems[ScanUp].ptlPos.y;
  1427.   WinDrawBitmap( hps, 
  1428.                  pRadio->pSkin->SItems[ScanUp].hBmp[ON],
  1429.                  NULL, &ptlPos,0,0, DBM_NORMAL);
  1430. }
  1431.  
  1432. /*
  1433.  *@@ WgtPaint:
  1434.  *      implementation for WM_PAINT.
  1435.  *
  1436.  *      This really does nothing, except painting a
  1437.  *      3D rectangle and printing a question mark.
  1438.  */
  1439.  
  1440. VOID WgtPaint(HWND hwnd,
  1441.               PXCENTERWIDGET pWidget)
  1442. {
  1443.   HPS hps = WinBeginPaint(hwnd, NULLHANDLE, NULL);
  1444.   if (hps)
  1445.   {
  1446.     RECTL       rclWin;
  1447.     PRADIOPRIVATE pRadio = (PRADIOPRIVATE)pWidget->pUser;
  1448.     WinQueryWindowRect(hwnd,
  1449.                        &rclWin);        // exclusive
  1450.     if (pRadio->pSkin)
  1451.     {
  1452.       POINTL ptlPos;
  1453.       ptlPos.x = 0;
  1454.       ptlPos.y = 0;
  1455.       WinDrawBitmap( hps, 
  1456.                      pRadio->pSkin->hBackground, 
  1457.                      NULL, &ptlPos, 0,0, DBM_NORMAL);
  1458.       ptlPos.x = rclWin.xLeft   + pRadio->pSkin->SItems[UsbPres].ptlPos.x;
  1459.       ptlPos.y = rclWin.yBottom + pRadio->pSkin->SItems[UsbPres].ptlPos.y;
  1460.       WinDrawBitmap( hps, 
  1461.                      pRadio->pSkin->SItems[UsbPres].hBmp[g_USBFuncs.hDLL!=NULL?ON:OFF],
  1462.                      NULL, &ptlPos,0,0, DBM_NORMAL);
  1463.  
  1464.       if (pRadio->Setup.fTurnOn)
  1465.       {
  1466.         DrawFreq(hps,(PPOINTL)&rclWin,pRadio);
  1467.         DrawStereo(hps,(PPOINTL)&rclWin,pRadio);
  1468.         DrawStations(hps,(PPOINTL)&rclWin,pRadio);
  1469.         DrawControls(hps,(PPOINTL)&rclWin,pRadio);
  1470.       }
  1471.       else
  1472.       {
  1473.         if (pRadio->ulNumRadios)
  1474.         {
  1475.           DrawStations(hps,(PPOINTL)&rclWin,pRadio);
  1476.           DrawControls(hps,(PPOINTL)&rclWin,pRadio);
  1477.         }
  1478.       }
  1479.     }
  1480.     else
  1481.     {
  1482.       WinFillRect(hps,&rclWin,CLR_WHITE);
  1483.       WinDrawText(hps, 0, "Init Error", &rclWin, CLR_BLACK, CLR_WHITE,DT_VCENTER|DT_CENTER);
  1484.     }
  1485.     WinEndPaint(hps);
  1486.   }
  1487. }
  1488.  
  1489. /*
  1490.  *@@ WgtPresParamChanged:
  1491.  *      implementation for WM_PRESPARAMCHANGED.
  1492.  *
  1493.  *      While this isn't exactly required, it's a nice
  1494.  *      thing for a widget to react to colors and fonts
  1495.  *      dropped on it. While we're at it, we also save
  1496.  *      these colors and fonts in our setup string data.
  1497.  *
  1498.  *@@changed V0.9.13 (2001-06-21) [umoeller]: changed XCM_SAVESETUP call for tray support
  1499.  */
  1500.  
  1501. VOID WgtPresParamChanged(HWND hwnd,
  1502.                          ULONG ulAttrChanged,
  1503.                          PXCENTERWIDGET pWidget)
  1504. {
  1505.   PRADIOPRIVATE pRadio = (PRADIOPRIVATE)pWidget->pUser;
  1506.   if (pRadio)
  1507.   {
  1508.     BOOL fInvalidate = TRUE;
  1509.     switch (ulAttrChanged)
  1510.     {
  1511.       case 0:     // layout palette thing dropped
  1512.       case PP_BACKGROUNDCOLOR:    // background color (no ctrl pressed)
  1513.       case PP_FOREGROUNDCOLOR:    // foreground color (ctrl pressed)
  1514.         // update our setup data; the presparam has already
  1515.         // been changed, so we can just query it
  1516. #if 0
  1517.         pRadio->Setup.lcolBackground
  1518.         = pwinhQueryPresColor(hwnd,
  1519.                               PP_BACKGROUNDCOLOR,
  1520.                               FALSE,
  1521.                               SYSCLR_DIALOGBACKGROUND);
  1522.         pRadio->Setup.lcolForeground
  1523.         = pwinhQueryPresColor(hwnd,
  1524.                               PP_FOREGROUNDCOLOR,
  1525.                               FALSE,
  1526.                               SYSCLR_WINDOWSTATICTEXT);
  1527. #endif
  1528.         break;
  1529.  
  1530.       case PP_FONTNAMESIZE:       // font dropped:
  1531.         break;
  1532.  
  1533.       default:
  1534.         fInvalidate = FALSE;
  1535.     }
  1536.     fInvalidate = FALSE;
  1537.  
  1538.     if (fInvalidate)
  1539.     {
  1540.       // something has changed:
  1541.       XSTRING strSetup;
  1542.  
  1543.       // repaint
  1544.       WinInvalidateRect(hwnd, NULL, FALSE);
  1545.  
  1546.       // recompose our setup string
  1547.       WgtSaveSetup(&strSetup,
  1548.                    &pRadio->Setup);
  1549.       if (strSetup.ulLength)
  1550.         // we have a setup string:
  1551.         // tell the XCenter to save it with the XCenter data
  1552.         // changed V0.9.13 (2001-06-21) [umoeller]:
  1553.         // post it to parent instead of fixed XCenter client
  1554.         // to make this trayable
  1555.         WinSendMsg(WinQueryWindow(hwnd, QW_PARENT), // pRadio->pWidget->pGlobals->hwndClient,
  1556.                    XCM_SAVESETUP,
  1557.                    (MPARAM)hwnd,
  1558.                    (MPARAM)strSetup.psz);
  1559.       pxstrClear(&strSetup);
  1560.     }
  1561.   } // end if (pRadio)
  1562. }
  1563.  
  1564. /*
  1565.  *@@ WgtDestroy:
  1566.  *      implementation for WM_DESTROY.
  1567.  *
  1568.  *      This must clean up all allocated resources.
  1569.  */
  1570.  
  1571. VOID WgtDestroy(HWND hwnd,
  1572.                 PXCENTERWIDGET pWidget)
  1573. {
  1574.   PRADIOPRIVATE pRadio = (PRADIOPRIVATE)pWidget->pUser;
  1575.   if (pRadio)
  1576.   {
  1577.     WgtClearSetup(&pRadio->Setup);
  1578.     pRadio->ulState = 0;
  1579.     DosPostEventSem(pRadio->hRadioPluged);
  1580.     DosWaitThread(&pRadio->hMonThread, DCWW_WAIT);
  1581.     DosPostEventSem(pRadio->hEvtFreqChange);
  1582.     DosWaitThread(&pRadio->hFreqThread, DCWW_WAIT);
  1583.     if (g_USBFuncs.hDLL)
  1584.       DosFreeModule(g_USBFuncs.hDLL);
  1585.     free(pRadio);
  1586.     // pWidget is cleaned up by DestroyWidgets
  1587.   }
  1588. }
  1589.  
  1590. /*
  1591.  *@@ fnwpSampleWidget:
  1592.  *      window procedure for the winlist widget class.
  1593.  *
  1594.  *      There are a few rules which widget window procs
  1595.  *      must follow. See XCENTERWIDGETCLASS in center.h
  1596.  *      for details.
  1597.  *
  1598.  *      Other than that, this is a regular window procedure
  1599.  *      which follows the basic rules for a PM window class.
  1600.  */
  1601.  
  1602. MRESULT EXPENTRY fnwpSampleWidget(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1603. {
  1604.   MRESULT mrc = 0;
  1605.   // get widget data from QWL_USER (stored there by WM_CREATE)
  1606.   PXCENTERWIDGET pWidget = (PXCENTERWIDGET)WinQueryWindowPtr(hwnd, QWL_USER);
  1607.   // this ptr is valid after WM_CREATE
  1608.  
  1609.   switch (msg)
  1610.   {
  1611.     /*
  1612.      * WM_CREATE:
  1613.      *      as with all widgets, we receive a pointer to the
  1614.      *      XCENTERWIDGET in mp1, which was created for us.
  1615.      *
  1616.      *      The first thing the widget MUST do on WM_CREATE
  1617.      *      is to store the XCENTERWIDGET pointer (from mp1)
  1618.      *      in the QWL_USER window word by calling:
  1619.      *
  1620.      *          WinSetWindowPtr(hwnd, QWL_USER, mp1);
  1621.      *
  1622.      *      We use XCENTERWIDGET.pUser for allocating
  1623.      *      SAMPLEPRIVATE for our own stuff.
  1624.      */
  1625.     
  1626.     case WM_CREATE:
  1627.       WinSetWindowPtr(hwnd, QWL_USER, mp1);
  1628.       pWidget = (PXCENTERWIDGET)mp1;
  1629.       if ((pWidget) && (pWidget->pfnwpDefWidgetProc))
  1630.         mrc = WgtCreate(hwnd, pWidget);
  1631.       else
  1632.         // stop window creation!!
  1633.         mrc = (MPARAM)TRUE;
  1634.       break;
  1635.  
  1636.       /*
  1637.        * WM_CONTROL:
  1638.        *      process notifications/queries from the XCenter.
  1639.        */
  1640.  
  1641.     case WM_CONTROL:
  1642.       mrc = (MPARAM)WgtControl(hwnd, mp1, mp2);
  1643.       break;
  1644.  
  1645.       /*
  1646.        * WM_PAINT:
  1647.        *
  1648.        */
  1649.  
  1650.     case WM_PAINT:
  1651.       WgtPaint(hwnd, pWidget);
  1652.       break;
  1653.  
  1654.       /*
  1655.        * WM_PRESPARAMCHANGED:
  1656.        *
  1657.        */
  1658.  
  1659.     case WM_PRESPARAMCHANGED:
  1660.       if (pWidget)
  1661.         // this gets sent before this is set!
  1662.         WgtPresParamChanged(hwnd, (ULONG)mp1, pWidget);
  1663.       break;
  1664.  
  1665.       /*
  1666.        * WM_DESTROY:
  1667.        *      clean up. This _must_ be passed on to
  1668.        *      ctrDefWidgetProc.
  1669.        */
  1670.     case WM_BUTTON1CLICK:
  1671.       mrc = (MPARAM)WgtButtonclick(hwnd, mp1, mp2);
  1672.       break;
  1673.     case WM_DESTROY:
  1674.       WgtDestroy(hwnd, pWidget);
  1675.       // we _MUST_ pass this on, or the default widget proc
  1676.       // cannot clean up.
  1677.       mrc = pWidget->pfnwpDefWidgetProc(hwnd, msg, mp1, mp2);
  1678.       break;
  1679.  
  1680.     default:
  1681.       mrc = pWidget->pfnwpDefWidgetProc(hwnd, msg, mp1, mp2);
  1682.   } // end switch(msg)
  1683.  
  1684.   return(mrc);
  1685. }
  1686.  
  1687. /* ******************************************************************
  1688.  *
  1689.  *   Exported procedures
  1690.  *
  1691.  ********************************************************************/
  1692.  
  1693. /*
  1694.  *@@ WgtInitModule:
  1695.  *      required export with ordinal 1, which must tell
  1696.  *      the XCenter how many widgets this DLL provides,
  1697.  *      and give the XCenter an array of XCENTERWIDGETCLASS
  1698.  *      structures describing the widgets.
  1699.  *
  1700.  *      With this call, you are given the module handle of
  1701.  *      XFLDR.DLL. For convenience, you may resolve imports
  1702.  *      for some useful functions which are exported thru
  1703.  *      src\shared\xwp.def. See the code below.
  1704.  *
  1705.  *      This function must also register the PM window classes
  1706.  *      which are specified in the XCENTERWIDGETCLASS array
  1707.  *      entries. For this, you are given a HAB which you
  1708.  *      should pass to WinRegisterClass. For the window
  1709.  *      class style (4th param to WinRegisterClass),
  1710.  *      you should specify
  1711.  *
  1712.  +          CS_PARENTCLIP | CS_SIZEREDRAW | CS_SYNCPAINT
  1713.  *
  1714.  *      Your widget window _will_ be resized, even if you're
  1715.  *      not planning it to be.
  1716.  *
  1717.  *      This function only gets called _once_ when the widget
  1718.  *      DLL has been successfully loaded by the XCenter. If
  1719.  *      there are several instances of a widget running (in
  1720.  *      the same or in several XCenters), this function does
  1721.  *      not get called again. However, since the XCenter unloads
  1722.  *      the widget DLLs again if they are no longer referenced
  1723.  *      by any XCenter, this might get called again when the
  1724.  *      DLL is re-loaded.
  1725.  *
  1726.  *      There will ever be only one load occurence of the DLL.
  1727.  *      The XCenter manages sharing the DLL between several
  1728.  *      XCenters. As a result, it doesn't matter if the DLL
  1729.  *      has INITINSTANCE etc. set or not.
  1730.  *
  1731.  *      If this returns 0, this is considered an error, and the
  1732.  *      DLL will be unloaded again immediately.
  1733.  *
  1734.  *      If this returns any value > 0, *ppaClasses must be
  1735.  *      set to a static array (best placed in the DLL's
  1736.  *      global data) of XCENTERWIDGETCLASS structures,
  1737.  *      which must have as many entries as the return value.
  1738.  */
  1739.  
  1740. ULONG EXPENTRY WgtInitModule(HAB hab,         // XCenter's anchor block
  1741.                              HMODULE hmodPlugin, // module handle of the widget DLL
  1742.                              HMODULE hmodXFLDR,    // XFLDR.DLL module handle
  1743.                              PXCENTERWIDGETCLASS *ppaClasses,
  1744.                              PSZ pszErrorMsg)  // if 0 is returned, 500 bytes of error msg
  1745. {
  1746.   ULONG   ulrc = 0,
  1747.   ul = 0;
  1748.   BOOL    fImportsFailed = FALSE;
  1749.   g_hResDLL = hmodPlugin;
  1750.   // resolve imports from XFLDR.DLL (this is basically
  1751.   // a copy of the doshResolveImports code, but we can't
  1752.   // use that before resolving...)
  1753.   for (ul = 0;
  1754.       ul < sizeof(G_aImports) / sizeof(G_aImports[0]);
  1755.       ul++)
  1756.   {
  1757.     if (DosQueryProcAddr(hmodXFLDR,
  1758.                          0,               // ordinal, ignored
  1759.                          (PSZ)G_aImports[ul].pcszFunctionName,
  1760.                          G_aImports[ul].ppFuncAddress)
  1761.         != NO_ERROR)
  1762.     {
  1763.       sprintf(pszErrorMsg,
  1764.               "Import %s failed.",
  1765.               G_aImports[ul].pcszFunctionName);
  1766.       fImportsFailed = TRUE;
  1767.       break;
  1768.     }
  1769.   }
  1770.  
  1771.   if (!fImportsFailed)
  1772.   {
  1773.     // all imports OK:
  1774.     // register our PM window class
  1775.     if (!WinRegisterClass(hab,
  1776.                           WNDCLASS_WIDGET_RADIO,
  1777.                           fnwpSampleWidget,
  1778.                           CS_PARENTCLIP | CS_SIZEREDRAW | CS_SYNCPAINT,
  1779.                           sizeof(PRADIOPRIVATE))
  1780.         // extra memory to reserve for QWL_USER
  1781.        )
  1782.       strcpy(pszErrorMsg, "WinRegisterClass failed.");
  1783.     else
  1784.     {
  1785.       // no error:
  1786.       // return widget classes
  1787.       *ppaClasses = G_WidgetClasses;
  1788.  
  1789.       // return no. of classes in this DLL (one here):
  1790.       ulrc = sizeof(G_WidgetClasses) / sizeof(G_WidgetClasses[0]);
  1791.     }
  1792.   }
  1793.  
  1794.   return(ulrc);
  1795. }
  1796.  
  1797. /*
  1798.  *@@ WgtUnInitModule:
  1799.  *      optional export with ordinal 2, which can clean
  1800.  *      up global widget class data.
  1801.  *
  1802.  *      This gets called by the XCenter right before
  1803.  *      a widget DLL gets unloaded. Note that this
  1804.  *      gets called even if the "init module" export
  1805.  *      returned 0 (meaning an error) and the DLL
  1806.  *      gets unloaded right away.
  1807.  */
  1808.  
  1809. VOID EXPENTRY WgtUnInitModule(VOID)
  1810. {
  1811. }
  1812.  
  1813. /*
  1814.  *@@ WgtQueryVersion:
  1815.  *      this new export with ordinal 3 can return the
  1816.  *      XWorkplace version number which is required
  1817.  *      for this widget to run. For example, if this
  1818.  *      returns 0.9.10, this widget will not run on
  1819.  *      earlier XWorkplace versions.
  1820.  *
  1821.  *      NOTE: This export was mainly added because the
  1822.  *      prototype for the "Init" export was changed
  1823.  *      with V0.9.9. If this returns 0.9.9, it is
  1824.  *      assumed that the INIT export understands
  1825.  *      the new FNWGTINITMODULE_099 format (see center.h).
  1826.  *
  1827.  *@@added V0.9.9 (2001-02-06) [umoeller]
  1828.  */
  1829.  
  1830. VOID EXPENTRY WgtQueryVersion(PULONG pulMajor,
  1831.                               PULONG pulMinor,
  1832.                               PULONG pulRevision)
  1833. {
  1834.   // report 0.9.9
  1835.   *pulMajor = 0;
  1836.   *pulMinor = 9;
  1837.   *pulRevision = 9;
  1838. }
  1839.  
  1840.