1#include "QuickTimeTcl.h" 2#include "osxMacTcl.h" 3 4//#if TARGET_RT_MAC_MACHO 5 6#ifndef __CARBON__ 7#include <Carbon/Carbon.h> 8#endif 9 10// ------------------------------------------------------------------------ 11 12 13static Tcl_Encoding gFSpPathMacRomanEncoding=NULL; 14 15#define SetupFSpPathEncoding() { \ 16 if(!gFSpPathMacRomanEncoding) \ 17 gFSpPathMacRomanEncoding = Tcl_GetEncoding(NULL,"macRoman"); \ 18} 19 20 21/*============================== CFStrings ==============================*/ 22 23/* 24 * CFStringGetCString[Path]() with kCFStringEncodingUTF8 do not work. 25 * They return fully decomposed Utf8 characters which Tcl does not 26 * understand. See Bug 587 and associated discussion on 27 * AlphaTcl-developers 28 * 29 * !!! conversion through macRoman is grotesque and should not be 30 * necessary, but Tcl appears not to properly handle accented character 31 * encodings. See Bug 587 and the associated discussion on 32 * AlphaTcl-developers. !!! 33 */ 34 35#ifndef MAC_OS_X_VERSION_10_2 36/* define constants from 10.2 CFString.h to allow compilation in 10.1 */ 37typedef enum { 38 kCFStringNormalizationFormD = 0, // Canonical Decomposition 39 kCFStringNormalizationFormKD, // Compatibility Decomposition 40 kCFStringNormalizationFormC, // Canonical Decomposition followed by Canonical Composition 41 kCFStringNormalizationFormKC // Compatibility Decomposition followed by Canonical Composition 42} CFStringNormalizationForm; 43#endif 44 45/* 46 *---------------------------------------------------------------------- 47 * 48 * TryCFStringNormalize -- 49 * 50 * call the 10.2 only CFStringNormalize() in a backwards compatible way. 51 * 52 * Results: 53 * normalized mutable copy of string (retained, needs to be released!) 54 * or NULL if CFStringNormalize not available. 55 * 56 * Side effects: 57 * None. 58 * 59 *---------------------------------------------------------------------- 60 */ 61#include <mach-o/dyld.h> 62 63static CFMutableStringRef TryCFStringNormalize(CFStringRef theString, CFStringNormalizationForm theForm) 64{ 65 static Boolean initialized = FALSE; 66 static void (*cfstringnormalize)(CFMutableStringRef, CFStringNormalizationForm) = NULL; 67 68 if(!initialized) { 69 if(NSIsSymbolNameDefinedWithHint("_CFStringNormalize", "CoreFoundation")) { 70 NSSymbol nsSymbol = NSLookupAndBindSymbolWithHint("_CFStringNormalize", "CoreFoundation"); 71 if(nsSymbol) cfstringnormalize = NSAddressOfSymbol(nsSymbol); 72 } 73 initialized = TRUE; 74 } 75 if(cfstringnormalize) { 76 CFMutableStringRef theMutableString = CFStringCreateMutableCopy(NULL, 0, theString); 77 if (theMutableString) { 78 cfstringnormalize(theMutableString, theForm); 79 return(theMutableString); 80 } 81 } 82 return(NULL); 83} 84 85/* 86 *---------------------------------------------------------------------- 87 * 88 * CFStringToDString -- 89 * 90 * This helper function converts a CFString into a DString, 91 * first transforming to canonical composed or decomposed unicode 92 * depending on the 'compose' flag then transforming to external 93 * (macRoman) encoding if 'external' is set. 94 * 95 * Uses the most direct transformation possible on the current 96 * system, e.g. CFStringNormalize if available, or by transcoding 97 * to/from macRoman otherwise (potentially lossy!). 98 * 99 * Results: 100 * Tcl error code. 101 * 102 * Side effects: 103 * None. 104 * 105 *---------------------------------------------------------------------- 106 */ 107 108static int CFStringToDString(Tcl_Interp * interp, CFStringRef strRef, Tcl_DString * dsPtr, 109 Boolean compose, Boolean external) 110{ 111 CONST84 char * str; 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, needConvert; 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; 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, 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; 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 CFURLPathStyle pathStyle=kCFURLPOSIXPathStyle; 326 err = coreFoundationUnknownErr; 327 if(appBundle) 328 { 329 appURL=CFBundleCopyBundleURL(appBundle); 330 if(appURL) 331 { 332 parentURL=CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault,appURL); 333 CFRelease(appURL); 334 if(parentURL) 335 { 336 if(CFURLGetFSRef(parentURL, &fsref)) 337 err=noErr; 338 CFRelease(parentURL); 339 } 340 } 341 } 342 } 343 if (err != noErr) goto done; 344 if(!done){ 345 err = FSRefMakePath(&fsref,fileName,MAXPATHLEN); 346 if (err != noErr) goto done; 347 fileNameLen=strlen(fileName); 348 } 349 } else { 350 if(path[0] == '/') { 351 if((done=(length == 1))) 352 { 353 /* 354 * If path = "/", just get root directory. 355 */ 356 err = FSPathMakeRef((UInt8 *) path, &fsref, &isDirectory); 357 if (err != noErr) goto done; 358 } else { 359 pos++; 360 } 361 362 } 363 } 364 if(!done) { 365 fileName[fileNameLen++] = '/'; 366 fileName[fileNameLen] = 0; 367 368 while (pos < length) { 369 if (!isDirectory || filenotexist) {err=dirNFErr; goto done;} 370 cur = pos; 371 while (path[pos] != '/' && pos < length) { 372 pos++; 373 } 374 if (fileNameLen+pos-cur > MAXPATHLEN) { 375 err=bdNamErr; goto done; 376 } else { 377 strncpy(fileName+fileNameLen, &path[cur], pos - cur); 378 fileNameLen += pos - cur; 379 } 380 fileName[fileNameLen] = 0; 381 err = FSPathMakeRef(fileName, &fsref, &isDirectory); 382 if ((err != noErr) && !(filenotexist=(err == fnfErr))) goto done; 383 if (!filenotexist) { 384 err = FSResolveAliasFile(&fsref, true, &isDirectory, &wasAlias); 385 if (err != noErr) goto done; 386 if(wasAlias){ 387 err = FSRefMakePath(&fsref,fileName,MAXPATHLEN); 388 if (err != noErr) goto done; 389 fileNameLen=strlen(fileName); 390 } 391 } 392 393 if (path[pos] == '/') { 394 if (!isDirectory || filenotexist) {err=dirNFErr; goto done;} 395 pos++; 396 fileName[fileNameLen++] = '/'; 397 fileName[fileNameLen] = 0; 398 } 399 } 400 } 401 if(!filenotexist) { 402 err = FSGetCatalogInfo(&fsref,kFSCatInfoNone,NULL,NULL,fileSpecPtr,NULL); 403 } else { 404 FSCatalogInfo catalogInfo; 405 Tcl_DString ds; 406 if(pos - cur>sizeof(StrFileName)) {err=bdNamErr; goto done;} 407 err = FSGetCatalogInfo(&fsref, kFSCatInfoNodeID | kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL); 408 if (err != noErr) goto done; 409 fileSpecPtr->vRefNum = catalogInfo.volume; 410 fileSpecPtr->parID = catalogInfo.nodeID; 411 if(DUtfToExternalDString(NULL, &path[cur], pos - cur, &ds) == TCL_ERROR) { 412 err = coreFoundationUnknownErr; 413 goto done; 414 } 415 strncpy(fileSpecPtr->name+1, Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); 416 fileSpecPtr->name[0] = Tcl_DStringLength(&ds); 417 Tcl_DStringFree(&ds); 418 err = fnfErr; 419 } 420 421done: 422 Tcl_DStringFree(&ds); 423 return err; 424} 425 426/* 427 *---------------------------------------------------------------------- 428 * 429 * FSpPathFromLocation -- 430 * 431 * This function obtains a full path name for a given macintosh 432 * FSSpec. Unlike the More Files function FSpGetFullPath, this 433 * function will return a C string in the Handle. It also will 434 * create paths for FSSpec that do not yet exist. 435 * 436 * Results: 437 * OSErr code. 438 * 439 * Side effects: 440 * None. 441 * 442 *---------------------------------------------------------------------- 443 */ 444 445OSErr 446FSpPathFromLocation( 447 FSSpecPtr spec, /* The location we want a path for. */ 448 int *length, /* Length of the resulting path. */ 449 Handle *fullPath) /* Handle to path. */ 450{ 451 OSErr err; 452 FSSpec tempSpec; 453 UInt8 fileName[MAXPATHLEN]; 454 unsigned int fileNameLen; 455 Boolean filenotexist=FALSE; 456 FSRef fsref; 457 458 *fullPath = NULL; 459 460 err=FSpMakeFSRef(spec,&fsref); 461 462 if ((err == noErr) || (filenotexist=(err == fnfErr))) { 463 if (filenotexist) { 464 // file does not exist, find parent dir 465 memmove(&tempSpec, spec, sizeof(FSSpec)); 466 tempSpec.name[0]=0; 467 err=FSpMakeFSRef(&tempSpec,&fsref); 468 } 469 if (err == noErr) { 470 err = FSRefMakePath(&fsref,fileName,MAXPATHLEN); 471 if (err == noErr) { 472 fileNameLen=strlen(fileName); 473 if(filenotexist) { // add file name manually 474 // need to convert spec name from macroman to utf8d before adding to fileName 475 Tcl_DString ds; 476 if (ExternalToDUtfDString(NULL,&spec->name[1], spec->name[0], &ds) == TCL_OK) { // bug 671 477 if(fileNameLen+Tcl_DStringLength(&ds)<MAXPATHLEN) { 478 fileName[fileNameLen++] = '/'; 479 strncpy(fileName+fileNameLen, Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); 480 fileNameLen += Tcl_DStringLength(&ds); 481 } else { 482 err=bdNamErr; 483 } 484 Tcl_DStringFree(&ds); 485 } else { 486 err = coreFoundationUnknownErr; 487 } 488 } else { 489 FSCatalogInfo catalogInfo; 490 err = FSGetCatalogInfo(&fsref,kFSCatInfoNodeFlags,&catalogInfo,NULL,NULL,NULL); 491 if (err == noErr && (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) { 492 // if we have a directory, end path with / 493 if(fileNameLen < MAXPATHLEN) { 494 fileName[fileNameLen++] = '/'; 495 } else { 496 err=bdNamErr; 497 } 498 } 499 } 500 if (err == noErr) { 501 // FSRefMakePath et al use decomposed UTF8 on OSX 502 Tcl_DString ds; 503 fileName[fileNameLen] = 0; // add 0 cstr terminator 504 if (DUtfToExternalDString(NULL, fileName, -1, &ds) == TCL_OK) { 505 err = PtrToHand(Tcl_DStringValue(&ds), fullPath, Tcl_DStringLength(&ds)+1); 506 *length = Tcl_DStringLength(&ds); 507 Tcl_DStringFree(&ds); // bug 671 508 } else { 509 err = coreFoundationUnknownErr; 510 } 511 } 512 } 513 } 514 } 515 516 /* 517 * On error Dispose the handle, set it to NULL & return the err. 518 * Otherwise, set the length & return. 519 */ 520 if (err != noErr) { 521 if ( *fullPath != NULL ) { 522 DisposeHandle(*fullPath); 523 } 524 *fullPath = NULL; 525 *length = 0; 526 } 527 528 return err; 529} 530 531// ------------------------------------------------------------------------ 532 533 534// das 271100 modified and adapted from MacTcl for Tcl on OSX 535 536 537/* 538 * tclMacResource.c -- 539 * 540 * This file contains several commands that manipulate or use 541 * Macintosh resources. Included are extensions to the "source" 542 * command, the mac specific "beep" and "resource" commands, and 543 * administration for open resource file references. 544 * 545 * Copyright (c) 1996-1997 Sun Microsystems, Inc. 546 * 547 * See the file "license.terms" for information on usage and redistribution 548 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 549 * 550 * RCS: @(#) $Id: osxMacTcl.c,v 1.1.1.1 2003/04/04 16:24:35 matben Exp $ 551 */ 552 553/* 554 * Pass this in the mode parameter of SetSoundVolume to determine 555 * which volume to set. 556 */ 557 558enum WhichVolume { 559 SYS_BEEP_VOLUME, /* This sets the volume for SysBeep calls */ 560 DEFAULT_SND_VOLUME, /* This one for SndPlay calls */ 561 RESET_VOLUME /* And this undoes the last call to SetSoundVolume */ 562}; 563 564/* 565 * Prototypes for procedures defined later in this file: 566 */ 567 568 569static void SetSoundVolume(int volume, enum WhichVolume mode); 570 571/* 572 *---------------------------------------------------------------------- 573 * 574 * Tcl_BeepObjCmd -- 575 * 576 * This procedure makes the beep sound. 577 * 578 * Results: 579 * A standard Tcl result. 580 * 581 * Side effects: 582 * Makes a beep. 583 * 584 *---------------------------------------------------------------------- 585 */ 586 587int 588Tcl_BeepObjCmd( 589 ClientData dummy, /* Not used. */ 590 Tcl_Interp *interp, /* Current interpreter. */ 591 int objc, /* Number of arguments. */ 592 Tcl_Obj *CONST84 objv[]) /* Argument values. */ 593{ 594 Tcl_Obj *resultPtr, *objPtr; 595 Handle sound; 596 Str255 sndName; 597 int volume = -1, length; 598 char * sndArg = NULL; 599 600 resultPtr = Tcl_GetObjResult(interp); 601 if (objc == 1) { 602 SysBeep(1); 603 return TCL_OK; 604 } else if (objc == 2) { 605 if (!strcmp(Tcl_GetStringFromObj(objv[1], &length), "-list")) { 606 int count, i; 607 short id; 608 Str255 theName; 609 ResType rezType; 610 611 count = CountResources('snd '); 612 for (i = 1; i <= count; i++) { 613 sound = GetIndResource('snd ', i); 614 if (sound != NULL) { 615 GetResInfo(sound, &id, &rezType, theName); 616 if (theName[0] == 0) { 617 continue; 618 } 619 objPtr = Tcl_NewStringObj((char *) theName + 1, 620 theName[0]); 621 Tcl_ListObjAppendElement(interp, resultPtr, objPtr); 622 } 623 } 624 return TCL_OK; 625 } else { 626 sndArg = Tcl_GetStringFromObj(objv[1], &length); 627 } 628 } else if (objc == 3) { 629 if (!strcmp(Tcl_GetStringFromObj(objv[1], &length), "-volume")) { 630 Tcl_GetIntFromObj(interp, objv[2], &volume); 631 } else { 632 goto beepUsage; 633 } 634 } else if (objc == 4) { 635 if (!strcmp(Tcl_GetStringFromObj(objv[1], &length), "-volume")) { 636 Tcl_GetIntFromObj(interp, objv[2], &volume); 637 sndArg = Tcl_GetStringFromObj(objv[3], &length); 638 } else { 639 goto beepUsage; 640 } 641 } else { 642 goto beepUsage; 643 } 644 645 /* 646 * Play the sound 647 */ 648 if (sndArg == NULL) { 649 /* 650 * Set Volume for SysBeep 651 */ 652 653 if (volume >= 0) { 654 SetSoundVolume(volume, SYS_BEEP_VOLUME); 655 } 656 SysBeep(1); 657 658 /* 659 * Reset Volume 660 */ 661 662 if (volume >= 0) { 663 SetSoundVolume(0, RESET_VOLUME); 664 } 665 } else { 666 strcpy((char *) sndName + 1, sndArg); 667 sndName[0] = length; 668 sound = GetNamedResource('snd ', sndName); 669 if (sound != NULL) { 670 /* 671 * Set Volume for Default Output device 672 */ 673 674 if (volume >= 0) { 675 SetSoundVolume(volume, DEFAULT_SND_VOLUME); 676 } 677 678 SndPlay(NULL, (SndListHandle) sound, false); 679 680 /* 681 * Reset Volume 682 */ 683 684 if (volume >= 0) { 685 SetSoundVolume(0, RESET_VOLUME); 686 } 687 } else { 688 Tcl_AppendStringsToObj(resultPtr, " \"", sndArg, 689 "\" is not a valid sound. (Try ", 690 Tcl_GetString(objv[0]), " -list)", NULL); 691 return TCL_ERROR; 692 } 693 } 694 695 return TCL_OK; 696 697 beepUsage: 698 Tcl_WrongNumArgs(interp, 1, objv, "[-volume num] [-list | sndName]?"); 699 return TCL_ERROR; 700} 701 702/* 703 *----------------------------------------------------------------------------- 704 * 705 * SetSoundVolume -- 706 * 707 * Set the volume for either the SysBeep or the SndPlay call depending 708 * on the value of mode (SYS_BEEP_VOLUME or DEFAULT_SND_VOLUME 709 * respectively. 710 * 711 * It also stores the last channel set, and the old value of its 712 * VOLUME. If you call SetSoundVolume with a mode of RESET_VOLUME, 713 * it will undo the last setting. The volume parameter is 714 * ignored in this case. 715 * 716 * Side Effects: 717 * Sets the System Volume 718 * 719 * Results: 720 * None 721 * 722 *----------------------------------------------------------------------------- 723 */ 724 725void 726SetSoundVolume( 727 int volume, /* This is the new volume */ 728 enum WhichVolume mode) /* This flag says which volume to 729 * set: SysBeep, SndPlay, or instructs us 730 * to reset the volume */ 731{ 732 static int hasSM3 = 1; 733 static enum WhichVolume oldMode; 734 static long oldVolume = -1; 735 736 737 /* 738 * If we don't have Sound Manager 3.0, we can't set the sound volume. 739 * We will just ignore the request rather than raising an error. 740 */ 741 742 if (!hasSM3) { 743 return; 744 } 745 746 switch (mode) { 747 case SYS_BEEP_VOLUME: 748 GetSysBeepVolume(&oldVolume); 749 SetSysBeepVolume(volume); 750 oldMode = SYS_BEEP_VOLUME; 751 break; 752 case DEFAULT_SND_VOLUME: 753 GetDefaultOutputVolume(&oldVolume); 754 SetDefaultOutputVolume(volume); 755 oldMode = DEFAULT_SND_VOLUME; 756 break; 757 case RESET_VOLUME: 758 /* 759 * If oldVolume is -1 someone has made a programming error 760 * and called reset before setting the volume. This is benign 761 * however, so we will just exit. 762 */ 763 764 if (oldVolume != -1) { 765 if (oldMode == SYS_BEEP_VOLUME) { 766 SetSysBeepVolume(oldVolume); 767 } else if (oldMode == DEFAULT_SND_VOLUME) { 768 SetDefaultOutputVolume(oldVolume); 769 } 770 } 771 oldVolume = -1; 772 } 773} 774 775 776//#endif 777