Code

Fix for show/hide.
[inkscape.git] / src / interface.cpp
index 933d407a367db240a6510a38bd01356d83673518..47563238a50dde69c30937847ec8dd22cb252c67 100644 (file)
@@ -23,7 +23,9 @@
 #include <glib.h>
 
 #include "inkscape-private.h"
+#include "extension/db.h"
 #include "extension/effect.h"
+#include "extension/input.h"
 #include "widgets/icon.h"
 #include "preferences.h"
 #include "path-prefix.h"
@@ -51,6 +53,7 @@
 #include "io/sys.h"
 #include "dialogs/dialog-events.h"
 #include "message-context.h"
+#include "ui/uxmanager.h"
 
 // Added for color drag-n-drop
 #if ENABLE_LCMS
@@ -98,6 +101,7 @@ static GtkTargetEntry ui_drop_target_entries [] = {
 
 static GtkTargetEntry *completeDropTargets = 0;
 static int completeDropTargetsCount = 0;
+static bool temporarily_block_actions = false;
 
 #define ENTRIES_SIZE(n) sizeof(n)/sizeof(n[0])
 static guint nui_drop_target_entries = ENTRIES_SIZE(ui_drop_target_entries);
@@ -182,11 +186,9 @@ sp_create_window(SPViewWidget *vw, gboolean editable)
                 gint h = MIN(gdk_screen_height(), ph);
                 gint x = MIN(gdk_screen_width() - MIN_ONSCREEN_DISTANCE, px);
                 gint y = MIN(gdk_screen_height() - MIN_ONSCREEN_DISTANCE, py);
-                if (w>0 && h>0 && x>0 && y>0) {
+                if (w>0 && h>0) {
                     x = MIN(gdk_screen_width() - w, x);
                     y = MIN(gdk_screen_height() - h, y);
-                }
-                if (w>0 && h>0) {
                     desktop->setWindowSize(w, h);
                 }
 
@@ -196,11 +198,9 @@ sp_create_window(SPViewWidget *vw, gboolean editable)
 
                 // Empirically it seems that active_desktop==this desktop only the first time a
                 // desktop is created.
-                if (x>0 && y>0) {
-                    SPDesktop *active_desktop = SP_ACTIVE_DESKTOP;
-                    if (active_desktop == desktop || active_desktop==NULL) {
-                        desktop->setWindowPosition(Geom::Point(x, y));
-                    }
+                SPDesktop *active_desktop = SP_ACTIVE_DESKTOP;
+                if (active_desktop == desktop || active_desktop==NULL) {
+                    desktop->setWindowPosition(Geom::Point(x, y));
                 }
             }
             if (maxed) {
@@ -312,13 +312,19 @@ sp_ui_new_view_preview()
 void
 sp_ui_close_view(GtkWidget */*widget*/)
 {
-    if (SP_ACTIVE_DESKTOP == NULL) {
+       SPDesktop *dt = SP_ACTIVE_DESKTOP;
+
+       if (dt == NULL) {
         return;
     }
-    if ((SP_ACTIVE_DESKTOP)->shutdown()) {
-        return;
+
+    if (dt->shutdown()) {
+        return; // Shutdown operation has been canceled, so do nothing
     }
-    SP_ACTIVE_DESKTOP->destroyWidget();
+
+    // Shutdown can proceed; use the stored reference to the desktop here instead of the current SP_ACTIVE_DESKTOP,
+    // because the user might have changed the focus in the meantime (see bug #381357 on Launchpad)
+    dt->destroyWidget();
 }
 
 
@@ -339,11 +345,14 @@ sp_ui_close_all(void)
     /* Iterate through all the windows, destroying each in the order they
        become active */
     while (SP_ACTIVE_DESKTOP) {
-        if ((SP_ACTIVE_DESKTOP)->shutdown()) {
-            /* The user cancelled the operation, so end doing the close */
+       SPDesktop *dt = SP_ACTIVE_DESKTOP;
+       if (dt->shutdown()) {
+            /* The user canceled the operation, so end doing the close */
             return FALSE;
         }
-        SP_ACTIVE_DESKTOP->destroyWidget();
+       // Shutdown can proceed; use the stored reference to the desktop here instead of the current SP_ACTIVE_DESKTOP,
+       // because the user might have changed the focus in the meantime (see bug #381357 on Launchpad)
+       dt->destroyWidget();
     }
 
     return TRUE;
@@ -359,7 +368,9 @@ sp_ui_close_all(void)
 static void
 sp_ui_menu_activate(void */*object*/, SPAction *action)
 {
-    sp_action_perform(action, NULL);
+    if (!temporarily_block_actions) {
+       sp_action_perform(action, NULL);
+    }
 }
 
 static void
@@ -610,9 +621,8 @@ sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb *verb, Inkscape::
             sp_ui_menuitem_add_icon(item, action->image);
         }
         gtk_widget_set_events(item, GDK_KEY_PRESS_MASK);
-        g_signal_connect( G_OBJECT(item), "activate",
-                          G_CALLBACK(sp_ui_menu_activate), action );
-
+        g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
+        g_signal_connect( G_OBJECT(item), "activate", G_CALLBACK(sp_ui_menu_activate), action );
         g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select_action), action );
         g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect_action), action );
     }
@@ -625,20 +635,28 @@ sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb *verb, Inkscape::
 } // end of sp_ui_menu_append_item_from_verb
 
 
-static void
-checkitem_toggled(GtkCheckMenuItem *menuitem, gpointer user_data)
+static Glib::ustring getLayoutPrefPath( Inkscape::UI::View::View *view )
 {
-    gchar const *pref = (gchar const *) user_data;
-    Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
+    Glib::ustring prefPath;
 
-    Glib::ustring pref_path;
     if (reinterpret_cast<SPDesktop*>(view)->is_focusMode()) {
-        pref_path = "/focus/";
+        prefPath = "/focus/";
     } else if (reinterpret_cast<SPDesktop*>(view)->is_fullscreen()) {
-        pref_path = "/fullscreen/";
+        prefPath = "/fullscreen/";
     } else {
-        pref_path = "/window/";
+        prefPath = "/window/";
     }
+
+    return prefPath;
+}
+
+static void
+checkitem_toggled(GtkCheckMenuItem *menuitem, gpointer user_data)
+{
+    gchar const *pref = (gchar const *) user_data;
+    Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
+
+    Glib::ustring pref_path = getLayoutPrefPath( view );
     pref_path += pref;
     pref_path += "/state";
 
@@ -657,16 +675,12 @@ checkitem_update(GtkWidget *widget, GdkEventExpose */*event*/, gpointer user_dat
     gchar const *pref = (gchar const *) user_data;
     Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
 
-    Glib::ustring pref_path;
-    if ((static_cast<SPDesktop*>(view))->is_fullscreen()) {
-        pref_path = "/fullscreen/";
-    } else {
-        pref_path = "/window/";
-    }
+    Glib::ustring pref_path = getLayoutPrefPath( view );
     pref_path += pref;
+    pref_path += "/state";
 
     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-    bool ison = prefs->getBool(pref_path + "/state", true);
+    bool ison = prefs->getBool(pref_path, true);
 
     g_signal_handlers_block_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
     gtk_check_menu_item_set_active(menuitem, ison);
@@ -675,6 +689,60 @@ checkitem_update(GtkWidget *widget, GdkEventExpose */*event*/, gpointer user_dat
     return FALSE;
 }
 
+static void taskToggled(GtkCheckMenuItem *menuitem, gpointer userData)
+{
+    if ( gtk_check_menu_item_get_active(menuitem) ) {
+        gint taskNum = GPOINTER_TO_INT(userData);
+        taskNum = (taskNum < 0) ? 0 : (taskNum > 2) ? 2 : taskNum;
+
+        Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
+
+        // note: this will change once more options are in the task set support:
+        Inkscape::UI::UXManager::getInstance()->setTask( dynamic_cast<SPDesktop*>(view), taskNum );
+    }
+}
+
+
+/**
+ *  \brief Callback function to update the status of the radio buttons in the View -> Display mode menu (Normal, No Filters, Outline)
+ */
+
+static gboolean
+update_view_menu(GtkWidget *widget, GdkEventExpose */*event*/, gpointer user_data)
+{
+       SPAction *action = (SPAction *) user_data;
+       g_assert(action->id != NULL);
+
+       Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(widget), "view");
+    SPDesktop *dt = static_cast<SPDesktop*>(view);
+       Inkscape::RenderMode mode = dt->getMode();
+
+       bool new_state = false;
+       if (!strcmp(action->id, "ViewModeNormal")) {
+       new_state = mode == Inkscape::RENDERMODE_NORMAL;
+       } else if (!strcmp(action->id, "ViewModeNoFilters")) {
+       new_state = mode == Inkscape::RENDERMODE_NO_FILTERS;
+    } else if (!strcmp(action->id, "ViewModeOutline")) {
+       new_state = mode == Inkscape::RENDERMODE_OUTLINE;
+    } else if (!strcmp(action->id, "ViewModePrintColorsPreview")) {
+       new_state = mode == Inkscape::RENDERMODE_PRINT_COLORS_PREVIEW;
+    } else {
+       g_warning("update_view_menu does not handle this verb");
+    }
+
+       if (new_state) { //only one of the radio buttons has to be activated; the others will automatically be deactivated
+               if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) {
+                       // When the GtkMenuItem version of the "activate" signal has been emitted by a GtkRadioMenuItem, there is a second
+                       // emission as the most recently active item is toggled to inactive. This is dealt with before the original signal is handled.
+                       // This emission however should not invoke any actions, hence we block it here:
+                       temporarily_block_actions = true;
+                       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (widget), TRUE);
+                       temporarily_block_actions = false;
+               }
+       }
+
+       return FALSE;
+}
 
 void
 sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *view, gchar const *label, gchar const *tip, gchar const *pref,
@@ -682,15 +750,9 @@ sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *
                                        gboolean (*callback_update)(GtkWidget *widget, GdkEventExpose *event, gpointer user_data),
                                        Inkscape::Verb *verb)
 {
-    GtkWidget *item;
-
-    unsigned int shortcut = 0;
-    SPAction *action = NULL;
-
-    if (verb) {
-        shortcut = sp_shortcut_get_primary(verb);
-        action = verb->get_action(view);
-    }
+    unsigned int shortcut = (verb) ? sp_shortcut_get_primary(verb) : 0;
+    SPAction *action = (verb) ? verb->get_action(view) : 0;
+    GtkWidget *item = gtk_check_menu_item_new();
 
     if (verb && shortcut) {
         gchar c[256];
@@ -712,12 +774,10 @@ sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *
 
         gtk_widget_show_all(hb);
 
-        item = gtk_check_menu_item_new();
         gtk_container_add((GtkContainer *) item, hb);
     } else {
         GtkWidget *l = gtk_label_new_with_mnemonic(action ? action->name : label);
         gtk_misc_set_alignment((GtkMisc *) l, 0.0, 0.5);
-        item = gtk_check_menu_item_new();
         gtk_container_add((GtkContainer *) item, l);
     }
 #if 0
@@ -838,6 +898,39 @@ sp_ui_checkboxes_menus(GtkMenu *m, Inkscape::UI::View::View *view)
                                            checkitem_toggled, checkitem_update, 0);
 }
 
+
+void addTaskMenuItems(GtkMenu *menu, Inkscape::UI::View::View *view)
+{
+    gchar const* data[] = {
+        _("Default"), _("Default interface setup"),
+        _("Custom"), _("Set the custom task"),
+        _("Wide"), _("Setup for widescreen work."),
+        0, 0
+    };
+
+    GSList *group = 0;
+    int count = 0;
+    gint active = Inkscape::UI::UXManager::getInstance()->getDefaultTask( dynamic_cast<SPDesktop*>(view) );
+    for (gchar const **strs = data; strs[0]; strs += 2, count++)
+    {
+        GtkWidget *item = gtk_radio_menu_item_new_with_label( group, strs[0] );
+        group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(item) );
+        if ( count == active )
+        {
+            gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(item), TRUE );
+        }
+
+        g_object_set_data( G_OBJECT(item), "view", view );
+        g_signal_connect( G_OBJECT(item), "toggled", reinterpret_cast<GCallback>(taskToggled), GINT_TO_POINTER(count) );
+        g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), const_cast<gchar*>(strs[1]) );
+        g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), 0 );
+
+        gtk_widget_show( item );
+        gtk_menu_shell_append( GTK_MENU_SHELL(menu), item );
+    }
+}
+
+
 /** @brief Observer that updates the recent list's max document count */
 class MaxRecentObserver : public Inkscape::Preferences::Observer {
 public:
@@ -865,7 +958,7 @@ private:
     a couple of submenus, it is unlikely this will go more than two or
     three times.
 
-    In the case of an unreconginzed verb, a menu item is made to identify
+    In the case of an unrecognized verb, a menu item is made to identify
     the verb that is missing, and display that.  The menu item is also made
     insensitive.
 */
@@ -898,6 +991,10 @@ sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, Inkscape::UI:
                     if (menu_pntr->attribute("default") != NULL) {
                         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
                     }
+                    if (verb->get_code() != SP_VERB_NONE) {
+                       SPAction *action = verb->get_action(view);
+                       g_signal_connect( G_OBJECT(item), "expose_event", (GCallback) update_view_menu, (void *) action);
+                    }
                 } else {
                     sp_ui_menu_append_item_from_verb(GTK_MENU(menu), verb, view);
                     group = NULL;
@@ -943,6 +1040,9 @@ sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, Inkscape::UI:
             gtk_recent_filter_add_application(inkscape_only_filter, g_get_prgname());
             gtk_recent_chooser_add_filter(GTK_RECENT_CHOOSER(recent_menu), inkscape_only_filter);
 
+            gtk_recent_chooser_set_show_tips (GTK_RECENT_CHOOSER(recent_menu), TRUE);
+            gtk_recent_chooser_set_show_not_found (GTK_RECENT_CHOOSER(recent_menu), FALSE);
+
             GtkWidget *recent_item = gtk_menu_item_new_with_mnemonic(_("Open _Recent"));
             gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent_item), recent_menu);
 
@@ -956,6 +1056,10 @@ sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, Inkscape::UI:
             sp_ui_checkboxes_menus(GTK_MENU(menu), view);
             continue;
         }
+        if (!strcmp(menu_pntr->name(), "task-checkboxes")) {
+            addTaskMenuItems(GTK_MENU(menu), view);
+            continue;
+        }
     }
 }
 
@@ -1044,7 +1148,7 @@ sp_ui_context_menu(Inkscape::UI::View::View *view, SPItem *item)
 
     if ( group && group != dt->currentLayer() ) {
         /* TRANSLATORS: #%s is the id of the group e.g. <g id="#g7">, not a number. */
-        gchar *label=g_strdup_printf(_("Enter group #%s"), SP_OBJECT_ID(group));
+        gchar *label=g_strdup_printf(_("Enter group #%s"), group->getId());
         GtkWidget *w = gtk_menu_item_new_with_label(label);
         g_free(label);
         g_object_set_data(G_OBJECT(w), "group", group);
@@ -1262,7 +1366,7 @@ sp_ui_drag_data_received(GtkWidget *widget,
                         const GSList *gradients = sp_document_get_resource_list(doc, "gradient");
                         for (const GSList *item = gradients; item; item = item->next) {
                             SPGradient* grad = SP_GRADIENT(item->data);
-                            if ( color.descr == grad->id ) {
+                            if ( color.descr == grad->getId() ) {
                                 if ( grad->has_stops ) {
                                     matches = grad;
                                     break;
@@ -1271,7 +1375,7 @@ sp_ui_drag_data_received(GtkWidget *widget,
                         }
                         if (matches) {
                             colorspec = "url(#";
-                            colorspec += matches->id;
+                            colorspec += matches->getId();
                             colorspec += ")";
                         } else {
                             gchar* tmp = g_strdup_printf("#%02x%02x%02x", r, g, b);
@@ -1400,48 +1504,26 @@ sp_ui_drag_data_received(GtkWidget *widget,
         case PNG_DATA:
         case JPEG_DATA:
         case IMAGE_DATA: {
-            Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
-            Inkscape::XML::Node *newImage = xml_doc->createElement("svg:image");
-            gchar *atom_name = gdk_atom_name(data->type);
-
-            // this formula taken from Glib docs
-            guint needed_size = data->length * 4 / 3 + data->length * 4 / (3 * 72) + 7;
-            needed_size += 5 + 8 + strlen(atom_name); // 5 bytes for data:, 8 for ;base64,
-
-            gchar *buffer = (gchar *) g_malloc(needed_size), *buf_work = buffer;
-            buf_work += g_sprintf(buffer, "data:%s;base64,", atom_name);
-
-            gint state = 0, save = 0;
-            g_base64_encode_step(data->data, data->length, TRUE, buf_work, &state, &save);
-            g_base64_encode_close(TRUE, buf_work, &state, &save);
-
-            newImage->setAttribute("xlink:href", buffer);
-            g_free(buffer);
-
-            GError *error = NULL;
-            GdkPixbufLoader *loader = gdk_pixbuf_loader_new_with_mime_type( gdk_atom_name(data->type), &error );
-            if ( loader ) {
-                error = NULL;
-                if ( gdk_pixbuf_loader_write( loader, data->data, data->length, &error) ) {
-                    GdkPixbuf *pbuf = gdk_pixbuf_loader_get_pixbuf(loader);
-                    if ( pbuf ) {
-                        char tmp[1024];
-                        int width = gdk_pixbuf_get_width(pbuf);
-                        int height = gdk_pixbuf_get_height(pbuf);
-                        snprintf( tmp, sizeof(tmp), "%d", width );
-                        newImage->setAttribute("width", tmp);
-
-                        snprintf( tmp, sizeof(tmp), "%d", height );
-                        newImage->setAttribute("height", tmp);
-                    }
-                }
-            }
-            g_free(atom_name);
-
-            // Add it to the current layer
-            desktop->currentLayer()->appendChildRepr(newImage);
+            const char *mime = (info == JPEG_DATA ? "image/jpeg" : "image/png");
 
-            Inkscape::GC::release(newImage);
+            Inkscape::Extension::DB::InputList o;
+            Inkscape::Extension::db.get_input_list(o);
+            Inkscape::Extension::DB::InputList::const_iterator i = o.begin();
+            while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
+                ++i;
+            }
+            Inkscape::Extension::Extension *ext = *i;
+            bool save = (strcmp(ext->get_param_optiongroup("link"), "embed") == 0);
+            ext->set_param_optiongroup("link", "embed");
+            ext->set_gui(false);
+
+            gchar *filename = g_build_filename( g_get_tmp_dir(), "inkscape-dnd-import", NULL );
+            g_file_set_contents(filename, reinterpret_cast<gchar const *>(data->data), data->length, NULL);
+            file_import(doc, filename, ext);
+            g_free(filename);
+
+            ext->set_param_optiongroup("link", save ? "embed" : "link");
+            ext->set_gui(true);
             sp_document_done( doc , SP_VERB_NONE,
                               _("Drop bitmap image"));
             break;