From c51ef797a707f4e2c6f9688d4378f2b0e9898a66 Mon Sep 17 00:00:00 2001 From: Perberos Date: Thu, 1 Dec 2011 22:56:10 -0300 Subject: moving from https://github.com/perberos/mate-desktop-environment --- mate-panel/xstuff.c | 736 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 736 insertions(+) create mode 100644 mate-panel/xstuff.c (limited to 'mate-panel/xstuff.c') diff --git a/mate-panel/xstuff.c b/mate-panel/xstuff.c new file mode 100644 index 00000000..6bcc3396 --- /dev/null +++ b/mate-panel/xstuff.c @@ -0,0 +1,736 @@ +/* + * MATE panel x stuff + * + * Copyright (C) 2000, 2001 Eazel, Inc. + * 2002 Sun Microsystems Inc. + * + * Authors: George Lebl + * Mark McLoughlin + * + * Contains code from the Window Maker window manager + * + * Copyright (c) 1997-2002 Alfredo K. Kojima + + */ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "panel-enums.h" +#include "xstuff.h" + +static int (* xstuff_old_xio_error_handler) (Display *) = NULL; +static int (* xstuff_old_x_error_handler) (Display *, XErrorEvent *); +static gboolean xstuff_display_is_dead = FALSE; + +static Atom +panel_atom_get (const char *atom_name) +{ + static GHashTable *atom_hash; + Display *xdisplay; + Atom retval; + + g_return_val_if_fail (atom_name != NULL, None); + + xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); + + if (!atom_hash) + atom_hash = g_hash_table_new_full ( + g_str_hash, g_str_equal, g_free, NULL); + + retval = GPOINTER_TO_UINT (g_hash_table_lookup (atom_hash, atom_name)); + if (!retval) { + retval = XInternAtom (xdisplay, atom_name, FALSE); + + if (retval != None) + g_hash_table_insert (atom_hash, g_strdup (atom_name), + GUINT_TO_POINTER (retval)); + } + + return retval; +} + +/* Stolen from deskguide */ +static gpointer +get_typed_property_data (Display *xdisplay, + Window xwindow, + Atom property, + Atom requested_type, + gint *size_p, + guint expected_format) +{ + static const guint prop_buffer_lengh = 1024 * 1024; + unsigned char *prop_data = NULL; + Atom type_returned = 0; + unsigned long nitems_return = 0, bytes_after_return = 0; + int format_returned = 0; + gpointer data = NULL; + gboolean abort = FALSE; + + g_return_val_if_fail (size_p != NULL, NULL); + *size_p = 0; + + gdk_error_trap_push (); + + abort = XGetWindowProperty (xdisplay, + xwindow, + property, + 0, prop_buffer_lengh, + False, + requested_type, + &type_returned, &format_returned, + &nitems_return, + &bytes_after_return, + &prop_data) != Success; + if (gdk_error_trap_pop () || + type_returned == None) + abort++; + if (!abort && + requested_type != AnyPropertyType && + requested_type != type_returned) + { + g_warning ("%s(): Property has wrong type, probably on crack", G_STRFUNC); + abort++; + } + if (!abort && bytes_after_return) + { + g_warning ("%s(): Eeek, property has more than %u bytes, stored on harddisk?", + G_STRFUNC, prop_buffer_lengh); + abort++; + } + if (!abort && expected_format && expected_format != format_returned) + { + g_warning ("%s(): Expected format (%u) unmatched (%d), programmer was drunk?", + G_STRFUNC, expected_format, format_returned); + abort++; + } + if (!abort && prop_data && nitems_return && format_returned) + { + switch (format_returned) + { + case 32: + *size_p = nitems_return * 4; + if (sizeof (gulong) == 8) + { + guint32 i, *mem = g_malloc0 (*size_p + 1); + gulong *prop_longs = (gulong*) prop_data; + + for (i = 0; i < *size_p / 4; i++) + mem[i] = prop_longs[i]; + data = mem; + } + break; + case 16: + *size_p = nitems_return * 2; + break; + case 8: + *size_p = nitems_return; + break; + default: + g_warning ("Unknown property data format with %d bits (extraterrestrial?)", + format_returned); + break; + } + if (!data && *size_p) + { + guint8 *mem = g_malloc (*size_p + 1); + + memcpy (mem, prop_data, *size_p); + mem[*size_p] = 0; + data = mem; + } + } + + if (prop_data) + XFree (prop_data); + + return data; +} + +gboolean +xstuff_is_compliant_wm (void) +{ + Display *xdisplay; + Window root_window; + gpointer data; + int size; + + xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); + root_window = GDK_WINDOW_XWINDOW ( + gdk_get_default_root_window ()); + + /* FIXME this is totally broken; should be using + * gdk_net_wm_supports() on particular hints when we rely + * on those particular hints + */ + data = get_typed_property_data ( + xdisplay, root_window, + panel_atom_get ("_NET_SUPPORTED"), + XA_ATOM, &size, 32); + + if (!data) + return FALSE; + + /* Actually checks for some of these */ + g_free (data); + return TRUE; +} + +gboolean +xstuff_net_wm_supports (const char *hint) +{ + return gdk_net_wm_supports (gdk_atom_intern (hint, FALSE)); +} + +/* This is such a broken stupid function. */ +void +xstuff_set_pos_size (GdkWindow *window, int x, int y, int w, int h) +{ + XSizeHints size_hints; + int old_x, old_y, old_w, old_h; + + old_x = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "xstuff-cached-x")); + old_y = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "xstuff-cached-y")); + old_w = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "xstuff-cached-w")); + old_h = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "xstuff-cached-h")); + + if (x == old_x && y == old_y && w == old_w && h == old_h) + return; + + /* Do not add USPosition / USSize here, fix the damn WM */ + size_hints.flags = PPosition | PSize | PMaxSize | PMinSize; + size_hints.x = 0; /* window managers aren't supposed to and */ + size_hints.y = 0; /* don't use these fields */ + size_hints.width = w; + size_hints.height = h; + size_hints.min_width = w; + size_hints.min_height = h; + size_hints.max_width = w; + size_hints.max_height = h; + + gdk_error_trap_push (); + + XSetWMNormalHints (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XWINDOW (window), + &size_hints); + + gdk_window_move_resize (window, x, y, w, h); + + gdk_flush (); + gdk_error_trap_pop (); + + g_object_set_data (G_OBJECT (window), "xstuff-cached-x", GINT_TO_POINTER (x)); + g_object_set_data (G_OBJECT (window), "xstuff-cached-y", GINT_TO_POINTER (y)); + g_object_set_data (G_OBJECT (window), "xstuff-cached-w", GINT_TO_POINTER (w)); + g_object_set_data (G_OBJECT (window), "xstuff-cached-h", GINT_TO_POINTER (h)); +} + +void +xstuff_set_wmspec_dock_hints (GdkWindow *window, + gboolean autohide) +{ + Atom atoms [2] = { None, None }; + + if (!autohide) + atoms [0] = panel_atom_get ("_NET_WM_WINDOW_TYPE_DOCK"); + else { + atoms [0] = panel_atom_get ("_MATE_WINDOW_TYPE_AUTOHIDE_PANEL"); + atoms [1] = panel_atom_get ("_NET_WM_WINDOW_TYPE_DOCK"); + } + + XChangeProperty (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XWINDOW (window), + panel_atom_get ("_NET_WM_WINDOW_TYPE"), + XA_ATOM, 32, PropModeReplace, + (unsigned char *) atoms, + autohide ? 2 : 1); +} + +void +xstuff_set_wmspec_strut (GdkWindow *window, + int left, + int right, + int top, + int bottom) +{ + long vals [4]; + + vals [0] = left; + vals [1] = right; + vals [2] = top; + vals [3] = bottom; + + XChangeProperty (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XWINDOW (window), + panel_atom_get ("_NET_WM_STRUT"), + XA_CARDINAL, 32, PropModeReplace, + (unsigned char *) vals, 4); +} + +void +xstuff_delete_property (GdkWindow *window, const char *name) +{ + Display *xdisplay = GDK_WINDOW_XDISPLAY (window); + Window xwindow = GDK_WINDOW_XWINDOW (window); + + XDeleteProperty (xdisplay, xwindow, + panel_atom_get (name)); +} + +/* Zoom animation */ +#define MINIATURIZE_ANIMATION_FRAMES_Z 1 +#define MINIATURIZE_ANIMATION_STEPS_Z 6 +/* the delay per draw */ +#define MINIATURIZE_ANIMATION_DELAY_Z 10 + +/* zoom factor, steps and delay if composited (factor must be odd) */ +#define ZOOM_FACTOR 5 +#define ZOOM_STEPS 14 +#define ZOOM_DELAY 10 + +typedef struct { + int size; + int size_start; + int size_end; + PanelOrientation orientation; + double opacity; + GdkPixbuf *pixbuf; + guint timeout_id; +} CompositedZoomData; + +static gboolean +zoom_timeout (GtkWidget *window) +{ + gtk_widget_queue_draw (window); + return TRUE; +} + +static gboolean +zoom_expose (GtkWidget *widget, + GdkEventExpose *event, + gpointer user_data) +{ + CompositedZoomData *zoom; + + zoom = user_data; + + if (zoom->size >= zoom->size_end) { + if (zoom->timeout_id) + g_source_remove (zoom->timeout_id); + zoom->timeout_id = 0; + + g_object_unref (zoom->pixbuf); + zoom->pixbuf = NULL; + + g_slice_free (CompositedZoomData, zoom); + + gtk_widget_destroy (widget); + } else { + GdkPixbuf *scaled; + int width, height; + int x = 0, y = 0; + cairo_t *cr; + + gtk_window_get_size (GTK_WINDOW (widget), &width, &height); + + zoom->size += MAX ((zoom->size_end - zoom->size_start) / ZOOM_STEPS, 1); + zoom->opacity -= 1.0 / ((double) ZOOM_STEPS + 1); + + scaled = gdk_pixbuf_scale_simple (zoom->pixbuf, + zoom->size, zoom->size, + GDK_INTERP_BILINEAR); + + switch (zoom->orientation) { + case PANEL_ORIENTATION_TOP: + x = (width - gdk_pixbuf_get_width (scaled)) / 2; + y = 0; + break; + + case PANEL_ORIENTATION_RIGHT: + x = width - gdk_pixbuf_get_width (scaled); + y = (height - gdk_pixbuf_get_height (scaled)) / 2; + break; + + case PANEL_ORIENTATION_BOTTOM: + x = (width - gdk_pixbuf_get_width (scaled)) / 2; + y = height - gdk_pixbuf_get_height (scaled); + break; + + case PANEL_ORIENTATION_LEFT: + x = 0; + y = (height - gdk_pixbuf_get_height (scaled)) / 2; + break; + } + + + cr = gdk_cairo_create (gtk_widget_get_window (widget)); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba (cr, 0, 0, 0, 0.0); + cairo_rectangle (cr, 0, 0, width, height); + cairo_fill (cr); + + gdk_cairo_set_source_pixbuf (cr, scaled, x, y); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_paint_with_alpha (cr, MAX (zoom->opacity, 0)); + + cairo_destroy (cr); + g_object_unref (scaled); + } + + return FALSE; +} + +static void +draw_zoom_animation_composited (GdkScreen *gscreen, + int x, int y, int w, int h, + GdkPixbuf *pixbuf, + PanelOrientation orientation) +{ + GtkWidget *win; + CompositedZoomData *zoom; + int wx = 0, wy = 0; + + w += 2; + h += 2; + + zoom = g_slice_new (CompositedZoomData); + zoom->size = w; + zoom->size_start = w; + zoom->size_end = w * ZOOM_FACTOR; + zoom->orientation = orientation; + zoom->opacity = 1.0; + zoom->pixbuf = g_object_ref (pixbuf); + zoom->timeout_id = 0; + + win = gtk_window_new (GTK_WINDOW_POPUP); + + gtk_window_set_screen (GTK_WINDOW (win), gscreen); + gtk_window_set_keep_above (GTK_WINDOW (win), TRUE); + gtk_window_set_decorated (GTK_WINDOW (win), FALSE); + gtk_widget_set_app_paintable(win, TRUE); + gtk_widget_set_colormap (win, gdk_screen_get_rgba_colormap (gscreen)); + + gtk_window_set_gravity (GTK_WINDOW (win), GDK_GRAVITY_STATIC); + gtk_window_set_default_size (GTK_WINDOW (win), + w * ZOOM_FACTOR, h * ZOOM_FACTOR); + + switch (zoom->orientation) { + case PANEL_ORIENTATION_TOP: + wx = x - w * (ZOOM_FACTOR / 2); + wy = y; + break; + + case PANEL_ORIENTATION_RIGHT: + wx = x - w * (ZOOM_FACTOR - 1); + wy = y - h * (ZOOM_FACTOR / 2); + break; + + case PANEL_ORIENTATION_BOTTOM: + wx = x - w * (ZOOM_FACTOR / 2); + wy = y - h * (ZOOM_FACTOR - 1); + break; + + case PANEL_ORIENTATION_LEFT: + wx = x; + wy = y - h * (ZOOM_FACTOR / 2); + break; + } + + gtk_window_move (GTK_WINDOW (win), wx, wy); + + g_signal_connect (G_OBJECT (win), "expose-event", + G_CALLBACK (zoom_expose), zoom); + + /* see doc for gtk_widget_set_app_paintable() */ + gtk_widget_realize (win); + gdk_window_set_back_pixmap (gtk_widget_get_window (win), NULL, FALSE); + gtk_widget_show (win); + + zoom->timeout_id = g_timeout_add (ZOOM_DELAY, + (GSourceFunc) zoom_timeout, + win); +} + +static void +draw_zoom_animation (GdkScreen *gscreen, + int x, int y, int w, int h, + int fx, int fy, int fw, int fh, + int steps) +{ +#define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z) + float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES]; + int cxi[FRAMES], cyi[FRAMES], cwi[FRAMES], chi[FRAMES]; + float xstep, ystep, wstep, hstep; + int i, j; + GC frame_gc; + XGCValues gcv; + GdkColor color = { 65535, 65535, 65535 }; + Display *dpy; + Window root_win; + int screen; + int depth; + + dpy = gdk_x11_display_get_xdisplay (gdk_screen_get_display (gscreen)); + root_win = gdk_x11_drawable_get_xid (gdk_screen_get_root_window (gscreen)); + screen = gdk_screen_get_number (gscreen); + depth = gdk_drawable_get_depth (gdk_screen_get_root_window (gscreen)); + + /* frame GC */ + gdk_colormap_alloc_color ( + gdk_screen_get_system_colormap (gscreen), &color, FALSE, TRUE); + gcv.function = GXxor; + /* this will raise the probability of the XORed color being different + * of the original color in PseudoColor when not all color cells are + * initialized */ + if (DefaultVisual(dpy, screen)->class==PseudoColor) + gcv.plane_mask = (1<<(depth-1))|1; + else + gcv.plane_mask = AllPlanes; + gcv.foreground = color.pixel; + if (gcv.foreground == 0) + gcv.foreground = 1; + gcv.line_width = 1; + gcv.subwindow_mode = IncludeInferiors; + gcv.graphics_exposures = False; + + frame_gc = XCreateGC(dpy, root_win, GCForeground|GCGraphicsExposures + |GCFunction|GCSubwindowMode|GCLineWidth + |GCPlaneMask, &gcv); + + xstep = (float)(fx-x)/steps; + ystep = (float)(fy-y)/steps; + wstep = (float)(fw-w)/steps; + hstep = (float)(fh-h)/steps; + + for (j=0; j 0) + usleep(MINIATURIZE_ANIMATION_DELAY_Z); +#else + usleep(10); +#endif + for (j=0; j 0) + usleep(MINIATURIZE_ANIMATION_DELAY_Z); +#else + usleep(10); +#endif + for (j=0; jerror_code) + return 0; + + /* If we got a BadDrawable or a BadWindow, we ignore it for now. + * FIXME: We need to somehow distinguish real errors from + * X-server-induced errors. Keeping a list of windows for which we will + * ignore BadDrawables would be a good idea. */ + if (error->error_code == BadDrawable || + error->error_code == BadWindow) + return 0; + + return xstuff_old_x_error_handler (display, error); +} + +void +xstuff_init (void) +{ + xstuff_old_xio_error_handler = XSetIOErrorHandler (xstuff_xio_error_handler); + xstuff_old_x_error_handler = XSetErrorHandler (xstuff_x_error_handler); +} -- cgit v1.2.1