1 /* Icon View/Icon View Basics
2  *
3  * The GtkIconView widget is used to display and manipulate icons.
4  * It uses a GtkTreeModel for data storage, so the list store
5  * example might be helpful.
6  */
7 
8 #include <glib/gi18n.h>
9 #include <gtk/gtk.h>
10 #include <string.h>
11 
12 static GtkWidget *window = NULL;
13 
14 #define FOLDER_NAME "/iconview/gnome-fs-directory.png"
15 #define FILE_NAME "/iconview/gnome-fs-regular.png"
16 
17 enum
18 {
19   COL_PATH,
20   COL_DISPLAY_NAME,
21   COL_PIXBUF,
22   COL_IS_DIRECTORY,
23   NUM_COLS
24 };
25 
26 
27 static GdkPixbuf *file_pixbuf, *folder_pixbuf;
28 char *parent;
29 GtkWidget *up_button;
30 
31 /* Loads the images for the demo and returns whether the operation succeeded */
32 static void
load_pixbufs(void)33 load_pixbufs (void)
34 {
35   if (file_pixbuf)
36     return; /* already loaded earlier */
37 
38   file_pixbuf = gdk_pixbuf_new_from_resource (FILE_NAME, NULL);
39   /* resources must load successfully */
40   g_assert (file_pixbuf);
41 
42   folder_pixbuf = gdk_pixbuf_new_from_resource (FOLDER_NAME, NULL);
43   g_assert (folder_pixbuf);
44 }
45 
46 static void
fill_store(GtkListStore * store)47 fill_store (GtkListStore *store)
48 {
49   GDir *dir;
50   const char *name;
51   GtkTreeIter iter;
52 
53   /* First clear the store */
54   gtk_list_store_clear (store);
55 
56   /* Now go through the directory and extract all the file
57    * information */
58   dir = g_dir_open (parent, 0, NULL);
59   if (!dir)
60     return;
61 
62   name = g_dir_read_name (dir);
63   while (name != NULL)
64     {
65       char *path, *display_name;
66       gboolean is_dir;
67 
68       /* We ignore hidden files that start with a '.' */
69       if (name[0] != '.')
70         {
71           path = g_build_filename (parent, name, NULL);
72 
73           is_dir = g_file_test (path, G_FILE_TEST_IS_DIR);
74 
75           display_name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL);
76 
77           gtk_list_store_append (store, &iter);
78           gtk_list_store_set (store, &iter,
79                               COL_PATH, path,
80                               COL_DISPLAY_NAME, display_name,
81                               COL_IS_DIRECTORY, is_dir,
82                               COL_PIXBUF, is_dir ? folder_pixbuf : file_pixbuf,
83                               -1);
84           g_free (path);
85           g_free (display_name);
86         }
87 
88       name = g_dir_read_name (dir);
89     }
90   g_dir_close (dir);
91 }
92 
93 static int
sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)94 sort_func (GtkTreeModel *model,
95            GtkTreeIter  *a,
96            GtkTreeIter  *b,
97            gpointer      user_data)
98 {
99   gboolean is_dir_a, is_dir_b;
100   char *name_a, *name_b;
101   int ret;
102 
103   /* We need this function because we want to sort
104    * folders before files.
105    */
106 
107 
108   gtk_tree_model_get (model, a,
109                       COL_IS_DIRECTORY, &is_dir_a,
110                       COL_DISPLAY_NAME, &name_a,
111                       -1);
112 
113   gtk_tree_model_get (model, b,
114                       COL_IS_DIRECTORY, &is_dir_b,
115                       COL_DISPLAY_NAME, &name_b,
116                       -1);
117 
118   if (!is_dir_a && is_dir_b)
119     ret = 1;
120   else if (is_dir_a && !is_dir_b)
121     ret = -1;
122   else
123     {
124       ret = g_utf8_collate (name_a, name_b);
125     }
126 
127   g_free (name_a);
128   g_free (name_b);
129 
130   return ret;
131 }
132 
133 static GtkListStore *
create_store(void)134 create_store (void)
135 {
136   GtkListStore *store;
137 
138   store = gtk_list_store_new (NUM_COLS,
139                               G_TYPE_STRING,
140                               G_TYPE_STRING,
141                               GDK_TYPE_PIXBUF,
142                               G_TYPE_BOOLEAN);
143 
144   /* Set sort column and function */
145   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (store),
146                                            sort_func,
147                                            NULL, NULL);
148   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
149                                         GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
150                                         GTK_SORT_ASCENDING);
151 
152   return store;
153 }
154 
155 static void
item_activated(GtkIconView * icon_view,GtkTreePath * tree_path,gpointer user_data)156 item_activated (GtkIconView *icon_view,
157                 GtkTreePath *tree_path,
158                 gpointer     user_data)
159 {
160   GtkListStore *store;
161   char *path;
162   GtkTreeIter iter;
163   gboolean is_dir;
164 
165   store = GTK_LIST_STORE (user_data);
166 
167   gtk_tree_model_get_iter (GTK_TREE_MODEL (store),
168                            &iter, tree_path);
169   gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
170                       COL_PATH, &path,
171                       COL_IS_DIRECTORY, &is_dir,
172                       -1);
173 
174   if (!is_dir)
175     {
176       g_free (path);
177       return;
178     }
179 
180   /* Replace parent with path and re-fill the model*/
181   g_free (parent);
182   parent = path;
183 
184   fill_store (store);
185 
186   /* Sensitize the up button */
187   gtk_widget_set_sensitive (GTK_WIDGET (up_button), TRUE);
188 }
189 
190 static void
up_clicked(GtkButton * item,gpointer user_data)191 up_clicked (GtkButton *item,
192             gpointer   user_data)
193 {
194   GtkListStore *store;
195   char *dir_name;
196 
197   store = GTK_LIST_STORE (user_data);
198 
199   dir_name = g_path_get_dirname (parent);
200   g_free (parent);
201 
202   parent = dir_name;
203 
204   fill_store (store);
205 
206   /* Maybe de-sensitize the up button */
207   gtk_widget_set_sensitive (GTK_WIDGET (up_button),
208                             strcmp (parent, "/") != 0);
209 }
210 
211 static void
home_clicked(GtkButton * item,gpointer user_data)212 home_clicked (GtkButton *item,
213               gpointer   user_data)
214 {
215   GtkListStore *store;
216 
217   store = GTK_LIST_STORE (user_data);
218 
219   g_free (parent);
220   parent = g_strdup (g_get_home_dir ());
221 
222   fill_store (store);
223 
224   /* Sensitize the up button */
225   gtk_widget_set_sensitive (GTK_WIDGET (up_button),
226                             TRUE);
227 }
228 
close_window(void)229 static void close_window(void)
230 {
231   gtk_window_destroy (GTK_WINDOW (window));
232   window = NULL;
233 
234   g_object_unref (file_pixbuf);
235   file_pixbuf = NULL;
236 
237   g_object_unref (folder_pixbuf);
238   folder_pixbuf = NULL;
239 }
240 
241 GtkWidget *
do_iconview(GtkWidget * do_widget)242 do_iconview (GtkWidget *do_widget)
243 {
244   if (!window)
245     {
246       GtkWidget *sw;
247       GtkWidget *icon_view;
248       GtkListStore *store;
249       GtkWidget *vbox;
250       GtkWidget *tool_bar;
251       GtkWidget *home_button;
252 
253       window = gtk_window_new ();
254       gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
255 
256       gtk_window_set_display (GTK_WINDOW (window),
257                               gtk_widget_get_display (do_widget));
258       gtk_window_set_title (GTK_WINDOW (window), "Icon View Basics");
259 
260       g_signal_connect (window, "destroy",
261                         G_CALLBACK (close_window), NULL);
262 
263       load_pixbufs ();
264 
265       vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
266       gtk_window_set_child (GTK_WINDOW (window), vbox);
267 
268       tool_bar = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
269       gtk_box_append (GTK_BOX (vbox), tool_bar);
270 
271       up_button = gtk_button_new_with_mnemonic ("_Up");
272       gtk_widget_set_sensitive (GTK_WIDGET (up_button), FALSE);
273       gtk_box_append (GTK_BOX (tool_bar), up_button);
274 
275       home_button = gtk_button_new_with_mnemonic ("_Home");
276       gtk_box_append (GTK_BOX (tool_bar), home_button);
277 
278 
279       sw = gtk_scrolled_window_new ();
280       gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (sw), TRUE);
281       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
282                                       GTK_POLICY_AUTOMATIC,
283                                       GTK_POLICY_AUTOMATIC);
284       gtk_widget_set_vexpand (sw, TRUE);
285 
286       gtk_box_append (GTK_BOX (vbox), sw);
287 
288       /* Create the store and fill it with the contents of '/' */
289       parent = g_strdup ("/");
290       store = create_store ();
291       fill_store (store);
292 
293       icon_view = gtk_icon_view_new_with_model (GTK_TREE_MODEL (store));
294       gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (icon_view),
295                                         GTK_SELECTION_MULTIPLE);
296       g_object_unref (store);
297 
298       /* Connect to the "clicked" signal of the "Up" tool button */
299       g_signal_connect (up_button, "clicked",
300                         G_CALLBACK (up_clicked), store);
301 
302       /* Connect to the "clicked" signal of the "Home" tool button */
303       g_signal_connect (home_button, "clicked",
304                         G_CALLBACK (home_clicked), store);
305 
306       /* We now set which model columns that correspond to the text
307        * and pixbuf of each item
308        */
309       gtk_icon_view_set_text_column (GTK_ICON_VIEW (icon_view), COL_DISPLAY_NAME);
310       gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (icon_view), COL_PIXBUF);
311 
312       /* Connect to the "item-activated" signal */
313       g_signal_connect (icon_view, "item-activated",
314                         G_CALLBACK (item_activated), store);
315       gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), icon_view);
316 
317       gtk_widget_grab_focus (icon_view);
318     }
319 
320   if (!gtk_widget_get_visible (window))
321     gtk_widget_show (window);
322   else
323     gtk_window_destroy (GTK_WINDOW (window));
324 
325   return window;
326 }
327