From 21c068f1916330e90f814bed461fe0821d1665ec Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sun, 9 Oct 2011 16:36:37 +0000 Subject: checked in pd-0.43-0.src.tar.gz svn path=/trunk/; revision=15557 --- pd/tcl/pd-gui.tcl | 506 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 347 insertions(+), 159 deletions(-) (limited to 'pd/tcl/pd-gui.tcl') diff --git a/pd/tcl/pd-gui.tcl b/pd/tcl/pd-gui.tcl index 6dfe1663..39b260f5 100644 --- a/pd/tcl/pd-gui.tcl +++ b/pd/tcl/pd-gui.tcl @@ -8,15 +8,19 @@ # "." automatically gets a window, we don't want it. Withdraw it before doing # anything else, so that we don't get the automatic window flashing for a # second while pd loads. -wm withdraw . - -puts -------------------------------pd-gui.tcl----------------------------------- +if { [catch {wm withdraw .} fid] } { exit 2 } package require Tcl 8.3 package require Tk -package require Tk -if {[tk windowingsystem] ne "win32"} {package require msgcat} +#package require tile +## replace Tk widgets with Ttk widgets on 8.5 +#namespace import -force ttk::* + +package require msgcat # TODO figure out msgcat issue on Windows +# TODO create a constructor in each package to create things at startup, that +# way they can be easily be modified by startup scripts +# TODO create alt-Enter/Cmd-I binding to bring up Properties panels # Pd's packages are stored in the same directory as the main script (pd-gui.tcl) set auto_path [linsert $auto_path 0 [file dirname [info script]]] @@ -27,26 +31,52 @@ package require pdwindow package require dialog_array package require dialog_audio package require dialog_canvas +package require dialog_data package require dialog_font package require dialog_gatom package require dialog_iemgui +package require dialog_message package require dialog_midi +package require dialog_path +package require dialog_startup +package require helpbrowser +package require pd_menucommands +package require opt_parser package require pdtk_canvas package require pdtk_text # TODO eliminate this kludge: package require wheredoesthisgo +#------------------------------------------------------------------------------# +# import functions into the global namespace + +# make global since they are used throughout +namespace import ::pd_menucommands::* + # import into the global namespace for backwards compatibility namespace import ::pd_connect::pdsend namespace import ::pdwindow::pdtk_post +namespace import ::pdwindow::pdtk_pd_dio +namespace import ::pdwindow::pdtk_pd_dsp +namespace import ::pdwindow::pdtk_pd_meters +namespace import ::pdtk_canvas::pdtk_canvas_popup +namespace import ::pdtk_canvas::pdtk_canvas_editmode +namespace import ::pdtk_canvas::pdtk_canvas_getscroll +namespace import ::pdtk_canvas::pdtk_canvas_setparents +namespace import ::pdtk_canvas::pdtk_canvas_reflecttitle +namespace import ::pdtk_canvas::pdtk_canvas_menuclose namespace import ::dialog_array::pdtk_array_dialog namespace import ::dialog_audio::pdtk_audio_dialog namespace import ::dialog_canvas::pdtk_canvas_dialog +namespace import ::dialog_data::pdtk_data_dialog +namespace import ::dialog_find::pdtk_couldnotfind namespace import ::dialog_font::pdtk_canvas_dofont namespace import ::dialog_gatom::pdtk_gatom_dialog namespace import ::dialog_iemgui::pdtk_iemgui_dialog namespace import ::dialog_midi::pdtk_midi_dialog namespace import ::dialog_midi::pdtk_alsa_midi_dialog +namespace import ::dialog_path::pdtk_path_dialog +namespace import ::dialog_startup::pdtk_startup_dialog # hack - these should be better handled in the C code namespace import ::dialog_array::pdtk_array_listview_new @@ -57,10 +87,16 @@ namespace import ::dialog_array::pdtk_array_listview_closeWindow #------------------------------------------------------------------------------# # global variables +# this is a wide array of global variables that are used throughout the GUI. +# they can be used in plugins to check the status of various things since they +# should all have been properly initialized by the time startup plugins are +# loaded. + set PD_MAJOR_VERSION 0 set PD_MINOR_VERSION 0 set PD_BUGFIX_VERSION 0 set PD_TEST_VERSION "" +set done_init 0 set TCL_MAJOR_VERSION 0 set TCL_MINOR_VERSION 0 @@ -69,8 +105,13 @@ set TCL_BUGFIX_VERSION 0 # for testing which platform we are running on ("aqua", "win32", or "x11") set windowingsystem "" -# variable for vwait so that 'pd-gui' will timeout if 'pd' never shows up -set wait4pd "init" +# args about how much and where to log +set loglevel 2 +set stderr 0 + +# connection between 'pd' and 'pd-gui' +set host "" +set port 0 # canvas font, received from pd in pdtk_pd_startup, set in s_main.c set font_family "courier" @@ -78,45 +119,95 @@ set font_weight "normal" # sizes of chars for each of the Pd fixed font sizes: # fontsize width(pixels) height(pixels) set font_fixed_metrics { - 8 5 10 - 9 6 11 + 8 5 11 + 9 6 12 10 6 13 - 12 7 15 + 12 7 16 14 8 17 - 16 10 20 + 16 10 19 18 11 22 - 24 14 30 + 24 14 29 30 18 37 - 36 22 45 + 36 22 44 } +set font_measured_metrics {} # root path to lib of Pd's files, see s_main.c for more info set sys_libdir {} # root path where the pd-gui.tcl GUI script is located set sys_guidir {} - -set audioapi_list {} -set midiapi_list {} +# user-specified search path for objects, help, fonts, etc. +set sys_searchpath {} +# hard-coded search patch for objects, help, plugins, etc. +set sys_staticpath {} +# the path to the folder where the current plugin is being loaded from +set current_plugin_loadpath {} +# list of command line flags set at startup +set startup_flags {} +# list of libraries loaded on startup +set startup_libraries {} +# start dirs for new files and open panels +set filenewdir [pwd] +set fileopendir [pwd] + + +# lists of audio/midi devices and APIs for prefs dialogs +set audio_apilist {} +set audio_indevlist {} +set audio_outdevlist {} +set midi_apilist {} +set midi_indevlist {} +set midi_outdevlist {} set pd_whichapi 0 set pd_whichmidiapi 0 # current state of the DSP set dsp 0 +# state of the peak meters in the Pd window +set meters 0 # the toplevel window that currently is on top and has focus set focused_window . -# TODO figure out how to get all windows into the menu_windowlist -# store list of parent windows for Window menu -set menu_windowlist {} # store that last 10 files that were opened set recentfiles_list {} set total_recentfiles 10 -# keep track of the location of popup menu for CanvasWindows -set popup_xpix 0 -set popup_ypix 0 +# keep track of the location of popup menu for PatchWindows, in canvas coords +set popup_xcanvas 0 +set popup_ycanvas 0 +# modifier for key commands (Ctrl/Control on most platforms, Cmd/Mod1 on MacOSX) +set modifier "" +# current state of the Edit Mode menu item +set editmode_button 0 + ## per toplevel/patch data -# store editmode for each open canvas, starting with a blank array -array set editmode {} +# window location modifiers +set menubarsize 0 ;# Mac OS X and other platforms have a menubar on top +set windowframex 0 ;# different platforms have different window frames +set windowframey 0 ;# different platforms have different window frames +# patch properties +array set editmode {} ;# store editmode for each open patch canvas +array set editingtext {};# if an obj, msg, or comment is being edited, per patch +array set loaded {} ;# store whether a patch has completed loading +array set xscrollable {};# keep track of whether the scrollbars are present +array set yscrollable {} +# patch window tree, these might contain patch IDs without a mapped toplevel +array set windowname {} ;# window names based on mytoplevel IDs +array set childwindows {} ;# all child windows based on mytoplevel IDs +array set parentwindows {} ;# topmost parent window ID based on mytoplevel IDs + +# variables for holding the menubar to allow for configuration by plugins +set ::pdwindow_menubar ".menubar" +set ::patch_menubar ".menubar" +set ::dialog_menubar "" + +# minimum size of the canvas window of a patch +set canvas_minwidth 50 +set canvas_minheight 20 + +# undo states +set ::undo_action "no" +set ::redo_action "no" +set ::undo_toplevel "." #------------------------------------------------------------------------------# # coding style @@ -129,17 +220,23 @@ array set editmode {} # - if a menu_* proc opens a dialog panel, that proc is called menu_*_dialog # - use "eq/ne" for string comparison, NOT "==/!=" (http://wiki.tcl.tk/15323) # +# ## Names for Common Variables #---------------------------- -# # variables named after the Tk widgets they represent +# $window = any kind of Tk widget that can be a Tk 'window' # $mytoplevel = a window id made by a 'toplevel' command -# $mygfxstub = a window id made by a 'toplevel' command via gfxstub/x_gui.c -# $menubar = the 'menu' attached to each 'toplevel' -# $mymenu = 'menu' attached to the menubar -# $menuitem = 'menu' item -# $mycanvas = 'canvas' -# $canvasitem = 'canvas' item +# $gfxstub = a 'toplevel' window id for dialogs made in gfxstub/x_gui.c +# $menubar = the 'menu' attached to each 'toplevel' +# $mymenu = 'menu' attached to the menubar, like the File menu +# $tkcanvas = a Tk 'canvas', which is the root of each patch +# +# +## Dialog Panel Types +#---------------------------- +# global (only one): find, sendmessage, prefs, helpbrowser +# per-canvas: font, canvas properties (created with a message from pd) +# per object: gatom, iemgui, array, data structures (created with a message from pd) # # ## Prefix Names for procs @@ -150,18 +247,6 @@ array set editmode {} # ------------------------------------------------------------------------------ # init functions -proc set_pd_version {versionstring} { - regexp -- {.*([0-9])\.([0-9]+)[\.\-]([0-9]+)([^0-9]?.*)} $versionstring \ - wholematch \ - ::PD_MAJOR_VERSION ::PD_MINOR_VERSION ::PD_BUGFIX_VERSION ::PD_TEST_VERSION -} - -proc set_tcl_version {} { - regexp {([0-9])\.([0-9])\.([0-9]+)} [info patchlevel] \ - wholematch \ - ::TCL_MAJOR_VERSION ::TCL_MINOR_VERSION ::TCL_BUGFIX_VERSION -} - # root paths to find Pd's files where they are installed proc set_pd_paths {} { set ::sys_guidir [file normalize [file dirname [info script]]] @@ -175,6 +260,8 @@ proc init_for_platform {} { switch -- $::windowingsystem { "x11" { + set ::modifier "Control" + option add *PatchWindow*Canvas.background "white" startupFile # add control to show/hide hidden files in the open panel (load # the tk_getOpenFile dialog once, otherwise it will not work) catch {tk_getOpenFile -with-invalid-argument} @@ -188,8 +275,31 @@ proc init_for_platform {} { [list [_ "Max Patch Files"] {.pat} ] \ [list [_ "Max Text Files"] {.mxt} ] \ ] + # some platforms have a menubar on the top, so place below them + set ::menubarsize 0 + # Tk handles the window placement differently on each + # platform. With X11, the x,y placement refers to the window + # frame's upper left corner. http://wiki.tcl.tk/11502 + set ::windowframex 3 + set ::windowframey 53 + # TODO add wm iconphoto/iconbitmap here if it makes sense + # mouse cursors for all the different modes + set ::cursor_runmode_nothing "left_ptr" + set ::cursor_runmode_clickme "arrow" + set ::cursor_runmode_thicken "sb_v_double_arrow" + set ::cursor_runmode_addpoint "plus" + set ::cursor_editmode_nothing "hand2" + set ::cursor_editmode_connect "circle" + set ::cursor_editmode_disconnect "X_cursor" } "aqua" { + set ::modifier "Mod1" + option add *DialogWindow*background "#E8E8E8" startupFile + option add *DialogWindow*Entry.highlightBackground "#E8E8E8" startupFile + option add *DialogWindow*Button.highlightBackground "#E8E8E8" startupFile + option add *DialogWindow*Entry.background "white" startupFile + # Mac OS X needs a menubar all the time + set ::dialog_menubar ".menubar" # set file types that open/save recognize set ::filetypes \ [list \ @@ -197,10 +307,33 @@ proc init_for_platform {} { [list [_ "Pd Files"] {.pd} ] \ [list [_ "Max Patch Files (.pat)"] {.pat} ] \ [list [_ "Max Text Files (.mxt)"] {.mxt} ] \ - ] + ] + # some platforms have a menubar on the top, so place below them + set ::menubarsize 22 + # Tk handles the window placement differently on each platform, on + # Mac OS X, the x,y placement refers to the content window's upper + # left corner (not of the window frame) http://wiki.tcl.tk/11502 + set ::windowframex 0 + set ::windowframey 0 + # mouse cursors for all the different modes + set ::cursor_runmode_nothing "arrow" + set ::cursor_runmode_clickme "center_ptr" + set ::cursor_runmode_thicken "sb_v_double_arrow" + set ::cursor_runmode_addpoint "plus" + set ::cursor_editmode_nothing "hand2" + set ::cursor_editmode_connect "circle" + set ::cursor_editmode_disconnect "X_cursor" } "win32" { + set ::modifier "Control" + option add *PatchWindow*Canvas.background "white" startupFile + # fix menu font size on Windows with tk scaling = 1 font create menufont -family Tahoma -size -11 + option add *Menu.font menufont startupFile + option add *HelpBrowser*font menufont startupFile + option add *DialogWindow*font menufont startupFile + option add *PdWindow*font menufont startupFile + option add *ErrorDialog*font menufont startupFile # set file types that open/save recognize set ::filetypes \ [list \ @@ -209,6 +342,24 @@ proc init_for_platform {} { [list [_ "Max Patch Files"] {.pat} ] \ [list [_ "Max Text Files"] {.mxt} ] \ ] + # some platforms have a menubar on the top, so place below them + set ::menubarsize 0 + # Tk handles the window placement differently on each platform, on + # Mac OS X, the x,y placement refers to the content window's upper + # left corner. http://wiki.tcl.tk/11502 + # TODO this probably needs a script layer: http://wiki.tcl.tk/11291 + set ::windowframex 0 + set ::windowframey 0 + # TODO use 'winico' package for full, hicolor icon support + wm iconbitmap . -default [file join $::sys_guidir pd.ico] + # mouse cursors for all the different modes + set ::cursor_runmode_nothing "right_ptr" + set ::cursor_runmode_clickme "arrow" + set ::cursor_runmode_thicken "sb_v_double_arrow" + set ::cursor_runmode_addpoint "plus" + set ::cursor_editmode_nothing "hand2" + set ::cursor_editmode_connect "circle" + set ::cursor_editmode_disconnect "X_cursor" } } } @@ -217,26 +368,32 @@ proc init_for_platform {} { # locale handling # official GNU gettext msgcat shortcut -if {[tk windowingsystem] ne "win32"} { - proc _ {s} {return [::msgcat::mc $s]} -} else { - proc _ {s} {return $s} -} +proc _ {s} {return [::msgcat::mc $s]} proc load_locale {} { - if {[tk windowingsystem] ne "win32"} { - ::msgcat::mcload [file join [file dirname [info script]] .. po] + # on any UNIX-like environment, Tcl should automatically use LANG, LC_ALL, + # etc. otherwise we need to dig it up. Mac OS X only uses LANG, etc. from + # the Terminal, and Windows doesn't have LANG, etc unless you manually set + # it up yourself. Windows apps don't use the locale env vars usually. + if {$::tcl_platform(os) eq "Darwin" && ! [info exists ::env(LANG)]} { + # http://thread.gmane.org/gmane.comp.lang.tcl.mac/5215 + # http://thread.gmane.org/gmane.comp.lang.tcl.mac/6433 + if {![catch "exec defaults read com.apple.dock loc" lang]} { + ::msgcat::mclocale $lang + } elseif {![catch "exec defaults read NSGlobalDomain AppleLocale" lang]} { + ::msgcat::mclocale $lang + } + } elseif {$::tcl_platform(platform) eq "windows"} { + # using LANG on Windows is useful for easy debugging + if {[info exists ::env(LANG)] && $::env(LANG) ne "C" && $::env(LANG) ne ""} { + ::msgcat::mclocale $::env(LANG) + } elseif {![catch {package require registry}]} { + ::msgcat::mclocale [string tolower \ + [string range \ + [registry get {HKEY_CURRENT_USER\Control Panel\International} sLanguage] 0 1] ] + } } - - # for Windows - #set locale "en" ;# Use whatever is right for your app - #if {[catch {package require registry}]} { - # tk_messageBox -icon error -message "Could not get locale from registry" - #} else { - # set locale [string tolower \ - # [string range \ - # [registry get {HKEY_CURRENT_USER\Control Panel\International} sLanguage] 0 1] ] - #} + ::msgcat::mcload [file join [file dirname [info script]] .. po] ##--moo: force default system and stdio encoding to UTF-8 encoding system utf-8 @@ -258,32 +415,32 @@ proc get_font_for_size {size} { # always do a good job of choosing in respect to Pd's needs. So this chooses # from a list of fonts that are known to work well with Pd. proc find_default_font {} { - set testfonts {Inconsolata "Courier New" "Liberation Mono" FreeMono \ - "DejaVu Sans Mono" "Bitstream Vera Sans Mono"} + set testfonts {"DejaVu Sans Mono" "Bitstream Vera Sans Mono" \ + "Inconsolata" "Courier 10 Pitch" "Andale Mono" "Droid Sans Mono"} foreach family $testfonts { if {[lsearch -exact -nocase [font families] $family] > -1} { set ::font_family $family break } } - puts "DEFAULT FONT: $::font_family" + ::pdwindow::verbose 0 "Default font: $::font_family\n" } proc set_base_font {family weight} { if {[lsearch -exact [font families] $family] > -1} { set ::font_family $family } else { - pdtk_post [format \ - [_ "WARNING: Font family '%s' not found, using default (%s)"] \ - $family $::font_family] + ::pdwindow::post [format \ + [_ "WARNING: Font family '%s' not found, using default (%s)\n"] \ + $family $::font_family] } if {[lsearch -exact {bold normal} $weight] > -1} { set ::font_weight $weight set using_defaults 0 } else { - pdtk_post [format \ - [_ "WARNING: Font weight '%s' not found, using default (%s)"] \ - $weight $::font_weight] + ::pdwindow::post [format \ + [_ "WARNING: Font weight '%s' not found, using default (%s)\n"] \ + $weight $::font_weight] } } @@ -297,17 +454,22 @@ proc fit_font_into_metrics {} { -size [expr {-$height}] set height2 $height set giveup 0 - while {[font measure $myfont M] > $width} { + while {[font measure $myfont M] > $width || \ + [font metrics $myfont -linespace] > $height} { incr height2 -1 font configure $myfont -size [expr {-$height2}] if {$height2 * 2 <= $height} { set giveup 1 + set ::font_measured_metrics $::font_fixed_metrics break } } + set ::font_measured_metrics \ + "$::font_measured_metrics $size\ + [font measure $myfont M] [font metrics $myfont -linespace]" if {$giveup} { - pdtk_post [format \ - [_ "ERROR: %s failed to find font size (%s) that fits into %sx%s!"]\ + ::pdwindow::post [format \ + [_ "WARNING: %s failed to find font size (%s) that fits into %sx%s!\n"]\ [lindex [info level 0] 0] $size $width $height] continue } @@ -318,46 +480,77 @@ proc fit_font_into_metrics {} { # ------------------------------------------------------------------------------ # procs called directly by pd -# this is only called when 'pd' starts 'pd-gui', not the other way around -proc pdtk_pd_startup {versionstring audio_apis midi_apis sys_font sys_fontweight} { -# pdtk_post "-------------- pdtk_pd_startup ----------------" -# pdtk_post "version: $versionstring" -# pdtk_post "audio_apis: $audio_apis" -# pdtk_post "midi_apis: $midi_apis" -# pdtk_post "sys_font: $sys_font" -# pdtk_post "sys_fontweight: $sys_fontweight" +proc pdtk_pd_startup {major minor bugfix test + audio_apis midi_apis sys_font sys_fontweight} { + set ::PD_MAJOR_VERSION $major + set ::PD_MINOR_VERSION $minor + set ::PD_BUGFIX_VERSION $bugfix + set ::PD_TEST_VERSION $test set oldtclversion 0 - pdsend "pd init [enquote_path [pwd]] $oldtclversion $::font_fixed_metrics" - set_pd_version $versionstring - set ::audioapi_list $audio_apis - set ::midiapi_list $midi_apis + set ::audio_apilist $audio_apis + set ::midi_apilist $midi_apis if {$::tcl_version >= 8.5} {find_default_font} set_base_font $sys_font $sys_fontweight fit_font_into_metrics - # TODO what else is needed from the original? - set ::wait4pd "started" + pdsend "pd init [enquote_path [pwd]] $oldtclversion $::font_measured_metrics" + ::pd_bindings::class_bindings + ::pd_bindings::global_bindings + ::pd_menus::create_menubar + ::pdtk_canvas::create_popup + ::pdwindow::create_window + ::pd_menus::configure_for_pdwindow + load_startup_plugins + open_filestoopen + set ::done_init 1 } ##### routine to ask user if OK and, if so, send a message on to Pd ###### -# TODO add 'mytoplevel' once merged to 0.43, with -parent -proc pdtk_check {message reply_to_pd default} { - # TODO this should use -parent and -title, but the hard part is figuring - # out how to get the values for those without changing g_editor.c - set answer [tk_messageBox -type yesno -icon question -default $default \ - -message [_ $message]] +proc pdtk_check {mytoplevel message reply_to_pd default} { + wm deiconify $mytoplevel + raise $mytoplevel + if {$::windowingsystem eq "win32"} { + set answer [tk_messageBox -message [_ $message] -type yesno -default $default \ + -icon question -title [wm title $mytoplevel]] + } else { + set answer [tk_messageBox -message [_ $message] -type yesno \ + -default $default -parent $mytoplevel -icon question] + } if {$answer eq "yes"} { pdsend $reply_to_pd } } -proc pdtk_fixwindowmenu {} { - # TODO canvas_updatewindowlist() sets up the menu_windowlist with all of - # the parent CanvasWindows, we should then use [wm stackorder .] to get - # the rest of the CanvasWindows to make sure that all CanvasWindows are in - # the menu. This would probably be better handled on the C side of - # things, since then, the menu_windowlist could be built with the proper - # parent/child relationships. - # pdtk_post "Running pdtk_fixwindowmenu" +# ------------------------------------------------------------------------------ +# parse command line args when Wish/pd-gui.tcl is started first + +proc parse_args {argc argv} { + opt_parser::init { + {-stderr set {::stderr}} + {-open lappend {- ::filestoopen_list}} + } + set unflagged_files [opt_parser::get_options $argv] + # if we have a single arg that is not a file, its a port or host:port combo + if {$argc == 1 && ! [file exists $argv]} { + if { [string is int $argv] && $argv > 0} { + # 'pd-gui' got the port number from 'pd' + set ::host "localhost" + set ::port $argv + } else { + set hostport [split $argv ":"] + set ::host [lindex $hostport 0] + set ::port [lindex $hostport 1] + } + } elseif {$unflagged_files ne ""} { + foreach filename $unflagged_files { + lappend ::filestoopen_list $filename + } + } +} + +proc open_filestoopen {} { + foreach filename $::filestoopen_list { + open_file $filename + } } # ------------------------------------------------------------------------------ @@ -384,28 +577,37 @@ proc first_lost {} { selection own -command first_lost -selection PUREDATA . } -# all other instances -proc send_args {offset maxChars} { - return [string range $::argv $offset [expr {$offset+$maxChars}]] -} - proc others_lost {} { set ::singleton_state "exit" destroy . exit } +# all other instances +proc send_args {offset maxChars} { + set sendargs {} + foreach filename $::filestoopen_list { + lappend sendargs [file normalize $filename] + } + return [string range $sendargs $offset [expr {$offset+$maxChars}]] +} -# ------------------------------------------------------------------------------ -# various startup related procs +# this command will open files received from a 2nd instance of Pd +proc receive_args {filelist} { + raise . + foreach filename $filelist { + open_file $filename + } +} proc check_for_running_instances {argc argv} { - # pdtk_post "check_for_running_instances $argc $argv" switch -- $::windowingsystem { "aqua" { # handled by ::tk::mac::OpenDocument in apple_events.tcl } "x11" { # http://wiki.tcl.tk/1558 + # TODO replace PUREDATA name with path so this code is a singleton + # based on install location rather than this hard-coded name if {![singleton PUREDATA_MANAGER]} { # other instances called by wish/pd-gui (exempt 'pd' by 5400 arg) if {$argc == 1 && [string is int $argv] && $argv >= 5400} {return} @@ -425,32 +627,33 @@ proc check_for_running_instances {argc argv} { } } -# this command will open files received from a 2nd instance of Pd -proc receive_args args { - # pdtk_post "receive_files $args" - raise . - foreach filename $args { - open_file $filename + +# ------------------------------------------------------------------------------ +# load plugins on startup + +proc load_plugin_script {filename} { + global errorInfo + + ::pdwindow::debug "Loading plugin: $filename\n" + set tclfile [open $filename] + set tclcode [read $tclfile] + close $tclfile + if {[catch {uplevel #0 $tclcode} errorname]} { + ::pdwindow::error "-----------\n" + ::pdwindow::error "UNHANDLED ERROR: $errorInfo\n" + ::pdwindow::error "FAILED TO LOAD $filename\n" + ::pdwindow::error "-----------\n" } } -proc load_startup {} { - global errorInfo -# TODO search all paths for startup.tcl - set startupdir [file normalize "$::sys_libdir/startup"] - # pdtk_post "load_startup $startupdir" - puts stderr "load_startup $startupdir" - if { ! [file isdirectory $startupdir]} { return } - foreach filename [glob -directory $startupdir -nocomplain -types {f} -- *.tcl] { - puts "Loading $filename" - set tclfile [open $filename] - set tclcode [read $tclfile] - close $tclfile - if {[catch {uplevel #0 $tclcode} errorname]} { - puts stderr "------------------------------------------------------" - puts stderr "UNHANDLED ERROR: $errorInfo" - puts stderr "FAILED TO LOAD $filename" - puts stderr "------------------------------------------------------" +proc load_startup_plugins {} { + foreach pathdir [concat $::sys_searchpath $::sys_staticpath] { + set dir [file normalize $pathdir] + if { ! [file isdirectory $dir]} {continue} + foreach filename [glob -directory $dir -nocomplain -types {f} -- \ + *-plugin/*-plugin.tcl *-plugin.tcl] { + set ::current_plugin_loadpath [file dirname $filename] + load_plugin_script $filename } } } @@ -462,42 +665,27 @@ proc main {argc argv} { set ::windowingsystem [tk windowingsystem] tk appname pd-gui load_locale + parse_args $argc $argv check_for_running_instances $argc $argv set_pd_paths init_for_platform - # post_tclinfo - # set a timeout for how long 'pd-gui' should wait for 'pd' to start - after 20000 set ::wait4pd "timeout" - # TODO check args for -stderr and set pdtk_post accordingly - if {$argc == 1 && [string is int $argv] && $argv >= 5400} { + # ::host and ::port are parsed from argv by parse_args + if { $::port > 0 && $::host ne "" } { # 'pd' started first and launched us, so get the port to connect to - ::pd_connect::to_pd [lindex $argv 0] + ::pd_connect::to_pd $::port $::host } else { # the GUI is starting first, so create socket and exec 'pd' - set portnumber [::pd_connect::create_socket] + set ::port [::pd_connect::create_socket] set pd_exec [file join [file dirname [info script]] ../bin/pd] - exec -- $pd_exec -guiport $portnumber & - } - # wait for 'pd' to call pdtk_pd_startup, or exit on timeout - vwait ::wait4pd - if {$::wait4pd eq "timeout"} { - puts stderr [_ "ERROR: 'pd' never showed up, 'pd-gui' quitting!"] - exit 2 + exec -- $pd_exec -guiport $::port & + if {$::windowingsystem eq "aqua"} { + # on Aqua, if 'pd-gui' first, then initial dir is home + set ::filenewdir $::env(HOME) + set ::fileopendir $::env(HOME) + } } - ::pd_bindings::class_bindings - ::pd_menus::create_menubar - ::pdtk_canvas::create_popup - ::pdwindow::create_window - ::pd_menus::configure_for_pdwindow - load_startup - # pdtk_post "------------------ done with main ----------------------" + ::pdwindow::verbose 0 "------------------ done with main ----------------------\n" } main $::argc $::argv - - - - - - -- cgit v1.2.1