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 |
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 |
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 (list_store: store); |
55 | |
56 | /* Now go through the directory and extract all the file |
57 | * information */ |
58 | dir = g_dir_open (path: parent, flags: 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 (first_element: parent, name, NULL); |
72 | |
73 | is_dir = g_file_test (filename: path, test: G_FILE_TEST_IS_DIR); |
74 | |
75 | display_name = g_filename_to_utf8 (opsysstring: name, len: -1, NULL, NULL, NULL); |
76 | |
77 | gtk_list_store_append (list_store: store, iter: &iter); |
78 | gtk_list_store_set (list_store: store, iter: &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 (mem: path); |
85 | g_free (mem: display_name); |
86 | } |
87 | |
88 | name = g_dir_read_name (dir); |
89 | } |
90 | g_dir_close (dir); |
91 | } |
92 | |
93 | static int |
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 (tree_model: model, iter: a, |
109 | COL_IS_DIRECTORY, &is_dir_a, |
110 | COL_DISPLAY_NAME, &name_a, |
111 | -1); |
112 | |
113 | gtk_tree_model_get (tree_model: model, iter: 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 (str1: name_a, str2: name_b); |
125 | } |
126 | |
127 | g_free (mem: name_a); |
128 | g_free (mem: name_b); |
129 | |
130 | return ret; |
131 | } |
132 | |
133 | static GtkListStore * |
134 | create_store (void) |
135 | { |
136 | GtkListStore *store; |
137 | |
138 | store = gtk_list_store_new (n_columns: 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 | order: GTK_SORT_ASCENDING); |
151 | |
152 | return store; |
153 | } |
154 | |
155 | static void |
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: &iter, path: tree_path); |
169 | gtk_tree_model_get (GTK_TREE_MODEL (store), iter: &iter, |
170 | COL_PATH, &path, |
171 | COL_IS_DIRECTORY, &is_dir, |
172 | -1); |
173 | |
174 | if (!is_dir) |
175 | { |
176 | g_free (mem: path); |
177 | return; |
178 | } |
179 | |
180 | /* Replace parent with path and re-fill the model*/ |
181 | g_free (mem: 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 |
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 (file_name: parent); |
200 | g_free (mem: 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 | sensitive: strcmp (s1: parent, s2: "/" ) != 0); |
209 | } |
210 | |
211 | static void |
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 (mem: parent); |
220 | parent = g_strdup (str: 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 | |
229 | static void close_window(void) |
230 | { |
231 | gtk_window_destroy (GTK_WINDOW (window)); |
232 | window = NULL; |
233 | |
234 | g_object_unref (object: file_pixbuf); |
235 | file_pixbuf = NULL; |
236 | |
237 | g_object_unref (object: folder_pixbuf); |
238 | folder_pixbuf = NULL; |
239 | } |
240 | |
241 | GtkWidget * |
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), width: 650, height: 400); |
255 | |
256 | gtk_window_set_display (GTK_WINDOW (window), |
257 | display: gtk_widget_get_display (widget: do_widget)); |
258 | gtk_window_set_title (GTK_WINDOW (window), title: "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 (orientation: GTK_ORIENTATION_VERTICAL, spacing: 0); |
266 | gtk_window_set_child (GTK_WINDOW (window), child: vbox); |
267 | |
268 | tool_bar = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 0); |
269 | gtk_box_append (GTK_BOX (vbox), child: tool_bar); |
270 | |
271 | up_button = gtk_button_new_with_mnemonic (label: "_Up" ); |
272 | gtk_widget_set_sensitive (GTK_WIDGET (up_button), FALSE); |
273 | gtk_box_append (GTK_BOX (tool_bar), child: up_button); |
274 | |
275 | home_button = gtk_button_new_with_mnemonic (label: "_Home" ); |
276 | gtk_box_append (GTK_BOX (tool_bar), child: 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 | hscrollbar_policy: GTK_POLICY_AUTOMATIC, |
283 | vscrollbar_policy: GTK_POLICY_AUTOMATIC); |
284 | gtk_widget_set_vexpand (widget: sw, TRUE); |
285 | |
286 | gtk_box_append (GTK_BOX (vbox), child: sw); |
287 | |
288 | /* Create the store and fill it with the contents of '/' */ |
289 | parent = g_strdup (str: "/" ); |
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 | mode: GTK_SELECTION_MULTIPLE); |
296 | g_object_unref (object: 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), column: COL_DISPLAY_NAME); |
310 | gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (icon_view), column: 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), child: icon_view); |
316 | |
317 | gtk_widget_grab_focus (widget: icon_view); |
318 | } |
319 | |
320 | if (!gtk_widget_get_visible (widget: window)) |
321 | gtk_widget_show (widget: window); |
322 | else |
323 | gtk_window_destroy (GTK_WINDOW (window)); |
324 | |
325 | return window; |
326 | } |
327 | |