2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2022 the Claws Mail team and Hiroyuki Yamamoto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "claws-features.h"
27 #include <glib/gi18n.h>
29 #include <gdk/gdkkeysyms.h>
36 #include "prefs_gtk.h"
37 #include "prefs_customheader.h"
38 #include "prefs_common.h"
39 #include "prefs_account.h"
40 #include "mainwindow.h"
41 #include "foldersel.h"
42 #include "manage_window.h"
43 #include "customheader.h"
47 #include "alertpanel.h"
50 #include "file-utils.h"
53 CUSTHDR_STRING
, /*!< display string managed by list store */
54 CUSTHDR_DATA
, /*!< string managed by us */
58 static struct CustomHdr
{
62 GtkWidget
*cancel_btn
;
71 /* widget creating functions */
72 static void prefs_custom_header_create (void);
74 static void prefs_custom_header_set_dialog (PrefsAccount
*ac
);
75 static void prefs_custom_header_set_list (PrefsAccount
*ac
);
76 static void prefs_custom_header_list_view_set_row (PrefsAccount
*ac
);
78 /* callback functions */
79 static void prefs_custom_header_add_cb (void);
80 static void prefs_custom_header_val_from_file_cb(void);
81 static void prefs_custom_header_delete_cb (void);
82 static void prefs_custom_header_up (void);
83 static void prefs_custom_header_down (void);
85 static gboolean
prefs_custom_header_key_pressed (GtkWidget
*widget
,
88 static void prefs_custom_header_ok (void);
89 static void prefs_custom_header_cancel (void);
90 static gint
prefs_custom_header_deleted (GtkWidget
*widget
,
94 static GtkListStore
* prefs_custom_header_create_data_store (void);
96 static void prefs_custom_header_list_view_insert_header (GtkWidget
*list_view
,
97 GtkTreeIter
*row_iter
,
101 static GtkWidget
*prefs_custom_header_list_view_create (void);
103 static void prefs_custom_header_create_list_view_columns (GtkWidget
*list_view
);
105 static gboolean
prefs_custom_header_selected (GtkTreeSelection
*selector
,
108 gboolean currently_selected
,
112 static PrefsAccount
*cur_ac
= NULL
;
114 void prefs_custom_header_open(PrefsAccount
*ac
)
116 if (!customhdr
.window
) {
117 prefs_custom_header_create();
120 manage_window_set_transient(GTK_WINDOW(customhdr
.window
));
121 gtk_widget_grab_focus(customhdr
.ok_btn
);
123 prefs_custom_header_set_dialog(ac
);
127 gtk_widget_show(customhdr
.window
);
128 gtk_window_set_modal(GTK_WINDOW(customhdr
.window
), TRUE
);
131 static void prefs_custom_header_create(void)
137 GtkWidget
*cancel_btn
;
139 GtkWidget
*confirm_area
;
144 GtkWidget
*hdr_label
;
145 GtkWidget
*hdr_combo
;
146 GtkWidget
*val_label
;
147 GtkWidget
*val_entry
;
158 GtkWidget
*ch_scrolledwin
;
159 GtkWidget
*list_view
;
165 debug_print("Creating custom header setting window...\n");
167 window
= gtkut_window_new(GTK_WINDOW_TOPLEVEL
, "prefs_customheader");
168 gtk_container_set_border_width (GTK_CONTAINER (window
), 8);
169 gtk_window_set_position (GTK_WINDOW (window
), GTK_WIN_POS_CENTER
);
170 gtk_window_set_resizable(GTK_WINDOW (window
), TRUE
);
171 gtk_window_set_type_hint(GTK_WINDOW(window
), GDK_WINDOW_TYPE_HINT_DIALOG
);
173 vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 6);
174 gtk_widget_show (vbox
);
175 gtk_container_add (GTK_CONTAINER (window
), vbox
);
177 gtkut_stock_button_set_create(&confirm_area
, &cancel_btn
, NULL
, _("_Cancel"),
178 &ok_btn
, NULL
, _("_OK"), NULL
, NULL
, NULL
);
179 gtk_widget_show (confirm_area
);
180 gtk_box_pack_end (GTK_BOX(vbox
), confirm_area
, FALSE
, FALSE
, 0);
181 gtk_widget_grab_default (ok_btn
);
183 gtk_window_set_title (GTK_WINDOW(window
), _("Custom header configuration"));
184 MANAGE_WINDOW_SIGNALS_CONNECT (window
);
185 g_signal_connect (G_OBJECT(window
), "delete_event",
186 G_CALLBACK(prefs_custom_header_deleted
),
188 g_signal_connect (G_OBJECT(window
), "key_press_event",
189 G_CALLBACK(prefs_custom_header_key_pressed
),
191 g_signal_connect (G_OBJECT(ok_btn
), "clicked",
192 G_CALLBACK(prefs_custom_header_ok
), NULL
);
193 g_signal_connect (G_OBJECT(cancel_btn
), "clicked",
194 G_CALLBACK(prefs_custom_header_cancel
), NULL
);
196 vbox1
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, VSPACING
);
197 gtk_widget_show (vbox1
);
198 gtk_box_pack_start (GTK_BOX (vbox
), vbox1
, TRUE
, TRUE
, 0);
199 gtk_container_set_border_width (GTK_CONTAINER (vbox1
), 2);
201 table1
= gtk_grid_new();
202 gtk_widget_show (table1
);
203 gtk_box_pack_start (GTK_BOX (vbox1
), table1
,
205 gtk_grid_set_row_spacing(GTK_GRID(table1
), 8);
206 gtk_grid_set_column_spacing(GTK_GRID(table1
), 8);
208 hdr_label
= gtk_label_new (_("Header"));
209 gtk_widget_show (hdr_label
);
210 gtk_label_set_xalign(GTK_LABEL (hdr_label
), 0.0);
211 gtk_grid_attach(GTK_GRID(table1
), hdr_label
, 0, 0, 1, 1);
213 hdr_combo
= combobox_text_new(TRUE
, "User-Agent", "Face", "X-Face",
214 "X-Operating-System", NULL
);
215 gtk_grid_attach(GTK_GRID(table1
), hdr_combo
, 0, 1, 1, 1);
217 val_label
= gtk_label_new (_("Value"));
218 gtk_widget_show (val_label
);
219 gtk_label_set_xalign(GTK_LABEL (val_label
), 0.0);
220 gtk_grid_attach(GTK_GRID(table1
), val_label
, 1, 0, 1, 1);
222 val_entry
= gtk_entry_new ();
223 gtk_widget_show (val_entry
);
224 gtk_grid_attach(GTK_GRID(table1
), val_entry
, 1, 1, 1, 1);
225 gtk_widget_set_hexpand(val_entry
, TRUE
);
226 gtk_widget_set_halign(val_entry
, GTK_ALIGN_FILL
);
228 val_btn
= gtkut_get_browse_file_btn(_("Bro_wse"));
229 gtk_widget_show (val_btn
);
230 gtk_grid_attach(GTK_GRID(table1
), val_btn
, 2, 1, 1, 1);
231 g_signal_connect (G_OBJECT (val_btn
), "clicked",
232 G_CALLBACK (prefs_custom_header_val_from_file_cb
),
237 reg_hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
238 gtk_widget_show (reg_hbox
);
239 gtk_box_pack_start (GTK_BOX (vbox1
), reg_hbox
, FALSE
, FALSE
, 0);
241 arrow
= gtk_image_new_from_icon_name("pan-down-symbolic", GTK_ICON_SIZE_MENU
);
242 gtk_widget_show (arrow
);
243 gtk_box_pack_start (GTK_BOX (reg_hbox
), arrow
, FALSE
, FALSE
, 0);
245 btn_hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
246 gtk_widget_show (btn_hbox
);
247 gtk_box_pack_start (GTK_BOX (reg_hbox
), btn_hbox
, FALSE
, FALSE
, 0);
249 add_btn
= gtkut_stock_button("list-add", _("_Add"));
250 gtk_widget_show (add_btn
);
251 gtk_box_pack_start (GTK_BOX (btn_hbox
), add_btn
, FALSE
, TRUE
, 0);
252 g_signal_connect (G_OBJECT (add_btn
), "clicked",
253 G_CALLBACK (prefs_custom_header_add_cb
),
256 del_btn
= gtkut_stock_button("edit-delete", _("D_elete"));
257 gtk_widget_show (del_btn
);
258 gtk_box_pack_start (GTK_BOX (btn_hbox
), del_btn
, FALSE
, TRUE
, 0);
259 g_signal_connect (G_OBJECT (del_btn
), "clicked",
260 G_CALLBACK (prefs_custom_header_delete_cb
),
264 ch_hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 8);
265 gtk_widget_show (ch_hbox
);
266 gtk_box_pack_start (GTK_BOX (vbox1
), ch_hbox
, TRUE
, TRUE
, 0);
268 ch_scrolledwin
= gtk_scrolled_window_new (NULL
, NULL
);
269 gtk_widget_show (ch_scrolledwin
);
270 gtk_box_pack_start (GTK_BOX (ch_hbox
), ch_scrolledwin
, TRUE
, TRUE
, 0);
271 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (ch_scrolledwin
),
272 GTK_POLICY_AUTOMATIC
,
273 GTK_POLICY_AUTOMATIC
);
275 list_view
= prefs_custom_header_list_view_create();
276 gtk_widget_show (list_view
);
277 gtk_container_add (GTK_CONTAINER (ch_scrolledwin
), list_view
);
279 btn_vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 8);
280 gtk_widget_show (btn_vbox
);
281 gtk_box_pack_start (GTK_BOX (ch_hbox
), btn_vbox
, FALSE
, FALSE
, 0);
283 up_btn
= gtkut_stock_button("go-up", _("_Up"));
284 gtk_widget_show (up_btn
);
285 gtk_box_pack_start (GTK_BOX (btn_vbox
), up_btn
, FALSE
, FALSE
, 0);
286 g_signal_connect (G_OBJECT (up_btn
), "clicked",
287 G_CALLBACK (prefs_custom_header_up
), NULL
);
289 down_btn
= gtkut_stock_button("go-down", _("_Down"));
290 gtk_widget_show (down_btn
);
291 gtk_box_pack_start (GTK_BOX (btn_vbox
), down_btn
, FALSE
, FALSE
, 0);
292 g_signal_connect (G_OBJECT (down_btn
), "clicked",
293 G_CALLBACK (prefs_custom_header_down
), NULL
);
295 preview
= gtk_image_new ();
296 gtk_widget_show (preview
);
297 gtk_box_pack_start (GTK_BOX (btn_vbox
), preview
, FALSE
, FALSE
, 0);
299 gtk_widget_show_all(window
);
301 customhdr
.window
= window
;
302 customhdr
.ok_btn
= ok_btn
;
303 customhdr
.cancel_btn
= cancel_btn
;
304 customhdr
.preview
= preview
;
306 customhdr
.hdr_combo
= hdr_combo
;
307 customhdr
.hdr_entry
= gtk_bin_get_child(GTK_BIN((hdr_combo
)));
308 customhdr
.val_entry
= val_entry
;
310 customhdr
.list_view
= list_view
;
313 void prefs_custom_header_read_config(PrefsAccount
*ac
)
317 gchar buf
[PREFSBUFSIZE
];
320 debug_print("Reading custom header configuration...\n");
322 rcpath
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
323 CUSTOM_HEADER_RC
, NULL
);
324 if ((fp
= claws_fopen(rcpath
, "rb")) == NULL
) {
325 if (ENOENT
!= errno
) FILE_OP_ERROR(rcpath
, "claws_fopen");
327 ac
->customhdr_list
= NULL
;
332 /* remove all previous headers list */
333 while (ac
->customhdr_list
!= NULL
) {
334 ch
= (CustomHeader
*)ac
->customhdr_list
->data
;
335 ac
->customhdr_list
= g_slist_remove(ac
->customhdr_list
, ch
);
336 custom_header_free(ch
);
339 while (claws_fgets(buf
, sizeof(buf
), fp
) != NULL
) {
340 ch
= custom_header_read_str(buf
);
342 if (ch
->account_id
== ac
->account_id
) {
344 g_slist_append(ac
->customhdr_list
, ch
);
346 custom_header_free(ch
);
353 static void prefs_custom_header_write_config(PrefsAccount
*ac
)
358 gchar buf
[PREFSBUFSIZE
];
362 GSList
*all_hdrs
= NULL
;
364 debug_print("Writing custom header configuration...\n");
366 rcpath
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
367 CUSTOM_HEADER_RC
, NULL
);
369 if ((fp
= claws_fopen(rcpath
, "rb")) == NULL
) {
370 if (ENOENT
!= errno
) FILE_OP_ERROR(rcpath
, "claws_fopen");
374 while (claws_fgets(buf
, sizeof(buf
), fp
) != NULL
) {
375 ch
= custom_header_read_str(buf
);
377 if (ch
->account_id
!= ac
->account_id
)
379 g_slist_append(all_hdrs
, ch
);
381 custom_header_free(ch
);
388 if ((pfile
= prefs_write_open(rcpath
)) == NULL
) {
389 g_warning("failed to write configuration to file");
394 for (cur
= all_hdrs
; cur
!= NULL
; cur
= cur
->next
) {
395 CustomHeader
*hdr
= (CustomHeader
*)cur
->data
;
398 chstr
= custom_header_get_str(hdr
);
399 if (claws_fputs(chstr
, pfile
->fp
) == EOF
||
400 claws_fputc('\n', pfile
->fp
) == EOF
) {
401 FILE_OP_ERROR(rcpath
, "claws_fputs || claws_fputc");
402 prefs_file_close_revert(pfile
);
410 for (cur
= ac
->customhdr_list
; cur
!= NULL
; cur
= cur
->next
) {
411 CustomHeader
*hdr
= (CustomHeader
*)cur
->data
;
414 chstr
= custom_header_get_str(hdr
);
415 if (claws_fputs(chstr
, pfile
->fp
) == EOF
||
416 claws_fputc('\n', pfile
->fp
) == EOF
) {
417 FILE_OP_ERROR(rcpath
, "claws_fputs || claws_fputc");
418 prefs_file_close_revert(pfile
);
428 while (all_hdrs
!= NULL
) {
429 ch
= (CustomHeader
*)all_hdrs
->data
;
430 all_hdrs
= g_slist_remove(all_hdrs
, ch
);
431 custom_header_free(ch
);
434 if (prefs_file_close(pfile
) < 0) {
435 g_warning("failed to write configuration to file");
440 static void prefs_custom_header_set_dialog(PrefsAccount
*ac
)
445 store
= GTK_LIST_STORE(gtk_tree_view_get_model
446 (GTK_TREE_VIEW(customhdr
.list_view
)));
447 gtk_list_store_clear(store
);
449 for (cur
= ac
->customhdr_list
; cur
!= NULL
; cur
= cur
->next
) {
450 CustomHeader
*ch
= (CustomHeader
*)cur
->data
;
453 ch_str
= g_strdup_printf("%s: %s", ch
->name
,
454 ch
->value
? ch
->value
: "");
456 prefs_custom_header_list_view_insert_header
457 (customhdr
.list_view
, NULL
, ch_str
, ch
);
463 static void prefs_custom_header_set_list(PrefsAccount
*ac
)
469 g_slist_free(ac
->customhdr_list
);
470 ac
->customhdr_list
= NULL
;
472 store
= GTK_LIST_STORE(gtk_tree_view_get_model
473 (GTK_TREE_VIEW(customhdr
.list_view
)));
475 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store
), &iter
)) {
477 gtk_tree_model_get(GTK_TREE_MODEL(store
), &iter
,
480 ac
->customhdr_list
= g_slist_append(ac
->customhdr_list
, ch
);
481 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store
),
486 static void prefs_custom_header_list_view_set_row(PrefsAccount
*ac
)
489 const gchar
*entry_text
;
492 entry_text
= gtk_entry_get_text(GTK_ENTRY(customhdr
.hdr_entry
));
493 if (entry_text
[0] == '\0') {
494 alertpanel_error(_("Header name is not set."));
498 while (*entry_text
&&
499 (*entry_text
== '\n' || *entry_text
== '\r' ||
500 *entry_text
== '\t' || *entry_text
== ' '))
503 if (strchr(entry_text
, ':') != NULL
) {
504 alertpanel_error(_("A colon (:) is not allowed in a custom header."));
508 if (!custom_header_is_allowed(entry_text
)) {
509 alertpanel_error(_("This Header name is not allowed as a custom header."));
513 ch
= g_new0(CustomHeader
, 1);
515 ch
->account_id
= ac
->account_id
;
517 ch
->name
= g_strdup(entry_text
);
518 unfold_line(ch
->name
);
519 g_strstrip(ch
->name
);
520 gtk_entry_set_text(GTK_ENTRY(customhdr
.hdr_entry
), ch
->name
);
522 entry_text
= gtk_entry_get_text(GTK_ENTRY(customhdr
.val_entry
));
523 while (*entry_text
&&
524 (*entry_text
== '\n' || *entry_text
== '\r' ||
525 *entry_text
== '\t' || *entry_text
== ' '))
528 if (entry_text
[0] != '\0') {
529 ch
->value
= g_strdup(entry_text
);
530 unfold_line(ch
->value
);
531 g_strstrip(ch
->value
);
532 gtk_entry_set_text(GTK_ENTRY(customhdr
.val_entry
), ch
->value
);
535 ch_str
= g_strdup_printf("%s: %s", ch
->name
,
536 ch
->value
? ch
->value
: "");
538 prefs_custom_header_list_view_insert_header
539 (customhdr
.list_view
, NULL
, ch_str
, ch
);
543 prefs_custom_header_set_list(cur_ac
);
547 #define B64_LINE_SIZE 57
548 #define B64_BUFFSIZE 77
549 static void prefs_custom_header_val_from_file_cb(void)
551 gchar
*filename
= NULL
;
552 gchar
*contents
= NULL
;
553 const gchar
*hdr
= gtk_entry_get_text(GTK_ENTRY(customhdr
.hdr_entry
));
555 if (!strcmp(hdr
, "Face"))
556 filename
= filesel_select_file_open(_("Choose a PNG file"), NULL
);
557 else if (!strcmp(hdr
, "X-Face"))
558 filename
= filesel_select_file_open(_("Choose an XBM file"), NULL
);
560 filename
= filesel_select_file_open(_("Choose a text file"), NULL
);
562 if (!strcmp(hdr
, "Face") || !strcmp(hdr
, "X-Face")) {
563 if (filename
&& is_file_exist(filename
)) {
566 gchar inbuf
[B64_LINE_SIZE
], *outbuf
;
569 GdkPixbufFormat
*format
= gdk_pixbuf_get_file_info(
572 if (format
== NULL
) {
573 alertpanel_error(_("This file isn't an image."));
577 if (w
!= 48 || h
!= 48) {
578 alertpanel_error(_("The chosen image isn't the correct size (48x48)."));
582 if (!strcmp(hdr
, "Face")) {
583 if (get_file_size(filename
) > 725) {
584 alertpanel_error(_("The image is too big; it must be maximum 725 bytes."));
588 if (g_ascii_strcasecmp("png", gdk_pixbuf_format_get_name(format
))) {
589 alertpanel_error(_("The image isn't in the correct format (PNG)."));
590 g_print("%s\n", gdk_pixbuf_format_get_name(format
));
594 } else if (!strcmp(hdr
, "X-Face")) {
595 gchar
*tmp
= NULL
, *cmd
= NULL
;
597 if (g_ascii_strcasecmp("xbm", gdk_pixbuf_format_get_name(format
))) {
598 alertpanel_error(_("The image isn't in the correct format (XBM)."));
599 g_print("%s\n", gdk_pixbuf_format_get_name(format
));
603 cmd
= g_strdup_printf("compface %s", filename
);
604 tmp
= get_command_output(cmd
);
606 if (tmp
== NULL
|| *tmp
== '\0') {
607 alertpanel_error(_("Couldn't call `compface`. Make sure it's in your $PATH."));
612 if (strstr(tmp
, "compface:")) {
613 alertpanel_error(_("Compface error: %s"), tmp
);
623 if (tmp
[i
] == '\r' || tmp
[i
] == '\n') {
627 contents
= g_strdup_printf("%s%c",tmp2
?tmp2
:"", tmp
[i
]);
635 fp
= claws_fopen(filename
, "rb");
641 while ((len
= claws_fread(inbuf
, sizeof(gchar
),
644 outbuf
= g_base64_encode(inbuf
, B64_LINE_SIZE
);
647 contents
= g_strconcat(tmp
?tmp
:"",outbuf
, NULL
);
651 if (len
> 0 && claws_feof(fp
)) {
653 outbuf
= g_base64_encode(inbuf
, len
);
654 contents
= g_strconcat(tmp
?tmp
:"",outbuf
, NULL
);
664 contents
= file_read_to_str(filename
);
665 if (strchr(contents
, '\n') || strchr(contents
,'\r')) {
666 alertpanel_error(_("This file contains newlines."));
673 if (contents
&& strlen(contents
))
674 gtk_entry_set_text(GTK_ENTRY(customhdr
.val_entry
), contents
);
680 static void prefs_custom_header_add_cb(void)
682 prefs_custom_header_list_view_set_row(cur_ac
);
685 static void prefs_custom_header_delete_cb(void)
691 if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection
692 (GTK_TREE_VIEW(customhdr
.list_view
)),
696 if (alertpanel(_("Delete header"),
697 _("Do you really want to delete this header?"),
698 NULL
, _("_Cancel"), "edit-delete", _("_Delete"), NULL
, NULL
,
699 ALERTFOCUS_FIRST
) != G_ALERTALTERNATE
)
702 gtk_tree_model_get(model
, &sel
,
705 gtk_list_store_remove(GTK_LIST_STORE(model
), &sel
);
707 cur_ac
->customhdr_list
= g_slist_remove(cur_ac
->customhdr_list
, ch
);
709 custom_header_free(ch
);
712 static void prefs_custom_header_up(void)
714 GtkTreePath
*prev
, *sel
;
716 GtkListStore
*store
= NULL
;
717 GtkTreeModel
*model
= NULL
;
720 if (!gtk_tree_selection_get_selected
721 (gtk_tree_view_get_selection
722 (GTK_TREE_VIEW(customhdr
.list_view
)),
726 store
= (GtkListStore
*)model
;
727 sel
= gtk_tree_model_get_path(GTK_TREE_MODEL(store
), &isel
);
731 /* no move if we're at row 0... */
732 prev
= gtk_tree_path_copy(sel
);
733 if (!gtk_tree_path_prev(prev
)) {
734 gtk_tree_path_free(prev
);
735 gtk_tree_path_free(sel
);
739 gtk_tree_model_get_iter(GTK_TREE_MODEL(store
),
741 gtk_tree_path_free(sel
);
742 gtk_tree_path_free(prev
);
744 gtk_list_store_swap(store
, &iprev
, &isel
);
745 prefs_custom_header_set_list(cur_ac
);
748 static void prefs_custom_header_down(void)
750 GtkListStore
*store
= NULL
;
751 GtkTreeModel
*model
= NULL
;
752 GtkTreeIter next
, sel
;
754 if (!gtk_tree_selection_get_selected
755 (gtk_tree_view_get_selection
756 (GTK_TREE_VIEW(customhdr
.list_view
)),
760 store
= (GtkListStore
*)model
;
762 if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(store
), &next
))
765 gtk_list_store_swap(store
, &next
, &sel
);
766 prefs_custom_header_set_list(cur_ac
);
769 static gboolean
prefs_custom_header_key_pressed(GtkWidget
*widget
,
773 if (event
&& event
->keyval
== GDK_KEY_Escape
)
774 prefs_custom_header_cancel();
778 static void prefs_custom_header_ok(void)
780 prefs_custom_header_write_config(cur_ac
);
781 gtk_widget_hide(customhdr
.window
);
782 gtk_window_set_modal(GTK_WINDOW(customhdr
.window
), FALSE
);
785 static void prefs_custom_header_cancel(void)
787 prefs_custom_header_read_config(cur_ac
);
788 gtk_widget_hide(customhdr
.window
);
789 gtk_window_set_modal(GTK_WINDOW(customhdr
.window
), FALSE
);
792 static gint
prefs_custom_header_deleted(GtkWidget
*widget
, GdkEventAny
*event
,
795 prefs_custom_header_cancel();
799 static GtkListStore
* prefs_custom_header_create_data_store(void)
801 return gtk_list_store_new(N_CUSTHDR_COLUMNS
,
807 static void prefs_custom_header_list_view_insert_header(GtkWidget
*list_view
,
808 GtkTreeIter
*row_iter
,
813 GtkListStore
*list_store
= GTK_LIST_STORE(gtk_tree_view_get_model
814 (GTK_TREE_VIEW(list_view
)));
816 if (row_iter
== NULL
) {
818 gtk_list_store_append(list_store
, &iter
);
819 gtk_list_store_set(list_store
, &iter
,
820 CUSTHDR_STRING
, header
,
824 /* change existing */
825 CustomHeader
*old_data
;
827 gtk_tree_model_get(GTK_TREE_MODEL(list_store
), row_iter
,
828 CUSTHDR_DATA
, &old_data
,
831 custom_header_free(old_data
);
833 gtk_list_store_set(list_store
, row_iter
,
834 CUSTHDR_STRING
, header
,
840 static GtkWidget
*prefs_custom_header_list_view_create(void)
842 GtkTreeView
*list_view
;
843 GtkTreeSelection
*selector
;
846 model
= GTK_TREE_MODEL(prefs_custom_header_create_data_store());
847 list_view
= GTK_TREE_VIEW(gtk_tree_view_new_with_model(model
));
848 g_object_unref(model
);
850 gtk_tree_view_set_rules_hint(list_view
, prefs_common
.use_stripes_everywhere
);
851 gtk_tree_view_set_reorderable(list_view
, TRUE
);
853 selector
= gtk_tree_view_get_selection(list_view
);
854 gtk_tree_selection_set_mode(selector
, GTK_SELECTION_BROWSE
);
855 gtk_tree_selection_set_select_function(selector
, prefs_custom_header_selected
,
858 /* create the columns */
859 prefs_custom_header_create_list_view_columns(GTK_WIDGET(list_view
));
861 return GTK_WIDGET(list_view
);
864 static void prefs_custom_header_create_list_view_columns(GtkWidget
*list_view
)
866 GtkTreeViewColumn
*column
;
867 GtkCellRenderer
*renderer
;
869 renderer
= gtk_cell_renderer_text_new();
870 column
= gtk_tree_view_column_new_with_attributes
871 (_("Current custom headers"),
873 "text", CUSTHDR_STRING
,
875 gtk_tree_view_append_column(GTK_TREE_VIEW(list_view
), column
);
878 #define ENTRY_SET_TEXT(entry, str) \
879 gtk_entry_set_text(GTK_ENTRY(entry), str ? str : "")
881 static gboolean
prefs_custom_header_selected(GtkTreeSelection
*selector
,
884 gboolean currently_selected
,
891 CustomHeader default_ch
= { 0, "", NULL
};
893 if (currently_selected
)
896 if (!gtk_tree_model_get_iter(model
, &iter
, path
))
899 gtk_tree_model_get(model
, &iter
,
903 if (!ch
) ch
= &default_ch
;
905 ENTRY_SET_TEXT(customhdr
.hdr_entry
, ch
->name
);
906 ENTRY_SET_TEXT(customhdr
.val_entry
, ch
->value
);
907 if (!g_strcmp0("Face",ch
->name
) && ch
->value
!= NULL
) {
908 preview
= GTK_IMAGE(face_get_from_header (ch
->value
));
909 pixbuf
= gtk_image_get_pixbuf(preview
);
910 gtk_image_set_from_pixbuf (GTK_IMAGE(customhdr
.preview
), pixbuf
);
911 gtk_widget_show(customhdr
.preview
);
912 g_object_ref_sink (G_OBJECT(preview
));
915 else if (!g_strcmp0("X-Face", ch
->name
) && ch
->value
!= NULL
) {
916 preview
= GTK_IMAGE(xface_get_from_header(ch
->value
));
917 pixbuf
= gtk_image_get_pixbuf(preview
);
918 gtk_image_set_from_pixbuf (GTK_IMAGE(customhdr
.preview
), pixbuf
);
919 gtk_widget_show(customhdr
.preview
);
920 g_object_ref_sink (G_OBJECT(preview
));
924 gtk_widget_hide(customhdr
.preview
);
929 #undef ENTRY_SET_TEXT