2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2024 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_account.h"
39 #include "mainwindow.h"
40 #include "foldersel.h"
41 #include "manage_window.h"
42 #include "customheader.h"
46 #include "alertpanel.h"
49 #include "file-utils.h"
52 CUSTHDR_STRING
, /*!< display string managed by list store */
53 CUSTHDR_DATA
, /*!< string managed by us */
57 static struct CustomHdr
{
61 GtkWidget
*cancel_btn
;
70 /* widget creating functions */
71 static void prefs_custom_header_create (void);
73 static void prefs_custom_header_set_dialog (PrefsAccount
*ac
);
74 static void prefs_custom_header_set_list (PrefsAccount
*ac
);
75 static void prefs_custom_header_list_view_set_row (PrefsAccount
*ac
);
77 /* callback functions */
78 static void prefs_custom_header_add_cb (void);
79 static void prefs_custom_header_val_from_file_cb(void);
80 static void prefs_custom_header_delete_cb (void);
81 static void prefs_custom_header_up (void);
82 static void prefs_custom_header_down (void);
84 static gboolean
prefs_custom_header_key_pressed (GtkWidget
*widget
,
87 static void prefs_custom_header_ok (void);
88 static void prefs_custom_header_cancel (void);
89 static gint
prefs_custom_header_deleted (GtkWidget
*widget
,
93 static GtkListStore
* prefs_custom_header_create_data_store (void);
95 static void prefs_custom_header_list_view_insert_header (GtkWidget
*list_view
,
96 GtkTreeIter
*row_iter
,
100 static GtkWidget
*prefs_custom_header_list_view_create (void);
102 static void prefs_custom_header_create_list_view_columns (GtkWidget
*list_view
);
104 static gboolean
prefs_custom_header_selected (GtkTreeSelection
*selector
,
107 gboolean currently_selected
,
111 static PrefsAccount
*cur_ac
= NULL
;
113 void prefs_custom_header_open(PrefsAccount
*ac
)
115 if (!customhdr
.window
) {
116 prefs_custom_header_create();
119 manage_window_set_transient(GTK_WINDOW(customhdr
.window
));
120 gtk_widget_grab_focus(customhdr
.ok_btn
);
122 prefs_custom_header_set_dialog(ac
);
126 gtk_widget_show(customhdr
.window
);
127 gtk_window_set_modal(GTK_WINDOW(customhdr
.window
), TRUE
);
130 static void prefs_custom_header_create(void)
136 GtkWidget
*cancel_btn
;
138 GtkWidget
*confirm_area
;
143 GtkWidget
*hdr_label
;
144 GtkWidget
*hdr_combo
;
145 GtkWidget
*val_label
;
146 GtkWidget
*val_entry
;
157 GtkWidget
*ch_scrolledwin
;
158 GtkWidget
*list_view
;
164 debug_print("Creating custom header setting window...\n");
166 window
= gtkut_window_new(GTK_WINDOW_TOPLEVEL
, "prefs_customheader");
167 gtk_container_set_border_width (GTK_CONTAINER (window
), 8);
168 gtk_window_set_position (GTK_WINDOW (window
), GTK_WIN_POS_CENTER
);
169 gtk_window_set_resizable(GTK_WINDOW (window
), TRUE
);
170 gtk_window_set_type_hint(GTK_WINDOW(window
), GDK_WINDOW_TYPE_HINT_DIALOG
);
172 vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 6);
173 gtk_widget_show (vbox
);
174 gtk_container_add (GTK_CONTAINER (window
), vbox
);
176 gtkut_stock_button_set_create(&confirm_area
, &cancel_btn
, NULL
, _("_Cancel"),
177 &ok_btn
, NULL
, _("_OK"), NULL
, NULL
, NULL
);
178 gtk_widget_show (confirm_area
);
179 gtk_box_pack_end (GTK_BOX(vbox
), confirm_area
, FALSE
, FALSE
, 0);
180 gtk_widget_grab_default (ok_btn
);
182 gtk_window_set_title (GTK_WINDOW(window
), _("Custom header configuration"));
183 MANAGE_WINDOW_SIGNALS_CONNECT (window
);
184 g_signal_connect (G_OBJECT(window
), "delete_event",
185 G_CALLBACK(prefs_custom_header_deleted
),
187 g_signal_connect (G_OBJECT(window
), "key_press_event",
188 G_CALLBACK(prefs_custom_header_key_pressed
),
190 g_signal_connect (G_OBJECT(ok_btn
), "clicked",
191 G_CALLBACK(prefs_custom_header_ok
), NULL
);
192 g_signal_connect (G_OBJECT(cancel_btn
), "clicked",
193 G_CALLBACK(prefs_custom_header_cancel
), NULL
);
195 vbox1
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, VSPACING
);
196 gtk_widget_show (vbox1
);
197 gtk_box_pack_start (GTK_BOX (vbox
), vbox1
, TRUE
, TRUE
, 0);
198 gtk_container_set_border_width (GTK_CONTAINER (vbox1
), 2);
200 table1
= gtk_grid_new();
201 gtk_widget_show (table1
);
202 gtk_box_pack_start (GTK_BOX (vbox1
), table1
,
204 gtk_grid_set_row_spacing(GTK_GRID(table1
), 8);
205 gtk_grid_set_column_spacing(GTK_GRID(table1
), 8);
207 hdr_label
= gtk_label_new (_("Header"));
208 gtk_widget_show (hdr_label
);
209 gtk_label_set_xalign(GTK_LABEL (hdr_label
), 0.0);
210 gtk_grid_attach(GTK_GRID(table1
), hdr_label
, 0, 0, 1, 1);
212 hdr_combo
= combobox_text_new(TRUE
, "User-Agent", "Face", "X-Face",
213 "X-Operating-System", NULL
);
214 gtk_grid_attach(GTK_GRID(table1
), hdr_combo
, 0, 1, 1, 1);
216 val_label
= gtk_label_new (_("Value"));
217 gtk_widget_show (val_label
);
218 gtk_label_set_xalign(GTK_LABEL (val_label
), 0.0);
219 gtk_grid_attach(GTK_GRID(table1
), val_label
, 1, 0, 1, 1);
221 val_entry
= gtk_entry_new ();
222 gtk_widget_show (val_entry
);
223 gtk_grid_attach(GTK_GRID(table1
), val_entry
, 1, 1, 1, 1);
224 gtk_widget_set_hexpand(val_entry
, TRUE
);
225 gtk_widget_set_halign(val_entry
, GTK_ALIGN_FILL
);
227 val_btn
= gtkut_get_browse_file_btn(_("Bro_wse"));
228 gtk_widget_show (val_btn
);
229 gtk_grid_attach(GTK_GRID(table1
), val_btn
, 2, 1, 1, 1);
230 g_signal_connect (G_OBJECT (val_btn
), "clicked",
231 G_CALLBACK (prefs_custom_header_val_from_file_cb
),
236 reg_hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
237 gtk_widget_show (reg_hbox
);
238 gtk_box_pack_start (GTK_BOX (vbox1
), reg_hbox
, FALSE
, FALSE
, 0);
240 arrow
= gtk_image_new_from_icon_name("pan-down-symbolic", GTK_ICON_SIZE_MENU
);
241 gtk_widget_show (arrow
);
242 gtk_box_pack_start (GTK_BOX (reg_hbox
), arrow
, FALSE
, FALSE
, 0);
244 btn_hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
245 gtk_widget_show (btn_hbox
);
246 gtk_box_pack_start (GTK_BOX (reg_hbox
), btn_hbox
, FALSE
, FALSE
, 0);
248 add_btn
= gtkut_stock_button("list-add", _("_Add"));
249 gtk_widget_show (add_btn
);
250 gtk_box_pack_start (GTK_BOX (btn_hbox
), add_btn
, FALSE
, TRUE
, 0);
251 g_signal_connect (G_OBJECT (add_btn
), "clicked",
252 G_CALLBACK (prefs_custom_header_add_cb
),
255 del_btn
= gtkut_stock_button("edit-delete", _("D_elete"));
256 gtk_widget_show (del_btn
);
257 gtk_box_pack_start (GTK_BOX (btn_hbox
), del_btn
, FALSE
, TRUE
, 0);
258 g_signal_connect (G_OBJECT (del_btn
), "clicked",
259 G_CALLBACK (prefs_custom_header_delete_cb
),
263 ch_hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 8);
264 gtk_widget_show (ch_hbox
);
265 gtk_box_pack_start (GTK_BOX (vbox1
), ch_hbox
, TRUE
, TRUE
, 0);
267 ch_scrolledwin
= gtk_scrolled_window_new (NULL
, NULL
);
268 gtk_widget_show (ch_scrolledwin
);
269 gtk_box_pack_start (GTK_BOX (ch_hbox
), ch_scrolledwin
, TRUE
, TRUE
, 0);
270 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (ch_scrolledwin
),
271 GTK_POLICY_AUTOMATIC
,
272 GTK_POLICY_AUTOMATIC
);
274 list_view
= prefs_custom_header_list_view_create();
275 gtk_widget_show (list_view
);
276 gtk_container_add (GTK_CONTAINER (ch_scrolledwin
), list_view
);
278 btn_vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 8);
279 gtk_widget_show (btn_vbox
);
280 gtk_box_pack_start (GTK_BOX (ch_hbox
), btn_vbox
, FALSE
, FALSE
, 0);
282 up_btn
= gtkut_stock_button("go-up", _("_Up"));
283 gtk_widget_show (up_btn
);
284 gtk_box_pack_start (GTK_BOX (btn_vbox
), up_btn
, FALSE
, FALSE
, 0);
285 g_signal_connect (G_OBJECT (up_btn
), "clicked",
286 G_CALLBACK (prefs_custom_header_up
), NULL
);
288 down_btn
= gtkut_stock_button("go-down", _("_Down"));
289 gtk_widget_show (down_btn
);
290 gtk_box_pack_start (GTK_BOX (btn_vbox
), down_btn
, FALSE
, FALSE
, 0);
291 g_signal_connect (G_OBJECT (down_btn
), "clicked",
292 G_CALLBACK (prefs_custom_header_down
), NULL
);
294 preview
= gtk_image_new ();
295 gtk_widget_show (preview
);
296 gtk_box_pack_start (GTK_BOX (btn_vbox
), preview
, FALSE
, FALSE
, 0);
298 gtk_widget_show_all(window
);
300 customhdr
.window
= window
;
301 customhdr
.ok_btn
= ok_btn
;
302 customhdr
.cancel_btn
= cancel_btn
;
303 customhdr
.preview
= preview
;
305 customhdr
.hdr_combo
= hdr_combo
;
306 customhdr
.hdr_entry
= gtk_bin_get_child(GTK_BIN((hdr_combo
)));
307 customhdr
.val_entry
= val_entry
;
309 customhdr
.list_view
= list_view
;
312 void prefs_custom_header_read_config(PrefsAccount
*ac
)
316 gchar buf
[PREFSBUFSIZE
];
319 debug_print("Reading custom header configuration...\n");
321 rcpath
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
322 CUSTOM_HEADER_RC
, NULL
);
323 if ((fp
= claws_fopen(rcpath
, "rb")) == NULL
) {
324 if (ENOENT
!= errno
) FILE_OP_ERROR(rcpath
, "claws_fopen");
326 ac
->customhdr_list
= NULL
;
331 /* remove all previous headers list */
332 while (ac
->customhdr_list
!= NULL
) {
333 ch
= (CustomHeader
*)ac
->customhdr_list
->data
;
334 ac
->customhdr_list
= g_slist_remove(ac
->customhdr_list
, ch
);
335 custom_header_free(ch
);
338 while (claws_fgets(buf
, sizeof(buf
), fp
) != NULL
) {
339 ch
= custom_header_read_str(buf
);
341 if (ch
->account_id
== ac
->account_id
) {
343 g_slist_append(ac
->customhdr_list
, ch
);
345 custom_header_free(ch
);
352 static void prefs_custom_header_write_config(PrefsAccount
*ac
)
357 gchar buf
[PREFSBUFSIZE
];
361 GSList
*all_hdrs
= NULL
;
363 debug_print("Writing custom header configuration...\n");
365 rcpath
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
366 CUSTOM_HEADER_RC
, NULL
);
368 if ((fp
= claws_fopen(rcpath
, "rb")) == NULL
) {
369 if (ENOENT
!= errno
) FILE_OP_ERROR(rcpath
, "claws_fopen");
373 while (claws_fgets(buf
, sizeof(buf
), fp
) != NULL
) {
374 ch
= custom_header_read_str(buf
);
376 if (ch
->account_id
!= ac
->account_id
)
378 g_slist_append(all_hdrs
, ch
);
380 custom_header_free(ch
);
387 if ((pfile
= prefs_write_open(rcpath
)) == NULL
) {
388 g_warning("failed to write configuration to file");
393 for (cur
= all_hdrs
; cur
!= NULL
; cur
= cur
->next
) {
394 CustomHeader
*hdr
= (CustomHeader
*)cur
->data
;
397 chstr
= custom_header_get_str(hdr
);
398 if (claws_fputs(chstr
, pfile
->fp
) == EOF
||
399 claws_fputc('\n', pfile
->fp
) == EOF
) {
400 FILE_OP_ERROR(rcpath
, "claws_fputs || claws_fputc");
401 prefs_file_close_revert(pfile
);
409 for (cur
= ac
->customhdr_list
; cur
!= NULL
; cur
= cur
->next
) {
410 CustomHeader
*hdr
= (CustomHeader
*)cur
->data
;
413 chstr
= custom_header_get_str(hdr
);
414 if (claws_fputs(chstr
, pfile
->fp
) == EOF
||
415 claws_fputc('\n', pfile
->fp
) == EOF
) {
416 FILE_OP_ERROR(rcpath
, "claws_fputs || claws_fputc");
417 prefs_file_close_revert(pfile
);
427 while (all_hdrs
!= NULL
) {
428 ch
= (CustomHeader
*)all_hdrs
->data
;
429 all_hdrs
= g_slist_remove(all_hdrs
, ch
);
430 custom_header_free(ch
);
433 if (prefs_file_close(pfile
) < 0) {
434 g_warning("failed to write configuration to file");
439 static void prefs_custom_header_set_dialog(PrefsAccount
*ac
)
444 store
= GTK_LIST_STORE(gtk_tree_view_get_model
445 (GTK_TREE_VIEW(customhdr
.list_view
)));
446 gtk_list_store_clear(store
);
448 for (cur
= ac
->customhdr_list
; cur
!= NULL
; cur
= cur
->next
) {
449 CustomHeader
*ch
= (CustomHeader
*)cur
->data
;
452 ch_str
= g_strdup_printf("%s: %s", ch
->name
,
453 ch
->value
? ch
->value
: "");
455 prefs_custom_header_list_view_insert_header
456 (customhdr
.list_view
, NULL
, ch_str
, ch
);
462 static void prefs_custom_header_set_list(PrefsAccount
*ac
)
468 g_slist_free(ac
->customhdr_list
);
469 ac
->customhdr_list
= NULL
;
471 store
= GTK_LIST_STORE(gtk_tree_view_get_model
472 (GTK_TREE_VIEW(customhdr
.list_view
)));
474 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store
), &iter
)) {
476 gtk_tree_model_get(GTK_TREE_MODEL(store
), &iter
,
479 ac
->customhdr_list
= g_slist_append(ac
->customhdr_list
, ch
);
480 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store
),
485 static void prefs_custom_header_list_view_set_row(PrefsAccount
*ac
)
488 const gchar
*entry_text
;
491 entry_text
= gtk_entry_get_text(GTK_ENTRY(customhdr
.hdr_entry
));
492 if (entry_text
[0] == '\0') {
493 alertpanel_error(_("Header name is not set."));
497 while (*entry_text
&&
498 (*entry_text
== '\n' || *entry_text
== '\r' ||
499 *entry_text
== '\t' || *entry_text
== ' '))
502 if (strchr(entry_text
, ':') != NULL
) {
503 alertpanel_error(_("A colon (:) is not allowed in a custom header."));
507 if (!custom_header_is_allowed(entry_text
)) {
508 alertpanel_error(_("This Header name is not allowed as a custom header."));
512 ch
= g_new0(CustomHeader
, 1);
514 ch
->account_id
= ac
->account_id
;
516 ch
->name
= g_strdup(entry_text
);
517 unfold_line(ch
->name
);
518 g_strstrip(ch
->name
);
519 gtk_entry_set_text(GTK_ENTRY(customhdr
.hdr_entry
), ch
->name
);
521 entry_text
= gtk_entry_get_text(GTK_ENTRY(customhdr
.val_entry
));
522 while (*entry_text
&&
523 (*entry_text
== '\n' || *entry_text
== '\r' ||
524 *entry_text
== '\t' || *entry_text
== ' '))
527 if (entry_text
[0] != '\0') {
528 ch
->value
= g_strdup(entry_text
);
529 unfold_line(ch
->value
);
530 g_strstrip(ch
->value
);
531 gtk_entry_set_text(GTK_ENTRY(customhdr
.val_entry
), ch
->value
);
534 ch_str
= g_strdup_printf("%s: %s", ch
->name
,
535 ch
->value
? ch
->value
: "");
537 prefs_custom_header_list_view_insert_header
538 (customhdr
.list_view
, NULL
, ch_str
, ch
);
542 prefs_custom_header_set_list(cur_ac
);
546 static void prefs_custom_header_val_from_file_cb(void)
548 gchar
*filename
= NULL
;
549 gchar
*contents
= NULL
;
550 const gchar
*hdr
= gtk_entry_get_text(GTK_ENTRY(customhdr
.hdr_entry
));
552 if (!strcmp(hdr
, "Face"))
553 filename
= filesel_select_file_open(_("Choose a PNG file"), NULL
);
554 else if (!strcmp(hdr
, "X-Face"))
555 filename
= filesel_select_file_open(_("Choose an XBM file"), NULL
);
557 filename
= filesel_select_file_open(_("Choose a text file"), NULL
);
559 if (!strcmp(hdr
, "Face") || !strcmp(hdr
, "X-Face")) {
560 if (filename
&& is_file_exist(filename
)) {
563 gchar inbuf
[B64_LINE_SIZE
], *outbuf
;
566 GdkPixbufFormat
*format
= gdk_pixbuf_get_file_info(
569 if (format
== NULL
) {
570 alertpanel_error(_("This file isn't an image."));
574 if (w
!= 48 || h
!= 48) {
575 alertpanel_error(_("The chosen image isn't the correct size (48x48)."));
579 if (!strcmp(hdr
, "Face")) {
580 if (get_file_size(filename
) > 725) {
581 alertpanel_error(_("The image is too big; it must be maximum 725 bytes."));
585 if (g_ascii_strcasecmp("png", gdk_pixbuf_format_get_name(format
))) {
586 alertpanel_error(_("The image isn't in the correct format (PNG)."));
587 g_print("%s\n", gdk_pixbuf_format_get_name(format
));
591 } else if (!strcmp(hdr
, "X-Face")) {
592 gchar
*tmp
= NULL
, *cmd
= NULL
;
594 if (g_ascii_strcasecmp("xbm", gdk_pixbuf_format_get_name(format
))) {
595 alertpanel_error(_("The image isn't in the correct format (XBM)."));
596 g_print("%s\n", gdk_pixbuf_format_get_name(format
));
600 cmd
= g_strdup_printf("compface %s", filename
);
601 tmp
= get_command_output(cmd
);
603 if (tmp
== NULL
|| *tmp
== '\0') {
604 alertpanel_error(_("Couldn't call `compface`. Make sure it's in your $PATH."));
609 if (strstr(tmp
, "compface:")) {
610 alertpanel_error(_("Compface error: %s"), tmp
);
620 if (tmp
[i
] == '\r' || tmp
[i
] == '\n') {
624 contents
= g_strdup_printf("%s%c",tmp2
?tmp2
:"", tmp
[i
]);
632 fp
= claws_fopen(filename
, "rb");
638 while ((len
= claws_fread(inbuf
, sizeof(gchar
),
641 outbuf
= g_base64_encode(inbuf
, B64_LINE_SIZE
);
644 contents
= g_strconcat(tmp
?tmp
:"",outbuf
, NULL
);
648 if (len
> 0 && claws_feof(fp
)) {
650 outbuf
= g_base64_encode(inbuf
, len
);
651 contents
= g_strconcat(tmp
?tmp
:"",outbuf
, NULL
);
661 contents
= file_read_to_str(filename
);
662 if (strchr(contents
, '\n') || strchr(contents
,'\r')) {
663 alertpanel_error(_("This file contains newlines."));
670 if (contents
&& strlen(contents
))
671 gtk_entry_set_text(GTK_ENTRY(customhdr
.val_entry
), contents
);
677 static void prefs_custom_header_add_cb(void)
679 prefs_custom_header_list_view_set_row(cur_ac
);
682 static void prefs_custom_header_delete_cb(void)
688 if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection
689 (GTK_TREE_VIEW(customhdr
.list_view
)),
693 if (alertpanel(_("Delete header"),
694 _("Do you really want to delete this header?"),
695 NULL
, _("_Cancel"), "edit-delete", _("_Delete"), NULL
, NULL
,
696 ALERTFOCUS_FIRST
) != G_ALERTALTERNATE
)
699 gtk_tree_model_get(model
, &sel
,
702 gtk_list_store_remove(GTK_LIST_STORE(model
), &sel
);
704 cur_ac
->customhdr_list
= g_slist_remove(cur_ac
->customhdr_list
, ch
);
706 custom_header_free(ch
);
709 static void prefs_custom_header_up(void)
711 GtkTreePath
*prev
, *sel
;
713 GtkListStore
*store
= NULL
;
714 GtkTreeModel
*model
= NULL
;
717 if (!gtk_tree_selection_get_selected
718 (gtk_tree_view_get_selection
719 (GTK_TREE_VIEW(customhdr
.list_view
)),
723 store
= (GtkListStore
*)model
;
724 sel
= gtk_tree_model_get_path(GTK_TREE_MODEL(store
), &isel
);
728 /* no move if we're at row 0... */
729 prev
= gtk_tree_path_copy(sel
);
730 if (!gtk_tree_path_prev(prev
)) {
731 gtk_tree_path_free(prev
);
732 gtk_tree_path_free(sel
);
736 gtk_tree_model_get_iter(GTK_TREE_MODEL(store
),
738 gtk_tree_path_free(sel
);
739 gtk_tree_path_free(prev
);
741 gtk_list_store_swap(store
, &iprev
, &isel
);
742 prefs_custom_header_set_list(cur_ac
);
745 static void prefs_custom_header_down(void)
747 GtkListStore
*store
= NULL
;
748 GtkTreeModel
*model
= NULL
;
749 GtkTreeIter next
, sel
;
751 if (!gtk_tree_selection_get_selected
752 (gtk_tree_view_get_selection
753 (GTK_TREE_VIEW(customhdr
.list_view
)),
757 store
= (GtkListStore
*)model
;
759 if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(store
), &next
))
762 gtk_list_store_swap(store
, &next
, &sel
);
763 prefs_custom_header_set_list(cur_ac
);
766 static gboolean
prefs_custom_header_key_pressed(GtkWidget
*widget
,
770 if (event
&& event
->keyval
== GDK_KEY_Escape
)
771 prefs_custom_header_cancel();
775 static void prefs_custom_header_ok(void)
777 prefs_custom_header_write_config(cur_ac
);
778 gtk_widget_hide(customhdr
.window
);
779 gtk_window_set_modal(GTK_WINDOW(customhdr
.window
), FALSE
);
782 static void prefs_custom_header_cancel(void)
784 prefs_custom_header_read_config(cur_ac
);
785 gtk_widget_hide(customhdr
.window
);
786 gtk_window_set_modal(GTK_WINDOW(customhdr
.window
), FALSE
);
789 static gint
prefs_custom_header_deleted(GtkWidget
*widget
, GdkEventAny
*event
,
792 prefs_custom_header_cancel();
796 static GtkListStore
* prefs_custom_header_create_data_store(void)
798 return gtk_list_store_new(N_CUSTHDR_COLUMNS
,
804 static void prefs_custom_header_list_view_insert_header(GtkWidget
*list_view
,
805 GtkTreeIter
*row_iter
,
810 GtkListStore
*list_store
= GTK_LIST_STORE(gtk_tree_view_get_model
811 (GTK_TREE_VIEW(list_view
)));
813 if (row_iter
== NULL
) {
815 gtk_list_store_append(list_store
, &iter
);
816 gtk_list_store_set(list_store
, &iter
,
817 CUSTHDR_STRING
, header
,
821 /* change existing */
822 CustomHeader
*old_data
;
824 gtk_tree_model_get(GTK_TREE_MODEL(list_store
), row_iter
,
825 CUSTHDR_DATA
, &old_data
,
828 custom_header_free(old_data
);
830 gtk_list_store_set(list_store
, row_iter
,
831 CUSTHDR_STRING
, header
,
837 static GtkWidget
*prefs_custom_header_list_view_create(void)
839 GtkTreeView
*list_view
;
840 GtkTreeSelection
*selector
;
843 model
= GTK_TREE_MODEL(prefs_custom_header_create_data_store());
844 list_view
= GTK_TREE_VIEW(gtk_tree_view_new_with_model(model
));
845 g_object_unref(model
);
847 gtk_tree_view_set_reorderable(list_view
, TRUE
);
849 selector
= gtk_tree_view_get_selection(list_view
);
850 gtk_tree_selection_set_mode(selector
, GTK_SELECTION_BROWSE
);
851 gtk_tree_selection_set_select_function(selector
, prefs_custom_header_selected
,
854 /* create the columns */
855 prefs_custom_header_create_list_view_columns(GTK_WIDGET(list_view
));
857 return GTK_WIDGET(list_view
);
860 static void prefs_custom_header_create_list_view_columns(GtkWidget
*list_view
)
862 GtkTreeViewColumn
*column
;
863 GtkCellRenderer
*renderer
;
865 renderer
= gtk_cell_renderer_text_new();
866 column
= gtk_tree_view_column_new_with_attributes
867 (_("Current custom headers"),
869 "text", CUSTHDR_STRING
,
871 gtk_tree_view_append_column(GTK_TREE_VIEW(list_view
), column
);
874 #define ENTRY_SET_TEXT(entry, str) \
875 gtk_entry_set_text(GTK_ENTRY(entry), str ? str : "")
877 static gboolean
prefs_custom_header_selected(GtkTreeSelection
*selector
,
880 gboolean currently_selected
,
887 CustomHeader default_ch
= { 0, "", NULL
};
889 if (currently_selected
)
892 if (!gtk_tree_model_get_iter(model
, &iter
, path
))
895 gtk_tree_model_get(model
, &iter
,
899 if (!ch
) ch
= &default_ch
;
901 ENTRY_SET_TEXT(customhdr
.hdr_entry
, ch
->name
);
902 ENTRY_SET_TEXT(customhdr
.val_entry
, ch
->value
);
903 if (!g_strcmp0("Face",ch
->name
) && ch
->value
!= NULL
) {
904 preview
= GTK_IMAGE(face_get_from_header (ch
->value
));
905 pixbuf
= gtk_image_get_pixbuf(preview
);
906 gtk_image_set_from_pixbuf (GTK_IMAGE(customhdr
.preview
), pixbuf
);
907 gtk_widget_show(customhdr
.preview
);
908 g_object_ref_sink (G_OBJECT(preview
));
911 else if (!g_strcmp0("X-Face", ch
->name
) && ch
->value
!= NULL
) {
912 preview
= GTK_IMAGE(xface_get_from_header(ch
->value
));
913 pixbuf
= gtk_image_get_pixbuf(preview
);
914 gtk_image_set_from_pixbuf (GTK_IMAGE(customhdr
.preview
), pixbuf
);
915 gtk_widget_show(customhdr
.preview
);
916 g_object_ref_sink (G_OBJECT(preview
));
920 gtk_widget_hide(customhdr
.preview
);
925 #undef ENTRY_SET_TEXT