diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 463 | ||||
-rw-r--r-- | plugin.info | 2 | ||||
-rw-r--r-- | session.c | 878 | ||||
-rw-r--r-- | session.xml.in | 17 |
5 files changed, 1361 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e1835ab --- /dev/null +++ b/Makefile @@ -0,0 +1,463 @@ +## +# +# 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 +# + +#load config file +include plugin.info + + +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 + +ECHO = `which echo` + +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 ) + +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 $(PLUGIN).h ]; then $(ECHO) "$(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 += $(shell pkg-config --variable=includedir compiz)/compiz/compiz.h + +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) + +# default color settings +color := $(shell if [ $$TERM = "dumb" ]; then $(ECHO) "no"; else $(ECHO) "yes"; fi) + +# +# 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); \ + cp $(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; \ + cp $(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; \ + cp $(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; \ + gconftool-2 --install-schema-file=$(schema-output) > /dev/null; \ + 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; \ + cp 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; \ + cp 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 "$(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/plugin.info b/plugin.info new file mode 100644 index 0000000..2298638 --- /dev/null +++ b/plugin.info @@ -0,0 +1,2 @@ +PLUGIN = session +PKG_DEP = libxml-2.0 diff --git a/session.c b/session.c new file mode 100644 index 0000000..0762743 --- /dev/null +++ b/session.c @@ -0,0 +1,878 @@ +/** + * + * Compiz session plugin + * + * session.c + * + * Copyright (c) 2007 Travis Watkins <amaranth@ubuntu.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. + * + **/ + +#define _GNU_SOURCE +#include <X11/Xatom.h> + +#include <compiz.h> + +#include <stdlib.h> +#include <stdio.h> +#include <poll.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <pwd.h> +#include <X11/SM/SMlib.h> +#include <X11/ICE/ICElib.h> +#include <libxml/xmlmemory.h> +#include <libxml/parser.h> +#include <libxml/xpath.h> + +#define SM_DEBUG(x) + +#define XDG_DATA_DEFAULT ".local/share" + +static SmcConn smcConnection; +static CompWatchFdHandle iceWatchFdHandle; +static Bool connected = 0; +static Bool iceConnected = 0; +static char *smClientId; + +static void iceInit (void); + +static int displayPrivateIndex; + +typedef void (* SessionWindowFunc) (CompWindow *w, char *clientId, char *name, + void *user_data); + +typedef struct _SessionDisplay +{ + Atom visibleNameAtom; + Atom clientIdAtom; + Atom embedInfoAtom; +} SessionDisplay; + +#define GET_SESSION_DISPLAY(d) \ + ((SessionDisplay *) (d)->privates[displayPrivateIndex].ptr) + +#define SESSION_DISPLAY(d) \ + SessionDisplay *sd = GET_SESSION_DISPLAY (d) + +static char* +sessionGetUtf8Property (CompDisplay *d, + Window id, + Atom atom) +{ + Atom type; + int format; + unsigned long nitems; + unsigned long bytesAfter; + char *val; + int result; + char *retval; + + result = XGetWindowProperty (d->display, id, atom, 0L, 65536, False, + d->utf8StringAtom, &type, &format, &nitems, + &bytesAfter, (unsigned char **)&val); + + if (result != Success) + return NULL; + + if (type != d->utf8StringAtom || format != 8 || nitems == 0) + { + if (val) + XFree (val); + return NULL; + } + + retval = strndup (val, nitems); + XFree (val); + + return retval; +} + +static char* +sessionGetTextProperty (CompDisplay *d, + Window id, + Atom atom) +{ + XTextProperty text; + char *retval = NULL; + + text.nitems = 0; + if (XGetTextProperty (d->display, id, &text, atom)) + { + if (text.value) { + retval = strndup ((char *)text.value,text.nitems); + XFree (text.value); + } + } + + return retval; +} + +static char* +sessionGetWindowName (CompDisplay *d, + Window id) +{ + char *name; + + SESSION_DISPLAY (d); + + name = sessionGetUtf8Property (d, id, sd->visibleNameAtom); + + if (!name) + name = sessionGetUtf8Property(d, id, d->wmNameAtom); + + if (!name) + name = sessionGetTextProperty (d, id, XA_WM_NAME); + + return name; +} + +static Bool +sessionGetIsEmbedded (CompDisplay *d, Window id) +{ + SESSION_DISPLAY (d); + Atom actual_type_return; + int actual_format_return; + unsigned long nitems_return; + unsigned long bytes_after_return; + unsigned char *prop_return = 0; + if (XGetWindowProperty(d->display, id, sd->embedInfoAtom, 0, 2, + FALSE, XA_CARDINAL, &actual_type_return, + &actual_format_return, &nitems_return, + &bytes_after_return, &prop_return) == Success) + { + if (nitems_return > 1) + return TRUE; + } + return FALSE; +} + +static char* +sessionGetClientId (CompWindow *w) +{ + SESSION_DISPLAY (w->screen->display); + Window clientLeader; + char *clientId; + XTextProperty text; + text.nitems = 0; + + clientId = NULL; + clientLeader = w->clientLeader; + + if (clientLeader == w->id) + return NULL; + + //try to find clientLeader on transient parents + if (clientLeader == None) + { + CompWindow *window; + window = w; + while (window->transientFor != None) + { + if (window->transientFor == window->id) + break; + + window = findWindowAtScreen (w->screen, window->transientFor); + if (window->clientLeader != None) + { + clientLeader = window->clientLeader; + break; + } + } + } + + if (clientLeader != None) + { + if (XGetTextProperty (w->screen->display->display, clientLeader, &text, + sd->clientIdAtom)) + { + if (text.value) { + clientId = strndup ((char *)text.value, text.nitems); + XFree (text.value); + } + } + } + else + { + //some apps set SM_CLIENT_ID on the app + if (XGetTextProperty (w->screen->display->display, w->id, &text, + sd->clientIdAtom)) + { + if (text.value) { + clientId = strndup ((char *)text.value, text.nitems); + XFree (text.value); + } + } + } + return clientId; +} + +static int +sessionGetIntForProp (xmlNodePtr node, char *prop) +{ + xmlChar *temp; + int num; + + temp = xmlGetProp (node, BAD_CAST prop); + if (temp != NULL) + { + num = xmlXPathCastStringToNumber (temp); + xmlFree (temp); + return num; + } + return 0; +} + +static void +sessionForeachWindow (CompDisplay *d, SessionWindowFunc func, void *user_data) +{ + CompScreen *s; + CompWindow *w; + char *clientId; + char *name; + + for (s = d->screens; s; s = s->next) + { + for (w = s->windows; w; w = w->next) + { + //filter out embedded windows (notification icons) + if (sessionGetIsEmbedded (d, w->id)) + continue; + + clientId = sessionGetClientId (w); + + if (clientId == NULL) + continue; + + name = sessionGetWindowName (d, w->id); + + (* func) (w, clientId, name, user_data); + } + } +} + +static void +sessionWriteWindow (CompWindow *w, char *clientId, char *name, void *user_data) +{ + FILE *outfile = (FILE*) user_data; + + fprintf (outfile, " <window id=\"%s\" title=\"%s\" class=\"%s\" name=\"%s\">\n", + clientId, + name ? name : "", + w->resClass ? w->resClass : "", + w->resName ? w->resName : ""); + + //save sticky + if (w->state & CompWindowStateStickyMask || + w->type & CompWindowTypeDesktopMask || + w->type & CompWindowTypeDockMask) + fprintf (outfile, " <sticky/>\n"); + + //save minimized + if (w->minimized) + fprintf (outfile, " <minimized/>\n"); + + //save maximized + if (w->state & MAXIMIZE_STATE) + fprintf (outfile, " <maximized/>\n"); + + //save workspace + if (!(w->type & CompWindowTypeDesktopMask || + w->type & CompWindowTypeDockMask)) + fprintf (outfile, " <workspace index=\"%d\"/>\n", + w->desktop); + + //save geometry + fprintf (outfile, " <geometry x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n", + w->serverX, w->serverY, w->width, w->height); + + fprintf (outfile, " </window>\n"); +} + +/** + * Implementation of mkdir -p. Create the directory given by @path, creating + * the whole directory tree if necessary. + * + * @param path: The absolute path to be created, not `/` terminated + * @param mode: The permissions given to newly created directories + * @return: True if the directory given by @path now exists + * + * TODO: It doesn't check if EEXIST means the directory exists or that it's a + * file. It should return FALSE if a file exists with the name we want. +**/ + +static Bool mkdirp(const char *path, mode_t mode) +{ + char *partialPath; + char *delim; + Bool success; + + success = !mkdir (path, mode); /* Mkdir returns 0 on success */ + success |= (errno == EEXIST); /* We don't care if the directory is + already there */ + if (!success && (errno == ENOENT)) /* ENOENT means we must recursively */ + { /* create the parent's parent */ + delim = strrchr (path, '/'); + if (!delim) + return FALSE; /* Input string is not a valid absolue path! */ + + partialPath = malloc (delim - path + 1); + if (!partialPath) + return FALSE; + + strncpy (partialPath, path, delim - path); + partialPath[delim - path] = '\0'; + + if (mkdirp (partialPath, mode)); + success = !mkdir (path, mode); + + free (partialPath); + } + return success; +} + +/** + * Get absolute path to the session file directory. + * @param buffer: Buffer to place path in + * @param size: Size of the buffer + * @return: buffer + */ +static char * +getSessionFilePath (char *buffer, size_t size) +{ + char *xdgDir; + struct passwd *p = getpwuid(geteuid()); + + //setup filename and create directories as needed + buffer[0] = '\0'; + if ((xdgDir = getenv ("XDG_DATA_HOME"))) + { + strncat (buffer, xdgDir, size); + } + else + { + strncat (buffer, p->pw_dir, size); + strncat (buffer, "/", size); + strncat (buffer, XDG_DATA_DEFAULT, size); + } + strncat (buffer, "/compiz/session", size); + return buffer; +} + +static void +saveState (CompDisplay *d) +{ + char filename[1024]; + FILE *outfile; + + getSessionFilePath(filename, 1024); + if (mkdirp (filename, 0700)) + { + strncat (filename, "/", 1024); + strncat (filename, smClientId, 1024); + } + else + { + return; + } + + outfile = fopen (filename, "w"); + if (outfile == NULL) + { + return; + } + + fprintf (outfile, "<compiz_session id=\"%s\">\n", smClientId); + + sessionForeachWindow (d, sessionWriteWindow, outfile); + + fprintf (outfile, "</compiz_session>\n"); + fclose (outfile); +} + +static void +sessionReadWindow (CompWindow *w, char *clientId, char *name, void *user_data) +{ + xmlNodePtr cur; + xmlChar *newName; + xmlChar *newClientId; + Bool foundWindow = FALSE; + xmlNodePtr root = (xmlNodePtr) user_data; + + if (clientId == NULL) + return; + + for (cur = root->xmlChildrenNode; cur; cur = cur->next) + { + if (xmlStrcmp (cur->name, BAD_CAST "window") == 0) + { + newClientId = xmlGetProp (cur, BAD_CAST "id"); + if (newClientId != NULL) + { + if (clientId == (char*) newClientId) + { + foundWindow = TRUE; + break; + } + xmlFree (newClientId); + } + + newName = xmlGetProp (cur, BAD_CAST "name"); + if (newName != NULL) + { + if (name == (char*) newName) + { + foundWindow = TRUE; + break; + } + xmlFree (newName); + } + } + } + + if (foundWindow) + { + printf ("found window\n"); + for (cur = cur->xmlChildrenNode; cur; cur = cur->next) + { + if (xmlStrcmp (cur->name, BAD_CAST "geometry") == 0) + { + double x, y, width, height; + + x = sessionGetIntForProp (cur, "x"); + y = sessionGetIntForProp (cur, "y"); + width = sessionGetIntForProp (cur, "width"); + height = sessionGetIntForProp (cur, "height"); + + resizeWindow (w, x, y, width, height, 0); + } + } + } +} + +static void +loadState (CompDisplay *d, char *previousId) +{ + xmlDocPtr doc; + xmlNodePtr root; + char filename[1024]; + + getSessionFilePath (filename, 1024); + strncat (filename, "/", 1024); + strncat (filename, previousId, 1024); + + doc = xmlParseFile (filename); + if (doc == NULL) + return; + + root = xmlDocGetRootElement (doc); + if (root == NULL) + goto out; + + if (xmlStrcmp (root->name, BAD_CAST "compiz_session") != 0) + goto out; + + sessionForeachWindow (d, sessionReadWindow, root); + + out: + xmlFreeDoc(doc); + xmlCleanupParser(); +} + + + + +static void +setCloneRestartCommands (SmcConn connection) +{ + char *restartv[10]; + char *clonev[10]; + SmProp prop1, prop2, *props[2]; + int i; + + prop1.name = SmRestartCommand; + prop1.type = SmLISTofARRAY8; + + i = 0; + restartv[i] = "compiz"; + ++i; + restartv[i] = "--sm-client-id"; + ++i; + restartv[i] = smClientId; + ++i; + restartv[i] = NULL; + + prop1.vals = malloc (i * sizeof (SmPropValue)); + if (!prop1.vals) + return; + + i = 0; + while (restartv[i]) + { + prop1.vals[i].value = restartv[i]; + prop1.vals[i].length = strlen (restartv[i]); + ++i; + } + prop1.num_vals = i; + + + prop2.name = SmCloneCommand; + prop2.type = SmLISTofARRAY8; + + i = 0; + clonev[i] = "compiz"; + ++i; + clonev[i] = NULL; + + prop2.vals = malloc (i * sizeof (SmPropValue)); + if (!prop2.vals) + return; + + i = 0; + while (clonev[i]) + { + prop2.vals[i].value = clonev[i]; + prop2.vals[i].length = strlen (clonev[i]); + ++i; + } + prop2.num_vals = i; + + + props[0] = &prop1; + props[1] = &prop2; + + SmcSetProperties (connection, 2, props); +} + +static void +setRestartStyle (SmcConn connection, char hint) +{ + SmProp prop, *pProp; + SmPropValue propVal; + + prop.name = SmRestartStyleHint; + prop.type = SmCARD8; + prop.num_vals = 1; + prop.vals = &propVal; + propVal.value = &hint; + propVal.length = 1; + + pProp = ∝ + + SmcSetProperties (connection, 1, &pProp); +} + +static void +saveYourselfGotProps (SmcConn connection, + SmPointer client_data, + int num_props, + SmProp **props) +{ + setRestartStyle (connection, SmRestartIfRunning); + setCloneRestartCommands (connection); + SmcSaveYourselfDone (connection, 1); +} + +static void +saveYourselfCallback (SmcConn connection, + SmPointer client_data, + int saveType, + Bool shutdown, + int interact_Style, + Bool fast) +{ + saveState ((CompDisplay*) client_data); + + if (!SmcGetProperties (connection, saveYourselfGotProps, NULL)) + SmcSaveYourselfDone (connection, 1); +} + +static void +dieCallback (SmcConn connection, + SmPointer clientData) +{ + closeSession (); + exit (0); +} + +static void +saveCompleteCallback (SmcConn connection, + SmPointer clientData) +{ +} + +static void +shutdownCancelledCallback (SmcConn connection, + SmPointer clientData) +{ +} + +static void +initSession2 (CompDisplay *d, char *smPrevClientId) +{ + static SmcCallbacks callbacks; + + if (getenv ("SESSION_MANAGER")) + { + char errorBuffer[1024]; + + iceInit (); + + callbacks.save_yourself.callback = saveYourselfCallback; + callbacks.save_yourself.client_data = d; + + callbacks.die.callback = dieCallback; + callbacks.die.client_data = NULL; + + callbacks.save_complete.callback = saveCompleteCallback; + callbacks.save_complete.client_data = NULL; + + callbacks.shutdown_cancelled.callback = shutdownCancelledCallback; + callbacks.shutdown_cancelled.client_data = NULL; + + smcConnection = SmcOpenConnection (NULL, + NULL, + SmProtoMajor, + SmProtoMinor, + SmcSaveYourselfProcMask | + SmcDieProcMask | + SmcSaveCompleteProcMask | + SmcShutdownCancelledProcMask, + &callbacks, + smPrevClientId, + &smClientId, + sizeof (errorBuffer), + errorBuffer); + if (!smcConnection) + compLogMessage (NULL, "session", CompLogLevelWarn, + "SmcOpenConnection failed: %s", + errorBuffer); + else + connected = TRUE; + } +} + +void +closeSession (void) +{ + if (connected) + { + setRestartStyle (smcConnection, SmRestartIfRunning); + + if (SmcCloseConnection (smcConnection, 0, NULL) != SmcConnectionInUse) + connected = FALSE; + if (smClientId) { + free (smClientId); + smClientId = NULL; + } + } +} + +/* ice connection handling taken and updated from gnome-ice.c + * original gnome-ice.c code written by Tom Tromey <tromey@cygnus.com> + */ + +/* This is called when data is available on an ICE connection. */ +static Bool +iceProcessMessages (void *data) +{ + IceConn connection = (IceConn) data; + IceProcessMessagesStatus status; + + SM_DEBUG (printf ("ICE connection process messages\n")); + + status = IceProcessMessages (connection, NULL, NULL); + + if (status == IceProcessMessagesIOError) + { + SM_DEBUG (printf ("ICE connection process messages" + " - error => shutting down the connection\n")); + + IceSetShutdownNegotiation (connection, False); + IceCloseConnection (connection); + } + + return 1; +} + +/* This is called when a new ICE connection is made. It arranges for + the ICE connection to be handled via the event loop. */ +static void +iceNewConnection (IceConn connection, + IcePointer clientData, + Bool opening, + IcePointer *watchData) +{ + if (opening) + { + SM_DEBUG (printf ("ICE connection opening\n")); + + /* Make sure we don't pass on these file descriptors to any + exec'ed children */ + fcntl (IceConnectionNumber (connection), F_SETFD, + fcntl (IceConnectionNumber (connection), + F_GETFD,0) | FD_CLOEXEC); + + iceWatchFdHandle = compAddWatchFd (IceConnectionNumber (connection), + POLLIN | POLLPRI | POLLHUP | POLLERR, + iceProcessMessages, connection); + + iceConnected = 1; + } + else + { + SM_DEBUG (printf ("ICE connection closing\n")); + + if (iceConnected) + { + compRemoveWatchFd (iceWatchFdHandle); + + iceWatchFdHandle = 0; + iceConnected = 0; + } + } +} + +static IceIOErrorHandler oldIceHandler; + +static void +iceErrorHandler (IceConn connection) +{ + if (oldIceHandler) + (*oldIceHandler) (connection); +} + +/* We call any handler installed before (or after) iceInit but + avoid calling the default libICE handler which does an exit() */ +static void +iceInit (void) +{ + static Bool iceInitialized = 0; + + if (!iceInitialized) + { + IceIOErrorHandler defaultIceHandler; + + oldIceHandler = IceSetIOErrorHandler (NULL); + defaultIceHandler = IceSetIOErrorHandler (iceErrorHandler); + + if (oldIceHandler == defaultIceHandler) + oldIceHandler = NULL; + + IceAddConnectionWatch (iceNewConnection, NULL); + + iceInitialized = 1; + } +} + + + + +static int +sessionGetVersion(CompPlugin * p, + int version) +{ + return ABIVERSION; +} + +static int +sessionInit (CompPlugin *p) +{ + displayPrivateIndex = allocateDisplayPrivateIndex (); + if (displayPrivateIndex < 0) + return FALSE; + + return TRUE; +} + +static void +sessionFini (CompPlugin *p) +{ + freeDisplayPrivateIndex(displayPrivateIndex); +} + +static int +sessionInitDisplay (CompPlugin *p, CompDisplay *d) +{ + SessionDisplay *sd; + int i; + char *previousId = NULL; + + sd = malloc (sizeof (SessionDisplay)); + if (!sd) + return FALSE; + + d->privates[displayPrivateIndex].ptr = sd; + + sd->visibleNameAtom = XInternAtom (d->display, + "_NET_WM_VISIBLE_NAME", 0); + sd->clientIdAtom = XInternAtom (d->display, + "SM_CLIENT_ID", 0); + sd->embedInfoAtom = XInternAtom (d->display, + "_XEMBED_INFO", 0); + + for (i = 0; i < programArgc; i++) + { + if (strcmp(programArgv[i], "--sm-client-id") == 0) + { + i++; + printf ("%s\n", programArgv[i]); + previousId = malloc (strlen (programArgv[i]) + 1); + previousId = strdup (programArgv[i]); + break; + } + } + + initSession2 (d, previousId); + + if (previousId != NULL) + loadState (d, previousId); + + return TRUE; +} + +static void +sessionFiniDisplay (CompPlugin *p, CompDisplay *d) +{ + SESSION_DISPLAY (d); + closeSession (); + free (sd); +} + +static CompPluginVTable sessionVTable = +{ + "session", + sessionGetVersion, + 0, + sessionInit, + sessionFini, + sessionInitDisplay, + sessionFiniDisplay, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 +}; + +CompPluginVTable * getCompPluginInfo(void) +{ + return &sessionVTable; +} + diff --git a/session.xml.in b/session.xml.in new file mode 100644 index 0000000..c2ecc2e --- /dev/null +++ b/session.xml.in @@ -0,0 +1,17 @@ +<compiz> + <plugin name="session"> + <deps> + <relation type="before"> + <plugin>ccp</plugin> + <plugin>gconf</plugin> + <plugin>kconfig</plugin> + </relation> + </deps> + <_short>Session Management</_short> + <_long>Talk to session manager and save/load window state</_long> + <category>Utility</category> + </plugin> +</compiz> + + + |