Code

Fix [ 1835591 ] Reproducible crash on opening the attached file
[inkscape.git] / src / ui / widget / dock-item.cpp
index 1e232cb4e8acc4c0dd78db574d7e2461871cf747..6390eca504ebb2cf020a72a9c40e6b3f11993c37 100644 (file)
@@ -12,6 +12,7 @@
 #include "dock-item.h"
 #include "desktop.h"
 #include "inkscape.h"
+#include "prefs-utils.h"
 #include "ui/widget/dock.h"
 #include "widgets/icon.h"
 
@@ -31,27 +32,17 @@ DockItem::DockItem(Dock& dock, const Glib::ustring& name, const Glib::ustring& l
     _window (NULL),
     _dock_item_action_area (NULL)
 {
-    /* Add a "signal_response" signal to the GdlDockItem, make sure it is
-     * only done once for the class.
-     */
-    static guint response_signal = 0;
-
-    if (response_signal == 0) {
-        response_signal = g_signal_new ("signal_response",
-                                        GDL_TYPE_DOCK_ITEM,
-                                        G_SIGNAL_RUN_FIRST,
-                                        0,
-                                        NULL, NULL,
-                                        g_cclosure_marshal_VOID__INT,
-                                        G_TYPE_NONE, 1, G_TYPE_INT);
-    }
 
+    GdlDockItemBehavior gdl_dock_behavior =
+        (prefs_get_int_attribute_limited ("options.dock", "cancenterdock", 1, 0, 1) == 0 ?
+         GDL_DOCK_ITEM_BEH_CANT_DOCK_CENTER
+         : GDL_DOCK_ITEM_BEH_NORMAL);
 
     if (!icon_name.empty()) {
         Gtk::Widget *icon = sp_icon_get_icon(icon_name, Inkscape::ICON_SIZE_MENU);
         if (icon) {
-            // check icon type (inkscape, gtk, none) 
-            if ( SP_IS_ICON(icon->gobj()) ) { 
+            // check icon type (inkscape, gtk, none)
+            if ( SP_IS_ICON(icon->gobj()) ) {
                 SPIcon* sp_icon = SP_ICON(icon->gobj());
                 sp_icon_fetch_pixbuf(sp_icon);
                 _icon_pixbuf = Glib::wrap(sp_icon->pb, true);
@@ -61,13 +52,13 @@ DockItem::DockItem(Dock& dock, const Glib::ustring& name, const Glib::ustring& l
             }
             delete icon;
 
-            _gdl_dock_item = 
-                gdl_dock_item_new_with_pixbuf_icon(name.c_str(), long_name.c_str(), _icon_pixbuf->gobj(),
-                                                   GDL_DOCK_ITEM_BEH_NORMAL);
+            _gdl_dock_item =
+                gdl_dock_item_new_with_pixbuf_icon(name.c_str(), long_name.c_str(),
+                                                   _icon_pixbuf->gobj(), gdl_dock_behavior);
         }
     } else {
-        _gdl_dock_item = 
-            gdl_dock_item_new(name.c_str(), long_name.c_str(), GDL_DOCK_ITEM_BEH_NORMAL);
+        _gdl_dock_item =
+            gdl_dock_item_new(name.c_str(), long_name.c_str(), gdl_dock_behavior);
     }
 
     _frame.set_shadow_type(Gtk::SHADOW_IN);
@@ -81,6 +72,7 @@ DockItem::DockItem(Dock& dock, const Glib::ustring& name, const Glib::ustring& l
     signal_show().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onShow), false);
     signal_state_changed().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onStateChanged));
     signal_delete_event().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onDeleteEvent));
+    signal_realize().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onRealize));
 
     _dock.addItem(*this, (_prev_state == FLOATING_STATE ? FLOATING : TOP));
 
@@ -111,6 +103,74 @@ DockItem::get_vbox()
 }
 
 
+void
+DockItem::get_position(int& x, int& y)
+{
+    if (getWindow()) {
+        getWindow()->get_position(x, y);
+    } else {
+        x = _x;
+        y = _y;
+    }
+}
+
+void
+DockItem::get_size(int& width, int& height)
+{
+    if (_window) {
+        _window->get_size(width, height);
+    } else {
+        width = get_vbox()->get_width();
+        height = get_vbox()->get_height();
+    }
+}
+
+
+void
+DockItem::resize(int width, int height)
+{
+    if (_window)
+        _window->resize(width, height);
+}
+
+
+void
+DockItem::move(int x, int y)
+{
+    if (_window)
+        _window->move(x, y);
+}
+
+void
+DockItem::set_position(Gtk::WindowPosition position)
+{
+    if (_window)
+        _window->set_position(position);
+}
+
+void
+DockItem::set_size_request(int width, int height)
+{
+    getWidget().set_size_request(width, height);
+}
+
+void
+DockItem::size_request(Gtk::Requisition& requisition)
+{
+    getWidget().size_request(requisition);
+}
+
+void
+DockItem::set_title(Glib::ustring title)
+{
+    g_object_set (_gdl_dock_item,
+                  "long-name", title.c_str(),
+                  NULL);
+
+    gdl_dock_item_set_tablabel(GDL_DOCK_ITEM(_gdl_dock_item),
+                               gtk_label_new (title.c_str()));
+}
+
 bool
 DockItem::isAttached() const
 {
@@ -121,14 +181,8 @@ DockItem::isAttached() const
 bool
 DockItem::isFloating() const
 {
-    gboolean floating = FALSE;
-    if (GDL_IS_DOCK (gdl_dock_object_get_parent_object (GDL_DOCK_OBJECT (_gdl_dock_item)))) {
-        GdlDock* dock = GDL_DOCK (gdl_dock_object_get_parent_object (GDL_DOCK_OBJECT (_gdl_dock_item)));
-        g_object_get (dock,
-                      "floating", &floating,
-                      NULL);
-    }
-    return floating;
+    return (GTK_WIDGET(gdl_dock_object_get_toplevel(GDL_DOCK_OBJECT (_gdl_dock_item))) !=
+            _dock.getGdlWidget());
 }
 
 bool
@@ -159,20 +213,6 @@ DockItem::getPlacement() const
     return (Placement)placement;
 }
 
-
-void
-DockItem::addButton(Gtk::Button* button, int response_id)
-{
-    // Create a button box for the response buttons if it's the first button to be added
-    if (!_dock_item_action_area) {
-        _dock_item_action_area = new Gtk::HButtonBox(Gtk::BUTTONBOX_END, 6);
-        _dock_item_box.pack_end(*_dock_item_action_area, Gtk::PACK_SHRINK, 0);
-        _dock_item_action_area->set_border_width(6);
-    }
-
-    _dock_item_action_area->pack_start(*button);
-}
-
 void
 DockItem::hide()
 {
@@ -194,113 +234,59 @@ DockItem::show_all()
 void
 DockItem::present()
 {
-    // iconified
-    if (isIconified()) {
+
+    if (isIconified() || !isAttached()) {
         show();
-        return;
-    }
-    
-    // unattached
-    if (!isAttached()) {
-        gdl_dock_item_show_item (GDL_DOCK_ITEM(_gdl_dock_item));
-        return;
     }
 
     // tabbed
-    if (getPlacement() == CENTER) {
+    else if (getPlacement() == CENTER) {
         int i = gtk_notebook_page_num (GTK_NOTEBOOK (_gdl_dock_item->parent),
                                        GTK_WIDGET (_gdl_dock_item));
         if (i >= 0)
             gtk_notebook_set_current_page (GTK_NOTEBOOK (_gdl_dock_item->parent), i);
-        return;
     }
 
-    // we're already present, do nothing
-}
-
+    // always grab focus, even if we're already present
+    grab_focus();
 
-void 
-DockItem::get_position(int& x, int& y)
-{ 
-    if (_getWindow()) {
-        _getWindow()->get_position(x, y);
-    } else {
-        x = _x;
-        y = _y;
-    }
-}
-
-void 
-DockItem::get_size(int& width, int& height)
-{ 
-    if (_window) {
-        _window->get_size(width, height);
-    } else {
-        width = get_vbox()->get_width();
-        height = get_vbox()->get_height();
-    }
-}
-
-
-void
-DockItem::resize(int width, int height) 
-{
-    if (_window)
-        _window->resize(width, height);
+    if (!isFloating() && getWidget().is_realized())
+        _dock.scrollToItem(*this);
 }
 
 
 void
-DockItem::move(int x, int y)
+DockItem::grab_focus()
 {
-    if (_window)
-        _window->move(x, y);
-}
+    if (GTK_WIDGET_REALIZED (_gdl_dock_item)) {
 
-void
-DockItem::set_position(Gtk::WindowPosition position)
-{
-    if (_window)
-        _window->set_position(position);
-}
+        // make sure the window we're in is present
+        Gtk::Widget *toplevel = getWidget().get_toplevel();
+        if (Gtk::Window *window = dynamic_cast<Gtk::Window *>(toplevel)) {
+            window->present();
+        }
 
-void
-DockItem::set_size_request(int width, int height)
-{
-    getWidget().set_size_request(width, height);
-}
+        gtk_widget_grab_focus (_gdl_dock_item);
 
-void 
-DockItem::size_request(Gtk::Requisition& requisition)
-{ 
-    getWidget().size_request(requisition);
+    } else {
+        _grab_focus_on_realize = true;
+    }
 }
 
 
-void
-DockItem::set_title(Glib::ustring title)
-{
-    g_object_set (_gdl_dock_item,
-                  "long-name", title.c_str(),
-                  NULL);
-
-    gdl_dock_item_set_tablabel(GDL_DOCK_ITEM(_gdl_dock_item),
-                               gtk_label_new (title.c_str()));
-}
-
 /* Signal wrappers */
 
 Glib::SignalProxy0<void>
 DockItem::signal_show()
-{ 
-    return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)), 
+{
+    return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
                                     &_signal_show_proxy);
 }
 
 Glib::SignalProxy0<void>
 DockItem::signal_hide()
-{ 
-    return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)), 
+{
+    return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
                                     &_signal_hide_proxy);
 }
 
@@ -311,13 +297,6 @@ DockItem::signal_delete_event()
                                                   &_signal_delete_event_proxy);
 }
 
-Glib::SignalProxy1<void, int>
-DockItem::signal_response()
-{
-    return Glib::SignalProxy1<void, int>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)), 
-                                         &_signal_response_proxy);
-}
-
 Glib::SignalProxy0<void>
 DockItem::signal_drag_begin()
 {
@@ -332,6 +311,13 @@ DockItem::signal_drag_end()
                                           &_signal_drag_end_proxy);
 }
 
+Glib::SignalProxy0<void>
+DockItem::signal_realize()
+{
+    return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
+                                    &_signal_realize_proxy);
+}
+
 sigc::signal<void, DockItem::State, DockItem::State>
 DockItem::signal_state_changed()
 {
@@ -381,6 +367,15 @@ DockItem::_onDragEnd(bool)
     _prev_state = state;
 }
 
+void
+DockItem::_onRealize()
+{
+    if (_grab_focus_on_realize) {
+        _grab_focus_on_realize = false;
+        grab_focus();
+    }
+}
+
 bool
 DockItem::_onKeyPress(GdkEventKey *event)
 {
@@ -390,20 +385,20 @@ DockItem::_onKeyPress(GdkEventKey *event)
 }
 
 void
-DockItem::_onStateChanged(State prev_state, State new_state)
+DockItem::_onStateChanged(State /*prev_state*/, State new_state)
 {
-    _window = _getWindow();
+    _window = getWindow();
 
-    if (new_state == FLOATING_STATE) {
+    if (new_state == FLOATING_STATE && _window) {
         _window->signal_hide().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onHideWindow));
-        _signal_key_press_event_connection = 
+        _signal_key_press_event_connection =
             _window->signal_key_press_event().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onKeyPress));
     }
 }
 
 
 bool
-DockItem::_onDeleteEvent(GdkEventAny *event)
+DockItem::_onDeleteEvent(GdkEventAny */*event*/)
 {
     hide();
     return false;
@@ -411,7 +406,7 @@ DockItem::_onDeleteEvent(GdkEventAny *event)
 
 
 Gtk::Window *
-DockItem::_getWindow()
+DockItem::getWindow()
 {
     g_return_val_if_fail(_gdl_dock_item, 0);
     Gtk::Container *parent = getWidget().get_parent();
@@ -420,7 +415,7 @@ DockItem::_getWindow()
 }
 
 const Glib::SignalProxyInfo
-DockItem::_signal_show_proxy = 
+DockItem::_signal_show_proxy =
 {
     "show",
     (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
@@ -428,7 +423,7 @@ DockItem::_signal_show_proxy =
 };
 
 const Glib::SignalProxyInfo
-DockItem::_signal_hide_proxy = 
+DockItem::_signal_hide_proxy =
 {
     "hide",
     (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
@@ -437,7 +432,7 @@ DockItem::_signal_hide_proxy =
 
 
 const Glib::SignalProxyInfo
-DockItem::_signal_delete_event_proxy = 
+DockItem::_signal_delete_event_proxy =
 {
     "delete_event",
     (GCallback) &_signal_delete_event_callback,
@@ -446,15 +441,7 @@ DockItem::_signal_delete_event_proxy =
 
 
 const Glib::SignalProxyInfo
-DockItem::_signal_response_proxy = 
-{
-    "signal_response",
-    (GCallback) &_signal_response_callback,
-    (GCallback) &_signal_response_callback
-};
-
-const Glib::SignalProxyInfo
-DockItem::_signal_drag_begin_proxy = 
+DockItem::_signal_drag_begin_proxy =
 {
     "dock-drag-begin",
     (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
@@ -463,7 +450,7 @@ DockItem::_signal_drag_begin_proxy =
 
 
 const Glib::SignalProxyInfo
-DockItem::_signal_drag_end_proxy = 
+DockItem::_signal_drag_end_proxy =
 {
     "dock_drag_end",
     (GCallback) &_signal_drag_end_callback,
@@ -471,6 +458,15 @@ DockItem::_signal_drag_end_proxy =
 };
 
 
+const Glib::SignalProxyInfo
+DockItem::_signal_realize_proxy =
+{
+    "realize",
+    (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
+    (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
+};
+
+
 gboolean
 DockItem::_signal_delete_event_callback(GtkWidget *self, GdkEventAny *event, void *data)
 {
@@ -490,23 +486,7 @@ DockItem::_signal_delete_event_callback(GtkWidget *self, GdkEventAny *event, voi
     return RType();
 }
 
-void 
-DockItem::_signal_response_callback(GtkWidget *self, gint response_id, void *data)
-{
-    using namespace Gtk;
-    typedef sigc::slot<void, int> SlotType;
-
-    if (Glib::ObjectBase::_get_current_wrapper((GObject *) self)) {
-        try {
-            if(sigc::slot_base *const slot = Glib::SignalProxyNormal::data_to_slot(data))
-                (*static_cast<SlotType *>(slot))(response_id);
-        } catch(...) {
-            Glib::exception_handlers_invoke();
-        }
-    }
-}
-
-void 
+void
 DockItem::_signal_drag_end_callback(GtkWidget *self, gboolean cancelled, void *data)
 {
     using namespace Gtk;