blob: 4b365af409c6ea859dff68ef6dadb5edefc6669e [file] [log] [blame]
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001"""
2A number of function that enhance IDLE on MacOSX when it used as a normal
3GUI application (as opposed to an X11 application).
4"""
5import sys
Georg Brandl14fc4272008-05-17 18:39:55 +00006import tkinter
Georg Brandlaedd2892010-12-19 10:10:32 +00007from os import path
Thomas Wouters0e3f5912006-08-11 14:57:12 +00008
Ronald Oussoren6f6c5622009-12-24 14:03:19 +00009
10_appbundle = None
11
Thomas Wouters0e3f5912006-08-11 14:57:12 +000012def runningAsOSXApp():
Ronald Oussoren827822e2009-02-12 15:01:44 +000013 """
14 Returns True if Python is running from within an app on OSX.
15 If so, assume that Python was built with Aqua Tcl/Tk rather than
Benjamin Peterson8719ad52009-09-11 22:24:02 +000016 X11 Tcl/Tk.
Ronald Oussoren827822e2009-02-12 15:01:44 +000017 """
Ronald Oussoren6f6c5622009-12-24 14:03:19 +000018 global _appbundle
19 if _appbundle is None:
20 _appbundle = (sys.platform == 'darwin' and '.app' in sys.executable)
21 return _appbundle
Thomas Wouters0e3f5912006-08-11 14:57:12 +000022
Georg Brandlaedd2892010-12-19 10:10:32 +000023_carbonaquatk = None
24
25def isCarbonAquaTk(root):
26 """
27 Returns True if IDLE is using a Carbon Aqua Tk (instead of the
28 newer Cocoa Aqua Tk).
29 """
30 global _carbonaquatk
31 if _carbonaquatk is None:
32 _carbonaquatk = (runningAsOSXApp() and
33 'aqua' in root.tk.call('tk', 'windowingsystem') and
34 'AppKit' not in root.tk.call('winfo', 'server', '.'))
35 return _carbonaquatk
36
Thomas Wouters0e3f5912006-08-11 14:57:12 +000037def addOpenEventSupport(root, flist):
38 """
39 This ensures that the application will respont to open AppleEvents, which
40 makes is feaseable to use IDLE as the default application for python files.
41 """
42 def doOpenFile(*args):
43 for fn in args:
44 flist.open(fn)
45
46 # The command below is a hook in aquatk that is called whenever the app
47 # receives a file open event. The callback can have multiple arguments,
48 # one for every file that should be opened.
49 root.createcommand("::tk::mac::OpenDocument", doOpenFile)
50
51def hideTkConsole(root):
Guido van Rossumb5a755e2007-07-18 18:15:48 +000052 try:
53 root.tk.call('console', 'hide')
Georg Brandl14fc4272008-05-17 18:39:55 +000054 except tkinter.TclError:
Guido van Rossumb5a755e2007-07-18 18:15:48 +000055 # Some versions of the Tk framework don't have a console object
56 pass
Thomas Wouters0e3f5912006-08-11 14:57:12 +000057
58def overrideRootMenu(root, flist):
59 """
60 Replace the Tk root menu by something that's more appropriate for
61 IDLE.
62 """
63 # The menu that is attached to the Tk root (".") is also used by AquaTk for
64 # all windows that don't specify a menu of their own. The default menubar
65 # contains a number of menus, none of which are appropriate for IDLE. The
66 # Most annoying of those is an 'About Tck/Tk...' menu in the application
67 # menu.
68 #
69 # This function replaces the default menubar by a mostly empty one, it
70 # should only contain the correct application menu and the window menu.
71 #
72 # Due to a (mis-)feature of TkAqua the user will also see an empty Help
73 # menu.
Georg Brandl14fc4272008-05-17 18:39:55 +000074 from tkinter import Menu, Text, Text
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000075 from idlelib.EditorWindow import prepstr, get_accelerator
76 from idlelib import Bindings
77 from idlelib import WindowList
78 from idlelib.MultiCall import MultiCallCreator
Thomas Wouters0e3f5912006-08-11 14:57:12 +000079
80 menubar = Menu(root)
81 root.configure(menu=menubar)
82 menudict = {}
83
84 menudict['windows'] = menu = Menu(menubar, name='windows')
85 menubar.add_cascade(label='Window', menu=menu, underline=0)
86
87 def postwindowsmenu(menu=menu):
88 end = menu.index('end')
89 if end is None:
90 end = -1
91
92 if end > 0:
93 menu.delete(0, end)
94 WindowList.add_windows_to_menu(menu)
95 WindowList.register_callback(postwindowsmenu)
96
Thomas Wouters0e3f5912006-08-11 14:57:12 +000097 def about_dialog(event=None):
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000098 from idlelib import aboutDialog
Thomas Wouters0e3f5912006-08-11 14:57:12 +000099 aboutDialog.AboutDialog(root, 'About IDLE')
100
101 def config_dialog(event=None):
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000102 from idlelib import configDialog
Ronald Oussoren220a9fb2009-05-26 18:41:00 +0000103
104 # Ensure that the root object has an instance_dict attribute,
105 # mirrors code in EditorWindow (although that sets the attribute
106 # on an EditorWindow instance that is then passed as the first
107 # argument to ConfigDialog)
108 root.instance_dict = flist.inversedict
Benjamin Petersonfa0d7032009-06-01 22:42:33 +0000109 root.instance_dict = flist.inversedict
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000110 configDialog.ConfigDialog(root, 'Settings')
111
Georg Brandlaedd2892010-12-19 10:10:32 +0000112 def help_dialog(event=None):
113 from idlelib import textView
114 fn = path.join(path.abspath(path.dirname(__file__)), 'help.txt')
115 textView.view_file(root, 'Help', fn)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000116
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000117 root.bind('<<about-idle>>', about_dialog)
118 root.bind('<<open-config-dialog>>', config_dialog)
Georg Brandlaedd2892010-12-19 10:10:32 +0000119 root.createcommand('::tk::mac::ShowPreferences', config_dialog)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000120 if flist:
121 root.bind('<<close-all-windows>>', flist.close_all_callback)
122
Ronald Oussoren10e05e12010-12-07 15:28:10 +0000123 # The binding above doesn't reliably work on all versions of Tk
124 # on MacOSX. Adding command definition below does seem to do the
125 # right thing for now.
126 root.createcommand('exit', flist.close_all_callback)
127
Georg Brandlaedd2892010-12-19 10:10:32 +0000128 if isCarbonAquaTk(root):
129 # for Carbon AquaTk, replace the default Tk apple menu
130 menudict['application'] = menu = Menu(menubar, name='apple')
131 menubar.add_cascade(label='IDLE', menu=menu)
132 Bindings.menudefs.insert(0,
133 ('application', [
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000134 ('About IDLE', '<<about-idle>>'),
Georg Brandlaedd2892010-12-19 10:10:32 +0000135 None,
136 ]))
137 tkversion = root.tk.eval('info patchlevel')
138 if tuple(map(int, tkversion.split('.'))) < (8, 4, 14):
139 # for earlier AquaTk versions, supply a Preferences menu item
140 Bindings.menudefs[0][1].append(
141 ('_Preferences....', '<<open-config-dialog>>'),
142 )
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000143 else:
Georg Brandlaedd2892010-12-19 10:10:32 +0000144 # assume Cocoa AquaTk
145 # replace default About dialog with About IDLE one
146 root.createcommand('tkAboutDialog', about_dialog)
147 # replace default "Help" item in Help menu
148 root.createcommand('::tk::mac::ShowHelp', help_dialog)
149 # remove redundant "IDLE Help" from menu
150 del Bindings.menudefs[-1][1][0]
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000151
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000152def setupApp(root, flist):
153 """
154 Perform setup for the OSX application bundle.
155 """
156 if not runningAsOSXApp(): return
157
158 hideTkConsole(root)
159 overrideRootMenu(root, flist)
160 addOpenEventSupport(root, flist)