1/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2/*
3 * GTK - The GIMP Toolkit
4 * Copyright (C) 2006 Carlos Garnacho Parro <carlosg@gnome.org>
5 *
6 * All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20 */
21#include <gtk/gtk.h>
22
23static gconstpointer GROUP_A = "GROUP_A";
24static gconstpointer GROUP_B = "GROUP_B";
25
26const char *tabs1 [] = {
27 "aaaaaaaaaa",
28 "bbbbbbbbbb",
29 "cccccccccc",
30 "dddddddddd",
31 NULL
32};
33
34const char *tabs2 [] = {
35 "1",
36 "2",
37 "3",
38 "4",
39 "55555",
40 NULL
41};
42
43const char *tabs3 [] = {
44 "foo",
45 "bar",
46 NULL
47};
48
49const char *tabs4 [] = {
50 "beer",
51 "water",
52 "lemonade",
53 "coffee",
54 "tea",
55 NULL
56};
57
58static GtkNotebook*
59window_creation_function (GtkNotebook *source_notebook,
60 GtkWidget *child,
61 int x,
62 int y,
63 gpointer data)
64{
65 GtkWidget *window, *notebook;
66
67 window = gtk_window_new ();
68 notebook = gtk_notebook_new ();
69 g_signal_connect (notebook, "create-window",
70 G_CALLBACK (window_creation_function), NULL);
71
72 gtk_notebook_set_group_name (GTK_NOTEBOOK (notebook),
73 group_name: gtk_notebook_get_group_name (notebook: source_notebook));
74
75 gtk_window_set_child (GTK_WINDOW (window), child: notebook);
76
77 gtk_window_set_default_size (GTK_WINDOW (window), width: 300, height: 300);
78 gtk_widget_show (widget: window);
79
80 return GTK_NOTEBOOK (notebook);
81}
82
83static void
84on_page_reordered (GtkNotebook *notebook, GtkWidget *child, guint page_num, gpointer data)
85{
86 g_print (format: "page %d reordered\n", page_num);
87}
88
89static gboolean
90remove_in_idle (gpointer data)
91{
92 GtkNotebookPage *page = data;
93 GtkWidget *child = gtk_notebook_page_get_child (page);
94 GtkWidget *parent = gtk_widget_get_ancestor (widget: child, GTK_TYPE_NOTEBOOK);
95 GtkWidget *tab_label;
96
97 tab_label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (parent), child);
98 g_print (format: "Removing tab: %s\n", gtk_label_get_text (GTK_LABEL (tab_label)));
99 gtk_box_remove (GTK_BOX (parent), child);
100
101 return G_SOURCE_REMOVE;
102}
103
104static gboolean
105on_button_drag_drop (GtkDropTarget *dest,
106 const GValue *value,
107 double x,
108 double y,
109 gpointer user_data)
110{
111 GtkNotebookPage *page;
112
113 page = g_value_get_object (value);
114 g_idle_add (function: remove_in_idle, data: page);
115
116 return TRUE;
117}
118
119static void
120action_clicked_cb (GtkWidget *button,
121 GtkWidget *notebook)
122{
123 GtkWidget *page, *title;
124
125 page = gtk_entry_new ();
126 gtk_editable_set_text (GTK_EDITABLE (page), text: "Addition");
127
128 title = gtk_label_new (str: "Addition");
129
130 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child: page, tab_label: title);
131 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), child: page, TRUE);
132 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook), child: page, TRUE);
133}
134
135static GtkWidget*
136create_notebook (const char **labels,
137 const char *group,
138 GtkPositionType pos)
139{
140 GtkWidget *notebook, *title, *page, *action_widget;
141
142 notebook = gtk_notebook_new ();
143 gtk_widget_set_vexpand (widget: notebook, TRUE);
144 gtk_widget_set_hexpand (widget: notebook, TRUE);
145
146 action_widget = gtk_button_new_from_icon_name (icon_name: "list-add-symbolic");
147 g_signal_connect (action_widget, "clicked", G_CALLBACK (action_clicked_cb), notebook);
148 gtk_notebook_set_action_widget (GTK_NOTEBOOK (notebook), widget: action_widget, pack_type: GTK_PACK_END);
149
150 g_signal_connect (notebook, "create-window",
151 G_CALLBACK (window_creation_function), NULL);
152
153 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), pos);
154 gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
155 gtk_notebook_set_group_name (GTK_NOTEBOOK (notebook), group_name: group);
156
157 while (*labels)
158 {
159 page = gtk_entry_new ();
160 gtk_editable_set_text (GTK_EDITABLE (page), text: *labels);
161
162 title = gtk_label_new (str: *labels);
163
164 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child: page, tab_label: title);
165 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), child: page, TRUE);
166 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook), child: page, TRUE);
167
168 labels++;
169 }
170
171 g_signal_connect (GTK_NOTEBOOK (notebook), "page-reordered",
172 G_CALLBACK (on_page_reordered), NULL);
173 return notebook;
174}
175
176static GtkWidget*
177create_notebook_non_dragable_content (const char **labels,
178 const char *group,
179 GtkPositionType pos)
180{
181 GtkWidget *notebook, *title, *page, *action_widget;
182
183 notebook = gtk_notebook_new ();
184 gtk_widget_set_vexpand (widget: notebook, TRUE);
185 gtk_widget_set_hexpand (widget: notebook, TRUE);
186
187 action_widget = gtk_button_new_from_icon_name (icon_name: "list-add-symbolic");
188 g_signal_connect (action_widget, "clicked", G_CALLBACK (action_clicked_cb), notebook);
189 gtk_notebook_set_action_widget (GTK_NOTEBOOK (notebook), widget: action_widget, pack_type: GTK_PACK_END);
190
191 g_signal_connect (notebook, "create-window",
192 G_CALLBACK (window_creation_function), NULL);
193
194 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), pos);
195 gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
196 gtk_notebook_set_group_name (GTK_NOTEBOOK (notebook), group_name: group);
197
198 while (*labels)
199 {
200 GtkWidget *button;
201 button = gtk_button_new_with_label (label: "example content");
202 /* Use GtkListBox since it bubbles up motion notify event, which can
203 * experience more issues than GtkBox. */
204 page = gtk_list_box_new ();
205 gtk_box_append (GTK_BOX (page), child: button);
206
207 button = gtk_button_new_with_label (label: "row 2");
208 gtk_box_append (GTK_BOX (page), child: button);
209
210 button = gtk_button_new_with_label (label: "third row");
211 gtk_box_append (GTK_BOX (page), child: button);
212
213 title = gtk_label_new (str: *labels);
214
215 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child: page, tab_label: title);
216 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), child: page, TRUE);
217 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook), child: page, TRUE);
218
219 labels++;
220 }
221
222 g_signal_connect (GTK_NOTEBOOK (notebook), "page-reordered",
223 G_CALLBACK (on_page_reordered), NULL);
224 return notebook;
225}
226
227static GtkWidget*
228create_notebook_with_notebooks (const char **labels,
229 const char *group,
230 GtkPositionType pos)
231{
232 GtkWidget *notebook, *title, *page;
233 int count = 0;
234
235 notebook = gtk_notebook_new ();
236 g_signal_connect (notebook, "create-window",
237 G_CALLBACK (window_creation_function), NULL);
238
239 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), pos);
240 gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
241 gtk_notebook_set_group_name (GTK_NOTEBOOK (notebook), group_name: group);
242
243 while (*labels)
244 {
245 page = create_notebook (labels, group, pos);
246 gtk_notebook_popup_enable (GTK_NOTEBOOK (page));
247
248 title = gtk_label_new (str: *labels);
249
250 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child: page, tab_label: title);
251 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), child: page, TRUE);
252 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook), child: page, TRUE);
253
254 count++;
255 labels++;
256 }
257
258 g_signal_connect (GTK_NOTEBOOK (notebook), "page-reordered",
259 G_CALLBACK (on_page_reordered), NULL);
260 return notebook;
261}
262
263static GtkWidget*
264create_trash_button (void)
265{
266 GtkWidget *button;
267 GtkDropTarget *dest;
268
269 button = gtk_button_new_with_mnemonic (label: "_Delete");
270
271 dest = gtk_drop_target_new (GTK_TYPE_NOTEBOOK_PAGE, actions: GDK_ACTION_MOVE);
272 g_signal_connect (dest, "drop", G_CALLBACK (on_button_drag_drop), NULL);
273 gtk_widget_add_controller (widget: button, GTK_EVENT_CONTROLLER (dest));
274
275 return button;
276}
277
278static void
279quit_cb (GtkWidget *widget,
280 gpointer data)
281{
282 gboolean *done = data;
283
284 *done = TRUE;
285
286 g_main_context_wakeup (NULL);
287}
288
289int
290main (int argc, char *argv[])
291{
292 GtkWidget *window, *grid;
293 gboolean done = FALSE;
294
295 gtk_init ();
296
297 window = gtk_window_new ();
298 grid = gtk_grid_new ();
299
300 gtk_grid_attach (GTK_GRID (grid),
301 child: create_notebook_non_dragable_content (labels: tabs1, group: GROUP_A, pos: GTK_POS_TOP),
302 column: 0, row: 0, width: 1, height: 1);
303
304 gtk_grid_attach (GTK_GRID (grid),
305 child: create_notebook (labels: tabs2, group: GROUP_B, pos: GTK_POS_BOTTOM),
306 column: 0, row: 1, width: 1, height: 1);
307
308 gtk_grid_attach (GTK_GRID (grid),
309 child: create_notebook (labels: tabs3, group: GROUP_B, pos: GTK_POS_LEFT),
310 column: 1, row: 0, width: 1, height: 1);
311
312 gtk_grid_attach (GTK_GRID (grid),
313 child: create_notebook_with_notebooks (labels: tabs4, group: GROUP_A, pos: GTK_POS_RIGHT),
314 column: 1, row: 1, width: 1, height: 1);
315
316 gtk_grid_attach (GTK_GRID (grid),
317 child: create_trash_button (),
318 column: 1, row: 2, width: 1, height: 1);
319
320 gtk_window_set_child (GTK_WINDOW (window), child: grid);
321 gtk_window_set_default_size (GTK_WINDOW (window), width: 400, height: 400);
322
323 g_signal_connect (window, "destroy", G_CALLBACK (quit_cb), &done);
324
325 gtk_widget_show (widget: window);
326
327 while (!done)
328 g_main_context_iteration (NULL, TRUE);
329
330 return 0;
331}
332

source code of gtk/tests/testnotebookdnd.c