/*
 * Copyright (C) 1998-2013 The gtkmm Development Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <vector>

#include <glibmm/object.h>
#include <gtkmm/bin.h>
#include <gtkmm/application.h>
#include <gtkmm/windowgroup.h>

_DEFS(gtkmm,gtk)
_PINCLUDE(gtkmm/private/bin_p.h)

namespace Gtk
{

class AccelGroup;
class WindowGroup;

/** Toplevel Window
 * This represents all widgets which are physical windows controlled
 * by the window manager.
 *
 * The window will be hidden when the window manager's close button is clicked. Override on_delete_event() to stop this.
 *
 * Gtk::manage() has no effect on Windows because they have no parent Containers.
 * @ingroup Widgets
 */
class Window : public Bin
{
  _CLASS_GTKOBJECT(Window,GtkWindow,GTK_WINDOW,Gtk::Bin,GtkBin)
  _UNMANAGEABLE
  _IGNORE(gtk_window_set_has_user_ref_count, gtk_window_set_destroy_with_parent)

  //TODO: Use gtk_window_set_destroy_with_parent() to allow use of Gtk::manage() with top-level windows, using the transient-parent?

public:
  _WRAP_CTOR(Window(WindowType type = WINDOW_TOPLEVEL), gtk_window_new)

  _WRAP_PROPERTY("type", WindowType)
  _WRAP_PROPERTY("title", Glib::ustring)
  _WRAP_PROPERTY("startup-id", Glib::ustring)
  _WRAP_PROPERTY("resizable", bool)
  _WRAP_PROPERTY("modal", bool)
  _WRAP_PROPERTY("window_position", WindowPosition)
  _WRAP_PROPERTY("default_width", int)
  _WRAP_PROPERTY("default_height", int)
  _WRAP_PROPERTY("destroy_with_parent", bool)
  _WRAP_PROPERTY("hide-titlebar-when-maximized", bool)
  _WRAP_PROPERTY("icon", Glib::RefPtr<Gdk::Pixbuf>)
  _WRAP_PROPERTY("mnemonics-visible", bool)
  _WRAP_PROPERTY("icon-name", Glib::ustring)
  _WRAP_PROPERTY("screen", Glib::RefPtr<Gdk::Screen>)
  _WRAP_PROPERTY("is_active", bool)
  _WRAP_PROPERTY("has_toplevel_focus", bool)
  _WRAP_PROPERTY("type_hint", GdkWindowTypeHint)
  _WRAP_PROPERTY("skip_taskbar_hint", bool)
  _WRAP_PROPERTY("skip_pager_hint", bool)
  _WRAP_PROPERTY("role", Glib::ustring)
  _WRAP_PROPERTY("decorated", bool)
  _WRAP_PROPERTY("gravity", Gdk::Gravity)
  _WRAP_PROPERTY("transient_for", Window*)

#ifndef GTKMM_DISABLE_DEPRECATED
// _WRAP_PROPERTY("opacity", double, deprecated "Use the opacity property in the Widget base class instead.")
// The GtkWindow::opacity property does not exist in gtk+ 3.7.10 and later. Must hand-code to avoid an ABI break.
/** The opacity of the window, from 0 to 1.
   * @deprecated Use the opacity property in the Widget base class instead.
   *
   * You rarely need to use properties because there are get_ and set_ methods for almost all of them.
   * @return A PropertyProxy that allows you to get or set the value of the property,
   * or receive notification when the value of the property changes.
   */
  Glib::PropertyProxy< double > property_opacity() ;

/** The opacity of the window, from 0 to 1.
   * @deprecated Use the opacity property in the Widget base class instead.
   *
   * You rarely need to use properties because there are get_ and set_ methods for almost all of them.
   * @return A PropertyProxy_ReadOnly that allows you to get the value of the property,
   * or receive notification when the value of the property changes.
   */
  Glib::PropertyProxy_ReadOnly< double > property_opacity() const;
#endif // GTKMM_DISABLE_DEPRECATED

  _WRAP_PROPERTY("has-resize-grip", bool, deprecated "Resize grips have been removed.")
  _WRAP_PROPERTY("resize-grip-visible", bool, deprecated "Resize grips have been removed.")
  _WRAP_PROPERTY("urgency_hint", bool)
  _WRAP_PROPERTY("accept-focus", bool)
  _WRAP_PROPERTY("focus-on-map", bool)
  _WRAP_PROPERTY("deletable", bool)
  _WRAP_PROPERTY("application", Glib::RefPtr<Application>)
  _WRAP_PROPERTY("focus-visible", bool)
  _WRAP_PROPERTY("attached-to", Widget*)
  _WRAP_PROPERTY("is-maximized", bool)

  _WRAP_SIGNAL(void set_focus(Widget* focus), "set_focus")

  //TODO: Remove no_default_handler when we can break ABI:
  _WRAP_SIGNAL(void keys_changed(), "keys_changed", no_default_handler)

  //Keybinding signals:
  _IGNORE_SIGNAL("activate_focus")
  _IGNORE_SIGNAL("activate_default")
  _IGNORE_SIGNAL("enable-debugging")

#m4begin
dnl// Hook in special code to catch explicit uses of gtk_object_destroy() by
dnl// GTK+ code, e.g. when receiving the GDK_DELETE event.  For details, look
dnl// at Gtk::Window_Class::dispose_vfunc_callback() in window.ccg.
dnl
  _PUSH(SECTION_PCC_CLASS_INIT_VFUNCS)
    reinterpret_cast<GObjectClass*>(klass)->dispose = &dispose_vfunc_callback;
  _SECTION(SECTION_PH_VFUNCS)
    static void dispose_vfunc_callback(GObject* self);
  _POP()
#m4end


  _WRAP_METHOD(void set_title(const Glib::ustring& title),
               gtk_window_set_title)

  _WRAP_METHOD(Glib::ustring get_title() const, gtk_window_get_title)

  _WRAP_METHOD(void set_wmclass(const Glib::ustring& wmclass_name,
                                const Glib::ustring& wmclass_class),
               gtk_window_set_wmclass)

  _WRAP_METHOD(void set_role(const Glib::ustring& role), gtk_window_set_role)

  _WRAP_METHOD(void set_startup_id(const Glib::ustring& startup_id), gtk_window_set_startup_id)

  _WRAP_METHOD(Glib::ustring get_role() const, gtk_window_get_role)


  _WRAP_METHOD(void add_accel_group(const Glib::RefPtr<AccelGroup>& accel_group),
               gtk_window_add_accel_group)

  _WRAP_METHOD(void remove_accel_group(const Glib::RefPtr<AccelGroup>& accel_group),
               gtk_window_remove_accel_group)

  _WRAP_METHOD(void set_position(WindowPosition position),
               gtk_window_set_position)

  _WRAP_METHOD(bool activate_focus(), gtk_window_activate_focus)

  _WRAP_METHOD(void set_focus(Gtk::Widget& focus), gtk_window_set_focus)
  void unset_focus();

  _WRAP_METHOD(Widget* get_focus(), gtk_window_get_focus)
  _WRAP_METHOD(const Widget* get_focus() const, gtk_window_get_focus, constversion)
  _WRAP_METHOD(void set_default(Gtk::Widget& default_widget), gtk_window_set_default)
  void unset_default();

  _WRAP_METHOD(Widget* get_default_widget(), gtk_window_get_default_widget)
  _WRAP_METHOD(const Widget* get_default_widget() const, gtk_window_get_default_widget, constversion)

  _WRAP_METHOD(bool activate_default(), gtk_window_activate_default)

  _WRAP_METHOD(void set_transient_for(Window& parent), gtk_window_set_transient_for)

  /** Unsets the current transient window.
   * @see set_transient_for().
   * @newin{2,20}
   */
  void unset_transient_for();

  _WRAP_METHOD(Window* get_transient_for(), gtk_window_get_transient_for)
  _WRAP_METHOD(const Window* get_transient_for() const, gtk_window_get_transient_for, constversion)

  /** Unsets the attached-to widget.
   * @see set_attached_to().
   * @newin{3,4}
   */
  void unset_attached_to();

  _WRAP_METHOD(void set_attached_to(Widget& attach_widget), gtk_window_set_attached_to)

  _WRAP_METHOD(Widget* get_attached_to(), gtk_window_get_attached_to)
  _WRAP_METHOD(const Widget* get_attached_to() const, gtk_window_get_attached_to, constversion)

  _WRAP_METHOD(void set_opacity(double opacity), gtk_window_set_opacity, deprecated "Use Widget::set_opacity() instead.")
  _WRAP_METHOD(double get_opacity() const, gtk_window_get_opacity, deprecated "Use Widget::get_opacity() instead.")

  _WRAP_METHOD(void set_type_hint(Gdk::WindowTypeHint hint), gtk_window_set_type_hint)
  _WRAP_METHOD(Gdk::WindowTypeHint get_type_hint() const, gtk_window_get_type_hint)

  _WRAP_METHOD(void set_skip_taskbar_hint(bool setting = true), gtk_window_set_skip_taskbar_hint)
  _WRAP_METHOD(bool get_skip_taskbar_hint() const, gtk_window_get_skip_taskbar_hint)

  _WRAP_METHOD(void set_skip_pager_hint(bool setting = true), gtk_window_set_skip_pager_hint)
  _WRAP_METHOD(bool get_skip_pager_hint() const, gtk_window_get_skip_pager_hint)

  _WRAP_METHOD(void set_urgency_hint(bool setting = true), gtk_window_set_urgency_hint)
  _WRAP_METHOD(bool get_urgency_hint() const, gtk_window_get_urgency_hint)

  _WRAP_METHOD(void set_accept_focus(bool setting = true), gtk_window_set_accept_focus)
  _WRAP_METHOD(bool get_accept_focus() const, gtk_window_get_accept_focus)
  _WRAP_METHOD(void set_focus_on_map(bool setting = true), gtk_window_set_focus_on_map)
  _WRAP_METHOD(bool get_focus_on_map() const, gtk_window_get_focus_on_map)

  //_WRAP_METHOD(void set_destroy_with_parent(bool setting = true), gtk_window_set_destroy_with_parent)
  // I don't that that this is ever a good thing for C++.murrayc.

  //TODO: Remove?
  _WRAP_METHOD(bool get_destroy_with_parent() const, gtk_window_get_destroy_with_parent)
  // I don't that that this is ever a good thing for C++.murrayc.

  _WRAP_METHOD(void set_hide_titlebar_when_maximized(bool setting = true), gtk_window_set_hide_titlebar_when_maximized)
  _WRAP_METHOD(bool get_hide_titlebar_when_maximized() const, gtk_window_get_hide_titlebar_when_maximized)

  _WRAP_METHOD(void set_mnemonics_visible(bool setting = true), gtk_window_set_mnemonics_visible)
  _WRAP_METHOD(bool get_mnemonics_visible() const, gtk_window_get_mnemonics_visible)

  _WRAP_METHOD(void set_focus_visible(bool setting = true), gtk_window_set_focus_visible)
  _WRAP_METHOD(bool get_focus_visible() const, gtk_window_get_focus_visible)

  _WRAP_METHOD(void set_resizable(bool resizable = true), gtk_window_set_resizable)

  _WRAP_METHOD(bool get_resizable() const, gtk_window_get_resizable)

  _WRAP_METHOD(void set_gravity(Gdk::Gravity gravity), gtk_window_set_gravity)

  _WRAP_METHOD(Gdk::Gravity get_gravity() const, gtk_window_get_gravity)

  _WRAP_METHOD(void set_geometry_hints(Widget& geometry_widget,
                                       const Gdk::Geometry& geometry,
                                       Gdk::WindowHints geom_mask),
               gtk_window_set_geometry_hints)

  _WRAP_METHOD(void set_screen(const Glib::RefPtr<Gdk::Screen>& screen), gtk_window_set_screen)

  _WRAP_METHOD(Glib::RefPtr<Gdk::Screen> get_screen(), gtk_window_get_screen, refreturn)
  _WRAP_METHOD(Glib::RefPtr<const Gdk::Screen> get_screen() const, gtk_window_get_screen, refreturn, constversion)

  _WRAP_METHOD(bool is_active() const, gtk_window_is_active)
  _WRAP_METHOD(bool has_toplevel_focus() const, gtk_window_has_toplevel_focus)

  _WRAP_METHOD(void set_decorated(bool setting = true), gtk_window_set_decorated)
  _WRAP_METHOD(bool get_decorated() const, gtk_window_get_decorated)

  _WRAP_METHOD(void set_deletable(bool setting = true), gtk_window_set_deletable)
  _WRAP_METHOD(bool get_deletable() const, gtk_window_get_deletable)

#m4 _CONVERSION(`GList*',`std::vector< Glib::RefPtr<Gdk::Pixbuf> >',`Glib::ListHandler< Glib::RefPtr<Gdk::Pixbuf> >::list_to_vector($3, Glib::OWNERSHIP_SHALLOW)')
  _WRAP_METHOD(std::vector< Glib::RefPtr<Gdk::Pixbuf> > get_icon_list(), gtk_window_get_icon_list)
#m4 _CONVERSION(`GList*',`std::vector< Glib::RefPtr<const Gdk::Pixbuf> >',`Glib::ListHandler< Glib::RefPtr<const Gdk::Pixbuf> >::list_to_vector($3, Glib::OWNERSHIP_SHALLOW)')
  _WRAP_METHOD(std::vector< Glib::RefPtr<const Gdk::Pixbuf> > get_icon_list() const, gtk_window_get_icon_list)

#m4 _CONVERSION(`const std::vector< Glib::RefPtr<Gdk::Pixbuf> >&',`GList*',`Glib::ListHandler< Glib::RefPtr<Gdk::Pixbuf> >::vector_to_list($3).data ()')
  _WRAP_METHOD(void set_icon_list(const std::vector< Glib::RefPtr<Gdk::Pixbuf> >& list),
               gtk_window_set_icon_list)

  _WRAP_METHOD(void set_icon(const Glib::RefPtr<Gdk::Pixbuf>& icon),
               gtk_window_set_icon)

  //TODO: Correct the since tag.
  _WRAP_METHOD(void set_icon_name(const Glib::ustring& name), gtk_window_set_icon_name)
  _WRAP_METHOD(bool set_icon_from_file(const std::string& filename), gtk_window_set_icon_from_file, errthrow)

  _WRAP_METHOD(Glib::RefPtr<Gdk::Pixbuf> get_icon(), gtk_window_get_icon, refreturn)
  _WRAP_METHOD(Glib::RefPtr<const Gdk::Pixbuf> get_icon() const, gtk_window_get_icon, refreturn, constversion)

  _WRAP_METHOD(Glib::ustring get_icon_name() const, gtk_window_get_icon_name)

  _WRAP_METHOD(static void set_default_icon_list(
                   const std::vector< Glib::RefPtr<Gdk::Pixbuf> >& list),
               gtk_window_set_default_icon_list)

  _WRAP_METHOD(static std::vector< Glib::RefPtr<Gdk::Pixbuf> > get_default_icon_list(), gtk_window_get_default_icon_list)

  _WRAP_METHOD(static void set_default_icon(const Glib::RefPtr<Gdk::Pixbuf>& icon), gtk_window_set_default_icon)
  _WRAP_METHOD(static void set_default_icon_name(const Glib::ustring& name), gtk_window_set_default_icon_name)
  _WRAP_METHOD(static bool set_default_icon_from_file(const std::string& filename), gtk_window_set_default_icon_from_file, errthrow)
  _WRAP_METHOD(static void set_auto_startup_notification(bool setting = true), gtk_window_set_auto_startup_notification)

  _WRAP_METHOD(void set_modal(bool modal = true), gtk_window_set_modal)

  _WRAP_METHOD(bool get_modal() const, gtk_window_get_modal)

#m4 _CONVERSION(`GList*',`std::vector<Window*>',`Glib::ListHandler<Window*>::list_to_vector($3, Glib::OWNERSHIP_SHALLOW)')
  _WRAP_METHOD(static std::vector<Window*> list_toplevels(), gtk_window_list_toplevels)

  _WRAP_METHOD(void add_mnemonic(guint keyval, Widget& target),
               gtk_window_add_mnemonic)

  _WRAP_METHOD(void remove_mnemonic(guint keyval, Widget& target),
               gtk_window_remove_mnemonic)

  _WRAP_METHOD(bool mnemonic_activate(guint keyval, Gdk::ModifierType modifier),
               gtk_window_mnemonic_activate)

  _WRAP_METHOD(void set_mnemonic_modifier(Gdk::ModifierType modifier),
               gtk_window_set_mnemonic_modifier)

  _WRAP_METHOD(Gdk::ModifierType get_mnemonic_modifier(),
               gtk_window_get_mnemonic_modifier)


  _WRAP_METHOD(void present(), gtk_window_present)
  _WRAP_METHOD(void present(guint32 timestamp), gtk_window_present_with_time)

  _WRAP_METHOD(void iconify(), gtk_window_iconify)
  _WRAP_METHOD(void deiconify(), gtk_window_deiconify)

  _WRAP_METHOD(void stick(), gtk_window_stick)
  _WRAP_METHOD(void unstick(), gtk_window_unstick)

  _WRAP_METHOD(void maximize(), gtk_window_maximize)
  _WRAP_METHOD(void unmaximize(), gtk_window_unmaximize)

  _WRAP_METHOD(void fullscreen(), gtk_window_fullscreen)
  _WRAP_METHOD(void unfullscreen(), gtk_window_unfullscreen)
  _WRAP_METHOD(void fullscreen_on_monitor(const Glib::RefPtr<Gdk::Screen>& screen, int monitor), gtk_window_fullscreen_on_monitor)
  _WRAP_METHOD(void close(), gtk_window_close)

  _WRAP_METHOD(void begin_resize_drag(Gdk::WindowEdge edge,
                   int button, int root_x, int root_y, guint32 timestamp),
               gtk_window_begin_resize_drag)

  _WRAP_METHOD(void begin_move_drag(
                   int button, int root_x, int root_y, guint32 timestamp),
               gtk_window_begin_move_drag)

  _WRAP_METHOD(void set_default_size(int width, int height),
               gtk_window_set_default_size)

  _WRAP_METHOD(void get_default_size(int& width, int& height) const,
               gtk_window_get_default_size)

  _WRAP_METHOD(void resize(int width, int height), gtk_window_resize)

  _WRAP_METHOD(void get_size(int& width, int& height) const,
               gtk_window_get_size)


  _WRAP_METHOD(void move(int x, int y), gtk_window_move)

  _WRAP_METHOD(void get_position(int& root_x, int& root_y) const,
               gtk_window_get_position)

  _WRAP_METHOD(bool parse_geometry(const Glib::ustring& geometry),
               gtk_window_parse_geometry)

  _WRAP_METHOD(void set_default_geometry(int width, int height), gtk_window_set_default_geometry)
  _WRAP_METHOD(void resize_to_geometry(int width, int height), gtk_window_resize_to_geometry,
    deprecated "This function does nothing. Use resize() and compute the geometry yourself.")

  _WRAP_METHOD(Glib::RefPtr<WindowGroup> get_group(), gtk_window_get_group, refreturn)
  _WRAP_METHOD(Glib::RefPtr<const WindowGroup> get_group() const, gtk_window_get_group, refreturn, constversion)

  _WRAP_METHOD(bool has_group() const, gtk_window_has_group)

  _WRAP_METHOD(WindowType get_window_type() const, gtk_window_get_window_type)

  _WRAP_METHOD(void reshow_with_initial_size(), gtk_window_reshow_with_initial_size, deprecated "GUI builders can call Widget::hide(), Widget::unrealize() and then Widget::show() themselves, if they still need this functionality.")

  _WRAP_METHOD(Glib::RefPtr<Application> get_application(), gtk_window_get_application, refreturn)
  _WRAP_METHOD(Glib::RefPtr<const Application> get_application() const, gtk_window_get_application, refreturn)

  _WRAP_METHOD(void set_application(const Glib::RefPtr<Application>& application), gtk_window_set_application)

  /** Unsets the Application associated with the window.
   * This could cause the application to exit if it is the application's last window.
   */
  void unset_application();

  _WRAP_METHOD(void set_has_resize_grip(bool value = true), gtk_window_set_has_resize_grip, deprecated "Resize grips have been removed.")
  _WRAP_METHOD(bool get_has_resize_grip() const, gtk_window_get_has_resize_grip, deprecated "Resize grips have been removed.")

  _WRAP_METHOD(bool get_resize_grip_is_visible() const, gtk_window_resize_grip_is_visible, deprecated "Resize grips have been removed.")
  _WRAP_METHOD(bool get_resize_grip_area(Gdk::Rectangle& rect) const, gtk_window_get_resize_grip_area, deprecated "Resize grips have been removed.")

  _WRAP_METHOD(void set_keep_above(bool setting = true), gtk_window_set_keep_above)
  _WRAP_METHOD(void set_keep_below(bool setting = true), gtk_window_set_keep_below)

  _WRAP_METHOD(void set_titlebar(Widget& titlebar), gtk_window_set_titlebar)

  _WRAP_METHOD(Widget* get_titlebar(), gtk_window_get_titlebar)
  _WRAP_METHOD(const Widget* get_titlebar() const, gtk_window_get_titlebar, constversion)

  _WRAP_METHOD(bool is_maximized() const, gtk_window_is_maximized)

  /** Returns a default accel group for this window
   * This is a gtkmm-specific function.  This accel group can not
   * be removed.
   */
  Glib::RefPtr<AccelGroup> get_accel_group();

  //TODO: Remove the virtual from this when we can break ABI.
  /** Brings the window to the front.
   * This is just a more obvious convenience wrapper for get_window()->raise().
   */
  virtual void raise();

  ///Overriden to warn that it doesn't make sense to use Gtk::manage() on this class because it has no parent container.
  void set_manage() override;

protected:

  //See comments in the implementations:
  void destroy_();
  void _release_c_instance();

private:

  //We'll create an accel_group if it's requested, and remember it.
  //Otherwise, you'd have to create it, add it to the window, then remember it somewhere else while you add it to other widgets.
  Glib::RefPtr<AccelGroup> accel_group_;
};


} // namespace Gtk
