1 /* retawq/wk.c - window kinds
2 This file is part of retawq (<http://retawq.sourceforge.net/>), a network
3 client created by Arne Thomassen; retawq is basically released under certain
4 versions of the GNU General Public License and WITHOUT ANY WARRANTY.
5 Read the file COPYING for license details, README for program information.
6 Copyright (C) 2001-2005 Arne Thomassen <arne@arne-thomassen.de>
7 */
8
9 /* This code is part of the user interface; it's taken out for the only reason
10 that source files are smaller this way. Look how it's #include'd from
11 main.c; maybe dirty, but simple and functional...
12 */
13
14 /* Helper functions for text/graphics modes */
15
16 #if CONFIG_TG == TG_GTK
17
18 #define connect_object(object, signal, handler, data) \
19 gtk_signal_connect(object, signal, GTK_SIGNAL_FUNC(handler), data)
20 #define connect_widget(widget, signal, handler, data) \
21 connect_object(GTK_OBJECT(widget), signal, handler, data)
22 #define connect_window(window, signal, handler, data) \
23 connect_object(GTK_OBJECT(window), signal, handler, data)
24 #define show_widget(x) gtk_widget_show(GTK_WIDGET(x))
25 #define pack_box(container, element) \
26 gtk_box_pack_start(GTK_BOX(container), element, FALSE, FALSE, 0)
27
28 typedef struct
29 { tWindow* window;
30 tProgramCommandCode pcc;
31 } tGtkWindowCommand;
32
33 static my_inline __sallocator tGtkWindowCommand* __callocator
create_window_command(const tWindow * window,tProgramCommandCode pcc)34 create_window_command(const tWindow* window, tProgramCommandCode pcc)
35 { tGtkWindowCommand* retval =
36 (tGtkWindowCommand*) __memory_allocate(sizeof(tGtkWindowCommand), mapGtk);
37 retval->window = __unconstify(tWindow*, window); retval->pcc = pcc;
38 return(retval);
39 }
40
graphics_handle_command_code(GtkWidget * widget,gpointer _data)41 static void graphics_handle_command_code(GtkWidget* widget, gpointer _data)
42 { const tGtkWindowCommand* data = (tGtkWindowCommand*) _data;
43 tWindow* window = data->window;
44 const GtkWindow* ww = window->ww;
45 tProgramCommandCode pcc = data->pcc;
46 current_window = window; handle_command_code(pcc); current_window = NULL;
47 }
48
graphics_propagate_event(tGraphicsWidget * w __cunused,tGraphicsEvent * event __cunused,gpointer data __cunused)49 static gint graphics_propagate_event(tGraphicsWidget* w __cunused,
50 tGraphicsEvent* event __cunused, gpointer data __cunused)
51 { /* just enforce the propagation of signals to parent widgets: */
52 return(FALSE);
53 }
54
window_handle_delete(tGraphicsWidget * w __cunused,tGraphicsEvent * event __cunused,gpointer data __cunused)55 static gint window_handle_delete(tGraphicsWidget* w __cunused,
56 tGraphicsEvent* event __cunused, gpointer data __cunused)
57 { /* don't handle it here, let GTK call window_handle_destroy()... */
58 return(FALSE);
59 }
60
window_handle_destroy(tGraphicsWidget * w __cunused,gpointer data)61 static gint window_handle_destroy(tGraphicsWidget* w __cunused, gpointer data)
62 { window_hide((tWindow*) data, 2);
63 return(TRUE);
64 }
65
window_handle_configure(tGraphicsWidget * widget __cunused,tGraphicsEvent * event __cunused,gpointer data)66 static gint window_handle_configure(tGraphicsWidget* widget __cunused,
67 tGraphicsEvent* event __cunused, gpointer data)
68 { tWindow* w = (tWindow*) data;
69 window_redraw(w);
70 return(TRUE);
71 }
72
create_menu(tGraphicsWidget * bar,char * _title)73 static tGraphicsWidget* create_menu(tGraphicsWidget* bar, char* _title)
74 { tGraphicsWidget *menu = gtk_menu_new(),
75 *title = gtk_menu_item_new_with_label(_title);
76 show_widget(title);
77 gtk_menu_item_set_submenu(GTK_MENU_ITEM(title), menu);
78 gtk_menu_bar_append(GTK_MENU_BAR(bar), title);
79 return(menu);
80 }
81
__create_item(const tWindow * window,GtkAccelGroup * accel,tGraphicsWidget * menu,const char * text,tProgramCommandCode pcc,tKey key)82 static void __create_item(const tWindow* window, GtkAccelGroup* accel,
83 tGraphicsWidget* menu, const char* text, tProgramCommandCode pcc, tKey key)
84 { tGraphicsWidget* item = gtk_menu_item_new_with_label(text);
85 gtk_menu_append(GTK_MENU(menu), item);
86 connect_widget(item, strGtkActivate, graphics_handle_command_code,
87 (gpointer) create_window_command(window, pcc));
88 if (key != '\0')
89 { GdkModifierType t;
90 if (my_isupper(key)) { t = GDK_CONTROL_MASK; key = my_tolower(key); }
91 else t = GDK_MOD1_MASK;
92 gtk_widget_add_accelerator(item, strGtkActivate, accel, key, t,
93 GTK_ACCEL_VISIBLE);
94 }
95 show_widget(item);
96 }
97
98 #define create_item(m, t, pcc, k) __create_item(retval, accel, m, t, pcc, k)
99
create_button(const tWindow * window,tGraphicsWidget * container,char * text,tProgramCommandCode pcc)100 static void create_button(const tWindow* window, tGraphicsWidget* container,
101 char* text, tProgramCommandCode pcc)
102 { tGraphicsWidget* button = gtk_button_new_with_label(text);
103 connect_widget(button, strGtkClicked, graphics_handle_command_code,
104 (gpointer) create_window_command(window, pcc));
105 pack_box(container, button);
106 show_widget(button);
107 }
108
graphics_cm(tGraphicsWidget * w __cunused,tGraphicsEvent * _event,gpointer data)109 static gint graphics_cm(tGraphicsWidget* w __cunused, tGraphicsEvent* _event,
110 gpointer data)
111 /* shows a contextual menu in graphics mode */
112 {
113 if (_event->type == GDK_BUTTON_PRESS)
114 { GdkEventButton* event = (GdkEventButton*) _event;
115 guint b = event->button;
116 if (b == 3)
117 { tGraphicsWidget *menu = gtk_menu_new(),
118 *item = gtk_menu_item_new_with_label("TEST");
119 tWindow* window = (tWindow*) data;
120 show_widget(menu); show_widget(item);
121 gtk_menu_append(GTK_MENU(menu), item);
122 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, b, event->time);
123 return(TRUE);
124 }
125 }
126 return(FALSE);
127 }
128
129
130 static const char* const retawq_logo_mini[] = {
131 "64 64 2 1",
132 " c None",
133 ". c #FF0000",
134 " ",
135 " ",
136 " ",
137 " ",
138 " ",
139 " ",
140 " ",
141 " ",
142 " ",
143 " ",
144 " ",
145 " ",
146 " ",
147 " ..... ",
148 " .... ........... ",
149 " .................. .............. ",
150 " .................. ................ ",
151 " .................. .................. ",
152 " .................. .................. ",
153 " ............. ...... ............ ",
154 " ............ ..... ............ ",
155 " ............ .... ............ ",
156 " ................. ............ ",
157 " ............... ............ ",
158 " ............... ............ ",
159 " .............. .......... ",
160 " .............. ........ ",
161 " .............. .... ",
162 " ............. ",
163 " ............. ",
164 " ............. ",
165 " ............. ",
166 " ............ ",
167 " ............ ",
168 " ............ ",
169 " ............ ",
170 " ............ ",
171 " ............ ",
172 " ............ ",
173 " ............ ",
174 " ............ ",
175 " ............ ",
176 " ............ ",
177 " ............ ",
178 " ............ ",
179 " ............. ",
180 " .............. ",
181 " ......................... ",
182 " .......................... ",
183 " .......................... ",
184 " .......................... ",
185 " ",
186 " ",
187 " ",
188 " ",
189 " ",
190 " ",
191 " ",
192 " ",
193 " ",
194 " ",
195 " ",
196 " ",
197 " "};
198
199 #elif TGC_IS_CURSES
200
cu_display_title(const tWindow * window,const char * title,short titlerow)201 static void cu_display_title(const tWindow* window, const char* title,
202 short titlerow)
203 { short count = 0, maxcount = COLS - 1;
204 char ch, buf[1024];
205 if (maxcount > 1000) maxcount = 1000; /* avoid buffer overflows... */
206 /* setup */
207 buf[count++] = window->spec->ui_char; buf[count++] = ' '; buf[count++] = '-';
208 buf[count++] = ' ';
209 while ( ((ch = *title++) != '\0') && (count < maxcount) ) buf[count++] = ch;
210 while (count <= maxcount) buf[count++] = ' ';
211 buf[count] = '\0';
212 /* output */
213 (void) move(titlerow, 0); (void) attron(A_REVERSE); (void) addstr(buf);
214 (void) attroff(A_REVERSE);
215 }
216
217 #endif /* CONFIG_TG */
218
219
220 /*** Window kind: browser window */
221
222 typedef struct tWindowView /* a "view" of a resource within a browser window */
223 { tBrowserDocument bd; /* "bd": "browser document" or "base document" */
224 struct tWindow* window; /* the window to which the view belongs */
225 struct tWindowView *prev, *next; /* the list of views within that window */
226 } tWindowView; /* CHECKME: rename! */
227
228 typedef struct
229 { tWindowView *first_view, *current_view;
230 #if TGC_IS_GRAPHICS
231 tGraphicsWindow* ww; /* "window widget" */
232 tGraphicsWidget *contents, *location, *info, *message;
233 tGraphicsLowlevelWindow* drawable; /* for the actual contents */
234 tGraphicsContext* gc; /* ditto */
235 #endif
236 } tWkBrowserData; /* for window->wksd */
237
238
239 /** Browser window stuff */
240
wk_browser_redraw_message(tBrowserDocument * document)241 static void wk_browser_redraw_message(tBrowserDocument* document)
242 { const tWindowView* view = (const tWindowView*) (document->container);
243 const tWindow* window = view->window;
244 const tResourceRequest* request = document->request;
245 const tResource* resource = request->resource;
246 tBoolean is_error;
247 const char *message = calculate_reqresmsg(request, resource, 0, &is_error);
248 const size_t msgsize = strlen(message) + 1;
249 char* temp = __memory_allocate(msgsize + 1, mapString); /* ("+1": flags) */
250 #if TGC_IS_CURSES
251 if (window == current_window_x)
252 #endif
253 { show_message(message, is_error); }
254 *temp = boolean2bool(is_error); /* (flags - just is_error for now) */
255 my_memcpy(temp + 1, message, msgsize);
256 __dealloc(document->last_info); document->last_info = temp;
257 }
258
wk_browser_redraw_title(const tBrowserDocument * document,short titlerow)259 static void wk_browser_redraw_title(/*@notnull@*/ const tBrowserDocument*
260 document, short titlerow)
261 { const tWindowView* view = (const tWindowView*) (document->container);
262 const tWindow* window = view->window;
263 tResource* resource = document->request->resource;
264 char* temp;
265 #if TGC_IS_GRAPHICS
266 tGraphicsWindow* ww = window->ww;
267 char* window_title = unconstify(strProgramVersion);
268 char* s = strbuf;
269 if (document->html_title != NULL)
270 window_title = unconstify(document->html_title);
271 if (document->title != NULL)
272 gtk_label_set_text(GTK_LABEL(window->location), document->title);
273 #if OPTION_COOKIES
274 if ( (resource != NULL) && (resource->flags & rfCookieAnything) )
275 s += sprint_safe(s, strPercs, _(strCookies));
276 #endif
277 if (document->flags & wvfHandledRedirection)
278 s += sprint_safe(s, strPercsDash, _(strRedirection));
279 else if (document->bddm == bddmSource)
280 s += sprint_safe(s, strPercsDash, _(strSource));
281 *s = '\0';
282 temp = strbuf;
283 gtk_window_set_title(ww, window_title);
284 gtk_label_set_text(GTK_LABEL(window->info), temp);
285
286 #else /* #if TGC_IS_GRAPHICS */
287
288 const tCantent* cantent = document->cantent;
289 const char *major = ( (cantent != NULL) ? (cantent->major_html_title) :
290 NULL ), *html_title = ( (major != NULL) ? major :
291 (document->minor_html_title) ), *title = document->title;
292 #define dashify(cond, str) \
293 ( (cond) ? str : strEmpty ), ( (cond) ? strSpacedDash : strEmpty )
294 my_spf(strbuf, STRBUF_SIZE, &temp,
295 #if OPTION_COOKIES
296 /*A*/ "%s"
297 #endif
298 /*BCDE*/ "%s%s%s%s%s%s%s"
299 ,
300 #if OPTION_COOKIES
301 /*A*/ ( ( (resource != NULL) && (resource->flags & rfCookieAnything) )
302 /*A*/ ? _(strCookies) : strEmpty ), /* RFC2965, 6.1, *2 */
303 #endif
304 /*B*/ dashify((document->flags & wvfHandledRedirection), _(strRedirection)),
305 /*C*/ dashify((document->bddm == bddmSource), _(strSource)),
306 /*D*/ dashify((html_title != NULL), html_title),
307 /*E*/ null2empty(title)
308 );
309 #undef dashify
310 cu_display_title(window, temp, titlerow); my_spf_cleanup(strbuf, temp);
311
312 #endif /* #if TGC_IS_GRAPHICS */
313 }
314
315 #if DO_WK_INFO
316
317 typedef struct tIbuf
318 { struct tIbuf* next;
319 const char* str;
320 } tIbuf;
321
322 typedef struct
323 { tIbuf *head, *tail;
324 } tIbuffer; /* "ibuffer" like "inode" :-) */
325
326 my_enum1 enum
327 { iiInvalid = -1, iiImage = 0, iiForm = 1, iiFrame = 2, iiLink = 3
328 } my_enum2(signed char) tIbufferIndex;
329 #define iiMax (iiLink)
330 static const char* const strIheader[iiMax + 1] =
331 { N_("Images: "), N_("Forms: "), N_("Frames: "), N_("Links: ") };
332
wk_browser_build_document_info(tBrowserDocument * document)333 static one_caller void wk_browser_build_document_info(/*@notnull@*/
334 tBrowserDocument* document)
335 { static const char strMasterPre[] = "<ul>\n", strMasterPost[] = "</ul>\n",
336 strIpre[] = "<li>", strIpost[] = "</li>\n";
337 tWindow* iw; /* "info window" */
338 tIbuffer ibuf[iiMax + 1];
339 tIbufferIndex idx;
340 const tHtmlNode* node;
341 const tResourceRequest* request = document->request;
342 const tUriData* req_ud = request->uri_data;
343 const tResource* resource = request->resource;
344 tCantent* cantent = document->cantent;
345 const char *uri = document->title, *html_title;
346 tActiveElementNumber _ae, __ae;
347 tHtmlFormNumber _hfn, __hfn;
348 char* spfbuf;
349
350 my_spf(NULL, 0, &spfbuf, _("Information about \"%s\""), ( (uri != NULL) ? uri
351 : _(strUnknown) ));
352 iw = visible_window_x[1 - current_window_index_x] =
353 wk_info_create(my_spf_use(spfbuf), bddmHtml, NULL);
354
355 if (uri != NULL)
356 { const char* html_uri = htmlify(uri);
357 my_spf(strbuf, STRBUF_SIZE, &spfbuf, "<p>%s<a href=\"%s\">%s</a></p>\n",
358 _(strUriColonSpace), html_uri, html_uri);
359 htmlify_cleanup(uri, html_uri); wk_info_collect(iw, spfbuf);
360 my_spf_cleanup(strbuf, spfbuf);
361 }
362
363 html_title = ( (cantent != NULL) ? cantent->major_html_title : NULL );
364 if (html_title == NULL) html_title = document->minor_html_title;
365 if ( (html_title != NULL) && (*html_title != '\0') )
366 { const char* htitle = htmlify(html_title);
367 my_spf(strbuf, STRBUF_SIZE, &spfbuf, "<p>%s\"%s\"</p>\n", _("Title: "),
368 htitle);
369 htmlify_cleanup(html_title, htitle);
370 wk_info_collect(iw, spfbuf); my_spf_cleanup(strbuf, spfbuf);
371 }
372
373 if (resource != NULL)
374 { const size_t size = resource->bytecount;
375 my_spf(strbuf, STRBUF_SIZE, &spfbuf, "<p>%s%d %s</p>\n", _("Size: "),
376 localized_size(size), bytebytes(size));
377 wk_info_collect(iw, spfbuf); my_spf_cleanup(strbuf, spfbuf);
378 }
379
380 if ( (cantent == NULL) ||
381 ( (document->bddm != bddmHtml) && (cantent->kind != rckHtml) ) )
382 goto not_html;
383
384 /* Currently we must run the whole document once through the renderer to get
385 the handling of "inside <pre> tag" correctly in the permanently stored
386 tree of HTML nodes. Rubbish... IMPROVEME! */
387 #if 0
388 { const tLinenumber l = document->origin_y;
389 const tActiveElementNumber a = document->aecur;
390 document_display(document, wrtToEnd);
391 if (document->origin_y != l) /* ("likely") */
392 { document->origin_y = l; document->aecur = a;
393 document_display(document, wrtRedraw);
394 }
395 }
396 #else
397 document_display(document, wrtToEnd);
398 #endif
399
400 parser_html_start(cantent); my_memclr_arr(ibuf);
401 _ae = __ae = INVALID_AE; _hfn = __hfn = INVALID_HTML_FORM_NUMBER;
402 while ( (node = parser_html_next(falsE)) != NULL )
403 { const tHtmlTagKind htk = node->kind;
404 const tHtmlNodeFlags hnf = node->flags;
405 const tBoolean has_aebase = cond2boolean(hnf & hnfHasAeBase);
406 const tActiveElementBase* aeb;
407 const tAttribute* attr;
408 const char *str, *hstr;
409 if (has_aebase) { __ae++; _ae = __ae; }
410 else _ae = INVALID_AE;
411 if (hnf & hnfGoodForm) { __hfn++; _hfn = __hfn; }
412 else _hfn = INVALID_HTML_FORM_NUMBER;
413 if (htk == htkText) goto do_next;
414 idx = iiInvalid;
415 /* CHECKME: avoid duplicates in the lists of links and images? */
416 switch (htk)
417 { case htkA:
418 if (_ae == INVALID_AE) goto do_next;
419 aeb = &(cantent->aebase[_ae]);
420 if ( ( (str = aeb->data) != NULL ) && (*str != '\0') )
421 { tUriData* uri_data;
422 idx = iiLink;
423 use_linkstr:
424 uri_data = uri_parse(str, req_ud, NULL, NULL, 2);
425 /* CHECKME: use the "proper" referrer! */
426 str = uri_data->uri; hstr = htmlify(str);
427 my_spf(NULL, 0, &spfbuf, "%s<a href=\"%s\">%s</a>%s", strIpre, hstr,
428 hstr, strIpost);
429 htmlify_cleanup(str, hstr); uri_put(uri_data);
430 }
431 break;
432 case htkImg:
433 attr = find_attribute(node, anSrc);
434 if ( (attr != NULL) && ( (str = attr->value) != NULL ) && (*str!='\0'))
435 { idx = iiImage; goto use_linkstr; }
436 break;
437 case htkForm:
438 if (_hfn != INVALID_HTML_FORM_NUMBER)
439 { const tHtmlForm* f = &(cantent->form[_hfn]);
440 const char* au = f->action_uri;
441 if ( (au != NULL) && (*au != '\0') )
442 { const tHtmlFormFlags hff = f->flags;
443 my_spf(NULL, 0, &spfbuf, "%s\"%s\"%s%s%s", strIpre, au,
444 ( (hff & hffMethodPost) ? " - POST" : strEmpty ),
445 ( (hff & hffEncodingMultipart) ? " - multipart" : strEmpty ),
446 strIpost);
447 idx = iiForm;
448 }
449 }
450 break;
451 case htkFrame:
452 if (_ae == INVALID_AE) goto do_next;
453 aeb = &(cantent->aebase[_ae]);
454 if ( ( (str = aeb->data) != NULL ) && (*str != '\0') )
455 { idx = iiFrame; goto use_linkstr; }
456 break;
457 }
458 if (idx >= 0)
459 { tIbuf* ib = __memory_allocate(sizeof(tIbuf), mapOther);
460 ib->next = NULL; ib->str = my_spf_use(spfbuf);
461 if (ibuf[idx].tail != NULL) ibuf[idx].tail->next = ib;
462 ibuf[idx].tail = ib;
463 if (ibuf[idx].head == NULL) ibuf[idx].head = ib;
464 }
465 do_next:
466 if (!(hnf & hnfStoredInTree)) deallocate_html_node(node);
467 }
468 parser_html_finish();
469
470 for (idx = 0; idx <= iiMax; idx++)
471 { tIbuf* ib = ibuf[idx].head;
472 if (ib == NULL) goto do_next_idx; /* no entries exist for this one */
473 sprint_safe(strbuf, "<p>%s</p>\n%s", _(strIheader[idx]), strMasterPre);
474 wk_info_collect(iw, strbuf);
475 while (ib != NULL)
476 { tIbuf* next = ib->next;
477 const char* str = ib->str;
478 wk_info_collect(iw, str);
479 memory_deallocate(str); memory_deallocate(ib); ib = next;
480 }
481 wk_info_collect(iw, strMasterPost);
482 do_next_idx: {}
483 }
484
485 not_html: {}
486 wk_info_finalize(iw);
487 }
488
489 #endif /* #if DO_WK_INFO */
490
491
492 /** Browser window document operations interface */
493
wk_browser_dop_find_coords(const tBrowserDocument * document,short * _x1,short * _y1,short * _x2,short * _y2)494 static tBoolean wk_browser_dop_find_coords(const tBrowserDocument* document,
495 /*@out@*/ short* _x1, /*@out@*/ short* _y1, /*@out@*/ short* _x2,
496 /*@out@*/ short* _y2)
497 { const tWindowView* view = (const tWindowView*) (document->container);
498 const tWindow* window = view->window;
499 short minrow, maxrow;
500 const tBoolean retval = window_contents_minmaxrow(window, &minrow, &maxrow);
501 if (retval) { *_x1 = 0; *_y1 = minrow; *_x2 = COLS - 1; *_y2 = maxrow; }
502 return(retval);
503 }
504
wk_browser_dop_display_meta1(tBrowserDocument * document)505 static void wk_browser_dop_display_meta1(tBrowserDocument* document)
506 { wk_browser_redraw_message(document);
507 }
508
wk_browser_dop_display_meta2(tBrowserDocument * document)509 static void wk_browser_dop_display_meta2(tBrowserDocument* document)
510 { short minrow, maxrow;
511 if (document_minmaxrow(document, &minrow, &maxrow))
512 wk_browser_redraw_title(document, maxrow + 1);
513 }
514
515 static const tBrowserDocumentOps wk_browser_document_ops =
516 { wk_browser_dop_find_coords, wk_browser_dop_display_meta1,
517 wk_browser_dop_display_meta2
518 };
519
520
521 /** Browser window view handling */
522
deallocate_windowviewlist(const tWindowView * view)523 static void deallocate_windowviewlist(const tWindowView* view)
524 /* deallocates the given list of views and drops associated request and
525 resource data */
526 { while (view != NULL)
527 { const tWindowView* next = view->next;
528 document_tear(&(view->bd)); memory_deallocate(view); view = next;
529 }
530 }
531
cut_windowviewlist(tWindow * window)532 static void cut_windowviewlist(tWindow* window)
533 /* "cuts" the current view and all its successors out of the <window> and
534 deallocates them */
535 { tWkBrowserData* wksd = (tWkBrowserData*) (window->wksd);
536 tWindowView* view = wksd->current_view;
537 if (view != NULL)
538 { if (view->prev != NULL) view->prev->next = NULL;
539 wksd->current_view = view->prev;
540 if (wksd->first_view == view) wksd->first_view = NULL;
541 deallocate_windowviewlist(view);
542 }
543 }
544
545 static /* __sallocator -- not an "only" reference... */ tWindowView*
wk_browser_append_view(tWindow * window)546 __callocator wk_browser_append_view(tWindow* window)
547 /* prepares a new view in the given browser window and removes any old "tail"
548 of views in that window */
549 { tWkBrowserData* wksd = (tWkBrowserData*) (window->wksd);
550 tWindowView *current_view = wksd->current_view,
551 *new_view = memory_allocate(sizeof(tWindowView), mapWindowView);
552 new_view->window = window;
553 if (current_view != NULL) /* wasn't a new (empty) window */
554 { const tWindowView* tail = current_view->next;
555 if (tail != NULL) deallocate_windowviewlist(tail); /* remove old tail */
556 current_view->next = new_view; new_view->prev = current_view;
557 }
558 wksd->current_view = new_view;
559 if (wksd->first_view == NULL) wksd->first_view = new_view;
560 return(new_view);
561 }
562
wk_browser_request_callback(void * _document,tDhmNotificationFlags flags)563 static void wk_browser_request_callback(void* _document,
564 tDhmNotificationFlags flags)
565 { tBrowserDocument* document = (tBrowserDocument*) _document;
566 tResourceRequest* request = document->request;
567 tResource* resource = request->resource;
568 tWindowView* view = (tWindowView*) (document->container);
569 tWindow* window = view->window;
570 #if CONFIG_DEBUG
571 sprint_safe(debugstrbuf, "wk_browser_request_callback(): document=%p, request=%p, resource=%p, dhmnf=%d\n", document, request, resource, flags);
572 debugmsg(debugstrbuf);
573 #endif
574 if (resource != NULL) request_copy_error(request, resource);
575 if (flags & (dhmnfDataChange | dhmnfMetadataChange))
576 { tWkBrowserData* wksd = (tWkBrowserData*) (window->wksd);
577 #if MIGHT_USE_SCROLL_BARS
578 document->sbvi = 0;
579 #endif
580 if ( (window_is_visible(window)) && (wksd->current_view == view) )
581 { if (request->flags & rrfResourceChanged) /* REMOVEME?! */
582 request->flags &= ~rrfResourceChanged;
583 else if (document->flags & wvfScreenFull)
584 document->flags |= wvfDontDrawContents;
585 document_display(document, wrtRedraw);
586 }
587 }
588 else if (flags & dhmnfAttachery) /* a resource was attached to the request */
589 { dhm_notification_setup(resource, wk_browser_request_callback,
590 document, dhmnfDataChange | dhmnfMetadataChange, dhmnSet);
591 cantent_attach(document->cantent, resource->cantent);
592 }
593 test_redirection(window, document);
594 }
595
wk_browser_prr(tWindow * window,const char * uri,tPrrFlags prrf,const tBrowserDocument * referrer)596 static void wk_browser_prr(tWindow* window, const char* uri, tPrrFlags prrf,
597 const tBrowserDocument* referrer)
598 /* prepares a resource request in a browser window */
599 { tWkBrowserData* wksd = (tWkBrowserData*) (window->wksd);
600 tWindowView *current_view = wksd->current_view, *new_view;
601 tPrrData prr_data;
602 tResourceRequest* request;
603 tBrowserDocument* document;
604 const char* anchor;
605 unsigned char redirections = 0;
606
607 prr_setup(&prr_data, uri, prrf | prrfWantUriAnchor);
608 prr_data.referrer = referrer; prepare_resource_request(&prr_data);
609 request = prr_data.result; prr_data.result = NULL;
610 anchor = prr_data.uri_anchor; prr_data.uri_anchor = NULL;
611
612 if ( (prrf & prrfIsRedirection) && (referrer != NULL) )
613 { const unsigned char count = redirections = referrer->redirections + 1;
614 if (count > config.redirections)
615 { redirection_error: request_set_error(request, reRedirection);
616 goto redirection_checked;
617 }
618 if ( (prrf & prrfIsHttpRedirection) && (referrer != NULL) )
619 { const tResource* res = referrer->request->resource;
620 if ( (res != NULL) && (res->flags & rfPost) )
621 goto redirection_error; /* RFC2616, 9.3 */
622 }
623 }
624 redirection_checked: {}
625
626 new_view = wk_browser_append_view(window);
627 document = &(new_view->bd);
628 document_init(document, &wk_browser_document_ops, new_view, request);
629 document->anchor = anchor; document->redirections = redirections;
630 document->title = my_strdup(request->uri_data->uri);
631 if (prrf & prrfPost) document->flags |= wvfPost;
632 if (prrf & prrfSource)
633 { document->bddm = bddmSource;
634 if (current_view != NULL)
635 { const char* html_title = current_view->bd.minor_html_title;
636 if (html_title != NULL)
637 document->minor_html_title = my_strdup(html_title);
638 }
639 }
640 else if (prrf & prrfHtml) document->bddm = bddmHtml;
641
642 if (prrf & prrfRedrawAll) window_redraw_all();
643 else if (prrf & prrfRedrawOne) window_redraw(window);
644 if (request->state != rrsError)
645 { tResourceRequestAction action;
646 if (prrf & prrfEnforcedReload) action = rraEnforcedReload;
647 else if (prrf & prrfReload) action = rraReload;
648 else
649 { action = rraLoad;
650 #if CONFIG_MENUS & MENUS_UHIST
651 if (is_environed)
652 { my_strdedup(uri_history[uri_history_index], request->uri_data->uri);
653 if (uri_history_index < URI_HISTORY_LEN - 1) uri_history_index++;
654 else uri_history_index = 0;
655 /* IMPLEMENTME: if the URI already is in the list, just "move it" to
656 the top of the list! */
657 }
658 #endif
659 }
660 dhm_notification_setup(request, wk_browser_request_callback, document,
661 dhmnfDataChange | dhmnfMetadataChange | dhmnfAttachery, dhmnSet);
662 request_queue(request, action);
663 }
664 prr_setdown(&prr_data);
665 }
666
667 #if TGC_IS_GRAPHICS
wk_browser_build_graphics(tWindow * window)668 static one_caller void wk_browser_build_graphics(tWindow* window)
669 { tGraphicsWindow* w = (GtkWindow*) gtk_window_new(GTK_WINDOW_TOPLEVEL);
670 tGraphicsWidget *base=gtk_vbox_new(FALSE,0), *fluff=gtk_vbox_new(FALSE,0),
671 *buttons = gtk_hbox_new(FALSE, 0), *texts = gtk_vbox_new(FALSE, 0),
672 *contents = gtk_drawing_area_new(), *url0 = gtk_hbox_new(FALSE, 0),
673 *url1 = gtk_label_new(_("Location: ")), *url2 = gtk_label_new(strEmpty),
674 *info0 = gtk_hbox_new(FALSE, 0), *info1 = gtk_label_new(strEmpty),
675 *info2 = gtk_label_new(strEmpty), *mbar = gtk_menu_bar_new(),
676 *mFile = create_menu(mbar, _(strFileUc)), *mView = create_menu(mbar,
677 _("View")), *mBookmark = create_menu(mbar, _("Bookmark")),
678 *mWindow = create_menu(mbar, _("Window"));
679 tGraphicsLowlevelWindow *some_parent, *drawable;
680 GdkWindowAttr* drawattrs = memory_allocate(sizeof(GdkWindowAttr), mapGtk);
681 GtkStyle* style;
682 tGraphicsContext* gc;
683 static tBoolean is_first_call = truE;
684 static char *strHome, *strStop;
685 static GdkPixmap* logo_mini_pixmap;
686 static GdkBitmap* logo_mini_mask;
687 GtkAccelGroup* accel = gtk_accel_group_new();
688
689 if (is_first_call)
690 { tGraphicsLowlevelWindow* template_window;
691 GdkWindowAttr* attr = memory_allocate(sizeof(GdkWindowAttr), mapGtk);
692 is_first_call = falsE;
693 strHome = i18n_strdup(_("Home")); strStop = i18n_strdup(_("Stop"));
694 attr->window_type = GDK_WINDOW_CHILD;
695 template_window = gdk_window_new(NULL, attr, 0);
696 logo_mini_pixmap = gdk_pixmap_create_from_xpm_d(template_window,
697 &logo_mini_mask, NULL, (gchar**) retawq_logo_mini);
698 }
699
700 gtk_window_set_policy(w, TRUE /* CHECKME: documentation contradicts it! */,
701 TRUE, FALSE);
702 gtk_window_set_title(GTK_WINDOW(w), strProgramVersion);
703 gtk_window_add_accel_group(GTK_WINDOW(w), accel);
704
705 gtk_drawing_area_size(GTK_DRAWING_AREA(contents), config.width,
706 config.height);
707 gtk_widget_set_events(contents, GDK_EXPOSURE_MASK);
708
709 /* basic window structure */
710 gtk_container_add(GTK_CONTAINER(w), base);
711 pack_box(base, mbar); pack_box(base, fluff); pack_box(base, contents);
712 pack_box(fluff, buttons); pack_box(fluff, texts);
713 pack_box(texts, url0); pack_box(texts, info0);
714 pack_box(url0, url1); pack_box(url0, url2);
715 pack_box(info0, info1); pack_box(info0, info2);
716
717 /* menus */
718 create_item(mFile, _("New Window"), pccWindowNew, 'n');
719 create_item(mFile, _(strOpenInNewWindow), pccWindowNewFromDocument, 'N');
720 create_item(mFile, _("Open Local File..."), pccLocalFileDirOpen, 'O');
721 create_item(mFile, _("Open URL..."), pccGoUri, 'o');
722 create_item(mFile, _("Open Relative URL..."), pccGoUriPreset, '\0');
723 create_item(mFile, _(strSaveAs), pccDocumentSave, 's');
724 create_item(mFile, _(strUcClose), pccWindowClose, 'c');
725 create_item(mFile, _(strUcQuit), pccQuit, 'q');
726 create_item(mView, _(strBack), pccViewBack, '\0');
727 create_item(mView, _(strForward), pccViewForward, '\0');
728 create_item(mView, _(strReload), pccDocumentReload, 'R');
729 if (config.home_uri != NULL) create_item(mView, strHome,pccGoHome, 'h');
730 if (config.search_engine != NULL)
731 create_item(mView, _(strSearch), pccGoSearch, 'e');
732 create_item(mView, strStop, pccStop, '.');
733 create_item(mView, _("Document Info"), pccUnknown, 'I');
734 create_item(mView, _(strSourceCode), pccDocumentEnforceSource, '\\');
735 create_item(mBookmark, _(strAddBookmark), pccUnknown, '\0');
736 create_item(mWindow, "(Titles of all windows)", pccUnknown, '\0');
737
738 /* buttons */
739 create_button(retval, buttons, _(strBack), pccViewBack);
740 create_button(retval, buttons, _(strForward), pccViewForward);
741 create_button(retval, buttons, _(strReload), pccDocumentReload);
742 if (config.home_uri != NULL)
743 create_button(retval, buttons, strHome, pccGoHome);
744 if (config.search_engine != NULL)
745 create_button(retval, buttons, _(strSearch), pccGoSearch);
746 create_button(retval, buttons, strStop, pccStop);
747
748 /* show all */
749 show_widget(url0); show_widget(url1); show_widget(url2);
750 show_widget(info0); show_widget(info1); show_widget(info2);
751 show_widget(mbar); show_widget(buttons); show_widget(texts);
752 show_widget(fluff); show_widget(contents); show_widget(base);
753 show_widget(w);
754
755 /* GDK window and gc for contents */
756 drawattrs->event_mask = gtk_widget_get_events(contents) | GDK_EXPOSURE_MASK
757 | GDK_KEY_PRESS_MASK | GDK_BUTTON_PRESS_MASK;
758 drawattrs->x = contents->allocation.x;
759 drawattrs->y = contents->allocation.y;
760 drawattrs->width = contents->allocation.width;
761 drawattrs->height = contents->allocation.height;
762 drawattrs->wclass = GDK_INPUT_OUTPUT;
763 drawattrs->visual = gtk_widget_get_visual(contents);
764 drawattrs->colormap = gtk_widget_get_colormap(contents);
765 drawattrs->window_type = GDK_WINDOW_CHILD;
766 some_parent = gtk_widget_get_parent_window(contents);
767 drawable = gdk_window_new(some_parent, drawattrs,
768 GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP);
769 gdk_window_set_icon(some_parent, NULL, logo_mini_pixmap, logo_mini_mask);
770 style = gtk_widget_get_style(contents);
771 gc = gdk_gc_new(drawable);
772 gdk_window_set_background(drawable, &(style->white));
773 gdk_gc_set_foreground(gc, &(style->black));
774 gdk_gc_set_background(gc, &(style->white));
775 gdk_window_show(drawable);
776
777 /* store */
778 retval->ww = w;
779 retval->contents = contents; retval->location = url2;
780 retval->info = info1; retval->message = info2;
781 retval->drawable = drawable; retval->gc = gc;
782
783 /* connect signal handlers */
784 connect_window(w, strGtkDestroy, window_handle_destroy, retval);
785 connect_window(w, strGtkDelete, window_handle_delete, retval);
786 connect_widget(contents, strGtkConfigure, window_handle_configure, retval);
787 connect_widget(contents, strGtkKey, graphics_propagate_event, NULL);
788 connect_widget(contents, strGtkButton, graphics_cm, retval);
789 }
790 #endif
791
792
793 /** Browser window operations interface */
794
wop_browser_create(tWindow * window)795 static void wop_browser_create(tWindow* window)
796 { window->wksd = memory_allocate(sizeof(tWkBrowserData), mapWksd);
797 #if TGC_IS_GRAPHICS
798 #endif
799 }
800
wop_browser_remove(tWindow * window)801 static void wop_browser_remove(tWindow* window)
802 { const tWkBrowserData* wksd = (tWkBrowserData*) (window->wksd);
803 const tWindowView* view = wksd->first_view;
804 if (view != NULL) deallocate_windowviewlist(view);
805 #if TGC_IS_GRAPHICS
806 #endif
807 memory_deallocate(wksd);
808 }
809
wop_browser_redraw(const tWindow * window)810 static void wop_browser_redraw(const tWindow* window)
811 { const tWkBrowserData* wksd = (tWkBrowserData*) (window->wksd);
812 tWindowView* view = wksd->current_view;
813 tBrowserDocument* document = ( (view != NULL) ? (&(view->bd)) : NULL );
814 short i, minrow, maxrow;
815 #if CONFIG_DEBUG
816 sprint_safe(debugstrbuf, "wop_browser_redraw(): window=%p, view=%p, document=%p\n", window, view, document);
817 debugmsg(debugstrbuf);
818 #endif
819 if (document != NULL) document_display(document, wrtRedraw);
820 else if (window_contents_minmaxrow(window, &minrow, &maxrow))
821 { for (i = minrow; i <= maxrow; i++) { (void) move(i,0); (void) clrtoeol(); }
822 cu_display_title(window, _(strBracedNewWindow), maxrow + 1);
823 if (window == current_window_x) show_message(strEmpty, falsE);
824 }
825 must_reset_cursor();
826 }
827
wop_browser_is_precious(const tWindow * window)828 static tBoolean wop_browser_is_precious(const tWindow* window)
829 { const tWkBrowserData* wksd = (tWkBrowserData*) (window->wksd);
830 return(cond2boolean(wksd->first_view != NULL));
831 }
832
wop_browser_handle_pcc(tWindow * window,tProgramCommandCode pcc)833 static tBoolean wop_browser_handle_pcc(tWindow* window,tProgramCommandCode pcc)
834 { tBoolean retval = truE;
835 tWkBrowserData* wksd;
836 tWindowView* view;
837 switch (pcc)
838 {case pccViewBack:
839 wksd = (tWkBrowserData*) (window->wksd); view = wksd->current_view;
840 if ( (view != NULL) && (view->prev != NULL) )
841 { wksd->current_view = view->prev; window_redraw(window); }
842 break;
843 case pccViewForward:
844 wksd = (tWkBrowserData*) (window->wksd); view = wksd->current_view;
845 if ( (view != NULL) && (view->next != NULL) )
846 { wksd->current_view = view->next; window_redraw(window); }
847 break;
848 case pccDocumentReload: case pccDocumentReloadEnforced:
849 { tBrowserDocument* document;
850 tBoolean is_post;
851 wksd = (tWkBrowserData*) (window->wksd); view = wksd->current_view;
852 if (view == NULL) goto out;
853 document = &(view->bd); is_post = cond2boolean(document->flags &wvfPost);
854 lid.prrf = ( (pcc == pccDocumentReloadEnforced) ? prrfEnforcedReload :
855 prrfReload );
856 if (is_post) lid.prrf |= prrfPost;
857 if ( (!is_post) || (config.flags & cfDontConfirmRepost) )
858 wk_browser_reload(window);
859 else ask_yesno(_("Really repost form data?"), cgRepost, NULL);
860 }
861 break;
862 case pccDocumentEnforceSource:
863 { const tBrowserDocument* document = window_currdoc(window);
864 if ( (document != NULL) && (document->bddm != bddmSource) )
865 { wk_browser_prr(require_browser_window(), document->title,
866 prrfRedrawOne | prrfSource, NULL);
867 }
868 }
869 break;
870 case pccDocumentInfo:
871 #if DO_WK_INFO
872 wksd = (tWkBrowserData*) (window->wksd); view = wksd->current_view;
873 if (view != NULL) wk_browser_build_document_info(&(view->bd));
874 #else
875 fwdact(_("Finformation window"));
876 #endif
877 break;
878 default: retval = falsE; break; /* not handled here, try generic handler */
879 }
880 out:
881 return(retval);
882 }
883
wop_browser_find_currdoc(const tWindow * window)884 static tBrowserDocument* wop_browser_find_currdoc(const tWindow* window)
885 { const tWkBrowserData* wksd = (tWkBrowserData*) (window->wksd);
886 tWindowView* view = wksd->current_view;
887 return( (view != NULL) ? (&(view->bd)) : NULL );
888 }
889
wop_browser_get_info(tWindow * window,tBoolean * _is_error)890 static const char* wop_browser_get_info(tWindow* window,
891 /*@out@*/ tBoolean* _is_error)
892 { const tWkBrowserData* wksd = (tWkBrowserData*) (window->wksd);
893 const tWindowView* view = wksd->current_view;
894 const char* retval = ( (view != NULL) ? (view->bd.last_info) : NULL );
895 *_is_error = ( (retval != NULL) ? cond2boolean(*retval++ & 1) : falsE );
896 return(retval);
897 }
898
wop_browser_get_menu_entry(tWindow * window)899 static const char* wop_browser_get_menu_entry(tWindow* window)
900 { const tWkBrowserData* wksd = (tWkBrowserData*) (window->wksd);
901 const tWindowView* view = wksd->current_view;
902 const tBrowserDocument* document;
903 const tCantent* cantent;
904 const char* text;
905 if (view == NULL) { text = _(strBracedNewWindow); goto out; }
906 document = &(view->bd); cantent = document->cantent;
907 if ( (cantent != NULL) && ( (text = cantent->major_html_title) != NULL ) )
908 goto out;
909 if ( (text = document->minor_html_title) != NULL ) goto out;
910 if ( (text = document->title) != NULL ) goto out;
911 text = unconstify_or_(strUnknown); /* "should not happen" */
912 out:
913 return(text);
914 }
915
916 #if CONFIG_MENUS & MENUS_CONTEXT
wop_browser_setup_cm(tWindow * window,short * _x,short * _y,tActiveElementNumber _ae)917 static void wop_browser_setup_cm(tWindow* window, short* _x, short* _y,
918 tActiveElementNumber _ae)
919 { const tWkBrowserData* wksd = (tWkBrowserData*) (window->wksd);
920 const tWindowView* view = wksd->current_view;
921 if (view != NULL)
922 { const tBrowserDocument* document = &(view->bd);
923 const tResourceRequest* request = document->request;
924 const char* uri = ( (request != NULL) ? request->uri_data->uri : NULL );
925 short x, y;
926
927 /* ae-specific entries */
928 if (_ae != INVALID_AE)
929 { const tCantent* cantent = document->cantent;
930 const tActiveElementBase* aeb = cantent->aebase;
931 tActiveElementKind aek = ( (aeb != NULL) ? aeb[_ae].kind : aekUnknown );
932 const tActiveElementCoordinates* aec = find_visible_aec(document, _ae);
933 if ( (aec != NULL) && (document_line2row(document, aec->y, &y)) )
934 { x = aec->x1; y++; *_x = x; *_y = y; }
935 cm_add(strShowElementInfo, cm_handle_command_code, pccElementInfo);
936 if ( (aeb != NULL) && (aeb[_ae].flags & aefDisabled) )
937 cm_add(strEnableThisElement, cm_handle_command_code, pccElementEnable);
938 if (aek == aekLink)
939 { cm_add(strOpenLinkInNewWindow, cm_handle_command_code,
940 pccWindowNewFromElement);
941 #if CONFIG_EXTRA & EXTRA_DOWNLOAD
942 cm_add(strSaveLinkAs, cm_handle_command_code, pccDownloadFromElement);
943 #endif
944 }
945 else if (is_form_aek(aek))
946 { tHtmlFormNumber hfn = calc_hfn(cantent, _ae);
947 if (hfn != INVALID_HTML_FORM_NUMBER)
948 { cm_add(strSubmitThisForm, cm_handle_command_code, pccFormSubmit);
949 /* IMPLEMENTME: "Show Form Info" */
950 }
951 }
952 cm_add_separator();
953 }
954
955 /* general entries */
956 if (view->prev != NULL)
957 cm_add(strBack, cm_handle_command_code, pccViewBack);
958 if (view->next != NULL)
959 cm_add(strForward, cm_handle_command_code, pccViewForward);
960 if ( (uri != NULL) && (*uri != '\0') )
961 { cm_add(strReload, cm_handle_command_code, pccDocumentReload);
962 cm_add(strEnforcedReload, cm_handle_command_code,
963 pccDocumentReloadEnforced);
964 cm_add(strSaveAs, cm_handle_command_code, pccDocumentSave);
965 cm_add(strOpenInNewWindow, cm_handle_command_code,
966 pccWindowNewFromDocument);
967 #if 0
968 cm_add(strAddBookmark, cm_handle_command_code, pccBookmarkAdd);
969 #endif
970 }
971 cm_add(strSourceCode, cm_handle_command_code, pccDocumentEnforceSource);
972 cm_add_separator();
973 }
974 }
975 #endif /* #if CONFIG_MENUS & MENUS_CONTEXT */
976
977 #if CONFIG_SESSIONS
wop_browser_save_session(tWindow * window,int fd)978 static void wop_browser_save_session(tWindow* window, int fd)
979 { tWkBrowserData* wksd = (tWkBrowserData*) (window->wksd);
980 tWindowView *view = wksd->first_view, *currview = wksd->current_view;
981 tBoolean is_fuiw = truE; /* first URI in window? */
982 while (view != NULL)
983 { const tBrowserDocument* document = &(view->bd);
984 const tResourceRequest* request;
985 const tWindowViewFlags wvf = document->flags;
986 tBrowserDocumentDisplayMode bddm;
987 const char *uri, *html_title, *flagsptr, *linenumptr;
988 char* spfbuf;
989 tLinenumber linenum;
990 tBoolean is_currview;
991
992 if (wvf & wvfPost) goto nextview; /* can't handle this correctly */
993 is_currview = cond2boolean(view == currview); request = document->request;
994 if (request != NULL)
995 { const tResource* resource = request->resource;
996 if ( (resource != NULL) && ( (uri = resource->uri_data->uri) != NULL ) &&
997 (*uri != '\0') )
998 { goto write_uri; }
999 if ( ( (uri = request->uri_data->uri) != NULL ) && (*uri != '\0') )
1000 goto write_uri;
1001 }
1002 if ( ( (uri = document->title) != NULL ) && (*uri != '\0') )
1003 goto write_uri;
1004 goto nextview; /* no usable URI found */
1005
1006 write_uri:
1007 if (is_fuiw)
1008 { char* temp = winbuf + 2;
1009 #if TGC_IS_CURSES
1010 unsigned char num;
1011 for (num = 0; num < 2; num++)
1012 { if (window == visible_window_x[num])
1013 { psm(temp, 'v'); temp = bdp(temp); *temp++ = '0' + num; break; }
1014 }
1015 #endif
1016 *temp++ = '\n'; *temp = '\0'; my_write_str(fd, winbuf); is_fuiw = falsE;
1017 }
1018
1019 bddm = document->bddm;
1020 if ( (bddm != bddmAutodetect) || (is_currview) )
1021 { char* temp = bdp(flagsbuf);
1022 if (bddm == bddmSource) *temp++ = 's';
1023 else if (bddm == bddmHtml) *temp++ = 'h';
1024 if (is_currview) *temp++ = 'c';
1025 *temp = '\0';
1026 flagsptr = flagsbuf;
1027 }
1028 else flagsptr = strEmpty;
1029
1030 linenum = document->origin_y;
1031 if (linenum <= 0) linenumptr = strEmpty;
1032 else
1033 { sprint_safe(bdp(linenumbuf), strPercd, linenum); linenumptr = linenumbuf;
1034 }
1035
1036 html_title = ( (bddm == bddmSource) ? document->minor_html_title : NULL );
1037 if ( (html_title != NULL) && (*html_title == '\0') ) html_title = NULL;
1038
1039 my_spf(strbuf, STRBUF_SIZE, &spfbuf, "U:%s%s%s%s%s%s\n", flagsptr,
1040 linenumptr, urimarker, uri, ( (html_title != NULL) ? htmltitlemarker :
1041 strEmpty ), null2empty(html_title));
1042 my_write_str(fd, spfbuf); my_spf_cleanup(strbuf, spfbuf);
1043
1044 nextview: view = view->next;
1045 }
1046 }
1047 #endif /* #if CONFIG_SESSIONS */
1048
1049 #if CONFIG_DO_TEXTMODEMOUSE
wop_browser_handle_mouse(tWindow * window __cunused,tCoordinate x __cunused,tCoordinate y __cunused,int flags __cunused)1050 static void wop_browser_handle_mouse(tWindow* window __cunused, tCoordinate x
1051 __cunused, tCoordinate y __cunused, int flags __cunused)
1052 { /* IMPLEMENTME! */
1053 }
1054 #endif
1055
1056 static const tWindowSpec wk_browser_spec =
1057 { wop_browser_create, wop_browser_remove, wop_browser_redraw,
1058 wop_browser_is_precious, NULL, wop_browser_handle_pcc,
1059 wop_browser_find_currdoc, wop_browser_get_info, wop_browser_get_menu_entry,
1060 WSPEC_CM(wop_browser_setup_cm) WSPEC_SESSION(wop_browser_save_session)
1061 WSPEC_MOUSE(wop_browser_handle_mouse) 'B', 'B', wkBrowser, wsfNone
1062 };
1063
1064
1065 /** Browser window stuff */
1066
wk_browser_reload(tWindow * window)1067 static void wk_browser_reload(tWindow* window)
1068 { const tWkBrowserData* wksd = (tWkBrowserData*) (window->wksd);
1069 const tWindowView* view = wksd->current_view;
1070 const tBrowserDocument* document;
1071 const char* uri;
1072 tBoolean do_post;
1073 tPrrFlags prrf;
1074 if (view == NULL) return; /* "should not happen" */
1075 document = &(view->bd); uri = my_strdup(document->title);
1076 prrf = lid.prrf | prrfRedrawOne; do_post = cond2boolean(prrf & prrfPost);
1077 if (do_post)
1078 { const char* post = document->request->uri_data->post;
1079 sfbuf = my_strdup(null2empty(post));
1080 sfbuf_size = sfbuf_maxsize = strlen(sfbuf) + 1;
1081 prrf |= prrfUseSfbuf;
1082 }
1083 cut_windowviewlist(window);
1084 wk_browser_prr(window, uri, prrf, NULL); memory_deallocate(uri);
1085 }
1086
wk_browser_create(void)1087 static tWindow* wk_browser_create(void)
1088 { return(window_create(&wk_browser_spec)); /* just a frequently used wrapper */
1089 }
1090
1091
1092 /*** Window kind: information window */
1093
1094 #if DO_WK_INFO
1095
1096 typedef struct
1097 { tBrowserDocument document; /* exactly one document per window */
1098 const char *window_title, *message;
1099 tBoolean is_finalized, message_is_error;
1100 } tWkInfoData; /* for window->wksd */
1101
1102
1103 /** Information window document operations interface */
1104
wk_info_dop_find_coords(const tBrowserDocument * document,short * _x1,short * _y1,short * _x2,short * _y2)1105 static tBoolean wk_info_dop_find_coords(const tBrowserDocument* document,
1106 /*@out@*/ short* _x1, /*@out@*/ short* _y1, /*@out@*/ short* _x2,
1107 /*@out@*/ short* _y2)
1108 { const tWindow* window = (const tWindow*) (document->container);
1109 short minrow, maxrow;
1110 const tBoolean retval = window_contents_minmaxrow(window, &minrow, &maxrow);
1111 if (retval) { *_x1 = 0; *_y1 = minrow; *_x2 = COLS - 1; *_y2 = maxrow; }
1112 return(retval);
1113 }
1114
wk_info_dop_display_meta1(tBrowserDocument * document)1115 static void wk_info_dop_display_meta1(tBrowserDocument* document)
1116 {
1117 #if TGC_IS_CURSES
1118 const tWindow* window = (const tWindow*) (document->container);
1119 if (window == current_window_x)
1120 #endif
1121 { const tWkInfoData* wksd = (const tWkInfoData*) (window->wksd);
1122 const char* msg = wksd->message;
1123 show_message(null2empty(msg), wksd->message_is_error);
1124 }
1125 }
1126
wk_info_dop_display_meta2(tBrowserDocument * document)1127 static void wk_info_dop_display_meta2(tBrowserDocument* document)
1128 { short minrow, maxrow;
1129 if (document_minmaxrow(document, &minrow, &maxrow))
1130 { const tWindow* window = (const tWindow*) (document->container);
1131 const tWkInfoData* wksd = (const tWkInfoData*) (window->wksd);
1132 cu_display_title(window, wksd->window_title, maxrow + 1);
1133 }
1134 }
1135
1136 static const tBrowserDocumentOps wk_info_document_ops =
1137 { wk_info_dop_find_coords, wk_info_dop_display_meta1, wk_info_dop_display_meta2
1138 };
1139
1140
1141 /** Information window operations interface */
1142
wop_info_create(tWindow * window)1143 static void wop_info_create(tWindow* window)
1144 { tWkInfoData* wksd = window->wksd = memory_allocate(sizeof(tWkInfoData),
1145 mapWksd);
1146 tBrowserDocument* document = &(wksd->document);
1147 tCantent* cantent = cantent_create();
1148 document_init(document, &wk_info_document_ops, window, NULL);
1149 cantent_attach(document->cantent, cantent);
1150 }
1151
wop_info_remove(tWindow * window)1152 static void wop_info_remove(tWindow* window)
1153 { tWkInfoData* wksd = (tWkInfoData*) (window->wksd);
1154 document_tear(&(wksd->document)); __dealloc(wksd->window_title);
1155 memory_deallocate(wksd);
1156 }
1157
wop_info_redraw(const tWindow * window)1158 static void wop_info_redraw(const tWindow* window)
1159 { tWkInfoData* wksd = (tWkInfoData*) (window->wksd);
1160 tBrowserDocument* document = &(wksd->document);
1161 #if CONFIG_DEBUG
1162 sprint_safe(debugstrbuf, "wop_info_redraw(): window=%p\n", window);
1163 debugmsg(debugstrbuf);
1164 #endif
1165 document_display(document, wrtRedraw);
1166 }
1167
wop_info_find_currdoc(const tWindow * window)1168 static tBrowserDocument* wop_info_find_currdoc(const tWindow* window)
1169 { tWkInfoData* wksd = (tWkInfoData*) (window->wksd);
1170 tBrowserDocument* document = &(wksd->document);
1171 return(document);
1172 }
1173
wop_info_get_info(tWindow * window,tBoolean * _is_error)1174 static const char* wop_info_get_info(tWindow* window,
1175 /*@out@*/ tBoolean* _is_error)
1176 { const tWkInfoData* wksd = (tWkInfoData*) (window->wksd);
1177 const char* retval = wksd->message; *_is_error = wksd->message_is_error;
1178 return(retval);
1179 }
1180
wop_info_get_menu_entry(tWindow * window)1181 static const char* wop_info_get_menu_entry(tWindow* window)
1182 { const tWkInfoData* wksd = (const tWkInfoData*) (window->wksd);
1183 return(wksd->window_title);
1184 }
1185
1186 static const tWindowSpec wk_info_spec =
1187 { wop_info_create, wop_info_remove, wop_info_redraw, NULL, NULL, NULL,
1188 wop_info_find_currdoc, wop_info_get_info, wop_info_get_menu_entry,
1189 WSPEC_CM(NULL) WSPEC_MOUSE(NULL) WSPEC_SESSION(NULL) 'I', 'I', wkInfo,
1190 wsfNone /* IMPLEMENTME: cm etc.! */
1191 };
1192
1193
1194 /** Information window stuff */
1195
wk_info_create(const char * title,tBrowserDocumentDisplayMode bddm,tBrowserDocument ** _document)1196 static tWindow* wk_info_create(const char* title,
1197 tBrowserDocumentDisplayMode bddm, /*@out@*/ tBrowserDocument** _document)
1198 { tWindow* retval = window_create(&wk_info_spec);
1199 tWkInfoData* wksd = (tWkInfoData*) (retval->wksd);
1200 tBrowserDocument* document = &(wksd->document);
1201 wksd->window_title = title; document->bddm = bddm;
1202 if (bddm == bddmHtml) cantent_collect_title(document->cantent, title);
1203 if (_document != NULL) *_document = document;
1204 return(retval);
1205 }
1206
wk_info_collect(tWindow * window,const char * str)1207 static void wk_info_collect(tWindow* window, const char* str)
1208 { tWkInfoData* wksd = (tWkInfoData*) (window->wksd);
1209 cantent_collect_str(wksd->document.cantent, str);
1210 if (wksd->is_finalized) window_redraw(window);
1211 }
1212
wk_info_finalize(tWindow * window)1213 static void wk_info_finalize(tWindow* window)
1214 /* The ("initial amount" of) information which should be displayed in this
1215 window has been collected, now it is displayed for the first time. */
1216 { tWkInfoData* wksd = (tWkInfoData*) (window->wksd);
1217 wksd->is_finalized = truE; window_redraw_all();
1218 }
1219
wk_info_set_message(tWindow * window,const char * msg,tBoolean is_error)1220 static void wk_info_set_message(tWindow* window, const char* msg,
1221 tBoolean is_error)
1222 { tWkInfoData* wksd = (tWkInfoData*) (window->wksd);
1223 wksd->message = msg; wksd->message_is_error = is_error;
1224 }
1225
1226 #endif /* #if DO_WK_INFO */
1227
1228
1229 /*** Window kind: custom connection window */
1230
1231 #if DO_WK_CUSTOM_CONN
1232
1233 #endif /* #if DO_WK_CUSTOM_CONN */
1234
1235
1236 /*** Window kind: built-in text editor */
1237
1238 #if DO_WK_EDITOR
1239 #endif /* #if DO_WK_EDITOR */
1240