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 | |
54 | typedef struct _GtkDeviceGrabInfo GtkDeviceGrabInfo; |
55 | struct _GtkDeviceGrabInfo |
56 | { |
57 | GtkWidget *widget; |
58 | GdkDevice *device; |
59 | guint block_others : 1; |
60 | }; |
61 | |
62 | struct _GtkWindowGroupPrivate |
63 | { |
64 | GSList *grabs; |
65 | }; |
66 | |
67 | G_DEFINE_TYPE_WITH_PRIVATE (GtkWindowGroup, gtk_window_group, G_TYPE_OBJECT) |
68 | |
69 | static void |
70 | gtk_window_group_init (GtkWindowGroup *group) |
71 | { |
72 | group->priv = gtk_window_group_get_instance_private (self: group); |
73 | } |
74 | |
75 | static void |
76 | gtk_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 | **/ |
91 | GtkWindowGroup * |
92 | gtk_window_group_new (void) |
93 | { |
94 | return g_object_new (GTK_TYPE_WINDOW_GROUP, NULL); |
95 | } |
96 | |
97 | static void |
98 | window_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 | */ |
130 | void |
131 | gtk_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 | */ |
164 | void |
165 | gtk_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 | */ |
190 | GList * |
191 | gtk_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 | |
213 | GtkWidget * |
214 | gtk_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 | |
223 | static void |
224 | revoke_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 | |
242 | void |
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 | |
254 | void |
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 | |