From e24ebc3dd35e1a5b1d16db4469b346722d683fb6 Mon Sep 17 00:00:00 2001 From: Benedikt Meurer <benny@xfce.org> Date: Sun, 24 Jul 2005 17:12:27 +0000 Subject: [PATCH] 2005-07-24 Benedikt Meurer <benny@xfce.org> * thunar/thunar-file.c(thunar_file_load_icon): Actually cache the result of an icon lookup. * thunarx/, thunarx/Makefile.am, configure.in.in: Add "thunarx" namespace, which contains extensions to existing frameworks and various helper functions that don't fit anywhere else. * thunarx/thunarx-gdk-pixbuf-extensions.{c,h}: Add a method to colorize a GdkPixbuf to a given GdkColor. * thunar/main.c, thunar/thunar-desktop-model.{c,h}, thunar/Makefile.am, thunar/thunar-desktop-window.{c,h}, thunar/thunar-desktop-view.{c,h}: Add proof-of-concept for the desktop support. (Old svn revision: 16409) --- ChangeLog | 13 + Makefile.am | 1 + configure.in.in | 1 + thunar/Makefile.am | 10 +- thunar/main.c | 9 + thunar/thunar-desktop-model.c | 471 +++++++++++++++ thunar/thunar-desktop-model.h | 67 ++ thunar/thunar-desktop-view.c | 771 +++++++++++++++++++++--- thunar/thunar-desktop-view.h | 33 +- thunar/thunar-desktop-window.c | 216 +++++++ thunar/thunar-desktop-window.h | 44 ++ thunar/thunar-file.c | 21 +- thunarx/Makefile.am | 25 + thunarx/thunarx-gdk-pixbuf-extensions.c | 90 +++ thunarx/thunarx-gdk-pixbuf-extensions.h | 32 + 15 files changed, 1692 insertions(+), 112 deletions(-) create mode 100644 thunar/thunar-desktop-model.c create mode 100644 thunar/thunar-desktop-model.h create mode 100644 thunar/thunar-desktop-window.c create mode 100644 thunar/thunar-desktop-window.h create mode 100644 thunarx/Makefile.am create mode 100644 thunarx/thunarx-gdk-pixbuf-extensions.c create mode 100644 thunarx/thunarx-gdk-pixbuf-extensions.h diff --git a/ChangeLog b/ChangeLog index ca1965c62..d9edb358a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2005-07-24 Benedikt Meurer <benny@xfce.org> + + * thunar/thunar-file.c(thunar_file_load_icon): Actually cache the result + of an icon lookup. + * thunarx/, thunarx/Makefile.am, configure.in.in: Add "thunarx" + namespace, which contains extensions to existing frameworks and + various helper functions that don't fit anywhere else. + * thunarx/thunarx-gdk-pixbuf-extensions.{c,h}: Add a method to colorize + a GdkPixbuf to a given GdkColor. + * thunar/main.c, thunar/thunar-desktop-model.{c,h}, thunar/Makefile.am, + thunar/thunar-desktop-window.{c,h}, thunar/thunar-desktop-view.{c,h}: + Add proof-of-concept for the desktop support. + 2005-07-23 Benedikt Meurer <benny@xfce.org> * thunar/thunar-list-model.c: Fix incorrect ThunarVfsMimeInfo -> GObject diff --git a/Makefile.am b/Makefile.am index 8d98f9fd0..bdef6e54d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,6 +3,7 @@ SUBDIRS = \ docs \ thunar-vfs \ + thunarx \ thunar \ tests diff --git a/configure.in.in b/configure.in.in index 7d350ee2c..5702d6bbe 100644 --- a/configure.in.in +++ b/configure.in.in @@ -108,4 +108,5 @@ tests/data/Makefile thunar/Makefile thunar-vfs/Makefile thunar-vfs/xdgmime/Makefile +thunarx/Makefile ]) diff --git a/thunar/Makefile.am b/thunar/Makefile.am index 582e85cac..3dd53e549 100644 --- a/thunar/Makefile.am +++ b/thunar/Makefile.am @@ -17,8 +17,12 @@ Thunar_SOURCES = \ thunar-clipboard-manager.h \ thunar-computer-folder.c \ thunar-computer-folder.h \ + thunar-desktop-model.c \ + thunar-desktop-model.h \ thunar-desktop-view.c \ thunar-desktop-view.h \ + thunar-desktop-window.c \ + thunar-desktop-window.h \ thunar-details-view.c \ thunar-details-view.h \ thunar-details-view-icon-renderer.c \ @@ -90,10 +94,12 @@ Thunar_LDFLAGS = \ $(GTHREAD_LIBS) Thunar_LDADD = \ - $(top_builddir)/thunar-vfs/libthunar-vfs.la + $(top_builddir)/thunar-vfs/libthunar-vfs.la \ + $(top_builddir)/thunarx/libthunarx.la Thunar_DEPENDENCIES = \ - $(top_builddir)/thunar-vfs/libthunar-vfs.la + $(top_builddir)/thunar-vfs/libthunar-vfs.la \ + $(top_builddir)/thunarx/libthunarx.la # install symlink to 'thunar' install-data-local: diff --git a/thunar/main.c b/thunar/main.c index c847fe983..f375be9be 100644 --- a/thunar/main.c +++ b/thunar/main.c @@ -28,6 +28,7 @@ #include <stdlib.h> #endif +#include <thunar/thunar-desktop-window.h> #include <thunar/thunar-window.h> @@ -58,6 +59,14 @@ main (int argc, char **argv) /* initialize the ThunarVFS library */ thunar_vfs_init (); + if (argc >= 2 && exo_str_is_equal (argv[1], "--desktop")) + { + window = thunar_desktop_window_new (); + gtk_widget_show (window); + gtk_main (); + return 0; + } + path = (argc > 1) ? argv[1] : xfce_get_homedir (); uri = thunar_vfs_uri_new (path, &error); diff --git a/thunar/thunar-desktop-model.c b/thunar/thunar-desktop-model.c new file mode 100644 index 000000000..059325e8f --- /dev/null +++ b/thunar/thunar-desktop-model.c @@ -0,0 +1,471 @@ +/* $Id$ */ +/*- + * Copyright (c) 2005 Benedikt Meurer <benny@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 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 <config.h> +#endif + +#ifdef HAVE_MEMORY_H +#include <memory.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#include <thunar/thunar-desktop-model.h> + + + +GType +thunar_desktop_position_get_type (void) +{ + static GType type = G_TYPE_INVALID; + + if (G_UNLIKELY (type == G_TYPE_INVALID)) + { + type = g_boxed_type_register_static ("ThunarDesktopPosition", + (GBoxedCopyFunc) thunar_desktop_position_dup, + (GBoxedFreeFunc) thunar_desktop_position_free); + } + + return type; +} + + + +/** + * thunar_desktop_position_dup: + * @position : a #ThunarDesktopPosition. + * + * Returns a duplicate of @position. The caller + * is responsible to call #thunar_desktop_position_free() + * on the returned object. + * + * Return value: a duplicate of @position. + **/ +ThunarDesktopPosition* +thunar_desktop_position_dup (const ThunarDesktopPosition *position) +{ + g_return_val_if_fail (position != NULL, NULL); + return g_memdup (position, sizeof (*position)); +} + + + +/** + * thunar_desktop_position_free: + * @position : a #ThunarDesktopPosition. + * + * Frees the resources allocated for @position. + **/ +void +thunar_desktop_position_free (ThunarDesktopPosition *position) +{ + g_return_if_fail (position != NULL); + +#ifndef G_DISABLE_CHECKS + memset (position, 0xaa, sizeof (*position)); +#endif + + g_free (position); +} + + + + +typedef struct _ThunarDesktopModelItem ThunarDesktopModelItem; + + + +static void thunar_desktop_model_class_init (ThunarDesktopModelClass *klass); +static void thunar_desktop_model_tree_model_init (GtkTreeModelIface *iface); +static void thunar_desktop_model_init (ThunarDesktopModel *model); +static void thunar_desktop_model_finalize (GObject *object); +static GtkTreeModelFlags thunar_desktop_model_get_flags (GtkTreeModel *tree_model); +static gint thunar_desktop_model_get_n_columns (GtkTreeModel *tree_model); +static GType thunar_desktop_model_get_column_type (GtkTreeModel *tree_model, + gint index); +static gboolean thunar_desktop_model_get_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreePath *path); +static GtkTreePath *thunar_desktop_model_get_path (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static void thunar_desktop_model_get_value (GtkTreeModel *tree_model, + GtkTreeIter *iter, + gint column, + GValue *value); +static gboolean thunar_desktop_model_iter_next (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static gboolean thunar_desktop_model_iter_children (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent); +static gboolean thunar_desktop_model_iter_has_child (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static gint thunar_desktop_model_iter_n_children (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static gboolean thunar_desktop_model_iter_nth_child (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent, + gint n); +static gboolean thunar_desktop_model_iter_parent (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *child); +static void thunar_desktop_model_item_free (ThunarDesktopModelItem *item); + + + +struct _ThunarDesktopModelClass +{ + GObjectClass __parent__; +}; + +struct _ThunarDesktopModel +{ + GObject __parent__; + + guint stamp; + GList *items; + gint n_items; +}; + +struct _ThunarDesktopModelItem +{ + ThunarFile *file; + ThunarDesktopPosition position; +}; + + + +G_DEFINE_TYPE_WITH_CODE (ThunarDesktopModel, + thunar_desktop_model, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, + thunar_desktop_model_tree_model_init)); + + + +static void +thunar_desktop_model_class_init (ThunarDesktopModelClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + gobject_class->finalize = thunar_desktop_model_finalize; +} + + + +static void +thunar_desktop_model_tree_model_init (GtkTreeModelIface *iface) +{ + iface->get_flags = thunar_desktop_model_get_flags; + iface->get_n_columns = thunar_desktop_model_get_n_columns; + iface->get_column_type = thunar_desktop_model_get_column_type; + iface->get_iter = thunar_desktop_model_get_iter; + iface->get_path = thunar_desktop_model_get_path; + iface->get_value = thunar_desktop_model_get_value; + iface->iter_next = thunar_desktop_model_iter_next; + iface->iter_children = thunar_desktop_model_iter_children; + iface->iter_has_child = thunar_desktop_model_iter_has_child; + iface->iter_n_children = thunar_desktop_model_iter_n_children; + iface->iter_nth_child = thunar_desktop_model_iter_nth_child; + iface->iter_parent = thunar_desktop_model_iter_parent; +} + + + +static void +thunar_desktop_model_init (ThunarDesktopModel *model) +{ + ThunarDesktopModelItem *item; + ThunarVfsURI *uri; + + model->stamp = g_random_int (); + + uri = thunar_vfs_uri_new_for_path (xfce_get_homedir ()); + item = g_new (ThunarDesktopModelItem, 1); + item->file = thunar_file_get_for_uri (uri, NULL); + item->position.row = 0; + item->position.column = 0; + item->position.screen_number = 0; + model->items = g_list_append (model->items, item); + ++model->n_items; + thunar_vfs_uri_unref (uri); + + uri = thunar_vfs_uri_new ("trash:", NULL); + item = g_new (ThunarDesktopModelItem, 1); + item->file = thunar_file_get_for_uri (uri, NULL); + item->position.row = 4; + item->position.column = 1; + item->position.screen_number = 0; + model->items = g_list_append (model->items, item); + ++model->n_items; + thunar_vfs_uri_unref (uri); +} + + + +static void +thunar_desktop_model_finalize (GObject *object) +{ + ThunarDesktopModel *model = THUNAR_DESKTOP_MODEL (object); + + /* free the desktop items */ + g_list_foreach (model->items, (GFunc) thunar_desktop_model_item_free, NULL); + g_list_free (model->items); + + G_OBJECT_CLASS (thunar_desktop_model_parent_class)->finalize (object); +} + + + +static GtkTreeModelFlags +thunar_desktop_model_get_flags (GtkTreeModel *tree_model) +{ + return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY; +} + + + +static gint +thunar_desktop_model_get_n_columns (GtkTreeModel *tree_model) +{ + return THUNAR_DESKTOP_MODEL_N_COLUMNS; +} + + + +static GType +thunar_desktop_model_get_column_type (GtkTreeModel *tree_model, + gint index) +{ + switch (index) + { + case THUNAR_DESKTOP_MODEL_COLUMN_FILE: + return THUNAR_TYPE_FILE; + + case THUNAR_DESKTOP_MODEL_COLUMN_POSITION: + return THUNAR_TYPE_DESKTOP_POSITION; + } + + g_assert_not_reached (); + return G_TYPE_INVALID; +} + + + +static gboolean +thunar_desktop_model_get_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreePath *path) +{ + ThunarDesktopModel *model = THUNAR_DESKTOP_MODEL (tree_model); + gint index; + + g_return_val_if_fail (THUNAR_IS_DESKTOP_MODEL (model), FALSE); + g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE); + + index = gtk_tree_path_get_indices (path)[0]; + if (G_UNLIKELY (index >= model->n_items)) + return FALSE; + + iter->stamp = model->stamp; + iter->user_data = g_list_nth (model->items, index); + + return TRUE; +} + + + +static GtkTreePath* +thunar_desktop_model_get_path (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + ThunarDesktopModel *model = THUNAR_DESKTOP_MODEL (tree_model); + + g_return_val_if_fail (THUNAR_IS_DESKTOP_MODEL (model), NULL); + g_return_val_if_fail (iter->stamp == model->stamp, NULL); + + return gtk_tree_path_new_from_indices (g_list_position (model->items, iter->user_data), -1); +} + + + +static void +thunar_desktop_model_get_value (GtkTreeModel *tree_model, + GtkTreeIter *iter, + gint column, + GValue *value) +{ + ThunarDesktopModelItem *item = ((GList *) iter->user_data)->data; + ThunarDesktopModel *model = THUNAR_DESKTOP_MODEL (tree_model); + + g_return_if_fail (THUNAR_IS_DESKTOP_MODEL (model)); + g_return_if_fail (model->stamp == iter->stamp); + + switch (column) + { + case THUNAR_DESKTOP_MODEL_COLUMN_FILE: + g_value_init (value, THUNAR_TYPE_FILE); + g_value_set_object (value, item->file); + break; + + case THUNAR_DESKTOP_MODEL_COLUMN_POSITION: + g_value_init (value, THUNAR_TYPE_DESKTOP_POSITION); + g_value_set_boxed (value, &item->position); + break; + + default: + g_assert_not_reached (); + } +} + + + +static gboolean +thunar_desktop_model_iter_next (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + g_return_val_if_fail (THUNAR_IS_DESKTOP_MODEL (tree_model), FALSE); + g_return_val_if_fail (iter->stamp == THUNAR_DESKTOP_MODEL (tree_model)->stamp, FALSE); + + iter->user_data = ((GList *) iter->user_data)->next; + return (iter->user_data != NULL); +} + + + +static gboolean +thunar_desktop_model_iter_children (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent) +{ + ThunarDesktopModel *model = THUNAR_DESKTOP_MODEL (tree_model); + + g_return_val_if_fail (THUNAR_IS_DESKTOP_MODEL (model), FALSE); + g_return_val_if_fail (parent == NULL || parent->stamp == model->stamp, FALSE); + + if (G_LIKELY (parent == NULL && model->items != NULL)) + { + iter->stamp = model->stamp; + iter->user_data = model->items; + return TRUE; + } + + return FALSE; +} + + + +static gboolean +thunar_desktop_model_iter_has_child (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + return FALSE; +} + + + +static gint +thunar_desktop_model_iter_n_children (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + ThunarDesktopModel *model = THUNAR_DESKTOP_MODEL (tree_model); + + g_return_val_if_fail (THUNAR_IS_DESKTOP_MODEL (model), 0); + g_return_val_if_fail (iter == NULL || iter->stamp == model->stamp, 0); + + return (iter == NULL) ? model->n_items : 0; +} + + + +static gboolean +thunar_desktop_model_iter_nth_child (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent, + gint n) +{ + ThunarDesktopModel *model = THUNAR_DESKTOP_MODEL (tree_model); + + g_return_val_if_fail (THUNAR_IS_DESKTOP_MODEL (model), FALSE); + g_return_val_if_fail (parent == NULL || parent->stamp == model->stamp, FALSE); + + if (G_LIKELY (parent == NULL && n < model->n_items)) + { + iter->stamp = model->stamp; + iter->user_data = g_list_nth (model->items, n); + return TRUE; + } + + return FALSE; +} + + + +static gboolean +thunar_desktop_model_iter_parent (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *child) +{ + return FALSE; +} + + + +static void +thunar_desktop_model_item_free (ThunarDesktopModelItem *item) +{ + g_object_unref (G_OBJECT (item->file)); + g_free (item); +} + + + +/** + * thunar_desktop_model_get_default: + * + * Returns the default #ThunarDesktopModel instance, + * which is shared by all #ThunarDesktopView<!---->s. + * + * The caller is responsible to free the returned + * object using #g_object_unref(). + * + * Return value: the default #ThunarDesktopModel. + **/ +ThunarDesktopModel* +thunar_desktop_model_get_default (void) +{ + static ThunarDesktopModel *model = NULL; + + if (G_LIKELY (model == NULL)) + { + model = g_object_new (THUNAR_TYPE_DESKTOP_MODEL, NULL); + g_object_add_weak_pointer (G_OBJECT (model), (gpointer) &model); + } + else + { + g_object_ref (G_OBJECT (model)); + } + + return model; +} + + + diff --git a/thunar/thunar-desktop-model.h b/thunar/thunar-desktop-model.h new file mode 100644 index 000000000..7a1e9a42a --- /dev/null +++ b/thunar/thunar-desktop-model.h @@ -0,0 +1,67 @@ +/* $Id$ */ +/*- + * Copyright (c) 2005 Benedikt Meurer <benny@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 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 + */ + +#ifndef __THUNAR_DESKTOP_MODEL_H__ +#define __THUNAR_DESKTOP_MODEL_H__ + +#include <thunar/thunar-file.h> + +G_BEGIN_DECLS; + +typedef struct _ThunarDesktopPosition ThunarDesktopPosition; + +#define THUNAR_TYPE_DESKTOP_POSITION (thunar_desktop_position_get_type ()) + +struct _ThunarDesktopPosition +{ + gint row; + gint column; + gint screen_number; +}; + +GType thunar_desktop_position_get_type (void) G_GNUC_CONST; + +ThunarDesktopPosition *thunar_desktop_position_dup (const ThunarDesktopPosition *position) G_GNUC_MALLOC; +void thunar_desktop_position_free (ThunarDesktopPosition *position); + + +typedef struct _ThunarDesktopModelClass ThunarDesktopModelClass; +typedef struct _ThunarDesktopModel ThunarDesktopModel; + +#define THUNAR_TYPE_DESKTOP_MODEL (thunar_desktop_model_get_type ()) +#define THUNAR_DESKTOP_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_DESKTOP_MODEL, ThunarDesktopModel)) +#define THUNAR_DESKTOP_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_DESKTOP_MODEL, ThunarDesktopModelClass)) +#define THUNAR_IS_DESKTOP_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_DESKTOP_MODEL)) +#define THUNAR_IS_DESKTOP_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_DESKTOP_MODEL)) +#define THUNAR_DESKTOP_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_DESKTOP_MODEL, ThunarDesktopModelClass)) + +enum +{ + THUNAR_DESKTOP_MODEL_COLUMN_FILE, + THUNAR_DESKTOP_MODEL_COLUMN_POSITION, + THUNAR_DESKTOP_MODEL_N_COLUMNS, +}; + +GType thunar_desktop_model_get_type (void) G_GNUC_CONST; + +ThunarDesktopModel *thunar_desktop_model_get_default (void); + +G_END_DECLS; + +#endif /* !__THUNAR_DESKTOP_MODEL_H__ */ diff --git a/thunar/thunar-desktop-view.c b/thunar/thunar-desktop-view.c index 157bedc50..d1eecfd9d 100644 --- a/thunar/thunar-desktop-view.c +++ b/thunar/thunar-desktop-view.c @@ -21,33 +21,81 @@ #include <config.h> #endif -#include <exo/exo.h> +#ifdef HAVE_MEMORY_H +#include <memory.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#include <thunar/thunar-desktop-model.h> #include <thunar/thunar-desktop-view.h> +#include <thunar/thunar-file.h> + +#include <thunarx/thunarx-gdk-pixbuf-extensions.h> + + + +#define TILE_WIDTH (48) +#define TILE_HEIGHT (32) + +typedef struct _ThunarDesktopViewItem ThunarDesktopViewItem; enum { PROP_0, - PROP_DISPLAY, + PROP_ICON_SIZE, + PROP_MODEL, + PROP_FILE_COLUMN, + PROP_POSITION_COLUMN, }; -static void thunar_desktop_view_class_init (ThunarDesktopViewClass *klass); -static void thunar_desktop_view_init (ThunarDesktopView *view); -static void thunar_desktop_view_finalize (GObject *object); -static void thunar_desktop_view_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void thunar_desktop_view_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void thunar_desktop_view_realize (GtkWidget *widget); -static void thunar_desktop_view_unrealize (GtkWidget *widget); +static void thunar_desktop_view_class_init (ThunarDesktopViewClass *klass); +static void thunar_desktop_view_init (ThunarDesktopView *view); +static void thunar_desktop_view_finalize (GObject *object); +static void thunar_desktop_view_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void thunar_desktop_view_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void thunar_desktop_view_destroy (GtkObject *object); +static void thunar_desktop_view_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static gboolean thunar_desktop_view_button_press_event (GtkWidget *widget, + GdkEventButton *event); +static gboolean thunar_desktop_view_expose_event (GtkWidget *widget, + GdkEventExpose *event); +static void thunar_desktop_view_build_items (ThunarDesktopView *view); +static ThunarDesktopViewItem *thunar_desktop_view_get_item_at_pos (ThunarDesktopView *view, + gint x, + gint y); +static void thunar_desktop_view_get_item_area (ThunarDesktopView *view, + ThunarDesktopViewItem *item, + GdkRectangle *area); +static void thunar_desktop_view_render_item (ThunarDesktopView *view, + ThunarDesktopViewItem *item, + GdkRectangle *item_area, + GdkRectangle *expose_area); +static void thunar_desktop_view_queue_render_item (ThunarDesktopView *view, + ThunarDesktopViewItem *item); +static void thunar_desktop_view_row_changed (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + ThunarDesktopView *view); +static void thunar_desktop_view_row_inserted (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + ThunarDesktopView *view); +static void thunar_desktop_view_row_deleted (GtkTreeModel *model, + GtkTreePath *path, + ThunarDesktopView *view); @@ -60,7 +108,23 @@ struct _ThunarDesktopView { GtkWidget __parent__; - GdkDisplay *display; + PangoLayout *layout; + + GList *items; + + GtkTreeModel *model; + + gint icon_size; + + gint file_column; + gint position_column; +}; + +struct _ThunarDesktopViewItem +{ + ThunarDesktopPosition position; + GtkTreeIter iter; + gboolean selected : 1; }; @@ -72,6 +136,7 @@ G_DEFINE_TYPE (ThunarDesktopView, thunar_desktop_view, GTK_TYPE_WIDGET); static void thunar_desktop_view_class_init (ThunarDesktopViewClass *klass) { + GtkObjectClass *gtkobject_class; GtkWidgetClass *gtkwidget_class; GObjectClass *gobject_class; @@ -80,24 +145,65 @@ thunar_desktop_view_class_init (ThunarDesktopViewClass *klass) gobject_class->get_property = thunar_desktop_view_get_property; gobject_class->set_property = thunar_desktop_view_set_property; + gtkobject_class = GTK_OBJECT_CLASS (klass); + gtkobject_class->destroy = thunar_desktop_view_destroy; + gtkwidget_class = GTK_WIDGET_CLASS (klass); - gtkwidget_class->realize = thunar_desktop_view_realize; - gtkwidget_class->unrealize = thunar_desktop_view_unrealize; + gtkwidget_class->size_request = thunar_desktop_view_size_request; + gtkwidget_class->button_press_event = thunar_desktop_view_button_press_event; + gtkwidget_class->expose_event = thunar_desktop_view_expose_event; + + /** + * ThunarDesktopView:icon-size: + * + * The icon size in pixels. + **/ + g_object_class_install_property (gobject_class, + PROP_ICON_SIZE, + g_param_spec_int ("icon-size", + _("Icon size"), + _("The icon size in pixels"), + 1, G_MAXINT, 48, + EXO_PARAM_READWRITE)); + + /** + * ThunarDesktopView:model: + * + * The model which is displayed by this #ThunarDesktopView. + **/ + g_object_class_install_property (gobject_class, + PROP_MODEL, + g_param_spec_object ("model", + _("Model"), + _("The model to display"), + GTK_TYPE_TREE_MODEL, + EXO_PARAM_READWRITE)); + + /** + * ThunarDesktopView:file-column: + * + * The column in the model which contains the #ThunarFile. + **/ + g_object_class_install_property (gobject_class, + PROP_FILE_COLUMN, + g_param_spec_int ("file-column", + _("File column"), + _("The column which contains the file"), + -1, G_MAXINT, -1, + EXO_PARAM_READWRITE)); /** - * ThunarDesktopView:display: + * ThunarDesktopView:position-column: * - * The #GdkDisplay covered by this desktop view or %NULL if - * the desktop view is not currently connected to any - * display. + * The column in the model which contains the location (as #ThunarDesktopPosition). **/ g_object_class_install_property (gobject_class, - PROP_DISPLAY, - g_param_spec_object ("display", - _("Display"), - _("The display currently associated with"), - GDK_TYPE_DISPLAY, - G_PARAM_READWRITE)); + PROP_POSITION_COLUMN, + g_param_spec_int ("position-column", + _("Position column"), + _("The column which contains the position"), + -1, G_MAXINT, -1, + EXO_PARAM_READWRITE)); } @@ -105,6 +211,17 @@ thunar_desktop_view_class_init (ThunarDesktopViewClass *klass) static void thunar_desktop_view_init (ThunarDesktopView *view) { + GTK_WIDGET_SET_FLAGS (view, GTK_CAN_FOCUS); + GTK_WIDGET_SET_FLAGS (view, GTK_NO_WINDOW); + + view->layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), NULL); + pango_layout_set_alignment (view->layout, PANGO_ALIGN_CENTER); + pango_layout_set_wrap (view->layout, PANGO_WRAP_WORD_CHAR); + + view->file_column = -1; + view->position_column = -1; + + thunar_desktop_view_set_icon_size (view, 48); } @@ -114,9 +231,9 @@ thunar_desktop_view_finalize (GObject *object) { ThunarDesktopView *view = THUNAR_DESKTOP_VIEW (object); - g_return_if_fail (THUNAR_IS_DESKTOP_VIEW (view)); + g_object_unref (G_OBJECT (view->layout)); - G_OBJECT_CLASS (thunar_desktop_view_parent_class)->finalize (object); + (*G_OBJECT_CLASS (thunar_desktop_view_parent_class)->finalize) (object); } @@ -131,8 +248,20 @@ thunar_desktop_view_get_property (GObject *object, switch (prop_id) { - case PROP_DISPLAY: - g_value_set_object (value, thunar_desktop_view_get_display (view)); + case PROP_ICON_SIZE: + g_value_set_int (value, thunar_desktop_view_get_icon_size (view)); + break; + + case PROP_MODEL: + g_value_set_object (value, thunar_desktop_view_get_model (view)); + break; + + case PROP_FILE_COLUMN: + g_value_set_int (value, thunar_desktop_view_get_file_column (view)); + break; + + case PROP_POSITION_COLUMN: + g_value_set_int (value, thunar_desktop_view_get_position_column (view)); break; default: @@ -144,17 +273,29 @@ thunar_desktop_view_get_property (GObject *object, static void -thunar_desktop_view_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) +thunar_desktop_view_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { ThunarDesktopView *view = THUNAR_DESKTOP_VIEW (object); switch (prop_id) { - case PROP_DISPLAY: - thunar_desktop_view_set_display (view, g_value_get_object (value)); + case PROP_ICON_SIZE: + thunar_desktop_view_set_icon_size (view, g_value_get_int (value)); + break; + + case PROP_MODEL: + thunar_desktop_view_set_model (view, g_value_get_object (value)); + break; + + case PROP_FILE_COLUMN: + thunar_desktop_view_set_file_column (view, g_value_get_int (value)); + break; + + case PROP_POSITION_COLUMN: + thunar_desktop_view_set_position_column (view, g_value_get_int (value)); break; default: @@ -166,24 +307,293 @@ thunar_desktop_view_set_property (GObject *object, static void -thunar_desktop_view_realize (GtkWidget *widget) +thunar_desktop_view_destroy (GtkObject *object) { - ThunarDesktopView *view = THUNAR_DESKTOP_VIEW (widget); + ThunarDesktopView *view = THUNAR_DESKTOP_VIEW (object); + + thunar_desktop_view_set_model (view, NULL); - // TODO: Create one GdkWindow per screen (each spanning - // all monitors connected to the given screen) - (void)&view; + (*GTK_OBJECT_CLASS (thunar_desktop_view_parent_class)->destroy) (object); } static void -thunar_desktop_view_unrealize (GtkWidget *widget) +thunar_desktop_view_size_request (GtkWidget *widget, + GtkRequisition *requisition) { ThunarDesktopView *view = THUNAR_DESKTOP_VIEW (widget); - // TODO: Destroy all previously created GdkWindow's - (void)&view; + requisition->width = view->icon_size; + requisition->height = view->icon_size; +} + + + +static gboolean +thunar_desktop_view_button_press_event (GtkWidget *widget, + GdkEventButton *event) +{ + ThunarDesktopViewItem *item; + ThunarDesktopView *view = THUNAR_DESKTOP_VIEW (widget); + + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + + if (event->button == 1 && event->type == GDK_BUTTON_PRESS) + { + item = thunar_desktop_view_get_item_at_pos (view, event->x, event->y); + if (item != NULL) + { + item->selected = TRUE; + thunar_desktop_view_queue_render_item (view, item); + } + else + { + thunar_desktop_view_unselect_all (view); + } + } + + return (event->button == 1); +} + + + +static gboolean +thunar_desktop_view_expose_event (GtkWidget *widget, + GdkEventExpose *event) +{ + ThunarDesktopViewItem *item; + ThunarDesktopView *view = THUNAR_DESKTOP_VIEW (widget); + GdkRectangle item_area; + GList *lp; + gint screen_number; + + /* check if all necessary attributes are set */ + if (view->model == NULL || view->file_column < 0 || view->position_column < 0) + return FALSE; + + screen_number = gdk_screen_get_number (gtk_widget_get_screen (widget)); + + for (lp = view->items; lp != NULL; lp = lp->next) + { + item = lp->data; + + /* check if the item should be display on this screen */ + if (G_UNLIKELY (item->position.screen_number != screen_number)) + continue; + + thunar_desktop_view_get_item_area (view, item, &item_area); + + if (gdk_region_rect_in (event->region, &item_area) != GDK_OVERLAP_RECTANGLE_OUT) + thunar_desktop_view_render_item (view, item, &item_area, &event->area); + } + + return TRUE; +} + + + +static void +thunar_desktop_view_build_items (ThunarDesktopView *view) +{ + ThunarDesktopViewItem *item; + GtkTreeIter iter; + GValue value = { 0, }; + + if (gtk_tree_model_get_iter_first (view->model, &iter)) + { + do + { + item = g_new (ThunarDesktopViewItem, 1); + item->iter = iter; + + if (G_LIKELY (view->position_column >= 0)) + { + gtk_tree_model_get_value (view->model, &item->iter, view->position_column, &value); + item->position = *((ThunarDesktopPosition *) g_value_get_boxed (&value)); + g_value_unset (&value); + } + else + memset (&item->position, 0, sizeof (item->position)); + + view->items = g_list_prepend (view->items, item); + } + while (gtk_tree_model_iter_next (view->model, &iter)); + } +} + + + +static ThunarDesktopViewItem* +thunar_desktop_view_get_item_at_pos (ThunarDesktopView *view, + gint x, + gint y) +{ + ThunarDesktopViewItem *item; + GdkRectangle item_area; + GdkRectangle icon_area; + GdkRectangle text_area; + ThunarFile *file; + GdkRegion *region; + GdkPixbuf *icon; + GList *lp; + + region = gdk_region_new (); + + for (lp = view->items; lp != NULL; lp = lp->next) + { + item = lp->data; + thunar_desktop_view_get_item_area (view, item, &item_area); + + gtk_tree_model_get (view->model, &item->iter, view->file_column, &file, -1); + + /* add the icon area */ + icon = thunar_file_load_icon (file, view->icon_size); + icon_area.width = gdk_pixbuf_get_width (icon); + icon_area.height = gdk_pixbuf_get_height (icon); + icon_area.x = item_area.x + (TILE_WIDTH * 2 - icon_area.width) / 2; + icon_area.y = item_area.y + (TILE_HEIGHT * 2 - icon_area.height) / 2; + gdk_region_union_with_rect (region, &icon_area); + g_object_unref (G_OBJECT (icon)); + + /* add the text area */ + pango_layout_set_text (view->layout, thunar_file_get_special_name (file), -1); + pango_layout_set_width (view->layout, item_area.width * PANGO_SCALE); + pango_layout_get_pixel_size (view->layout, &text_area.width, &text_area.height); + text_area.x = item_area.x + (item_area.width - text_area.width) / 2; + text_area.y = item_area.y + TILE_HEIGHT * 2; + gdk_region_union_with_rect (region, &text_area); + + g_object_unref (G_OBJECT (file)); + + if (gdk_region_point_in (region, x, y)) + return item; + } + + return NULL; +} + + + +static void +thunar_desktop_view_get_item_area (ThunarDesktopView *view, + ThunarDesktopViewItem *item, + GdkRectangle *area) +{ + area->x = item->position.column * TILE_WIDTH + GTK_WIDGET (view)->allocation.x; + area->y = item->position.row * TILE_HEIGHT + GTK_WIDGET (view)->allocation.y; + area->width = TILE_WIDTH * 2; + area->height = TILE_HEIGHT * 3; +} + + + +static void +thunar_desktop_view_render_item (ThunarDesktopView *view, + ThunarDesktopViewItem *item, + GdkRectangle *item_area, + GdkRectangle *expose_area) +{ + GdkRectangle draw_area; + GdkRectangle icon_area; + GdkRectangle text_area; + ThunarFile *file; + GdkPixbuf *colorized_icon; + GdkPixbuf *icon; + + gtk_tree_model_get (view->model, &item->iter, view->file_column, &file, -1); + + icon = thunar_file_load_icon (file, view->icon_size); + + icon_area.width = gdk_pixbuf_get_width (icon); + icon_area.height = gdk_pixbuf_get_height (icon); + icon_area.x = item_area->x + (TILE_WIDTH * 2 - icon_area.width) / 2; + icon_area.y = item_area->y + (TILE_HEIGHT * 2 - icon_area.height) / 2; + + if (gdk_rectangle_intersect (expose_area, &icon_area, &draw_area)) + { + if (G_UNLIKELY (item->selected)) + { + colorized_icon = thunarx_gdk_pixbuf_colorize (icon, >K_WIDGET (view)->style->base[GTK_STATE_SELECTED]); + g_object_unref (G_OBJECT (icon)); + icon = colorized_icon; + } + + gdk_draw_pixbuf (GTK_WIDGET (view)->window, GTK_WIDGET (view)->style->black_gc, icon, + draw_area.x - icon_area.x, draw_area.y - icon_area.y, + draw_area.x, draw_area.y, draw_area.width, draw_area.height, + GDK_RGB_DITHER_NORMAL, 0, 0); + } + + text_area.x = item_area->x; + text_area.y = item_area->y + TILE_HEIGHT * 2; + text_area.width = 2 * TILE_WIDTH; + text_area.height = TILE_HEIGHT; + + if (gdk_rectangle_intersect (expose_area, &text_area, &draw_area)) + { + pango_layout_set_text (view->layout, thunar_file_get_special_name (file), -1); + pango_layout_set_width (view->layout, text_area.width * PANGO_SCALE); + + gtk_paint_layout (GTK_WIDGET (view)->style, GTK_WIDGET (view)->window, + item->selected ? GTK_STATE_SELECTED : GTK_STATE_NORMAL, + TRUE, expose_area, GTK_WIDGET (view), "icon_view", + text_area.x, text_area.y, view->layout); + } + + g_object_unref (G_OBJECT (file)); + g_object_unref (G_OBJECT (icon)); +} + + + +static void +thunar_desktop_view_queue_render_item (ThunarDesktopView *view, + ThunarDesktopViewItem *item) +{ + GdkRectangle item_area; + + if (G_LIKELY (GTK_WIDGET_REALIZED (view))) + { + thunar_desktop_view_get_item_area (view, item, &item_area); + gdk_window_invalidate_rect (GTK_WIDGET (view)->window, &item_area, FALSE); + } +} + + + +static void +thunar_desktop_view_row_changed (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + ThunarDesktopView *view) +{ + // FIXME: Implement this + g_error ("Not implemented!"); +} + + + +static void +thunar_desktop_view_row_inserted (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + ThunarDesktopView *view) +{ + // FIXME: Implement this + g_error ("Not implemented!"); +} + + + +static void +thunar_desktop_view_row_deleted (GtkTreeModel *model, + GtkTreePath *path, + ThunarDesktopView *view) +{ + // FIXME: Implement this + g_error ("Not implemented!"); } @@ -191,12 +601,9 @@ thunar_desktop_view_unrealize (GtkWidget *widget) /** * thunar_desktop_view_new: * - * Creates a new #ThunarDesktopView, which is associated with - * no #GdkDisplay. You'll need to set a display using - * #thunar_desktop_view_set_display() before realizing the - * view. + * Allocates a new #ThunarDesktopView instance. * - * Return value: the newly allocated #ThunarDesktopView instance. + * Return value: the newly allocated #ThunarDesktopView. **/ GtkWidget* thunar_desktop_view_new (void) @@ -207,80 +614,262 @@ thunar_desktop_view_new (void) /** - * thunar_desktop_view_new_with_display: - * @display : a valid #GdkDisplay. + * thunar_desktop_view_get_icon_size: + * @view : a #ThunarDesktopView. * - * Creates a new #ThunarDesktop and associates it with the given - * @display. You can instantly show (and thereby realize) the - * returned object. + * Returns the icon size set for @view. * - * Return value: the newly allocated #ThunarDesktopView instance. + * Return value: the icon size for @view. **/ -GtkWidget* -thunar_desktop_view_new_with_display (GdkDisplay *display) +gint +thunar_desktop_view_get_icon_size (ThunarDesktopView *view) +{ + g_return_val_if_fail (THUNAR_IS_DESKTOP_VIEW (view), -1); + return view->icon_size; +} + + + +/** + * thunar_desktop_view_set_icon_size: + * @view : a #ThunarDesktopView. + * @icon_size : the new icon size for @view. + * + * Sets the icon size for @view to @icon_size. + **/ +void +thunar_desktop_view_set_icon_size (ThunarDesktopView *view, + gint icon_size) { - g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL); + g_return_if_fail (THUNAR_IS_DESKTOP_VIEW (view)); + g_return_if_fail (icon_size > 0); - return g_object_new (THUNAR_TYPE_DESKTOP_VIEW, - "display", display, - NULL); + if (G_LIKELY (view->icon_size != icon_size)) + { + view->icon_size = icon_size; + gtk_widget_queue_resize (GTK_WIDGET (view)); + g_object_notify (G_OBJECT (view), "icon-size"); + } } /** - * thunar_desktop_view_get_display: + * thunar_desktop_view_get_model: * @view : a #ThunarDesktopView. * - * Queries the #GdkDisplay currently used by the @view. May return - * %NULL if no display has been set yet. + * Returns the #GtkTreeModel set for @view. * - * Return value: the #GdkDisplay @view is associated with or %NULL. + * Return value: the model of @view. **/ -GdkDisplay* -thunar_desktop_view_get_display (ThunarDesktopView *view) +GtkTreeModel* +thunar_desktop_view_get_model (ThunarDesktopView *view) { g_return_val_if_fail (THUNAR_IS_DESKTOP_VIEW (view), NULL); - return view->display; + return view->model; } /** - * thunar_desktop_view_set_display: - * @view : a #ThunarDesktopView. - * @display : a #GdkDisplay or %NULL. + * thunar_desktop_view_set_model: + * @view : a #ThunarDesktopView. + * @model : a #GtkTreeModel or %NULL. * - * Sets the display to use for @view to @display. If @view was - * previously connected to another #GdkDisplay, it'll first - * disconnect from the old display, then connect to the new - * display. + * Sets the model to use for @view to @model. **/ void -thunar_desktop_view_set_display (ThunarDesktopView *view, - GdkDisplay *display) +thunar_desktop_view_set_model (ThunarDesktopView *view, + GtkTreeModel *model) { + GType type; + g_return_if_fail (THUNAR_IS_DESKTOP_VIEW (view)); - g_return_if_fail (display == NULL || GDK_IS_DISPLAY (display)); + g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model)); - /* don't do anything if we already use that display */ - if (G_UNLIKELY (display == view->display)) + if (G_UNLIKELY (view->model == model)) return; - if (view->display != NULL) + /* verify the new model (if any) */ + if (G_LIKELY (model != NULL)) + { + g_return_if_fail ((gtk_tree_model_get_flags (model) & (GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY)) != 0); + + if (view->file_column >= 0) + { + type = gtk_tree_model_get_column_type (model, view->file_column); + g_return_if_fail (type == THUNAR_TYPE_FILE); + } + + if (view->position_column >= 0) + { + type = gtk_tree_model_get_column_type (model, view->position_column); + g_return_if_fail (type == THUNAR_TYPE_DESKTOP_POSITION); + } + } + + /* disconnect from the previous model */ + if (G_LIKELY (view->model != NULL)) + { + /* disconnect signals */ + g_signal_handlers_disconnect_by_func (G_OBJECT (view->model), thunar_desktop_view_row_changed, view); + g_signal_handlers_disconnect_by_func (G_OBJECT (view->model), thunar_desktop_view_row_inserted, view); + g_signal_handlers_disconnect_by_func (G_OBJECT (view->model), thunar_desktop_view_row_deleted, view); + + /* drop items */ + g_list_foreach (view->items, (GFunc) g_free, NULL); + g_list_free (view->items); + view->items = NULL; + + /* drop the model */ + g_object_unref (G_OBJECT (view->model)); + } + + /* activate the new model */ + view->model = model; + + /* connect to the new model */ + if (G_LIKELY (model != NULL)) + { + /* connect signals */ + g_signal_connect (G_OBJECT (model), "row-changed", G_CALLBACK (thunar_desktop_view_row_changed), view); + g_signal_connect (G_OBJECT (model), "row-inserted", G_CALLBACK (thunar_desktop_view_row_inserted), view); + g_signal_connect (G_OBJECT (model), "row-deleted", G_CALLBACK (thunar_desktop_view_row_deleted), view); + + /* generate the items */ + thunar_desktop_view_build_items (view); + + /* take a reference on the model */ + g_object_ref (G_OBJECT (model)); + } + + gtk_widget_queue_draw (GTK_WIDGET (view)); + g_object_notify (G_OBJECT (view), "model"); +} + + + +/** + * thunar_desktop_view_get_file_column: + * @view : a #ThunarDesktopView. + * + * Return value: the file column or -1. + **/ +gint +thunar_desktop_view_get_file_column (ThunarDesktopView *view) +{ + g_return_val_if_fail (THUNAR_IS_DESKTOP_VIEW (view), -1); + return view->file_column; +} + + + +/** + * thunar_desktop_view_set_file_column: + * @view : a #ThunarDesktopView. + * @file_column : the new file column or -1. + **/ +void +thunar_desktop_view_set_file_column (ThunarDesktopView *view, + gint file_column) +{ + g_return_if_fail (THUNAR_IS_DESKTOP_VIEW (view)); + g_return_if_fail (file_column == -1 || file_column >= 0); + + if (G_LIKELY (view->file_column != file_column)) { - // TODO: Disconnect from the old display (take into account the - // REALIZED state) + view->file_column = file_column; + gtk_widget_queue_draw (GTK_WIDGET (view)); + g_object_notify (G_OBJECT (view), "file-column"); } +} + - view->display = display; - if (view->display != NULL) +/** + * thunar_desktop_view_get_position_column: + * @view : a #ThunarDesktopView. + * + * Returns the position column. + * + * Return value: the position column or -1. + **/ +gint +thunar_desktop_view_get_position_column (ThunarDesktopView *view) +{ + g_return_val_if_fail (THUNAR_IS_DESKTOP_VIEW (view), -1); + return view->position_column; +} + + + +/** + * thunar_desktop_view_set_position_column: + * @view : a #ThunarDesktopView. + * @position_column : the new position column or -1. + **/ +void +thunar_desktop_view_set_position_column (ThunarDesktopView *view, + gint position_column) +{ + ThunarDesktopViewItem *item; + GValue value = { 0, }; + GList *lp; + + g_return_if_fail (THUNAR_IS_DESKTOP_VIEW (view)); + g_return_if_fail (position_column == -1 || position_column >= 0); + + if (G_LIKELY (view->position_column != position_column)) { - // TODO: Connect to the new display (take into account the - // REALIZED state) + /* update all item positions */ + if (G_LIKELY (view->model != NULL)) + { + for (lp = view->items; lp != NULL; lp = lp->next) + { + item = lp->data; + if (G_LIKELY (position_column >= 0)) + { + gtk_tree_model_get_value (view->model, &item->iter, position_column, &value); + item->position = *((ThunarDesktopPosition *) g_value_get_boxed (&value)); + g_value_unset (&value); + } + else + memset (&item->position, 0, sizeof (item->position)); + } + } + + /* apply the new column */ + view->position_column = position_column; + gtk_widget_queue_draw (GTK_WIDGET (view)); + g_object_notify (G_OBJECT (view), "position-column"); } +} + + - /* notify listeners */ - g_object_notify (G_OBJECT (view), "display"); +/** + * thunar_desktop_view_unselect_all: + * @view : a #ThunarDesktopView. + * + * Unselects all selected items in @view. + **/ +void +thunar_desktop_view_unselect_all (ThunarDesktopView *view) +{ + ThunarDesktopViewItem *item; + GList *lp; + + g_return_if_fail (THUNAR_IS_DESKTOP_VIEW (view)); + + for (lp = view->items; lp != NULL; lp = lp->next) + { + item = lp->data; + if (G_UNLIKELY (item->selected)) + { + item->selected = FALSE; + thunar_desktop_view_queue_render_item (view, item); + } + } } + + diff --git a/thunar/thunar-desktop-view.h b/thunar/thunar-desktop-view.h index 7963ee91c..9311a80ff 100644 --- a/thunar/thunar-desktop-view.h +++ b/thunar/thunar-desktop-view.h @@ -22,28 +22,39 @@ #include <gtk/gtk.h> -#include <thunar/thunar-preferences.h> - G_BEGIN_DECLS; -typedef struct _ThunarDesktopViewClass ThunarDesktopViewClass; -typedef struct _ThunarDesktopView ThunarDesktopView; +typedef struct _ThunarDesktopViewClass ThunarDesktopViewClass; +typedef struct _ThunarDesktopView ThunarDesktopView; #define THUNAR_TYPE_DESKTOP_VIEW (thunar_desktop_view_get_type ()) #define THUNAR_DESKTOP_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_DESKTOP_VIEW, ThunarDesktopView)) #define THUNAR_DESKTOP_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_DESKTOP_VIEW, ThunarDesktopViewClass)) #define THUNAR_IS_DESKTOP_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_DESKTOP_VIEW)) #define THUNAR_IS_DESKTOP_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_DESKTOP_VIEW)) -#define THUNAR_DESKTOP_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_DESKTOP_VIEW, ThunarDesktopViewClass)) +#define THUNAR_DESKTOP_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_DESKTOP_VIEW, ThunarDesktopView)) + +GType thunar_desktop_view_get_type (void) G_GNUC_CONST; + +GtkWidget *thunar_desktop_view_new (void); + +gint thunar_desktop_view_get_icon_size (ThunarDesktopView *view); +void thunar_desktop_view_set_icon_size (ThunarDesktopView *view, + gint icon_size); + +GtkTreeModel *thunar_desktop_view_get_model (ThunarDesktopView *view); +void thunar_desktop_view_set_model (ThunarDesktopView *view, + GtkTreeModel *model); -GType thunar_desktop_view_get_type (void) G_GNUC_CONST; +gint thunar_desktop_view_get_file_column (ThunarDesktopView *view); +void thunar_desktop_view_set_file_column (ThunarDesktopView *view, + gint file_column); -GtkWidget *thunar_desktop_view_new (void); -GtkWidget *thunar_desktop_view_new_with_display (GdkDisplay *display); +gint thunar_desktop_view_get_position_column (ThunarDesktopView *view); +void thunar_desktop_view_set_position_column (ThunarDesktopView *view, + gint position_column); -GdkDisplay *thunar_desktop_view_get_display (ThunarDesktopView *view); -void thunar_desktop_view_set_display (ThunarDesktopView *view, - GdkDisplay *display); +void thunar_desktop_view_unselect_all (ThunarDesktopView *view); G_END_DECLS; diff --git a/thunar/thunar-desktop-window.c b/thunar/thunar-desktop-window.c new file mode 100644 index 000000000..b7d7a1f9c --- /dev/null +++ b/thunar/thunar-desktop-window.c @@ -0,0 +1,216 @@ +/* $Id$ */ +/*- + * Copyright (c) 2005 Benedikt Meurer <benny@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 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 <config.h> +#endif + +#include <thunar/thunar-desktop-model.h> +#include <thunar/thunar-desktop-window.h> +#include <thunar/thunar-desktop-view.h> + + + +static void thunar_desktop_window_class_init (ThunarDesktopWindowClass *klass); +static void thunar_desktop_window_init (ThunarDesktopWindow *window); +static void thunar_desktop_window_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void thunar_desktop_window_realize (GtkWidget *widget); +static void thunar_desktop_window_unrealize (GtkWidget *widget); +static gboolean thunar_desktop_window_forward_event (GtkWidget *widget, + GdkEvent *event); + + + +struct _ThunarDesktopWindowClass +{ + GtkWindowClass __parent__; +}; + +struct _ThunarDesktopWindow +{ + GtkWindow __parent__; + + GtkWidget *view; +}; + + + +G_DEFINE_TYPE (ThunarDesktopWindow, thunar_desktop_window, GTK_TYPE_WINDOW); + + + +static void +thunar_desktop_window_class_init (ThunarDesktopWindowClass *klass) +{ + GtkWidgetClass *gtkwidget_class; + + gtkwidget_class = GTK_WIDGET_CLASS (klass); + gtkwidget_class->size_request = thunar_desktop_window_size_request; + gtkwidget_class->realize = thunar_desktop_window_realize; + gtkwidget_class->unrealize = thunar_desktop_window_unrealize; + gtkwidget_class->button_press_event = (gpointer) thunar_desktop_window_forward_event; + gtkwidget_class->button_release_event = (gpointer) thunar_desktop_window_forward_event; +} + + + +static void +thunar_desktop_window_init (ThunarDesktopWindow *window) +{ + ThunarDesktopModel *model; + + GTK_WIDGET_UNSET_FLAGS (window, GTK_DOUBLE_BUFFERED); + + gtk_widget_add_events (GTK_WIDGET (window), + GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK); + + gtk_window_move (GTK_WINDOW (window), 0, 0); + gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DESKTOP); + + /* setup the view */ + window->view = thunar_desktop_view_new (); + thunar_desktop_view_set_file_column (THUNAR_DESKTOP_VIEW (window->view), THUNAR_DESKTOP_MODEL_COLUMN_FILE); + thunar_desktop_view_set_position_column (THUNAR_DESKTOP_VIEW (window->view), THUNAR_DESKTOP_MODEL_COLUMN_POSITION); + gtk_container_add (GTK_CONTAINER (window), window->view); + gtk_widget_show (window->view); + + /* setup the model */ + model = thunar_desktop_model_get_default (); + thunar_desktop_view_set_model (THUNAR_DESKTOP_VIEW (window->view), GTK_TREE_MODEL (model)); + g_object_unref (G_OBJECT (model)); +} + + + +static void +thunar_desktop_window_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GdkScreen *screen = gtk_widget_get_screen (widget); + + requisition->width = gdk_screen_get_width (screen); + requisition->height = gdk_screen_get_height (screen); +} + + + +static void +thunar_desktop_window_realize (GtkWidget *widget) +{ + GdkScreen *screen; + GdkWindow *root; + GdkAtom atom; + Window xid; + + GTK_WIDGET_CLASS (thunar_desktop_window_parent_class)->realize (widget); + + xid = GDK_DRAWABLE_XID (widget->window); + screen = gtk_widget_get_screen (widget); + root = gdk_screen_get_root_window (screen); + + /* configure this window to be a "desktop" window */ + atom = gdk_atom_intern ("_NET_WM_WINDOW_TYPE_DESKTOP", FALSE); + gdk_property_change (widget->window, + gdk_atom_intern ("_NET_WM_WINDOW_TYPE", FALSE), + gdk_atom_intern ("ATOM", FALSE), 32, + GDK_PROP_MODE_REPLACE, (gpointer) &atom, 1); + + /* tell the root window that we have a new "desktop" window */ + gdk_property_change (root, + gdk_atom_intern ("NAUTILUS_DESKTOP_WINDOW_ID", FALSE), + gdk_atom_intern ("WINDOW", FALSE), 32, + GDK_PROP_MODE_REPLACE, (gpointer) &xid, 1); + gdk_property_change (root, + gdk_atom_intern ("XFCE_DESKTOP_WINDOW", FALSE), + gdk_atom_intern ("WINDOW", FALSE), 32, + GDK_PROP_MODE_REPLACE, (gpointer) &xid, 1); + + /* XRandR support */ + g_signal_connect_swapped (G_OBJECT (screen), "size-changed", G_CALLBACK (gtk_widget_queue_resize), widget); +} + + + +static void +thunar_desktop_window_unrealize (GtkWidget *widget) +{ + GdkScreen *screen; + GdkWindow *root; + + screen = gtk_widget_get_screen (widget); + root = gdk_screen_get_root_window (screen); + + /* disconnect the XRandR support handler */ + g_signal_handlers_disconnect_by_func (G_OBJECT (screen), gtk_widget_queue_resize, widget); + + /* unset root window properties */ + gdk_property_delete (root, gdk_atom_intern ("NAUTILUS_DESKTOP_WINDOW_ID", FALSE)); + gdk_property_delete (root, gdk_atom_intern ("XFCE_DESKTOP_WINDOW", FALSE)); + + GTK_WIDGET_CLASS (thunar_desktop_window_parent_class)->unrealize (widget); +} + + + +static gboolean +thunar_desktop_window_forward_event (GtkWidget *widget, + GdkEvent *event) +{ + if (G_LIKELY (GTK_BIN (widget)->child != NULL)) + return gtk_widget_event (GTK_BIN (widget)->child, event); + return FALSE; +} + + + +/** + * thunar_desktop_window_new: + * + * Allocates a new #ThunarDesktopWindow instance. + * + * Return value: the newly allocated #ThunarDesktopWindow. + **/ +GtkWidget* +thunar_desktop_window_new (void) +{ + return thunar_desktop_window_new_with_screen (gdk_screen_get_default ()); +} + + + +/** + * thunar_desktop_window_new_with_screen: + * @screen : a #GdkScreen. + * + * Allocates a new #ThunarDesktopWindow instance and + * associates it with the given @screen. + * + * Return value: the newly allocated #ThunarDesktopWindow. + **/ +GtkWidget* +thunar_desktop_window_new_with_screen (GdkScreen *screen) +{ + g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); + return g_object_new (THUNAR_TYPE_DESKTOP_WINDOW, + "screen", screen, + NULL); +} + diff --git a/thunar/thunar-desktop-window.h b/thunar/thunar-desktop-window.h new file mode 100644 index 000000000..9e5cd7bf8 --- /dev/null +++ b/thunar/thunar-desktop-window.h @@ -0,0 +1,44 @@ +/* $Id$ */ +/*- + * Copyright (c) 2005 Benedikt Meurer <benny@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 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 + */ + +#ifndef __THUNAR_DESKTOP_WINDOW_H__ +#define __THUNAR_DESKTOP_WINDOW_H__ + +#include <gtk/gtk.h> + +G_BEGIN_DECLS; + +typedef struct _ThunarDesktopWindowClass ThunarDesktopWindowClass; +typedef struct _ThunarDesktopWindow ThunarDesktopWindow; + +#define THUNAR_TYPE_DESKTOP_WINDOW (thunar_desktop_window_get_type ()) +#define THUNAR_DESKTOP_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_DESKTOP_WINDOW, ThunarDesktopWindow)) +#define THUNAR_DESKTOP_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_DESKTOP_WINDOW, ThunarDesktopWindowClass)) +#define THUNAR_IS_DESKTOP_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_DESKTOP_WINDOW)) +#define THUNAR_IS_DESKTOP_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_DESKTOP_WINDOW)) +#define THUNAR_DESKTOP_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_DESKTOP_WINDOW, ThunarDesktopWindowClass)) + +GType thunar_desktop_window_get_type (void) G_GNUC_CONST; + +GtkWidget *thunar_desktop_window_new (void); +GtkWidget *thunar_desktop_window_new_with_screen (GdkScreen *screen); + +G_END_DECLS; + +#endif /* !__THUNAR_DESKTOP_WINDOW_H__ */ diff --git a/thunar/thunar-file.c b/thunar/thunar-file.c index d8a9143e4..938b6f57c 100644 --- a/thunar/thunar-file.c +++ b/thunar/thunar-file.c @@ -1168,17 +1168,22 @@ thunar_file_load_icon (ThunarFile *file, g_return_val_if_fail (THUNAR_IS_FILE (file), NULL); /* see if we have a cached icon that matches the request */ - if (file->cached_icon != NULL && file->cached_size == size) + if (file->cached_icon == NULL || file->cached_size != size) { - /* take a reference on the cached icon for the caller */ - g_object_ref (G_OBJECT (file->cached_icon)); - return file->cached_icon; + /* drop any previous icon */ + if (file->cached_icon != NULL) + g_object_unref (G_OBJECT (file->cached_icon)); + + /* load the icon */ + icon_factory = thunar_icon_factory_get_default (); + icon_theme = thunar_icon_factory_get_icon_theme (icon_factory); + icon_name = THUNAR_FILE_GET_CLASS (file)->get_icon_name (file, icon_theme); + file->cached_icon = thunar_icon_factory_load_icon (icon_factory, icon_name, size, NULL, TRUE); } - icon_factory = thunar_icon_factory_get_default (); - icon_theme = thunar_icon_factory_get_icon_theme (icon_factory); - icon_name = THUNAR_FILE_GET_CLASS (file)->get_icon_name (file, icon_theme); - return thunar_icon_factory_load_icon (icon_factory, icon_name, size, NULL, TRUE); + /* take a reference on the cached icon for the caller */ + g_object_ref (G_OBJECT (file->cached_icon)); + return file->cached_icon; } diff --git a/thunarx/Makefile.am b/thunarx/Makefile.am new file mode 100644 index 000000000..4f639bd25 --- /dev/null +++ b/thunarx/Makefile.am @@ -0,0 +1,25 @@ +# $Id$ + +INCLUDES = \ + -I$(top_srcdir) \ + -DEXO_API_SUBJECT_TO_CHANGE \ + -DEXO_DISABLE_DEPRECATED \ + -DG_LOG_DOMAIN=\"thunarx\" + +noinst_LTLIBRARIES = \ + libthunarx.la + +libthunarx_la_SOURCES = \ + thunarx-gdk-pixbuf-extensions.c \ + thunarx-gdk-pixbuf-extensions.h + +libthunarx_la_CFLAGS = \ + $(EXO_CFLAGS) + +libthunarx_la_LDFLAGS = \ + -no-undefined + +libthunarx_la_LIBADD = \ + $(EXO_LIBS) + +# vi:set ts=8 sw=8 noet ai nocindent syntax=automake: diff --git a/thunarx/thunarx-gdk-pixbuf-extensions.c b/thunarx/thunarx-gdk-pixbuf-extensions.c new file mode 100644 index 000000000..f5d51bfd9 --- /dev/null +++ b/thunarx/thunarx-gdk-pixbuf-extensions.c @@ -0,0 +1,90 @@ +/* $Id$ */ +/*- + * Copyright (c) 2005 Benedikt Meurer <benny@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 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 <config.h> +#endif + +#include <thunarx/thunarx-gdk-pixbuf-extensions.h> + + + +/** + * thunarx_gdk_pixbuf_colorize: + * @src : the source #GdkPixbuf. + * @color : the new color. + * + * Creates a new #GdkPixbuf based on @src, which is + * colorized to @color. + * + * Return value: the colorized #GdkPixbuf. + **/ +GdkPixbuf* +thunarx_gdk_pixbuf_colorize (GdkPixbuf *src, + const GdkColor *color) +{ + gint i, j; + gint width, height, has_alpha, src_row_stride, dst_row_stride; + gint red_value, green_value, blue_value; + guchar *target_pixels; + guchar *original_pixels; + guchar *pixsrc; + guchar *pixdest; + GdkPixbuf *dest; + + red_value = color->red / 255.0; + green_value = color->green / 255.0; + blue_value = color->blue / 255.0; + + dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src), + gdk_pixbuf_get_has_alpha (src), + gdk_pixbuf_get_bits_per_sample (src), + gdk_pixbuf_get_width (src), + gdk_pixbuf_get_height (src)); + + has_alpha = gdk_pixbuf_get_has_alpha (src); + width = gdk_pixbuf_get_width (src); + height = gdk_pixbuf_get_height (src); + src_row_stride = gdk_pixbuf_get_rowstride (src); + dst_row_stride = gdk_pixbuf_get_rowstride (dest); + target_pixels = gdk_pixbuf_get_pixels (dest); + original_pixels = gdk_pixbuf_get_pixels (src); + + for (i = 0; i < height; i++) + { + pixdest = target_pixels + i*dst_row_stride; + pixsrc = original_pixels + i*src_row_stride; + + for (j = 0; j < width; j++) + { + *pixdest++ = (*pixsrc++ * red_value) >> 8; + *pixdest++ = (*pixsrc++ * green_value) >> 8; + *pixdest++ = (*pixsrc++ * blue_value) >> 8; + + if (has_alpha) + *pixdest++ = *pixsrc++; + } + } + + return dest; +} + + + + diff --git a/thunarx/thunarx-gdk-pixbuf-extensions.h b/thunarx/thunarx-gdk-pixbuf-extensions.h new file mode 100644 index 000000000..6f685cdaa --- /dev/null +++ b/thunarx/thunarx-gdk-pixbuf-extensions.h @@ -0,0 +1,32 @@ +/* $Id$ */ +/*- + * Copyright (c) 2005 Benedikt Meurer <benny@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 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 + */ + +#ifndef __THUNARX_GDK_PIXBUF_EXTENSIONS_H__ +#define __THUNARX_GDK_PIXBUF_EXTENSIONS_H__ + +#include <gdk/gdk.h> + +G_BEGIN_DECLS; + +GdkPixbuf *thunarx_gdk_pixbuf_colorize (GdkPixbuf *src, + const GdkColor *color); + +G_END_DECLS; + +#endif /* !__THUNARX_GDK_PIXBUF_EXTENSIONS_H__ */ -- GitLab