summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Kasprzyk <onestone@opencompositing.org>2008-06-19 02:20:21 +0200
committerDennis kasprzyk <onestone@opencompositing.org>2008-06-19 02:20:21 +0200
commitacff8cbe8bde3899544396f7f36cbb7945c592cc (patch)
treef0a927cf1b90513b199cd31e55198a46d14081c2
parentbd706c10e13d971e677c1f1a8903f5e11ca61b8f (diff)
downloadstackswitch-acff8cbe8bde3899544396f7f36cbb7945c592cc.tar.gz
stackswitch-acff8cbe8bde3899544396f7f36cbb7945c592cc.tar.bz2
Initial commit.
-rw-r--r--CMakeLists.txt3
-rw-r--r--Makefile533
-rw-r--r--dummy0
-rw-r--r--plugin.info4
-rw-r--r--stackswitch.c1851
-rw-r--r--stackswitch.xml.in189
6 files changed, 2580 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..7c39a43
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,3 @@
+include (CompizFusion)
+
+compiz_fusion_plugin (stackswitch PLUGINDEPS text)
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..d9a07cf
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,533 @@
+##
+#
+# Compiz plugin Makefile
+#
+# Copyright : (C) 2007 by Dennis Kasprzyk
+# E-mail : onestone@deltatauchi.de
+#
+#
+# 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.
+#
+##
+
+# plugin.info file contents
+#
+# PLUGIN = foo
+# PKG_DEP = pango
+# LDFLAGS_ADD = -lGLU
+# CFLAGS_ADD = -I/usr/include/foo
+# CHK_HEADERS = compiz-cube.h
+#
+
+#load config file
+
+ECHO = `which echo`
+
+# default color settings
+color := $(shell if [ $$TERM = "dumb" ]; then $(ECHO) "no"; else $(ECHO) "yes"; fi)
+
+ifeq ($(shell if [ -f plugin.info ]; then $(ECHO) -n "found"; fi ),found)
+include plugin.info
+else
+$(error $(shell if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\033[1;31m[ERROR]\033[0m \"plugin.info\" file not found"; \
+ else \
+ $(ECHO) "[ERROR] \"plugin.info\" file not found"; \
+ fi;))
+endif
+
+ifneq ($(shell if pkg-config --exists compiz; then $(ECHO) -n "found"; fi ),found)
+$(error $(shell if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[1;31m[ERROR]\033[0m Compiz not installed"; \
+ else \
+ $(ECHO) -n "[ERROR] Compiz not installed"; \
+ fi))
+endif
+
+
+ifneq ($(shell if [ -n "$(PKG_DEP)" ]; then if pkg-config --exists $(PKG_DEP); then $(ECHO) -n "found"; fi; \
+ else $(ECHO) -n "found"; fi ),found)
+$(error $(shell if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[1;31m[ERROR]\033[0m "; \
+ else \
+ $(ECHO) -n "[ERROR] "; \
+ fi; \
+ pkg-config --print-errors --short-errors --errors-to-stdout $(PKG_DEP); ))
+endif
+
+
+ifeq ($(BUILD_GLOBAL),true)
+ PREFIX = $(shell pkg-config --variable=prefix compiz)
+ CLIBDIR = $(shell pkg-config --variable=libdir compiz)
+ CINCDIR = $(shell pkg-config --variable=includedir compiz)
+ PKGDIR = $(CLIBDIR)/pkgconfig
+ DESTDIR = $(shell pkg-config --variable=libdir compiz)/compiz
+ XMLDIR = $(shell pkg-config --variable=prefix compiz)/share/compiz
+ IMAGEDIR = $(shell pkg-config --variable=prefix compiz)/share/compiz
+ DATADIR = $(shell pkg-config --variable=prefix compiz)/share/compiz
+else
+ DESTDIR = $(HOME)/.compiz/plugins
+ XMLDIR = $(HOME)/.compiz/metadata
+ IMAGEDIR = $(HOME)/.compiz/images
+ DATADIR = $(HOME)/.compiz/data
+endif
+
+BUILDDIR = build
+
+CC = gcc
+CPP = g++
+LIBTOOL = libtool
+INSTALL = install
+
+BCOP = `pkg-config --variable=bin bcop`
+
+CFLAGS = -g -Wall -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -fno-strict-aliasing `pkg-config --cflags $(PKG_DEP) compiz ` $(CFLAGS_ADD)
+LDFLAGS = `pkg-config --libs $(PKG_DEP) compiz ` $(LDFLAGS_ADD)
+
+DEFINES = -DIMAGEDIR=\"$(IMAGEDIR)\" -DDATADIR=\"$(DATADIR)\"
+
+POFILEDIR = $(shell if [ -n "$(PODIR)" ]; then $(ECHO) $(PODIR); else $(ECHO) ./po;fi )
+
+COMPIZ_HEADERS = compiz.h compiz-core.h
+COMPIZ_INC = $(shell pkg-config --variable=includedir compiz)/compiz/
+
+is-bcop-target := $(shell if [ -e $(PLUGIN).xml.in ]; then cat $(PLUGIN).xml.in | grep "useBcop=\"true\""; \
+ else if [ -e $(PLUGIN).xml ]; then cat $(PLUGIN).xml | grep "useBcop=\"true\""; fi; fi)
+
+trans-target := $(shell if [ -e $(PLUGIN).xml.in -o -e $(PLUGIN).xml ]; then $(ECHO) $(BUILDDIR)/$(PLUGIN).xml;fi )
+
+bcop-target := $(shell if [ -n "$(is-bcop-target)" ]; then $(ECHO) $(BUILDDIR)/$(PLUGIN).xml; fi )
+bcop-target-src := $(shell if [ -n "$(is-bcop-target)" ]; then $(ECHO) $(BUILDDIR)/$(PLUGIN)_options.c; fi )
+bcop-target-hdr := $(shell if [ -n "$(is-bcop-target)" ]; then $(ECHO) $(BUILDDIR)/$(PLUGIN)_options.h; fi )
+
+gen-schemas := $(shell if [ \( -e $(PLUGIN).xml.in -o -e $(PLUGIN).xml \) -a -n "`pkg-config --variable=xsltdir compiz-gconf`" ]; then $(ECHO) true; fi )
+schema-target := $(shell if [ -n "$(gen-schemas)" ]; then $(ECHO) $(BUILDDIR)/$(PLUGIN).xml; fi )
+schema-output := $(shell if [ -n "$(gen-schemas)" ]; then $(ECHO) $(BUILDDIR)/compiz-$(PLUGIN).schema; fi )
+
+ifeq ($(BUILD_GLOBAL),true)
+ pkg-target := $(shell if [ -e compiz-$(PLUGIN).pc.in -a -n "$(PREFIX)" -a -d "$(PREFIX)" ]; then $(ECHO) "$(BUILDDIR)/compiz-$(PLUGIN).pc"; fi )
+ hdr-install-target := $(shell if [ -e compiz-$(PLUGIN).pc.in -a -n "$(PREFIX)" -a -d "$(PREFIX)" -a -e compiz-$(PLUGIN).h ]; then $(ECHO) "compiz-$(PLUGIN).h"; fi )
+endif
+
+# find all the object files
+
+c-objs := $(patsubst %.c,%.lo,$(shell find -name '*.c' 2> /dev/null | grep -v "$(BUILDDIR)/" | sed -e 's/^.\///'))
+c-objs += $(patsubst %.cpp,%.lo,$(shell find -name '*.cpp' 2> /dev/null | grep -v "$(BUILDDIR)/" | sed -e 's/^.\///'))
+c-objs += $(patsubst %.cxx,%.lo,$(shell find -name '*.cxx' 2> /dev/null | grep -v "$(BUILDDIR)/" | sed -e 's/^.\///'))
+c-objs := $(filter-out $(bcop-target-src:.c=.lo),$(c-objs))
+
+h-files := $(shell find -name '*.h' 2> /dev/null | grep -v "$(BUILDDIR)/" | sed -e 's/^.\///')
+h-files += $(bcop-target-hdr)
+h-files += $(foreach file,$(COMPIZ_HEADERS) $(CHK_HEADERS),$(shell $(ECHO) -n "$(COMPIZ_INC)$(file)"))
+
+all-c-objs := $(addprefix $(BUILDDIR)/,$(c-objs))
+all-c-objs += $(bcop-target-src:.c=.lo)
+
+# additional files
+
+data-files := $(shell find data/ -name '*' -type f 2> /dev/null | sed -e 's/data\///')
+image-files := $(shell find images/ -name '*' -type f 2> /dev/null | sed -e 's/images\///')
+
+# system include path parameter, -isystem doesn't work on old gcc's
+inc-path-param = $(shell if [ -z "`gcc --version | head -n 1 | grep ' 3'`" ]; then $(ECHO) "-isystem"; else $(ECHO) "-I"; fi)
+
+# Tests
+ifeq ($(shell if [ -n "$(is-bcop-target)" -a -z "$(BCOP)" ]; then $(ECHO) -n "error"; fi ),error)
+$(error $(shell if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[1;31m[ERROR]\033[0m BCOP not installed but is needed to build plugin"; \
+ else \
+ $(ECHO) -n "[ERROR] BCOP not installed but is needed to build plugin"; \
+ fi))
+endif
+
+ifeq ($(shell if [ "x$(BUILD_GLOBAL)" != "xtrue" -a -e compiz-$(PLUGIN).pc.in ]; then $(ECHO) -n "warn"; fi ),warn)
+$(warning $(shell if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[1;31m[WARNING]\033[0m This plugin might be needed by other plugins. Install it with \"BUILD_GLOBAL=true sudo make install\" "; \
+ else \
+ $(ECHO) -n "[WARNING] This plugin might be needed by other plugins. Install it with \"BUILD_GLOBAL=true sudo make install\""; \
+ fi))
+endif
+
+#
+# Do it.
+#
+
+.PHONY: $(BUILDDIR) build-dir trans-target bcop-build pkg-creation schema-creation c-build-objs c-link-plugin
+
+all: $(BUILDDIR) build-dir trans-target bcop-build pkg-creation schema-creation c-build-objs c-link-plugin
+
+trans-build: $(trans-target)
+
+bcop-build: $(bcop-target-hdr) $(bcop-target-src)
+
+schema-creation: $(schema-output)
+
+c-build-objs: $(all-c-objs)
+
+c-link-plugin: $(BUILDDIR)/lib$(PLUGIN).la
+
+pkg-creation: $(pkg-target)
+
+#
+# Create build directory
+#
+
+$(BUILDDIR) :
+ @mkdir -p $(BUILDDIR)
+
+$(DESTDIR) :
+ @mkdir -p $(DESTDIR)
+
+#
+# fallback if xml.in doesn't exists
+#
+$(BUILDDIR)/%.xml: %.xml
+ @cp $< $@
+
+#
+# Translating
+#
+$(BUILDDIR)/%.xml: %.xml.in
+ @if [ -d $(POFILEDIR) ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mtranslate \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "translate $< -> $@"; \
+ fi; \
+ intltool-merge -x -u $(POFILEDIR) $< $@ > /dev/null; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mtranslate : \033[34m$< -> $@\033[0m"; \
+ fi; \
+ else \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mconvert \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "convert $< -> $@"; \
+ fi; \
+ cat $< | sed -e 's;<_;<;g' -e 's;</_;</;g' > $@; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mconvert : \033[34m$< -> $@\033[0m"; \
+ fi; \
+ fi
+
+#
+# BCOP'ing
+
+$(BUILDDIR)/%_options.h: $(BUILDDIR)/%.xml
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mbcop'ing \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "bcop'ing $< -> $@"; \
+ fi
+ @$(BCOP) --header=$@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mbcop'ing : \033[34m$< -> $@\033[0m"; \
+ fi
+
+$(BUILDDIR)/%_options.c: $(BUILDDIR)/%.xml
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mbcop'ing \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "bcop'ing $< -> $@"; \
+ fi
+ @$(BCOP) --source=$@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mbcop'ing : \033[34m$< -> $@\033[0m"; \
+ fi
+
+#
+# Schema generation
+
+$(BUILDDIR)/compiz-%.schema: $(BUILDDIR)/%.xml
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mschema'ing\033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "schema'ing $< -> $@"; \
+ fi
+ @xsltproc `pkg-config --variable=xsltdir compiz-gconf`/schemas.xslt $< > $@
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mschema : \033[34m$< -> $@\033[0m"; \
+ fi
+
+#
+# pkg config file generation
+
+$(BUILDDIR)/compiz-%.pc: compiz-%.pc.in
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mpkgconfig \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "pkgconfig $< -> $@"; \
+ fi
+ @COMPIZREQUIRES=`cat $(PKGDIR)/compiz.pc | grep Requires | sed -e 's;Requires: ;;g'`; \
+ COMPIZCFLAGS=`cat $(PKGDIR)/compiz.pc | grep Cflags | sed -e 's;Cflags: ;;g'`; \
+ sed -e 's;@prefix@;$(PREFIX);g' -e 's;\@libdir@;$(CLIBDIR);g' \
+ -e 's;@includedir@;$(CINCDIR);g' -e 's;\@VERSION@;0.0.1;g' \
+ -e "s;@COMPIZ_REQUIRES@;$$COMPIZREQUIRES;g" \
+ -e "s;@COMPIZ_CFLAGS@;$$COMPIZCFLAGS;g" $< > $@;
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mpkgconfig : \033[34m$< -> $@\033[0m"; \
+ fi
+
+#
+# Compiling
+#
+
+$(BUILDDIR)/%.lo: %.c $(h-files)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5mcompiling \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "compiling $< -> $@"; \
+ fi
+ @$(LIBTOOL) --quiet --mode=compile $(CC) $(CFLAGS) $(DEFINES) -I$(BUILDDIR) -c -o $@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mcompiling : \033[34m$< -> $@\033[0m"; \
+ fi
+
+$(BUILDDIR)/%.lo: $(BUILDDIR)/%.c $(h-files)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5mcompiling \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "compiling $< -> $@"; \
+ fi
+ @$(LIBTOOL) --quiet --mode=compile $(CC) $(CFLAGS) $(DEFINES) -I$(BUILDDIR) -c -o $@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mcompiling : \033[34m$< -> $@\033[0m"; \
+ fi
+
+$(BUILDDIR)/%.lo: %.cpp $(h-files)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5mcompiling \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "compiling $< -> $@"; \
+ fi
+ @$(LIBTOOL) --quiet --mode=compile $(CPP) $(CFLAGS) $(DEFINES) -I$(BUILDDIR) -c -o $@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mcompiling : \033[34m$< -> $@\033[0m"; \
+ fi
+
+$(BUILDDIR)/%.lo: %.cxx $(h-files)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5mcompiling \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "compiling $< -> $@"; \
+ fi
+ @$(LIBTOOL) --quiet --mode=compile $(CPP) $(CFLAGS) $(DEFINES) -I$(BUILDDIR) -c -o $@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mcompiling : \033[34m$< -> $@\033[0m"; \
+ fi
+
+#
+# Linking
+#
+
+cxx-rpath-prefix := -Wl,-rpath,
+
+$(BUILDDIR)/lib$(PLUGIN).la: $(all-c-objs)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mlinking \033[0m: \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "linking : $@"; \
+ fi
+ @$(LIBTOOL) --quiet --mode=link $(CC) $(LDFLAGS) -rpath $(DESTDIR) -o $@ $(all-c-objs)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mlinking : \033[34m$@\033[0m"; \
+ fi
+
+
+clean:
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mremoving \033[0m: \033[0;31m./$(BUILDDIR)\033[0m"; \
+ else \
+ $(ECHO) "removing : ./$(BUILDDIR)"; \
+ fi
+ @rm -rf $(BUILDDIR)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mremoving : \033[34m./$(BUILDDIR)\033[0m"; \
+ fi
+
+
+install: $(DESTDIR) all
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(DESTDIR)/lib$(PLUGIN).so\033[0m"; \
+ else \
+ $(ECHO) "install : $(DESTDIR)/lib$(PLUGIN).so"; \
+ fi
+ @mkdir -p $(DESTDIR)
+ @$(INSTALL) $(BUILDDIR)/.libs/lib$(PLUGIN).so $(DESTDIR)/lib$(PLUGIN).so
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(DESTDIR)/lib$(PLUGIN).so\033[0m"; \
+ fi
+ @if [ -e $(BUILDDIR)/$(PLUGIN).xml ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(XMLDIR)/$(PLUGIN).xml\033[0m"; \
+ else \
+ $(ECHO) "install : $(XMLDIR)/$(PLUGIN).xml"; \
+ fi; \
+ mkdir -p $(XMLDIR); \
+ $(INSTALL) $(BUILDDIR)/$(PLUGIN).xml $(XMLDIR)/$(PLUGIN).xml; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(XMLDIR)/$(PLUGIN).xml\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(hdr-install-target)" ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(CINCDIR)/compiz/$(hdr-install-target)\033[0m"; \
+ else \
+ $(ECHO) "install : $(CINCDIR)/compiz/$(hdr-install-target)"; \
+ fi; \
+ $(INSTALL) --mode=u=rw,go=r,a-s $(hdr-install-target) $(CINCDIR)/compiz/$(hdr-install-target); \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(CINCDIR)/compiz/$(hdr-install-target)\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(pkg-target)" ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(PKGDIR)/compiz-$(PLUGIN).pc\033[0m"; \
+ else \
+ $(ECHO) "install : $(PKGDIR)/compiz-$(PLUGIN).pc"; \
+ fi; \
+ $(INSTALL) --mode=u=rw,go=r,a-s $(pkg-target) $(PKGDIR)/compiz-$(PLUGIN).pc; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(PKGDIR)/compiz-$(PLUGIN).pc\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(schema-output)" -a -e "$(schema-output)" ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(schema-output)\033[0m"; \
+ else \
+ $(ECHO) "install : $(schema-output)"; \
+ fi; \
+ if [ "x$(USER)" = "xroot" ]; then \
+ GCONF_CONFIG_SOURCE=`gconftool-2 --get-default-source` \
+ gconftool-2 --makefile-install-rule $(schema-output) > /dev/null; \
+ else \
+ gconftool-2 --install-schema-file=$(schema-output) > /dev/null; \
+ fi; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(schema-output)\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(data-files)" ]; then \
+ mkdir -p $(DATADIR); \
+ for FILE in $(data-files); do \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(DATADIR)/$$FILE\033[0m"; \
+ else \
+ $(ECHO) "install : $(DATADIR)/$$FILE"; \
+ fi; \
+ FILEDIR="$(DATADIR)/`dirname "$$FILE"`"; \
+ mkdir -p "$$FILEDIR"; \
+ $(INSTALL) --mode=u=rw,go=r,a-s data/$$FILE $(DATADIR)/$$FILE; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(DATADIR)/$$FILE\033[0m"; \
+ fi; \
+ done \
+ fi
+ @if [ -n "$(image-files)" ]; then \
+ mkdir -p $(IMAGEDIR); \
+ for FILE in $(image-files); do \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(IMAGEDIR)/$$FILE\033[0m"; \
+ else \
+ $(ECHO) "install : $(IMAGEDIR)/$$FILE"; \
+ fi; \
+ FILEDIR="$(IMAGEDIR)/`dirname "$$FILE"`"; \
+ mkdir -p "$$FILEDIR"; \
+ $(INSTALL) --mode=u=rw,go=r,a-s images/$$FILE $(IMAGEDIR)/$$FILE; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(IMAGEDIR)/$$FILE\033[0m"; \
+ fi; \
+ done \
+ fi
+
+uninstall:
+ @if [ -e $(DESTDIR)/lib$(PLUGIN).so ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(DESTDIR)/lib$(PLUGIN).so\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(DESTDIR)/lib$(PLUGIN).so"; \
+ fi; \
+ rm -f $(DESTDIR)/lib$(PLUGIN).so; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(DESTDIR)/lib$(PLUGIN).so\033[0m"; \
+ fi; \
+ fi
+ @if [ -e $(XMLDIR)/$(PLUGIN).xml ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(XMLDIR)/$(PLUGIN).xml\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(XMLDIR)/$(PLUGIN).xml"; \
+ fi; \
+ rm -f $(XMLDIR)/$(PLUGIN).xml; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(XMLDIR)/$(PLUGIN).xml\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(hdr-install-target)" -a -e $(CINCDIR)/compiz/$(hdr-install-target) ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(CINCDIR)/compiz/$(hdr-install-target)\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(CINCDIR)/compiz/$(hdr-install-target)"; \
+ fi; \
+ rm -f $(CINCDIR)/compiz/$(hdr-install-target); \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(CINCDIR)/compiz/$(hdr-install-target)\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(pkg-target)" -a -e $(PKGDIR)/compiz-$(PLUGIN).pc ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(PKGDIR)/compiz-$(PLUGIN).pc\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(PKGDIR)/compiz-$(PLUGIN).pc"; \
+ fi; \
+ rm -f $(PKGDIR)/compiz-$(PLUGIN).pc; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(PKGDIR)/compiz-$(PLUGIN).pc\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(schema-output)" -a -e "$(schema-output)" -a 'x$(USER)' = 'xroot' ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(schema-output)\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(schema-output)"; \
+ fi; \
+ GCONF_CONFIG_SOURCE=`gconftool-2 --get-default-source` \
+ gconftool-2 --makefile-uninstall-rule $(schema-output) > /dev/null; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(schema-output)\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(data-files)" ]; then \
+ for FILE in $(data-files); do \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(DATADIR)/$$FILE\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(DATADIR)/$$FILE"; \
+ fi; \
+ rm -f $(DATADIR)/$$FILE; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(DATADIR)/$$FILE\033[0m"; \
+ fi; \
+ done \
+ fi
+ @if [ -n "$(image-files)" ]; then \
+ for FILE in $(image-files); do \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(IMAGEDIR)/$$FILE\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(IMAGEDIR)/$$FILE"; \
+ fi; \
+ rm -f $(IMAGEDIR)/$$FILE; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(IMAGEDIR)/$$FILE\033[0m"; \
+ fi; \
+ done \
+ fi
diff --git a/dummy b/dummy
deleted file mode 100644
index e69de29..0000000
--- a/dummy
+++ /dev/null
diff --git a/plugin.info b/plugin.info
new file mode 100644
index 0000000..e851ab0
--- /dev/null
+++ b/plugin.info
@@ -0,0 +1,4 @@
+PLUGIN = stackswitch
+PKG_DEP = compiz-text
+CHK_HEADERS = compiz-text.h
+
diff --git a/stackswitch.c b/stackswitch.c
new file mode 100644
index 0000000..7f0abe5
--- /dev/null
+++ b/stackswitch.c
@@ -0,0 +1,1851 @@
+/*
+ *
+ * Compiz stackswitch switcher plugin
+ *
+ * stackswitch.c
+ *
+ * Copyright : (C) 2007 by Danny Baumann
+ * E-mail : maniac@opencompositing.org
+ *
+ * Based on scale.c and switcher.c:
+ * Copyright : (C) 2007 David Reveman
+ * E-mail : davidr@novell.com
+ *
+ * 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.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <sys/time.h>
+
+#include <X11/Xatom.h>
+#include <X11/cursorfont.h>
+
+#include <compiz-core.h>
+#include <compiz-text.h>
+#include "stackswitch_options.h"
+
+typedef enum {
+ StackswitchStateNone = 0,
+ StackswitchStateOut,
+ StackswitchStateSwitching,
+ StackswitchStateIn
+} StackswitchState;
+
+typedef enum {
+ StackswitchTypeNormal = 0,
+ StackswitchTypeGroup,
+ StackswitchTypeAll
+} StackswitchType;
+
+static int StackswitchDisplayPrivateIndex;
+
+typedef struct _StackswitchSlot {
+ int x, y; /* thumb center coordinates */
+ float scale; /* size scale (fit to maximal thumb size) */
+} StackswitchSlot;
+
+typedef struct _StackswitchDrawSlot {
+ CompWindow *w;
+ StackswitchSlot **slot;
+} StackswitchDrawSlot;
+
+typedef struct _StackswitchDisplay {
+ int screenPrivateIndex;
+ HandleEventProc handleEvent;
+ Bool textAvailable;
+} StackswitchDisplay;
+
+typedef struct _StackswitchScreen {
+ int windowPrivateIndex;
+
+ PreparePaintScreenProc preparePaintScreen;
+ DonePaintScreenProc donePaintScreen;
+ PaintOutputProc paintOutput;
+ PaintWindowProc paintWindow;
+ DamageWindowRectProc damageWindowRect;
+
+ int grabIndex;
+
+ StackswitchState state;
+ StackswitchType type;
+ Bool moreAdjust;
+ Bool rotateAdjust;
+
+ Bool paintingSwitcher;
+
+ GLfloat rVelocity;
+ GLfloat rotation;
+
+ /* only used for sorting */
+ CompWindow **windows;
+ StackswitchDrawSlot *drawSlots;
+ int windowsSize;
+ int nWindows;
+
+ Window clientLeader;
+ Window selectedWindow;
+
+ /* text display support */
+ CompTexture textTexture;
+ Pixmap textPixmap;
+ int textWidth;
+ int textHeight;
+
+ CompMatch match;
+ CompMatch *currentMatch;
+} StackswitchScreen;
+
+typedef struct _StackswitchWindow {
+
+ StackswitchSlot *slot;
+
+ GLfloat xVelocity;
+ GLfloat yVelocity;
+ GLfloat scaleVelocity;
+ GLfloat rotVelocity;
+
+ GLfloat tx;
+ GLfloat ty;
+ GLfloat scale;
+ GLfloat rotation;
+ Bool adjust;
+} StackswitchWindow;
+
+#define STACKSWITCH_DISPLAY(d) PLUGIN_DISPLAY(d, Stackswitch, s)
+#define STACKSWITCH_SCREEN(sc) PLUGIN_SCREEN(sc, Stackswitch, s)
+#define STACKSWITCH_WINDOW(w) PLUGIN_WINDOW(w, Stackswitch, s)
+
+static Bool
+isStackswitchWin (CompWindow *w)
+{
+ STACKSWITCH_SCREEN (w->screen);
+
+ if (w->attrib.override_redirect)
+ return FALSE;
+
+ if (w->wmType & (CompWindowTypeDockMask | CompWindowTypeDesktopMask))
+ return FALSE;
+
+ if (!w->mapNum || w->attrib.map_state != IsViewable)
+ {
+ if (stackswitchGetMinimized (w->screen))
+ {
+ if (!w->minimized && !w->inShowDesktopMode && !w->shaded)
+ return FALSE;
+ }
+ else
+ return FALSE;
+ }
+
+ if (ss->type == StackswitchTypeNormal)
+ {
+ if (!w->mapNum || w->attrib.map_state != IsViewable)
+ {
+ if (w->serverX + w->width <= 0 ||
+ w->serverY + w->height <= 0 ||
+ w->serverX >= w->screen->width ||
+ w->serverY >= w->screen->height)
+ return FALSE;
+ }
+ else
+ {
+ if (!(*w->screen->focusWindow) (w))
+ return FALSE;
+ }
+ }
+ else if (ss->type == StackswitchTypeGroup &&
+ ss->clientLeader != w->clientLeader &&
+ ss->clientLeader != w->id)
+ {
+ return FALSE;
+ }
+
+ if (w->state & CompWindowStateSkipTaskbarMask)
+ return FALSE;
+
+ if (!matchEval (ss->currentMatch, w))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+stackswitchFreeWindowTitle (CompScreen *s)
+{
+ STACKSWITCH_SCREEN(s);
+
+ if (!ss->textPixmap)
+ return;
+
+ releasePixmapFromTexture (s, &ss->textTexture);
+ initTexture (s, &ss->textTexture);
+ XFreePixmap (s->display->display, ss->textPixmap);
+ ss->textPixmap = None;
+}
+
+static void
+stackswitchRenderWindowTitle (CompScreen *s)
+{
+ CompTextAttrib tA;
+ int stride;
+ void *data;
+ int ox1, ox2, oy1, oy2;
+
+ STACKSWITCH_SCREEN (s);
+ STACKSWITCH_DISPLAY (s->display);
+
+ stackswitchFreeWindowTitle (s);
+
+ if (!sd->textAvailable)
+ return;
+
+ if (!stackswitchGetWindowTitle (s))
+ return;
+
+ getCurrentOutputExtents (s, &ox1, &oy1, &ox2, &oy2);
+
+ /* 75% of the output device as maximum width */
+ tA.maxWidth = (ox2 - ox1) * 3 / 4;
+ tA.maxHeight = 100;
+ tA.screen = s;
+ tA.size = stackswitchGetTitleFontSize (s);
+ tA.color[0] = stackswitchGetTitleFontColorRed (s);
+ tA.color[1] = stackswitchGetTitleFontColorGreen (s);
+ tA.color[2] = stackswitchGetTitleFontColorBlue (s);
+ tA.color[3] = stackswitchGetTitleFontColorAlpha (s);
+ tA.style = (stackswitchGetTitleFontBold (s)) ?
+ TEXT_STYLE_BOLD : TEXT_STYLE_NORMAL;
+ tA.style |= TEXT_STYLE_BACKGROUND;
+ tA.family = "Sans";
+ tA.ellipsize = TRUE;
+ tA.backgroundHMargin = 15;
+ tA.backgroundVMargin = 15;
+ tA.backgroundColor[0] = stackswitchGetTitleBackColorRed (s);
+ tA.backgroundColor[1] = stackswitchGetTitleBackColorGreen (s);
+ tA.backgroundColor[2] = stackswitchGetTitleBackColorBlue (s);
+ tA.backgroundColor[3] = stackswitchGetTitleBackColorAlpha (s);
+
+ if (ss->type == StackswitchTypeAll)
+ tA.renderMode = TextRenderWindowTitleWithViewport;
+ else
+ tA.renderMode = TextRenderWindowTitle;
+
+ tA.data = (void*)ss->selectedWindow;
+
+ initTexture (s, &ss->textTexture);
+
+ if ((*s->display->fileToImage) (s->display, TEXT_ID, (char *)&tA,
+ &ss->textWidth, &ss->textHeight,
+ &stride, &data))
+ {
+ ss->textPixmap = (Pixmap)data;
+ bindPixmapToTexture (s, &ss->textTexture, ss->textPixmap,
+ ss->textWidth, ss->textHeight, 32);
+ }
+ else
+ {
+ ss->textPixmap = None;
+ ss->textWidth = 0;
+ ss->textHeight = 0;
+ }
+}
+
+static void
+stackswitchDrawWindowTitle (CompScreen *s,
+ CompTransform *transform,
+ CompWindow *w)
+{
+ GLboolean wasBlend;
+ GLint oldBlendSrc, oldBlendDst;
+ CompTransform wTransform = *transform, mvp, pm;
+ float x, y, tx, ix, width, height;
+ int ox1, ox2, oy1, oy2, i;
+ CompMatrix *m;
+ CompVector v;
+ CompIcon *icon;
+
+ STACKSWITCH_SCREEN (s);
+ STACKSWITCH_WINDOW (w);
+
+ getCurrentOutputExtents (s, &ox1, &oy1, &ox2, &oy2);
+
+ width = ss->textWidth;
+ height = ss->textHeight;
+
+ x = ox1 + ((ox2 - ox1) / 2);
+ tx = x - (ss->textWidth / 2);
+
+ switch (stackswitchGetTitleTextPlacement (s))
+ {
+ case TitleTextPlacementOnThumbnail:
+ v.x = w->attrib.x + (w->attrib.width / 2.0);
+ v.y = w->attrib.y + (w->attrib.height / 2.0);
+ v.z = 0.0;
+ v.w = 1.0;
+
+ matrixScale (&wTransform, 1.0, 1.0, 1.0 / s->height);
+ matrixTranslate (&wTransform, sw->tx, sw->ty, 0.0f);
+ matrixRotate (&wTransform, -ss->rotation, 1.0, 0.0, 0.0);
+ matrixScale (&wTransform, sw->scale, sw->scale, 1.0);
+ matrixTranslate (&wTransform, +w->input.left, 0.0 -(w->attrib.height + w->input.bottom), 0.0f);
+ matrixTranslate (&wTransform, -w->attrib.x, -w->attrib.y, 0.0f);
+
+ for (i=0; i < 16; i++)
+ pm.m[i] = s->projection[i];
+ matrixMultiply (&mvp, &pm, &wTransform);
+ matrixMultiplyVector (&v, &v, &mvp);
+ matrixVectorDiv (&v);
+
+ x = (v.x + 1.0) * (ox2 - ox1) * 0.5;
+ y = (v.y - 1.0) * (oy2 - oy1) * -0.5;
+
+ x += ox1;
+ y += oy1;
+
+ tx = MAX (ox1, x - (width / 2.0));
+ if (tx + width > ox2)
+ tx = ox2 - width;
+ break;
+ case TitleTextPlacementCenteredOnScreen:
+ y = oy1 + ((oy2 - oy1) / 2) + (height / 2);
+ break;
+ case TitleTextPlacementAbove:
+ case TitleTextPlacementBelow:
+ {
+ XRectangle workArea;
+ getWorkareaForOutput (s, s->currentOutputDev, &workArea);
+
+ if (stackswitchGetTitleTextPlacement (s) ==
+ TitleTextPlacementAbove)
+ y = oy1 + workArea.y + height;
+ else
+ y = oy1 + workArea.y + workArea.height - 96;
+ }
+ break;
+ default:
+ return;
+ break;
+ }
+
+ tx = floor (tx);
+ y = floor (y);
+
+ glGetIntegerv (GL_BLEND_SRC, &oldBlendSrc);
+ glGetIntegerv (GL_BLEND_DST, &oldBlendDst);
+
+ wasBlend = glIsEnabled (GL_BLEND);
+ if (!wasBlend)
+ glEnable (GL_BLEND);
+
+ glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glColor4f (1.0, 1.0, 1.0, 1.0);
+
+ icon = getWindowIcon (w, 96, 96);
+ if (!icon)
+ icon = w->screen->defaultIcon;
+
+ if (icon && (icon->texture.name || iconToTexture (w->screen, icon)))
+ {
+ int off;
+
+ ix = x - (icon->width / 2.0);
+ ix = floor (ix);
+
+ enableTexture (s, &icon->texture,COMP_TEXTURE_FILTER_GOOD);
+
+ m = &icon->texture.matrix;
+
+ glColor4f (0.0, 0.0, 0.0, 0.1);
+
+ for (off = 0; off < 6; off++)
+ {
+ glBegin (GL_QUADS);
+
+ glTexCoord2f (COMP_TEX_COORD_X (m, 0), COMP_TEX_COORD_Y (m ,0));
+ glVertex2f (ix - off, y - off);
+ glTexCoord2f (COMP_TEX_COORD_X (m, 0), COMP_TEX_COORD_Y (m, icon->height));
+ glVertex2f (ix - off, y + icon->height + off);
+ glTexCoord2f (COMP_TEX_COORD_X (m, icon->width), COMP_TEX_COORD_Y (m, icon->height));
+ glVertex2f (ix + icon->width + off, y + icon->height + off);
+ glTexCoord2f (COMP_TEX_COORD_X (m, icon->width), COMP_TEX_COORD_Y (m, 0));
+ glVertex2f (ix + icon->width + off, y - off);
+
+ glEnd ();
+ }
+
+ glColor4f (1.0, 1.0, 1.0, 1.0);
+
+ glBegin (GL_QUADS);
+
+ glTexCoord2f (COMP_TEX_COORD_X (m, 0), COMP_TEX_COORD_Y (m ,0));
+ glVertex2f (ix, y);
+ glTexCoord2f (COMP_TEX_COORD_X (m, 0), COMP_TEX_COORD_Y (m, icon->height));
+ glVertex2f (ix, y + icon->height);
+ glTexCoord2f (COMP_TEX_COORD_X (m, icon->width), COMP_TEX_COORD_Y (m, icon->height));
+ glVertex2f (ix + icon->width, y + icon->height);
+ glTexCoord2f (COMP_TEX_COORD_X (m, icon->width), COMP_TEX_COORD_Y (m, 0));
+ glVertex2f (ix + icon->width, y);
+
+ glEnd ();
+
+ disableTexture (s, &icon->texture);
+ }
+
+ enableTexture (s, &ss->textTexture,COMP_TEXTURE_FILTER_GOOD);
+
+ m = &ss->textTexture.matrix;
+
+ glBegin (GL_QUADS);
+
+ glTexCoord2f (COMP_TEX_COORD_X (m, 0), COMP_TEX_COORD_Y (m ,0));
+ glVertex2f (tx, y - height);
+ glTexCoord2f (COMP_TEX_COORD_X (m, 0), COMP_TEX_COORD_Y (m, height));
+ glVertex2f (tx, y);
+ glTexCoord2f (COMP_TEX_COORD_X (m, width), COMP_TEX_COORD_Y (m, height));
+ glVertex2f (tx + width, y);
+ glTexCoord2f (COMP_TEX_COORD_X (m, width), COMP_TEX_COORD_Y (m, 0));
+ glVertex2f (tx + width, y - height);
+
+ glEnd ();
+
+ disableTexture (s, &ss->textTexture);
+ glColor4usv (defaultColor);
+
+ if (!wasBlend)
+ glDisable (GL_BLEND);
+ glBlendFunc (oldBlendSrc, oldBlendDst);
+}
+
+static Bool
+stackswitchPaintWindow (CompWindow *w,
+ const WindowPaintAttrib *attrib,
+ const CompTransform *transform,
+ Region region,
+ unsigned int mask)
+{
+ CompScreen *s = w->screen;
+ Bool status;
+
+ STACKSWITCH_SCREEN (s);
+
+ if (ss->state != StackswitchStateNone)
+ {
+ WindowPaintAttrib sAttrib = *attrib;
+ Bool scaled = FALSE;
+ float rotation;
+
+ STACKSWITCH_WINDOW (w);
+
+ if (w->mapNum)
+ {
+ if (!w->texture->pixmap && !w->bindFailed)
+ bindWindow (w);
+ }
+
+ if (sw->adjust || sw->slot)
+ {
+ scaled = (sw->adjust && ss->state != StackswitchStateSwitching) ||
+ (sw->slot && ss->paintingSwitcher);
+ mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
+ }
+ else if (ss->state != StackswitchStateIn)
+ {
+ if (stackswitchGetDarkenBack (s))
+ {
+ /* modify brightness of the other windows */
+ sAttrib.brightness = sAttrib.brightness / 2;
+ }
+ }
+
+ UNWRAP (ss, s, paintWindow);
+ status = (*s->paintWindow) (w, &sAttrib, transform, region, mask);
+ WRAP (ss, s, paintWindow, stackswitchPaintWindow);
+
+ if (stackswitchGetInactiveRotate(s))
+ rotation = MIN (sw->rotation, ss->rotation);
+ else
+ rotation = ss->rotation;
+
+ if (scaled && w->texture->pixmap)
+ {
+ FragmentAttrib fragment;
+ CompTransform wTransform = *transform;
+
+ if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
+ return FALSE;
+
+ initFragmentAttrib (&fragment, &w->lastPaint);
+
+ if (sw->slot)
+ {
+ if (w->id != ss->selectedWindow)
+ fragment.opacity = (float)fragment.opacity *
+ stackswitchGetInactiveOpacity (s) / 100;
+ }
+
+ if (w->alpha || fragment.opacity != OPAQUE)
+ mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
+
+
+ matrixScale (&wTransform, 1.0, 1.0, 1.0 / s->height);
+ matrixTranslate (&wTransform, sw->tx, sw->ty, 0.0f);
+
+ matrixRotate (&wTransform, -rotation, 1.0, 0.0, 0.0);
+ matrixScale (&wTransform, sw->scale, sw->scale, 1.0);
+
+ matrixTranslate (&wTransform, +w->input.left, 0.0 -(w->attrib.height + w->input.bottom), 0.0f);
+ matrixTranslate (&wTransform, -w->attrib.x, -w->attrib.y, 0.0f);
+ glPushMatrix ();
+ glLoadMatrixf (wTransform.m);
+
+ (*s->drawWindow) (w, &wTransform, &fragment, region,
+ mask | PAINT_WINDOW_TRANSFORMED_MASK);
+
+ glPopMatrix ();
+ }
+
+ if (scaled && !w->texture->pixmap)
+ {
+ CompIcon *icon;
+
+ icon = getWindowIcon (w, 96, 96);
+ if (!icon)
+ icon = w->screen->defaultIcon;
+
+ if (icon && (icon->texture.name || iconToTexture (w->screen, icon)))
+ {
+ REGION iconReg;
+ CompMatrix matrix;
+ float scale;
+
+ scale = MIN (w->attrib.width / icon->width,
+ w->attrib.height / icon->height);
+ scale *= sw->scale;
+
+ mask |= PAINT_WINDOW_BLEND_MASK;
+
+ /* if we paint the icon for a minimized window, we need
+ to force the usage of a good texture filter */
+ if (!w->texture->pixmap)
+ mask |= PAINT_WINDOW_TRANSFORMED_MASK;
+
+ iconReg.rects = &iconReg.extents;
+ iconReg.numRects = 1;
+
+ iconReg.extents.x1 = 0;
+ iconReg.extents.y1 = 0;
+ iconReg.extents.x2 = icon->width;
+ iconReg.extents.y2 = icon->height;
+
+ matrix = icon->texture.matrix;
+
+ w->vCount = w->indexCount = 0;
+ (*w->screen->addWindowGeometry) (w, &matrix, 1,
+ &iconReg, &infiniteRegion);
+
+ if (w->vCount)
+ {
+ FragmentAttrib fragment;
+ CompTransform wTransform = *transform;
+
+ if (!w->texture->pixmap)
+ {
+ /* the fade plugin does weird things to
+ w->paint.opacity, so better use the atom value */
+ sAttrib.opacity = w->opacity;
+ }
+
+ initFragmentAttrib (&fragment, &sAttrib);
+
+ matrixScale (&wTransform, 1.0, 1.0, 1.0 / s->height);
+ matrixTranslate (&wTransform, sw->tx, sw->ty, 0.0f);
+
+ matrixRotate (&wTransform, -rotation, 1.0, 0.0, 0.0);
+ matrixScale (&wTransform, scale, scale, 1.0);
+
+ matrixTranslate (&wTransform, 0.0, -icon->height, 0.0f);
+
+ glPushMatrix ();
+ glLoadMatrixf (wTransform.m);
+
+ (*w->screen->drawWindowTexture) (w, &icon->texture,
+ &fragment, mask);
+
+ glPopMatrix ();
+ }
+ }
+ }
+ }
+ else
+ {
+ UNWRAP (ss, s, paintWindow);
+ status = (*s->paintWindow) (w, attrib, transform, region, mask);
+ WRAP (ss, s, paintWindow, stackswitchPaintWindow);
+ }
+
+ return status;
+}
+
+static int
+compareWindows (const void *elem1,
+ const void *elem2)
+{
+ CompWindow *w1 = *((CompWindow **) elem1);
+ CompWindow *w2 = *((CompWindow **) elem2);
+
+ if (w1->mapNum && !w2->mapNum)
+ return -1;
+
+ if (w2->mapNum && !w1->mapNum)
+ return 1;
+
+ return w2->activeNum - w1->activeNum;
+}
+
+static int
+compareStackswitchWindowDepth (const void *elem1,
+ const void *elem2)
+{
+ StackswitchSlot *a1 = *(((StackswitchDrawSlot *) elem1)->slot);
+ StackswitchSlot *a2 = *(((StackswitchDrawSlot *) elem2)->slot);
+
+ if (a1->y < a2->y)
+ return -1;
+ else if (a1->y > a2->y)
+ return 1;
+ else
+ {
+ CompWindow *a1 = (((StackswitchDrawSlot *) elem1)->w);
+ CompWindow *a2 = (((StackswitchDrawSlot *) elem2)->w);
+ STACKSWITCH_SCREEN (a1->screen);
+ if (a1->id == ss->selectedWindow)
+ return 1;
+ else if (a2->id == ss->selectedWindow)
+ return -1;
+ else
+ return 0;
+ }
+}
+
+static Bool
+layoutThumbs (CompScreen *s)
+{
+ CompWindow *w;
+ int index;
+ int ww, wh;
+ float xScale, yScale;
+ int ox1, ox2, oy1, oy2;
+ float swi = 0.0, oh, rh, ow;
+ int cols, rows, col = 0, row = 0, r, c;
+ int cindex, ci, gap, hasActive = 0;
+ Bool exit;
+
+ STACKSWITCH_SCREEN (s);
+
+ if ((ss->state == StackswitchStateNone) || (ss->state == StackswitchStateIn))
+ return FALSE;
+
+ getCurrentOutputExtents (s, &ox1, &oy1, &ox2, &oy2);
+ ow = (float)(ox2 - ox1) * 0.9;
+
+ for (index = 0; index < ss->nWindows; index++)
+ {
+ w = ss->windows[index];
+
+ ww = w->attrib.width + w->input.left + w->input.right;
+ wh = w->attrib.height + w->input.top + w->input.bottom;
+
+ swi += ((float)ww / (float)wh) * (ow / (float)(oy2 - oy1));
+ }
+
+ cols = ceil (sqrtf (swi));
+
+ swi = 0.0;
+ for (index = 0; index < ss->nWindows; index++)
+ {
+ w = ss->windows[index];
+
+ ww = w->attrib.width + w->input.left + w->input.right;
+ wh = w->attrib.height + w->input.top + w->input.bottom;
+
+ swi += (float)ww / (float)wh;
+
+ if (swi > cols)
+ {
+ row++;
+ swi = (float)ww / (float)wh;
+ col = 0;
+ }
+
+ col++;
+ }
+ rows = row + 1;
+
+ oh = ow / cols;
+ oh *= (float)(oy2 - oy1) / (float)(oy2 - oy1);
+
+ rh = ((float)(oy2 - oy1) * 0.8) / rows;
+
+ for (index = 0; index < ss->nWindows; index++)
+ {
+ w = ss->windows[index];
+
+ STACKSWITCH_WINDOW (w);
+
+ if (!sw->slot)
+ sw->slot = malloc (sizeof (StackswitchSlot));
+
+ if (!sw->slot)
+ return FALSE;
+
+ ss->drawSlots[index].w = w;
+ ss->drawSlots[index].slot = &sw->slot;
+ }
+
+ index = 0;
+
+ for (r = 0; r < rows && index < ss->nWindows; r++)
+ {
+ c = 0;
+ swi = 0.0;
+ cindex = index;
+ exit = FALSE;
+ while (index < ss->nWindows && !exit)
+ {
+ w = ss->windows[index];
+
+ STACKSWITCH_WINDOW (w);
+ sw->slot->x = ox1 + swi;
+ sw->slot->y = oy2 - (rh * r) - ((oy2 - oy1) * 0.1);
+
+
+ ww = w->attrib.width + w->input.left + w->input.right;
+ wh = w->attrib.height + w->input.top + w->input.bottom;
+
+ if (ww > ow)
+ xScale = ow / (float) ww;
+ else
+ xScale = 1.0f;
+
+ if (wh > oh)
+ yScale = oh / (float) wh;
+ else
+ yScale = 1.0f;
+
+ sw->slot->scale = MIN (xScale, yScale);
+
+ if (swi + (ww * sw->slot->scale) > ow && cindex != index)
+ {
+ exit = TRUE;
+ continue;
+ }
+
+ if (w->id == ss->selectedWindow)
+ hasActive = 1;
+ swi += ww * sw->slot->scale;
+
+ c++;
+ index++;
+ }
+
+ gap = ox2 - ox1 - swi;
+ gap /= c + 1;
+
+ index = cindex;
+ ci = 1;
+ while (ci <= c)
+ {
+ w = ss->windows[index];
+
+ STACKSWITCH_WINDOW (w);
+ sw->slot->x += ci * gap;
+
+ if (hasActive == 0)
+ sw->slot->y += sqrt(2 * oh * oh) - rh;
+
+ ci++;
+ index++;
+ }
+
+ if (hasActive == 1)
+ hasActive++;
+ }
+
+ /* sort the draw list so that the windows with the
+ lowest Y value (the windows being farest away)
+ are drawn first */
+ qsort (ss->drawSlots, ss->nWindows, sizeof (StackswitchDrawSlot),
+ compareStackswitchWindowDepth);
+
+ return TRUE;
+}
+
+static void
+stackswitchAddWindowToList (CompScreen *s,
+ CompWindow *w)
+{
+ STACKSWITCH_SCREEN (s);
+
+ if (ss->windowsSize <= ss->nWindows)
+ {
+ ss->windows = realloc (ss->windows,
+ sizeof (CompWindow *) * (ss->nWindows + 32));
+ if (!ss->windows)
+ return;
+
+ ss->drawSlots = realloc (ss->drawSlots,
+ sizeof (StackswitchDrawSlot) * (ss->nWindows + 32));
+
+ if (!ss->drawSlots)
+ return;
+
+ ss->windowsSize = ss->nWindows + 32;
+ }
+
+ ss->windows[ss->nWindows++] = w;
+}
+
+static Bool
+stackswitchUpdateWindowList (CompScreen *s)
+{
+ STACKSWITCH_SCREEN (s);
+
+ qsort (ss->windows, ss->nWindows, sizeof (CompWindow *), compareWindows);
+
+ return layoutThumbs (s);
+}
+
+static Bool
+stackswitchCreateWindowList (CompScreen *s)
+{
+ CompWindow *w;
+
+ STACKSWITCH_SCREEN (s);
+
+ ss->nWindows = 0;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ if (isStackswitchWin (w))
+ {
+ STACKSWITCH_WINDOW (w);
+
+ stackswitchAddWindowToList (s, w);
+ sw->adjust = TRUE;
+ }
+ }
+
+ return stackswitchUpdateWindowList (s);
+}
+
+static void
+switchToWindow (CompScreen *s,
+ Bool toNext)
+{
+ CompWindow *w;
+ int cur;
+
+ STACKSWITCH_SCREEN (s);
+
+ if (!ss->grabIndex)
+ return;
+
+ for (cur = 0; cur < ss->nWindows; cur++)
+ {
+ if (ss->windows[cur]->id == ss->selectedWindow)
+ break;
+ }
+
+ if (cur == ss->nWindows)
+ return;
+
+ if (toNext)
+ w = ss->windows[(cur + 1) % ss->nWindows];
+ else
+ w = ss->windows[(cur + ss->nWindows - 1) % ss->nWindows];
+
+ if (w)
+ {
+ Window old = ss->selectedWindow;
+
+ ss->selectedWindow = w->id;
+ if (old != w->id)
+ {
+
+ ss->rotateAdjust = TRUE;
+ ss->moreAdjust = TRUE;
+ for (w = s->windows; w; w = w->next)
+ {
+ STACKSWITCH_WINDOW (w);
+ sw->adjust = TRUE;
+ }
+
+ damageScreen (s);
+ stackswitchRenderWindowTitle (s);
+ }
+ }
+}
+
+static int
+stackswitchCountWindows (CompScreen *s)
+{
+ CompWindow *w;
+ int count = 0;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ if (isStackswitchWin (w))
+ count++;
+ }
+
+ return count;
+}
+
+static int
+adjustStackswitchRotation (CompScreen *s,
+ float chunk)
+{
+ float dx, adjust, amount, rot;
+
+ STACKSWITCH_SCREEN(s);
+
+ if (ss->state != StackswitchStateNone && ss->state != StackswitchStateIn)
+ rot = stackswitchGetRotation (s);
+ else
+ rot = 0.0;
+
+ dx = rot - ss->rotation;
+
+ adjust = dx * 0.15f;
+ amount = fabs (dx) * 1.5f;
+ if (amount < 0.2f)
+ amount = 0.2f;
+ else if (amount > 2.0f)
+ amount = 2.0f;
+
+ ss->rVelocity = (amount * ss->rVelocity + adjust) / (amount + 1.0f);
+
+ if (fabs (dx) < 0.1f && fabs (ss->rVelocity) < 0.2f)
+ {
+ ss->rVelocity = 0.0f;
+ ss->rotation = rot;
+ return FALSE;
+ }
+
+ ss->rotation += ss->rVelocity * chunk;
+ return TRUE;
+}
+
+static int
+adjustStackswitchVelocity (CompWindow *w)
+{
+ float dx, dy, ds, dr, adjust, amount;
+ float x1, y1, scale, rot;
+
+ STACKSWITCH_WINDOW (w);
+ STACKSWITCH_SCREEN (w->screen);
+
+ if (sw->slot)
+ {
+ scale = sw->slot->scale;
+ x1 = sw->slot->x;
+ y1 = sw->slot->y;
+ }
+ else
+ {
+ scale = 1.0f;
+ x1 = w->attrib.x - w->input.left;
+ y1 = w->attrib.y + w->attrib.height + w->input.bottom;
+ }
+
+ if (w->id == ss->selectedWindow)
+ rot = ss->rotation;
+ else
+ rot = 0.0;
+
+ dx = x1 - sw->tx;
+
+ adjust = dx * 0.15f;
+ amount = fabs (dx) * 1.5f;
+ if (amount < 0.5f)
+ amount = 0.5f;
+ else if (amount > 5.0f)
+ amount = 5.0f;
+
+ sw->xVelocity = (amount * sw->xVelocity + adjust) / (amount + 1.0f);
+
+ dy = y1 - sw->ty;
+
+ adjust = dy * 0.15f;
+ amount = fabs (dy) * 1.5f;
+ if (amount < 0.5f)
+ amount = 0.5f;
+ else if (amount > 5.0f)
+ amount = 5.0f;
+
+ sw->yVelocity = (amount * sw->yVelocity + adjust) / (amount + 1.0f);
+
+ ds = scale - sw->scale;
+ adjust = ds * 0.1f;
+ amount = fabs (ds) * 7.0f;
+ if (amount < 0.01f)
+ amount = 0.01f;
+ else if (amount > 0.15f)
+ amount = 0.15f;
+
+ sw->scaleVelocity = (amount * sw->scaleVelocity + adjust) /
+ (amount + 1.0f);
+
+ dr = rot - sw->rotation;
+ adjust = dr * 0.15f;
+ amount = fabs (dr) * 1.5f;
+ if (amount < 0.2f)
+ amount = 0.2f;
+ else if (amount > 2.0f)
+ amount = 2.0f;
+
+ sw->rotVelocity = (amount * sw->rotVelocity + adjust) / (amount + 1.0f);
+
+ if (fabs (dx) < 0.1f && fabs (sw->xVelocity) < 0.2f &&
+ fabs (dy) < 0.1f && fabs (sw->yVelocity) < 0.2f &&
+ fabs (ds) < 0.001f && fabs (sw->scaleVelocity) < 0.002f &&
+ fabs (dr) < 0.1f && fabs (sw->rotVelocity) < 0.2f)
+ {
+ sw->xVelocity = sw->yVelocity = sw->scaleVelocity = 0.0f;
+ sw->tx = x1;
+ sw->ty = y1;
+ sw->rotation = rot;
+ sw->scale = scale;
+
+ return 0;
+ }
+
+ return 1;
+}
+
+static Bool
+stackswitchPaintOutput (CompScreen *s,
+ const ScreenPaintAttrib *sAttrib,
+ const CompTransform *transform,
+ Region region,
+ CompOutput *output,
+ unsigned int mask)
+{
+ Bool status;
+ CompTransform sTransform = *transform;
+
+ STACKSWITCH_SCREEN (s);
+
+ if (ss->state != StackswitchStateNone || ss->rotation != 0.0)
+ {
+ mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
+ mask |= PAINT_SCREEN_TRANSFORMED_MASK;
+ mask |= PAINT_SCREEN_CLEAR_MASK;
+ matrixTranslate (&sTransform, 0.0, -0.5, -DEFAULT_Z_CAMERA);
+ matrixRotate (&sTransform, -ss->rotation, 1.0, 0.0, 0.0);
+ matrixTranslate (&sTransform, 0.0, 0.5, DEFAULT_Z_CAMERA);
+ }
+
+ UNWRAP (ss, s, paintOutput);
+ status = (*s->paintOutput) (s, sAttrib, &sTransform, region, output, mask);
+ WRAP (ss, s, paintOutput, stackswitchPaintOutput);
+
+ if (ss->state != StackswitchStateNone && (output->id == ~0 ||
+ s->outputDev[s->currentOutputDev].id == output->id))
+ {
+ int i;
+ CompWindow *aw = NULL;
+
+ transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &sTransform);
+ glPushMatrix ();
+ glLoadMatrixf (sTransform.m);
+
+ ss->paintingSwitcher = TRUE;
+
+ for (i = 0; i < ss->nWindows; i++)
+ {
+ if (ss->drawSlots[i].slot && *(ss->drawSlots[i].slot))
+ {
+ CompWindow *w = ss->drawSlots[i].w;
+ if (w->id == ss->selectedWindow)
+ aw = w;
+
+ (*s->paintWindow) (w, &w->paint, &sTransform,
+ &infiniteRegion, 0);
+ }
+ }
+
+
+ CompTransform tTransform = *transform;
+ transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &tTransform);
+ glLoadMatrixf (tTransform.m);
+
+ if (ss->textPixmap && (ss->state != StackswitchStateIn) && aw)
+ stackswitchDrawWindowTitle (s, &sTransform, aw);
+
+ ss->paintingSwitcher = FALSE;
+
+ glPopMatrix ();
+ }
+
+ return status;
+}
+
+static void
+stackswitchPreparePaintScreen (CompScreen *s,
+ int msSinceLastPaint)
+{
+ STACKSWITCH_SCREEN (s);
+
+ if (ss->state != StackswitchStateNone && (ss->moreAdjust || ss->rotateAdjust))
+ {
+ CompWindow *w;
+ int steps;
+ float amount, chunk;
+
+ amount = msSinceLastPaint * 0.05f * stackswitchGetSpeed (s);
+ steps = amount / (0.5f * stackswitchGetTimestep (s));
+
+ if (!steps)
+ steps = 1;
+ chunk = amount / (float) steps;
+
+ layoutThumbs (s);
+ while (steps--)
+ {
+ ss->rotateAdjust = adjustStackswitchRotation (s, chunk);
+ ss->moreAdjust = FALSE;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ STACKSWITCH_WINDOW (w);
+
+ if (sw->adjust)
+ {
+ sw->adjust = adjustStackswitchVelocity (w);
+
+ ss->moreAdjust |= sw->adjust;
+
+ sw->tx += sw->xVelocity * chunk;
+ sw->ty += sw->yVelocity * chunk;
+ sw->scale += sw->scaleVelocity * chunk;
+ sw->rotation += sw->rotVelocity * chunk;
+ }
+ else if (sw->slot)
+ {
+ sw->scale = sw->slot->scale;
+ sw->tx = sw->slot->x;
+ sw->ty = sw->slot->y;
+ if (w->id == ss->selectedWindow)
+ sw->rotation = ss->rotation;
+ else
+ sw->rotation = 0.0;
+ }
+ }
+
+ if (!ss->moreAdjust && !ss->rotateAdjust)
+ break;
+ }
+ }
+
+ UNWRAP (ss, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s, msSinceLastPaint);
+ WRAP (ss, s, preparePaintScreen, stackswitchPreparePaintScreen);
+}
+
+static void
+stackswitchDonePaintScreen (CompScreen *s)
+{
+ STACKSWITCH_SCREEN (s);
+
+ if (ss->state != StackswitchStateNone)
+ {
+ if (ss->moreAdjust)
+ {
+ damageScreen (s);
+ }
+ else
+ {
+ if (ss->rotateAdjust)
+ damageScreen (s);
+
+ if (ss->state == StackswitchStateIn)
+ ss->state = StackswitchStateNone;
+ else if (ss->state == StackswitchStateOut)
+ ss->state = StackswitchStateSwitching;
+ }
+ }
+
+ UNWRAP (ss, s, donePaintScreen);
+ (*s->donePaintScreen) (s);
+ WRAP (ss, s, donePaintScreen, stackswitchDonePaintScreen);
+}
+
+static Bool
+stackswitchTerminate (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ CompScreen *s;
+ Window xid;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
+
+ for (s = d->screens; s; s = s->next)
+ {
+ STACKSWITCH_SCREEN (s);
+
+ if (xid && s->root != xid)
+ continue;
+
+ if (ss->grabIndex)
+ {
+ removeScreenGrab (s, ss->grabIndex, 0);
+ ss->grabIndex = 0;
+ }
+
+ if (ss->state != StackswitchStateNone)
+ {
+ CompWindow *w;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ STACKSWITCH_WINDOW (w);
+
+ if (sw->slot)
+ {
+ free (sw->slot);
+ sw->slot = NULL;
+
+ sw->adjust = TRUE;
+ }
+ }
+ ss->moreAdjust = TRUE;
+ ss->state = StackswitchStateIn;
+ damageScreen (s);
+
+ if (!(state & CompActionStateCancel) && ss->selectedWindow)
+ {
+ w = findWindowAtScreen (s, ss->selectedWindow);
+ if (w)
+ sendWindowActivationRequest (s, w->id);
+ }
+ }
+ }
+
+ if (action)
+ action->state &= ~(CompActionStateTermKey |
+ CompActionStateTermButton |
+ CompActionStateTermEdge);
+
+ return FALSE;
+}
+
+static Bool
+stackswitchInitiate (CompScreen *s,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ CompWindow *w;
+ CompMatch *match;
+ int count;
+
+ STACKSWITCH_SCREEN (s);
+
+ if (otherScreenGrabExist (s, "stackswitch", 0))
+ return FALSE;
+
+ ss->currentMatch = stackswitchGetWindowMatch (s);
+
+ match = getMatchOptionNamed (option, nOption, "match", NULL);
+ if (match)
+ {
+ matchFini (&ss->match);
+ matchInit (&ss->match);
+ if (matchCopy (&ss->match, match))
+ {
+ matchUpdate (s->display, &ss->match);
+ ss->currentMatch = &ss->match;
+ }
+ }
+
+ count = stackswitchCountWindows (s);
+
+ if (count < 1)
+ return FALSE;
+
+ if (!ss->grabIndex)
+ {
+ ss->grabIndex = pushScreenGrab (s, s->invisibleCursor, "stackswitch");
+ }
+
+ if (ss->grabIndex)
+ {
+ ss->state = StackswitchStateOut;
+
+ if (!stackswitchCreateWindowList (s))
+ return FALSE;
+
+ ss->selectedWindow = ss->windows[0]->id;
+ stackswitchRenderWindowTitle (s);
+
+ for (w = s->windows; w; w = w->next)
+ {
+ STACKSWITCH_WINDOW (w);
+
+ sw->tx = w->attrib.x - w->input.left;
+ sw->ty = w->attrib.y + w->attrib.height + w->input.bottom;
+ }
+ ss->moreAdjust = TRUE;
+ damageScreen (s);
+ }
+
+ return TRUE;
+}
+
+static Bool
+stackswitchDoSwitch (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption,
+ Bool nextWindow,
+ StackswitchType type)
+{
+ CompScreen *s;
+ Window xid;
+ Bool ret = TRUE;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
+
+ s = findScreenAtDisplay (d, xid);
+ if (s)
+ {
+ STACKSWITCH_SCREEN (s);
+
+ if ((ss->state == StackswitchStateNone) || (ss->state == StackswitchStateIn))
+ {
+ if (type == StackswitchTypeGroup)
+ {
+ CompWindow *w;
+ w = findWindowAtDisplay (d, getIntOptionNamed (option, nOption,
+ "window", 0));
+ if (w)
+ {
+ ss->type = StackswitchTypeGroup;
+ ss->clientLeader =
+ (w->clientLeader) ? w->clientLeader : w->id;
+ ret = stackswitchInitiate (s, action, state, option, nOption);
+ }
+ }
+ else
+ {
+ ss->type = type;
+ ret = stackswitchInitiate (s, action, state, option, nOption);
+ }
+
+ if (state & CompActionStateInitKey)
+ action->state |= CompActionStateTermKey;
+
+ if (state & CompActionStateInitEdge)
+ action->state |= CompActionStateTermEdge;
+ else if (state & CompActionStateInitButton)
+ action->state |= CompActionStateTermButton;
+ }
+
+ if (ret)
+ switchToWindow (s, nextWindow);
+ }
+
+ return ret;
+}
+
+static Bool
+stackswitchNext (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ return stackswitchDoSwitch (d, action, state, option, nOption,
+ TRUE, StackswitchTypeNormal);
+}
+
+static Bool
+stackswitchPrev (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ return stackswitchDoSwitch (d, action, state, option, nOption,
+ FALSE, StackswitchTypeNormal);
+}
+
+static Bool
+stackswitchNextAll (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ return stackswitchDoSwitch (d, action, state, option, nOption,
+ TRUE, StackswitchTypeAll);
+}
+
+static Bool
+stackswitchPrevAll (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ return stackswitchDoSwitch (d, action, state, option, nOption,
+ FALSE, StackswitchTypeAll);
+}
+
+static Bool
+stackswitchNextGroup (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ return stackswitchDoSwitch (d, action, state, option, nOption,
+ TRUE, StackswitchTypeGroup);
+}
+
+static Bool
+stackswitchPrevGroup (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ return stackswitchDoSwitch (d, action, state, option, nOption,
+ FALSE, StackswitchTypeGroup);
+}
+
+
+static void
+stackswitchWindowRemove (CompDisplay *d,
+ Window id)
+{
+ CompWindow *w;
+
+ w = findWindowAtDisplay (d, id);
+ if (w)
+ {
+ Bool inList = FALSE;
+ int j, i = 0;
+ Window selected;
+
+ STACKSWITCH_SCREEN (w->screen);
+
+ if (ss->state == StackswitchStateNone)
+ return;
+
+ if (isStackswitchWin (w))
+ return;
+
+ selected = ss->selectedWindow;
+
+ while (i < ss->nWindows)
+ {
+ if (w->id == ss->windows[i]->id)
+ {
+ inList = TRUE;
+
+ if (w->id == selected)
+ {
+ if (i < (ss->nWindows - 1))
+ selected = ss->windows[i + 1]->id;
+ else
+ selected = ss->windows[0]->id;
+
+ ss->selectedWindow = selected;
+ }
+
+ ss->nWindows--;
+ for (j = i; j < ss->nWindows; j++)
+ ss->windows[j] = ss->windows[j + 1];
+ }
+ else
+ {
+ i++;
+ }
+ }
+
+ if (!inList)
+ return;
+
+ if (ss->nWindows == 0)
+ {
+ CompOption o;
+
+ o.type = CompOptionTypeInt;
+ o.name = "root";
+ o.value.i = w->screen->root;
+
+ stackswitchTerminate (d, NULL, 0, &o, 1);
+ return;
+ }
+
+ if (!ss->grabIndex)
+ return;
+
+ if (stackswitchUpdateWindowList (w->screen))
+ {
+ ss->moreAdjust = TRUE;
+ ss->state = StackswitchStateOut;
+ damageScreen (w->screen);
+ }
+ }
+}
+
+static void
+stackswitchHandleEvent (CompDisplay *d,
+ XEvent *event)
+{
+ STACKSWITCH_DISPLAY (d);
+
+ UNWRAP (sd, d, handleEvent);
+ (*d->handleEvent) (d, event);
+ WRAP (sd, d, handleEvent, stackswitchHandleEvent);
+
+ switch (event->type) {
+ case PropertyNotify:
+ if (event->xproperty.atom == XA_WM_NAME)
+ {
+ CompWindow *w;
+ w = findWindowAtDisplay (d, event->xproperty.window);
+ if (w)
+ {
+ STACKSWITCH_SCREEN (w->screen);
+ if (ss->grabIndex && (w->id == ss->selectedWindow))
+ {
+ stackswitchRenderWindowTitle (w->screen);
+ damageScreen (w->screen);
+ }
+ }
+ }
+ break;
+ case UnmapNotify:
+ stackswitchWindowRemove (d, event->xunmap.window);
+ break;
+ case DestroyNotify:
+ stackswitchWindowRemove (d, event->xdestroywindow.window);
+ break;
+ }
+}
+
+static Bool
+stackswitchDamageWindowRect (CompWindow *w,
+ Bool initial,
+ BoxPtr rect)
+{
+ Bool status = FALSE;
+ CompScreen *s = w->screen;
+
+ STACKSWITCH_SCREEN (s);
+
+ if (initial)
+ {
+ if (ss->grabIndex && isStackswitchWin (w))
+ {
+ stackswitchAddWindowToList (s, w);
+ if (stackswitchUpdateWindowList (s))
+ {
+ STACKSWITCH_WINDOW (w);
+
+ sw->adjust = TRUE;
+ ss->moreAdjust = TRUE;
+ ss->state = StackswitchStateOut;
+ damageScreen (s);
+ }
+ }
+ }
+ else if (ss->state == StackswitchStateSwitching)
+ {
+ STACKSWITCH_WINDOW (w);
+
+ if (sw->slot)
+ {
+ damageScreen (s);
+ status = TRUE;
+ }
+ }
+
+ UNWRAP (ss, s, damageWindowRect);
+ status |= (*s->damageWindowRect) (w, initial, rect);
+ WRAP (ss, s, damageWindowRect, stackswitchDamageWindowRect);
+
+ return status;
+}
+
+static Bool
+stackswitchInitDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ StackswitchDisplay *sd;
+
+ if (!checkPluginABI ("core", CORE_ABIVERSION))
+ return FALSE;
+
+ sd = malloc (sizeof (StackswitchDisplay));
+ if (!sd)
+ return FALSE;
+
+ sd->screenPrivateIndex = allocateScreenPrivateIndex (d);
+ if (sd->screenPrivateIndex < 0)
+ {
+ free (sd);
+ return FALSE;
+ }
+
+ sd->textAvailable = checkPluginABI ("text", TEXT_ABIVERSION);
+ if (!sd->textAvailable)
+ compLogMessage (d, "stackswitch", CompLogLevelWarn,
+ "No compatible text plugin found.");
+
+ stackswitchSetNextKeyInitiate (d, stackswitchNext);
+ stackswitchSetNextKeyTerminate (d, stackswitchTerminate);
+ stackswitchSetPrevKeyInitiate (d, stackswitchPrev);
+ stackswitchSetPrevKeyTerminate (d, stackswitchTerminate);
+ stackswitchSetNextAllKeyInitiate (d, stackswitchNextAll);
+ stackswitchSetNextAllKeyTerminate (d, stackswitchTerminate);
+ stackswitchSetPrevAllKeyInitiate (d, stackswitchPrevAll);
+ stackswitchSetPrevAllKeyTerminate (d, stackswitchTerminate);
+ stackswitchSetNextGroupKeyInitiate (d, stackswitchNextGroup);
+ stackswitchSetNextGroupKeyTerminate (d, stackswitchTerminate);
+ stackswitchSetPrevGroupKeyInitiate (d, stackswitchPrevGroup);
+ stackswitchSetPrevGroupKeyTerminate (d, stackswitchTerminate);
+
+ stackswitchSetNextButtonInitiate (d, stackswitchNext);
+ stackswitchSetNextButtonTerminate (d, stackswitchTerminate);
+ stackswitchSetPrevButtonInitiate (d, stackswitchPrev);
+ stackswitchSetPrevButtonTerminate (d, stackswitchTerminate);
+ stackswitchSetNextAllButtonInitiate (d, stackswitchNextAll);
+ stackswitchSetNextAllButtonTerminate (d, stackswitchTerminate);
+ stackswitchSetPrevAllButtonInitiate (d, stackswitchPrevAll);
+ stackswitchSetPrevAllButtonTerminate (d, stackswitchTerminate);
+ stackswitchSetNextGroupButtonInitiate (d, stackswitchNextGroup);
+ stackswitchSetNextGroupButtonTerminate (d, stackswitchTerminate);
+ stackswitchSetPrevGroupButtonInitiate (d, stackswitchPrevGroup);
+ stackswitchSetPrevGroupButtonTerminate (d, stackswitchTerminate);
+
+ WRAP (sd, d, handleEvent, stackswitchHandleEvent);
+
+ d->base.privates[StackswitchDisplayPrivateIndex].ptr = sd;
+
+ return TRUE;
+}
+
+static void
+stackswitchFiniDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ STACKSWITCH_DISPLAY (d);
+
+ freeScreenPrivateIndex (d, sd->screenPrivateIndex);
+
+ UNWRAP (sd, d, handleEvent);
+
+ free (sd);
+}
+
+static Bool
+stackswitchInitScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ StackswitchScreen *ss;
+
+ STACKSWITCH_DISPLAY (s->display);
+
+ ss = malloc (sizeof (StackswitchScreen));
+ if (!ss)
+ return FALSE;
+
+ ss->windowPrivateIndex = allocateWindowPrivateIndex (s);
+ if (ss->windowPrivateIndex < 0)
+ {
+ free (ss);
+ return FALSE;
+ }
+
+ ss->grabIndex = 0;
+
+ ss->state = StackswitchStateNone;
+
+ ss->windows = NULL;
+ ss->drawSlots = NULL;
+ ss->windowsSize = 0;
+
+ ss->paintingSwitcher = FALSE;
+
+ ss->selectedWindow = None;
+
+ ss->moreAdjust = FALSE;
+ ss->rotateAdjust = FALSE;
+
+ ss->rVelocity = 0;
+ ss->rotation = 0.0;
+
+ ss->textPixmap = None;
+
+ matchInit (&ss->match);
+
+ WRAP (ss, s, preparePaintScreen, stackswitchPreparePaintScreen);
+ WRAP (ss, s, donePaintScreen, stackswitchDonePaintScreen);
+ WRAP (ss, s, paintOutput, stackswitchPaintOutput);
+ WRAP (ss, s, paintWindow, stackswitchPaintWindow);
+ WRAP (ss, s, damageWindowRect, stackswitchDamageWindowRect);
+
+ s->base.privates[sd->screenPrivateIndex].ptr = ss;
+
+ return TRUE;
+}
+
+static void
+stackswitchFiniScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ STACKSWITCH_SCREEN (s);
+
+ freeWindowPrivateIndex (s, ss->windowPrivateIndex);
+
+ UNWRAP (ss, s, preparePaintScreen);
+ UNWRAP (ss, s, donePaintScreen);
+ UNWRAP (ss, s, paintOutput);
+ UNWRAP (ss, s, paintWindow);
+ UNWRAP (ss, s, damageWindowRect);
+
+ matchFini (&ss->match);
+
+ stackswitchFreeWindowTitle (s);
+
+ if (ss->windows)
+ free (ss->windows);
+
+ if (ss->drawSlots)
+ free (ss->drawSlots);
+
+ free (ss);
+}
+
+static Bool
+stackswitchInitWindow (CompPlugin *p,
+ CompWindow *w)
+{
+ StackswitchWindow *sw;
+
+ STACKSWITCH_SCREEN (w->screen);
+
+ sw = malloc (sizeof (StackswitchWindow));
+ if (!sw)
+ return FALSE;
+
+ sw->slot = 0;
+ sw->scale = 1.0f;
+ sw->tx = sw->ty = 0.0f;
+ sw->adjust = FALSE;
+ sw->xVelocity = sw->yVelocity = 0.0f;
+ sw->scaleVelocity = 0.0f;
+ sw->rotation = 0.0f;
+ sw->rotVelocity = 0.0f;
+
+ w->base.privates[ss->windowPrivateIndex].ptr = sw;
+
+ return TRUE;
+}
+
+static void
+stackswitchFiniWindow (CompPlugin *p,
+ CompWindow *w)
+{
+ STACKSWITCH_WINDOW (w);
+
+ if (sw->slot)
+ free (sw->slot);
+
+ free (sw);
+}
+
+static CompBool
+stackswitchInitObject (CompPlugin *p,
+ CompObject *o)
+{
+ static InitPluginObjectProc dispTab[] = {
+ (InitPluginObjectProc) 0, /* InitCore */
+ (InitPluginObjectProc) stackswitchInitDisplay,
+ (InitPluginObjectProc) stackswitchInitScreen,
+ (InitPluginObjectProc) stackswitchInitWindow
+ };
+
+ RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
+}
+
+static void
+stackswitchFiniObject (CompPlugin *p,
+ CompObject *o)
+{
+ static FiniPluginObjectProc dispTab[] = {
+ (FiniPluginObjectProc) 0, /* FiniCore */
+ (FiniPluginObjectProc) stackswitchFiniDisplay,
+ (FiniPluginObjectProc) stackswitchFiniScreen,
+ (FiniPluginObjectProc) stackswitchFiniWindow
+ };
+
+ DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
+}
+
+static Bool
+stackswitchInit (CompPlugin *p)
+{
+ StackswitchDisplayPrivateIndex = allocateDisplayPrivateIndex ();
+ if (StackswitchDisplayPrivateIndex < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+stackswitchFini (CompPlugin *p)
+{
+ freeDisplayPrivateIndex (StackswitchDisplayPrivateIndex);
+}
+
+CompPluginVTable stackswitchVTable = {
+ "stackswitch",
+ 0,
+ stackswitchInit,
+ stackswitchFini,
+ stackswitchInitObject,
+ stackswitchFiniObject,
+ 0,
+ 0
+};
+
+CompPluginVTable *
+getCompPluginInfo (void)
+{
+ return &stackswitchVTable;
+}
diff --git a/stackswitch.xml.in b/stackswitch.xml.in
new file mode 100644
index 0000000..d8000f8
--- /dev/null
+++ b/stackswitch.xml.in
@@ -0,0 +1,189 @@
+<?xml version="1.0"?>
+<compiz>
+ <plugin name="stackswitch" useBcop="true">
+ <_short>Stack Window Switcher</_short>
+ <_long>Stack Window Switcher</_long>
+ <category>Window Management</category>
+ <deps>
+ <relation type="after">
+ <plugin>text</plugin>
+ </relation>
+ </deps>
+ <display>
+ <group>
+ <_short>Key bindings</_short>
+ <option name="next_key" type="key">
+ <_short>Next Window</_short>
+ <_long>Show switcher if not visible and select next window.</_long>
+ <default>&lt;Super&gt;Tab</default>
+ </option>
+ <option name="next_button" type="button">
+ <_short>Next Window</_short>
+ <_long>Show switcher if not visible and select next window.</_long>
+ </option>
+ <option name="prev_key" type="key">
+ <_short>Previous Window</_short>
+ <_long>Show switcher if not visible and select previous window.</_long>
+ <default>&lt;Super&gt;&lt;Shift&gt;Tab</default>
+ </option>
+ <option name="prev_button" type="button">
+ <_short>Previous Window</_short>
+ <_long>Show switcher if not visible and select previous window.</_long>
+ </option>
+ <option name="next_all_key" type="key">
+ <_short>Next Window (All Workspaces)</_short>
+ <_long>Show switcher if not visible and select next window out of all windows.</_long>
+ <default>&lt;Super&gt;&lt;Alt&gt;Tab</default>
+ </option>
+ <option name="next_all_button" type="button">
+ <_short>Next Window (All Workspaces)</_short>
+ <_long>Show switcher if not visible and select next window out of all windows.</_long>
+ </option>
+ <option name="prev_all_key" type="key">
+ <_short>Previous Window (All Workspaces)</_short>
+ <_long>Show switcher if not visible and select previous window out of all windows.</_long>
+ <default>&lt;Super&gt;&lt;Shift&gt;&lt;Alt&gt;Tab</default>
+ </option>
+ <option name="prev_all_button" type="button">
+ <_short>Previous Window (All Workspaces)</_short>
+ <_long>Show switcher if not visible and select previous window out of all windows.</_long>
+ </option>
+ <option name="next_group_key" type="key">
+ <_short>Next Window (Group)</_short>
+ <_long>Show switcher if not visible and select next window of the current application.</_long>
+ </option>
+ <option name="next_group_button" type="button">
+ <_short>Next Window (Group)</_short>
+ <_long>Show switcher if not visible and select next window of the current application.</_long>
+ </option>
+ <option name="prev_group_key" type="key">
+ <_short>Previous Window (Group)</_short>
+ <_long>Show switcher if not visible and select previous window of the current application.</_long>
+ </option>
+ <option name="prev_group_button" type="button">
+ <_short>Previous Window (Group)</_short>
+ <_long>Show switcher if not visible and select previous window of the current application.</_long>
+ </option>
+ </group>
+ </display>
+ <screen>
+ <group>
+ <_short>Behavior</_short>
+ <option name="speed" type="float">
+ <_short>Speed</_short>
+ <_long>Animation speed</_long>
+ <default>1.5</default>
+ <min>0.1</min>
+ <max>50.0</max>
+ <precision>0.1</precision>
+ </option>
+ <option name="timestep" type="float">
+ <_short>Timestep</_short>
+ <_long>Animation timestep</_long>
+ <default>1.2</default>
+ <min>0.1</min>
+ <max>50.0</max>
+ <precision>0.1</precision>
+ </option>
+ <option name="inactive_opacity" type="int">
+ <_short>Inactive Window Opacity</_short>
+ <_long>Amount of opacity (in percent) for windows in the switcher which are not selected</_long>
+ <default>100</default>
+ <min>1</min>
+ <max>100</max>
+ </option>
+ <option name="inactive_rotate" type="bool">
+ <_short>Rotate inactive windows</_short>
+ <_long>Should not selected windows be rotated</_long>
+ <default>true</default>
+ </option>
+ <option name="window_match" type="match">
+ <_short>Windows</_short>
+ <_long>Windows that should be shown in the switcher</_long>
+ <default>Normal | Dialog | ModalDialog | Utility | Unknown</default>
+ </option>
+ <option name="darken_back" type="bool">
+ <_short>Darken Background</_short>
+ <_long>Darken background when showing the stack</_long>
+ <default>true</default>
+ </option>
+ <option name="minimized" type="bool">
+ <_short>Show Minimized</_short>
+ <_long>Show windows that are minimized, shaded or in show desktop mode.</_long>
+ <default>true</default>
+ </option>
+ <option name="rotation" type="int">
+ <_short>Rotation</_short>
+ <_long>Rotation angle.</_long>
+ <default>30</default>
+ <min>0</min>
+ <max>90</max>
+ </option>
+ </group>
+ <group>
+ <_short>Window title display</_short>
+ <option name="window_title" type="bool">
+ <_short>Show Window Title</_short>
+ <_long>Show window title of currently selected window.</_long>
+ <default>true</default>
+ </option>
+ <option name="title_font_bold" type="bool">
+ <_short>Bold Font</_short>
+ <_long>Selects if the window title should be displayed in bold font or not.</_long>
+ <default>false</default>
+ </option>
+ <option name="title_font_size" type="int">
+ <_short>Font Size</_short>
+ <_long>Font size for the window title</_long>
+ <default>16</default>
+ <min>6</min>
+ <max>96</max>
+ </option>
+ <option name="title_back_color" type="color">
+ <_short>Background Color</_short>
+ <_long>Background color for the window title</_long>
+ <default>
+ <red>0x0000</red>
+ <green>0x0000</green>
+ <blue>0x0000</blue>
+ <alpha>0x9999</alpha>
+ </default>
+ </option>
+ <option name="title_font_color" type="color">
+ <_short>Font Color</_short>
+ <_long>Font color for the window title</_long>
+ <default>
+ <red>0xffff</red>
+ <green>0xffff</green>
+ <blue>0xffff</blue>
+ <alpha>0xffff</alpha>
+ </default>
+ </option>
+ <option name="title_text_placement" type="int">
+ <_short>Text Placement</_short>
+ <_long>Selects where to place the window title.</_long>
+ <default>0</default>
+ <min>0</min>
+ <max>3</max>
+ <desc>
+ <value>0</value>
+ <_name>On Thumbnail</_name>
+ </desc>
+
+ <desc>
+ <value>1</value>
+ <_name>Centered on screen</_name>
+ </desc>
+ <desc>
+ <value>2</value>
+ <_name>Above</_name>
+ </desc>
+ <desc>
+ <value>3</value>
+ <_name>Below</_name>
+ </desc>
+ </option>
+ </group>
+ </screen>
+ </plugin>
+</compiz>