1 /*
2 langselwin.c - Shows a language selection window if no language specified in the ini file.
3
4 Each available language is displayed from languages/langsel.xml. The user can click on
5 their preferred language and then press save which will save the value in the ini file.
6 Beside the save button a note can be displayed explaining a bit about languages in EL.
7 If the language "en" is chosen the client will continue to open the login/new
8 character/rules screen. Otherwise, the client will be restarted. All the text and
9 colours are configurable in the langsel.xml file.
10
11 Most user will only see this window once, existing users probably never :(
12
13 23/09/07 bluap/pjbroad
14 */
15
16
17 #include <string.h>
18 #include <libxml/parser.h>
19
20 #include "asc.h"
21 #include "elconfig.h"
22 #include "elwindows.h"
23 #include "errors.h"
24 #include "gamewin.h"
25 #include "gl_init.h"
26 #include "hud.h"
27 #include "interface.h"
28 #include "list.h"
29 #include "loginwin.h"
30 #include "main.h"
31 #include "misc.h"
32 #include "multiplayer.h"
33 #include "openingwin.h"
34 #include "rules.h"
35 #include "sound.h"
36
37 typedef struct { char *code; unsigned char *text; char *save; char *note; } LANGSEL_LIST_NODE;
38
39 int langsel_rootwin = -1;
40 int have_saved_langsel = 0;
41 static int langsel_win = -1;
42 static int langsel_scroll_id = -1;
43 static int langsel_first_lang_line = 0;
44 static int langsel_num_note_lines = 4;
45 static unsigned char *langsel_save_note_boxed = NULL;
46 static char *langsel_list_error = NULL;
47 static list_node_t *langsel_list = NULL;
48 static LANGSEL_LIST_NODE *langsel_default_node = NULL;
49 static LANGSEL_LIST_NODE *langsel_chosen_node = NULL;
50 static LANGSEL_LIST_NODE *langsel_selected_node = NULL;
51 static float langsel_winRGB[4][3] = {{0.0f,0.25f,1.0f},{0.2f,0.7f,1.2f},{0.2f,1.0f,1.2f},{1.0f, 1.0f, 1.0f}};
52
53
langsel_load_list(void)54 static int langsel_load_list(void)
55 {
56 xmlDocPtr doc;
57 xmlNodePtr cur;
58 char *error_prefix = "Reading langsel.xml: ";
59
60 langsel_winRGB[3][0] = gui_color[0];
61 langsel_winRGB[3][1] = gui_color[1];
62 langsel_winRGB[3][2] = gui_color[2];
63
64 if ((doc = xmlReadFile("languages/langsel.xml", NULL, 0)) == NULL)
65 {
66 langsel_list_error = "Can't open file.";
67 LOG_ERROR("%s%s\n", error_prefix, langsel_list_error );
68 return 0;
69 }
70
71 if ((cur = xmlDocGetRootElement (doc)) == NULL)
72 {
73 langsel_list_error = "Empty xml document.";
74 LOG_ERROR("%s%s\n", error_prefix, langsel_list_error );
75 xmlFreeDoc(doc);
76 return 0;
77 }
78
79 if (xmlStrcasecmp (cur->name, (const xmlChar *) "LANGUAGE_LIST"))
80 {
81 langsel_list_error = "Not language list.";
82 LOG_ERROR("%s%s\n", error_prefix, langsel_list_error );
83 xmlFreeDoc(doc);
84 return 0;
85 }
86
87 for (cur = cur->xmlChildrenNode; cur; cur = cur->next)
88 {
89 if (!xmlStrcasecmp(cur->name, (const xmlChar *)"LANG"))
90 {
91 LANGSEL_LIST_NODE *new_lang_node = NULL;
92 char *note = (char*)(cur->children ? cur->children->content : NULL);
93 char *code = (char*)xmlGetProp(cur, (xmlChar *)"CODE");
94 char *text = (char*)xmlGetProp(cur, (xmlChar *)"TEXT");
95 char *save = (char*)xmlGetProp(cur, (xmlChar *)"SAVE");
96 char *def = (char*)xmlGetProp(cur, (xmlChar *)"DEFAULT");
97
98 if ((code == NULL) || (text == NULL))
99 {
100 LOG_WARNING("%sInvalid language node\n", error_prefix );
101 continue;
102 }
103
104 new_lang_node = (LANGSEL_LIST_NODE *)malloc(sizeof(LANGSEL_LIST_NODE));
105 new_lang_node->note = new_lang_node->code = new_lang_node->save = NULL;
106 new_lang_node->text = NULL;
107
108 if (note)
109 MY_XMLSTRCPY(&new_lang_node->note, note);
110 if (code)
111 MY_XMLSTRCPY(&new_lang_node->code, code);
112 if (text)
113 MY_XMLSTRCPY((char**)&new_lang_node->text, text);
114 if (save)
115 MY_XMLSTRCPY(&new_lang_node->save, save);
116 if (def)
117 langsel_default_node = new_lang_node;
118
119 xmlFree(code);
120 xmlFree(text);
121 xmlFree(save);
122 xmlFree(def);
123
124 list_push(&langsel_list, new_lang_node);
125 }
126 else if (!xmlStrcasecmp(cur->name, (const xmlChar *)"SETTINGS"))
127 {
128 char *propstr[4] = {"TEXT", "HIGHLIGHT", "CHOSEN", "BUTTONS" };
129 char *noteslines = (char*)xmlGetProp(cur, (xmlChar *)"NOTELINES");
130 int i = atoi(noteslines);
131 if (i >= 0)
132 langsel_num_note_lines = i;
133 for (i=0; i<4; i++)
134 {
135 char *text = (char*)xmlGetProp(cur, (xmlChar *)propstr[i]);
136 float r = 0, g = 0, b = 0;
137 if (sscanf(text, "%f %f %f", &r, &g, &b) == 3)
138 {
139 langsel_winRGB[i][0] = r;
140 langsel_winRGB[i][1] = g;
141 langsel_winRGB[i][2] = b;
142 }
143 else
144 LOG_WARNING("%sColour error\n", error_prefix );
145 xmlFree(text);
146 }
147 }
148 }
149 xmlFreeDoc(doc);
150
151 if (!langsel_default_node || (langsel_default_node->save == NULL))
152 {
153 langsel_list_error = "Invalid default language.";
154 LOG_ERROR("%s%s\n", error_prefix, langsel_list_error );
155 if (langsel_default_node)
156 langsel_default_node = NULL;
157 return 0;
158 }
159
160 if (langsel_list == NULL)
161 {
162 langsel_list_error = "No languages found.";
163 LOG_ERROR("%s%s\n", error_prefix, langsel_list_error );
164 return 0;
165 }
166
167 return 1;
168 }
169
170
langsel_free_list(void)171 static void langsel_free_list(void)
172 {
173 while (langsel_list != NULL)
174 {
175 LANGSEL_LIST_NODE *new_lang_node = (LANGSEL_LIST_NODE *)list_pop(&langsel_list);
176 if (new_lang_node->note)
177 free(new_lang_node->note);
178 if (new_lang_node->code)
179 free(new_lang_node->code);
180 if (new_lang_node->text)
181 free(new_lang_node->text);
182 if (new_lang_node->save)
183 free(new_lang_node->save);
184 free(new_lang_node);
185 }
186 }
187
188
langsel_destroy_wins(void)189 static void langsel_destroy_wins(void)
190 {
191 if (langsel_save_note_boxed)
192 free(langsel_save_note_boxed);
193
194 destroy_window(langsel_win);
195 destroy_window(langsel_rootwin);
196 langsel_win = langsel_rootwin = -1;
197 }
198
199
langsel_save_handler(widget_list * widget,int mx,int my,Uint32 flags)200 static int langsel_save_handler(widget_list *widget, int mx, int my, Uint32 flags)
201 {
202 char *selected_lang = lang;
203
204 /* don't use scroll wheel - leave for scroll bar */
205 if ((flags & ELW_MOUSE_BUTTON) == 0)
206 return 0;
207
208 langsel_destroy_wins();
209
210 if (langsel_chosen_node)
211 selected_lang = langsel_chosen_node->code;
212
213 /* if the chosen language the that used during initialisation, no client restart is required */
214 if (strcmp(selected_lang, lang) == 0)
215 {
216 /* go to the console->login screen */
217 if (has_accepted)
218 {
219 show_window (opening_root_win);
220 show_hud_windows();
221 if (disconnected)
222 connect_to_server();
223 }
224 /* unless we need to read the rules first */
225 else
226 {
227 create_rules_root_window (window_width, window_height, opening_root_win, 15);
228 show_window (rules_root_win);
229 }
230 }
231 else
232 {
233 /* a different language has been chosen so restart the client */
234 restart_required = 1;
235 exit_now = 1;
236 }
237
238 /* set the chosen language, it will be saved on exit, then complete the clean up */
239 change_language(selected_lang);
240 langsel_free_list();
241 have_saved_langsel = 1;
242
243 return 1;
244 }
245
246
langsel_quit_handler(widget_list * widget,int mx,int my,Uint32 flags)247 static int langsel_quit_handler(widget_list *widget, int mx, int my, Uint32 flags)
248 {
249 /* don't use scroll wheel - leave for scroll bar */
250 if ((flags & ELW_MOUSE_BUTTON) == 0)
251 return 0;
252 langsel_destroy_wins();
253 langsel_free_list();
254 exit_now = 1;
255 return 1;
256 }
257
258
langsel_scroll_click_handler(widget_list * widget,int mx,int my,Uint32 flags)259 static int langsel_scroll_click_handler(widget_list *widget, int mx, int my, Uint32 flags)
260 {
261 langsel_first_lang_line = vscrollbar_get_pos(widget->window_id, widget->id);
262 return 1;
263 }
264
265
langsel_scroll_drag_handler(widget_list * widget,int mx,int my,Uint32 flags,int dx,int dy)266 static int langsel_scroll_drag_handler(widget_list *widget, int mx, int my, Uint32 flags, int dx, int dy)
267 {
268 return langsel_scroll_click_handler(widget, mx, my, flags);
269 }
270
271
click_langsel_handler(window_info * win,int mx,int my,Uint32 flags)272 static int click_langsel_handler(window_info *win, int mx, int my, Uint32 flags)
273 {
274 if ((langsel_scroll_id > 0) && flags & ELW_WHEEL_UP)
275 vscrollbar_scroll_up(langsel_win, langsel_scroll_id);
276 else if ((langsel_scroll_id > 0) && flags & ELW_WHEEL_DOWN)
277 vscrollbar_scroll_down(langsel_win, langsel_scroll_id);
278 else if ((flags & ELW_MOUSE_BUTTON) && langsel_selected_node)
279 {
280 langsel_chosen_node = langsel_selected_node;
281 do_click_sound();
282 }
283 if (langsel_scroll_id > 0)
284 langsel_first_lang_line = vscrollbar_get_pos(langsel_win, langsel_scroll_id);
285 return 1;
286 }
287
288
langsel_keypress_handler(window_info * win,int mx,int my,SDL_Keycode key_code,Uint32 key_unicode,Uint16 key_mod)289 static int langsel_keypress_handler(window_info *win, int mx, int my, SDL_Keycode key_code, Uint32 key_unicode, Uint16 key_mod)
290 {
291 if (check_quit_or_fullscreen(key_code, key_mod))
292 {
293 return 1;
294 }
295 else if (KEY_DEF_CMP(K_OPAQUEWIN, key_code, key_mod))
296 {
297 win->opaque ^= 1;
298 }
299 else
300 return 0;
301 return 1;
302 }
303
304
305 /* display the loading/login image as a background */
langsel_display_root_handler(window_info * win)306 static int langsel_display_root_handler(window_info *win)
307 {
308 if (login_text > 0)
309 draw_console_pic(login_text);
310 return 1;
311 }
312
313
314 /* displayed if the config file is missing or invalid */
langsel_display_error_handler(window_info * win)315 static int langsel_display_error_handler(window_info *win)
316 {
317 static int first_time = 1;
318 static int save_button = -1;
319 static int quit_button = -1;
320 static int sep = 0;
321 static const unsigned char *message = (const unsigned char*)
322 "The language selection file langsel.xml could\n"
323 "not be read. Either click Save to accept the\n"
324 "default language (English), or click Quit if\n"
325 "you wish to manually correct this error.\n\n"
326 "The error message was:\n\n";
327
328 const unsigned char* error
329 = (const unsigned char *)(langsel_list_error ? langsel_list_error : "Unknown error");
330
331 if (first_time)
332 {
333 int width, height, button_width, button_height;
334
335 sep = (int)(0.5 + win->current_scale * 10);
336
337 save_button = button_add_extended(langsel_win, 100, NULL, 0, 0, 0, 0, 0, win->current_scale, "Save");
338 widget_set_color(langsel_win, save_button, langsel_winRGB[3][0], langsel_winRGB[3][1],
339 langsel_winRGB[3][2]);
340 widget_set_OnClick(langsel_win, save_button, langsel_save_handler);
341 button_width = widget_get_width(langsel_win, save_button);
342 button_height = widget_get_height(langsel_win, save_button);
343
344 quit_button = button_add_extended(langsel_win, 101, NULL, 0, 0, 0, 0, 0, win->current_scale, "Quit");
345 widget_set_color(langsel_win, quit_button, langsel_winRGB[3][0], langsel_winRGB[3][1],
346 langsel_winRGB[3][2]);
347 widget_set_OnClick(langsel_win, quit_button, langsel_quit_handler);
348
349 get_buf_dimensions(message, strlen((const char*)message), win->font_category,
350 win->current_scale_small, &width, &height);
351 width += 2 * sep;
352 height += button_height + 3 * sep;
353
354 resize_window(langsel_win, width, height);
355 widget_move(langsel_win, save_button, sep, win->len_y - button_height - sep);
356 widget_move(langsel_win, quit_button, sep + button_width + sep,
357 win->len_y - button_height - sep);
358
359 first_time = 0;
360 return 1;
361 }
362
363 draw_string_small_zoomed(sep, sep, (const unsigned char *)message, 6, win->current_scale);
364 draw_string_small_zoomed(sep, sep + win->small_font_len_y * 6, error, 1, win->current_scale);
365
366 return 1;
367 }
368
369
370 /* the main business is done here */
display_langsel_handler(window_info * win)371 static int display_langsel_handler(window_info *win)
372 {
373 static float font_zoom = 1.5;
374 static float text_zoom = 1.0;
375 static float line_step = 0;
376 static int num_lang_lines = 0;
377 static float max_str_width = 0;
378 static list_node_t *first_node = NULL;
379 static LANGSEL_LIST_NODE *last_langsel_chosen_node = NULL;
380 static int save_button = -1;
381 static int first_time = 1;
382 static int second_time = 0;
383 static int add_scroll_bar = 0;
384 static int max_lang_lines = 0;
385 static int winwidth = 0;
386 static int winheight = 0;
387 static char *langwin_save_note = NULL;
388 static float note_height = 0;
389 static int scroll_width = 0;
390
391 const float winsep = 15;
392 list_node_t *local_head = NULL;
393 int current_y = 0;
394 int lang_line_num = 0;
395
396 /* first time through, create additional widgets and resize everything */
397 if (first_time)
398 {
399 widget_list *save_widget = NULL;
400 unsigned char *longest_string = NULL;
401 int non_line_height = 0;
402 float sizefrac = 0.80;
403
404 font_zoom *= win->current_scale;
405
406 /* count the number of language lines and find the widest line and the first line
407 - font_zoom unknow as yet */
408 for (local_head = langsel_list; local_head; local_head = local_head->next)
409 {
410 LANGSEL_LIST_NODE *new_lang_node = (LANGSEL_LIST_NODE *)local_head->data;
411 float str_width = get_string_width_zoom(new_lang_node->text, win->font_category,
412 font_zoom);
413 if (str_width > max_str_width)
414 {
415 max_str_width = str_width;
416 longest_string = new_lang_node->text;
417 }
418 num_lang_lines++;
419 first_node = local_head;
420 }
421
422 /* if required, change the zoom based on a reasonable limit of using all the main window */
423 if (max_str_width > (sizefrac * window_width))
424 {
425 font_zoom = sizefrac * window_width / max_str_width;
426 max_str_width = get_string_width_zoom(longest_string, win->font_category, font_zoom);
427 }
428
429 text_zoom = font_zoom / 1.5;
430 note_height = get_line_height(win->font_category, text_zoom) * langsel_num_note_lines;
431 scroll_width = ELW_BOX_SIZE * text_zoom;
432
433 /* number of pixels used per language line drawn */
434 line_step = 3 + get_line_height(win->font_category, font_zoom);
435
436 /* set the window width now things about the width are known */
437 winwidth = max_str_width + 2 * winsep;
438
439 /* to set the height, we need to know button sizes so create a temporary button */
440 save_button = button_add_extended(langsel_win, 100, NULL, 0, 0, 0, 0, WIDGET_INVISIBLE, text_zoom, "Temp");
441 save_widget = widget_find(langsel_win, save_button);
442
443 /* calculate the window height assuming we can display all languages without a scroll bar */
444 max_lang_lines = num_lang_lines;
445 non_line_height = 3 * winsep + max2i(save_widget->len_y, note_height);
446 winheight = non_line_height + line_step * max_lang_lines;
447
448 /* if the height is too big, reduce it to something reasonable and add a scroll bar */
449 if (winheight > (sizefrac * window_height))
450 {
451 add_scroll_bar = 1;
452 max_lang_lines = ((sizefrac * window_height) - non_line_height) / line_step;
453 winheight = non_line_height + line_step * max_lang_lines;
454 winwidth += scroll_width;
455 }
456
457 /* move the window to the centre of the screen and resize it as calculate */
458 move_window(langsel_win, langsel_rootwin, 0, (window_width-winwidth)/2, (window_height-winheight)/2);
459 resize_window(langsel_win, winwidth, winheight);
460
461 /* clean up then exit, leave the rest to next time so the buttons don't flash on the screen */
462 widget_destroy(langsel_win, save_button);
463 save_button = -1;
464 first_time = 0;
465 second_time = 1;
466 return 1;
467 }
468
469 /* if no button etc, or language choice has changed, redisplay the button and note */
470 if (second_time || (langsel_chosen_node && (last_langsel_chosen_node != langsel_chosen_node)))
471 {
472 widget_list *save_widget = NULL;
473 const char *save = "Save";
474
475 /* get the save button text, using the default if required */
476 if (langsel_chosen_node->save)
477 save = langsel_chosen_node->save;
478 else if (langsel_default_node->save)
479 save = langsel_default_node->save;
480
481 /* create the save button, resized and moved to keep things tidy */
482 if (save_button > 0)
483 widget_destroy(langsel_win, save_button);
484 save_button = button_add_extended(langsel_win, 100, NULL, 0, 0, 0, 0, 0, text_zoom, save);
485 widget_set_color(langsel_win, save_button, langsel_winRGB[3][0], langsel_winRGB[3][1],
486 langsel_winRGB[3][2]);
487 save_widget = widget_find(langsel_win, save_button);
488 widget_move(langsel_win, save_button, winwidth - (winsep + save_widget->len_x), winheight - winsep - save_widget->len_y);
489 widget_set_OnClick(langsel_win, save_button, langsel_save_handler);
490
491 /* get the note text, using the default if required */
492 if (langsel_chosen_node->note)
493 langwin_save_note = langsel_chosen_node->note;
494 else if (langsel_default_node->note)
495 langwin_save_note = langsel_default_node->note;
496 else
497 langwin_save_note = NULL;
498
499 /* wrap the text so that it fits into the window space available */
500 if (langwin_save_note)
501 {
502 langsel_save_note_boxed = realloc(langsel_save_note_boxed,
503 strlen(langwin_save_note)*2);
504 put_small_text_in_box_zoomed((const Uint8 *)langwin_save_note,
505 strlen(langwin_save_note), winwidth - (2 * winsep + save_widget->len_x),
506 langsel_save_note_boxed, text_zoom);
507 }
508
509 if (add_scroll_bar)
510 {
511 langsel_scroll_id = vscrollbar_add_extended(langsel_win, 102, NULL, winwidth - scroll_width, winsep,
512 scroll_width, line_step * max_lang_lines, 0, 1.0,
513 0, 1, num_lang_lines - max_lang_lines);
514 widget_set_color(langsel_win, langsel_scroll_id, langsel_winRGB[3][0], langsel_winRGB[3][1],
515 langsel_winRGB[3][2]);
516 widget_set_OnDrag(langsel_win, langsel_scroll_id, langsel_scroll_drag_handler);
517 widget_set_OnClick(langsel_win, langsel_scroll_id, langsel_scroll_click_handler);
518 add_scroll_bar = 0;
519 }
520
521 last_langsel_chosen_node = langsel_chosen_node;
522 second_time = 0;
523 }
524
525 /* if we have note text, display it */
526 if (langwin_save_note)
527 {
528 draw_string_small_zoomed(winsep, winheight - winsep - note_height,
529 langsel_save_note_boxed, langsel_num_note_lines, text_zoom);
530 }
531
532 /* draw a line under the language list */
533 glColor3f(langsel_winRGB[3][0], langsel_winRGB[3][1], langsel_winRGB[3][2]);
534 glDisable(GL_TEXTURE_2D);
535 glBegin(GL_LINES);
536 glVertex2i(winsep, winsep + line_step * max_lang_lines);
537 glVertex2i(winsep + max_str_width, winsep + line_step * max_lang_lines);
538 glEnd();
539 glEnable(GL_TEXTURE_2D);
540
541 /* display the language list */
542 current_y = winsep;
543 langsel_selected_node = NULL;
544 lang_line_num = 0;
545 for (local_head = first_node; local_head; local_head = local_head->prev, lang_line_num++)
546 {
547 LANGSEL_LIST_NODE *new_lang_node = (LANGSEL_LIST_NODE *)local_head->data;
548
549 /* if off the top if the window, don't display */
550 if (lang_line_num < langsel_first_lang_line)
551 continue;
552
553 /* if off the bottom of the window, don't display this or any more lines */
554 if ((lang_line_num - langsel_first_lang_line) >= max_lang_lines)
555 break;
556
557 /* colour the list lines as required*/
558 if (new_lang_node == langsel_chosen_node)
559 glColor3f(langsel_winRGB[2][0],langsel_winRGB[2][1],langsel_winRGB[2][2]);
560 /* if the mouse is over the current line.... */
561 else if ((mouse_y > win->cur_y + current_y) &&
562 (mouse_y < win->cur_y + current_y + line_step) &&
563 (mouse_x >= win->cur_x + winsep) &&
564 (mouse_x - winsep <= win->cur_x + max_str_width))
565 {
566 glColor3f(langsel_winRGB[1][0],langsel_winRGB[1][1],langsel_winRGB[1][2]);
567 /* save the highlighted line in case it is clicked - and so chosen */
568 langsel_selected_node = new_lang_node;
569 }
570 else
571 glColor3f(langsel_winRGB[0][0],langsel_winRGB[0][1],langsel_winRGB[0][2]);
572
573 /* draw the line of text and step down for the next */
574 draw_string_zoomed(winsep, current_y, new_lang_node->text, 1, font_zoom);
575 current_y += line_step;
576 }
577
578 return 1;
579
580 } /* end display_langsel_handler() */
581
langsel_rootwin_resize_handler(window_info * win,int width,int height)582 static int langsel_rootwin_resize_handler(window_info *win, int width, int height)
583 {
584 if (langsel_win >=0 && langsel_win < windows_list.num_windows)
585 {
586 window_info *lwin = &windows_list.window[langsel_win];
587 move_window(lwin->window_id, lwin->pos_id, lwin->pos_loc, (width-lwin->len_x)/2, (height-lwin->len_y)/2);
588 }
589 return 1;
590 }
591
592 /* load the language list and create the windows */
display_langsel_win(void)593 int display_langsel_win(void)
594 {
595 int loaded_lang_list = langsel_load_list();
596 langsel_chosen_node = langsel_default_node;
597
598 /* create and show the root window */
599 langsel_rootwin = create_window("", -1, -1, 0, 0, window_width, window_height, ELW_TITLE_NONE|ELW_SHOW_LAST);
600 set_window_handler(langsel_rootwin, ELW_HANDLER_DISPLAY, &langsel_display_root_handler );
601 set_window_handler(langsel_rootwin, ELW_HANDLER_RESIZE, &langsel_rootwin_resize_handler);
602 show_window(langsel_rootwin);
603
604 /* create and show the language selection window */
605 langsel_win = create_window("", langsel_rootwin, -1, (window_width-400)/2, (window_height-400/1.62)/2,
606 400, 400/1.62, (ELW_USE_UISCALE|ELW_WIN_DEFAULT)^(ELW_CLOSE_BOX|ELW_TITLE_BAR));
607 set_window_handler(langsel_win, ELW_HANDLER_CLICK, &click_langsel_handler );
608 set_window_handler(langsel_win, ELW_HANDLER_KEYPRESS, (int (*)())&langsel_keypress_handler);
609
610 /* use the error window if the list could not be read */
611 if (loaded_lang_list)
612 set_window_handler(langsel_win, ELW_HANDLER_DISPLAY, &display_langsel_handler );
613 else
614 set_window_handler(langsel_win, ELW_HANDLER_DISPLAY, &langsel_display_error_handler );
615
616 show_window(langsel_win);
617
618 return 1;
619 }
620