diff audacious/hints.c @ 0:cb178e5ad177 trunk

[svn] Import audacious source.
author nenolod
date Mon, 24 Oct 2005 03:06:47 -0700
parents
children 5c457dac866a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/audacious/hints.c	Mon Oct 24 03:06:47 2005 -0700
@@ -0,0 +1,337 @@
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "hints.h"
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include "equalizer.h"
+#include "mainwin.h"
+#include "playlistwin.h"
+
+#include <gdk/gdkx.h>
+#include <gdk/gdkprivate.h>
+#include <X11/Xlib.h>
+#include <X11/Xmd.h>
+#include <X11/Xatom.h>
+
+/* flags for the window layer */
+typedef enum {
+    WIN_LAYER_DESKTOP = 0,
+    WIN_LAYER_BELOW = 2,
+    WIN_LAYER_NORMAL = 4,
+    WIN_LAYER_ONTOP = 6,
+    WIN_LAYER_DOCK = 8,
+    WIN_LAYER_ABOVE_DOCK = 10
+} WinLayer;
+
+#define WIN_STATE_STICKY                (1 << 0)
+
+#define WIN_HINTS_SKIP_WINLIST          (1 << 1)    /* not in win list */
+#define WIN_HINTS_SKIP_TASKBAR          (1 << 2)    /* not on taskbar */
+
+#define _NET_WM_STATE_REMOVE   0
+#define _NET_WM_STATE_ADD      1
+#define _NET_WM_STATE_TOGGLE   2
+
+#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
+#define _NET_WM_MOVERESIZE_SIZE_TOP          1
+#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
+#define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
+#define _NET_WM_MOVERESIZE_SIZE_LEFT         7
+#define _NET_WM_MOVERESIZE_MOVE              8
+
+
+static void (*set_always_func) (GtkWidget *, gboolean) = NULL;
+static void (*set_sticky_func) (GtkWidget *, gboolean) = NULL;
+static void (*set_skip_winlist_func) (GtkWidget *) = NULL;
+static void (*move_resize_func) (GtkWidget *, gint, gint, gboolean) = NULL;
+
+void
+hint_set_skip_winlist(GtkWidget * window)
+{
+    if (set_skip_winlist_func)
+        set_skip_winlist_func(window);
+}
+
+void
+hint_set_always(gboolean always)
+{
+    if (set_always_func) {
+        set_always_func(mainwin, always);
+        set_always_func(equalizerwin, always);
+        set_always_func(playlistwin, always);
+    }
+}
+
+gboolean
+hint_always_on_top_available(void)
+{
+    return !!set_always_func;
+}
+
+void
+hint_set_sticky(gboolean sticky)
+{
+    if (sticky) {
+        gtk_window_stick(GTK_WINDOW(mainwin));
+        gtk_window_stick(GTK_WINDOW(equalizerwin));
+        gtk_window_stick(GTK_WINDOW(playlistwin));
+    }
+    else {
+        gtk_window_unstick(GTK_WINDOW(mainwin));
+        gtk_window_unstick(GTK_WINDOW(equalizerwin));
+        gtk_window_unstick(GTK_WINDOW(playlistwin));
+    }
+}
+
+gboolean
+hint_move_resize_available(void)
+{
+    return !!move_resize_func;
+}
+
+void
+hint_move_resize(GtkWidget * window, gint x, gint y, gboolean move)
+{
+    move_resize_func(window, x, y, move);
+}
+
+static gboolean
+net_wm_found(void)
+{
+    Atom r_type, support_check;
+    gint r_format, p;
+    gulong count, bytes_remain;
+    guchar *prop = NULL, *prop2 = NULL;
+    gboolean ret = FALSE;
+
+    gdk_error_trap_push();
+    support_check =
+        XInternAtom(GDK_DISPLAY(), "_NET_SUPPORTING_WM_CHECK", FALSE);
+
+    p = XGetWindowProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), support_check,
+                           0, 1, False, XA_WINDOW, &r_type, &r_format,
+                           &count, &bytes_remain, &prop);
+
+    if (p == Success && prop && r_type == XA_WINDOW &&
+        r_format == 32 && count == 1) {
+        Window n = *(Window *) prop;
+
+        p = XGetWindowProperty(GDK_DISPLAY(), n, support_check, 0, 1,
+                               False, XA_WINDOW, &r_type, &r_format,
+                               &count, &bytes_remain, &prop2);
+
+        if (p == Success && prop2 && *prop2 == *prop &&
+            r_type == XA_WINDOW && r_format == 32 && count == 1)
+            ret = TRUE;
+    }
+
+    if (prop)
+        XFree(prop);
+    if (prop2)
+        XFree(prop2);
+    if (gdk_error_trap_pop())
+        return FALSE;
+    return ret;
+}
+
+static void
+net_wm_set_property(GtkWidget * window, gchar * atom, gboolean state)
+{
+    XEvent xev;
+    gint set = _NET_WM_STATE_ADD;
+    Atom type, property;
+
+    if (state == FALSE)
+        set = _NET_WM_STATE_REMOVE;
+
+    type = XInternAtom(GDK_DISPLAY(), "_NET_WM_STATE", FALSE);
+    property = XInternAtom(GDK_DISPLAY(), atom, FALSE);
+
+
+    xev.type = ClientMessage;
+    xev.xclient.type = ClientMessage;
+    xev.xclient.window = GDK_WINDOW_XWINDOW(window->window);
+    xev.xclient.message_type = type;
+    xev.xclient.format = 32;
+    xev.xclient.data.l[0] = set;
+    xev.xclient.data.l[1] = property;
+    xev.xclient.data.l[2] = 0;
+
+    XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), False,
+               SubstructureNotifyMask, &xev);
+}
+
+static void
+net_wm_set_desktop(GtkWidget * window, gboolean all)
+{
+    XEvent xev;
+    guint32 current_desktop = 0;
+
+    if (!all) {
+        gint r_format, p;
+        gulong count, bytes_remain;
+        guchar *prop;
+        Atom r_type;
+        Atom current =
+            XInternAtom(GDK_DISPLAY(), "_NET_CURRENT_DESKTOP", FALSE);
+
+        p = XGetWindowProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), current,
+                               0, 1, False, XA_CARDINAL, &r_type,
+                               &r_format, &count, &bytes_remain, &prop);
+
+        if (p == Success && prop && r_type == XA_CARDINAL &&
+            r_format == 32 && count == 1) {
+            current_desktop = *(long *) prop;
+            XFree(prop);
+        }
+    }
+    else
+        current_desktop = 0xffffffff;
+
+    xev.type = ClientMessage;
+    xev.xclient.type = ClientMessage;
+    xev.xclient.window = GDK_WINDOW_XWINDOW(window->window);
+    xev.xclient.message_type =
+        XInternAtom(GDK_DISPLAY(), "_NET_WM_DESKTOP", FALSE);
+    xev.xclient.format = 32;
+    xev.xclient.data.l[0] = current_desktop;
+
+    XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), False,
+               SubstructureNotifyMask, &xev);
+}
+
+
+
+static void
+net_wm_set_window_always(GtkWidget * window, gboolean always)
+{
+    net_wm_set_property(window, "_NET_WM_STATE_STAYS_ON_TOP", always);
+}
+
+static void
+net_wm_set_window_above(GtkWidget * window, gboolean always)
+{
+    net_wm_set_property(window, "_NET_WM_STATE_ABOVE", always);
+}
+
+static void
+net_wm_move_resize(GtkWidget * window, gint x, gint y, gboolean move)
+{
+    XEvent xev;
+    gint dir;
+    Atom type;
+
+    if (move)
+        dir = _NET_WM_MOVERESIZE_MOVE;
+    else
+        dir = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
+
+    gdk_pointer_ungrab(GDK_CURRENT_TIME);
+
+    type = XInternAtom(GDK_DISPLAY(), "_NET_WM_MOVERESIZE", FALSE);
+
+    xev.type = ClientMessage;
+    xev.xclient.type = ClientMessage;
+    xev.xclient.window = GDK_WINDOW_XWINDOW(window->window);
+    xev.xclient.message_type = type;
+    xev.xclient.format = 32;
+    xev.xclient.data.l[0] = x;
+    xev.xclient.data.l[1] = y;
+    xev.xclient.data.l[2] = dir;
+    xev.xclient.data.l[3] = 1;  /* button */
+
+
+    XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), False,
+               SubstructureNotifyMask, &xev);
+}
+
+static gboolean
+find_atom(Atom * atoms, gint n, const gchar * name)
+{
+    Atom a = XInternAtom(GDK_DISPLAY(), name, FALSE);
+    gint i;
+
+    for (i = 0; i < n; i++)
+        if (a == atoms[i])
+            return TRUE;
+    return FALSE;
+}
+
+static gboolean
+get_supported_atoms(Atom ** atoms, gulong * natoms, const gchar * name)
+{
+    Atom supported = XInternAtom(GDK_DISPLAY(), name, FALSE), r_type;
+    gulong bremain;
+    gint r_format, p;
+
+    *atoms = NULL;
+    gdk_error_trap_push();
+    p = XGetWindowProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), supported,
+                           0, 1000, False, XA_ATOM, &r_type, &r_format,
+                           natoms, &bremain, (guchar **) atoms);
+    if (gdk_error_trap_pop() || p != Success || r_type != XA_ATOM ||
+        *natoms == 0 || *atoms == NULL)
+        return FALSE;
+
+    return TRUE;
+}
+
+static void
+net_wm_check_features(void)
+{
+    Atom *atoms;
+    gulong n_atoms;
+
+    if (!get_supported_atoms(&atoms, &n_atoms, "_NET_SUPPORTED"))
+        return;
+
+    if (find_atom(atoms, n_atoms, "_NET_WM_STATE")) {
+        if (!set_always_func &&
+            find_atom(atoms, n_atoms, "_NET_WM_STATE_ABOVE"))
+            set_always_func = net_wm_set_window_above;
+        if (!set_always_func &&
+            find_atom(atoms, n_atoms, "_NET_WM_STATE_STAYS_ON_TOP"))
+            set_always_func = net_wm_set_window_always;
+        if (!set_sticky_func && find_atom(atoms, n_atoms, "_NET_WM_DESKTOP"))
+            set_sticky_func = net_wm_set_desktop;
+    }
+
+    if (find_atom(atoms, n_atoms, "_NET_WM_MOVERESIZE"))
+        move_resize_func = net_wm_move_resize;
+
+    XFree(atoms);
+}
+
+void
+check_wm_hints(void)
+{
+    if (net_wm_found()) {
+        g_message("found NET_WM");
+        net_wm_check_features();
+    }
+
+}