remove all remaining WIN32 code
[rofl0r-ixchat.git] / src / fe-gtk / setup.c
blobb7baed9ac0a1573c9c2c40b9499be0ee3f13fd3f
1 /* X-Chat
2 * Copyright (C) 2004-2007 Peter Zelezny.
3 */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
11 #include "../common/xchat.h"
12 #include "../common/cfgfiles.h"
13 #include "../common/fe.h"
14 #include "../common/text.h"
15 #include "../common/userlist.h"
16 #include "../common/util.h"
17 #include "../common/xchatc.h"
18 #include "fe-gtk.h"
19 #include "gtkutil.h"
20 #include "maingui.h"
21 #include "palette.h"
22 #include "pixmaps.h"
23 #include "menu.h"
25 #include <gtk/gtkcolorseldialog.h>
26 #include <gtk/gtktable.h>
27 #include <gtk/gtkentry.h>
28 #include <gtk/gtklabel.h>
29 #include <gtk/gtkmisc.h>
30 #include <gtk/gtkhbox.h>
31 #include <gtk/gtkvbox.h>
32 #include <gtk/gtkalignment.h>
33 #include <gtk/gtknotebook.h>
34 #include <gtk/gtkframe.h>
35 #include <gtk/gtkfontsel.h>
36 #include <gtk/gtkcheckbutton.h>
37 #include <gtk/gtkscrolledwindow.h>
38 #include <gtk/gtkspinbutton.h>
39 #include <gtk/gtkstock.h>
40 #include <gtk/gtktreeview.h>
41 #include <gtk/gtkhbbox.h>
42 #include <gtk/gtkhseparator.h>
43 #include <gtk/gtkradiobutton.h>
44 #include <gtk/gtkcombobox.h>
45 #include <gtk/gtkliststore.h>
46 #include <gtk/gtktreestore.h>
47 #include <gtk/gtktreeselection.h>
48 #include <gtk/gtkcellrenderertext.h>
49 #include <gtk/gtkhscale.h>
50 #ifdef USE_GTKSPELL
51 #include <gtk/gtktextview.h>
52 #include <gtkspell/gtkspell.h>
53 #endif
54 #ifdef USE_LIBSEXY
55 #include "sexy-spell-entry.h"
56 #endif
58 GtkStyle *create_input_style (GtkStyle *);
60 #define LABEL_INDENT 12
62 static int last_selected_page = 0;
63 static int last_selected_row = 0; /* sound row */
64 static gboolean color_change;
65 static struct xchatprefs setup_prefs;
66 static GtkWidget *cancel_button;
67 static GtkWidget *font_dialog = NULL;
69 enum
71 ST_END,
72 ST_TOGGLE,
73 ST_TOGGLR,
74 ST_3OGGLE,
75 ST_ENTRY,
76 ST_EFONT,
77 ST_EFILE,
78 ST_EFOLDER,
79 ST_MENU,
80 ST_RADIO,
81 ST_NUMBER,
82 ST_HSCALE,
83 ST_HEADER,
84 ST_LABEL,
85 ST_ALERTHEAD
88 typedef struct
90 int type;
91 char *label;
92 int offset;
93 char *tooltip;
94 char const *const *list;
95 int extra;
96 } setting;
99 static const setting textbox_settings[] =
101 {ST_HEADER, N_("Text Box Appearance"),0,0,0},
102 {ST_EFONT, N_("Font:"), P_OFFSETNL(font_normal), 0, 0, sizeof prefs.font_normal},
103 {ST_EFILE, N_("Background image:"), P_OFFSETNL(background), 0, 0, sizeof prefs.background},
104 {ST_NUMBER, N_("Scrollback lines:"), P_OFFINTNL(max_lines),0,0,100000},
105 {ST_TOGGLE, N_("Colored nick names"), P_OFFINTNL(colorednicks),
106 N_("Give each person on IRC a different color"),0,0},
107 {ST_TOGGLR, N_("Indent nick names"), P_OFFINTNL(indent_nicks),
108 N_("Make nick names right-justified"),0,0},
109 {ST_TOGGLE, N_("Transparent background"), P_OFFINTNL(transparent),0,0,0},
110 {ST_TOGGLR, N_("Show marker line"), P_OFFINTNL(show_marker),
111 N_("Insert a red line after the last read text."),0,0},
112 {ST_HEADER, N_("Transparency Settings"), 0,0,0},
113 {ST_HSCALE, N_("Red:"), P_OFFINTNL(tint_red),0,0,0},
114 {ST_HSCALE, N_("Green:"), P_OFFINTNL(tint_green),0,0,0},
115 {ST_HSCALE, N_("Blue:"), P_OFFINTNL(tint_blue),0,0,0},
117 {ST_HEADER, N_("Time Stamps"),0,0,0},
118 {ST_TOGGLE, N_("Enable time stamps"), P_OFFINTNL(timestamp),0,0,2},
119 {ST_ENTRY, N_("Time stamp format:"), P_OFFSETNL(stamp_format),
120 N_("See strftime manpage for details."),0,sizeof prefs.stamp_format},
122 {ST_END, 0, 0, 0, 0, 0}
125 static const char *const tabcompmenu[] =
127 N_("A-Z"),
128 N_("Last-spoke order"),
129 NULL
132 static const setting inputbox_settings[] =
134 {ST_HEADER, N_("Input box"),0,0,0},
135 {ST_TOGGLE, N_("Use the Text box font and colors"), P_OFFINTNL(style_inputbox),0,0,0},
136 #if defined(USE_GTKSPELL) || defined(USE_LIBSEXY)
137 {ST_TOGGLE, N_("Spell checking"), P_OFFINTNL(gui_input_spell),0,0,0},
138 #endif
140 {ST_HEADER, N_("Nick Completion"),0,0,0},
141 {ST_TOGGLE, N_("Automatic nick completion (without TAB key)"), P_OFFINTNL(nickcompletion),
142 0,0,0},
143 {ST_ENTRY, N_("Nick completion suffix:"), P_OFFSETNL(nick_suffix),0,0,sizeof prefs.nick_suffix},
144 {ST_MENU, N_("Nick completion sorted:"), P_OFFINTNL(completion_sort), 0, tabcompmenu, 0},
146 #if 0 /* obsolete */
147 {ST_HEADER, N_("Input Box Codes"),0,0,0},
148 {ST_TOGGLE, N_("Interpret %nnn as an ASCII value"), P_OFFINTNL(perc_ascii),0,0,0},
149 {ST_TOGGLE, N_("Interpret %C, %B as Color, Bold etc"), P_OFFINTNL(perc_color),0,0,0},
150 #endif
152 {ST_END, 0, 0, 0, 0, 0}
155 /*static const char *const lagmenutext[] =
157 N_("Off"),
158 N_("Graph"),
159 N_("Info text"),
160 N_("Both"),
161 NULL
162 };*/
164 static const char *const ulmenutext[] =
166 N_("A-Z, Ops first"),
167 N_("A-Z"),
168 N_("Z-A, Ops last"),
169 N_("Z-A"),
170 N_("Unsorted"),
171 NULL
174 static const char *const cspos[] =
176 N_("Left (Upper)"),
177 N_("Left (Lower)"),
178 N_("Right (Upper)"),
179 N_("Right (Lower)"),
180 N_("Top"),
181 N_("Bottom"),
182 N_("Hidden"),
183 NULL
186 static const char *const ulpos[] =
188 N_("Left (Upper)"),
189 N_("Left (Lower)"),
190 N_("Right (Upper)"),
191 N_("Right (Lower)"),
192 NULL
195 static const setting userlist_settings[] =
197 {ST_HEADER, N_("User List"),0,0,0},
198 {ST_TOGGLE, N_("Show hostnames in user list"), P_OFFINTNL(showhostname_in_userlist), 0, 0, 0},
199 {ST_TOGGLE, N_("Use the Text box font and colors"), P_OFFINTNL(style_namelistgad),0,0,0},
200 /* {ST_TOGGLE, N_("Resizable user list"), P_OFFINTNL(paned_userlist),0,0,0},*/
201 {ST_MENU, N_("User list sorted by:"), P_OFFINTNL(userlist_sort), 0, ulmenutext, 0},
202 {ST_MENU, N_("Show user list at:"), P_OFFINTNL(gui_ulist_pos), 0, ulpos, 1},
204 {ST_HEADER, N_("Away tracking"),0,0,0},
205 {ST_TOGGLE, N_("Track the Away status of users and mark them in a different color"), P_OFFINTNL(away_track),0,0,2},
206 {ST_NUMBER, N_("On channels smaller than:"), P_OFFINTNL(away_size_max),0,0,10000},
208 {ST_HEADER, N_("Action Upon Double Click"),0,0,0},
209 {ST_ENTRY, N_("Execute command:"), P_OFFSETNL(doubleclickuser), 0, 0, sizeof prefs.doubleclickuser},
211 /* {ST_HEADER, N_("Extra Gadgets"),0,0,0},
212 {ST_MENU, N_("Lag meter:"), P_OFFINTNL(lagometer), 0, lagmenutext, 0},
213 {ST_MENU, N_("Throttle meter:"), P_OFFINTNL(throttlemeter), 0, lagmenutext, 0},*/
215 {ST_END, 0, 0, 0, 0, 0}
218 static const char *const tabwin[] =
220 N_("Windows"),
221 N_("Tabs"),
222 NULL
225 #if 0
226 static const char *const focusnewtabsmenu[] =
228 N_("Never"),
229 N_("Always"),
230 N_("Only requested tabs"),
231 NULL
233 #endif
235 static const char *const swtype[] =
237 N_("Tabs"), /* 0 tabs */
238 "", /* 1 reserved */
239 N_("Tree"), /* 2 tree */
240 NULL
243 static const setting tabs_settings[] =
245 /*{ST_HEADER, N_("Channel Switcher"),0,0,0},*/
246 {ST_RADIO, N_("Switcher type:"),P_OFFINTNL(tab_layout), 0, swtype, 0},
247 {ST_TOGGLE, N_("Open an extra tab for server messages"), P_OFFINTNL(use_server_tab), 0, 0, 0},
248 {ST_TOGGLE, N_("Open an extra tab for server notices"), P_OFFINTNL(notices_tabs), 0, 0, 0},
249 {ST_TOGGLE, N_("Open a new tab when you receive a private message"), P_OFFINTNL(autodialog), 0, 0, 0},
250 {ST_TOGGLE, N_("Sort tabs in alphabetical order"), P_OFFINTNL(tab_sort), 0, 0, 0},
251 {ST_TOGGLE, N_("Smaller text"), P_OFFINTNL(tab_small), 0, 0, 0},
252 #if 0
253 {ST_MENU, N_("Focus new tabs:"), P_OFFINTNL(newtabstofront), 0, focusnewtabsmenu, 0},
254 #endif
255 {ST_MENU, N_("Show channel switcher at:"), P_OFFINTNL(tab_pos), 0, cspos, 1},
256 {ST_NUMBER, N_("Shorten tab labels to:"), P_OFFINTNL(truncchans), 0, (const char **)N_("letters."), 99},
258 {ST_HEADER, N_("Tabs or Windows"),0,0,0},
259 {ST_MENU, N_("Open channels in:"), P_OFFINTNL(tabchannels), 0, tabwin, 0},
260 {ST_MENU, N_("Open dialogs in:"), P_OFFINTNL(privmsgtab), 0, tabwin, 0},
261 {ST_MENU, N_("Open utilities in:"), P_OFFINTNL(windows_as_tabs), N_("Open DCC, Ignore, Notify etc, in tabs or windows?"), tabwin, 0},
263 {ST_END, 0, 0, 0, 0, 0}
266 static const char *const dccaccept[] =
268 N_("No"),
269 N_("Yes"),
270 N_("Browse for save folder every time"),
271 NULL
274 static const setting filexfer_settings[] =
276 {ST_HEADER, N_("Files and Directories"), 0, 0, 0},
277 {ST_MENU, N_("Auto accept file offers:"), P_OFFINTNL(autodccsend), 0, dccaccept, 0},
278 {ST_EFOLDER,N_("Download files to:"), P_OFFSETNL(dccdir), 0, 0, sizeof prefs.dccdir},
279 {ST_EFOLDER,N_("Move completed files to:"), P_OFFSETNL(dcc_completed_dir), 0, 0, sizeof prefs.dcc_completed_dir},
280 {ST_TOGGLE, N_("Save nick name in filenames"), P_OFFINTNL(dccwithnick), 0, 0, 0},
282 {ST_HEADER, N_("Network Settings"), 0, 0, 0},
283 {ST_TOGGLE, N_("Get my address from the IRC server"), P_OFFINTNL(ip_from_server),
284 N_("Asks the IRC server for your real address. Use this if you have a 192.168.*.* address!"), 0, 0},
285 {ST_ENTRY, N_("DCC IP address:"), P_OFFSETNL(dcc_ip_str),
286 N_("Claim you are at this address when offering files."), 0, sizeof prefs.dcc_ip_str},
287 {ST_NUMBER, N_("First DCC send port:"), P_OFFINTNL(first_dcc_send_port), 0, 0, 65535},
288 {ST_NUMBER, N_("Last DCC send port:"), P_OFFINTNL(last_dcc_send_port), 0,
289 (const char **)N_("!Leave ports at zero for full range."), 65535},
291 {ST_HEADER, N_("Maximum File Transfer Speeds (bytes per second)"), 0, 0, 0},
292 {ST_NUMBER, N_("One upload:"), P_OFFINTNL(dcc_max_send_cps),
293 N_("Maximum speed for one transfer"), 0, 1000000},
294 {ST_NUMBER, N_("One download:"), P_OFFINTNL(dcc_max_get_cps),
295 N_("Maximum speed for one transfer"), 0, 1000000},
296 {ST_NUMBER, N_("All uploads combined:"), P_OFFINTNL(dcc_global_max_send_cps),
297 N_("Maximum speed for all files"), 0, 1000000},
298 {ST_NUMBER, N_("All downloads combined:"), P_OFFINTNL(dcc_global_max_get_cps),
299 N_("Maximum speed for all files"), 0, 1000000},
301 {ST_END, 0, 0, 0, 0, 0}
304 static const int balloonlist[3] =
306 P_OFFINTNL(input_balloon_chans), P_OFFINTNL(input_balloon_priv), P_OFFINTNL(input_balloon_hilight)
309 static const int trayblinklist[3] =
311 P_OFFINTNL(input_tray_chans), P_OFFINTNL(input_tray_priv), P_OFFINTNL(input_tray_hilight)
314 static const int taskbarlist[3] =
316 P_OFFINTNL(input_flash_chans), P_OFFINTNL(input_flash_priv), P_OFFINTNL(input_flash_hilight)
319 static const int beeplist[3] =
321 P_OFFINTNL(input_beep_chans), P_OFFINTNL(input_beep_priv), P_OFFINTNL(input_beep_hilight)
324 static const setting alert_settings[] =
326 {ST_HEADER, N_("Alerts"),0,0,0},
328 {ST_ALERTHEAD},
329 {ST_3OGGLE, N_("Show tray balloons on:"), 0, 0, (void *)balloonlist, 0},
330 {ST_3OGGLE, N_("Blink tray icon on:"), 0, 0, (void *)trayblinklist, 0},
331 {ST_3OGGLE, N_("Blink task bar on:"), 0, 0, (void *)taskbarlist, 0},
332 {ST_3OGGLE, N_("Make a beep sound on:"), 0, 0, (void *)beeplist, 0},
334 {ST_TOGGLE, N_("Enable system tray icon"), P_OFFINTNL(gui_tray), 0, 0, 0},
336 {ST_HEADER, N_("Highlighted Messages"),0,0,0},
337 {ST_LABEL, N_("Highlighted messages are ones where your nickname is mentioned, but also:"), 0, 0, 0, 1},
339 {ST_ENTRY, N_("Extra words to highlight:"), P_OFFSETNL(irc_extra_hilight), 0, 0, sizeof prefs.irc_extra_hilight},
340 {ST_ENTRY, N_("Nick names not to highlight:"), P_OFFSETNL(irc_no_hilight), 0, 0, sizeof prefs.irc_no_hilight},
341 {ST_ENTRY, N_("Nick names to always highlight:"), P_OFFSETNL(irc_nick_hilight), 0, 0, sizeof prefs.irc_nick_hilight},
342 {ST_LABEL, N_("Separate multiple words with commas.\nWildcards are accepted.")},
343 {ST_END, 0, 0, 0, 0, 0}
346 static const setting general_settings[] =
348 {ST_HEADER, N_("Default Messages"),0,0,0},
349 {ST_ENTRY, N_("Quit:"), P_OFFSETNL(quitreason), 0, 0, sizeof prefs.quitreason},
350 {ST_ENTRY, N_("Leave channel:"), P_OFFSETNL(partreason), 0, 0, sizeof prefs.partreason},
351 {ST_ENTRY, N_("Away:"), P_OFFSETNL(awayreason), 0, 0, sizeof prefs.awayreason},
353 {ST_HEADER, N_("Away"),0,0,0},
354 {ST_TOGGLE, N_("Announce away messages"), P_OFFINTNL(show_away_message),
355 N_("Announce your away messages to all channels"), 0, 0},
356 {ST_TOGGLE, N_("Show away once"), P_OFFINTNL(show_away_once), N_("Show identical away messages only once"), 0, 0},
357 {ST_TOGGLE, N_("Automatically unmark away"), P_OFFINTNL(auto_unmark_away), N_("Unmark yourself as away before sending messages"), 0, 0},
358 {ST_END, 0, 0, 0, 0, 0}
361 #if 0
362 static const setting advanced_settings[] =
364 {ST_HEADER, N_("Advanced Settings"),0,0,0},
365 {ST_NUMBER, N_("Auto reconnect delay:"), P_OFFINTNL(recon_delay), 0, 0, 9999},
366 {ST_TOGGLE, N_("Display MODEs in raw form"), P_OFFINTNL(raw_modes), 0, 0, 0},
367 {ST_TOGGLE, N_("Whois on notify"), P_OFFINTNL(whois_on_notifyonline), N_("Sends a /WHOIS when a user comes online in your notify list"), 0, 0},
368 {ST_TOGGLE, N_("Hide join and part messages"), P_OFFINTNL(confmode), N_("Hide channel join/part messages by default"), 0, 0},
369 {ST_HEADER, N_("Auto Open DCC Windows"),0,0,0},
370 {ST_TOGGLE, N_("Send window"), P_OFFINTNL(autoopendccsendwindow), 0, 0, 0},
371 {ST_TOGGLE, N_("Receive window"), P_OFFINTNL(autoopendccrecvwindow), 0, 0, 0},
372 {ST_TOGGLE, N_("Chat window"), P_OFFINTNL(autoopendccchatwindow), 0, 0, 0},
374 {ST_END, 0, 0, 0, 0, 0}
376 #endif
378 static const setting logging_settings[] =
380 {ST_HEADER, N_("Logging"),0,0,0},
381 {ST_TOGGLE, N_("Display scrollback from previous session"), P_OFFINTNL(text_replay), 0, 0, 0},
382 {ST_TOGGLE, N_("Enable logging of conversations to disk"), P_OFFINTNL(logging), 0, 0, 2},
383 {ST_ENTRY, N_("Log filename:"), P_OFFSETNL(logmask), 0, 0, sizeof prefs.logmask},
384 {ST_LABEL, N_("%s=Server %c=Channel %n=Network.")},
386 {ST_HEADER, N_("Time Stamps"),0,0,0},
387 {ST_TOGGLE, N_("Insert timestamps in logs"), P_OFFINTNL(timestamp_logs), 0, 0, 2},
388 {ST_ENTRY, N_("Log timestamp format:"), P_OFFSETNL(timestamp_log_format), 0, 0, sizeof prefs.timestamp_log_format},
389 {ST_LABEL, N_("See strftime manpage for details.")},
391 {ST_END, 0, 0, 0, 0, 0}
394 static const char *const proxytypes[] =
396 N_("(Disabled)"),
397 N_("Wingate"),
398 N_("Socks4"),
399 N_("Socks5"),
400 N_("HTTP"),
401 #ifdef USE_MSPROXY
402 N_("MS Proxy (ISA)"),
403 #endif
404 #ifdef USE_LIBPROXY
405 N_("Auto"),
406 #endif
407 NULL
410 static const char *const proxyuse[] =
412 N_("All Connections"),
413 N_("IRC Server Only"),
414 N_("DCC Get Only"),
415 NULL
418 static const setting network_settings[] =
420 {ST_HEADER, N_("Your Address"), 0, 0, 0, 0},
421 {ST_ENTRY, N_("Bind to:"), P_OFFSETNL(hostname), 0, 0, sizeof prefs.hostname},
422 {ST_LABEL, N_("Only useful for computers with multiple addresses.")},
424 {ST_HEADER, N_("Proxy Server"), 0, 0, 0, 0},
425 {ST_ENTRY, N_("Hostname:"), P_OFFSETNL(proxy_host), 0, 0, sizeof prefs.proxy_host},
426 {ST_NUMBER, N_("Port:"), P_OFFINTNL(proxy_port), 0, 0, 65535},
427 {ST_MENU, N_("Type:"), P_OFFINTNL(proxy_type), 0, proxytypes, 0},
428 {ST_MENU, N_("Use proxy for:"), P_OFFINTNL(proxy_use), 0, proxyuse, 0},
430 {ST_HEADER, N_("Proxy Authentication"), 0, 0, 0, 0},
431 #ifdef USE_MSPROXY
432 {ST_TOGGLE, N_("Use Authentication (MS Proxy, HTTP or Socks5 only)"), P_OFFINTNL(proxy_auth), 0, 0, 0},
433 #else
434 {ST_TOGGLE, N_("Use Authentication (HTTP or Socks5 only)"), P_OFFINTNL(proxy_auth), 0, 0, 0},
435 #endif
436 {ST_ENTRY, N_("Username:"), P_OFFSETNL(proxy_user), 0, 0, sizeof prefs.proxy_user},
437 {ST_ENTRY, N_("Password:"), P_OFFSETNL(proxy_pass), 0, GINT_TO_POINTER(1), sizeof prefs.proxy_pass},
439 {ST_END, 0, 0, 0, 0, 0}
442 #define setup_get_str(pr,set) (((char *)pr)+set->offset)
443 #define setup_get_int(pr,set) *(((int *)pr)+set->offset)
444 #define setup_get_int3(pr,off) *(((int *)pr)+off)
446 #define setup_set_int(pr,set,num) *((int *)pr+set->offset)=num
447 #define setup_set_str(pr,set,str) strcpy(((char *)pr)+set->offset,str)
450 static void
451 setup_3oggle_cb (GtkToggleButton *but, unsigned int *setting)
453 *setting = but->active;
456 static void
457 setup_headlabel (GtkWidget *tab, int row, int col, char *text)
459 GtkWidget *label;
460 char buf[128];
461 char *sp;
463 snprintf (buf, sizeof (buf), "<b><span size=\"smaller\">%s</span></b>", text);
464 sp = strchr (buf + 17, ' ');
465 if (sp)
466 *sp = '\n';
468 label = gtk_label_new (NULL);
469 gtk_label_set_markup (GTK_LABEL (label), buf);
470 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
471 gtk_table_attach (GTK_TABLE (tab), label, col, col + 1, row, row + 1, 0, 0, 4, 0);
474 static void
475 setup_create_alert_header (GtkWidget *tab, int row, const setting *set)
477 setup_headlabel (tab, row, 3, _("Channel Message"));
478 setup_headlabel (tab, row, 4, _("Private Message"));
479 setup_headlabel (tab, row, 5, _("Highlighted Message"));
482 /* makes 3 toggles side-by-side */
484 static void
485 setup_create_3oggle (GtkWidget *tab, int row, const setting *set)
487 GtkWidget *label, *wid;
488 int *offsets = (int *)set->list;
490 label = gtk_label_new (_(set->label));
491 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
492 gtk_table_attach (GTK_TABLE (tab), label, 2, 3, row, row + 1,
493 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
495 wid = gtk_check_button_new ();
496 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
497 setup_get_int3 (&setup_prefs, offsets[0]));
498 g_signal_connect (G_OBJECT (wid), "toggled",
499 G_CALLBACK (setup_3oggle_cb), ((int *)&setup_prefs) + offsets[0]);
500 gtk_table_attach (GTK_TABLE (tab), wid, 3, 4, row, row + 1, 0, 0, 0, 0);
502 wid = gtk_check_button_new ();
503 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
504 setup_get_int3 (&setup_prefs, offsets[1]));
505 g_signal_connect (G_OBJECT (wid), "toggled",
506 G_CALLBACK (setup_3oggle_cb), ((int *)&setup_prefs) + offsets[1]);
507 gtk_table_attach (GTK_TABLE (tab), wid, 4, 5, row, row + 1, 0, 0, 0, 0);
509 wid = gtk_check_button_new ();
510 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
511 setup_get_int3 (&setup_prefs, offsets[2]));
512 g_signal_connect (G_OBJECT (wid), "toggled",
513 G_CALLBACK (setup_3oggle_cb), ((int *)&setup_prefs) + offsets[2]);
514 gtk_table_attach (GTK_TABLE (tab), wid, 5, 6, row, row + 1, 0, 0, 0, 0);
517 static void
518 setup_toggle_cb (GtkToggleButton *but, const setting *set)
520 GtkWidget *label, *disable_wid;
522 setup_set_int (&setup_prefs, set, but->active ? 1 : 0);
524 /* does this toggle also enable/disable another widget? */
525 disable_wid = g_object_get_data (G_OBJECT (but), "nxt");
526 if (disable_wid)
528 gtk_widget_set_sensitive (disable_wid, but->active);
529 label = g_object_get_data (G_OBJECT (disable_wid), "lbl");
530 gtk_widget_set_sensitive (label, but->active);
534 static void
535 setup_create_toggleR (GtkWidget *tab, int row, const setting *set)
537 GtkWidget *wid;
539 wid = gtk_check_button_new_with_label (_(set->label));
540 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
541 setup_get_int (&setup_prefs, set));
542 g_signal_connect (G_OBJECT (wid), "toggled",
543 G_CALLBACK (setup_toggle_cb), (gpointer)set);
544 if (set->tooltip)
545 add_tip (wid, _(set->tooltip));
546 gtk_table_attach (GTK_TABLE (tab), wid, 4, 5, row, row + 1,
547 GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
550 static GtkWidget *
551 setup_create_toggleL (GtkWidget *tab, int row, const setting *set)
553 GtkWidget *wid;
555 wid = gtk_check_button_new_with_label (_(set->label));
556 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
557 setup_get_int (&setup_prefs, set));
558 g_signal_connect (G_OBJECT (wid), "toggled",
559 G_CALLBACK (setup_toggle_cb), (gpointer)set);
560 if (set->tooltip)
561 add_tip (wid, _(set->tooltip));
562 gtk_table_attach (GTK_TABLE (tab), wid, 2, row==6 ? 6 : 4, row, row + 1,
563 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
565 return wid;
568 #if 0
569 static void
570 setup_create_toggle (GtkWidget *box, int row, const setting *set)
572 GtkWidget *wid;
574 wid = gtk_check_button_new_with_label (_(set->label));
575 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
576 setup_get_int (&setup_prefs, set));
577 g_signal_connect (G_OBJECT (wid), "toggled",
578 G_CALLBACK (setup_toggle_cb), (gpointer)set);
579 if (set->tooltip)
580 add_tip (wid, _(set->tooltip));
581 gtk_box_pack_start (GTK_BOX (box), wid, 0, 0, 0);
583 #endif
585 static GtkWidget *
586 setup_create_italic_label (char *text)
588 GtkWidget *label;
589 char buf[256];
591 label = gtk_label_new (NULL);
592 snprintf (buf, sizeof (buf), "<i><span size=\"smaller\">%s</span></i>", text);
593 gtk_label_set_markup (GTK_LABEL (label), buf);
594 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
596 return label;
599 static void
600 setup_spin_cb (GtkSpinButton *spin, const setting *set)
602 setup_set_int (&setup_prefs, set, gtk_spin_button_get_value_as_int (spin));
605 static GtkWidget *
606 setup_create_spin (GtkWidget *table, int row, const setting *set)
608 GtkWidget *label, *wid, *rbox, *align;
609 char *text;
611 label = gtk_label_new (_(set->label));
612 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
613 gtk_table_attach (GTK_TABLE (table), label, 2, 3, row, row + 1,
614 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
616 align = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
617 gtk_table_attach (GTK_TABLE (table), align, 3, 4, row, row + 1,
618 GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
620 rbox = gtk_hbox_new (0, 0);
621 gtk_container_add (GTK_CONTAINER (align), rbox);
623 wid = gtk_spin_button_new_with_range (0, set->extra, 1);
624 g_object_set_data (G_OBJECT (wid), "lbl", label);
625 if (set->tooltip)
626 add_tip (wid, _(set->tooltip));
627 gtk_spin_button_set_value (GTK_SPIN_BUTTON (wid),
628 setup_get_int (&setup_prefs, set));
629 g_signal_connect (G_OBJECT (wid), "value_changed",
630 G_CALLBACK (setup_spin_cb), (gpointer)set);
631 gtk_box_pack_start (GTK_BOX (rbox), wid, 0, 0, 0);
633 if (set->list)
635 text = _((char *)set->list);
636 if (text[0] == '!')
637 label = setup_create_italic_label (text + 1);
638 else
639 label = gtk_label_new (text);
640 gtk_box_pack_start (GTK_BOX (rbox), label, 0, 0, 6);
643 return wid;
646 static gint
647 setup_apply_tint (int *tag)
649 prefs.tint_red = setup_prefs.tint_red;
650 prefs.tint_green = setup_prefs.tint_green;
651 prefs.tint_blue = setup_prefs.tint_blue;
652 mg_update_xtext (current_sess->gui->xtext);
653 *tag = 0;
654 return 0;
657 static void
658 setup_hscale_cb (GtkHScale *wid, const setting *set)
660 static int tag = 0;
662 setup_set_int (&setup_prefs, set, gtk_range_get_value(GTK_RANGE(wid)));
663 if(tag == 0)
664 tag = g_idle_add ((GSourceFunc)setup_apply_tint, &tag);
667 static void
668 setup_create_hscale (GtkWidget *table, int row, const setting *set)
670 GtkWidget *wid;
672 wid = gtk_label_new (_(set->label));
673 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5);
674 gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1,
675 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
677 wid = gtk_hscale_new_with_range (0., 255., 1.);
678 gtk_scale_set_value_pos (GTK_SCALE (wid), GTK_POS_RIGHT);
679 gtk_range_set_value (GTK_RANGE (wid), setup_get_int (&setup_prefs, set));
680 g_signal_connect (G_OBJECT(wid), "value_changed",
681 G_CALLBACK (setup_hscale_cb), (gpointer)set);
682 gtk_table_attach (GTK_TABLE (table), wid, 3, 6, row, row + 1,
683 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
687 static GtkWidget *proxy_user; /* username GtkEntry */
688 static GtkWidget *proxy_pass; /* password GtkEntry */
690 static void
691 setup_menu_cb (GtkWidget *cbox, const setting *set)
693 int n = gtk_combo_box_get_active (GTK_COMBO_BOX (cbox));
695 /* set the prefs.<field> */
696 setup_set_int (&setup_prefs, set, n + set->extra);
698 if (set->list == proxytypes)
700 /* only HTTP and Socks5 can use a username/pass */
701 gtk_widget_set_sensitive (proxy_user, (n == 3 || n == 4 || n == 5));
702 gtk_widget_set_sensitive (proxy_pass, (n == 3 || n == 4 || n == 5));
706 static void
707 setup_radio_cb (GtkWidget *item, const setting *set)
709 if (GTK_TOGGLE_BUTTON (item)->active)
711 int n = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "n"));
712 /* set the prefs.<field> */
713 setup_set_int (&setup_prefs, set, n);
717 static int
718 setup_create_radio (GtkWidget *table, int row, const setting *set)
720 GtkWidget *wid, *hbox;
721 int i;
722 const char **text = (const char **)set->list;
723 GSList *group;
725 wid = gtk_label_new (_(set->label));
726 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5);
727 gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1,
728 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
730 hbox = gtk_hbox_new (0, 0);
731 gtk_table_attach (GTK_TABLE (table), hbox, 3, 4, row, row + 1,
732 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
734 i = 0;
735 group = NULL;
736 while (text[i])
738 if (text[i][0] != 0)
740 wid = gtk_radio_button_new_with_mnemonic (group, _(text[i]));
741 /*if (set->tooltip)
742 add_tip (wid, _(set->tooltip));*/
743 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (wid));
744 gtk_container_add (GTK_CONTAINER (hbox), wid);
745 if (i == setup_get_int (&setup_prefs, set))
746 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid), TRUE);
747 g_object_set_data (G_OBJECT (wid), "n", GINT_TO_POINTER (i));
748 g_signal_connect (G_OBJECT (wid), "toggled",
749 G_CALLBACK (setup_radio_cb), (gpointer)set);
751 i++;
752 row++;
755 return i;
759 static const char *id_strings[] =
762 "*",
763 "%C4*%C18%B%B",
764 "%U"
767 static void
768 setup_id_menu_cb (GtkWidget *item, char *dest)
770 int n = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "n"));
772 strcpy (dest, id_strings[n]);
775 static void
776 setup_create_id_menu (GtkWidget *table, char *label, int row, char *dest)
778 GtkWidget *wid, *menu, *item;
779 int i, def = 0;
780 static const char *text[] =
782 ("(disabled)"),
783 ("A star (*)"),
784 ("A red star (*)"),
785 ("Underlined")
788 wid = gtk_label_new (label);
789 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5);
790 gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1,
791 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
793 wid = gtk_option_menu_new ();
794 menu = gtk_menu_new ();
796 for (i = 0; i < 4; i++)
798 if (strcmp (id_strings[i], dest) == 0)
800 def = i;
801 break;
805 i = 0;
806 while (text[i])
808 item = gtk_menu_item_new_with_label (_(text[i]));
809 g_object_set_data (G_OBJECT (item), "n", GINT_TO_POINTER (i));
811 gtk_widget_show (item);
812 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
813 g_signal_connect (G_OBJECT (item), "activate",
814 G_CALLBACK (setup_id_menu_cb), dest);
815 i++;
818 gtk_option_menu_set_menu (GTK_OPTION_MENU (wid), menu);
819 gtk_option_menu_set_history (GTK_OPTION_MENU (wid), def);
821 gtk_table_attach (GTK_TABLE (table), wid, 3, 4, row, row + 1,
822 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
827 static void
828 setup_create_menu (GtkWidget *table, int row, const setting *set)
830 GtkWidget *wid, *cbox, *box;
831 const char **text = (const char **)set->list;
832 int i;
834 wid = gtk_label_new (_(set->label));
835 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5);
836 gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1,
837 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
839 cbox = gtk_combo_box_new_text ();
841 for (i = 0; text[i]; i++)
842 gtk_combo_box_append_text (GTK_COMBO_BOX (cbox), _(text[i]));
844 gtk_combo_box_set_active (GTK_COMBO_BOX (cbox),
845 setup_get_int (&setup_prefs, set) - set->extra);
846 g_signal_connect (G_OBJECT (cbox), "changed",
847 G_CALLBACK (setup_menu_cb), (gpointer)set);
849 box = gtk_hbox_new (0, 0);
850 gtk_box_pack_start (GTK_BOX (box), cbox, 0, 0, 0);
851 gtk_table_attach (GTK_TABLE (table), box, 3, 4, row, row + 1,
852 GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
855 static void
856 setup_filereq_cb (GtkWidget *entry, char *file)
858 if (file)
860 if (file[0])
861 gtk_entry_set_text (GTK_ENTRY (entry), file);
865 static void
866 setup_browsefile_cb (GtkWidget *button, GtkWidget *entry)
868 gtkutil_file_req (_("Select an Image File"), setup_filereq_cb, entry, NULL, 0);
871 static void
872 setup_fontsel_destroy (GtkWidget *button, GtkFontSelectionDialog *dialog)
874 font_dialog = NULL;
877 static void
878 setup_fontsel_cb (GtkWidget *button, GtkFontSelectionDialog *dialog)
880 GtkWidget *entry;
881 char *font_name;
883 entry = g_object_get_data (G_OBJECT (button), "e");
884 font_name = gtk_font_selection_dialog_get_font_name (dialog);
886 gtk_entry_set_text (GTK_ENTRY (entry), font_name);
888 g_free (font_name);
889 gtk_widget_destroy (GTK_WIDGET (dialog));
890 font_dialog = NULL;
893 static void
894 setup_fontsel_cancel (GtkWidget *button, GtkFontSelectionDialog *dialog)
896 gtk_widget_destroy (GTK_WIDGET (dialog));
897 font_dialog = NULL;
900 static void
901 setup_browsefolder_cb (GtkWidget *button, GtkEntry *entry)
903 gtkutil_file_req (_("Select Download Folder"), setup_filereq_cb, entry, entry->text, FRF_CHOOSEFOLDER);
906 static void
907 setup_browsefont_cb (GtkWidget *button, GtkWidget *entry)
909 GtkFontSelection *sel;
910 GtkFontSelectionDialog *dialog;
912 dialog = (GtkFontSelectionDialog *) gtk_font_selection_dialog_new (_("Select font"));
913 font_dialog = (GtkWidget *)dialog; /* global var */
915 sel = (GtkFontSelection *) dialog->fontsel;
917 if (GTK_ENTRY (entry)->text[0])
918 gtk_font_selection_set_font_name (sel, GTK_ENTRY (entry)->text);
920 g_object_set_data (G_OBJECT (dialog->ok_button), "e", entry);
922 g_signal_connect (G_OBJECT (dialog), "destroy",
923 G_CALLBACK (setup_fontsel_destroy), dialog);
924 g_signal_connect (G_OBJECT (dialog->ok_button), "clicked",
925 G_CALLBACK (setup_fontsel_cb), dialog);
926 g_signal_connect (G_OBJECT (dialog->cancel_button), "clicked",
927 G_CALLBACK (setup_fontsel_cancel), dialog);
929 gtk_widget_show (GTK_WIDGET (dialog));
932 static void
933 setup_entry_cb (GtkEntry *entry, setting *set)
935 int size;
936 int pos;
937 int len = strlen (entry->text);
938 unsigned char *p = entry->text;
940 /* need to truncate? */
941 if (len >= set->extra)
943 len = pos = 0;
944 while (1)
946 size = g_utf8_skip [*p];
947 len += size;
948 p += size;
949 /* truncate to "set->extra" BYTES */
950 if (len >= set->extra)
952 gtk_editable_delete_text (GTK_EDITABLE (entry), pos, -1);
953 break;
955 pos++;
958 else
960 setup_set_str (&setup_prefs, set, entry->text);
964 static void
965 setup_create_label (GtkWidget *table, int row, const setting *set)
967 gtk_table_attach (GTK_TABLE (table), setup_create_italic_label (_(set->label)),
968 set->extra ? 1 : 3, 5, row, row + 1, GTK_FILL,
969 GTK_SHRINK | GTK_FILL, 0, 0);
972 static GtkWidget *
973 setup_create_entry (GtkWidget *table, int row, const setting *set)
975 GtkWidget *label;
976 GtkWidget *wid, *bwid;
978 label = gtk_label_new (_(set->label));
979 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
980 gtk_table_attach (GTK_TABLE (table), label, 2, 3, row, row + 1,
981 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
983 wid = gtk_entry_new ();
984 g_object_set_data (G_OBJECT (wid), "lbl", label);
985 if (set->list)
986 gtk_entry_set_visibility (GTK_ENTRY (wid), FALSE);
987 if (set->tooltip)
988 add_tip (wid, _(set->tooltip));
989 gtk_entry_set_max_length (GTK_ENTRY (wid), set->extra - 1);
990 gtk_entry_set_text (GTK_ENTRY (wid), setup_get_str (&setup_prefs, set));
991 g_signal_connect (G_OBJECT (wid), "changed",
992 G_CALLBACK (setup_entry_cb), (gpointer)set);
994 if (set->offset == P_OFFSETNL(proxy_user))
995 proxy_user = wid;
996 if (set->offset == P_OFFSETNL(proxy_pass))
997 proxy_pass = wid;
999 /* only http and Socks5 can auth */
1000 if ( (set->offset == P_OFFSETNL(proxy_pass) ||
1001 set->offset == P_OFFSETNL(proxy_user)) &&
1002 (setup_prefs.proxy_type != 4 && setup_prefs.proxy_type != 3 && setup_prefs.proxy_type != 5) )
1003 gtk_widget_set_sensitive (wid, FALSE);
1005 if (set->type == ST_ENTRY)
1006 gtk_table_attach (GTK_TABLE (table), wid, 3, 6, row, row + 1,
1007 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
1008 else
1010 gtk_table_attach (GTK_TABLE (table), wid, 3, 5, row, row + 1,
1011 GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
1012 bwid = gtk_button_new_with_label (_("Browse..."));
1013 gtk_table_attach (GTK_TABLE (table), bwid, 5, 6, row, row + 1,
1014 GTK_SHRINK | GTK_FILL, GTK_FILL, 0, 0);
1015 if (set->type == ST_EFILE)
1016 g_signal_connect (G_OBJECT (bwid), "clicked",
1017 G_CALLBACK (setup_browsefile_cb), wid);
1018 if (set->type == ST_EFONT)
1019 g_signal_connect (G_OBJECT (bwid), "clicked",
1020 G_CALLBACK (setup_browsefont_cb), wid);
1021 if (set->type == ST_EFOLDER)
1022 g_signal_connect (G_OBJECT (bwid), "clicked",
1023 G_CALLBACK (setup_browsefolder_cb), wid);
1026 return wid;
1029 static void
1030 setup_create_header (GtkWidget *table, int row, char *labeltext)
1032 GtkWidget *label;
1033 char buf[128];
1035 if (row == 0)
1036 snprintf (buf, sizeof (buf), "<b>%s</b>", _(labeltext));
1037 else
1038 snprintf (buf, sizeof (buf), "\n<b>%s</b>", _(labeltext));
1040 label = gtk_label_new (NULL);
1041 gtk_label_set_markup (GTK_LABEL (label), buf);
1042 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1043 gtk_table_attach (GTK_TABLE (table), label, 0, 4, row, row + 1,
1044 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 5);
1047 static GtkWidget *
1048 setup_create_frame (GtkWidget **left, GtkWidget *box)
1050 GtkWidget *tab, *hbox, *inbox = box;
1052 tab = gtk_table_new (3, 2, FALSE);
1053 gtk_container_set_border_width (GTK_CONTAINER (tab), 6);
1054 gtk_table_set_row_spacings (GTK_TABLE (tab), 2);
1055 gtk_table_set_col_spacings (GTK_TABLE (tab), 3);
1056 gtk_container_add (GTK_CONTAINER (inbox), tab);
1058 hbox = gtk_hbox_new (FALSE, 0);
1059 gtk_container_add (GTK_CONTAINER (inbox), hbox);
1061 *left = gtk_vbox_new (FALSE, 0);
1062 gtk_box_pack_start (GTK_BOX (hbox), *left, 0, 0, 0);
1064 return tab;
1067 static void
1068 open_data_cb (GtkWidget *button, gpointer data)
1070 fe_open_url (get_xdir_utf8 ());
1073 static GtkWidget *
1074 setup_create_page (const setting *set)
1076 int i, row, do_disable;
1077 GtkWidget *tab, *box, *left;
1078 GtkWidget *wid = NULL, *prev;
1080 box = gtk_vbox_new (FALSE, 1);
1081 gtk_container_set_border_width (GTK_CONTAINER (box), 6);
1083 tab = setup_create_frame (&left, box);
1085 i = row = do_disable = 0;
1086 while (set[i].type != ST_END)
1088 prev = wid;
1090 switch (set[i].type)
1092 case ST_HEADER:
1093 setup_create_header (tab, row, set[i].label);
1094 break;
1095 case ST_EFONT:
1096 case ST_ENTRY:
1097 case ST_EFILE:
1098 case ST_EFOLDER:
1099 wid = setup_create_entry (tab, row, &set[i]);
1100 break;
1101 case ST_TOGGLR:
1102 row--;
1103 setup_create_toggleR (tab, row, &set[i]);
1104 break;
1105 case ST_TOGGLE:
1106 wid = setup_create_toggleL (tab, row, &set[i]);
1107 do_disable = set[i].extra;
1108 break;
1109 case ST_3OGGLE:
1110 setup_create_3oggle (tab, row, &set[i]);
1111 break;
1112 case ST_MENU:
1113 setup_create_menu (tab, row, &set[i]);
1114 break;
1115 case ST_RADIO:
1116 row += setup_create_radio (tab, row, &set[i]);
1117 break;
1118 case ST_NUMBER:
1119 wid = setup_create_spin (tab, row, &set[i]);
1120 break;
1121 case ST_HSCALE:
1122 setup_create_hscale (tab, row, &set[i]);
1123 break;
1124 case ST_LABEL:
1125 setup_create_label (tab, row, &set[i]);
1126 break;
1127 case ST_ALERTHEAD:
1128 setup_create_alert_header (tab, row, &set[i]);
1131 /* will this toggle disable the "next" widget? */
1132 do_disable--;
1133 if (do_disable == 0)
1135 /* setup_toggle_cb uses this data */
1136 g_object_set_data (G_OBJECT (prev), "nxt", wid);
1137 /* force initial sensitive state */
1138 gtk_widget_set_sensitive (wid, GTK_TOGGLE_BUTTON (prev)->active);
1139 gtk_widget_set_sensitive (g_object_get_data (G_OBJECT (wid), "lbl"),
1140 GTK_TOGGLE_BUTTON (prev)->active);
1143 i++;
1144 row++;
1147 #if 0
1148 if (set == general_settings)
1150 setup_create_id_menu (tab, _("Mark identified users with:"),
1151 row, setup_prefs.irc_id_ytext);
1152 setup_create_id_menu (tab, _("Mark not-identified users with:"),
1153 row + 1, setup_prefs.irc_id_ntext);
1155 #endif
1157 if (set == logging_settings)
1159 GtkWidget *but = gtk_button_new_with_label (_("Open Data Folder"));
1160 gtk_box_pack_start (GTK_BOX (left), but, 0, 0, 0);
1161 g_signal_connect (G_OBJECT (but), "clicked",
1162 G_CALLBACK (open_data_cb), 0);
1165 return box;
1168 static void
1169 setup_color_ok_cb (GtkWidget *button, GtkWidget *dialog)
1171 GtkColorSelectionDialog *cdialog = GTK_COLOR_SELECTION_DIALOG (dialog);
1172 GdkColor *col;
1173 GdkColor old_color;
1174 GtkStyle *style;
1176 col = g_object_get_data (G_OBJECT (button), "c");
1177 old_color = *col;
1179 button = g_object_get_data (G_OBJECT (button), "b");
1181 if (!GTK_IS_WIDGET (button))
1183 gtk_widget_destroy (dialog);
1184 return;
1187 color_change = TRUE;
1189 gtk_color_selection_get_current_color (GTK_COLOR_SELECTION (cdialog->colorsel), col);
1191 gdk_colormap_alloc_color (gtk_widget_get_colormap (button), col, TRUE, TRUE);
1193 style = gtk_style_new ();
1194 style->bg[0] = *col;
1195 gtk_widget_set_style (button, style);
1196 g_object_unref (style);
1198 /* is this line correct?? */
1199 gdk_colormap_free_colors (gtk_widget_get_colormap (button), &old_color, 1);
1201 gtk_widget_destroy (dialog);
1204 static void
1205 setup_color_cb (GtkWidget *button, gpointer userdata)
1207 GtkWidget *dialog;
1208 GtkColorSelectionDialog *cdialog;
1209 GdkColor *color;
1211 color = &colors[GPOINTER_TO_INT (userdata)];
1213 dialog = gtk_color_selection_dialog_new (_("Select color"));
1214 cdialog = GTK_COLOR_SELECTION_DIALOG (dialog);
1216 gtk_widget_hide (cdialog->help_button);
1217 g_signal_connect (G_OBJECT (cdialog->ok_button), "clicked",
1218 G_CALLBACK (setup_color_ok_cb), dialog);
1219 g_signal_connect (G_OBJECT (cdialog->cancel_button), "clicked",
1220 G_CALLBACK (gtkutil_destroy), dialog);
1221 g_object_set_data (G_OBJECT (cdialog->ok_button), "c", color);
1222 g_object_set_data (G_OBJECT (cdialog->ok_button), "b", button);
1223 gtk_widget_set_sensitive (cdialog->help_button, FALSE);
1224 gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (cdialog->colorsel), color);
1225 gtk_widget_show (dialog);
1228 static void
1229 setup_create_color_button (GtkWidget *table, int num, int row, int col)
1231 GtkWidget *but;
1232 GtkStyle *style;
1233 char buf[64];
1235 if (num > 31)
1236 strcpy (buf, "<span size=\"x-small\"> </span>");
1237 else
1238 /* 12345678901 23456789 01 23456789 */
1239 sprintf (buf, "<span size=\"x-small\">%d</span>", num);
1240 but = gtk_button_new_with_label (" ");
1241 gtk_label_set_markup (GTK_LABEL (GTK_BIN (but)->child), buf);
1242 /* win32 build uses this to turn off themeing */
1243 g_object_set_data (G_OBJECT (but), "xchat-color", (gpointer)1);
1244 gtk_table_attach (GTK_TABLE (table), but, col, col+1, row, row+1,
1245 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
1246 g_signal_connect (G_OBJECT (but), "clicked",
1247 G_CALLBACK (setup_color_cb), GINT_TO_POINTER (num));
1248 style = gtk_style_new ();
1249 style->bg[GTK_STATE_NORMAL] = colors[num];
1250 gtk_widget_set_style (but, style);
1251 g_object_unref (style);
1254 static void
1255 setup_create_other_colorR (char *text, int num, int row, GtkWidget *tab)
1257 GtkWidget *label;
1259 label = gtk_label_new (text);
1260 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1261 gtk_table_attach (GTK_TABLE (tab), label, 5, 9, row, row + 1,
1262 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
1263 setup_create_color_button (tab, num, row, 9);
1266 static void
1267 setup_create_other_color (char *text, int num, int row, GtkWidget *tab)
1269 GtkWidget *label;
1271 label = gtk_label_new (text);
1272 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1273 gtk_table_attach (GTK_TABLE (tab), label, 2, 3, row, row + 1,
1274 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
1275 setup_create_color_button (tab, num, row, 3);
1278 static GtkWidget *
1279 setup_create_color_page (void)
1281 GtkWidget *tab, *box, *label;
1282 int i;
1284 box = gtk_vbox_new (FALSE, 0);
1285 gtk_container_set_border_width (GTK_CONTAINER (box), 6);
1287 tab = gtk_table_new (9, 2, FALSE);
1288 gtk_container_set_border_width (GTK_CONTAINER (tab), 6);
1289 gtk_table_set_row_spacings (GTK_TABLE (tab), 2);
1290 gtk_table_set_col_spacings (GTK_TABLE (tab), 3);
1291 gtk_container_add (GTK_CONTAINER (box), tab);
1293 setup_create_header (tab, 0, N_("Text Colors"));
1295 label = gtk_label_new (_("mIRC colors:"));
1296 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1297 gtk_table_attach (GTK_TABLE (tab), label, 2, 3, 1, 2,
1298 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
1300 for (i = 0; i < 16; i++)
1301 setup_create_color_button (tab, i, 1, i+3);
1303 label = gtk_label_new (_("Local colors:"));
1304 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1305 gtk_table_attach (GTK_TABLE (tab), label, 2, 3, 2, 3,
1306 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
1308 for (i = 16; i < 32; i++)
1309 setup_create_color_button (tab, i, 2, (i+3) - 16);
1311 setup_create_other_color (_("Foreground:"), COL_FG, 3, tab);
1312 setup_create_other_colorR (_("Background:"), COL_BG, 3, tab);
1314 setup_create_header (tab, 5, N_("Marking Text"));
1316 setup_create_other_color (_("Foreground:"), COL_MARK_FG, 6, tab);
1317 setup_create_other_colorR (_("Background:"), COL_MARK_BG, 6, tab);
1319 setup_create_header (tab, 8, N_("Interface Colors"));
1321 setup_create_other_color (_("New data:"), COL_NEW_DATA, 9, tab);
1322 setup_create_other_colorR (_("Marker line:"), COL_MARKER, 9, tab);
1323 setup_create_other_color (_("New message:"), COL_NEW_MSG, 10, tab);
1324 setup_create_other_colorR (_("Away user:"), COL_AWAY, 10, tab);
1325 setup_create_other_color (_("Highlight:"), COL_HILIGHT, 11, tab);
1327 return box;
1330 /* === GLOBALS for sound GUI === */
1332 static GtkWidget *sndprog_entry;
1333 static GtkWidget *sndfile_entry;
1334 static GtkWidget *snddir_entry;
1335 static int ignore_changed = FALSE;
1337 extern struct text_event te[]; /* text.c */
1338 extern char *sound_files[];
1340 static void
1341 setup_snd_apply (void)
1343 strcpy (setup_prefs.sounddir, GTK_ENTRY (snddir_entry)->text);
1344 strcpy (setup_prefs.soundcmd, GTK_ENTRY (sndprog_entry)->text);
1347 static void
1348 setup_snd_populate (GtkTreeView * treeview)
1350 GtkListStore *store;
1351 GtkTreeIter iter;
1352 GtkTreeSelection *sel;
1353 GtkTreePath *path;
1354 int i;
1356 sel = gtk_tree_view_get_selection (treeview);
1357 store = (GtkListStore *)gtk_tree_view_get_model (treeview);
1359 for (i = NUM_XP-1; i >= 0; i--)
1361 gtk_list_store_prepend (store, &iter);
1362 if (sound_files[i])
1363 gtk_list_store_set (store, &iter, 0, te[i].name, 1, sound_files[i], 2, i, -1);
1364 else
1365 gtk_list_store_set (store, &iter, 0, te[i].name, 1, "", 2, i, -1);
1366 if (i == last_selected_row)
1368 gtk_tree_selection_select_iter (sel, &iter);
1369 path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
1370 if (path)
1372 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.5, 0.5);
1373 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
1374 gtk_tree_path_free (path);
1380 static int
1381 setup_snd_get_selected (GtkTreeSelection *sel, GtkTreeIter *iter)
1383 int n;
1384 GtkTreeModel *model;
1386 if (!gtk_tree_selection_get_selected (sel, &model, iter))
1387 return -1;
1389 gtk_tree_model_get (model, iter, 2, &n, -1);
1390 return n;
1393 static void
1394 setup_snd_row_cb (GtkTreeSelection *sel, gpointer user_data)
1396 int n;
1397 GtkTreeIter iter;
1399 n = setup_snd_get_selected (sel, &iter);
1400 if (n == -1)
1401 return;
1402 last_selected_row = n;
1404 ignore_changed = TRUE;
1405 if (sound_files[n])
1406 gtk_entry_set_text (GTK_ENTRY (sndfile_entry), sound_files[n]);
1407 else
1408 gtk_entry_set_text (GTK_ENTRY (sndfile_entry), "");
1409 ignore_changed = FALSE;
1412 static void
1413 setup_snd_add_columns (GtkTreeView * treeview)
1415 GtkCellRenderer *renderer;
1416 GtkTreeModel *model;
1418 /* event column */
1419 renderer = gtk_cell_renderer_text_new ();
1420 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
1421 -1, _("Event"), renderer,
1422 "text", 0, NULL);
1424 /* file column */
1425 renderer = gtk_cell_renderer_text_new ();
1426 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
1427 -1, _("Sound file"), renderer,
1428 "text", 1, NULL);
1430 model = GTK_TREE_MODEL (gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT));
1431 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), model);
1432 g_object_unref (model);
1435 static void
1436 setup_autotoggle_cb (GtkToggleButton *but, GtkToggleButton *ext)
1438 if (but->active)
1440 setup_prefs.soundcmd[0] = 0;
1441 gtk_entry_set_text (GTK_ENTRY (sndprog_entry), "");
1442 gtk_widget_set_sensitive (sndprog_entry, FALSE);
1443 } else
1445 gtk_widget_set_sensitive (sndprog_entry, TRUE);
1449 static void
1450 setup_snd_filereq_cb (GtkWidget *entry, char *file)
1452 if (file)
1454 if (file[0])
1455 gtk_entry_set_text (GTK_ENTRY (entry), file);
1459 static void
1460 setup_snd_browse_cb (GtkWidget *button, GtkEntry *entry)
1462 gtkutil_file_req (_("Select a sound file"), setup_snd_filereq_cb, entry, NULL, 0);
1465 static void
1466 setup_snd_play_cb (GtkWidget *button, GtkEntry *entry)
1468 sound_play (entry->text, FALSE);
1471 static void
1472 setup_snd_changed_cb (GtkEntry *ent, GtkTreeView *tree)
1474 int n;
1475 GtkTreeIter iter;
1476 GtkListStore *store;
1477 GtkTreeSelection *sel;
1479 if (ignore_changed)
1480 return;
1482 sel = gtk_tree_view_get_selection (tree);
1483 n = setup_snd_get_selected (sel, &iter);
1484 if (n == -1)
1485 return;
1487 /* get the new sound file */
1488 if (sound_files[n])
1489 free (sound_files[n]);
1490 sound_files[n] = strdup (GTK_ENTRY (ent)->text);
1492 /* update the TreeView list */
1493 store = (GtkListStore *)gtk_tree_view_get_model (tree);
1494 gtk_list_store_set (store, &iter, 1, sound_files[n], -1);
1496 gtk_widget_set_sensitive (cancel_button, FALSE);
1499 static GtkWidget *
1500 setup_create_sound_page (void)
1502 GtkWidget *vbox1;
1503 GtkWidget *vbox2;
1504 GtkWidget *table2;
1505 GtkWidget *label2;
1506 GtkWidget *label3;
1507 GtkWidget *radio_external;
1508 GSList *radio_group = NULL;
1509 GtkWidget *radio_auto;
1510 GtkWidget *label4;
1511 GtkWidget *entry3;
1512 GtkWidget *scrolledwindow1;
1513 GtkWidget *sound_tree;
1514 GtkWidget *table1;
1515 GtkWidget *sound_label;
1516 GtkWidget *sound_browse;
1517 GtkWidget *sound_play;
1518 GtkTreeSelection *sel;
1520 vbox1 = gtk_vbox_new (FALSE, 0);
1521 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 6);
1522 gtk_widget_show (vbox1);
1524 vbox2 = gtk_vbox_new (FALSE, 0);
1525 gtk_widget_show (vbox2);
1526 gtk_container_add (GTK_CONTAINER (vbox1), vbox2);
1528 table2 = gtk_table_new (4, 3, FALSE);
1529 gtk_widget_show (table2);
1530 gtk_box_pack_start (GTK_BOX (vbox2), table2, FALSE, TRUE, 8);
1531 gtk_table_set_row_spacings (GTK_TABLE (table2), 2);
1532 gtk_table_set_col_spacings (GTK_TABLE (table2), 4);
1534 label2 = gtk_label_new (_("Sound playing method:"));
1535 gtk_widget_show (label2);
1536 gtk_table_attach (GTK_TABLE (table2), label2, 0, 1, 0, 1,
1537 (GtkAttachOptions) (GTK_FILL),
1538 (GtkAttachOptions) (0), 0, 0);
1539 gtk_misc_set_alignment (GTK_MISC (label2), 0, 0.5);
1541 label3 =
1542 gtk_label_new_with_mnemonic (_("External sound playing _program:"));
1543 gtk_widget_show (label3);
1544 gtk_table_attach (GTK_TABLE (table2), label3, 0, 1, 2, 3,
1545 (GtkAttachOptions) (GTK_FILL),
1546 (GtkAttachOptions) (0), 0, 0);
1547 gtk_misc_set_alignment (GTK_MISC (label3), 0, 0.5);
1549 sndprog_entry = gtk_entry_new ();
1550 if (setup_prefs.soundcmd[0] == 0)
1551 gtk_widget_set_sensitive (sndprog_entry, FALSE);
1552 else
1553 gtk_entry_set_text (GTK_ENTRY (sndprog_entry), setup_prefs.soundcmd);
1554 gtk_widget_show (sndprog_entry);
1555 gtk_table_attach (GTK_TABLE (table2), sndprog_entry, 1, 3, 2, 3,
1556 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1557 (GtkAttachOptions) (0), 0, 0);
1559 radio_external =
1560 gtk_radio_button_new_with_mnemonic (NULL, _("_External program"));
1561 gtk_widget_show (radio_external);
1562 gtk_table_attach (GTK_TABLE (table2), radio_external, 1, 3, 1, 2,
1563 (GtkAttachOptions) (GTK_FILL),
1564 (GtkAttachOptions) (0), 0, 0);
1565 gtk_radio_button_set_group (GTK_RADIO_BUTTON (radio_external),
1566 radio_group);
1567 radio_group =
1568 gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio_external));
1570 radio_auto = gtk_radio_button_new_with_mnemonic (NULL, _("_Automatic"));
1571 g_signal_connect (G_OBJECT (radio_auto), "toggled",
1572 G_CALLBACK (setup_autotoggle_cb), radio_external);
1573 gtk_widget_show (radio_auto);
1574 gtk_table_attach (GTK_TABLE (table2), radio_auto, 1, 3, 0, 1,
1575 (GtkAttachOptions) (GTK_FILL),
1576 (GtkAttachOptions) (0), 0, 0);
1577 gtk_radio_button_set_group (GTK_RADIO_BUTTON (radio_auto),
1578 radio_group);
1579 radio_group =
1580 gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio_auto));
1581 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_auto), setup_prefs.soundcmd[0] == 0);
1583 label4 = gtk_label_new_with_mnemonic (_("Sound files _directory:"));
1584 gtk_widget_show (label4);
1585 gtk_table_attach (GTK_TABLE (table2), label4, 0, 1, 3, 4,
1586 (GtkAttachOptions) (GTK_FILL),
1587 (GtkAttachOptions) (0), 0, 0);
1588 gtk_misc_set_alignment (GTK_MISC (label4), 0, 0.5);
1590 snddir_entry = entry3 = gtk_entry_new ();
1591 gtk_entry_set_text (GTK_ENTRY (entry3), setup_prefs.sounddir);
1592 gtk_widget_show (entry3);
1593 gtk_table_attach (GTK_TABLE (table2), entry3, 1, 3, 3, 4,
1594 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1595 (GtkAttachOptions) (0), 0, 0);
1597 scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
1598 gtk_widget_show (scrolledwindow1);
1599 gtk_container_add (GTK_CONTAINER (vbox2), scrolledwindow1);
1600 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1),
1601 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1602 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow1),
1603 GTK_SHADOW_IN);
1605 sound_tree = gtk_tree_view_new ();
1606 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (sound_tree));
1607 gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
1608 setup_snd_add_columns (GTK_TREE_VIEW (sound_tree));
1609 setup_snd_populate (GTK_TREE_VIEW (sound_tree));
1610 g_signal_connect (G_OBJECT (sel), "changed",
1611 G_CALLBACK (setup_snd_row_cb), NULL);
1612 gtk_widget_show (sound_tree);
1613 gtk_container_add (GTK_CONTAINER (scrolledwindow1), sound_tree);
1614 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (sound_tree), TRUE);
1616 table1 = gtk_table_new (2, 3, FALSE);
1617 gtk_widget_show (table1);
1618 gtk_box_pack_start (GTK_BOX (vbox2), table1, FALSE, TRUE, 8);
1619 gtk_table_set_row_spacings (GTK_TABLE (table1), 2);
1620 gtk_table_set_col_spacings (GTK_TABLE (table1), 4);
1622 sound_label = gtk_label_new_with_mnemonic (_("Sound file:"));
1623 gtk_widget_show (sound_label);
1624 gtk_table_attach (GTK_TABLE (table1), sound_label, 0, 1, 0, 1,
1625 (GtkAttachOptions) (GTK_FILL),
1626 (GtkAttachOptions) (0), 0, 0);
1627 gtk_misc_set_alignment (GTK_MISC (sound_label), 0, 0.5);
1629 sndfile_entry = gtk_entry_new ();
1630 g_signal_connect (G_OBJECT (sndfile_entry), "changed",
1631 G_CALLBACK (setup_snd_changed_cb), sound_tree);
1632 gtk_widget_show (sndfile_entry);
1633 gtk_table_attach (GTK_TABLE (table1), sndfile_entry, 0, 1, 1, 2,
1634 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1635 (GtkAttachOptions) (0), 0, 0);
1637 sound_browse = gtk_button_new_with_mnemonic (_("_Browse..."));
1638 g_signal_connect (G_OBJECT (sound_browse), "clicked",
1639 G_CALLBACK (setup_snd_browse_cb), sndfile_entry);
1640 gtk_widget_show (sound_browse);
1641 gtk_table_attach (GTK_TABLE (table1), sound_browse, 1, 2, 1, 2,
1642 (GtkAttachOptions) (GTK_FILL),
1643 (GtkAttachOptions) (0), 0, 0);
1645 #ifdef GTK_STOCK_MEDIA_PLAY
1646 sound_play = gtk_button_new_from_stock (GTK_STOCK_MEDIA_PLAY);
1647 #else
1648 sound_play = gtk_button_new_with_mnemonic (_("_Play"));
1649 #endif
1650 g_signal_connect (G_OBJECT (sound_play), "clicked",
1651 G_CALLBACK (setup_snd_play_cb), sndfile_entry);
1652 gtk_widget_show (sound_play);
1653 gtk_table_attach (GTK_TABLE (table1), sound_play, 2, 3, 1, 2,
1654 (GtkAttachOptions) (GTK_FILL),
1655 (GtkAttachOptions) (0), 0, 0);
1657 gtk_label_set_mnemonic_widget (GTK_LABEL (label3), sndprog_entry);
1658 gtk_label_set_mnemonic_widget (GTK_LABEL (label4), entry3);
1659 setup_snd_row_cb (sel, NULL);
1661 return vbox1;
1664 static void
1665 setup_add_page (const char *title, GtkWidget *book, GtkWidget *tab)
1667 GtkWidget *oframe, *frame, *label, *vvbox;
1668 char buf[128];
1670 /* frame for whole page */
1671 oframe = gtk_frame_new (NULL);
1672 gtk_frame_set_shadow_type (GTK_FRAME (oframe), GTK_SHADOW_IN);
1674 vvbox = gtk_vbox_new (FALSE, 0);
1675 gtk_container_add (GTK_CONTAINER (oframe), vvbox);
1677 /* border for the label */
1678 frame = gtk_frame_new (NULL);
1679 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
1680 gtk_box_pack_start (GTK_BOX (vvbox), frame, FALSE, TRUE, 0);
1682 /* label */
1683 label = gtk_label_new (NULL);
1684 snprintf (buf, sizeof (buf), "<b><big>%s</big></b>", _(title));
1685 gtk_label_set_markup (GTK_LABEL (label), buf);
1686 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1687 gtk_misc_set_padding (GTK_MISC (label), 2, 1);
1688 gtk_container_add (GTK_CONTAINER (frame), label);
1690 gtk_container_add (GTK_CONTAINER (vvbox), tab);
1692 gtk_notebook_append_page (GTK_NOTEBOOK (book), oframe, NULL);
1695 static const char *const cata[] =
1697 N_("Interface"),
1698 N_("Text box"),
1699 N_("Input box"),
1700 N_("User list"),
1701 N_("Channel switcher"),
1702 N_("Colors"),
1703 NULL,
1704 N_("Chatting"),
1705 N_("Alerts"),
1706 N_("General"),
1707 N_("Logging"),
1708 N_("Sound"),
1709 /* N_("Advanced"),*/
1710 NULL,
1711 N_("Network"),
1712 N_("Network setup"),
1713 N_("File transfers"),
1714 NULL,
1715 NULL
1718 static GtkWidget *
1719 setup_create_pages (GtkWidget *box)
1721 GtkWidget *book;
1723 book = gtk_notebook_new ();
1725 setup_add_page (cata[1], book, setup_create_page (textbox_settings));
1726 setup_add_page (cata[2], book, setup_create_page (inputbox_settings));
1727 setup_add_page (cata[3], book, setup_create_page (userlist_settings));
1728 setup_add_page (cata[4], book, setup_create_page (tabs_settings));
1729 setup_add_page (cata[5], book, setup_create_color_page ());
1730 setup_add_page (cata[8], book, setup_create_page (alert_settings));
1731 setup_add_page (cata[9], book, setup_create_page (general_settings));
1732 setup_add_page (cata[10], book, setup_create_page (logging_settings));
1733 setup_add_page (cata[11], book, setup_create_sound_page ());
1734 setup_add_page (cata[14], book, setup_create_page (network_settings));
1735 setup_add_page (cata[15], book, setup_create_page (filexfer_settings));
1737 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (book), FALSE);
1738 gtk_notebook_set_show_border (GTK_NOTEBOOK (book), FALSE);
1739 gtk_container_add (GTK_CONTAINER (box), book);
1741 return book;
1744 static void
1745 setup_tree_cb (GtkTreeView *treeview, GtkWidget *book)
1747 GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
1748 GtkTreeIter iter;
1749 GtkTreeModel *model;
1750 int page;
1752 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1754 gtk_tree_model_get (model, &iter, 1, &page, -1);
1755 if (page != -1)
1757 gtk_notebook_set_current_page (GTK_NOTEBOOK (book), page);
1758 last_selected_page = page;
1763 static gboolean
1764 setup_tree_select_filter (GtkTreeSelection *selection, GtkTreeModel *model,
1765 GtkTreePath *path, gboolean path_selected,
1766 gpointer data)
1768 if (gtk_tree_path_get_depth (path) > 1)
1769 return TRUE;
1770 return FALSE;
1773 static void
1774 setup_create_tree (GtkWidget *box, GtkWidget *book)
1776 GtkWidget *tree;
1777 GtkWidget *frame;
1778 GtkTreeStore *model;
1779 GtkTreeIter iter;
1780 GtkTreeIter child_iter;
1781 GtkTreeIter *sel_iter = NULL;
1782 GtkCellRenderer *renderer;
1783 GtkTreeSelection *sel;
1784 int i, page;
1786 model = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
1788 i = 0;
1789 page = 0;
1792 gtk_tree_store_append (model, &iter, NULL);
1793 gtk_tree_store_set (model, &iter, 0, _(cata[i]), 1, -1, -1);
1794 i++;
1798 gtk_tree_store_append (model, &child_iter, &iter);
1799 gtk_tree_store_set (model, &child_iter, 0, _(cata[i]), 1, page, -1);
1800 if (page == last_selected_page)
1801 sel_iter = gtk_tree_iter_copy (&child_iter);
1802 page++;
1803 i++;
1804 } while (cata[i]);
1806 i++;
1808 } while (cata[i]);
1810 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
1811 g_object_unref (G_OBJECT (model));
1812 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
1813 gtk_tree_selection_set_mode (sel, GTK_SELECTION_BROWSE);
1814 gtk_tree_selection_set_select_function (sel, setup_tree_select_filter,
1815 NULL, NULL);
1816 g_signal_connect (G_OBJECT (tree), "cursor_changed",
1817 G_CALLBACK (setup_tree_cb), book);
1819 renderer = gtk_cell_renderer_text_new ();
1820 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree),
1821 -1, _("Categories"), renderer, "text", 0, NULL);
1822 gtk_tree_view_expand_all (GTK_TREE_VIEW (tree));
1824 frame = gtk_frame_new (NULL);
1825 gtk_container_add (GTK_CONTAINER (frame), tree);
1826 gtk_box_pack_start (GTK_BOX (box), frame, 0, 0, 0);
1827 gtk_box_reorder_child (GTK_BOX (box), frame, 0);
1829 if (sel_iter)
1831 gtk_tree_selection_select_iter (sel, sel_iter);
1832 gtk_tree_iter_free (sel_iter);
1836 static void
1837 setup_apply_entry_style (GtkWidget *entry)
1839 gtk_widget_modify_base (entry, GTK_STATE_NORMAL, &colors[COL_BG]);
1840 gtk_widget_modify_text (entry, GTK_STATE_NORMAL, &colors[COL_FG]);
1841 gtk_widget_modify_font (entry, input_style->font_desc);
1844 static void
1845 setup_apply_to_sess (session_gui *gui)
1847 #ifdef USE_GTKSPELL
1848 GtkSpell *spell;
1849 #endif
1851 mg_update_xtext (gui->xtext);
1853 if (prefs.style_namelistgad)
1854 gtk_widget_set_style (gui->user_tree, input_style);
1856 if (prefs.style_inputbox)
1858 extern char cursor_color_rc[];
1859 char buf[256];
1860 sprintf (buf, cursor_color_rc,
1861 (colors[COL_FG].red >> 8),
1862 (colors[COL_FG].green >> 8),
1863 (colors[COL_FG].blue >> 8));
1864 gtk_rc_parse_string (buf);
1866 setup_apply_entry_style (gui->input_box);
1867 setup_apply_entry_style (gui->limit_entry);
1868 setup_apply_entry_style (gui->key_entry);
1869 setup_apply_entry_style (gui->topic_entry);
1872 if (prefs.userlistbuttons)
1873 gtk_widget_show (gui->button_box);
1874 else
1875 gtk_widget_hide (gui->button_box);
1877 #ifdef USE_GTKSPELL
1878 spell = gtkspell_get_from_text_view (GTK_TEXT_VIEW (gui->input_box));
1879 if (prefs.gui_input_spell)
1881 if (!spell)
1882 gtkspell_new_attach (GTK_TEXT_VIEW (gui->input_box), NULL, NULL);
1884 else
1886 if (spell)
1887 gtkspell_detach (spell);
1889 #endif
1891 #ifdef USE_LIBSEXY
1892 sexy_spell_entry_set_checked ((SexySpellEntry *)gui->input_box, prefs.gui_input_spell);
1893 #endif
1896 static void
1897 unslash (char *dir)
1899 if (dir[0])
1901 int len = strlen (dir) - 1;
1902 if (dir[len] == '/')
1903 dir[len] = 0;
1907 void
1908 setup_apply_real (int new_pix, int do_ulist, int do_layout)
1910 GSList *list;
1911 session *sess;
1912 int done_main = FALSE;
1914 /* remove trailing slashes */
1915 unslash (prefs.dccdir);
1916 unslash (prefs.dcc_completed_dir);
1918 mkdir_utf8 (prefs.dccdir);
1919 mkdir_utf8 (prefs.dcc_completed_dir);
1921 if (new_pix)
1923 if (channelwin_pix)
1924 g_object_unref (channelwin_pix);
1925 channelwin_pix = pixmap_load_from_file (prefs.background);
1928 input_style = create_input_style (input_style);
1930 list = sess_list;
1931 while (list)
1933 sess = list->data;
1934 if (sess->gui->is_tab)
1936 /* only apply to main tabwindow once */
1937 if (!done_main)
1939 done_main = TRUE;
1940 setup_apply_to_sess (sess->gui);
1942 } else
1944 setup_apply_to_sess (sess->gui);
1947 log_open_or_close (sess);
1949 if (do_ulist)
1950 userlist_rehash (sess);
1952 list = list->next;
1955 mg_apply_setup ();
1956 tray_apply_setup ();
1958 if (do_layout)
1959 menu_change_layout ();
1962 static void
1963 setup_apply (struct xchatprefs *pr)
1965 int new_pix = FALSE;
1966 int noapply = FALSE;
1967 int do_ulist = FALSE;
1968 int do_layout = FALSE;
1970 if (strcmp (pr->background, prefs.background) != 0)
1971 new_pix = TRUE;
1973 #define DIFF(a) (pr->a != prefs.a)
1975 if (DIFF (paned_userlist))
1976 noapply = TRUE;
1977 if (DIFF (lagometer))
1978 noapply = TRUE;
1979 if (DIFF (throttlemeter))
1980 noapply = TRUE;
1981 if (DIFF (showhostname_in_userlist))
1982 noapply = TRUE;
1983 if (DIFF (tab_small))
1984 noapply = TRUE;
1985 if (DIFF (tab_sort))
1986 noapply = TRUE;
1987 if (DIFF (use_server_tab))
1988 noapply = TRUE;
1989 if (DIFF (style_namelistgad))
1990 noapply = TRUE;
1991 if (DIFF (truncchans))
1992 noapply = TRUE;
1993 if (DIFF (tab_layout))
1994 do_layout = TRUE;
1996 if (color_change || (DIFF (away_size_max)) || (DIFF (away_track)))
1997 do_ulist = TRUE;
1999 if ((pr->tab_pos == 5 || pr->tab_pos == 6) &&
2000 pr->tab_layout == 2 && pr->tab_pos != prefs.tab_pos)
2001 fe_message (_("You cannot place the tree on the top or bottom!\n"
2002 "Please change to the <b>Tabs</b> layout in the <b>View</b>"
2003 " menu first."),
2004 FE_MSG_WARN | FE_MSG_MARKUP);
2006 memcpy (&prefs, pr, sizeof (prefs));
2008 setup_apply_real (new_pix, do_ulist, do_layout);
2010 if (noapply)
2011 fe_message (_("Some settings were changed that require a"
2012 " restart to take full effect."), FE_MSG_WARN);
2014 if (prefs.autodccsend == 1)
2016 if (!strcmp ((char *)g_get_home_dir (), prefs.dccdir))
2018 fe_message (_("*WARNING*\n"
2019 "Auto accepting DCC to your home directory\n"
2020 "can be dangerous and is exploitable. Eg:\n"
2021 "Someone could send you a .bash_profile"), FE_MSG_WARN);
2026 #if 0
2027 static void
2028 setup_apply_cb (GtkWidget *but, GtkWidget *win)
2030 /* setup_prefs -> xchat */
2031 setup_apply (&setup_prefs);
2033 #endif
2035 static void
2036 setup_ok_cb (GtkWidget *but, GtkWidget *win)
2038 setup_snd_apply ();
2039 gtk_widget_destroy (win);
2040 setup_apply (&setup_prefs);
2041 save_config ();
2042 palette_save ();
2045 static GtkWidget *
2046 setup_window_open (void)
2048 GtkWidget *wid, *win, *vbox, *hbox, *hbbox;
2050 win = gtkutil_window_new (_("XChat: Preferences"), "prefs", 0, 0, 3);
2052 vbox = gtk_vbox_new (FALSE, 5);
2053 gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
2054 gtk_container_add (GTK_CONTAINER (win), vbox);
2056 hbox = gtk_hbox_new (FALSE, 4);
2057 gtk_container_add (GTK_CONTAINER (vbox), hbox);
2059 setup_create_tree (hbox, setup_create_pages (hbox));
2061 hbox = gtk_hbox_new (FALSE, 0);
2062 gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
2064 /* prepare the button box */
2065 hbbox = gtk_hbutton_box_new ();
2066 gtk_box_set_spacing (GTK_BOX (hbbox), 4);
2067 gtk_box_pack_end (GTK_BOX (hbox), hbbox, FALSE, FALSE, 0);
2069 /* standard buttons */
2070 /* GNOME doesn't like apply */
2071 #if 0
2072 wid = gtk_button_new_from_stock (GTK_STOCK_APPLY);
2073 g_signal_connect (G_OBJECT (wid), "clicked",
2074 G_CALLBACK (setup_apply_cb), win);
2075 gtk_box_pack_start (GTK_BOX (hbbox), wid, FALSE, FALSE, 0);
2076 #endif
2078 cancel_button = wid = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
2079 g_signal_connect (G_OBJECT (wid), "clicked",
2080 G_CALLBACK (gtkutil_destroy), win);
2081 gtk_box_pack_start (GTK_BOX (hbbox), wid, FALSE, FALSE, 0);
2083 wid = gtk_button_new_from_stock (GTK_STOCK_OK);
2084 g_signal_connect (G_OBJECT (wid), "clicked",
2085 G_CALLBACK (setup_ok_cb), win);
2086 gtk_box_pack_start (GTK_BOX (hbbox), wid, FALSE, FALSE, 0);
2088 wid = gtk_hseparator_new ();
2089 gtk_box_pack_end (GTK_BOX (vbox), wid, FALSE, FALSE, 0);
2091 gtk_widget_show_all (win);
2093 return win;
2096 static void
2097 setup_close_cb (GtkWidget *win, GtkWidget **swin)
2099 *swin = NULL;
2101 if (font_dialog)
2103 gtk_widget_destroy (font_dialog);
2104 font_dialog = NULL;
2108 void
2109 setup_open (void)
2111 static GtkWidget *setup_window = NULL;
2113 if (setup_window)
2115 gtk_window_present (GTK_WINDOW (setup_window));
2116 return;
2119 memcpy (&setup_prefs, &prefs, sizeof (prefs));
2121 color_change = FALSE;
2122 setup_window = setup_window_open ();
2124 g_signal_connect (G_OBJECT (setup_window), "destroy",
2125 G_CALLBACK (setup_close_cb), &setup_window);