Remove the outer scrollbar from header area.
[claws.git] / src / compose.c
index 612748c436d43a86a0dbc2efc2f224b0444da453..cb506352c38a0e62a9e208012f4a791a17819f7d 100644 (file)
@@ -61,7 +61,7 @@
 #include "main.h"
 #include "mainwindow.h"
 #include "compose.h"
-#ifndef USE_NEW_ADDRBOOK
+#ifndef USE_ALT_ADDRBOOK
        #include "addressbook.h"
 #else
        #include "addressbook-dbus.h"
@@ -336,13 +336,19 @@ static gboolean attach_property_key_pressed       (GtkWidget      *widget,
 
 static void compose_exec_ext_editor            (Compose        *compose);
 #ifdef G_OS_UNIX
-static gint compose_exec_ext_editor_real       (const gchar    *file);
+static gint compose_exec_ext_editor_real       (const gchar    *file,
+                                                GdkNativeWindow socket_wid);
 static gboolean compose_ext_editor_kill                (Compose        *compose);
 static gboolean compose_input_cb               (GIOChannel     *source,
                                                 GIOCondition    condition,
                                                 gpointer        data);
 static void compose_set_ext_editor_sensitive   (Compose        *compose,
                                                 gboolean        sensitive);
+static gboolean compose_get_ext_editor_cmd_valid();
+static gboolean compose_get_ext_editor_uses_socket();
+static gboolean compose_ext_editor_plug_removed_cb
+                                               (GtkSocket      *socket,
+                                                Compose        *compose);
 #endif /* G_OS_UNIX */
 
 static void compose_undo_state_changed         (UndoMain       *undostruct,
@@ -1199,7 +1205,7 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI
                }
 
        }
-       procmsg_msginfo_free( dummyinfo );
+       procmsg_msginfo_free( &dummyinfo );
 
        if (attach_files) {
                GList *curr;
@@ -1820,7 +1826,7 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
                quote_fmt_reset_vartable();
 
                g_free(tmp);
-               procmsg_msginfo_free(full_msginfo);
+               procmsg_msginfo_free(&full_msginfo);
        }
 
        textview = GTK_TEXT_VIEW(compose->text);
@@ -1879,7 +1885,7 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
                quote_fmt_reset_vartable();
                compose_attach_parts(compose, msginfo);
 
-               procmsg_msginfo_free(full_msginfo);
+               procmsg_msginfo_free(&full_msginfo);
        }
 
        SIGNAL_BLOCK(textbuf);
@@ -3183,7 +3189,7 @@ error:
 ok:
        SIGNAL_UNBLOCK(buffer);
 
-       procmsg_msginfo_free( dummyinfo );
+       procmsg_msginfo_free( &dummyinfo );
 
        return buf;
 }
@@ -3772,7 +3778,7 @@ static gboolean compose_attach_append(Compose *compose, const gchar *file,
 
                        ainfo->name = g_strdup_printf(_("Message: %s"), name);
 
-                       procmsg_msginfo_free(msginfo);
+                       procmsg_msginfo_free(&msginfo);
                } else {
                        if (!g_ascii_strncasecmp(content_type, "text/", 5)) {
                                ainfo->charset = g_strdup(charset);
@@ -5208,7 +5214,7 @@ gint compose_send(Compose *compose)
                                if (tmp) {
                                        debug_print("removing %d via %s\n", tmp->msgnum, tmsgid);
                                        folder_item_remove_msg(folder, tmp->msgnum);
-                                       procmsg_msginfo_free(tmp);
+                                       procmsg_msginfo_free(&tmp);
                                } 
                        }
                }
@@ -5224,7 +5230,7 @@ gint compose_send(Compose *compose)
                        if (tmp) {
                                debug_print("removing %d via %s\n", tmp->msgnum, tmsgid);
                                folder_item_remove_msg(folder, tmp->msgnum);
-                               procmsg_msginfo_free(tmp);
+                               procmsg_msginfo_free(&tmp);
                        }
                }
                if (!discard_window) {
@@ -6488,11 +6494,22 @@ static gchar *compose_get_header(Compose *compose)
                
                g_string_append_printf(header, "From: %s <%s>\n",
                        qname, from_address);
+               if (!IS_IN_CUSTOM_HEADER("Disposition-Notification-To") &&
+                   compose->return_receipt) {
+                       compose_convert_header(compose, buf, sizeof(buf), from_name,
+                                              strlen("Disposition-Notification-To: "),
+                                              TRUE);
+                       g_string_append_printf(header, "Disposition-Notification-To: %s <%s>\n", buf, from_address);
+               }
                if (qname != name)
                        g_free(qname);
-       } else
+       } else {
                g_string_append_printf(header, "From: %s\n", from_address);
-       
+               if (!IS_IN_CUSTOM_HEADER("Disposition-Notification-To") &&
+                   compose->return_receipt)
+                       g_string_append_printf(header, "Disposition-Notification-To: %s\n", from_address);
+
+       }
        g_free(from_name);
        g_free(from_address);
 
@@ -6648,21 +6665,6 @@ static gchar *compose_get_header(Compose *compose)
                                     compose->priority);
        }
 
-       /* Request Return Receipt */
-       if (!IS_IN_CUSTOM_HEADER("Disposition-Notification-To")) {
-               if (compose->return_receipt) {
-                       if (compose->account->name
-                           && *compose->account->name) {
-                               compose_convert_header(compose, buf, sizeof(buf), 
-                                                      compose->account->name, 
-                                                      strlen("Disposition-Notification-To: "),
-                                                      TRUE);
-                               g_string_append_printf(header, "Disposition-Notification-To: %s <%s>\n", buf, compose->account->address);
-                       } else
-                               g_string_append_printf(header, "Disposition-Notification-To: %s\n", compose->account->address);
-               }
-       }
-
        /* get special headers */
        for (list = compose->header_list; list; list = list->next) {
                ComposeHeaderEntry *headerentry;
@@ -6792,7 +6794,7 @@ static void compose_add_to_addressbook_cb(GtkMenuItem *menuitem, gpointer user_d
        if (*address != '\0') {
                gchar *name = procheader_get_fromname(address);
                extract_address(address);
-#ifndef USE_NEW_ADDRBOOK
+#ifndef USE_ALT_ADDRBOOK
                addressbook_add_contact(name, address, NULL, NULL);
 #else
                debug_print("%s: %s\n", name, address);
@@ -7113,21 +7115,14 @@ static void compose_remove_header_entries(Compose *compose)
 static GtkWidget *compose_create_header(Compose *compose) 
 {
        GtkWidget *from_optmenu_hbox;
-       GtkWidget *header_scrolledwin_main;
        GtkWidget *header_table_main;
        GtkWidget *header_scrolledwin;
        GtkWidget *header_table;
 
        /* parent with account selection and from header */
-       header_scrolledwin_main = gtk_scrolled_window_new(NULL, NULL);
-       gtk_widget_show(header_scrolledwin_main);
-       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(header_scrolledwin_main), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-
        header_table_main = gtk_table_new(2, 2, FALSE);
        gtk_widget_show(header_table_main);
        gtk_container_set_border_width(GTK_CONTAINER(header_table_main), BORDER_WIDTH);
-       gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(header_scrolledwin_main), header_table_main);
-       gtk_viewport_set_shadow_type(GTK_VIEWPORT(gtk_bin_get_child(GTK_BIN((header_scrolledwin_main)))), GTK_SHADOW_NONE);
 
        from_optmenu_hbox = compose_account_option_menu_create(compose);
        gtk_table_attach(GTK_TABLE(header_table_main), from_optmenu_hbox,
@@ -7157,7 +7152,7 @@ static GtkWidget *compose_create_header(Compose *compose)
 
        compose->table = NULL;
 
-       return header_scrolledwin_main;
+       return header_table_main;
 }
 
 static gboolean popup_attach_button_pressed(GtkWidget *widget, gpointer data)
@@ -8013,6 +8008,7 @@ static Compose *compose_create(PrefsAccount *account,
        compose->exteditor_file    = NULL;
        compose->exteditor_pid     = -1;
        compose->exteditor_tag     = -1;
+       compose->exteditor_socket  = NULL;
        compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_FORBIDDEN; /* inhibit auto-drafting while loading */
 
        compose->folder_update_callback_id =
@@ -8075,7 +8071,7 @@ static Compose *compose_create(PrefsAccount *account,
                gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN((compose->header_last->combo)))),
                                prefs_common_translated_header_name("Newsgroups:"));
 
-#ifndef USE_NEW_ADDRBOOK
+#ifndef USE_ALT_ADDRBOOK
        addressbook_set_target_compose(compose);
 #endif 
        if (mode != COMPOSE_REDIRECT)
@@ -8612,7 +8608,7 @@ static void compose_template_apply(Compose *compose, Template *tmpl,
 
                        parsed_str = compose_quote_fmt(compose, dummyinfo,
                                                           tmpl->value, qmark, tmp, FALSE, FALSE, err_msg);
-                       procmsg_msginfo_free( dummyinfo );
+                       procmsg_msginfo_free( &dummyinfo );
 
                        g_free( tmp );
                } 
@@ -8778,7 +8774,7 @@ static void compose_template_apply_fields(Compose *compose, Template *tmpl)
                }
        }
 
-       procmsg_msginfo_free( dummyinfo );
+       procmsg_msginfo_free( &dummyinfo );
 }
 
 static void compose_destroy(Compose *compose)
@@ -8813,9 +8809,9 @@ static void compose_destroy(Compose *compose)
        hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST,
                        compose->folder_update_callback_id);
 
-       procmsg_msginfo_free(compose->targetinfo);
-       procmsg_msginfo_free(compose->replyinfo);
-       procmsg_msginfo_free(compose->fwdinfo);
+       procmsg_msginfo_free(&(compose->targetinfo));
+       procmsg_msginfo_free(&(compose->replyinfo));
+       procmsg_msginfo_free(&(compose->fwdinfo));
 
        g_free(compose->replyto);
        g_free(compose->cc);
@@ -8843,7 +8839,7 @@ static void compose_destroy(Compose *compose)
        g_free(compose->privacy_system);
        g_free(compose->encdata);
 
-#ifndef USE_NEW_ADDRBOOK
+#ifndef USE_ALT_ADDRBOOK
        if (addressbook_get_target_compose() == compose)
                addressbook_set_target_compose(NULL);
 #endif
@@ -9278,12 +9274,37 @@ static void compose_exec_ext_editor(Compose *compose)
 {
 #ifdef G_OS_UNIX
        gchar *tmp;
+       GtkWidget *socket;
+       GdkNativeWindow socket_wid = 0;
        pid_t pid;
        gint pipe_fds[2];
 
        tmp = g_strdup_printf("%s%ctmpmsg.%p", get_tmp_dir(),
                              G_DIR_SEPARATOR, compose);
 
+       if (compose_get_ext_editor_uses_socket()) {
+               /* Only allow one socket */
+               if (compose->exteditor_socket != NULL) {
+                       if (gtk_widget_is_focus(compose->exteditor_socket)) {
+                               /* Move the focus off of the socket */
+                               gtk_widget_child_focus(compose->window, GTK_DIR_TAB_BACKWARD);
+                       }
+                       g_free(tmp);
+                       return;
+               }
+               /* Create the receiving GtkSocket */
+               socket = gtk_socket_new ();
+               g_signal_connect (GTK_OBJECT(socket), "plug-removed",
+                                 G_CALLBACK(compose_ext_editor_plug_removed_cb),
+                                 compose);
+               gtk_box_pack_start(GTK_BOX(compose->edit_vbox), socket, TRUE, TRUE, 0);
+               gtk_widget_set_size_request(socket, prefs_common.compose_width, -1);
+               /* Realize the socket so that we can use its ID */
+               gtk_widget_realize(socket);
+               socket_wid = gtk_socket_get_id(GTK_SOCKET (socket));
+               compose->exteditor_socket = socket;
+       }
+
        if (pipe(pipe_fds) < 0) {
                perror("pipe");
                g_free(tmp);
@@ -9328,7 +9349,7 @@ static void compose_exec_ext_editor(Compose *compose)
                        _exit(1);
                }
 
-               pid_ed = compose_exec_ext_editor_real(tmp);
+               pid_ed = compose_exec_ext_editor_real(tmp, socket_wid);
                if (pid_ed < 0) {
                        fd_write_all(pipe_fds[1], "1\n", 2);
                        _exit(1);
@@ -9348,10 +9369,34 @@ static void compose_exec_ext_editor(Compose *compose)
 }
 
 #ifdef G_OS_UNIX
-static gint compose_exec_ext_editor_real(const gchar *file)
+static gboolean compose_get_ext_editor_cmd_valid()
+{
+       gboolean has_s = FALSE;
+       gboolean has_w = FALSE;
+       const gchar *p = prefs_common_get_ext_editor_cmd();
+       if (!p)
+               return FALSE;
+       while ((p = strchr(p, '%'))) {
+               p++;
+               if (*p == 's') {
+                       if (has_s)
+                               return FALSE;
+                       has_s = TRUE;
+               } else if (*p == 'w') {
+                       if (has_w)
+                               return FALSE;
+                       has_w = TRUE;
+               } else {
+                       return FALSE;
+               }
+       }
+       return TRUE;
+}
+
+static gint compose_exec_ext_editor_real(const gchar *file, GdkNativeWindow socket_wid)
 {
        gchar buf[1024];
-       gchar *p;
+       gchar *p, *s;
        gchar **cmdline;
        pid_t pid;
 
@@ -9369,10 +9414,20 @@ static gint compose_exec_ext_editor_real(const gchar *file)
        if (setpgid(0, getppid()))
                perror("setpgid");
 
-       if (prefs_common_get_ext_editor_cmd() &&
-           (p = strchr(prefs_common_get_ext_editor_cmd(), '%')) &&
-           *(p + 1) == 's' && !strchr(p + 2, '%')) {
-               g_snprintf(buf, sizeof(buf), prefs_common_get_ext_editor_cmd(), file);
+       if (compose_get_ext_editor_cmd_valid()) {
+               if (compose_get_ext_editor_uses_socket()) {
+                       p = g_strdup(prefs_common_get_ext_editor_cmd());
+                       s = strstr(p, "%w");
+                       s[1] = 'u';
+                       if (strstr(p, "%s") < s)
+                               g_snprintf(buf, sizeof(buf), p, file, socket_wid);
+                       else
+                               g_snprintf(buf, sizeof(buf), p, socket_wid, file);
+                       g_free(p);
+               } else {
+                       g_snprintf(buf, sizeof(buf),
+                                  prefs_common_get_ext_editor_cmd(), file);
+               }
        } else {
                if (prefs_common_get_ext_editor_cmd())
                        g_warning("External editor command-line is invalid: '%s'",
@@ -9492,23 +9547,66 @@ static gboolean compose_input_cb(GIOChannel *source, GIOCondition condition,
        compose->exteditor_pid     = -1;
        compose->exteditor_ch      = NULL;
        compose->exteditor_tag     = -1;
+       if (compose->exteditor_socket) {
+               gtk_widget_destroy(compose->exteditor_socket);
+               compose->exteditor_socket = NULL;
+       }
+
 
        return FALSE;
 }
 
+static char *ext_editor_menu_entries[] = {
+       "Menu/Message/Send",
+       "Menu/Message/SendLater",
+       "Menu/Message/InsertFile",
+       "Menu/Message/InsertSig",
+       "Menu/Message/ReplaceSig",
+       "Menu/Message/Save",
+       "Menu/Message/Print",
+       "Menu/Edit",
+#if USE_ENCHANT
+       "Menu/Spelling",
+#endif
+       "Menu/Tools/ShowRuler",
+       "Menu/Tools/Actions",
+       "Menu/Help",
+       NULL
+};
+
 static void compose_set_ext_editor_sensitive(Compose *compose,
                                             gboolean sensitive)
 {
-       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/Send", sensitive);
-       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/SendLater", sensitive);
-       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertFile", sensitive);
-       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertSig", sensitive);
-       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/ReplaceSig", sensitive);
-       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Edit/WrapPara", sensitive);
-       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Edit/WrapAllLines", sensitive);
-       cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Edit/ExtEditor", sensitive);
+       int i;
 
-       gtk_widget_set_sensitive(compose->text,                       sensitive);
+       for (i = 0; ext_editor_menu_entries[i]; ++i) {
+               cm_menu_set_sensitive_full(compose->ui_manager,
+                       ext_editor_menu_entries[i], sensitive);
+       }
+
+       if (compose_get_ext_editor_uses_socket()) {
+               if (sensitive) {
+                       if (compose->exteditor_socket)
+                               gtk_widget_hide(compose->exteditor_socket);
+                       gtk_widget_show(compose->scrolledwin);
+                       if (prefs_common.show_ruler)
+                               gtk_widget_show(compose->ruler_hbox);
+                       /* Fix the focus, as it doesn't go anywhere when the
+                        * socket is hidden or destroyed */
+                       gtk_widget_child_focus(compose->window, GTK_DIR_TAB_BACKWARD);
+               } else {
+                       g_assert (compose->exteditor_socket != NULL);
+                       /* Fix the focus, as it doesn't go anywhere when the
+                        * edit box is hidden */
+                       if (gtk_widget_is_focus(compose->text))
+                               gtk_widget_child_focus(compose->window, GTK_DIR_TAB_BACKWARD);
+                       gtk_widget_hide(compose->scrolledwin);
+                       gtk_widget_hide(compose->ruler_hbox);
+                       gtk_widget_show(compose->exteditor_socket);
+               }
+       } else {
+               gtk_widget_set_sensitive(compose->text,                   sensitive);
+       }
        if (compose->toolbar->send_btn)
                gtk_widget_set_sensitive(compose->toolbar->send_btn,      sensitive);
        if (compose->toolbar->sendl_btn)
@@ -9526,6 +9624,19 @@ static void compose_set_ext_editor_sensitive(Compose *compose,
        if (compose->toolbar->linewrap_all_btn)
                gtk_widget_set_sensitive(compose->toolbar->linewrap_all_btn, sensitive);
 }
+
+static gboolean compose_get_ext_editor_uses_socket()
+{
+       return (prefs_common_get_ext_editor_cmd() &&
+               strstr(prefs_common_get_ext_editor_cmd(), "%w"));
+}
+
+static gboolean compose_ext_editor_plug_removed_cb(GtkSocket *socket, Compose *compose)
+{
+       compose->exteditor_socket = NULL;
+       /* returning FALSE allows destruction of the socket */
+       return FALSE;
+}
 #endif /* G_OS_UNIX */
 
 /**
@@ -9826,6 +9937,12 @@ static void compose_send_cb(GtkAction *action, gpointer data)
 {
        Compose *compose = (Compose *)data;
 
+#ifdef G_OS_UNIX
+       if (compose->exteditor_tag != -1) {
+               debug_print("ignoring send: external editor still open\n");
+               return;
+       }
+#endif
        if (prefs_common.work_offline && 
            !inc_offline_should_override(TRUE,
                _("Claws Mail needs network access in order "
@@ -10020,7 +10137,7 @@ gboolean compose_draft (gpointer data, guint action)
                }
                if (tmpinfo) {
                        msgnum = tmpinfo->msgnum;
-                       procmsg_msginfo_free(tmpinfo);
+                       procmsg_msginfo_free(&tmpinfo);
                        debug_print("got draft msgnum %d from scanning\n", msgnum);
                } else {
                        debug_print("didn't get draft msgnum after scanning\n");
@@ -10078,7 +10195,7 @@ warn_err:
                if (action == COMPOSE_DRAFT_FOR_EXIT) {
                        compose_register_draft(newmsginfo);
                }
-               procmsg_msginfo_free(newmsginfo);
+               procmsg_msginfo_free(&newmsginfo);
        }
        
        folder_item_scan(draft);
@@ -10104,7 +10221,7 @@ warn_err:
                }
                g_free(path);
 
-               procmsg_msginfo_free(compose->targetinfo);
+               procmsg_msginfo_free(&(compose->targetinfo));
                compose->targetinfo = procmsg_msginfo_new();
                compose->targetinfo->msgnum = msgnum;
                compose->targetinfo->size = (goffset)s.st_size;
@@ -10367,7 +10484,7 @@ static void compose_address_cb(GtkAction *action, gpointer data)
 {
        Compose *compose = (Compose *)data;
 
-#ifndef USE_NEW_ADDRBOOK
+#ifndef USE_ALT_ADDRBOOK
        addressbook_open(compose);
 #else
        GError* error = NULL;
@@ -11748,7 +11865,7 @@ static void compose_reply_from_messageview_real(MessageView *msgview, GSList *ms
 
        if (new_msglist) {
                compose = compose_reply_mode((ComposeMode)action, new_msglist, body);
-               procmsg_msginfo_free(tmp_msginfo);
+               procmsg_msginfo_free(&tmp_msginfo);
                g_slist_free(new_msglist);
        } else
                compose = compose_reply_mode((ComposeMode)action, msginfo_list, body);