summaryrefslogtreecommitdiff
path: root/plugins/xrandr
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/xrandr')
-rw-r--r--plugins/xrandr/Makefile.am76
-rw-r--r--plugins/xrandr/Makefile.in711
-rw-r--r--plugins/xrandr/gsd-xrandr-16.pngbin0 -> 613 bytes
-rw-r--r--plugins/xrandr/gsd-xrandr-22.pngbin0 -> 866 bytes
-rw-r--r--plugins/xrandr/gsd-xrandr-24.pngbin0 -> 909 bytes
-rw-r--r--plugins/xrandr/gsd-xrandr-32.pngbin0 -> 1602 bytes
-rw-r--r--plugins/xrandr/gsd-xrandr-manager.c2584
-rw-r--r--plugins/xrandr/gsd-xrandr-manager.h61
-rw-r--r--plugins/xrandr/gsd-xrandr-manager.xml23
-rw-r--r--plugins/xrandr/gsd-xrandr-plugin.c104
-rw-r--r--plugins/xrandr/gsd-xrandr-plugin.h63
-rw-r--r--plugins/xrandr/gsd-xrandr.svg470
-rw-r--r--plugins/xrandr/xrandr.mate-settings-plugin.in8
13 files changed, 4100 insertions, 0 deletions
diff --git a/plugins/xrandr/Makefile.am b/plugins/xrandr/Makefile.am
new file mode 100644
index 0000000..b7d8684
--- /dev/null
+++ b/plugins/xrandr/Makefile.am
@@ -0,0 +1,76 @@
+icondir = $(datadir)/icons/mate
+context = apps
+
+BUILT_SOURCES = \
+ gsd-xrandr-manager-glue.h
+
+ICON_FILES = \
+ gsd-xrandr-16.png \
+ gsd-xrandr-22.png \
+ gsd-xrandr-24.png \
+ gsd-xrandr-32.png \
+ gsd-xrandr.svg
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(sysconfdir)/mate-settings-daemon/xrandr
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/16x16/$(context)
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/22x22/$(context)
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/24x24/$(context)
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/32x32/$(context)
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/scalable/$(context)
+ $(INSTALL_DATA) $(srcdir)/gsd-xrandr-16.png $(DESTDIR)$(icondir)/16x16/$(context)/gsd-xrandr.png
+ $(INSTALL_DATA) $(srcdir)/gsd-xrandr-22.png $(DESTDIR)$(icondir)/22x22/$(context)/gsd-xrandr.png
+ $(INSTALL_DATA) $(srcdir)/gsd-xrandr-24.png $(DESTDIR)$(icondir)/24x24/$(context)/gsd-xrandr.png
+ $(INSTALL_DATA) $(srcdir)/gsd-xrandr-32.png $(DESTDIR)$(icondir)/32x32/$(context)/gsd-xrandr.png
+ $(INSTALL_DATA) $(srcdir)/gsd-xrandr.svg $(DESTDIR)$(icondir)/scalable/$(context)/gsd-xrandr.svg
+
+uninstall-local:
+ rm -f $(DESTDIR)$(icondir)/16x16/$(context)/gsd-xrandr.png
+ rm -f $(DESTDIR)$(icondir)/22x22/$(context)/gsd-xrandr.png
+ rm -f $(DESTDIR)$(icondir)/24x24/$(context)/gsd-xrandr.png
+ rm -f $(DESTDIR)$(icondir)/32x32/$(context)/gsd-xrandr.png
+ rm -f $(DESTDIR)$(icondir)/scalable/$(context)/gsd-xrandr.svg
+
+plugin_LTLIBRARIES = \
+ libxrandr.la
+
+gsd-xrandr-manager-glue.h: gsd-xrandr-manager.xml Makefile
+ dbus-binding-tool --prefix=gsd_xrandr_manager --mode=glib-server $< > xgen-$(@F) \
+ && ( cmp -s xgen-$(@F) $@ || cp xgen-$(@F) $@ ) \
+ && rm -f xgen-$(@F)
+
+libxrandr_la_SOURCES = \
+ $(BUILT_SOURCES) \
+ gsd-xrandr-plugin.h \
+ gsd-xrandr-plugin.c \
+ gsd-xrandr-manager.h \
+ gsd-xrandr-manager.c
+
+libxrandr_la_CPPFLAGS = \
+ -I$(top_srcdir)/mate-settings-daemon \
+ -DBINDIR=\"$(bindir)\" \
+ -DMATE_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+ $(AM_CPPFLAGS)
+
+libxrandr_la_CFLAGS = \
+ $(SETTINGS_PLUGIN_CFLAGS) \
+ $(LIBMATENOTIFY_CFLAGS) \
+ $(AM_CFLAGS)
+
+libxrandr_la_LDFLAGS = \
+ $(GSD_PLUGIN_LDFLAGS)
+
+libxrandr_la_LIBADD = \
+ $(SETTINGS_PLUGIN_LIBS) \
+ $(LIBMATENOTIFY_LIBS)
+
+plugin_in_files = \
+ xrandr.mate-settings-plugin.in
+
+plugin_DATA = $(plugin_in_files:.mate-settings-plugin.in=.mate-settings-plugin)
+
+EXTRA_DIST = $(plugin_in_files) $(ICON_FILES) gsd-xrandr-manager.xml
+CLEANFILES = $(plugin_DATA) $(BUILT_SOURCES)
+DISTCLEANFILES = $(plugin_DATA)
+
+@GSD_INTLTOOL_PLUGIN_RULE@
diff --git a/plugins/xrandr/Makefile.in b/plugins/xrandr/Makefile.in
new file mode 100644
index 0000000..ba8edc4
--- /dev/null
+++ b/plugins/xrandr/Makefile.in
@@ -0,0 +1,711 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = plugins/xrandr
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libxrandr_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am__objects_1 =
+am_libxrandr_la_OBJECTS = $(am__objects_1) \
+ libxrandr_la-gsd-xrandr-plugin.lo \
+ libxrandr_la-gsd-xrandr-manager.lo
+libxrandr_la_OBJECTS = $(am_libxrandr_la_OBJECTS)
+libxrandr_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libxrandr_la_CFLAGS) \
+ $(CFLAGS) $(libxrandr_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libxrandr_la_SOURCES)
+DIST_SOURCES = $(libxrandr_la_SOURCES)
+DATA = $(plugin_DATA)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DBUS_SYS_DIR = @DBUS_SYS_DIR@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
+FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIOUNIX_CFLAGS = @GIOUNIX_CFLAGS@
+GIOUNIX_LIBS = @GIOUNIX_LIBS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GREP = @GREP@
+GSD_INTLTOOL_PLUGIN_RULE = @GSD_INTLTOOL_PLUGIN_RULE@
+GSD_PLUGIN_LDFLAGS = @GSD_PLUGIN_LDFLAGS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBEXECDIR = @LIBEXECDIR@
+LIBMATEKBDUI_CFLAGS = @LIBMATEKBDUI_CFLAGS@
+LIBMATEKBDUI_LIBS = @LIBMATEKBDUI_LIBS@
+LIBMATENOTIFY_CFLAGS = @LIBMATENOTIFY_CFLAGS@
+LIBMATENOTIFY_LIBS = @LIBMATENOTIFY_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MATECONFTOOL = @MATECONFTOOL@
+MATECONF_SCHEMA_CONFIG_SOURCE = @MATECONF_SCHEMA_CONFIG_SOURCE@
+MATECONF_SCHEMA_FILE_DIR = @MATECONF_SCHEMA_FILE_DIR@
+MATE_KEYBINDINGS_KEYSDIR = @MATE_KEYBINDINGS_KEYSDIR@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_DATABASE = @NSS_DATABASE@
+NSS_LIBS = @NSS_LIBS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POFILES = @POFILES@
+POLKIT_CFLAGS = @POLKIT_CFLAGS@
+POLKIT_LIBS = @POLKIT_LIBS@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SETTINGS_DAEMON_CFLAGS = @SETTINGS_DAEMON_CFLAGS@
+SETTINGS_DAEMON_LIBS = @SETTINGS_DAEMON_LIBS@
+SETTINGS_PLUGIN_CFLAGS = @SETTINGS_PLUGIN_CFLAGS@
+SETTINGS_PLUGIN_LIBS = @SETTINGS_PLUGIN_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+X11_LIBS = @X11_LIBS@
+XF86MISC_LIBS = @XF86MISC_LIBS@
+XGETTEXT = @XGETTEXT@
+XINPUT_LIBS = @XINPUT_LIBS@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+icondir = $(datadir)/icons/mate
+context = apps
+BUILT_SOURCES = \
+ gsd-xrandr-manager-glue.h
+
+ICON_FILES = \
+ gsd-xrandr-16.png \
+ gsd-xrandr-22.png \
+ gsd-xrandr-24.png \
+ gsd-xrandr-32.png \
+ gsd-xrandr.svg
+
+plugin_LTLIBRARIES = \
+ libxrandr.la
+
+libxrandr_la_SOURCES = \
+ $(BUILT_SOURCES) \
+ gsd-xrandr-plugin.h \
+ gsd-xrandr-plugin.c \
+ gsd-xrandr-manager.h \
+ gsd-xrandr-manager.c
+
+libxrandr_la_CPPFLAGS = \
+ -I$(top_srcdir)/mate-settings-daemon \
+ -DBINDIR=\"$(bindir)\" \
+ -DMATE_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+ $(AM_CPPFLAGS)
+
+libxrandr_la_CFLAGS = \
+ $(SETTINGS_PLUGIN_CFLAGS) \
+ $(LIBMATENOTIFY_CFLAGS) \
+ $(AM_CFLAGS)
+
+libxrandr_la_LDFLAGS = \
+ $(GSD_PLUGIN_LDFLAGS)
+
+libxrandr_la_LIBADD = \
+ $(SETTINGS_PLUGIN_LIBS) \
+ $(LIBMATENOTIFY_LIBS)
+
+plugin_in_files = \
+ xrandr.mate-settings-plugin.in
+
+plugin_DATA = $(plugin_in_files:.mate-settings-plugin.in=.mate-settings-plugin)
+EXTRA_DIST = $(plugin_in_files) $(ICON_FILES) gsd-xrandr-manager.xml
+CLEANFILES = $(plugin_DATA) $(BUILT_SOURCES)
+DISTCLEANFILES = $(plugin_DATA)
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu plugins/xrandr/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu plugins/xrandr/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libxrandr.la: $(libxrandr_la_OBJECTS) $(libxrandr_la_DEPENDENCIES)
+ $(libxrandr_la_LINK) -rpath $(plugindir) $(libxrandr_la_OBJECTS) $(libxrandr_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxrandr_la-gsd-xrandr-manager.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxrandr_la-gsd-xrandr-plugin.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+libxrandr_la-gsd-xrandr-plugin.lo: gsd-xrandr-plugin.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxrandr_la_CPPFLAGS) $(CPPFLAGS) $(libxrandr_la_CFLAGS) $(CFLAGS) -MT libxrandr_la-gsd-xrandr-plugin.lo -MD -MP -MF $(DEPDIR)/libxrandr_la-gsd-xrandr-plugin.Tpo -c -o libxrandr_la-gsd-xrandr-plugin.lo `test -f 'gsd-xrandr-plugin.c' || echo '$(srcdir)/'`gsd-xrandr-plugin.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxrandr_la-gsd-xrandr-plugin.Tpo $(DEPDIR)/libxrandr_la-gsd-xrandr-plugin.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-xrandr-plugin.c' object='libxrandr_la-gsd-xrandr-plugin.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxrandr_la_CPPFLAGS) $(CPPFLAGS) $(libxrandr_la_CFLAGS) $(CFLAGS) -c -o libxrandr_la-gsd-xrandr-plugin.lo `test -f 'gsd-xrandr-plugin.c' || echo '$(srcdir)/'`gsd-xrandr-plugin.c
+
+libxrandr_la-gsd-xrandr-manager.lo: gsd-xrandr-manager.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxrandr_la_CPPFLAGS) $(CPPFLAGS) $(libxrandr_la_CFLAGS) $(CFLAGS) -MT libxrandr_la-gsd-xrandr-manager.lo -MD -MP -MF $(DEPDIR)/libxrandr_la-gsd-xrandr-manager.Tpo -c -o libxrandr_la-gsd-xrandr-manager.lo `test -f 'gsd-xrandr-manager.c' || echo '$(srcdir)/'`gsd-xrandr-manager.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxrandr_la-gsd-xrandr-manager.Tpo $(DEPDIR)/libxrandr_la-gsd-xrandr-manager.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-xrandr-manager.c' object='libxrandr_la-gsd-xrandr-manager.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxrandr_la_CPPFLAGS) $(CPPFLAGS) $(libxrandr_la_CFLAGS) $(CFLAGS) -c -o libxrandr_la-gsd-xrandr-manager.lo `test -f 'gsd-xrandr-manager.c' || echo '$(srcdir)/'`gsd-xrandr-manager.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pluginDATA: $(plugin_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_DATA)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(plugindir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(plugindir)" || exit $$?; \
+ done
+
+uninstall-pluginDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_DATA)'; test -n "$(plugindir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(plugindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(plugindir)" && rm -f $$files
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-data-local install-pluginDATA \
+ install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-local uninstall-pluginDATA \
+ uninstall-pluginLTLIBRARIES
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-data-local install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pluginDATA install-pluginLTLIBRARIES install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-local uninstall-pluginDATA \
+ uninstall-pluginLTLIBRARIES
+
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(sysconfdir)/mate-settings-daemon/xrandr
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/16x16/$(context)
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/22x22/$(context)
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/24x24/$(context)
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/32x32/$(context)
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/scalable/$(context)
+ $(INSTALL_DATA) $(srcdir)/gsd-xrandr-16.png $(DESTDIR)$(icondir)/16x16/$(context)/gsd-xrandr.png
+ $(INSTALL_DATA) $(srcdir)/gsd-xrandr-22.png $(DESTDIR)$(icondir)/22x22/$(context)/gsd-xrandr.png
+ $(INSTALL_DATA) $(srcdir)/gsd-xrandr-24.png $(DESTDIR)$(icondir)/24x24/$(context)/gsd-xrandr.png
+ $(INSTALL_DATA) $(srcdir)/gsd-xrandr-32.png $(DESTDIR)$(icondir)/32x32/$(context)/gsd-xrandr.png
+ $(INSTALL_DATA) $(srcdir)/gsd-xrandr.svg $(DESTDIR)$(icondir)/scalable/$(context)/gsd-xrandr.svg
+
+uninstall-local:
+ rm -f $(DESTDIR)$(icondir)/16x16/$(context)/gsd-xrandr.png
+ rm -f $(DESTDIR)$(icondir)/22x22/$(context)/gsd-xrandr.png
+ rm -f $(DESTDIR)$(icondir)/24x24/$(context)/gsd-xrandr.png
+ rm -f $(DESTDIR)$(icondir)/32x32/$(context)/gsd-xrandr.png
+ rm -f $(DESTDIR)$(icondir)/scalable/$(context)/gsd-xrandr.svg
+
+gsd-xrandr-manager-glue.h: gsd-xrandr-manager.xml Makefile
+ dbus-binding-tool --prefix=gsd_xrandr_manager --mode=glib-server $< > xgen-$(@F) \
+ && ( cmp -s xgen-$(@F) $@ || cp xgen-$(@F) $@ ) \
+ && rm -f xgen-$(@F)
+
+@GSD_INTLTOOL_PLUGIN_RULE@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/plugins/xrandr/gsd-xrandr-16.png b/plugins/xrandr/gsd-xrandr-16.png
new file mode 100644
index 0000000..f996ddf
--- /dev/null
+++ b/plugins/xrandr/gsd-xrandr-16.png
Binary files differ
diff --git a/plugins/xrandr/gsd-xrandr-22.png b/plugins/xrandr/gsd-xrandr-22.png
new file mode 100644
index 0000000..cc47eec
--- /dev/null
+++ b/plugins/xrandr/gsd-xrandr-22.png
Binary files differ
diff --git a/plugins/xrandr/gsd-xrandr-24.png b/plugins/xrandr/gsd-xrandr-24.png
new file mode 100644
index 0000000..49b4e12
--- /dev/null
+++ b/plugins/xrandr/gsd-xrandr-24.png
Binary files differ
diff --git a/plugins/xrandr/gsd-xrandr-32.png b/plugins/xrandr/gsd-xrandr-32.png
new file mode 100644
index 0000000..95de3ea
--- /dev/null
+++ b/plugins/xrandr/gsd-xrandr-32.png
Binary files differ
diff --git a/plugins/xrandr/gsd-xrandr-manager.c b/plugins/xrandr/gsd-xrandr-manager.c
new file mode 100644
index 0000000..b8d9c66
--- /dev/null
+++ b/plugins/xrandr/gsd-xrandr-manager.c
@@ -0,0 +1,2584 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <[email protected]>
+ * Copyright (C) 2007, 2008 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <locale.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+#include <dbus/dbus-glib.h>
+
+#define MATE_DESKTOP_USE_UNSTABLE_API
+
+#include <libmateui/mate-rr-config.h>
+#include <libmateui/mate-rr.h>
+#include <libmateui/mate-rr-labeler.h>
+
+#ifdef HAVE_LIBMATENOTIFY
+#include <libmatenotify/notify.h>
+#endif
+
+#include "mate-settings-profile.h"
+#include "gsd-xrandr-manager.h"
+
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 255
+#endif
+
+#define GSD_XRANDR_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_XRANDR_MANAGER, GsdXrandrManagerPrivate))
+
+#define CONF_DIR "/apps/mate_settings_daemon/xrandr"
+#define CONF_KEY_SHOW_NOTIFICATION_ICON (CONF_DIR "/show_notification_icon")
+#define CONF_KEY_TURN_ON_EXTERNAL_MONITORS_AT_STARTUP (CONF_DIR "/turn_on_external_monitors_at_startup")
+#define CONF_KEY_TURN_ON_LAPTOP_MONITOR_AT_STARTUP (CONF_DIR "/turn_on_laptop_monitor_at_startup")
+#define CONF_KEY_DEFAULT_CONFIGURATION_FILE (CONF_DIR "/default_configuration_file")
+
+#define VIDEO_KEYSYM "XF86Display"
+#define ROTATE_KEYSYM "XF86RotateWindows"
+
+/* Number of seconds that the confirmation dialog will last before it resets the
+ * RANDR configuration to its old state.
+ */
+#define CONFIRMATION_DIALOG_SECONDS 30
+
+/* name of the icon files (gsd-xrandr.svg, etc.) */
+#define GSD_XRANDR_ICON_NAME "gsd-xrandr"
+
+/* executable of the control center's display configuration capplet */
+#define GSD_XRANDR_DISPLAY_CAPPLET "mate-control-center display"
+
+#define GSD_DBUS_PATH "/org/mate/SettingsDaemon"
+#define GSD_DBUS_NAME "org.mate.SettingsDaemon"
+#define GSD_XRANDR_DBUS_PATH GSD_DBUS_PATH "/XRANDR"
+#define GSD_XRANDR_DBUS_NAME GSD_DBUS_NAME ".XRANDR"
+
+struct GsdXrandrManagerPrivate
+{
+ DBusGConnection *dbus_connection;
+
+ /* Key code of the XF86Display key (Fn-F7 on Thinkpads, Fn-F4 on HP machines, etc.) */
+ guint switch_video_mode_keycode;
+
+ /* Key code of the XF86RotateWindows key (present on some tablets) */
+ guint rotate_windows_keycode;
+
+ MateRRScreen *rw_screen;
+ gboolean running;
+
+ GtkStatusIcon *status_icon;
+ GtkWidget *popup_menu;
+ MateRRConfig *configuration;
+ MateRRLabeler *labeler;
+ MateConfClient *client;
+ int notify_id;
+
+ /* fn-F7 status */
+ int current_fn_f7_config; /* -1 if no configs */
+ MateRRConfig **fn_f7_configs; /* NULL terminated, NULL if there are no configs */
+
+ /* Last time at which we got a "screen got reconfigured" event; see on_randr_event() */
+ guint32 last_config_timestamp;
+};
+
+static const MateRRRotation possible_rotations[] = {
+ MATE_RR_ROTATION_0,
+ MATE_RR_ROTATION_90,
+ MATE_RR_ROTATION_180,
+ MATE_RR_ROTATION_270
+ /* We don't allow REFLECT_X or REFLECT_Y for now, as mate-display-properties doesn't allow them, either */
+};
+
+static void gsd_xrandr_manager_class_init (GsdXrandrManagerClass *klass);
+static void gsd_xrandr_manager_init (GsdXrandrManager *xrandr_manager);
+static void gsd_xrandr_manager_finalize (GObject *object);
+
+static void error_message (GsdXrandrManager *mgr, const char *primary_text, GError *error_to_display, const char *secondary_text);
+
+static void status_icon_popup_menu (GsdXrandrManager *manager, guint button, guint32 timestamp);
+static void run_display_capplet (GtkWidget *widget);
+static void get_allowed_rotations_for_output (MateRRConfig *config,
+ MateRRScreen *rr_screen,
+ MateOutputInfo *output,
+ int *out_num_rotations,
+ MateRRRotation *out_rotations);
+
+G_DEFINE_TYPE (GsdXrandrManager, gsd_xrandr_manager, G_TYPE_OBJECT)
+
+static gpointer manager_object = NULL;
+
+static FILE *log_file;
+
+static void
+log_open (void)
+{
+ char *toggle_filename;
+ char *log_filename;
+ struct stat st;
+
+ if (log_file)
+ return;
+
+ toggle_filename = g_build_filename (g_get_home_dir (), "gsd-debug-randr", NULL);
+ log_filename = g_build_filename (g_get_home_dir (), "gsd-debug-randr.log", NULL);
+
+ if (stat (toggle_filename, &st) != 0)
+ goto out;
+
+ log_file = fopen (log_filename, "a");
+
+ if (log_file && ftell (log_file) == 0)
+ fprintf (log_file, "To keep this log from being created, please rm ~/gsd-debug-randr\n");
+
+out:
+ g_free (toggle_filename);
+ g_free (log_filename);
+}
+
+static void
+log_close (void)
+{
+ if (log_file) {
+ fclose (log_file);
+ log_file = NULL;
+ }
+}
+
+static void
+log_msg (const char *format, ...)
+{
+ if (log_file) {
+ va_list args;
+
+ va_start (args, format);
+ vfprintf (log_file, format, args);
+ va_end (args);
+ }
+}
+
+static void
+log_output (MateOutputInfo *output)
+{
+ log_msg (" %s: ", output->name ? output->name : "unknown");
+
+ if (output->connected) {
+ if (output->on) {
+ log_msg ("%dx%d@%d +%d+%d",
+ output->width,
+ output->height,
+ output->rate,
+ output->x,
+ output->y);
+ } else
+ log_msg ("off");
+ } else
+ log_msg ("disconnected");
+
+ if (output->display_name)
+ log_msg (" (%s)", output->display_name);
+
+ if (output->primary)
+ log_msg (" (primary output)");
+
+ log_msg ("\n");
+}
+
+static void
+log_configuration (MateRRConfig *config)
+{
+ int i;
+
+ log_msg (" cloned: %s\n", config->clone ? "yes" : "no");
+
+ for (i = 0; config->outputs[i] != NULL; i++)
+ log_output (config->outputs[i]);
+
+ if (i == 0)
+ log_msg (" no outputs!\n");
+}
+
+static char
+timestamp_relationship (guint32 a, guint32 b)
+{
+ if (a < b)
+ return '<';
+ else if (a > b)
+ return '>';
+ else
+ return '=';
+}
+
+static void
+log_screen (MateRRScreen *screen)
+{
+ MateRRConfig *config;
+ int min_w, min_h, max_w, max_h;
+ guint32 change_timestamp, config_timestamp;
+
+ if (!log_file)
+ return;
+
+ config = mate_rr_config_new_current (screen);
+
+ mate_rr_screen_get_ranges (screen, &min_w, &max_w, &min_h, &max_h);
+ mate_rr_screen_get_timestamps (screen, &change_timestamp, &config_timestamp);
+
+ log_msg (" Screen min(%d, %d), max(%d, %d), change=%u %c config=%u\n",
+ min_w, min_h,
+ max_w, max_h,
+ change_timestamp,
+ timestamp_relationship (change_timestamp, config_timestamp),
+ config_timestamp);
+
+ log_configuration (config);
+ mate_rr_config_free (config);
+}
+
+static void
+log_configurations (MateRRConfig **configs)
+{
+ int i;
+
+ if (!configs) {
+ log_msg (" No configurations\n");
+ return;
+ }
+
+ for (i = 0; configs[i]; i++) {
+ log_msg (" Configuration %d\n", i);
+ log_configuration (configs[i]);
+ }
+}
+
+static void
+show_timestamps_dialog (GsdXrandrManager *manager, const char *msg)
+{
+#if 1
+ return;
+#else
+ struct GsdXrandrManagerPrivate *priv = manager->priv;
+ GtkWidget *dialog;
+ guint32 change_timestamp, config_timestamp;
+ static int serial;
+
+ mate_rr_screen_get_timestamps (priv->rw_screen, &change_timestamp, &config_timestamp);
+
+ dialog = gtk_message_dialog_new (NULL,
+ 0,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CLOSE,
+ "RANDR timestamps (%d):\n%s\nchange: %u\nconfig: %u",
+ serial++,
+ msg,
+ change_timestamp,
+ config_timestamp);
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+ gtk_widget_show (dialog);
+#endif
+}
+
+/* This function centralizes the use of mate_rr_config_apply_from_filename_with_time().
+ *
+ * Optionally filters out MATE_RR_ERROR_NO_MATCHING_CONFIG from
+ * mate_rr_config_apply_from_filename_with_time(), since that is not usually an error.
+ */
+static gboolean
+apply_configuration_from_filename (GsdXrandrManager *manager,
+ const char *filename,
+ gboolean no_matching_config_is_an_error,
+ guint32 timestamp,
+ GError **error)
+{
+ struct GsdXrandrManagerPrivate *priv = manager->priv;
+ GError *my_error;
+ gboolean success;
+ char *str;
+
+ str = g_strdup_printf ("Applying %s with timestamp %d", filename, timestamp);
+ show_timestamps_dialog (manager, str);
+ g_free (str);
+
+ my_error = NULL;
+ success = mate_rr_config_apply_from_filename_with_time (priv->rw_screen, filename, timestamp, &my_error);
+ if (success)
+ return TRUE;
+
+ if (g_error_matches (my_error, MATE_RR_ERROR, MATE_RR_ERROR_NO_MATCHING_CONFIG)) {
+ if (no_matching_config_is_an_error)
+ goto fail;
+
+ /* This is not an error; the user probably changed his monitors
+ * and so they don't match any of the stored configurations.
+ */
+ g_error_free (my_error);
+ return TRUE;
+ }
+
+fail:
+ g_propagate_error (error, my_error);
+ return FALSE;
+}
+
+/* This function centralizes the use of mate_rr_config_apply_with_time().
+ *
+ * Applies a configuration and displays an error message if an error happens.
+ * We just return whether setting the configuration succeeded.
+ */
+static gboolean
+apply_configuration_and_display_error (GsdXrandrManager *manager, MateRRConfig *config, guint32 timestamp)
+{
+ GsdXrandrManagerPrivate *priv = manager->priv;
+ GError *error;
+ gboolean success;
+
+ error = NULL;
+ success = mate_rr_config_apply_with_time (config, priv->rw_screen, timestamp, &error);
+ if (!success) {
+ log_msg ("Could not switch to the following configuration (timestamp %u): %s\n", timestamp, error->message);
+ log_configuration (config);
+ error_message (manager, _("Could not switch the monitor configuration"), error, NULL);
+ g_error_free (error);
+ }
+
+ return success;
+}
+
+static void
+restore_backup_configuration_without_messages (const char *backup_filename, const char *intended_filename)
+{
+ backup_filename = mate_rr_config_get_backup_filename ();
+ rename (backup_filename, intended_filename);
+}
+
+static void
+restore_backup_configuration (GsdXrandrManager *manager, const char *backup_filename, const char *intended_filename, guint32 timestamp)
+{
+ int saved_errno;
+
+ if (rename (backup_filename, intended_filename) == 0) {
+ GError *error;
+
+ error = NULL;
+ if (!apply_configuration_from_filename (manager, intended_filename, FALSE, timestamp, &error)) {
+ error_message (manager, _("Could not restore the display's configuration"), error, NULL);
+
+ if (error)
+ g_error_free (error);
+ }
+
+ return;
+ }
+
+ saved_errno = errno;
+
+ /* ENOENT means the original file didn't exist. That is *not* an error;
+ * the backup was not created because there wasn't even an original
+ * monitors.xml (such as on a first-time login). Note that *here* there
+ * is a "didn't work" monitors.xml, so we must delete that one.
+ */
+ if (saved_errno == ENOENT)
+ unlink (intended_filename);
+ else {
+ char *msg;
+
+ msg = g_strdup_printf ("Could not rename %s to %s: %s",
+ backup_filename, intended_filename,
+ g_strerror (saved_errno));
+ error_message (manager,
+ _("Could not restore the display's configuration from a backup"),
+ NULL,
+ msg);
+ g_free (msg);
+ }
+
+ unlink (backup_filename);
+}
+
+typedef struct {
+ GsdXrandrManager *manager;
+ GtkWidget *dialog;
+
+ int countdown;
+ int response_id;
+} TimeoutDialog;
+
+static void
+print_countdown_text (TimeoutDialog *timeout)
+{
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (timeout->dialog),
+ ngettext ("The display will be reset to its previous configuration in %d second",
+ "The display will be reset to its previous configuration in %d seconds",
+ timeout->countdown),
+ timeout->countdown);
+}
+
+static gboolean
+timeout_cb (gpointer data)
+{
+ TimeoutDialog *timeout = data;
+
+ timeout->countdown--;
+
+ if (timeout->countdown == 0) {
+ timeout->response_id = GTK_RESPONSE_CANCEL;
+ gtk_main_quit ();
+ } else {
+ print_countdown_text (timeout);
+ }
+
+ return TRUE;
+}
+
+static void
+timeout_response_cb (GtkDialog *dialog, int response_id, gpointer data)
+{
+ TimeoutDialog *timeout = data;
+
+ if (response_id == GTK_RESPONSE_DELETE_EVENT) {
+ /* The user closed the dialog or pressed ESC, revert */
+ timeout->response_id = GTK_RESPONSE_CANCEL;
+ } else
+ timeout->response_id = response_id;
+
+ gtk_main_quit ();
+}
+
+static gboolean
+user_says_things_are_ok (GsdXrandrManager *manager, GdkWindow *parent_window)
+{
+ TimeoutDialog timeout;
+ guint timeout_id;
+
+ timeout.manager = manager;
+
+ timeout.dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ _("Does the display look OK?"));
+
+ timeout.countdown = CONFIRMATION_DIALOG_SECONDS;
+
+ print_countdown_text (&timeout);
+
+ gtk_dialog_add_button (GTK_DIALOG (timeout.dialog), _("_Restore Previous Configuration"), GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_button (GTK_DIALOG (timeout.dialog), _("_Keep This Configuration"), GTK_RESPONSE_ACCEPT);
+ gtk_dialog_set_default_response (GTK_DIALOG (timeout.dialog), GTK_RESPONSE_ACCEPT); /* ah, the optimism */
+
+ g_signal_connect (timeout.dialog, "response",
+ G_CALLBACK (timeout_response_cb),
+ &timeout);
+
+ gtk_widget_realize (timeout.dialog);
+
+ if (parent_window)
+ gdk_window_set_transient_for (gtk_widget_get_window (timeout.dialog), parent_window);
+
+ gtk_widget_show_all (timeout.dialog);
+ /* We don't use g_timeout_add_seconds() since we actually care that the user sees "real" second ticks in the dialog */
+ timeout_id = g_timeout_add (1000,
+ timeout_cb,
+ &timeout);
+ gtk_main ();
+
+ gtk_widget_destroy (timeout.dialog);
+ g_source_remove (timeout_id);
+
+ if (timeout.response_id == GTK_RESPONSE_ACCEPT)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+struct confirmation {
+ GsdXrandrManager *manager;
+ GdkWindow *parent_window;
+ guint32 timestamp;
+};
+
+static gboolean
+confirm_with_user_idle_cb (gpointer data)
+{
+ struct confirmation *confirmation = data;
+ char *backup_filename;
+ char *intended_filename;
+
+ backup_filename = mate_rr_config_get_backup_filename ();
+ intended_filename = mate_rr_config_get_intended_filename ();
+
+ if (user_says_things_are_ok (confirmation->manager, confirmation->parent_window))
+ unlink (backup_filename);
+ else
+ restore_backup_configuration (confirmation->manager, backup_filename, intended_filename, confirmation->timestamp);
+
+ g_free (confirmation);
+
+ return FALSE;
+}
+
+static void
+queue_confirmation_by_user (GsdXrandrManager *manager, GdkWindow *parent_window, guint32 timestamp)
+{
+ struct confirmation *confirmation;
+
+ confirmation = g_new (struct confirmation, 1);
+ confirmation->manager = manager;
+ confirmation->parent_window = parent_window;
+ confirmation->timestamp = timestamp;
+
+ g_idle_add (confirm_with_user_idle_cb, confirmation);
+}
+
+static gboolean
+try_to_apply_intended_configuration (GsdXrandrManager *manager, GdkWindow *parent_window, guint32 timestamp, GError **error)
+{
+ char *backup_filename;
+ char *intended_filename;
+ gboolean result;
+
+ /* Try to apply the intended configuration */
+
+ backup_filename = mate_rr_config_get_backup_filename ();
+ intended_filename = mate_rr_config_get_intended_filename ();
+
+ result = apply_configuration_from_filename (manager, intended_filename, FALSE, timestamp, error);
+ if (!result) {
+ error_message (manager, _("The selected configuration for displays could not be applied"), error ? *error : NULL, NULL);
+ restore_backup_configuration_without_messages (backup_filename, intended_filename);
+ goto out;
+ } else {
+ /* We need to return as quickly as possible, so instead of
+ * confirming with the user right here, we do it in an idle
+ * handler. The caller only expects a status for "could you
+ * change the RANDR configuration?", not "is the user OK with it
+ * as well?".
+ */
+ queue_confirmation_by_user (manager, parent_window, timestamp);
+ }
+
+out:
+ g_free (backup_filename);
+ g_free (intended_filename);
+
+ return result;
+}
+
+/* DBus method for org.mate.SettingsDaemon.XRANDR ApplyConfiguration; see gsd-xrandr-manager.xml for the interface definition */
+static gboolean
+gsd_xrandr_manager_apply_configuration (GsdXrandrManager *manager,
+ GError **error)
+{
+ return try_to_apply_intended_configuration (manager, NULL, GDK_CURRENT_TIME, error);
+}
+
+/* DBus method for org.mate.SettingsDaemon.XRANDR_2 ApplyConfiguration; see gsd-xrandr-manager.xml for the interface definition */
+static gboolean
+gsd_xrandr_manager_2_apply_configuration (GsdXrandrManager *manager,
+ gint64 parent_window_id,
+ gint64 timestamp,
+ GError **error)
+{
+ GdkWindow *parent_window;
+ gboolean result;
+
+ if (parent_window_id != 0)
+ parent_window = gdk_window_foreign_new_for_display (gdk_display_get_default (), (GdkNativeWindow) parent_window_id);
+ else
+ parent_window = NULL;
+
+ result = try_to_apply_intended_configuration (manager, parent_window, (guint32) timestamp, error);
+
+ if (parent_window)
+ g_object_unref (parent_window);
+
+ return result;
+}
+
+/* We include this after the definition of gsd_xrandr_manager_apply_configuration() so the prototype will already exist */
+#include "gsd-xrandr-manager-glue.h"
+
+static gboolean
+is_laptop (MateRRScreen *screen, MateOutputInfo *output)
+{
+ MateRROutput *rr_output;
+
+ rr_output = mate_rr_screen_get_output_by_name (screen, output->name);
+ return mate_rr_output_is_laptop (rr_output);
+}
+
+static gboolean
+get_clone_size (MateRRScreen *screen, int *width, int *height)
+{
+ MateRRMode **modes = mate_rr_screen_list_clone_modes (screen);
+ int best_w, best_h;
+ int i;
+
+ best_w = 0;
+ best_h = 0;
+
+ for (i = 0; modes[i] != NULL; ++i) {
+ MateRRMode *mode = modes[i];
+ int w, h;
+
+ w = mate_rr_mode_get_width (mode);
+ h = mate_rr_mode_get_height (mode);
+
+ if (w * h > best_w * best_h) {
+ best_w = w;
+ best_h = h;
+ }
+ }
+
+ if (best_w > 0 && best_h > 0) {
+ if (width)
+ *width = best_w;
+ if (height)
+ *height = best_h;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+print_output (MateOutputInfo *info)
+{
+ g_print (" Output: %s attached to %s\n", info->display_name, info->name);
+ g_print (" status: %s\n", info->on ? "on" : "off");
+ g_print (" width: %d\n", info->width);
+ g_print (" height: %d\n", info->height);
+ g_print (" rate: %d\n", info->rate);
+ g_print (" position: %d %d\n", info->x, info->y);
+}
+
+static void
+print_configuration (MateRRConfig *config, const char *header)
+{
+ int i;
+
+ g_print ("=== %s Configuration ===\n", header);
+ if (!config) {
+ g_print (" none\n");
+ return;
+ }
+
+ for (i = 0; config->outputs[i] != NULL; ++i)
+ print_output (config->outputs[i]);
+}
+
+static gboolean
+config_is_all_off (MateRRConfig *config)
+{
+ int j;
+
+ for (j = 0; config->outputs[j] != NULL; ++j) {
+ if (config->outputs[j]->on) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static MateRRConfig *
+make_clone_setup (MateRRScreen *screen)
+{
+ MateRRConfig *result;
+ int width, height;
+ int i;
+
+ if (!get_clone_size (screen, &width, &height))
+ return NULL;
+
+ result = mate_rr_config_new_current (screen);
+
+ for (i = 0; result->outputs[i] != NULL; ++i) {
+ MateOutputInfo *info = result->outputs[i];
+
+ info->on = FALSE;
+ if (info->connected) {
+ MateRROutput *output =
+ mate_rr_screen_get_output_by_name (screen, info->name);
+ MateRRMode **modes = mate_rr_output_list_modes (output);
+ int j;
+ int best_rate = 0;
+
+ for (j = 0; modes[j] != NULL; ++j) {
+ MateRRMode *mode = modes[j];
+ int w, h;
+
+ w = mate_rr_mode_get_width (mode);
+ h = mate_rr_mode_get_height (mode);
+
+ if (w == width && h == height) {
+ int r = mate_rr_mode_get_freq (mode);
+ if (r > best_rate)
+ best_rate = r;
+ }
+ }
+
+ if (best_rate > 0) {
+ info->on = TRUE;
+ info->width = width;
+ info->height = height;
+ info->rate = best_rate;
+ info->rotation = MATE_RR_ROTATION_0;
+ info->x = 0;
+ info->y = 0;
+ }
+ }
+ }
+
+ if (config_is_all_off (result)) {
+ mate_rr_config_free (result);
+ result = NULL;
+ }
+
+ print_configuration (result, "clone setup");
+
+ return result;
+}
+
+static MateRRMode *
+find_best_mode (MateRROutput *output)
+{
+ MateRRMode *preferred;
+ MateRRMode **modes;
+ int best_size;
+ int best_width, best_height, best_rate;
+ int i;
+ MateRRMode *best_mode;
+
+ preferred = mate_rr_output_get_preferred_mode (output);
+ if (preferred)
+ return preferred;
+
+ modes = mate_rr_output_list_modes (output);
+ if (!modes)
+ return NULL;
+
+ best_size = best_width = best_height = best_rate = 0;
+ best_mode = NULL;
+
+ for (i = 0; modes[i] != NULL; i++) {
+ int w, h, r;
+ int size;
+
+ w = mate_rr_mode_get_width (modes[i]);
+ h = mate_rr_mode_get_height (modes[i]);
+ r = mate_rr_mode_get_freq (modes[i]);
+
+ size = w * h;
+
+ if (size > best_size) {
+ best_size = size;
+ best_width = w;
+ best_height = h;
+ best_rate = r;
+ best_mode = modes[i];
+ } else if (size == best_size) {
+ if (r > best_rate) {
+ best_rate = r;
+ best_mode = modes[i];
+ }
+ }
+ }
+
+ return best_mode;
+}
+
+static gboolean
+turn_on (MateRRScreen *screen,
+ MateOutputInfo *info,
+ int x, int y)
+{
+ MateRROutput *output = mate_rr_screen_get_output_by_name (screen, info->name);
+ MateRRMode *mode = find_best_mode (output);
+
+ if (mode) {
+ info->on = TRUE;
+ info->x = x;
+ info->y = y;
+ info->width = mate_rr_mode_get_width (mode);
+ info->height = mate_rr_mode_get_height (mode);
+ info->rotation = MATE_RR_ROTATION_0;
+ info->rate = mate_rr_mode_get_freq (mode);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static MateRRConfig *
+make_laptop_setup (MateRRScreen *screen)
+{
+ /* Turn on the laptop, disable everything else */
+ MateRRConfig *result = mate_rr_config_new_current (screen);
+ int i;
+
+ for (i = 0; result->outputs[i] != NULL; ++i) {
+ MateOutputInfo *info = result->outputs[i];
+
+ if (is_laptop (screen, info)) {
+ if (!turn_on (screen, info, 0, 0)) {
+ mate_rr_config_free (result);
+ result = NULL;
+ break;
+ }
+ }
+ else {
+ info->on = FALSE;
+ }
+ }
+
+ if (config_is_all_off (result)) {
+ mate_rr_config_free (result);
+ result = NULL;
+ }
+
+ print_configuration (result, "Laptop setup");
+
+ /* FIXME - Maybe we should return NULL if there is more than
+ * one connected "laptop" screen?
+ */
+ return result;
+
+}
+
+static int
+turn_on_and_get_rightmost_offset (MateRRScreen *screen, MateOutputInfo *info, int x)
+{
+ if (turn_on (screen, info, x, 0))
+ x += info->width;
+
+ return x;
+}
+
+static MateRRConfig *
+make_xinerama_setup (MateRRScreen *screen)
+{
+ /* Turn on everything that has a preferred mode, and
+ * position it from left to right
+ */
+ MateRRConfig *result = mate_rr_config_new_current (screen);
+ int i;
+ int x;
+
+ x = 0;
+ for (i = 0; result->outputs[i] != NULL; ++i) {
+ MateOutputInfo *info = result->outputs[i];
+
+ if (is_laptop (screen, info))
+ x = turn_on_and_get_rightmost_offset (screen, info, x);
+ }
+
+ for (i = 0; result->outputs[i] != NULL; ++i) {
+ MateOutputInfo *info = result->outputs[i];
+
+ if (info->connected && !is_laptop (screen, info))
+ x = turn_on_and_get_rightmost_offset (screen, info, x);
+ }
+
+ if (config_is_all_off (result)) {
+ mate_rr_config_free (result);
+ result = NULL;
+ }
+
+ print_configuration (result, "xinerama setup");
+
+ return result;
+}
+
+static MateRRConfig *
+make_other_setup (MateRRScreen *screen)
+{
+ /* Turn off all laptops, and make all external monitors clone
+ * from (0, 0)
+ */
+
+ MateRRConfig *result = mate_rr_config_new_current (screen);
+ int i;
+
+ for (i = 0; result->outputs[i] != NULL; ++i) {
+ MateOutputInfo *info = result->outputs[i];
+
+ if (is_laptop (screen, info)) {
+ info->on = FALSE;
+ }
+ else {
+ if (info->connected)
+ turn_on (screen, info, 0, 0);
+ }
+ }
+
+ if (config_is_all_off (result)) {
+ mate_rr_config_free (result);
+ result = NULL;
+ }
+
+ print_configuration (result, "other setup");
+
+ return result;
+}
+
+static GPtrArray *
+sanitize (GsdXrandrManager *manager, GPtrArray *array)
+{
+ int i;
+ GPtrArray *new;
+
+ g_debug ("before sanitizing");
+
+ for (i = 0; i < array->len; ++i) {
+ if (array->pdata[i]) {
+ print_configuration (array->pdata[i], "before");
+ }
+ }
+
+
+ /* Remove configurations that are duplicates of
+ * configurations earlier in the cycle
+ */
+ for (i = 0; i < array->len; i++) {
+ int j;
+
+ for (j = i + 1; j < array->len; j++) {
+ MateRRConfig *this = array->pdata[j];
+ MateRRConfig *other = array->pdata[i];
+
+ if (this && other && mate_rr_config_equal (this, other)) {
+ g_debug ("removing duplicate configuration");
+ mate_rr_config_free (this);
+ array->pdata[j] = NULL;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < array->len; ++i) {
+ MateRRConfig *config = array->pdata[i];
+
+ if (config && config_is_all_off (config)) {
+ g_debug ("removing configuration as all outputs are off");
+ mate_rr_config_free (array->pdata[i]);
+ array->pdata[i] = NULL;
+ }
+ }
+
+ /* Do a final sanitization pass. This will remove configurations that
+ * don't fit in the framebuffer's Virtual size.
+ */
+
+ for (i = 0; i < array->len; i++) {
+ MateRRConfig *config = array->pdata[i];
+
+ if (config) {
+ GError *error;
+
+ error = NULL;
+ if (!mate_rr_config_applicable (config, manager->priv->rw_screen, &error)) { /* NULL-GError */
+ g_debug ("removing configuration which is not applicable because %s", error->message);
+ g_error_free (error);
+
+ mate_rr_config_free (config);
+ array->pdata[i] = NULL;
+ }
+ }
+ }
+
+ /* Remove NULL configurations */
+ new = g_ptr_array_new ();
+
+ for (i = 0; i < array->len; ++i) {
+ if (array->pdata[i]) {
+ g_ptr_array_add (new, array->pdata[i]);
+ print_configuration (array->pdata[i], "Final");
+ }
+ }
+
+ if (new->len > 0) {
+ g_ptr_array_add (new, NULL);
+ } else {
+ g_ptr_array_free (new, TRUE);
+ new = NULL;
+ }
+
+ g_ptr_array_free (array, TRUE);
+
+ return new;
+}
+
+static void
+generate_fn_f7_configs (GsdXrandrManager *mgr)
+{
+ GPtrArray *array = g_ptr_array_new ();
+ MateRRScreen *screen = mgr->priv->rw_screen;
+
+ g_debug ("Generating configurations");
+
+ /* Free any existing list of configurations */
+ if (mgr->priv->fn_f7_configs) {
+ int i;
+
+ for (i = 0; mgr->priv->fn_f7_configs[i] != NULL; ++i)
+ mate_rr_config_free (mgr->priv->fn_f7_configs[i]);
+ g_free (mgr->priv->fn_f7_configs);
+
+ mgr->priv->fn_f7_configs = NULL;
+ mgr->priv->current_fn_f7_config = -1;
+ }
+
+ g_ptr_array_add (array, mate_rr_config_new_current (screen));
+ g_ptr_array_add (array, make_clone_setup (screen));
+ g_ptr_array_add (array, make_xinerama_setup (screen));
+ g_ptr_array_add (array, make_laptop_setup (screen));
+ g_ptr_array_add (array, make_other_setup (screen));
+
+ array = sanitize (mgr, array);
+
+ if (array) {
+ mgr->priv->fn_f7_configs = (MateRRConfig **)g_ptr_array_free (array, FALSE);
+ mgr->priv->current_fn_f7_config = 0;
+ }
+}
+
+static void
+error_message (GsdXrandrManager *mgr, const char *primary_text, GError *error_to_display, const char *secondary_text)
+{
+#ifdef HAVE_LIBMATENOTIFY
+ GsdXrandrManagerPrivate *priv = mgr->priv;
+ NotifyNotification *notification;
+
+ g_assert (error_to_display == NULL || secondary_text == NULL);
+
+ if (priv->status_icon)
+ notification = notify_notification_new_with_status_icon (primary_text,
+ error_to_display ? error_to_display->message : secondary_text,
+ GSD_XRANDR_ICON_NAME,
+ priv->status_icon);
+ else
+ notification = notify_notification_new (primary_text,
+ error_to_display ? error_to_display->message : secondary_text,
+ GSD_XRANDR_ICON_NAME,
+ NULL);
+
+ notify_notification_show (notification, NULL); /* NULL-GError */
+#else
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+ "%s", primary_text);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s",
+ error_to_display ? error_to_display->message : secondary_text);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+#endif /* HAVE_LIBMATENOTIFY */
+}
+
+static void
+handle_fn_f7 (GsdXrandrManager *mgr, guint32 timestamp)
+{
+ GsdXrandrManagerPrivate *priv = mgr->priv;
+ MateRRScreen *screen = priv->rw_screen;
+ MateRRConfig *current;
+ GError *error;
+
+ /* Theory of fn-F7 operation
+ *
+ * We maintain a datastructure "fn_f7_status", that contains
+ * a list of MateRRConfig's. Each of the MateRRConfigs has a
+ * mode (or "off") for each connected output.
+ *
+ * When the user hits fn-F7, we cycle to the next MateRRConfig
+ * in the data structure. If the data structure does not exist, it
+ * is generated. If the configs in the data structure do not match
+ * the current hardware reality, it is regenerated.
+ *
+ */
+ g_debug ("Handling fn-f7");
+
+ log_open ();
+ log_msg ("Handling XF86Display hotkey - timestamp %u\n", timestamp);
+
+ error = NULL;
+ if (!mate_rr_screen_refresh (screen, &error) && error) {
+ char *str;
+
+ str = g_strdup_printf (_("Could not refresh the screen information: %s"), error->message);
+ g_error_free (error);
+
+ log_msg ("%s\n", str);
+ error_message (mgr, str, NULL, _("Trying to switch the monitor configuration anyway."));
+ g_free (str);
+ }
+
+ if (!priv->fn_f7_configs) {
+ log_msg ("Generating stock configurations:\n");
+ generate_fn_f7_configs (mgr);
+ log_configurations (priv->fn_f7_configs);
+ }
+
+ current = mate_rr_config_new_current (screen);
+
+ if (priv->fn_f7_configs &&
+ (!mate_rr_config_match (current, priv->fn_f7_configs[0]) ||
+ !mate_rr_config_equal (current, priv->fn_f7_configs[mgr->priv->current_fn_f7_config]))) {
+ /* Our view of the world is incorrect, so regenerate the
+ * configurations
+ */
+ generate_fn_f7_configs (mgr);
+ log_msg ("Regenerated stock configurations:\n");
+ log_configurations (priv->fn_f7_configs);
+ }
+
+ mate_rr_config_free (current);
+
+ if (priv->fn_f7_configs) {
+ guint32 server_timestamp;
+ gboolean success;
+
+ mgr->priv->current_fn_f7_config++;
+
+ if (priv->fn_f7_configs[mgr->priv->current_fn_f7_config] == NULL)
+ mgr->priv->current_fn_f7_config = 0;
+
+ g_debug ("cycling to next configuration (%d)", mgr->priv->current_fn_f7_config);
+
+ print_configuration (priv->fn_f7_configs[mgr->priv->current_fn_f7_config], "new config");
+
+ g_debug ("applying");
+
+ /* See https://bugzilla.gnome.org/show_bug.cgi?id=610482
+ *
+ * Sometimes we'll get two rapid XF86Display keypress events,
+ * but their timestamps will be out of order with respect to the
+ * RANDR timestamps. This *may* be due to stupid BIOSes sending
+ * out display-switch keystrokes "to make Windows work".
+ *
+ * The X server will error out if the timestamp provided is
+ * older than a previous change configuration timestamp. We
+ * assume here that we do want this event to go through still,
+ * since kernel timestamps may be skewed wrt the X server.
+ */
+ mate_rr_screen_get_timestamps (screen, NULL, &server_timestamp);
+ if (timestamp < server_timestamp)
+ timestamp = server_timestamp;
+
+ success = apply_configuration_and_display_error (mgr, priv->fn_f7_configs[mgr->priv->current_fn_f7_config], timestamp);
+
+ if (success) {
+ log_msg ("Successfully switched to configuration (timestamp %u):\n", timestamp);
+ log_configuration (priv->fn_f7_configs[mgr->priv->current_fn_f7_config]);
+ }
+ }
+ else {
+ g_debug ("no configurations generated");
+ }
+
+ log_close ();
+
+ g_debug ("done handling fn-f7");
+}
+
+static MateOutputInfo *
+get_laptop_output_info (MateRRScreen *screen, MateRRConfig *config)
+{
+ int i;
+
+ for (i = 0; config->outputs[i] != NULL; i++) {
+ MateOutputInfo *info;
+
+ info = config->outputs[i];
+ if (is_laptop (screen, info))
+ return info;
+ }
+
+ return NULL;
+
+}
+
+static MateRRRotation
+get_next_rotation (MateRRRotation allowed_rotations, MateRRRotation current_rotation)
+{
+ int i;
+ int current_index;
+
+ /* First, find the index of the current rotation */
+
+ current_index = -1;
+
+ for (i = 0; i < G_N_ELEMENTS (possible_rotations); i++) {
+ MateRRRotation r;
+
+ r = possible_rotations[i];
+ if (r == current_rotation) {
+ current_index = i;
+ break;
+ }
+ }
+
+ if (current_index == -1) {
+ /* Huh, the current_rotation was not one of the supported rotations. Bail out. */
+ return current_rotation;
+ }
+
+ /* Then, find the next rotation that is allowed */
+
+ i = (current_index + 1) % G_N_ELEMENTS (possible_rotations);
+
+ while (1) {
+ MateRRRotation r;
+
+ r = possible_rotations[i];
+ if (r == current_rotation) {
+ /* We wrapped around and no other rotation is suported. Bummer. */
+ return current_rotation;
+ } else if (r & allowed_rotations)
+ return r;
+
+ i = (i + 1) % G_N_ELEMENTS (possible_rotations);
+ }
+}
+
+/* We use this when the XF86RotateWindows key is pressed. That key is present
+ * on some tablet PCs; they use it so that the user can rotate the tablet
+ * easily.
+ */
+static void
+handle_rotate_windows (GsdXrandrManager *mgr, guint32 timestamp)
+{
+ GsdXrandrManagerPrivate *priv = mgr->priv;
+ MateRRScreen *screen = priv->rw_screen;
+ MateRRConfig *current;
+ MateOutputInfo *rotatable_output_info;
+ int num_allowed_rotations;
+ MateRRRotation allowed_rotations;
+ MateRRRotation next_rotation;
+
+ g_debug ("Handling XF86RotateWindows");
+
+ /* Which output? */
+
+ current = mate_rr_config_new_current (screen);
+
+ rotatable_output_info = get_laptop_output_info (screen, current);
+ if (rotatable_output_info == NULL) {
+ g_debug ("No laptop outputs found to rotate; XF86RotateWindows key will do nothing");
+ goto out;
+ }
+
+ /* Which rotation? */
+
+ get_allowed_rotations_for_output (current, priv->rw_screen, rotatable_output_info, &num_allowed_rotations, &allowed_rotations);
+ next_rotation = get_next_rotation (allowed_rotations, rotatable_output_info->rotation);
+
+ if (next_rotation == rotatable_output_info->rotation) {
+ g_debug ("No rotations are supported other than the current one; XF86RotateWindows key will do nothing");
+ goto out;
+ }
+
+ /* Rotate */
+
+ rotatable_output_info->rotation = next_rotation;
+
+ apply_configuration_and_display_error (mgr, current, timestamp);
+
+out:
+ mate_rr_config_free (current);
+}
+
+static GdkFilterReturn
+event_filter (GdkXEvent *xevent,
+ GdkEvent *event,
+ gpointer data)
+{
+ GsdXrandrManager *manager = data;
+ XEvent *xev = (XEvent *) xevent;
+
+ if (!manager->priv->running)
+ return GDK_FILTER_CONTINUE;
+
+ /* verify we have a key event */
+ if (xev->xany.type != KeyPress && xev->xany.type != KeyRelease)
+ return GDK_FILTER_CONTINUE;
+
+ if (xev->xany.type == KeyPress) {
+ if (xev->xkey.keycode == manager->priv->switch_video_mode_keycode)
+ handle_fn_f7 (manager, xev->xkey.time);
+ else if (xev->xkey.keycode == manager->priv->rotate_windows_keycode)
+ handle_rotate_windows (manager, xev->xkey.time);
+
+ return GDK_FILTER_CONTINUE;
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+refresh_tray_icon_menu_if_active (GsdXrandrManager *manager, guint32 timestamp)
+{
+ GsdXrandrManagerPrivate *priv = manager->priv;
+
+ if (priv->popup_menu) {
+ gtk_menu_shell_cancel (GTK_MENU_SHELL (priv->popup_menu)); /* status_icon_popup_menu_selection_done_cb() will free everything */
+ status_icon_popup_menu (manager, 0, timestamp);
+ }
+}
+
+static void
+auto_configure_outputs (GsdXrandrManager *manager, guint32 timestamp)
+{
+ GsdXrandrManagerPrivate *priv = manager->priv;
+ MateRRConfig *config;
+ int i;
+ GList *just_turned_on;
+ GList *l;
+ int x;
+ GError *error;
+ gboolean applicable;
+
+ config = mate_rr_config_new_current (priv->rw_screen);
+
+ /* For outputs that are connected and on (i.e. they have a CRTC assigned
+ * to them, so they are getting a signal), we leave them as they are
+ * with their current modes.
+ *
+ * For other outputs, we will turn on connected-but-off outputs and turn
+ * off disconnected-but-on outputs.
+ *
+ * FIXME: If an output remained connected+on, it would be nice to ensure
+ * that the output's CRTCs still has a reasonable mode (think of
+ * changing one monitor for another with different capabilities).
+ */
+
+ just_turned_on = NULL;
+
+ for (i = 0; config->outputs[i] != NULL; i++) {
+ MateOutputInfo *output = config->outputs[i];
+
+ if (output->connected && !output->on) {
+ output->on = TRUE;
+ output->rotation = MATE_RR_ROTATION_0;
+ just_turned_on = g_list_prepend (just_turned_on, GINT_TO_POINTER (i));
+ } else if (!output->connected && output->on)
+ output->on = FALSE;
+ }
+
+ /* Now, lay out the outputs from left to right. Put first the outputs
+ * which remained on; put last the outputs that were newly turned on.
+ */
+
+ x = 0;
+
+ /* First, outputs that remained on */
+
+ for (i = 0; config->outputs[i] != NULL; i++) {
+ MateOutputInfo *output = config->outputs[i];
+
+ if (g_list_find (just_turned_on, GINT_TO_POINTER (i)))
+ continue;
+
+ if (output->on) {
+ g_assert (output->connected);
+
+ output->x = x;
+ output->y = 0;
+
+ x += output->width;
+ }
+ }
+
+ /* Second, outputs that were newly-turned on */
+
+ for (l = just_turned_on; l; l = l->next) {
+ MateOutputInfo *output;
+
+ i = GPOINTER_TO_INT (l->data);
+ output = config->outputs[i];
+
+ g_assert (output->on && output->connected);
+
+ output->x = x;
+ output->y = 0;
+
+ /* since the output was off, use its preferred width/height (it doesn't have a real width/height yet) */
+ output->width = output->pref_width;
+ output->height = output->pref_height;
+
+ x += output->width;
+ }
+
+ /* Check if we have a large enough framebuffer size. If not, turn off
+ * outputs from right to left until we reach a usable size.
+ */
+
+ just_turned_on = g_list_reverse (just_turned_on); /* now the outputs here are from right to left */
+
+ l = just_turned_on;
+ while (1) {
+ MateOutputInfo *output;
+ gboolean is_bounds_error;
+
+ error = NULL;
+ applicable = mate_rr_config_applicable (config, priv->rw_screen, &error);
+
+ if (applicable)
+ break;
+
+ is_bounds_error = g_error_matches (error, MATE_RR_ERROR, MATE_RR_ERROR_BOUNDS_ERROR);
+ g_error_free (error);
+
+ if (!is_bounds_error)
+ break;
+
+ if (l) {
+ i = GPOINTER_TO_INT (l->data);
+ l = l->next;
+
+ output = config->outputs[i];
+ output->on = FALSE;
+ } else
+ break;
+ }
+
+ /* Apply the configuration! */
+
+ if (applicable)
+ apply_configuration_and_display_error (manager, config, timestamp);
+
+ g_list_free (just_turned_on);
+ mate_rr_config_free (config);
+
+ /* Finally, even though we did a best-effort job in sanitizing the
+ * outputs, we don't know the physical layout of the monitors. We'll
+ * start the display capplet so that the user can tweak things to his
+ * liking.
+ */
+
+#if 0
+ /* FIXME: This is disabled for now. The capplet is not a single-instance application.
+ * If you do this:
+ *
+ * 1. Start the display capplet
+ *
+ * 2. Plug an extra monitor
+ *
+ * 3. Hit the "Detect displays" button
+ *
+ * Then we will get a RANDR event because X re-probes the outputs. We don't want to
+ * start up a second display capplet right there!
+ */
+
+ run_display_capplet (NULL);
+#endif
+}
+
+static void
+apply_color_profiles (void)
+{
+ gboolean ret;
+ GError *error = NULL;
+
+ /* run the mate-color-manager apply program */
+ ret = g_spawn_command_line_async (BINDIR "/gcm-apply", &error);
+ if (!ret) {
+ /* only print the warning if the binary is installed */
+ if (error->code != G_SPAWN_ERROR_NOENT) {
+ g_warning ("failed to apply color profiles: %s", error->message);
+ }
+ g_error_free (error);
+ }
+}
+
+static void
+on_randr_event (MateRRScreen *screen, gpointer data)
+{
+ GsdXrandrManager *manager = GSD_XRANDR_MANAGER (data);
+ GsdXrandrManagerPrivate *priv = manager->priv;
+ guint32 change_timestamp, config_timestamp;
+
+ if (!priv->running)
+ return;
+
+ mate_rr_screen_get_timestamps (screen, &change_timestamp, &config_timestamp);
+
+ log_open ();
+ log_msg ("Got RANDR event with timestamps change=%u %c config=%u\n",
+ change_timestamp,
+ timestamp_relationship (change_timestamp, config_timestamp),
+ config_timestamp);
+
+ if (change_timestamp >= config_timestamp) {
+ /* The event is due to an explicit configuration change.
+ *
+ * If the change was performed by us, then we need to do nothing.
+ *
+ * If the change was done by some other X client, we don't need
+ * to do anything, either; the screen is already configured.
+ */
+ show_timestamps_dialog (manager, "ignoring since change > config");
+ log_msg (" Ignoring event since change >= config\n");
+ } else {
+ /* Here, config_timestamp > change_timestamp. This means that
+ * the screen got reconfigured because of hotplug/unplug; the X
+ * server is just notifying us, and we need to configure the
+ * outputs in a sane way.
+ */
+
+ char *intended_filename;
+ GError *error;
+ gboolean success;
+
+ show_timestamps_dialog (manager, "need to deal with reconfiguration, as config > change");
+
+ intended_filename = mate_rr_config_get_intended_filename ();
+
+ error = NULL;
+ success = apply_configuration_from_filename (manager, intended_filename, TRUE, config_timestamp, &error);
+ g_free (intended_filename);
+
+ if (!success) {
+ /* We don't bother checking the error type.
+ *
+ * Both G_FILE_ERROR_NOENT and
+ * MATE_RR_ERROR_NO_MATCHING_CONFIG would mean, "there
+ * was no configuration to apply, or none that matched
+ * the current outputs", and in that case we need to run
+ * our fallback.
+ *
+ * Any other error means "we couldn't do the smart thing
+ * of using a previously- saved configuration, anyway,
+ * for some other reason. In that case, we also need to
+ * run our fallback to avoid leaving the user with a
+ * bogus configuration.
+ */
+
+ if (error)
+ g_error_free (error);
+
+ if (config_timestamp != priv->last_config_timestamp) {
+ priv->last_config_timestamp = config_timestamp;
+ auto_configure_outputs (manager, config_timestamp);
+ log_msg (" Automatically configured outputs to deal with event\n");
+ } else
+ log_msg (" Ignored event as old and new config timestamps are the same\n");
+ } else
+ log_msg ("Applied stored configuration to deal with event\n");
+ }
+
+ /* poke mate-color-manager */
+ apply_color_profiles ();
+
+ refresh_tray_icon_menu_if_active (manager, MAX (change_timestamp, config_timestamp));
+
+ log_close ();
+}
+
+static void
+run_display_capplet (GtkWidget *widget)
+{
+ GdkScreen *screen;
+ GError *error;
+
+ if (widget)
+ screen = gtk_widget_get_screen (widget);
+ else
+ screen = gdk_screen_get_default ();
+
+ error = NULL;
+ if (!gdk_spawn_command_line_on_screen (screen, GSD_XRANDR_DISPLAY_CAPPLET, &error)) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new_with_markup (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ "<span weight=\"bold\" size=\"larger\">"
+ "Display configuration could not be run"
+ "</span>\n\n"
+ "%s", error->message);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ g_error_free (error);
+ }
+}
+
+static void
+popup_menu_configure_display_cb (GtkMenuItem *item, gpointer data)
+{
+ run_display_capplet (GTK_WIDGET (item));
+}
+
+static void
+status_icon_popup_menu_selection_done_cb (GtkMenuShell *menu_shell, gpointer data)
+{
+ GsdXrandrManager *manager = GSD_XRANDR_MANAGER (data);
+ struct GsdXrandrManagerPrivate *priv = manager->priv;
+
+ gtk_widget_destroy (priv->popup_menu);
+ priv->popup_menu = NULL;
+
+ mate_rr_labeler_hide (priv->labeler);
+ g_object_unref (priv->labeler);
+ priv->labeler = NULL;
+
+ mate_rr_config_free (priv->configuration);
+ priv->configuration = NULL;
+}
+
+#define OUTPUT_TITLE_ITEM_BORDER 2
+#define OUTPUT_TITLE_ITEM_PADDING 4
+
+/* This is an expose-event hander for the title label for each MateRROutput.
+ * We want each title to have a colored background, so we paint that background, then
+ * return FALSE to let GtkLabel expose itself (i.e. paint the label's text), and then
+ * we have a signal_connect_after handler as well. See the comments below
+ * to see why that "after" handler is needed.
+ */
+static gboolean
+output_title_label_expose_event_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
+{
+ GsdXrandrManager *manager = GSD_XRANDR_MANAGER (data);
+ struct GsdXrandrManagerPrivate *priv = manager->priv;
+ MateOutputInfo *output;
+ GdkColor color;
+ cairo_t *cr;
+ GtkAllocation allocation;
+
+ g_assert (GTK_IS_LABEL (widget));
+
+ output = g_object_get_data (G_OBJECT (widget), "output");
+ g_assert (output != NULL);
+
+ g_assert (priv->labeler != NULL);
+
+ /* Draw a black rectangular border, filled with the color that corresponds to this output */
+
+ mate_rr_labeler_get_color_for_output (priv->labeler, output, &color);
+
+ cr = gdk_cairo_create (gtk_widget_get_window (widget));
+
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_set_line_width (cr, OUTPUT_TITLE_ITEM_BORDER);
+ gtk_widget_get_allocation (widget, &allocation);
+ cairo_rectangle (cr,
+ allocation.x + OUTPUT_TITLE_ITEM_BORDER / 2.0,
+ allocation.y + OUTPUT_TITLE_ITEM_BORDER / 2.0,
+ allocation.width - OUTPUT_TITLE_ITEM_BORDER,
+ allocation.height - OUTPUT_TITLE_ITEM_BORDER);
+ cairo_stroke (cr);
+
+ gdk_cairo_set_source_color (cr, &color);
+ cairo_rectangle (cr,
+ allocation.x + OUTPUT_TITLE_ITEM_BORDER,
+ allocation.y + OUTPUT_TITLE_ITEM_BORDER,
+ allocation.width - 2 * OUTPUT_TITLE_ITEM_BORDER,
+ allocation.height - 2 * OUTPUT_TITLE_ITEM_BORDER);
+
+ cairo_fill (cr);
+
+ /* We want the label to always show up as if it were sensitive
+ * ("style->fg[GTK_STATE_NORMAL]"), even though the label is insensitive
+ * due to being inside an insensitive menu item. So, here we have a
+ * HACK in which we frob the label's state directly. GtkLabel's expose
+ * handler will be run after this function, so it will think that the
+ * label is in GTK_STATE_NORMAL. We reset the label's state back to
+ * insensitive in output_title_label_after_expose_event_cb().
+ *
+ * Yay for fucking with GTK+'s internals.
+ */
+
+ gtk_widget_set_state (widget, GTK_STATE_NORMAL);
+
+ return FALSE;
+}
+
+/* See the comment in output_title_event_box_expose_event_cb() about this funny label widget */
+static gboolean
+output_title_label_after_expose_event_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
+{
+ g_assert (GTK_IS_LABEL (widget));
+ gtk_widget_set_state (widget, GTK_STATE_INSENSITIVE);
+
+ return FALSE;
+}
+
+static void
+title_item_size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation, gpointer data)
+{
+ /* When GtkMenu does size_request on its items, it asks them for their "toggle size",
+ * which will be non-zero when there are check/radio items. GtkMenu remembers
+ * the largest of those sizes. During the size_allocate pass, GtkMenu calls
+ * gtk_menu_item_toggle_size_allocate() with that value, to tell the menu item
+ * that it should later paint its child a bit to the right of its edge.
+ *
+ * However, we want the "title" menu items for each RANDR output to span the *whole*
+ * allocation of the menu item, not just the "allocation minus toggle" area.
+ *
+ * So, we let the menu item size_allocate itself as usual, but this
+ * callback gets run afterward. Here we hack a toggle size of 0 into
+ * the menu item, and size_allocate it by hand *again*. We also need to
+ * avoid recursing into this function.
+ */
+
+ g_assert (GTK_IS_MENU_ITEM (widget));
+
+ gtk_menu_item_toggle_size_allocate (GTK_MENU_ITEM (widget), 0);
+
+ g_signal_handlers_block_by_func (widget, title_item_size_allocate_cb, NULL);
+
+ /* Sigh. There is no way to turn on GTK_ALLOC_NEEDED outside of GTK+
+ * itself; also, since calling size_allocate on a widget with the same
+ * allcation is a no-op, we need to allocate with a "different" size
+ * first.
+ */
+
+ allocation->width++;
+ gtk_widget_size_allocate (widget, allocation);
+
+ allocation->width--;
+ gtk_widget_size_allocate (widget, allocation);
+
+ g_signal_handlers_unblock_by_func (widget, title_item_size_allocate_cb, NULL);
+}
+
+static GtkWidget *
+make_menu_item_for_output_title (GsdXrandrManager *manager, MateOutputInfo *output)
+{
+ GtkWidget *item;
+ GtkWidget *label;
+ char *str;
+ GdkColor black = { 0, 0, 0, 0 };
+
+ item = gtk_menu_item_new ();
+
+ g_signal_connect (item, "size-allocate",
+ G_CALLBACK (title_item_size_allocate_cb), NULL);
+
+ str = g_markup_printf_escaped ("<b>%s</b>", output->display_name);
+ label = gtk_label_new (NULL);
+ gtk_label_set_markup (GTK_LABEL (label), str);
+ g_free (str);
+
+ /* Make the label explicitly black. We don't want it to follow the
+ * theme's colors, since the label is always shown against a light
+ * pastel background. See bgo#556050
+ */
+ gtk_widget_modify_fg (label, gtk_widget_get_state (label), &black);
+
+ /* Add padding around the label to fit the box that we'll draw for color-coding */
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_misc_set_padding (GTK_MISC (label),
+ OUTPUT_TITLE_ITEM_BORDER + OUTPUT_TITLE_ITEM_PADDING,
+ OUTPUT_TITLE_ITEM_BORDER + OUTPUT_TITLE_ITEM_PADDING);
+
+ gtk_container_add (GTK_CONTAINER (item), label);
+
+ /* We want to paint a colored box as the background of the label, so we connect
+ * to its expose-event signal. See the comment in *** to see why need to connect
+ * to the label both 'before' and 'after'.
+ */
+ g_signal_connect (label, "expose-event",
+ G_CALLBACK (output_title_label_expose_event_cb), manager);
+ g_signal_connect_after (label, "expose-event",
+ G_CALLBACK (output_title_label_after_expose_event_cb), manager);
+
+ g_object_set_data (G_OBJECT (label), "output", output);
+
+ gtk_widget_set_sensitive (item, FALSE); /* the title is not selectable */
+ gtk_widget_show_all (item);
+
+ return item;
+}
+
+static void
+get_allowed_rotations_for_output (MateRRConfig *config,
+ MateRRScreen *rr_screen,
+ MateOutputInfo *output,
+ int *out_num_rotations,
+ MateRRRotation *out_rotations)
+{
+ MateRRRotation current_rotation;
+ int i;
+
+ *out_num_rotations = 0;
+ *out_rotations = 0;
+
+ current_rotation = output->rotation;
+
+ /* Yay for brute force */
+
+ for (i = 0; i < G_N_ELEMENTS (possible_rotations); i++) {
+ MateRRRotation rotation_to_test;
+
+ rotation_to_test = possible_rotations[i];
+
+ output->rotation = rotation_to_test;
+
+ if (mate_rr_config_applicable (config, rr_screen, NULL)) { /* NULL-GError */
+ (*out_num_rotations)++;
+ (*out_rotations) |= rotation_to_test;
+ }
+ }
+
+ output->rotation = current_rotation;
+
+ if (*out_num_rotations == 0 || *out_rotations == 0) {
+ g_warning ("Huh, output %p says it doesn't support any rotations, and yet it has a current rotation?", output);
+ *out_num_rotations = 1;
+ *out_rotations = output->rotation;
+ }
+}
+
+static void
+add_unsupported_rotation_item (GsdXrandrManager *manager)
+{
+ struct GsdXrandrManagerPrivate *priv = manager->priv;
+ GtkWidget *item;
+ GtkWidget *label;
+ gchar *markup;
+
+ item = gtk_menu_item_new ();
+
+ label = gtk_label_new (NULL);
+ markup = g_strdup_printf ("<i>%s</i>", _("Rotation not supported"));
+ gtk_label_set_markup (GTK_LABEL (label), markup);
+ g_free (markup);
+ gtk_container_add (GTK_CONTAINER (item), label);
+
+ gtk_widget_show_all (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
+}
+
+static void
+ensure_current_configuration_is_saved (void)
+{
+ MateRRScreen *rr_screen;
+ MateRRConfig *rr_config;
+
+ /* Normally, mate_rr_config_save() creates a backup file based on the
+ * old monitors.xml. However, if *that* file didn't exist, there is
+ * nothing from which to create a backup. So, here we'll save the
+ * current/unchanged configuration and then let our caller call
+ * mate_rr_config_save() again with the new/changed configuration, so
+ * that there *will* be a backup file in the end.
+ */
+
+ rr_screen = mate_rr_screen_new (gdk_screen_get_default (), NULL, NULL, NULL); /* NULL-GError */
+ if (!rr_screen)
+ return;
+
+ rr_config = mate_rr_config_new_current (rr_screen);
+ mate_rr_config_save (rr_config, NULL); /* NULL-GError */
+
+ mate_rr_config_free (rr_config);
+ mate_rr_screen_destroy (rr_screen);
+}
+
+static void
+output_rotation_item_activate_cb (GtkCheckMenuItem *item, gpointer data)
+{
+ GsdXrandrManager *manager = GSD_XRANDR_MANAGER (data);
+ struct GsdXrandrManagerPrivate *priv = manager->priv;
+ MateOutputInfo *output;
+ MateRRRotation rotation;
+ GError *error;
+
+ /* Not interested in deselected items */
+ if (!gtk_check_menu_item_get_active (item))
+ return;
+
+ ensure_current_configuration_is_saved ();
+
+ output = g_object_get_data (G_OBJECT (item), "output");
+ rotation = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "rotation"));
+
+ output->rotation = rotation;
+
+ error = NULL;
+ if (!mate_rr_config_save (priv->configuration, &error)) {
+ error_message (manager, _("Could not save monitor configuration"), error, NULL);
+ if (error)
+ g_error_free (error);
+
+ return;
+ }
+
+ try_to_apply_intended_configuration (manager, NULL, gtk_get_current_event_time (), NULL); /* NULL-GError */
+}
+
+static void
+add_items_for_rotations (GsdXrandrManager *manager, MateOutputInfo *output, MateRRRotation allowed_rotations)
+{
+ typedef struct {
+ MateRRRotation rotation;
+ const char * name;
+ } RotationInfo;
+ static const RotationInfo rotations[] = {
+ { MATE_RR_ROTATION_0, N_("Normal") },
+ { MATE_RR_ROTATION_90, N_("Left") },
+ { MATE_RR_ROTATION_270, N_("Right") },
+ { MATE_RR_ROTATION_180, N_("Upside Down") },
+ /* We don't allow REFLECT_X or REFLECT_Y for now, as mate-display-properties doesn't allow them, either */
+ };
+
+ struct GsdXrandrManagerPrivate *priv = manager->priv;
+ int i;
+ GSList *group;
+ GtkWidget *active_item;
+ gulong active_item_activate_id;
+
+ group = NULL;
+ active_item = NULL;
+ active_item_activate_id = 0;
+
+ for (i = 0; i < G_N_ELEMENTS (rotations); i++) {
+ MateRRRotation rot;
+ GtkWidget *item;
+ gulong activate_id;
+
+ rot = rotations[i].rotation;
+
+ if ((allowed_rotations & rot) == 0) {
+ /* don't display items for rotations which are
+ * unavailable. Their availability is not under the
+ * user's control, anyway.
+ */
+ continue;
+ }
+
+ item = gtk_radio_menu_item_new_with_label (group, _(rotations[i].name));
+ gtk_widget_show_all (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
+
+ g_object_set_data (G_OBJECT (item), "output", output);
+ g_object_set_data (G_OBJECT (item), "rotation", GINT_TO_POINTER (rot));
+
+ activate_id = g_signal_connect (item, "activate",
+ G_CALLBACK (output_rotation_item_activate_cb), manager);
+
+ group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
+
+ if (rot == output->rotation) {
+ active_item = item;
+ active_item_activate_id = activate_id;
+ }
+ }
+
+ if (active_item) {
+ /* Block the signal temporarily so our callback won't be called;
+ * we are just setting up the UI.
+ */
+ g_signal_handler_block (active_item, active_item_activate_id);
+
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (active_item), TRUE);
+
+ g_signal_handler_unblock (active_item, active_item_activate_id);
+ }
+
+}
+
+static void
+add_rotation_items_for_output (GsdXrandrManager *manager, MateOutputInfo *output)
+{
+ struct GsdXrandrManagerPrivate *priv = manager->priv;
+ int num_rotations;
+ MateRRRotation rotations;
+
+ get_allowed_rotations_for_output (priv->configuration, priv->rw_screen, output, &num_rotations, &rotations);
+
+ if (num_rotations == 1)
+ add_unsupported_rotation_item (manager);
+ else
+ add_items_for_rotations (manager, output, rotations);
+}
+
+static void
+add_menu_items_for_output (GsdXrandrManager *manager, MateOutputInfo *output)
+{
+ struct GsdXrandrManagerPrivate *priv = manager->priv;
+ GtkWidget *item;
+
+ item = make_menu_item_for_output_title (manager, output);
+ gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
+
+ add_rotation_items_for_output (manager, output);
+}
+
+static void
+add_menu_items_for_outputs (GsdXrandrManager *manager)
+{
+ struct GsdXrandrManagerPrivate *priv = manager->priv;
+ int i;
+
+ for (i = 0; priv->configuration->outputs[i] != NULL; i++) {
+ if (priv->configuration->outputs[i]->connected)
+ add_menu_items_for_output (manager, priv->configuration->outputs[i]);
+ }
+}
+
+static void
+status_icon_popup_menu (GsdXrandrManager *manager, guint button, guint32 timestamp)
+{
+ struct GsdXrandrManagerPrivate *priv = manager->priv;
+ GtkWidget *item;
+
+ g_assert (priv->configuration == NULL);
+ priv->configuration = mate_rr_config_new_current (priv->rw_screen);
+
+ g_assert (priv->labeler == NULL);
+ priv->labeler = mate_rr_labeler_new (priv->configuration);
+
+ g_assert (priv->popup_menu == NULL);
+ priv->popup_menu = gtk_menu_new ();
+
+ add_menu_items_for_outputs (manager);
+
+ item = gtk_separator_menu_item_new ();
+ gtk_widget_show (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
+
+ item = gtk_menu_item_new_with_mnemonic (_("_Configure Display Settings…"));
+ g_signal_connect (item, "activate",
+ G_CALLBACK (popup_menu_configure_display_cb), manager);
+ gtk_widget_show (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
+
+ g_signal_connect (priv->popup_menu, "selection-done",
+ G_CALLBACK (status_icon_popup_menu_selection_done_cb), manager);
+
+ gtk_menu_popup (GTK_MENU (priv->popup_menu), NULL, NULL,
+ gtk_status_icon_position_menu,
+ priv->status_icon, button, timestamp);
+}
+
+static void
+status_icon_activate_cb (GtkStatusIcon *status_icon, gpointer data)
+{
+ GsdXrandrManager *manager = GSD_XRANDR_MANAGER (data);
+
+ /* Suck; we don't get a proper button/timestamp */
+ status_icon_popup_menu (manager, 0, gtk_get_current_event_time ());
+}
+
+static void
+status_icon_popup_menu_cb (GtkStatusIcon *status_icon, guint button, guint32 timestamp, gpointer data)
+{
+ GsdXrandrManager *manager = GSD_XRANDR_MANAGER (data);
+
+ status_icon_popup_menu (manager, button, timestamp);
+}
+
+static void
+status_icon_start (GsdXrandrManager *manager)
+{
+ struct GsdXrandrManagerPrivate *priv = manager->priv;
+
+ /* Ideally, we should detect if we are on a tablet and only display
+ * the icon in that case.
+ */
+ if (!priv->status_icon) {
+ priv->status_icon = gtk_status_icon_new_from_icon_name (GSD_XRANDR_ICON_NAME);
+ gtk_status_icon_set_tooltip_text (priv->status_icon, _("Configure display settings"));
+
+ g_signal_connect (priv->status_icon, "activate",
+ G_CALLBACK (status_icon_activate_cb), manager);
+ g_signal_connect (priv->status_icon, "popup-menu",
+ G_CALLBACK (status_icon_popup_menu_cb), manager);
+ }
+}
+
+static void
+status_icon_stop (GsdXrandrManager *manager)
+{
+ struct GsdXrandrManagerPrivate *priv = manager->priv;
+
+ if (priv->status_icon) {
+ g_signal_handlers_disconnect_by_func (
+ priv->status_icon, G_CALLBACK (status_icon_activate_cb), manager);
+ g_signal_handlers_disconnect_by_func (
+ priv->status_icon, G_CALLBACK (status_icon_popup_menu_cb), manager);
+
+ /* hide the icon before unreffing it; otherwise we will leak
+ whitespace in the notification area due to a bug in there */
+ gtk_status_icon_set_visible (priv->status_icon, FALSE);
+ g_object_unref (priv->status_icon);
+ priv->status_icon = NULL;
+ }
+}
+
+static void
+start_or_stop_icon (GsdXrandrManager *manager)
+{
+ if (mateconf_client_get_bool (manager->priv->client, CONF_KEY_SHOW_NOTIFICATION_ICON, NULL)) {
+ status_icon_start (manager);
+ }
+ else {
+ status_icon_stop (manager);
+ }
+}
+
+static void
+on_config_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ GsdXrandrManager *manager)
+{
+ if (strcmp (entry->key, CONF_KEY_SHOW_NOTIFICATION_ICON) == 0)
+ start_or_stop_icon (manager);
+}
+
+static gboolean
+apply_intended_configuration (GsdXrandrManager *manager, const char *intended_filename, guint32 timestamp)
+{
+ GError *my_error;
+ gboolean result;
+
+ my_error = NULL;
+ result = apply_configuration_from_filename (manager, intended_filename, FALSE, timestamp, &my_error);
+ if (!result) {
+ if (my_error) {
+ if (!g_error_matches (my_error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
+ error_message (manager, _("Could not apply the stored configuration for monitors"), my_error, NULL);
+
+ g_error_free (my_error);
+ }
+ }
+
+ return result;
+}
+
+static void
+apply_default_boot_configuration (GsdXrandrManager *mgr, guint32 timestamp)
+{
+ GsdXrandrManagerPrivate *priv = mgr->priv;
+ MateRRScreen *screen = priv->rw_screen;
+ MateRRConfig *config;
+ gboolean turn_on_external, turn_on_laptop;
+
+ turn_on_external =
+ mateconf_client_get_bool (mgr->priv->client, CONF_KEY_TURN_ON_EXTERNAL_MONITORS_AT_STARTUP, NULL);
+ turn_on_laptop =
+ mateconf_client_get_bool (mgr->priv->client, CONF_KEY_TURN_ON_LAPTOP_MONITOR_AT_STARTUP, NULL);
+
+ if (turn_on_external && turn_on_laptop)
+ config = make_clone_setup (screen);
+ else if (!turn_on_external && turn_on_laptop)
+ config = make_laptop_setup (screen);
+ else if (turn_on_external && !turn_on_laptop)
+ config = make_other_setup (screen);
+ else
+ config = make_laptop_setup (screen);
+
+ if (config) {
+ apply_configuration_and_display_error (mgr, config, timestamp);
+ mate_rr_config_free (config);
+ }
+}
+
+static gboolean
+apply_stored_configuration_at_startup (GsdXrandrManager *manager, guint32 timestamp)
+{
+ GError *my_error;
+ gboolean success;
+ char *backup_filename;
+ char *intended_filename;
+
+ backup_filename = mate_rr_config_get_backup_filename ();
+ intended_filename = mate_rr_config_get_intended_filename ();
+
+ /* 1. See if there was a "saved" configuration. If there is one, it means
+ * that the user had selected to change the display configuration, but the
+ * machine crashed. In that case, we'll apply *that* configuration and save it on top of the
+ * "intended" one.
+ */
+
+ my_error = NULL;
+
+ success = apply_configuration_from_filename (manager, backup_filename, FALSE, timestamp, &my_error);
+ if (success) {
+ /* The backup configuration existed, and could be applied
+ * successfully, so we must restore it on top of the
+ * failed/intended one.
+ */
+ restore_backup_configuration (manager, backup_filename, intended_filename, timestamp);
+ goto out;
+ }
+
+ if (!g_error_matches (my_error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) {
+ /* Epic fail: there (probably) was a backup configuration, but
+ * we could not apply it. The only thing we can do is delete
+ * the backup configuration. Let's hope that the user doesn't
+ * get left with an unusable display...
+ */
+
+ unlink (backup_filename);
+ goto out;
+ }
+
+ /* 2. There was no backup configuration! This means we are
+ * good. Apply the intended configuration instead.
+ */
+
+ success = apply_intended_configuration (manager, intended_filename, timestamp);
+
+out:
+
+ if (my_error)
+ g_error_free (my_error);
+
+ g_free (backup_filename);
+ g_free (intended_filename);
+
+ return success;
+}
+
+static gboolean
+apply_default_configuration_from_file (GsdXrandrManager *manager, guint32 timestamp)
+{
+ GsdXrandrManagerPrivate *priv = manager->priv;
+ char *default_config_filename;
+ gboolean result;
+
+ default_config_filename = mateconf_client_get_string (priv->client, CONF_KEY_DEFAULT_CONFIGURATION_FILE, NULL);
+ if (!default_config_filename)
+ return FALSE;
+
+ result = apply_configuration_from_filename (manager, default_config_filename, TRUE, timestamp, NULL);
+
+ g_free (default_config_filename);
+ return result;
+}
+
+gboolean
+gsd_xrandr_manager_start (GsdXrandrManager *manager,
+ GError **error)
+{
+ g_debug ("Starting xrandr manager");
+ mate_settings_profile_start (NULL);
+
+ log_open ();
+ log_msg ("------------------------------------------------------------\nSTARTING XRANDR PLUGIN\n");
+
+ manager->priv->rw_screen = mate_rr_screen_new (
+ gdk_screen_get_default (), on_randr_event, manager, error);
+
+ if (manager->priv->rw_screen == NULL) {
+ log_msg ("Could not initialize the RANDR plugin%s%s\n",
+ (error && *error) ? ": " : "",
+ (error && *error) ? (*error)->message : "");
+ log_close ();
+ return FALSE;
+ }
+
+ log_msg ("State of screen at startup:\n");
+ log_screen (manager->priv->rw_screen);
+
+ manager->priv->running = TRUE;
+ manager->priv->client = mateconf_client_get_default ();
+
+ g_assert (manager->priv->notify_id == 0);
+
+ mateconf_client_add_dir (manager->priv->client, CONF_DIR,
+ MATECONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+
+ manager->priv->notify_id =
+ mateconf_client_notify_add (
+ manager->priv->client, CONF_DIR,
+ (MateConfClientNotifyFunc)on_config_changed,
+ manager, NULL, NULL);
+
+ if (manager->priv->switch_video_mode_keycode) {
+ gdk_error_trap_push ();
+
+ XGrabKey (gdk_x11_get_default_xdisplay(),
+ manager->priv->switch_video_mode_keycode, AnyModifier,
+ gdk_x11_get_default_root_xwindow(),
+ True, GrabModeAsync, GrabModeAsync);
+
+ gdk_flush ();
+ gdk_error_trap_pop ();
+ }
+
+ if (manager->priv->rotate_windows_keycode) {
+ gdk_error_trap_push ();
+
+ XGrabKey (gdk_x11_get_default_xdisplay(),
+ manager->priv->rotate_windows_keycode, AnyModifier,
+ gdk_x11_get_default_root_xwindow(),
+ True, GrabModeAsync, GrabModeAsync);
+
+ gdk_flush ();
+ gdk_error_trap_pop ();
+ }
+
+ show_timestamps_dialog (manager, "Startup");
+ if (!apply_stored_configuration_at_startup (manager, GDK_CURRENT_TIME)) /* we don't have a real timestamp at startup anyway */
+ if (!apply_default_configuration_from_file (manager, GDK_CURRENT_TIME))
+ apply_default_boot_configuration (manager, GDK_CURRENT_TIME);
+
+ log_msg ("State of screen after initial configuration:\n");
+ log_screen (manager->priv->rw_screen);
+
+ gdk_window_add_filter (gdk_get_default_root_window(),
+ (GdkFilterFunc)event_filter,
+ manager);
+
+ start_or_stop_icon (manager);
+
+ log_close ();
+
+ mate_settings_profile_end (NULL);
+
+ return TRUE;
+}
+
+void
+gsd_xrandr_manager_stop (GsdXrandrManager *manager)
+{
+ g_debug ("Stopping xrandr manager");
+
+ manager->priv->running = FALSE;
+
+ if (manager->priv->switch_video_mode_keycode) {
+ gdk_error_trap_push ();
+
+ XUngrabKey (gdk_x11_get_default_xdisplay(),
+ manager->priv->switch_video_mode_keycode, AnyModifier,
+ gdk_x11_get_default_root_xwindow());
+
+ gdk_error_trap_pop ();
+ }
+
+ if (manager->priv->rotate_windows_keycode) {
+ gdk_error_trap_push ();
+
+ XUngrabKey (gdk_x11_get_default_xdisplay(),
+ manager->priv->rotate_windows_keycode, AnyModifier,
+ gdk_x11_get_default_root_xwindow());
+
+ gdk_error_trap_pop ();
+ }
+
+ gdk_window_remove_filter (gdk_get_default_root_window (),
+ (GdkFilterFunc) event_filter,
+ manager);
+
+ if (manager->priv->notify_id != 0) {
+ mateconf_client_remove_dir (manager->priv->client,
+ CONF_DIR, NULL);
+ mateconf_client_notify_remove (manager->priv->client,
+ manager->priv->notify_id);
+ manager->priv->notify_id = 0;
+ }
+
+ if (manager->priv->client != NULL) {
+ g_object_unref (manager->priv->client);
+ manager->priv->client = NULL;
+ }
+
+ if (manager->priv->rw_screen != NULL) {
+ mate_rr_screen_destroy (manager->priv->rw_screen);
+ manager->priv->rw_screen = NULL;
+ }
+
+ if (manager->priv->dbus_connection != NULL) {
+ dbus_g_connection_unref (manager->priv->dbus_connection);
+ manager->priv->dbus_connection = NULL;
+ }
+
+ status_icon_stop (manager);
+
+ log_open ();
+ log_msg ("STOPPING XRANDR PLUGIN\n------------------------------------------------------------\n");
+ log_close ();
+}
+
+static void
+gsd_xrandr_manager_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GsdXrandrManager *self;
+
+ self = GSD_XRANDR_MANAGER (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsd_xrandr_manager_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GsdXrandrManager *self;
+
+ self = GSD_XRANDR_MANAGER (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+gsd_xrandr_manager_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GsdXrandrManager *xrandr_manager;
+ GsdXrandrManagerClass *klass;
+
+ klass = GSD_XRANDR_MANAGER_CLASS (g_type_class_peek (GSD_TYPE_XRANDR_MANAGER));
+
+ xrandr_manager = GSD_XRANDR_MANAGER (G_OBJECT_CLASS (gsd_xrandr_manager_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ return G_OBJECT (xrandr_manager);
+}
+
+static void
+gsd_xrandr_manager_dispose (GObject *object)
+{
+ GsdXrandrManager *xrandr_manager;
+
+ xrandr_manager = GSD_XRANDR_MANAGER (object);
+
+ G_OBJECT_CLASS (gsd_xrandr_manager_parent_class)->dispose (object);
+}
+
+static void
+gsd_xrandr_manager_class_init (GsdXrandrManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = gsd_xrandr_manager_get_property;
+ object_class->set_property = gsd_xrandr_manager_set_property;
+ object_class->constructor = gsd_xrandr_manager_constructor;
+ object_class->dispose = gsd_xrandr_manager_dispose;
+ object_class->finalize = gsd_xrandr_manager_finalize;
+
+ dbus_g_object_type_install_info (GSD_TYPE_XRANDR_MANAGER, &dbus_glib_gsd_xrandr_manager_object_info);
+
+ g_type_class_add_private (klass, sizeof (GsdXrandrManagerPrivate));
+}
+
+static guint
+get_keycode_for_keysym_name (const char *name)
+{
+ Display *dpy;
+ guint keyval;
+
+ dpy = gdk_x11_get_default_xdisplay ();
+
+ keyval = gdk_keyval_from_name (name);
+ return XKeysymToKeycode (dpy, keyval);
+}
+
+static void
+gsd_xrandr_manager_init (GsdXrandrManager *manager)
+{
+ manager->priv = GSD_XRANDR_MANAGER_GET_PRIVATE (manager);
+
+ manager->priv->switch_video_mode_keycode = get_keycode_for_keysym_name (VIDEO_KEYSYM);
+ manager->priv->rotate_windows_keycode = get_keycode_for_keysym_name (ROTATE_KEYSYM);
+
+ manager->priv->current_fn_f7_config = -1;
+ manager->priv->fn_f7_configs = NULL;
+}
+
+static void
+gsd_xrandr_manager_finalize (GObject *object)
+{
+ GsdXrandrManager *xrandr_manager;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GSD_IS_XRANDR_MANAGER (object));
+
+ xrandr_manager = GSD_XRANDR_MANAGER (object);
+
+ g_return_if_fail (xrandr_manager->priv != NULL);
+
+ G_OBJECT_CLASS (gsd_xrandr_manager_parent_class)->finalize (object);
+}
+
+static gboolean
+register_manager_dbus (GsdXrandrManager *manager)
+{
+ GError *error = NULL;
+
+ manager->priv->dbus_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (manager->priv->dbus_connection == NULL) {
+ if (error != NULL) {
+ g_warning ("Error getting session bus: %s", error->message);
+ g_error_free (error);
+ }
+ return FALSE;
+ }
+
+ /* Hmm, should we do this in gsd_xrandr_manager_start()? */
+ dbus_g_connection_register_g_object (manager->priv->dbus_connection, GSD_XRANDR_DBUS_PATH, G_OBJECT (manager));
+
+ return TRUE;
+}
+
+GsdXrandrManager *
+gsd_xrandr_manager_new (void)
+{
+ if (manager_object != NULL) {
+ g_object_ref (manager_object);
+ } else {
+ manager_object = g_object_new (GSD_TYPE_XRANDR_MANAGER, NULL);
+ g_object_add_weak_pointer (manager_object,
+ (gpointer *) &manager_object);
+
+ if (!register_manager_dbus (manager_object)) {
+ g_object_unref (manager_object);
+ return NULL;
+ }
+ }
+
+ return GSD_XRANDR_MANAGER (manager_object);
+}
diff --git a/plugins/xrandr/gsd-xrandr-manager.h b/plugins/xrandr/gsd-xrandr-manager.h
new file mode 100644
index 0000000..c404bfe
--- /dev/null
+++ b/plugins/xrandr/gsd-xrandr-manager.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __GSD_XRANDR_MANAGER_H
+#define __GSD_XRANDR_MANAGER_H
+
+#include <glib-object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GSD_TYPE_XRANDR_MANAGER (gsd_xrandr_manager_get_type ())
+#define GSD_XRANDR_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_XRANDR_MANAGER, GsdXrandrManager))
+#define GSD_XRANDR_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_XRANDR_MANAGER, GsdXrandrManagerClass))
+#define GSD_IS_XRANDR_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_XRANDR_MANAGER))
+#define GSD_IS_XRANDR_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_XRANDR_MANAGER))
+#define GSD_XRANDR_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_XRANDR_MANAGER, GsdXrandrManagerClass))
+
+typedef struct GsdXrandrManagerPrivate GsdXrandrManagerPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GsdXrandrManagerPrivate *priv;
+} GsdXrandrManager;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} GsdXrandrManagerClass;
+
+GType gsd_xrandr_manager_get_type (void);
+
+GsdXrandrManager * gsd_xrandr_manager_new (void);
+gboolean gsd_xrandr_manager_start (GsdXrandrManager *manager,
+ GError **error);
+void gsd_xrandr_manager_stop (GsdXrandrManager *manager);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSD_XRANDR_MANAGER_H */
diff --git a/plugins/xrandr/gsd-xrandr-manager.xml b/plugins/xrandr/gsd-xrandr-manager.xml
new file mode 100644
index 0000000..e8dde7c
--- /dev/null
+++ b/plugins/xrandr/gsd-xrandr-manager.xml
@@ -0,0 +1,23 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.mate.SettingsDaemon.XRANDR">
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="gsd_xrandr_manager"/>
+ <method name="ApplyConfiguration">
+ <!-- This method is implemented, but deprecated in favor of the
+ same method in the XRANDR-2 interface defined below. -->
+ </method>
+ </interface>
+
+ <interface name="org.mate.SettingsDaemon.XRANDR_2">
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="gsd_xrandr_manager_2"/>
+ <method name="ApplyConfiguration">
+ <!-- transient-parent window for the confirmation dialog; use 0
+ for no parent -->
+ <arg name="parent_window_id" type="x" direction="in"/>
+
+ <!-- Timestamp used to present the confirmation dialog and (in
+ the future) for the RANDR calls themselves -->
+ <arg name="timestamp" type="x" direction="in"/>
+ </method>
+ </interface>
+</node>
diff --git a/plugins/xrandr/gsd-xrandr-plugin.c b/plugins/xrandr/gsd-xrandr-plugin.c
new file mode 100644
index 0000000..e765124
--- /dev/null
+++ b/plugins/xrandr/gsd-xrandr-plugin.c
@@ -0,0 +1,104 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <[email protected]>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include "mate-settings-plugin.h"
+#include "gsd-xrandr-plugin.h"
+#include "gsd-xrandr-manager.h"
+
+struct GsdXrandrPluginPrivate {
+ GsdXrandrManager *manager;
+};
+
+#define GSD_XRANDR_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), GSD_TYPE_XRANDR_PLUGIN, GsdXrandrPluginPrivate))
+
+MATE_SETTINGS_PLUGIN_REGISTER (GsdXrandrPlugin, gsd_xrandr_plugin)
+
+static void
+gsd_xrandr_plugin_init (GsdXrandrPlugin *plugin)
+{
+ plugin->priv = GSD_XRANDR_PLUGIN_GET_PRIVATE (plugin);
+
+ g_debug ("GsdXrandrPlugin initializing");
+
+ plugin->priv->manager = gsd_xrandr_manager_new ();
+}
+
+static void
+gsd_xrandr_plugin_finalize (GObject *object)
+{
+ GsdXrandrPlugin *plugin;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GSD_IS_XRANDR_PLUGIN (object));
+
+ g_debug ("GsdXrandrPlugin finalizing");
+
+ plugin = GSD_XRANDR_PLUGIN (object);
+
+ g_return_if_fail (plugin->priv != NULL);
+
+ if (plugin->priv->manager != NULL) {
+ g_object_unref (plugin->priv->manager);
+ }
+
+ G_OBJECT_CLASS (gsd_xrandr_plugin_parent_class)->finalize (object);
+}
+
+static void
+impl_activate (MateSettingsPlugin *plugin)
+{
+ gboolean res;
+ GError *error;
+
+ g_debug ("Activating xrandr plugin");
+
+ error = NULL;
+ res = gsd_xrandr_manager_start (GSD_XRANDR_PLUGIN (plugin)->priv->manager, &error);
+ if (! res) {
+ g_warning ("Unable to start xrandr manager: %s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+impl_deactivate (MateSettingsPlugin *plugin)
+{
+ g_debug ("Deactivating xrandr plugin");
+ gsd_xrandr_manager_stop (GSD_XRANDR_PLUGIN (plugin)->priv->manager);
+}
+
+static void
+gsd_xrandr_plugin_class_init (GsdXrandrPluginClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MateSettingsPluginClass *plugin_class = MATE_SETTINGS_PLUGIN_CLASS (klass);
+
+ object_class->finalize = gsd_xrandr_plugin_finalize;
+
+ plugin_class->activate = impl_activate;
+ plugin_class->deactivate = impl_deactivate;
+
+ g_type_class_add_private (klass, sizeof (GsdXrandrPluginPrivate));
+}
diff --git a/plugins/xrandr/gsd-xrandr-plugin.h b/plugins/xrandr/gsd-xrandr-plugin.h
new file mode 100644
index 0000000..18bb79a
--- /dev/null
+++ b/plugins/xrandr/gsd-xrandr-plugin.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <[email protected]>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __GSD_XRANDR_PLUGIN_H__
+#define __GSD_XRANDR_PLUGIN_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gmodule.h>
+
+#include "mate-settings-plugin.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GSD_TYPE_XRANDR_PLUGIN (gsd_xrandr_plugin_get_type ())
+#define GSD_XRANDR_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_XRANDR_PLUGIN, GsdXrandrPlugin))
+#define GSD_XRANDR_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_XRANDR_PLUGIN, GsdXrandrPluginClass))
+#define GSD_IS_XRANDR_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_XRANDR_PLUGIN))
+#define GSD_IS_XRANDR_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_XRANDR_PLUGIN))
+#define GSD_XRANDR_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_XRANDR_PLUGIN, GsdXrandrPluginClass))
+
+typedef struct GsdXrandrPluginPrivate GsdXrandrPluginPrivate;
+
+typedef struct
+{
+ MateSettingsPlugin parent;
+ GsdXrandrPluginPrivate *priv;
+} GsdXrandrPlugin;
+
+typedef struct
+{
+ MateSettingsPluginClass parent_class;
+} GsdXrandrPluginClass;
+
+GType gsd_xrandr_plugin_get_type (void) G_GNUC_CONST;
+
+/* All the plugins must implement this function */
+G_MODULE_EXPORT GType register_mate_settings_plugin (GTypeModule *module);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSD_XRANDR_PLUGIN_H__ */
diff --git a/plugins/xrandr/gsd-xrandr.svg b/plugins/xrandr/gsd-xrandr.svg
new file mode 100644
index 0000000..0679b6b
--- /dev/null
+++ b/plugins/xrandr/gsd-xrandr.svg
@@ -0,0 +1,470 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="48.000000px"
+ height="48.000000px"
+ id="svg3304"
+ sodipodi:version="0.32"
+ inkscape:version="0.44+devel"
+ sodipodi:docbase="/home/jimmac/gfx/ximian/art/icons/control-center/scalable"
+ sodipodi:docname="change-resolution.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ sodipodi:modified="true">
+ <defs
+ id="defs3306">
+ <linearGradient
+ id="linearGradient2804">
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="0"
+ id="stop2806" />
+ <stop
+ id="stop2812"
+ offset="0.5"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop2808" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2804"
+ id="linearGradient2831"
+ gradientUnits="userSpaceOnUse"
+ x1="21.875"
+ y1="48.000977"
+ x2="21.875"
+ y2="40" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2781"
+ id="radialGradient2829"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2,0,0,0.8,36,8.8)"
+ cx="1"
+ cy="44"
+ fx="1"
+ fy="44"
+ r="5" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2781">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop2783" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop2785" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2781"
+ id="radialGradient2827"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2,0,0,0.8,-13,-79.2)"
+ cx="1"
+ cy="44"
+ fx="1"
+ fy="44"
+ r="5" />
+ <linearGradient
+ id="linearGradient5137">
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1;"
+ offset="0"
+ id="stop5139" />
+ <stop
+ style="stop-color:#e6e6e3;stop-opacity:1;"
+ offset="1"
+ id="stop5141" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient6240">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop6242" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop6244" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient11400">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop11402" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop11404" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11400"
+ id="linearGradient11406"
+ x1="23.154902"
+ y1="34.572548"
+ x2="23.529411"
+ y2="40.219608"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(0,0.7954955)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5137"
+ id="linearGradient5147"
+ gradientUnits="userSpaceOnUse"
+ x1="17.247635"
+ y1="6.3760414"
+ x2="39.904388"
+ y2="38.876041"
+ gradientTransform="translate(0,0.7954955)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5137"
+ id="linearGradient5223"
+ gradientUnits="userSpaceOnUse"
+ x1="31.743324"
+ y1="37.842293"
+ x2="31.86105"
+ y2="43.82579"
+ gradientTransform="translate(0,0.7954955)" />
+ <linearGradient
+ id="linearGradient7025"
+ inkscape:collect="always">
+ <stop
+ id="stop7027"
+ offset="0"
+ style="stop-color:#e6ce46;stop-opacity:1" />
+ <stop
+ id="stop7029"
+ offset="1"
+ style="stop-color:#d6ba1c;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient22122"
+ inkscape:collect="always">
+ <stop
+ id="stop22124"
+ offset="0"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ id="stop22126"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient22140">
+ <stop
+ id="stop22142"
+ offset="0"
+ style="stop-color:black;stop-opacity:0;" />
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0.5"
+ id="stop22148" />
+ <stop
+ id="stop22144"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient22122"
+ id="radialGradient4770"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0,-1.000001,1.142856,0,-41.10259,45.50001)"
+ cx="7"
+ cy="39.464806"
+ fx="7"
+ fy="39.464806"
+ r="3.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient22122"
+ id="radialGradient4772"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0,-1.000001,1.142856,0,-89.10259,-31.49999)"
+ cx="7"
+ cy="39.464806"
+ fx="7"
+ fy="39.464806"
+ r="3.5" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient22140"
+ id="linearGradient4774"
+ gradientUnits="userSpaceOnUse"
+ x1="18.142136"
+ y1="35"
+ x2="18.142136"
+ y2="42.040661" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7025"
+ id="linearGradient4776"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(53,1.428571)"
+ x1="13.630114"
+ y1="28.5"
+ x2="25.208096"
+ y2="41.180992" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6240"
+ id="linearGradient4778"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(7.843e-3,0.7954955)"
+ x1="20.156862"
+ y1="5.0996137"
+ x2="20.156862"
+ y2="26.039215" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#849193"
+ borderopacity="1.0000000"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1"
+ inkscape:cx="39.697787"
+ inkscape:cy="26.598514"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:showpageshadow="false"
+ showborder="true"
+ inkscape:window-width="923"
+ inkscape:window-height="937"
+ inkscape:window-x="2004"
+ inkscape:window-y="169"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:grid-points="true" />
+ <metadata
+ id="metadata3309">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Change Resolution</dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Jakub Steiner</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>display</rdf:li>
+ <rdf:li>resolution</rdf:li>
+ <rdf:li>video</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title>Andreas Nilsson
+Luca Ferretti &lt;[email protected]&gt;</dc:title>
+ </cc:Agent>
+ </dc:contributor>
+ <dc:date></dc:date>
+ <dc:source>http://www.gnome.org</dc:source>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer">
+ <g
+ id="g2822"
+ style="opacity:0.3"
+ transform="matrix(0.9308511,0,0,1.037397,1.6941489,-1.795056)">
+ <rect
+ transform="scale(-1,-1)"
+ y="-48"
+ x="-11"
+ height="8"
+ width="10"
+ id="rect1892"
+ style="opacity:1;color:#000000;fill:url(#radialGradient2827);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ y="40"
+ x="38"
+ height="8"
+ width="10"
+ id="rect2789"
+ style="opacity:1;color:#000000;fill:url(#radialGradient2829);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ y="40"
+ x="11"
+ height="8"
+ width="27"
+ id="rect2793"
+ style="opacity:1;color:#000000;fill:url(#linearGradient2831);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ <rect
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect4784"
+ width="48"
+ height="48"
+ x="0"
+ y="0.79549509" />
+ <path
+ style="opacity:1;color:#000000;fill:url(#linearGradient5223);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 14.375479,36.328843 C 14.375479,36.328843 15.592355,41.263443 10.51915,41.309767 C 8.0888743,41.331672 8.5866723,45.344918 8.5866723,45.344918 L 39.433139,45.313545 C 39.433139,45.313545 39.851577,41.418182 37.410922,41.372513 C 32.423455,41.280374 33.600393,36.266098 33.600393,36.266098 L 14.375479,36.328843 z "
+ id="path9222"
+ sodipodi:nodetypes="csccscc" />
+ <path
+ style="fill:url(#linearGradient5147);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
+ d="M 4.8886262,4.2739318 L 43.01746,4.2739318 C 45.042579,4.2739318 46.518438,5.7015863 46.518438,7.9000726 L 46.529388,34.103908 C 46.529388,35.795975 46.001041,36.319137 44.494732,36.319137 L 3.5320635,36.300202 C 2.3527922,36.271409 1.513468,35.805541 1.4976345,34.280899 L 1.5128113,7.7123281 C 1.5128113,5.9385022 3.0522187,4.2739318 4.8886262,4.2739318 z "
+ id="rect5040"
+ sodipodi:nodetypes="ccccccccc" />
+ <rect
+ style="fill:#555753;fill-opacity:1;fill-rule:evenodd;stroke:#2e3436;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect9208"
+ width="37.00032"
+ height="22.996691"
+ x="5.5059438"
+ y="8.2973185" />
+ <path
+ sodipodi:type="inkscape:offset"
+ inkscape:radius="-0.875"
+ inkscape:original="M 4.875 4.28125 C 3.0385925 4.28125 1.5 5.9449242 1.5 7.71875 L 1.5 34.28125 C 1.5158335 35.805892 2.3519787 36.283708 3.53125 36.3125 L 44.5 36.3125 C 46.006309 36.3125 46.53125 35.785816 46.53125 34.09375 L 46.53125 7.90625 C 46.53125 5.7077637 45.056369 4.2812498 43.03125 4.28125 L 4.875 4.28125 z "
+ xlink:href="#rect5040"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
+ id="path5145"
+ inkscape:href="#rect5040"
+ d="M 4.875,5.0625 C 3.5670573,5.0625 2.375,6.3571498 2.375,7.625 L 2.375,34.1875 C 2.3812657,34.79084 2.515801,34.970853 2.65625,35.09375 C 2.796699,35.216647 3.0858905,35.332113 3.5625,35.34375 L 44.5,35.34375 C 45.151173,35.34375 45.356981,35.24273 45.4375,35.15625 C 45.518019,35.06977 45.65625,34.755549 45.65625,34 L 45.65625,7.8125 C 45.65625,6.0053499 44.645463,5.0624999 43.03125,5.0625 L 4.875,5.0625 z " />
+ <path
+ style="opacity:0.6;fill:url(#linearGradient11406);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 13.992156,36.834708 C 14.075817,39.007257 13.708803,39.746151 12.358532,40.509939 L 35.973934,41.807257 C 35.024915,40.638629 33.644523,38.873923 34.020993,36.819022 L 13.992156,36.834708 z "
+ id="path10672"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#8d8d8f;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:0.43902438"
+ d="M 9.9921262,42.291555 C 16.698819,42.293524 37.78891,42.291555 37.78891,42.291555"
+ id="path6575"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path8029"
+ d="M 9.647928,43.299429 C 16.354621,43.301398 38.367789,43.299429 38.367789,43.299429"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ style="opacity:0.4;fill:url(#linearGradient4778);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 6.031372,8.8268676 L 6.031372,26.834708 C 22.475817,25.480459 28.630065,16.722289 41.999999,15.807256 L 42,8.7954956 L 6.031372,8.8268676 z "
+ id="path4073"
+ sodipodi:nodetypes="ccccc" />
+ <g
+ id="g4754"
+ transform="translate(-46.77135,-7.3370294)">
+ <g
+ transform="matrix(0.916667,0,0,0.714282,49.771334,11.132681)"
+ style="opacity:0.3"
+ id="g22150">
+ <rect
+ style="opacity:1;fill:url(#radialGradient4770);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1"
+ id="rect22120"
+ width="4"
+ height="7"
+ x="0"
+ y="35" />
+ <rect
+ style="opacity:1;fill:url(#radialGradient4772);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1"
+ id="rect22134"
+ width="4"
+ height="7"
+ x="-48"
+ y="-42"
+ transform="scale(-1,-1)" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient4774);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1"
+ id="rect22138"
+ width="40"
+ height="7"
+ x="4"
+ y="35" />
+ </g>
+ <g
+ id="g4743">
+ <g
+ id="g10824"
+ transform="translate(-5.228666,-6.29601)">
+ <path
+ id="path4319"
+ d="M 57.5,14.928571 L 57.5,44.928571 L 96.5,44.928571 L 57.5,14.928571 z M 63.5,27.928571 L 78.5,38.928571 L 63.5,38.928571 L 63.5,27.928571 z "
+ style="fill:url(#linearGradient4776);fill-opacity:1;fill-rule:evenodd;stroke:#a38503;stroke-width:1.00000024px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4326"
+ d="M 61.5,44.928571 L 61.5,41.928571"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a38503;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4328"
+ d="M 67.5,44.928571 L 67.5,41.928571"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a38503;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4330"
+ d="M 73.5,44.928571 L 73.5,41.964285"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a38503;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4332"
+ d="M 79.5,44.928571 L 79.5,41.928571"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a38503;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4334"
+ d="M 85.5,44.928571 L 85.5,41.928571"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a38503;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ id="path6126"
+ d="M 58.500002,16.928575 L 58.500002,43.928586 L 93.500014,43.928586 L 58.500002,16.928575 z "
+ style="opacity:0.4;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.0000006px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ </g>
+ <path
+ style="opacity:0.4;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 9.5017474,38.542446 L 9.4575532,24.532894 L 28.541592,38.563262 L 9.5017474,38.542446 z "
+ id="path12221"
+ sodipodi:nodetypes="cccc"
+ transform="translate(47.771334,-4.867439)" />
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/plugins/xrandr/xrandr.mate-settings-plugin.in b/plugins/xrandr/xrandr.mate-settings-plugin.in
new file mode 100644
index 0000000..a07305c
--- /dev/null
+++ b/plugins/xrandr/xrandr.mate-settings-plugin.in
@@ -0,0 +1,8 @@
+[MATE Settings Plugin]
+Module=xrandr
+IAge=0
+_Name=XRandR
+_Description=Set up screen size and rotation settings
+Authors=Various
+Copyright=Copyright © 2007 Novell
+Website=