/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "gsm-inhibit-dialog.h" #include "gsm-store.h" #include "gsm-client.h" #include "gsm-inhibitor.h" #include "eggdesktopfile.h" #include "gsm-util.h" #ifdef HAVE_XRENDER #include #endif #define GSM_INHIBIT_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_INHIBIT_DIALOG, GsmInhibitDialogPrivate)) #define GTKBUILDER_FILE "gsm-inhibit-dialog.ui" #ifndef DEFAULT_ICON_SIZE #define DEFAULT_ICON_SIZE 32 #endif #ifndef DEFAULT_SNAPSHOT_SIZE #define DEFAULT_SNAPSHOT_SIZE 128 #endif #define DIALOG_RESPONSE_LOCK_SCREEN 1 struct GsmInhibitDialogPrivate { GtkBuilder *xml; int action; gboolean is_done; GsmStore *inhibitors; GsmStore *clients; GtkListStore *list_store; gboolean have_xrender; int xrender_event_base; int xrender_error_base; }; enum { PROP_0, PROP_ACTION, PROP_INHIBITOR_STORE, PROP_CLIENT_STORE }; enum { INHIBIT_IMAGE_COLUMN = 0, INHIBIT_NAME_COLUMN, INHIBIT_REASON_COLUMN, INHIBIT_ID_COLUMN, NUMBER_OF_COLUMNS }; static void gsm_inhibit_dialog_class_init (GsmInhibitDialogClass *klass); static void gsm_inhibit_dialog_init (GsmInhibitDialog *inhibit_dialog); static void gsm_inhibit_dialog_finalize (GObject *object); G_DEFINE_TYPE (GsmInhibitDialog, gsm_inhibit_dialog, GTK_TYPE_DIALOG) static void lock_screen (GsmInhibitDialog *dialog) { GError *error; error = NULL; g_spawn_command_line_async ("mate-screensaver-command --lock", &error); if (error != NULL) { g_warning ("Couldn't lock screen: %s", error->message); g_error_free (error); } } static void on_response (GsmInhibitDialog *dialog, gint response_id) { if (dialog->priv->is_done) { g_signal_stop_emission_by_name (dialog, "response"); return; } switch (response_id) { case DIALOG_RESPONSE_LOCK_SCREEN: g_signal_stop_emission_by_name (dialog, "response"); lock_screen (dialog); break; default: dialog->priv->is_done = TRUE; break; } } static void gsm_inhibit_dialog_set_action (GsmInhibitDialog *dialog, int action) { dialog->priv->action = action; } static gboolean find_inhibitor (GsmInhibitDialog *dialog, const char *id, GtkTreeIter *iter) { GtkTreeModel *model; gboolean found_item; g_assert (GSM_IS_INHIBIT_DIALOG (dialog)); found_item = FALSE; model = GTK_TREE_MODEL (dialog->priv->list_store); if (!gtk_tree_model_get_iter_first (model, iter)) { return FALSE; } do { char *item_id; gtk_tree_model_get (model, iter, INHIBIT_ID_COLUMN, &item_id, -1); if (item_id != NULL && id != NULL && strcmp (item_id, id) == 0) { found_item = TRUE; } g_free (item_id); } while (!found_item && gtk_tree_model_iter_next (model, iter)); return found_item; } /* copied from mate-panel panel-util.c */ static char * _util_icon_remove_extension (const char *icon) { char *icon_no_extension; char *p; icon_no_extension = g_strdup (icon); p = strrchr (icon_no_extension, '.'); if (p && (strcmp (p, ".png") == 0 || strcmp (p, ".xpm") == 0 || strcmp (p, ".svg") == 0)) { *p = 0; } return icon_no_extension; } /* copied from mate-panel panel-util.c */ static char * _find_icon (GtkIconTheme *icon_theme, const char *icon_name, gint size) { GtkIconInfo *info; char *retval; char *icon_no_extension; if (icon_name == NULL || strcmp (icon_name, "") == 0) return NULL; if (g_path_is_absolute (icon_name)) { if (g_file_test (icon_name, G_FILE_TEST_EXISTS)) { return g_strdup (icon_name); } else { char *basename; basename = g_path_get_basename (icon_name); retval = _find_icon (icon_theme, basename, size); g_free (basename); return retval; } } /* This is needed because some .desktop files have an icon name *and* * an extension as icon */ icon_no_extension = _util_icon_remove_extension (icon_name); info = gtk_icon_theme_lookup_icon (icon_theme, icon_no_extension, size, 0); g_free (icon_no_extension); if (info) { retval = g_strdup (gtk_icon_info_get_filename (info)); #if GTK_CHECK_VERSION (3, 8, 0) g_object_unref (info); #else gtk_icon_info_free (info); #endif } else retval = NULL; return retval; } /* copied from mate-panel panel-util.c */ static GdkPixbuf * _load_icon (GtkIconTheme *icon_theme, const char *icon_name, int size, int desired_width, int desired_height, char **error_msg) { GdkPixbuf *retval; char *file; GError *error; g_return_val_if_fail (error_msg == NULL || *error_msg == NULL, NULL); file = _find_icon (icon_theme, icon_name, size); if (!file) { if (error_msg) *error_msg = g_strdup_printf (_("Icon '%s' not found"), icon_name); return NULL; } error = NULL; retval = gdk_pixbuf_new_from_file_at_size (file, desired_width, desired_height, &error); if (error) { if (error_msg) *error_msg = g_strdup (error->message); g_error_free (error); } g_free (file); return retval; } static GdkPixbuf * scale_pixbuf (GdkPixbuf *pixbuf, int max_width, int max_height, gboolean no_stretch_hint) { int pw; int ph; float scale_factor_x = 1.0; float scale_factor_y = 1.0; float scale_factor = 1.0; pw = gdk_pixbuf_get_width (pixbuf); ph = gdk_pixbuf_get_height (pixbuf); /* Determine which dimension requires the smallest scale. */ scale_factor_x = (float) max_width / (float) pw; scale_factor_y = (float) max_height / (float) ph; if (scale_factor_x > scale_factor_y) { scale_factor = scale_factor_y; } else { scale_factor = scale_factor_x; } /* always scale down, allow to disable scaling up */ if (scale_factor < 1.0 || !no_stretch_hint) { int scale_x = (int) (pw * scale_factor); int scale_y = (int) (ph * scale_factor); g_debug ("Scaling to %dx%d", scale_x, scale_y); return gdk_pixbuf_scale_simple (pixbuf, scale_x, scale_y, GDK_INTERP_BILINEAR); } else { return g_object_ref (pixbuf); } } #ifdef HAVE_XRENDER #if !GTK_CHECK_VERSION (3, 0, 0) /* adapted from marco */ static GdkColormap* get_cmap (GdkPixmap *pixmap) { GdkColormap *cmap; cmap = gdk_drawable_get_colormap (pixmap); if (cmap) { g_object_ref (G_OBJECT (cmap)); } if (cmap == NULL) { if (gdk_drawable_get_depth (pixmap) == 1) { g_debug ("Using NULL colormap for snapshotting bitmap\n"); cmap = NULL; } else { g_debug ("Using system cmap to snapshot pixmap\n"); cmap = gdk_screen_get_system_colormap (gdk_drawable_get_screen (pixmap)); g_object_ref (G_OBJECT (cmap)); } } /* Be sure we aren't going to blow up due to visual mismatch */ if (cmap && (gdk_visual_get_depth (gdk_colormap_get_visual (cmap)) != gdk_drawable_get_depth (pixmap))) { cmap = NULL; g_debug ("Switching back to NULL cmap because of depth mismatch\n"); } return cmap; } #endif static GdkPixbuf * pixbuf_get_from_pixmap (Display *display, Pixmap xpixmap, int width, int height) { GdkPixbuf *retval; #if GTK_CHECK_VERSION (3, 0, 0) cairo_surface_t *surface; Visual *visual; #else GdkDrawable *drawable; GdkColormap *cmap; cmap = NULL; #endif retval = NULL; g_debug ("GsmInhibitDialog: getting foreign pixmap for %u", (guint)xpixmap); #if GTK_CHECK_VERSION (3, 0, 0) visual = DefaultVisual (display, 0); surface = cairo_xlib_surface_create (display, xpixmap, visual, width, height); if (surface != NULL) { g_debug ("GsmInhibitDialog: getting pixbuf w=%d h=%d", width, height); retval = gdk_pixbuf_get_from_surface (surface, 0, 0, width, height); cairo_surface_destroy (surface); } #else drawable = gdk_pixmap_foreign_new (xpixmap); if (GDK_IS_PIXMAP (drawable)) { cmap = get_cmap (drawable); g_debug ("GsmInhibitDialog: getting pixbuf w=%d h=%d", width, height); retval = gdk_pixbuf_get_from_drawable (NULL, drawable, cmap, 0, 0, 0, 0, width, height); } if (cmap) { g_object_unref (G_OBJECT (cmap)); } if (drawable) { g_object_unref (G_OBJECT (drawable)); } #endif return retval; } static Pixmap get_pixmap_for_window (Display *display, Window window, int *widthp, int *heightp) { XWindowAttributes attr; XRenderPictureAttributes pa; Pixmap pixmap; XRenderPictFormat *format; Picture src_picture; Picture dst_picture; gboolean has_alpha; int width; int height; XGetWindowAttributes (display, window, &attr); format = XRenderFindVisualFormat (display, attr.visual); has_alpha = (format->type == PictTypeDirect && format->direct.alphaMask); width = attr.width; height = attr.height; pa.subwindow_mode = IncludeInferiors; /* Don't clip child widgets */ src_picture = XRenderCreatePicture (display, window, format, CPSubwindowMode, &pa); pixmap = XCreatePixmap (display, window, width, height, attr.depth); dst_picture = XRenderCreatePicture (display, pixmap, format, 0, 0); XRenderComposite (display, has_alpha ? PictOpOver : PictOpSrc, src_picture, None, dst_picture, 0, 0, 0, 0, 0, 0, width, height); if (widthp != NULL) { *widthp = width; } if (heightp != NULL) { *heightp = height; } return pixmap; } #endif /* HAVE_COMPOSITE */ static GdkPixbuf * get_pixbuf_for_window (GdkDisplay *gdkdisplay, guint xid, int thumb_width, int thumb_height) { GdkPixbuf *pixbuf = NULL; #ifdef HAVE_XRENDER Display *display; Window xwindow; Pixmap xpixmap; int width; int height; display = GDK_DISPLAY_XDISPLAY (gdkdisplay); xwindow = (Window) xid; xpixmap = get_pixmap_for_window (display, xwindow, &width, &height); if (xpixmap == None) { g_debug ("GsmInhibitDialog: Unable to get window snapshot for %u", xid); return NULL; } else { g_debug ("GsmInhibitDialog: Got xpixmap %u", (guint)xpixmap); } pixbuf = pixbuf_get_from_pixmap (display, xpixmap, width, height); if (xpixmap != None) { gdk_error_trap_push (); XFreePixmap (display, xpixmap); gdk_display_sync (gdkdisplay); #if GTK_CHECK_VERSION (3, 0, 0) gdk_error_trap_pop_ignored (); #else gdk_error_trap_pop (); #endif } if (pixbuf != NULL) { GdkPixbuf *scaled; g_debug ("GsmInhibitDialog: scaling pixbuf to w=%d h=%d", width, height); scaled = scale_pixbuf (pixbuf, thumb_width, thumb_height, TRUE); g_object_unref (pixbuf); pixbuf = scaled; } #else g_debug ("GsmInhibitDialog: no support for getting window snapshot"); #endif return pixbuf; } static void add_inhibitor (GsmInhibitDialog *dialog, GsmInhibitor *inhibitor) { GdkDisplay *gdkdisplay; const char *name; const char *icon_name; const char *app_id; char *desktop_filename; GdkPixbuf *pixbuf; EggDesktopFile *desktop_file; GError *error; char **search_dirs; guint xid; char *freeme; gdkdisplay = gtk_widget_get_display (GTK_WIDGET (dialog)); /* FIXME: get info from xid */ desktop_file = NULL; name = NULL; pixbuf = NULL; freeme = NULL; app_id = gsm_inhibitor_peek_app_id (inhibitor); if (IS_STRING_EMPTY (app_id)) { desktop_filename = NULL; } else if (! g_str_has_suffix (app_id, ".desktop")) { desktop_filename = g_strdup_printf ("%s.desktop", app_id); } else { desktop_filename = g_strdup (app_id); } xid = gsm_inhibitor_peek_toplevel_xid (inhibitor); g_debug ("GsmInhibitDialog: inhibitor has XID %u", xid); if (xid > 0 && dialog->priv->have_xrender) { pixbuf = get_pixbuf_for_window (gdkdisplay, xid, DEFAULT_SNAPSHOT_SIZE, DEFAULT_SNAPSHOT_SIZE); if (pixbuf == NULL) { g_debug ("GsmInhibitDialog: unable to read pixbuf from %u", xid); } } if (desktop_filename != NULL) { search_dirs = gsm_util_get_desktop_dirs (); if (g_path_is_absolute (desktop_filename)) { char *basename; error = NULL; desktop_file = egg_desktop_file_new (desktop_filename, &error); if (desktop_file == NULL) { if (error) { g_warning ("Unable to load desktop file '%s': %s", desktop_filename, error->message); g_error_free (error); } else { g_warning ("Unable to load desktop file '%s'", desktop_filename); } basename = g_path_get_basename (desktop_filename); g_free (desktop_filename); desktop_filename = basename; } } if (desktop_file == NULL) { error = NULL; desktop_file = egg_desktop_file_new_from_dirs (desktop_filename, (const char **)search_dirs, &error); } /* look for a file with a vendor prefix */ if (desktop_file == NULL) { if (error) { g_warning ("Unable to find desktop file '%s': %s", desktop_filename, error->message); g_error_free (error); } else { g_warning ("Unable to find desktop file '%s'", desktop_filename); } g_free (desktop_filename); desktop_filename = g_strdup_printf ("mate-%s.desktop", app_id); error = NULL; desktop_file = egg_desktop_file_new_from_dirs (desktop_filename, (const char **)search_dirs, &error); } g_strfreev (search_dirs); if (desktop_file == NULL) { if (error) { g_warning ("Unable to find desktop file '%s': %s", desktop_filename, error->message); g_error_free (error); } else { g_warning ("Unable to find desktop file '%s'", desktop_filename); } } else { name = egg_desktop_file_get_name (desktop_file); icon_name = egg_desktop_file_get_icon (desktop_file); if (pixbuf == NULL) { pixbuf = _load_icon (gtk_icon_theme_get_default (), icon_name, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE, NULL); } } } /* try client info */ if (name == NULL) { const char *client_id; client_id = gsm_inhibitor_peek_client_id (inhibitor); if (! IS_STRING_EMPTY (client_id)) { GsmClient *client; client = GSM_CLIENT (gsm_store_lookup (dialog->priv->clients, client_id)); if (client != NULL) { freeme = gsm_client_get_app_name (client); name = freeme; } } } if (name == NULL) { if (! IS_STRING_EMPTY (app_id)) { name = app_id; } else { name = _("Unknown"); } } if (pixbuf == NULL) { pixbuf = _load_icon (gtk_icon_theme_get_default (), "mate-windows", DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE, NULL); } gtk_list_store_insert_with_values (dialog->priv->list_store, NULL, 0, INHIBIT_IMAGE_COLUMN, pixbuf, INHIBIT_NAME_COLUMN, name, INHIBIT_REASON_COLUMN, gsm_inhibitor_peek_reason (inhibitor), INHIBIT_ID_COLUMN, gsm_inhibitor_peek_id (inhibitor), -1); g_free (desktop_filename); g_free (freeme); if (pixbuf != NULL) { g_object_unref (pixbuf); } if (desktop_file != NULL) { egg_desktop_file_free (desktop_file); } } static gboolean model_has_one_entry (GtkTreeModel *model) { guint n_rows; n_rows = gtk_tree_model_iter_n_children (model, NULL); g_debug ("Model has %d rows", n_rows); return (n_rows > 0 && n_rows < 2); } static void update_dialog_text (GsmInhibitDialog *dialog) { const char *description_text; const char *header_text; GtkWidget *widget; if (model_has_one_entry (GTK_TREE_MODEL (dialog->priv->list_store))) { g_debug ("Found one entry in model"); header_text = _("A program is still running:"); description_text = _("Waiting for the program to finish. Interrupting the program may cause you to lose work."); } else { g_debug ("Found multiple entries (or none) in model"); header_text = _("Some programs are still running:"); description_text = _("Waiting for programs to finish. Interrupting these programs may cause you to lose work."); } widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, "header-label")); if (widget != NULL) { char *markup; markup = g_strdup_printf ("%s", header_text); gtk_label_set_markup (GTK_LABEL (widget), markup); g_free (markup); } widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, "description-label")); if (widget != NULL) { gtk_label_set_text (GTK_LABEL (widget), description_text); } } static void on_store_inhibitor_added (GsmStore *store, const char *id, GsmInhibitDialog *dialog) { GsmInhibitor *inhibitor; GtkTreeIter iter; g_debug ("GsmInhibitDialog: inhibitor added: %s", id); if (dialog->priv->is_done) { return; } inhibitor = (GsmInhibitor *)gsm_store_lookup (store, id); /* Add to model */ if (! find_inhibitor (dialog, id, &iter)) { add_inhibitor (dialog, inhibitor); update_dialog_text (dialog); } } static void on_store_inhibitor_removed (GsmStore *store, const char *id, GsmInhibitDialog *dialog) { GtkTreeIter iter; g_debug ("GsmInhibitDialog: inhibitor removed: %s", id); if (dialog->priv->is_done) { return; } /* Remove from model */ if (find_inhibitor (dialog, id, &iter)) { gtk_list_store_remove (dialog->priv->list_store, &iter); update_dialog_text (dialog); } /* if there are no inhibitors left then trigger response */ if (! gtk_tree_model_get_iter_first (GTK_TREE_MODEL (dialog->priv->list_store), &iter)) { gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); } } static void gsm_inhibit_dialog_set_inhibitor_store (GsmInhibitDialog *dialog, GsmStore *store) { g_return_if_fail (GSM_IS_INHIBIT_DIALOG (dialog)); if (store != NULL) { g_object_ref (store); } if (dialog->priv->inhibitors != NULL) { g_signal_handlers_disconnect_by_func (dialog->priv->inhibitors, on_store_inhibitor_added, dialog); g_signal_handlers_disconnect_by_func (dialog->priv->inhibitors, on_store_inhibitor_removed, dialog); g_object_unref (dialog->priv->inhibitors); } g_debug ("GsmInhibitDialog: setting store %p", store); dialog->priv->inhibitors = store; if (dialog->priv->inhibitors != NULL) { g_signal_connect (dialog->priv->inhibitors, "added", G_CALLBACK (on_store_inhibitor_added), dialog); g_signal_connect (dialog->priv->inhibitors, "removed", G_CALLBACK (on_store_inhibitor_removed), dialog); } } static void gsm_inhibit_dialog_set_client_store (GsmInhibitDialog *dialog, GsmStore *store) { g_return_if_fail (GSM_IS_INHIBIT_DIALOG (dialog)); if (store != NULL) { g_object_ref (store); } if (dialog->priv->clients != NULL) { g_object_unref (dialog->priv->clients); } dialog->priv->clients = store; } static void gsm_inhibit_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GsmInhibitDialog *dialog = GSM_INHIBIT_DIALOG (object); switch (prop_id) { case PROP_ACTION: gsm_inhibit_dialog_set_action (dialog, g_value_get_int (value)); break; case PROP_INHIBITOR_STORE: gsm_inhibit_dialog_set_inhibitor_store (dialog, g_value_get_object (value)); break; case PROP_CLIENT_STORE: gsm_inhibit_dialog_set_client_store (dialog, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gsm_inhibit_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GsmInhibitDialog *dialog = GSM_INHIBIT_DIALOG (object); switch (prop_id) { case PROP_ACTION: g_value_set_int (value, dialog->priv->action); break; case PROP_INHIBITOR_STORE: g_value_set_object (value, dialog->priv->inhibitors); break; case PROP_CLIENT_STORE: g_value_set_object (value, dialog->priv->clients); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void name_cell_data_func (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, GsmInhibitDialog *dialog) { char *name; char *reason; char *markup; name = NULL; reason = NULL; gtk_tree_model_get (model, iter, INHIBIT_NAME_COLUMN, &name, INHIBIT_REASON_COLUMN, &reason, -1); markup = g_strdup_printf ("%s\n" "%s", name ? name : "(null)", reason ? reason : "(null)"); g_free (name); g_free (reason); g_object_set (cell, "markup", markup, NULL); g_free (markup); } static gboolean add_to_model (const char *id, GsmInhibitor *inhibitor, GsmInhibitDialog *dialog) { add_inhibitor (dialog, inhibitor); return FALSE; } static void populate_model (GsmInhibitDialog *dialog) { gsm_store_foreach_remove (dialog->priv->inhibitors, (GsmStoreFunc)add_to_model, dialog); update_dialog_text (dialog); } static void setup_dialog (GsmInhibitDialog *dialog) { const char *button_text; GtkWidget *treeview; GtkTreeViewColumn *column; GtkCellRenderer *renderer; switch (dialog->priv->action) { case GSM_LOGOUT_ACTION_SWITCH_USER: button_text = _("Switch User Anyway"); break; case GSM_LOGOUT_ACTION_LOGOUT: button_text = _("Log Out Anyway"); break; case GSM_LOGOUT_ACTION_SLEEP: button_text = _("Suspend Anyway"); break; case GSM_LOGOUT_ACTION_HIBERNATE: button_text = _("Hibernate Anyway"); break; case GSM_LOGOUT_ACTION_SHUTDOWN: button_text = _("Shut Down Anyway"); break; case GSM_LOGOUT_ACTION_REBOOT: button_text = _("Reboot Anyway"); break; default: g_assert_not_reached (); break; } gtk_dialog_add_button (GTK_DIALOG (dialog), _("Lock Screen"), DIALOG_RESPONSE_LOCK_SCREEN); gtk_dialog_add_button (GTK_DIALOG (dialog), _("Cancel"), GTK_RESPONSE_CANCEL); gtk_dialog_add_button (GTK_DIALOG (dialog), button_text, GTK_RESPONSE_ACCEPT); g_signal_connect (dialog, "response", G_CALLBACK (on_response), dialog); dialog->priv->list_store = gtk_list_store_new (NUMBER_OF_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); treeview = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, "inhibitors-treeview")); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (dialog->priv->list_store)); /* IMAGE COLUMN */ renderer = gtk_cell_renderer_pixbuf_new (); column = gtk_tree_view_column_new (); gtk_tree_view_column_pack_start (column, renderer, FALSE); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); gtk_tree_view_column_set_attributes (column, renderer, "pixbuf", INHIBIT_IMAGE_COLUMN, NULL); g_object_set (renderer, "xalign", 1.0, NULL); /* NAME COLUMN */ renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new (); gtk_tree_view_column_pack_start (column, renderer, FALSE); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); gtk_tree_view_column_set_cell_data_func (column, renderer, (GtkTreeCellDataFunc) name_cell_data_func, dialog, NULL); gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (treeview), INHIBIT_REASON_COLUMN); populate_model (dialog); } static GObject * gsm_inhibit_dialog_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GsmInhibitDialog *dialog; #ifdef HAVE_XRENDER GdkDisplay *gdkdisplay; #endif /* HAVE_XRENDER */ dialog = GSM_INHIBIT_DIALOG (G_OBJECT_CLASS (gsm_inhibit_dialog_parent_class)->constructor (type, n_construct_properties, construct_properties)); #ifdef HAVE_XRENDER gdkdisplay = gdk_display_get_default (); gdk_error_trap_push (); if (XRenderQueryExtension (GDK_DISPLAY_XDISPLAY (gdkdisplay), &dialog->priv->xrender_event_base, &dialog->priv->xrender_error_base)) { g_debug ("GsmInhibitDialog: Initialized XRender extension"); dialog->priv->have_xrender = TRUE; } else { g_debug ("GsmInhibitDialog: Unable to initialize XRender extension"); dialog->priv->have_xrender = FALSE; } gdk_display_sync (gdkdisplay); #if GTK_CHECK_VERSION (3, 0, 0) gdk_error_trap_pop_ignored (); #else gdk_error_trap_pop (); #endif #endif /* HAVE_XRENDER */ /* FIXME: turn this on when it is ready */ dialog->priv->have_xrender = FALSE; setup_dialog (dialog); gtk_widget_show_all (GTK_WIDGET (dialog)); return G_OBJECT (dialog); } static void gsm_inhibit_dialog_dispose (GObject *object) { GsmInhibitDialog *dialog; g_return_if_fail (object != NULL); g_return_if_fail (GSM_IS_INHIBIT_DIALOG (object)); dialog = GSM_INHIBIT_DIALOG (object); g_debug ("GsmInhibitDialog: dispose called"); if (dialog->priv->list_store != NULL) { g_object_unref (dialog->priv->list_store); dialog->priv->list_store = NULL; } if (dialog->priv->inhibitors != NULL) { g_signal_handlers_disconnect_by_func (dialog->priv->inhibitors, on_store_inhibitor_added, dialog); g_signal_handlers_disconnect_by_func (dialog->priv->inhibitors, on_store_inhibitor_removed, dialog); g_object_unref (dialog->priv->inhibitors); dialog->priv->inhibitors = NULL; } if (dialog->priv->xml != NULL) { g_object_unref (dialog->priv->xml); dialog->priv->xml = NULL; } G_OBJECT_CLASS (gsm_inhibit_dialog_parent_class)->dispose (object); } static void gsm_inhibit_dialog_class_init (GsmInhibitDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = gsm_inhibit_dialog_get_property; object_class->set_property = gsm_inhibit_dialog_set_property; object_class->constructor = gsm_inhibit_dialog_constructor; object_class->dispose = gsm_inhibit_dialog_dispose; object_class->finalize = gsm_inhibit_dialog_finalize; g_object_class_install_property (object_class, PROP_ACTION, g_param_spec_int ("action", "action", "action", -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_INHIBITOR_STORE, g_param_spec_object ("inhibitor-store", NULL, NULL, GSM_TYPE_STORE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_CLIENT_STORE, g_param_spec_object ("client-store", NULL, NULL, GSM_TYPE_STORE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (GsmInhibitDialogPrivate)); } static void gsm_inhibit_dialog_init (GsmInhibitDialog *dialog) { GtkWidget *content_area; GtkWidget *widget; GError *error; dialog->priv = GSM_INHIBIT_DIALOG_GET_PRIVATE (dialog); dialog->priv->xml = gtk_builder_new (); gtk_builder_set_translation_domain (dialog->priv->xml, GETTEXT_PACKAGE); error = NULL; if (!gtk_builder_add_from_file (dialog->priv->xml, GTKBUILDER_DIR "/" GTKBUILDER_FILE, &error)) { if (error) { g_warning ("Could not load inhibitor UI file: %s", error->message); g_error_free (error); } else { g_warning ("Could not load inhibitor UI file."); } } content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, "main-box")); gtk_container_add (GTK_CONTAINER (content_area), widget); gtk_container_set_border_width (GTK_CONTAINER (dialog), 6); gtk_window_set_icon_name (GTK_WINDOW (dialog), "system-log-out"); gtk_window_set_title (GTK_WINDOW (dialog), ""); g_object_set (dialog, "resizable", FALSE, NULL); } static void gsm_inhibit_dialog_finalize (GObject *object) { GsmInhibitDialog *dialog; g_return_if_fail (object != NULL); g_return_if_fail (GSM_IS_INHIBIT_DIALOG (object)); dialog = GSM_INHIBIT_DIALOG (object); g_return_if_fail (dialog->priv != NULL); g_debug ("GsmInhibitDialog: finalizing"); G_OBJECT_CLASS (gsm_inhibit_dialog_parent_class)->finalize (object); } GtkWidget * gsm_inhibit_dialog_new (GsmStore *inhibitors, GsmStore *clients, int action) { GObject *object; object = g_object_new (GSM_TYPE_INHIBIT_DIALOG, "action", action, "inhibitor-store", inhibitors, "client-store", clients, NULL); return GTK_WIDGET (object); }