// -*- c++ -*-
/* $Id: window.ccg,v 1.5 2006/05/10 20:59:28 murrayc Exp $ */

/* 
 *
 * Copyright 1998-2002 The gtkmm Development Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <gtkmm/accelgroup.h>
#include <gdkmm/cursor.h>
#include <gtk/gtkwindow.h>


namespace Gtk
{

Glib::RefPtr<AccelGroup> Window::get_accel_group()
{
  //There doesn't seem to be any gtk_window_get_accel_group().
  //I think that you're supposed to remember what you added yourself.
  //And that's what we do here.

  if(!accel_group_)
  {
    accel_group_ = AccelGroup::create();
    add_accel_group(accel_group_);
  }

  return accel_group_;
}

bool Window::is_toplevel() const
{
  return gobj()->type == GTK_WINDOW_TOPLEVEL;
}

bool Window::is_popup() const
{
  return gobj()->type == GTK_WINDOW_POPUP;
}

void Window::raise()
{
  get_window()->raise();
}

void Window::set_manage()
{
  g_warning("gtkmm: Attempt to call Gtk::manage() on a Gtk::Window, but a Gtk::Window has no parent container to manage its lifetime.\n");
}

void Window::destroy_()
{
  //Called from destructors.
  //overridden so that the correct _destroy_c_instance() ends up being called by the destructor.

  //GTKMM_LIFECYCLE

  #ifdef GLIBMM_DEBUG_REFCOUNTING
  g_warning("Gtk::Window::destroy_(): gobject_: %10X\n", gobject_);
  if(gobject_)
   g_warning("  gtypename: %s\n", G_OBJECT_TYPE_NAME(gobject_));
  #endif

  if ( !cpp_destruction_in_progress_ ) //see comment below.
  {
    //Prevent destroy_notify_() from running as a possible side-effect of gtk_object_destroy.
    //We can't predict whether destroy_notify_() will really be run, so we'll disconnect the C++ instance here.
    cpp_destruction_in_progress_ = true;

    //destroy the C instance:
    _destroy_c_instance();
  }

  //The C++ destructor will be reached later. This function was called by a destructor.
}

void Window::_destroy_c_instance()
{
  //We override this,
  //because though top-level windows can only be destroyed with gtk_widget_destroy, according to Owen Taylor. murrayc.
  #ifdef GLIBMM_DEBUG_REFCOUNTING
  g_warning("Gtk::Window::_destroy_c_instance() gobject_=%10X\n", gobject_);
  #endif

  cpp_destruction_in_progress_ = true;

  // remove our hook.
  GtkObject* object = (GtkObject*)gobj();
  if (object)
  {
    disconnect_cpp_wrapper();
    //If we are killing the C++ instance before the C instance, then this might lead to strange behaviour.
    //If this is a problem, then you'll have to use a managed() object, which will die only upon GTK+'s request.

    //We can't do anything with the gobject_ if it's already been disposed.
    //This prevents us from unref-ing it again, or destroying it again after GTK+ has told us that it has been disposed.
    if (!gobject_disposed_)
    {
      //Windows can not be unrefed. They are "self-owning".
      gtk_object_destroy(object);
    }

    //Glib::Object::~Object() will not g_object_unref() it too. because gobject_ is now 0.
  }
}

void Window_Class::dispose_vfunc_callback(GObject* self)
{
  //Avoid disposal of Windows on delete_event (window close) signal.
  
  #ifdef GLIBMM_DEBUG_REFCOUNTING
  g_warning("Window_Class::dispose_vfunc_callback(): gobject_: %p\n", (void*)self);
  #endif

  Widget *const obj = dynamic_cast<Widget*>(
      Glib::ObjectBase::_get_current_wrapper(self));

  // This function might be invoked recursively because we're triggering
  // several signal emissions, particularly signal_hide().  Therefore we
  // have to test for cpp_destruction_in_progress_ at this point.

  if(obj && !obj->_cpp_destruction_is_in_progress()) //When it should really be destroyed, we zero gobj_.
  {
    GtkWidget* const pWidget = obj->gobj();
    g_return_if_fail(pWidget == GTK_WIDGET(self));

    // Abort dispose if the widget isn't managed, in order to prevent
    // the nasty self-destroying behaviour of GTK+.  This applies to:
    //
    // - GtkWindow, if it received "delete_event"
    // - GtkDialog, which destroys on "response" by default

    #ifdef GLIBMM_DEBUG_REFCOUNTING
    g_warning("Window_Class::dispose_vfunc_callback(): before gtk_widget_hide().");
    #endif

    // Now hide the widget.  The C++ object must _not_ be accessed anymore
    // after this call, because a signal_hide() handler might delete it.
    gtk_widget_hide(pWidget);

    #ifdef GLIBMM_DEBUG_REFCOUNTING
    g_warning("Window_Class::dispose_vfunc_callback(): after gtk_widget_hide().");
    #endif

    // GTKMM_LIFECYCLE
    return; // Prevent calling of normal C dispose vfunc (see below)
  }
  else
  {
    #ifdef GLIBMM_DEBUG_REFCOUNTING
    //g_warning("Window_Class::dispose_vfunc_callback(): unreferenced: before gtk_widget_hide().");
    #endif

    // Always hide widgets on gtk_object_destroy(), regardless of whether
    // the widget is managed or not.  This is done for consistency so that
    // connecting to signal_hide() is guaranteed to work.
    //gtk_widget_hide(pWidget);

    #ifdef GLIBMM_DEBUG_REFCOUNTING
    //g_warning("Window_Class::dispose_vfunc_callback(): unreferenced:  after gtk_widget_hide().");
    #endif
  
    GObjectClass *const base = static_cast<GObjectClass*>(
        g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)));

    #ifdef GLIBMM_DEBUG_REFCOUNTING
    g_warning("Window_Class::dispose_vfunc_callback(): before calling base->dispose.");
    #endif

    if(base->dispose)
      (*base->dispose)(self);

    #ifdef GLIBMM_DEBUG_REFCOUNTING
    g_warning("Window_Class::dispose_vfunc_callback(): after calling base->dispose.");
    #endif
  }
}

void Window::unset_focus()
{
  gtk_window_set_focus(gobj(), 0 /* See GTK+ docs */);
}

void Window::unset_default()
{
  gtk_window_set_default(gobj(), 0 /* See GTK+ docs */);
}
   
} // namespace Gtk


