Changeset 68
- Timestamp:
- May 15, 2001, 6:15:18 PM (24 years ago)
- Location:
- trunk
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/helpers/comctl.h
r65 r68 102 102 { 103 103 USHORT usStartAngle, 104 // angle to start with (0%).104 // for "pie chart" mode, angle to start with (0%). 105 105 // This must be in the range of 0 to 360 degrees, 106 106 // with 0 degrees being the rightmost point 107 107 // of the arc. 108 108 109 // All degree values are counter-clockwise from that point. 109 110 // 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 110 128 usSweepAngle; 111 // the maximum angle to use for 100%. 129 // the maximum angle to use for 100%, in addition to 130 // usStartAngle. 112 131 // This must be in the range of 0 to 360 degrees, 113 132 // with 0 degrees being usStartAngle. 114 133 // 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 119 154 ULONG cValues; 120 155 // data item count; the arrays in *padValues and *palColors … … 124 159 // pointer to an array of double values; 125 160 // 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. 128 166 // Otherwise, this array must have cValues items. 129 167 LONG* palColors; 130 168 // pointer to an array of LONG RGB colors; 131 169 // 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. 133 172 // This _must_ be specified if padValues is != NULL. 134 173 // This array must have cValues items. … … 141 180 } CHARTDATA, *PCHARTDATA; 142 181 143 // chart display mode: currently only PCF_PIECHART is supported.182 // chart display mode: 144 183 #define CHS_PIECHART 0x0000 184 #define CHS_BARCHART 0x0001 145 185 146 186 // 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; 149 190 // 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 151 193 // compared to surface; 152 194 // CHARTSTYLE.ulThickness defines thickness 153 195 196 #define CHS_DRAWLINES 0x0800 // draw lines between pie slices 197 // added V0.9.12 (2001-05-03) [umoeller] 198 154 199 #define CHS_DESCRIPTIONS 0x1000 // show descriptions 155 200 #define CHS_DESCRIPTIONS_3D 0x3000 // same as CHS_DESCRIPTIONS, but shaded 156 201 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 158 205 159 206 /* … … 165 212 { 166 213 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 169 220 // size. A value of 1 would make the pie chart 170 221 // consume all available space. A value of .5 … … 172 223 // control's space. The pie chart is always 173 224 // 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 175 228 // relative to the window size. To calculate the 176 229 // description positions, the control calculates … … 191 244 } CHARTSTYLE, *PCHARTSTYLE; 192 245 193 /*194 *@@ CHARTCDATA:195 * pie chart control data. Composed from the various196 * chart initialization data.197 * Stored in QWL_USER of the subclassed static control.198 * Not available to the application.199 */200 201 typedef struct _CHARTCDATA202 {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 bitmap208 HPS hpsMem; // memory presentation space for bitmap209 CHARTDATA cd; // chart data: initialized to null values210 CHARTSTYLE cs; // chart style: initialized to null values211 212 HBITMAP hbmChart; // chart bitmap (for quick painting)213 HRGN* paRegions; // pointer to array of GPI regions for each data item214 215 // user interaction data:216 LONG lSelected; // zero-based index of selected chart item, or -1 if none217 BOOL fHasFocus;218 } CHARTCDATA, *PCHARTCDATA;219 220 246 HBITMAP ctlCreateChartBitmap(HPS hpsMem, 221 247 LONG lcx, … … 229 255 BOOL ctlChartFromStatic(HWND hwndStatic); 230 256 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; 236 373 237 374 /* ****************************************************************** -
trunk/include/helpers/prfh.h
r41 r68 48 48 #define PRFERR_KEY_EXISTS 10010 49 49 50 PSZ prfhQueryKeysForApp(HINI hIni, 51 const char *pcszApp); 50 APIRET prfhQueryKeysForApp(HINI hIni, 51 const char *pcszApp, 52 PSZ *ppszKeys); 52 53 53 54 #ifdef __XWPMEMDEBUG__ // setup.h, helpers\memdebug.c … … 104 105 VOID prfhQueryCountrySettings(PCOUNTRYSETTINGS pcs); 105 106 106 ULONGprfhCopyKey(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); 111 112 112 ULONGprfhCopyApp(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); 117 118 118 119 ULONG prfhRenameKey(HINI hini, -
trunk/src/helpers/cctl_chart.c
r63 r68 2 2 /* 3 3 *@@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. 6 8 * 7 9 * 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); 8 159 * 9 160 * Note: Version numbering in this file relates to XWorkplace version … … 86 237 /* ****************************************************************** 87 238 * 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 251 typedef 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 * 88 273 * Chart Control 89 274 * 90 275 ********************************************************************/ 276 277 /* 278 *@@ DrawCenteredText: 279 * 280 *@@added V0.9.12 (2001-05-03) [umoeller] 281 */ 282 283 VOID 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 356 VOID 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 559 VOID 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 } 91 955 92 956 /* … … 119 983 * 120 984 * If (paRegions != NULL), this function will 121 * create GPI regions fordata item. Each GPI985 * create a GPI region for each data item. Each GPI 122 986 * region will then contain the outline of the 123 987 * corresponding pie chart slice. This allows … … 137 1001 * This returns NULLHANDLE if an error occured. 138 1002 * This can mean the following: 1003 * 139 1004 * -- The data is invalid, because the total is 0. 1005 * 140 1006 * -- 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 141 1010 */ 142 1011 … … 158 1027 for (ul = 0; ul < pChartData->cValues; ul++) 159 1028 { 1029 _Pmpf((" dThis is %d", (ULONG)(*pdThis))); // printf 1030 160 1031 dTotal += *pdThis; 161 1032 pdThis++; 162 1033 } 1034 1035 _Pmpf((__FUNCTION__ ": dTotal is %d", (ULONG)dTotal)); // printf 163 1036 164 1037 // avoid division by zero … … 166 1039 { 167 1040 RECTL rclWholeStatic; 168 ULONG ulYBottomNow = 0;169 170 1041 // get window rectangle (bottom left is 0, 0) 171 1042 rclWholeStatic.xLeft = 0; … … 181 1052 // successfully created: 182 1053 183 // allocate array for storing text positions later184 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 191 1054 // associate bitmap with memory PS 192 1055 GpiSetBitmap(hpsMem, hbmReturn); … … 201 1064 &rclWholeStatic); 202 1065 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); 538 1082 539 1083 // deselect (free) bitmap … … 551 1095 * 552 1096 *@@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 553 1098 */ 554 1099 … … 557 1102 if (pChtCData) 558 1103 { 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 559 1121 // bitmap already created? 560 1122 if (pChtCData->hbmChart) 561 1123 { 562 1124 // free current bitmap 563 //GpiSetBitmap(pChtCData->hpsMem, NULLHANDLE);1125 GpiSetBitmap(pChtCData->hpsMem, NULLHANDLE); 564 1126 // delete bitmap; fails if not freed! 565 GpiDeleteBitmap(pChtCData->hbmChart); 1127 if (!GpiDeleteBitmap(pChtCData->hbmChart)) 1128 _Pmpf((__FUNCTION__ ": GpiDeleteBitmap failed.")); 566 1129 pChtCData->hbmChart = NULLHANDLE; 567 1130 } 568 1131 569 // destroy regions, but not the array itself 570 // (this is done in CleanupData) 571 if (pChtCData->paRegions) 1132 if (pChtCData->hpsMem) 572 1133 { 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; 586 1141 } 587 1142 } … … 647 1202 * 648 1203 *@@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 649 1205 */ 650 1206 … … 663 1219 CleanupData(pChtCData); 664 1220 665 // _Pmpf(("Setting up data"));666 667 if (pChtCData->hpsMem == NULLHANDLE)668 {669 // first call:670 // create a memory PS for the bitmap671 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 680 1221 pChtCData->cd.usStartAngle = pcdNew->usStartAngle; 681 1222 pChtCData->cd.usSweepAngle = pcdNew->usSweepAngle; … … 695 1236 696 1237 // 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 703 1241 { 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 } 710 1256 } 711 1257 … … 716 1262 717 1263 pChtCData->lSelected = -1; // none selected 1264 pChtCData->lSourceEmphasis = -1; // none selected 718 1265 719 1266 WinInvalidateRect(hwndChart, NULL, FALSE); … … 726 1273 * 727 1274 *@@added V0.9.2 (2000-02-29) [umoeller] 1275 *@@changed V0.9.12 (2001-05-03) [umoeller]: fixed major PM resource leaks 728 1276 */ 729 1277 … … 735 1283 RECTL rclStatic; 736 1284 WinQueryWindowRect(hwndChart, &rclStatic); 737 738 // _Pmpf(("ctl_fnwpChart: WM_PAINT, cValues: %d", pChtCData->cd.cValues));739 1285 740 1286 // do we have any values yet? … … 762 1308 SYSCLR_WINDOWTEXT); 763 1309 764 // yes: check if we created the bitmap 765 // already 1310 gpihSwitchToRGB(hps); 1311 1312 // check if the bitmap needs to be (re)created 766 1313 if (pChtCData->hbmChart == NULLHANDLE) 767 1314 { 768 1315 // no: do it now 769 1316 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) 782 1320 { 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 } 786 1347 } 787 788 789 gpihSwitchToRGB(hps);790 1348 791 1349 pChtCData->hbmChart = ctlCreateChartBitmap( … … 804 1362 pChtCData->paRegions); 805 1363 // out: regions array 806 // _Pmpf(("Created bitmap 0x%lX", pChtCData->hbmChart));807 1364 808 1365 // unset and delete font 809 GpiSetCharSet(pChtCData->hpsMem, LCID_DEFAULT);810 1366 if (lLCIDSet) 1367 { 1368 GpiSetCharSet(pChtCData->hpsMem, LCID_DEFAULT); 811 1369 GpiDeleteSetId(pChtCData->hpsMem, lLCIDSet); 1370 } 812 1371 813 1372 WinSetPointer(HWND_DESKTOP, hptrOld); … … 816 1375 if (pChtCData->hbmChart) 817 1376 { 1377 // draw the chart bitmap 818 1378 POINTL ptlDest = { 0, 0 }; 819 1379 WinDrawBitmap(hps, … … 824 1384 DBM_NORMAL); 825 1385 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]) 831 1396 { 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]); 843 1412 } 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 } 844 1442 } 845 1443 } … … 847 1445 848 1446 /* 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 1455 LONG 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 1496 VOID 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 1528 BOOL 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 /* 849 1572 *@@ ctl_fnwpChart: 850 1573 * window procedure for the "chart" control. … … 856 1579 *@@changed V0.9.2 (2000-02-29) [umoeller]: added resize support 857 1580 *@@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 858 1582 */ 859 1583 … … 887 1611 // _Pmpf(("CHTM_SETCHARTDATA, mp1: 0x%lX", mp1)); 888 1612 if (mp1) 889 { 890 PCHARTDATA pcdNew = (PCHARTDATA)mp1; 891 SetChartData(hwndChart, pChtCData, pcdNew); 892 } 1613 SetChartData(hwndChart, 1614 pChtCData, 1615 (PCHARTDATA)mp1); 893 1616 break; 894 1617 … … 943 1666 case CHTM_ITEMFROMPOINT: 944 1667 { 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 ) 954 1707 { 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); 980 1715 } 981 982 mrc = (MPARAM)lRegionFound; 983 break; } 1716 } 1717 break; 984 1718 985 1719 /* 986 * WM_BUTTON1 DOWN:987 * 1720 * WM_BUTTON1CLICK: 1721 * WM_CONTEXTMENU: V0.9.12 (2001-05-03) [umoeller] 988 1722 */ 989 1723 990 case WM_BUTTON1DOWN: 1724 case WM_BUTTON1CLICK: 1725 case WM_BUTTON1DBLCLK: 1726 case WM_CONTEXTMENU: 991 1727 if (pChtCData->cs.ulStyle & CHS_SELECTIONS) 992 1728 { 993 LONG lRegionFound = (LONG)WinSendMsg(hwndChart, 994 CHTM_ITEMFROMPOINT, 995 mp1, 996 NULL); 1729 LONG lRegionFound = FindItemFromPoint(pChtCData, 1730 SHORT1FROMMP(mp1), 1731 SHORT2FROMMP(mp1)); 997 1732 998 1733 // selections allowed: … … 1001 1736 WinSetFocus(HWND_DESKTOP, hwndChart); 1002 1737 // 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 1004 1749 { 1005 1750 // 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); 1009 1765 } 1010 1766 } … … 1047 1803 // resizing? 1048 1804 if (pswpNew->fl & SWP_SIZE) 1805 { 1049 1806 if (pChtCData->hbmChart) 1050 {1051 1807 // invalidate bitmap so that 1052 1808 // it will be recreated with new size 1053 1809 CleanupBitmap(pChtCData); 1054 WinInvalidateRect(hwndChart, NULL, FALSE); 1055 }1056 1810 1811 WinInvalidateRect(hwndChart, NULL, FALSE); 1812 } 1057 1813 // return default NULL 1058 1814 break; } … … 1103 1859 case WM_DESTROY: 1104 1860 CleanupBitmap(pChtCData); 1861 1105 1862 CleanupData(pChtCData); 1106 1863 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!"));1113 1864 free(pChtCData); 1114 1865 … … 1130 1881 * window procedure with ctl_fnwpChart. 1131 1882 * 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. 1251 1884 * 1252 1885 *@@added V0.9.0 [umoeller] -
trunk/src/helpers/cctl_tooltip.c
r66 r68 164 164 * 165 165 *@@added V0.9.12 (2001-04-28) [umoeller] 166 *@@changed V0.9.12 (2001-05-03) [umoeller]: this did nothing... fixed 166 167 */ 167 168 168 169 VOID UnlockSubclassedTools(VOID) 169 170 { 171 DosReleaseMutexSem(G_hmtxSubclassedTools); // was missing V0.9.12 (2001-05-03) [umoeller] 170 172 } 171 173 -
trunk/src/helpers/debug.c
r31 r68 366 366 367 367 /* 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 386 VOID 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 /* 368 397 *@@ dbgPrintDebugInfo: 369 398 * this is the main entry point into analyzing debug 370 399 * code. 400 * 371 401 * This analyzes a given address and tries to find 372 402 * debug code descriptions for this address. If found, … … 383 413 APIRET dbgPrintDebugInfo(FILE *LogFile, // out: log file to write to 384 414 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) 387 417 { 388 418 APIRET rc = 0; … … 391 421 static struct new_exe NewExeHeader; 392 422 423 ULONG ulSegment = Object + 1; // segment no. is object no. + 1 424 393 425 XDEBUGINFO xdi; 394 426 memset(&xdi, 0, sizeof(xdi)); … … 430 462 431 463 // 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 444 472 close(ModuleFile); 445 473 … … 451 479 if (ModuleFile != -1) 452 480 { 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 460 489 close(ModuleFile); 461 490 } 462 } // endif491 } 463 492 464 493 return rc; … … 473 502 */ 474 503 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) 476 507 { 477 508 fprintf(LogFile, "Out of memory!"); … … 479 510 return -1; 480 511 } 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) 482 515 { 483 516 fprintf(LogFile, "Error %u seeking segment table in %s\n", errno, FileName); … … 487 520 } 488 521 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) 490 526 { 491 527 fprintf(LogFile, "Error %u reading segment table from %s\n", errno, FileName); … … 494 530 return 10; 495 531 } 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 503 541 free(xdi.pseg); 504 542 close(ModuleFile); … … 508 546 { 509 547 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); 511 550 if (ModuleFile != -1) 512 551 { 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 520 560 close(ModuleFile); 521 561 } 522 } // endif562 } 523 563 return rc; 524 525 564 } 526 565 else … … 608 647 } 609 648 610 if (read(ModuleFile, (void *)&G_eodbug, 8) == -1) 649 if (read(ModuleFile, 650 (void *)&G_eodbug, 8) 651 == -1) 611 652 { 612 653 fprintf(LogFile, "Error %u reading debug info from %s\n", errno, FileName); … … 619 660 } 620 661 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) 622 666 { 623 667 fprintf(LogFile, "Error %u seeking base codeview data in %s\n", errno, FileName); … … 625 669 } 626 670 627 if (read(ModuleFile, (void *)&pxdi->base, 8) == -1) 671 if (read(ModuleFile, 672 (void *)&pxdi->base, 8) 673 == -1) 628 674 { 629 675 fprintf(LogFile, "Error %u reading base codeview data in %s\n", errno, FileName); … … 631 677 } 632 678 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) 634 683 { 635 684 fprintf(LogFile, "Error %u seeking dir codeview data in %s\n", errno, FileName); … … 637 686 } 638 687 639 if (read(ModuleFile, (void *)&numdir, 4) == -1) 688 if (read(ModuleFile, 689 (void *)&numdir, 4) 690 == -1) 640 691 { 641 692 fprintf(LogFile, "Error %u reading dir codeview data in %s\n", errno, FileName); … … 644 695 645 696 // 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) 649 700 { 650 701 fprintf(LogFile, "Out of memory!"); … … 652 703 } 653 704 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) 655 709 { 656 710 fprintf(LogFile, "Error %u reading codeview dir table from %s\n", errno, FileName); … … 667 721 continue; 668 722 } 723 669 724 NrPublic = 0x0; 670 725 NrSymbol = 0; … … 673 728 CurrSymSeg = 0; 674 729 // 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); 678 739 ModIndex = pxdi->pDirTab32[i].modindex; 679 740 ModName[pxdi->ssmod32.csize] = '\0'; … … 687 748 { 688 749 // 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 690 754 switch (pxdi->pDirTab32[i].sst) 691 755 { … … 694 758 while (bytesread < pxdi->pDirTab32[i].cb) 695 759 { 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); 698 766 ename[pxdi->sspub32.csize] = '\0'; 699 767 if ( (pxdi->sspub32.segment == TrapSeg) … … 705 773 read_types = TRUE; 706 774 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 : " ", 709 779 ename, 710 ModName, // () 711 (ULONG)pxdi->sspub32.segment, 712 pxdi->sspub32.offset 780 ModName 713 781 ); 714 782 // but continue, because there might be a -
trunk/src/helpers/except.c
r55 r68 313 313 * 314 314 *@@added V0.9.2 (2000-03-10) [umoeller] 315 *@@changed V0.9.12 (2001-05-12) [umoeller]: added seg:ofs to output always 315 316 */ 316 317 … … 338 339 // error: 339 340 fprintf(file, 340 " %-8s :%luError: DosQueryModFromEIP returned %lu\n",341 " %-8s Error: DosQueryModFromEIP returned %lu\n", 341 342 szMod1, 342 ulObject,343 343 arc); 344 344 } … … 348 348 349 349 fprintf(file, 350 " %-8s :%lu",350 " %-8s %02lX:%08lX\n ", 351 351 szMod1, 352 ulObject); 352 ulObject + 1, // V0.9.12 (2001-05-12) [umoeller] 353 ulOffset); // V0.9.12 (2001-05-12) [umoeller] 353 354 354 355 DosQueryModuleName(hmod1, sizeof(szFullName), szFullName); 355 356 356 dbgPrintStackFrame(file, 357 357 szFullName, … … 381 381 PULONG pulStackWord = 0; 382 382 383 fprintf(file, "\n\nStack frames:\n Address Module :Object\n");383 fprintf(file, "\n\nStack frames:\n Address Module seg:ofs\n"); 384 384 385 385 // first the trapping address itself -
trunk/src/helpers/helpers_post.in
r56 r68 196 196 $(OUTPUTDIR)\xprf.obj: $(@B).c $(HLPINC)\$(@B).h \ 197 197 $(PROJECTINC)\setup.h \ 198 $(HLPINC)\linklist.h 198 $(HLPINC)\linklist.h $(HLPINC)\prfh.h 199 199 200 200 $(OUTPUTDIR)\xprf2.obj: $(@B).c $(HLPINC)\xprf.h \ 201 201 $(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 204 203 205 204 $(OUTPUTDIR)\xstring.obj: $(@B).c $(HLPINC)\$(@B).h \ -
trunk/src/helpers/prfh.c
r38 r68 70 70 * 71 71 * <B>Example</B> for iterating over a keys list: 72 * 72 73 + PSZ pszKeysList = prfhQueryKeysForApp(...); 73 74 + if (pszKeysList) … … 85 86 * You can also use this function to query the applications 86 87 * 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 92 APIRET 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; 92 97 PSZ pKeys = NULL; 93 98 ULONG ulSizeOfKeysList = 0; 94 99 95 100 // 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 97 106 { 98 107 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) 101 119 free(pKeys); 102 pKeys = NULL; 103 } 104 } 105 return (pKeys); 120 121 return (arc); 106 122 } 107 123 … … 295 311 * Returns: 296 312 * -- 0: no error 313 * 297 314 * -- PRFERR_DATASIZE: couldn't query data size for key 315 * 298 316 * -- PRFERR_MEMORY: couldn't allocate memory 317 * 299 318 * -- PRFERR_READ: couldn't read data from source (PrfQueryProfileData error) 319 * 300 320 * -- PRFERR_WRITE: couldn't write data to target (PrfWriteProfileData error) 301 321 * … … 303 323 */ 304 324 305 ULONGprfhCopyKey(HINI hiniSource, // in: source profile (can be HINI_USER or HINI_SYSTEM)306 const char *pcszSourceApp, // in: source application307 const char *pcszKey, // in: source/target key308 HINI hiniTarget, // in: target profile (can be HINI_USER or HINI_SYSTEM)309 const char *pcszTargetApp) // in: target app325 APIRET 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 310 330 { 311 331 ULONG ulSizeOfData = 0, … … 365 385 * 366 386 * You can use this function in several contexts: 387 * 367 388 * -- copy one application within the same profile 368 389 * (i.e. hiniSource == hiniTarget); 369 390 * in this case, pszSourceApp must be != pszTargetApp; 391 * 370 392 * -- copy an application from one profile to another 371 393 * (i.e. hiniSource != hiniTarget); … … 375 397 * WARNING: This does _not_ check for whether the target 376 398 * application exists already. This has two consequences: 399 * 377 400 * -- existing data will be overwritten without warning; 401 * 378 402 * -- if the existing target application has keys that are 379 403 * not in the source application, they are not deleted. … … 383 407 * So you should delete the target application before 384 408 * calling this function, like this: 409 * 385 410 + PrfWriteProfileString(hiniTarget, pszTargetApp, NULL, NULL); 386 411 * … … 407 432 */ 408 433 409 ULONGprfhCopyApp(HINI hiniSource, // in: source profile (can be HINI_USER or HINI_SYSTEM)410 const char *pcszSourceApp, // in: source application411 HINI hiniTarget, // in: target profile (can be HINI_USER or HINI_SYSTEM)412 const char *pcszTargetApp, // in: name of pszSourceApp in hiniTarget413 PSZ pszErrorKey) // out: failing key in case of error; ptr can be NULL414 { 415 ULONG ulrc;416 PSZ pszKeysList;434 APIRET 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; 417 442 418 443 if (pszErrorKey) 419 444 *pszErrorKey = 0; 420 445 421 pszKeysList = prfhQueryKeysForApp(hiniSource, (PSZ)pcszSourceApp); 422 if (pszKeysList) 446 if (!(arc = prfhQueryKeysForApp(hiniSource, 447 (PSZ)pcszSourceApp, 448 &pszKeysList))) 423 449 { 424 450 PSZ pKey2 = pszKeysList; … … 427 453 { 428 454 // copy this key 429 ulrc = prfhCopyKey(hiniSource,430 431 432 433 434 if ( ulrc)455 arc = prfhCopyKey(hiniSource, 456 pcszSourceApp, 457 pKey2, 458 hiniTarget, 459 pcszTargetApp); 460 if (arc) 435 461 { 436 462 // error: copy failing key to buffer … … 444 470 free (pszKeysList); 445 471 } 446 else 447 ulrc = PRFERR_KEYSLIST; 448 449 return (ulrc); 472 473 return (arc); 450 474 } 451 475 -
trunk/src/helpers/syssound.c
r59 r68 467 467 { 468 468 // 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))) 472 473 { 473 474 PSZ pKey2 = pszKeysList; … … 594 595 595 596 // 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))) 599 601 { 600 602 PSZ pMMPMKey2 = pszMMPMKeysList, -
trunk/src/helpers/timer.c
r44 r68 144 144 ********************************************************************/ 145 145 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 } */ 146 HMTX G_hmtxTimers = NULLHANDLE; // timers lock mutex 228 147 229 148 /* ****************************************************************** … … 232 151 * 233 152 ********************************************************************/ 153 154 /* 155 *@@ LockTimers: 156 * 157 *@@added V0.9.12 (2001-05-12) [umoeller] 158 */ 159 160 BOOL 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 177 VOID UnlockTimers(VOID) 178 { 179 DosReleaseMutexSem(G_hmtxTimers); 180 } 234 181 235 182 /* … … 239 186 * _and_ timer ID. 240 187 * 241 * Internal function. 188 * Internal function. Caller must hold the mutex. 242 189 */ 243 190 … … 272 219 * the global linked list of running timers. 273 220 * 274 * Internal function. 221 * Internal function. Caller must hold the mutex. 275 222 */ 276 223 … … 339 286 * 340 287 *@@added V0.9.9 (2001-02-28) [umoeller] 288 *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection 341 289 */ 342 290 … … 347 295 if (pSet->pvllXTimers) 348 296 { 349 PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers; 350 351 PLISTNODE pTimerNode; 352 353 while (pTimerNode = lstQueryFirstNode(pllXTimers)) 297 if (LockTimers()) 354 298 { 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(); 357 312 } 358 359 lstFree(pllXTimers);360 313 } 361 314 … … 373 326 * goes thru all XTimers in the sets and starts 374 327 * or stops the PM timer with a decent frequency. 328 * 329 * Internal function. Caller must hold the mutex. 375 330 * 376 331 *@@added V0.9.9 (2001-03-07) [umoeller] … … 435 390 * 436 391 *@@added V0.9.9 (2001-02-28) [umoeller] 392 *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection 437 393 */ 438 394 … … 441 397 if (pSet && pSet->pvllXTimers) 442 398 { 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()) 450 400 { 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) 453 408 { 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; 460 421 } 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 484 423 { 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) 488 442 { 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) 493 446 { 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; 504 486 } 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); 528 490 } 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) 535 496 } 536 497 … … 552 513 * 553 514 *@@changed V0.9.7 (2000-12-08) [umoeller]: got rid of dtGetULongTime 515 *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection 554 516 */ 555 517 … … 565 527 if (pSet && pSet->pvllXTimers) 566 528 { 567 PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers; 568 569 if ((hwnd) && (ulTimeout)) 529 if (LockTimers()) 570 530 { 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)) 578 534 { 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); 590 541 if (pTimer) 591 542 { 543 // exists already: reset only 592 544 ULONG ulTimeNow; 593 545 DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, 594 546 &ulTimeNow, sizeof(ulTimeNow)); 595 pTimer->usTimerID = usTimerID;596 pTimer->hwndTarget = hwnd;597 pTimer->ulTimeout = ulTimeout;598 547 pTimer->ulNextFire = ulTimeNow + ulTimeout; 599 600 lstAppendItem(pllXTimers,601 pTimer);602 548 usrc = pTimer->usTimerID; 603 549 } 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 } 615 580 616 581 return (usrc); … … 625 590 * 626 591 * Returns TRUE if the timer was stopped. 592 * 593 *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection 627 594 */ 628 595 … … 634 601 if (pSet && pSet->pvllXTimers) 635 602 { 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()) 643 604 { 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(); 648 620 } 649 621 } -
trunk/src/helpers/xprf2.c
r14 r68 153 153 { 154 154 APIRET arc = NO_ERROR; 155 PSZ pszKeysList ;155 PSZ pszKeysList = NULL; 156 156 157 157 if (pszErrorKey) 158 158 *pszErrorKey = 0; 159 159 160 pszKeysList = prfhQueryKeysForApp(hiniSource, pszSourceApp); 161 if (pszKeysList) 160 if (!(arc = prfhQueryKeysForApp(hiniSource, 161 pszSourceApp, 162 &pszKeysList))) 162 163 { 163 164 PSZ pKey2 = pszKeysList;
Note:
See TracChangeset
for help on using the changeset viewer.