Index: CallTips.py
===================================================================
--- CallTips.py	(revision 58672)
+++ CallTips.py	(working copy)
@@ -8,6 +8,7 @@
 import re
 import sys
 import types
+import textwrap
 
 import CallTipWindow
 from HyperParser import HyperParser
@@ -74,11 +75,12 @@
         name = hp.get_expression()
         if not name or (not evalfuncs and name.find('(') != -1):
             return
-        arg_text = self.fetch_tip(name)
-        if not arg_text:
+        arg_text, doc = self.fetch_tip(name)
+        if not (arg_text or doc):
             return
         self.calltip = self._make_calltip_window()
-        self.calltip.showtip(arg_text, sur_paren[0], sur_paren[1])
+        self.calltip.showtip(name, arg_text, doc,
+                             sur_paren[0], sur_paren[1])
 
     def fetch_tip(self, name):
         """Return the argument list and docstring of a function or class
@@ -129,6 +131,7 @@
 def get_arg_text(ob):
     """Get a string describing the arguments for the given object"""
     arg_text = ""
+    doc = ""
     if ob is not None:
         arg_offset = 0
         if type(ob) in (types.ClassType, types.TypeType):
@@ -162,14 +165,8 @@
         # See if we can use the docstring
         doc = getattr(ob, "__doc__", "")
         if doc:
-            doc = doc.lstrip()
-            pos = doc.find("\n")
-            if pos < 0 or pos > 70:
-                pos = 70
-            if arg_text:
-                arg_text += "\n"
-            arg_text += doc[:pos]
-    return arg_text
+            doc = textwrap.dedent(doc).strip()
+    return arg_text, doc
 
 #################################################
 #
@@ -207,7 +204,7 @@
                 qualified_name = "%s.%s" % (t.im_class.__name__, name)
             except AttributeError:
                 qualified_name = name
-            arg_text = ct.fetch_tip(qualified_name)
+            arg_text = ct.fetch_tip(qualified_name)[0]
             if arg_text != expected:
                 failed.append(t)
                 fmt = "%s - expected %s, but got %s"
Index: CallTipWindow.py
===================================================================
--- CallTipWindow.py	(revision 58672)
+++ CallTipWindow.py	(working copy)
@@ -6,11 +6,15 @@
 """
 from Tkinter import *
 
+from configHandler import idleConf
+import textView
+
 HIDE_VIRTUAL_EVENT_NAME = "<<calltipwindow-hide>>"
 HIDE_SEQUENCES = ("<Key-Escape>", "<FocusOut>")
 CHECKHIDE_VIRTUAL_EVENT_NAME = "<<calltipwindow-checkhide>>"
 CHECKHIDE_SEQUENCES = ("<KeyRelease>", "<ButtonRelease>")
 CHECKHIDE_TIME = 100 # miliseconds
+SHOW_FULL_DOC_EVENT_NAME = "<<calltipwindow-showfulldoc>>"
 
 MARK_RIGHT = "calltipwindowregion_right"
 
@@ -22,6 +26,7 @@
         self.parenline = self.parencol = None
         self.lastline = None
         self.hideid = self.checkhideid = None
+        self.showfulldoc_seqs_and_id = None
 
     def position_window(self):
         """Check if needs to reposition the window, and if so - do it."""
@@ -44,10 +49,12 @@
         y = box[1] + box[3] + self.widget.winfo_rooty()
         self.tipwindow.wm_geometry("+%d+%d" % (x, y))
 
-    def showtip(self, text, parenleft, parenright):
+    def showtip(self, name, arg_text, doc,
+                parenleft, parenright):
         """Show the calltip, bind events which will close it and reposition it.
         """
         # truncate overly long calltip
+        text = '\n'.join([x for x in [arg_text] + doc.splitlines()[:1] if x])
         if len(text) >= 79:
             textlines = text.splitlines()
             for i, line in enumerate(textlines):
@@ -89,6 +96,26 @@
         for seq in HIDE_SEQUENCES:
             self.widget.event_add(HIDE_VIRTUAL_EVENT_NAME, seq)
 
+        if doc and (len(doc) >= 79 or '\n' in doc):
+            # bind the force-open-calltip sequence(s) to open the full
+            # doc-string in a new window
+            text = ''
+            if arg_text: text += name + arg_text
+            if text and doc: text += '\n\n'
+            text += doc
+            title = "In-code documentation for %s" % name
+            def show_full_doc_event(event):
+                textView.view_text(self.widget, title, text)
+                return "break"
+            seqs = idleConf.GetOption(
+                'extensions', 'CallTips_cfgBindings', 'force-open-calltip',
+                type='str', default='<Control-Key-backslash>')
+            seqs = seqs.split(' ')
+            for seq in seqs:
+                self.widget.event_add(SHOW_FULL_DOC_EVENT_NAME, seq)
+            id = self.widget.bind(SHOW_FULL_DOC_EVENT_NAME, show_full_doc_event)
+            self.showfulldoc_seqs_and_id = (seqs, id)
+
     def checkhide_event(self, event=None):
         if not self.tipwindow:
             # If the event was triggered by the same event that unbinded
@@ -122,6 +149,12 @@
             self.widget.event_delete(HIDE_VIRTUAL_EVENT_NAME, seq)
         self.widget.unbind(HIDE_VIRTUAL_EVENT_NAME, self.hideid)
         self.hideid = None
+        if self.showfulldoc_seqs_and_id is not None:
+            seqs, id = self.showfulldoc_seqs_and_id
+            for seq in seqs:
+                self.widget.event_delete(SHOW_FULL_DOC_EVENT_NAME, seq)
+            self.widget.unbind(SHOW_FULL_DOC_EVENT_NAME, id)
+            self.showfulldoc_seqs_and_id = None
 
         self.label.destroy()
         self.label = None
@@ -158,7 +191,13 @@
         root.mainloop()
 
     def calltip_show(self, event):
-        self.calltip.showtip("Hello world")
+        paren_left = self.text.index("insert")
+        paren_right = self.text.search(")", paren_left)
+        if not paren_right:
+            paren_right = "end"
+        self.calltip.showtip("God", "Hello world",
+                             "Oh\nMy\nIt\nWorks!",
+                             paren_left, paren_right)
 
     def calltip_hide(self, event):
         self.calltip.hidetip()
