From 5343752c353a5abbaaef2a342614b32b7f0e0e8c Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Sat, 07 Apr 2007 11:17:36 +0000 Subject: Make browser a modules inside sugar library --- (limited to 'browser') diff --git a/browser/GeckoContentHandler.cpp b/browser/GeckoContentHandler.cpp new file mode 100644 index 0000000..8b6c9fb --- /dev/null +++ b/browser/GeckoContentHandler.cpp @@ -0,0 +1,142 @@ +#include +#include +#include +#include +#include + +#include + +#include "GeckoContentHandler.h" + +class GeckoContentHandler : public nsIHelperAppLauncherDialog +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIHELPERAPPLAUNCHERDIALOG + + GeckoContentHandler(); + virtual ~GeckoContentHandler(); +}; + +GeckoContentHandler::GeckoContentHandler() +{ + +} + +GeckoContentHandler::~GeckoContentHandler() +{ + +} + +NS_IMPL_ISUPPORTS1(GeckoContentHandler, nsIHelperAppLauncherDialog) + +NS_IMETHODIMP +GeckoContentHandler::Show (nsIHelperAppLauncher *aLauncher, + nsISupports *aContext, + PRUint32 aReason) +{ + aLauncher->SaveToDisk(NULL, PR_FALSE); + + return NS_OK; +} + +#include +NS_IMETHODIMP +GeckoContentHandler::PromptForSaveToFile (nsIHelperAppLauncher *aLauncher, + nsISupports *aWindowContext, + const PRUnichar *aDefaultFile, + const PRUnichar *aSuggestedFileExtension, + nsILocalFile **_retval) +{ + char *filename = NULL; + nsCString defaultFile; + + NS_UTF16ToCString(nsString(aDefaultFile), NS_CSTRING_ENCODING_UTF8, defaultFile); + + nsCOMPtr destFile(do_CreateInstance("@mozilla.org/file/local;1")); + NS_ENSURE_TRUE(destFile, NS_ERROR_FAILURE); + + const char * suggested = defaultFile.get(); + if (strlen(suggested) > 0) { + filename = g_build_path("/", g_get_tmp_dir (), suggested, NULL); + } else { + filename = tempnam(NULL, NULL); + } + + if (filename == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + destFile->InitWithNativePath(nsCString(filename)); + g_free(filename); + + NS_IF_ADDREF(*_retval = destFile); + return NS_OK; +} + +//***************************************************************************** +// GeckoContentHandlerFactory +//***************************************************************************** + +class GeckoContentHandlerFactory : public nsIFactory { +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIFACTORY + + GeckoContentHandlerFactory(); + virtual ~GeckoContentHandlerFactory(); +}; + +//***************************************************************************** + +NS_IMPL_ISUPPORTS1(GeckoContentHandlerFactory, nsIFactory) + +GeckoContentHandlerFactory::GeckoContentHandlerFactory() { +} + +GeckoContentHandlerFactory::~GeckoContentHandlerFactory() { +} + +NS_IMETHODIMP +GeckoContentHandlerFactory::CreateInstance(nsISupports *aOuter, + const nsIID & aIID, + void **aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + + *aResult = NULL; + GeckoContentHandler *inst = new GeckoContentHandler; + if (!inst) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = inst->QueryInterface(aIID, aResult); + if (rv != NS_OK) { + // We didn't get the right interface, so clean up + delete inst; + } + + return rv; +} + +NS_IMETHODIMP +GeckoContentHandlerFactory::LockFactory(PRBool lock) +{ + return NS_OK; +} + +//***************************************************************************** + +nsresult +NS_NewGeckoContentHandlerFactory(nsIFactory** aFactory) +{ + NS_ENSURE_ARG_POINTER(aFactory); + *aFactory = nsnull; + + GeckoContentHandlerFactory *result = new GeckoContentHandlerFactory; + if (!result) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(result); + *aFactory = result; + + return NS_OK; +} diff --git a/browser/GeckoContentHandler.h b/browser/GeckoContentHandler.h new file mode 100644 index 0000000..103166c --- /dev/null +++ b/browser/GeckoContentHandler.h @@ -0,0 +1,19 @@ +#ifndef __GECKO_CONTENT_HANDLER_H__ +#define __GECKO_CONTENT_HANDLER_H__ + +#include +#include + +#define GECKOCONTENTHANDLER_CID \ +{ /* 2321843e-6377-11db-967b-00e08161165f */ \ + 0x2321843e, \ + 0x6377, \ + 0x11db, \ + {0x96, 0x7b, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f} \ +} + +class nsIFactory; + +extern "C" NS_EXPORT nsresult NS_NewGeckoContentHandlerFactory(nsIFactory** aFactory); + +#endif /* __GECKO_CONTENT_HANDLER_H */ diff --git a/browser/GeckoDownload.cpp b/browser/GeckoDownload.cpp new file mode 100644 index 0000000..6f099bd --- /dev/null +++ b/browser/GeckoDownload.cpp @@ -0,0 +1,268 @@ +#include "config.h" + +#include +#include +#include +#include +#include + +#include "sugar-download-manager.h" + +#include "GeckoDownload.h" + +#define APPLICATION_OCTET_STREAM "application/octet-stream" + +class GeckoDownload : public nsITransfer +{ +public: + GeckoDownload(); + virtual ~GeckoDownload(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIWEBPROGRESSLISTENER + NS_DECL_NSIWEBPROGRESSLISTENER2 + NS_DECL_NSITRANSFER + +protected: + nsIURI *mSource; + nsCString mTargetFileName; + nsIMIMEInfo *mMIMEInfo; + nsILocalFile *mTempFile; +}; + +GeckoDownload::GeckoDownload () +{ +} + +GeckoDownload::~GeckoDownload () +{ +} + +NS_IMPL_ISUPPORTS3 (GeckoDownload, + nsIWebProgressListener, + nsIWebProgressListener2, + nsITransfer) + +NS_IMETHODIMP +GeckoDownload::Init (nsIURI *aSource, + nsIURI *aTarget, + const nsAString &aDisplayName, + nsIMIMEInfo *aMIMEInfo, + PRTime aStartTime, + nsILocalFile *aTempFile, + nsICancelable *aCancelable) +{ + mSource = aSource; + mMIMEInfo = aMIMEInfo; + mTempFile = aTempFile; + + nsresult rv; + + nsCOMPtr fileURL = do_QueryInterface(aTarget); + NS_ENSURE_TRUE(fileURL, NS_ERROR_FAILURE); + + nsCOMPtr file; + rv = fileURL->GetFile(getter_AddRefs(file)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + + file->GetNativePath (mTargetFileName); + + return NS_OK; +} + +NS_IMETHODIMP +GeckoDownload::OnStateChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRUint32 aStateFlags, + nsresult aStatus) +{ + SugarDownloadManager *download_manager = sugar_get_download_manager(); + + if(aStateFlags == STATE_START) { + + nsCString url; + nsCString mimeType; + + mMIMEInfo->GetMIMEType(mimeType); + mSource->GetSpec(url); + +#ifdef HAVE_GECKO_1_9 + /* If the file is application/octet-stream, look up a better mime type + from the extension. */ + if(mimeType.Equals(APPLICATION_OCTET_STREAM)) { + nsresult rv; + nsCOMPtr mimeService( + do_GetService("@mozilla.org/mime;1", &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + const char *fileExt = strrchr(mTargetFileName.get(), '.'); + if(fileExt) { + nsCString contentType; + + mimeService->GetTypeFromExtension(nsCString(fileExt), + contentType); + if(!contentType.IsEmpty()) { + mimeType = contentType; + } + } + } +#endif + + sugar_download_manager_download_started(download_manager, + url.get(), + mimeType.get(), + mTargetFileName.get()); + + } else if(aStateFlags == STATE_STOP) { + + if(NS_SUCCEEDED(aStatus)) { + sugar_download_manager_download_completed(download_manager, + mTargetFileName.get()); + } else { + sugar_download_manager_download_cancelled(download_manager, + mTargetFileName.get()); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +GeckoDownload::OnProgressChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRInt32 aCurSelfProgress, + PRInt32 aMaxSelfProgress, + PRInt32 aCurTotalProgress, + PRInt32 aMaxTotalProgress) +{ + return OnProgressChange64 (aWebProgress, + aRequest, + aCurSelfProgress, + aMaxSelfProgress, + aCurTotalProgress, + aMaxTotalProgress); +} + +NS_IMETHODIMP +GeckoDownload::OnProgressChange64 (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRInt64 aCurSelfProgress, + PRInt64 aMaxSelfProgress, + PRInt64 aCurTotalProgress, + PRInt64 aMaxTotalProgress) +{ + SugarDownloadManager *download_manager = sugar_get_download_manager (); + PRInt32 percentComplete = + (PRInt32)(((float)aCurSelfProgress / (float)aMaxSelfProgress) * 100.0); + + sugar_download_manager_update_progress (download_manager, + mTargetFileName.get (), + percentComplete); + + return NS_OK; +} + +NS_IMETHODIMP +GeckoDownload::OnLocationChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + nsIURI *location) +{ + return NS_OK; +} + +NS_IMETHODIMP +GeckoDownload::OnStatusChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + nsresult aStatus, + const PRUnichar *aMessage) +{ + return NS_OK; +} + +NS_IMETHODIMP +GeckoDownload::OnSecurityChange (nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRUint32 state) +{ + return NS_OK; +} + +#ifdef HAVE_GECKO_1_9 + +NS_IMETHODIMP +GeckoDownload::OnRefreshAttempted (nsIWebProgress *aWebProgress, + nsIURI *aRefreshURI, + PRInt32 aMillis, + PRBool aSameURI, + PRBool *_retval) +{ + return NS_OK; +} + +#endif + +//***************************************************************************** +// GeckoDownloadFactory +//***************************************************************************** + +class GeckoDownloadFactory : public nsIFactory { +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIFACTORY + + GeckoDownloadFactory(); + virtual ~GeckoDownloadFactory(); +}; + +//***************************************************************************** + +NS_IMPL_ISUPPORTS1(GeckoDownloadFactory, nsIFactory) + +GeckoDownloadFactory::GeckoDownloadFactory() { +} + +GeckoDownloadFactory::~GeckoDownloadFactory() { +} + +NS_IMETHODIMP +GeckoDownloadFactory::CreateInstance(nsISupports *aOuter, const nsIID & aIID, void **aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + + *aResult = NULL; + GeckoDownload *inst = new GeckoDownload; + if (!inst) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = inst->QueryInterface(aIID, aResult); + if (rv != NS_OK) { + // We didn't get the right interface, so clean up + delete inst; + } + + return rv; +} + +NS_IMETHODIMP +GeckoDownloadFactory::LockFactory(PRBool lock) +{ + return NS_OK; +} + +//***************************************************************************** + +nsresult +NS_NewGeckoDownloadFactory(nsIFactory** aFactory) +{ + NS_ENSURE_ARG_POINTER(aFactory); + *aFactory = nsnull; + + GeckoDownloadFactory *result = new GeckoDownloadFactory; + if (!result) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(result); + *aFactory = result; + + return NS_OK; +} diff --git a/browser/GeckoDownload.h b/browser/GeckoDownload.h new file mode 100644 index 0000000..dd788f0 --- /dev/null +++ b/browser/GeckoDownload.h @@ -0,0 +1,25 @@ +#ifndef __GECKO_DOWNLOAD_H__ +#define __GECKO_DOWNLOAD_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define GECKODOWNLOAD_CID \ +{ /* b1813bbe-6518-11db-967e-00e08161165f */ \ + 0xb1813bbe, \ + 0x6518, \ + 0x11db, \ + {0x96, 0x7e, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f} \ +} + +class nsIFactory; + +extern "C" NS_EXPORT nsresult NS_NewGeckoDownloadFactory(nsIFactory** aFactory); + +#endif // __GECKO_DOWNLOAD_H__ diff --git a/browser/Makefile.am b/browser/Makefile.am new file mode 100644 index 0000000..ae013e0 --- /dev/null +++ b/browser/Makefile.am @@ -0,0 +1,66 @@ +libsugarbrowser_la_CPPFLAGS = \ + $(WARN_CFLAGS) \ + $(LIB_CFLAGS) \ + $(GECKO_CFLAGS) \ + $(NSPR_CFLAGS) \ + -I$(MOZILLA_INCLUDE_DIR)/dom \ + -I$(MOZILLA_INCLUDE_DIR)/docshell \ + -I$(MOZILLA_INCLUDE_DIR)/exthandler \ + -I$(MOZILLA_INCLUDE_DIR)/gtkembedmoz \ + -I$(MOZILLA_INCLUDE_DIR)/imglib2 \ + -I$(MOZILLA_INCLUDE_DIR)/mimetype \ + -I$(MOZILLA_INCLUDE_DIR)/necko \ + -I$(MOZILLA_INCLUDE_DIR)/pref \ + -I$(MOZILLA_INCLUDE_DIR)/shistory \ + -I$(MOZILLA_INCLUDE_DIR)/uriloader \ + -I$(MOZILLA_INCLUDE_DIR)/webbrwsr \ + -I$(MOZILLA_INCLUDE_DIR)/webbrowserpersist \ + -DPLUGIN_DIR=\"$(libdir)/mozilla/plugins\" \ + -DSHARE_DIR=\"$(pkgdatadir)\" + +noinst_LTLIBRARIES = libsugarbrowser.la + +libsugarbrowser_la_LIBADD = \ + $(LIB_LIBS) \ + $(GECKO_LIBS) + +libsugarbrowser_la_SOURCES = \ + $(BUILT_SOURCES) \ + GeckoContentHandler.h \ + GeckoContentHandler.cpp \ + GeckoDownload.h \ + GeckoDownload.cpp \ + sugar-address-entry.c \ + sugar-address-entry.h \ + sugar-browser.h \ + sugar-browser.cpp \ + sugar-download.h \ + sugar-download.c \ + sugar-download-manager.h \ + sugar-download-manager.c + +BUILT_SOURCES = \ + sugar-marshal.c \ + sugar-marshal.h + +stamp_files = \ + stamp-sugar-marshal.c \ + stamp-sugar-marshal.h + +sugar-marshal.c: stamp-sugar-marshal.c + @true +stamp-sugar-marshal.c: sugar-marshal.list + $(GLIB_GENMARSHAL) --prefix=sugar_marshal $(srcdir)/sugar-marshal.list --header --body > sugar-marshal.c \ + && echo timestamp > $(@F) + +sugar-marshal.h: stamp-sugar-marshal.h + @true +stamp-sugar-marshal.h: sugar-marshal.list + $(GLIB_GENMARSHAL) --prefix=sugar_marshal $(srcdir)/sugar-marshal.list --header > sugar-marshal.h \ + && echo timestamp > $(@F) + +CLEANFILES = $(stamp_files) $(BUILT_SOURCES) +DISTCLEANFILES = $(stamp_files) $(BUILT_SOURCES) +MAINTAINERCLEANFILES = $(stamp_files) $(BUILT_SOURCES) + +EXTRA_DIST = sugar-marshal.list diff --git a/browser/sugar-address-entry.c b/browser/sugar-address-entry.c new file mode 100644 index 0000000..07f2d13 --- /dev/null +++ b/browser/sugar-address-entry.c @@ -0,0 +1,661 @@ +/* + * Copyright (C) 2006, Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include + +#include "sugar-address-entry.h" + +enum { + PROP_0, + PROP_PROGRESS, + PROP_ADDRESS, + PROP_TITLE +}; + +typedef enum { + CURSOR_STANDARD, + CURSOR_DND +} CursorType; + +static void _gtk_entry_effective_inner_border (GtkEntry *entry, + GtkBorder *border); +static void get_text_area_size (GtkEntry *entry, + gint *x, + gint *y, + gint *width, + gint *height); + +G_DEFINE_TYPE(SugarAddressEntry, sugar_address_entry, GTK_TYPE_ENTRY) + +static GQuark quark_inner_border = 0; +static const GtkBorder default_inner_border = { 2, 2, 2, 2 }; + +static void +draw_insertion_cursor (GtkEntry *entry, + GdkRectangle *cursor_location, + gboolean is_primary, + PangoDirection direction, + gboolean draw_arrow) +{ + GtkWidget *widget = GTK_WIDGET (entry); + GtkTextDirection text_dir; + + if (direction == PANGO_DIRECTION_LTR) + text_dir = GTK_TEXT_DIR_LTR; + else + text_dir = GTK_TEXT_DIR_RTL; + + gtk_draw_insertion_cursor (widget, entry->text_area, NULL, + cursor_location, + is_primary, text_dir, draw_arrow); +} + +static void +gtk_entry_get_pixel_ranges (GtkEntry *entry, + gint **ranges, + gint *n_ranges) +{ + gint start_char, end_char; + + if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_char, &end_char)) + { + //PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE); + PangoLayout *layout = gtk_entry_get_layout (entry); + PangoLayoutLine *line = pango_layout_get_lines (layout)->data; + const char *text = pango_layout_get_text (layout); + gint start_index = g_utf8_offset_to_pointer (text, start_char) - text; + gint end_index = g_utf8_offset_to_pointer (text, end_char) - text; + gint real_n_ranges, i; + + pango_layout_line_get_x_ranges (line, start_index, end_index, ranges, &real_n_ranges); + + if (ranges) + { + gint *r = *ranges; + + for (i = 0; i < real_n_ranges; ++i) + { + r[2 * i + 1] = (r[2 * i + 1] - r[2 * i]) / PANGO_SCALE; + r[2 * i] = r[2 * i] / PANGO_SCALE; + } + } + + if (n_ranges) + *n_ranges = real_n_ranges; + } + else + { + if (n_ranges) + *n_ranges = 0; + if (ranges) + *ranges = NULL; + } +} + +static void +gtk_entry_get_cursor_locations (GtkEntry *entry, + CursorType type, + gint *strong_x, + gint *weak_x) +{ + if (!entry->visible && !entry->invisible_char) + { + if (strong_x) + *strong_x = 0; + + if (weak_x) + *weak_x = 0; + } + else + { + //PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE); + PangoLayout *layout = gtk_entry_get_layout (entry); + const gchar *text = pango_layout_get_text (layout); + PangoRectangle strong_pos, weak_pos; + gint index; + + if (type == CURSOR_STANDARD) + { + index = g_utf8_offset_to_pointer (text, entry->current_pos + entry->preedit_cursor) - text; + } + else /* type == CURSOR_DND */ + { + index = g_utf8_offset_to_pointer (text, entry->dnd_position) - text; + + if (entry->dnd_position > entry->current_pos) + { + if (entry->visible) + index += entry->preedit_length; + else + { + gint preedit_len_chars = g_utf8_strlen (text, -1) - entry->text_length; + index += preedit_len_chars * g_unichar_to_utf8 (entry->invisible_char, NULL); + } + } + } + + pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos); + + if (strong_x) + *strong_x = strong_pos.x / PANGO_SCALE; + + if (weak_x) + *weak_x = weak_pos.x / PANGO_SCALE; + } +} + +static void +gtk_entry_draw_cursor (GtkEntry *entry, + CursorType type) +{ + GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry))); + PangoDirection keymap_direction = gdk_keymap_get_direction (keymap); + + if (GTK_WIDGET_DRAWABLE (entry)) + { + GtkWidget *widget = GTK_WIDGET (entry); + GdkRectangle cursor_location; + gboolean split_cursor; + + GtkBorder inner_border; + gint xoffset; + gint strong_x, weak_x; + gint text_area_height; + PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL; + PangoDirection dir2 = PANGO_DIRECTION_NEUTRAL; + gint x1 = 0; + gint x2 = 0; + + _gtk_entry_effective_inner_border (entry, &inner_border); + + xoffset = inner_border.left - entry->scroll_offset; + + gdk_drawable_get_size (entry->text_area, NULL, &text_area_height); + + gtk_entry_get_cursor_locations (entry, type, &strong_x, &weak_x); + + g_object_get (gtk_widget_get_settings (widget), + "gtk-split-cursor", &split_cursor, + NULL); + + dir1 = entry->resolved_dir; + + if (split_cursor) + { + x1 = strong_x; + + if (weak_x != strong_x) + { + dir2 = (entry->resolved_dir == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR; + x2 = weak_x; + } + } + else + { + if (keymap_direction == entry->resolved_dir) + x1 = strong_x; + else + x1 = weak_x; + } + + cursor_location.x = xoffset + x1; + cursor_location.y = inner_border.top; + cursor_location.width = 0; + cursor_location.height = text_area_height - inner_border.top - inner_border.bottom; + + draw_insertion_cursor (entry, + &cursor_location, TRUE, dir1, + dir2 != PANGO_DIRECTION_NEUTRAL); + + if (dir2 != PANGO_DIRECTION_NEUTRAL) + { + cursor_location.x = xoffset + x2; + draw_insertion_cursor (entry, + &cursor_location, FALSE, dir2, + TRUE); + } + } +} + +static void +get_layout_position (GtkEntry *entry, + gint *x, + gint *y) +{ + PangoLayout *layout; + PangoRectangle logical_rect; + gint area_width, area_height; + GtkBorder inner_border; + gint y_pos; + PangoLayoutLine *line; + +// layout = gtk_entry_ensure_layout (entry, TRUE); + layout = gtk_entry_get_layout(entry); + + get_text_area_size (entry, NULL, NULL, &area_width, &area_height); + _gtk_entry_effective_inner_border (entry, &inner_border); + + area_height = PANGO_SCALE * (area_height - inner_border.top - inner_border.bottom); + + line = pango_layout_get_lines (layout)->data; + pango_layout_line_get_extents (line, NULL, &logical_rect); + + /* Align primarily for locale's ascent/descent */ + y_pos = ((area_height - entry->ascent - entry->descent) / 2 + + entry->ascent + logical_rect.y); + + /* Now see if we need to adjust to fit in actual drawn string */ + if (logical_rect.height > area_height) + y_pos = (area_height - logical_rect.height) / 2; + else if (y_pos < 0) + y_pos = 0; + else if (y_pos + logical_rect.height > area_height) + y_pos = area_height - logical_rect.height; + + y_pos = inner_border.top + y_pos / PANGO_SCALE; + + if (x) + *x = inner_border.left - entry->scroll_offset; + + if (y) + *y = y_pos; +} + +static void +_gtk_entry_effective_inner_border (GtkEntry *entry, + GtkBorder *border) +{ + GtkBorder *tmp_border; + + tmp_border = g_object_get_qdata (G_OBJECT (entry), quark_inner_border); + + if (tmp_border) + { + *border = *tmp_border; + return; + } + + gtk_widget_style_get (GTK_WIDGET (entry), "inner-border", &tmp_border, NULL); + + if (tmp_border) + { + *border = *tmp_border; + g_free (tmp_border); + return; + } + + *border = default_inner_border; +} + +static void +gtk_entry_draw_text (GtkEntry *entry) +{ + GtkWidget *widget; + + if (!entry->visible && entry->invisible_char == 0) + return; + + if (GTK_WIDGET_DRAWABLE (entry)) + { + //PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE); + PangoLayout *layout = gtk_entry_get_layout (entry); + cairo_t *cr; + gint x, y; + gint start_pos, end_pos; + + widget = GTK_WIDGET (entry); + + get_layout_position (entry, &x, &y); + + cr = gdk_cairo_create (entry->text_area); + + cairo_move_to (cr, x, y); + gdk_cairo_set_source_color (cr, &widget->style->text [widget->state]); + pango_cairo_show_layout (cr, layout); + + if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_pos, &end_pos)) + { + gint *ranges; + gint n_ranges, i; + PangoRectangle logical_rect; + GdkColor *selection_color, *text_color; + GtkBorder inner_border; + + pango_layout_get_pixel_extents (layout, NULL, &logical_rect); + gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges); + + if (GTK_WIDGET_HAS_FOCUS (entry)) + { + selection_color = &widget->style->base [GTK_STATE_SELECTED]; + text_color = &widget->style->text [GTK_STATE_SELECTED]; + } + else + { + selection_color = &widget->style->base [GTK_STATE_ACTIVE]; + text_color = &widget->style->text [GTK_STATE_ACTIVE]; + } + + _gtk_entry_effective_inner_border (entry, &inner_border); + + for (i = 0; i < n_ranges; ++i) + cairo_rectangle (cr, + inner_border.left - entry->scroll_offset + ranges[2 * i], + y, + ranges[2 * i + 1], + logical_rect.height); + + cairo_clip (cr); + + gdk_cairo_set_source_color (cr, selection_color); + cairo_paint (cr); + + cairo_move_to (cr, x, y); + gdk_cairo_set_source_color (cr, text_color); + pango_cairo_show_layout (cr, layout); + + g_free (ranges); + } + + cairo_destroy (cr); + } +} + +static void +sugar_address_entry_get_borders (GtkEntry *entry, + gint *xborder, + gint *yborder) +{ + GtkWidget *widget = GTK_WIDGET (entry); + gint focus_width; + gboolean interior_focus; + + gtk_widget_style_get (widget, + "interior-focus", &interior_focus, + "focus-line-width", &focus_width, + NULL); + + if (entry->has_frame) + { + *xborder = widget->style->xthickness; + *yborder = widget->style->ythickness; + } + else + { + *xborder = 0; + *yborder = 0; + } + + if (!interior_focus) + { + *xborder += focus_width; + *yborder += focus_width; + } +} + +static void +get_text_area_size (GtkEntry *entry, + gint *x, + gint *y, + gint *width, + gint *height) +{ + gint xborder, yborder; + GtkRequisition requisition; + GtkWidget *widget = GTK_WIDGET (entry); + + gtk_widget_get_child_requisition (widget, &requisition); + + sugar_address_entry_get_borders (entry, &xborder, &yborder); + + if (x) + *x = xborder; + + if (y) + *y = yborder; + + if (width) + *width = GTK_WIDGET (entry)->allocation.width - xborder * 2; + + if (height) + *height = requisition.height - yborder * 2; +} + +static gint +sugar_address_entry_expose(GtkWidget *widget, + GdkEventExpose *event) +{ + GtkEntry *entry = GTK_ENTRY (widget); + SugarAddressEntry *address_entry = SUGAR_ADDRESS_ENTRY(widget); + cairo_t *cr; + + if (entry->text_area == event->window) { + gint area_width, area_height; + + get_text_area_size (entry, NULL, NULL, &area_width, &area_height); + +/* gtk_paint_flat_box (widget->style, entry->text_area, + GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE, + NULL, widget, "entry_bg", + 0, 0, area_width, area_height); +*/ + + if (address_entry->progress != 0.0 && address_entry->progress != 1.0 && + !GTK_WIDGET_HAS_FOCUS(entry)) { + int bar_width = area_width * address_entry->progress; + float radius = area_height / 2; + + cr = gdk_cairo_create(entry->text_area); + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + + cairo_move_to (cr, radius, 0); + cairo_arc (cr, bar_width - radius, radius, radius, M_PI * 1.5, M_PI * 2); + cairo_arc (cr, bar_width - radius, area_height - radius, radius, 0, M_PI * 0.5); + cairo_arc (cr, radius, area_height - radius, radius, M_PI * 0.5, M_PI); + cairo_arc (cr, radius, radius, radius, M_PI, M_PI * 1.5); + + cairo_fill(cr); + cairo_destroy (cr); + } + + + if ((entry->visible || entry->invisible_char != 0) && + GTK_WIDGET_HAS_FOCUS (widget) && + entry->selection_bound == entry->current_pos && entry->cursor_visible) + gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_STANDARD); + + if (entry->dnd_position != -1) + gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_DND); + + gtk_entry_draw_text (GTK_ENTRY (widget)); + } else { + GtkWidgetClass *parent_class; + parent_class = GTK_WIDGET_CLASS(sugar_address_entry_parent_class); + parent_class->expose_event(widget, event); + } + + return FALSE; +} + +static void +update_entry_text(SugarAddressEntry *address_entry, + gboolean has_focus) +{ + if (has_focus) { + gtk_entry_set_text(GTK_ENTRY(address_entry), + address_entry->address); + } else { + gtk_entry_set_text(GTK_ENTRY(address_entry), + address_entry->title); + } +} + +static void +sugar_address_entry_set_address(SugarAddressEntry *address_entry, + const char *address) +{ + g_free(address_entry->address); + address_entry->address = g_strdup(address); + + update_entry_text(address_entry, + gtk_widget_is_focus(GTK_WIDGET(address_entry))); +} + +static void +sugar_address_entry_set_title(SugarAddressEntry *address_entry, + const char *title) +{ + g_free(address_entry->title); + address_entry->title = g_strdup(title); + + update_entry_text(address_entry, + gtk_widget_is_focus(GTK_WIDGET(address_entry))); +} + +static void +sugar_address_entry_set_property(GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SugarAddressEntry *address_entry = SUGAR_ADDRESS_ENTRY(object); + GtkEntry *entry = GTK_ENTRY(object); + + switch (prop_id) { + case PROP_PROGRESS: + address_entry->progress = g_value_get_double(value); + if (GTK_WIDGET_REALIZED(entry)) + gdk_window_invalidate_rect(entry->text_area, NULL, FALSE); + break; + case PROP_ADDRESS: + sugar_address_entry_set_address(address_entry, + g_value_get_string(value)); + break; + case PROP_TITLE: + sugar_address_entry_set_title(address_entry, + g_value_get_string(value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +sugar_address_entry_get_property(GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SugarAddressEntry *entry = SUGAR_ADDRESS_ENTRY(object); + + switch (prop_id) { + case PROP_PROGRESS: + g_value_set_double(value, entry->progress); + break; + case PROP_TITLE: + g_value_set_string(value, entry->title); + break; + case PROP_ADDRESS: + g_value_set_string(value, entry->address); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +sugar_address_entry_class_init(SugarAddressEntryClass *klass) +{ + GtkWidgetClass *widget_class = (GtkWidgetClass*)klass; + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + widget_class->expose_event = sugar_address_entry_expose; + + gobject_class->set_property = sugar_address_entry_set_property; + gobject_class->get_property = sugar_address_entry_get_property; + + quark_inner_border = g_quark_from_static_string ("gtk-entry-inner-border"); + + g_object_class_install_property (gobject_class, PROP_PROGRESS, + g_param_spec_double("progress", + "Progress", + "Progress", + 0.0, 1.0, 0.0, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_TITLE, + g_param_spec_string("title", + "Title", + "Title", + "", + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_ADDRESS, + g_param_spec_string("address", + "Address", + "Address", + "", + G_PARAM_READWRITE)); +} + +static gboolean +button_press_event_cb (GtkWidget *widget, GdkEventButton *event) +{ + if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) { + gtk_editable_select_region(GTK_EDITABLE(widget), 0, -1); + gtk_widget_grab_focus(widget); + + return TRUE; + } + + return FALSE; +} + +static gboolean +focus_in_event_cb(GtkWidget *widget, GdkEventFocus *event) +{ + update_entry_text(SUGAR_ADDRESS_ENTRY(widget), TRUE); + return FALSE; +} + +static gboolean +focus_out_event_cb(GtkWidget *widget, GdkEventFocus *event) +{ + update_entry_text(SUGAR_ADDRESS_ENTRY(widget), FALSE); + return FALSE; +} + +static void +sugar_address_entry_init(SugarAddressEntry *entry) +{ + entry->progress = 0.0; + entry->address = NULL; + entry->title = g_strdup(""); + + g_signal_connect(entry, "focus-in-event", + G_CALLBACK(focus_in_event_cb), NULL); + g_signal_connect(entry, "focus-out-event", + G_CALLBACK(focus_out_event_cb), NULL); + g_signal_connect(entry, "button-press-event", + G_CALLBACK(button_press_event_cb), NULL); +} diff --git a/browser/sugar-address-entry.h b/browser/sugar-address-entry.h new file mode 100644 index 0000000..bf1838d --- /dev/null +++ b/browser/sugar-address-entry.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2006, Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __SUGAR_ADDRESS_ENTRY_H__ +#define __SUGAR_ADDRESS_ENTRY_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _SugarAddressEntry SugarAddressEntry; +typedef struct _SugarAddressEntryClass SugarAddressEntryClass; +typedef struct _SugarAddressEntryPrivate SugarAddressEntryPrivate; + +#define SUGAR_TYPE_ADDRESS_ENTRY (sugar_address_entry_get_type()) +#define SUGAR_ADDRESS_ENTRY(object) (G_TYPE_CHECK_INSTANCE_CAST((object), SUGAR_TYPE_ADDRESS_ENTRY, SugarAddressEntry)) +#define SUGAR_ADDRESS_ENTRY_CLASS(klass) (G_TYPE_CHACK_CLASS_CAST((klass), SUGAR_TYPE_ADDRESS_ENTRY, SugarAddressEntryClass)) +#define SUGAR_IS_ADDRESS_ENTRY(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), SUGAR_TYPE_ADDRESS_ENTRY)) +#define SUGAR_IS_ADDRESS_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SUGAR_TYPE_ADDRESS_ENTRY)) +#define SUGAR_ADDRESS_ENTRY_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), SUGAR_TYPE_ADDRESS_ENTRY, SugarAddressEntryClass)) + +struct _SugarAddressEntry { + GtkEntry base_instance; + + float progress; + char *title; + char *address; +}; + +struct _SugarAddressEntryClass { + GtkEntryClass base_class; +}; + +GType sugar_address_entry_get_type (void); + +G_END_DECLS + +#endif /* __SUGAR_ADDRESS_ENTRY_H__ */ diff --git a/browser/sugar-browser.cpp b/browser/sugar-browser.cpp new file mode 100644 index 0000000..cd455b6 --- /dev/null +++ b/browser/sugar-browser.cpp @@ -0,0 +1,938 @@ +/* + * Copyright (C) 2006, Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "sugar-browser.h" +#include "sugar-marshal.h" +#include "GeckoContentHandler.h" +#include "GeckoDownload.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + PROP_0, + PROP_PROGRESS, + PROP_TITLE, + PROP_ADDRESS, + PROP_CAN_GO_BACK, + PROP_CAN_GO_FORWARD, + PROP_LOADING, + PROP_DOCUMENT_METADATA +}; + +enum { + MOUSE_CLICK, + N_SIGNALS +}; + +static guint signals[N_SIGNALS]; + +static const nsModuleComponentInfo sSugarComponents[] = { + { + "Gecko Content Handler", + GECKOCONTENTHANDLER_CID, + NS_IHELPERAPPLAUNCHERDLG_CONTRACTID, + NULL + }, + { + "Gecko Download", + GECKODOWNLOAD_CID, + NS_TRANSFER_CONTRACTID, + NULL + } +}; + +int (*old_handler) (Display *, XErrorEvent *); + +static int +error_handler (Display *d, XErrorEvent *e) +{ + gchar buf[64]; + gchar *msg; + + XGetErrorText(d, e->error_code, buf, 63); + + msg = + g_strdup_printf("The program '%s' received an X Window System error.\n" + "This probably reflects a bug in the program.\n" + "The error was '%s'.\n" + " (Details: serial %ld error_code %d request_code %d minor_code %d)\n", + g_get_prgname (), + buf, + e->serial, + e->error_code, + e->request_code, + e->minor_code); + + g_warning ("%s", msg); + + return 0; + /*return (*old_handler)(d, e);*/ +} + +static void +setup_plugin_path () +{ + const char *user_path; + char *new_path; + + user_path = g_getenv ("MOZ_PLUGIN_PATH"); + new_path = g_strconcat (user_path ? user_path : "", + user_path ? ":" : "", + PLUGIN_DIR, + (char *) NULL); + g_setenv ("MOZ_PLUGIN_PATH", new_path, TRUE); + g_free (new_path); +} + +gboolean +sugar_browser_startup(const char *profile_path, const char *profile_name) +{ + nsresult rv; + + setup_plugin_path(); + + gtk_moz_embed_set_profile_path(profile_path, profile_name); + + old_handler = XSetErrorHandler(error_handler); + + gtk_moz_embed_push_startup(); + + nsCOMPtr prefService; + prefService = do_GetService(NS_PREFSERVICE_CONTRACTID); + NS_ENSURE_TRUE(prefService, FALSE); + + /* Read our predefined default prefs */ + nsCOMPtr file; + NS_NewNativeLocalFile(nsCString(SHARE_DIR"/gecko-prefs.js"), + PR_TRUE, getter_AddRefs(file)); + NS_ENSURE_TRUE(file, FALSE); + + rv = prefService->ReadUserPrefs (file); + if (NS_FAILED(rv)) { + g_warning ("failed to read default preferences, error: %x", rv); + return FALSE; + } + + nsCOMPtr pref; + prefService->GetBranch ("", getter_AddRefs(pref)); + NS_ENSURE_TRUE(pref, FALSE); + + pref->SetCharPref ("helpers.private_mime_types_file", SHARE_DIR"/mime.types"); + + rv = prefService->ReadUserPrefs (nsnull); + if (NS_FAILED(rv)) { + g_warning ("failed to read user preferences, error: %x", rv); + } + + nsCOMPtr componentRegistrar; + NS_GetComponentRegistrar(getter_AddRefs(componentRegistrar)); + NS_ENSURE_TRUE (componentRegistrar, FALSE); + + nsCOMPtr contentHandlerFactory; + rv = NS_NewGeckoContentHandlerFactory(getter_AddRefs(contentHandlerFactory)); + rv = componentRegistrar->RegisterFactory(sSugarComponents[0].mCID, + sSugarComponents[0].mDescription, + sSugarComponents[0].mContractID, + contentHandlerFactory); + if (NS_FAILED(rv)) { + g_warning ("Failed to register factory for %s\n", sSugarComponents[0].mDescription); + return FALSE; + } + + nsCOMPtr downloadFactory; + rv = NS_NewGeckoDownloadFactory(getter_AddRefs(downloadFactory)); + rv = componentRegistrar->RegisterFactory(sSugarComponents[1].mCID, + sSugarComponents[1].mDescription, + sSugarComponents[1].mContractID, + downloadFactory); + if (NS_FAILED(rv)) { + g_warning ("Failed to register factory for %s\n", sSugarComponents[1].mDescription); + return FALSE; + } + + return TRUE; +} + +void +sugar_browser_shutdown(void) +{ + gtk_moz_embed_pop_startup(); +} + +G_DEFINE_TYPE(SugarBrowser, sugar_browser, GTK_TYPE_MOZ_EMBED) + +static nsresult +NewURI(const char *uri, nsIURI **result) +{ + nsresult rv; + + nsCOMPtr mgr; + NS_GetServiceManager (getter_AddRefs (mgr)); + NS_ENSURE_TRUE(mgr, FALSE); + + nsCOMPtr ioService; + rv = mgr->GetServiceByContractID ("@mozilla.org/network/io-service;1", + NS_GET_IID (nsIIOService), + getter_AddRefs(ioService)); + NS_ENSURE_SUCCESS(rv, FALSE); + + nsCString cSpec(uri); + return ioService->NewURI (cSpec, nsnull, nsnull, result); +} + +static nsresult +FilenameFromContentDisposition(nsCString contentDisposition, nsCString &fileName) +{ + nsresult rv; + + nsCString fallbackCharset; + + nsCOMPtr mimehdrpar = + do_GetService("@mozilla.org/network/mime-hdrparam;1"); + NS_ENSURE_TRUE(mimehdrpar, NS_ERROR_FAILURE); + + nsString aFileName; + rv = mimehdrpar->GetParameter (contentDisposition, "filename", + fallbackCharset, PR_TRUE, nsnull, + aFileName); + + if (NS_FAILED(rv) || !fileName.Length()) { + rv = mimehdrpar->GetParameter (contentDisposition, "name", + fallbackCharset, PR_TRUE, nsnull, + aFileName); + } + + if (NS_SUCCEEDED(rv) && fileName.Length()) { + NS_UTF16ToCString (aFileName, NS_CSTRING_ENCODING_UTF8, fileName); + } + + return NS_OK; +} + +static nsresult +ImageNameFromCache(nsIURI *imgURI, nsCString &imgName) +{ + nsresult rv; + + nsCOMPtr mgr; + NS_GetServiceManager (getter_AddRefs (mgr)); + NS_ENSURE_TRUE(mgr, NS_ERROR_FAILURE); + + nsCOMPtr imgCache; + rv = mgr->GetServiceByContractID("@mozilla.org/image/cache;1", + NS_GET_IID (imgICache), + getter_AddRefs(imgCache)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + + nsCOMPtr imgProperties; + imgCache->FindEntryProperties(imgURI, getter_AddRefs(imgProperties)); + if (imgProperties) { + nsCOMPtr dispositionCString; + imgProperties->Get("content-disposition", + NS_GET_IID(nsISupportsCString), + getter_AddRefs(dispositionCString)); + if (dispositionCString) { + nsCString contentDisposition; + dispositionCString->GetData(contentDisposition); + FilenameFromContentDisposition(contentDisposition, imgName); + } + } + + return NS_OK; +} + +static SugarBrowserMetadata * +sugar_browser_get_document_metadata(SugarBrowser *browser) +{ + SugarBrowserMetadata *metadata = sugar_browser_metadata_new(); + +#ifdef HAVE_NS_WEB_BROWSER + nsCOMPtr webBrowser; + gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser), + getter_AddRefs(webBrowser)); + NS_ENSURE_TRUE(webBrowser, metadata); + + nsCOMPtr DOMWindow; + webBrowser->GetContentDOMWindow(getter_AddRefs(DOMWindow)); + NS_ENSURE_TRUE(DOMWindow, metadata); + + nsCOMPtr DOMWindowUtils(do_GetInterface(DOMWindow)); + NS_ENSURE_TRUE(DOMWindowUtils, metadata); + + const PRUnichar contentDispositionLiteral[] = + {'c', 'o', 'n', 't', 'e', 'n', 't', '-', 'd', 'i', 's', 'p', + 'o', 's', 'i', 't', 'i', 'o', 'n', '\0'}; + + nsString contentDisposition; + DOMWindowUtils->GetDocumentMetadata(nsString(contentDispositionLiteral), + contentDisposition); + + nsCString cContentDisposition; + NS_UTF16ToCString (contentDisposition, NS_CSTRING_ENCODING_UTF8, + cContentDisposition); + + nsCString fileName; + FilenameFromContentDisposition(cContentDisposition, fileName); + + if (!fileName.Length()) { + nsCOMPtr webNav(do_QueryInterface(webBrowser)); + if (webNav) { + nsCOMPtr docURI; + webNav->GetCurrentURI (getter_AddRefs(docURI)); + + nsCOMPtr url(do_QueryInterface(docURI)); + if (url) { + url->GetFileName(fileName); + } + } + } + + if (fileName.Length()) { + metadata->filename = g_strdup(fileName.get()); + } +#endif + + return metadata; +} + +static void +sugar_browser_get_property(GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SugarBrowser *browser = SUGAR_BROWSER(object); + + switch (prop_id) { + case PROP_PROGRESS: + g_value_set_double(value, browser->progress); + break; + case PROP_ADDRESS: + g_value_set_string(value, browser->address); + break; + case PROP_TITLE: + g_value_set_string(value, browser->title); + break; + case PROP_CAN_GO_BACK: + g_value_set_boolean(value, browser->can_go_back); + break; + case PROP_CAN_GO_FORWARD: + g_value_set_boolean(value, browser->can_go_forward); + break; + case PROP_LOADING: + g_value_set_boolean(value, browser->loading); + break; + case PROP_DOCUMENT_METADATA: + SugarBrowserMetadata *metadata; + metadata = sugar_browser_get_document_metadata(browser); + g_value_set_boxed(value, metadata); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +static void +sugar_browser_class_init(SugarBrowserClass *browser_class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(browser_class); + + gobject_class->get_property = sugar_browser_get_property; + + signals[MOUSE_CLICK] = g_signal_new ("mouse_click", + SUGAR_TYPE_BROWSER, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(SugarBrowser, mouse_click), + g_signal_accumulator_true_handled, NULL, + sugar_marshal_BOOLEAN__BOXED, + G_TYPE_BOOLEAN, + 1, + SUGAR_TYPE_BROWSER_EVENT); + + g_object_class_install_property(gobject_class, PROP_PROGRESS, + g_param_spec_double ("progress", + "Progress", + "Progress", + 0.0, 1.0, 0.0, + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, PROP_ADDRESS, + g_param_spec_string ("address", + "Address", + "Address", + "", + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, PROP_TITLE, + g_param_spec_string ("title", + "Title", + "Title", + "", + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, PROP_CAN_GO_BACK, + g_param_spec_boolean ("can-go-back", + "Can go back", + "Can go back", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, PROP_CAN_GO_FORWARD, + g_param_spec_boolean ("can-go-forward", + "Can go forward", + "Can go forward", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, PROP_LOADING, + g_param_spec_boolean ("loading", + "Loading", + "Loading", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property(gobject_class, PROP_DOCUMENT_METADATA, + g_param_spec_boxed("document-metadata", + "Document Metadata", + "Document metadata", + SUGAR_TYPE_BROWSER_METADATA, + G_PARAM_READABLE)); + +} + +SugarBrowser * +sugar_browser_create_window(SugarBrowser *browser) +{ + return SUGAR_BROWSER_GET_CLASS(browser)->create_window(browser); +} + +static void +update_navigation_properties(SugarBrowser *browser) +{ + GtkMozEmbed *embed = GTK_MOZ_EMBED(browser); + gboolean can_go_back; + gboolean can_go_forward; + + can_go_back = gtk_moz_embed_can_go_back(embed); + if (can_go_back != browser->can_go_back) { + browser->can_go_back = can_go_back; + g_object_notify (G_OBJECT(browser), "can-go-back"); + } + + can_go_forward = gtk_moz_embed_can_go_forward(embed); + if (can_go_forward != browser->can_go_forward) { + browser->can_go_forward = can_go_forward; + g_object_notify (G_OBJECT(browser), "can-go-forward"); + } +} + +static void +new_window_cb(GtkMozEmbed *embed, + GtkMozEmbed **newEmbed, + guint chromemask) +{ + SugarBrowser *browser; + + browser = sugar_browser_create_window(SUGAR_BROWSER(embed)); + + *newEmbed = GTK_MOZ_EMBED(browser); +} + +static void +sugar_browser_set_progress(SugarBrowser *browser, float progress) +{ + g_return_if_fail(SUGAR_IS_BROWSER(browser)); + + browser->progress = progress; + g_object_notify (G_OBJECT(browser), "progress"); +} + +static void +sugar_browser_set_loading(SugarBrowser *browser, gboolean loading) +{ + g_return_if_fail(SUGAR_IS_BROWSER(browser)); + + browser->loading = loading; + g_object_notify (G_OBJECT(browser), "loading"); +} + +static void +net_state_cb(GtkMozEmbed *embed, const char *aURI, gint state, guint status) +{ + SugarBrowser *browser = SUGAR_BROWSER(embed); + + if (state & GTK_MOZ_EMBED_FLAG_IS_NETWORK) { + if (state & GTK_MOZ_EMBED_FLAG_START) { + browser->total_requests = 0; + browser->current_requests = 0; + + sugar_browser_set_progress(browser, 0.03); + sugar_browser_set_loading(browser, TRUE); + update_navigation_properties(browser); + } else if (state & GTK_MOZ_EMBED_FLAG_STOP) { + sugar_browser_set_progress(browser, 1.0); + sugar_browser_set_loading(browser, FALSE); + update_navigation_properties(browser); + } + } + + if (state & GTK_MOZ_EMBED_FLAG_IS_REQUEST) { + float progress; + + if (state & GTK_MOZ_EMBED_FLAG_START) { + browser->total_requests++; + } + else if (state & GTK_MOZ_EMBED_FLAG_STOP) + { + browser->current_requests++; + } + + progress = float(browser->current_requests) / + float(browser->total_requests); + if (progress > browser->progress) { + sugar_browser_set_progress(browser, progress); + } + } +} + +static void +title_cb(GtkMozEmbed *embed) +{ + SugarBrowser *browser = SUGAR_BROWSER(embed); + + g_free(browser->title); + browser->title = gtk_moz_embed_get_title(embed); + + g_object_notify (G_OBJECT(browser), "title"); +} + +static void +location_cb(GtkMozEmbed *embed) +{ + SugarBrowser *browser = SUGAR_BROWSER(embed); + + g_free(browser->address); + browser->address = gtk_moz_embed_get_location(embed); + + g_object_notify (G_OBJECT(browser), "address"); + + update_navigation_properties(browser); +} + +static char * +get_image_name(const char *uri) +{ + nsresult rv; + + nsCString imgName; + + nsCOMPtr imgURI; + rv = NewURI(uri, getter_AddRefs(imgURI)); + NS_ENSURE_SUCCESS(rv, NULL); + + ImageNameFromCache(imgURI, imgName); + + if (!imgName.Length()) { + nsCOMPtr url(do_QueryInterface(imgURI)); + if (url) { + url->GetFileName(imgName); + } + } + + return imgName.Length() ? g_strdup(imgName.get()) : NULL; +} + +static gboolean +dom_mouse_click_cb(GtkMozEmbed *embed, nsIDOMMouseEvent *mouseEvent) +{ + SugarBrowser *browser = SUGAR_BROWSER(embed); + SugarBrowserEvent *event; + gint return_value = FALSE; + + nsCOMPtr eventTarget; + mouseEvent->GetTarget(getter_AddRefs(eventTarget)); + NS_ENSURE_TRUE(mouseEvent, FALSE); + + nsCOMPtr targetNode; + targetNode = do_QueryInterface(eventTarget); + NS_ENSURE_TRUE(targetNode, FALSE); + + event = sugar_browser_event_new(); + + nsresult rv; + + PRUint16 type; + rv = targetNode->GetNodeType(&type); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCOMPtr element = do_QueryInterface(targetNode); + if ((nsIDOMNode::ELEMENT_NODE == type) && element) { + nsString uTag; + rv = element->GetLocalName(uTag); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCString tag; + NS_UTF16ToCString (uTag, NS_CSTRING_ENCODING_UTF8, tag); + + if (g_ascii_strcasecmp (tag.get(), "img") == 0) { + nsString img; + + nsCOMPtr image; + image = do_QueryInterface(targetNode, &rv); + if (NS_FAILED(rv) || !image) return NS_ERROR_FAILURE; + + rv = image->GetSrc(img); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCString cImg; + NS_UTF16ToCString (img, NS_CSTRING_ENCODING_UTF8, cImg); + event->image_uri = g_strdup(cImg.get()); + event->image_name = get_image_name(event->image_uri); + } + } + + PRUint16 btn = 0; + mouseEvent->GetButton (&btn); + event->button = btn + 1; + + g_signal_emit(browser, signals[MOUSE_CLICK], 0, event, &return_value); + + sugar_browser_event_free(event); + + return return_value; +} + +static void +sugar_browser_init(SugarBrowser *browser) +{ + browser->title = NULL; + browser->address = NULL; + browser->progress = 0.0; + + g_signal_connect(G_OBJECT(browser), "new-window", + G_CALLBACK(new_window_cb), NULL); + g_signal_connect(G_OBJECT(browser), "net-state-all", + G_CALLBACK(net_state_cb), NULL); + g_signal_connect(G_OBJECT(browser), "title", + G_CALLBACK(title_cb), NULL); + g_signal_connect(G_OBJECT(browser), "location", + G_CALLBACK(location_cb), NULL); + g_signal_connect(G_OBJECT(browser), "dom-mouse-click", + G_CALLBACK(dom_mouse_click_cb), NULL); +} + +void +sugar_browser_scroll_pixels(SugarBrowser *browser, + int dx, + int dy) +{ +#ifndef HAVE_GECKO_1_9 + nsCOMPtr webBrowser; + gtk_moz_embed_get_nsIWebBrowser (GTK_MOZ_EMBED(browser), + getter_AddRefs(webBrowser)); + NS_ENSURE_TRUE (webBrowser, ); + + nsCOMPtr webBrowserFocus; + webBrowserFocus = do_QueryInterface (webBrowser); + NS_ENSURE_TRUE (webBrowserFocus, ); + + nsCOMPtr DOMWindow; + webBrowserFocus->GetFocusedWindow (getter_AddRefs(DOMWindow)); + if (!DOMWindow) { + webBrowser->GetContentDOMWindow (getter_AddRefs(DOMWindow)); + } + NS_ENSURE_TRUE (DOMWindow, ); + + DOMWindow->ScrollBy (dx, dy); +#endif +} + +void +sugar_browser_grab_focus(SugarBrowser *browser) +{ + GtkWidget *child; + + child = gtk_bin_get_child(GTK_BIN(browser)); + + if (child != NULL) { + gtk_widget_grab_focus (child); + } else { + g_warning ("Need to realize the embed before grabbing focus!\n"); + } +} + + +static nsresult +GetPostData(SugarBrowser *browser, nsIInputStream **postData) +{ +#ifdef HAVE_NS_WEB_BROWSER + nsCOMPtr webBrowser; + gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser), + getter_AddRefs(webBrowser)); + NS_ENSURE_TRUE(webBrowser, NS_ERROR_FAILURE); + + nsCOMPtr webNav(do_QueryInterface(webBrowser)); + NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE); + + PRInt32 sindex; + + nsCOMPtr sessionHistory; + webNav->GetSessionHistory(getter_AddRefs(sessionHistory)); + NS_ENSURE_TRUE(sessionHistory, NS_ERROR_FAILURE); + + nsCOMPtr entry; + sessionHistory->GetIndex(&sindex); + sessionHistory->GetEntryAtIndex(sindex, PR_FALSE, getter_AddRefs(entry)); + + nsCOMPtr shEntry(do_QueryInterface(entry)); + if (shEntry) { + shEntry->GetPostData(postData); + } + + return NS_OK; +#endif + return NS_ERROR_NOT_IMPLEMENTED; +} + +gboolean +sugar_browser_save_uri(SugarBrowser *browser, + const char *uri, + const char *filename) +{ +#ifdef HAVE_NS_WEB_BROWSER + nsresult rv; + + nsCOMPtr sourceURI; + rv = NewURI(uri, getter_AddRefs(sourceURI)); + NS_ENSURE_SUCCESS(rv, FALSE); + + nsCOMPtr destFile = do_CreateInstance("@mozilla.org/file/local;1"); + NS_ENSURE_TRUE(destFile, FALSE); + + destFile->InitWithNativePath(nsCString(filename)); + + nsCOMPtr webBrowser; + gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser), + getter_AddRefs(webBrowser)); + NS_ENSURE_TRUE(webBrowser, FALSE); + + nsCOMPtr webPersist = do_QueryInterface (webBrowser); + NS_ENSURE_TRUE(webPersist, FALSE); + + nsCOMPtr postData; + GetPostData(browser, getter_AddRefs(postData)); + + rv = webPersist->SaveURI(sourceURI, nsnull, nsnull, postData, nsnull, destFile); + NS_ENSURE_SUCCESS(rv, FALSE); + + return TRUE; +#else + return FALSE; +#endif +} + +gboolean +sugar_browser_save_document(SugarBrowser *browser, + const char *filename) +{ +#ifdef HAVE_NS_WEB_BROWSER + nsresult rv; + + nsCString cFile(filename); + + nsCOMPtr destFile = do_CreateInstance("@mozilla.org/file/local;1"); + NS_ENSURE_TRUE(destFile, FALSE); + + destFile->InitWithNativePath(cFile); + + GString *path = g_string_new (filename); + char *dot_pos = strchr (path->str, '.'); + if (dot_pos) { + g_string_truncate (path, dot_pos - path->str); + } + g_string_append (path, " Files"); + + nsCOMPtr filesFolder; + filesFolder = do_CreateInstance ("@mozilla.org/file/local;1"); + filesFolder->InitWithNativePath (nsCString(path->str)); + + g_string_free (path, TRUE); + + nsCOMPtr webBrowser; + gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser), + getter_AddRefs(webBrowser)); + NS_ENSURE_TRUE(webBrowser, FALSE); + + nsCOMPtr DOMWindow; + webBrowser->GetContentDOMWindow(getter_AddRefs(DOMWindow)); + NS_ENSURE_TRUE(DOMWindow, FALSE); + + nsCOMPtr DOMDocument; + DOMWindow->GetDocument (getter_AddRefs(DOMDocument)); + NS_ENSURE_TRUE(DOMDocument, FALSE); + + nsCOMPtr webPersist = do_QueryInterface (webBrowser); + NS_ENSURE_TRUE(webPersist, FALSE); + + rv = webPersist->SaveDocument(DOMDocument, destFile, filesFolder, nsnull, 0, 0); + NS_ENSURE_SUCCESS(rv, FALSE); + + return TRUE; +#else + return FALSE; +#endif +} + +GType +sugar_browser_event_get_type(void) +{ + static GType type = 0; + + if (G_UNLIKELY(type == 0)) { + type = g_boxed_type_register_static("SugarBrowserEvent", + (GBoxedCopyFunc)sugar_browser_event_copy, + (GBoxedFreeFunc)sugar_browser_event_free); + } + + return type; +} + +SugarBrowserEvent * +sugar_browser_event_new(void) +{ + SugarBrowserEvent *event; + + event = g_new0(SugarBrowserEvent, 1); + + return event; +} + +SugarBrowserEvent * +sugar_browser_event_copy(SugarBrowserEvent *event) +{ + SugarBrowserEvent *copy; + + g_return_val_if_fail(event != NULL, NULL); + + copy = g_new0(SugarBrowserEvent, 1); + copy->button = event->button; + copy->image_uri = g_strdup(event->image_uri); + copy->image_name = g_strdup(event->image_name); + + return copy; +} + +void +sugar_browser_event_free(SugarBrowserEvent *event) +{ + g_return_if_fail(event != NULL); + + if (event->image_uri) { + g_free(event->image_uri); + } + if (event->image_name) { + g_free(event->image_name); + } + + g_free(event); +} + +GType +sugar_browser_metadata_get_type(void) +{ + static GType type = 0; + + if (G_UNLIKELY(type == 0)) { + type = g_boxed_type_register_static("SugarBrowserMetadata", + (GBoxedCopyFunc)sugar_browser_metadata_copy, + (GBoxedFreeFunc)sugar_browser_metadata_free); + } + + return type; +} + +SugarBrowserMetadata * +sugar_browser_metadata_new(void) +{ + SugarBrowserMetadata *metadata; + + metadata = g_new0(SugarBrowserMetadata, 1); + + return metadata; +} + +SugarBrowserMetadata * +sugar_browser_metadata_copy(SugarBrowserMetadata *metadata) +{ + SugarBrowserMetadata *copy; + + g_return_val_if_fail(metadata != NULL, NULL); + + copy = g_new0(SugarBrowserMetadata, 1); + copy->filename = g_strdup(metadata->filename); + + return copy; +} + +void +sugar_browser_metadata_free(SugarBrowserMetadata *metadata) +{ + g_return_if_fail(metadata != NULL); + + if (metadata->filename) { + g_free(metadata->filename); + } + + g_free(metadata); +} diff --git a/browser/sugar-browser.h b/browser/sugar-browser.h new file mode 100644 index 0000000..43108ec --- /dev/null +++ b/browser/sugar-browser.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2006, Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __SUGAR_BROWSER_H__ +#define __SUGAR_BROWSER_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _SugarBrowser SugarBrowser; +typedef struct _SugarBrowserClass SugarBrowserClass; +typedef struct _SugarBrowserEvent SugarBrowserEvent; +typedef struct _SugarBrowserMetadata SugarBrowserMetadata; + +#define SUGAR_TYPE_BROWSER (sugar_browser_get_type()) +#define SUGAR_BROWSER(object) (G_TYPE_CHECK_INSTANCE_CAST((object), SUGAR_TYPE_BROWSER, SugarBrowser)) +#define SUGAR_BROWSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SUGAR_TYPE_BROWSER, SugarBrowserClass)) +#define SUGAR_IS_BROWSER(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), SUGAR_TYPE_BROWSER)) +#define SUGAR_IS_BROWSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SUGAR_TYPE_BROWSER)) +#define SUGAR_BROWSER_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), SUGAR_TYPE_BROWSER, SugarBrowserClass)) + +struct _SugarBrowser { + GtkMozEmbed base_instance; + + int total_requests; + int current_requests; + float progress; + char *address; + char *title; + gboolean can_go_back; + gboolean can_go_forward; + gboolean loading; + + gboolean (* mouse_click) (SugarBrowser *browser, + SugarBrowserEvent *event); +}; + +struct _SugarBrowserClass { + GtkMozEmbedClass base_class; + + SugarBrowser * (* create_window) (SugarBrowser *browser); +}; + +GType sugar_browser_get_type (void); +SugarBrowser *sugar_browser_create_window (SugarBrowser *browser); +void sugar_browser_scroll_pixels (SugarBrowser *browser, + int dx, + int dy); +void sugar_browser_grab_focus (SugarBrowser *browser); +gboolean sugar_browser_save_uri (SugarBrowser *browser, + const char *uri, + const char *filename); +gboolean sugar_browser_save_document (SugarBrowser *browser, + const char *filename); + +gboolean sugar_browser_startup (const char *profile_path, + const char *profile_name); +void sugar_browser_shutdown (void); + +#define SUGAR_TYPE_BROWSER_EVENT (sugar_browser_event_get_type()) + +struct _SugarBrowserEvent { + int button; + char *image_uri; + char *image_name; +}; + +GType sugar_browser_event_get_type (void); +SugarBrowserEvent *sugar_browser_event_new (void); +SugarBrowserEvent *sugar_browser_event_copy (SugarBrowserEvent *event); +void sugar_browser_event_free (SugarBrowserEvent *event); + +#define SUGAR_TYPE_BROWSER_METADATA (sugar_browser_metadata_get_type()) + +struct _SugarBrowserMetadata { + char *filename; +}; + +GType sugar_browser_metadata_get_type (void); +SugarBrowserMetadata *sugar_browser_metadata_new (void); +SugarBrowserMetadata *sugar_browser_metadata_copy (SugarBrowserMetadata *event); +void sugar_browser_metadata_free (SugarBrowserMetadata *event); + +G_END_DECLS + +#endif diff --git a/browser/sugar-download-manager.c b/browser/sugar-download-manager.c new file mode 100644 index 0000000..ead3bc8 --- /dev/null +++ b/browser/sugar-download-manager.c @@ -0,0 +1,165 @@ +#include "sugar-marshal.h" +#include "sugar-download.h" +#include "sugar-download-manager.h" + +enum { + DOWNLOAD_STARTED, + DOWNLOAD_COMPLETED, + DOWNLOAD_CANCELLED, + DOWNLOAD_PROGRESS, + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + +static void sugar_download_manager_finalize (GObject *object); +static void sugar_download_remove_download (gpointer key, gpointer value, gpointer user_data); + +G_DEFINE_TYPE (SugarDownloadManager, sugar_download_manager, G_TYPE_OBJECT) + +SugarDownloadManager *DownloadManager = NULL; + +static void +sugar_download_manager_init (SugarDownloadManager *download_manager) +{ + download_manager->downloads = g_hash_table_new (g_str_hash, g_str_equal); +} + +static void +sugar_download_manager_class_init (SugarDownloadManagerClass *download_manager_class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (download_manager_class); + + gobject_class->finalize = sugar_download_manager_finalize; + + signals[DOWNLOAD_STARTED] = + g_signal_new ("download-started", + G_OBJECT_CLASS_TYPE (download_manager_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (SugarDownloadManagerClass, handle_content), + NULL, NULL, + sugar_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + G_TYPE_OBJECT); + + signals[DOWNLOAD_COMPLETED] = + g_signal_new ("download-completed", + G_OBJECT_CLASS_TYPE (download_manager_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (SugarDownloadManagerClass, handle_content), + NULL, NULL, + sugar_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + G_TYPE_OBJECT); + + signals[DOWNLOAD_CANCELLED] = + g_signal_new ("download-cancelled", + G_OBJECT_CLASS_TYPE (download_manager_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (SugarDownloadManagerClass, handle_content), + NULL, NULL, + sugar_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + G_TYPE_OBJECT); + + signals[DOWNLOAD_PROGRESS] = + g_signal_new ("download-progress", + G_OBJECT_CLASS_TYPE (download_manager_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (SugarDownloadManagerClass, handle_content), + NULL, NULL, + sugar_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + G_TYPE_OBJECT); +} + +static void +sugar_download_manager_finalize (GObject *object) +{ + SugarDownloadManager *download_manager = SUGAR_DOWNLOAD_MANAGER (object); + g_hash_table_foreach (download_manager->downloads, sugar_download_remove_download, NULL); + g_hash_table_destroy (download_manager->downloads); +} + +static void +sugar_download_remove_download (gpointer key, gpointer value, gpointer user_data) +{ + g_free (value); +} + +SugarDownloadManager * +sugar_get_download_manager () +{ + if (DownloadManager == NULL) + DownloadManager = g_object_new (SUGAR_TYPE_DOWNLOAD_MANAGER, NULL); + + return DownloadManager; +} + +void +sugar_download_manager_download_started (SugarDownloadManager *download_manager, + const char *url, + const char *mime_type, + const char *file_name) +{ + SugarDownload *download = (SugarDownload *) g_hash_table_lookup ( + download_manager->downloads, + file_name); + + g_return_if_fail (download == NULL); + + download = g_object_new (SUGAR_TYPE_DOWNLOAD, NULL); + sugar_download_set_url (download, url); + sugar_download_set_mime_type (download, mime_type); + sugar_download_set_file_name (download, file_name); + + g_hash_table_insert (download_manager->downloads, + (gpointer)file_name, + download); + + g_signal_emit (download_manager, signals[DOWNLOAD_STARTED], 0, download); +} + +void +sugar_download_manager_download_completed (SugarDownloadManager *download_manager, + const char *file_name) +{ + SugarDownload *download = (SugarDownload *) g_hash_table_lookup ( + download_manager->downloads, + file_name); + + g_return_if_fail (download); + + g_signal_emit (download_manager, signals[DOWNLOAD_COMPLETED], 0, download); + + g_hash_table_remove (download_manager->downloads, file_name); +} + +void sugar_download_manager_download_cancelled (SugarDownloadManager *download_manager, + const char *file_name) +{ + SugarDownload *download = (SugarDownload *) g_hash_table_lookup ( + download_manager->downloads, + file_name); + + g_return_if_fail (download); + + g_signal_emit (download_manager, signals[DOWNLOAD_CANCELLED], 0, download); + + g_hash_table_remove (download_manager->downloads, file_name); +} + +void +sugar_download_manager_update_progress (SugarDownloadManager *download_manager, + const char *file_name, + const int percent) +{ + SugarDownload *download = (SugarDownload *) g_hash_table_lookup ( + download_manager->downloads, + file_name); + + g_return_if_fail (download); + + sugar_download_set_percent (download, percent); + + g_signal_emit (download_manager, signals [DOWNLOAD_PROGRESS], 0, download); +} diff --git a/browser/sugar-download-manager.h b/browser/sugar-download-manager.h new file mode 100644 index 0000000..c58436b --- /dev/null +++ b/browser/sugar-download-manager.h @@ -0,0 +1,57 @@ +#ifndef __SUGAR_DOWNLOAD_MANAGER_H__ +#define __SUGAR_DOWNLOAD_MANAGER_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _SugarDownloadManager SugarDownloadManager; +typedef struct _SugarDownloadManagerClass SugarDownloadManagerClass; + +#define SUGAR_TYPE_DOWNLOAD_MANAGER (sugar_download_manager_get_type()) +#define SUGAR_DOWNLOAD_MANAGER(object) (G_TYPE_CHECK_INSTANCE_CAST((object), SUGAR_TYPE_DOWNLOAD_MANAGER, SugarDownloadManager)) +#define SUGAR_DOWNLOAD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SUGAR_TYPE_DOWNLOAD_MANAGER, SugarDownloadManagerClass)) +#define SUGAR_IS_DOWNLOAD_MANAGER(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), SUGAR_TYPE_DOWNLOAD_MANAGER)) +#define SUGAR_IS_DOWNLOAD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SUGAR_TYPE_DOWNLOAD_MANAGER)) +#define SUGAR_DOWNLOAD_MANAGER_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), SUGAR_TYPE_DOWNLOAD_MANAGER, SugarDownloadManagerClass)) + +struct _SugarDownloadManager { + GObject base_instance; + + GHashTable *downloads; +}; + +struct _SugarDownloadManagerClass { + GObjectClass base_class; + + void (* handle_content) (char *url, char *tmp_file_name); + +}; + +GType sugar_download_manager_get_type(void); + +SugarDownloadManager *sugar_get_download_manager(void); + +void sugar_download_manager_download_started( + SugarDownloadManager *download_manager, + const char *url, + const char *mime_type, + const char *tmp_file_name); + +void sugar_download_manager_download_completed( + SugarDownloadManager *download_manager, + const char *tmp_file_name); + +void sugar_download_manager_download_cancelled( + SugarDownloadManager *download_manager, + const char *tmp_file_name); + +void sugar_download_manager_update_progress( + SugarDownloadManager *download_manager, + const char *tmp_file_name, + const int percent); + +G_END_DECLS + +#endif diff --git a/browser/sugar-download.c b/browser/sugar-download.c new file mode 100644 index 0000000..01ad809 --- /dev/null +++ b/browser/sugar-download.c @@ -0,0 +1,108 @@ +#include "sugar-download.h" + +static void sugar_download_finalize (GObject *object); + +G_DEFINE_TYPE (SugarDownload, sugar_download, G_TYPE_OBJECT) + +static void +sugar_download_init (SugarDownload *download) +{ + download->file_name = NULL; + download->url = NULL; + download->mime_type = NULL; + download->percent = 0; +} + +static void +sugar_download_class_init (SugarDownloadClass *download_class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (download_class); + + gobject_class->finalize = sugar_download_finalize; +} + +void +sugar_download_set_file_name (SugarDownload *download, const gchar *file_name) +{ + gchar *new_file_name; + + g_return_if_fail (SUGAR_IS_DOWNLOAD (download)); + + new_file_name = g_strdup (file_name); + g_free (download->file_name); + download->file_name = new_file_name; +} + +void +sugar_download_set_url (SugarDownload *download, const gchar *url) +{ + gchar *new_url; + + g_return_if_fail (SUGAR_IS_DOWNLOAD (download)); + + new_url = g_strdup (url); + g_free (download->url); + download->url = new_url; +} + +void +sugar_download_set_mime_type (SugarDownload *download, const gchar *mime_type) +{ + gchar *new_mime_type; + + g_return_if_fail (SUGAR_IS_DOWNLOAD (download)); + + new_mime_type = g_strdup (mime_type); + g_free (download->mime_type); + download->mime_type = new_mime_type; +} + +void +sugar_download_set_percent (SugarDownload *download, const gint percent) +{ + g_return_if_fail (SUGAR_IS_DOWNLOAD (download)); + + download->percent = percent; +} + +const gchar * +sugar_download_get_file_name (SugarDownload *download) +{ + g_return_val_if_fail (SUGAR_IS_DOWNLOAD (download), NULL); + + return download->file_name; +} + +const gchar * +sugar_download_get_url (SugarDownload *download) +{ + g_return_val_if_fail (SUGAR_IS_DOWNLOAD (download), NULL); + + return download->url; +} + +const gchar * +sugar_download_get_mime_type (SugarDownload *download) +{ + g_return_val_if_fail (SUGAR_IS_DOWNLOAD (download), NULL); + + return download->mime_type; +} + +gint +sugar_download_get_percent (SugarDownload *download) +{ + g_return_val_if_fail (SUGAR_IS_DOWNLOAD (download), -1); + + return download->percent; +} + +static void +sugar_download_finalize (GObject *object) +{ + SugarDownload *download = SUGAR_DOWNLOAD (object); + + g_free (download->file_name); + g_free (download->url); + g_free (download->mime_type); +} diff --git a/browser/sugar-download.h b/browser/sugar-download.h new file mode 100644 index 0000000..ac3760b --- /dev/null +++ b/browser/sugar-download.h @@ -0,0 +1,50 @@ +#ifndef __SUGAR_DOWNLOAD_H__ +#define __SUGAR_DOWNLOAD_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _SugarDownload SugarDownload; +typedef struct _SugarDownloadClass SugarDownloadClass; + +#define SUGAR_TYPE_DOWNLOAD (sugar_download_get_type()) +#define SUGAR_DOWNLOAD(object) (G_TYPE_CHECK_INSTANCE_CAST((object), SUGAR_TYPE_DOWNLOAD, SugarDownload)) +#define SUGAR_DOWNLOAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SUGAR_TYPE_DOWNLOAD, SugarDownloadClass)) +#define SUGAR_IS_DOWNLOAD(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), SUGAR_TYPE_DOWNLOAD)) +#define SUGAR_IS_DOWNLOAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SUGAR_TYPE_DOWNLOAD)) +#define SUGAR_DOWNLOAD_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), SUGAR_TYPE_DOWNLOAD, SugarDownloadClass)) + +struct _SugarDownload { + GObject base_instance; + + gchar *file_name; + gchar *url; + gchar *mime_type; + gint percent; +}; + +struct _SugarDownloadClass { + GObjectClass base_class; +}; + +GType sugar_download_get_type(void); + +void sugar_download_set_file_name (SugarDownload *download, + const gchar *file_name); +void sugar_download_set_url (SugarDownload *download, + const gchar *url); +void sugar_download_set_mime_type (SugarDownload *download, + const gchar *mime_type); +void sugar_download_set_percent (SugarDownload *download, + const gint percent); + +const gchar *sugar_download_get_file_name (SugarDownload *download); +const gchar *sugar_download_get_url (SugarDownload *download); +const gchar *sugar_download_get_mime_type (SugarDownload *download); +gint sugar_download_get_percent (SugarDownload *download); + +G_END_DECLS + +#endif /* __SUGAR_DOWNLOAD_H__ */ diff --git a/browser/sugar-marshal.list b/browser/sugar-marshal.list new file mode 100644 index 0000000..81b3ae1 --- /dev/null +++ b/browser/sugar-marshal.list @@ -0,0 +1,4 @@ +VOID:OBJECT,STRING,LONG,LONG +VOID:OBJECT,LONG +VOID:OBJECT +BOOLEAN:BOXED -- cgit v0.9.1