1/* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23 */
24
25#include "config.h"
26
27#include "gtkmain.h"
28#include "gtkwindowprivate.h"
29#include "gtkwindowgroup.h"
30#include "gtkprivate.h"
31
32
33/**
34 * GtkWindowGroup:
35 *
36 * `GtkWindowGroup` makes group of windows behave like separate applications.
37 *
38 * It achieves this by limiting the effect of GTK grabs and modality
39 * to windows in the same group.
40 *
41 * A window can be a member in at most one window group at a time.
42 * Windows that have not been explicitly assigned to a group are
43 * implicitly treated like windows of the default window group.
44 *
45 * `GtkWindowGroup` objects are referenced by each window in the group,
46 * so once you have added all windows to a `GtkWindowGroup`, you can drop
47 * the initial reference to the window group with g_object_unref(). If the
48 * windows in the window group are subsequently destroyed, then they will
49 * be removed from the window group and drop their references on the window
50 * group; when all window have been removed, the window group will be
51 * freed.
52 */
53
54typedef struct _GtkDeviceGrabInfo GtkDeviceGrabInfo;
55struct _GtkDeviceGrabInfo
56{
57 GtkWidget *widget;
58 GdkDevice *device;
59 guint block_others : 1;
60};
61
62struct _GtkWindowGroupPrivate
63{
64 GSList *grabs;
65};
66
67G_DEFINE_TYPE_WITH_PRIVATE (GtkWindowGroup, gtk_window_group, G_TYPE_OBJECT)
68
69static void
70gtk_window_group_init (GtkWindowGroup *group)
71{
72 group->priv = gtk_window_group_get_instance_private (self: group);
73}
74
75static void
76gtk_window_group_class_init (GtkWindowGroupClass *klass)
77{
78}
79
80
81/**
82 * gtk_window_group_new:
83 *
84 * Creates a new `GtkWindowGroup` object.
85 *
86 * Modality of windows only affects windows
87 * within the same `GtkWindowGroup`.
88 *
89 * Returns: a new `GtkWindowGroup`.
90 **/
91GtkWindowGroup *
92gtk_window_group_new (void)
93{
94 return g_object_new (GTK_TYPE_WINDOW_GROUP, NULL);
95}
96
97static void
98window_group_cleanup_grabs (GtkWindowGroup *group,
99 GtkWindow *window)
100{
101 GtkWindowGroupPrivate *priv;
102 GSList *tmp_list;
103 GSList *to_remove = NULL;
104
105 priv = group->priv;
106
107 tmp_list = priv->grabs;
108 while (tmp_list)
109 {
110 if (gtk_widget_get_root (widget: tmp_list->data) == (GtkRoot*) window)
111 to_remove = g_slist_prepend (list: to_remove, g_object_ref (tmp_list->data));
112 tmp_list = tmp_list->next;
113 }
114
115 while (to_remove)
116 {
117 gtk_grab_remove (widget: to_remove->data);
118 g_object_unref (object: to_remove->data);
119 to_remove = g_slist_delete_link (list: to_remove, link_: to_remove);
120 }
121}
122
123/**
124 * gtk_window_group_add_window:
125 * @window_group: a `GtkWindowGroup`
126 * @window: the `GtkWindow` to add
127 *
128 * Adds a window to a `GtkWindowGroup`.
129 */
130void
131gtk_window_group_add_window (GtkWindowGroup *window_group,
132 GtkWindow *window)
133{
134 GtkWindowGroup *old_group;
135
136 g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
137 g_return_if_fail (GTK_IS_WINDOW (window));
138
139 old_group = _gtk_window_get_window_group (window);
140
141 if (old_group != window_group)
142 {
143 g_object_ref (window);
144 g_object_ref (window_group);
145
146 if (old_group)
147 gtk_window_group_remove_window (window_group: old_group, window);
148 else
149 window_group_cleanup_grabs (group: gtk_window_get_group (NULL), window);
150
151 _gtk_window_set_window_group (window, group: window_group);
152
153 g_object_unref (object: window);
154 }
155}
156
157/**
158 * gtk_window_group_remove_window:
159 * @window_group: a `GtkWindowGroup`
160 * @window: the `GtkWindow` to remove
161 *
162 * Removes a window from a `GtkWindowGroup`.
163 */
164void
165gtk_window_group_remove_window (GtkWindowGroup *window_group,
166 GtkWindow *window)
167{
168 g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
169 g_return_if_fail (GTK_IS_WINDOW (window));
170 g_return_if_fail (_gtk_window_get_window_group (window) == window_group);
171
172 g_object_ref (window);
173
174 window_group_cleanup_grabs (group: window_group, window);
175 _gtk_window_set_window_group (window, NULL);
176
177 g_object_unref (object: window_group);
178 g_object_unref (object: window);
179}
180
181/**
182 * gtk_window_group_list_windows:
183 * @window_group: a `GtkWindowGroup`
184 *
185 * Returns a list of the `GtkWindows` that belong to @window_group.
186 *
187 * Returns: (element-type GtkWindow) (transfer container): A
188 * newly-allocated list of windows inside the group.
189 */
190GList *
191gtk_window_group_list_windows (GtkWindowGroup *window_group)
192{
193 GList *toplevels, *toplevel, *group_windows;
194
195 g_return_val_if_fail (GTK_IS_WINDOW_GROUP (window_group), NULL);
196
197 group_windows = NULL;
198 toplevels = gtk_window_list_toplevels ();
199
200 for (toplevel = toplevels; toplevel; toplevel = toplevel->next)
201 {
202 GtkWindow *window = toplevel->data;
203
204 if (window_group == gtk_window_get_group (window))
205 group_windows = g_list_prepend (list: group_windows, data: window);
206 }
207
208 g_list_free (list: toplevels);
209
210 return g_list_reverse (list: group_windows);
211}
212
213GtkWidget *
214gtk_window_group_get_current_grab (GtkWindowGroup *window_group)
215{
216 g_return_val_if_fail (GTK_IS_WINDOW_GROUP (window_group), NULL);
217
218 if (window_group->priv->grabs)
219 return GTK_WIDGET (window_group->priv->grabs->data);
220 return NULL;
221}
222
223static void
224revoke_implicit_grabs (GtkWindowGroup *window_group,
225 GdkDevice *device,
226 GtkWidget *grab_widget)
227{
228 GList *windows, *l;
229
230 windows = gtk_window_group_list_windows (window_group);
231
232 for (l = windows; l; l = l->next)
233 {
234 gtk_window_maybe_revoke_implicit_grab (window: l->data,
235 device,
236 grab_widget);
237 }
238
239 g_list_free (list: windows);
240}
241
242void
243_gtk_window_group_add_grab (GtkWindowGroup *window_group,
244 GtkWidget *widget)
245{
246 GtkWindowGroupPrivate *priv;
247
248 priv = window_group->priv;
249 priv->grabs = g_slist_prepend (list: priv->grabs, data: widget);
250
251 revoke_implicit_grabs (window_group, NULL, grab_widget: widget);
252}
253
254void
255_gtk_window_group_remove_grab (GtkWindowGroup *window_group,
256 GtkWidget *widget)
257{
258 GtkWindowGroupPrivate *priv;
259
260 priv = window_group->priv;
261 priv->grabs = g_slist_remove (list: priv->grabs, data: widget);
262}
263

source code of gtk/gtk/gtkwindowgroup.c