#
#   Python GUI - Windows - Gtk version
#

import sys
import gtk
from gtk import gdk
from GGeometry import sub_pt
from Components import _gtk_find_component
from Containers import Container
import Applications
from Applications import application
#from GtkInput import GtkInput
from GWindows import Window as GWindow

_default_width = 200
_default_height = 200

_modal_styles = ('modal_dialog', 'alert')
_dialog_styles = ('nonmodal_dialog', 'modal_dialog', 'alert')
    
class Window(GWindow):

    _size = (_default_width, _default_height)
    _gtk_menubar = None
    _need_menubar_update = 0
    _target = None
    
    def __init__(self, style = 'standard', title = "New Window",
            movable = 1, closable = 1, hidable = None, resizable = 1,
            zoomable = 1, **kwds):
        self._all_menus = []
        modal = style in _modal_styles
        if hidable is None:
            hidable = not modal
        self._resizable = resizable
        gtk_win = gtk.Window(gtk.WINDOW_TOPLEVEL)
        gtk_win.set_gravity(gdk.GRAVITY_STATIC)
        gtk_win.set_decorated(movable or closable or hidable or zoomable)
        gtk_win.set_resizable(resizable)
        gtk_win.set_modal(style in _modal_styles)
        gtk_content = gtk.Layout()
        gtk_content.show()
        if style in _dialog_styles:
            gtk_win.set_type_hint(gdk.WINDOW_TYPE_HINT_DIALOG)
            gtk_win.add(gtk_content)
        else:
            self._gtk_create_menubar()
            gtk_box = gtk.VBox()
            gtk_box.show()
            gtk_box.pack_start(self._gtk_menubar, expand = 0, fill = 0)
            gtk_box.pack_end(gtk_content, expand = 1, fill = 1)
            gtk_win.add(gtk_box)
        self._need_menubar_update = 1
        self._gtk_connect(gtk_win, 'configure-event', self._gtk_configure_event)
        self._gtk_connect(gtk_win, 'key-press-event', self._gtk_key_press_event)
        self._gtk_connect(gtk_win, 'delete-event', self._gtk_delete_event)
        #GtkInput.__init__(self, gtk_content)
        GWindow.__init__(self, _gtk_outer = gtk_win, _gtk_inner = gtk_content, 
            _gtk_focus = gtk_content, _gtk_input = gtk_content,
            title = title, closable = closable)
        self.set_size((_default_width, _default_height))
        self.set(**kwds)
        self.become_target()
    
    def _gtk_create_menubar(self):
        gtk_menubar = gtk.MenuBar()
        gtk_dummy_item = gtk.MenuItem("")
        gtk_menubar.append(gtk_dummy_item)
        gtk_menubar.show_all()
        h = gtk_menubar.size_request()[1]
        gtk_menubar.set_size_request(-1, h)
        gtk_dummy_item.remove_submenu()
        self._gtk_menubar = gtk_menubar
        self._gtk_connect(gtk_menubar, 'button-press-event',
            self._gtk_menubar_button_press_event)
    
    def destroy(self):
        self.hide()
        GWindow.destroy(self)
    
    def set_menus(self, x):
        GWindow.set_menus(self, x)
        self._need_menubar_update = 1
        if self.visible:
            self._gtk_update_menubar()
    
    def get_title(self):
        return self._gtk_outer_widget.get_title()
    
    def set_title(self, new_title):
        self._gtk_outer_widget.set_title(new_title)
    
    def set_position(self, v):
        self._position = v
        self._gtk_outer_widget.move(*v)
    
    def set_size(self, new_size):
        w, h = new_size
        if self._resizable:
            h += self._gtk_menubar_height()
            gtk_resize = self._gtk_outer_widget.resize
        else:
            gtk_resize = self._gtk_inner_widget.set_size_request
        gtk_resize(max(w, 1), max(h, 1))
        self._size = new_size
    
    def _gtk_configure_event(self, gtk_event):
        gtk_win = self._gtk_outer_widget
        self._position = gtk_win.get_position()
        #self._update_size(gtk_win.get_size())
        w, h = gtk_win.get_size()
        #w, h = self._gtk_inner_widget.get_size()
        #w, h = self._gtk_inner_widget.size_request()
        old_size = self._size
        new_size = (w, h - self._gtk_menubar_height())
        #new_size = (w, h)
        #print "Window._gtk_configure_event:", old_size, "->", new_size ###
        self._size = new_size
        if old_size <> new_size:
            self.resized(sub_pt(new_size, old_size))		
    
    def set_visible(self, new_v):
        old_v = self.visible
        GWindow.set_visible(self, new_v)
        if new_v and not old_v and self._need_menubar_update:
            self._gtk_update_menubar()
    
    def show(self):
        self.set_visible(1)
        self._gtk_outer_widget.present()
    
    def key_down(self, event):
        if event.char == '\t':
            if event.shift:
                self._tab_to_prev()
            else:
                self._tab_to_next()
        else:
            self.pass_to_next_handler('key_down', event)
    
    def get_target(self):
        target = _gtk_find_component(self._gtk_outer_widget.get_focus())
        return target or self

    def _screen_rect(self):
        w = gdk.screen_width()
        h = gdk.screen_height()
        return (0, 0, w, h)
    
    def _gtk_menubar_height(self):
        mb = self._gtk_menubar
        if mb:
            h = mb.size_request()[1]
        else:
            h = 0
        #print "Window._gtk_menubar_height -->", h ###
        return h
    
    def _gtk_delete_event(self, event):
        try:
            self.close_cmd()
        except:
            sys.excepthook(*sys.exc_info())
        return 1
    
    def _gtk_update_menubar(self):
        #
        #  Update the contents of the menubar after either the application
        #  menu list or this window's menu list has changed. We only add
        #  the menu titles at this stage; the menus themselves are attached
        #  during menu setup. We also attach the accel groups associated
        #  with the new menus.
        #
        #  Things would be simpler if we could attach the menus here,
        #  but attempting to share menus between menubar items provokes
        #  a warning from Gtk, even though it otherwise appears to work.
        #
        gtk_menubar = self._gtk_menubar
        gtk_window = self._gtk_outer_widget
        #  Remove old accel groups
        for menu in self._all_menus:
            gtk_window.remove_accel_group(menu._gtk_accel_group)
        #  Detach any existing menus and remove old menu titles
        if gtk_menubar:
            for gtk_menubar_item in gtk_menubar.get_children():
                gtk_menubar_item.remove_submenu()
                gtk_menubar_item.destroy()
        #  Install new menu list
        all_menus = application().menus + self.menus
        self._all_menus = all_menus
        #  Create new menu titles and attach accel groups
        for menu in all_menus:
            if gtk_menubar:
                gtk_menubar_item = gtk.MenuItem(menu._title)
                gtk_menubar_item.show()
                gtk_menubar.append(gtk_menubar_item)
            gtk_window.add_accel_group(menu._gtk_accel_group)
        self._need_menubar_update = 0
    
    def _gtk_menubar_button_press_event(self, event):
        #  A button press has occurred in the menu bar. Before pulling
        #  down the menu, perform menu setup and attach the menus to
        #  the menubar items.
        self._gtk_menu_setup()
        for (gtk_menubar_item, menu) in \
            zip(self._gtk_menubar.get_children(), self._all_menus):
                gtk_menu = menu._gtk_menu
                attached_widget = gtk_menu.get_attach_widget()
                if attached_widget and attached_widget is not gtk_menubar_item:
                    attached_widget.remove_submenu()
                gtk_menubar_item.set_submenu(gtk_menu)
    
    def _gtk_key_press_event(self, gtk_event):
        #  Intercept key presses with the Control key down and update
        #  menus, in case this is a keyboard equivalent for a menu command.
        if gtk_event.state & gdk.CONTROL_MASK:
            #print "Window._gtk_key_press_event: doing menu setup"
            self._gtk_menu_setup()
            #  It appears that GtkWindow caches accelerators, and updates
            #  the cache in an idle task after accelerators change. This
            #  would be too late for us, so we force it to be done now.
            self._gtk_outer_widget.emit("keys-changed")
            #print "Window._gtk_key_press_event: done menu setup"
    
    def _gtk_menu_setup(self):
        application()._perform_menu_setup(self._all_menus)

    def dispatch(self, message, *args):
        self.target.handle(message, *args)


_gtk_menubar_height = None

def _gtk_find_menubar_height():
    global _gtk_menubar_height
    if _gtk_menubar_height is None:
        print "Windows: Finding menubar height"
        item = gtk.MenuItem("X")
        bar = gtk.MenuBar()
        bar.append(item)
        bar.show_all()
        w, h = bar.size_request()
        _gtk_menubar_height = h
        print "...done"
    return _gtk_menubar_height

#_gtk_menubar_height = _gtk_find_menubar_height()
