1/* Author: Daniel A. Steffen */ 2 3#include "osxMacTcl.h" 4 5#if TARGET_RT_MAC_MACHO 6 7#ifndef __CARBON__ 8#include <Carbon/Carbon.h> 9#endif 10 11// ------------------------------------------------------------------------ 12 13 14static Tcl_Encoding gFSpPathMacRomanEncoding=NULL; 15 16#define SetupFSpPathEncoding() { \ 17 if(!gFSpPathMacRomanEncoding) \ 18 gFSpPathMacRomanEncoding = Tcl_GetEncoding(NULL,"macRoman"); \ 19} 20 21 22/*============================== CFStrings ==============================*/ 23 24/* 25 * CFStringGetCString[Path]() with kCFStringEncodingUTF8 do not work. 26 * They return fully decomposed Utf8 characters which Tcl does not 27 * understand. See Bug 587 and associated discussion on 28 * AlphaTcl-developers 29 * 30 * !!! conversion through macRoman is grotesque and should not be 31 * necessary, but Tcl appears not to properly handle accented character 32 * encodings. See Bug 587 and the associated discussion on 33 * AlphaTcl-developers. !!! 34 */ 35 36#ifndef MAC_OS_X_VERSION_10_2 37/* define constants from 10.2 CFString.h to allow compilation in 10.1 */ 38typedef enum { 39 kCFStringNormalizationFormD = 0, // Canonical Decomposition 40 kCFStringNormalizationFormKD, // Compatibility Decomposition 41 kCFStringNormalizationFormC, // Canonical Decomposition followed by Canonical Composition 42 kCFStringNormalizationFormKC // Compatibility Decomposition followed by Canonical Composition 43} CFStringNormalizationForm; 44#endif 45 46/* 47 *---------------------------------------------------------------------- 48 * 49 * TryCFStringNormalize -- 50 * 51 * call the 10.2 only CFStringNormalize() in a backwards compatible way. 52 * 53 * Results: 54 * normalized mutable copy of string (retained, needs to be released!) 55 * or NULL if CFStringNormalize not available. 56 * 57 * Side effects: 58 * None. 59 * 60 *---------------------------------------------------------------------- 61 */ 62#include <mach-o/dyld.h> 63 64static CFMutableStringRef TryCFStringNormalize(CFStringRef theString, CFStringNormalizationForm theForm) 65{ 66 static Boolean initialized = FALSE; 67 static void (*cfstringnormalize)(CFMutableStringRef, CFStringNormalizationForm) = NULL; 68 69 if(!initialized) { 70 if(NSIsSymbolNameDefinedWithHint("_CFStringNormalize", "CoreFoundation")) { 71 NSSymbol nsSymbol = NSLookupAndBindSymbolWithHint("_CFStringNormalize", "CoreFoundation"); 72 if(nsSymbol) cfstringnormalize = NSAddressOfSymbol(nsSymbol); 73 } 74 initialized = TRUE; 75 } 76 if(cfstringnormalize) { 77 CFMutableStringRef theMutableString = CFStringCreateMutableCopy(NULL, 0, theString); 78 if (theMutableString) { 79 cfstringnormalize(theMutableString, theForm); 80 return(theMutableString); 81 } 82 } 83 return(NULL); 84} 85 86/* 87 *---------------------------------------------------------------------- 88 * 89 * CFStringToDString -- 90 * 91 * This helper function converts a CFString into a DString, 92 * first transforming to canonical composed or decomposed unicode 93 * depending on the 'compose' flag then transforming to external 94 * (macRoman) encoding if 'external' is set. 95 * 96 * Uses the most direct transformation possible on the current 97 * system, e.g. CFStringNormalize if available, or by transcoding 98 * to/from macRoman otherwise (potentially lossy!). 99 * 100 * Results: 101 * Tcl error code. 102 * 103 * Side effects: 104 * None. 105 * 106 *---------------------------------------------------------------------- 107 */ 108 109static int CFStringToDString(Tcl_Interp * interp, CFStringRef strRef, Tcl_DString * dsPtr, 110 Boolean compose, Boolean external) 111{ 112 Boolean success; 113 int len; 114 int result = TCL_ERROR; 115 116 CFStringRef theStrRef = NULL; 117 CFStringEncoding theEncoding; 118 Tcl_DString ds, *theDsPtr = dsPtr; 119 Boolean usedNormalize = FALSE; 120 121 if (compose) 122 theStrRef = TryCFStringNormalize(strRef, kCFStringNormalizationFormC); 123 else 124 theStrRef = TryCFStringNormalize(strRef, kCFStringNormalizationFormD); 125 126 if(theStrRef) { 127 usedNormalize = TRUE; 128 129 } else { 130 theStrRef = strRef; 131 theEncoding = kCFStringEncodingMacRoman; 132 } 133 134 if (usedNormalize && !external) 135 theEncoding = kCFStringEncodingUTF8; 136 else 137 theEncoding = kCFStringEncodingMacRoman; 138 139 if(!usedNormalize && !external) 140 theDsPtr = &ds; // will need ExternalToUtf conversion 141 142 len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(theStrRef), theEncoding); 143 Tcl_DStringInit(theDsPtr); 144 Tcl_DStringSetLength(theDsPtr, len); 145 146 success = CFStringGetCString(theStrRef, Tcl_DStringValue(theDsPtr), len+1, theEncoding); 147 148 if (success) { 149 /* len was only a guess */ 150 Tcl_DStringSetLength(theDsPtr, strlen(Tcl_DStringValue(theDsPtr))); 151 result = TCL_OK; 152 } else 153 if (interp) Tcl_SetResult(interp, "Can't extract string from CFString", TCL_STATIC); 154 155 if (!usedNormalize && !external) { 156 // need ExternalToUtf conversion 157 if(success) { 158 SetupFSpPathEncoding(); 159 Tcl_ExternalToUtfDString(gFSpPathMacRomanEncoding, 160 Tcl_DStringValue(theDsPtr), Tcl_DStringLength(theDsPtr), dsPtr); 161 } 162 Tcl_DStringFree(theDsPtr); 163 } 164 if(usedNormalize) 165 CFRelease(theStrRef); 166 167 return result; 168} 169 170/* 171 *---------------------------------------------------------------------- 172 * 173 * BufferToDString -- 174 * 175 * This helper function converts a text buffer of given lenth into 176 * a DString (if length == -1, buffer is assumed to be a C string), 177 * first transforming from external (macRoman) encoding if 178 * 'fromExternal' is set, then transforming to canonical composed 179 * or decomposed unicode depending on the 'compose' flag and finally 180 * transforming to external (macRoman) encoding if 'external' is set. 181 * 182 * Tries to use the most efficient transformations possible on the 183 * current system, e.g. CFStringNormalize if available, and 184 * CFStringCreateWithCStringNoCopy if given a C string. 185 * 186 * Results: 187 * Tcl error code. 188 * 189 * Side effects: 190 * None. 191 * 192 *---------------------------------------------------------------------- 193 */ 194 195static int BufferToDString(Tcl_Interp * interp, CONST84 char *buffer, int length, 196 Tcl_DString * dsPtr, Boolean compose, Boolean toExternal, Boolean fromExternal) 197{ 198 int result = TCL_ERROR; 199 CFStringRef theString; 200 CFStringEncoding theEncoding; 201 202 theEncoding = (fromExternal ? kCFStringEncodingMacRoman : kCFStringEncodingUTF8); 203 204 if(length < 0) //assume buffer is a C string 205 theString = CFStringCreateWithCStringNoCopy(NULL, buffer, theEncoding, kCFAllocatorNull); 206 else 207 theString = CFStringCreateWithBytes(NULL, (const unsigned char *) buffer, length, theEncoding, FALSE); 208 209 if(theString) { 210 result = CFStringToDString(interp, theString, dsPtr, compose, toExternal); 211 CFRelease(theString); // bug 671 212 } else { 213 if (interp) Tcl_SetResult(interp, "Can't create CFString from buffer", TCL_STATIC); 214 } 215 216 return result; 217} 218 219/* CFString to external DString */ 220int CFStringToExternalDString(Tcl_Interp * interp, CFStringRef strRef, Tcl_DString * dsPtr) 221{ 222 return CFStringToDString(interp, strRef, dsPtr, TRUE, TRUE); 223} 224 225/* CFString to DString */ 226int CFStringToUtfDString(Tcl_Interp * interp, CFStringRef strRef, Tcl_DString * dsPtr) 227{ 228 return CFStringToDString(interp, strRef, dsPtr, TRUE, FALSE); 229} 230 231/* decomposed utf8 buffer to external DString */ 232int DUtfToExternalDString(Tcl_Interp * interp, CONST84 char * src, int length, Tcl_DString * dsPtr) 233{ 234 return BufferToDString(interp, src, length, dsPtr, TRUE, TRUE, FALSE); 235} 236 237/* decomposed utf8 buffer to DString */ 238int DUtfToUtfDString(Tcl_Interp * interp, CONST84 char * src, int length, Tcl_DString * dsPtr) 239{ 240 return BufferToDString(interp, src, length, dsPtr, TRUE, FALSE, FALSE); 241} 242 243/* external buffer to decomposed utf8 DString */ 244int ExternalToDUtfDString(Tcl_Interp * interp, CONST84 char * src, int length, Tcl_DString * dsPtr) 245{ 246 return BufferToDString(interp, src, length, dsPtr, FALSE, FALSE, TRUE); 247} 248 249/* utf8 buffer to decomposed utf8 DString */ 250int UtfToDUtfDString(Tcl_Interp * interp, CONST84 char * src, int length, Tcl_DString * dsPtr) 251{ 252 return BufferToDString(interp, src, length, dsPtr, FALSE, FALSE, FALSE); 253} 254 255/*============================== ==============================*/ 256 257// das 091200 reimplemented the following routines from scratch 258// for Tcl on OSX using modern FileMgr APIs and FSRefs 259// they are analogous to the MacTcl routines in tclMacUtil.c 260// 261// on OSX these routines are used in oldEndre.c instead 262// of the crufty old Alpha versions 263 264 265#define MAXPATHLEN 1024 266 267/* 268 *---------------------------------------------------------------------- 269 * 270 * FSpLocationFromPath -- 271 * 272 * This function obtains an FSSpec for a given macintosh path. 273 * Unlike the More Files function FSpLocationFromFullPath, this 274 * function will also accept partial paths and resolve any aliases 275 * along the path. It will also create an FSSpec for a path that 276 * does not yet exist. 277 * 278 * Results: 279 * OSErr code. 280 * 281 * Side effects: 282 * None. 283 * 284 *---------------------------------------------------------------------- 285 */ 286 287 288OSErr 289FSpLocationFromPath( 290 int length, /* Length of path. */ 291 CONST84 char *path, /* The path to convert. */ 292 FSSpecPtr fileSpecPtr) /* On return the spec for the path. */ 293{ 294 UInt8 fileName[MAXPATHLEN]; 295 unsigned int fileNameLen; 296 OSErr err; 297 unsigned int pos, cur = 0; 298 Boolean isDirectory=TRUE, filenotexist=FALSE, wasAlias, done; 299 FSRef fsref; 300 Tcl_DString ds; 301 302 // FSRefMakePath et al use deomposed UTF8 on OSX 303 if(ExternalToDUtfDString(NULL, path, length, &ds) == TCL_ERROR) { 304 err = coreFoundationUnknownErr; 305 goto done; 306 } 307 308 path = Tcl_DStringValue(&ds); 309 length = Tcl_DStringLength(&ds); 310 311 pos = 0; 312 fileName[0] = 0; 313 fileNameLen = 0; 314 315 /* 316 * Check to see if this is a full path. If partial 317 * we assume that path starts with the current working 318 * directory. (Ie. volume & dir = 0) 319 */ 320 if ((done=(length == 0)) || (path[0] != '/')) { 321 // start at current directory 322 { 323 CFBundleRef appBundle=CFBundleGetMainBundle(); 324 CFURLRef appURL=NULL, parentURL=NULL; 325 err = coreFoundationUnknownErr; 326 if(appBundle) 327 { 328 appURL=CFBundleCopyBundleURL(appBundle); 329 if(appURL) 330 { 331 parentURL=CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault,appURL); 332 CFRelease(appURL); 333 if(parentURL) 334 { 335 if(CFURLGetFSRef(parentURL, &fsref)) 336 err=noErr; 337 CFRelease(parentURL); 338 } 339 } 340 } 341 } 342 if (err != noErr) goto done; 343 if(!done){ 344 err = FSRefMakePath(&fsref,fileName,MAXPATHLEN); 345 if (err != noErr) goto done; 346 fileNameLen=strlen( (const char *) fileName); 347 } 348 } else { 349 if(path[0] == '/') { 350 if((done=(length == 1))) 351 { 352 /* 353 * If path = "/", just get root directory. 354 */ 355 err = FSPathMakeRef((UInt8 *) path, &fsref, &isDirectory); 356 if (err != noErr) goto done; 357 } else { 358 pos++; 359 } 360 361 } 362 } 363 if(!done) { 364 fileName[fileNameLen++] = '/'; 365 fileName[fileNameLen] = 0; 366 367 while (pos < length) { 368 if (!isDirectory || filenotexist) {err=dirNFErr; goto done;} 369 cur = pos; 370 while (path[pos] != '/' && pos < length) { 371 pos++; 372 } 373 if (fileNameLen+pos-cur > MAXPATHLEN) { 374 err=bdNamErr; goto done; 375 } else { 376 strncpy( (char *) fileName+fileNameLen, &path[cur], pos - cur); 377 fileNameLen += pos - cur; 378 } 379 fileName[fileNameLen] = 0; 380 err = FSPathMakeRef(fileName, &fsref, &isDirectory); 381 if ((err != noErr) && !(filenotexist=(err == fnfErr))) goto done; 382 if (!filenotexist) { 383 err = FSResolveAliasFile(&fsref, true, &isDirectory, &wasAlias); 384 if (err != noErr) goto done; 385 if(wasAlias){ 386 err = FSRefMakePath(&fsref,fileName,MAXPATHLEN); 387 if (err != noErr) goto done; 388 fileNameLen=strlen( (const char *) fileName); 389 } 390 } 391 392 if (path[pos] == '/') { 393 if (!isDirectory || filenotexist) {err=dirNFErr; goto done;} 394 pos++; 395 fileName[fileNameLen++] = '/'; 396 fileName[fileNameLen] = 0; 397 } 398 } 399 } 400 if(!filenotexist) { 401 err = FSGetCatalogInfo(&fsref,kFSCatInfoNone,NULL,NULL,fileSpecPtr,NULL); 402 } else { 403 FSCatalogInfo catalogInfo; 404 Tcl_DString ds; 405 if(pos - cur>sizeof(StrFileName)) {err=bdNamErr; goto done;} 406 err = FSGetCatalogInfo(&fsref, kFSCatInfoNodeID | kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL); 407 if (err != noErr) goto done; 408 fileSpecPtr->vRefNum = catalogInfo.volume; 409 fileSpecPtr->parID = catalogInfo.nodeID; 410 if(DUtfToExternalDString(NULL, &path[cur], pos - cur, &ds) == TCL_ERROR) { 411 err = coreFoundationUnknownErr; 412 goto done; 413 } 414 strncpy( (char *) fileSpecPtr->name+1, Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); 415 fileSpecPtr->name[0] = Tcl_DStringLength(&ds); 416 Tcl_DStringFree(&ds); 417 err = fnfErr; 418 } 419 420done: 421 Tcl_DStringFree(&ds); 422 return err; 423} 424 425/* 426 *---------------------------------------------------------------------- 427 * 428 * FSpPathFromLocation -- 429 * 430 * This function obtains a full path name for a given macintosh 431 * FSSpec. Unlike the More Files function FSpGetFullPath, this 432 * function will return a C string in the Handle. It also will 433 * create paths for FSSpec that do not yet exist. 434 * 435 * Results: 436 * OSErr code. 437 * 438 * Side effects: 439 * None. 440 * 441 *---------------------------------------------------------------------- 442 */ 443 444OSErr 445FSpPathFromLocation( 446 FSSpecPtr spec, /* The location we want a path for. */ 447 int *length, /* Length of the resulting path. */ 448 Handle *fullPath) /* Handle to path. */ 449{ 450 OSErr err; 451 FSSpec tempSpec; 452 UInt8 fileName[MAXPATHLEN]; 453 unsigned int fileNameLen; 454 Boolean filenotexist=FALSE; 455 FSRef fsref; 456 457 *fullPath = NULL; 458 459 err=FSpMakeFSRef(spec,&fsref); 460 461 if ((err == noErr) || (filenotexist=(err == fnfErr))) { 462 if (filenotexist) { 463 // file does not exist, find parent dir 464 memmove(&tempSpec, spec, sizeof(FSSpec)); 465 tempSpec.name[0]=0; 466 err=FSpMakeFSRef(&tempSpec,&fsref); 467 } 468 if (err == noErr) { 469 err = FSRefMakePath(&fsref,fileName,MAXPATHLEN); 470 if (err == noErr) { 471 fileNameLen=strlen( (const char *) fileName); 472 if(filenotexist) { // add file name manually 473 // need to convert spec name from macroman to utf8d before adding to fileName 474 Tcl_DString ds; 475 if (ExternalToDUtfDString(NULL, (char *) &spec->name[1], spec->name[0], &ds) == TCL_OK) { // bug 671 476 if(fileNameLen+Tcl_DStringLength(&ds)<MAXPATHLEN) { 477 fileName[fileNameLen++] = '/'; 478 strncpy( (char *) fileName+fileNameLen, Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); 479 fileNameLen += Tcl_DStringLength(&ds); 480 } else { 481 err=bdNamErr; 482 } 483 Tcl_DStringFree(&ds); 484 } else { 485 err = coreFoundationUnknownErr; 486 } 487 } else { 488 FSCatalogInfo catalogInfo; 489 err = FSGetCatalogInfo(&fsref,kFSCatInfoNodeFlags,&catalogInfo,NULL,NULL,NULL); 490 if (err == noErr && (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) { 491 // if we have a directory, end path with / 492 if(fileNameLen < MAXPATHLEN) { 493 fileName[fileNameLen++] = '/'; 494 } else { 495 err=bdNamErr; 496 } 497 } 498 } 499 if (err == noErr) { 500 // FSRefMakePath et al use decomposed UTF8 on OSX 501 Tcl_DString ds; 502 fileName[fileNameLen] = 0; // add 0 cstr terminator 503 if (DUtfToExternalDString(NULL, (const char *) fileName, -1, &ds) == TCL_OK) { 504 err = PtrToHand(Tcl_DStringValue(&ds), fullPath, Tcl_DStringLength(&ds)+1); 505 *length = Tcl_DStringLength(&ds); 506 Tcl_DStringFree(&ds); // bug 671 507 } else { 508 err = coreFoundationUnknownErr; 509 } 510 } 511 } 512 } 513 } 514 515 /* 516 * On error Dispose the handle, set it to NULL & return the err. 517 * Otherwise, set the length & return. 518 */ 519 if (err != noErr) { 520 if ( *fullPath != NULL ) { 521 DisposeHandle(*fullPath); 522 } 523 *fullPath = NULL; 524 *length = 0; 525 } 526 527 return err; 528} 529 530// ------------------------------------------------------------------------ 531 532 533// das 271100 modified and adapted from MacTcl for Tcl on OSX 534 535 536/* 537 * tclMacResource.c -- 538 * 539 * This file contains several commands that manipulate or use 540 * Macintosh resources. Included are extensions to the "source" 541 * command, the mac specific "beep" and "resource" commands, and 542 * administration for open resource file references. 543 * 544 * Copyright (c) 1996-1997 Sun Microsystems, Inc. 545 * 546 * See the file "license.terms" for information on usage and redistribution 547 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 548 * 549 * RCS: @(#) $Id: osxMacTcl.c,v 1.2 2007/08/23 10:58:27 das Exp $ 550 */ 551 552/* 553 * Pass this in the mode parameter of SetSoundVolume to determine 554 * which volume to set. 555 */ 556 557enum WhichVolume { 558 SYS_BEEP_VOLUME, /* This sets the volume for SysBeep calls */ 559 DEFAULT_SND_VOLUME, /* This one for SndPlay calls */ 560 RESET_VOLUME /* And this undoes the last call to SetSoundVolume */ 561}; 562 563/* 564 * Prototypes for procedures defined later in this file: 565 */ 566 567 568static void SetSoundVolume(int volume, enum WhichVolume mode); 569 570/* 571 *---------------------------------------------------------------------- 572 * 573 * Tcl_BeepObjCmd -- 574 * 575 * This procedure makes the beep sound. 576 * 577 * Results: 578 * A standard Tcl result. 579 * 580 * Side effects: 581 * Makes a beep. 582 * 583 *---------------------------------------------------------------------- 584 */ 585 586int 587Tcl_BeepObjCmd( 588 ClientData dummy, /* Not used. */ 589 Tcl_Interp *interp, /* Current interpreter. */ 590 int objc, /* Number of arguments. */ 591 Tcl_Obj *CONST84 objv[]) /* Argument values. */ 592{ 593 Tcl_Obj *resultPtr, *objPtr; 594 Handle sound; 595 Str255 sndName; 596 int volume = -1, length; 597 char * sndArg = NULL; 598 599 resultPtr = Tcl_GetObjResult(interp); 600 if (objc == 1) { 601 SysBeep(1); 602 return TCL_OK; 603 } else if (objc == 2) { 604 if (!strcmp(Tcl_GetStringFromObj(objv[1], &length), "-list")) { 605 int count, i; 606 short id; 607 Str255 theName; 608 ResType rezType; 609 610 count = CountResources('snd '); 611 for (i = 1; i <= count; i++) { 612 sound = GetIndResource('snd ', i); 613 if (sound != NULL) { 614 GetResInfo(sound, &id, &rezType, theName); 615 if (theName[0] == 0) { 616 continue; 617 } 618 objPtr = Tcl_NewStringObj((char *) theName + 1, 619 theName[0]); 620 Tcl_ListObjAppendElement(interp, resultPtr, objPtr); 621 } 622 } 623 return TCL_OK; 624 } else { 625 sndArg = Tcl_GetStringFromObj(objv[1], &length); 626 } 627 } else if (objc == 3) { 628 if (!strcmp(Tcl_GetStringFromObj(objv[1], &length), "-volume")) { 629 Tcl_GetIntFromObj(interp, objv[2], &volume); 630 } else { 631 goto beepUsage; 632 } 633 } else if (objc == 4) { 634 if (!strcmp(Tcl_GetStringFromObj(objv[1], &length), "-volume")) { 635 Tcl_GetIntFromObj(interp, objv[2], &volume); 636 sndArg = Tcl_GetStringFromObj(objv[3], &length); 637 } else { 638 goto beepUsage; 639 } 640 } else { 641 goto beepUsage; 642 } 643 644 /* 645 * Play the sound 646 */ 647 if (sndArg == NULL) { 648 /* 649 * Set Volume for SysBeep 650 */ 651 652 if (volume >= 0) { 653 SetSoundVolume(volume, SYS_BEEP_VOLUME); 654 } 655 SysBeep(1); 656 657 /* 658 * Reset Volume 659 */ 660 661 if (volume >= 0) { 662 SetSoundVolume(0, RESET_VOLUME); 663 } 664 } else { 665 strcpy((char *) sndName + 1, sndArg); 666 sndName[0] = length; 667 sound = GetNamedResource('snd ', sndName); 668 if (sound != NULL) { 669 /* 670 * Set Volume for Default Output device 671 */ 672 673 if (volume >= 0) { 674 SetSoundVolume(volume, DEFAULT_SND_VOLUME); 675 } 676 677 SndPlay(NULL, (SndListHandle) sound, false); 678 679 /* 680 * Reset Volume 681 */ 682 683 if (volume >= 0) { 684 SetSoundVolume(0, RESET_VOLUME); 685 } 686 } else { 687 Tcl_AppendStringsToObj(resultPtr, " \"", sndArg, 688 "\" is not a valid sound. (Try ", 689 Tcl_GetString(objv[0]), " -list)", NULL); 690 return TCL_ERROR; 691 } 692 } 693 694 return TCL_OK; 695 696 beepUsage: 697 Tcl_WrongNumArgs(interp, 1, objv, "[-volume num] [-list | sndName]?"); 698 return TCL_ERROR; 699} 700 701/* 702 *----------------------------------------------------------------------------- 703 * 704 * SetSoundVolume -- 705 * 706 * Set the volume for either the SysBeep or the SndPlay call depending 707 * on the value of mode (SYS_BEEP_VOLUME or DEFAULT_SND_VOLUME 708 * respectively. 709 * 710 * It also stores the last channel set, and the old value of its 711 * VOLUME. If you call SetSoundVolume with a mode of RESET_VOLUME, 712 * it will undo the last setting. The volume parameter is 713 * ignored in this case. 714 * 715 * Side Effects: 716 * Sets the System Volume 717 * 718 * Results: 719 * None 720 * 721 *----------------------------------------------------------------------------- 722 */ 723 724void 725SetSoundVolume( 726 int volume, /* This is the new volume */ 727 enum WhichVolume mode) /* This flag says which volume to 728 * set: SysBeep, SndPlay, or instructs us 729 * to reset the volume */ 730{ 731 static int hasSM3 = 1; 732 static enum WhichVolume oldMode; 733 static long oldVolume = -1; 734 735 736 /* 737 * If we don't have Sound Manager 3.0, we can't set the sound volume. 738 * We will just ignore the request rather than raising an error. 739 */ 740 741 if (!hasSM3) { 742 return; 743 } 744 745 switch (mode) { 746 case SYS_BEEP_VOLUME: 747 GetSysBeepVolume(&oldVolume); 748 SetSysBeepVolume(volume); 749 oldMode = SYS_BEEP_VOLUME; 750 break; 751 case DEFAULT_SND_VOLUME: 752 GetDefaultOutputVolume(&oldVolume); 753 SetDefaultOutputVolume(volume); 754 oldMode = DEFAULT_SND_VOLUME; 755 break; 756 case RESET_VOLUME: 757 /* 758 * If oldVolume is -1 someone has made a programming error 759 * and called reset before setting the volume. This is benign 760 * however, so we will just exit. 761 */ 762 763 if (oldVolume != -1) { 764 if (oldMode == SYS_BEEP_VOLUME) { 765 SetSysBeepVolume(oldVolume); 766 } else if (oldMode == DEFAULT_SND_VOLUME) { 767 SetDefaultOutputVolume(oldVolume); 768 } 769 } 770 oldVolume = -1; 771 } 772} 773 774 775#endif 776