/* * File: plain.c * * Copyright (C) 1997 Raph Levien * Copyright (C) 1999 James McCollough * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ /* * Module for decoding a text/plain object into a gtk_page widget. */ #include /* for memcpy and memmove */ #include /* for rint() */ #include #include "prefs.h" #include "dw_page.h" #include "cache.h" #include "browser.h" #include "web.h" #include "interface.h" #include "progressbar.h" #include "misc.h" #include "history.h" #include "nav.h" #include "menu.h" typedef struct _DilloPlain { DwWidget *dw; size_t Start_Ofs; /* Offset of where to start reading next */ DwStyle *style; BrowserWindow *bw; gint state; } DilloPlain; /* FSM states */ enum { ST_SeekingEol, ST_Eol, ST_Eof }; /* * Forward declarations */ static void Plain_write(DilloPlain *plain, void *Buf, guint BufSize, gint Eof); static void Plain_callback(int Op, CacheClient_t *Client); /* exported function */ DwWidget* a_Plain_text(const char *type, void *P, CA_Callback_t *Call, void **Data); /* * Popup the page menu ("button_press_event" callback of the viewport) */ static int Plain_page_menu(GtkWidget *viewport, GdkEventButton *event, BrowserWindow *bw) { if (event->button == 3) { a_Menu_popup_set_url(bw, a_History_get_url(NAV_TOP(bw))); gtk_menu_popup(GTK_MENU(bw->menu_popup.over_page), NULL, NULL, NULL, NULL, event->button, event->time); return TRUE; } else return FALSE; } /* * Create and initialize a new DilloPlain structure. */ static DilloPlain *Plain_new(BrowserWindow *bw) { DilloPlain *plain; DwPage *page; DwStyle style_attrs; DwStyleFont font_attrs; plain = g_new(DilloPlain, 1); plain->state = ST_SeekingEol; plain->Start_Ofs = 0; plain->bw = bw; plain->dw = a_Dw_page_new(); page = (DwPage *) plain->dw; /* Create the font and attribute for the page. */ font_attrs.name = prefs.fw_fontname; font_attrs.size = rint(12.0 * prefs.font_factor); font_attrs.weight = 400; font_attrs.style = DW_STYLE_FONT_STYLE_NORMAL; a_Dw_style_init_values (&style_attrs, plain->bw->main_window->window); style_attrs.font = a_Dw_style_font_new (&font_attrs); style_attrs.color = a_Dw_style_color_new (prefs.text_color, plain->bw->main_window->window); plain->style = a_Dw_style_new (&style_attrs, plain->bw->main_window->window); /* a_Dw_widget_set_style (plain->dw, plain->style); */ /* The context menu */ gtk_signal_connect_while_alive (GTK_OBJECT(GTK_BIN(plain->bw->docwin)->child),"button_press_event", GTK_SIGNAL_FUNC(Plain_page_menu), (gpointer)plain->bw, GTK_OBJECT (page)); return plain; } /* * Set callback function and callback data for "text/" MIME major-type. */ DwWidget* a_Plain_text(const char *type, void *P, CA_Callback_t *Call, void **Data) { DilloWeb *web = P; DilloPlain *plain = Plain_new(web->bw); *Call = (CA_Callback_t)Plain_callback; *Data = (void*)plain; return plain->dw; } /* * This function is a cache client */ static void Plain_callback(int Op, CacheClient_t *Client) { DilloPlain *plain= Client->CbData; DwPage *page = (DwPage *)plain->dw; if ( Op ) { /* Do the last line: */ if (plain->Start_Ofs < Client->BufSize) Plain_write(plain, Client->Buf, Client->BufSize, 1); /* remove this client from our active list */ a_Interface_close_client(plain->bw, Client->Key); /* set progress bar insensitive */ a_Progressbar_update(plain->bw->progress, NULL, 0); a_Dw_style_unref (plain->style); g_free(plain); } else { Plain_write(plain, Client->Buf, Client->BufSize, 0); } a_Dw_page_flush(page); } /* * Here we parse plain text and put it into the page structure. * (This function is called by Plain_callback whenever there's new data) */ static void Plain_write(DilloPlain *plain, void *Buf, guint BufSize, gint Eof) { DwPage *page = (DwPage *)plain->dw; char *Start; char *data; guint i, len, MaxBytes; Start = (char*)Buf + plain->Start_Ofs; MaxBytes = BufSize - plain->Start_Ofs; i = len = 0; while ( i < MaxBytes ) { switch ( plain->state ) { case ST_SeekingEol: if ( Start[i] == '\n' || Start[i] == '\r' ) plain->state = ST_Eol; else { ++i; ++len; } break; case ST_Eol: data = g_strndup(Start + i - len, len); a_Dw_page_add_text(page, a_Misc_expand_tabs(data), plain->style); g_free(data); a_Dw_page_add_parbreak(page, 0, plain->style); if ( Start[i] == '\r' && Start[i + 1] == '\n' ) ++i; if ( i < MaxBytes ) ++i; plain->state = ST_SeekingEol; len = 0; break; } } plain->Start_Ofs += i - len; if ( Eof && len ) { data = g_strndup(Start + i - len, len); a_Dw_page_add_text(page, a_Misc_expand_tabs(data), plain->style); g_free(data); a_Dw_page_add_parbreak(page, 0, plain->style); plain->Start_Ofs += len; } if ( plain->bw ) { gchar completestr[32]; g_snprintf( completestr, 32, "%s%.1f Kb", PBAR_PSTR(prefs.panel_size == 1), (float)plain->Start_Ofs/1024); a_Progressbar_update(plain->bw->progress, completestr, 1); } }