1# Init.tcl --- 2# 3# This file is part of The Coccinella application. 4# It sets up the global 'this' array for useful things. 5# 6# Copyright (c) 2004-2008 Mats Bengtsson 7# 8# This program is free software: you can redistribute it and/or modify 9# it under the terms of the GNU General Public License as published by 10# the Free Software Foundation, either version 3 of the License, or 11# (at your option) any later version. 12# 13# This program is distributed in the hope that it will be useful, 14# but WITHOUT ANY WARRANTY; without even the implied warranty of 15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16# GNU General Public License for more details. 17# 18# You should have received a copy of the GNU General Public License 19# along with this program. If not, see <http://www.gnu.org/licenses/>. 20# 21# $Id: Init.tcl,v 1.108 2008-08-19 07:56:57 matben Exp $ 22 23namespace eval ::Init { 24 25 # Mutually exclusive. 26 set ::config(prefs,sameDrive) 0 27 set ::config(prefs,sameDir) 1 28} 29 30proc ::Init::SetThis {mainScript} { 31 global this auto_path tcl_platform prefs config 32 33 # If we store the prefs file on a removable drive, use this folder name: 34 # F:\CoccinellaPrefs etc. 35 set this(prefsDriverDir) "CoccinellaPrefs" 36 37 # Collect paths in 'this' array. 38 set path [file dirname $mainScript] 39 set this(path) $path 40 set this(script) $mainScript 41 42 # Sub paths. Use relative source, prefs, or theme dirs. 43 # Keep generic path separator for theme engine. 44 set this(emoticons) iconsets/emoticons 45 set this(images) images 46 set this(resources) resources 47 set this(sounds) sounds 48 set this(themes) themes 49 50 # Absolute paths. 51 set this(componentPath) [file join $path components] 52 set this(docsPath) [file join $path docs] 53 set this(emoticonsPath) [file join $path iconsets emoticons] 54 set this(itemPath) [file join $path items] 55 set this(msgcatPath) [file join $path msgs] 56 set this(msgcatCompPath) [file join $path msgs components] 57 set this(msgcatPostPath) [file join $path msgs post] 58 set this(pluginsPath) [file join $path plugins] 59 set this(appletsPath) [file join $path plugins applets] 60 set this(resourcePath) [file join $path resources] 61 set this(postPrefsPath) [file join $path resources post] 62 set this(postPrefsFile) [file join $path resources post prefs.rdb] 63 set this(prePrefsPath) [file join $path resources pre] 64 set this(prePrefsFile) [file join $path resources pre prefs.rdb] 65 set this(themesPath) [file join $path themes] 66 set this(httpdRootPath) $path 67 set this(isAppWrapped) 0 68 set this(appPath) $path 69 70 # 'appPath' points to folder which contains: 71 # Coccinella.tcl if run from sources 72 # Coccinella*.exe on Windows 73 # Coccinella*.bin on Unix 74 # Coccinella*.app on Mac OS X 75 76 if {[info exists starkit::topdir]} { 77 set this(appPath) [file dirname [info nameofexecutable]] 78 set this(isAppWrapped) 1 79 } elseif {$this(platform) eq "macosx"} { 80 81 # If we have an application bundle we must get the .app folder. 82 # bundle typically 'Coccinella-0.96.0.app' 83 set psplit [file split $this(appPath)] 84 set bundle [lsearch -glob -inline $psplit *.app] 85 if {$bundle ne ""} { 86 set appBundle [lsearch -glob -inline \ 87 [file split [info nameofexecutable]] *.app] 88 if {$appBundle eq $bundle} { 89 set idx [lsearch -glob $psplit *.app] 90 incr idx -1 91 set this(appPath) [eval file join [lrange $psplit 0 $idx]] 92 set this(isAppWrapped) 1 93 } 94 } 95 } 96 97 # Path where preferences etc are stored. 98 set this(prefsDefPath) [GetDefaultPrefsPath] 99 set this(prefsPath) $this(prefsDefPath) 100 set this(prefsName) "preferences.rdb" 101 102 # Old prefs name (changed 0.96.3) 103 switch -- $this(platform) { 104 macosx { 105 set this(oldPrefsName) "Whiteboard Prefs" 106 } 107 unix { 108 set this(oldPrefsName) "whiteboard" 109 } 110 windows { 111 set this(oldPrefsName) "WBPREFS.TXT" 112 } 113 } 114 115 if {$config(prefs,sameDrive)} { 116 117 # Handle the situation where the app lives on a removable drive (USB stick). 118 # If it lives on a removable drive, and if we find an existing prefs 119 # file there, then we should relate all prefs related paths to it. 120 set this(prefsPathRemovable) 0 121 if {[IsAppOnRemovableDrive]} { 122 set prefsPathDrive [GetAppDrivePrefsPath] 123 set prefFile [file join $prefsPathDrive $this(prefsName)] 124 set oldFile [file join $prefsPathDir $this(oldPrefsName)] 125 if {([file exists $prefFile] && [file writable $prefFile]) || \ 126 ([file exists $oldFile] && [file writable $oldFile])} { 127 set this(prefsPathRemovable) 1 128 set this(prefsPath) $prefsPathDrive 129 } 130 } 131 } elseif {$config(prefs,sameDir)} { 132 133 # Search for the prefs file in the applicatons folder first. 134 set this(prefsPathAppDir) 0 135 set prefsPathDir [GetAppDirPrefsPath] 136 set prefFile [file join $prefsPathDir $this(prefsName)] 137 set oldFile [file join $prefsPathDir $this(oldPrefsName)] 138 if {([file exists $prefFile] && [file writable $prefFile]) || \ 139 ([file exists $oldFile] && [file writable $oldFile])} { 140 set this(prefsPathAppDir) 1 141 set this(prefsPath) $prefsPathDir 142 } 143 } 144 145 # Import any old (pre 0.96.3) prefs file. 146 set oldPrefs [file join $this(prefsPath) $this(oldPrefsName)] 147 if {[file exists $oldPrefs]} { 148 set newPrefs [file join $this(prefsPath) $this(prefsName)] 149 file rename -force $oldPrefs $newPrefs 150 } 151 152 # Sets all paths that are dependent on this(prefsPath). 153 SetPrefsPaths 154 155 # Make sure all dirs exist. 156 MakePrefsDirs 157 158 # Need to rework this... 159 if {0 && [info exists starkit::topdir]} { 160 set this(httpdRootPath) $starkit::topdir 161 set this(httpdRelPath) \ 162 [file join $::starkit::topdir lib app-Coccinella httpd] 163 } 164 set this(internalIPnum) 127.0.0.1 165 set this(internalIPname) "localhost" 166 167 # Set our IP number temporarily. 168 set this(ipnum) $this(internalIPnum) 169 170 # Need a tmp directory, typically in a StarKit when QuickTime movies are opened. 171 set MAX_INT 0x7FFFFFFF 172 set hex [format {%x} [expr {int($MAX_INT*rand())}]] 173 set tail coccinella[pid]-$hex 174 set this(tmpPath) [file join [TempDir] $tail] 175 if {![file isdirectory $this(tmpPath)]} { 176 file mkdir $this(tmpPath) 177 } 178 179 # This is where the "Batteries Included" binaries go. Empty if non. 180 if {$this(platform) eq "unix"} { 181 set machine $tcl_platform(machine) 182 if {[regexp {[2-9]86} $tcl_platform(machine)]} { 183 set machine "i686" 184 } elseif {$tcl_platform(machine) eq "x86_64"} { 185 if {[info exists ::starkit::topdir]} { 186 set machine "i686" 187 } else { 188 set machine "x86_64" 189 } 190 } 191 set machineSpecPath [file join $tcl_platform(os) $machine] 192 } elseif {$this(platform) eq "macosx"} { 193 194 # We keep universal builds for 8.5 in 'i386'. 195 if {[info tclversion] >= 8.5} { 196 set machineSpecPath i386 197 } else { 198 set machineSpecPath $tcl_platform(machine) 199 } 200 } else { 201 set machineSpecPath $tcl_platform(machine) 202 } 203 204 # Make cvs happy. 205 regsub -all " " $machineSpecPath "" machineSpecPath 206 207 set this(binLibPath) [file join $path bin library] 208 set this(binPath) [file join $path bin $this(platform) $machineSpecPath] 209 if {[file exists $this(binPath)]} { 210 set auto_path [concat [list $this(binPath)] $auto_path] 211 set auto_path [concat [list $this(binLibPath)] $auto_path] 212 } else { 213 set this(binPath) {} 214 } 215 216 switch -- [tk windowingsystem] { 217 "aqua" { set this(modkey) Command } 218 default { set this(modkey) Control } 219 } 220 221 # Find user name. 222 set this(username) [GetUserName] 223 224 # Write a pid file with our pid that gets deleted when quit. 225 # This is a way to detect if we are running. 226 set this(pidFile) [file join $this(prefsPath) coccinella.pid] 227 set fd [open $this(pidFile) w] 228 puts -nonewline $fd [pid] 229 close $fd 230 231 # Write a file to the prefs dir with our execution path. 232 if {[info exists ::starkit::topdir]} { 233 set exe [file nativename [info nameofexecutable]] 234 } else { 235 set exe "wish \"$mainScript\"" 236 } 237 set this(execFile) [file join $this(prefsPath) launchCmd] 238 set fd [open $this(execFile) w] 239 puts -nonewline $fd $exe 240 close $fd 241} 242 243# Init::GetDefaultPrefsPath -- 244# 245# Finds the actual file path to our default prefs dir. 246 247proc ::Init::GetDefaultPrefsPath {} { 248 global this 249 250 # Path where preferences etc are stored. 251 switch -- $this(platform) { 252 macosx { 253 set prefsPath \ 254 [file join [file nativename ~/Library/Preferences] Coccinella] 255 } 256 unix { 257 set prefsPath [file nativename ~/.coccinella] 258 } 259 windows { 260 261 # The default prefs dir is now obtained from the registry. 262 # If any old be sure to copy to new. 263 set appPath [GetWindowsAppPath] 264 set prefsPath [file join $appPath Coccinella] 265 if {![file isdirectory $prefsPath]} { 266 set oldPath [GetWindowsAdhocPrefsPath] 267 if {[file isdirectory $oldPath]} { 268 file copy -force -- $oldPath $appPath 269 file delete -force -- $oldPath 270 } 271 } 272 } 273 } 274 return $prefsPath 275} 276 277proc ::Init::GetWindowsAppPath {} { 278 279 set appPath "" 280 281 catch { 282 package require registry 283 set shellFoldersKey \ 284 {HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders} 285 set appPath [registry get $shellFoldersKey AppData] 286 regsub -all {%([a-zA-Z]+)%} $appPath \$::env(\\1) appPath 287 set appPath [subst -nobackslashes -nocommands $appPath] 288 if {![file isdirectory $appPath]} { 289 file mkdir $appPath 290 } 291 } 292 return $appPath 293} 294 295proc ::Init::GetWindowsAdhocPrefsPath {} { 296 297 set prefsPath "" 298 299 foreach key {USERPROFILE APPDATA HOME HOMEPATH \ 300 ALLUSERSPROFILE CommonProgramFiles HOMEDRIVE} { 301 if {[info exists ::env($key)] && [file writable $::env($key)]} { 302 set winPrefsDir $::env($key) 303 break 304 } 305 } 306 if {![info exists winPrefsDir]} { 307 set vols [lsort [file volumes]] 308 set vols [lsearch -all -inline -glob -not $vols A:*] 309 set vols [lsearch -all -inline -glob -not $vols B:*] 310 311 # If none of the above are writable this is unlikely. 312 if {[file writable [lindex $vols 0]]} { 313 set winPrefsDir [lindex $vols 0] 314 } else { 315 if {[info exists starkit::topdir]} { 316 set dir [file dirname [info nameofexecutable]] 317 } else { 318 set dir [file dirname [file dirname $this(script)]] 319 } 320 if {[file writable $dir]} { 321 set winPrefsDir $dir 322 } 323 } 324 } 325 if {[info exists winPrefsDir]} { 326 set prefsPath [file join $winPrefsDir Coccinella] 327 } 328 return $prefsPath 329} 330 331proc ::Init::IsAppOnRemovableDrive {} { 332 global this 333 334 set ans 0 335 336 if {$this(platform) eq "windows"} { 337 set prefsDrive [string tolower [string index $this(prefsDefPath) 0]] 338 set appDrive [string tolower [string index $this(appPath) 0]] 339 if {$prefsDrive ne $appDrive} { 340 set ans 1 341 } 342 } elseif {$this(platform) eq "macosx"} { 343 344 # Try to see if different drives. Ad hoc. 345 set lprefs [file split $this(prefsDefPath)] 346 set lapp [file split $this(appPath)] 347 set prefs1 [lindex $lprefs 1] 348 set app1 [lindex $lapp 1] 349 if {($app1 ne $prefs1) && ($app1 eq "Volumes")} { 350 set ans 1 351 } 352 } elseif {$this(platform) eq "unix"} { 353 # @@@ Don't know how to detect drives on unix in general. 354 } 355 return $ans 356} 357 358# Init::GetAppDrivePrefsPath -- 359# 360# Gets the prefs path for nonstandard drive. 361# It doesn't check for its existence. 362# You MUST have 'IsAppOnRemovableDrive' for this to make sense. 363 364proc ::Init::GetAppDrivePrefsPath {} { 365 global this 366 367 set lapp [file split $this(appPath)] 368 369 if {$this(platform) eq "windows"} { 370 set path [file join [lindex $lapp 0] $this(prefsDriverDir)] 371 } elseif {$this(platform) eq "macosx"} { 372 set drive [lindex $lapp 2] 373 set path [file join [lindex $lapp 0] [lindex $lapp 1] [lindex $lapp 2] \ 374 $this(prefsDriverDir)] 375 } elseif {$this(platform) eq "unix"} { 376 # @@@ Don't know how to detect drives on unix in general. 377 set path "" 378 } 379 return $path 380} 381 382# One above this(appPath). 383 384proc ::Init::GetAppDirPrefsPath {} { 385 global this 386 if {$this(isAppWrapped)} { 387 set path [file join $this(appPath) $this(prefsDriverDir)] 388 } else { 389 set psplit [file split $this(appPath)] 390 set path [eval file join [lrange $psplit 0 end-1] $this(prefsDriverDir)] 391 } 392 return $path 393} 394 395# Init::SetPrefsPaths -- 396# 397# Is supposed to set all standard paths that are dependent on 398# this(prefsPath). 399 400proc ::Init::SetPrefsPaths {} { 401 global this 402 403 set path $this(prefsPath) 404 405 set this(altItemPath) [file join $path items] 406 set this(altEmoticonsPath) [file join $path $this(emoticons)] 407 set this(altThemesPath) [file join $path themes] 408 set this(inboxFile) [file join $path Inbox.tcl] 409 set this(prefsAvatarPath) [file join $path avatar] 410 set this(myAvatarPath) [file join $path avatar my] 411 set this(cacheAvatarPath) [file join $path avatar cache] 412 set this(recentAvatarPath) [file join $path avatar recent] 413 set this(scriptsPath) [file join $path scripts] 414 set this(backgroundsPath) [file join $path backgrounds] 415 set this(certificatesPath) [file join $path certificates] 416 417 set pname $this(prefsName) 418 419 switch -- $this(platform) { 420 unix { 421 422 # On a central installation need to have local dirs for write access. 423 set this(userPrefsFilePath) [file nativename [file join $path $pname]] 424 set this(inboxCanvasPath) [file nativename [file join $path canvases]] 425 set this(historyPath) [file nativename [file join $path history]] 426 } 427 macosx { 428 set this(userPrefsFilePath) [file join $path $pname] 429 set this(inboxCanvasPath) [file join $path Canvases] 430 set this(historyPath) [file join $path History] 431 } 432 windows { 433 set this(userPrefsFilePath) [file join $path $pname] 434 set this(inboxCanvasPath) [file join $path Canvases] 435 set this(historyPath) [file join $path History] 436 } 437 } 438} 439 440# Init::SetPrefsPathToDefault, SetPrefsPathToRemovable -- 441# 442# Helpers to allow switching prefs location. 443 444proc ::Init::SetPrefsPathToDefault {} { 445 global this 446 447 set this(prefsPath) [GetDefaultPrefsPath] 448 set this(prefsPathRemovable) 0 449 set this(prefsPathAppDir) 0 450 451 SetPrefsPaths 452 MakePrefsDirs 453} 454 455proc ::Init::SetPrefsPathToRemovable {} { 456 global this 457 458 set this(prefsPath) [GetAppDrivePrefsPath] 459 set this(prefsPathRemovable) 1 460 set this(prefsPathAppDir) 0 461 462 SetPrefsPaths 463 MakePrefsDirs 464} 465 466proc ::Init::SetPrefsPathToAppDir {} { 467 global this 468 469 set this(prefsPath) [GetAppDirPrefsPath] 470 set this(prefsPathAppDir) 1 471 472 SetPrefsPaths 473 MakePrefsDirs 474} 475 476proc ::Init::GetUserName {} { 477 global this 478 479 # Find user name. 480 if {[info exists ::env(USER)]} { 481 set username $::env(USER) 482 } elseif {[info exists ::env(LOGIN)]} { 483 set username $::env(LOGIN) 484 } elseif {[info exists ::env(USERNAME)]} { 485 set username $::env(USERNAME) 486 } elseif {[llength [set this(hostname) [info hostname]]]} { 487 set username $this(hostname) 488 } else { 489 set username "Unknown" 490 } 491 return $username 492} 493 494proc ::Init::SetThisVersion {} { 495 global this 496 497 # The application major and minor version numbers; should only be written to 498 # default file, never read. 499 set this(vers,major) 0 500 set this(vers,minor) 96 501 set this(vers,release) 20 502 503 # NB: The 'minorRelease' number is only used for released versions and not 504 # in cvs or so called daily builds. cvs always have odd 'release' 505 # numbers and 'minorRelease' equal to 0. 506 # A minor release has always a nonzero 'minorRelease' number and 507 # an even 'release' number one minus the cvs 'release' number. 508 # An example: if the cvs version id 0.96.5 we can create a series 509 # of minor releases 0.96.4.1, 0.96.4.2, 0.96.4.3, ... 510 set this(vers,minorRelease) 0 511 512 set this(vers,full) $this(vers,major).$this(vers,minor).$this(vers,release) 513 if {$this(vers,minorRelease)} { 514 append this(vers,full) .$this(vers,minorRelease) 515 } 516 517 # This is used only to track upgrades. 518 set this(vers,previous) $this(vers,full) 519} 520 521proc ::Init::SetThisEmbedded {} { 522 global this 523 524 # We may be embedded in another application, say an ActiveX component. 525 # The TclControl ActiveX package defines the browser namespace. 526 # So does the TclPlugin, at least version 2.0: 527 # http://www.tcl.tk/man/plugin2.0/pluginDoc/plugin.htm 528 if {[namespace exists ::browser]} { 529 set this(embedded) 1 530 } else { 531 set this(embedded) 0 532 } 533} 534 535proc ::Init::MakePrefsDirs {} { 536 global this tcl_platform 537 538 foreach name { 539 prefsPath 540 inboxCanvasPath 541 historyPath 542 prefsAvatarPath 543 myAvatarPath 544 cacheAvatarPath 545 recentAvatarPath 546 altItemPath 547 altEmoticonsPath 548 altThemesPath 549 scriptsPath 550 backgroundsPath 551 } { 552 if {[file isfile $this($name)]} { 553 file delete -force $this($name) 554 } 555 if {![file isdirectory $this($name)]} { 556 file mkdir $this($name) 557 } 558 } 559 560 # Privacy! 561 # Make sure other have absolutely no access to our prefs. 562 # [Bug 243364] [NEW] umask needs to be set to 077 (?) 563 if {$tcl_platform(platform) eq "unix"} { 564 file attributes $this(prefsPath) -permissions 0700 565 } 566} 567 568proc ::Init::SetAutoPath {} { 569 global auto_path this prefs 570 571 # Hack on MacOSX to avoid all old installed packages. 572 if {$this(platform) eq "macosx"} { 573 set auto_path [lsearch -all -not -inline $auto_path "/System/Library/Tcl"] 574 set auto_path [lsearch -all -not -inline $auto_path "/System/Library/Frameworks"] 575 set auto_path [lsearch -all -not -inline $auto_path "/Network/Library/Tcl"] 576 set auto_path [lsearch -all -not -inline $auto_path "/Network/Library/Frameworks"] 577 set auto_path [lsearch -all -not -inline $auto_path "~/Library/Tcl"] 578 set auto_path [lsearch -all -not -inline $auto_path "~/Library/Frameworks"] 579 } 580 581 # Add our lib and whiteboard directory to our search path. 582 lappend auto_path [file join $this(path) lib] 583 lappend auto_path [file join $this(path) whiteboard] 584 585 # Add the contrib directory which has things like widgets etc. 586 lappend auto_path [file join $this(path) contrib] 587 588 # Add the jabberlib directory which provides jabber support. 589 lappend auto_path [file join $this(path) jabberlib] 590 591 # Add the jabber directory which provides client specific jabber stuffs. 592 lappend auto_path [file join $this(path) jabber] 593 594 # Add the components directory since we may have packages used by components. 595 lappend auto_path [file join $this(path) components] 596 597 # Do we need TclXML. This is in its own app specific dir. 598 # Perhaps there can be a conflict if there is already an TclXML 599 # package installed in the standard 'auto_path'. Be sure to have it first! 600 set auto_path [concat [list [file join $this(path) TclXML]] $auto_path] 601} 602 603proc ::Init::Msgcat {} { 604 global prefs this 605 606 package require msgcat 607 608 # The message catalog for language customization. Use 'en' as fallback. 609 if {$prefs(messageLocale) eq ""} { 610 if {[string match -nocase "c" [::msgcat::mclocale]]} { 611 ::msgcat::mclocale en 612 } 613 set locale [::msgcat::mclocale] 614 615 # Avoid the mac encoding problems by rejecting certain locales. 616 if {[tk windowingsystem] eq "aqua"} { 617 if {[regexp {ru} $locale]} { 618 set locale en 619 ::msgcat::mclocale en 620 } 621 } 622 } else { 623 set locale $prefs(messageLocale) 624 ::msgcat::mclocale $locale 625 } 626 627 set this(systemLocale) $locale 628 set lang [lindex [split [file rootname $locale] _] 0] 629 set langs [glob -nocomplain -tails -directory $this(msgcatPath) -- *.msg] 630 set havecat 0 631 foreach f $langs { 632 set langcode [lindex [split [file rootname $f] _] 0] 633 if {[string match -nocase ${langcode}* $locale]} { 634 set havecat 1 635 break 636 } 637 } 638 if {!$havecat} { 639 ::msgcat::mclocale en 640 } 641 642 # Windows is not utf-8 by default 643 encoding system utf-8 644 645 # Test here if you want a particular message catalog (en, nl, de, fr, sv,...). 646 #::msgcat::mclocale pl 647 uplevel #0 [list ::msgcat::mcload $this(msgcatPath)] 648 649 # This is a method to override default messages with custom ones for each 650 # language. 651 if {[file isdirectory $this(msgcatPostPath)]} { 652 uplevel #0 [list ::msgcat::mcload $this(msgcatPostPath)] 653 } 654 uplevel #0 namespace import ::msgcat::mc 655} 656 657# From tcllib (fileutil) + modifications: 658 659# ::Init::TempDir -- 660# 661# Return the correct directory to use for temporary files. 662# Python attempts this sequence, which seems logical: 663# 664# 1. The directory named by the `TMPDIR' environment variable. 665# 666# 2. The directory named by the `TEMP' environment variable. 667# 668# 3. The directory named by the `TMP' environment variable. 669# 670# 4. A platform-specific location: 671# * On Macintosh, the `Temporary Items' folder. 672# 673# * On Windows, the directories `C:\\TEMP', `C:\\TMP', 674# `\\TEMP', and `\\TMP', in that order. 675# 676# * On all other platforms, the directories `/tmp', 677# `/var/tmp', and `/usr/tmp', in that order. 678# 679# 5. As a last resort, the current working directory. 680# 681# Arguments: 682# None. 683# 684# Side Effects: 685# None. 686# 687# Results: 688# The directory for temporary files. 689 690proc ::Init::TempDir {} { 691 global tcl_platform env 692 693 set attempdirs [list] 694 695 foreach tmp {TMPDIR TEMP TMP} { 696 if {[info exists env($tmp)]} { 697 lappend attempdirs $env($tmp) 698 } 699 } 700 701 switch $tcl_platform(platform) { 702 windows { 703 lappend attempdirs "C:\\TEMP" "C:\\TMP" "\\TEMP" "\\TMP" 704 } 705 default { 706 lappend attempdirs [file join / tmp] \ 707 [file join / var tmp] [file join / usr tmp] 708 } 709 } 710 711 foreach tmp $attempdirs { 712 if {[file isdirectory $tmp] && [file writable $tmp]} { 713 return [file normalize $tmp] 714 } 715 } 716 717 # If nothing else worked... 718 return [file normalize [pwd]] 719} 720 721proc ::Init::LoadTkPng {} { 722 global this 723 724 # tkpng is required for the gui. 725 if {[catch {package require tkpng 0.7}]} { 726 tk_messageBox -icon error -title [::msgcat::mc "Error"] \ 727 -message "The tkpng package is required for the GUI" 728 exit 729 } 730 set this(package,tkpng) 1 731} 732 733proc ::Init::LoadPackages {} { 734 global this auto_path 735 736 # Take precautions and load only our own treectrl. 737 738 # tileqt has its own library support. 739 if {[tk windowingsystem] eq "x11"} { 740 namespace eval ::tileqt {} 741 set ::tileqt::library [file join $this(binLibPath) tileqt] 742 } 743 744 # treectrl is required. 745 ::Splash::SetMsg [mc "Looking for %s" treectrl]... 746 set ::treectrl_library [file join $this(binLibPath) treectrl] 747 if {[catch {package require treectrl 2.2} msg]} { 748 tk_messageBox -icon error -title [::msgcat::mc "Error"] \ 749 -message "This application requires the treectrl widget to work! $::errorInfo" 750 exit 751 } 752 753 # Other utility packages that can be platform specific. 754 # The 'Thread' package requires that the Tcl core has been built with support. 755 array set extraPacksArr { 756 macosx {Itcl Tclapplescript tls Thread MacCarbonPrint carbon} 757 windows {Itcl printer gdi tls Thread optcl tcom} 758 unix {Itcl tls Thread} 759 } 760 foreach {platform packList} [array get extraPacksArr] { 761 foreach name $packList { 762 set this(package,$name) 0 763 } 764 } 765 foreach name $extraPacksArr($this(platform)) { 766 ::Splash::SetMsg [mc "Looking for %s" $name]... 767 if {![catch {package require $name} msg]} { 768 set this(package,$name) 1 769 } else { 770 ::Debug 2 "unable to load package: $name, reason: $msg" 771 } 772 } 773 if {$this(package,Itcl)} { 774 uplevel #0 {namespace import ::itcl::*} 775 } 776 if {!($this(package,printer) && $this(package,gdi))} { 777 set this(package,printer) 0 778 } 779 780 # Not ready for this yet. 781 set this(package,Thread) 0 782} 783 784# Init::Config -- 785# 786# Sets any 'config' array entries. 787# The config array shall be used for hardcoded configuration settings 788# that can be overriden only at build time by adding a config.tcl file 789# in resources/. 790# array set config {junk "The Junk" ...} 791 792proc ::Init::Config {} { 793 global this config 794 795 set f [file join $this(resourcePath) config.tcl] 796 if {[file exists $f]} { 797 source $f 798 } 799 800 # Let any user defined config file override hard coded and build configs. 801 set f [file join $this(prefsPath) resources config.tcl] 802 if {[file exists $f]} { 803 source $f 804 } 805} 806 807proc ::Init::SetHostname {} { 808 global this 809 810 set this(hostname) [info hostname] 811} 812 813#------------------------------------------------------------------------------- 814