fe8abbf4 |
1 | /* |
2 | * wincfg.c - the Windows-specific parts of the PuTTY configuration |
3 | * box. |
4 | */ |
5 | |
fe8abbf4 |
6 | #include <assert.h> |
7 | #include <stdlib.h> |
8 | |
9 | #include "putty.h" |
10 | #include "dialog.h" |
11 | #include "storage.h" |
12 | |
13 | static void about_handler(union control *ctrl, void *dlg, |
14 | void *data, int event) |
15 | { |
16 | HWND *hwndp = (HWND *)ctrl->generic.context.p; |
17 | |
18 | if (event == EVENT_ACTION) { |
19 | modal_about_box(*hwndp); |
20 | } |
21 | } |
22 | |
23 | static void help_handler(union control *ctrl, void *dlg, |
24 | void *data, int event) |
25 | { |
26 | HWND *hwndp = (HWND *)ctrl->generic.context.p; |
27 | |
28 | if (event == EVENT_ACTION) { |
29 | show_help(*hwndp); |
30 | } |
31 | } |
32 | |
33 | void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, |
8a7f1392 |
34 | int midsession, int protocol) |
fe8abbf4 |
35 | { |
36 | struct controlset *s; |
37 | union control *c; |
f6f450e2 |
38 | char *str; |
fe8abbf4 |
39 | |
40 | if (!midsession) { |
41 | /* |
42 | * Add the About and Help buttons to the standard panel. |
43 | */ |
44 | s = ctrl_getset(b, "", "", ""); |
45 | c = ctrl_pushbutton(s, "About", 'a', HELPCTX(no_help), |
46 | about_handler, P(hwndp)); |
47 | c->generic.column = 0; |
48 | if (has_help) { |
49 | c = ctrl_pushbutton(s, "Help", 'h', HELPCTX(no_help), |
50 | help_handler, P(hwndp)); |
51 | c->generic.column = 1; |
52 | } |
53 | } |
54 | |
55 | /* |
1d0d4a3b |
56 | * Full-screen mode is a Windows peculiarity; hence |
57 | * scrollbar_in_fullscreen is as well. |
58 | */ |
59 | s = ctrl_getset(b, "Window", "scrollback", |
60 | "Control the scrollback in the window"); |
61 | ctrl_checkbox(s, "Display scrollbar in full screen mode", 'i', |
62 | HELPCTX(window_scrollback), |
63 | dlg_stdcheckbox_handler, |
64 | I(offsetof(Config,scrollbar_in_fullscreen))); |
65 | /* |
66 | * Really this wants to go just after `Display scrollbar'. See |
67 | * if we can find that control, and do some shuffling. |
68 | */ |
69 | { |
70 | int i; |
71 | for (i = 0; i < s->ncontrols; i++) { |
72 | c = s->ctrls[i]; |
73 | if (c->generic.type == CTRL_CHECKBOX && |
74 | c->generic.context.i == offsetof(Config,scrollbar)) { |
75 | /* |
76 | * Control i is the scrollbar checkbox. |
77 | * Control s->ncontrols-1 is the scrollbar-in-FS one. |
78 | */ |
79 | if (i < s->ncontrols-2) { |
80 | c = s->ctrls[s->ncontrols-1]; |
81 | memmove(s->ctrls+i+2, s->ctrls+i+1, |
82 | (s->ncontrols-i-2)*sizeof(union control *)); |
83 | s->ctrls[i+1] = c; |
84 | } |
85 | break; |
86 | } |
87 | } |
88 | } |
89 | |
90 | /* |
fe8abbf4 |
91 | * Windows has the AltGr key, which has various Windows- |
92 | * specific options. |
93 | */ |
94 | s = ctrl_getset(b, "Terminal/Keyboard", "features", |
95 | "Enable extra keyboard features:"); |
96 | ctrl_checkbox(s, "AltGr acts as Compose key", 't', |
97 | HELPCTX(keyboard_compose), |
98 | dlg_stdcheckbox_handler, I(offsetof(Config,compose_key))); |
99 | ctrl_checkbox(s, "Control-Alt is different from AltGr", 'd', |
100 | HELPCTX(keyboard_ctrlalt), |
101 | dlg_stdcheckbox_handler, I(offsetof(Config,ctrlaltkeys))); |
102 | |
103 | /* |
85f6b361 |
104 | * Windows allows an arbitrary .WAV to be played as a bell, and |
105 | * also the use of the PC speaker. For this we must search the |
106 | * existing controlset for the radio-button set controlling the |
107 | * `beep' option, and add extra buttons to it. |
fe8abbf4 |
108 | * |
109 | * Note that although this _looks_ like a hideous hack, it's |
110 | * actually all above board. The well-defined interface to the |
111 | * per-platform dialog box code is the _data structures_ `union |
112 | * control', `struct controlset' and so on; so code like this |
113 | * that reaches into those data structures and changes bits of |
114 | * them is perfectly legitimate and crosses no boundaries. All |
115 | * the ctrl_* routines that create most of the controls are |
116 | * convenient shortcuts provided on the cross-platform side of |
117 | * the interface, and template creation code is under no actual |
118 | * obligation to use them. |
119 | */ |
120 | s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell"); |
121 | { |
122 | int i; |
123 | for (i = 0; i < s->ncontrols; i++) { |
124 | c = s->ctrls[i]; |
125 | if (c->generic.type == CTRL_RADIO && |
126 | c->generic.context.i == offsetof(Config, beep)) { |
127 | assert(c->generic.handler == dlg_stdradiobutton_handler); |
85f6b361 |
128 | c->radio.nbuttons += 2; |
fe8abbf4 |
129 | c->radio.buttons = |
3d88e64d |
130 | sresize(c->radio.buttons, c->radio.nbuttons, char *); |
fe8abbf4 |
131 | c->radio.buttons[c->radio.nbuttons-1] = |
132 | dupstr("Play a custom sound file"); |
85f6b361 |
133 | c->radio.buttons[c->radio.nbuttons-2] = |
134 | dupstr("Beep using the PC speaker"); |
fe8abbf4 |
135 | c->radio.buttondata = |
3d88e64d |
136 | sresize(c->radio.buttondata, c->radio.nbuttons, intorptr); |
fe8abbf4 |
137 | c->radio.buttondata[c->radio.nbuttons-1] = I(BELL_WAVEFILE); |
85f6b361 |
138 | c->radio.buttondata[c->radio.nbuttons-2] = I(BELL_PCSPEAKER); |
fe8abbf4 |
139 | if (c->radio.shortcuts) { |
140 | c->radio.shortcuts = |
3d88e64d |
141 | sresize(c->radio.shortcuts, c->radio.nbuttons, char); |
fe8abbf4 |
142 | c->radio.shortcuts[c->radio.nbuttons-1] = NO_SHORTCUT; |
85f6b361 |
143 | c->radio.shortcuts[c->radio.nbuttons-2] = NO_SHORTCUT; |
fe8abbf4 |
144 | } |
145 | break; |
146 | } |
147 | } |
148 | } |
149 | ctrl_filesel(s, "Custom sound file to play as a bell:", NO_SHORTCUT, |
150 | FILTER_WAVE_FILES, FALSE, "Select bell sound file", |
151 | HELPCTX(bell_style), |
152 | dlg_stdfilesel_handler, I(offsetof(Config, bell_wavefile))); |
153 | |
154 | /* |
155 | * While we've got this box open, taskbar flashing on a bell is |
156 | * also Windows-specific. |
157 | */ |
158 | ctrl_radiobuttons(s, "Taskbar/caption indication on bell:", 'i', 3, |
159 | HELPCTX(bell_taskbar), |
160 | dlg_stdradiobutton_handler, |
161 | I(offsetof(Config, beep_ind)), |
162 | "Disabled", I(B_IND_DISABLED), |
163 | "Flashing", I(B_IND_FLASH), |
164 | "Steady", I(B_IND_STEADY), NULL); |
165 | |
166 | /* |
167 | * The sunken-edge border is a Windows GUI feature. |
168 | */ |
169 | s = ctrl_getset(b, "Window/Appearance", "border", |
170 | "Adjust the window border"); |
171 | ctrl_checkbox(s, "Sunken-edge border (slightly thicker)", 's', |
172 | HELPCTX(appearance_border), |
173 | dlg_stdcheckbox_handler, I(offsetof(Config,sunken_edge))); |
174 | |
175 | /* |
17c7fed1 |
176 | * Configurable font quality settings for Windows. |
177 | */ |
178 | s = ctrl_getset(b, "Window/Appearance", "font", |
179 | "Font settings"); |
180 | ctrl_radiobuttons(s, "Font quality:", 'q', 2, |
181 | HELPCTX(appearance_font), |
182 | dlg_stdradiobutton_handler, |
183 | I(offsetof(Config, font_quality)), |
184 | "Antialiased", I(FQ_ANTIALIASED), |
185 | "Non-Antialiased", I(FQ_NONANTIALIASED), |
186 | "ClearType", I(FQ_CLEARTYPE), |
187 | "Default", I(FQ_DEFAULT), NULL); |
188 | |
189 | /* |
fe8abbf4 |
190 | * Cyrillic Lock is a horrid misfeature even on Windows, and |
191 | * the least we can do is ensure it never makes it to any other |
192 | * platform (at least unless someone fixes it!). |
193 | */ |
74790953 |
194 | s = ctrl_getset(b, "Window/Translation", "tweaks", NULL); |
fe8abbf4 |
195 | ctrl_checkbox(s, "Caps Lock acts as Cyrillic switch", 's', |
196 | HELPCTX(translation_cyrillic), |
197 | dlg_stdcheckbox_handler, |
198 | I(offsetof(Config,xlat_capslockcyr))); |
199 | |
200 | /* |
894ba831 |
201 | * On Windows we can use but not enumerate translation tables |
202 | * from the operating system. Briefly document this. |
203 | */ |
204 | s = ctrl_getset(b, "Window/Translation", "trans", |
205 | "Character set translation on received data"); |
206 | ctrl_text(s, "(Codepages supported by Windows but not listed here, " |
207 | "such as CP866 on many systems, can be entered manually)", |
208 | HELPCTX(translation_codepage)); |
209 | |
210 | /* |
fe8abbf4 |
211 | * Windows has the weird OEM font mode, which gives us some |
212 | * additional options when working with line-drawing |
213 | * characters. |
214 | */ |
f6f450e2 |
215 | str = dupprintf("Adjust how %s displays line drawing characters", appname); |
216 | s = ctrl_getset(b, "Window/Translation", "linedraw", str); |
217 | sfree(str); |
fe8abbf4 |
218 | { |
219 | int i; |
220 | for (i = 0; i < s->ncontrols; i++) { |
221 | c = s->ctrls[i]; |
222 | if (c->generic.type == CTRL_RADIO && |
223 | c->generic.context.i == offsetof(Config, vtmode)) { |
224 | assert(c->generic.handler == dlg_stdradiobutton_handler); |
3900c2d6 |
225 | c->radio.nbuttons += 3; |
fe8abbf4 |
226 | c->radio.buttons = |
3d88e64d |
227 | sresize(c->radio.buttons, c->radio.nbuttons, char *); |
3900c2d6 |
228 | c->radio.buttons[c->radio.nbuttons-3] = |
229 | dupstr("Font has XWindows encoding"); |
fe8abbf4 |
230 | c->radio.buttons[c->radio.nbuttons-2] = |
231 | dupstr("Use font in both ANSI and OEM modes"); |
232 | c->radio.buttons[c->radio.nbuttons-1] = |
233 | dupstr("Use font in OEM mode only"); |
234 | c->radio.buttondata = |
3d88e64d |
235 | sresize(c->radio.buttondata, c->radio.nbuttons, intorptr); |
3900c2d6 |
236 | c->radio.buttondata[c->radio.nbuttons-3] = I(VT_XWINDOWS); |
fe8abbf4 |
237 | c->radio.buttondata[c->radio.nbuttons-2] = I(VT_OEMANSI); |
238 | c->radio.buttondata[c->radio.nbuttons-1] = I(VT_OEMONLY); |
239 | if (!c->radio.shortcuts) { |
240 | int j; |
3d88e64d |
241 | c->radio.shortcuts = snewn(c->radio.nbuttons, char); |
fe8abbf4 |
242 | for (j = 0; j < c->radio.nbuttons; j++) |
243 | c->radio.shortcuts[j] = NO_SHORTCUT; |
244 | } else { |
3d88e64d |
245 | c->radio.shortcuts = sresize(c->radio.shortcuts, |
246 | c->radio.nbuttons, char); |
fe8abbf4 |
247 | } |
3900c2d6 |
248 | c->radio.shortcuts[c->radio.nbuttons-3] = 'x'; |
fe8abbf4 |
249 | c->radio.shortcuts[c->radio.nbuttons-2] = 'b'; |
250 | c->radio.shortcuts[c->radio.nbuttons-1] = 'e'; |
251 | break; |
252 | } |
253 | } |
254 | } |
255 | |
256 | /* |
257 | * RTF paste is Windows-specific. |
258 | */ |
00381fc7 |
259 | s = ctrl_getset(b, "Window/Selection", "format", |
260 | "Formatting of pasted characters"); |
fe8abbf4 |
261 | ctrl_checkbox(s, "Paste to clipboard in RTF as well as plain text", 'f', |
262 | HELPCTX(selection_rtf), |
263 | dlg_stdcheckbox_handler, I(offsetof(Config,rtf_paste))); |
264 | |
265 | /* |
266 | * Windows often has no middle button, so we supply a selection |
267 | * mode in which the more critical Paste action is available on |
268 | * the right button instead. |
269 | */ |
270 | s = ctrl_getset(b, "Window/Selection", "mouse", |
271 | "Control use of mouse"); |
ebc0310d |
272 | ctrl_radiobuttons(s, "Action of mouse buttons:", 'm', 1, |
fe8abbf4 |
273 | HELPCTX(selection_buttons), |
274 | dlg_stdradiobutton_handler, |
275 | I(offsetof(Config, mouse_is_xterm)), |
ebc0310d |
276 | "Windows (Middle extends, Right brings up menu)", I(2), |
277 | "Compromise (Middle extends, Right pastes)", I(0), |
278 | "xterm (Right extends, Middle pastes)", I(1), NULL); |
fe8abbf4 |
279 | /* |
280 | * This really ought to go at the _top_ of its box, not the |
281 | * bottom, so we'll just do some shuffling now we've set it |
282 | * up... |
283 | */ |
284 | c = s->ctrls[s->ncontrols-1]; /* this should be the new control */ |
285 | memmove(s->ctrls+1, s->ctrls, (s->ncontrols-1)*sizeof(union control *)); |
286 | s->ctrls[0] = c; |
287 | |
288 | /* |
289 | * Logical palettes don't even make sense anywhere except Windows. |
290 | */ |
291 | s = ctrl_getset(b, "Window/Colours", "general", |
292 | "General options for colour usage"); |
293 | ctrl_checkbox(s, "Attempt to use logical palettes", 'l', |
294 | HELPCTX(colours_logpal), |
295 | dlg_stdcheckbox_handler, I(offsetof(Config,try_palette))); |
26d1da7b |
296 | ctrl_checkbox(s, "Use system colours", 's', |
297 | HELPCTX(colours_system), |
298 | dlg_stdcheckbox_handler, I(offsetof(Config,system_colour))); |
299 | |
fe8abbf4 |
300 | |
301 | /* |
302 | * Resize-by-changing-font is a Windows insanity. |
303 | */ |
304 | s = ctrl_getset(b, "Window", "size", "Set the size of the window"); |
305 | ctrl_radiobuttons(s, "When window is resized:", 'z', 1, |
306 | HELPCTX(window_resize), |
307 | dlg_stdradiobutton_handler, |
308 | I(offsetof(Config, resize_action)), |
309 | "Change the number of rows and columns", I(RESIZE_TERM), |
310 | "Change the size of the font", I(RESIZE_FONT), |
311 | "Change font size only when maximised", I(RESIZE_EITHER), |
312 | "Forbid resizing completely", I(RESIZE_DISABLED), NULL); |
313 | |
314 | /* |
315 | * Most of the Window/Behaviour stuff is there to mimic Windows |
316 | * conventions which PuTTY can optionally disregard. Hence, |
317 | * most of these options are Windows-specific. |
318 | */ |
319 | s = ctrl_getset(b, "Window/Behaviour", "main", NULL); |
320 | ctrl_checkbox(s, "Window closes on ALT-F4", '4', |
321 | HELPCTX(behaviour_altf4), |
322 | dlg_stdcheckbox_handler, I(offsetof(Config,alt_f4))); |
323 | ctrl_checkbox(s, "System menu appears on ALT-Space", 'y', |
324 | HELPCTX(behaviour_altspace), |
325 | dlg_stdcheckbox_handler, I(offsetof(Config,alt_space))); |
326 | ctrl_checkbox(s, "System menu appears on ALT alone", 'l', |
327 | HELPCTX(behaviour_altonly), |
328 | dlg_stdcheckbox_handler, I(offsetof(Config,alt_only))); |
329 | ctrl_checkbox(s, "Ensure window is always on top", 'e', |
330 | HELPCTX(behaviour_alwaysontop), |
331 | dlg_stdcheckbox_handler, I(offsetof(Config,alwaysontop))); |
332 | ctrl_checkbox(s, "Full screen on Alt-Enter", 'f', |
333 | HELPCTX(behaviour_altenter), |
334 | dlg_stdcheckbox_handler, |
335 | I(offsetof(Config,fullscreenonaltenter))); |
0edafb21 |
336 | |
337 | /* |
338 | * Windows supports a local-command proxy. This also means we |
339 | * must adjust the text on the `Telnet command' control. |
340 | */ |
341 | if (!midsession) { |
342 | int i; |
343 | s = ctrl_getset(b, "Connection/Proxy", "basics", NULL); |
344 | for (i = 0; i < s->ncontrols; i++) { |
345 | c = s->ctrls[i]; |
346 | if (c->generic.type == CTRL_RADIO && |
347 | c->generic.context.i == offsetof(Config, proxy_type)) { |
348 | assert(c->generic.handler == dlg_stdradiobutton_handler); |
349 | c->radio.nbuttons++; |
350 | c->radio.buttons = |
351 | sresize(c->radio.buttons, c->radio.nbuttons, char *); |
352 | c->radio.buttons[c->radio.nbuttons-1] = |
353 | dupstr("Local"); |
354 | c->radio.buttondata = |
355 | sresize(c->radio.buttondata, c->radio.nbuttons, intorptr); |
356 | c->radio.buttondata[c->radio.nbuttons-1] = I(PROXY_CMD); |
357 | break; |
358 | } |
359 | } |
360 | |
361 | for (i = 0; i < s->ncontrols; i++) { |
362 | c = s->ctrls[i]; |
363 | if (c->generic.type == CTRL_EDITBOX && |
364 | c->generic.context.i == |
365 | offsetof(Config, proxy_telnet_command)) { |
366 | assert(c->generic.handler == dlg_stdeditbox_handler); |
367 | sfree(c->generic.label); |
368 | c->generic.label = dupstr("Telnet command, or local" |
369 | " proxy command"); |
370 | break; |
371 | } |
372 | } |
373 | } |
7374c779 |
374 | |
375 | /* |
376 | * Serial back end is available on Windows. |
377 | */ |
8a7f1392 |
378 | if (!midsession || (protocol == PROT_SERIAL)) |
379 | ser_setup_config_box(b, midsession, 0x1F, 0x0F); |
fe8abbf4 |
380 | } |