1 /* X-Chat
2 * Copyright (C) 2004-2007 Peter Zelezny.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24
25 #include "../common/hexchat.h"
26 #include "../common/cfgfiles.h"
27 #include "../common/fe.h"
28 #include "../common/text.h"
29 #include "../common/userlist.h"
30 #include "../common/util.h"
31 #include "../common/hexchatc.h"
32 #include "../common/outbound.h"
33 #include "fe-gtk.h"
34 #include "gtkutil.h"
35 #include "maingui.h"
36 #include "palette.h"
37 #include "pixmaps.h"
38 #include "menu.h"
39 #include "plugin-tray.h"
40 #include "notifications/notification-backend.h"
41
42 #ifdef WIN32
43 #include "../common/fe.h"
44 #endif
45 #include "sexy-spell-entry.h"
46
47 GtkStyle *create_input_style (GtkStyle *);
48
49 #define LABEL_INDENT 12
50
51 static int last_selected_page = 0;
52 static int last_selected_row = 0; /* sound row */
53 static gboolean color_change;
54 static struct hexchatprefs setup_prefs;
55 static GtkWidget *cancel_button;
56 static GtkWidget *font_dialog = NULL;
57
58 enum
59 {
60 ST_END,
61 ST_TOGGLE,
62 ST_TOGGLR,
63 ST_3OGGLE,
64 ST_ENTRY,
65 ST_EFONT,
66 ST_EFILE,
67 ST_EFOLDER,
68 ST_MENU,
69 ST_RADIO,
70 ST_NUMBER,
71 ST_HSCALE,
72 ST_HEADER,
73 ST_LABEL,
74 ST_ALERTHEAD
75 };
76
77 typedef struct
78 {
79 int type;
80 char *label;
81 int offset;
82 char *tooltip;
83 char const *const *list;
84 int extra;
85 } setting;
86
87 #ifdef WIN32
88 static const char *const langsmenu[] =
89 {
90 N_("Afrikaans"),
91 N_("Albanian"),
92 N_("Amharic"),
93 N_("Asturian"),
94 N_("Azerbaijani"),
95 N_("Basque"),
96 N_("Belarusian"),
97 N_("Bulgarian"),
98 N_("Catalan"),
99 N_("Chinese (Simplified)"),
100 N_("Chinese (Traditional)"),
101 N_("Czech"),
102 N_("Danish"),
103 N_("Dutch"),
104 N_("English (British)"),
105 N_("English"),
106 N_("Estonian"),
107 N_("Finnish"),
108 N_("French"),
109 N_("Galician"),
110 N_("German"),
111 N_("Greek"),
112 N_("Gujarati"),
113 N_("Hindi"),
114 N_("Hungarian"),
115 N_("Indonesian"),
116 N_("Italian"),
117 N_("Japanese"),
118 N_("Kannada"),
119 N_("Kinyarwanda"),
120 N_("Korean"),
121 N_("Latvian"),
122 N_("Lithuanian"),
123 N_("Macedonian"),
124 N_("Malay"),
125 N_("Malayalam"),
126 N_("Norwegian (Bokmal)"),
127 N_("Norwegian (Nynorsk)"),
128 N_("Polish"),
129 N_("Portuguese"),
130 N_("Portuguese (Brazilian)"),
131 N_("Punjabi"),
132 N_("Russian"),
133 N_("Serbian"),
134 N_("Slovak"),
135 N_("Slovenian"),
136 N_("Spanish"),
137 N_("Swedish"),
138 N_("Thai"),
139 N_("Turkish"),
140 N_("Ukrainian"),
141 N_("Vietnamese"),
142 N_("Walloon"),
143 NULL
144 };
145 #endif
146
147 static const setting appearance_settings[] =
148 {
149 {ST_HEADER, N_("General"),0,0,0},
150 #ifdef WIN32
151 {ST_MENU, N_("Language:"), P_OFFINTNL(hex_gui_lang), 0, langsmenu, 0},
152 {ST_EFONT, N_("Main font:"), P_OFFSETNL(hex_text_font_main), 0, 0, sizeof prefs.hex_text_font_main},
153 #else
154 {ST_EFONT, N_("Font:"), P_OFFSETNL(hex_text_font), 0, 0, sizeof prefs.hex_text_font},
155 #endif
156
157 {ST_HEADER, N_("Text Box"),0,0,0},
158 {ST_TOGGLE, N_("Colored nick names"), P_OFFINTNL(hex_text_color_nicks), N_("Give each person on IRC a different color"),0,0},
159 {ST_TOGGLR, N_("Indent nick names"), P_OFFINTNL(hex_text_indent), N_("Make nick names right-justified"),0,0},
160 {ST_TOGGLE, N_ ("Show marker line"), P_OFFINTNL (hex_text_show_marker), N_ ("Insert a red line after the last read text."), 0, 0},
161 {ST_EFILE, N_ ("Background image:"), P_OFFSETNL (hex_text_background), 0, 0, sizeof prefs.hex_text_background},
162
163 {ST_HEADER, N_("Transparency Settings"), 0,0,0},
164 {ST_HSCALE, N_("Window opacity:"), P_OFFINTNL(hex_gui_transparency),0,0,0},
165
166 {ST_HEADER, N_("Timestamps"),0,0,0},
167 {ST_TOGGLE, N_("Enable timestamps"), P_OFFINTNL(hex_stamp_text),0,0,1},
168 {ST_ENTRY, N_("Timestamp format:"), P_OFFSETNL(hex_stamp_text_format),
169 #ifdef WIN32
170 N_("See the strftime MSDN article for details."),0,sizeof prefs.hex_stamp_text_format},
171 #else
172 N_("See the strftime manpage for details."),0,sizeof prefs.hex_stamp_text_format},
173 #endif
174
175 {ST_HEADER, N_("Title Bar"),0,0,0},
176 {ST_TOGGLE, N_("Show channel modes"), P_OFFINTNL(hex_gui_win_modes),0,0,0},
177 {ST_TOGGLR, N_("Show number of users"), P_OFFINTNL(hex_gui_win_ucount),0,0,0},
178
179 {ST_END, 0, 0, 0, 0, 0}
180 };
181
182 static const char *const tabcompmenu[] =
183 {
184 N_("A-Z"),
185 N_("Last-spoke order"),
186 NULL
187 };
188
189 static const setting inputbox_settings[] =
190 {
191 {ST_HEADER, N_("Input Box"),0,0,0},
192 {ST_TOGGLE, N_("Use the text box font and colors"), P_OFFINTNL(hex_gui_input_style),0,0,0},
193 {ST_TOGGLE, N_("Render colors and attributes"), P_OFFINTNL (hex_gui_input_attr),0,0,0},
194 {ST_TOGGLE, N_("Show nick box"), P_OFFINTNL(hex_gui_input_nick),0,0,1},
195 {ST_TOGGLE, N_("Show user mode icon in nick box"), P_OFFINTNL(hex_gui_input_icon),0,0,0},
196 {ST_TOGGLE, N_("Spell checking"), P_OFFINTNL(hex_gui_input_spell),0,0,1},
197 {ST_ENTRY, N_("Dictionaries to use:"), P_OFFSETNL(hex_text_spell_langs),0,0,sizeof prefs.hex_text_spell_langs},
198 #ifdef WIN32
199 {ST_LABEL, N_("Use language codes (as in \"%LOCALAPPDATA%\\enchant\\myspell\\dicts\").\nSeparate multiple entries with commas.")},
200 #else
201 {ST_LABEL, N_("Use language codes. Separate multiple entries with commas.")},
202 #endif
203
204 {ST_HEADER, N_("Nick Completion"),0,0,0},
205 {ST_ENTRY, N_("Nick completion suffix:"), P_OFFSETNL(hex_completion_suffix),0,0,sizeof prefs.hex_completion_suffix},
206 {ST_MENU, N_("Nick completion sorted:"), P_OFFINTNL(hex_completion_sort), 0, tabcompmenu, 0},
207 {ST_NUMBER, N_("Nick completion amount:"), P_OFFINTNL(hex_completion_amount), N_("Threshold of nicks to start listing instead of completing"), (const char **)N_("nicks."), 1000},
208
209 {ST_END, 0, 0, 0, 0, 0}
210 };
211
212 static const char *const lagmenutext[] =
213 {
214 N_("Off"),
215 N_("Graphical"),
216 N_("Text"),
217 N_("Both"),
218 NULL
219 };
220
221 static const char *const ulmenutext[] =
222 {
223 N_("A-Z, ops first"),
224 N_("A-Z"),
225 N_("Z-A, ops last"),
226 N_("Z-A"),
227 N_("Unsorted"),
228 NULL
229 };
230
231 static const char *const cspos[] =
232 {
233 N_("Left (upper)"),
234 N_("Left (lower)"),
235 N_("Right (upper)"),
236 N_("Right (lower)"),
237 N_("Top"),
238 N_("Bottom"),
239 N_("Hidden"),
240 NULL
241 };
242
243 static const char *const ulpos[] =
244 {
245 N_("Left (upper)"),
246 N_("Left (lower)"),
247 N_("Right (upper)"),
248 N_("Right (lower)"),
249 NULL
250 };
251
252 static const setting userlist_settings[] =
253 {
254 {ST_HEADER, N_("User List"),0,0,0},
255 {ST_TOGGLE, N_("Show hostnames in user list"), P_OFFINTNL(hex_gui_ulist_show_hosts), 0, 0, 0},
256 {ST_TOGGLE, N_("Use the Text box font and colors"), P_OFFINTNL(hex_gui_ulist_style),0,0,0},
257 {ST_TOGGLE, N_("Show icons for user modes"), P_OFFINTNL(hex_gui_ulist_icons), N_("Use graphical icons instead of text symbols in the user list."), 0, 0},
258 {ST_TOGGLE, N_("Color nicknames in userlist"), P_OFFINTNL(hex_gui_ulist_color), N_("Will color nicknames the same as in chat."), 0, 0},
259 {ST_TOGGLE, N_("Show user count in channels"), P_OFFINTNL(hex_gui_ulist_count), 0, 0, 0},
260 {ST_MENU, N_("User list sorted by:"), P_OFFINTNL(hex_gui_ulist_sort), 0, ulmenutext, 0},
261 {ST_MENU, N_("Show user list at:"), P_OFFINTNL(hex_gui_ulist_pos), 0, ulpos, 1},
262
263 {ST_HEADER, N_("Away Tracking"),0,0,0},
264 {ST_TOGGLE, N_("Track the away status of users and mark them in a different color"), P_OFFINTNL(hex_away_track),0,0,1},
265 {ST_NUMBER, N_("On channels smaller than:"), P_OFFINTNL(hex_away_size_max),0,0,10000},
266
267 {ST_HEADER, N_("Action Upon Double Click"),0,0,0},
268 {ST_ENTRY, N_("Execute command:"), P_OFFSETNL(hex_gui_ulist_doubleclick), 0, 0, sizeof prefs.hex_gui_ulist_doubleclick},
269
270 {ST_HEADER, N_("Extra Gadgets"),0,0,0},
271 {ST_MENU, N_("Lag meter:"), P_OFFINTNL(hex_gui_lagometer), 0, lagmenutext, 0},
272 {ST_MENU, N_("Throttle meter:"), P_OFFINTNL(hex_gui_throttlemeter), 0, lagmenutext, 0},
273
274 {ST_END, 0, 0, 0, 0, 0}
275 };
276
277 static const char *const tabwin[] =
278 {
279 N_("Windows"),
280 N_("Tabs"),
281 NULL
282 };
283
284 static const char *const focusnewtabsmenu[] =
285 {
286 N_("Never"),
287 N_("Always"),
288 N_("Only requested tabs"),
289 NULL
290 };
291
292 static const char *const noticeposmenu[] =
293 {
294 N_("Automatic"),
295 N_("In an extra tab"),
296 N_("In the front tab"),
297 NULL
298 };
299
300 static const char *const swtype[] =
301 {
302 N_("Tabs"), /* 0 tabs */
303 "", /* 1 reserved */
304 N_("Tree"), /* 2 tree */
305 NULL
306 };
307
308 static const setting tabs_settings[] =
309 {
310 /*{ST_HEADER, N_("Channel Switcher"),0,0,0},*/
311 {ST_RADIO, N_("Switcher type:"),P_OFFINTNL(hex_gui_tab_layout), 0, swtype, 0},
312 {ST_TOGGLE, N_("Open an extra tab for server messages"), P_OFFINTNL(hex_gui_tab_server), 0, 0, 0},
313 {ST_TOGGLE, N_("Open a new tab when you receive a private message"), P_OFFINTNL(hex_gui_autoopen_dialog), 0, 0, 0},
314 {ST_TOGGLE, N_("Sort tabs in alphabetical order"), P_OFFINTNL(hex_gui_tab_sort), 0, 0, 0},
315 {ST_TOGGLE, N_("Show icons in the channel tree"), P_OFFINTNL(hex_gui_tab_icons), 0, 0, 0},
316 {ST_TOGGLE, N_("Show dotted lines in the channel tree"), P_OFFINTNL(hex_gui_tab_dots), 0, 0, 0},
317 {ST_TOGGLE, N_("Scroll mouse-wheel to change tabs"), P_OFFINTNL (hex_gui_tab_scrollchans), 0, 0, 0},
318 {ST_TOGGLE, N_("Middle click to close tab"), P_OFFINTNL(hex_gui_tab_middleclose), 0, 0, 0},
319 {ST_TOGGLE, N_("Smaller text"), P_OFFINTNL(hex_gui_tab_small), 0, 0, 0},
320 {ST_MENU, N_("Focus new tabs:"), P_OFFINTNL(hex_gui_tab_newtofront), 0, focusnewtabsmenu, 0},
321 {ST_MENU, N_("Placement of notices:"), P_OFFINTNL(hex_irc_notice_pos), 0, noticeposmenu, 0},
322 {ST_MENU, N_("Show channel switcher at:"), P_OFFINTNL(hex_gui_tab_pos), 0, cspos, 1},
323 {ST_NUMBER, N_("Shorten tab labels to:"), P_OFFINTNL(hex_gui_tab_trunc), 0, (const char **)N_("letters."), 99},
324
325 {ST_HEADER, N_("Tabs or Windows"),0,0,0},
326 {ST_MENU, N_("Open channels in:"), P_OFFINTNL(hex_gui_tab_chans), 0, tabwin, 0},
327 {ST_MENU, N_("Open dialogs in:"), P_OFFINTNL(hex_gui_tab_dialogs), 0, tabwin, 0},
328 {ST_MENU, N_("Open utilities in:"), P_OFFINTNL(hex_gui_tab_utils), N_("Open DCC, Ignore, Notify etc, in tabs or windows?"), tabwin, 0},
329
330 {ST_END, 0, 0, 0, 0, 0}
331 };
332
333 static const setting color_settings[] =
334 {
335 {ST_TOGGLE, N_("Messages"), P_OFFINTNL(hex_text_stripcolor_msg), 0, 0, 0},
336 {ST_TOGGLE, N_("Scrollback"), P_OFFINTNL(hex_text_stripcolor_replay), 0, 0, 0},
337 {ST_TOGGLE, N_("Topic"), P_OFFINTNL(hex_text_stripcolor_topic), 0, 0, 0},
338
339 {ST_END, 0, 0, 0, 0, 0}
340 };
341
342 static const char *const dccaccept[] =
343 {
344 N_("Ask for confirmation"),
345 N_("Ask for download folder"),
346 N_("Save without interaction"),
347 NULL
348 };
349
350 static const setting filexfer_settings[] =
351 {
352 {ST_HEADER, N_("Files and Directories"), 0, 0, 0},
353 {ST_MENU, N_("Auto accept file offers:"), P_OFFINTNL(hex_dcc_auto_recv), 0, dccaccept, 0},
354 {ST_EFOLDER,N_("Download files to:"), P_OFFSETNL(hex_dcc_dir), 0, 0, sizeof prefs.hex_dcc_dir},
355 {ST_EFOLDER,N_("Move completed files to:"), P_OFFSETNL(hex_dcc_completed_dir), 0, 0, sizeof prefs.hex_dcc_completed_dir},
356 {ST_TOGGLE, N_("Save nick name in filenames"), P_OFFINTNL(hex_dcc_save_nick), 0, 0, 0},
357
358 {ST_HEADER, N_("Auto Open DCC Windows"),0,0,0},
359 {ST_TOGGLE, N_("Send window"), P_OFFINTNL(hex_gui_autoopen_send), 0, 0, 0},
360 {ST_TOGGLE, N_("Receive window"), P_OFFINTNL(hex_gui_autoopen_recv), 0, 0, 0},
361 {ST_TOGGLE, N_("Chat window"), P_OFFINTNL(hex_gui_autoopen_chat), 0, 0, 0},
362
363 {ST_HEADER, N_("Maximum File Transfer Speeds (Byte per Second)"), 0, 0, 0},
364 {ST_NUMBER, N_("One upload:"), P_OFFINTNL(hex_dcc_max_send_cps),
365 N_("Maximum speed for one transfer"), 0, 10000000},
366 {ST_NUMBER, N_("One download:"), P_OFFINTNL(hex_dcc_max_get_cps),
367 N_("Maximum speed for one transfer"), 0, 10000000},
368 {ST_NUMBER, N_("All uploads combined:"), P_OFFINTNL(hex_dcc_global_max_send_cps),
369 N_("Maximum speed for all files"), 0, 10000000},
370 {ST_NUMBER, N_("All downloads combined:"), P_OFFINTNL(hex_dcc_global_max_get_cps),
371 N_("Maximum speed for all files"), 0, 10000000},
372
373 {ST_END, 0, 0, 0, 0, 0}
374 };
375
376 static const int balloonlist[3] =
377 {
378 P_OFFINTNL(hex_input_balloon_chans), P_OFFINTNL(hex_input_balloon_priv), P_OFFINTNL(hex_input_balloon_hilight)
379 };
380
381 static const int trayblinklist[3] =
382 {
383 P_OFFINTNL(hex_input_tray_chans), P_OFFINTNL(hex_input_tray_priv), P_OFFINTNL(hex_input_tray_hilight)
384 };
385
386 static const int taskbarlist[3] =
387 {
388 P_OFFINTNL(hex_input_flash_chans), P_OFFINTNL(hex_input_flash_priv), P_OFFINTNL(hex_input_flash_hilight)
389 };
390
391 static const int beeplist[3] =
392 {
393 P_OFFINTNL(hex_input_beep_chans), P_OFFINTNL(hex_input_beep_priv), P_OFFINTNL(hex_input_beep_hilight)
394 };
395
396 static const setting alert_settings[] =
397 {
398 {ST_HEADER, N_("Alerts"),0,0,0},
399
400 {ST_ALERTHEAD},
401
402
403 {ST_3OGGLE, N_("Show notifications on:"), 0, 0, (void *)balloonlist, 0},
404 {ST_3OGGLE, N_("Blink tray icon on:"), 0, 0, (void *)trayblinklist, 0},
405 {ST_3OGGLE, N_("Blink task bar on:"), 0, 0, (void *)taskbarlist, 0},
406 #ifdef WIN32
407 {ST_3OGGLE, N_("Make a beep sound on:"), 0, N_("Play the \"Instant Message Notification\" system sound upon the selected events"), (void *)beeplist, 0},
408 #else
409 #ifdef USE_LIBCANBERRA
410 {ST_3OGGLE, N_("Make a beep sound on:"), 0, N_("Play \"message-new-instant\" from the freedesktop.org sound theme upon the selected events"), (void *)beeplist, 0},
411 #else
412 {ST_3OGGLE, N_("Make a beep sound on:"), 0, N_("Play a GTK beep upon the selected events"), (void *)beeplist, 0},
413 #endif
414 #endif
415
416 {ST_TOGGLE, N_("Omit alerts when marked as being away"), P_OFFINTNL(hex_away_omit_alerts), 0, 0, 0},
417 {ST_TOGGLE, N_("Omit alerts while the window is focused"), P_OFFINTNL(hex_gui_focus_omitalerts), 0, 0, 0},
418
419 {ST_HEADER, N_("Tray Behavior"), 0, 0, 0},
420 {ST_TOGGLE, N_("Enable system tray icon"), P_OFFINTNL(hex_gui_tray), 0, 0, 4},
421 {ST_TOGGLE, N_("Minimize to tray"), P_OFFINTNL(hex_gui_tray_minimize), 0, 0, 0},
422 {ST_TOGGLE, N_("Close to tray"), P_OFFINTNL(hex_gui_tray_close), 0, 0, 0},
423 {ST_TOGGLE, N_("Automatically mark away/back"), P_OFFINTNL(hex_gui_tray_away), N_("Automatically change status when hiding to tray."), 0, 0},
424 {ST_TOGGLE, N_("Only show notifications when hidden or iconified"), P_OFFINTNL(hex_gui_tray_quiet), 0, 0, 0},
425
426 {ST_HEADER, N_("Highlighted Messages"),0,0,0},
427 {ST_LABEL, N_("Highlighted messages are ones where your nickname is mentioned, but also:"), 0, 0, 0, 1},
428
429 {ST_ENTRY, N_("Extra words to highlight:"), P_OFFSETNL(hex_irc_extra_hilight), 0, 0, sizeof prefs.hex_irc_extra_hilight},
430 {ST_ENTRY, N_("Nick names not to highlight:"), P_OFFSETNL(hex_irc_no_hilight), 0, 0, sizeof prefs.hex_irc_no_hilight},
431 {ST_ENTRY, N_("Nick names to always highlight:"), P_OFFSETNL(hex_irc_nick_hilight), 0, 0, sizeof prefs.hex_irc_nick_hilight},
432 {ST_LABEL, N_("Separate multiple words with commas.\nWildcards are accepted.")},
433
434 {ST_END, 0, 0, 0, 0, 0}
435 };
436
437 static const setting alert_settings_nonotifications[] =
438 {
439 {ST_HEADER, N_("Alerts"),0,0,0},
440
441 {ST_ALERTHEAD},
442 {ST_3OGGLE, N_("Blink tray icon on:"), 0, 0, (void *)trayblinklist, 0},
443 #ifdef HAVE_GTK_MAC
444 {ST_3OGGLE, N_("Bounce dock icon on:"), 0, 0, (void *)taskbarlist, 0},
445 #else
446 #ifndef __APPLE__
447 {ST_3OGGLE, N_("Blink task bar on:"), 0, 0, (void *)taskbarlist, 0},
448 #endif
449 #endif
450 #ifdef WIN32
451 {ST_3OGGLE, N_("Make a beep sound on:"), 0, N_("Play the \"Instant Message Notification\" system sound upon the selected events"), (void *)beeplist, 0},
452 #else
453 #ifdef USE_LIBCANBERRA
454 {ST_3OGGLE, N_("Make a beep sound on:"), 0, N_("Play \"message-new-instant\" from the freedesktop.org sound theme upon the selected events"), (void *)beeplist, 0},
455 #else
456 {ST_3OGGLE, N_("Make a beep sound on:"), 0, N_("Play a GTK beep upon the selected events"), (void *)beeplist, 0},
457 #endif
458 #endif
459
460 {ST_TOGGLE, N_("Omit alerts when marked as being away"), P_OFFINTNL(hex_away_omit_alerts), 0, 0, 0},
461 {ST_TOGGLE, N_("Omit alerts while the window is focused"), P_OFFINTNL(hex_gui_focus_omitalerts), 0, 0, 0},
462
463 {ST_HEADER, N_("Tray Behavior"), 0, 0, 0},
464 {ST_TOGGLE, N_("Enable system tray icon"), P_OFFINTNL(hex_gui_tray), 0, 0, 4},
465 {ST_TOGGLE, N_("Minimize to tray"), P_OFFINTNL(hex_gui_tray_minimize), 0, 0, 0},
466 {ST_TOGGLE, N_("Close to tray"), P_OFFINTNL(hex_gui_tray_close), 0, 0, 0},
467 {ST_TOGGLE, N_("Automatically mark away/back"), P_OFFINTNL(hex_gui_tray_away), N_("Automatically change status when hiding to tray."), 0, 0},
468
469 {ST_HEADER, N_("Highlighted Messages"),0,0,0},
470 {ST_LABEL, N_("Highlighted messages are ones where your nickname is mentioned, but also:"), 0, 0, 0, 1},
471
472 {ST_ENTRY, N_("Extra words to highlight:"), P_OFFSETNL(hex_irc_extra_hilight), 0, 0, sizeof prefs.hex_irc_extra_hilight},
473 {ST_ENTRY, N_("Nick names not to highlight:"), P_OFFSETNL(hex_irc_no_hilight), 0, 0, sizeof prefs.hex_irc_no_hilight},
474 {ST_ENTRY, N_("Nick names to always highlight:"), P_OFFSETNL(hex_irc_nick_hilight), 0, 0, sizeof prefs.hex_irc_nick_hilight},
475 {ST_LABEL, N_("Separate multiple words with commas.\nWildcards are accepted.")},
476
477 {ST_END, 0, 0, 0, 0, 0}
478 };
479
480 static const setting alert_settings_unity[] =
481 {
482 {ST_HEADER, N_("Alerts"),0,0,0},
483
484 {ST_ALERTHEAD},
485 {ST_3OGGLE, N_("Show notifications on:"), 0, 0, (void *)balloonlist, 0},
486 {ST_3OGGLE, N_("Blink task bar on:"), 0, 0, (void *)taskbarlist, 0},
487 {ST_3OGGLE, N_("Make a beep sound on:"), 0, 0, (void *)beeplist, 0},
488
489 {ST_TOGGLE, N_("Omit alerts when marked as being away"), P_OFFINTNL(hex_away_omit_alerts), 0, 0, 0},
490 {ST_TOGGLE, N_("Omit alerts while the window is focused"), P_OFFINTNL(hex_gui_focus_omitalerts), 0, 0, 0},
491
492 {ST_HEADER, N_("Highlighted Messages"),0,0,0},
493 {ST_LABEL, N_("Highlighted messages are ones where your nickname is mentioned, but also:"), 0, 0, 0, 1},
494
495 {ST_ENTRY, N_("Extra words to highlight:"), P_OFFSETNL(hex_irc_extra_hilight), 0, 0, sizeof prefs.hex_irc_extra_hilight},
496 {ST_ENTRY, N_("Nick names not to highlight:"), P_OFFSETNL(hex_irc_no_hilight), 0, 0, sizeof prefs.hex_irc_no_hilight},
497 {ST_ENTRY, N_("Nick names to always highlight:"), P_OFFSETNL(hex_irc_nick_hilight), 0, 0, sizeof prefs.hex_irc_nick_hilight},
498 {ST_LABEL, N_("Separate multiple words with commas.\nWildcards are accepted.")},
499
500 {ST_END, 0, 0, 0, 0, 0}
501 };
502
503 static const setting alert_settings_unityandnonotifications[] =
504 {
505 {ST_HEADER, N_("Alerts"), 0, 0, 0},
506
507 {ST_ALERTHEAD},
508 {ST_3OGGLE, N_("Blink task bar on:"), 0, 0, (void *)taskbarlist, 0},
509 {ST_3OGGLE, N_("Make a beep sound on:"), 0, 0, (void *)beeplist, 0},
510
511 {ST_TOGGLE, N_("Omit alerts when marked as being away"), P_OFFINTNL (hex_away_omit_alerts), 0, 0, 0},
512 {ST_TOGGLE, N_("Omit alerts while the window is focused"), P_OFFINTNL (hex_gui_focus_omitalerts), 0, 0, 0},
513
514 {ST_HEADER, N_("Highlighted Messages"), 0, 0, 0},
515 {ST_LABEL, N_("Highlighted messages are ones where your nickname is mentioned, but also:"), 0, 0, 0, 1},
516
517 {ST_ENTRY, N_("Extra words to highlight:"), P_OFFSETNL (hex_irc_extra_hilight), 0, 0, sizeof prefs.hex_irc_extra_hilight},
518 {ST_ENTRY, N_("Nick names not to highlight:"), P_OFFSETNL (hex_irc_no_hilight), 0, 0, sizeof prefs.hex_irc_no_hilight},
519 {ST_ENTRY, N_("Nick names to always highlight:"), P_OFFSETNL (hex_irc_nick_hilight), 0, 0, sizeof prefs.hex_irc_nick_hilight},
520 {ST_LABEL, N_("Separate multiple words with commas.\nWildcards are accepted.")},
521
522 {ST_END, 0, 0, 0, 0, 0}
523 };
524
525 static const setting general_settings[] =
526 {
527 {ST_HEADER, N_("Default Messages"),0,0,0},
528 {ST_ENTRY, N_("Quit:"), P_OFFSETNL(hex_irc_quit_reason), 0, 0, sizeof prefs.hex_irc_quit_reason},
529 {ST_ENTRY, N_("Leave channel:"), P_OFFSETNL(hex_irc_part_reason), 0, 0, sizeof prefs.hex_irc_part_reason},
530 {ST_ENTRY, N_("Away:"), P_OFFSETNL(hex_away_reason), 0, 0, sizeof prefs.hex_away_reason},
531
532 {ST_HEADER, N_("Away"),0,0,0},
533 {ST_TOGGLE, N_("Show away once"), P_OFFINTNL(hex_away_show_once), N_("Show identical away messages only once."), 0, 0},
534 {ST_TOGGLE, N_("Automatically unmark away"), P_OFFINTNL(hex_away_auto_unmark), N_("Unmark yourself as away before sending messages."), 0, 0},
535
536 {ST_HEADER, N_("Miscellaneous"),0,0,0},
537 {ST_TOGGLE, N_("Display MODEs in raw form"), P_OFFINTNL(hex_irc_raw_modes), 0, 0, 0},
538 {ST_TOGGLE, N_("WHOIS on notify"), P_OFFINTNL(hex_notify_whois_online), N_("Sends a /WHOIS when a user comes online in your notify list."), 0, 0},
539 {ST_TOGGLE, N_("Hide join and part messages"), P_OFFINTNL(hex_irc_conf_mode), N_("Hide channel join/part messages by default."), 0, 0},
540 {ST_TOGGLE, N_("Hide nick change messages"), P_OFFINTNL(hex_irc_hide_nickchange), 0, 0, 0},
541
542 {ST_END, 0, 0, 0, 0, 0}
543 };
544
545 static const char *const bantypemenu[] =
546 {
547 N_("*!*@*.host"),
548 N_("*!*@domain"),
549 N_("*!*user@*.host"),
550 N_("*!*user@domain"),
551 NULL
552 };
553
554 static const setting advanced_settings[] =
555 {
556 {ST_HEADER, N_("Auto Copy Behavior"),0,0,0},
557 {ST_TOGGLE, N_("Automatically copy selected text"), P_OFFINTNL(hex_text_autocopy_text),
558 N_("Copy selected text to clipboard when left mouse button is released. "
559 "Otherwise, Ctrl+Shift+C will copy the "
560 "selected text to the clipboard."), 0, 0},
561 {ST_TOGGLE, N_("Automatically include timestamps"), P_OFFINTNL(hex_text_autocopy_stamp),
562 N_("Automatically include timestamps in copied lines of text. Otherwise, "
563 "include timestamps if the Shift key is held down while selecting."), 0, 0},
564 {ST_TOGGLE, N_("Automatically include color information"), P_OFFINTNL(hex_text_autocopy_color),
565 N_("Automatically include color information in copied lines of text. "
566 "Otherwise, include color information if the Ctrl key is held down "
567 "while selecting."), 0, 0},
568
569 {ST_HEADER, N_("Miscellaneous"), 0, 0, 0},
570 {ST_ENTRY, N_("Real name:"), P_OFFSETNL(hex_irc_real_name), 0, 0, sizeof prefs.hex_irc_real_name},
571 #ifdef WIN32
572 {ST_ENTRY, N_("Alternative fonts:"), P_OFFSETNL(hex_text_font_alternative), N_("Separate multiple entries with commas without spaces before or after."), 0, sizeof prefs.hex_text_font_alternative},
573 #endif
574 {ST_TOGGLE, N_("Display lists in compact mode"), P_OFFINTNL(hex_gui_compact), N_("Use less spacing between user list/channel tree rows."), 0, 0},
575 {ST_TOGGLE, N_("Use server time if supported"), P_OFFINTNL(hex_irc_cap_server_time), N_("Display timestamps obtained from server if it supports the time-server extension."), 0, 0},
576 {ST_TOGGLE, N_("Automatically reconnect to servers on disconnect"), P_OFFINTNL(hex_net_auto_reconnect), 0, 0, 1},
577 {ST_NUMBER, N_("Auto reconnect delay:"), P_OFFINTNL(hex_net_reconnect_delay), 0, 0, 9999},
578 {ST_NUMBER, N_("Auto join delay:"), P_OFFINTNL(hex_irc_join_delay), 0, 0, 9999},
579 {ST_MENU, N_("Ban Type:"), P_OFFINTNL(hex_irc_ban_type), N_("Attempt to use this banmask when banning or quieting. (requires irc_who_join)"), bantypemenu, 0},
580
581 {ST_END, 0, 0, 0, 0, 0}
582 };
583
584 static const setting logging_settings[] =
585 {
586 {ST_HEADER, N_("Logging"),0,0,0},
587 {ST_TOGGLE, N_("Display scrollback from previous session"), P_OFFINTNL(hex_text_replay), 0, 0, 0},
588 {ST_NUMBER, N_("Scrollback lines:"), P_OFFINTNL(hex_text_max_lines),0,0,100000},
589 {ST_TOGGLE, N_("Enable logging of conversations to disk"), P_OFFINTNL(hex_irc_logging), 0, 0, 0},
590 {ST_ENTRY, N_("Log filename:"), P_OFFSETNL(hex_irc_logmask), 0, 0, sizeof prefs.hex_irc_logmask},
591 {ST_LABEL, N_("%s=Server %c=Channel %n=Network.")},
592
593 {ST_HEADER, N_("Timestamps"),0,0,0},
594 {ST_TOGGLE, N_("Insert timestamps in logs"), P_OFFINTNL(hex_stamp_log), 0, 0, 1},
595 {ST_ENTRY, N_("Log timestamp format:"), P_OFFSETNL(hex_stamp_log_format), 0, 0, sizeof prefs.hex_stamp_log_format},
596 #ifdef WIN32
597 {ST_LABEL, N_("See the strftime MSDN article for details.")},
598 #else
599 {ST_LABEL, N_("See the strftime manpage for details.")},
600 #endif
601
602 {ST_HEADER, N_("URLs"),0,0,0},
603 {ST_TOGGLE, N_("Enable logging of URLs to disk"), P_OFFINTNL(hex_url_logging), 0, 0, 0},
604 {ST_TOGGLE, N_("Enable URL grabber"), P_OFFINTNL(hex_url_grabber), 0, 0, 1},
605 {ST_NUMBER, N_("Maximum number of URLs to grab:"), P_OFFINTNL(hex_url_grabber_limit), 0, 0, 9999},
606
607 {ST_END, 0, 0, 0, 0, 0}
608 };
609
610 static const char *const proxytypes[] =
611 {
612 N_("(Disabled)"),
613 N_("Wingate"),
614 N_("SOCKS4"),
615 N_("SOCKS5"),
616 N_("HTTP"),
617 N_("Auto"),
618 NULL
619 };
620
621 static const char *const proxyuse[] =
622 {
623 N_("All connections"),
624 N_("IRC server only"),
625 N_("DCC only"),
626 NULL
627 };
628
629 static const setting network_settings[] =
630 {
631 {ST_HEADER, N_("Your Address"), 0, 0, 0, 0},
632 {ST_ENTRY, N_("Bind to:"), P_OFFSETNL(hex_net_bind_host), 0, 0, sizeof prefs.hex_net_bind_host},
633 {ST_LABEL, N_("Only useful for computers with multiple addresses.")},
634
635 {ST_HEADER, N_("File Transfers"), 0, 0, 0},
636 {ST_TOGGLE, N_("Get my address from the IRC server"), P_OFFINTNL(hex_dcc_ip_from_server),
637 N_("Asks the IRC server for your real address. Use this if you have a 192.168.*.* address!"), 0, 0},
638 {ST_ENTRY, N_("DCC IP address:"), P_OFFSETNL(hex_dcc_ip),
639 N_("Claim you are at this address when offering files."), 0, sizeof prefs.hex_dcc_ip},
640 {ST_NUMBER, N_("First DCC listen port:"), P_OFFINTNL(hex_dcc_port_first), 0, 0, 65535},
641 {ST_NUMBER, N_("Last DCC listen port:"), P_OFFINTNL(hex_dcc_port_last), 0,
642 (const char **)N_("!Leave ports at zero for full range."), 65535},
643
644 {ST_HEADER, N_("Proxy Server"), 0, 0, 0, 0},
645 {ST_ENTRY, N_("Hostname:"), P_OFFSETNL(hex_net_proxy_host), 0, 0, sizeof prefs.hex_net_proxy_host},
646 {ST_NUMBER, N_("Port:"), P_OFFINTNL(hex_net_proxy_port), 0, 0, 65535},
647 {ST_MENU, N_("Type:"), P_OFFINTNL(hex_net_proxy_type), 0, proxytypes, 0},
648 {ST_MENU, N_("Use proxy for:"), P_OFFINTNL(hex_net_proxy_use), 0, proxyuse, 0},
649
650 {ST_HEADER, N_("Proxy Authentication"), 0, 0, 0, 0},
651 {ST_TOGGLE, N_("Use authentication (HTTP or SOCKS5 only)"), P_OFFINTNL(hex_net_proxy_auth), 0, 0, 0},
652 {ST_ENTRY, N_("Username:"), P_OFFSETNL(hex_net_proxy_user), 0, 0, sizeof prefs.hex_net_proxy_user},
653 {ST_ENTRY, N_("Password:"), P_OFFSETNL(hex_net_proxy_pass), 0, GINT_TO_POINTER(1), sizeof prefs.hex_net_proxy_pass},
654
655 {ST_END, 0, 0, 0, 0, 0}
656 };
657
658 static const setting identd_settings[] =
659 {
660 {ST_HEADER, N_("Identd Server"), 0, 0, 0, 0},
661 {ST_TOGGLE, N_("Enabled"), P_OFFINTNL(hex_identd_server), N_("Server will respond with the networks username"), 0, 1},
662 {ST_NUMBER, N_("Port:"), P_OFFINTNL(hex_identd_port), N_("You must have permissions to listen on this port. "
663 "If not 113 (0 defaults to this) then you must configure port-forwarding."), 0, 65535},
664
665 {ST_END, 0, 0, 0, 0, 0}
666 };
667
668 #define setup_get_str(pr,set) (((char *)pr)+set->offset)
669 #define setup_get_int(pr,set) *(((int *)pr)+set->offset)
670 #define setup_get_int3(pr,off) *(((int *)pr)+off)
671
672 #define setup_set_int(pr,set,num) *((int *)pr+set->offset)=num
673 #define setup_set_str(pr,set,str) strcpy(((char *)pr)+set->offset,str)
674
675
676 static void
setup_3oggle_cb(GtkToggleButton * but,unsigned int * setting)677 setup_3oggle_cb (GtkToggleButton *but, unsigned int *setting)
678 {
679 *setting = gtk_toggle_button_get_active (but);
680 }
681
682 static void
setup_headlabel(GtkWidget * tab,int row,int col,char * text)683 setup_headlabel (GtkWidget *tab, int row, int col, char *text)
684 {
685 GtkWidget *label;
686 char buf[128];
687 char *sp;
688
689 g_snprintf (buf, sizeof (buf), "<b><span size=\"smaller\">%s</span></b>", text);
690 sp = strchr (buf + 17, ' ');
691 if (sp)
692 *sp = '\n';
693
694 label = gtk_label_new (NULL);
695 gtk_label_set_markup (GTK_LABEL (label), buf);
696 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
697 gtk_table_attach (GTK_TABLE (tab), label, col, col + 1, row, row + 1, 0, 0, 4, 0);
698 }
699
700 static void
setup_create_alert_header(GtkWidget * tab,int row,const setting * set)701 setup_create_alert_header (GtkWidget *tab, int row, const setting *set)
702 {
703 setup_headlabel (tab, row, 3, _("Channel Message"));
704 setup_headlabel (tab, row, 4, _("Private Message"));
705 setup_headlabel (tab, row, 5, _("Highlighted Message"));
706 }
707
708 /* makes 3 toggles side-by-side */
709
710 static void
setup_create_3oggle(GtkWidget * tab,int row,const setting * set)711 setup_create_3oggle (GtkWidget *tab, int row, const setting *set)
712 {
713 GtkWidget *label, *wid;
714 int *offsets = (int *)set->list;
715
716 label = gtk_label_new (_(set->label));
717 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
718 if (set->tooltip)
719 {
720 gtk_widget_set_tooltip_text (label, _(set->tooltip));
721 }
722 gtk_table_attach (GTK_TABLE (tab), label, 2, 3, row, row + 1,
723 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
724
725 wid = gtk_check_button_new ();
726 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
727 setup_get_int3 (&setup_prefs, offsets[0]));
728 g_signal_connect (G_OBJECT (wid), "toggled",
729 G_CALLBACK (setup_3oggle_cb), ((int *)&setup_prefs) + offsets[0]);
730 gtk_table_attach (GTK_TABLE (tab), wid, 3, 4, row, row + 1, 0, 0, 0, 0);
731
732 wid = gtk_check_button_new ();
733 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
734 setup_get_int3 (&setup_prefs, offsets[1]));
735 g_signal_connect (G_OBJECT (wid), "toggled",
736 G_CALLBACK (setup_3oggle_cb), ((int *)&setup_prefs) + offsets[1]);
737 gtk_table_attach (GTK_TABLE (tab), wid, 4, 5, row, row + 1, 0, 0, 0, 0);
738
739 wid = gtk_check_button_new ();
740 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
741 setup_get_int3 (&setup_prefs, offsets[2]));
742 g_signal_connect (G_OBJECT (wid), "toggled",
743 G_CALLBACK (setup_3oggle_cb), ((int *)&setup_prefs) + offsets[2]);
744 gtk_table_attach (GTK_TABLE (tab), wid, 5, 6, row, row + 1, 0, 0, 0, 0);
745 }
746
747 static void
setup_toggle_cb(GtkToggleButton * but,const setting * set)748 setup_toggle_cb (GtkToggleButton *but, const setting *set)
749 {
750 GtkWidget *label, *disable_wid;
751
752 setup_set_int (&setup_prefs, set, gtk_toggle_button_get_active (but));
753
754 /* does this toggle also enable/disable another widget? */
755 disable_wid = g_object_get_data (G_OBJECT (but), "nxt");
756 if (disable_wid)
757 {
758 gtk_widget_set_sensitive (disable_wid, gtk_toggle_button_get_active (but));
759 label = g_object_get_data (G_OBJECT (disable_wid), "lbl");
760 gtk_widget_set_sensitive (label, gtk_toggle_button_get_active (but));
761 }
762 }
763
764 static void
setup_toggle_sensitive_cb(GtkToggleButton * but,GtkWidget * wid)765 setup_toggle_sensitive_cb (GtkToggleButton *but, GtkWidget *wid)
766 {
767 gtk_widget_set_sensitive (wid, gtk_toggle_button_get_active (but));
768 }
769
770 static void
setup_create_toggleR(GtkWidget * tab,int row,const setting * set)771 setup_create_toggleR (GtkWidget *tab, int row, const setting *set)
772 {
773 GtkWidget *wid;
774
775 wid = gtk_check_button_new_with_label (_(set->label));
776 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
777 setup_get_int (&setup_prefs, set));
778 g_signal_connect (G_OBJECT (wid), "toggled",
779 G_CALLBACK (setup_toggle_cb), (gpointer)set);
780 if (set->tooltip)
781 gtk_widget_set_tooltip_text (wid, _(set->tooltip));
782 gtk_table_attach (GTK_TABLE (tab), wid, 4, 5, row, row + 1,
783 GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
784 }
785
786 static GtkWidget *
setup_create_toggleL(GtkWidget * tab,int row,const setting * set)787 setup_create_toggleL (GtkWidget *tab, int row, const setting *set)
788 {
789 GtkWidget *wid;
790
791 wid = gtk_check_button_new_with_label (_(set->label));
792 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid),
793 setup_get_int (&setup_prefs, set));
794 g_signal_connect (G_OBJECT (wid), "toggled",
795 G_CALLBACK (setup_toggle_cb), (gpointer)set);
796 if (set->tooltip)
797 gtk_widget_set_tooltip_text (wid, _(set->tooltip));
798 gtk_table_attach (GTK_TABLE (tab), wid, 2, row==6 ? 6 : 4, row, row + 1,
799 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
800
801 return wid;
802 }
803
804 static GtkWidget *
setup_create_italic_label(char * text)805 setup_create_italic_label (char *text)
806 {
807 GtkWidget *label;
808 char buf[256];
809
810 label = gtk_label_new (NULL);
811 g_snprintf (buf, sizeof (buf), "<i><span size=\"smaller\">%s</span></i>", text);
812 gtk_label_set_markup (GTK_LABEL (label), buf);
813 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
814
815 return label;
816 }
817
818 static void
setup_spin_cb(GtkSpinButton * spin,const setting * set)819 setup_spin_cb (GtkSpinButton *spin, const setting *set)
820 {
821 setup_set_int (&setup_prefs, set, gtk_spin_button_get_value_as_int (spin));
822 }
823
824 static GtkWidget *
setup_create_spin(GtkWidget * table,int row,const setting * set)825 setup_create_spin (GtkWidget *table, int row, const setting *set)
826 {
827 GtkWidget *label, *wid, *rbox, *align;
828 char *text;
829
830 label = gtk_label_new (_(set->label));
831 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
832 gtk_table_attach (GTK_TABLE (table), label, 2, 3, row, row + 1,
833 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
834
835 align = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
836 gtk_table_attach (GTK_TABLE (table), align, 3, 4, row, row + 1,
837 GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
838
839 rbox = gtk_hbox_new (0, 0);
840 gtk_container_add (GTK_CONTAINER (align), rbox);
841
842 wid = gtk_spin_button_new_with_range (0, set->extra, 1);
843 g_object_set_data (G_OBJECT (wid), "lbl", label);
844 if (set->tooltip)
845 gtk_widget_set_tooltip_text (wid, _(set->tooltip));
846 gtk_spin_button_set_value (GTK_SPIN_BUTTON (wid),
847 setup_get_int (&setup_prefs, set));
848 g_signal_connect (G_OBJECT (wid), "value_changed",
849 G_CALLBACK (setup_spin_cb), (gpointer)set);
850 gtk_box_pack_start (GTK_BOX (rbox), wid, 0, 0, 0);
851
852 if (set->list)
853 {
854 text = _((char *)set->list);
855 if (text[0] == '!')
856 label = setup_create_italic_label (text + 1);
857 else
858 label = gtk_label_new (text);
859 gtk_box_pack_start (GTK_BOX (rbox), label, 0, 0, 6);
860 }
861
862 return wid;
863 }
864
865 static gint
setup_apply_trans(int * tag)866 setup_apply_trans (int *tag)
867 {
868 prefs.hex_gui_transparency = setup_prefs.hex_gui_transparency;
869 gtk_window_set_opacity (GTK_WINDOW (current_sess->gui->window),
870 (prefs.hex_gui_transparency / 255.));
871
872 /* mg_update_xtext (current_sess->gui->xtext); */
873 *tag = 0;
874 return 0;
875 }
876
877 static void
setup_hscale_cb(GtkHScale * wid,const setting * set)878 setup_hscale_cb (GtkHScale *wid, const setting *set)
879 {
880 static int tag = 0;
881
882 setup_set_int (&setup_prefs, set, (int) gtk_range_get_value (GTK_RANGE (wid)));
883
884 if (tag == 0)
885 {
886 tag = g_idle_add ((GSourceFunc) setup_apply_trans, &tag);
887 }
888 }
889
890 static void
setup_create_hscale(GtkWidget * table,int row,const setting * set)891 setup_create_hscale (GtkWidget *table, int row, const setting *set)
892 {
893 GtkWidget *wid;
894
895 wid = gtk_label_new (_(set->label));
896 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5);
897 gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1,
898 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
899
900 wid = gtk_hscale_new_with_range (0., 255., 1.);
901 gtk_scale_set_value_pos (GTK_SCALE (wid), GTK_POS_RIGHT);
902 gtk_range_set_value (GTK_RANGE (wid), setup_get_int (&setup_prefs, set));
903 g_signal_connect (G_OBJECT(wid), "value_changed",
904 G_CALLBACK (setup_hscale_cb), (gpointer)set);
905 gtk_table_attach (GTK_TABLE (table), wid, 3, 6, row, row + 1,
906 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
907
908 #ifndef WIN32 /* Windows always supports this */
909 /* Only used for transparency currently */
910 if (!gtk_widget_is_composited (current_sess->gui->window))
911 gtk_widget_set_sensitive (wid, FALSE);
912 #endif
913 }
914
915
916 static GtkWidget *proxy_user; /* username GtkEntry */
917 static GtkWidget *proxy_pass; /* password GtkEntry */
918
919 static void
setup_menu_cb(GtkWidget * cbox,const setting * set)920 setup_menu_cb (GtkWidget *cbox, const setting *set)
921 {
922 int n = gtk_combo_box_get_active (GTK_COMBO_BOX (cbox));
923
924 /* set the prefs.<field> */
925 setup_set_int (&setup_prefs, set, n + set->extra);
926
927 if (set->list == proxytypes)
928 {
929 /* only HTTP and SOCKS5 can use a username/pass */
930 gtk_widget_set_sensitive (proxy_user, (n == 3 || n == 4 || n == 5));
931 gtk_widget_set_sensitive (proxy_pass, (n == 3 || n == 4 || n == 5));
932 }
933 }
934
935 static void
setup_radio_cb(GtkWidget * item,const setting * set)936 setup_radio_cb (GtkWidget *item, const setting *set)
937 {
938 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (item)))
939 {
940 int n = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "n"));
941 /* set the prefs.<field> */
942 setup_set_int (&setup_prefs, set, n);
943 }
944 }
945
946 static int
setup_create_radio(GtkWidget * table,int row,const setting * set)947 setup_create_radio (GtkWidget *table, int row, const setting *set)
948 {
949 GtkWidget *wid, *hbox;
950 int i;
951 const char **text = (const char **)set->list;
952 GSList *group;
953
954 wid = gtk_label_new (_(set->label));
955 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5);
956 gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1,
957 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
958
959 hbox = gtk_hbox_new (0, 0);
960 gtk_table_attach (GTK_TABLE (table), hbox, 3, 4, row, row + 1,
961 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
962
963 i = 0;
964 group = NULL;
965 while (text[i])
966 {
967 if (text[i][0] != 0)
968 {
969 wid = gtk_radio_button_new_with_mnemonic (group, _(text[i]));
970 /*if (set->tooltip)
971 gtk_widget_set_tooltip_text (wid, _(set->tooltip));*/
972 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (wid));
973 gtk_container_add (GTK_CONTAINER (hbox), wid);
974 if (i == setup_get_int (&setup_prefs, set))
975 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid), TRUE);
976 g_object_set_data (G_OBJECT (wid), "n", GINT_TO_POINTER (i));
977 g_signal_connect (G_OBJECT (wid), "toggled",
978 G_CALLBACK (setup_radio_cb), (gpointer)set);
979 }
980 i++;
981 row++;
982 }
983
984 return i;
985 }
986
987 /*
988 static const char *id_strings[] =
989 {
990 "",
991 "*",
992 "%C4*%C18%B%B",
993 "%U"
994 };
995
996 static void
997 setup_id_menu_cb (GtkWidget *item, char *dest)
998 {
999 int n = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "n"));
1000
1001 strcpy (dest, id_strings[n]);
1002 }
1003
1004 static void
1005 setup_create_id_menu (GtkWidget *table, char *label, int row, char *dest)
1006 {
1007 GtkWidget *wid, *menu, *item;
1008 int i, def = 0;
1009 static const char *text[] =
1010 {
1011 ("(disabled)"),
1012 ("A star (*)"),
1013 ("A red star (*)"),
1014 ("Underlined")
1015 };
1016
1017 wid = gtk_label_new (label);
1018 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5);
1019 gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1,
1020 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
1021
1022 wid = gtk_option_menu_new ();
1023 menu = gtk_menu_new ();
1024
1025 for (i = 0; i < 4; i++)
1026 {
1027 if (strcmp (id_strings[i], dest) == 0)
1028 {
1029 def = i;
1030 break;
1031 }
1032 }
1033
1034 i = 0;
1035 while (text[i])
1036 {
1037 item = gtk_menu_item_new_with_label (_(text[i]));
1038 g_object_set_data (G_OBJECT (item), "n", GINT_TO_POINTER (i));
1039
1040 gtk_widget_show (item);
1041 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1042 g_signal_connect (G_OBJECT (item), "activate",
1043 G_CALLBACK (setup_id_menu_cb), dest);
1044 i++;
1045 }
1046
1047 gtk_option_menu_set_menu (GTK_OPTION_MENU (wid), menu);
1048 gtk_option_menu_set_history (GTK_OPTION_MENU (wid), def);
1049
1050 gtk_table_attach (GTK_TABLE (table), wid, 3, 4, row, row + 1,
1051 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
1052 }
1053
1054 */
1055
1056 static void
setup_create_menu(GtkWidget * table,int row,const setting * set)1057 setup_create_menu (GtkWidget *table, int row, const setting *set)
1058 {
1059 GtkWidget *wid, *cbox, *box;
1060 const char **text = (const char **)set->list;
1061 int i;
1062
1063 wid = gtk_label_new (_(set->label));
1064 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5);
1065 gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1,
1066 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
1067
1068 cbox = gtk_combo_box_text_new ();
1069
1070 for (i = 0; text[i]; i++)
1071 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cbox), _(text[i]));
1072
1073 gtk_combo_box_set_active (GTK_COMBO_BOX (cbox),
1074 setup_get_int (&setup_prefs, set) - set->extra);
1075 g_signal_connect (G_OBJECT (cbox), "changed",
1076 G_CALLBACK (setup_menu_cb), (gpointer)set);
1077
1078 box = gtk_hbox_new (0, 0);
1079 gtk_box_pack_start (GTK_BOX (box), cbox, 0, 0, 0);
1080 gtk_table_attach (GTK_TABLE (table), box, 3, 4, row, row + 1,
1081 GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
1082 }
1083
1084 static void
setup_filereq_cb(GtkWidget * entry,char * file)1085 setup_filereq_cb (GtkWidget *entry, char *file)
1086 {
1087 if (file)
1088 {
1089 if (file[0])
1090 gtk_entry_set_text (GTK_ENTRY (entry), file);
1091 }
1092 }
1093
1094 static void
setup_browsefile_cb(GtkWidget * button,GtkWidget * entry)1095 setup_browsefile_cb (GtkWidget *button, GtkWidget *entry)
1096 {
1097 /* used for background image only */
1098 char *filter;
1099 int filter_type;
1100
1101 #ifdef WIN32
1102 filter = "*png;*.tiff;*.gif;*.jpeg;*.jpg";
1103 filter_type = FRF_EXTENSIONS;
1104 #else
1105 filter = "image/*";
1106 filter_type = FRF_MIMETYPES;
1107 #endif
1108 gtkutil_file_req (_("Select an Image File"), setup_filereq_cb,
1109 entry, NULL, filter, filter_type|FRF_RECENTLYUSED);
1110 }
1111
1112 static void
setup_fontsel_destroy(GtkWidget * button,GtkFontSelectionDialog * dialog)1113 setup_fontsel_destroy (GtkWidget *button, GtkFontSelectionDialog *dialog)
1114 {
1115 font_dialog = NULL;
1116 }
1117
1118 static void
setup_fontsel_cb(GtkWidget * button,GtkFontSelectionDialog * dialog)1119 setup_fontsel_cb (GtkWidget *button, GtkFontSelectionDialog *dialog)
1120 {
1121 GtkWidget *entry;
1122 char *font_name;
1123
1124 entry = g_object_get_data (G_OBJECT (button), "e");
1125 font_name = gtk_font_selection_dialog_get_font_name (dialog);
1126
1127 gtk_entry_set_text (GTK_ENTRY (entry), font_name);
1128
1129 g_free (font_name);
1130 gtk_widget_destroy (GTK_WIDGET (dialog));
1131 font_dialog = NULL;
1132 }
1133
1134 static void
setup_fontsel_cancel(GtkWidget * button,GtkFontSelectionDialog * dialog)1135 setup_fontsel_cancel (GtkWidget *button, GtkFontSelectionDialog *dialog)
1136 {
1137 gtk_widget_destroy (GTK_WIDGET (dialog));
1138 font_dialog = NULL;
1139 }
1140
1141 static void
setup_browsefolder_cb(GtkWidget * button,GtkEntry * entry)1142 setup_browsefolder_cb (GtkWidget *button, GtkEntry *entry)
1143 {
1144 gtkutil_file_req (_("Select Download Folder"), setup_filereq_cb, entry, (char*)gtk_entry_get_text (entry), NULL, FRF_CHOOSEFOLDER);
1145 }
1146
1147 static void
setup_browsefont_cb(GtkWidget * button,GtkWidget * entry)1148 setup_browsefont_cb (GtkWidget *button, GtkWidget *entry)
1149 {
1150 GtkFontSelection *sel;
1151 GtkFontSelectionDialog *dialog;
1152 GtkWidget *ok_button;
1153
1154 dialog = (GtkFontSelectionDialog *) gtk_font_selection_dialog_new (_("Select font"));
1155 font_dialog = (GtkWidget *)dialog; /* global var */
1156
1157 sel = (GtkFontSelection *) gtk_font_selection_dialog_get_font_selection (dialog);
1158
1159 if (gtk_entry_get_text (GTK_ENTRY (entry))[0])
1160 gtk_font_selection_set_font_name (sel, gtk_entry_get_text (GTK_ENTRY (entry)));
1161
1162 ok_button = gtk_font_selection_dialog_get_ok_button (dialog);
1163 g_object_set_data (G_OBJECT (ok_button), "e", entry);
1164
1165 g_signal_connect (G_OBJECT (dialog), "destroy",
1166 G_CALLBACK (setup_fontsel_destroy), dialog);
1167 g_signal_connect (G_OBJECT (ok_button), "clicked",
1168 G_CALLBACK (setup_fontsel_cb), dialog);
1169 g_signal_connect (G_OBJECT (gtk_font_selection_dialog_get_cancel_button (dialog)), "clicked",
1170 G_CALLBACK (setup_fontsel_cancel), dialog);
1171
1172 gtk_widget_show (GTK_WIDGET (dialog));
1173 }
1174
1175 static void
setup_entry_cb(GtkEntry * entry,setting * set)1176 setup_entry_cb (GtkEntry *entry, setting *set)
1177 {
1178 int size;
1179 int pos;
1180 unsigned char *p = (unsigned char*)gtk_entry_get_text (entry);
1181 int len = strlen (p);
1182
1183 /* need to truncate? */
1184 if (len >= set->extra)
1185 {
1186 len = pos = 0;
1187 while (1)
1188 {
1189 size = g_utf8_skip [*p];
1190 len += size;
1191 p += size;
1192 /* truncate to "set->extra" BYTES */
1193 if (len >= set->extra)
1194 {
1195 gtk_editable_delete_text (GTK_EDITABLE (entry), pos, -1);
1196 break;
1197 }
1198 pos++;
1199 }
1200 }
1201 else
1202 {
1203 setup_set_str (&setup_prefs, set, gtk_entry_get_text (entry));
1204 }
1205 }
1206
1207 static void
setup_create_label(GtkWidget * table,int row,const setting * set)1208 setup_create_label (GtkWidget *table, int row, const setting *set)
1209 {
1210 gtk_table_attach (GTK_TABLE (table), setup_create_italic_label (_(set->label)),
1211 set->extra ? 1 : 3, 5, row, row + 1, GTK_FILL,
1212 GTK_SHRINK | GTK_FILL, 0, 0);
1213 }
1214
1215 static GtkWidget *
setup_create_entry(GtkWidget * table,int row,const setting * set)1216 setup_create_entry (GtkWidget *table, int row, const setting *set)
1217 {
1218 GtkWidget *label;
1219 GtkWidget *wid, *bwid;
1220
1221 label = gtk_label_new (_(set->label));
1222 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1223 gtk_table_attach (GTK_TABLE (table), label, 2, 3, row, row + 1,
1224 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
1225
1226 wid = gtk_entry_new ();
1227 g_object_set_data (G_OBJECT (wid), "lbl", label);
1228 if (set->list)
1229 gtk_entry_set_visibility (GTK_ENTRY (wid), FALSE);
1230 if (set->tooltip)
1231 gtk_widget_set_tooltip_text (wid, _(set->tooltip));
1232 gtk_entry_set_max_length (GTK_ENTRY (wid), set->extra - 1);
1233 gtk_entry_set_text (GTK_ENTRY (wid), setup_get_str (&setup_prefs, set));
1234 g_signal_connect (G_OBJECT (wid), "changed",
1235 G_CALLBACK (setup_entry_cb), (gpointer)set);
1236
1237 if (set->offset == P_OFFSETNL(hex_net_proxy_user))
1238 proxy_user = wid;
1239 if (set->offset == P_OFFSETNL(hex_net_proxy_pass))
1240 proxy_pass = wid;
1241
1242 /* only http and Socks5 can auth */
1243 if ( (set->offset == P_OFFSETNL(hex_net_proxy_pass) ||
1244 set->offset == P_OFFSETNL(hex_net_proxy_user)) &&
1245 (setup_prefs.hex_net_proxy_type != 4 && setup_prefs.hex_net_proxy_type != 3 && setup_prefs.hex_net_proxy_type != 5) )
1246 gtk_widget_set_sensitive (wid, FALSE);
1247
1248 if (set->type == ST_ENTRY)
1249 gtk_table_attach (GTK_TABLE (table), wid, 3, 6, row, row + 1,
1250 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
1251 else
1252 {
1253 gtk_table_attach (GTK_TABLE (table), wid, 3, 5, row, row + 1,
1254 GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
1255 bwid = gtk_button_new_with_label (_("Browse..."));
1256 gtk_table_attach (GTK_TABLE (table), bwid, 5, 6, row, row + 1,
1257 GTK_SHRINK | GTK_FILL, GTK_FILL, 0, 0);
1258 if (set->type == ST_EFILE)
1259 g_signal_connect (G_OBJECT (bwid), "clicked",
1260 G_CALLBACK (setup_browsefile_cb), wid);
1261 if (set->type == ST_EFONT)
1262 g_signal_connect (G_OBJECT (bwid), "clicked",
1263 G_CALLBACK (setup_browsefont_cb), wid);
1264 if (set->type == ST_EFOLDER)
1265 g_signal_connect (G_OBJECT (bwid), "clicked",
1266 G_CALLBACK (setup_browsefolder_cb), wid);
1267 }
1268
1269 return wid;
1270 }
1271
1272 static void
setup_create_header(GtkWidget * table,int row,char * labeltext)1273 setup_create_header (GtkWidget *table, int row, char *labeltext)
1274 {
1275 GtkWidget *label;
1276 char buf[128];
1277
1278 if (row == 0)
1279 g_snprintf (buf, sizeof (buf), "<b>%s</b>", _(labeltext));
1280 else
1281 g_snprintf (buf, sizeof (buf), "\n<b>%s</b>", _(labeltext));
1282
1283 label = gtk_label_new (NULL);
1284 gtk_label_set_markup (GTK_LABEL (label), buf);
1285 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1286 gtk_table_attach (GTK_TABLE (table), label, 0, 4, row, row + 1,
1287 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 5);
1288 }
1289
1290 static void
setup_create_button(GtkWidget * table,int row,char * label,GCallback callback)1291 setup_create_button (GtkWidget *table, int row, char *label, GCallback callback)
1292 {
1293 GtkWidget *but = gtk_button_new_with_label (label);
1294 gtk_table_attach (GTK_TABLE (table), but, 2, 3, row, row + 1,
1295 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 5);
1296 g_signal_connect (G_OBJECT (but), "clicked", callback, NULL);
1297 }
1298
1299 static GtkWidget *
setup_create_frame(void)1300 setup_create_frame (void)
1301 {
1302 GtkWidget *tab;
1303
1304 tab = gtk_table_new (3, 2, FALSE);
1305 gtk_container_set_border_width (GTK_CONTAINER (tab), 6);
1306 gtk_table_set_row_spacings (GTK_TABLE (tab), 2);
1307 gtk_table_set_col_spacings (GTK_TABLE (tab), 3);
1308
1309 return tab;
1310 }
1311
1312 static void
open_data_cb(GtkWidget * button,gpointer data)1313 open_data_cb (GtkWidget *button, gpointer data)
1314 {
1315 fe_open_url (get_xdir ());
1316 }
1317
1318 static GtkWidget *
setup_create_page(const setting * set)1319 setup_create_page (const setting *set)
1320 {
1321 int i, row, do_disable;
1322 GtkWidget *tab;
1323 GtkWidget *wid = NULL, *parentwid = NULL;
1324
1325 tab = setup_create_frame ();
1326 gtk_container_set_border_width (GTK_CONTAINER (tab), 6);
1327
1328 i = row = do_disable = 0;
1329 while (set[i].type != ST_END)
1330 {
1331 switch (set[i].type)
1332 {
1333 case ST_HEADER:
1334 setup_create_header (tab, row, set[i].label);
1335 break;
1336 case ST_EFONT:
1337 case ST_ENTRY:
1338 case ST_EFILE:
1339 case ST_EFOLDER:
1340 wid = setup_create_entry (tab, row, &set[i]);
1341 break;
1342 case ST_TOGGLR:
1343 row--;
1344 setup_create_toggleR (tab, row, &set[i]);
1345 break;
1346 case ST_TOGGLE:
1347 wid = setup_create_toggleL (tab, row, &set[i]);
1348 if (set[i].extra)
1349 do_disable = set[i].extra;
1350 break;
1351 case ST_3OGGLE:
1352 setup_create_3oggle (tab, row, &set[i]);
1353 break;
1354 case ST_MENU:
1355 setup_create_menu (tab, row, &set[i]);
1356 break;
1357 case ST_RADIO:
1358 row += setup_create_radio (tab, row, &set[i]);
1359 break;
1360 case ST_NUMBER:
1361 wid = setup_create_spin (tab, row, &set[i]);
1362 break;
1363 case ST_HSCALE:
1364 setup_create_hscale (tab, row, &set[i]);
1365 break;
1366 case ST_LABEL:
1367 setup_create_label (tab, row, &set[i]);
1368 break;
1369 case ST_ALERTHEAD:
1370 setup_create_alert_header (tab, row, &set[i]);
1371 }
1372
1373 if (do_disable)
1374 {
1375 if (GTK_IS_WIDGET (parentwid))
1376 {
1377 g_signal_connect (G_OBJECT (parentwid), "toggled", G_CALLBACK(setup_toggle_sensitive_cb), wid);
1378 gtk_widget_set_sensitive (wid, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (parentwid)));
1379 do_disable--;
1380 if (!do_disable)
1381 parentwid = NULL;
1382 }
1383 else
1384 parentwid = wid;
1385 }
1386
1387 i++;
1388 row++;
1389 }
1390
1391 if (set == logging_settings)
1392 {
1393 setup_create_button (tab, row, _("Open Data Folder"), G_CALLBACK(open_data_cb));
1394 }
1395
1396 return tab;
1397 }
1398
1399 static void
setup_color_ok_cb(GtkWidget * button,GtkWidget * dialog)1400 setup_color_ok_cb (GtkWidget *button, GtkWidget *dialog)
1401 {
1402 GtkColorSelectionDialog *cdialog = GTK_COLOR_SELECTION_DIALOG (dialog);
1403 GdkColor *col;
1404 GdkColor old_color;
1405 GtkStyle *style;
1406
1407 col = g_object_get_data (G_OBJECT (button), "c");
1408 old_color = *col;
1409
1410 button = g_object_get_data (G_OBJECT (button), "b");
1411
1412 if (!GTK_IS_WIDGET (button))
1413 {
1414 gtk_widget_destroy (dialog);
1415 return;
1416 }
1417
1418 color_change = TRUE;
1419
1420 gtk_color_selection_get_current_color (GTK_COLOR_SELECTION (gtk_color_selection_dialog_get_color_selection (cdialog)), col);
1421
1422 gdk_colormap_alloc_color (gtk_widget_get_colormap (button), col, TRUE, TRUE);
1423
1424 style = gtk_style_new ();
1425 style->bg[0] = *col;
1426 gtk_widget_set_style (button, style);
1427 g_object_unref (style);
1428
1429 /* is this line correct?? */
1430 gdk_colormap_free_colors (gtk_widget_get_colormap (button), &old_color, 1);
1431
1432 gtk_widget_destroy (dialog);
1433 }
1434
1435 static void
setup_color_cb(GtkWidget * button,gpointer userdata)1436 setup_color_cb (GtkWidget *button, gpointer userdata)
1437 {
1438 GtkWidget *dialog, *cancel_button, *ok_button, *help_button;
1439 GtkColorSelectionDialog *cdialog;
1440 GdkColor *color;
1441
1442 color = &colors[GPOINTER_TO_INT (userdata)];
1443
1444 dialog = gtk_color_selection_dialog_new (_("Select color"));
1445 cdialog = GTK_COLOR_SELECTION_DIALOG (dialog);
1446
1447 g_object_get (G_OBJECT(cdialog), "cancel-button", &cancel_button,
1448 "ok-button", &ok_button,
1449 "help-button", &help_button, NULL);
1450
1451 gtk_widget_hide (help_button);
1452 g_signal_connect (G_OBJECT (ok_button), "clicked",
1453 G_CALLBACK (setup_color_ok_cb), dialog);
1454 g_signal_connect (G_OBJECT (cancel_button), "clicked",
1455 G_CALLBACK (gtkutil_destroy), dialog);
1456 g_object_set_data (G_OBJECT (ok_button), "c", color);
1457 g_object_set_data (G_OBJECT (ok_button), "b", button);
1458 gtk_widget_set_sensitive (help_button, FALSE);
1459 gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (gtk_color_selection_dialog_get_color_selection (cdialog)), color);
1460 gtk_widget_show (dialog);
1461
1462 g_object_unref (cancel_button);
1463 g_object_unref (ok_button);
1464 g_object_unref (help_button);
1465 }
1466
1467 static void
setup_create_color_button(GtkWidget * table,int num,int row,int col)1468 setup_create_color_button (GtkWidget *table, int num, int row, int col)
1469 {
1470 GtkWidget *but;
1471 GtkStyle *style;
1472 char buf[64];
1473
1474 if (num > 31)
1475 strcpy (buf, "<span size=\"x-small\"> </span>");
1476 else
1477 /* 12345678901 23456789 01 23456789 */
1478 sprintf (buf, "<span size=\"x-small\">%d</span>", num);
1479 but = gtk_button_new_with_label (" ");
1480 gtk_label_set_markup (GTK_LABEL (gtk_bin_get_child (GTK_BIN (but))), buf);
1481 /* win32 build uses this to turn off themeing */
1482 g_object_set_data (G_OBJECT (but), "hexchat-color", (gpointer)1);
1483 gtk_table_attach (GTK_TABLE (table), but, col, col+1, row, row+1,
1484 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
1485 g_signal_connect (G_OBJECT (but), "clicked",
1486 G_CALLBACK (setup_color_cb), GINT_TO_POINTER (num));
1487 style = gtk_style_new ();
1488 style->bg[GTK_STATE_NORMAL] = colors[num];
1489 gtk_widget_set_style (but, style);
1490 g_object_unref (style);
1491 }
1492
1493 static void
setup_create_other_colorR(char * text,int num,int row,GtkWidget * tab)1494 setup_create_other_colorR (char *text, int num, int row, GtkWidget *tab)
1495 {
1496 GtkWidget *label;
1497
1498 label = gtk_label_new (text);
1499 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1500 gtk_table_attach (GTK_TABLE (tab), label, 5, 9, row, row + 1,
1501 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
1502 setup_create_color_button (tab, num, row, 9);
1503 }
1504
1505 static void
setup_create_other_color(char * text,int num,int row,GtkWidget * tab)1506 setup_create_other_color (char *text, int num, int row, GtkWidget *tab)
1507 {
1508 GtkWidget *label;
1509
1510 label = gtk_label_new (text);
1511 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1512 gtk_table_attach (GTK_TABLE (tab), label, 2, 3, row, row + 1,
1513 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
1514 setup_create_color_button (tab, num, row, 3);
1515 }
1516
1517 static GtkWidget *
setup_create_color_page(void)1518 setup_create_color_page (void)
1519 {
1520 GtkWidget *tab, *box, *label;
1521 int i;
1522
1523 box = gtk_vbox_new (FALSE, 0);
1524 gtk_container_set_border_width (GTK_CONTAINER (box), 6);
1525
1526 tab = gtk_table_new (9, 2, FALSE);
1527 gtk_container_set_border_width (GTK_CONTAINER (tab), 6);
1528 gtk_table_set_row_spacings (GTK_TABLE (tab), 2);
1529 gtk_table_set_col_spacings (GTK_TABLE (tab), 3);
1530 gtk_container_add (GTK_CONTAINER (box), tab);
1531
1532 setup_create_header (tab, 0, N_("Text Colors"));
1533
1534 label = gtk_label_new (_("mIRC colors:"));
1535 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1536 gtk_table_attach (GTK_TABLE (tab), label, 2, 3, 1, 2,
1537 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
1538
1539 for (i = 0; i < 16; i++)
1540 setup_create_color_button (tab, i, 1, i+3);
1541
1542 label = gtk_label_new (_("Local colors:"));
1543 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1544 gtk_table_attach (GTK_TABLE (tab), label, 2, 3, 2, 3,
1545 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0);
1546
1547 for (i = 16; i < 32; i++)
1548 setup_create_color_button (tab, i, 2, (i+3) - 16);
1549
1550 setup_create_other_color (_("Foreground:"), COL_FG, 3, tab);
1551 setup_create_other_colorR (_("Background:"), COL_BG, 3, tab);
1552
1553 setup_create_header (tab, 5, N_("Selected Text"));
1554
1555 setup_create_other_color (_("Foreground:"), COL_MARK_FG, 6, tab);
1556 setup_create_other_colorR (_("Background:"), COL_MARK_BG, 6, tab);
1557
1558 setup_create_header (tab, 8, N_("Interface Colors"));
1559
1560 setup_create_other_color (_("New data:"), COL_NEW_DATA, 9, tab);
1561 setup_create_other_colorR (_("Marker line:"), COL_MARKER, 9, tab);
1562 setup_create_other_color (_("New message:"), COL_NEW_MSG, 10, tab);
1563 setup_create_other_colorR (_("Away user:"), COL_AWAY, 10, tab);
1564 setup_create_other_color (_("Highlight:"), COL_HILIGHT, 11, tab);
1565 setup_create_other_colorR (_("Spell checker:"), COL_SPELL, 11, tab);
1566
1567 setup_create_header (tab, 15, N_("Color Stripping"));
1568
1569 /* label = gtk_label_new (_("Strip colors from:"));
1570 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1571 gtk_table_attach (GTK_TABLE (tab), label, 2, 3, 16, 17,
1572 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0); */
1573
1574 for (i = 0; i < 3; i++)
1575 {
1576 setup_create_toggleL (tab, i + 16, &color_settings[i]);
1577 }
1578
1579 return box;
1580 }
1581
1582 /* === GLOBALS for sound GUI === */
1583
1584 static GtkWidget *sndfile_entry;
1585 static int ignore_changed = FALSE;
1586
1587 extern struct text_event te[]; /* text.c */
1588 extern char *sound_files[];
1589
1590 static void
setup_snd_populate(GtkTreeView * treeview)1591 setup_snd_populate (GtkTreeView * treeview)
1592 {
1593 GtkListStore *store;
1594 GtkTreeIter iter;
1595 GtkTreeSelection *sel;
1596 GtkTreePath *path;
1597 int i;
1598
1599 sel = gtk_tree_view_get_selection (treeview);
1600 store = (GtkListStore *)gtk_tree_view_get_model (treeview);
1601
1602 for (i = NUM_XP-1; i >= 0; i--)
1603 {
1604 gtk_list_store_prepend (store, &iter);
1605 if (sound_files[i])
1606 gtk_list_store_set (store, &iter, 0, te[i].name, 1, sound_files[i], 2, i, -1);
1607 else
1608 gtk_list_store_set (store, &iter, 0, te[i].name, 1, "", 2, i, -1);
1609 if (i == last_selected_row)
1610 {
1611 gtk_tree_selection_select_iter (sel, &iter);
1612 path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
1613 if (path)
1614 {
1615 gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.5, 0.5);
1616 gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
1617 gtk_tree_path_free (path);
1618 }
1619 }
1620 }
1621 }
1622
1623 static int
setup_snd_get_selected(GtkTreeSelection * sel,GtkTreeIter * iter)1624 setup_snd_get_selected (GtkTreeSelection *sel, GtkTreeIter *iter)
1625 {
1626 int n;
1627 GtkTreeModel *model;
1628
1629 if (!gtk_tree_selection_get_selected (sel, &model, iter))
1630 return -1;
1631
1632 gtk_tree_model_get (model, iter, 2, &n, -1);
1633 return n;
1634 }
1635
1636 static void
setup_snd_row_cb(GtkTreeSelection * sel,gpointer user_data)1637 setup_snd_row_cb (GtkTreeSelection *sel, gpointer user_data)
1638 {
1639 int n;
1640 GtkTreeIter iter;
1641
1642 n = setup_snd_get_selected (sel, &iter);
1643 if (n == -1)
1644 return;
1645 last_selected_row = n;
1646
1647 ignore_changed = TRUE;
1648 if (sound_files[n])
1649 gtk_entry_set_text (GTK_ENTRY (sndfile_entry), sound_files[n]);
1650 else
1651 gtk_entry_set_text (GTK_ENTRY (sndfile_entry), "");
1652 ignore_changed = FALSE;
1653 }
1654
1655 static void
setup_snd_add_columns(GtkTreeView * treeview)1656 setup_snd_add_columns (GtkTreeView * treeview)
1657 {
1658 GtkCellRenderer *renderer;
1659 GtkTreeModel *model;
1660
1661 /* event column */
1662 renderer = gtk_cell_renderer_text_new ();
1663 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
1664 -1, _("Event"), renderer,
1665 "text", 0, NULL);
1666
1667 /* file column */
1668 renderer = gtk_cell_renderer_text_new ();
1669 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
1670 -1, _("Sound file"), renderer,
1671 "text", 1, NULL);
1672
1673 model = GTK_TREE_MODEL (gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT));
1674 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), model);
1675 g_object_unref (model);
1676 }
1677
1678 static void
setup_snd_filereq_cb(GtkWidget * entry,char * file)1679 setup_snd_filereq_cb (GtkWidget *entry, char *file)
1680 {
1681 if (file)
1682 {
1683 if (file[0])
1684 {
1685 /* Use just the filename if the given sound file is in the default <config>/sounds directory.
1686 * We're comparing absolute paths so this won't work in portable mode which uses a relative path.
1687 */
1688 if (!strcmp (g_path_get_dirname (file), g_build_filename (get_xdir (), HEXCHAT_SOUND_DIR, NULL)))
1689 {
1690 gtk_entry_set_text (GTK_ENTRY (entry), g_path_get_basename (file));
1691 }
1692 else
1693 {
1694 gtk_entry_set_text (GTK_ENTRY (entry), file);
1695 }
1696 }
1697 }
1698 }
1699
1700 static void
setup_snd_browse_cb(GtkWidget * button,GtkEntry * entry)1701 setup_snd_browse_cb (GtkWidget *button, GtkEntry *entry)
1702 {
1703 char *sounds_dir = g_build_filename (get_xdir (), HEXCHAT_SOUND_DIR, NULL);
1704 char *filter = NULL;
1705 int filter_type;
1706 #ifdef WIN32 /* win32 only supports wav, others could support anything */
1707 filter = "*.wav";
1708 filter_type = FRF_EXTENSIONS;
1709 #else
1710 filter = "audio/*";
1711 filter_type = FRF_MIMETYPES;
1712 #endif
1713
1714 gtkutil_file_req (_("Select a sound file"), setup_snd_filereq_cb, entry,
1715 sounds_dir, filter, FRF_FILTERISINITIAL|filter_type);
1716 g_free (sounds_dir);
1717 }
1718
1719 static void
setup_snd_play_cb(GtkWidget * button,GtkEntry * entry)1720 setup_snd_play_cb (GtkWidget *button, GtkEntry *entry)
1721 {
1722 sound_play (gtk_entry_get_text (entry), FALSE);
1723 }
1724
1725 static void
setup_snd_changed_cb(GtkEntry * ent,GtkTreeView * tree)1726 setup_snd_changed_cb (GtkEntry *ent, GtkTreeView *tree)
1727 {
1728 int n;
1729 GtkTreeIter iter;
1730 GtkListStore *store;
1731 GtkTreeSelection *sel;
1732
1733 if (ignore_changed)
1734 return;
1735
1736 sel = gtk_tree_view_get_selection (tree);
1737 n = setup_snd_get_selected (sel, &iter);
1738 if (n == -1)
1739 return;
1740
1741 /* get the new sound file */
1742 g_free (sound_files[n]);
1743 sound_files[n] = g_strdup (gtk_entry_get_text (GTK_ENTRY (ent)));
1744
1745 /* update the TreeView list */
1746 store = (GtkListStore *)gtk_tree_view_get_model (tree);
1747 gtk_list_store_set (store, &iter, 1, sound_files[n], -1);
1748
1749 gtk_widget_set_sensitive (cancel_button, FALSE);
1750 }
1751
1752 static GtkWidget *
setup_create_sound_page(void)1753 setup_create_sound_page (void)
1754 {
1755 GtkWidget *vbox1;
1756 GtkWidget *vbox2;
1757 GtkWidget *scrolledwindow1;
1758 GtkWidget *sound_tree;
1759 GtkWidget *table1;
1760 GtkWidget *sound_label;
1761 GtkWidget *sound_browse;
1762 GtkWidget *sound_play;
1763 GtkTreeSelection *sel;
1764
1765 vbox1 = gtk_vbox_new (FALSE, 0);
1766 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 6);
1767 gtk_widget_show (vbox1);
1768
1769 vbox2 = gtk_vbox_new (FALSE, 0);
1770 gtk_widget_show (vbox2);
1771 gtk_container_add (GTK_CONTAINER (vbox1), vbox2);
1772
1773 scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
1774 gtk_widget_show (scrolledwindow1);
1775 gtk_container_add (GTK_CONTAINER (vbox2), scrolledwindow1);
1776 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1),
1777 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1778 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow1),
1779 GTK_SHADOW_IN);
1780
1781 sound_tree = gtk_tree_view_new ();
1782 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (sound_tree));
1783 gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
1784 setup_snd_add_columns (GTK_TREE_VIEW (sound_tree));
1785 setup_snd_populate (GTK_TREE_VIEW (sound_tree));
1786 g_signal_connect (G_OBJECT (sel), "changed",
1787 G_CALLBACK (setup_snd_row_cb), NULL);
1788 gtk_widget_show (sound_tree);
1789 gtk_container_add (GTK_CONTAINER (scrolledwindow1), sound_tree);
1790 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (sound_tree), TRUE);
1791
1792 table1 = gtk_table_new (2, 3, FALSE);
1793 gtk_widget_show (table1);
1794 gtk_box_pack_start (GTK_BOX (vbox2), table1, FALSE, TRUE, 8);
1795 gtk_table_set_row_spacings (GTK_TABLE (table1), 2);
1796 gtk_table_set_col_spacings (GTK_TABLE (table1), 4);
1797
1798 sound_label = gtk_label_new_with_mnemonic (_("Sound file:"));
1799 gtk_widget_show (sound_label);
1800 gtk_table_attach (GTK_TABLE (table1), sound_label, 0, 1, 0, 1,
1801 (GtkAttachOptions) (GTK_FILL),
1802 (GtkAttachOptions) (0), 0, 0);
1803 gtk_misc_set_alignment (GTK_MISC (sound_label), 0, 0.5);
1804
1805 sndfile_entry = gtk_entry_new ();
1806 g_signal_connect (G_OBJECT (sndfile_entry), "changed",
1807 G_CALLBACK (setup_snd_changed_cb), sound_tree);
1808 gtk_widget_show (sndfile_entry);
1809 gtk_table_attach (GTK_TABLE (table1), sndfile_entry, 0, 1, 1, 2,
1810 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1811 (GtkAttachOptions) (0), 0, 0);
1812
1813 sound_browse = gtk_button_new_with_mnemonic (_("_Browse..."));
1814 g_signal_connect (G_OBJECT (sound_browse), "clicked",
1815 G_CALLBACK (setup_snd_browse_cb), sndfile_entry);
1816 gtk_widget_show (sound_browse);
1817 gtk_table_attach (GTK_TABLE (table1), sound_browse, 1, 2, 1, 2,
1818 (GtkAttachOptions) (GTK_FILL),
1819 (GtkAttachOptions) (0), 0, 0);
1820
1821 #ifdef GTK_STOCK_MEDIA_PLAY
1822 sound_play = gtk_button_new_from_stock (GTK_STOCK_MEDIA_PLAY);
1823 #else
1824 sound_play = gtk_button_new_with_mnemonic (_("_Play"));
1825 #endif
1826 g_signal_connect (G_OBJECT (sound_play), "clicked",
1827 G_CALLBACK (setup_snd_play_cb), sndfile_entry);
1828 gtk_widget_show (sound_play);
1829 gtk_table_attach (GTK_TABLE (table1), sound_play, 2, 3, 1, 2,
1830 (GtkAttachOptions) (GTK_FILL),
1831 (GtkAttachOptions) (0), 0, 0);
1832
1833 setup_snd_row_cb (sel, NULL);
1834
1835 return vbox1;
1836 }
1837
1838 static void
setup_add_page(const char * title,GtkWidget * book,GtkWidget * tab)1839 setup_add_page (const char *title, GtkWidget *book, GtkWidget *tab)
1840 {
1841 GtkWidget *label, *vvbox, *viewport;
1842 GtkScrolledWindow *sw;
1843 char buf[128];
1844
1845 vvbox = gtk_vbox_new (FALSE, 0);
1846
1847 /* label */
1848 label = gtk_label_new (NULL);
1849 g_snprintf (buf, sizeof (buf), "<b><big>%s</big></b>", _(title));
1850 gtk_label_set_markup (GTK_LABEL (label), buf);
1851 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1852 gtk_misc_set_padding (GTK_MISC (label), 2, 1);
1853 gtk_box_pack_start (GTK_BOX (vvbox), label, FALSE, FALSE, 2);
1854
1855 gtk_container_add (GTK_CONTAINER (vvbox), tab);
1856
1857 sw = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new (NULL, NULL));
1858 gtk_scrolled_window_set_shadow_type (sw, GTK_SHADOW_IN);
1859 gtk_scrolled_window_set_policy (sw, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1860 gtk_scrolled_window_add_with_viewport (sw, vvbox);
1861
1862 viewport = gtk_bin_get_child (GTK_BIN(sw));
1863 gtk_viewport_set_shadow_type (GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1864
1865 gtk_notebook_append_page (GTK_NOTEBOOK (book), GTK_WIDGET(sw), NULL);
1866 }
1867
1868 static const char *const cata[] =
1869 {
1870 N_("Interface"),
1871 N_("Appearance"),
1872 N_("Input box"),
1873 N_("User list"),
1874 N_("Channel switcher"),
1875 N_("Colors"),
1876 NULL,
1877 N_("Chatting"),
1878 N_("General"),
1879 N_("Alerts"),
1880 N_("Sounds"),
1881 N_("Logging"),
1882 N_("Advanced"),
1883 NULL,
1884 N_("Network"),
1885 N_("Network setup"),
1886 N_("File transfers"),
1887 N_("Identd"),
1888 NULL,
1889 NULL
1890 };
1891
1892 static GtkWidget *
setup_create_pages(GtkWidget * box)1893 setup_create_pages (GtkWidget *box)
1894 {
1895 GtkWidget *book;
1896 GtkWindow *win = GTK_WINDOW(gtk_widget_get_toplevel (box));
1897
1898 book = gtk_notebook_new ();
1899
1900 setup_add_page (cata[1], book, setup_create_page (appearance_settings));
1901 setup_add_page (cata[2], book, setup_create_page (inputbox_settings));
1902 setup_add_page (cata[3], book, setup_create_page (userlist_settings));
1903 setup_add_page (cata[4], book, setup_create_page (tabs_settings));
1904 setup_add_page (cata[5], book, setup_create_color_page ());
1905
1906 setup_add_page (cata[8], book, setup_create_page (general_settings));
1907
1908 if (!gtkutil_tray_icon_supported (win) && !notification_backend_supported ())
1909 {
1910 setup_add_page (cata[9], book, setup_create_page (alert_settings_unityandnonotifications));
1911 }
1912 else if (!gtkutil_tray_icon_supported (win))
1913 {
1914 setup_add_page (cata[9], book, setup_create_page (alert_settings_unity));
1915 }
1916 else if (!notification_backend_supported ())
1917 {
1918 setup_add_page (cata[9], book, setup_create_page (alert_settings_nonotifications));
1919 }
1920 else
1921 {
1922 setup_add_page (cata[9], book, setup_create_page (alert_settings));
1923 }
1924
1925 setup_add_page (cata[10], book, setup_create_sound_page ());
1926 setup_add_page (cata[11], book, setup_create_page (logging_settings));
1927 setup_add_page (cata[12], book, setup_create_page (advanced_settings));
1928
1929 setup_add_page (cata[15], book, setup_create_page (network_settings));
1930 setup_add_page (cata[16], book, setup_create_page (filexfer_settings));
1931 setup_add_page (cata[17], book, setup_create_page (identd_settings));
1932
1933 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (book), FALSE);
1934 gtk_notebook_set_show_border (GTK_NOTEBOOK (book), FALSE);
1935 gtk_container_add (GTK_CONTAINER (box), book);
1936
1937 return book;
1938 }
1939
1940 static void
setup_tree_cb(GtkTreeView * treeview,GtkWidget * book)1941 setup_tree_cb (GtkTreeView *treeview, GtkWidget *book)
1942 {
1943 GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
1944 GtkTreeIter iter;
1945 GtkTreeModel *model;
1946 int page;
1947
1948 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1949 {
1950 gtk_tree_model_get (model, &iter, 1, &page, -1);
1951 if (page != -1)
1952 {
1953 gtk_notebook_set_current_page (GTK_NOTEBOOK (book), page);
1954 last_selected_page = page;
1955 }
1956 }
1957 }
1958
1959 static gboolean
setup_tree_select_filter(GtkTreeSelection * selection,GtkTreeModel * model,GtkTreePath * path,gboolean path_selected,gpointer data)1960 setup_tree_select_filter (GtkTreeSelection *selection, GtkTreeModel *model,
1961 GtkTreePath *path, gboolean path_selected,
1962 gpointer data)
1963 {
1964 if (gtk_tree_path_get_depth (path) > 1)
1965 return TRUE;
1966 return FALSE;
1967 }
1968
1969 static void
setup_create_tree(GtkWidget * box,GtkWidget * book)1970 setup_create_tree (GtkWidget *box, GtkWidget *book)
1971 {
1972 GtkWidget *tree;
1973 GtkWidget *frame;
1974 GtkTreeStore *model;
1975 GtkTreeIter iter;
1976 GtkTreeIter child_iter;
1977 GtkTreeIter *sel_iter = NULL;
1978 GtkCellRenderer *renderer;
1979 GtkTreeSelection *sel;
1980 int i, page;
1981
1982 model = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
1983
1984 i = 0;
1985 page = 0;
1986 do
1987 {
1988 gtk_tree_store_append (model, &iter, NULL);
1989 gtk_tree_store_set (model, &iter, 0, _(cata[i]), 1, -1, -1);
1990 i++;
1991
1992 do
1993 {
1994 gtk_tree_store_append (model, &child_iter, &iter);
1995 gtk_tree_store_set (model, &child_iter, 0, _(cata[i]), 1, page, -1);
1996 if (page == last_selected_page)
1997 sel_iter = gtk_tree_iter_copy (&child_iter);
1998 page++;
1999 i++;
2000 } while (cata[i]);
2001
2002 i++;
2003
2004 } while (cata[i]);
2005
2006 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
2007 g_object_unref (G_OBJECT (model));
2008 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
2009 gtk_tree_selection_set_mode (sel, GTK_SELECTION_BROWSE);
2010 gtk_tree_selection_set_select_function (sel, setup_tree_select_filter,
2011 NULL, NULL);
2012 g_signal_connect (G_OBJECT (tree), "cursor_changed",
2013 G_CALLBACK (setup_tree_cb), book);
2014
2015 renderer = gtk_cell_renderer_text_new ();
2016 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree),
2017 -1, _("Categories"), renderer, "text", 0, NULL);
2018 gtk_tree_view_expand_all (GTK_TREE_VIEW (tree));
2019
2020 frame = gtk_frame_new (NULL);
2021 gtk_container_add (GTK_CONTAINER (frame), tree);
2022 gtk_box_pack_start (GTK_BOX (box), frame, 0, 0, 0);
2023 gtk_box_reorder_child (GTK_BOX (box), frame, 0);
2024
2025 if (sel_iter)
2026 {
2027 gtk_tree_selection_select_iter (sel, sel_iter);
2028 gtk_tree_iter_free (sel_iter);
2029 }
2030 }
2031
2032 static void
setup_apply_entry_style(GtkWidget * entry)2033 setup_apply_entry_style (GtkWidget *entry)
2034 {
2035 gtk_widget_modify_base (entry, GTK_STATE_NORMAL, &colors[COL_BG]);
2036 gtk_widget_modify_text (entry, GTK_STATE_NORMAL, &colors[COL_FG]);
2037 gtk_widget_modify_font (entry, input_style->font_desc);
2038 }
2039
2040 static void
setup_apply_to_sess(session_gui * gui)2041 setup_apply_to_sess (session_gui *gui)
2042 {
2043 mg_update_xtext (gui->xtext);
2044
2045 if (prefs.hex_gui_ulist_style)
2046 gtk_widget_set_style (gui->user_tree, input_style);
2047
2048 if (prefs.hex_gui_input_style)
2049 {
2050 extern char cursor_color_rc[];
2051 char buf[256];
2052 sprintf (buf, cursor_color_rc,
2053 (colors[COL_FG].red >> 8),
2054 (colors[COL_FG].green >> 8),
2055 (colors[COL_FG].blue >> 8));
2056 gtk_rc_parse_string (buf);
2057
2058 setup_apply_entry_style (gui->input_box);
2059 setup_apply_entry_style (gui->limit_entry);
2060 setup_apply_entry_style (gui->key_entry);
2061 setup_apply_entry_style (gui->topic_entry);
2062 }
2063
2064 if (prefs.hex_gui_ulist_buttons)
2065 gtk_widget_show (gui->button_box);
2066 else
2067 gtk_widget_hide (gui->button_box);
2068
2069 /* update active languages */
2070 sexy_spell_entry_deactivate_language((SexySpellEntry *)gui->input_box,NULL);
2071 sexy_spell_entry_activate_default_languages((SexySpellEntry *)gui->input_box);
2072
2073 sexy_spell_entry_set_checked ((SexySpellEntry *)gui->input_box, prefs.hex_gui_input_spell);
2074 sexy_spell_entry_set_parse_attributes ((SexySpellEntry *)gui->input_box, prefs.hex_gui_input_attr);
2075 }
2076
2077 static void
unslash(char * dir)2078 unslash (char *dir)
2079 {
2080 if (dir[0])
2081 {
2082 int len = strlen (dir) - 1;
2083 #ifdef WIN32
2084 if (dir[len] == '/' || dir[len] == '\\')
2085 #else
2086 if (dir[len] == '/')
2087 #endif
2088 dir[len] = 0;
2089 }
2090 }
2091
2092 void
setup_apply_real(int new_pix,int do_ulist,int do_layout,int do_identd)2093 setup_apply_real (int new_pix, int do_ulist, int do_layout, int do_identd)
2094 {
2095 GSList *list;
2096 session *sess;
2097 int done_main = FALSE;
2098
2099 /* remove trailing slashes */
2100 unslash (prefs.hex_dcc_dir);
2101 unslash (prefs.hex_dcc_completed_dir);
2102
2103 g_mkdir (prefs.hex_dcc_dir, 0700);
2104 g_mkdir (prefs.hex_dcc_completed_dir, 0700);
2105
2106 if (new_pix)
2107 {
2108 if (channelwin_pix)
2109 g_object_unref (channelwin_pix);
2110 channelwin_pix = pixmap_load_from_file (prefs.hex_text_background);
2111 }
2112
2113 input_style = create_input_style (input_style);
2114
2115 list = sess_list;
2116 while (list)
2117 {
2118 sess = list->data;
2119 if (sess->gui->is_tab)
2120 {
2121 /* only apply to main tabwindow once */
2122 if (!done_main)
2123 {
2124 done_main = TRUE;
2125 setup_apply_to_sess (sess->gui);
2126 }
2127 } else
2128 {
2129 setup_apply_to_sess (sess->gui);
2130 }
2131
2132 log_open_or_close (sess);
2133
2134 if (do_ulist)
2135 userlist_rehash (sess);
2136
2137 list = list->next;
2138 }
2139
2140 mg_apply_setup ();
2141 tray_apply_setup ();
2142 hexchat_reinit_timers ();
2143
2144 if (do_layout)
2145 menu_change_layout ();
2146
2147 if (do_identd)
2148 handle_command (current_sess, "IDENTD reload", FALSE);
2149 }
2150
2151 static void
setup_apply(struct hexchatprefs * pr)2152 setup_apply (struct hexchatprefs *pr)
2153 {
2154 #ifdef WIN32
2155 PangoFontDescription *old_desc;
2156 PangoFontDescription *new_desc;
2157 char buffer[4 * FONTNAMELEN + 1];
2158 #endif
2159 int new_pix = FALSE;
2160 int noapply = FALSE;
2161 int do_ulist = FALSE;
2162 int do_layout = FALSE;
2163 int do_identd = FALSE;
2164
2165 if (strcmp (pr->hex_text_background, prefs.hex_text_background) != 0)
2166 new_pix = TRUE;
2167
2168 #define DIFF(a) (pr->a != prefs.a)
2169
2170 #ifdef WIN32
2171 if (DIFF (hex_gui_lang))
2172 noapply = TRUE;
2173 #endif
2174 if (DIFF (hex_gui_compact))
2175 noapply = TRUE;
2176 if (DIFF (hex_gui_input_icon))
2177 noapply = TRUE;
2178 if (DIFF (hex_gui_input_nick))
2179 noapply = TRUE;
2180 if (DIFF (hex_gui_lagometer))
2181 noapply = TRUE;
2182 if (DIFF (hex_gui_tab_icons))
2183 noapply = TRUE;
2184 if (DIFF (hex_gui_tab_server))
2185 noapply = TRUE;
2186 if (DIFF (hex_gui_tab_small))
2187 noapply = TRUE;
2188 if (DIFF (hex_gui_tab_sort))
2189 noapply = TRUE;
2190 if (DIFF (hex_gui_tab_trunc))
2191 noapply = TRUE;
2192 if (DIFF (hex_gui_throttlemeter))
2193 noapply = TRUE;
2194 if (DIFF (hex_gui_ulist_count))
2195 noapply = TRUE;
2196 if (DIFF (hex_gui_ulist_icons))
2197 noapply = TRUE;
2198 if (DIFF (hex_gui_ulist_show_hosts))
2199 noapply = TRUE;
2200 if (DIFF (hex_gui_ulist_style))
2201 noapply = TRUE;
2202 if (DIFF (hex_gui_ulist_sort))
2203 noapply = TRUE;
2204 if (DIFF (hex_gui_input_style) && prefs.hex_gui_input_style == TRUE)
2205 noapply = TRUE; /* Requires restart to *disable* */
2206
2207 if (DIFF (hex_gui_tab_dots))
2208 do_layout = TRUE;
2209 if (DIFF (hex_gui_tab_layout))
2210 do_layout = TRUE;
2211
2212 if (DIFF (hex_identd_server) || DIFF (hex_identd_port))
2213 do_identd = TRUE;
2214
2215 if (color_change || (DIFF (hex_gui_ulist_color)) || (DIFF (hex_away_size_max)) || (DIFF (hex_away_track)))
2216 do_ulist = TRUE;
2217
2218 if ((pr->hex_gui_tab_pos == 5 || pr->hex_gui_tab_pos == 6) &&
2219 pr->hex_gui_tab_layout == 2 && pr->hex_gui_tab_pos != prefs.hex_gui_tab_pos)
2220 fe_message (_("You cannot place the tree on the top or bottom!\n"
2221 "Please change to the <b>Tabs</b> layout in the <b>View</b>"
2222 " menu first."),
2223 FE_MSG_WARN | FE_MSG_MARKUP);
2224
2225 /* format cannot be blank, there is already a setting for this */
2226 if (pr->hex_stamp_text_format[0] == 0)
2227 {
2228 pr->hex_stamp_text = 0;
2229 strcpy (pr->hex_stamp_text_format, prefs.hex_stamp_text_format);
2230 }
2231
2232 memcpy (&prefs, pr, sizeof (prefs));
2233
2234 #ifdef WIN32
2235 /* merge hex_font_main and hex_font_alternative into hex_font_normal */
2236 old_desc = pango_font_description_from_string (prefs.hex_text_font_main);
2237 sprintf (buffer, "%s,%s", pango_font_description_get_family (old_desc), prefs.hex_text_font_alternative);
2238 new_desc = pango_font_description_from_string (buffer);
2239 pango_font_description_set_weight (new_desc, pango_font_description_get_weight (old_desc));
2240 pango_font_description_set_style (new_desc, pango_font_description_get_style (old_desc));
2241 pango_font_description_set_size (new_desc, pango_font_description_get_size (old_desc));
2242 sprintf (prefs.hex_text_font, "%s", pango_font_description_to_string (new_desc));
2243
2244 /* FIXME this is not required after pango_font_description_from_string()
2245 g_free (old_desc);
2246 g_free (new_desc);
2247 */
2248 #endif
2249
2250 if (prefs.hex_irc_real_name[0] == 0)
2251 {
2252 fe_message (_("The Real name option cannot be left blank. Falling back to \"realname\"."), FE_MSG_WARN);
2253 strcpy (prefs.hex_irc_real_name, "realname");
2254 }
2255
2256 setup_apply_real (new_pix, do_ulist, do_layout, do_identd);
2257
2258 if (noapply)
2259 fe_message (_("Some settings were changed that require a"
2260 " restart to take full effect."), FE_MSG_WARN);
2261
2262 #ifndef WIN32
2263 if (prefs.hex_dcc_auto_recv == 2) /* Auto */
2264 {
2265 if (!strcmp ((char *)g_get_home_dir (), prefs.hex_dcc_dir))
2266 {
2267 fe_message (_("*WARNING*\n"
2268 "Auto accepting DCC to your home directory\n"
2269 "can be dangerous and is exploitable. Eg:\n"
2270 "Someone could send you a .bash_profile"), FE_MSG_WARN);
2271 }
2272 }
2273 #endif
2274 }
2275
2276 static void
setup_ok_cb(GtkWidget * but,GtkWidget * win)2277 setup_ok_cb (GtkWidget *but, GtkWidget *win)
2278 {
2279 gtk_widget_destroy (win);
2280 setup_apply (&setup_prefs);
2281 save_config ();
2282 palette_save ();
2283 }
2284
2285 static GtkWidget *
setup_window_open(void)2286 setup_window_open (void)
2287 {
2288 GtkWidget *wid, *win, *vbox, *hbox, *hbbox;
2289 char buf[128];
2290
2291 g_snprintf(buf, sizeof(buf), _("Preferences - %s"), _(DISPLAY_NAME));
2292 win = gtkutil_window_new (buf, "prefs", 0, 600, 2);
2293
2294 vbox = gtk_vbox_new (FALSE, 5);
2295 gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
2296 gtk_container_add (GTK_CONTAINER (win), vbox);
2297
2298 hbox = gtk_hbox_new (FALSE, 4);
2299 gtk_container_add (GTK_CONTAINER (vbox), hbox);
2300
2301 setup_create_tree (hbox, setup_create_pages (hbox));
2302
2303 /* prepare the button box */
2304 hbbox = gtk_hbutton_box_new ();
2305 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbbox), GTK_BUTTONBOX_END);
2306 gtk_box_set_spacing (GTK_BOX (hbbox), 4);
2307 gtk_box_pack_end (GTK_BOX (vbox), hbbox, FALSE, FALSE, 0);
2308
2309 cancel_button = wid = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
2310 g_signal_connect (G_OBJECT (wid), "clicked",
2311 G_CALLBACK (gtkutil_destroy), win);
2312 gtk_box_pack_start (GTK_BOX (hbbox), wid, FALSE, FALSE, 0);
2313
2314 wid = gtk_button_new_from_stock (GTK_STOCK_OK);
2315 g_signal_connect (G_OBJECT (wid), "clicked",
2316 G_CALLBACK (setup_ok_cb), win);
2317 gtk_box_pack_start (GTK_BOX (hbbox), wid, FALSE, FALSE, 0);
2318
2319 gtk_widget_show_all (win);
2320
2321 return win;
2322 }
2323
2324 static void
setup_close_cb(GtkWidget * win,GtkWidget ** swin)2325 setup_close_cb (GtkWidget *win, GtkWidget **swin)
2326 {
2327 *swin = NULL;
2328
2329 if (font_dialog)
2330 {
2331 gtk_widget_destroy (font_dialog);
2332 font_dialog = NULL;
2333 }
2334 }
2335
2336 void
setup_open(void)2337 setup_open (void)
2338 {
2339 static GtkWidget *setup_window = NULL;
2340
2341 if (setup_window)
2342 {
2343 gtk_window_present (GTK_WINDOW (setup_window));
2344 return;
2345 }
2346
2347 memcpy (&setup_prefs, &prefs, sizeof (prefs));
2348
2349 color_change = FALSE;
2350 setup_window = setup_window_open ();
2351
2352 g_signal_connect (G_OBJECT (setup_window), "destroy",
2353 G_CALLBACK (setup_close_cb), &setup_window);
2354 }
2355