source: trunk/third/gnome-core/panel/gstc.c @ 15821

Revision 15821, 8.5 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15820, which included commits to RCS files with non-trunk default branches.
Line 
1/* gstc.c - G(something) stacking cache
2 * Copyright (C) 1999 Tim Janik
3 *
4 * This library is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * 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
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19#define G_LOG_DOMAIN "GStC"
20#include        "gstc.h"
21#include        <gdk/gdkx.h>
22#include        <string.h>
23
24
25/* --- prototypes --- */
26static GdkFilterReturn  gstc_parent_event_monitor (GdkXEvent  *gdk_xevent,
27                                                   GdkEvent   *event,
28                                                   gpointer    sparent_pointer);
29static void             gstc_parent_add_child     (GstcParent *sparent,
30                                                   Window      xchild);
31static void             gstc_parent_remove_child  (GstcParent *sparent,
32                                                   Window      xchild);
33static void             gstc_parent_restack_child (GstcParent *sparent,
34                                                   Window      xchild,
35                                                   Window      xbelow);
36
37
38/* --- variables --- */
39static GSList *gstc_parents = NULL;
40
41
42/* --- functions --- */
43GstcParent*
44gstc_parent_from_window (GdkWindow *window)
45{
46  GSList *node;
47
48  g_return_val_if_fail (window != NULL, NULL);
49
50  for (node = gstc_parents; node; node = node->next)
51    {
52      GstcParent *sparent = node->data;
53
54      if (sparent->window == window)
55        return sparent;
56    }
57
58  return NULL;
59}
60
61GstcParent*
62gstc_parent_add_watch (GdkWindow *window)
63{
64  GstcParent *sparent;
65
66  g_return_val_if_fail (window != NULL, NULL);
67
68  sparent = gstc_parent_from_window (window);
69  if (!sparent)
70    {
71      XWindowAttributes attribs = { 0, };
72      Window xroot = None, xparent = None, *children = NULL;
73      guint n_children = 0;
74      guint i;
75
76      gdk_error_trap_push ();
77      XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
78                            GDK_WINDOW_XWINDOW (window),
79                            &attribs);
80      XSelectInput (GDK_WINDOW_XDISPLAY (window),
81                    GDK_WINDOW_XWINDOW (window),
82                    attribs.your_event_mask |
83                    SubstructureNotifyMask);
84
85      XQueryTree (GDK_WINDOW_XDISPLAY (window),
86                  GDK_WINDOW_XWINDOW (window),
87                  &xroot,
88                  &xparent,
89                  &children,
90                  &n_children);
91
92      if (gdk_error_trap_pop ())
93        {
94          if (children)
95            XFree (children);
96
97          return NULL;
98        }
99
100      sparent = g_new (GstcParent, 1);
101      gstc_parents = g_slist_prepend (gstc_parents, sparent);
102      sparent->window = window;
103      gdk_window_ref (sparent->window);
104      sparent->ref_count = 0;
105      gdk_window_add_filter (window, gstc_parent_event_monitor, sparent);
106      sparent->n_children = n_children;
107      sparent->children = g_renew (gulong, NULL, n_children);
108      for (i = 0; i < sparent->n_children; i++)
109        sparent->children[i] = children[i];
110      if (children)
111        XFree (children);
112    }
113  sparent->ref_count++;
114
115  return sparent;
116}
117
118void
119gstc_parent_delete_watch (GdkWindow *window)
120{
121  GstcParent *sparent;
122
123  g_return_if_fail (window != NULL);
124
125  sparent = gstc_parent_from_window (window);
126  if (sparent)
127    sparent->ref_count--;
128  if (sparent && !sparent->ref_count)
129    {
130      GdkWindowPrivate *private = (GdkWindowPrivate*) sparent->window;
131
132      /* reset event mask */
133      gdk_error_trap_push ();
134      if (!private->destroyed && private->window_type == GDK_WINDOW_FOREIGN)
135        {
136          XWindowAttributes attribs = { 0, };
137
138          XGetWindowAttributes (private->xdisplay,
139                                private->xwindow,
140                                &attribs);
141          XSelectInput (private->xdisplay,
142                        private->xwindow,
143                        attribs.your_event_mask &
144                        ~(StructureNotifyMask | FocusChangeMask | PropertyChangeMask));
145        }
146      gdk_flush ();
147      gdk_error_trap_pop ();
148     
149      gdk_window_remove_filter (sparent->window, gstc_parent_event_monitor, sparent);
150      g_free (sparent->children);
151      gdk_window_unref (sparent->window);
152      gstc_parents = g_slist_remove (gstc_parents, sparent);
153      sparent->ref_count = 42;
154      g_free (sparent);
155    }
156}
157
158static void
159gstc_parent_add_child (GstcParent *sparent,
160                       Window      xchild)
161{
162  gint i, ci = -1;
163
164  /* sanity checks, find child */
165  for (i = 0; i < sparent->n_children; i++)
166    {
167      if (sparent->children[i] == xchild)
168        {
169          ci = i;
170          break;
171        }
172    }
173  if (ci >= 0)
174    {
175      g_warning (G_GNUC_PRETTY_FUNCTION "(): can't add known window %ld to %ld",
176                 xchild,
177                 GSTC_PARENT_XWINDOW (sparent));
178      return;
179    }
180
181  /* provide space for new child */
182  sparent->n_children++;
183  sparent->children = g_renew (gulong,
184                               sparent->children,
185                               sparent->n_children);
186
187  /* append child */
188  sparent->children[sparent->n_children - 1] = xchild;
189}
190
191static void
192gstc_parent_remove_child (GstcParent *sparent,
193                          Window      xchild)
194{
195  gint i, ci = -1;
196
197  /* find child */
198  for (i = 0; i < sparent->n_children; i++)
199    {
200      if (sparent->children[i] == xchild)
201        {
202          ci = i;
203          break;
204        }
205    }
206
207  /* sanity checks */
208  if (ci < 0)
209    {
210      g_warning (G_GNUC_PRETTY_FUNCTION "(): can't remove unknown window %ld",
211                 xchild);
212      return;
213    }
214
215  /* remove child from children array */
216  sparent->n_children--;
217  g_memmove (sparent->children + ci,
218             sparent->children + ci + 1,
219             sizeof (gulong) * (sparent->n_children - ci));
220  sparent->children = g_renew (gulong,
221                               sparent->children,
222                               sparent->n_children);
223}
224
225static void
226gstc_parent_restack_child (GstcParent *sparent,
227                           Window      xchild,
228                           Window      xbelow)
229{
230  gint i, ci = -1, bi = -1;
231
232  /* find both children */
233  for (i = 0; i < sparent->n_children; i++)
234    {
235      if (sparent->children[i] == xchild)
236        {
237          ci = i;
238          if (bi >= 0 || !xbelow)
239            break;
240        }
241      if (sparent->children[i] == xbelow)
242        {
243          bi = i;
244          if (ci >= 0)
245            break;
246        }
247    }
248
249  /* sanity checks */
250  if (ci < 0)
251    {
252      g_warning (G_GNUC_PRETTY_FUNCTION "(): can't restack unknown window %ld",
253                 xchild);
254      return;
255    }
256  if (xbelow && bi < 0)
257    {
258      g_warning (G_GNUC_PRETTY_FUNCTION "(): can't restack window %ld on top of unknown window %ld",
259                 xchild,
260                 xbelow);
261      return;
262    }
263
264  /* bail out if stacking order is correct already */
265  if (bi + 1 == ci)
266    return;
267
268  /* remove child from children array */
269  g_memmove (sparent->children + ci,
270             sparent->children + ci + 1,
271             sizeof (gulong) * (sparent->n_children - 1 - ci));
272
273  /* assign new child index */
274  ci = bi < ci ? bi + 1 : bi;
275
276  /* provide space for child */
277  g_memmove (sparent->children + ci + 1,
278             sparent->children + ci,
279             sizeof (gulong) * (sparent->n_children - 1 - ci));
280
281  /* insert child */
282  sparent->children[ci] = xchild;
283}
284
285static GdkFilterReturn
286gstc_parent_event_monitor (GdkXEvent *gdk_xevent,
287                           GdkEvent  *event,
288                           gpointer   sparent_pointer)
289{
290  XEvent *xevent = gdk_xevent;
291  GstcParent *sparent = sparent_pointer;
292  Window xparent = GDK_WINDOW_XWINDOW (sparent->window);
293
294  g_return_val_if_fail (g_slist_find (gstc_parents, sparent), GDK_FILTER_CONTINUE);
295
296  switch (xevent->type)
297    {
298    case CreateNotify:
299      if (xevent->xcreatewindow.parent != xparent)
300        g_warning (G_GNUC_PRETTY_FUNCTION "(): now what is THIS? "
301                   "i receive a SubstructureNotify XCreateWindowEvent "
302                   "for a *foreign* child (%ld)??? X is on drugs!",
303                   xevent->xcreatewindow.window);
304      else
305        gstc_parent_add_child (sparent, xevent->xcreatewindow.window);
306      break;
307    case CirculateNotify:
308      if (xevent->xcirculate.event == xparent)
309        gstc_parent_restack_child (sparent,
310                                   xevent->xcirculate.window,
311                                   (xevent->xcirculate.place == PlaceOnTop &&
312                                    sparent->n_children
313                                    ? sparent->children[sparent->n_children - 1]
314                                    : None));
315      break;
316    case ConfigureNotify:
317      if (xevent->xconfigure.event == xparent)
318        gstc_parent_restack_child (sparent,
319                                   xevent->xconfigure.window,
320                                   xevent->xconfigure.above);
321      break;
322    case ReparentNotify:
323      if (xevent->xreparent.event == xparent)
324        {
325          if (xevent->xreparent.parent == xparent)
326            gstc_parent_add_child (sparent, xevent->xreparent.window);
327          else
328            gstc_parent_remove_child (sparent, xevent->xreparent.window);
329        }
330      break;
331    case DestroyNotify:
332      if (xevent->xdestroywindow.event == xparent)
333        gstc_parent_remove_child (sparent, xevent->xdestroywindow.window);
334      break;
335    default:
336      break;
337    }
338
339  return GDK_FILTER_CONTINUE;
340}
Note: See TracBrowser for help on using the repository browser.