1 #ifdef OSX
2 #include <sys/malloc.h>
3 #include <CoreFoundation/CoreFoundation.h>
4 #elif BSD
5 #include <stdlib.h>
6 #else
7 #include <malloc.h>
8 #endif /* OSX */
9 #if !defined(OSX) && !defined(WINDOWS)
10 #include <signal.h>
11 #endif
12 #include <sys/types.h>
13 #include <string.h>
14 #ifndef _MSC_VER
15 #include <unistd.h>
16 #endif //MSVC
17 #include <ctype.h>
18 #include <SDL.h>
19 #include <SDL_thread.h>
20 #include "asc.h"
21 #include "client_serv.h"
22 #include "consolewin.h"
23 #include "context_menu.h"
24 #ifdef WINDOWS
25 #include "elloggingwrapper.h"
26 #endif
27 #include "elwindows.h"
28 #include "font.h"
29 #include "gamewin.h"
30 #include "hud.h"
31 #include "interface.h"
32 #include "list.h"
33 #include "load_gl_extensions.h"
34 #include "misc.h"
35 #include "tabs.h"
36 #include "text.h"
37 #include "translate.h"
38 #include "url.h"
39 #ifdef OPENGL_TRACE
40 #include "gl_init.h"
41 #endif
42 #include "sound.h"
43
44 char browser_name[120];
45 static Uint32 url_win_sep = 0;
46 static float url_win_text_zoom = 1.0;
47 static const int max_url_count = 100;
48 static int clear_all_button = 101;
49 static int url_scroll_id = 0;
50 static int url_win_top_line = 0;
51 static Uint32 url_win_max_string_width = 0;
52 static int url_win_help_x = 0;
53 static int url_win_text_len_y = 0;
54 static int url_win_text_start_y = 0;
55 static int url_win_full_url_y_start = 0;
56 static int url_win_full_url_y_len = 0;
57 static int url_win_line_step = 0;
58 static Uint32 url_win_clicktime = 0;
59 static enum { URLW_EMPTY=1, URLW_CLEAR, URLW_OVER } url_win_status = URLW_EMPTY;
60 static list_node_t *url_win_clicked_url = NULL;
61 static list_node_t *url_win_hover_url = NULL;
62
63 static int have_url_count = 0;
64 static int saved_url_count = 0;
65
66 static list_node_t *newest_url = NULL;
67 static list_node_t *active_url = NULL;
68 static list_node_t *cm_url = NULL;
69
70
71 /* define the structure stored for each URL */
72 typedef struct
73 {
74 int seen_count; /* incremented each time a link is seen in chat */
75 int visited; /* true when link has been opened in the browser */
76 char *text; /* the actual url text */
77 } URLDATA;
78
79
80 /* store the current url count, used in num_new_url() */
save_url_count(void)81 void save_url_count(void)
82 {
83 saved_url_count = have_url_count;
84 }
85
86
87 /* return the number of url since last save_url_count() call */
num_new_url(void)88 int num_new_url(void)
89 {
90 return have_url_count - saved_url_count;
91 }
92
93
94 /* open last seen URL */
open_last_seen_url(void)95 void open_last_seen_url(void)
96 {
97 if (!have_url_count)
98 return;
99 open_web_link(((URLDATA *)active_url->data)->text);
100 ((URLDATA *)active_url->data)->visited = 1;
101 }
102
103
104 /* free all url list memory */
destroy_url_list(void)105 void destroy_url_list(void)
106 {
107 if (have_url_count)
108 {
109 /* free all the text */
110 list_node_t *local_head = newest_url;
111 while (local_head->next != NULL)
112 {
113 if (local_head->data != NULL)
114 free(((URLDATA *)local_head->data)->text);
115 local_head = local_head->next;
116 }
117
118 /* free the list */
119 list_destroy(newest_url);
120 saved_url_count = have_url_count = 0;
121 active_url = newest_url = NULL;
122 }
123 }
124
125
126 /* #url command - List, clear list or open a specific URL */
url_command(const char * text,int len)127 int url_command(const char *text, int len)
128 {
129 /* no URLs so far so display a message then exit */
130 if (!have_url_count)
131 {
132 LOG_TO_CONSOLE(c_red2, urlcmd_none_str);
133 return 1;
134 }
135
136 /* get any parameter text */
137 while(*text && !isspace(*text))
138 text++;
139 while(*text && isspace(*text))
140 text++;
141
142 /* no parameter specified - list the URL(s) we have, oldest first */
143 if (!strlen(text))
144 {
145 char *out_str = NULL;
146 size_t out_len = 0;
147 int irl_num = 0;
148 int line_colour = c_grey1;
149 list_node_t *local_head = newest_url;
150
151 LOG_TO_CONSOLE(c_green2, urlcmd_list_str);
152
153 /* go to the oldest in the list */
154 while (local_head->next != NULL)
155 local_head = local_head->next;
156
157 /* display the list ending with the newest, alternating colours */
158 while (local_head != NULL)
159 {
160 size_t new_len = sizeof(char) * (strlen(((URLDATA *)local_head->data)->text) + 60);
161 if (new_len > out_len)
162 {
163 if (out_str != NULL)
164 free(out_str);
165 out_str = (char *)malloc(new_len);
166 out_len = new_len;
167 }
168 safe_snprintf(out_str, new_len, "%c %d) %s (seen %d time%s) (%s)", ((local_head==active_url) ?'>':' '),
169 ++irl_num, ((URLDATA *)local_head->data)->text, ((URLDATA *)local_head->data)->seen_count,
170 ((URLDATA *)local_head->data)->seen_count == 1?"":"s", ((((URLDATA *)local_head->data)->visited) ?"visited":"unvisited"));
171 LOG_TO_CONSOLE(line_colour, out_str);
172 local_head = local_head->prev;
173 line_colour = (line_colour==c_grey1) ?c_grey2 :c_grey1;
174 }
175
176 if (out_str != NULL)
177 free(out_str);
178 }
179
180 /* if parameter is "clear" delete all entries */
181 else if (strcmp(text, urlcmd_clear_str) == 0)
182 {
183 destroy_url_list();
184 }
185
186 /* else assume parameter is an index, if its a valid index, open the URL */
187 else
188 {
189 int open_index = atoi(text) - 1;
190 int valid_node = 0;
191 if (open_index >= 0)
192 {
193 list_node_t *local_head = newest_url;
194 int url_num = 0;
195 /* go to the oldest int the list */
196 while (local_head->next != NULL)
197 local_head = local_head->next;
198 /* go to the specified entry */
199 while ((local_head->prev != NULL) && (url_num < open_index))
200 {
201 local_head = local_head->prev;
202 url_num++;
203 }
204 /* if we end up at a valid node, go for it */
205 if ((local_head != NULL) && (url_num == open_index) && strlen(((URLDATA *)local_head->data)->text))
206 {
207 open_web_link(((URLDATA *)local_head->data)->text);
208 ((URLDATA *)local_head->data)->visited = 1;
209 valid_node = 1;
210 }
211 }
212 if (!valid_node)
213 LOG_TO_CONSOLE(c_red2, urlcmd_invalid_str);
214 }
215
216 return 1;
217 }
218
219
220 /* find and store all urls in the provided string */
find_all_url(const char * source_string,const int len)221 void find_all_url(const char *source_string, const int len)
222 {
223 char search_for[][10] = {"http://", "https://", "ftp://", "www."};
224 int next_start = 0;
225
226 while (next_start < len)
227 {
228 int first_found = len-next_start; /* set to max */
229 int i;
230
231 /* find the first of the url start strings */
232 for(i = 0; i < sizeof(search_for)/10; i++)
233 {
234 int found_at = get_string_occurance(search_for[i], source_string+next_start, len-next_start, 1);
235 if ((found_at >= 0) && (found_at < first_found))
236 first_found = found_at;
237 }
238
239 /* if url found, store (if new) it then continue the search straight after the end */
240 if (first_found < len-next_start)
241 {
242 char *new_url = NULL;
243 char *add_start = "";
244 size_t url_len;
245 int url_start = next_start + first_found;
246 int have_already = 0;
247
248 /* find the url end */
249 for (next_start = url_start; next_start < len; next_start++)
250 {
251 char cur_char = source_string[next_start];
252 if(!cur_char || cur_char == ' ' || cur_char == '\n' || cur_char == '<'
253 || cur_char == '>' || cur_char == '|' || cur_char == '"' || cur_char == '\'' || cur_char == '`'
254 || cur_char == ']' || cur_char == ';' || cur_char == '\\' || (cur_char&0x80) != 0)
255 break;
256 }
257
258 /* prefix www. with http:// */
259 if (strncmp(&source_string[url_start], "www.", 4) == 0)
260 add_start = "http://";
261
262 /* extract the string */
263 url_len = strlen(add_start) + (next_start-url_start) + 1;
264 new_url = (char *)malloc(sizeof(char)*url_len);
265 /* could use safe_xxx() functions but I think its simpler not to here */
266 strcpy(new_url, add_start);
267 strncat(new_url, &source_string[url_start], next_start-url_start );
268 new_url[url_len-1] = 0;
269
270 /* check the new URL is not already in the list */
271 if (have_url_count)
272 {
273 list_node_t *local_head = newest_url;
274 while (local_head != NULL)
275 {
276 /* if its already stored, just make existing version active */
277 if (strcmp(((URLDATA *)local_head->data)->text, new_url) == 0)
278 {
279 active_url = local_head;
280 ((URLDATA *)local_head->data)->seen_count++;
281 have_already = 1;
282 free(new_url);
283 break;
284 }
285 local_head = local_head->next;
286 }
287 }
288
289 /* if its a new url, create a new node in the url list */
290 if (!have_already)
291 {
292 URLDATA *new_node = (URLDATA *)malloc(sizeof(URLDATA));
293
294 /* if there's a max number of url and we've reached it, remove the oldest */
295 /* we don't need to worry if its the active_url as thats going to change */
296 if (max_url_count && (max_url_count==have_url_count))
297 {
298 list_node_t *local_head = newest_url;
299 /* go to the oldest in the list */
300 while (local_head->next != NULL)
301 local_head = local_head->next;
302 free(((URLDATA *)local_head->data)->text);
303 free(local_head->data);
304 if (local_head==newest_url)
305 {
306 /* the special case is when max_url_count=1... */
307 free(local_head);
308 newest_url = NULL;
309 }
310 else
311 {
312 local_head = local_head->prev;
313 free(local_head->next);
314 local_head->next = NULL;
315 }
316 have_url_count--;
317 }
318
319 new_node->seen_count = 1;
320 new_node->visited = 0;
321 new_node->text = new_url;
322 list_push(&newest_url, new_node);
323 active_url = newest_url;
324 have_url_count++;
325 }
326
327 } /* end if url found */
328
329 /* no more urls found so stop looking */
330 else
331 break;
332 }
333
334 } /* end find_all_url() */
335
336
337 #ifdef WINDOWS
only_call_from_open_web_link__go_to_url(void * url)338 static int only_call_from_open_web_link__go_to_url(void * url)
339 {
340 char browser_command[400];
341
342 init_thread_log("web_link");
343
344 // build the command line and execute it
345 safe_snprintf (browser_command, sizeof (browser_command), "%s \"%s\"", browser_name, url),
346 system(browser_command); // Do not use this command on UNIX.
347
348 // free the memory allocated in open_web_link()
349 free(url);
350
351 return 0;
352 }
353 #endif
354
open_web_link(const char * url)355 void open_web_link(const char * url)
356 {
357 #ifdef OSX
358 CFURLRef newurl = CFURLCreateWithString(kCFAllocatorDefault,CFStringCreateWithCStringNoCopy(NULL,url,kCFStringEncodingMacRoman, NULL),NULL);
359 LSOpenCFURLRef(newurl,NULL);
360 CFRelease(newurl);
361 #else
362 // browser name can override the windows default, and if not defined in Linux, don't error
363 if(*browser_name){
364 #ifndef WINDOWS
365 static int have_set_signal = 0;
366 #ifdef SOUND_FORK_BUGFIX
367 int sound_on_copy = sound_on;
368 int music_on_copy = music_on;
369 #endif
370
371 /* we're not interested in the exit status of the child so
372 set SA_NOCLDWAIT to stop it becoming a zombie if we don't wait() */
373 if (!have_set_signal)
374 {
375 struct sigaction act;
376 memset(&act, 0, sizeof(act));
377 act.sa_handler = SIG_DFL;
378 act.sa_flags = SA_NOCLDWAIT;
379 sigaction(SIGCHLD, &act, NULL);
380 have_set_signal = 1;
381 }
382
383 #ifdef SOUND_FORK_BUGFIX
384 if (sound_on_copy)
385 toggle_sounds(&sound_on);
386 if (music_on_copy)
387 toggle_music(&music_on);
388 #endif
389
390 if (fork() == 0){
391 execlp(browser_name, browser_name, url, NULL);
392 // in case the exec errors
393 _exit(1);
394 }
395
396 #ifdef SOUND_FORK_BUGFIX
397 if (sound_on_copy)
398 toggle_sounds(&sound_on);
399 if (music_on_copy)
400 toggle_music(&music_on);
401 #endif
402
403 #else
404 // make a copy of the url string as it may be freed by the caller
405 // will be freed as the only_call_from_open_web_link__go_to_url() exits
406 char *cp_url = malloc(strlen(url)+1);
407 safe_strncpy(cp_url, url, strlen(url)+1);
408
409 // windows needs to spawn it in its own thread
410 SDL_CreateThread(only_call_from_open_web_link__go_to_url, "BrowserThread", cp_url);
411 } else {
412 ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNOACTIVATE); //this returns an int we could check for errors, but that's mainly when you use shellexecute for local files
413 #endif //_WIN32
414 }
415 #endif // OSX
416 }
417
418
419 /* Access the caught url list and display in a scrollable window. */
display_url_handler(window_info * win)420 static int display_url_handler(window_info *win)
421 {
422 #ifdef OPENGL_TRACE
423 CHECK_GL_ERRORS();
424 #endif //OPENGL_TRACE
425
426 url_win_hover_url = NULL;
427
428 glEnable(GL_TEXTURE_2D);
429
430 /* check for external state change */
431 if (!have_url_count && !url_win_status)
432 url_win_status = URLW_EMPTY;
433 /* if we have a status message, display it */
434 if (url_win_status)
435 {
436 char *message[] = { urlcmd_none_str, urlwin_clear_str, urlwin_open_str };
437 int y_start = (url_win_text_start_y - 0.75 * win->default_font_len_y) / 2;
438 glColor3f(1.0f,1.0f,1.0f);
439 draw_string_zoomed(url_win_help_x, y_start, (unsigned char *)message[url_win_status-1], 1, 0.75 * win->current_scale);
440 url_win_status = (have_url_count) ?0 :URLW_EMPTY;
441 }
442
443 /* display a page of url */
444 if (have_url_count)
445 {
446 list_node_t *local_head = newest_url;
447 int currenty = url_win_text_start_y;
448 int start_url = 0;
449 int num_url_displayed = 0;
450
451 /* don't scroll if everything will fit in the window, also catch if the list has been cleared via #url */
452 if (((url_win_line_step * have_url_count) <= url_win_text_len_y) || (url_win_top_line > have_url_count))
453 url_win_top_line = 0;
454
455 /* move to the first url to be displayed - set from the scroll bar */
456 while (start_url < url_win_top_line && local_head->next != NULL)
457 {
458 local_head = local_head->next;
459 start_url++;
460 }
461
462 /* loop over the remaining URLs while there is room in the window */
463 while (local_head != NULL)
464 {
465 char *thetext = ((URLDATA *)local_head->data)->text;
466 int dsp_string_len = 0;
467 int highlight_url = 0;
468
469 /* stop now if the url line will not fit into the window */
470 if (((currenty - url_win_text_start_y) + url_win_line_step) > url_win_text_len_y)
471 break;
472
473 /* highlight the active (F2) url */
474 if (local_head == active_url)
475 glColor3f(0.0f,1.0f,0.0f);
476 else
477 glColor3f(1.0f,1.0f,1.0f);
478
479 draw_string_zoomed_ellipsis_font(url_win_sep, currenty,
480 (const unsigned char *)((URLDATA *)local_head->data)->text,
481 url_win_max_string_width, 1, win->font_category, url_win_text_zoom);
482
483 /* step down a line, do it now as the maths for mouse over below is easier */
484 currenty += url_win_line_step;
485
486 /* if the mouse is over the current line, hightlight it */
487 if ((mouse_y >= win->cur_y + currenty - url_win_line_step) &&
488 (mouse_y < win->cur_y + currenty) &&
489 (mouse_x >= win->cur_x + (int)url_win_sep) &&
490 (mouse_x - (int)url_win_sep <= win->cur_x + url_win_max_string_width))
491 {
492 /* remember which url we're over in case it's clicked */
493 url_win_hover_url = local_head;
494 highlight_url = 1;
495 }
496
497 /* if a context menu is open, only hightlight the last URL hovered over before the context opened */
498 if (cm_window_shown() != CM_INIT_VALUE)
499 {
500 if (cm_url == local_head)
501 highlight_url = 1;
502 else
503 highlight_url = 0;
504 }
505 else
506 cm_url = NULL;
507
508 /* if mouse over or context activated, highlight the current URL */
509 if (highlight_url)
510 {
511 char *help_substring = NULL;
512 size_t help_substring_len = 0;
513 int dsp_start = 0;
514 int helpline = 0;
515 Uint32 currenttime = SDL_GetTicks();
516 size_t full_help_len = strlen(((URLDATA *)local_head->data)->text) + 30;
517 char *full_help_text = (char *)malloc(sizeof(char) * full_help_len);
518 float string_width = min2i(get_string_width_zoom((const unsigned char *)((URLDATA *)local_head->data)->text,
519 win->font_category, url_win_text_zoom), url_win_max_string_width);
520
521 /* display the mouse over help next time round */
522 url_win_status = URLW_OVER;
523
524 /* underline the text, just clicked links are red, otherwise blue - paler when visited */
525 if ((currenttime - url_win_clicktime < 500) && (url_win_clicked_url == url_win_hover_url))
526 glColor3f(1.0f,0.0f,0.3f);
527 else if (((URLDATA *)local_head->data)->visited)
528 glColor3f(0.3f,0.5f,1.0f);
529 else
530 glColor3f(0.1f,0.2f,1.0f);
531 glDisable(GL_TEXTURE_2D);
532 glBegin(GL_LINES);
533 glVertex2i(url_win_sep, currenty-2);
534 glVertex2i(url_win_sep+string_width, currenty-2);
535 glEnd();
536 glEnable(GL_TEXTURE_2D);
537
538 /* write the full url as help text at the bottom of the window */
539 safe_snprintf(full_help_text, full_help_len, "%s (seen %d time%s) (%s)",
540 ((URLDATA *)local_head->data)->text, ((URLDATA *)local_head->data)->seen_count,
541 ((URLDATA *)local_head->data)->seen_count == 1?"":"s", ((((URLDATA *)local_head->data)->visited)?"visited":"unvisited"));
542 thetext = full_help_text;
543 dsp_string_len = 0;
544 string_width = 0;
545 glColor3f(1.0f,1.0f,1.0f);
546 while(*thetext != '\0')
547 {
548 float char_width = get_char_width_zoom(*thetext++,
549 win->font_category, win->current_scale_small);
550 if (((string_width+char_width) > (win->len_x - 2*url_win_sep)) || (*thetext == '\0'))
551 {
552 if (*thetext == '\0') /* catch the last line */
553 dsp_string_len++;
554 if (help_substring_len < dsp_string_len)
555 {
556 if (help_substring != NULL)
557 free(help_substring);
558 help_substring = (char *)malloc(sizeof(char)*(dsp_string_len+1));
559 help_substring_len = dsp_string_len;
560 }
561 strncpy(help_substring, &full_help_text[dsp_start], dsp_string_len);
562 help_substring[dsp_string_len] = '\0';
563 draw_string_small_zoomed(url_win_sep, url_win_full_url_y_start + url_win_sep + helpline++ * win->small_font_len_y, (const unsigned char*)help_substring, 1, win->current_scale);
564 dsp_start += dsp_string_len;
565 dsp_string_len = 0;
566 string_width = 0;
567 }
568 dsp_string_len++;
569 string_width += char_width;
570 }
571 free(help_substring);
572 free(full_help_text);
573
574 } /* end if mouse over url */
575
576 /* count how many displayed so we can set the scroll bar properly */
577 num_url_displayed++;
578
579 local_head = local_head->next;
580 }
581
582 /* set the number of steps for the scroll bar */
583 vscrollbar_set_bar_len(win->window_id, url_scroll_id, have_url_count - num_url_displayed);
584
585 } /* end if have url */
586
587 /* draw a line below the list of url, above the current url full text */
588 glColor3fv(gui_color);
589 glDisable(GL_TEXTURE_2D);
590 glBegin(GL_LINES);
591 glVertex2i(0, url_win_full_url_y_start);
592 glVertex2i(win->len_x, url_win_full_url_y_start);
593 glEnd();
594 glEnable(GL_TEXTURE_2D);
595
596 #ifdef OPENGL_TRACE
597 CHECK_GL_ERRORS();
598 #endif //OPENGL_TRACE
599
600 return 1;
601
602 } /* end display_url_handler() */
603
604
605 /* common function to delete specified url record */
delete_current_url(list_node_t * chosen_url)606 static void delete_current_url(list_node_t *chosen_url)
607 {
608 if (have_url_count && chosen_url != NULL)
609 {
610 list_node_t *prev = chosen_url->prev;
611 list_node_t *next = chosen_url->next;
612 if (prev != NULL)
613 prev->next = next;
614 if (next != NULL)
615 next->prev = prev;
616 if (chosen_url == newest_url)
617 newest_url = next;
618 if (chosen_url == active_url)
619 active_url = prev;
620 if (active_url == NULL)
621 active_url = next;
622 free(((URLDATA *)chosen_url->data)->text);
623 free(chosen_url->data);
624 free(chosen_url);
625 url_win_hover_url = NULL;
626 have_url_count--;
627 }
628 }
629
630 /* common function to open link of the specified url record */
open_current_url(list_node_t * chosen_url)631 static void open_current_url(list_node_t *chosen_url)
632 {
633 if (have_url_count && chosen_url != NULL)
634 {
635 url_win_clicktime = SDL_GetTicks();
636 url_win_clicked_url = chosen_url;
637 open_web_link(((URLDATA *)chosen_url->data)->text);
638 ((URLDATA *)chosen_url->data)->visited = 1;
639 }
640 }
641
642 /* called just before a context menu is displayed */
context_url_pre_show_handler(window_info * win,int widget_id,int mx,int my,window_info * cm_win)643 static void context_url_pre_show_handler(window_info *win, int widget_id, int mx, int my, window_info *cm_win)
644 {
645 // propagate opacity from parent tab window
646 if (cm_win!= NULL && get_id_MW(MW_INFO) >-1 && get_id_MW(MW_INFO) < windows_list.num_windows)
647 cm_win->opaque = windows_list.window[get_id_MW(MW_INFO)].opaque;
648 }
649
650 /* called when a context menu option is selected */
context_url_handler(window_info * win,int widget_id,int mx,int my,int option)651 static int context_url_handler(window_info *win, int widget_id, int mx, int my, int option)
652 {
653 if (cm_url)
654 {
655 switch (option)
656 {
657 case 0: open_current_url(cm_url); break;
658 case 1:
659 {
660 char *theurl = ((URLDATA *)cm_url->data)->text;
661 char *skiptext = "http://";
662 if (theurl && strlen(theurl) > strlen(skiptext))
663 history_grep(theurl+strlen(skiptext), strlen(theurl)-strlen(skiptext));
664 }
665 break;
666 case 2: ((URLDATA *)cm_url->data)->visited = 1; break;
667 case 3: ((URLDATA *)cm_url->data)->visited = 0; break;
668 case 5: delete_current_url(cm_url); break;
669 case 7: destroy_url_list(); break;
670 }
671 cm_url = NULL;
672 }
673 url_win_clicktime = SDL_GetTicks();
674 return 1;
675 }
676
677 /* act on scroll wheel in the main window or clicking a URL */
click_url_handler(window_info * win,int mx,int my,Uint32 flags)678 static int click_url_handler(window_info *win, int mx, int my, Uint32 flags)
679 {
680 static size_t cm_id = CM_INIT_VALUE;
681
682 if (flags & ELW_WHEEL_UP)
683 vscrollbar_scroll_up(win->window_id, url_scroll_id);
684 else if (flags & ELW_WHEEL_DOWN)
685 vscrollbar_scroll_down(win->window_id, url_scroll_id);
686 else if (have_url_count && url_win_hover_url != NULL)
687 {
688 if (flags & KMOD_CTRL)
689 {
690 delete_current_url(url_win_hover_url);
691 do_window_close_sound();
692 }
693 else if (flags & ELW_RIGHT_MOUSE)
694 {
695 cm_url = url_win_hover_url;
696 /* create first time needed */
697 if (!cm_valid(cm_id))
698 {
699 cm_id = cm_create(cm_url_menu_str, context_url_handler);
700 cm_set_pre_show_handler(cm_id, context_url_pre_show_handler);
701 }
702 cm_show_direct(cm_id, -1, -1);
703 }
704 else
705 {
706 /* open the URL but block double clicks */
707 Uint32 currentclicktime = SDL_GetTicks();
708 if (currentclicktime < url_win_clicktime)
709 url_win_clicktime = 0; /* just in case we're running for 49 days :) */
710 if ((currentclicktime - url_win_clicktime > 1000) || (url_win_clicked_url != url_win_hover_url))
711 {
712 do_click_sound();
713 open_current_url(url_win_hover_url);
714 }
715 }
716 }
717 url_win_top_line = vscrollbar_get_pos(win->window_id, url_scroll_id);
718 return 0;
719 }
720
url_win_click_clear_all(widget_list * widget,int mx,int my,Uint32 flags)721 static int url_win_click_clear_all(widget_list *widget, int mx, int my, Uint32 flags)
722 {
723 if ((flags & ELW_WHEEL_UP) || (flags & ELW_WHEEL_DOWN))
724 return 1;
725 destroy_url_list();
726 return 1;
727 }
728
url_win_mouseover_clear_all(widget_list * widget,int mx,int my)729 static int url_win_mouseover_clear_all(widget_list *widget, int mx, int my)
730 {
731 url_win_status = URLW_CLEAR;
732 return 1;
733 }
734
735
url_win_scroll_click(widget_list * widget,int mx,int my,Uint32 flags)736 static int url_win_scroll_click(widget_list *widget, int mx, int my, Uint32 flags)
737 {
738 url_win_top_line = vscrollbar_get_pos(widget->window_id, url_scroll_id);
739 return 1;
740 }
741
742
url_win_scroll_drag(widget_list * widget,int mx,int my,Uint32 flags,int dx,int dy)743 static int url_win_scroll_drag(widget_list *widget, int mx, int my, Uint32 flags, int dx, int dy)
744 {
745 return url_win_scroll_click(widget, mx, my, flags);
746 }
747
748
resize_url_handler(window_info * win,int new_width,int new_height)749 static int resize_url_handler(window_info *win, int new_width, int new_height)
750 {
751 widget_list *widget = widget_find(win->window_id, clear_all_button);
752
753 url_win_text_zoom = 1.0 * win->current_scale;
754 url_win_sep = (int)(0.5 + 5 * win->current_scale);
755
756 button_resize(win->window_id, clear_all_button, 0, 0, win->current_scale * 0.75);
757 widget_move(win->window_id, clear_all_button, url_win_sep, url_win_sep);
758
759 url_win_help_x = widget->len_x + 2 * url_win_sep;
760 url_win_max_string_width = win->len_x - (2*url_win_sep + win->box_size);
761
762 url_win_line_step = (int)(3 + get_line_height(win->font_category, url_win_text_zoom));
763
764 url_win_full_url_y_len = 2*url_win_sep + 4 * win->small_font_len_y;
765
766 url_win_text_start_y = 2*url_win_sep + widget->len_y;
767
768 url_win_text_len_y = url_win_line_step * (int)((win->len_y - url_win_text_start_y - url_win_full_url_y_len) / url_win_line_step);
769 url_win_full_url_y_start = url_win_text_start_y + url_win_text_len_y;
770
771 widget_resize(win->window_id, url_scroll_id, win->box_size, url_win_text_len_y);
772 widget_move(win->window_id, url_scroll_id, win->len_x - win->box_size, url_win_text_start_y);
773
774 return 0;
775 }
776
777
778 /* fill the URL window created as a tab. */
fill_url_window(int window_id)779 void fill_url_window(int window_id)
780 {
781 set_window_custom_scale(window_id, MW_INFO);
782 set_window_handler(window_id, ELW_HANDLER_DISPLAY, &display_url_handler );
783 set_window_handler(window_id, ELW_HANDLER_CLICK, &click_url_handler );
784 set_window_handler(window_id, ELW_HANDLER_RESIZE, &resize_url_handler );
785
786 /* create the clear all button */
787 clear_all_button = button_add_extended (window_id, clear_all_button, NULL,
788 0, 0, 0, 0, 0, 0, "Clear All");
789 widget_set_OnClick(window_id, clear_all_button, url_win_click_clear_all);
790 widget_set_OnMouseover(window_id, clear_all_button, url_win_mouseover_clear_all);
791
792 /* create the scroll bar */
793 url_scroll_id = vscrollbar_add_extended(window_id, url_scroll_id, NULL,
794 0, 0, 0, 0, 0, 1.0, 0, 1, have_url_count);
795 widget_set_OnDrag(window_id, url_scroll_id, url_win_scroll_drag);
796 widget_set_OnClick(window_id, url_scroll_id, url_win_scroll_click);
797 }
798
799