aboutsummaryrefslogtreecommitdiffstats
path: root/embed/mozilla/GeckoPrintSession.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'embed/mozilla/GeckoPrintSession.cpp')
-rw-r--r--embed/mozilla/GeckoPrintSession.cpp622
1 files changed, 622 insertions, 0 deletions
diff --git a/embed/mozilla/GeckoPrintSession.cpp b/embed/mozilla/GeckoPrintSession.cpp
new file mode 100644
index 000000000..4d184eb9f
--- /dev/null
+++ b/embed/mozilla/GeckoPrintSession.cpp
@@ -0,0 +1,622 @@
+/*
+ * Copyright (C) 2006 Christian Persch
+ *
+ * This program 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.1, or (at your option)
+ * any later version.
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#include "mozilla-config.h"
+#include "config.h"
+
+#include <unistd.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <nsStringAPI.h>
+
+#include <nsIDOMWindow.h>
+#include <nsIDOMWindowInternal.h>
+#include <nsIPrintSettings.h>
+
+#include "ephy-debug.h"
+#include "ephy-embed-shell.h"
+#include "ephy-file-helpers.h"
+
+#include "EphyUtils.h"
+
+#include "GeckoPrintSession.h"
+
+#define MAX_STRING_LENGTH 512
+
+GeckoPrintSession::GeckoPrintSession ()
+: mSettings(NULL)
+, mPageSetup(NULL)
+, mPrinter(NULL)
+, mJob(NULL)
+, mProgressDialog(NULL)
+, mTitleLabel(NULL)
+, mProgressBar(NULL)
+, mStartPrintIdleID(0)
+, mSourceFileIsTemp(PR_FALSE)
+, mDone(PR_FALSE)
+, mCancelled(PR_FALSE)
+{
+ LOG ("GeckoPrintSession ctor [%p]", (void*) this);
+
+ /* FIXME: connect to "prepare-close" ? */
+ g_object_ref (ephy_embed_shell_get_default ());
+}
+
+GeckoPrintSession::~GeckoPrintSession ()
+{
+ LOG ("GeckoPrintSession dtor [%p]", (void*) this);
+
+ NS_ASSERTION (mStartPrintIdleID == 0, "Impossible");
+
+ if (!mDone && !mCancelled) {
+ Cancel ();
+ }
+ DestroyJob ();
+
+ if (mSettings) {
+ g_object_unref (mSettings);
+ }
+ if (mPageSetup) {
+ g_object_unref (mPageSetup);
+ }
+ if (mPrinter) {
+ g_object_unref (mPrinter);
+ }
+ if (mProgressDialog) {
+ gtk_widget_destroy (mProgressDialog);
+ }
+ if (mSourceFileIsTemp) {
+ unlink (mSourceFile.get ());
+ }
+
+ g_object_unref (ephy_embed_shell_get_default ());
+}
+
+void
+GeckoPrintSession::GetSourceFile (nsACString &aSource)
+{
+ aSource.Assign (mSourceFile);
+}
+
+nsresult
+GeckoPrintSession::SetSettings (GtkPrintSettings *aSettings,
+ GtkPageSetup *aPageSetup,
+ GtkPrinter *aPrinter)
+{
+ NS_ASSERTION (!mSettings && !mPageSetup && !mPrinter, "Already have settings!");
+
+ NS_ENSURE_ARG (aSettings);
+ mSettings = aSettings; /* this one is adopted */
+
+ NS_ENSURE_ARG (aPageSetup);
+ NS_ENSURE_ARG (aPrinter);
+
+ mPageSetup = (GtkPageSetup *) g_object_ref (aPageSetup);
+ mPrinter = (GtkPrinter *) g_object_ref (aPrinter);
+
+ /* Compute the source file name */
+ if (gtk_print_settings_get_print_to_file (mSettings)) {
+ /* FIXME: support gnome-VFS uris here! */
+ const char *fileURI = gtk_print_settings_get (aSettings, "export-uri");
+ NS_ENSURE_TRUE (fileURI, NS_ERROR_FAILURE);
+
+ char *fileName = g_filename_from_uri (fileURI, NULL, NULL);
+ NS_ENSURE_TRUE (fileURI, NS_ERROR_FAILURE);
+
+ mSourceFile.Assign (fileName);
+ g_free (fileName);
+ } else {
+ char *base, *tmpName;
+
+ /* FIXME: use pure glib here! */
+ base = g_build_filename (ephy_file_tmp_dir (), "print-XXXXXX", (const char *) NULL);
+ tmpName = ephy_file_tmp_filename (base, "ps");
+ g_free (base);
+
+ NS_ENSURE_TRUE (tmpName, NS_ERROR_FAILURE);
+ mSourceFile.Assign (tmpName);
+ g_free (tmpName);
+
+ mSourceFileIsTemp = PR_TRUE;
+ }
+
+ return NS_OK;
+}
+
+/* static methods */
+
+/* static */ GeckoPrintSession *
+GeckoPrintSession::FromSettings (nsIPrintSettings *aSettings)
+{
+ nsresult rv;
+ nsCOMPtr<nsIPrintSession> session;
+ rv = aSettings->GetPrintSession (getter_AddRefs (session));
+ NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && session, nsnull);
+
+ /* this is ok since the caller holds a ref to the settings which hold a ref to the session */
+ nsIPrintSession *sessionPtr = session.get();
+ return NS_STATIC_CAST (GeckoPrintSession*, sessionPtr);
+}
+
+/* static functions */
+
+static void
+ReleaseSession (GeckoPrintSession *aSession)
+{
+ NS_RELEASE (aSession);
+}
+
+static gboolean
+ProgressDeleteCallback (GtkDialog *aDialog)
+{
+ gtk_dialog_response (aDialog, GTK_RESPONSE_DELETE_EVENT);
+ return TRUE;
+}
+
+static void
+ProgressResponseCallback (GtkDialog *aDialog,
+ int aResponse,
+ GeckoPrintSession *aSession)
+{
+ aSession->Cancel ();
+}
+
+static gboolean
+StartPrintIdleCallback (GeckoPrintSession *aSession)
+{
+ aSession->StartPrinting ();
+
+ return FALSE;
+}
+
+static void
+JobStatusChangedCallback (GtkPrintJob *aJob,
+ GeckoPrintSession *aSession)
+{
+ aSession->JobStatusChanged ();
+}
+
+static void
+JobCompletedCallback (GtkPrintJob *aJob,
+ GeckoPrintSession *aSession,
+ GError *aError)
+{
+ aSession->JobDone ();
+
+ if (aError) {
+ aSession->JobError (aError->message);
+ }
+}
+
+/* Private methods */
+
+void
+GeckoPrintSession::SetProgress (PRInt32 aCurrent,
+ PRInt32 aMaximum)
+{
+ NS_ENSURE_TRUE (mProgressDialog, );
+
+ if (mCancelled) return;
+
+ /* Mozilla is weird */
+ if (aCurrent > aMaximum || (aCurrent == 100 && aMaximum == 100)) return;
+
+ double fraction = 0.0;
+ if (aMaximum > 0 && aCurrent >= 0) {
+ char *text = g_strdup_printf (_("Page %d of %d"), aCurrent, aMaximum);
+ gtk_progress_bar_set_text (GTK_PROGRESS_BAR (mProgressBar), text);
+ g_free (text);
+
+ fraction = (double) aCurrent / (double) aMaximum;
+ }
+
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (mProgressBar), CLAMP (fraction, 0.0, 1.0));
+}
+
+void
+GeckoPrintSession::SetProgressText (const char *aText)
+{
+ NS_ENSURE_TRUE (mProgressDialog, );
+
+ gtk_progress_bar_set_text (GTK_PROGRESS_BAR (mProgressBar), aText);
+}
+
+void
+GeckoPrintSession::Cancel ()
+{
+ SetProcessCanceledByUser (PR_TRUE);
+
+ if (mProgressDialog) {
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (mProgressDialog),
+ GTK_RESPONSE_CANCEL, FALSE);
+
+ SetProgress (0, 0);
+ SetProgressText (_("Cancelling print"));
+ }
+
+ if (mJob) {
+ /* FIXME: There's no way to cancel mJob! Bug #339323 */
+ }
+}
+
+void
+GeckoPrintSession::StartPrinting ()
+{
+ mStartPrintIdleID = 0;
+
+ GError *error = NULL;
+
+ /* FIXME: this could also be a print job to a file which was
+ * printed to a temp file and now needs to be uploaded to its
+ * final location with gnome-vfs.
+ */
+ if (gtk_print_settings_get_print_to_file (mSettings)) return;
+
+ NS_ENSURE_TRUE (mSettings && mPageSetup && mPrinter, );
+
+ mJob = gtk_print_job_new (mTitle.get (),
+ mPrinter,
+ mSettings,
+ mPageSetup);
+ if (!gtk_print_job_set_source_file (mJob, mSourceFile.get (), &error)) {
+ g_warning ("Couldn't set print job source: %s", error->message);
+ g_error_free (error);
+
+ g_object_unref (mJob);
+ mJob = NULL;
+
+ return;
+ }
+
+ /* Keep us alive until the job is done! */
+ NS_ADDREF_THIS ();
+ if (!gtk_print_job_send (mJob,
+ (GtkPrintJobCompleteFunc) JobCompletedCallback,
+ this,
+ (GDestroyNotify) ReleaseSession,
+ &error)) {
+ g_warning ("Couldn't start print job: %s", error->message);
+ g_error_free (error);
+
+ g_object_unref (mJob);
+ mJob = NULL;
+
+ NS_RELEASE_THIS ();
+ return;
+ };
+
+ g_signal_connect (mJob, "status-changed",
+ G_CALLBACK (JobStatusChangedCallback), this);
+}
+
+void
+GeckoPrintSession::JobStatusChanged ()
+{
+ NS_ENSURE_TRUE (mProgressDialog, );
+
+ LOG ("print session %p status changed %d\n", this, gtk_print_job_get_status (mJob));
+
+ if (gtk_print_job_get_status (mJob) == GTK_PRINT_STATUS_SENDING_DATA) {
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (mProgressBar), 0.75);
+ SetProgressText (_("Spooling..."));
+ }
+}
+
+void
+GeckoPrintSession::JobError (const char *aErrorMessage)
+{
+ LOG ("print job error: %s", aErrorMessage);
+
+ /* FIXME better text */
+ GtkWidget *dialog = gtk_message_dialog_new (NULL,
+ GtkDialogFlags (0),
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Print error"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s", aErrorMessage);
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ gtk_widget_show (dialog);
+}
+
+void
+GeckoPrintSession::JobDone ()
+{
+ NS_ENSURE_TRUE (mProgressDialog, );
+
+ mDone = PR_TRUE;
+
+ gtk_widget_hide (mProgressDialog);
+
+ DestroyJob ();
+}
+
+void
+GeckoPrintSession::DestroyJob ()
+{
+ NS_ENSURE_TRUE (mJob, );
+
+ g_signal_handlers_disconnect_by_func (mJob, (void*) JobStatusChangedCallback, this);
+ g_object_unref (mJob);
+ mJob = NULL;
+}
+
+void
+GeckoPrintSession::LaunchJobOnIdle ()
+{
+ NS_ASSERTION (!mStartPrintIdleID, "Already started printing!");
+
+ /* Don't send the job to the printer if the user cancelled the print */
+ if (mCancelled) return;
+
+ /* Keep us alive until the idle handler runs! */
+ NS_ADDREF_THIS ();
+ mStartPrintIdleID = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+ (GSourceFunc) StartPrintIdleCallback,
+ this,
+ (GDestroyNotify) ReleaseSession);
+}
+
+/* XPCOM interfaces */
+
+NS_IMPL_THREADSAFE_ISUPPORTS5 (GeckoPrintSession,
+ nsIPrintSession,
+ nsIWebProgressListener,
+ nsIPrintProgress,
+ nsIPrintProgressParams,
+ nsISupportsWeakReference)
+
+/* nsIPrintSession implementation */
+
+/* nsIWebProgressListener implementation */
+
+/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in nsresult aStatus); */
+NS_IMETHODIMP
+GeckoPrintSession::OnStateChange (nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ PRUint32 aStateFlags,
+ nsresult aStatus)
+{
+ if (NS_SUCCEEDED (aStatus) &&
+ aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) {
+ if (aStateFlags & nsIWebProgressListener::STATE_START) {
+ /* Printing starts now */
+ SetProgress (0, 0);
+ } else if ((aStateFlags & nsIWebProgressListener::STATE_STOP)) {
+ /* Printing done, upload to printer */
+ LaunchJobOnIdle ();
+ }
+ }
+
+ return NS_OK;
+}
+
+/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
+NS_IMETHODIMP
+GeckoPrintSession::OnProgressChange (nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ PRInt32 aCurSelfProgress,
+ PRInt32 aMaxSelfProgress,
+ PRInt32 aCurTotalProgress,
+ PRInt32 aMaxTotalProgress)
+{
+ SetProgress (aCurTotalProgress, aMaxTotalProgress);
+
+ return NS_OK;
+}
+
+/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI aLocation); */
+NS_IMETHODIMP
+GeckoPrintSession::OnLocationChange (nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ nsIURI *aLocation)
+{
+ NS_ASSERTION (0, "OnLocationChange reached!");
+ return NS_OK;
+}
+
+/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
+NS_IMETHODIMP
+GeckoPrintSession::OnStatusChange (nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ nsresult aStatus,
+ const PRUnichar *aMessage)
+{
+ NS_ASSERTION (0, "OnStatusChange reached!");
+ return NS_OK;
+}
+
+/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aState); */
+NS_IMETHODIMP
+GeckoPrintSession::OnSecurityChange (nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ PRUint32 aState)
+{
+ NS_ASSERTION (0, "OnSecurityChange reached!");
+ return NS_OK;
+}
+
+/* nsIPrintProgress implementation */
+
+/* void openProgressDialog (in nsIDOMWindowInternal parent, in string dialogURL, in nsISupports parameters, in nsIObserver openDialogObserver, out boolean notifyOnOpen); */
+NS_IMETHODIMP
+GeckoPrintSession::OpenProgressDialog (nsIDOMWindowInternal *aParent,
+ const char *aDialogURL,
+ nsISupports *aParameters,
+ nsIObserver *aOpenDialogObserver,
+ PRBool *_notifyOnOpen)
+{
+ NS_ENSURE_STATE (!mProgressDialog);
+
+ nsCOMPtr<nsIDOMWindow> domWindow (do_QueryInterface (aParent));
+ GtkWidget *parent = EphyUtils::FindGtkParent (domWindow);
+
+ GtkWidget *vbox, *hbox, *image;
+
+ mProgressDialog = gtk_dialog_new ();
+ GtkDialog *dialog = GTK_DIALOG (mProgressDialog);
+
+ gtk_dialog_add_button (dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+
+ g_signal_connect (dialog, "delete-event",
+ G_CALLBACK (ProgressDeleteCallback), NULL);
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (ProgressResponseCallback), this);
+
+ /* FIXME do we need transient? initially on top should suffice */
+ gtk_window_set_transient_for (GTK_WINDOW (dialog),
+ GTK_WINDOW (parent));
+
+ gtk_dialog_set_has_separator (dialog, FALSE);
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (dialog->vbox), 14); /* 2 * 5 + 14 = 24 */
+ gtk_box_set_spacing (GTK_BOX (dialog->action_area), 6);
+
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+ gtk_container_add (GTK_CONTAINER (dialog->vbox), hbox);
+
+ image = gtk_image_new_from_stock (GTK_STOCK_PRINT, GTK_ICON_SIZE_DIALOG);
+ gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+ gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+
+ vbox = gtk_vbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+
+ mTitleLabel = gtk_label_new (NULL);
+ gtk_label_set_line_wrap (GTK_LABEL (mTitleLabel), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (mTitleLabel), 0.0, 0.0);
+ gtk_box_pack_start (GTK_BOX (vbox), mTitleLabel, FALSE, FALSE, 0);
+
+ mProgressBar = gtk_progress_bar_new ();
+ gtk_box_pack_start (GTK_BOX (vbox), mProgressBar, FALSE, FALSE, 0);
+
+ gtk_widget_show_all (hbox);
+ gtk_window_present (GTK_WINDOW (dialog));
+
+ *_notifyOnOpen = PR_FALSE;
+
+ return NS_OK;
+}
+
+/* void closeProgressDialog (in boolean forceClose); */
+NS_IMETHODIMP
+GeckoPrintSession::CloseProgressDialog (PRBool forceClose)
+{
+ return NS_OK;
+}
+
+/* void registerListener (in nsIWebProgressListener listener); */
+NS_IMETHODIMP
+GeckoPrintSession::RegisterListener (nsIWebProgressListener *listener)
+{
+ return NS_OK;
+}
+
+/* void unregisterListener (in nsIWebProgressListener listener); */
+NS_IMETHODIMP
+GeckoPrintSession::UnregisterListener (nsIWebProgressListener *listener)
+{
+ return NS_OK;
+}
+
+/* void doneIniting (); */
+NS_IMETHODIMP
+GeckoPrintSession::DoneIniting()
+{
+ return NS_OK;
+}
+
+/* nsIPrompt getPrompter (); */
+NS_IMETHODIMP
+GeckoPrintSession::GetPrompter (nsIPrompt **_retval)
+{
+ g_return_val_if_reached (NS_ERROR_NOT_IMPLEMENTED);
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* attribute boolean processCanceledByUser; */
+NS_IMETHODIMP
+GeckoPrintSession::GetProcessCanceledByUser (PRBool *aProcessCanceledByUser)
+{
+ *aProcessCanceledByUser = mCancelled;
+ return NS_OK;
+}
+NS_IMETHODIMP
+GeckoPrintSession::SetProcessCanceledByUser (PRBool aProcessCanceledByUser)
+{
+ mCancelled = aProcessCanceledByUser;
+ return NS_OK;
+}
+
+/* nsIPrintProgressParams implementation */
+
+/* attribute wstring docTitle; */
+NS_IMETHODIMP
+GeckoPrintSession::GetDocTitle (PRUnichar * *aDocTitle)
+{
+ g_return_val_if_reached (NS_ERROR_NOT_IMPLEMENTED);
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+GeckoPrintSession::SetDocTitle (const PRUnichar * aDocTitle)
+{
+ NS_ENSURE_STATE (mProgressDialog);
+
+ char *converted = EphyUtils::ConvertUTF16toUTF8 (aDocTitle, MAX_STRING_LENGTH);
+ if (converted) {
+ mTitle.Assign (converted);
+
+ char *title = g_strdup_printf (_("Printing ā€œ%sā€"), converted);
+ gtk_window_set_title (GTK_WINDOW (mProgressDialog), title);
+ gtk_label_set_text (GTK_LABEL (mTitleLabel), title);
+ g_free (converted);
+ g_free (title);
+ }
+ return NS_OK;
+}
+
+/* attribute wstring docURL; */
+NS_IMETHODIMP
+GeckoPrintSession::GetDocURL (PRUnichar * *aDocURL)
+{
+ g_return_val_if_reached (NS_ERROR_NOT_IMPLEMENTED);
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+GeckoPrintSession::SetDocURL (const PRUnichar * aDocURL)
+{
+#if 0
+ NS_ENSURE_STATE (mJob);
+
+ char *converted = EphyUtils::ConvertUTF16toUTF8 (aDocTitle, MAX_STRING_LENGTH);
+ if (converted) {
+ g_free (converted);
+ }
+#endif
+ return NS_OK;
+}