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