/* * Copyright (c) 2003 Benedikt Meurer (benedikt.meurer@unix-ag.uni-siegen.de) * 2004-2006 Jean-François Wauthy (pollux@xfce.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 Library General Public License for more details. * * You should have received a copy of the GNU 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. */ #ifdef HAVE_CONFIG_H #include #endif /* !HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include #define PRINTER_QUEUE_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ PRINTER_QUEUE_WINDOW_TYPE, PrinterQueueWindowPrivate)) struct _PrinterQueueWindowPrivate { PrintingSystem *ps; gchar *printer; GtkIconTheme *icontheme; GtkUIManager *ui_manager; GtkActionGroup *action_group; GtkWidget *treeview; guint timeout_id; }; /* Prototypes */ static void printer_queue_window_class_init (PrinterQueueWindowClass * klass); static void printer_queue_window_init (PrinterQueueWindow * obj); static void action_close_cb (GtkAction * action, PrinterQueueWindow * win); static void action_remove_job_cb (GtkAction * action, PrinterQueueWindow * win); static void action_refresh_cb (GtkAction * action, PrinterQueueWindow * win); static void icon_theme_changed_cb (GtkIconTheme * icon_theme, PrinterQueueWindow * win); static void tree_selection_changed_cb (GtkTreeSelection * selection, PrinterQueueWindow * win); static gboolean tree_button_pressed_cb (GtkWidget * widget, GdkEventButton * event, PrinterQueueWindow * win); static gboolean timeout_fct (PrinterQueueWindow * win); /* globals */ static GtkWindowClass *parent_class = NULL; static GtkActionEntry action_entries[] = { {"printer-menu", NULL, N_("Printer"), NULL,}, {"close", GTK_STOCK_CLOSE, N_("Close"), NULL, N_("Close queue window"), G_CALLBACK (action_close_cb),}, {"jobs-menu", NULL, N_("Jobs"), NULL,}, {"remove-job", GTK_STOCK_REMOVE, N_("Remove job"), "Delete", N_("Remove the selected job from the queue"), G_CALLBACK (action_remove_job_cb),}, {"refresh", GTK_STOCK_REFRESH, N_("Refresh"), "F5", N_("Refresh queue"), G_CALLBACK (action_refresh_cb),}, }; /*********/ /* class */ /*********/ GType printer_queue_window_get_type () { static GType type = 0; if (type == 0) { static const GTypeInfo our_info = { sizeof (PrinterQueueWindowClass), NULL, NULL, (GClassInitFunc) printer_queue_window_class_init, NULL, NULL, sizeof (PrinterQueueWindow), 0, (GInstanceInitFunc) printer_queue_window_init, }; type = g_type_register_static (GTK_TYPE_WINDOW, "PrinterQueueWindow", &our_info, 0); } return type; } static void printer_queue_window_init (PrinterQueueWindow * win) { PrinterQueueWindowPrivate *priv; GError *error = NULL; GtkAccelGroup *accel_group; GtkWidget *vbox; GtkWidget *menubar; GtkListStore *store; GtkWidget *scrollwin; GtkTreeSelection *selection; GtkCellRenderer *cell; GtkTreeViewColumn *column; priv = win->priv = PRINTER_QUEUE_WINDOW_GET_PRIVATE (win); priv->icontheme = gtk_icon_theme_get_default (); g_signal_connect (G_OBJECT (priv->icontheme), "changed", G_CALLBACK (icon_theme_changed_cb), win); gtk_window_set_title (GTK_WINDOW (win), _("Queue Manager")); gtk_window_set_icon_name (GTK_WINDOW (win), "printer"); gtk_window_set_default_size (GTK_WINDOW (win), 450, 150); gtk_window_set_position (GTK_WINDOW (win), GTK_WIN_POS_NONE); /* ui manager */ priv->action_group = gtk_action_group_new ("printer-queue-default"); gtk_action_group_set_translation_domain (priv->action_group, GETTEXT_PACKAGE); gtk_action_group_add_actions (priv->action_group, action_entries, G_N_ELEMENTS (action_entries), GTK_WIDGET (win)); priv->ui_manager = gtk_ui_manager_new (); gtk_ui_manager_insert_action_group (priv->ui_manager, priv->action_group, 0); if (gtk_ui_manager_add_ui_from_string (priv->ui_manager, "" "" " " " " " " " " " " " " " " " " " " " " " " "" "" " " " " "" "", -1, &error) == 0) { g_warning ("Unable to build the user interface correctly : %s", error->message); g_error_free (error); } gtk_ui_manager_ensure_update (priv->ui_manager); accel_group = gtk_ui_manager_get_accel_group (priv->ui_manager); gtk_window_add_accel_group (GTK_WINDOW (win), accel_group); /* contents */ vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (win), vbox); /* menubar */ menubar = gtk_ui_manager_get_widget (priv->ui_manager, "/main-menu"); if (G_LIKELY (menubar != NULL)) { gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0); gtk_widget_show (menubar); } /* Add treeview */ store = gtk_list_store_new (JOBS_N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); scrollwin = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start (GTK_BOX (vbox), scrollwin, TRUE, TRUE, 0); priv->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); gtk_container_add (GTK_CONTAINER (scrollwin), priv->treeview); g_signal_connect (G_OBJECT (priv->treeview), "button-press-event", G_CALLBACK (tree_button_pressed_cb), win); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview)); g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (tree_selection_changed_cb), win); /* Columns in treeview */ cell = gtk_cell_renderer_pixbuf_new (); column = gtk_tree_view_column_new (); gtk_tree_view_column_pack_start (column, cell, FALSE); gtk_tree_view_column_set_attributes (column, cell, "pixbuf", JOBS_ICON_COLUMN, NULL); g_object_set (cell, "xalign", 0.0, "ypad", 0, NULL); cell = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (column, cell, TRUE); gtk_tree_view_column_set_attributes (column, cell, "markup", JOBS_NAME_COLUMN, NULL); g_object_set (cell, "ypad", 0, "yalign", 0.5, NULL); gtk_tree_view_column_set_title (column, _("Name")); gtk_tree_view_append_column (GTK_TREE_VIEW (priv->treeview), column); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->treeview), JOBS_ID_COLUMN, _("ID"), gtk_cell_renderer_text_new (), "text", JOBS_ID_COLUMN, NULL); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->treeview), JOBS_USER_COLUMN, _("User"), gtk_cell_renderer_text_new (), "text", JOBS_USER_COLUMN, NULL); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->treeview), JOBS_STATE_COLUMN, _("State"), gtk_cell_renderer_text_new (), "text", JOBS_STATE_COLUMN, NULL); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->treeview), JOBS_SIZE_COLUMN, _("Size"), gtk_cell_renderer_text_new (), "text", JOBS_SIZE_COLUMN, NULL); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->treeview), JOBS_PRIORITY_COLUMN, _("Priority"), gtk_cell_renderer_text_new (), "text", JOBS_PRIORITY_COLUMN, NULL); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->treeview), JOBS_CREATION_TIME_COLUMN, _("Creation time"), gtk_cell_renderer_text_new (), "text", JOBS_CREATION_TIME_COLUMN, NULL); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->treeview), JOBS_PROCESSING_TIME_COLUMN, _("Processing time"), gtk_cell_renderer_text_new (), "text", JOBS_PROCESSING_TIME_COLUMN, NULL); gtk_widget_show_all (vbox); } static void printer_queue_window_finalize (GObject * object) { PrinterQueueWindow *cobj; PrinterQueueWindowPrivate *priv = PRINTER_QUEUE_WINDOW_GET_PRIVATE (object); cobj = PRINTER_QUEUE_WINDOW (object); if (priv->timeout_id > 0) g_source_remove (priv->timeout_id); g_free (priv->printer); G_OBJECT_CLASS (parent_class)->finalize (object); } static void printer_queue_window_class_init (PrinterQueueWindowClass * klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); g_type_class_add_private (klass, sizeof (PrinterQueueWindowPrivate)); parent_class = g_type_class_peek_parent (klass); object_class->finalize = printer_queue_window_finalize; } /*****************************/ /* Manage icon theme changes */ /*****************************/ static gboolean icon_theme_update_foreach_func (GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, PrinterQueueWindow * win) { PrinterQueueWindowPrivate *priv = PRINTER_QUEUE_WINDOW_GET_PRIVATE (win); GdkPixbuf *icon; gint x, y; gtk_tree_model_get (model, iter, JOBS_ICON_COLUMN, &icon, -1); if (icon) g_object_unref (icon); if (gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &x, &y)) icon = gtk_icon_theme_load_icon (priv->icontheme, "gnome-mime-application-postscript", x, 0, NULL); else icon = gtk_icon_theme_load_icon (priv->icontheme, "gnome-mime-application-postscript", 24, 0, NULL); gtk_list_store_set (GTK_LIST_STORE (model), iter, JOBS_ICON_COLUMN, icon, -1); g_object_unref (icon); return FALSE; } static void icon_theme_changed_cb (GtkIconTheme * icon_theme, PrinterQueueWindow * win) { PrinterQueueWindowPrivate *priv = PRINTER_QUEUE_WINDOW_GET_PRIVATE (win); GtkTreeModel *model; model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview)); if (model) gtk_tree_model_foreach (model, (GtkTreeModelForeachFunc) & icon_theme_update_foreach_func, win); } static gboolean tree_button_pressed_cb (GtkWidget * widget, GdkEventButton * event, PrinterQueueWindow * win) { /* Right click draws the context menu */ if ((event->button == 3) && (event->type == GDK_BUTTON_PRESS)) { PrinterQueueWindowPrivate *priv = PRINTER_QUEUE_WINDOW_GET_PRIVATE (win); GtkTreePath *path; if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (priv->treeview), event->x, event->y, &path, NULL, NULL, NULL)) { GtkTreeSelection *selection; GtkWidget *menu; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview)); gtk_tree_selection_unselect_all (selection); gtk_tree_selection_select_path (selection, path); menu = gtk_ui_manager_get_widget (priv->ui_manager, "/popup-menu"); if (G_LIKELY (menu != NULL)) { gtk_widget_show (menu); gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time ()); return TRUE; } } } return FALSE; } static void tree_selection_changed_cb (GtkTreeSelection * selection, PrinterQueueWindow * win) { PrinterQueueWindowPrivate *priv = PRINTER_QUEUE_WINDOW_GET_PRIVATE (win); GtkAction *action = NULL; GtkTreeModel *model; GtkTreeIter iter; gtk_action_group_get_action (priv->action_group, "remove-job"); if (G_LIKELY (action)) { if (gtk_tree_selection_get_selected (selection, &model, &iter)) gtk_action_set_sensitive (action, TRUE); else gtk_action_set_sensitive (action, FALSE); } } static gboolean timeout_fct (PrinterQueueWindow * win) { action_refresh_cb (NULL, win); return TRUE; } /*---------*/ /* actions */ /*---------*/ static void action_close_cb (GtkAction * action, PrinterQueueWindow * win) { gtk_widget_destroy (GTK_WIDGET (win)); } static void action_remove_job_cb (GtkAction * action, PrinterQueueWindow * win) { PrinterQueueWindowPrivate *priv = PRINTER_QUEUE_WINDOW_GET_PRIVATE (win); GtkTreeModel *model; GtkTreeIter iter; GtkTreeSelection *selection; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview)); if (selection && gtk_tree_selection_get_selected (selection, &model, &iter)) { gint response = GTK_RESPONSE_NONE; gchar *string_id; gchar *string_title; gchar *dialog_message; gtk_tree_model_get (model, &iter, JOBS_NAME_COLUMN, &string_title, JOBS_ID_COLUMN, &string_id, -1); dialog_message = g_strdup_printf ("%s%s (%s) ?", _("Are you sure you want to remove the job "), string_id, string_title); response = xfce_message_dialog (GTK_WINDOW (win), _("Remove job"), GTK_STOCK_DIALOG_QUESTION, dialog_message, NULL, XFCE_CUSTOM_STOCK_BUTTON, _("Don't remove job"), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, XFCE_CUSTOM_STOCK_BUTTON, _("Remove job"), GTK_STOCK_REMOVE, GTK_RESPONSE_OK, NULL); if (response == GTK_RESPONSE_OK) { if (printing_system_remove_job (priv->ps, priv->printer, atoi (string_id))) action_refresh_cb (NULL, win); else xfce_err (_("An error occurred while removing job !")); } g_free (string_id); g_free (string_title); g_free (dialog_message); } } static void action_refresh_cb (GtkAction * action, PrinterQueueWindow * win) { PrinterQueueWindowPrivate *priv = PRINTER_QUEUE_WINDOW_GET_PRIVATE (win); GtkTreeModel *model; GtkTreeSelection *selection = NULL; gchar *selected_id = NULL; GtkTreeIter iter; GList *jobs = NULL, *job = NULL; /* Remember selected ID */ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview)); if (selection && gtk_tree_selection_get_selected (selection, &model, &iter)) gtk_tree_model_get (model, &iter, JOBS_ID_COLUMN, &selected_id, -1); else model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview)); /* Empty the list */ gtk_list_store_clear (GTK_LIST_STORE (model)); /* Obtain job list from cups server */ jobs = printing_system_get_jobs (priv->ps, priv->printer); /* Show job list */ job = g_list_first (jobs); while (job) { gchar *string_id = NULL, *string_state = NULL, *string_size = NULL, *string_priority = NULL; GdkPixbuf *icon = NULL; gint x, y; Job *job_data = (Job *) job->data; if (gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &x, &y)) icon = gtk_icon_theme_load_icon (priv->icontheme, "gnome-mime-application-postscript", x, 0, NULL); else icon = gtk_icon_theme_load_icon (priv->icontheme, "gnome-mime-application-postscript", 24, 0, NULL); string_id = g_strdup_printf ("%u", job_data->id); switch (job_data->state) { case JOB_STATE_PENDING: string_state = g_strdup (_("pending")); break; case JOB_STATE_PRINTING: string_state = g_strdup (_("printing")); break; } string_size = g_strdup_printf ("%u %s", job_data->size, _("Kb")); string_priority = g_strdup_printf ("%u", job_data->priority); gtk_list_store_append (GTK_LIST_STORE (model), &iter); gtk_list_store_set (GTK_LIST_STORE (model), &iter, JOBS_ICON_COLUMN, icon, JOBS_NAME_COLUMN, job_data->name ? job_data->name : "", JOBS_ID_COLUMN, string_id, JOBS_USER_COLUMN, job_data->user ? job_data->user : "", JOBS_STATE_COLUMN, string_state, JOBS_SIZE_COLUMN, string_size, JOBS_PRIORITY_COLUMN, string_priority, JOBS_CREATION_TIME_COLUMN, job_data->creation_time ? job_data->creation_time : "", JOBS_PROCESSING_TIME_COLUMN, job_data->processing_time ? job_data->processing_time : "", -1); g_free (string_id); g_free (string_state); g_free (string_size); g_object_unref (G_OBJECT (icon)); job = g_list_next (job); } jobs_free (jobs); /* Reselect previously selected job if still available */ if (selected_id && gtk_tree_model_get_iter_first (model, &iter)) { gchar *current_id; gtk_tree_model_get (model, &iter, JOBS_ID_COLUMN, ¤t_id, -1); if (strcmp (current_id, selected_id) == 0) { gtk_tree_selection_select_iter (selection, &iter); g_free (current_id); } else { g_free (current_id); while (gtk_tree_model_iter_next (model, &iter)) { gtk_tree_model_get (model, &iter, JOBS_ID_COLUMN, ¤t_id, -1); if (strcmp (current_id, selected_id) == 0) { gtk_tree_selection_select_iter (selection, &iter); g_free (current_id); break; } g_free (current_id); } } } g_free (selected_id); } /********************/ /* public functions */ /********************/ GtkUIManager * printer_queue_window_get_ui_manager (PrinterQueueWindow * win) { return PRINTER_QUEUE_WINDOW_GET_PRIVATE (win)->ui_manager; } void printer_queue_window_hide_column (PrinterQueueWindow * win, PrinterQueueWindowColumn column) { PrinterQueueWindowPrivate *priv = PRINTER_QUEUE_WINDOW_GET_PRIVATE (win); GtkTreeViewColumn *tree_column; tree_column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->treeview), column); gtk_tree_view_column_set_visible (tree_column, FALSE); } GtkWidget * printer_queue_window_new (PrintingSystem * ps, const gchar * printer) { GObject *obj; PrinterQueueWindowPrivate *priv; GList *printers = NULL; gchar *title = NULL; g_return_val_if_fail (ps, NULL); obj = g_object_new (PRINTER_QUEUE_WINDOW_TYPE, NULL); priv = PRINTER_QUEUE_WINDOW_GET_PRIVATE (obj); priv->ps = ps; priv->printer = g_strdup (printer); /* set title */ printers = printing_system_get_printers (ps); title = g_strdup_printf ("%s - %s", _("Queue Manager"), (printer_lookup_byname (printers, printer))->alias); gtk_window_set_title (GTK_WINDOW (obj), title); g_free (title); printers_free (printers); /* load jobs in tree */ action_refresh_cb (NULL, PRINTER_QUEUE_WINDOW (obj)); /* refresh job list every 5 sec */ priv->timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 5000, (GSourceFunc) timeout_fct, PRINTER_QUEUE_WINDOW (obj), NULL); /* customize the dialog for the printing system */ printing_system_customize_printer_queue_window (ps, PRINTER_QUEUE_WINDOW (obj)); return GTK_WIDGET (obj); } guint printer_queue_window_get_selected_job (PrinterQueueWindow * win) { PrinterQueueWindowPrivate *priv = PRINTER_QUEUE_WINDOW_GET_PRIVATE (win); GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; guint job = 0; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview)); if (selection && gtk_tree_selection_get_selected (selection, &model, &iter)) gtk_tree_model_get (model, &iter, JOBS_ID_COLUMN, &job, -1); return job; }