/*
- * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
+ * Claws Mail -- A GTK based, lightweight, and fast e-mail client
* Copyright(C) 2019 the Claws Mail Team
*
* This program is free software; you can redistribute it and/or modify
const gchar *prefs_common_get_uri_cmd(void);
}
-char master_css[] = {
-#include "css.inc"
-};
-
-static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
+static gboolean draw_cb(GtkWidget *widget, cairo_t *cr,
gpointer user_data);
static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event,
gpointer user_data);
{
GtkWidget *item;
+ m_force_render = false;
+ m_blank = false;
+
/* scrolled window */
m_scrolled_window = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(m_scrolled_window),
/* drawing area */
m_drawing_area = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(m_viewport), m_drawing_area);
- g_signal_connect(m_drawing_area, "expose-event",
- G_CALLBACK(expose_event_cb), this);
+ g_signal_connect(m_drawing_area, "draw",
+ G_CALLBACK(draw_cb), this);
g_signal_connect(m_drawing_area, "motion_notify_event",
G_CALLBACK(motion_notify_event), this);
g_signal_connect(m_drawing_area, "button_press_event",
m_html = NULL;
m_rendered_width = 0;
- m_context.load_master_stylesheet(master_css);
m_font_name = NULL;
m_font_size = 0;
m_showing_url = FALSE;
+ m_cairo_context = NULL;
+
gtk_widget_set_events(m_drawing_area,
GDK_BUTTON_RELEASE_MASK
| GDK_BUTTON_PRESS_MASK
return m_scrolled_window;
}
-void lh_widget::set_caption(const litehtml::tchar_t* caption)
+void lh_widget::set_caption(const char *caption)
{
debug_print("lh_widget set_caption\n");
return;
}
-void lh_widget::set_base_url(const litehtml::tchar_t* base_url)
+void lh_widget::set_base_url(const char *base_url)
{
debug_print("lh_widget set_base_url '%s'\n",
(base_url ? base_url : "(null)"));
- m_base_url = base_url;
+ if (base_url)
+ m_base_url = base_url;
+ else
+ m_base_url.clear();
+
return;
}
-void lh_widget::on_anchor_click(const litehtml::tchar_t* url, const litehtml::element::ptr& el)
+void lh_widget::on_anchor_click(const char *url, const litehtml::element::ptr& el)
{
debug_print("lh_widget on_anchor_click. url -> %s\n", url);
return;
}
-void lh_widget::import_css(litehtml::tstring& text, const litehtml::tstring& url, litehtml::tstring& baseurl)
+void lh_widget::import_css(litehtml::string& text, const litehtml::string& url, litehtml::string& baseurl)
{
- debug_print("lh_widget import_css\n");
- baseurl = master_css;
+ debug_print("lh_widget import_css. url=\"%s\" baseurl=\"%s\"\n", url.c_str(), baseurl.c_str());
}
void lh_widget::get_client_rect(litehtml::position& client) const
update_font();
lh_widget_statusbar_push("Loading HTML part ...");
- m_html = litehtml::document::createFromString(contents, this, &m_context);
+ m_html = litehtml::document::createFromString(contents, this);
m_rendered_width = 0;
if (m_html != NULL) {
debug_print("lh_widget::open_html created document\n");
adj = gtk_scrolled_window_get_vadjustment(
GTK_SCROLLED_WINDOW(m_scrolled_window));
gtk_adjustment_set_value(adj, 0.0);
- redraw(false);
+ m_blank = false;
}
lh_widget_statusbar_pop();
}
+void lh_widget::rerender()
+{
+ m_force_render = true;
+ gtk_widget_queue_draw(m_drawing_area);
+}
+
void lh_widget::draw(cairo_t *cr)
{
double x1, x2, y1, y2;
m_html->draw((litehtml::uint_ptr)cr, 0, 0, &pos);
}
-void lh_widget::redraw(gboolean force_render)
+void lh_widget::redraw()
{
GtkAllocation rect;
gint width;
GdkWindow *gdkwin;
cairo_t *cr;
-
- paint_white();
+ cairo_region_t *creg;
+ GdkDrawingContext *gdkctx;
+ gboolean destroy = FALSE;
if (m_html == NULL)
return;
/* Get width of the viewport. */
- gdkwin = gtk_viewport_get_view_window(GTK_VIEWPORT(m_viewport));
- width = gdk_window_get_width(gdkwin);
- m_height = gdk_window_get_height(gdkwin);
+ gtk_widget_get_allocation(GTK_WIDGET(m_viewport), &rect);
+ width = rect.width;
+ m_height = rect.height;
/* If the available width has changed, rerender the HTML content. */
- if (m_rendered_width != width || force_render) {
+ if (m_rendered_width != width || std::atomic_exchange(&m_force_render, false)) {
debug_print("lh_widget::redraw: width changed: %d != %d\n",
m_rendered_width, width);
m_html->width(), m_html->height());
}
- /* Paint the rendered HTML. */
- gdkwin = gtk_widget_get_window(m_drawing_area);
- if (gdkwin == NULL) {
- g_warning("lh_widget::redraw: No GdkWindow to draw on!");
- return;
+ /* Use provided cairo context, if any. Otherwise create our own. */
+ if (m_cairo_context != NULL) {
+ cr = m_cairo_context;
+ } else {
+ gdkwin = gtk_widget_get_window(m_drawing_area);
+ if (gdkwin == NULL) {
+ g_warning("lh_widget::redraw: No GdkWindow to draw on!");
+ return;
+ }
+ creg = cairo_region_create_rectangle(&rect);
+ gdkctx = gdk_window_begin_draw_frame(gdkwin, creg);
+ cr = gdk_drawing_context_get_cairo_context(gdkctx);
+ destroy = TRUE;
}
- cr = gdk_cairo_create(GDK_DRAWABLE(gdkwin));
- draw(cr);
-
- cairo_destroy(cr);
-}
-void lh_widget::paint_white()
-{
- GdkWindow *gdkwin = gtk_widget_get_window(m_drawing_area);
- if (gdkwin == NULL) {
- g_warning("lh_widget::clear: No GdkWindow to draw on!");
- return;
+ if(!std::atomic_exchange(&m_blank, false)) {
+ draw(cr);
+ } else {
+ cairo_rectangle(cr, rect.x, rect.y, rect.width, rect.height);
+ cairo_set_source_rgb(cr, 255, 255, 255);
+ cairo_fill(cr);
}
- cairo_t *cr = gdk_cairo_create(GDK_DRAWABLE(gdkwin));
- /* Paint white background. */
- gint width, height;
- gdk_drawable_get_size(gdkwin, &width, &height);
- cairo_rectangle(cr, 0, 0, width, height);
- cairo_set_source_rgb(cr, 255, 255, 255);
- cairo_fill(cr);
-
- cairo_destroy(cr);
+ /* Only destroy the used cairo context if we created it earlier. */
+ if (destroy) {
+ gdk_window_end_draw_frame(gdkwin, gdkctx);
+ cairo_region_destroy(creg);
+ }
}
+
void lh_widget::clear()
{
m_html = nullptr;
- paint_white();
+ m_blank = true;
m_rendered_width = 0;
m_base_url.clear();
m_clicked_url.clear();
}
-void lh_widget::set_cursor(const litehtml::tchar_t* cursor)
+void lh_widget::set_cursor(const char *cursor)
{
- litehtml::element::ptr over_el = m_html->over_element();
- gint x, y;
+ litehtml::element::const_ptr over_el = m_html->get_over_element();
if (m_showing_url &&
(over_el == NULL || over_el != m_over_element)) {
}
}
-void lh_widget::update_cursor(const litehtml::tchar_t* cursor)
+void lh_widget::update_cursor(const char *cursor)
{
GdkCursorType cursType = GDK_ARROW;
- const litehtml::tchar_t *href = get_href_at(m_over_element);
+ const char *href = get_href_at(m_over_element);
/* If there is a href, and litehtml is okay with showing a pointer
* cursor ("pointer" or "auto"), set it, otherwise keep the
if (cursType == GDK_ARROW) {
gdk_window_set_cursor(gtk_widget_get_window(m_drawing_area), NULL);
} else {
- gdk_window_set_cursor(gtk_widget_get_window(m_drawing_area), gdk_cursor_new(cursType));
+ gdk_window_set_cursor(gtk_widget_get_window(m_drawing_area),
+ gdk_cursor_new_for_display(gtk_widget_get_display(m_drawing_area),
+ cursType));
}
/* If there is a href, show it in statusbar */
}
}
-const litehtml::tchar_t *lh_widget::get_href_at(litehtml::element::ptr element) const
+const char *lh_widget::get_href_at(litehtml::element::const_ptr element)
{
- litehtml::element::ptr el;
+ litehtml::element::const_ptr el;
if (element == NULL)
return NULL;
/* At this point, over_el is pointing at an anchor tag, so let's
* grab its href attribute. */
- return el->get_attr(_t("href"));
-}
-
-const litehtml::tchar_t *lh_widget::get_href_at(const gint x, const gint y) const
-{
- litehtml::element::ptr over_el, el;
-
- if (m_html == NULL)
- return NULL;
-
- over_el = m_html->root()->get_element_by_point(x, y, x, y);
- if (over_el == NULL)
- return NULL;
-
- return get_href_at(over_el);
+ return el->get_attr("href");
}
void lh_widget::print()
gtk_widget_realize(GTK_WIDGET(m_drawing_area));
}
-void lh_widget::popup_context_menu(const litehtml::tchar_t *url,
+void lh_widget::popup_context_menu(const char *url,
GdkEventButton *event)
{
cm_return_if_fail(url != NULL);
m_clicked_url = url;
gtk_widget_show_all(m_context_menu);
- gtk_menu_popup(GTK_MENU(m_context_menu), NULL, NULL, NULL, NULL,
- event->button, event->time);
+ gtk_menu_popup_at_pointer(GTK_MENU(m_context_menu), (GdkEvent *)event);
}
void lh_widget::update_font()
debug_print("Font set to '%s', size %d\n", m_font_name, m_font_size);
}
-const litehtml::tstring lh_widget::fullurl(const litehtml::tchar_t *url) const
+const litehtml::string lh_widget::fullurl(const char *url) const
{
if (*url == '#' && !m_base_url.empty())
return m_base_url + url;
- return _t(url);
+ return url;
}
void lh_widget::set_partinfo(MimeInfo *partinfo)
m_partinfo = partinfo;
}
-GdkPixbuf *lh_widget::get_local_image(const litehtml::tstring url) const
+GdkPixbuf *lh_widget::get_local_image(const litehtml::string url) const
{
GdkPixbuf *pixbuf;
const gchar *name;
pixbuf = procmime_get_part_as_pixbuf(p, &error);
if (error != NULL) {
- g_warning("Couldn't load image: %s\n", error->message);
+ g_warning("couldn't load image: %s", error->message);
g_error_free(error);
return NULL;
}
return NULL;
}
+void lh_widget::set_cairo_context(cairo_t *cr)
+{
+ m_cairo_context = cr;
+}
+
+
////////////////////////////////////////////////
-static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
+static gboolean draw_cb(GtkWidget *widget, cairo_t *cr,
gpointer user_data)
{
lh_widget *w = (lh_widget *)user_data;
- w->redraw(false);
+ w->set_cairo_context(cr);
+ w->redraw();
+ w->set_cairo_context(NULL);
return FALSE;
}
lh_widget *w = (lh_widget *)user_data;
if (w->m_html == NULL)
- return false;
+ return FALSE;
//debug_print("lh_widget on_button_press_event\n");
if (event->type == GDK_2BUTTON_PRESS ||
event->type == GDK_3BUTTON_PRESS)
- return true;
+ return TRUE;
/* Right-click */
if (event->button == 3) {
- const litehtml::tchar_t *url = w->get_href_at((gint)event->x, (gint)event->y);
+ const char *url = w->get_href_at(w->m_html->get_over_element());
if (url != NULL)
w->popup_context_menu(url, event);
- return true;
+ return TRUE;
}
if(w->m_html->on_lbutton_down((int) event->x, (int) event->y,
}
}
- return true;
+ return TRUE;
}
static gboolean motion_notify_event(GtkWidget *widget, GdkEventButton *event,
}
}
- return true;
+ return TRUE;
}
static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event,
{
litehtml::position::vector redraw_boxes;
lh_widget *w = (lh_widget *)user_data;
- GError* error = NULL;
if (w->m_html == NULL)
- return false;
+ return FALSE;
//debug_print("lh_widget on_button_release_event\n");
if (event->type == GDK_2BUTTON_PRESS ||
event->type == GDK_3BUTTON_PRESS)
- return true;
+ return TRUE;
/* Right-click */
if (event->button == 3)
- return true;
+ return TRUE;
w->m_clicked_url.clear();
open_uri(w->m_clicked_url.c_str(), prefs_common_get_uri_cmd());
}
- return true;
+ return TRUE;
}
static void open_link_cb(GtkMenuItem *item, gpointer user_data)