ardour/libs/gtkmm2/gtk/src/widget.ccg
Paul Davis 449aab3c46 rollback to 3428, before the mysterious removal of libs/* at 3431/3432
git-svn-id: svn://localhost/ardour2/branches/3.0@3435 d708f5d6-7413-0410-9779-e7cbd77b26cf
2008-06-02 21:41:35 +00:00

584 lines
19 KiB
C++

// -*- c++ -*-
/* $Id: widget.ccg,v 1.23 2006/07/19 16:58:50 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/adjustment.h>
#include <gtkmm/window.h>
#include <gtkmm/accelgroup.h>
#include <gtkmm/settings.h>
#include <gtkmm/style.h>
#include <gtkmm/container.h>
#include <gtkmm/selectiondata_private.h>
#include <gtkmm/action.h>
#include <gtkmm/tooltip.h>
#include <gtk/gtkdnd.h>
#include <gtk/gtkselection.h>
#include <gtk/gtkwidget.h>
#include <gtk/gtkcontainer.h>
#include <gtk/gtkmenu.h>
#include <gtk/gtkmenuitem.h>
#include <gtk/gtkmain.h>
#include <gtk/gtkaction.h> //For gtk_widget_get_action().
namespace //anonymous
{
//These signal callbacks are custom implemented, so that we can create a temporary SelectionData instance.
//To do this, we used the optional custom_c_callback paramater to _WRAP_SIGNAL() in the .hg file.
static void Widget_signal_drag_data_get_callback(GtkWidget* self, GdkDragContext* p0,GtkSelectionData* p1,guint p2,guint p3,void* data)
{
using namespace Gtk;
typedef sigc::slot< void,const Glib::RefPtr<Gdk::DragContext>&,SelectionData&,guint,guint > SlotType;
// Do not try to call a signal on a disassociated wrapper.
if(Glib::ObjectBase::_get_current_wrapper((GObject*) self))
{
#ifdef GLIBMM_EXCEPTIONS_ENABLED
try
{
#endif //GLIBMM_EXCEPTIONS_ENABLED
if(sigc::slot_base *const slot = Glib::SignalProxyNormal::data_to_slot(data))
{
SelectionData_WithoutOwnership temp_instance(p1);
(*static_cast<SlotType*>(slot))( Glib::wrap(p0, true), temp_instance, p2, p3 );
}
#ifdef GLIBMM_EXCEPTIONS_ENABLED
}
catch(...)
{
Glib::exception_handlers_invoke();
}
#endif //GLIBMM_EXCEPTIONS_ENABLED
}
}
static void Widget_signal_selection_get_callback(GtkWidget* self, GtkSelectionData* p0,guint p1,guint p2,void* data)
{
using namespace Gtk;
typedef sigc::slot< void, SelectionData&, guint, guint > SlotType;
// Do not try to call a signal on a disassociated wrapper.
if(Glib::ObjectBase::_get_current_wrapper((GObject*) self))
{
#ifdef GLIBMM_EXCEPTIONS_ENABLED
try
{
#endif //GLIBMM_EXCEPTIONS_ENABLED
if(sigc::slot_base *const slot = Glib::SignalProxyNormal::data_to_slot(data))
{
SelectionData_WithoutOwnership temp_instance(p0);
(*static_cast<SlotType*>(slot))( temp_instance, p1, p2 );
}
#ifdef GLIBMM_EXCEPTIONS_ENABLED
}
catch(...)
{
Glib::exception_handlers_invoke();
}
#endif //GLIBMM_EXCEPTIONS_ENABLED
}
}
} //anonymous
namespace Gtk
{
#ifdef GLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED
//These default handler callbacks are custom implemented, so that we can create a temporary SelectionData instance.
//To do this, we used the optional custom_c_callback paramater to _WRAP_SIGNAL() in the .hg file.
void Widget_Class::selection_get_callback(GtkWidget* self, GtkSelectionData* p0, guint p1, guint p2)
{
CppObjectType *const obj = dynamic_cast<CppObjectType*>(
Glib::ObjectBase::_get_current_wrapper((GObject*)self));
// Non-gtkmmproc-generated custom classes implicitly call the default
// Glib::ObjectBase constructor, which sets is_derived_. But gtkmmproc-
// generated classes can use this optimisation, which avoids the unnecessary
// parameter conversions if there is no possibility of the virtual function
// being overridden:
if(obj && obj->is_derived_())
{
#ifdef GLIBMM_EXCEPTIONS_ENABLED
try // Trap C++ exceptions which would normally be lost because this is a C callback.
{
#endif //GLIBMM_EXCEPTIONS_ENABLED
// Call the virtual member method, which derived classes might override.
SelectionData_WithoutOwnership temp_instance(p0);
obj->on_selection_get(temp_instance, p1, p2);
#ifdef GLIBMM_EXCEPTIONS_ENABLED
}
catch(...)
{
Glib::exception_handlers_invoke();
}
#endif //GLIBMM_EXCEPTIONS_ENABLED
}
else
{
BaseClassType *const base = static_cast<BaseClassType*>(
g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The original underlying C class).
);
// Call the original underlying C function:
if(base && base->selection_get)
(*base->selection_get)(self, p0, p1, p2);
}
}
void Widget_Class::drag_data_get_callback(GtkWidget* self, GdkDragContext* p0, GtkSelectionData* p1, guint p2, guint p3)
{
CppObjectType *const obj = dynamic_cast<CppObjectType*>(
Glib::ObjectBase::_get_current_wrapper((GObject*)self));
// Non-gtkmmproc-generated custom classes implicitly call the default
// Glib::ObjectBase constructor, which sets is_derived_. But gtkmmproc-
// generated classes can use this optimisation, which avoids the unnecessary
// parameter conversions if there is no possibility of the virtual function
// being overridden:
if(obj && obj->is_derived_())
{
#ifdef GLIBMM_EXCEPTIONS_ENABLED
try // Trap C++ exceptions which would normally be lost because this is a C callback.
{
#endif //GLIBMM_EXCEPTIONS_ENABLED
// Call the virtual member method, which derived classes might override.
SelectionData_WithoutOwnership temp_instance(p1);
obj->on_drag_data_get(Glib::wrap(p0, true), temp_instance, p2, p3);
#ifdef GLIBMM_EXCEPTIONS_ENABLED
}
catch(...)
{
Glib::exception_handlers_invoke();
}
#endif //GLIBMM_EXCEPTIONS_ENABLED
}
else
{
BaseClassType *const base = static_cast<BaseClassType*>(
g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The original underlying C class).
);
// Call the original underlying C function:
if(base && base->drag_data_get)
(*base->drag_data_get)(self, p0, p1, p2, p3);
}
}
#endif //GLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED
Widget::~Widget()
{}
bool Widget::intersect(const Gdk::Rectangle& area) const
{
return gtk_widget_intersect(
const_cast<GtkWidget*>(gobj()), const_cast<GdkRectangle*>(area.gobj()), 0);
}
void Widget::unset_name()
{
gtk_widget_set_name(gobj(), 0);
}
void Widget::unset_composite_name()
{
gtk_widget_set_composite_name(gobj(), 0);
}
void Widget::realize_if_needed()
{
if(!is_realized())
realize();
}
void Widget::add_modal_grab()
{
gtk_grab_add(gobj());
}
void Widget::remove_modal_grab()
{
gtk_grab_remove(gobj());
}
Widget* Widget::get_current_modal_grab()
{
return Glib::wrap(gtk_grab_get_current());
}
void Widget::path(Glib::ustring& path_arg, Glib::ustring& path_reversed)
{
guint path_length = 0;
Glib::ScopedPtr<gchar> path_ptr;
Glib::ScopedPtr<gchar> rpath_ptr;
gtk_widget_path(gobj(), &path_length, path_ptr.addr(), rpath_ptr.addr());
path_arg.assign(path_ptr.get(), path_ptr.get() + path_length);
path_reversed.assign(rpath_ptr.get(), rpath_ptr.get() + path_length);
}
void Widget::class_path(Glib::ustring& path_arg, Glib::ustring& path_reversed)
{
guint path_length = 0;
Glib::ScopedPtr<gchar> path_ptr;
Glib::ScopedPtr<gchar> rpath_ptr;
gtk_widget_class_path(gobj(), &path_length, path_ptr.addr(), rpath_ptr.addr());
path_arg.assign(path_ptr.get(), path_ptr.get() + path_length);
path_reversed.assign(rpath_ptr.get(), rpath_ptr.get() + path_length);
}
void Widget::modify_bg_pixmap(StateType state, const Glib::ustring& pixmap_name)
{
const Glib::RefPtr<RcStyle> modifier_style = get_modifier_style();
modifier_style->set_bg_pixmap_name(state, pixmap_name);
modify_style(modifier_style);
}
void Widget::unset_fg(StateType state)
{
gtk_widget_modify_fg(gobj(), static_cast<GtkStateType>(int(state)), 0);
}
void Widget::unset_bg(StateType state)
{
gtk_widget_modify_bg(gobj(), static_cast<GtkStateType>(int(state)), 0);
}
void Widget::unset_text(StateType state)
{
gtk_widget_modify_text(gobj(), static_cast<GtkStateType>(int(state)), 0);
}
void Widget::unset_base(StateType state)
{
gtk_widget_modify_base(gobj(), static_cast<GtkStateType>(int(state)), 0);
}
void Widget::unset_font()
{
gtk_widget_modify_font(gobj(), 0);
}
void Widget::unset_cursor()
{
gtk_widget_modify_cursor(gobj(), 0, 0);
}
bool Widget::is_toplevel() const
{ return GTK_WIDGET_TOPLEVEL(gobj()); }
bool Widget::has_no_window() const
{ return GTK_WIDGET_NO_WINDOW(gobj()); }
bool Widget::is_realized() const
{ return GTK_WIDGET_REALIZED(gobj()); }
bool Widget::is_mapped() const
{ return GTK_WIDGET_MAPPED(gobj()); }
bool Widget::is_visible() const
{ return GTK_WIDGET_VISIBLE(gobj()); }
bool Widget::is_drawable() const
{ return GTK_WIDGET_DRAWABLE(gobj()); }
bool Widget::sensitive() const
{ return GTK_WIDGET_SENSITIVE(gobj()); }
bool Widget::parent_sensitive() const
{ return GTK_WIDGET_PARENT_SENSITIVE(gobj()); }
bool Widget::is_sensitive() const
{ return GTK_WIDGET_IS_SENSITIVE(gobj()); }
bool Widget::can_focus() const
{ return GTK_WIDGET_CAN_FOCUS(gobj()); }
bool Widget::has_focus() const
{ return GTK_WIDGET_HAS_FOCUS(gobj()); }
bool Widget::can_default() const
{ return GTK_WIDGET_CAN_DEFAULT(gobj()); }
bool Widget::has_default() const
{ return GTK_WIDGET_HAS_DEFAULT(gobj()); }
bool Widget::has_grab() const
{ return GTK_WIDGET_HAS_GRAB(gobj()); }
bool Widget::rc_style() const
{ return GTK_WIDGET_RC_STYLE(gobj()); }
bool Widget::is_composite_child() const
{ return GTK_WIDGET_COMPOSITE_CHILD(gobj()); }
bool Widget::app_paintable() const
{ return GTK_WIDGET_APP_PAINTABLE(gobj()); }
bool Widget::receives_default() const
{ return GTK_WIDGET_RECEIVES_DEFAULT(gobj()); }
bool Widget::double_buffered() const
{ return GTK_WIDGET_DOUBLE_BUFFERED(gobj()); }
WidgetFlags Widget::get_flags() const
{ return static_cast<WidgetFlags>(GTK_WIDGET_FLAGS(gobj())); }
void Widget::set_flags(WidgetFlags flags)
{ GTK_WIDGET_SET_FLAGS(gobj(), static_cast<guint32>(flags)); }
void Widget::unset_flags(WidgetFlags flags)
{ GTK_WIDGET_UNSET_FLAGS(gobj(), static_cast<guint32>(flags)); }
int Widget::get_width() const
{ return gobj()->allocation.width; }
int Widget::get_height() const
{ return gobj()->allocation.height; }
void Widget::drag_dest_set(DestDefaults flags, Gdk::DragAction actions)
{
gtk_drag_dest_set(gobj(), (GtkDestDefaults)flags, 0, 0, (GdkDragAction)actions);
}
void Widget::drag_dest_set(const ArrayHandle_TargetEntry& targets,
DestDefaults flags, Gdk::DragAction actions)
{
// I've used Gdk::ACTION_COPY as the default, because Gdk::ACTION_DEFAULT means that
// it's never a drag destination, so it would seem like this method didn't work. murrayc.
gtk_drag_dest_set(
gobj(), (GtkDestDefaults)flags,
targets.data(), targets.size(), (GdkDragAction)actions);
}
void Widget::drag_source_set(const ArrayHandle_TargetEntry& targets,
Gdk::ModifierType start_button_mask, Gdk::DragAction actions)
{
// I've used Gdk::MODIFIER_MASK as the default, because it seems
// to mean 'whatever is possible in the context'. murrayc.
gtk_drag_source_set(
gobj(), (GdkModifierType)start_button_mask,
targets.data(), targets.size(), (GdkDragAction)actions);
}
Widget* Widget::drag_get_source_widget(const Glib::RefPtr<Gdk::DragContext>& context) //static
{
return Glib::wrap( gtk_drag_get_source_widget(Glib::unwrap(context)) );
}
void Widget::drag_set_as_icon(const Glib::RefPtr<Gdk::DragContext>& context, int hot_x, int hot_y)
{
gtk_drag_set_icon_widget(Glib::unwrap(context), gobj(), hot_x, hot_y);
}
#ifdef GLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED
void Widget_Class::hierarchy_changed_callback_custom(GtkWidget* self, GtkWidget* p0)
{
//GTKMM_LIFECYCLE
//Don't call wrap() on a GTK+ instance whose gtkmm instance has been deleted - just call the original C callback.
bool gtkmm_child_already_deleted = Glib::_gobject_cppinstance_already_deleted((GObject*)p0);
if(!gtkmm_child_already_deleted)
{
//Call the regular, generated callback:
Widget_Class::hierarchy_changed_callback(self, p0);
}
else
{
BaseClassType *const base = static_cast<BaseClassType*>(
g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The original underlying C class).
);
//Call the original underlying C function:
if(base && base->hierarchy_changed)
(*base->hierarchy_changed)(self, p0);
}
}
void Widget_Class::parent_set_callback_custom(GtkWidget* self, GtkWidget* p0)
{
//GTKMM_LIFECYCLE
//Don't call wrap() on a GTK+ instance whose gtkmm instance has been deleted - just call the original C callback.
bool gtkmm_p0_already_deleted = Glib::_gobject_cppinstance_already_deleted((GObject*)p0);
if(!gtkmm_p0_already_deleted)
{
//Call the regular, generated callback:
Widget_Class::parent_set_callback(self, p0);
}
else
{
BaseClassType *const base = static_cast<BaseClassType*>(
g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The original underlying C class).
);
//Call the original underlying C function:
if(base && base->parent_set)
(*base->parent_set)(self, p0);
}
}
#endif //#GLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED
void Widget_Class::dispose_vfunc_callback(GObject* self)
{
//Avoid disposal. See also Window_Class::dispose_vfunc_callback().
#ifdef GLIBMM_DEBUG_REFCOUNTING
g_warning("Widget_Class::dispose_vfunc_callback(): gobject_: %p\n", (void*)self);
//if(self)
//g_warning(" gtypename: %s\n", G_OBJECT_TYPE_NAME(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
// any widget inside a GtkContainer on gtk_container_destroy()
// See also Window_Class::dispose_vfunc_callback().
if(obj->referenced_) //Not managed
{
// GTKMM_LIFECYCLE
// Remove the widget from its parent container so that it
// won't be destroyed later by gtk_container_destroy().
if(pWidget->parent)
{
// Normally, we would have to ref the child widget because
// gtk_container_remove() unrefs it. But since we only remove
// non-managed objects here, the container just releases the
// reference it has acquired before in gtk_container_add().
#ifdef GLIBMM_DEBUG_REFCOUNTING
g_warning("Widget_Class::dispose_vfunc_callback(): removing gobject_: %p from parent: %p", (void*)self, (void*)pWidget->parent);
#endif
gtk_container_remove(GTK_CONTAINER(pWidget->parent), pWidget);
#ifdef GLIBMM_DEBUG_REFCOUNTING
g_warning("Widget_Class::dispose_vfunc_callback(): after removing from parent.");
#endif
}
// Special case for GtkMenu because gtk_menu_attach_to_widget does
// not set widget->parent but gtk_menu_item_destroy() destroys the menu
// like gtk_container_destroy()
// Gtk::Menu does not use a parent widget because it must
// be contained in its Gtk::Window so that it can be displayed as a popup.
else if (GTK_IS_MENU(pWidget) && GTK_IS_MENU_ITEM(gtk_menu_get_attach_widget(GTK_MENU(pWidget))))
{
gtk_menu_detach(GTK_MENU(pWidget));
}
#ifdef GLIBMM_DEBUG_REFCOUNTING
g_warning("Widget_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("Widget_Class::dispose_vfunc_callback(): after gtk_widget_hide().");
#endif
// GTKMM_LIFECYCLE
return; // Prevent calling of normal C dispose vfunc (see below)
}
#ifdef GLIBMM_DEBUG_REFCOUNTING
g_warning("Widget_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("Widget_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("Widget_Class::dispose_vfunc_callback(): before calling base->dispose.");
#endif
if(base->dispose)
(*base->dispose)(self);
#ifdef GLIBMM_DEBUG_REFCOUNTING
g_warning("Widget_Class::dispose_vfunc_callback(): after calling base->dispose.");
#endif
}
void Widget::unset_style()
{
gtk_widget_set_style(gobj(), 0 /* See GTK+ docs */);
}
Glib::ustring Widget::drag_dest_find_target(const Glib::RefPtr<Gdk::DragContext>& context) const
{
return Gdk::AtomString::to_cpp_type(gtk_drag_dest_find_target(const_cast<GtkWidget*>(gobj()), Glib::unwrap(context), 0 /* See GTK+ docs */));
}
void Widget::unset_shape_combine_mask()
{
gtk_widget_shape_combine_mask(gobj(), 0, 0, 0); /* See GTK+ docs */
}
void Widget::unset_input_shape_combine_mask()
{
gtk_widget_input_shape_combine_mask(gobj(), 0, 0, 0); /* See GTK+ docs */
}
void Widget::draw_insertion_cursor(Glib::RefPtr<Gdk::Drawable> drawable, const Gdk::Rectangle& area, const Gdk::Rectangle& location, bool is_primary, TextDirection direction, bool draw_arrow)
{
gtk_draw_insertion_cursor(gobj(), drawable->gobj(), const_cast<GdkRectangle*>(area.gobj()), const_cast<GdkRectangle*>(location.gobj()), is_primary, (GtkTextDirection)direction, draw_arrow);
}
Requisition Widget::size_request() const
{
Requisition requisition;
gtk_widget_size_request(const_cast<GtkWidget*>(gobj()), (GtkRequisition*)(&requisition));
return requisition;
}
} // namespace Gtk