Changeset 68


Ignore:
Timestamp:
May 15, 2001, 6:15:18 PM (24 years ago)
Author:
umoeller
Message:

Lotsa fixes from the last two weeks.

Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/helpers/comctl.h

    r65 r68  
    102102    {
    103103        USHORT          usStartAngle,
    104                             // angle to start with (0%).
     104                            // for "pie chart" mode, angle to start with (0%).
    105105                            // This must be in the range of 0 to 360 degrees,
    106106                            // with 0 degrees being the rightmost point
    107107                            // of the arc.
     108
    108109                            // All degree values are counter-clockwise from that point.
    109110                            // Example: 90 will start the arc at the top.
     111
     112                            //                   90ø
     113                            //                 +++++++
     114                            //              +           +
     115                            //            +               +
     116                            //           +                 +
     117                            //          +                   +
     118                            //          +                   +
     119                            //   180ø   +         X         +     0ø
     120                            //          +                   +
     121                            //          +                   +
     122                            //           +                 +
     123                            //            +               +
     124                            //              +           +
     125                            //                 +++++++
     126                            //                   270ø
     127
    110128                        usSweepAngle;
    111                             // the maximum angle to use for 100%.
     129                            // the maximum angle to use for 100%, in addition to
     130                            // usStartAngle.
    112131                            // This must be in the range of 0 to 360 degrees,
    113132                            // with 0 degrees being usStartAngle.
    114133                            // All degree values are counter-clockwise from that point.
    115                             // Example 1: usStartAngle = 0 and usSweepAngle = 360
    116                             // will draw a full circle from the right.
    117                             // Example 2: usStartAngle = 180 and usSweepAngle = 270
    118                             // will draw a three-quarter angle from the left.
     134                            // Example: Specify usStartAngle = 180 (1) to start the pie
     135                            // at the left and usSweepAngle = 270 (2) to draw a
     136                            // three-quarter total pie.
     137
     138                            //                   90ø
     139                            //                    ++++
     140                            //                    +   _ +
     141                            //                    +  |\   +
     142                            //                    +    \   +
     143                            //                    +     \   +
     144                            //                    +     |   +
     145                            // (1) 180ø +++++++++++     |   +     0ø
     146                            //          +              /    +
     147                            //          +    \       (2)    +
     148                            //           +    \      /     +
     149                            //            +    ------     +
     150                            //              +           +
     151                            //                 +++++++
     152                            //                   270ø
     153
    119154        ULONG           cValues;
    120155                            // data item count; the arrays in *padValues and *palColors
     
    124159                            // pointer to an array of double values;
    125160                            // the sum of all these will make up 100%
    126                             // in the chart (i.e. the usSweepAngle angle).
    127                             // If this is NULL, the chart displays nothing.
     161                            // in the chart. In "pie chart" mode, the
     162                            // sum of all these values corresponds to
     163                            // the usSweepAngle angle; in "bar chart" mode,
     164                            // the sum corresponds to the width of the control.
     165                            // If this ptr is NULL, the chart displays nothing.
    128166                            // Otherwise, this array must have cValues items.
    129167        LONG*           palColors;
    130168                            // pointer to an array of LONG RGB colors;
    131169                            // each item in this array must correspond
    132                             // to an item in padValues.
     170                            // to an item in padValues and specifies the color
     171                            // to paint the corresponding data item with.
    133172                            // This _must_ be specified if padValues is != NULL.
    134173                            // This array must have cValues items.
     
    141180    } CHARTDATA, *PCHARTDATA;
    142181
    143     // chart display mode: currently only PCF_PIECHART is supported.
     182    // chart display mode:
    144183    #define CHS_PIECHART            0x0000
     184    #define CHS_BARCHART            0x0001
    145185
    146186    // chart display flags (CHARTSTYLE.ulStyle):
    147     #define CHS_SHADOW              0x0100  // draw shadow
    148     #define CHS_3D_BRIGHT           0x0200  // draw 3D block in same color as surface;
     187    #define CHS_SHADOW              0x0100  // (pie chart only) draw shadow
     188    #define CHS_3D_BRIGHT           0x0200  // (pie chart only)
     189                                            // // draw 3D block in same color as surface;
    149190                                            // CHARTSTYLE.ulThickness defines thickness
    150     #define CHS_3D_DARKEN           0x0600  // draw 3D block too, but darker
     191    #define CHS_3D_DARKEN           0x0600  // (pie chart only)
     192                                            // draw 3D block too, but darker
    151193                                            // compared to surface;
    152194                                            // CHARTSTYLE.ulThickness defines thickness
    153195
     196    #define CHS_DRAWLINES           0x0800  // draw lines between pie slices
     197                                            // added V0.9.12 (2001-05-03) [umoeller]
     198
    154199    #define CHS_DESCRIPTIONS        0x1000  // show descriptions
    155200    #define CHS_DESCRIPTIONS_3D     0x3000  // same as CHS_DESCRIPTIONS, but shaded
    156201
    157     #define CHS_SELECTIONS          0x4000  // allow data items to be selected
     202    #define CHS_SELECTIONS          0x4000  // allow data items to be selected using
     203                                            // mouse and keyboard; this also enables
     204                                            // WM_CONTROL notifications
    158205
    159206    /*
     
    165212    {
    166213        ULONG           ulStyle;        // CHS_* flags
    167         ULONG           ulThickness;    // pie thickness (with CHS_3D_xxx) in pixels
    168         double          dPieSize;       // size of the pie chart relative to the control
     214
     215        ULONG           ulThickness;    // (pie chart only)
     216                                        // pie thickness (with CHS_3D_xxx) in pixels
     217
     218        double          dPieSize;       // (pie chart only)
     219                                        // // size of the pie chart relative to the control
    169220                                        // size. A value of 1 would make the pie chart
    170221                                        // consume all available space. A value of .5
     
    172223                                        // control's space. The pie chart is always
    173224                                        // centered within the control.
    174         double          dDescriptions;  // position of the slice descriptions on the pie
     225
     226        double          dDescriptions;  // (pie chart only)
     227                                        // position of the slice descriptions on the pie
    175228                                        // relative to the window size. To calculate the
    176229                                        // description positions, the control calculates
     
    191244    } CHARTSTYLE, *PCHARTSTYLE;
    192245
    193     /*
    194      *@@ CHARTCDATA:
    195      *      pie chart control data. Composed from the various
    196      *      chart initialization data.
    197      *      Stored in QWL_USER of the subclassed static control.
    198      *      Not available to the application.
    199      */
    200 
    201     typedef struct _CHARTCDATA
    202     {
    203         // data which is initialized upon creation:
    204         PFNWP           OldStaticProc;  // old static window procedure (from WinSubclassWindow)
    205 
    206         // data which is initialized upon CHTM_SETCHARTDATA/CHTM_SETCHARTSTYLE:
    207         HDC             hdcMem;         // memory device context for bitmap
    208         HPS             hpsMem;         // memory presentation space for bitmap
    209         CHARTDATA       cd;             // chart data: initialized to null values
    210         CHARTSTYLE      cs;             // chart style: initialized to null values
    211 
    212         HBITMAP         hbmChart;       // chart bitmap (for quick painting)
    213         HRGN*           paRegions;      // pointer to array of GPI regions for each data item
    214 
    215         // user interaction data:
    216         LONG            lSelected;      // zero-based index of selected chart item, or -1 if none
    217         BOOL            fHasFocus;
    218     } CHARTCDATA, *PCHARTCDATA;
    219 
    220246    HBITMAP ctlCreateChartBitmap(HPS hpsMem,
    221247                                 LONG lcx,
     
    229255    BOOL ctlChartFromStatic(HWND hwndStatic);
    230256
    231     #define CHTM_SETCHARTDATA      WM_USER + 2
    232 
    233     #define CHTM_SETCHARTSTYLE     WM_USER + 3
    234 
    235     #define CHTM_ITEMFROMPOINT     WM_USER + 4
     257    #define CHTM_SETCHARTDATA      (WM_USER + 2)
     258
     259    #define CHTM_SETCHARTSTYLE     (WM_USER + 3)
     260
     261    #define CHTM_ITEMFROMPOINT     (WM_USER + 4)
     262
     263    #define CHTM_SETEMPHASIS       (WM_USER + 5)
     264
     265    // WM_CONTROL notification codes
     266
     267    /*
     268     *@@ CHTN_EMPHASISCHANGED:
     269     *      WM_CONTROL notification code sent (!)
     270     *      by a chart control to its owner when
     271     *      selections change in the control.
     272     *
     273     *      This is only sent if the CHS_SELECTIONS
     274     *      style bit is set in the control.
     275     *
     276     *      Parameters:
     277     *
     278     *      --  USHORT SHORT1FROMMP(mp1): usid (control ID).
     279     *      --  USHORT SHORT2FROMMP(mp1): CHTN_EMPHASISCHANGED.
     280     *
     281     *      --  mp2: pointer to EMPHASISNOTIFY structure.
     282     *
     283     *      Note: The control only sends one such notification,
     284     *      even if an old selection was undone. That is, if
     285     *      item 1 was previously selected and item 2 is then
     286     *      selected, only one notification for item 2 is sent.
     287     *
     288     *@@added V0.9.12 (2001-05-03) [umoeller]
     289     */
     290
     291    #define CHTN_EMPHASISCHANGED       1001
     292
     293    /*
     294     *@@ CHTN_CONTEXTMENU:
     295     *      WM_CONTROL notification code sent (!)
     296     *      by a chart control to its owner when
     297     *      a context menu was requested on the
     298     *      control.
     299     *
     300     *      This is only sent if the CHS_SELECTIONS
     301     *      style bit is set in the control.
     302     *
     303     *      Parameters:
     304     *
     305     *      --  USHORT SHORT1FROMMP(mp1): usid (control ID).
     306     *      --  USHORT SHORT2FROMMP(mp1): CHTN_EMPHASISCHANGED.
     307     *
     308     *      --  mp2: pointer to EMPHASISNOTIFY structure.
     309     *          If the context menu was requested on a chart
     310     *          slice, lIndex has the index of the slice.
     311     *          Otherwise (e.g. whitespace), lIndex will
     312     *          be -1.
     313     *
     314     *@@added V0.9.12 (2001-05-03) [umoeller]
     315     */
     316
     317    #define CHTN_CONTEXTMENU            1002
     318
     319    /*
     320     *@@ CHTN_ENTER:
     321     *      WM_CONTROL notification code sent (!)
     322     *      by a chart control to its owner when
     323     *      the user double-clicked on a data item.
     324     *
     325     *      This is only sent if the CHS_SELECTIONS
     326     *      style bit is set in the control.
     327     *
     328     *      Parameters:
     329     *
     330     *      --  USHORT SHORT1FROMMP(mp1): usid (control ID).
     331     *      --  USHORT SHORT2FROMMP(mp1): CHTN_ENTER.
     332     *
     333     *      --  mp2: pointer to EMPHASISNOTIFY structure.
     334     *          If the double click occured on a chart
     335     *          slice, lIndex has the index of the slice.
     336     *          Otherwise (e.g. whitespace), lIndex will
     337     *          be -1.
     338     *
     339     *@@added V0.9.12 (2001-05-03) [umoeller]
     340     */
     341
     342    #define CHTN_ENTER                  1003
     343
     344    /*
     345     *@@ EMPHASISNOTIFY:
     346     *      structure used with CHTN_EMPHASISCHANGED,
     347     *      CHTN_ENTER, and CHTN_CONTEXTMENU.
     348     *
     349     *@@added V0.9.12 (2001-05-03) [umoeller]
     350     */
     351
     352    typedef struct _EMPHASISNOTIFY
     353    {
     354        HWND    hwndSource;
     355                // window handle of the chart control
     356        ULONG   ulEmphasis;
     357                // with CHTN_EMPHASISCHANGED: emphasis which has changed
     358                // (0 for selection, 1 for source emphasis).
     359                // Otherwise undefined.
     360        LONG    lIndex;
     361                // with CHTN_EMPHASISCHANGED: index of the data
     362                // item for which emphasis has changed (counting
     363                // from 0); if -1, a previous emphasis has been undone.
     364                // With CHTN_CONTEXTMENU and CHTN_ENTER, index of the
     365                // data item for which the request occured, or -1 for
     366                // a request on the control's whitespace.
     367        POINTL  ptl;
     368                // exact window coordinates where mouse
     369                // click occured (e.g. for context menu).
     370                // This is undefined (-1) if the event was not
     371                // caused by a mouse click.
     372    } EMPHASISNOTIFY, *PEMPHASISNOTIFY;
    236373
    237374    /* ******************************************************************
  • trunk/include/helpers/prfh.h

    r41 r68  
    4848    #define PRFERR_KEY_EXISTS   10010
    4949
    50     PSZ prfhQueryKeysForApp(HINI hIni,
    51                             const char *pcszApp);
     50    APIRET prfhQueryKeysForApp(HINI hIni,
     51                               const char *pcszApp,
     52                               PSZ *ppszKeys);
    5253
    5354    #ifdef __XWPMEMDEBUG__ // setup.h, helpers\memdebug.c
     
    104105    VOID prfhQueryCountrySettings(PCOUNTRYSETTINGS pcs);
    105106
    106     ULONG prfhCopyKey(HINI hiniSource,
    107                       const char *pcszSourceApp,
    108                       const char *pcszKey,
    109                       HINI hiniTarget,
    110                       const char *pcszTargetApp);
     107    APIRET prfhCopyKey(HINI hiniSource,
     108                       const char *pcszSourceApp,
     109                       const char *pcszKey,
     110                       HINI hiniTarget,
     111                       const char *pcszTargetApp);
    111112
    112     ULONG prfhCopyApp(HINI hiniSource,
    113                       const char *pcszSourceApp,
    114                       HINI hiniTarget,
    115                       const char *pcszTargetApp,
    116                       PSZ pszErrorKey);
     113    APIRET prfhCopyApp(HINI hiniSource,
     114                       const char *pcszSourceApp,
     115                       HINI hiniTarget,
     116                       const char *pcszTargetApp,
     117                       PSZ pszErrorKey);
    117118
    118119    ULONG prfhRenameKey(HINI hini,
  • trunk/src/helpers/cctl_chart.c

    r63 r68  
    22/*
    33 *@@sourcefile cctl_chart.c:
    4  *      implementation for the "chart" common control.
    5  *      See comctl.c for an overview.
     4 *      implementation for the "chart" common control, which can
     5 *      represent an array of "double" values as either a pie chart
     6 *      or a bar chart. Selections of chart slices and owner
     7 *      notifications are also supported.
    68 *
    79 *      This has been extracted from comctl.c with V0.9.3 (2000-05-21) [umoeller].
     10 *
     11 *      The "chart" common control presently is a subclassed static
     12 *      text control. This way you can easily create a chart control
     13 *      as a static control in any Dialog Editor; after loading the
     14 *      dlg template, simply call ctlChartFromStatic with the hwnd
     15 *      of the static control to make it a chart.
     16 *
     17 *      Note: even though you can use _any_ type of static control
     18 *      with this function, you should use a static _text_ control,
     19 *      because not all types of static controls react to fonts and
     20 *      colors dragged upon them. The static _text_ control does.
     21 *
     22 *      The pie chart consumes all available space in the static control.
     23 *
     24 *      In XWorkplace, this is used for the pie chart on the new
     25 *      XFldDisk "Details" settings page to display the free space
     26 *      on a certain drive.
     27 *
     28 *      <B>Chart data:</B>
     29 *
     30 *      The pie chart control operates on an array of "double" values.
     31 *      Each value in that array corresponds to a color in a second
     32 *      array of (LONG) RGB values and, if description texts are
     33 *      enabled, to a third array of PSZ's with description texts.
     34 *      In each of the three arrays, the array item count must be
     35 *      the same, naturally.
     36 *
     37 *      The data on which the pie chart operates is initialized to
     38 *      be void, so that the pie chart will not paint anything
     39 *      initially. In order to have the pie chart display something,
     40 *      send a CHTM_SETCHARTDATA message (comctl.h) to the static
     41 *      control after it has been subclassed.
     42 *
     43 *      CHTM_SETCHARTDATA takes a CHARTDATA structure (comctl.h) in mp1,
     44 *      which must contain the three arrays with the chart data, colors,
     45 *      and descriptive texts to be displayed.
     46 *
     47 *      The chart data will automatically compute the sum of all values
     48 *      so that each data item will be displayed as a fraction of the
     49 *      total chart control size, proportionally to the item's value
     50 *      against the sum of all values. In other words,
     51 *
     52 +          (dValue / dTotal) == (sizeSlize / sizeTotal).
     53 *
     54 *      The display depends on whether the chart control operates in
     55 *      "pie chart" or "bar chart" mode.
     56 *
     57 *      --  In "pie chart" mode, data items are displayed as slices of
     58 *          a pie chart. The total sum of the "double" values will
     59 *          represent the angle in CHARTDATA.usSweepAngle.
     60 *
     61 *          For example, if two values of 50 and 100 are passed to the
     62 *          control and usSweepAngle is 270 (i.e. a three-quarter pie),
     63 *          the chart control will calculate the following:
     64 *
     65 *          1)  The sum of the data is 150.
     66 *
     67 *          2)  The first sub-arc will span an angle of 270 * (50/150)
     68 *              = 90 degrees.
     69 *
     70 *          3)  The second sub-arc will span an angle of 270 * (100/150)
     71 *              = 180 degrees.
     72 *
     73 *          You can also have descriptions displayed along the different
     74 *          chart items by specifying CHARTDATA.papszDescriptions and
     75 *          setting the CHS_DESCRIPTIONS flag (below).
     76 *
     77 *      --  In "bar chart" mode, the angle values make no sense and
     78 *          are therefore ignored. In "bar chart" mode, the chart will
     79 *          be drawn as a simple rectangle, with subrectangles representing
     80 *          the chart slices.
     81 *
     82 *      <B>Chart styles:</B>
     83 *
     84 *      Use CHTM_SETCHARTSTYLE with a PCHARTSTYLE (comctl.h) in mp1.
     85 *      This can be sent to the chart control several times.
     86 *
     87 *      Set either CHS_PIECHART or CHS_BARCHART to switch the control
     88 *      to "pie chart" or "bar chart" mode, respectively.
     89 *
     90 *      For pie charts, there are several "display sub-styles":
     91 *
     92 *      -- CHS_3D_BRIGHT: paint a "3D" socket below the actual chart.
     93 *
     94 *      -- CHS_3D_DARKEN: like CHS_3D_BRIGHT, but the socket will be made
     95 *                        darker compared to the surface.
     96 *
     97 *      General styles (for all modes):
     98 *
     99 *      -- CHS_DESCRIPTIONS: show descriptions on the chart
     100 *                           (CHARTDATA.papszDescriptions data).
     101 *
     102 *      -- CHS_SELECTIONS: allow pie chart slices to be selectable,
     103 *                         using the mouse and the keyboard (see below).
     104 *
     105 *      <B>Display:</B>
     106 *
     107 *      The chart control creates an internal bitmap for the display
     108 *      only once (ctlCreateChartBitmap). This bitmap is refreshed if
     109 *      neccessary, e.g. because chart data or styles have changed.
     110 *
     111 *      The chart control uses presentation parameters, as listed below.
     112 *      Presentation parameters are inherited from the parent window.
     113 *      If a presparam is not set, the corresponding system color is
     114 *      used. The following color pairs are recognized:
     115 *
     116 *      --  PP_BACKGROUNDCOLOR / SYSCLR_DIALOGBACKGROUND:
     117 *          background of the chart control (outside the chart).
     118 *
     119 *      --  PP_FOREGROUNDCOLOR / SYSCLR_WINDOWTEXT:
     120 *          text color, if description texts are enabled and valid.
     121 *
     122 *      --  PP_FONTNAMESIZE:
     123 *          text font, if description texts are enabled and valid.
     124 *          If this presparam is not set, the system font is used.
     125 *
     126 *      The control reacts to fonts and colors dropped upon it, if
     127 *      it has been subclassed from a static _text_ control (see above).
     128 *      It also recalculates the bitmap when it's resized.
     129 *
     130 *      <B>Example usage:</B>
     131 *
     132 +          // get static control:
     133 +          HWND    hwndChart = WinWindowFromID(hwndDialog, ID_...);
     134 +          CHARTSTYLE      cs;
     135 +          CHARTDATA       cd;
     136 +          // define data:
     137 +          double          adData[3] = { 100, 200, 300 };
     138 +          // define corresponding colors:
     139 +          LONG            alColors[3] = { 0x800000, 0x008000, 0x000080 };
     140 +          // define correspdonding descriptions:
     141 +          PSZ             apszDescriptions[3] = { "item 1", "item 3", "item 3" };
     142 +
     143 +          ctlChartFromStatic(hwndChart);     // create chart
     144 +
     145 +          cs.ulStyle = CHS_3D_DARKEN | CHS_DESCRIPTIONS;
     146 +          cs.ulThickness = 20;
     147 +          cs.dPieSize = .8;           // use 80% of control size
     148 +          cs.dDescriptions = .5       // draw descriptions at 50% from center
     149 +          WinSendMsg(hwndChart, CHTM_SETCHARTSTYLE, &cs, NULL);
     150 +
     151 +          cd.usStartAngle = 15;       // start at 15ø from right
     152 +          cd.usSweepAngle = 270;      // three-quarter pie (for the sum of the
     153 +                                      // above values: 100+200+300 = 600)
     154 +          cd.cValues = 3;             // array count
     155 +          cd.padValues = &adData[0];
     156 +          cd.palColors = &alColors[0];
     157 +          cd.papszDescriptions = &apszDescriptions[0];
     158 +          WinSendMsg(hwndChart, CHTM_SETCHARTDATA, &cd, NULL);
    8159 *
    9160 *      Note: Version numbering in this file relates to XWorkplace version
     
    86237/* ******************************************************************
    87238 *
     239 *   Private declarations
     240 *
     241 ********************************************************************/
     242
     243/*
     244 *@@ CHARTCDATA:
     245 *      pie chart control data. Composed from the various
     246 *      chart initialization data.
     247 *      Stored in QWL_USER of the subclassed static control.
     248 *      Not available to the application.
     249 */
     250
     251typedef struct _CHARTCDATA
     252{
     253    // data which is initialized upon creation:
     254    PFNWP           OldStaticProc;  // old static window procedure (from WinSubclassWindow)
     255
     256    // data which is initialized upon CHTM_SETCHARTDATA/CHTM_SETCHARTSTYLE:
     257    HDC             hdcMem;         // memory device context for bitmap
     258    HPS             hpsMem;         // memory presentation space for bitmap
     259    CHARTDATA       cd;             // chart data: initialized to null values
     260    CHARTSTYLE      cs;             // chart style: initialized to null values
     261
     262    HBITMAP         hbmChart;       // chart bitmap (for quick painting)
     263    HRGN*           paRegions;      // pointer to array of GPI regions for each data item
     264
     265    // user interaction data:
     266    LONG            lSelected;      // zero-based index of selected chart item, or -1 if none
     267    LONG            lSourceEmphasis;    // zero-based index of item with source emphysis, or -1 if none
     268    BOOL            fHasFocus;
     269} CHARTCDATA, *PCHARTCDATA;
     270
     271/* ******************************************************************
     272 *
    88273 *   Chart Control
    89274 *
    90275 ********************************************************************/
     276
     277/*
     278 *@@ DrawCenteredText:
     279 *
     280 *@@added V0.9.12 (2001-05-03) [umoeller]
     281 */
     282
     283VOID DrawCenteredText(HPS hpsMem,
     284                      PPOINTL pptlMiddlePoint,
     285                      const char *pcsz)
     286{
     287    if (pcsz)
     288    {
     289        PSZ psz = strdup(pcsz),
     290            p2 = psz;
     291        if (psz)
     292        {
     293            ULONG cLineBreaks = 0;
     294            LONG lLineSpacing = 0;
     295
     296            POINTL ptl;
     297            memcpy(&ptl, pptlMiddlePoint, sizeof(ptl));
     298
     299            // count how many lines we have
     300            while (p2 = strchr(p2, '\n'))
     301            {
     302                cLineBreaks++;
     303                p2++;
     304            }
     305
     306            if (cLineBreaks)
     307            {
     308                // if we have more than one line:
     309                lLineSpacing = gpihQueryLineSpacing(hpsMem);
     310
     311                // center vertically
     312                ptl.y += (lLineSpacing * cLineBreaks) / 2;
     313            }
     314
     315            p2 = psz;
     316            while (TRUE)
     317            {
     318                PSZ pNext = strchr(p2, '\n');
     319                if (pNext)
     320                {
     321                    *pNext = '\0';
     322                    pNext++;
     323                }
     324
     325                GpiCharStringAt(hpsMem,
     326                                &ptl,
     327                                strlen(p2),
     328                                (PSZ)p2);
     329
     330                if (pNext)
     331                {
     332                    p2 = pNext;
     333                    ptl.y -= lLineSpacing;
     334                }
     335                else
     336                    break;
     337            }
     338
     339            free(psz);
     340        }
     341    }
     342}
     343
     344/*
     345 *@@ PaintBarChart:
     346 *      paint implementation for the "bar chart".
     347 *
     348 *      This gets called from ctlCreateChartBitmap if the
     349 *      current style for the chart control is the "bar
     350 *      chart" style.
     351 *
     352 *@@added V0.9.12 (2001-05-03) [umoeller]
     353 *@@changed V0.9.12 (2001-05-03) [umoeller]: fixed another maaajor PM resource leak with regions
     354 */
     355
     356VOID PaintBarChart(HPS hpsMem,
     357                   PRECTL prclWholeStatic,    // in: rectl to paint into
     358                   PCHARTDATA pChartData,     // in: chart data
     359                   PCHARTSTYLE pChartStyle,   // in: chart style
     360                   double dTotal,             // in: sum of all values in pChartData
     361                   LONG lTextColor,           // in: description text color (RGB)
     362                   HRGN* paRegions)           // out: GPI regions for each data item
     363{
     364    ULONG       ulYBottomNow = 0;
     365    ULONG       ul;
     366
     367    PLONG       plColorThis;
     368    PSZ         *ppszDescriptionThis = NULL;
     369    HRGN        *phRegionThis;
     370    double      *pdValueThis;
     371
     372    // allocate array for storing text positions later
     373    PPOINTL     paptlDescriptions = (PPOINTL)malloc(sizeof(POINTL)
     374                                                    * pChartData->cValues);
     375
     376    RECTL       rclPaint;
     377
     378    POINTL      ptlLowerLeft,
     379                ptlUpperRight;
     380
     381    // thickness of line separators for CHS_DRAWLINES
     382    // V0.9.12 (2001-05-03) [umoeller]
     383    const SIZEL cszlDrawLines = {1, 1};
     384
     385    // calculate rectangle;
     386    // this is the size of the static control
     387    // minus the "3D thickness", if enabled
     388    memcpy(&rclPaint, prclWholeStatic, sizeof(RECTL));
     389    if (pChartStyle->ulStyle & CHS_3D_BRIGHT)
     390            // this includes CHS_3D_DARKEN
     391    {
     392        rclPaint.yBottom = prclWholeStatic->yBottom
     393                                    + ulYBottomNow;
     394        rclPaint.yTop = prclWholeStatic->yTop
     395                                    - pChartStyle->ulThickness
     396                                    + ulYBottomNow;
     397    }
     398
     399    // c)  Strangely, GpiSetPattern does work,
     400    //     while GpiSetColor doesn't (see below).
     401    GpiSetPattern(hpsMem, PATSYM_SOLID);
     402
     403    // initialize per-item data pointers for
     404    // loop below
     405    pdValueThis = pChartData->padValues;
     406    plColorThis = pChartData->palColors;
     407    ppszDescriptionThis = pChartData->papszDescriptions;
     408    phRegionThis = paRegions;
     409
     410    // initialize corners
     411    ptlLowerLeft.x = 0;
     412    ptlLowerLeft.y = 0;
     413    ptlUpperRight.x = 0;
     414    ptlUpperRight.y = rclPaint.yTop;
     415
     416    // inner "slice loop":
     417    // this loop goes over the data pointers
     418    // and paints accordingly. At the end of
     419    // the loop, we'll advance all those pointers.
     420    for (ul = 0;
     421         ul < pChartData->cValues;
     422         ul++)
     423    {
     424        HRGN        hrgnThis;
     425        SHORT       sSweepAngle,
     426                    sStartAngle;
     427
     428        GpiSetCurrentPosition(hpsMem, &ptlLowerLeft);
     429
     430        _Pmpf((__FUNCTION__ ": ptlLowerLeft.x = %d", ptlLowerLeft.x));
     431
     432        // calc upper right from data values
     433        ptlUpperRight.x += (ULONG)(   (double)rclPaint.xRight
     434                                    * (*pdValueThis)
     435                                    / dTotal);
     436
     437        // set the area (fill) color
     438        GpiSetColor(hpsMem,
     439                    *plColorThis);
     440
     441        // now draw the slice;
     442        // we could use an area, but since we need
     443        // to remember the coordinates of the slice
     444        // for mouse click handling, we require a
     445        // region. But areas cannot be converted
     446        // to regions, so we use a path instead.
     447        GpiBeginPath(hpsMem,
     448                     1);    // path ID, must be 1
     449
     450        GpiBox(hpsMem,
     451               DRO_OUTLINE,
     452               &ptlUpperRight,
     453               0, 0);       // no rounding
     454
     455        GpiEndPath(hpsMem);
     456
     457        // convert the path to a region;
     458        // we'll need the region for mouse hit testing later
     459        hrgnThis = GpiPathToRegion(hpsMem,
     460                                   1,
     461                                   FPATH_ALTERNATE);
     462            // after this, the path is deleted
     463
     464        // now, this FINALLY paints the slice
     465        GpiPaintRegion(hpsMem, hrgnThis);
     466
     467        // now paint descriptions
     468        if (pChartStyle->ulStyle & CHS_DESCRIPTIONS)
     469        {
     470            // description strings valid?
     471            if (ppszDescriptionThis)
     472            {
     473                POINTL  ptlMiddlePoint;
     474
     475                // set presentation color
     476                GpiSetColor(hpsMem, lTextColor);
     477
     478                // set text aligment to centered
     479                // both horizontally and vertically;
     480                // this affects subsequent GpiCharStringAt
     481                // calls in that the output text will
     482                // be centered around the specified
     483                // point
     484                GpiSetTextAlignment(hpsMem,
     485                                    TA_CENTER,      // horizontally
     486                                    TA_HALF);       // center vertically
     487
     488
     489
     490                // center the text in the box
     491                ptlMiddlePoint.x =   ptlLowerLeft.x
     492                                   + (ptlUpperRight.x - ptlLowerLeft.x) / 2;
     493                ptlMiddlePoint.y =   ptlLowerLeft.y
     494                                   + (ptlUpperRight.y - ptlLowerLeft.y) / 2;
     495
     496                // FINALLY, draw the description
     497                // at this point; since we have used
     498                // GpiSetTextAlignment above, the
     499                // text will be centered on exactly
     500                // that point
     501                DrawCenteredText(hpsMem,
     502                                 &ptlMiddlePoint,
     503                                 *ppszDescriptionThis);
     504
     505            } // end if (ppszDescriptionThis)
     506        } // end if (pChartStyle->ulStyle & CHS_DESCRIPTIONS)
     507
     508        // last run (are we painting the top now)?
     509        if (    // if separator lines are enabled,
     510                // draw a frame around the thing
     511                (pChartStyle->ulStyle & CHS_DRAWLINES)
     512           )
     513        {
     514            GpiSetColor(hpsMem, lTextColor);
     515            GpiFrameRegion(hpsMem,
     516                           hrgnThis,
     517                           (PSIZEL)&cszlDrawLines);      // always (1, 1)
     518        }
     519
     520        if (    phRegionThis
     521           )
     522            // region output requested by caller:
     523            // store region, the caller will clean this up
     524            *phRegionThis = hrgnThis;
     525        else
     526            // no region output requested: destroy region
     527            GpiDestroyRegion(hpsMem, hrgnThis);
     528
     529        // use the "right" xpos we had now as the "left"
     530        // xpos for the next loop
     531        ptlLowerLeft.x = ptlUpperRight.x;
     532
     533        // advance the data pointers
     534        pdValueThis++;
     535        plColorThis++;
     536        if (ppszDescriptionThis)
     537            ppszDescriptionThis++;
     538        if (phRegionThis)
     539            phRegionThis++;
     540    } // end for (ul...)
     541
     542    // cleanup
     543    free(paptlDescriptions);
     544}
     545
     546/*
     547 *@@ PaintPieChart:
     548 *      paint implementation for the "pie chart".
     549 *
     550 *      This gets called from ctlCreateChartBitmap if the
     551 *      current style for the chart control is the "pie
     552 *      chart" style.
     553 *
     554 *@@added V0.9.12 (2001-05-03) [umoeller]
     555 *@@changed V0.9.12 (2001-05-03) [umoeller]: fixed another maaajor PM resource leak with regions
     556 *@@changed V0.9.12 (2001-05-03) [umoeller]: fixed rounding errors
     557 */
     558
     559VOID PaintPieChart(HPS hpsMem,
     560                   PRECTL prclWholeStatic,    // in: rectl to paint into
     561                   PCHARTDATA pChartData,     // in: chart data
     562                   PCHARTSTYLE pChartStyle,   // in: chart style
     563                   double dTotal,             // in: sum of all values in pChartData
     564                   LONG lTextColor,           // in: description text color (RGB)
     565                   HRGN* paRegions)           // out: GPI regions for each data item
     566{
     567    ULONG       ulYBottomNow = 0;
     568    ULONG       ul;
     569
     570    // allocate array for storing text positions later
     571    PPOINTL     paptlDescriptions = (PPOINTL)malloc(sizeof(POINTL)
     572                                                    * pChartData->cValues);
     573    POINTL      ptlCenter;
     574
     575    FIXED       fxPieSize = (LONG)(pChartStyle->dPieSize * 65536),
     576                fxDescriptions = (LONG)(pChartStyle->dDescriptions * 65536);
     577
     578    // We'll paint into the bitmap in two loops:
     579    // +--  The outer "3D" loop is executed
     580    // |    pChartStyle->ulThickness-fold, if
     581    // |    CHS_3Dxxx has been enabled; otherwise
     582    // |    just once.
     583    // |
     584    // |    +-- The inner "slice" loop goes thru the
     585    // |        data fields in pChartData and draws
     586    // |        the pies accordingly.
     587    // |
     588    // +--  We then increase the base Y point (ulYBottomNow)
     589    //      by one and draw again, thereby getting the 3D
     590    //      effect.
     591
     592    // 1) outer 3D loop
     593    do // while (   (pChartStyle->ulStyle & CHS_3D_BRIGHT)...
     594    {
     595        RECTL       rclArc;
     596        PLONG       plColorThis;
     597        PSZ         *ppszDescriptionThis = NULL;
     598        PPOINTL     pptlDescriptionThis;
     599        HRGN        *phRegionThis;
     600        double      *pdValueThis;
     601
     602        ARCPARAMS   ap;
     603        AREABUNDLE  ab;
     604
     605        double      dStartAngle = pChartData->usStartAngle,
     606                    dSweepAngle = 0;
     607
     608        // thickness of line separators for CHS_DRAWLINES
     609        // V0.9.12 (2001-05-03) [umoeller]
     610        const SIZEL cszlDrawLines = {1, 1};
     611
     612        // this is only TRUE for the last loop
     613        BOOL        fNowDrawingSurface =
     614                      (
     615                           ((pChartStyle->ulStyle & CHS_3D_BRIGHT) == 0)
     616                        ||
     617                           (ulYBottomNow == pChartStyle->ulThickness - 1)
     618                      );
     619
     620        // // _Pmpf(("Looping, ulYBottomNow: %d", ulYBottomNow));
     621
     622        // calculate pie rectangle for this loop;
     623        // this is the size of the static control
     624        // minus the "3D thickness", if enabled
     625        memcpy(&rclArc, prclWholeStatic, sizeof(RECTL));
     626        if (pChartStyle->ulStyle & CHS_3D_BRIGHT)
     627                // this includes CHS_3D_DARKEN
     628        {
     629            rclArc.yBottom = prclWholeStatic->yBottom
     630                                        + ulYBottomNow;
     631            rclArc.yTop = prclWholeStatic->yTop
     632                                        - pChartStyle->ulThickness
     633                                        + ulYBottomNow;
     634        }
     635
     636        // calculate center point
     637        ptlCenter.x = rclArc.xRight / 2;
     638        ptlCenter.y = ((rclArc.yTop - rclArc.yBottom) / 2) + ulYBottomNow;
     639
     640        // Now, the "arc" APIs really suck. The following
     641        // has cost me hours of testing to find out:
     642
     643        // a) The arc functions expect some kind of
     644        //    "default arc" to be defined, which they
     645        //    refer to. We define the arc as elliptical;
     646        //    this will be used as the "current arc"
     647        //    for subsequent arc calls.
     648        //    (P, S) and (R, Q) define the end points
     649        //    of the major axes of the ellipse.
     650        //    The center of the arc will later be
     651        //    specified with GpiPartialArc (while GpiFullArc
     652        //    uses the current pen position...
     653        //    Who created these APIs?!? This might be a most
     654        //    flexible way to do things, but where's the
     655        //    simple stuff?!?)
     656        ap.lP = ptlCenter.x;        // X-axis X
     657        ap.lS = 0;                  // X-axis Y
     658        ap.lR = 0;                  // Y-axis X
     659        ap.lQ = ((rclArc.yTop - rclArc.yBottom) / 2);
     660                                    // Y-axis Y
     661        GpiSetArcParams(hpsMem, &ap);
     662
     663        // b)  The line primitives determine lines
     664        //     to be drawn around the pie slices.
     665        //     We don't want any.
     666        GpiSetLineType(hpsMem, LINETYPE_INVISIBLE);
     667
     668        // c)  Strangely, GpiSetPattern does work,
     669        //     while GpiSetColor doesn't (see below).
     670        GpiSetPattern(hpsMem, PATSYM_SOLID);
     671
     672        // initialize per-item data pointers for
     673        // loop below
     674        pdValueThis = pChartData->padValues;
     675        plColorThis = pChartData->palColors;
     676        ppszDescriptionThis = pChartData->papszDescriptions;
     677        pptlDescriptionThis = paptlDescriptions;
     678        phRegionThis = paRegions;
     679
     680        // 2) inner "pie slice loop":
     681        // this loop goes over the data pointers
     682        // and paints accordingly. At the end of
     683        // the loop, we'll advance all those pointers.
     684        for (ul = 0;
     685             ul < pChartData->cValues;
     686             ul++)
     687        {
     688            HRGN        hrgnThis;
     689            double      dSweepAngleRounded,
     690                        dStartAngleRounded;
     691
     692            // calculate the angle to sweep to:
     693            // a simple rule of three
     694            dSweepAngle = *pdValueThis      // current data pointer
     695                          * (double)pChartData->usSweepAngle
     696                                            // maximum angle
     697                          / dTotal;         // total data sum
     698
     699            // d)  And now comes the real fun part.
     700            //     GpiPartialArc is too dumb to draw
     701            //     anything on its own, it must _always_
     702            //     appear within an area or path definition.
     703            //     Unfortunately, this isn't really said
     704            //     clearly anywhere.
     705            //     Even worse, in order to set the color
     706            //     with which the slice is to be drawn,
     707            //     one has to define an AREABUNDLE because
     708            //     the regular GpiSetColor functions don't
     709            //     seem to work here. Or maybe it's my fault,
     710            //     but with this awful documentation, who knows.
     711
     712            //     We set the current color in the AREABUNDLE
     713            //     from the color which was defined in the
     714            //     pie chart data (this pointer was set above
     715            //     and will be advanced for the next slice).
     716            ab.lColor = *plColorThis;
     717
     718            // "3D mode" enabled with darkened socket?
     719            if (    (pChartStyle->ulStyle & CHS_3D_DARKEN)
     720                    // not last loop?
     721                 && (!fNowDrawingSurface)
     722               )
     723                // darken the current fill color
     724                // by halving each color component
     725                gpihManipulateRGB(&ab.lColor,
     726                                  .5);       // factor
     727
     728            // set the area (fill) color
     729            GpiSetAttrs(hpsMem,
     730                        PRIM_AREA,
     731                        ABB_COLOR,
     732                        0,
     733                        (PBUNDLE)&ab);
     734
     735            GpiSetCurrentPosition(hpsMem, &ptlCenter);
     736
     737            // round the angle values properly
     738            dStartAngleRounded = (dStartAngle + .5);
     739            dSweepAngleRounded = (dSweepAngle + .5);
     740
     741            // now draw the pie slice;
     742            // we could use an area, but since we need
     743            // to remember the coordinates of the slice
     744            // for mouse click handling, we require a
     745            // region. But areas cannot be converted
     746            // to regions, so we use a path instead.
     747            GpiBeginPath(hpsMem,
     748                         1);    // path ID, must be 1
     749
     750            // note that the arc functions use the FIXED type
     751            // for representing fractions... GPI was written back
     752            // at the days when coprocessors were a luxury, so
     753            // a floating point value is represented by a LONG
     754            // with the hiword containing the rounded integer
     755            // and the loword the remaining fraction. So we
     756            // can simply multiply the "double" by 65536, and
     757            // we get the FIXED value V0.9.12 (2001-05-03) [umoeller]
     758            GpiPartialArc(hpsMem,
     759                          &ptlCenter,
     760                          fxPieSize,    // calculated from CHARTSTYLE
     761                          (FIXED)(dStartAngleRounded * (double)65536),
     762                          (FIXED)(dSweepAngleRounded * (double)65536));
     763                // this moves the current position to the outer
     764                // point on the ellipse which corresponds to
     765                // sSweepAngle
     766            GpiEndPath(hpsMem);
     767
     768            // convert the path to a region;
     769            // we'll need the region for mouse hit testing later
     770            hrgnThis = GpiPathToRegion(hpsMem, 1,
     771                                       FPATH_ALTERNATE);
     772                // after this, the path is deleted
     773
     774            // last run (are we painting the top now)?
     775            if (    (fNowDrawingSurface)
     776                    // descriptions enabled?
     777                 && (ppszDescriptionThis)
     778                 && (*ppszDescriptionThis)
     779               )
     780            {
     781                // yes: calculate position to paint
     782                // text at later (we can't do this now,
     783                // because it might be overpainted by
     784                // the next arc again)
     785
     786                GpiSetCurrentPosition(hpsMem, &ptlCenter);
     787                // move the current position to
     788                // the center outer point on the ellipse
     789                // (in between sStartAngle and sSweepAngle);
     790                // since we're outside an area, this will not
     791                // paint anything
     792                GpiPartialArc(hpsMem,
     793                              &ptlCenter,
     794                              fxDescriptions, // calculated from CHARTSTYLE
     795                              (FIXED)(dStartAngleRounded * (double)65536),
     796                              // only half the sweep now:
     797                              (FIXED)((dSweepAngleRounded / 2) * (double)65536));
     798
     799                // store this outer point in the array
     800                // of description coordinates for later
     801                GpiQueryCurrentPosition(hpsMem, pptlDescriptionThis);
     802
     803                _Pmpf(("pptlDescriptionThis = %d, %d",
     804                            pptlDescriptionThis->x,
     805                            pptlDescriptionThis->y));
     806            }
     807
     808            // now, this FINALLY paints the arc
     809            GpiPaintRegion(hpsMem, hrgnThis);
     810
     811            // last run (are we painting the top now)?
     812            if (    (fNowDrawingSurface)
     813                    // if separator lines are enabled,
     814                    // draw a frame around the thing
     815                 && (pChartStyle->ulStyle & CHS_DRAWLINES)
     816               )
     817            {
     818                GpiSetColor(hpsMem, lTextColor);
     819                GpiFrameRegion(hpsMem,
     820                               hrgnThis,
     821                               (PSIZEL)&cszlDrawLines);      // always (1, 1)
     822            }
     823
     824            if (    phRegionThis
     825                 && fNowDrawingSurface      // this was missing
     826                                            // V0.9.12 (2001-05-03) [umoeller]
     827                                            // this created tons of regions which
     828                                            // were never deleted
     829               )
     830                // region output requested by caller:
     831                // store region, the caller will clean this up
     832                *phRegionThis = hrgnThis;
     833            else
     834                // no region output requested: destroy region
     835                GpiDestroyRegion(hpsMem, hrgnThis);
     836
     837            // increase the start angle by the sweep angle for next loop
     838            dStartAngle += dSweepAngle;
     839
     840            // advance the data pointers
     841            pdValueThis++;
     842            plColorThis++;
     843            if (ppszDescriptionThis)
     844                ppszDescriptionThis++;
     845            pptlDescriptionThis++;
     846            if (phRegionThis)
     847                phRegionThis++;
     848        } // end for (ul...)
     849
     850        // go for next "3D thickness" iteration
     851        ulYBottomNow++;
     852    } while (   (pChartStyle->ulStyle & CHS_3D_BRIGHT)
     853             && (ulYBottomNow < pChartStyle->ulThickness)
     854            );
     855
     856    // now paint descriptions
     857    if (pChartStyle->ulStyle & CHS_DESCRIPTIONS)
     858    {
     859        // we use two pointers during the iteration,
     860        // which point to the item corresponding
     861        // to the current data item:
     862        // 1)  pointer to center point on outer border
     863        //     of partial arc
     864        //     (calculated above)
     865        PPOINTL     pptlDescriptionThis = paptlDescriptions;
     866        // 2)  pointer to current description string
     867        PSZ*        ppszDescriptionThis = pChartData->papszDescriptions;
     868
     869        // description strings valid?
     870        if (ppszDescriptionThis)
     871        {
     872            // set presentation color
     873            GpiSetColor(hpsMem, lTextColor);
     874
     875            // set text aligment to centered
     876            // both horizontally and vertically;
     877            // this affects subsequent GpiCharStringAt
     878            // calls in that the output text will
     879            // be centered around the specified
     880            // point
     881            GpiSetTextAlignment(hpsMem,
     882                                TA_CENTER,      // horizontally
     883                                TA_HALF);       // center vertically
     884
     885            // loop thru data items
     886            for (ul = 0;
     887                 ul < pChartData->cValues;
     888                 ul++)
     889            {
     890                POINTL  ptlMiddlePoint;
     891
     892                // when drawing the arcs above, we have,
     893                // for each pie slice, stored the middle
     894                // point on the outer edge of the ellipse
     895                // in the paptlDescriptions POINTL array:
     896
     897                //                ++++
     898                //                +    +
     899                //                +      +
     900                //    ptlCenter\  +       +
     901                //              \ +        + <-- current partial arc
     902                //               \+        +
     903                //     +++++++++++X        +
     904                //     +                   +
     905                //      +                  +
     906                //       +               XX  <-- point calculated above
     907                //        +             +
     908                //           +        +
     909                //             ++++++
     910
     911                // now calculate a middle point between
     912                // that outer point on the ellipse and
     913                // the center of the ellipse, which will
     914                // be the center point for the text
     915
     916                //                ++++
     917                //                +    +
     918                //                +      +
     919                //    ptlCenter\  +       +
     920                //              \ +        + <-- current partial arc
     921                //               \+        +
     922                //     ++++++++++++        +
     923                //     +             XX    + <-- new middle point
     924                //      +                  +
     925                //       +               XX  <-- point calculated above
     926                //        +             +
     927                //           +        +
     928                //             ++++++
     929
     930                ptlMiddlePoint.x =
     931                        ptlCenter.x
     932                        + ((pptlDescriptionThis->x - ptlCenter.x) * 2 / 3);
     933                ptlMiddlePoint.y =
     934                        ptlCenter.y
     935                        - (ptlCenter.y - pptlDescriptionThis->y) * 2 / 3;
     936
     937                // FINALLY, draw the description
     938                // at this point; since we have used
     939                // GpiSetTextAlignment above, the
     940                // text will be centered on exactly
     941                // that point
     942                DrawCenteredText(hpsMem,
     943                                 &ptlMiddlePoint,
     944                                 *ppszDescriptionThis);
     945
     946                pptlDescriptionThis++;
     947                ppszDescriptionThis++;
     948            } // end for (ul = 0; ul < pChartData->cValues; ul++)
     949        } // end if (ppszDescriptionThis)
     950    } // end if (pChartStyle->ulStyle & CHS_DESCRIPTIONS)
     951
     952    // cleanup
     953    free(paptlDescriptions);
     954}
    91955
    92956/*
     
    119983 *
    120984 *      If (paRegions != NULL), this function will
    121  *      create GPI regions for data item. Each GPI
     985 *      create a GPI region for each data item. Each GPI
    122986 *      region will then contain the outline of the
    123987 *      corresponding pie chart slice. This allows
     
    1371001 *      This returns NULLHANDLE if an error occured.
    1381002 *      This can mean the following:
     1003 *
    1391004 *      --  The data is invalid, because the total is 0.
     1005 *
    1401006 *      --  The bitmap could not be created (memory?).
     1007 *
     1008 *@@changed V0.9.12 (2001-05-03) [umoeller]: extracted PaintPieChart
     1009 *@@changed V0.9.12 (2001-05-03) [umoeller]: added bar chart style
    1411010 */
    1421011
     
    1581027    for (ul = 0; ul < pChartData->cValues; ul++)
    1591028    {
     1029        _Pmpf(("    dThis is %d", (ULONG)(*pdThis))); // printf
     1030
    1601031        dTotal += *pdThis;
    1611032        pdThis++;
    1621033    }
     1034
     1035    _Pmpf((__FUNCTION__ ": dTotal is %d", (ULONG)dTotal)); // printf
    1631036
    1641037    // avoid division by zero
     
    1661039    {
    1671040        RECTL       rclWholeStatic;
    168         ULONG       ulYBottomNow = 0;
    169 
    1701041        // get window rectangle (bottom left is 0, 0)
    1711042        rclWholeStatic.xLeft = 0;
     
    1811052            // successfully created:
    1821053
    183             // allocate array for storing text positions later
    184             PPOINTL     paptlDescriptions = (PPOINTL)malloc(sizeof(POINTL)
    185                                                             * pChartData->cValues);
    186             POINTL      ptlCenter;
    187 
    188             FIXED       fxPieSize = (LONG)(pChartStyle->dPieSize * 65536),
    189                         fxDescriptions = (LONG)(pChartStyle->dDescriptions * 65536);
    190 
    1911054            // associate bitmap with memory PS
    1921055            GpiSetBitmap(hpsMem, hbmReturn);
     
    2011064                    &rclWholeStatic);
    2021065
    203             // We'll paint into the bitmap in two loops:
    204             // +--  The outer "3D" loop is executed
    205             // |    pChartStyle->ulThickness-fold, if
    206             // |    CHS_3Dxxx has been enabled; otherwise
    207             // |    just once.
    208             // |
    209             // |    +-- The inner "slice" loop goes thru the
    210             // |        data fields in pChartData and draws
    211             // |        the pies accordingly.
    212             // |
    213             // +--  We then increase the base Y point (ulYBottomNow)
    214             //      by one and draw again, thereby getting the 3D
    215             //      effect.
    216 
    217             // 1) outer 3D loop
    218             do // while (   (pChartStyle->ulStyle & CHS_3D_BRIGHT)...
    219             {
    220                 RECTL       rclArc;
    221                 PLONG       plColorThis;
    222                 PSZ         *ppszDescriptionThis = NULL;
    223                 PPOINTL     pptlDescriptionThis;
    224                 HRGN*       phRegionThis;
    225 
    226                 ARCPARAMS   ap;
    227                 AREABUNDLE  ab;
    228 
    229                 double      dStartAngle = pChartData->usStartAngle,
    230                             dSweepAngle = 0;
    231 
    232                 // this is only TRUE for the last loop
    233                 BOOL        fNowDrawingSurface =
    234                               (
    235                                    ((pChartStyle->ulStyle & CHS_3D_BRIGHT) == 0)
    236                                 ||
    237                                    (ulYBottomNow == pChartStyle->ulThickness - 1)
    238                               );
    239 
    240                 // // _Pmpf(("Looping, ulYBottomNow: %d", ulYBottomNow));
    241 
    242                 // calculate pie rectangle for this loop;
    243                 // this is the size of the static control
    244                 // minus the "3D thickness", if enabled
    245                 memcpy(&rclArc, &rclWholeStatic, sizeof(RECTL));
    246                 if (pChartStyle->ulStyle & CHS_3D_BRIGHT)
    247                         // this includes CHS_3D_DARKEN
    248                 {
    249                     rclArc.yBottom = rclWholeStatic.yBottom
    250                                                 + ulYBottomNow;
    251                     rclArc.yTop = rclWholeStatic.yTop
    252                                                 - pChartStyle->ulThickness
    253                                                 + ulYBottomNow;
    254                 }
    255 
    256                 // calculate center point
    257                 ptlCenter.x = rclArc.xRight / 2;
    258                 ptlCenter.y = ((rclArc.yTop - rclArc.yBottom) / 2) + ulYBottomNow;
    259 
    260                 // Now, the "arc" APIs really suck. The following
    261                 // has cost me hours of testing to find out:
    262 
    263                 // a) The arc functions expect some kind of
    264                 //    "default arc" to be defined, which they
    265                 //    refer to. We define the arc as elliptical;
    266                 //    this will be used as the "current arc"
    267                 //    for subsequent arc calls.
    268                 //    (P, S) and (R, Q) define the end points
    269                 //    of the major axes of the ellipse.
    270                 //    The center of the arc will later be
    271                 //    specified with GpiPartialArc (while GpiFullArc
    272                 //    uses the current pen position...
    273                 //    Who created these APIs?!? This might be a most
    274                 //    flexible way to do things, but where's the
    275                 //    simple stuff?!?)
    276                 ap.lP = ptlCenter.x;        // X-axis X
    277                 ap.lS = 0;                  // X-axis Y
    278                 ap.lR = 0;                  // Y-axis X
    279                 ap.lQ = ((rclArc.yTop - rclArc.yBottom) / 2);
    280                                             // Y-axis Y
    281                 GpiSetArcParams(hpsMem, &ap);
    282 
    283                 // b)  The line primitives determine lines
    284                 //     to be drawn around the pie slices.
    285                 //     We don't want any.
    286                 GpiSetLineType(hpsMem, LINETYPE_INVISIBLE);
    287 
    288                 // c)  Strangely, GpiSetPattern does work,
    289                 //     while GpiSetColor doesn't (see below).
    290                 GpiSetPattern(hpsMem, PATSYM_SOLID);
    291 
    292                 // initialize per-item data pointers for
    293                 // loop below
    294                 pdThis = pChartData->padValues;
    295                 plColorThis = pChartData->palColors;
    296                 ppszDescriptionThis = pChartData->papszDescriptions;
    297                 pptlDescriptionThis = paptlDescriptions;
    298                 phRegionThis = paRegions;
    299 
    300                 // 2) inner "pie slice loop":
    301                 // this loop goes over the data pointers
    302                 // and paints accordingly. At the end of
    303                 // the loop, we'll advance all those pointers.
    304                 for (ul = 0; ul < pChartData->cValues; ul++)
    305                 {
    306                     HRGN        hrgnThis;
    307                     SHORT       sSweepAngle,
    308                                 sStartAngle;
    309 
    310                     // calculate the angle to sweep to:
    311                     // a simple rule of three
    312                     dSweepAngle = *pdThis           // current data pointer
    313                                   * pChartData->usSweepAngle
    314                                                     // maximum angle
    315                                   / dTotal;         // total data sum
    316 
    317                     // d)  And now comes the real fun part.
    318                     //     GpiPartialArc is too dumb to draw
    319                     //     anything on its own, it must _always_
    320                     //     appear within an area or path definition.
    321                     //     Unfortunately, this isn't really said
    322                     //     clearly anywhere.
    323                     //     Even worse, in order to set the color
    324                     //     with which the slice is to be drawn,
    325                     //     one has to define an AREABUNDLE because
    326                     //     the regular GpiSetColor functions don't
    327                     //     seem to work here. Or maybe it's my fault,
    328                     //     but with this awful documentation, who knows.
    329                     //     We use the current color defined in the
    330                     //     pie chart data (this pointer was set above
    331                     //     and will be advanced for the next slice).
    332                     ab.lColor = *plColorThis;
    333 
    334                     // "3D mode" enabled with darkened socket?
    335                     if (    (pChartStyle->ulStyle & CHS_3D_DARKEN)
    336                             // not last loop?
    337                          && (!fNowDrawingSurface)
    338                        )
    339                         // darken the current fill color
    340                         // by halving each color component
    341                         gpihManipulateRGB(&ab.lColor,
    342                                           .5);       // factor
    343 
    344                     // set the area (fill) color
    345                     GpiSetAttrs(hpsMem,
    346                                 PRIM_AREA,
    347                                 ABB_COLOR,
    348                                 0,
    349                                 (PBUNDLE)&ab);
    350 
    351                     GpiSetCurrentPosition(hpsMem, &ptlCenter);
    352 
    353                     // round the angle values properly
    354                     sStartAngle = (SHORT)(dStartAngle + .5);
    355                     sSweepAngle = (SHORT)(dSweepAngle + .5);
    356 
    357                     // now draw the pie slice;
    358                     // we could use an area, but since we need
    359                     // to remember the coordinates of the slice
    360                     // for mouse click handling, we require a
    361                     // region. But areas cannot be converted
    362                     // to regions, so we use a path instead.
    363                     GpiBeginPath(hpsMem,
    364                                  1);    // path ID, must be 1
    365                     GpiPartialArc(hpsMem,
    366                                   &ptlCenter,
    367                                   fxPieSize,    // calculated from CHARTSTYLE
    368                                   MAKEFIXED(sStartAngle, 0),
    369                                   MAKEFIXED(sSweepAngle, 0));
    370                         // this moves the current position to the outer
    371                         // point on the ellipse which corresponds to
    372                         // sSweepAngle
    373                     GpiEndPath(hpsMem);
    374 
    375                     // convert the path to a region;
    376                     // we'll need the region for mouse hit testing later
    377                     hrgnThis = GpiPathToRegion(hpsMem, 1,
    378                                                FPATH_ALTERNATE);
    379                         // after this, the path is deleted
    380                     GpiPaintRegion(hpsMem, hrgnThis);
    381                     if (phRegionThis)
    382                         // region output requested by caller:
    383                         // store region, the caller will clean this up
    384                         *phRegionThis = hrgnThis;
    385                     else
    386                         // drop region
    387                         GpiDestroyRegion(hpsMem, hrgnThis);
    388 
    389                     // descriptions enabled and last run?
    390                     if (    (ppszDescriptionThis)
    391                          && (fNowDrawingSurface)
    392                        )
    393                     {
    394                         if (*ppszDescriptionThis)
    395                         {
    396                             // yes: calculate position to paint
    397                             // text at later (we can't do this now,
    398                             // because it might be overpainted by
    399                             // the next arc again)
    400 
    401                             GpiSetCurrentPosition(hpsMem, &ptlCenter);
    402                             // move the current position to
    403                             // the center outer point on the ellipse
    404                             // (in between sStartAngle and sSweepAngle);
    405                             // since we're outside an area, this will not
    406                             // paint anything
    407                             GpiPartialArc(hpsMem,
    408                                           &ptlCenter,
    409                                           fxDescriptions, // calculated from CHARTSTYLE
    410                                           MAKEFIXED(sStartAngle, 0),
    411                                             // only half the sweep now:
    412                                           MAKEFIXED(sSweepAngle / 2, 0));
    413 
    414                             // store this outer point in the array
    415                             // of description coordinates for later
    416                             GpiQueryCurrentPosition(hpsMem, pptlDescriptionThis);
    417                         }
    418                     }
    419 
    420                     // increase the start angle by the sweep angle for next loop
    421                     dStartAngle += dSweepAngle;
    422 
    423                     // advance the data pointers
    424                     pdThis++;
    425                     plColorThis++;
    426                     if (ppszDescriptionThis)
    427                         ppszDescriptionThis++;
    428                     pptlDescriptionThis++;
    429                     if (phRegionThis)
    430                         phRegionThis++;
    431                 } // end for (ul...)
    432 
    433                 // go for next "3D thickness" iteration
    434                 ulYBottomNow++;
    435             } while (   (pChartStyle->ulStyle & CHS_3D_BRIGHT)
    436                      && (ulYBottomNow < pChartStyle->ulThickness)
    437                     );
    438 
    439             // now paint descriptions
    440             if (pChartStyle->ulStyle & CHS_DESCRIPTIONS)
    441             {
    442                 // we use two pointers during the iteration,
    443                 // which point to the item corresponding
    444                 // to the current data item:
    445                 // 1)  pointer to center point on outer border
    446                 //     of partial arc
    447                 //     (calculated above)
    448                 PPOINTL     pptlDescriptionThis = paptlDescriptions;
    449                 // 2)  pointer to current description string
    450                 PSZ*        ppszDescriptionThis = pChartData->papszDescriptions;
    451 
    452                 // description strings valid?
    453                 if (ppszDescriptionThis)
    454                 {
    455                     // set presentation color
    456                     GpiSetColor(hpsMem, lTextColor);
    457 
    458                     // set text aligment to centered
    459                     // both horizontally and vertically;
    460                     // this affects subsequent GpiCharStringAt
    461                     // calls in that the output text will
    462                     // be centered around the specified
    463                     // point
    464                     GpiSetTextAlignment(hpsMem,
    465                                         TA_CENTER,      // horizontally
    466                                         TA_HALF);       // center vertically
    467 
    468                     // loop thru data items
    469                     for (ul = 0;
    470                          ul < pChartData->cValues;
    471                          ul++)
    472                     {
    473                         POINTL  ptlMiddlePoint;
    474 
    475                         // when drawing the arcs above, we have,
    476                         // for each pie slice, stored the middle
    477                         // point on the outer edge of the ellipse
    478                         // in the paptlDescriptions POINTL array:
    479 
    480                         //                ++++
    481                         //                +    +
    482                         //                +      +
    483                         //    ptlCenter\  +       +
    484                         //              \ +        + <-- current partial arc
    485                         //               \+        +
    486                         //     +++++++++++X        +
    487                         //     +                   +
    488                         //      +                  +
    489                         //       +               XX  <-- point calculated above
    490                         //        +             +
    491                         //           +        +
    492                         //             ++++++
    493 
    494                         // now calculate a middle point between
    495                         // that outer point on the ellipse and
    496                         // the center of the ellipse, which will
    497                         // be the center point for the text
    498 
    499                         //                ++++
    500                         //                +    +
    501                         //                +      +
    502                         //    ptlCenter\  +       +
    503                         //              \ +        + <-- current partial arc
    504                         //               \+        +
    505                         //     ++++++++++++        +
    506                         //     +             XX    + <-- new middle point
    507                         //      +                  +
    508                         //       +               XX  <-- point calculated above
    509                         //        +             +
    510                         //           +        +
    511                         //             ++++++
    512 
    513                         ptlMiddlePoint.x =
    514                                 ptlCenter.x
    515                                 + ((pptlDescriptionThis->x - ptlCenter.x) * 2 / 3);
    516                         ptlMiddlePoint.y =
    517                                 ptlCenter.y
    518                                 - (ptlCenter.y - pptlDescriptionThis->y) * 2 / 3;
    519 
    520                         // FINALLY, draw the description
    521                         // at this point; since we have used
    522                         // GpiSetTextAlignment above, the
    523                         // text will be centered on exactly
    524                         // that point
    525                         GpiCharStringAt(hpsMem,
    526                                         &ptlMiddlePoint,
    527                                         strlen(*ppszDescriptionThis),
    528                                         *ppszDescriptionThis);
    529 
    530                         pptlDescriptionThis++;
    531                         ppszDescriptionThis++;
    532                     } // end for (ul = 0; ul < pChartData->cValues; ul++)
    533                 } // end if (ppszDescriptionThis)
    534             } // end if (pChartStyle->ulStyle & CHS_DESCRIPTIONS)
    535 
    536             // cleanup
    537             free(paptlDescriptions);
     1066            if (pChartStyle->ulStyle & CHS_BARCHART)
     1067                PaintBarChart(hpsMem,
     1068                              &rclWholeStatic,
     1069                              pChartData,
     1070                              pChartStyle,
     1071                              dTotal,
     1072                              lTextColor,
     1073                              paRegions);
     1074            else
     1075                PaintPieChart(hpsMem,
     1076                              &rclWholeStatic,
     1077                              pChartData,
     1078                              pChartStyle,
     1079                              dTotal,
     1080                              lTextColor,
     1081                              paRegions);
    5381082
    5391083            // deselect (free) bitmap
     
    5511095 *
    5521096 *@@changed V0.9.2 (2000-02-29) [umoeller]: fixed maaajor memory leak
     1097 *@@changed V0.9.12 (2001-05-03) [umoeller]: fixed major PM resource leaks
    5531098 */
    5541099
     
    5571102    if (pChtCData)
    5581103    {
     1104        // destroy regions, but not the array itself
     1105        // (this is done in CleanupData)
     1106        if (pChtCData->hpsMem && pChtCData->paRegions)
     1107        {
     1108            ULONG   ul;
     1109            for (ul = 0;
     1110                 ul < pChtCData->cd.cValues;
     1111                 ul++)
     1112            {
     1113                if (pChtCData->paRegions[ul])
     1114                {
     1115                    GpiDestroyRegion(pChtCData->hpsMem, pChtCData->paRegions[ul]);
     1116                    pChtCData->paRegions[ul] = NULLHANDLE;
     1117                }
     1118            }
     1119        }
     1120
    5591121        // bitmap already created?
    5601122        if (pChtCData->hbmChart)
    5611123        {
    5621124            // free current bitmap
    563             // GpiSetBitmap(pChtCData->hpsMem, NULLHANDLE);
     1125            GpiSetBitmap(pChtCData->hpsMem, NULLHANDLE);
    5641126            // delete bitmap; fails if not freed!
    565             GpiDeleteBitmap(pChtCData->hbmChart);
     1127            if (!GpiDeleteBitmap(pChtCData->hbmChart))
     1128                _Pmpf((__FUNCTION__ ": GpiDeleteBitmap failed."));
    5661129            pChtCData->hbmChart = NULLHANDLE;
    5671130        }
    5681131
    569         // destroy regions, but not the array itself
    570         // (this is done in CleanupData)
    571         if (pChtCData->paRegions)
     1132        if (pChtCData->hpsMem)
    5721133        {
    573             ULONG   ul;
    574             HRGN    *phRegionThis = pChtCData->paRegions;
    575             for (ul = 0;
    576                  ul < pChtCData->cd.cValues;
    577                  ul++)
    578             {
    579                 if (*phRegionThis)
    580                 {
    581                     GpiDestroyRegion(pChtCData->hpsMem, *phRegionThis);
    582                     *phRegionThis = NULLHANDLE;
    583                 }
    584                 phRegionThis++;
    585             }
     1134            GpiDestroyPS(pChtCData->hpsMem);
     1135            pChtCData->hpsMem = NULLHANDLE;
     1136        }
     1137        if (pChtCData->hdcMem)
     1138        {
     1139            DevCloseDC(pChtCData->hdcMem);
     1140            pChtCData->hdcMem = NULLHANDLE;
    5861141        }
    5871142    }
     
    6471202 *
    6481203 *@@added V0.9.2 (2000-02-29) [umoeller]
     1204 *@@changed V0.9.12 (2001-05-03) [umoeller]: fixed trap if ptr to descriptions was null
    6491205 */
    6501206
     
    6631219    CleanupData(pChtCData);
    6641220
    665     // _Pmpf(("Setting up data"));
    666 
    667     if (pChtCData->hpsMem == NULLHANDLE)
    668     {
    669         // first call:
    670         // create a memory PS for the bitmap
    671         SIZEL szlPage = {0, 0};
    672         gpihCreateMemPS(WinQueryAnchorBlock(hwndChart),
    673                         &szlPage,
    674                         &pChtCData->hdcMem,
    675                         &pChtCData->hpsMem);
    676         // _Pmpf(("Created HPS 0x%lX", pChtCData->hpsMem));
    677         // _Pmpf(("Created HDC 0x%lX", pChtCData->hdcMem));
    678     }
    679 
    6801221    pChtCData->cd.usStartAngle = pcdNew->usStartAngle;
    6811222    pChtCData->cd.usSweepAngle = pcdNew->usSweepAngle;
     
    6951236
    6961237    // copy strings
    697     pChtCData->cd.papszDescriptions = (PSZ*)malloc(sizeof(PSZ) * pcdNew->cValues);
    698     ppszDescriptionSource = pcdNew->papszDescriptions;
    699     ppszDescriptionTarget = pChtCData->cd.papszDescriptions;
    700     for (ul = 0;
    701          ul < pcdNew->cValues;
    702          ul++)
     1238    if (!pcdNew->papszDescriptions)
     1239        pChtCData->cd.papszDescriptions = NULL;
     1240    else
    7031241    {
    704         if (*ppszDescriptionSource)
    705             *ppszDescriptionTarget = strdup(*ppszDescriptionSource);
    706         else
    707             *ppszDescriptionTarget = NULL;
    708         ppszDescriptionSource++;
    709         ppszDescriptionTarget++;
     1242        pChtCData->cd.papszDescriptions = (PSZ*)malloc(sizeof(PSZ) * pcdNew->cValues);
     1243        ppszDescriptionSource = pcdNew->papszDescriptions;
     1244        ppszDescriptionTarget = pChtCData->cd.papszDescriptions;
     1245        for (ul = 0;
     1246             ul < pcdNew->cValues;
     1247             ul++)
     1248        {
     1249            if (*ppszDescriptionSource)
     1250                *ppszDescriptionTarget = strdup(*ppszDescriptionSource);
     1251            else
     1252                *ppszDescriptionTarget = NULL;
     1253            ppszDescriptionSource++;
     1254            ppszDescriptionTarget++;
     1255        }
    7101256    }
    7111257
     
    7161262
    7171263    pChtCData->lSelected = -1;     // none selected
     1264    pChtCData->lSourceEmphasis = -1;     // none selected
    7181265
    7191266    WinInvalidateRect(hwndChart, NULL, FALSE);
     
    7261273 *
    7271274 *@@added V0.9.2 (2000-02-29) [umoeller]
     1275 *@@changed V0.9.12 (2001-05-03) [umoeller]: fixed major PM resource leaks
    7281276 */
    7291277
     
    7351283    RECTL   rclStatic;
    7361284    WinQueryWindowRect(hwndChart, &rclStatic);
    737 
    738     // _Pmpf(("ctl_fnwpChart: WM_PAINT, cValues: %d", pChtCData->cd.cValues));
    7391285
    7401286    // do we have any values yet?
     
    7621308                                                   SYSCLR_WINDOWTEXT);
    7631309
    764         // yes: check if we created the bitmap
    765         // already
     1310        gpihSwitchToRGB(hps);
     1311
     1312        // check if the bitmap needs to be (re)created
    7661313        if (pChtCData->hbmChart == NULLHANDLE)
    7671314        {
    7681315            // no: do it now
    7691316            HPOINTER    hptrOld = winhSetWaitPointer();
    770 
    771             // get presentation font
    772             FONTMETRICS FontMetrics;
    773             LONG        lPointSize;
    774             LONG lLCIDSet = gpihFindPresFont(hwndChart,
    775                                              TRUE,      // inherit PP
    776                                              pChtCData->hpsMem,
    777                                              "8.Helv",
    778                                              &FontMetrics,
    779                                              &lPointSize);
    780             // set presentation font
    781             if (lLCIDSet)
     1317            LONG        lLCIDSet = 0;
     1318
     1319            if (pChtCData->hpsMem == NULLHANDLE)
    7821320            {
    783                 GpiSetCharSet(pChtCData->hpsMem, lLCIDSet);
    784                 if (FontMetrics.fsDefn & FM_DEFN_OUTLINE)
    785                     gpihSetPointSize(pChtCData->hpsMem, lPointSize);
     1321                // first call:
     1322                FONTMETRICS FontMetrics;
     1323                LONG        lPointSize;
     1324
     1325                // create a memory PS for the bitmap
     1326                SIZEL szlPage = {rclStatic.xRight,
     1327                                 rclStatic.yTop};
     1328                gpihCreateMemPS(WinQueryAnchorBlock(hwndChart),
     1329                                &szlPage,
     1330                                &pChtCData->hdcMem,
     1331                                &pChtCData->hpsMem);
     1332
     1333                // get presentation font
     1334                lLCIDSet = gpihFindPresFont(hwndChart,
     1335                                            TRUE,      // inherit PP
     1336                                            pChtCData->hpsMem,
     1337                                            "8.Helv",
     1338                                            &FontMetrics,
     1339                                            &lPointSize);
     1340                // set presentation font
     1341                if (lLCIDSet)
     1342                {
     1343                    GpiSetCharSet(pChtCData->hpsMem, lLCIDSet);
     1344                    if (FontMetrics.fsDefn & FM_DEFN_OUTLINE)
     1345                        gpihSetPointSize(pChtCData->hpsMem, lPointSize);
     1346                }
    7861347            }
    787 
    788 
    789             gpihSwitchToRGB(hps);
    7901348
    7911349            pChtCData->hbmChart = ctlCreateChartBitmap(
     
    8041362                      pChtCData->paRegions);
    8051363                              // out: regions array
    806             // _Pmpf(("Created bitmap 0x%lX", pChtCData->hbmChart));
    8071364
    8081365            // unset and delete font
    809             GpiSetCharSet(pChtCData->hpsMem, LCID_DEFAULT);
    8101366            if (lLCIDSet)
     1367            {
     1368                GpiSetCharSet(pChtCData->hpsMem, LCID_DEFAULT);
    8111369                GpiDeleteSetId(pChtCData->hpsMem, lLCIDSet);
     1370            }
    8121371
    8131372            WinSetPointer(HWND_DESKTOP, hptrOld);
     
    8161375        if (pChtCData->hbmChart)
    8171376        {
     1377            // draw the chart bitmap
    8181378            POINTL  ptlDest = { 0, 0 };
    8191379            WinDrawBitmap(hps,
     
    8241384                          DBM_NORMAL);
    8251385
    826             // do we have the focus?
    827             if (pChtCData->fHasFocus)
    828                 // something selected?
    829                 if (pChtCData->lSelected != -1)
    830                     if (pChtCData->paRegions)
     1386            // now draw emphasis, if we have regions
     1387            if (pChtCData->paRegions)
     1388            {
     1389                AREABUNDLE ab;
     1390                SIZEL   sl = {2, 2};
     1391
     1392                // 1) source emphasis (even if we don't have focus)
     1393                if (pChtCData->lSourceEmphasis != -1)
     1394                {
     1395                    if (pChtCData->paRegions[pChtCData->lSourceEmphasis])
    8311396                    {
    832                         HRGN* pRegionThis = pChtCData->paRegions; // first region
    833                         pRegionThis += pChtCData->lSelected;      // array item
    834 
    835                         if (*pRegionThis)
    836                         {
    837                             SIZEL   sl = {2, 2};
    838                             GpiSetColor(hps, lForegroundColor);
    839                             GpiFrameRegion(hps,
    840                                            *pRegionThis,
    841                                            &sl);
    842                         }
     1397                        // GpiFrameRegion uses the current pattern
     1398                        // attributes, so we must set the correct
     1399                        // color in there (GpiSetColor doesn't work)
     1400                        // V0.9.12 (2001-05-03) [umoeller]
     1401
     1402                        ab.lColor = lForegroundColor;
     1403                        GpiSetAttrs(hps,
     1404                                    PRIM_AREA,
     1405                                    ABB_COLOR,
     1406                                    0,
     1407                                    (PBUNDLE)&ab);
     1408                        GpiSetPattern(hps,
     1409                                      PATSYM_DIAG1);
     1410                        GpiPaintRegion(hps,
     1411                                       pChtCData->paRegions[pChtCData->lSourceEmphasis]);
    8431412                    }
     1413                }
     1414
     1415                // 2) selection
     1416
     1417                // do we have the focus?
     1418                if (    (pChtCData->fHasFocus)
     1419                        // something selected?
     1420                     && (pChtCData->lSelected != -1)
     1421                   )
     1422                {
     1423                    if (pChtCData->paRegions[pChtCData->lSelected])
     1424                    {
     1425                        // GpiFrameRegion uses the current pattern
     1426                        // attributes, so we must set the correct
     1427                        // color in there (GpiSetColor doesn't work)
     1428                        // V0.9.12 (2001-05-03) [umoeller]
     1429
     1430                        ab.lColor = RGBCOL_RED; // lForegroundColor;
     1431                        GpiSetAttrs(hps,
     1432                                    PRIM_AREA,
     1433                                    ABB_COLOR,
     1434                                    0,
     1435                                    (PBUNDLE)&ab);
     1436                        GpiFrameRegion(hps,
     1437                                       pChtCData->paRegions[pChtCData->lSelected],
     1438                                       &sl);
     1439                    }
     1440                }
     1441            }
    8441442        }
    8451443    }
     
    8471445
    8481446/*
     1447 *@@ FindItemFromPoint:
     1448 *      returns the index of the slice under the
     1449 *      given window coordinates, or -1 if there's
     1450 *      none.
     1451 *
     1452 *@@added V0.9.12 (2001-05-03) [umoeller]
     1453 */
     1454
     1455LONG FindItemFromPoint(PCHARTCDATA pChtCData,
     1456                       LONG lx,
     1457                       LONG ly)
     1458{
     1459    LONG lRegionFound = -1; // none
     1460
     1461    POINTL ptlMouse = {lx, ly};
     1462
     1463    // data set?
     1464    if (    (pChtCData->cd.cValues)
     1465         && (pChtCData->paRegions)
     1466       )
     1467    {
     1468        ULONG   ul;
     1469        for (ul = 0;
     1470             ul < pChtCData->cd.cValues;
     1471             ul++)
     1472        {
     1473            HRGN hRgnThis = pChtCData->paRegions[ul];
     1474            if (hRgnThis)
     1475            {
     1476                if (GpiPtInRegion(pChtCData->hpsMem,
     1477                                  hRgnThis,
     1478                                  &ptlMouse)
     1479                     == PRGN_INSIDE)
     1480                {
     1481                    return (ul);
     1482                }
     1483            }
     1484        }
     1485    }
     1486
     1487    return (-1);
     1488}
     1489
     1490/*
     1491 *@@ SendWMControl:
     1492 *
     1493 *@@added V0.9.12 (2001-05-03) [umoeller]
     1494 */
     1495
     1496VOID SendWMControl(HWND hwndChart,
     1497                   MPARAM mp1Mouse,
     1498                   USHORT usNotify,
     1499                   ULONG ulEmphasis,            // 0 or 1
     1500                   LONG lIndex)
     1501{
     1502    HWND hwndOwner;
     1503
     1504    if (hwndOwner = WinQueryWindow(hwndChart, QW_OWNER))
     1505    {
     1506        EMPHASISNOTIFY en;
     1507        en.hwndSource = hwndChart;
     1508        en.lIndex = lIndex;        // can be -1
     1509        en.ulEmphasis = ulEmphasis;
     1510        en.ptl.x = SHORT1FROMMP(mp1Mouse);
     1511        en.ptl.y = SHORT2FROMMP(mp1Mouse);
     1512
     1513        WinSendMsg(hwndOwner,
     1514                   WM_CONTROL,
     1515                   MPFROM2SHORT(WinQueryWindowUShort(hwndChart,
     1516                                                     QWS_ID),
     1517                                usNotify),
     1518                   &en);
     1519    }
     1520}
     1521
     1522/*
     1523 *@@ SetEmphasis:
     1524 *
     1525 *@@added V0.9.12 (2001-05-03) [umoeller]
     1526 */
     1527
     1528BOOL SetEmphasis(HWND hwndChart,
     1529                 PCHARTCDATA pChtCData,
     1530                 ULONG ulEmphasis,      // in: 0 == selection, 1 == source emphasis
     1531                 MPARAM mp1,            // in: mp1 with mouse values or -1 if none
     1532                 LONG lIndex,
     1533                 BOOL fIsContextMenu)
     1534{
     1535    BOOL brc = FALSE;
     1536
     1537    PLONG plOld;
     1538
     1539    if (ulEmphasis == 0)
     1540        plOld = &pChtCData->lSelected;
     1541    else if (ulEmphasis == 1)
     1542        plOld = &pChtCData->lSourceEmphasis;
     1543
     1544    if (plOld)
     1545    {
     1546        if (    (*plOld != lIndex)
     1547             || (fIsContextMenu)
     1548           )
     1549        {
     1550            // selection changed:
     1551            *plOld = lIndex;
     1552
     1553            brc = TRUE;
     1554
     1555            // repaint
     1556            WinInvalidateRect(hwndChart, NULL, FALSE);
     1557
     1558            // send notification to owner
     1559            // V0.9.12 (2001-05-03) [umoeller]
     1560            SendWMControl(hwndChart,
     1561                          mp1,
     1562                          CHTN_EMPHASISCHANGED,
     1563                          ulEmphasis,
     1564                          lIndex);
     1565        }
     1566    }
     1567
     1568    return (brc);
     1569}
     1570
     1571/*
    8491572 *@@ ctl_fnwpChart:
    8501573 *      window procedure for the "chart" control.
     
    8561579 *@@changed V0.9.2 (2000-02-29) [umoeller]: added resize support
    8571580 *@@changed V0.9.2 (2000-02-29) [umoeller]: fixed baaad PM resource leaks, the bitmap was never freed
     1581 *@@changed V0.9.12 (2001-05-03) [umoeller]: added WM_CONTEXTMENU support
    8581582 */
    8591583
     
    8871611                // _Pmpf(("CHTM_SETCHARTDATA, mp1: 0x%lX", mp1));
    8881612                if (mp1)
    889                 {
    890                     PCHARTDATA   pcdNew = (PCHARTDATA)mp1;
    891                     SetChartData(hwndChart, pChtCData, pcdNew);
    892                 }
     1613                    SetChartData(hwndChart,
     1614                                 pChtCData,
     1615                                 (PCHARTDATA)mp1);
    8931616            break;
    8941617
     
    9431666            case CHTM_ITEMFROMPOINT:
    9441667            {
    945                 LONG lRegionFound = -1; // none
    946 
    947                 // get mouse coordinates
    948                 POINTL ptlMouse;
    949                 ptlMouse.x = SHORT1FROMMP(mp1);
    950                 ptlMouse.y = SHORT2FROMMP(mp1);
    951 
    952                 // data set?
    953                 if (pChtCData->cd.cValues)
     1668                mrc = (MPARAM)FindItemFromPoint(pChtCData,
     1669                                                SHORT1FROMMP(mp1),
     1670                                                SHORT2FROMMP(mp1));
     1671            break; }
     1672
     1673            /*
     1674             *@@ CHTM_SETEMPHASIS:
     1675             *      sets emphasis on a chart slice.
     1676             *
     1677             *      Parameters:
     1678             *
     1679             *      LONG mp1: emphasis to set. Currently
     1680             *              defined values:
     1681             *
     1682             *              -- 0: set selection.
     1683             *
     1684             *              -- 1: set source emphasis.
     1685             *
     1686             *      LONG mp2: zero-based index of slice to
     1687             *              set emphasis for, or -1 to
     1688             *              remove that emphasis.
     1689             *
     1690             *      Returns: TRUE if emphasis was changed.
     1691             *
     1692             *@@added V0.9.12 (2001-05-03) [umoeller]
     1693             */
     1694
     1695            case CHTM_SETEMPHASIS:
     1696            {
     1697                LONG lEmph = (LONG)mp1;
     1698                LONG lIndex = (LONG)mp2;
     1699                if (    lEmph > 0
     1700                     && lEmph < 2
     1701                     && (    lIndex >= -1
     1702                          || (    lIndex > 0
     1703                               && lIndex < pChtCData->cd.cValues
     1704                             )
     1705                        )
     1706                   )
    9541707                {
    955                     // regions defined?
    956                     if (pChtCData->paRegions)
    957                     {
    958                         ULONG   ul;
    959                         HRGN*   phRegionThis = pChtCData->paRegions;
    960                         for (ul = 0;
    961                              ul < pChtCData->cd.cValues;
    962                              ul++)
    963                         {
    964                             if (*phRegionThis)
    965                             {
    966                                 if (GpiPtInRegion(pChtCData->hpsMem,
    967                                                   *phRegionThis,
    968                                                   &ptlMouse)
    969                                      == PRGN_INSIDE)
    970                                 {
    971                                     // _Pmpf(("Clicked in region %d", ul));
    972                                     lRegionFound = ul;
    973                                     break;
    974                                 }
    975                             }
    976                             phRegionThis++;
    977                         }
    978 
    979                     }
     1708                    mrc = (MPARAM)SetEmphasis(hwndChart,
     1709                                              pChtCData,
     1710                                              lEmph,
     1711                                              (MPARAM)-1,
     1712                                              lIndex,
     1713                                              // force flag:
     1714                                              TRUE);
    9801715                }
    981 
    982                 mrc = (MPARAM)lRegionFound;
    983             break; }
     1716            }
     1717            break;
    9841718
    9851719            /*
    986              * WM_BUTTON1DOWN:
    987              *
     1720             * WM_BUTTON1CLICK:
     1721             * WM_CONTEXTMENU: V0.9.12 (2001-05-03) [umoeller]
    9881722             */
    9891723
    990             case WM_BUTTON1DOWN:
     1724            case WM_BUTTON1CLICK:
     1725            case WM_BUTTON1DBLCLK:
     1726            case WM_CONTEXTMENU:
    9911727                if (pChtCData->cs.ulStyle & CHS_SELECTIONS)
    9921728                {
    993                     LONG lRegionFound = (LONG)WinSendMsg(hwndChart,
    994                                                          CHTM_ITEMFROMPOINT,
    995                                                          mp1,
    996                                                          NULL);
     1729                    LONG lRegionFound = FindItemFromPoint(pChtCData,
     1730                                                SHORT1FROMMP(mp1),
     1731                                                SHORT2FROMMP(mp1));
    9971732
    9981733                    // selections allowed:
     
    10011736                    WinSetFocus(HWND_DESKTOP, hwndChart);
    10021737                        // this invalidates the window
    1003                     if (pChtCData->lSelected != lRegionFound)
     1738
     1739                    if (msg == WM_CONTEXTMENU)
     1740                    {
     1741                        // context menu:
     1742                        SendWMControl(hwndChart,
     1743                                      mp1,
     1744                                      CHTN_CONTEXTMENU,
     1745                                      -1,
     1746                                      lRegionFound);
     1747                    }
     1748                    else
    10041749                    {
    10051750                        // selection changed:
    1006                         pChtCData->lSelected = lRegionFound;
    1007                         // repaint
    1008                         WinInvalidateRect(hwndChart, NULL, FALSE);
     1751                        SetEmphasis(hwndChart,
     1752                                    pChtCData,
     1753                                    0,    // set selection; caller must set source emphasis
     1754                                    mp1,
     1755                                    lRegionFound,
     1756                                    // force flag:
     1757                                    FALSE);
     1758
     1759                        if (msg == WM_BUTTON1DBLCLK)
     1760                            SendWMControl(hwndChart,
     1761                                          mp1,
     1762                                          CHTN_ENTER,
     1763                                          0,
     1764                                          lRegionFound);
    10091765                    }
    10101766                }
     
    10471803                // resizing?
    10481804                if (pswpNew->fl & SWP_SIZE)
     1805                {
    10491806                    if (pChtCData->hbmChart)
    1050                     {
    10511807                        // invalidate bitmap so that
    10521808                        // it will be recreated with new size
    10531809                        CleanupBitmap(pChtCData);
    1054                         WinInvalidateRect(hwndChart, NULL, FALSE);
    1055                     }
    1056 
     1810
     1811                    WinInvalidateRect(hwndChart, NULL, FALSE);
     1812                }
    10571813                // return default NULL
    10581814            break; }
     
    11031859            case WM_DESTROY:
    11041860                CleanupBitmap(pChtCData);
     1861
    11051862                CleanupData(pChtCData);
    11061863
    1107                 // _Pmpf(("Destroying HPS 0x%lX", pChtCData->hpsMem));
    1108                 if (!GpiDestroyPS(pChtCData->hpsMem));
    1109                     // _Pmpf(("  Error!"));
    1110                 // _Pmpf(("Destroying HDC 0x%lX", pChtCData->hdcMem));
    1111                 if (!DevCloseDC(pChtCData->hdcMem));
    1112                     // _Pmpf(("  Error!"));
    11131864                free(pChtCData);
    11141865
     
    11301881 *      window procedure with ctl_fnwpChart.
    11311882 *
    1132  *      This way you can easily create a chart control as a static
    1133  *      control in any Dialog Editor;
    1134  *      after loading the dlg template, simply call this function
    1135  *      with the hwnd of the static control to make it a chart.
    1136  *
    1137  *      The pie chart consumes all available space in the static control.
    1138  *
    1139  *      In XWorkplace, this is used for the pie chart on the new
    1140  *      XFldDisk "Details" settings page to display the free space
    1141  *      on a certain drive.
    1142  *
    1143  *      Note: even though you can use _any_ type of static control
    1144  *      with this function, you should use a static _text_ control,
    1145  *      because not all types of static controls react to fonts and
    1146  *      colors dragged upon them. The static _text_ control does.
    1147  *
    1148  *      <B>Chart data:</B>
    1149  *
    1150  *      The pie chart control operates on an array of "double" values.
    1151  *      Each value in that array corresponds to a color in a second
    1152  *      array of (LONG) RGB values and, if description texts are
    1153  *      enabled, to a third array of PSZ's.
    1154  *
    1155  *      The data on which the pie chart operates is initialized to
    1156  *      be void, so that the pie chart will not paint anything
    1157  *      initially. In order to have the pie chart display something,
    1158  *      post or send a CHTM_SETCHARTDATA message (comctl.h) to the static
    1159  *      control after it has been subclassed.
    1160  *
    1161  *      CHTM_SETCHARTDATA takes a CHARTDATA structure (comctl.h) in mp1,
    1162  *      which must contain the chart data and corresponding colors to be
    1163  *      displayed.
    1164  *
    1165  *      The total sum of the "double" values will represent the angle in
    1166  *      CHARTDATA.usSweepAngle.
    1167  *
    1168  *      For example, if two values of 50 and 100 are passed to the
    1169  *      control and usSweepAngle is 270 (i.e. a three-quarter pie),
    1170  *      the chart control will calculate the following:
    1171  *
    1172  *      1)  The sum of the data is 150.
    1173  *
    1174  *      2)  The first sub-arc will span an angle of 270 * (50/150)
    1175  *          = 90 degrees.
    1176  *
    1177  *      3)  The second sub-arc will span an angle of 270 * (100/150)
    1178  *          = 180 degrees.
    1179  *
    1180  *      You can also have descriptions displayed along the different
    1181  *      chart items by specifying CHARTDATA.papszDescriptions and
    1182  *      setting the CHS_DESCRIPTIONS flag (below).
    1183  *
    1184  *      <B>Chart styles:</B>
    1185  *
    1186  *      Use CHTM_SETCHARTSTYLE with a PCHARTSTYLE (comctl.h) in mp1.
    1187  *      This can be sent to the chart control several times.
    1188  *
    1189  *      Presently, only pie charts are implemented. However, we do
    1190  *      have several "sub-styles" for pie charts:
    1191  *      -- CHS_3D_BRIGHT: paint a "3D" socket below the actual chart.
    1192  *      -- CHS_3D_DARKEN: like CHS_3D_BRIGHT, but the socket will be made
    1193  *                        darker compared to the surface.
    1194  *
    1195  *      General styles:
    1196  *      -- CHS_DESCRIPTIONS: show descriptions on the chart
    1197  *                           (CHARTDATA.papszDescriptions data).
    1198  *      -- CHS_SELECTIONS: allow pie chart slices to be selectable,
    1199  *                         using the mouse and the keyboard.
    1200  *
    1201  *      <B>Display:</B>
    1202  *
    1203  *      The chart control creates an internal bitmap for the display
    1204  *      only once (ctlCreateChartBitmap). This bitmap is refreshed if
    1205  *      neccessary, e.g. because chart data or styles have changed.
    1206  *
    1207  *      The chart control uses presentation parameters, as listed below.
    1208  *      Presentation parameters are inherited from the parent window.
    1209  *      If a presparam is not set, the corresponding system color is
    1210  *      used. The following color pairs are recognized:
    1211  *
    1212  *      --  PP_BACKGROUNDCOLOR / SYSCLR_DIALOGBACKGROUND:
    1213  *          background of the chart control (outside the chart).
    1214  *      --  PP_FOREGROUNDCOLOR / SYSCLR_WINDOWTEXT:
    1215  *          text color, if description texts are enabled and valid.
    1216  *      --  PP_FONTNAMESIZE:
    1217  *          text font, if description texts are enabled and valid.
    1218  *          If this presparam is not set, the system font is used.
    1219  *
    1220  *      The control reacts to fonts and colors dropped upon it, if
    1221  *      it has been subclassed from a static _text_ control (see above).
    1222  *      It also recalculates the bitmap when it's resized.
    1223  *
    1224  *      <B>Example usage:</B>
    1225  *
    1226  +          // get static control:
    1227  +          HWND    hwndChart = WinWindowFromID(hwndDialog, ID_...);
    1228  +          CHARTSTYLE      cs;
    1229  +          CHARTDATA       cd;
    1230  +          // define data:
    1231  +          double          adData[3] = { 100, 200, 300 };
    1232  +          // define corresponding colors:
    1233  +          LONG            alColors[3] = { 0x800000, 0x008000, 0x000080 };
    1234  +          // define correspdonding descriptions:
    1235  +          PSZ             apszDescriptions[3] = { "item 1", "item 3", "item 3" };
    1236  +
    1237  +          ctlChartFromStatic(hwndChart);     // create chart
    1238  +
    1239  +          cs.ulStyle = CHS_3D_DARKEN | CHS_DESCRIPTIONS;
    1240  +          cs.ulThickness = 20;
    1241  +          WinSendMsg(hwndChart, CHTM_SETCHARTSTYLE, &cs, NULL);
    1242  +
    1243  +          cd.usStartAngle = 15;       // start at 15ø from right
    1244  +          cd.usSweepAngle = 270;      // three-quarter pie (for the sum of the
    1245  +                                      // above values: 100+200+300 = 600)
    1246  +          cd.cValues = 3;             // array count
    1247  +          cd.padValues = &adData[0];
    1248  +          cd.palColors = &alColors[0];
    1249  +          cd.papszDescriptions = &apszDescriptions[0];
    1250  +          WinSendMsg(hwndChart, CHTM_SETCHARTDATA, &cd, NULL);
     1883 *      See cctl_chart.c for an overview and usage instructions.
    12511884 *
    12521885 *@@added V0.9.0 [umoeller]
  • trunk/src/helpers/cctl_tooltip.c

    r66 r68  
    164164 *
    165165 *@@added V0.9.12 (2001-04-28) [umoeller]
     166 *@@changed V0.9.12 (2001-05-03) [umoeller]: this did nothing... fixed
    166167 */
    167168
    168169VOID UnlockSubclassedTools(VOID)
    169170{
     171    DosReleaseMutexSem(G_hmtxSubclassedTools);      // was missing V0.9.12 (2001-05-03) [umoeller]
    170172}
    171173
  • trunk/src/helpers/debug.c

    r31 r68  
    366366
    367367/*
     368 *@@ WriteAddressInfo:
     369 *      formats and writes a line into the trap log
     370 *      file.
     371 *
     372 *      This gets called for each line from the
     373 *      stack dump. At this point, the line in the
     374 *      trap log already has:
     375 *
     376 +          CS:EIP  : 000109FF  XMLVIEW :0
     377 +                                          ^^^ and we write here
     378 *      After this call, we have.
     379 *
     380 +          CS:EIP  : 000109FF  XMLVIEW :0  xxx.c  123 ConfirmCreate__Fv
     381 +                                          ^^^ and we write here
     382 *
     383 *@@added V0.9.12 (2001-05-12) [umoeller]
     384 */
     385
     386VOID WriteDebugInfo(FILE *LogFile,              // in: open log file
     387                    PXDEBUGINFO pxdi)           // in: debug info
     388{
     389    fprintf(LogFile,
     390            "%s%s%s",
     391            pxdi->szNrFile,
     392            pxdi->szNrLine,
     393            pxdi->szNrPub);
     394}
     395
     396/*
    368397 *@@ dbgPrintDebugInfo:
    369398 *      this is the main entry point into analyzing debug
    370399 *      code.
     400 *
    371401 *      This analyzes a given address and tries to find
    372402 *      debug code descriptions for this address. If found,
     
    383413APIRET dbgPrintDebugInfo(FILE *LogFile,         // out: log file to write to
    384414                         CHAR *FileName,        // in: EXE/DLL module file name
    385                          ULONG Object,          // in: trapping object
    386                          ULONG TrapOffset)      // in: trapping address
     415                         ULONG Object,          // in: trapping object (from DosQueryModFromEIP)
     416                         ULONG TrapOffset)      // in: trapping address (from DosQueryModFromEIP)
    387417{
    388418    APIRET                  rc = 0;
     
    391421    static struct new_exe   NewExeHeader;
    392422
     423    ULONG                   ulSegment = Object + 1;     // segment no. is object no. + 1
     424
    393425    XDEBUGINFO              xdi;
    394426    memset(&xdi, 0, sizeof(xdi));
     
    430462
    431463            // do analysis for 32-bit code
    432             rc = Read32PmDebug(LogFile,
    433                                &xdi,
    434                                ModuleFile,
    435                                Object + 1,
    436                                TrapOffset,
    437                                FileName);
    438             if (rc == 0)
    439             {
    440                 fprintf(LogFile, "%s", xdi.szNrFile);
    441                 fprintf(LogFile, "%s", xdi.szNrLine);
    442                 fprintf(LogFile, "%s", xdi.szNrPub);
    443             }                   // endif
     464            if (!(rc = Read32PmDebug(LogFile,
     465                                     &xdi,                // output
     466                                     ModuleFile,
     467                                     ulSegment,
     468                                     TrapOffset,
     469                                     FileName)))
     470                WriteDebugInfo(LogFile, &xdi);
     471
    444472            close(ModuleFile);
    445473
     
    451479                if (ModuleFile != -1)
    452480                {
    453                     rc = Read32PmDebug(LogFile, &xdi, ModuleFile, Object + 1, TrapOffset, FileName);
    454                     if (rc == 0)
    455                     {
    456                         fprintf(LogFile, "%s", xdi.szNrFile);
    457                         fprintf(LogFile, "%s", xdi.szNrLine);
    458                         fprintf(LogFile, "%s", xdi.szNrPub);
    459                     }           // endif
     481                    if (!(rc = Read32PmDebug(LogFile,
     482                                             &xdi,
     483                                             ModuleFile,
     484                                             ulSegment,
     485                                             TrapOffset,
     486                                             FileName)))
     487                        WriteDebugInfo(LogFile, &xdi);
     488
    460489                    close(ModuleFile);
    461490                }
    462             }                   // endif
     491            }
    463492
    464493            return rc;
     
    473502                 */
    474503
    475                 if ((xdi.pseg = (struct new_seg *)calloc(NE_CSEG(NewExeHeader), sizeof(struct new_seg))) == NULL)
     504                if ((xdi.pseg = (struct new_seg *)calloc(NE_CSEG(NewExeHeader),
     505                                                         sizeof(struct new_seg)))
     506                            == NULL)
    476507                {
    477508                    fprintf(LogFile, "Out of memory!");
     
    479510                    return -1;
    480511                }
    481                 if (lseek(ModuleFile, E_LFANEW(OldExeHeader) + NE_SEGTAB(NewExeHeader), SEEK_SET) == -1L)
     512                if (  lseek(ModuleFile,
     513                            E_LFANEW(OldExeHeader) + NE_SEGTAB(NewExeHeader),
     514                            SEEK_SET) == -1L)
    482515                {
    483516                    fprintf(LogFile, "Error %u seeking segment table in %s\n", errno, FileName);
     
    487520                }
    488521
    489                 if (read(ModuleFile, (void *)xdi.pseg, NE_CSEG(NewExeHeader) * sizeof(struct new_seg)) == -1)
     522                if (read(ModuleFile,
     523                         (void *)xdi.pseg,
     524                         NE_CSEG(NewExeHeader) * sizeof(struct new_seg))
     525                      == -1)
    490526                {
    491527                    fprintf(LogFile, "Error %u reading segment table from %s\n", errno, FileName);
     
    494530                    return 10;
    495531                }
    496                 rc = Read16CodeView(LogFile, &xdi, ModuleFile, Object + 1, TrapOffset, FileName);
    497                 if (rc == 0)
    498                 {
    499                     fprintf(LogFile, "%s", xdi.szNrFile);
    500                     fprintf(LogFile, "%s", xdi.szNrLine);
    501                     fprintf(LogFile, "%s", xdi.szNrPub);
    502                 }               // endif
     532
     533                if (!(rc = Read16CodeView(LogFile,
     534                                          &xdi,
     535                                          ModuleFile,
     536                                          ulSegment,
     537                                          TrapOffset,
     538                                          FileName)))
     539                    WriteDebugInfo(LogFile, &xdi);
     540
    503541                free(xdi.pseg);
    504542                close(ModuleFile);
     
    508546                {
    509547                    strcpy(FileName + strlen(FileName) - 3, "DBG");     // Build DBG File name
    510                     ModuleFile = sopen(FileName, O_RDONLY | O_BINARY, SH_DENYNO);
     548                    ModuleFile = sopen(FileName,
     549                                       O_RDONLY | O_BINARY, SH_DENYNO);
    511550                    if (ModuleFile != -1)
    512551                    {
    513                         rc = Read16CodeView(LogFile, &xdi, ModuleFile, Object + 1, TrapOffset, FileName);
    514                         if (rc == 0)
    515                         {
    516                             fprintf(LogFile, "%s", xdi.szNrFile);
    517                             fprintf(LogFile, "%s", xdi.szNrLine);
    518                             fprintf(LogFile, "%s", xdi.szNrPub);
    519                         }       // endif
     552                        if (!(rc = Read16CodeView(LogFile,
     553                                                  &xdi,
     554                                                  ModuleFile,
     555                                                  ulSegment,
     556                                                  TrapOffset,
     557                                                  FileName)))
     558                            WriteDebugInfo(LogFile, &xdi);
     559
    520560                        close(ModuleFile);
    521561                    }
    522                 }               // endif
     562                }
    523563                return rc;
    524 
    525564            }
    526565            else
     
    608647    }
    609648
    610     if (read(ModuleFile, (void *)&G_eodbug, 8) == -1)
     649    if (read(ModuleFile,
     650             (void *)&G_eodbug, 8)
     651            == -1)
    611652    {
    612653        fprintf(LogFile, "Error %u reading debug info from %s\n", errno, FileName);
     
    619660    }
    620661
    621     if ((pxdi->lfaBase = lseek(ModuleFile, -(LONG)G_eodbug.dfaBase, SEEK_END)) == -1L)
     662    if (    (pxdi->lfaBase = lseek(ModuleFile,
     663                                   -(LONG)G_eodbug.dfaBase,
     664                                   SEEK_END))
     665         == -1L)
    622666    {
    623667        fprintf(LogFile, "Error %u seeking base codeview data in %s\n", errno, FileName);
     
    625669    }
    626670
    627     if (read(ModuleFile, (void *)&pxdi->base, 8) == -1)
     671    if (read(ModuleFile,
     672             (void *)&pxdi->base, 8)
     673        == -1)
    628674    {
    629675        fprintf(LogFile, "Error %u reading base codeview data in %s\n", errno, FileName);
     
    631677    }
    632678
    633     if (lseek(ModuleFile, pxdi->base.lfoDir - 8 + 4, SEEK_CUR) == -1)
     679    if (lseek(ModuleFile,
     680              pxdi->base.lfoDir - 8 + 4,
     681              SEEK_CUR)
     682        == -1)
    634683    {
    635684        fprintf(LogFile, "Error %u seeking dir codeview data in %s\n", errno, FileName);
     
    637686    }
    638687
    639     if (read(ModuleFile, (void *)&numdir, 4) == -1)
     688    if (read(ModuleFile,
     689             (void *)&numdir, 4)
     690        == -1)
    640691    {
    641692        fprintf(LogFile, "Error %u reading dir codeview data in %s\n", errno, FileName);
     
    644695
    645696    // Read dir table into buffer
    646     if ((pxdi->pDirTab32 = (SSDIR32*)calloc(numdir,
    647                                              sizeof(SSDIR32))
    648                      ) == NULL)
     697    if (    (pxdi->pDirTab32 = (SSDIR32*)calloc(numdir,
     698                                             sizeof(SSDIR32)))
     699        == NULL)
    649700    {
    650701        fprintf(LogFile, "Out of memory!");
     
    652703    }
    653704
    654     if (read(ModuleFile, (void *)pxdi->pDirTab32, numdir * sizeof(SSDIR32)) == -1)
     705    if (read(ModuleFile,
     706             (void*)pxdi->pDirTab32,
     707             numdir * sizeof(SSDIR32))
     708        == -1)
    655709    {
    656710        fprintf(LogFile, "Error %u reading codeview dir table from %s\n", errno, FileName);
     
    667721            continue;
    668722        }
     723
    669724        NrPublic = 0x0;
    670725        NrSymbol = 0;
     
    673728        CurrSymSeg = 0;
    674729        // point to subsection
    675         lseek(ModuleFile, pxdi->pDirTab32[i].lfoStart + pxdi->lfaBase, SEEK_SET);
    676         read(ModuleFile, (void*)&(pxdi->ssmod32.csBase), sizeof(SSMOD32));
    677         read(ModuleFile, (void*)ModName, (unsigned)pxdi->ssmod32.csize);
     730        lseek(ModuleFile,
     731              pxdi->pDirTab32[i].lfoStart + pxdi->lfaBase,
     732              SEEK_SET);
     733        read(ModuleFile,
     734             (void*)&pxdi->ssmod32.csBase,
     735             sizeof(SSMOD32));
     736        read(ModuleFile,
     737             (void*)ModName,
     738             (unsigned)pxdi->ssmod32.csize);
    678739        ModIndex = pxdi->pDirTab32[i].modindex;
    679740        ModName[pxdi->ssmod32.csize] = '\0';
     
    687748        {
    688749            // point to subsection
    689             lseek(ModuleFile, pxdi->pDirTab32[i].lfoStart + pxdi->lfaBase, SEEK_SET);
     750            lseek(ModuleFile,
     751                  pxdi->pDirTab32[i].lfoStart + pxdi->lfaBase,
     752                  SEEK_SET);
     753
    690754            switch (pxdi->pDirTab32[i].sst)
    691755            {
     
    694758                    while (bytesread < pxdi->pDirTab32[i].cb)
    695759                    {
    696                         bytesread += read(ModuleFile, (void *)&pxdi->sspub32.offset, sizeof(pxdi->sspub32));
    697                         bytesread += read(ModuleFile, (void *)ename, (unsigned)pxdi->sspub32.csize);
     760                        bytesread += read(ModuleFile,
     761                                          (void *)&pxdi->sspub32.offset,
     762                                          sizeof(pxdi->sspub32));
     763                        bytesread += read(ModuleFile,
     764                                          (void*)ename,
     765                                          (unsigned)pxdi->sspub32.csize);
    698766                        ename[pxdi->sspub32.csize] = '\0';
    699767                        if (    (pxdi->sspub32.segment == TrapSeg)
     
    705773                            read_types = TRUE;
    706774                            sprintf(pxdi->szNrPub,
    707                                     "%s %s (%s, seg %04lX : ofs %08lX\n",
    708                                     (pxdi->sspub32.type == 1) ? " Abs" : " ",
     775                                    "%s %s (%s)\n",
     776                                    (pxdi->sspub32.type == 1)
     777                                            ? " Abs"
     778                                            : " ",
    709779                                    ename,
    710                                     ModName, // ()
    711                                     (ULONG)pxdi->sspub32.segment,
    712                                     pxdi->sspub32.offset
     780                                    ModName
    713781                                );
    714782                            // but continue, because there might be a
  • trunk/src/helpers/except.c

    r55 r68  
    313313 *
    314314 *@@added V0.9.2 (2000-03-10) [umoeller]
     315 *@@changed V0.9.12 (2001-05-12) [umoeller]: added seg:ofs to output always
    315316 */
    316317
     
    338339        // error:
    339340        fprintf(file,
    340                 " %-8s:%lu  Error: DosQueryModFromEIP returned %lu\n",
     341                " %-8s Error: DosQueryModFromEIP returned %lu\n",
    341342                szMod1,
    342                 ulObject,
    343343                arc);
    344344    }
     
    348348
    349349        fprintf(file,
    350                 " %-8s:%lu   ",
     350                " %-8s %02lX:%08lX\n                                 ",
    351351                szMod1,
    352                 ulObject);
     352                ulObject + 1,       // V0.9.12 (2001-05-12) [umoeller]
     353                ulOffset);          // V0.9.12 (2001-05-12) [umoeller]
    353354
    354355        DosQueryModuleName(hmod1, sizeof(szFullName), szFullName);
    355 
    356356        dbgPrintStackFrame(file,
    357357                           szFullName,
     
    381381    PULONG pulStackWord = 0;
    382382
    383     fprintf(file, "\n\nStack frames:\n              Address   Module:Object\n");
     383    fprintf(file, "\n\nStack frames:\n              Address   Module   seg:ofs\n");
    384384
    385385    // first the trapping address itself
  • trunk/src/helpers/helpers_post.in

    r56 r68  
    196196$(OUTPUTDIR)\xprf.obj:  $(@B).c $(HLPINC)\$(@B).h \
    197197               $(PROJECTINC)\setup.h \
    198                $(HLPINC)\linklist.h
     198               $(HLPINC)\linklist.h $(HLPINC)\prfh.h
    199199
    200200$(OUTPUTDIR)\xprf2.obj:  $(@B).c $(HLPINC)\xprf.h \
    201201               $(PROJECTINC)\setup.h \
    202                $(INC)\expat\expat.h \
    203                $(HLPINC)\linklist.h $(HLPINC)\stringh.h $(HLPINC)\xstring.h
     202               $(HLPINC)\dosh.h $(HLPINC)\prfh.h $(HLPINC)\stringh.h
    204203
    205204$(OUTPUTDIR)\xstring.obj:  $(@B).c $(HLPINC)\$(@B).h \
  • trunk/src/helpers/prfh.c

    r38 r68  
    7070 *
    7171 *      <B>Example</B> for iterating over a keys list:
     72 *
    7273 +          PSZ pszKeysList = prfhQueryKeysForApp(...);
    7374 +          if (pszKeysList)
     
    8586 *      You can also use this function to query the applications
    8687 *      list for hIni, if you specifiy pszApp as NULL.
    87  */
    88 
    89 PSZ prfhQueryKeysForApp(HINI hIni,      // in: INI handle (can be HINI_USER or HINI_SYSTEM)
    90                         const char *pcszApp)     // in: application to query list for (or NULL for applications list)
    91 {
     88 *
     89 *@@changed V0.9.12 (2001-05-12) [umoeller]: changed prototypes to return APIRET now
     90 */
     91
     92APIRET prfhQueryKeysForApp(HINI hIni,      // in: INI handle (can be HINI_USER or HINI_SYSTEM)
     93                           const char *pcszApp, // in: application to query list for (or NULL for applications list)
     94                           PSZ *ppszKeys)   // out: keys list (newly allocated)
     95{
     96    APIRET  arc = NO_ERROR;
    9297    PSZ     pKeys = NULL;
    9398    ULONG   ulSizeOfKeysList = 0;
    9499
    95100    // get size of keys list for pszApp
    96     if (PrfQueryProfileSize(hIni, (PSZ)pcszApp, NULL, &ulSizeOfKeysList))
     101    if (    (!PrfQueryProfileSize(hIni, (PSZ)pcszApp, NULL, &ulSizeOfKeysList))
     102         || (ulSizeOfKeysList == 0)
     103       )
     104        arc = PRFERR_KEYSLIST;
     105    else
    97106    {
    98107        pKeys = (PSZ)malloc(ulSizeOfKeysList);
    99         if (!PrfQueryProfileData(hIni, (PSZ)pcszApp, NULL, pKeys, &ulSizeOfKeysList))
    100         {
     108        if (!pKeys)
     109            arc = ERROR_NOT_ENOUGH_MEMORY;
     110        else
     111            if (!PrfQueryProfileData(hIni, (PSZ)pcszApp, NULL, pKeys, &ulSizeOfKeysList))
     112                arc = PRFERR_KEYSLIST;
     113    }
     114
     115    if (!arc)       // V0.9.12 (2001-05-12) [umoeller]
     116        *ppszKeys = pKeys;
     117    else
     118        if (pKeys)
    101119            free(pKeys);
    102             pKeys = NULL;
    103         }
    104     }
    105     return (pKeys);
     120
     121    return (arc);
    106122}
    107123
     
    295311 *      Returns:
    296312 *      --  0: no error
     313 *
    297314 *      --  PRFERR_DATASIZE: couldn't query data size for key
     315 *
    298316 *      --  PRFERR_MEMORY: couldn't allocate memory
     317 *
    299318 *      --  PRFERR_READ: couldn't read data from source (PrfQueryProfileData error)
     319 *
    300320 *      --  PRFERR_WRITE: couldn't write data to target (PrfWriteProfileData error)
    301321 *
     
    303323 */
    304324
    305 ULONG prfhCopyKey(HINI hiniSource,       // in: source profile (can be HINI_USER or HINI_SYSTEM)
    306                   const char *pcszSourceApp,      // in: source application
    307                   const char *pcszKey,            // in: source/target key
    308                   HINI hiniTarget,       // in: target profile (can be HINI_USER or HINI_SYSTEM)
    309                   const char *pcszTargetApp)      // in: target app
     325APIRET prfhCopyKey(HINI hiniSource,       // in: source profile (can be HINI_USER or HINI_SYSTEM)
     326                   const char *pcszSourceApp,      // in: source application
     327                   const char *pcszKey,            // in: source/target key
     328                   HINI hiniTarget,       // in: target profile (can be HINI_USER or HINI_SYSTEM)
     329                   const char *pcszTargetApp)      // in: target app
    310330{
    311331    ULONG   ulSizeOfData = 0,
     
    365385 *
    366386 *      You can use this function in several contexts:
     387 *
    367388 *      -- copy one application within the same profile
    368389 *         (i.e. hiniSource == hiniTarget);
    369390 *         in this case, pszSourceApp must be != pszTargetApp;
     391 *
    370392 *      -- copy an application from one profile to another
    371393 *         (i.e. hiniSource != hiniTarget);
     
    375397 *      WARNING: This does _not_ check for whether the target
    376398 *      application exists already. This has two consequences:
     399 *
    377400 *      --  existing data will be overwritten without warning;
     401 *
    378402 *      --  if the existing target application has keys that are
    379403 *          not in the source application, they are not deleted.
     
    383407 *      So you should delete the target application before
    384408 *      calling this function, like this:
     409 *
    385410 +          PrfWriteProfileString(hiniTarget, pszTargetApp, NULL, NULL);
    386411 *
     
    407432 */
    408433
    409 ULONG prfhCopyApp(HINI hiniSource,   // in: source profile (can be HINI_USER or HINI_SYSTEM)
    410                   const char *pcszSourceApp,  // in: source application
    411                   HINI hiniTarget,   // in: target profile (can be HINI_USER or HINI_SYSTEM)
    412                   const char *pcszTargetApp,  // in: name of pszSourceApp in hiniTarget
    413                   PSZ pszErrorKey)   // out: failing key in case of error; ptr can be NULL
    414 {
    415     ULONG   ulrc;
    416     PSZ pszKeysList;
     434APIRET prfhCopyApp(HINI hiniSource,   // in: source profile (can be HINI_USER or HINI_SYSTEM)
     435                   const char *pcszSourceApp,  // in: source application
     436                   HINI hiniTarget,   // in: target profile (can be HINI_USER or HINI_SYSTEM)
     437                   const char *pcszTargetApp,  // in: name of pszSourceApp in hiniTarget
     438                   PSZ pszErrorKey)   // out: failing key in case of error; ptr can be NULL
     439{
     440    APIRET  arc = NO_ERROR;
     441    PSZ     pszKeysList = NULL;
    417442
    418443    if (pszErrorKey)
    419444        *pszErrorKey = 0;
    420445
    421     pszKeysList = prfhQueryKeysForApp(hiniSource, (PSZ)pcszSourceApp);
    422     if (pszKeysList)
     446    if (!(arc = prfhQueryKeysForApp(hiniSource,
     447                                    (PSZ)pcszSourceApp,
     448                                    &pszKeysList)))
    423449    {
    424450        PSZ pKey2 = pszKeysList;
     
    427453        {
    428454            // copy this key
    429             ulrc = prfhCopyKey(hiniSource,
    430                                pcszSourceApp,
    431                                pKey2,
    432                                hiniTarget,
    433                                pcszTargetApp);
    434             if (ulrc)
     455            arc = prfhCopyKey(hiniSource,
     456                              pcszSourceApp,
     457                              pKey2,
     458                              hiniTarget,
     459                              pcszTargetApp);
     460            if (arc)
    435461            {
    436462                // error: copy failing key to buffer
     
    444470        free (pszKeysList);
    445471    }
    446     else
    447         ulrc = PRFERR_KEYSLIST;
    448 
    449     return (ulrc);
     472
     473    return (arc);
    450474}
    451475
  • trunk/src/helpers/syssound.c

    r59 r68  
    467467    {
    468468        // get applications list for sounds list in MMPM.INI
    469         PSZ pszKeysList = prfhQueryKeysForApp(hiniMMPM,
    470                                               MMINIKEY_SYSSOUNDS); // "MMPM2_AlarmSounds"
    471         if (pszKeysList)
     469        PSZ pszKeysList = NULL;
     470        if (!(arc = prfhQueryKeysForApp(hiniMMPM,
     471                                        MMINIKEY_SYSSOUNDS, // "MMPM2_AlarmSounds"
     472                                        &pszKeysList)))
    472473        {
    473474            PSZ     pKey2 = pszKeysList;
     
    594595
    595596            // get applications list for sounds list in MMPM.INI
    596             PSZ pszMMPMKeysList = prfhQueryKeysForApp(hiniMMPM,
    597                                                   MMINIKEY_SYSSOUNDS); // "MMPM2_AlarmSounds"
    598             if (pszMMPMKeysList)
     597            PSZ pszMMPMKeysList = NULL;
     598            if (!(arc = prfhQueryKeysForApp(hiniMMPM,
     599                                            MMINIKEY_SYSSOUNDS,// "MMPM2_AlarmSounds"
     600                                            &pszMMPMKeysList)))
    599601            {
    600602                PSZ     pMMPMKey2 = pszMMPMKeysList,
  • trunk/src/helpers/timer.c

    r44 r68  
    144144 ********************************************************************/
    145145
    146 // timers thread
    147 // HMTX                G_hmtxTimers = NULLHANDLE;  // timers lock mutex
    148 // THREADINFO          G_tiTimers = {0};           // timers thread (only running
    149                                                 // if any timers were requested)
    150 // BOOL                G_fTimersThreadRunning = FALSE;
    151 // LINKLIST            G_llTimers;         // linked list of XTIMER pointers
    152 
    153 /*
    154  *@@ fntTimersThread:
    155  *      the actual thread which fires the timers by
    156  *      posting WM_TIMER messages to the respecive
    157  *      target windows when a timer has elapsed.
    158  *
    159  *      This thread is dynamically started when the
    160  *      first timer is started thru tmrStartXTimer.
    161  *      It is automatically stopped (to be precise:
    162  *      it terminates itself) when the last timer
    163  *      is stopped thru tmrStopXTimer, which then
    164  *      sets the thread's fExit flag to TRUE.
    165  *
    166  *@@changed V0.9.7 (2000-12-08) [umoeller]: got rid of dtGetULongTime
    167  */
    168 
    169 /* void _Optlink fntTimersThread(PTHREADINFO ptiMyself)
    170 {
    171     ULONG       ulInterval = 25;
    172     HAB         hab = WinInitialize(0);
    173     BOOL        fLocked = FALSE;
    174 
    175     // linked list of timers found to be invalid;
    176     // this holds LISTNODE pointers from the global
    177     // list to be removed
    178     LINKLIST    llInvalidTimers;
    179     lstInit(&llInvalidTimers,
    180             FALSE);     // no auto-free
    181 
    182     #ifdef __DEBUG__
    183         DosBeep(3000, 30);
    184     #endif
    185 
    186     // keep running while we have timers
    187     while (!ptiMyself->fExit)
    188     {
    189         // ULONG ulNesting = 0;
    190 
    191         ULONG ulTimeNow;
    192 
    193         DosSleep(ulInterval);
    194 
    195         // minimum interval: 100 ms; this is lowered
    196         // if we find any timers in the list which
    197         // have a lower timeout to make sure we can
    198         // fire at a lower interval...
    199         ulInterval = 100;
    200 
    201         // DosEnterMustComplete(&ulNesting);
    202 
    203         TRY_LOUD(excpt1)
    204         {
    205             fLocked = LockTimers();
    206             if (fLocked)
    207             {
    208             } // end if (fLocked)
    209         }
    210         CATCH(excpt1) { } END_CATCH();
    211 
    212         if (fLocked)
    213         {
    214             UnlockTimers();
    215             fLocked = FALSE;
    216         }
    217 
    218         // DosExitMustComplete(&ulNesting);
    219 
    220     } // end while (!ptiMyself->fExit)
    221 
    222     WinTerminate(hab);
    223 
    224     #ifdef __DEBUG__
    225         DosBeep(1500, 30);
    226     #endif
    227 } */
     146HMTX                G_hmtxTimers = NULLHANDLE;  // timers lock mutex
    228147
    229148/* ******************************************************************
     
    232151 *
    233152 ********************************************************************/
     153
     154/*
     155 *@@ LockTimers:
     156 *
     157 *@@added V0.9.12 (2001-05-12) [umoeller]
     158 */
     159
     160BOOL LockTimers(VOID)
     161{
     162    if (!G_hmtxTimers)
     163        return (!DosCreateMutexSem(NULL,
     164                                   &G_hmtxTimers,
     165                                   0,
     166                                   TRUE));      // request!
     167    else
     168        return (!WinRequestMutexSem(G_hmtxTimers, SEM_INDEFINITE_WAIT));
     169}
     170
     171/*
     172 *@@ UnlockTimers:
     173 *
     174 *@@added V0.9.12 (2001-05-12) [umoeller]
     175 */
     176
     177VOID UnlockTimers(VOID)
     178{
     179    DosReleaseMutexSem(G_hmtxTimers);
     180}
    234181
    235182/*
     
    239186 *      _and_ timer ID.
    240187 *
    241  *      Internal function.
     188 *      Internal function. Caller must hold the mutex.
    242189 */
    243190
     
    272219 *      the global linked list of running timers.
    273220 *
    274  *      Internal function.
     221 *      Internal function. Caller must hold the mutex.
    275222 */
    276223
     
    339286 *
    340287 *@@added V0.9.9 (2001-02-28) [umoeller]
     288 *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection
    341289 */
    342290
     
    347295        if (pSet->pvllXTimers)
    348296        {
    349             PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;
    350 
    351             PLISTNODE pTimerNode;
    352 
    353             while (pTimerNode = lstQueryFirstNode(pllXTimers))
     297            if (LockTimers())
    354298            {
    355                 PXTIMER pTimer = (PXTIMER)pTimerNode->pItemData;
    356                 RemoveTimer(pSet, pTimer);
     299                PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;
     300
     301                PLISTNODE pTimerNode;
     302
     303                while (pTimerNode = lstQueryFirstNode(pllXTimers))
     304                {
     305                    PXTIMER pTimer = (PXTIMER)pTimerNode->pItemData;
     306                    RemoveTimer(pSet, pTimer);
     307                }
     308
     309                lstFree(pllXTimers);
     310
     311                UnlockTimers();
    357312            }
    358 
    359             lstFree(pllXTimers);
    360313        }
    361314
     
    373326 *      goes thru all XTimers in the sets and starts
    374327 *      or stops the PM timer with a decent frequency.
     328 *
     329 *      Internal function. Caller must hold the mutex.
    375330 *
    376331 *@@added V0.9.9 (2001-03-07) [umoeller]
     
    435390 *
    436391 *@@added V0.9.9 (2001-02-28) [umoeller]
     392 *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection
    437393 */
    438394
     
    441397    if (pSet && pSet->pvllXTimers)
    442398    {
    443         PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;
    444         // go thru all XTimers and see which one
    445         // has elapsed; for all of these, post WM_TIMER
    446         // to the target window proc
    447         PLISTNODE pTimerNode = lstQueryFirstNode(pllXTimers);
    448 
    449         if (!pTimerNode)
     399        if (LockTimers())
    450400        {
    451             // no timers left:
    452             if (pSet->idPMTimerRunning)
     401            PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;
     402            // go thru all XTimers and see which one
     403            // has elapsed; for all of these, post WM_TIMER
     404            // to the target window proc
     405            PLISTNODE pTimerNode = lstQueryFirstNode(pllXTimers);
     406
     407            if (!pTimerNode)
    453408            {
    454                 // but PM timer running:
    455                 // stop it
    456                 WinStopTimer(pSet->hab,
    457                              pSet->hwndOwner,
    458                              pSet->idPMTimer);
    459                 pSet->idPMTimerRunning = 0;
     409                // no timers left:
     410                if (pSet->idPMTimerRunning)
     411                {
     412                    // but PM timer running:
     413                    // stop it
     414                    WinStopTimer(pSet->hab,
     415                                 pSet->hwndOwner,
     416                                 pSet->idPMTimer);
     417                    pSet->idPMTimerRunning = 0;
     418                }
     419
     420                pSet->ulPMTimeout = 0;
    460421            }
    461 
    462             pSet->ulPMTimeout = 0;
    463         }
    464         else
    465         {
    466             // we have timers:
    467             BOOL    fFoundInvalid = FALSE;
    468 
    469             ULONG   // ulInterval = 100,
    470                     ulTimeNow = 0;
    471 
    472             // linked list of timers found to be invalid;
    473             // this holds LISTNODE pointers from the global
    474             // list to be removed
    475             LINKLIST    llInvalidTimers;
    476             lstInit(&llInvalidTimers,
    477                     FALSE);     // no auto-free
    478 
    479             // get current time
    480             DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
    481                             &ulTimeNow, sizeof(ulTimeNow));
    482 
    483             while (pTimerNode)
     422            else
    484423            {
    485                 PXTIMER pTimer = (PXTIMER)pTimerNode->pItemData;
    486 
    487                 if (pTimer->ulNextFire < ulTimeNow)
     424                // we have timers:
     425                BOOL    fFoundInvalid = FALSE;
     426
     427                ULONG   // ulInterval = 100,
     428                        ulTimeNow = 0;
     429
     430                // linked list of timers found to be invalid;
     431                // this holds LISTNODE pointers from the global
     432                // list to be removed
     433                LINKLIST    llInvalidTimers;
     434                lstInit(&llInvalidTimers,
     435                        FALSE);     // no auto-free
     436
     437                // get current time
     438                DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
     439                                &ulTimeNow, sizeof(ulTimeNow));
     440
     441                while (pTimerNode)
    488442                {
    489                     // this timer has elapsed:
    490                     // fire!
    491                     if (WinIsWindow(pSet->hab,
    492                                     pTimer->hwndTarget))
     443                    PXTIMER pTimer = (PXTIMER)pTimerNode->pItemData;
     444
     445                    if (pTimer->ulNextFire < ulTimeNow)
    493446                    {
    494                         // window still valid:
    495                         // get the window's window proc
    496                         PFNWP pfnwp = (PFNWP)WinQueryWindowPtr(pTimer->hwndTarget,
    497                                                                QWP_PFNWP);
    498                         // call the window proc DIRECTLY
    499                         pfnwp(pTimer->hwndTarget,
    500                               WM_TIMER,
    501                               (MPARAM)pTimer->usTimerID,
    502                               0);
    503                         pTimer->ulNextFire = ulTimeNow + pTimer->ulTimeout;
     447                        // this timer has elapsed:
     448                        // fire!
     449                        if (WinIsWindow(pSet->hab,
     450                                        pTimer->hwndTarget))
     451                        {
     452                            // window still valid:
     453                            // get the window's window proc
     454                            PFNWP pfnwp = (PFNWP)WinQueryWindowPtr(pTimer->hwndTarget,
     455                                                                   QWP_PFNWP);
     456                            // call the window proc DIRECTLY
     457                            pfnwp(pTimer->hwndTarget,
     458                                  WM_TIMER,
     459                                  (MPARAM)pTimer->usTimerID,
     460                                  0);
     461                            pTimer->ulNextFire = ulTimeNow + pTimer->ulTimeout;
     462                        }
     463                        else
     464                        {
     465                            // window has been destroyed:
     466                            lstAppendItem(&llInvalidTimers,
     467                                          (PVOID)pTimerNode);
     468                            fFoundInvalid = TRUE;
     469                        }
     470                    } // end if (pTimer->ulNextFire < ulTimeNow)
     471
     472                    // next timer
     473                    pTimerNode = pTimerNode->pNext;
     474                } // end while (pTimerNode)
     475
     476                // destroy invalid timers, if any
     477                if (fFoundInvalid)
     478                {
     479                    PLISTNODE pNodeNode = lstQueryFirstNode(&llInvalidTimers);
     480                    while (pNodeNode)
     481                    {
     482                        PLISTNODE pNode2Remove = (PLISTNODE)pNodeNode->pItemData;
     483                        lstRemoveNode(pllXTimers,
     484                                      pNode2Remove);
     485                        pNodeNode = pNodeNode->pNext;
    504486                    }
    505                     else
    506                     {
    507                         // window has been destroyed:
    508                         lstAppendItem(&llInvalidTimers,
    509                                       (PVOID)pTimerNode);
    510                         fFoundInvalid = TRUE;
    511                     }
    512                 } // end if (pTimer->ulNextFire < ulTimeNow)
    513 
    514                 // next timer
    515                 pTimerNode = pTimerNode->pNext;
    516             } // end while (pTimerNode)
    517 
    518             // destroy invalid timers, if any
    519             if (fFoundInvalid)
    520             {
    521                 PLISTNODE pNodeNode = lstQueryFirstNode(&llInvalidTimers);
    522                 while (pNodeNode)
    523                 {
    524                     PLISTNODE pNode2Remove = (PLISTNODE)pNodeNode->pItemData;
    525                     lstRemoveNode(pllXTimers,
    526                                   pNode2Remove);
    527                     pNodeNode = pNodeNode->pNext;
     487                    lstClear(&llInvalidTimers);
     488
     489                    AdjustPMTimer(pSet);
    528490                }
    529                 lstClear(&llInvalidTimers);
    530 
    531                 AdjustPMTimer(pSet);
    532             }
    533         } // end else if (!pTimerNode)
    534     }
     491            } // end else if (!pTimerNode)
     492
     493            UnlockTimers();
     494        } // end if (LockTimers())
     495    } // end if (pSet && pSet->pvllXTimers)
    535496}
    536497
     
    552513 *
    553514 *@@changed V0.9.7 (2000-12-08) [umoeller]: got rid of dtGetULongTime
     515 *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection
    554516 */
    555517
     
    565527    if (pSet && pSet->pvllXTimers)
    566528    {
    567         PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;
    568 
    569         if ((hwnd) && (ulTimeout))
     529        if (LockTimers())
    570530        {
    571             PXTIMER pTimer;
    572 
    573             // check if this timer exists already
    574             pTimer = FindTimer(pSet,
    575                                hwnd,
    576                                usTimerID);
    577             if (pTimer)
     531            PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;
     532
     533            if ((hwnd) && (ulTimeout))
    578534            {
    579                 // exists already: reset only
    580                 ULONG ulTimeNow;
    581                 DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
    582                                 &ulTimeNow, sizeof(ulTimeNow));
    583                 pTimer->ulNextFire = ulTimeNow + ulTimeout;
    584                 usrc = pTimer->usTimerID;
    585             }
    586             else
    587             {
    588                 // new timer needed:
    589                 pTimer = (PXTIMER)malloc(sizeof(XTIMER));
     535                PXTIMER pTimer;
     536
     537                // check if this timer exists already
     538                pTimer = FindTimer(pSet,
     539                                   hwnd,
     540                                   usTimerID);
    590541                if (pTimer)
    591542                {
     543                    // exists already: reset only
    592544                    ULONG ulTimeNow;
    593545                    DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
    594546                                    &ulTimeNow, sizeof(ulTimeNow));
    595                     pTimer->usTimerID = usTimerID;
    596                     pTimer->hwndTarget = hwnd;
    597                     pTimer->ulTimeout = ulTimeout;
    598547                    pTimer->ulNextFire = ulTimeNow + ulTimeout;
    599 
    600                     lstAppendItem(pllXTimers,
    601                                   pTimer);
    602548                    usrc = pTimer->usTimerID;
    603549                }
    604             }
    605 
    606             if (usrc)
    607             {
    608                 // timer created or reset:
    609                 AdjustPMTimer(pSet);
    610             }
    611         } // if ((hwnd) && (ulTimeout))
    612     }
    613 
    614     // _Pmpf((__FUNCTION__ ": leaving, returning %d", usrc));
     550                else
     551                {
     552                    // new timer needed:
     553                    pTimer = (PXTIMER)malloc(sizeof(XTIMER));
     554                    if (pTimer)
     555                    {
     556                        ULONG ulTimeNow;
     557                        DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
     558                                        &ulTimeNow, sizeof(ulTimeNow));
     559                        pTimer->usTimerID = usTimerID;
     560                        pTimer->hwndTarget = hwnd;
     561                        pTimer->ulTimeout = ulTimeout;
     562                        pTimer->ulNextFire = ulTimeNow + ulTimeout;
     563
     564                        lstAppendItem(pllXTimers,
     565                                      pTimer);
     566                        usrc = pTimer->usTimerID;
     567                    }
     568                }
     569
     570                if (usrc)
     571                {
     572                    // timer created or reset:
     573                    AdjustPMTimer(pSet);
     574                }
     575            } // if ((hwnd) && (ulTimeout))
     576
     577            UnlockTimers();
     578        }
     579    }
    615580
    616581    return (usrc);
     
    625590 *
    626591 *      Returns TRUE if the timer was stopped.
     592 *
     593 *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection
    627594 */
    628595
     
    634601    if (pSet && pSet->pvllXTimers)
    635602    {
    636         PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;
    637         BOOL fLocked = FALSE;
    638 
    639         PXTIMER pTimer = FindTimer(pSet,
    640                                    hwnd,
    641                                    usTimerID);
    642         if (pTimer)
     603        if (LockTimers())
    643604        {
    644             RemoveTimer(pSet, pTimer);
    645             // recalculate
    646             AdjustPMTimer(pSet);
    647             brc = TRUE;
     605            PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;
     606            BOOL fLocked = FALSE;
     607
     608            PXTIMER pTimer = FindTimer(pSet,
     609                                       hwnd,
     610                                       usTimerID);
     611            if (pTimer)
     612            {
     613                RemoveTimer(pSet, pTimer);
     614                // recalculate
     615                AdjustPMTimer(pSet);
     616                brc = TRUE;
     617            }
     618
     619            UnlockTimers();
    648620        }
    649621    }
  • trunk/src/helpers/xprf2.c

    r14 r68  
    153153{
    154154    APIRET arc = NO_ERROR;
    155     PSZ pszKeysList;
     155    PSZ pszKeysList = NULL;
    156156
    157157    if (pszErrorKey)
    158158        *pszErrorKey = 0;
    159159
    160     pszKeysList = prfhQueryKeysForApp(hiniSource, pszSourceApp);
    161     if (pszKeysList)
     160    if (!(arc = prfhQueryKeysForApp(hiniSource,
     161                                    pszSourceApp,
     162                                    &pszKeysList)))
    162163    {
    163164        PSZ pKey2 = pszKeysList;
Note: See TracChangeset for help on using the changeset viewer.