source: trunk/third/gnome-panel/gnome-panel/xstuff.c @ 18631

Revision 18631, 12.0 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18630, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * GNOME panel x stuff
3 *
4 * Copyright (C) 2000, 2001 Eazel, Inc.
5 *               2002 Sun Microsystems Inc.
6 *
7 * Authors: George Lebl <jirka@5z.com>
8 *          Mark McLoughlin <mark@skynet.ie>
9 *
10 *  Contains code from the Window Maker window manager
11 *
12 *  Copyright (c) 1997-2002 Alfredo K. Kojima
13
14 */
15#include <config.h>
16#include <string.h>
17#include <unistd.h>
18
19#include <gdk/gdk.h>
20#include <gdk/gdkx.h>
21
22#include <X11/Xlib.h>
23#include <X11/Xatom.h>
24
25#include "xstuff.h"
26
27#include "global-keys.h"
28
29static Atom
30panel_atom_get (const char *atom_name)
31{
32        static GHashTable *atom_hash;
33        Display           *xdisplay;
34        Atom               retval;
35
36        g_return_val_if_fail (atom_name != NULL, None);
37
38        xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
39
40        if (!atom_hash)
41                atom_hash = g_hash_table_new_full (
42                                g_str_hash, g_str_equal, g_free, NULL);
43
44        retval = GPOINTER_TO_UINT (g_hash_table_lookup (atom_hash, atom_name));
45        if (!retval) {
46                retval = XInternAtom (xdisplay, atom_name, FALSE);
47
48                if (retval != None)
49                        g_hash_table_insert (atom_hash, g_strdup (atom_name),
50                                             GUINT_TO_POINTER (retval));
51        }
52
53        return retval;
54}
55
56/* Stolen from deskguide */
57static gpointer
58get_typed_property_data (Display *xdisplay,
59                         Window   xwindow,
60                         Atom     property,
61                         Atom     requested_type,
62                         gint    *size_p,
63                         guint    expected_format)
64{
65  static const guint prop_buffer_lengh = 1024 * 1024;
66  unsigned char *prop_data = NULL;
67  Atom type_returned = 0;
68  unsigned long nitems_return = 0, bytes_after_return = 0;
69  int format_returned = 0;
70  gpointer data = NULL;
71  gboolean abort = FALSE;
72
73  g_return_val_if_fail (size_p != NULL, NULL);
74  *size_p = 0;
75
76  gdk_error_trap_push ();
77
78  abort = XGetWindowProperty (xdisplay,
79                              xwindow,
80                              property,
81                              0, prop_buffer_lengh,
82                              False,
83                              requested_type,
84                              &type_returned, &format_returned,
85                              &nitems_return,
86                              &bytes_after_return,
87                              &prop_data) != Success;
88  if (gdk_error_trap_pop () ||
89      type_returned == None)
90    abort++;
91  if (!abort &&
92      requested_type != AnyPropertyType &&
93      requested_type != type_returned)
94    {
95      g_warning (G_GNUC_PRETTY_FUNCTION "(): Property has wrong type, probably on crack");
96      abort++;
97    }
98  if (!abort && bytes_after_return)
99    {
100      g_warning (G_GNUC_PRETTY_FUNCTION "(): Eeek, property has more than %u bytes, stored on harddisk?",
101                 prop_buffer_lengh);
102      abort++;
103    }
104  if (!abort && expected_format && expected_format != format_returned)
105    {
106      g_warning (G_GNUC_PRETTY_FUNCTION "(): Expected format (%u) unmatched (%d), programmer was drunk?",
107                 expected_format, format_returned);
108      abort++;
109    }
110  if (!abort && prop_data && nitems_return && format_returned)
111    {
112      switch (format_returned)
113        {
114        case 32:
115          *size_p = nitems_return * 4;
116          if (sizeof (gulong) == 8)
117            {
118              guint32 i, *mem = g_malloc0 (*size_p + 1);
119              gulong *prop_longs = (gulong*) prop_data;
120
121              for (i = 0; i < *size_p / 4; i++)
122                mem[i] = prop_longs[i];
123              data = mem;
124            }
125          break;
126        case 16:
127          *size_p = nitems_return * 2;
128          break;
129        case 8:
130          *size_p = nitems_return;
131          break;
132        default:
133          g_warning ("Unknown property data format with %d bits (extraterrestrial?)",
134                     format_returned);
135          break;
136        }
137      if (!data && *size_p)
138        {
139          guint8 *mem = g_malloc (*size_p + 1);
140
141          memcpy (mem, prop_data, *size_p);
142          mem[*size_p] = 0;
143          data = mem;
144        }
145    }
146
147  if (prop_data)
148    XFree (prop_data);
149 
150  return data;
151}
152
153gboolean
154xstuff_is_compliant_wm (void)
155{
156        Display  *xdisplay;
157        Window    root_window;
158        gpointer  data;
159        int       size;
160
161        xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
162        root_window = GDK_WINDOW_XWINDOW (
163                                gdk_get_default_root_window ());
164
165        /* FIXME this is totally broken; should be using
166         * gdk_net_wm_supports() on particular hints when we rely
167         * on those particular hints
168         */
169        data = get_typed_property_data (
170                        xdisplay, root_window,
171                        panel_atom_get ("_NET_SUPPORTED"),
172                        XA_ATOM, &size, 32);
173
174        if (!data)
175                return FALSE;
176
177        /* Actually checks for some of these */
178        g_free (data);
179        return TRUE;
180}
181
182gboolean
183xstuff_net_wm_supports (const char *hint)
184{
185        return gdk_net_wm_supports (gdk_atom_intern (hint, FALSE));
186}
187
188void
189xstuff_set_no_group_and_no_input (GdkWindow *win)
190{
191        XWMHints *old_wmhints;
192        XWMHints wmhints = {0};
193
194        XDeleteProperty (GDK_WINDOW_XDISPLAY (win),
195                         GDK_WINDOW_XWINDOW (win),
196                         panel_atom_get ("WM_CLIENT_LEADER"));
197
198        old_wmhints = XGetWMHints (GDK_WINDOW_XDISPLAY (win),
199                                   GDK_WINDOW_XWINDOW (win));
200        /* General paranoia */
201        if (old_wmhints != NULL) {
202                memcpy (&wmhints, old_wmhints, sizeof (XWMHints));
203                XFree (old_wmhints);
204
205                wmhints.flags &= ~WindowGroupHint;
206                wmhints.flags |= InputHint;
207                wmhints.input = False;
208                wmhints.window_group = 0;
209        } else {
210                /* General paranoia */
211                wmhints.flags = InputHint | StateHint;
212                wmhints.window_group = 0;
213                wmhints.input = False;
214                wmhints.initial_state = NormalState;
215        }
216
217        XSetWMHints (GDK_WINDOW_XDISPLAY (win),
218                     GDK_WINDOW_XWINDOW (win),
219                     &wmhints);
220}
221
222/* This is such a broken stupid function. */   
223void
224xstuff_set_pos_size (GdkWindow *window, int x, int y, int w, int h)
225{
226        XSizeHints size_hints;
227        int old_x, old_y, old_w, old_h;
228
229        old_x = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "xstuff-cached-x"));
230        old_y = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "xstuff-cached-y"));
231        old_w = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "xstuff-cached-w"));
232        old_h = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "xstuff-cached-h"));
233
234        if (x == old_x && y == old_y && w == old_w && h == old_h)
235                return;
236
237        /* Do not add USPosition / USSize here, fix the damn WM */
238        size_hints.flags = PPosition | PSize | PMaxSize | PMinSize;
239        size_hints.x = 0; /* window managers aren't supposed to and  */
240        size_hints.y = 0; /* don't use these fields */
241        size_hints.width = w;
242        size_hints.height = h;
243        size_hints.min_width = w;
244        size_hints.min_height = h;
245        size_hints.max_width = w;
246        size_hints.max_height = h;
247 
248        gdk_error_trap_push ();
249
250        XSetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
251                           GDK_WINDOW_XWINDOW (window),
252                           &size_hints);
253
254        gdk_window_move_resize (window, x, y, w, h);
255
256        gdk_flush ();
257        gdk_error_trap_pop ();
258
259        g_object_set_data (G_OBJECT (window), "xstuff-cached-x", GINT_TO_POINTER (x));
260        g_object_set_data (G_OBJECT (window), "xstuff-cached-y", GINT_TO_POINTER (y));
261        g_object_set_data (G_OBJECT (window), "xstuff-cached-w", GINT_TO_POINTER (w));
262        g_object_set_data (G_OBJECT (window), "xstuff-cached-h", GINT_TO_POINTER (h));
263}
264
265void
266xstuff_set_wmspec_dock_hints (GdkWindow *window,
267                              gboolean autohide)
268{
269        Atom atoms [2] = { None, None };
270       
271        if (!autohide)
272                atoms [0] = panel_atom_get ("_NET_WM_WINDOW_TYPE_DOCK");
273        else {
274                atoms [0] = panel_atom_get ("_GNOME_WINDOW_TYPE_AUTOHIDE_PANEL");
275                atoms [1] = panel_atom_get ("_NET_WM_WINDOW_TYPE_DOCK");
276        }
277
278        XChangeProperty (GDK_WINDOW_XDISPLAY (window),
279                         GDK_WINDOW_XWINDOW (window),
280                         panel_atom_get ("_NET_WM_WINDOW_TYPE"),
281                         XA_ATOM, 32, PropModeReplace,
282                         (unsigned char *) atoms,
283                         autohide ? 2 : 1);
284}
285
286void
287xstuff_set_wmspec_strut (GdkWindow *window,
288                         int        left,
289                         int        right,
290                         int        top,
291                         int        bottom)
292{
293        long vals [4];
294       
295        vals [0] = left;
296        vals [1] = right;
297        vals [2] = top;
298        vals [3] = bottom;
299
300        XChangeProperty (GDK_WINDOW_XDISPLAY (window),
301                         GDK_WINDOW_XWINDOW (window),
302                         panel_atom_get ("_NET_WM_STRUT"),
303                         XA_CARDINAL, 32, PropModeReplace,
304                         (unsigned char *) vals, 4);
305}
306
307void
308xstuff_delete_property (GdkWindow *window, const char *name)
309{
310        Display *xdisplay = GDK_WINDOW_XDISPLAY (window);
311        Window   xwindow  = GDK_WINDOW_XWINDOW (window);
312
313        XDeleteProperty (xdisplay, xwindow,
314                         panel_atom_get (name));
315}
316
317void
318xstuff_init (void)
319{
320        GdkDisplay *display;
321        int         screens, i;
322
323        display = gdk_display_get_default ();
324        screens = gdk_display_get_n_screens (display);
325
326        for (i = 0; i < screens; i++) {
327                GdkScreen *screen;
328                GdkWindow *root_window;
329
330                screen = gdk_display_get_screen (display, i);
331                root_window = gdk_screen_get_root_window (screen);
332
333                gdk_window_add_filter (
334                        root_window,
335                        (GdkFilterFunc) panel_global_keys_filter,
336                        screen);
337        }
338}
339
340/* Zoom animation */
341#define MINIATURIZE_ANIMATION_FRAMES_Z   1
342#define MINIATURIZE_ANIMATION_STEPS_Z    6
343/* the delay per draw */
344#define MINIATURIZE_ANIMATION_DELAY_Z    10
345
346static void
347draw_zoom_animation (GdkScreen *gscreen,
348                     int x, int y, int w, int h,
349                     int fx, int fy, int fw, int fh,
350                     int steps)
351{
352#define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z)
353        float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES];
354        float xstep, ystep, wstep, hstep;
355        int i, j;
356        GC frame_gc;
357        XGCValues gcv;
358        GdkColor color = { 65535, 65535, 65535 };
359        Display *dpy;
360        Window root_win;
361        int screen;
362        int depth;
363
364        dpy = gdk_x11_display_get_xdisplay (gdk_screen_get_display (gscreen));
365        root_win = gdk_x11_drawable_get_xid (gdk_screen_get_root_window (gscreen));
366        screen = gdk_screen_get_number (gscreen);
367        depth = gdk_drawable_get_depth (gdk_screen_get_root_window (gscreen));
368
369        /* frame GC */
370        gdk_colormap_alloc_color (
371                gdk_screen_get_system_colormap (gscreen), &color, FALSE, TRUE);
372        gcv.function = GXxor;
373        /* this will raise the probability of the XORed color being different
374         * of the original color in PseudoColor when not all color cells are
375         * initialized */
376        if (DefaultVisual(dpy, screen)->class==PseudoColor)
377                gcv.plane_mask = (1<<(depth-1))|1;
378        else
379                gcv.plane_mask = AllPlanes;
380        gcv.foreground = color.pixel;
381        if (gcv.foreground == 0)
382                gcv.foreground = 1;
383        gcv.line_width = 1;
384        gcv.subwindow_mode = IncludeInferiors;
385        gcv.graphics_exposures = False;
386
387        frame_gc = XCreateGC(dpy, root_win, GCForeground|GCGraphicsExposures
388                             |GCFunction|GCSubwindowMode|GCLineWidth
389                             |GCPlaneMask, &gcv);
390
391        xstep = (float)(fx-x)/steps;
392        ystep = (float)(fy-y)/steps;
393        wstep = (float)(fw-w)/steps;
394        hstep = (float)(fh-h)/steps;
395   
396        for (j=0; j<FRAMES; j++) {
397                cx[j] = (float)x;
398                cy[j] = (float)y;
399                cw[j] = (float)w;
400                ch[j] = (float)h;
401        }
402        XGrabServer(dpy);
403        for (i=0; i<steps; i++) {
404                for (j=0; j<FRAMES; j++) {
405                        XDrawRectangle(dpy, root_win, frame_gc,
406                                       (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
407                }
408                XFlush(dpy);
409#if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
410                usleep(MINIATURIZE_ANIMATION_DELAY_Z);
411#else
412                usleep(10);
413#endif
414                for (j=0; j<FRAMES; j++) {
415                        XDrawRectangle(dpy, root_win, frame_gc,
416                                       (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
417                        if (j<FRAMES-1) {
418                                cx[j]=cx[j+1];
419                                cy[j]=cy[j+1];
420                                cw[j]=cw[j+1];
421                                ch[j]=ch[j+1];
422                        } else {
423                                cx[j]+=xstep;
424                                cy[j]+=ystep;
425                                cw[j]+=wstep;
426                                ch[j]+=hstep;
427                        }
428                }
429        }
430
431        for (j=0; j<FRAMES; j++) {
432                XDrawRectangle(dpy, root_win, frame_gc,
433                               (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
434        }
435        XFlush(dpy);
436#if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
437        usleep(MINIATURIZE_ANIMATION_DELAY_Z);
438#else
439        usleep(10);
440#endif
441        for (j=0; j<FRAMES; j++) {
442                XDrawRectangle(dpy, root_win, frame_gc,
443                               (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
444        }
445   
446        XUngrabServer(dpy);
447        XFreeGC (dpy, frame_gc);
448        gdk_colormap_free_colors (gdk_screen_get_system_colormap (gscreen),
449                                  &color, 1);
450}
451#undef FRAMES
452
453void
454xstuff_zoom_animate (GtkWidget *widget, GdkRectangle *opt_rect)
455{
456        GdkScreen *gscreen;
457        GdkRectangle rect, dest;
458        int monitor;
459
460        if (opt_rect)
461                rect = *opt_rect;
462        else {
463                gdk_window_get_origin (widget->window, &rect.x, &rect.y);
464                if (GTK_WIDGET_NO_WINDOW (widget)) {
465                        rect.x += widget->allocation.x;
466                        rect.y += widget->allocation.y;
467                }
468                rect.height = widget->allocation.height;
469                rect.width = widget->allocation.width;
470        }
471
472        gscreen = gtk_widget_get_screen (widget);
473        monitor = gdk_screen_get_monitor_at_window (gscreen, widget->window);
474        gdk_screen_get_monitor_geometry (gscreen, monitor, &dest);
475
476        draw_zoom_animation (gscreen,
477                             rect.x, rect.y, rect.width, rect.height,
478                             dest.x, dest.y, dest.width, dest.height,
479                             MINIATURIZE_ANIMATION_DELAY_Z);
480}
Note: See TracBrowser for help on using the repository browser.