fix implicit declarations
[rofl0r-ixchat.git] / src / fe-gtk / setup.c
bloba42f823611354e9b6002aec488f1730418b28081
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"
24 #include "setup.h"
25 #include "plugin-tray.h"
27 #include <gtk/gtkcolorseldialog.h>
28 #include <gtk/gtktable.h>
29 #include <gtk/gtkentry.h>
30 #include <gtk/gtklabel.h>
31 #include <gtk/gtkmisc.h>
32 #include <gtk/gtkhbox.h>
33 #include <gtk/gtkvbox.h>
34 #include <gtk/gtkalignment.h>
35 #include <gtk/gtknotebook.h>
36 #include <gtk/gtkframe.h>
37 #include <gtk/gtkfontsel.h>
38 #include <gtk/gtkcheckbutton.h>
39 #include <gtk/gtkscrolledwindow.h>
40 #include <gtk/gtkspinbutton.h>
41 #include <gtk/gtkstock.h>
42 #include <gtk/gtktreeview.h>
43 #include <gtk/gtkhbbox.h>
44 #include <gtk/gtkhseparator.h>
45 #include <gtk/gtkradiobutton.h>
46 #include <gtk/gtkcombobox.h>
47 #include <gtk/gtkliststore.h>
48 #include <gtk/gtktreestore.h>
49 #include <gtk/gtktreeselection.h>
50 #include <gtk/gtkcellrenderertext.h>
51 #include <gtk/gtkhscale.h>
52 #ifdef USE_GTKSPELL
53 #include <gtk/gtktextview.h>
54 #include <gtkspell/gtkspell.h>
55 #endif
56 #ifdef USE_LIBSEXY
57 #include "sexy-spell-entry.h"
58 #endif
60 GtkStyle *create_input_style (GtkStyle *);
62 #define LABEL_INDENT 12
64 static int last_selected_page = 0;
65 static int last_selected_row = 0; /* sound row */
66 static gboolean color_change;
67 static struct xchatprefs setup_prefs;
68 static GtkWidget *cancel_button;
69 static GtkWidget *font_dialog = NULL;
71 enum
73 ST_END,
74 ST_TOGGLE,
75 ST_TOGGLR,
76 ST_3OGGLE,
77 ST_ENTRY,
78 ST_EFONT,
79 ST_EFILE,
80 ST_EFOLDER,
81 ST_MENU,
82 ST_RADIO,
83 ST_NUMBER,
84 ST_HSCALE,
85 ST_HEADER,
86 ST_LABEL,
87 ST_ALERTHEAD
90 typedef struct
92 int type;
93 char *label;
94 int offset;
95 char *tooltip;
96 char const *const *list;
97 int extra;
98 } setting;
101 static const setting textbox_settings[] =
103 {ST_HEADER, N_("Text Box Appearance"),0,0,0},
104 {ST_EFONT, N_("Font:"), P_OFFSETNL(font_normal), 0, 0, sizeof prefs.font_normal},
105 {ST_EFILE, N_("Background image:"), P_OFFSETNL(background), 0, 0, sizeof prefs.background},
106 {ST_NUMBER, N_("Scrollback lines:"), P_OFFINTNL(max_lines),0,0,100000},
107 {ST_TOGGLE, N_("Colored nick names"), P_OFFINTNL(colorednicks),
108 N_("Give each person on IRC a different color"),0,0},
109 {ST_TOGGLR, N_("Indent nick names"), P_OFFINTNL(indent_nicks),
110 N_("Make nick names right-justified"),0,0},
111 {ST_TOGGLE, N_("Transparent background"), P_OFFINTNL(transparent),0,0,0},
112 {ST_TOGGLR, N_("Show marker line"), P_OFFINTNL(show_marker),
113 N_("Insert a red line after the last read text."),0,0},
114 {ST_HEADER, N_("Transparency Settings"), 0,0,0},
115 {ST_HSCALE, N_("Red:"), P_OFFINTNL(tint_red),0,0,0},
116 {ST_HSCALE, N_("Green:"), P_OFFINTNL(tint_green),0,0,0},
117 {ST_HSCALE, N_("Blue:"), P_OFFINTNL(tint_blue),0,0,0},
119 {ST_HEADER, N_("Time Stamps"),0,0,0},
120 {ST_TOGGLE, N_("Enable time stamps"), P_OFFINTNL(timestamp),0,0,2},
121 {ST_ENTRY, N_("Time stamp format:"), P_OFFSETNL(stamp_format),
122 N_("See strftime manpage for details."),0,sizeof prefs.stamp_format},
124 {ST_END, 0, 0, 0, 0, 0}
127 static const char *const tabcompmenu[] =
129 N_("A-Z"),
130 N_("Last-spoke order"),
131 NULL
134 static const setting inputbox_settings[] =
136 {ST_HEADER, N_("Input box"),0,0,0},
137 {ST_TOGGLE, N_("Use the Text box font and colors"), P_OFFINTNL(style_inputbox),0,0,0},
138 #if defined(USE_GTKSPELL) || defined(USE_LIBSEXY)
139 {ST_TOGGLE, N_("Spell checking"), P_OFFINTNL(gui_input_spell),0,0,0},
140 #endif
142 {ST_HEADER, N_("Nick Completion"),0,0,0},
143 {ST_TOGGLE, N_("Automatic nick completion (without TAB key)"), P_OFFINTNL(nickcompletion),
144 0,0,0},
145 {ST_ENTRY, N_("Nick completion suffix:"), P_OFFSETNL(nick_suffix),0,0,sizeof prefs.nick_suffix},
146 {ST_MENU, N_("Nick completion sorted:"), P_OFFINTNL(completion_sort), 0, tabcompmenu, 0},
148 #if 0 /* obsolete */
149 {ST_HEADER, N_("Input Box Codes"),0,0,0},
150 {ST_TOGGLE, N_("Interpret %nnn as an ASCII value"), P_OFFINTNL(perc_ascii),0,0,0},
151 {ST_TOGGLE, N_("Interpret %C, %B as Color, Bold etc"), P_OFFINTNL(perc_color),0,0,0},
152 #endif
154 {ST_END, 0, 0, 0, 0, 0}
157 /*static const char *const lagmenutext[] =
159 N_("Off"),
160 N_("Graph"),
161 N_("Info text"),
162 N_("Both"),
163 NULL
164 };*/
166 static const char *const ulmenutext[] =
168 N_("A-Z, Ops first"),
169 N_("A-Z"),
170 N_("Z-A, Ops last"),
171 N_("Z-A"),
172 N_("Unsorted"),
173 NULL
176 static const char *const cspos[] =
178 N_("Left (Upper)"),
179 N_("Left (Lower)"),
180 N_("Right (Upper)"),
181 N_("Right (Lower)"),
182 N_("Top"),
183 N_("Bottom"),
184 N_("Hidden"),
185 NULL
188 static const char *const ulpos[] =
190 N_("Left (Upper)"),
191 N_("Left (Lower)"),
192 N_("Right (Upper)"),
193 N_("Right (Lower)"),
194 NULL
197 static const setting userlist_settings[] =
199 {ST_HEADER, N_("User List"),0,0,0},
200 {ST_TOGGLE, N_("Show hostnames in user list"), P_OFFINTNL(showhostname_in_userlist), 0, 0, 0},
201 {ST_TOGGLE, N_("Use the Text box font and colors"), P_OFFINTNL(style_namelistgad),0,0,0},
202 /* {ST_TOGGLE, N_("Resizable user list"), P_OFFINTNL(paned_userlist),0,0,0},*/
203 {ST_MENU, N_("User list sorted by:"), P_OFFINTNL(userlist_sort), 0, ulmenutext, 0},
204 {ST_MENU, N_("Show user list at:"), P_OFFINTNL(gui_ulist_pos), 0, ulpos, 1},
206 {ST_HEADER, N_("Away tracking"),0,0,0},
207 {ST_TOGGLE, N_("Track the Away status of users and mark them in a different color"), P_OFFINTNL(away_track),0,0,2},
208 {ST_NUMBER, N_("On channels smaller than:"), P_OFFINTNL(away_size_max),0,0,10000},
210 {ST_HEADER, N_("Action Upon Double Click"),0,0,0},
211 {ST_ENTRY, N_("Execute command:"), P_OFFSETNL(doubleclickuser), 0, 0, sizeof prefs.doubleclickuser},
213 /* {ST_HEADER, N_("Extra Gadgets"),0,0,0},
214 {ST_MENU, N_("Lag meter:"), P_OFFINTNL(lagometer), 0, lagmenutext, 0},
215 {ST_MENU, N_("Throttle meter:"), P_OFFINTNL(throttlemeter), 0, lagmenutext, 0},*/
217 {ST_END, 0, 0, 0, 0, 0}
220 static const char *const tabwin[] =
222 N_("Windows"),
223 N_("Tabs"),
224 NULL
227 static const char *const focusnewtabsmenu[] =
229 N_("Never"),
230 N_("Always"),
231 N_("Only requested tabs"),
232 NULL
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 {ST_MENU, N_("Focus new tabs:"), P_OFFINTNL(newtabstofront), 0, focusnewtabsmenu, 0},
253 {ST_MENU, N_("Show channel switcher at:"), P_OFFINTNL(tab_pos), 0, cspos, 1},
254 {ST_NUMBER, N_("Shorten tab labels to:"), P_OFFINTNL(truncchans), 0, (const char **)N_("letters."), 99},
256 {ST_HEADER, N_("Tabs or Windows"),0,0,0},
257 {ST_MENU, N_("Open channels in:"), P_OFFINTNL(tabchannels), 0, tabwin, 0},
258 {ST_MENU, N_("Open dialogs in:"), P_OFFINTNL(privmsgtab), 0, tabwin, 0},
259 {ST_MENU, N_("Open utilities in:"), P_OFFINTNL(windows_as_tabs), N_("Open DCC, Ignore, Notify etc, in tabs or windows?"), tabwin, 0},
261 {ST_END, 0, 0, 0, 0, 0}
264 static const char *const dccaccept[] =
266 N_("No"),
267 N_("Yes"),
268 N_("Browse for save folder every time"),
269 NULL
272 static const setting filexfer_settings[] =
274 {ST_HEADER, N_("Files and Directories"), 0, 0, 0},
275 {ST_MENU, N_("Auto accept file offers:"), P_OFFINTNL(autodccsend), 0, dccaccept, 0},
276 {ST_EFOLDER,N_("Download files to:"), P_OFFSETNL(dccdir), 0, 0, sizeof prefs.dccdir},
277 {ST_EFOLDER,N_("Move completed files to:"), P_OFFSETNL(dcc_completed_dir), 0, 0, sizeof prefs.dcc_completed_dir},
278 {ST_TOGGLE, N_("Save nick name in filenames"), P_OFFINTNL(dccwithnick), 0, 0, 0},
280 {ST_HEADER, N_("Network Settings"), 0, 0, 0},
281 {ST_TOGGLE, N_("Get my address from the IRC server"), P_OFFINTNL(ip_from_server),
282 N_("Asks the IRC server for your real address. Use this if you have a 192.168.*.* address!"), 0, 0},
283 {ST_ENTRY, N_("DCC IP address:"), P_OFFSETNL(dcc_ip_str),
284 N_("Claim you are at this address when offering files."), 0, sizeof prefs.dcc_ip_str},
285 {ST_NUMBER, N_("First DCC send port:"), P_OFFINTNL(first_dcc_send_port), 0, 0, 65535},
286 {ST_NUMBER, N_("Last DCC send port:"), P_OFFINTNL(last_dcc_send_port), 0,
287 (const char **)N_("!Leave ports at zero for full range."), 65535},
289 {ST_HEADER, N_("Maximum File Transfer Speeds (bytes per second)"), 0, 0, 0},
290 {ST_NUMBER, N_("One upload:"), P_OFFINTNL(dcc_max_send_cps),
291 N_("Maximum speed for one transfer"), 0, 1000000},
292 {ST_NUMBER, N_("One download:"), P_OFFINTNL(dcc_max_get_cps),
293 N_("Maximum speed for one transfer"), 0, 1000000},
294 {ST_NUMBER, N_("All uploads combined:"), P_OFFINTNL(dcc_global_max_send_cps),
295 N_("Maximum speed for all files"), 0, 1000000},
296 {ST_NUMBER, N_("All downloads combined:"), P_OFFINTNL(dcc_global_max_get_cps),
297 N_("Maximum speed for all files"), 0, 1000000},
299 {ST_END, 0, 0, 0, 0, 0}
302 static const int balloonlist[3] =
304 P_OFFINTNL(input_balloon_chans), P_OFFINTNL(input_balloon_priv), P_OFFINTNL(input_balloon_hilight)
307 static const int trayblinklist[3] =
309 P_OFFINTNL(input_tray_chans), P_OFFINTNL(input_tray_priv), P_OFFINTNL(input_tray_hilight)
312 static const int taskbarlist[3] =
314 P_OFFINTNL(input_flash_chans), P_OFFINTNL(input_flash_priv), P_OFFINTNL(input_flash_hilight)
317 static const int beeplist[3] =
319 P_OFFINTNL(input_beep_chans), P_OFFINTNL(input_beep_priv), P_OFFINTNL(input_beep_hilight)
322 static const setting alert_settings[] =
324 {ST_HEADER, N_("Alerts"),0,0,0},
326 {ST_ALERTHEAD},
327 {ST_3OGGLE, N_("Show tray balloons on:"), 0, 0, (void *)balloonlist, 0},
328 {ST_3OGGLE, N_("Blink tray icon on:"), 0, 0, (void *)trayblinklist, 0},
329 {ST_3OGGLE, N_("Blink task bar on:"), 0, 0, (void *)taskbarlist, 0},
330 {ST_3OGGLE, N_("Make a beep sound on:"), 0, 0, (void *)beeplist, 0},
332 {ST_TOGGLE, N_("Enable system tray icon"), P_OFFINTNL(gui_tray), 0, 0, 0},
334 {ST_HEADER, N_("Highlighted Messages"),0,0,0},
335 {ST_LABEL, N_("Highlighted messages are ones where your nickname is mentioned, but also:"), 0, 0, 0, 1},
337 {ST_ENTRY, N_("Extra words to highlight:"), P_OFFSETNL(irc_extra_hilight), 0, 0, sizeof prefs.irc_extra_hilight},
338 {ST_ENTRY, N_("Nick names not to highlight:"), P_OFFSETNL(irc_no_hilight), 0, 0, sizeof prefs.irc_no_hilight},
339 {ST_ENTRY, N_("Nick names to always highlight:"), P_OFFSETNL(irc_nick_hilight), 0, 0, sizeof prefs.irc_nick_hilight},
340 {ST_LABEL, N_("Separate multiple words with commas.\nWildcards are accepted.")},
341 {ST_END, 0, 0, 0, 0, 0}
344 static const setting general_settings[] =
346 {ST_HEADER, N_("Default Messages"),0,0,0},
347 {ST_ENTRY, N_("Quit:"), P_OFFSETNL(quitreason), 0, 0, sizeof prefs.quitreason},
348 {ST_ENTRY, N_("Leave channel:"), P_OFFSETNL(partreason), 0, 0, sizeof prefs.partreason},
349 {ST_ENTRY, N_("Away:"), P_OFFSETNL(awayreason), 0, 0, sizeof prefs.awayreason},
351 {ST_HEADER, N_("Away"),0,0,0},
352 {ST_TOGGLE, N_("Announce away messages"), P_OFFINTNL(show_away_message),
353 N_("Announce your away messages to all channels"), 0, 0},
354 {ST_TOGGLE, N_("Show away once"), P_OFFINTNL(show_away_once), N_("Show identical away messages only once"), 0, 0},
355 {ST_TOGGLE, N_("Automatically unmark away"), P_OFFINTNL(auto_unmark_away), N_("Unmark yourself as away before sending messages"), 0, 0},
356 {ST_END, 0, 0, 0, 0, 0}
359 #if 0
360 static const setting advanced_settings[] =
362 {ST_HEADER, N_("Advanced Settings"),0,0,0},
363 {ST_NUMBER, N_("Auto reconnect delay:"), P_OFFINTNL(recon_delay), 0, 0, 9999},
364 {ST_TOGGLE, N_("Display MODEs in raw form"), P_OFFINTNL(raw_modes), 0, 0, 0},
365 {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},
366 {ST_TOGGLE, N_("Hide join and part messages"), P_OFFINTNL(confmode), N_("Hide channel join/part messages by default"), 0, 0},
367 {ST_HEADER, N_("Auto Open DCC Windows"),0,0,0},
368 {ST_TOGGLE, N_("Send window"), P_OFFINTNL(autoopendccsendwindow), 0, 0, 0},
369 {ST_TOGGLE, N_("Receive window"), P_OFFINTNL(autoopendccrecvwindow), 0, 0, 0},
370 {ST_TOGGLE, N_("Chat window"), P_OFFINTNL(autoopendccchatwindow), 0, 0, 0},
372 {ST_END, 0, 0, 0, 0, 0}
374 #endif
376 static const setting logging_settings[] =
378 {ST_HEADER, N_("Logging"),0,0,0},
379 {ST_TOGGLE, N_("Display scrollback from previous session"), P_OFFINTNL(text_replay), 0, 0, 0},
380 {ST_TOGGLE, N_("Enable logging of conversations to disk"), P_OFFINTNL(logging), 0, 0, 2},
381 {ST_ENTRY, N_("Log filename:"), P_OFFSETNL(logmask), 0, 0, sizeof prefs.logmask},
382 {ST_LABEL, N_("%s=Server %c=Channel %n=Network.")},
384 {ST_HEADER, N_("Time Stamps"),0,0,0},
385 {ST_TOGGLE, N_("Insert timestamps in logs"), P_OFFINTNL(timestamp_logs), 0, 0, 2},
386 {ST_ENTRY, N_("Log timestamp format:"), P_OFFSETNL(timestamp_log_format), 0, 0, sizeof prefs.timestamp_log_format},
387 {ST_LABEL, N_("See strftime manpage for details.")},
389 {ST_END, 0, 0, 0, 0, 0}
392 static const char *const proxytypes[] =
394 N_("(Disabled)"),
395 N_("Wingate"),
396 N_("Socks4"),
397 N_("Socks5"),
398 N_("HTTP"),
399 #ifdef USE_MSPROXY
400 N_("MS Proxy (ISA)"),
401 #endif
402 #ifdef USE_LIBPROXY
403 N_("Auto"),
404 #endif
405 NULL
408 static const char *const proxyuse[] =
410 N_("All Connections"),
411 N_("IRC Server Only"),
412 N_("DCC Get Only"),
413 NULL
416 static const setting network_settings[] =
418 {ST_HEADER, N_("Your Address"), 0, 0, 0, 0},
419 {ST_ENTRY, N_("Bind to:"), P_OFFSETNL(hostname), 0, 0, sizeof prefs.hostname},
420 {ST_LABEL, N_("Only useful for computers with multiple addresses.")},
422 {ST_HEADER, N_("Proxy Server"), 0, 0, 0, 0},
423 {ST_ENTRY, N_("Hostname:"), P_OFFSETNL(proxy_host), 0, 0, sizeof prefs.proxy_host},
424 {ST_NUMBER, N_("Port:"), P_OFFINTNL(proxy_port), 0, 0, 65535},
425 {ST_MENU, N_("Type:"), P_OFFINTNL(proxy_type), 0, proxytypes, 0},
426 {ST_MENU, N_("Use proxy for:"), P_OFFINTNL(proxy_use), 0, proxyuse, 0},
428 {ST_HEADER, N_("Proxy Authentication"), 0, 0, 0, 0},
429 #ifdef USE_MSPROXY
430 {ST_TOGGLE, N_("Use Authentication (MS Proxy, HTTP or Socks5 only)"), P_OFFINTNL(proxy_auth), 0, 0, 0},
431 #else
432 {ST_TOGGLE, N_("Use Authentication (HTTP or Socks5 only)"), P_OFFINTNL(proxy_auth), 0, 0, 0},
433 #endif
434 {ST_ENTRY, N_("Username:"), P_OFFSETNL(proxy_user), 0, 0, sizeof prefs.proxy_user},
435 {ST_ENTRY, N_("Password:"), P_OFFSETNL(proxy_pass), 0, GINT_TO_POINTER(1), sizeof prefs.proxy_pass},
437 {ST_END, 0, 0, 0, 0, 0}
440 #define setup_get_str(pr,set) (((char *)pr)+set->offset)
441 #define setup_get_int(pr,set) *(((int *)pr)+set->offset)
442 #define setup_get_int3(pr,off) *(((int *)pr)+off)
444 #define setup_set_int(pr,set,num) *((int *)pr+set->offset)=num
445 #define setup_set_str(pr,set,str) strcpy(((char *)pr)+set->offset,str)
448 static void
449 setup_3oggle_cb (GtkToggleButton *but, unsigned int *setting)
451 *setting = but->active;
454 static void
455 setup_headlabel (GtkWidget *tab, int row, int col, char *text)
457 GtkWidget *label;
458 char buf[128];
459 char *sp;
461 snprintf (buf, sizeof (buf), "<b><span size=\"smaller\">%s</span></b>", text);
462 sp = strchr (buf + 17, ' ');
463 if (sp)
464 *sp = '\n';
466 label = gtk_label_new (NULL);
467 gtk_label_set_markup (GTK_LABEL (label), buf);
468 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
469 gtk_table_attach (GTK_TABLE (tab), label, col, col + 1, row, row + 1, 0, 0, 4, 0);
472 static void
473 setup_create_alert_header (GtkWidget *tab, int row, const setting *set)
475 setup_headlabel (tab, row, 3, _("Channel Message"));
476 setup_headlabel (tab, row, 4, _("Private Message"));
477 setup_headlabel (tab, row, 5, _("Highlighted Message"));
480 /* makes 3 toggles side-by-side */
482 static void
483 setup_create_3oggle (GtkWidget *tab, int row, const setting *set)
485 GtkWidget *label, *wid;
486 int *offsets = (int *)set->list;
488 label = gtk_label_new (_(set->label));
489 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
490 gtk_table_attach (GTK_TABLE (tab), label, 2, 3, row, row + 1,
491 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
493 wid = gtk_check_button_new ();
494 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
495 setup_get_int3 (&setup_prefs, offsets[0]));
496 g_signal_connect (G_OBJECT (wid), "toggled",
497 G_CALLBACK (setup_3oggle_cb), ((int *)&setup_prefs) + offsets[0]);
498 gtk_table_attach (GTK_TABLE (tab), wid, 3, 4, row, row + 1, 0, 0, 0, 0);
500 wid = gtk_check_button_new ();
501 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
502 setup_get_int3 (&setup_prefs, offsets[1]));
503 g_signal_connect (G_OBJECT (wid), "toggled",
504 G_CALLBACK (setup_3oggle_cb), ((int *)&setup_prefs) + offsets[1]);
505 gtk_table_attach (GTK_TABLE (tab), wid, 4, 5, row, row + 1, 0, 0, 0, 0);
507 wid = gtk_check_button_new ();
508 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
509 setup_get_int3 (&setup_prefs, offsets[2]));
510 g_signal_connect (G_OBJECT (wid), "toggled",
511 G_CALLBACK (setup_3oggle_cb), ((int *)&setup_prefs) + offsets[2]);
512 gtk_table_attach (GTK_TABLE (tab), wid, 5, 6, row, row + 1, 0, 0, 0, 0);
515 static void
516 setup_toggle_cb (GtkToggleButton *but, const setting *set)
518 GtkWidget *label, *disable_wid;
520 setup_set_int (&setup_prefs, set, but->active ? 1 : 0);
522 /* does this toggle also enable/disable another widget? */
523 disable_wid = g_object_get_data (G_OBJECT (but), "nxt");
524 if (disable_wid)
526 gtk_widget_set_sensitive (disable_wid, but->active);
527 label = g_object_get_data (G_OBJECT (disable_wid), "lbl");
528 gtk_widget_set_sensitive (label, but->active);
532 static void
533 setup_create_toggleR (GtkWidget *tab, int row, const setting *set)
535 GtkWidget *wid;
537 wid = gtk_check_button_new_with_label (_(set->label));
538 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
539 setup_get_int (&setup_prefs, set));
540 g_signal_connect (G_OBJECT (wid), "toggled",
541 G_CALLBACK (setup_toggle_cb), (gpointer)set);
542 if (set->tooltip)
543 add_tip (wid, _(set->tooltip));
544 gtk_table_attach (GTK_TABLE (tab), wid, 4, 5, row, row + 1,
545 GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
548 static GtkWidget *
549 setup_create_toggleL (GtkWidget *tab, int row, const setting *set)
551 GtkWidget *wid;
553 wid = gtk_check_button_new_with_label (_(set->label));
554 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
555 setup_get_int (&setup_prefs, set));
556 g_signal_connect (G_OBJECT (wid), "toggled",
557 G_CALLBACK (setup_toggle_cb), (gpointer)set);
558 if (set->tooltip)
559 add_tip (wid, _(set->tooltip));
560 gtk_table_attach (GTK_TABLE (tab), wid, 2, row==6 ? 6 : 4, row, row + 1,
561 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
563 return wid;
566 #if 0
567 static void
568 setup_create_toggle (GtkWidget *box, int row, const setting *set)
570 GtkWidget *wid;
572 wid = gtk_check_button_new_with_label (_(set->label));
573 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
574 setup_get_int (&setup_prefs, set));
575 g_signal_connect (G_OBJECT (wid), "toggled",
576 G_CALLBACK (setup_toggle_cb), (gpointer)set);
577 if (set->tooltip)
578 add_tip (wid, _(set->tooltip));
579 gtk_box_pack_start (GTK_BOX (box), wid, 0, 0, 0);
581 #endif
583 static GtkWidget *
584 setup_create_italic_label (char *text)
586 GtkWidget *label;
587 char buf[256];
589 label = gtk_label_new (NULL);
590 snprintf (buf, sizeof (buf), "<i><span size=\"smaller\">%s</span></i>", text);
591 gtk_label_set_markup (GTK_LABEL (label), buf);
592 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
594 return label;
597 static void
598 setup_spin_cb (GtkSpinButton *spin, const setting *set)
600 setup_set_int (&setup_prefs, set, gtk_spin_button_get_value_as_int (spin));
603 static GtkWidget *
604 setup_create_spin (GtkWidget *table, int row, const setting *set)
606 GtkWidget *label, *wid, *rbox, *align;
607 char *text;
609 label = gtk_label_new (_(set->label));
610 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
611 gtk_table_attach (GTK_TABLE (table), label, 2, 3, row, row + 1,
612 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
614 align = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
615 gtk_table_attach (GTK_TABLE (table), align, 3, 4, row, row + 1,
616 GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
618 rbox = gtk_hbox_new (0, 0);
619 gtk_container_add (GTK_CONTAINER (align), rbox);
621 wid = gtk_spin_button_new_with_range (0, set->extra, 1);
622 g_object_set_data (G_OBJECT (wid), "lbl", label);
623 if (set->tooltip)
624 add_tip (wid, _(set->tooltip));
625 gtk_spin_button_set_value (GTK_SPIN_BUTTON (wid),
626 setup_get_int (&setup_prefs, set));
627 g_signal_connect (G_OBJECT (wid), "value_changed",
628 G_CALLBACK (setup_spin_cb), (gpointer)set);
629 gtk_box_pack_start (GTK_BOX (rbox), wid, 0, 0, 0);
631 if (set->list)
633 text = _((char *)set->list);
634 if (text[0] == '!')
635 label = setup_create_italic_label (text + 1);
636 else
637 label = gtk_label_new (text);
638 gtk_box_pack_start (GTK_BOX (rbox), label, 0, 0, 6);
641 return wid;
644 static gint
645 setup_apply_tint (int *tag)
647 prefs.tint_red = setup_prefs.tint_red;
648 prefs.tint_green = setup_prefs.tint_green;
649 prefs.tint_blue = setup_prefs.tint_blue;
650 mg_update_xtext (current_sess->gui->xtext);
651 *tag = 0;
652 return 0;
655 static void
656 setup_hscale_cb (GtkHScale *wid, const setting *set)
658 static int tag = 0;
660 setup_set_int (&setup_prefs, set, gtk_range_get_value(GTK_RANGE(wid)));
661 if(tag == 0)
662 tag = g_idle_add ((GSourceFunc)setup_apply_tint, &tag);
665 static void
666 setup_create_hscale (GtkWidget *table, int row, const setting *set)
668 GtkWidget *wid;
670 wid = gtk_label_new (_(set->label));
671 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5);
672 gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1,
673 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
675 wid = gtk_hscale_new_with_range (0., 255., 1.);
676 gtk_scale_set_value_pos (GTK_SCALE (wid), GTK_POS_RIGHT);
677 gtk_range_set_value (GTK_RANGE (wid), setup_get_int (&setup_prefs, set));
678 g_signal_connect (G_OBJECT(wid), "value_changed",
679 G_CALLBACK (setup_hscale_cb), (gpointer)set);
680 gtk_table_attach (GTK_TABLE (table), wid, 3, 6, row, row + 1,
681 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
685 static GtkWidget *proxy_user; /* username GtkEntry */
686 static GtkWidget *proxy_pass; /* password GtkEntry */
688 static void
689 setup_menu_cb (GtkWidget *cbox, const setting *set)
691 int n = gtk_combo_box_get_active (GTK_COMBO_BOX (cbox));
693 /* set the prefs.<field> */
694 setup_set_int (&setup_prefs, set, n + set->extra);
696 if (set->list == proxytypes)
698 /* only HTTP and Socks5 can use a username/pass */
699 gtk_widget_set_sensitive (proxy_user, (n == 3 || n == 4 || n == 5));
700 gtk_widget_set_sensitive (proxy_pass, (n == 3 || n == 4 || n == 5));
704 static void
705 setup_radio_cb (GtkWidget *item, const setting *set)
707 if (GTK_TOGGLE_BUTTON (item)->active)
709 int n = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "n"));
710 /* set the prefs.<field> */
711 setup_set_int (&setup_prefs, set, n);
715 static int
716 setup_create_radio (GtkWidget *table, int row, const setting *set)
718 GtkWidget *wid, *hbox;
719 int i;
720 const char **text = (const char **)set->list;
721 GSList *group;
723 wid = gtk_label_new (_(set->label));
724 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5);
725 gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1,
726 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
728 hbox = gtk_hbox_new (0, 0);
729 gtk_table_attach (GTK_TABLE (table), hbox, 3, 4, row, row + 1,
730 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
732 i = 0;
733 group = NULL;
734 while (text[i])
736 if (text[i][0] != 0)
738 wid = gtk_radio_button_new_with_mnemonic (group, _(text[i]));
739 /*if (set->tooltip)
740 add_tip (wid, _(set->tooltip));*/
741 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (wid));
742 gtk_container_add (GTK_CONTAINER (hbox), wid);
743 if (i == setup_get_int (&setup_prefs, set))
744 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid), TRUE);
745 g_object_set_data (G_OBJECT (wid), "n", GINT_TO_POINTER (i));
746 g_signal_connect (G_OBJECT (wid), "toggled",
747 G_CALLBACK (setup_radio_cb), (gpointer)set);
749 i++;
750 row++;
753 return i;
757 static const char *id_strings[] =
760 "*",
761 "%C4*%C18%B%B",
762 "%U"
765 static void
766 setup_id_menu_cb (GtkWidget *item, char *dest)
768 int n = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "n"));
770 strcpy (dest, id_strings[n]);
773 static void
774 setup_create_id_menu (GtkWidget *table, char *label, int row, char *dest)
776 GtkWidget *wid, *menu, *item;
777 int i, def = 0;
778 static const char *text[] =
780 ("(disabled)"),
781 ("A star (*)"),
782 ("A red star (*)"),
783 ("Underlined")
786 wid = gtk_label_new (label);
787 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5);
788 gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1,
789 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
791 wid = gtk_option_menu_new ();
792 menu = gtk_menu_new ();
794 for (i = 0; i < 4; i++)
796 if (strcmp (id_strings[i], dest) == 0)
798 def = i;
799 break;
803 i = 0;
804 while (text[i])
806 item = gtk_menu_item_new_with_label (_(text[i]));
807 g_object_set_data (G_OBJECT (item), "n", GINT_TO_POINTER (i));
809 gtk_widget_show (item);
810 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
811 g_signal_connect (G_OBJECT (item), "activate",
812 G_CALLBACK (setup_id_menu_cb), dest);
813 i++;
816 gtk_option_menu_set_menu (GTK_OPTION_MENU (wid), menu);
817 gtk_option_menu_set_history (GTK_OPTION_MENU (wid), def);
819 gtk_table_attach (GTK_TABLE (table), wid, 3, 4, row, row + 1,
820 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
825 static void
826 setup_create_menu (GtkWidget *table, int row, const setting *set)
828 GtkWidget *wid, *cbox, *box;
829 const char **text = (const char **)set->list;
830 int i;
832 wid = gtk_label_new (_(set->label));
833 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5);
834 gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1,
835 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
837 cbox = gtk_combo_box_new_text ();
839 for (i = 0; text[i]; i++)
840 gtk_combo_box_append_text (GTK_COMBO_BOX (cbox), _(text[i]));
842 gtk_combo_box_set_active (GTK_COMBO_BOX (cbox),
843 setup_get_int (&setup_prefs, set) - set->extra);
844 g_signal_connect (G_OBJECT (cbox), "changed",
845 G_CALLBACK (setup_menu_cb), (gpointer)set);
847 box = gtk_hbox_new (0, 0);
848 gtk_box_pack_start (GTK_BOX (box), cbox, 0, 0, 0);
849 gtk_table_attach (GTK_TABLE (table), box, 3, 4, row, row + 1,
850 GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
853 static void
854 setup_filereq_cb (GtkWidget *entry, char *file)
856 if (file)
858 if (file[0])
859 gtk_entry_set_text (GTK_ENTRY (entry), file);
863 static void
864 setup_browsefile_cb (GtkWidget *button, GtkWidget *entry)
866 gtkutil_file_req (_("Select an Image File"), setup_filereq_cb, entry, NULL, 0);
869 static void
870 setup_fontsel_destroy (GtkWidget *button, GtkFontSelectionDialog *dialog)
872 font_dialog = NULL;
875 static void
876 setup_fontsel_cb (GtkWidget *button, GtkFontSelectionDialog *dialog)
878 GtkWidget *entry;
879 char *font_name;
881 entry = g_object_get_data (G_OBJECT (button), "e");
882 font_name = gtk_font_selection_dialog_get_font_name (dialog);
884 gtk_entry_set_text (GTK_ENTRY (entry), font_name);
886 g_free (font_name);
887 gtk_widget_destroy (GTK_WIDGET (dialog));
888 font_dialog = NULL;
891 static void
892 setup_fontsel_cancel (GtkWidget *button, GtkFontSelectionDialog *dialog)
894 gtk_widget_destroy (GTK_WIDGET (dialog));
895 font_dialog = NULL;
898 static void
899 setup_browsefolder_cb (GtkWidget *button, GtkEntry *entry)
901 gtkutil_file_req (_("Select Download Folder"), setup_filereq_cb, entry, entry->text, FRF_CHOOSEFOLDER);
904 static void
905 setup_browsefont_cb (GtkWidget *button, GtkWidget *entry)
907 GtkFontSelection *sel;
908 GtkFontSelectionDialog *dialog;
910 dialog = (GtkFontSelectionDialog *) gtk_font_selection_dialog_new (_("Select font"));
911 font_dialog = (GtkWidget *)dialog; /* global var */
913 sel = (GtkFontSelection *) dialog->fontsel;
915 if (GTK_ENTRY (entry)->text[0])
916 gtk_font_selection_set_font_name (sel, GTK_ENTRY (entry)->text);
918 g_object_set_data (G_OBJECT (dialog->ok_button), "e", entry);
920 g_signal_connect (G_OBJECT (dialog), "destroy",
921 G_CALLBACK (setup_fontsel_destroy), dialog);
922 g_signal_connect (G_OBJECT (dialog->ok_button), "clicked",
923 G_CALLBACK (setup_fontsel_cb), dialog);
924 g_signal_connect (G_OBJECT (dialog->cancel_button), "clicked",
925 G_CALLBACK (setup_fontsel_cancel), dialog);
927 gtk_widget_show (GTK_WIDGET (dialog));
930 static void
931 setup_entry_cb (GtkEntry *entry, setting *set)
933 int size;
934 int pos;
935 int len = strlen (entry->text);
936 unsigned char *p = entry->text;
938 /* need to truncate? */
939 if (len >= set->extra)
941 len = pos = 0;
942 while (1)
944 size = g_utf8_skip [*p];
945 len += size;
946 p += size;
947 /* truncate to "set->extra" BYTES */
948 if (len >= set->extra)
950 gtk_editable_delete_text (GTK_EDITABLE (entry), pos, -1);
951 break;
953 pos++;
956 else
958 setup_set_str (&setup_prefs, set, entry->text);
962 static void
963 setup_create_label (GtkWidget *table, int row, const setting *set)
965 gtk_table_attach (GTK_TABLE (table), setup_create_italic_label (_(set->label)),
966 set->extra ? 1 : 3, 5, row, row + 1, GTK_FILL,
967 GTK_SHRINK | GTK_FILL, 0, 0);
970 static GtkWidget *
971 setup_create_entry (GtkWidget *table, int row, const setting *set)
973 GtkWidget *label;
974 GtkWidget *wid, *bwid;
976 label = gtk_label_new (_(set->label));
977 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
978 gtk_table_attach (GTK_TABLE (table), label, 2, 3, row, row + 1,
979 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
981 wid = gtk_entry_new ();
982 g_object_set_data (G_OBJECT (wid), "lbl", label);
983 if (set->list)
984 gtk_entry_set_visibility (GTK_ENTRY (wid), FALSE);
985 if (set->tooltip)
986 add_tip (wid, _(set->tooltip));
987 gtk_entry_set_max_length (GTK_ENTRY (wid), set->extra - 1);
988 gtk_entry_set_text (GTK_ENTRY (wid), setup_get_str (&setup_prefs, set));
989 g_signal_connect (G_OBJECT (wid), "changed",
990 G_CALLBACK (setup_entry_cb), (gpointer)set);
992 if (set->offset == P_OFFSETNL(proxy_user))
993 proxy_user = wid;
994 if (set->offset == P_OFFSETNL(proxy_pass))
995 proxy_pass = wid;
997 /* only http and Socks5 can auth */
998 if ( (set->offset == P_OFFSETNL(proxy_pass) ||
999 set->offset == P_OFFSETNL(proxy_user)) &&
1000 (setup_prefs.proxy_type != 4 && setup_prefs.proxy_type != 3 && setup_prefs.proxy_type != 5) )
1001 gtk_widget_set_sensitive (wid, FALSE);
1003 if (set->type == ST_ENTRY)
1004 gtk_table_attach (GTK_TABLE (table), wid, 3, 6, row, row + 1,
1005 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
1006 else
1008 gtk_table_attach (GTK_TABLE (table), wid, 3, 5, row, row + 1,
1009 GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
1010 bwid = gtk_button_new_with_label (_("Browse..."));
1011 gtk_table_attach (GTK_TABLE (table), bwid, 5, 6, row, row + 1,
1012 GTK_SHRINK | GTK_FILL, GTK_FILL, 0, 0);
1013 if (set->type == ST_EFILE)
1014 g_signal_connect (G_OBJECT (bwid), "clicked",
1015 G_CALLBACK (setup_browsefile_cb), wid);
1016 if (set->type == ST_EFONT)
1017 g_signal_connect (G_OBJECT (bwid), "clicked",
1018 G_CALLBACK (setup_browsefont_cb), wid);
1019 if (set->type == ST_EFOLDER)
1020 g_signal_connect (G_OBJECT (bwid), "clicked",
1021 G_CALLBACK (setup_browsefolder_cb), wid);
1024 return wid;
1027 static void
1028 setup_create_header (GtkWidget *table, int row, char *labeltext)
1030 GtkWidget *label;
1031 char buf[128];
1033 if (row == 0)
1034 snprintf (buf, sizeof (buf), "<b>%s</b>", _(labeltext));
1035 else
1036 snprintf (buf, sizeof (buf), "\n<b>%s</b>", _(labeltext));
1038 label = gtk_label_new (NULL);
1039 gtk_label_set_markup (GTK_LABEL (label), buf);
1040 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1041 gtk_table_attach (GTK_TABLE (table), label, 0, 4, row, row + 1,
1042 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 5);
1045 static GtkWidget *
1046 setup_create_frame (GtkWidget **left, GtkWidget *box)
1048 GtkWidget *tab, *hbox, *inbox = box;
1050 tab = gtk_table_new (3, 2, FALSE);
1051 gtk_container_set_border_width (GTK_CONTAINER (tab), 6);
1052 gtk_table_set_row_spacings (GTK_TABLE (tab), 2);
1053 gtk_table_set_col_spacings (GTK_TABLE (tab), 3);
1054 gtk_container_add (GTK_CONTAINER (inbox), tab);
1056 hbox = gtk_hbox_new (FALSE, 0);
1057 gtk_container_add (GTK_CONTAINER (inbox), hbox);
1059 *left = gtk_vbox_new (FALSE, 0);
1060 gtk_box_pack_start (GTK_BOX (hbox), *left, 0, 0, 0);
1062 return tab;
1065 static void
1066 open_data_cb (GtkWidget *button, gpointer data)
1068 fe_open_url (get_xdir_utf8 ());
1071 static GtkWidget *
1072 setup_create_page (const setting *set)
1074 int i, row, do_disable;
1075 GtkWidget *tab, *box, *left;
1076 GtkWidget *wid = NULL, *prev;
1078 box = gtk_vbox_new (FALSE, 1);
1079 gtk_container_set_border_width (GTK_CONTAINER (box), 6);
1081 tab = setup_create_frame (&left, box);
1083 i = row = do_disable = 0;
1084 while (set[i].type != ST_END)
1086 prev = wid;
1088 switch (set[i].type)
1090 case ST_HEADER:
1091 setup_create_header (tab, row, set[i].label);
1092 break;
1093 case ST_EFONT:
1094 case ST_ENTRY:
1095 case ST_EFILE:
1096 case ST_EFOLDER:
1097 wid = setup_create_entry (tab, row, &set[i]);
1098 break;
1099 case ST_TOGGLR:
1100 row--;
1101 setup_create_toggleR (tab, row, &set[i]);
1102 break;
1103 case ST_TOGGLE:
1104 wid = setup_create_toggleL (tab, row, &set[i]);
1105 do_disable = set[i].extra;
1106 break;
1107 case ST_3OGGLE:
1108 setup_create_3oggle (tab, row, &set[i]);
1109 break;
1110 case ST_MENU:
1111 setup_create_menu (tab, row, &set[i]);
1112 break;
1113 case ST_RADIO:
1114 row += setup_create_radio (tab, row, &set[i]);
1115 break;
1116 case ST_NUMBER:
1117 wid = setup_create_spin (tab, row, &set[i]);
1118 break;
1119 case ST_HSCALE:
1120 setup_create_hscale (tab, row, &set[i]);
1121 break;
1122 case ST_LABEL:
1123 setup_create_label (tab, row, &set[i]);
1124 break;
1125 case ST_ALERTHEAD:
1126 setup_create_alert_header (tab, row, &set[i]);
1129 /* will this toggle disable the "next" widget? */
1130 do_disable--;
1131 if (do_disable == 0)
1133 /* setup_toggle_cb uses this data */
1134 g_object_set_data (G_OBJECT (prev), "nxt", wid);
1135 /* force initial sensitive state */
1136 gtk_widget_set_sensitive (wid, GTK_TOGGLE_BUTTON (prev)->active);
1137 gtk_widget_set_sensitive (g_object_get_data (G_OBJECT (wid), "lbl"),
1138 GTK_TOGGLE_BUTTON (prev)->active);
1141 i++;
1142 row++;
1145 #if 0
1146 if (set == general_settings)
1148 setup_create_id_menu (tab, _("Mark identified users with:"),
1149 row, setup_prefs.irc_id_ytext);
1150 setup_create_id_menu (tab, _("Mark not-identified users with:"),
1151 row + 1, setup_prefs.irc_id_ntext);
1153 #endif
1155 if (set == logging_settings)
1157 GtkWidget *but = gtk_button_new_with_label (_("Open Data Folder"));
1158 gtk_box_pack_start (GTK_BOX (left), but, 0, 0, 0);
1159 g_signal_connect (G_OBJECT (but), "clicked",
1160 G_CALLBACK (open_data_cb), 0);
1163 return box;
1166 static void
1167 setup_color_ok_cb (GtkWidget *button, GtkWidget *dialog)
1169 GtkColorSelectionDialog *cdialog = GTK_COLOR_SELECTION_DIALOG (dialog);
1170 GdkColor *col;
1171 GdkColor old_color;
1172 GtkStyle *style;
1174 col = g_object_get_data (G_OBJECT (button), "c");
1175 old_color = *col;
1177 button = g_object_get_data (G_OBJECT (button), "b");
1179 if (!GTK_IS_WIDGET (button))
1181 gtk_widget_destroy (dialog);
1182 return;
1185 color_change = TRUE;
1187 gtk_color_selection_get_current_color (GTK_COLOR_SELECTION (cdialog->colorsel), col);
1189 gdk_colormap_alloc_color (gtk_widget_get_colormap (button), col, TRUE, TRUE);
1191 style = gtk_style_new ();
1192 style->bg[0] = *col;
1193 gtk_widget_set_style (button, style);
1194 g_object_unref (style);
1196 /* is this line correct?? */
1197 gdk_colormap_free_colors (gtk_widget_get_colormap (button), &old_color, 1);
1199 gtk_widget_destroy (dialog);
1202 static void
1203 setup_color_cb (GtkWidget *button, gpointer userdata)
1205 GtkWidget *dialog;
1206 GtkColorSelectionDialog *cdialog;
1207 GdkColor *color;
1209 color = &colors[GPOINTER_TO_INT (userdata)];
1211 dialog = gtk_color_selection_dialog_new (_("Select color"));
1212 cdialog = GTK_COLOR_SELECTION_DIALOG (dialog);
1214 gtk_widget_hide (cdialog->help_button);
1215 g_signal_connect (G_OBJECT (cdialog->ok_button), "clicked",
1216 G_CALLBACK (setup_color_ok_cb), dialog);
1217 g_signal_connect (G_OBJECT (cdialog->cancel_button), "clicked",
1218 G_CALLBACK (gtkutil_destroy), dialog);
1219 g_object_set_data (G_OBJECT (cdialog->ok_button), "c", color);
1220 g_object_set_data (G_OBJECT (cdialog->ok_button), "b", button);
1221 gtk_widget_set_sensitive (cdialog->help_button, FALSE);
1222 gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (cdialog->colorsel), color);
1223 gtk_widget_show (dialog);
1226 static void
1227 setup_create_color_button (GtkWidget *table, int num, int row, int col)
1229 GtkWidget *but;
1230 GtkStyle *style;
1231 char buf[64];
1233 if (num > 31)
1234 strcpy (buf, "<span size=\"x-small\"> </span>");
1235 else
1236 /* 12345678901 23456789 01 23456789 */
1237 sprintf (buf, "<span size=\"x-small\">%d</span>", num);
1238 but = gtk_button_new_with_label (" ");
1239 gtk_label_set_markup (GTK_LABEL (GTK_BIN (but)->child), buf);
1240 /* win32 build uses this to turn off themeing */
1241 g_object_set_data (G_OBJECT (but), "xchat-color", (gpointer)1);
1242 gtk_table_attach (GTK_TABLE (table), but, col, col+1, row, row+1,
1243 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
1244 g_signal_connect (G_OBJECT (but), "clicked",
1245 G_CALLBACK (setup_color_cb), GINT_TO_POINTER (num));
1246 style = gtk_style_new ();
1247 style->bg[GTK_STATE_NORMAL] = colors[num];
1248 gtk_widget_set_style (but, style);
1249 g_object_unref (style);
1252 static void
1253 setup_create_other_colorR (char *text, int num, int row, GtkWidget *tab)
1255 GtkWidget *label;
1257 label = gtk_label_new (text);
1258 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1259 gtk_table_attach (GTK_TABLE (tab), label, 5, 9, row, row + 1,
1260 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
1261 setup_create_color_button (tab, num, row, 9);
1264 static void
1265 setup_create_other_color (char *text, int num, int row, GtkWidget *tab)
1267 GtkWidget *label;
1269 label = gtk_label_new (text);
1270 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1271 gtk_table_attach (GTK_TABLE (tab), label, 2, 3, row, row + 1,
1272 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
1273 setup_create_color_button (tab, num, row, 3);
1276 static GtkWidget *
1277 setup_create_color_page (void)
1279 GtkWidget *tab, *box, *label;
1280 int i;
1282 box = gtk_vbox_new (FALSE, 0);
1283 gtk_container_set_border_width (GTK_CONTAINER (box), 6);
1285 tab = gtk_table_new (9, 2, FALSE);
1286 gtk_container_set_border_width (GTK_CONTAINER (tab), 6);
1287 gtk_table_set_row_spacings (GTK_TABLE (tab), 2);
1288 gtk_table_set_col_spacings (GTK_TABLE (tab), 3);
1289 gtk_container_add (GTK_CONTAINER (box), tab);
1291 setup_create_header (tab, 0, N_("Text Colors"));
1293 label = gtk_label_new (_("mIRC colors:"));
1294 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1295 gtk_table_attach (GTK_TABLE (tab), label, 2, 3, 1, 2,
1296 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
1298 for (i = 0; i < 16; i++)
1299 setup_create_color_button (tab, i, 1, i+3);
1301 label = gtk_label_new (_("Local colors:"));
1302 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1303 gtk_table_attach (GTK_TABLE (tab), label, 2, 3, 2, 3,
1304 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
1306 for (i = 16; i < 32; i++)
1307 setup_create_color_button (tab, i, 2, (i+3) - 16);
1309 setup_create_other_color (_("Foreground:"), COL_FG, 3, tab);
1310 setup_create_other_colorR (_("Background:"), COL_BG, 3, tab);
1312 setup_create_header (tab, 5, N_("Marking Text"));
1314 setup_create_other_color (_("Foreground:"), COL_MARK_FG, 6, tab);
1315 setup_create_other_colorR (_("Background:"), COL_MARK_BG, 6, tab);
1317 setup_create_header (tab, 8, N_("Interface Colors"));
1319 setup_create_other_color (_("New data:"), COL_NEW_DATA, 9, tab);
1320 setup_create_other_colorR (_("Marker line:"), COL_MARKER, 9, tab);
1321 setup_create_other_color (_("New message:"), COL_NEW_MSG, 10, tab);
1322 setup_create_other_colorR (_("Away user:"), COL_AWAY, 10, tab);
1323 setup_create_other_color (_("Highlight:"), COL_HILIGHT, 11, tab);
1325 return box;
1328 /* === GLOBALS for sound GUI === */
1330 static GtkWidget *sndprog_entry;
1331 static GtkWidget *sndfile_entry;
1332 static GtkWidget *snddir_entry;
1333 static int ignore_changed = FALSE;
1335 extern struct text_event te[]; /* text.c */
1336 extern char *sound_files[];
1338 static void
1339 setup_snd_apply (void)
1341 strcpy (setup_prefs.sounddir, GTK_ENTRY (snddir_entry)->text);
1342 strcpy (setup_prefs.soundcmd, GTK_ENTRY (sndprog_entry)->text);
1345 static void
1346 setup_snd_populate (GtkTreeView * treeview)
1348 GtkListStore *store;
1349 GtkTreeIter iter;
1350 GtkTreeSelection *sel;
1351 GtkTreePath *path;
1352 int i;
1354 sel = gtk_tree_view_get_selection (treeview);
1355 store = (GtkListStore *)gtk_tree_view_get_model (treeview);
1357 for (i = NUM_XP-1; i >= 0; i--)
1359 gtk_list_store_prepend (store, &iter);
1360 if (sound_files[i])
1361 gtk_list_store_set (store, &iter, 0, te[i].name, 1, sound_files[i], 2, i, -1);
1362 else
1363 gtk_list_store_set (store, &iter, 0, te[i].name, 1, "", 2, i, -1);
1364 if (i == last_selected_row)
1366 gtk_tree_selection_select_iter (sel, &iter);
1367 path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
1368 if (path)
1370 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.5, 0.5);
1371 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
1372 gtk_tree_path_free (path);
1378 static int
1379 setup_snd_get_selected (GtkTreeSelection *sel, GtkTreeIter *iter)
1381 int n;
1382 GtkTreeModel *model;
1384 if (!gtk_tree_selection_get_selected (sel, &model, iter))
1385 return -1;
1387 gtk_tree_model_get (model, iter, 2, &n, -1);
1388 return n;
1391 static void
1392 setup_snd_row_cb (GtkTreeSelection *sel, gpointer user_data)
1394 int n;
1395 GtkTreeIter iter;
1397 n = setup_snd_get_selected (sel, &iter);
1398 if (n == -1)
1399 return;
1400 last_selected_row = n;
1402 ignore_changed = TRUE;
1403 if (sound_files[n])
1404 gtk_entry_set_text (GTK_ENTRY (sndfile_entry), sound_files[n]);
1405 else
1406 gtk_entry_set_text (GTK_ENTRY (sndfile_entry), "");
1407 ignore_changed = FALSE;
1410 static void
1411 setup_snd_add_columns (GtkTreeView * treeview)
1413 GtkCellRenderer *renderer;
1414 GtkTreeModel *model;
1416 /* event column */
1417 renderer = gtk_cell_renderer_text_new ();
1418 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
1419 -1, _("Event"), renderer,
1420 "text", 0, NULL);
1422 /* file column */
1423 renderer = gtk_cell_renderer_text_new ();
1424 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
1425 -1, _("Sound file"), renderer,
1426 "text", 1, NULL);
1428 model = GTK_TREE_MODEL (gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT));
1429 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), model);
1430 g_object_unref (model);
1433 static void
1434 setup_autotoggle_cb (GtkToggleButton *but, GtkToggleButton *ext)
1436 if (but->active)
1438 setup_prefs.soundcmd[0] = 0;
1439 gtk_entry_set_text (GTK_ENTRY (sndprog_entry), "");
1440 gtk_widget_set_sensitive (sndprog_entry, FALSE);
1441 } else
1443 gtk_widget_set_sensitive (sndprog_entry, TRUE);
1447 static void
1448 setup_snd_filereq_cb (GtkWidget *entry, char *file)
1450 if (file)
1452 if (file[0])
1453 gtk_entry_set_text (GTK_ENTRY (entry), file);
1457 static void
1458 setup_snd_browse_cb (GtkWidget *button, GtkEntry *entry)
1460 gtkutil_file_req (_("Select a sound file"), setup_snd_filereq_cb, entry, NULL, 0);
1463 static void
1464 setup_snd_play_cb (GtkWidget *button, GtkEntry *entry)
1466 sound_play (entry->text, FALSE);
1469 static void
1470 setup_snd_changed_cb (GtkEntry *ent, GtkTreeView *tree)
1472 int n;
1473 GtkTreeIter iter;
1474 GtkListStore *store;
1475 GtkTreeSelection *sel;
1477 if (ignore_changed)
1478 return;
1480 sel = gtk_tree_view_get_selection (tree);
1481 n = setup_snd_get_selected (sel, &iter);
1482 if (n == -1)
1483 return;
1485 /* get the new sound file */
1486 if (sound_files[n])
1487 free (sound_files[n]);
1488 sound_files[n] = strdup (GTK_ENTRY (ent)->text);
1490 /* update the TreeView list */
1491 store = (GtkListStore *)gtk_tree_view_get_model (tree);
1492 gtk_list_store_set (store, &iter, 1, sound_files[n], -1);
1494 gtk_widget_set_sensitive (cancel_button, FALSE);
1497 static GtkWidget *
1498 setup_create_sound_page (void)
1500 GtkWidget *vbox1;
1501 GtkWidget *vbox2;
1502 GtkWidget *table2;
1503 GtkWidget *label2;
1504 GtkWidget *label3;
1505 GtkWidget *radio_external;
1506 GSList *radio_group = NULL;
1507 GtkWidget *radio_auto;
1508 GtkWidget *label4;
1509 GtkWidget *entry3;
1510 GtkWidget *scrolledwindow1;
1511 GtkWidget *sound_tree;
1512 GtkWidget *table1;
1513 GtkWidget *sound_label;
1514 GtkWidget *sound_browse;
1515 GtkWidget *sound_play;
1516 GtkTreeSelection *sel;
1518 vbox1 = gtk_vbox_new (FALSE, 0);
1519 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 6);
1520 gtk_widget_show (vbox1);
1522 vbox2 = gtk_vbox_new (FALSE, 0);
1523 gtk_widget_show (vbox2);
1524 gtk_container_add (GTK_CONTAINER (vbox1), vbox2);
1526 table2 = gtk_table_new (4, 3, FALSE);
1527 gtk_widget_show (table2);
1528 gtk_box_pack_start (GTK_BOX (vbox2), table2, FALSE, TRUE, 8);
1529 gtk_table_set_row_spacings (GTK_TABLE (table2), 2);
1530 gtk_table_set_col_spacings (GTK_TABLE (table2), 4);
1532 label2 = gtk_label_new (_("Sound playing method:"));
1533 gtk_widget_show (label2);
1534 gtk_table_attach (GTK_TABLE (table2), label2, 0, 1, 0, 1,
1535 (GtkAttachOptions) (GTK_FILL),
1536 (GtkAttachOptions) (0), 0, 0);
1537 gtk_misc_set_alignment (GTK_MISC (label2), 0, 0.5);
1539 label3 =
1540 gtk_label_new_with_mnemonic (_("External sound playing _program:"));
1541 gtk_widget_show (label3);
1542 gtk_table_attach (GTK_TABLE (table2), label3, 0, 1, 2, 3,
1543 (GtkAttachOptions) (GTK_FILL),
1544 (GtkAttachOptions) (0), 0, 0);
1545 gtk_misc_set_alignment (GTK_MISC (label3), 0, 0.5);
1547 sndprog_entry = gtk_entry_new ();
1548 if (setup_prefs.soundcmd[0] == 0)
1549 gtk_widget_set_sensitive (sndprog_entry, FALSE);
1550 else
1551 gtk_entry_set_text (GTK_ENTRY (sndprog_entry), setup_prefs.soundcmd);
1552 gtk_widget_show (sndprog_entry);
1553 gtk_table_attach (GTK_TABLE (table2), sndprog_entry, 1, 3, 2, 3,
1554 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1555 (GtkAttachOptions) (0), 0, 0);
1557 radio_external =
1558 gtk_radio_button_new_with_mnemonic (NULL, _("_External program"));
1559 gtk_widget_show (radio_external);
1560 gtk_table_attach (GTK_TABLE (table2), radio_external, 1, 3, 1, 2,
1561 (GtkAttachOptions) (GTK_FILL),
1562 (GtkAttachOptions) (0), 0, 0);
1563 gtk_radio_button_set_group (GTK_RADIO_BUTTON (radio_external),
1564 radio_group);
1565 radio_group =
1566 gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio_external));
1568 radio_auto = gtk_radio_button_new_with_mnemonic (NULL, _("_Automatic"));
1569 g_signal_connect (G_OBJECT (radio_auto), "toggled",
1570 G_CALLBACK (setup_autotoggle_cb), radio_external);
1571 gtk_widget_show (radio_auto);
1572 gtk_table_attach (GTK_TABLE (table2), radio_auto, 1, 3, 0, 1,
1573 (GtkAttachOptions) (GTK_FILL),
1574 (GtkAttachOptions) (0), 0, 0);
1575 gtk_radio_button_set_group (GTK_RADIO_BUTTON (radio_auto),
1576 radio_group);
1577 radio_group =
1578 gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio_auto));
1579 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_auto), setup_prefs.soundcmd[0] == 0);
1581 label4 = gtk_label_new_with_mnemonic (_("Sound files _directory:"));
1582 gtk_widget_show (label4);
1583 gtk_table_attach (GTK_TABLE (table2), label4, 0, 1, 3, 4,
1584 (GtkAttachOptions) (GTK_FILL),
1585 (GtkAttachOptions) (0), 0, 0);
1586 gtk_misc_set_alignment (GTK_MISC (label4), 0, 0.5);
1588 snddir_entry = entry3 = gtk_entry_new ();
1589 gtk_entry_set_text (GTK_ENTRY (entry3), setup_prefs.sounddir);
1590 gtk_widget_show (entry3);
1591 gtk_table_attach (GTK_TABLE (table2), entry3, 1, 3, 3, 4,
1592 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1593 (GtkAttachOptions) (0), 0, 0);
1595 scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
1596 gtk_widget_show (scrolledwindow1);
1597 gtk_container_add (GTK_CONTAINER (vbox2), scrolledwindow1);
1598 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1),
1599 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1600 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow1),
1601 GTK_SHADOW_IN);
1603 sound_tree = gtk_tree_view_new ();
1604 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (sound_tree));
1605 gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
1606 setup_snd_add_columns (GTK_TREE_VIEW (sound_tree));
1607 setup_snd_populate (GTK_TREE_VIEW (sound_tree));
1608 g_signal_connect (G_OBJECT (sel), "changed",
1609 G_CALLBACK (setup_snd_row_cb), NULL);
1610 gtk_widget_show (sound_tree);
1611 gtk_container_add (GTK_CONTAINER (scrolledwindow1), sound_tree);
1612 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (sound_tree), TRUE);
1614 table1 = gtk_table_new (2, 3, FALSE);
1615 gtk_widget_show (table1);
1616 gtk_box_pack_start (GTK_BOX (vbox2), table1, FALSE, TRUE, 8);
1617 gtk_table_set_row_spacings (GTK_TABLE (table1), 2);
1618 gtk_table_set_col_spacings (GTK_TABLE (table1), 4);
1620 sound_label = gtk_label_new_with_mnemonic (_("Sound file:"));
1621 gtk_widget_show (sound_label);
1622 gtk_table_attach (GTK_TABLE (table1), sound_label, 0, 1, 0, 1,
1623 (GtkAttachOptions) (GTK_FILL),
1624 (GtkAttachOptions) (0), 0, 0);
1625 gtk_misc_set_alignment (GTK_MISC (sound_label), 0, 0.5);
1627 sndfile_entry = gtk_entry_new ();
1628 g_signal_connect (G_OBJECT (sndfile_entry), "changed",
1629 G_CALLBACK (setup_snd_changed_cb), sound_tree);
1630 gtk_widget_show (sndfile_entry);
1631 gtk_table_attach (GTK_TABLE (table1), sndfile_entry, 0, 1, 1, 2,
1632 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1633 (GtkAttachOptions) (0), 0, 0);
1635 sound_browse = gtk_button_new_with_mnemonic (_("_Browse..."));
1636 g_signal_connect (G_OBJECT (sound_browse), "clicked",
1637 G_CALLBACK (setup_snd_browse_cb), sndfile_entry);
1638 gtk_widget_show (sound_browse);
1639 gtk_table_attach (GTK_TABLE (table1), sound_browse, 1, 2, 1, 2,
1640 (GtkAttachOptions) (GTK_FILL),
1641 (GtkAttachOptions) (0), 0, 0);
1643 #ifdef GTK_STOCK_MEDIA_PLAY
1644 sound_play = gtk_button_new_from_stock (GTK_STOCK_MEDIA_PLAY);
1645 #else
1646 sound_play = gtk_button_new_with_mnemonic (_("_Play"));
1647 #endif
1648 g_signal_connect (G_OBJECT (sound_play), "clicked",
1649 G_CALLBACK (setup_snd_play_cb), sndfile_entry);
1650 gtk_widget_show (sound_play);
1651 gtk_table_attach (GTK_TABLE (table1), sound_play, 2, 3, 1, 2,
1652 (GtkAttachOptions) (GTK_FILL),
1653 (GtkAttachOptions) (0), 0, 0);
1655 gtk_label_set_mnemonic_widget (GTK_LABEL (label3), sndprog_entry);
1656 gtk_label_set_mnemonic_widget (GTK_LABEL (label4), entry3);
1657 setup_snd_row_cb (sel, NULL);
1659 return vbox1;
1662 static void
1663 setup_add_page (const char *title, GtkWidget *book, GtkWidget *tab)
1665 GtkWidget *oframe, *frame, *label, *vvbox;
1666 char buf[128];
1668 /* frame for whole page */
1669 oframe = gtk_frame_new (NULL);
1670 gtk_frame_set_shadow_type (GTK_FRAME (oframe), GTK_SHADOW_IN);
1672 vvbox = gtk_vbox_new (FALSE, 0);
1673 gtk_container_add (GTK_CONTAINER (oframe), vvbox);
1675 /* border for the label */
1676 frame = gtk_frame_new (NULL);
1677 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
1678 gtk_box_pack_start (GTK_BOX (vvbox), frame, FALSE, TRUE, 0);
1680 /* label */
1681 label = gtk_label_new (NULL);
1682 snprintf (buf, sizeof (buf), "<b><big>%s</big></b>", _(title));
1683 gtk_label_set_markup (GTK_LABEL (label), buf);
1684 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1685 gtk_misc_set_padding (GTK_MISC (label), 2, 1);
1686 gtk_container_add (GTK_CONTAINER (frame), label);
1688 gtk_container_add (GTK_CONTAINER (vvbox), tab);
1690 gtk_notebook_append_page (GTK_NOTEBOOK (book), oframe, NULL);
1693 static const char *const cata[] =
1695 N_("Interface"),
1696 N_("Text box"),
1697 N_("Input box"),
1698 N_("User list"),
1699 N_("Channel switcher"),
1700 N_("Colors"),
1701 NULL,
1702 N_("Chatting"),
1703 N_("Alerts"),
1704 N_("General"),
1705 N_("Logging"),
1706 N_("Sound"),
1707 /* N_("Advanced"),*/
1708 NULL,
1709 N_("Network"),
1710 N_("Network setup"),
1711 N_("File transfers"),
1712 NULL,
1713 NULL
1716 static GtkWidget *
1717 setup_create_pages (GtkWidget *box)
1719 GtkWidget *book;
1721 book = gtk_notebook_new ();
1723 setup_add_page (cata[1], book, setup_create_page (textbox_settings));
1724 setup_add_page (cata[2], book, setup_create_page (inputbox_settings));
1725 setup_add_page (cata[3], book, setup_create_page (userlist_settings));
1726 setup_add_page (cata[4], book, setup_create_page (tabs_settings));
1727 setup_add_page (cata[5], book, setup_create_color_page ());
1728 setup_add_page (cata[8], book, setup_create_page (alert_settings));
1729 setup_add_page (cata[9], book, setup_create_page (general_settings));
1730 setup_add_page (cata[10], book, setup_create_page (logging_settings));
1731 setup_add_page (cata[11], book, setup_create_sound_page ());
1732 setup_add_page (cata[14], book, setup_create_page (network_settings));
1733 setup_add_page (cata[15], book, setup_create_page (filexfer_settings));
1735 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (book), FALSE);
1736 gtk_notebook_set_show_border (GTK_NOTEBOOK (book), FALSE);
1737 gtk_container_add (GTK_CONTAINER (box), book);
1739 return book;
1742 static void
1743 setup_tree_cb (GtkTreeView *treeview, GtkWidget *book)
1745 GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
1746 GtkTreeIter iter;
1747 GtkTreeModel *model;
1748 int page;
1750 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1752 gtk_tree_model_get (model, &iter, 1, &page, -1);
1753 if (page != -1)
1755 gtk_notebook_set_current_page (GTK_NOTEBOOK (book), page);
1756 last_selected_page = page;
1761 static gboolean
1762 setup_tree_select_filter (GtkTreeSelection *selection, GtkTreeModel *model,
1763 GtkTreePath *path, gboolean path_selected,
1764 gpointer data)
1766 if (gtk_tree_path_get_depth (path) > 1)
1767 return TRUE;
1768 return FALSE;
1771 static void
1772 setup_create_tree (GtkWidget *box, GtkWidget *book)
1774 GtkWidget *tree;
1775 GtkWidget *frame;
1776 GtkTreeStore *model;
1777 GtkTreeIter iter;
1778 GtkTreeIter child_iter;
1779 GtkTreeIter *sel_iter = NULL;
1780 GtkCellRenderer *renderer;
1781 GtkTreeSelection *sel;
1782 int i, page;
1784 model = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
1786 i = 0;
1787 page = 0;
1790 gtk_tree_store_append (model, &iter, NULL);
1791 gtk_tree_store_set (model, &iter, 0, _(cata[i]), 1, -1, -1);
1792 i++;
1796 gtk_tree_store_append (model, &child_iter, &iter);
1797 gtk_tree_store_set (model, &child_iter, 0, _(cata[i]), 1, page, -1);
1798 if (page == last_selected_page)
1799 sel_iter = gtk_tree_iter_copy (&child_iter);
1800 page++;
1801 i++;
1802 } while (cata[i]);
1804 i++;
1806 } while (cata[i]);
1808 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
1809 g_object_unref (G_OBJECT (model));
1810 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
1811 gtk_tree_selection_set_mode (sel, GTK_SELECTION_BROWSE);
1812 gtk_tree_selection_set_select_function (sel, setup_tree_select_filter,
1813 NULL, NULL);
1814 g_signal_connect (G_OBJECT (tree), "cursor_changed",
1815 G_CALLBACK (setup_tree_cb), book);
1817 renderer = gtk_cell_renderer_text_new ();
1818 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree),
1819 -1, _("Categories"), renderer, "text", 0, NULL);
1820 gtk_tree_view_expand_all (GTK_TREE_VIEW (tree));
1822 frame = gtk_frame_new (NULL);
1823 gtk_container_add (GTK_CONTAINER (frame), tree);
1824 gtk_box_pack_start (GTK_BOX (box), frame, 0, 0, 0);
1825 gtk_box_reorder_child (GTK_BOX (box), frame, 0);
1827 if (sel_iter)
1829 gtk_tree_selection_select_iter (sel, sel_iter);
1830 gtk_tree_iter_free (sel_iter);
1834 static void
1835 setup_apply_entry_style (GtkWidget *entry)
1837 gtk_widget_modify_base (entry, GTK_STATE_NORMAL, &colors[COL_BG]);
1838 gtk_widget_modify_text (entry, GTK_STATE_NORMAL, &colors[COL_FG]);
1839 gtk_widget_modify_font (entry, input_style->font_desc);
1842 static void
1843 setup_apply_to_sess (session_gui *gui)
1845 #ifdef USE_GTKSPELL
1846 GtkSpell *spell;
1847 #endif
1849 mg_update_xtext (gui->xtext);
1851 if (prefs.style_namelistgad)
1852 gtk_widget_set_style (gui->user_tree, input_style);
1854 if (prefs.style_inputbox)
1856 extern char cursor_color_rc[];
1857 char buf[256];
1858 sprintf (buf, cursor_color_rc,
1859 (colors[COL_FG].red >> 8),
1860 (colors[COL_FG].green >> 8),
1861 (colors[COL_FG].blue >> 8));
1862 gtk_rc_parse_string (buf);
1864 setup_apply_entry_style (gui->input_box);
1865 setup_apply_entry_style (gui->limit_entry);
1866 setup_apply_entry_style (gui->key_entry);
1867 setup_apply_entry_style (gui->topic_entry);
1870 if (prefs.userlistbuttons)
1871 gtk_widget_show (gui->button_box);
1872 else
1873 gtk_widget_hide (gui->button_box);
1875 #ifdef USE_GTKSPELL
1876 spell = gtkspell_get_from_text_view (GTK_TEXT_VIEW (gui->input_box));
1877 if (prefs.gui_input_spell)
1879 if (!spell)
1880 gtkspell_new_attach (GTK_TEXT_VIEW (gui->input_box), NULL, NULL);
1882 else
1884 if (spell)
1885 gtkspell_detach (spell);
1887 #endif
1889 #ifdef USE_LIBSEXY
1890 sexy_spell_entry_set_checked ((SexySpellEntry *)gui->input_box, prefs.gui_input_spell);
1891 #endif
1894 static void
1895 unslash (char *dir)
1897 if (dir[0])
1899 int len = strlen (dir) - 1;
1900 if (dir[len] == '/')
1901 dir[len] = 0;
1905 void
1906 setup_apply_real (int new_pix, int do_ulist, int do_layout)
1908 GSList *list;
1909 session *sess;
1910 int done_main = FALSE;
1912 /* remove trailing slashes */
1913 unslash (prefs.dccdir);
1914 unslash (prefs.dcc_completed_dir);
1916 mkdir_utf8 (prefs.dccdir);
1917 mkdir_utf8 (prefs.dcc_completed_dir);
1919 if (new_pix)
1921 if (channelwin_pix)
1922 g_object_unref (channelwin_pix);
1923 channelwin_pix = pixmap_load_from_file (prefs.background);
1926 input_style = create_input_style (input_style);
1928 list = sess_list;
1929 while (list)
1931 sess = list->data;
1932 if (sess->gui->is_tab)
1934 /* only apply to main tabwindow once */
1935 if (!done_main)
1937 done_main = TRUE;
1938 setup_apply_to_sess (sess->gui);
1940 } else
1942 setup_apply_to_sess (sess->gui);
1945 log_open_or_close (sess);
1947 if (do_ulist)
1948 userlist_rehash (sess);
1950 list = list->next;
1953 mg_apply_setup ();
1954 tray_apply_setup ();
1956 if (do_layout)
1957 menu_change_layout ();
1960 static void
1961 setup_apply (struct xchatprefs *pr)
1963 int new_pix = FALSE;
1964 int noapply = FALSE;
1965 int do_ulist = FALSE;
1966 int do_layout = FALSE;
1968 if (strcmp (pr->background, prefs.background) != 0)
1969 new_pix = TRUE;
1971 #define DIFF(a) (pr->a != prefs.a)
1973 if (DIFF (paned_userlist))
1974 noapply = TRUE;
1975 if (DIFF (lagometer))
1976 noapply = TRUE;
1977 if (DIFF (throttlemeter))
1978 noapply = TRUE;
1979 if (DIFF (showhostname_in_userlist))
1980 noapply = TRUE;
1981 if (DIFF (tab_small))
1982 noapply = TRUE;
1983 if (DIFF (tab_sort))
1984 noapply = TRUE;
1985 if (DIFF (use_server_tab))
1986 noapply = TRUE;
1987 if (DIFF (style_namelistgad))
1988 noapply = TRUE;
1989 if (DIFF (truncchans))
1990 noapply = TRUE;
1991 if (DIFF (tab_layout))
1992 do_layout = TRUE;
1994 if (color_change || (DIFF (away_size_max)) || (DIFF (away_track)))
1995 do_ulist = TRUE;
1997 if ((pr->tab_pos == 5 || pr->tab_pos == 6) &&
1998 pr->tab_layout == 2 && pr->tab_pos != prefs.tab_pos)
1999 fe_message (_("You cannot place the tree on the top or bottom!\n"
2000 "Please change to the <b>Tabs</b> layout in the <b>View</b>"
2001 " menu first."),
2002 FE_MSG_WARN | FE_MSG_MARKUP);
2004 memcpy (&prefs, pr, sizeof (prefs));
2006 setup_apply_real (new_pix, do_ulist, do_layout);
2008 if (noapply)
2009 fe_message (_("Some settings were changed that require a"
2010 " restart to take full effect."), FE_MSG_WARN);
2012 if (prefs.autodccsend == 1)
2014 if (!strcmp ((char *)g_get_home_dir (), prefs.dccdir))
2016 fe_message (_("*WARNING*\n"
2017 "Auto accepting DCC to your home directory\n"
2018 "can be dangerous and is exploitable. Eg:\n"
2019 "Someone could send you a .bash_profile"), FE_MSG_WARN);
2024 #if 0
2025 static void
2026 setup_apply_cb (GtkWidget *but, GtkWidget *win)
2028 /* setup_prefs -> xchat */
2029 setup_apply (&setup_prefs);
2031 #endif
2033 static void
2034 setup_ok_cb (GtkWidget *but, GtkWidget *win)
2036 setup_snd_apply ();
2037 gtk_widget_destroy (win);
2038 setup_apply (&setup_prefs);
2039 save_config ();
2040 palette_save ();
2043 static GtkWidget *
2044 setup_window_open (void)
2046 GtkWidget *wid, *win, *vbox, *hbox, *hbbox;
2048 win = gtkutil_window_new (_("XChat: Preferences"), "prefs", 0, 0, 3);
2050 vbox = gtk_vbox_new (FALSE, 5);
2051 gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
2052 gtk_container_add (GTK_CONTAINER (win), vbox);
2054 hbox = gtk_hbox_new (FALSE, 4);
2055 gtk_container_add (GTK_CONTAINER (vbox), hbox);
2057 setup_create_tree (hbox, setup_create_pages (hbox));
2059 hbox = gtk_hbox_new (FALSE, 0);
2060 gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
2062 /* prepare the button box */
2063 hbbox = gtk_hbutton_box_new ();
2064 gtk_box_set_spacing (GTK_BOX (hbbox), 4);
2065 gtk_box_pack_end (GTK_BOX (hbox), hbbox, FALSE, FALSE, 0);
2067 /* standard buttons */
2068 /* GNOME doesn't like apply */
2069 #if 0
2070 wid = gtk_button_new_from_stock (GTK_STOCK_APPLY);
2071 g_signal_connect (G_OBJECT (wid), "clicked",
2072 G_CALLBACK (setup_apply_cb), win);
2073 gtk_box_pack_start (GTK_BOX (hbbox), wid, FALSE, FALSE, 0);
2074 #endif
2076 cancel_button = wid = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
2077 g_signal_connect (G_OBJECT (wid), "clicked",
2078 G_CALLBACK (gtkutil_destroy), win);
2079 gtk_box_pack_start (GTK_BOX (hbbox), wid, FALSE, FALSE, 0);
2081 wid = gtk_button_new_from_stock (GTK_STOCK_OK);
2082 g_signal_connect (G_OBJECT (wid), "clicked",
2083 G_CALLBACK (setup_ok_cb), win);
2084 gtk_box_pack_start (GTK_BOX (hbbox), wid, FALSE, FALSE, 0);
2086 wid = gtk_hseparator_new ();
2087 gtk_box_pack_end (GTK_BOX (vbox), wid, FALSE, FALSE, 0);
2089 gtk_widget_show_all (win);
2091 return win;
2094 static void
2095 setup_close_cb (GtkWidget *win, GtkWidget **swin)
2097 *swin = NULL;
2099 if (font_dialog)
2101 gtk_widget_destroy (font_dialog);
2102 font_dialog = NULL;
2106 void
2107 setup_open (void)
2109 static GtkWidget *setup_window = NULL;
2111 if (setup_window)
2113 gtk_window_present (GTK_WINDOW (setup_window));
2114 return;
2117 memcpy (&setup_prefs, &prefs, sizeof (prefs));
2119 color_change = FALSE;
2120 setup_window = setup_window_open ();
2122 g_signal_connect (G_OBJECT (setup_window), "destroy",
2123 G_CALLBACK (setup_close_cb), &setup_window);