talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

commit a0e9ba8a56459bcebe36107a1081d82fe0c673c3
parent fa12fb431ed433bc548cbec6900242cf8a252a91
Author: Colin Leroy <colin@colino.net>
Date:   Wed, 20 Feb 2013 11:25:36 +0000

2013-02-20 [colin]	3.9.0cvs85

	* configure.ac
		Rework plugin enabling logic. More clean!
	* src/plugins/fancy/fancy_viewer.c
	* src/plugins/fancy/fancy_viewer.h
	* src/plugins/spam_report/spam_report.c
		Make curl dependancy mandatory
	* src/plugins/notification/notification_plugin.c
		Fix build with every possible thing disabled
	* src/plugins/notification/Makefile.am
	* src/plugins/notification/gtkhotkey/.cvsignore
	* src/plugins/notification/gtkhotkey/Makefile.am
	* src/plugins/notification/gtkhotkey/gtk-hotkey-error.c
	* src/plugins/notification/gtkhotkey/gtk-hotkey-error.h
	* src/plugins/notification/gtkhotkey/gtk-hotkey-info.c
	* src/plugins/notification/gtkhotkey/gtk-hotkey-info.h
	* src/plugins/notification/gtkhotkey/gtk-hotkey-key-file-registry.c
	* src/plugins/notification/gtkhotkey/gtk-hotkey-key-file-registry.h
	* src/plugins/notification/gtkhotkey/gtk-hotkey-listener.c
	* src/plugins/notification/gtkhotkey/gtk-hotkey-listener.h
	* src/plugins/notification/gtkhotkey/gtk-hotkey-marshal.c
	* src/plugins/notification/gtkhotkey/gtk-hotkey-marshal.h
	* src/plugins/notification/gtkhotkey/gtk-hotkey-registry.c
	* src/plugins/notification/gtkhotkey/gtk-hotkey-registry.h
	* src/plugins/notification/gtkhotkey/gtk-hotkey-utils.c
	* src/plugins/notification/gtkhotkey/gtk-hotkey-utils.h
	* src/plugins/notification/gtkhotkey/gtk-hotkey-x11-listener.c
	* src/plugins/notification/gtkhotkey/gtk-hotkey-x11-listener.h
	* src/plugins/notification/gtkhotkey/gtkhotkey.h
	* src/plugins/notification/gtkhotkey/x11/eggaccelerators.c
	* src/plugins/notification/gtkhotkey/x11/eggaccelerators.h
	* src/plugins/notification/gtkhotkey/x11/tomboykeybinder.c
	* src/plugins/notification/gtkhotkey/x11/tomboykeybinder.h
		Re-add hotkey support
	* src/plugins/spam_report/Makefile.am
	* src/plugins/tnef_parse/Makefile.am
		Remove gettext.h

Diffstat:
MChangeLog | 39+++++++++++++++++++++++++++++++++++++++
MPATCHSETS | 1+
Mconfigure.ac | 1206+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/plugins/fancy/fancy_viewer.c | 23+++++++----------------
Msrc/plugins/fancy/fancy_viewer.h | 2--
Msrc/plugins/notification/Makefile.am | 12++++++------
Asrc/plugins/notification/gtkhotkey/.cvsignore | 7+++++++
Asrc/plugins/notification/gtkhotkey/Makefile.am | 37+++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtk-hotkey-error.c | 31+++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtk-hotkey-error.h | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtk-hotkey-info.c | 658+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtk-hotkey-info.h | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtk-hotkey-key-file-registry.c | 720+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtk-hotkey-key-file-registry.h | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtk-hotkey-listener.c | 218+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtk-hotkey-listener.h | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtk-hotkey-marshal.c | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtk-hotkey-marshal.h | 24++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtk-hotkey-registry.c | 341+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtk-hotkey-registry.h | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtk-hotkey-utils.c | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtk-hotkey-utils.h | 37+++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtk-hotkey-x11-listener.c | 243+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtk-hotkey-x11-listener.h | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/gtkhotkey.h | 12++++++++++++
Asrc/plugins/notification/gtkhotkey/x11/eggaccelerators.c | 657+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/x11/eggaccelerators.h | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/x11/tomboykeybinder.c | 328+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/notification/gtkhotkey/x11/tomboykeybinder.h | 27+++++++++++++++++++++++++++
Msrc/plugins/notification/notification_plugin.c | 2+-
Msrc/plugins/spam_report/Makefile.am | 3+--
Msrc/plugins/spam_report/spam_report.c | 7+++----
Msrc/plugins/tnef_parse/Makefile.am | 3+--
33 files changed, 4892 insertions(+), 463 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,42 @@ +2013-02-20 [colin] 3.9.0cvs85 + + * configure.ac + Rework plugin enabling logic. More clean! + * src/plugins/fancy/fancy_viewer.c + * src/plugins/fancy/fancy_viewer.h + * src/plugins/spam_report/spam_report.c + Make curl dependancy mandatory + * src/plugins/notification/notification_plugin.c + Fix build with every possible thing disabled + * src/plugins/notification/Makefile.am + * src/plugins/notification/gtkhotkey/.cvsignore + * src/plugins/notification/gtkhotkey/Makefile.am + * src/plugins/notification/gtkhotkey/gtk-hotkey-error.c + * src/plugins/notification/gtkhotkey/gtk-hotkey-error.h + * src/plugins/notification/gtkhotkey/gtk-hotkey-info.c + * src/plugins/notification/gtkhotkey/gtk-hotkey-info.h + * src/plugins/notification/gtkhotkey/gtk-hotkey-key-file-registry.c + * src/plugins/notification/gtkhotkey/gtk-hotkey-key-file-registry.h + * src/plugins/notification/gtkhotkey/gtk-hotkey-listener.c + * src/plugins/notification/gtkhotkey/gtk-hotkey-listener.h + * src/plugins/notification/gtkhotkey/gtk-hotkey-marshal.c + * src/plugins/notification/gtkhotkey/gtk-hotkey-marshal.h + * src/plugins/notification/gtkhotkey/gtk-hotkey-registry.c + * src/plugins/notification/gtkhotkey/gtk-hotkey-registry.h + * src/plugins/notification/gtkhotkey/gtk-hotkey-utils.c + * src/plugins/notification/gtkhotkey/gtk-hotkey-utils.h + * src/plugins/notification/gtkhotkey/gtk-hotkey-x11-listener.c + * src/plugins/notification/gtkhotkey/gtk-hotkey-x11-listener.h + * src/plugins/notification/gtkhotkey/gtkhotkey.h + * src/plugins/notification/gtkhotkey/x11/eggaccelerators.c + * src/plugins/notification/gtkhotkey/x11/eggaccelerators.h + * src/plugins/notification/gtkhotkey/x11/tomboykeybinder.c + * src/plugins/notification/gtkhotkey/x11/tomboykeybinder.h + Re-add hotkey support + * src/plugins/spam_report/Makefile.am + * src/plugins/tnef_parse/Makefile.am + Remove gettext.h + 2013-02-20 [colin] 3.9.0cvs84 * configure.ac diff --git a/PATCHSETS b/PATCHSETS @@ -4582,3 +4582,4 @@ ( cvs diff -u -r 1.1.2.7 -r 1.1.2.8 src/plugins/bogofilter/Makefile.am; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/clamd/Makefile.am; cvs diff -u -r 1.3.2.4 -r 1.3.2.5 src/plugins/demo/Makefile.am; cvs diff -u -r 1.4.2.9 -r 1.4.2.10 src/plugins/dillo_viewer/Makefile.am; cvs diff -u -r 1.1.2.2 -r 1.1.2.3 src/plugins/fancy/Makefile.am; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/fetchinfo/Makefile.am; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/gdata/Makefile.am; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/mailmbox/Makefile.am; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/newmail/Makefile.am; cvs diff -u -r 1.1.2.3 -r 1.1.2.4 src/plugins/notification/Makefile.am; cvs diff -u -r 1.1.2.2 -r 1.1.2.3 src/plugins/pdf_viewer/Makefile.am; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/perl/Makefile.am; cvs diff -u -r 1.1.2.2 -r 1.1.2.3 src/plugins/python/Makefile.am; cvs diff -u -r 1.5.2.10 -r 1.5.2.11 src/plugins/spamassassin/Makefile.am; cvs diff -u -r 1.4.2.14 -r 1.4.2.15 src/plugins/trayicon/Makefile.am; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/vcalendar/libical/libical/Makefile.am; ) > 3.9.0cvs82.patchset ( cvs diff -u -r 1.654.2.4659 -r 1.654.2.4660 configure.ac; cvs diff -u -r 1.8.2.14 -r 1.8.2.15 src/plugins/Makefile.am; diff -u /dev/null src/plugins/spam_report/.cvsignore; diff -u /dev/null src/plugins/spam_report/Makefile.am; cvs diff -u -r -1.1.2.1 -r -1.1.2.2 src/plugins/spam_report/placeholder.txt; diff -u /dev/null src/plugins/spam_report/spam_report.c; diff -u /dev/null src/plugins/spam_report/spam_report_prefs.c; diff -u /dev/null src/plugins/spam_report/spam_report_prefs.h; diff -u /dev/null src/plugins/tnef_parse/.cvsignore; diff -u /dev/null src/plugins/tnef_parse/Makefile.am; diff -u /dev/null src/plugins/tnef_parse/claws.def; diff -u /dev/null src/plugins/tnef_parse/mapi.h; diff -u /dev/null src/plugins/tnef_parse/mapidefs.h; diff -u /dev/null src/plugins/tnef_parse/mapitags.h; cvs diff -u -r -1.1.2.1 -r -1.1.2.2 src/plugins/tnef_parse/placeholder.txt; diff -u /dev/null src/plugins/tnef_parse/plugin.def; diff -u /dev/null src/plugins/tnef_parse/tnef-errors.h; diff -u /dev/null src/plugins/tnef_parse/tnef-types.h; diff -u /dev/null src/plugins/tnef_parse/tnef_dump.c; diff -u /dev/null src/plugins/tnef_parse/tnef_dump.h; diff -u /dev/null src/plugins/tnef_parse/tnef_parse.c; diff -u /dev/null src/plugins/tnef_parse/version.rc; diff -u /dev/null src/plugins/tnef_parse/ytnef.c; diff -u /dev/null src/plugins/tnef_parse/ytnef.h; ) > 3.9.0cvs83.patchset ( cvs diff -u -r 1.654.2.4660 -r 1.654.2.4661 configure.ac; cvs diff -u -r 1.53.2.46 -r 1.53.2.47 po/POTFILES.in; cvs diff -u -r 1.8.2.15 -r 1.8.2.16 src/plugins/Makefile.am; cvs diff -u -r -1.1 -r -1.2 src/plugins/dillo_viewer/.cvsignore; cvs diff -u -r -1.4.2.10 -r -1.4.2.11 src/plugins/dillo_viewer/Makefile.am; cvs diff -u -r -1.2.4.2 -r -1.2.4.3 src/plugins/dillo_viewer/README; cvs diff -u -r -1.5.2.30 -r -1.5.2.31 src/plugins/dillo_viewer/dillo_prefs.c; cvs diff -u -r -1.2.4.11 -r -1.2.4.12 src/plugins/dillo_viewer/dillo_prefs.h; cvs diff -u -r -1.12.2.32 -r -1.12.2.33 src/plugins/dillo_viewer/dillo_viewer.c; cvs diff -u -r -1.1 -r -1.2 src/plugins/trayicon/.cvsignore; cvs diff -u -r -1.4.2.15 -r -1.4.2.16 src/plugins/trayicon/Makefile.am; cvs diff -u -r -1.1.4.1 -r -1.1.4.2 src/plugins/trayicon/README; cvs diff -u -r -1.14.2.83 -r -1.14.2.84 src/plugins/trayicon/trayicon.c; cvs diff -u -r -1.1.2.12 -r -1.1.2.13 src/plugins/trayicon/trayicon_prefs.c; cvs diff -u -r -1.1.2.7 -r -1.1.2.8 src/plugins/trayicon/trayicon_prefs.h; cvs diff -u -r -1.1.4.2 -r -1.1.4.3 src/plugins/trayicon/libeggtrayicon/.cvsignore; ) > 3.9.0cvs84.patchset +( cvs diff -u -r 1.654.2.4661 -r 1.654.2.4662 configure.ac; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/fancy/fancy_viewer.c; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/fancy/fancy_viewer.h; cvs diff -u -r 1.1.2.4 -r 1.1.2.5 src/plugins/notification/Makefile.am; cvs diff -u -r 1.1.2.2 -r 1.1.2.3 src/plugins/notification/notification_plugin.c; diff -u /dev/null src/plugins/notification/gtkhotkey/.cvsignore; diff -u /dev/null src/plugins/notification/gtkhotkey/Makefile.am; diff -u /dev/null src/plugins/notification/gtkhotkey/gtk-hotkey-error.c; diff -u /dev/null src/plugins/notification/gtkhotkey/gtk-hotkey-error.h; diff -u /dev/null src/plugins/notification/gtkhotkey/gtk-hotkey-info.c; diff -u /dev/null src/plugins/notification/gtkhotkey/gtk-hotkey-info.h; diff -u /dev/null src/plugins/notification/gtkhotkey/gtk-hotkey-key-file-registry.c; diff -u /dev/null src/plugins/notification/gtkhotkey/gtk-hotkey-key-file-registry.h; diff -u /dev/null src/plugins/notification/gtkhotkey/gtk-hotkey-listener.c; diff -u /dev/null src/plugins/notification/gtkhotkey/gtk-hotkey-listener.h; diff -u /dev/null src/plugins/notification/gtkhotkey/gtk-hotkey-marshal.c; diff -u /dev/null src/plugins/notification/gtkhotkey/gtk-hotkey-marshal.h; diff -u /dev/null src/plugins/notification/gtkhotkey/gtk-hotkey-registry.c; diff -u /dev/null src/plugins/notification/gtkhotkey/gtk-hotkey-registry.h; diff -u /dev/null src/plugins/notification/gtkhotkey/gtk-hotkey-utils.c; diff -u /dev/null src/plugins/notification/gtkhotkey/gtk-hotkey-utils.h; diff -u /dev/null src/plugins/notification/gtkhotkey/gtk-hotkey-x11-listener.c; diff -u /dev/null src/plugins/notification/gtkhotkey/gtk-hotkey-x11-listener.h; diff -u /dev/null src/plugins/notification/gtkhotkey/gtkhotkey.h; diff -u /dev/null src/plugins/notification/gtkhotkey/x11/eggaccelerators.c; diff -u /dev/null src/plugins/notification/gtkhotkey/x11/eggaccelerators.h; diff -u /dev/null src/plugins/notification/gtkhotkey/x11/tomboykeybinder.c; diff -u /dev/null src/plugins/notification/gtkhotkey/x11/tomboykeybinder.h; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/spam_report/Makefile.am; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/spam_report/spam_report.c; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/tnef_parse/Makefile.am; ) > 3.9.0cvs85.patchset diff --git a/configure.ac b/configure.ac @@ -12,7 +12,7 @@ MINOR_VERSION=9 MICRO_VERSION=0 INTERFACE_AGE=0 BINARY_AGE=0 -EXTRA_VERSION=84 +EXTRA_VERSION=85 EXTRA_RELEASE= EXTRA_GTK2_VERSION= @@ -846,607 +846,931 @@ else enable_networkmanager_support=no fi +dnl Libetpan +AC_MSG_CHECKING([whether to use libetpan]) +AC_ARG_ENABLE(libetpan, + [ --disable-libetpan disable IMAP4/NNTP (libetpan) support], + [ac_cv_enable_libetpan=$enableval], [ac_cv_enable_libetpan=yes]) +if test x"$ac_cv_enable_libetpan" = xyes; then + AC_MSG_RESULT(yes) + libetpan_result=no + AC_PATH_PROG(libetpanconfig, [libetpan-config]) + if test "x$libetpanconfig" != "x"; then + CPPFLAGS="$CPPFLAGS `$libetpanconfig --cflags 2>/dev/null`" + AC_CHECK_HEADER(libetpan/libetpan.h, [libetpan_result=yes]) + if test "x$libetpan_result" = "xyes"; then + AC_MSG_CHECKING([whether libetpan-config hints compiles and links fine]) + LIBS="$LIBS `$libetpanconfig --libs 2>/dev/null`" + AC_TRY_LINK([#include <libetpan/dbstorage.h>], [db_mailstorage_init(NULL, NULL);], [libetpan_result=yes], [libetpan_result=no]) + AC_MSG_RESULT([$libetpan_result]) + fi + fi + if test "x$libetpan_result" = "xyes"; then + LIBETPAN_CPPFLAGS="`$libetpanconfig --cflags`" + LIBETPAN_LIBS="`$libetpanconfig --libs`" + LIBETPAN_STABLE=`$libetpanconfig --version | grep -v ^0` + LIBETPAN_VERSION=`$libetpanconfig --version | sed "s/\.//g" | sed "s/-.*$//"` + if test x"$LIBETPAN_STABLE" != "x"; then + LIBETPAN_VERSION="100" + fi + if test "$LIBETPAN_VERSION" -lt "057"; then + AC_MSG_RESULT([*** Claws Mail requires libetpan 0.57 or newer. See http://www.etpan.org/]) + AC_MSG_RESULT([*** You can use --disable-libetpan if you don't need IMAP4 and/or NNTP support.]) + AC_MSG_ERROR([libetpan 0.57 not found]) + fi + AC_SUBST(LIBETPAN_FLAGS) + AC_SUBST(LIBETPAN_LIBS) + AC_DEFINE(HAVE_LIBETPAN, 1, Define if you want IMAP and/or NNTP support.) + else + AC_MSG_RESULT([*** Claws Mail requires libetpan 0.57 or newer. See http://www.etpan.org/ ]) + AC_MSG_RESULT([*** You can use --disable-libetpan if you don't need IMAP4 and/or NNTP support.]) + AC_MSG_ERROR([libetpan 0.57 not found]) + fi +else + AC_MSG_RESULT(no) +fi +AM_CONDITIONAL(CLAWS_LIBETPAN, test "x$libetpan_result" = "xyes") + +AC_MSG_CHECKING([whether to use valgrind]) +AC_ARG_ENABLE(valgrind, + [ --disable-valgrind disable valgrind support for debugging], + [ac_cv_enable_valgrind=$enableval], [ac_cv_enable_valgrind=yes]) +if test x$ac_cv_enable_valgrind = xyes; then + AC_MSG_RESULT(yes) + PKG_CHECK_MODULES(VALGRIND, valgrind >= 2.4.0, + ac_cv_enable_valgrind=yes, ac_cv_enable_valgrind=no) + if test x"$ac_cv_enable_valgrind" = xyes; then + AC_DEFINE(HAVE_VALGRIND, 1, Define if you want valgrind support) + else + AC_MSG_RESULT(not found) + fi +else + AC_MSG_RESULT(no) +fi +AM_CONDITIONAL(CLAWS_VALGRIND, test x"$ac_cv_enable_valgrind" = x"yes") + dnl ************************* dnl ** section for plugins ** dnl ************************* PLUGINS="" +DISABLED_PLUGINS="" +MISSING_DEPS_PLUGINS="" + +dnl First we set the enabled status - either enabled (yes), auto-enabled (auto) +dnl or (auto-)disabled (no for both) +dnl +dnl All plugins are auto-enabled except for Demo which is just there to help +dnl potential plugins writers. + +AC_ARG_ENABLE(acpi_notifier-plugin, + [ --disable-acpi_notifier-plugin Do not build acpi_notifier plugin], + [enable_acpi_notifier_plugin=$enableval], [enable_acpi_notifier_plugin=auto]) + +AC_ARG_ENABLE(address_keeper-plugin, + [ --disable-address_keeper-plugin Do not build address_keeper plugin], + [enable_address_keeper_plugin=$enableval], [enable_address_keeper_plugin=auto]) + +AC_ARG_ENABLE(archive-plugin, + [ --disable-archive-plugin Do not build archive plugin], + [enable_archive_plugin=$enableval], [enable_archive_plugin=auto]) + +AC_ARG_ENABLE(att_remover-plugin, + [ --disable-att_remover-plugin Do not build att_remover plugin], + [enable_att_remover_plugin=$enableval], [enable_att_remover_plugin=auto]) + +AC_ARG_ENABLE(attachwarner-plugin, + [ --disable-attachwarner-plugin Do not build attachwarner plugin], + [enable_attachwarner_plugin=$enableval], [enable_attachwarner_plugin=auto]) + +AC_ARG_ENABLE(bogofilter-plugin, + [ --disable-bogofilter-plugin Do not build bogofilter plugin], + [enable_bogofilter_plugin=$enableval], [enable_bogofilter_plugin=auto]) + +AC_ARG_ENABLE(bsfilter-plugin, + [ --disable-bsfilter-plugin Do not build bsfilter plugin], + [enable_bsfilter_plugin=$enableval], [enable_bsfilter_plugin=auto]) + +AC_ARG_ENABLE(clamd-plugin, + [ --disable-clamd-plugin Do not build clamd plugin], + [enable_clamd_plugin=$enableval], [enable_clamd_plugin=auto]) -dnl Find curl-config, used by fancy, vcalendar -PKG_CHECK_MODULES(CURL, libcurl, [have_curl=yes], [have_curl=no]) +AC_ARG_ENABLE(fancy-plugin, + [ --disable-fancy-plugin Do not build fancy plugin], + [enable_fancy_plugin=$enableval], [enable_fancy_plugin=auto]) + +AC_ARG_ENABLE(fetchinfo-plugin, + [ --disable-fetchinfo-plugin Do not build fetchinfo plugin], + [enable_fetchinfo_plugin=$enableval], [enable_fetchinfo_plugin=auto]) + +AC_ARG_ENABLE(gdata-plugin, + [ --disable-gdata-plugin Do not build gdata plugin], + [enable_gdata_plugin=$enableval], [enable_gdata_plugin=auto]) + +AC_ARG_ENABLE(mailmbox-plugin, + [ --disable-mailmbox-plugin Do not build mailmbox plugin], + [enable_mailmbox_plugin=$enableval], [enable_mailmbox_plugin=auto]) + +AC_ARG_ENABLE(newmail-plugin, + [ --disable-newmail-plugin Do not build newmail plugin], + [enable_newmail_plugin=$enableval], [enable_newmail_plugin=auto]) + +AC_ARG_ENABLE(notification-plugin, + [ --disable-notification-plugin Do not build notification plugin], + [enable_notification_plugin=$enableval], [enable_notification_plugin=auto]) + +AC_ARG_ENABLE(pdf_viewer-plugin, + [ --disable-pdf_viewer-plugin Do not build pdf_viewer plugin], + [enable_pdf_viewer_plugin=$enableval], [enable_pdf_viewer_plugin=auto]) + +AC_ARG_ENABLE(perl-plugin, + [ --disable-perl-plugin Do not build perl plugin], + [enable_perl_plugin=$enableval], [enable_perl_plugin=auto]) + +AC_ARG_ENABLE(python-plugin, + [ --disable-python-plugin Do not build python plugin], + [enable_python_plugin=$enableval], [enable_python_plugin=auto]) + +AC_ARG_ENABLE(pgpcore-plugin, + [ --disable-pgpcore-plugin Do not build pgpcore plugin], + [enable_pgpcore_plugin=$enableval], [enable_pgpcore_plugin=auto]) + +AC_ARG_ENABLE(pgpmime-plugin, + [ --disable-pgpmime-plugin Do not build pgpmime plugin], + [enable_pgpmime_plugin=$enableval], [enable_pgpmime_plugin=auto]) + +AC_ARG_ENABLE(pgpinline-plugin, + [ --disable-pgpinline-plugin Do not build pgpinline plugin], + [enable_pgpinline_plugin=$enableval], [enable_pgpinline_plugin=auto]) + +AC_ARG_ENABLE(rssyl-plugin, + [ --disable-rssyl-plugin Do not build rssyl plugin], + [enable_rssyl_plugin=$enableval], [enable_rssyl_plugin=auto]) + +AC_ARG_ENABLE(smime-plugin, + [ --disable-smime-plugin Do not build smime plugin], + [enable_smime_plugin=$enableval], [enable_smime_plugin=auto]) + +AC_ARG_ENABLE(spamassassin-plugin, + [ --disable-spamassassin-plugin Do not build spamassassin plugin], + [enable_spamassassin_plugin=$enableval], [enable_spamassassin_plugin=auto]) + +AC_ARG_ENABLE(spam_report-plugin, + [ --disable-spam_report-plugin Do not build spam_report plugin], + [enable_spam_report_plugin=$enableval], [enable_spam_report_plugin=auto]) + +AC_ARG_ENABLE(tnef_parse-plugin, + [ --disable-tnef_parse-plugin Do not build tnef_parse plugin], + [enable_tnef_parse_plugin=$enableval], [enable_tnef_parse_plugin=auto]) + +AC_ARG_ENABLE(vcalendar-plugin, + [ --disable-vcalendar-plugin Do not build vcalendar plugin], + [enable_vcalendar_plugin=$enableval], [enable_vcalendar_plugin=auto]) + +dnl disabled by default +AC_ARG_ENABLE(demo-plugin, + [ --enable-demo-plugin Build demo plugin], + [enable_demo_plugin=$enableval], [enable_demo_plugin=no]) + + +dnl Then we check (unconditionnaly) for plugins dependencies +dnl Some dependancies are optional, some mandatories. This is taken care of +dnl later. +dnl +dnl During this dependancy check we do the checks themselves, define HAVE_X to +dnl either yes or no, and do the AC_SUBST calls. + +dnl Archive: libarchive +dnl Fancy: Webkit, curl, optionally libsoup-gnome, gtkprintunix +dnl Gdata: libgdata +dnl Notification: optionally libnotify libindicate libcanberra_gtk hotkey +dnl Pdf-Viewer: libpoppler +dnl Perl: sed perl +dnl PGP/Core: libgpgme +dnl PGP/Mime: pgpcore libgpgme +dnl PGP/Inline: pgpcore libgpgme +dnl S/Mime: pgpcore libgpgme +dnl Python: Python +dnl RSSyl: libxml2 libcurl +dnl SpamReport: libcurl +dnl vCalendar: libcurl + +dnl libcurl ******************************************************************** +PKG_CHECK_MODULES(CURL, libcurl, HAVE_CURL=yes, HAVE_CURL=no) AC_SUBST(CURL_LIBS) AC_SUBST(CURL_CFLAGS) -dnl --- acpi_notifier --- -AC_ARG_ENABLE(acpi_notifier-plugin, - [ --disable-acpi_notifier-plugin do not build acpi_notifier plugin], - [ac_cv_enable_acpi_notifier_plugin=$enableval], [ac_cv_enable_acpi_notifier_plugin=yes]) -if test x"$ac_cv_enable_acpi_notifier_plugin" = xyes; then - PLUGINS="acpi_notifier $PLUGINS" +dnl libxml2 ******************************************************************** +PKG_CHECK_MODULES(LIBXML, libxml-2.0, HAVE_LIBXML=yes, HAVE_LIBXML=no) +AC_SUBST(LIBXML_LIBS) +AC_SUBST(LIBXML_CFLAGS) + +dnl webkit ********************************************************************* +PKG_CHECK_MODULES(WEBKIT, webkit-1.0, HAVE_WEBKIT=yes, HAVE_WEBKIT=no) +AC_SUBST(WEBKIT_LIBS) +AC_SUBST(WEBKIT_CFLAGS) + +dnl libsoup-gnome ************************************************************** +PKG_CHECK_MODULES(LIBSOUP_GNOME, libsoup-gnome-2.4 >= 2.26, HAVE_LIBSOUP_GNOME=yes, HAVE_LIBSOUP_GNOME=no) +if test x"$HAVE_LIBSOUP_GNOME" = xyes; then + AC_DEFINE(HAVE_LIBSOUP_GNOME, 1, [Define if libsoup is available]) +fi +AC_SUBST(LIBSOUP_GNOME_CFLAGS) +AC_SUBST(LIBSOUP_GNOME_LIBS) + +dnl gtkprintunix *************************************************************** +PKG_CHECK_MODULES(GTKPRINTUNIX, gtk+-unix-print-2.0, HAVE_GTKPRINTUNIX=yes, HAVE_GTKPRINTUNIX=no) +if test x"$HAVE_GTKPRINTUNIX" = xyes; then + AC_DEFINE(HAVE_GTKPRINTUNIX, 1, [Define if GtkPrintUnix is available]) +fi +AC_SUBST(GTKPRINTUNIX_CFLAGS) +AC_SUBST(GTKPRINTUNIX_LIBS) + +dnl libarchive ***************************************************************** +AC_SEARCH_LIBS([archive_read_new], [archive], + ARCHIVE_LIBS=-larchive + HAVE_ARCHIVE=yes + AC_SUBST(ARCHIVE_LIBS), + HAVE_ARCHIVE=no + ) + +dnl libgdata ******************************************************************* +dnl Plugin handles compatibility back to 0.6.4 so there are multiple checks. +PKG_CHECK_MODULES(GDATA, libgdata >= 0.9.1, HAVE_GDATA=yes, HAVE_GDATA=no) +if test x"$HAVE_GDATA" = xyes; then + AC_DEFINE(HAVE_GDATA_VERSION_0_9_1, 1, [at least version 0.9.1 of libgdata is available]) + AC_DEFINE(HAVE_GDATA_VERSION_0_9, 1, [at least version 0.9 of libgdata is available]) +else + PKG_CHECK_MODULES(GDATA, libgdata >= 0.9, HAVE_GDATA=yes, HAVE_GDATA=no) +fi +if test x"$HAVE_GDATA" = xyes; then + AC_DEFINE(HAVE_GDATA_VERSION_0_9, 1, [at least version 0.9 of libgdata is available]) +else + PKG_CHECK_MODULES(GDATA, libgdata >= 0.6.4, HAVE_GDATA=yes, HAVE_GDATA=no) +fi +if test x"$HAVE_GDATA" = xyes; then + AC_DEFINE(CM_GDATA_CLIENT_ID, ["Claws Mail GData plugin"], [client id]) +fi +AC_SUBST(GDATA_CFLAGS) +AC_SUBST(GDATA_LIBS) + +dnl Poppler ******************************************************************** +PKG_CHECK_MODULES(POPPLER, poppler-glib >= 0.4.2, HAVE_POPPLER=yes, HAVE_POPPLER=no) +AC_SUBST(POPPLER_LIBS) +AC_SUBST(POPPLER_CFLAGS) + +dnl check for Poppler extra features that we conditionally support +if test x"$HAVE_POPPLER" = xyes; then + OLD_CFLAGS=$CFLAGS + CFLAGS="$POPPLER_CFLAGS $GTK_CFLAGS $GLIB_CFLAGS" + AC_CHECK_DECL(POPPLER_DEST_NAMED, + [AC_DEFINE([HAVE_POPPLER_DEST_NAMED], [], [Description])], + ,[#include <poppler-action.h>]) + AC_CHECK_DECL(POPPLER_DEST_XYZ, + [AC_DEFINE([HAVE_POPPLER_DEST_XYZ], [], [Description])], + ,[#include <poppler-action.h>]) + CFLAGS=$OLD_CFLAGS +fi + +dnl sed ************************************************************************ +AC_CHECK_PROG(HAVE_SED, sed, yes, no) + +dnl perl *********************************************************************** +AC_CHECK_PROG(HAVE_PERL, perl, yes, no) +if test x"$HAVE_PERL" = xyes; then + AC_MSG_CHECKING(for perl >= 5.8.0) + PERL_VER=`perl -e 'print $] > 5.0079999?"yes":"no"'` + if test "$PERL_VER" = "yes"; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + HAVE_PERL=no + fi +fi +if test x"$HAVE_PERL" = xyes; then + AC_MSG_CHECKING(for Perl compile flags) + if test x"$HAVE_SED" = xno; then + AC_MSG_RESULT(no - missing sed) + HAVE_PERL=no + else + PERL_CFLAGS=`perl -MExtUtils::Embed -e ccopts` + PERL_CFLAGS=`echo $PERL_CFLAGS | sed 's/-D_FILE_OFFSET_BITS=[[0-9]]*//'` + PERL_LDFLAGS=`perl -MExtUtils::Embed -e ldopts |sed 's/-lgdbm//'` + PERL_LDFLAGS=`echo $PERL_LDFLAGS |sed 's/-ldb//'` + PERL_LDFLAGS=`echo $PERL_LDFLAGS |sed 's/-lndbm//'` + PERL_LDFLAGS=`echo $PERL_LDFLAGS |sed 's/-lc//'` + AC_MSG_RESULT(ok) + fi + AC_SUBST(PERL_CFLAGS) + AC_SUBST(PERL_LDFLAGS) +fi + +dnl Gpgme ********************************************************************** +AM_PATH_GPGME(1.0.0, HAVE_GPGME=yes, HAVE_GPGME=no) +if test x"$HAVE_GPGME" = xyes; then + AC_DEFINE(USE_GPGME, 1, Define if you use GPGME to support OpenPGP.) + AM_PATH_GPGME(1.1.1, AC_DEFINE(HAVE_GPGME_PKA_TRUST, 1, [Define if GPGME supports PKA.])) +fi + +dnl Python ********************************************************************* +AM_PATH_PYTHON([2.5], [ + AC_PATH_PROG(PYTHON_CONFIG, python$PYTHON_VERSION-config) + if test x"$PYTHON_CONFIG" = x"" ; then + AC_PATH_PROG(PYTHON_CONFIG, python-config) + fi + if test x"$PYTHON_CONFIG" != x""; then + PYTHON_CFLAGS=`$PYTHON_CONFIG --includes` + PYTHON_LIBS=`$PYTHON_CONFIG --libs` + PYTHON_PREFIX=`$PYTHON_CONFIG --prefix` + HAVE_PYTHON=yes + else + AC_MSG_WARN(python-config not found. Maybe you need to install development packages for Python.) + HAVE_PYTHON=no + fi + + if test x"$HAVE_PYTHON" = xyes; then + # libpython.so + PYTHON_SO_FILE="libpython${PYTHON_VERSION}.so" + found_libpython_so="no" + if test -f "$PYTHON_PREFIX/lib/$PYTHON_SO_FILE"; then + found_libpython_so="yes" + PYTHON_SHARED_LIB=`python -c "import os,sys; print os.path.basename(os.path.realpath(\"$PYTHON_PREFIX/lib/$PYTHON_SO_FILE\"))"` + fi + if test -f "$PYTHON_PREFIX/lib64/$PYTHON_SO_FILE"; then + found_libpython_so="yes" + PYTHON_SHARED_LIB=`python -c "import os,sys; print os.path.basename(os.path.realpath(\"$PYTHON_PREFIX/lib64/$PYTHON_SO_FILE\"))"` + fi + if test x"$found_libpython_so" != x"yes"; then + AC_MSG_WARN(Could not find Python shared libary: $PYTHON_SO_FILE does not exist. Maybe you need to install development packages for Python.) + HAVE_PYTHON=no + fi + fi + if test x"$HAVE_PYTHON" = xyes; then + PKG_CHECK_MODULES(PYGTK, pygtk-2.0 >= 2.10.3, [AC_DEFINE(ENABLE_PYTHON, [1], [Enable Python support])], HAVE_PYTHON=no) + fi +]) +AC_SUBST(PYTHON_SHARED_LIB) +AC_SUBST(PYTHON_CFLAGS) +AC_SUBST(PYTHON_LIBS) +AC_SUBST(PYGTK_CFLAGS) +AC_SUBST(PYGTK_LIBS) + +dnl libnotify ****************************************************************** +PKG_CHECK_MODULES(libnotify, libnotify >= 0.4.3, HAVE_LIBNOTIFY=yes, HAVE_LIBNOTIFY=no) +if test x"$HAVE_LIBNOTIFY" = xyes; then + AC_DEFINE(HAVE_LIBNOTIFY, 1, [Define if libnotify support is enabled]) +fi +AC_SUBST(libnotify_CFLAGS) +AC_SUBST(libnotify_LIBS) + +dnl libcanberra-gtk ************************************************************ +PKG_CHECK_MODULES(libcanberra_gtk, libcanberra-gtk >= 0.6, HAVE_LIBCANBERRA_GTK=yes, HAVE_LIBCANBERRA_GTK=no) +if test x"$HAVE_LIBCANBERRA_GTK" = xyes; then + AC_DEFINE(HAVE_LIBCANBERRA_GTK, 1, [Define if libcanberra-gtk support is enabled]) +fi +AC_SUBST(libcanberra_gtk_CFLAGS) +AC_SUBST(libcanberra_gtk_LIBS) + +dnl libindicate **************************************************************** +dnl We support either 0.3+ or 0.5+ +LIBINDICATE_MODULE=indicate +LIBINDICATE_REQUIRED=0.3.0 + +PKG_CHECK_EXISTS(indicate-0.5 >= 0.5.0, LIBINDICATE_MODULE=indicate-0.5) +PKG_CHECK_MODULES(libindicate, $LIBINDICATE_MODULE >= $LIBINDICATE_REQUIRED, HAVE_LIBINDICATE=yes, HAVE_LIBINDICATE=no) +if test x"$HAVE_LIBINDICATE" = xyes; then + AC_DEFINE(NOTIFICATION_INDICATOR, 1, [Activate support for indicators]) +fi +AC_SUBST(libindicate_CFLAGS) +AC_SUBST(libindicate_LIBS) + +dnl hotkeys ******************************************************************** +PKG_CHECK_MODULES(CM_NP_HOTKEY, [gio-2.0 >= 2.15.6 gio-unix-2.0 >= 2.15.6], HAVE_HOTKEYS=yes, HAVE_HOTKEYS=no) +if test x"$HAVE_HOTKEYS" = xyes; then + AC_DEFINE(NOTIFICATION_HOTKEYS, 1, Activate support for global hotkeys) +fi +AC_SUBST(CM_NP_HOTKEY_CFLAGS) +AC_SUBST(CM_NP_HOTKEY_LIBS) + + +dnl Third, we now cross the requested plugins and the available dependancies +dnl If some dependancies are missing and the plugin was explicitely enabled, +dnl we error out, else we only inform. + +AC_MSG_CHECKING([whether to build acpi_notifier plugin]) +if test x"$enable_acpi_notifier_plugin" != xno; then + PLUGINS="$PLUGINS acpi_notifier" AC_MSG_RESULT(yes) else + DISABLED_PLUGINS="$DISABLED_PLUGINS acpi_notifier" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_ACPI_NOTIFIER_PLUGIN, test x"$ac_cv_enable_acpi_notifier_plugin" = xyes) - -dnl --- address_keeper --- -AC_ARG_ENABLE(address_keeper-plugin, - [ --disable-address_keeper-plugin do not build address_keeper plugin], - [ac_cv_enable_address_keeper_plugin=$enableval], [ac_cv_enable_address_keeper_plugin=yes]) -if test x"$ac_cv_enable_address_keeper_plugin" = xyes; then - PLUGINS="address_keeper $PLUGINS" + +AC_MSG_CHECKING([whether to build address_keeper plugin]) +if test x"$enable_address_keeper_plugin" != xno; then + PLUGINS="$PLUGINS address_keeper" AC_MSG_RESULT(yes) else + DISABLED_PLUGINS="$DISABLED_PLUGINS address_keeper" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_ADDRESS_KEEPER_PLUGIN, test x"$ac_cv_enable_address_keeper_plugin" = xyes) - -dnl --- archive --- -AC_ARG_ENABLE(archive-plugin, - [ --disable-archive-plugin do not build archive plugin], - [ac_cv_enable_archive_plugin=$enableval], [ac_cv_enable_archive_plugin=yes]) -if test x"$ac_cv_enable_archive_plugin" = xyes; then - AC_SEARCH_LIBS([archive_read_new], [archive], - ARCHIVE_LIBS=-larchive - AC_SUBST(ARCHIVE_LIBS), - echo "You need to install libarchive" - exit 1 - ) - PLUGINS="archive $PLUGINS" - AC_MSG_RESULT(yes) + +AC_MSG_CHECKING([whether to build archive plugin]) +if test x"$enable_archive_plugin" != xno; then + dependancies_missing="" + + if test x"$HAVE_ARCHIVE" = xno; then + dependancies_missing="libarchive $dependancies_missing" + fi + + if test x"$dependancies_missing" = x; then + PLUGINS="$PLUGINS archive" + AC_MSG_RESULT(yes) + elif test x"$enable_archive_plugin" = xauto; then + AC_MSG_RESULT(no) + AC_MSG_WARN("Plugin archive will not be built; missing $dependancies_missing") + enable_archive_plugin=no + MISSING_DEPS_PLUGINS="$MISSING_DEPS_PLUGINS archive" + else + AC_MSG_RESULT(no) + AC_MSG_ERROR("Plugin archive can not be built; missing $dependancies_missing") + fi else + DISABLED_PLUGINS="$DISABLED_PLUGINS archive" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_ARCHIVE_PLUGIN, test x"$ac_cv_enable_archive_plugin" = xyes) -dnl --- att_remover --- -AC_ARG_ENABLE(att_remover-plugin, - [ --disable-att_remover-plugin do not build att_remover plugin], - [ac_cv_enable_att_remover_plugin=$enableval], [ac_cv_enable_att_remover_plugin=yes]) -if test x"$ac_cv_enable_att_remover_plugin" = xyes; then - PLUGINS="att_remover $PLUGINS" +AC_MSG_CHECKING([whether to build att_remover plugin]) +if test x"$enable_att_remover_plugin" != xno; then + PLUGINS="$PLUGINS att_remover" AC_MSG_RESULT(yes) else + DISABLED_PLUGINS="$DISABLED_PLUGINS att_remover" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_ATT_REMOVER_PLUGIN, test x"$ac_cv_enable_att_remover_plugin" = xyes) -dnl --- attachwarner --- -AC_ARG_ENABLE(attachwarner-plugin, - [ --disable-attachwarner-plugin do not build attachwarner plugin], - [ac_cv_enable_attachwarner_plugin=$enableval], [ac_cv_enable_attachwarner_plugin=yes]) -if test x"$ac_cv_enable_attachwarner_plugin" = xyes; then - PLUGINS="attachwarner $PLUGINS" +AC_MSG_CHECKING([whether to build attachwarner plugin]) +if test x"$enable_attachwarner_plugin" != xno; then + PLUGINS="$PLUGINS attachwarner" AC_MSG_RESULT(yes) else + DISABLED_PLUGINS="$DISABLED_PLUGINS attachwarner" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_ATTACHWARNER_PLUGIN, test x"$ac_cv_enable_attachwarner_plugin" = xyes) -dnl --- Bogofilter --- -AC_MSG_CHECKING([whether to build Bogofilter plugin]) -AC_ARG_ENABLE(bogofilter-plugin, - [ --disable-bogofilter-plugin do not build bogofilter plugin], - [ac_cv_enable_bogofilter_plugin=$enableval], [ac_cv_enable_bogofilter_plugin=yes]) -if test x"$ac_cv_enable_bogofilter_plugin" = xyes; then +AC_MSG_CHECKING([whether to build bogofilter plugin]) +if test x"$enable_bogofilter_plugin" != xno; then + PLUGINS="$PLUGINS bogofilter" AC_MSG_RESULT(yes) - PLUGINS="bogofilter $PLUGINS" - AC_DEFINE(USE_BOGOFILTER_PLUGIN, 1, Define if bogofilter plugin is being built.) else + DISABLED_PLUGINS="$DISABLED_PLUGINS bogofilter" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_BOGOFILTER_PLUGIN, test x"$ac_cv_enable_bogofilter_plugin" = xyes) -dnl --- bsfilter --- AC_MSG_CHECKING([whether to build bsfilter plugin]) -AC_ARG_ENABLE(bsfilter-plugin, - [ --disable-bsfilter-plugin do not build bsfilter plugin], - [ac_cv_enable_bsfilter_plugin=$enableval], [ac_cv_enable_bsfilter_plugin=yes]) -if test x"$ac_cv_enable_bsfilter_plugin" = xyes; then - PLUGINS="bsfilter $PLUGINS" +if test x"$enable_bsfilter_plugin" != xno; then + PLUGINS="$PLUGINS bsfilter" AC_MSG_RESULT(yes) else + DISABLED_PLUGINS="$DISABLED_PLUGINS bsfilter" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_BSFILTER_PLUGIN, test x"$ac_cv_enable_bsfilter_plugin" = xyes) -dnl --- clamd --- AC_MSG_CHECKING([whether to build clamd plugin]) -AC_ARG_ENABLE(clamd-plugin, - [ --disable-clamd-plugin do not build clamd plugin], - [ac_cv_enable_clamd_plugin=$enableval], [ac_cv_enable_clamd_plugin=yes]) -if test x"$ac_cv_enable_clamd_plugin" = xyes; then - PLUGINS="clamd $PLUGINS" +if test x"$enable_clamd_plugin" != xno; then + PLUGINS="$PLUGINS clamd" AC_MSG_RESULT(yes) else + DISABLED_PLUGINS="$DISABLED_PLUGINS clamd" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_CLAMD_PLUGIN, test x"$ac_cv_enable_clamd_plugin" = xyes) -dnl --- Demo --- -AC_ARG_ENABLE(demo-plugin, - [ --enable-demo-plugin build demo plugin], - [ac_cv_enable_demo_plugin=$enableval], [ac_cv_enable_demo_plugin=no]) -if test x"$ac_cv_enable_demo_plugin" = xyes; then - PLUGINS="demo $PLUGINS" +AC_MSG_CHECKING([whether to build demo plugin]) +if test x"$enable_demo_plugin" != xno; then + PLUGINS="$PLUGINS demo" AC_MSG_RESULT(yes) else + DISABLED_PLUGINS="$DISABLED_PLUGINS demo" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_DEMO_PLUGIN, test x"$ac_cv_enable_demo_plugin" = xyes) -dnl --- Fancy --- -AC_MSG_CHECKING([whether to build Fancy plugin]) -AC_ARG_ENABLE(fancy-plugin, - [ --disable-fancy-plugin do not build Fancy plugin for html mail rendering], - [ac_cv_enable_fancy_plugin=$enableval], [ac_cv_enable_fancy_plugin=yes]) -if test x"$ac_cv_enable_fancy_plugin" = xyes; then - AC_MSG_RESULT(yes) - dnl Check for WebKit - PKG_CHECK_MODULES(WEBKIT, webkit-1.0, - [ - PLUGINS="fancy $PLUGINS" - ], - [ - echo "webkit-1.0 not found." - ac_cv_enable_fancy_plugin=no - ]) - AC_SUBST(WEBKIT_LIBS) - AC_SUBST(WEBKIT_CFLAGS) -fi -if test x"$ac_cv_enable_fancy_plugin" = xyes; then - dnl Check for libsoup-gnome - PKG_CHECK_MODULES(LIBSOUP_GNOME, libsoup-gnome-2.4 >= 2.26, ac_cv_enable_soup_gnome=yes, ac_cv_enable_soup_gnome=no) - if test x$ac_cv_enable_soup_gnome = xyes; then - AC_DEFINE(HAVE_LIBSOUP_GNOME, 1, Define if you want soup gnome proxy support) +AC_MSG_CHECKING([whether to build fancy plugin]) +if test x"$enable_fancy_plugin" != xno; then + dependancies_missing="" + + if test x"$HAVE_WEBKIT" = xno; then + dependancies_missing="libwebkit-1.0 $dependancies_missing" fi - AC_SUBST(LIBSOUP_GNOME_CFLAGS) - AC_SUBST(LIBSOUP_GNOME_LIBS) - - PKG_CHECK_MODULES(GTKPRINTUNIX, gtk+-unix-print-2.0, ac_cv_enable_gtkprint=yes, ac_cv_enable_gtkprint=no) - if test x$ac_cv_enable_gtkprint = xyes; then - AC_DEFINE(USE_PRINTUNIX, 1, Define if you want gtk+-unix-print support) + if test x"$HAVE_CURL" = xno; then + dependancies_missing="libcurl $dependancies_missing" + fi + + if test x"$dependancies_missing" = x; then + PLUGINS="$PLUGINS fancy" + AC_MSG_RESULT(yes) + elif test x"$enable_fancy_plugin" = xauto; then + AC_MSG_RESULT(no) + AC_MSG_WARN("Plugin fancy will not be built; missing $dependancies_missing") + enable_fancy_plugin=no + MISSING_DEPS_PLUGINS="$MISSING_DEPS_PLUGINS fancy" else - AC_MSG_RESULT(not found) + AC_MSG_RESULT(no) + AC_MSG_ERROR("Plugin fancy can not be built; missing $dependancies_missing") fi - AC_SUBST(GTKPRINTUNIX_CFLAGS) - AC_SUBST(GTKPRINTUNIX_LIBS) +else + DISABLED_PLUGINS="$DISABLED_PLUGINS fancy" + AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_FANCY_PLUGIN, test x"$ac_cv_enable_fancy_plugin" = xyes) -dnl --- fetchinfo --- AC_MSG_CHECKING([whether to build fetchinfo plugin]) -AC_ARG_ENABLE(fetchinfo-plugin, - [ --disable-fetchinfo-plugin do not build fetchinfo plugin], - [ac_cv_enable_fetchinfo_plugin=$enableval], [ac_cv_enable_fetchinfo_plugin=yes]) -if test x"$ac_cv_enable_fetchinfo_plugin" = xyes; then - PLUGINS="fetchinfo $PLUGINS" +if test x"$enable_fetchinfo_plugin" != xno; then + PLUGINS="$PLUGINS fetchinfo" AC_MSG_RESULT(yes) else + DISABLED_PLUGINS="$DISABLED_PLUGINS fetchinfo" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_FETCHINFO_PLUGIN, test x"$ac_cv_enable_fetchinfo_plugin" = xyes) -dnl --- gdata --- AC_MSG_CHECKING([whether to build gdata plugin]) -AC_ARG_ENABLE(gdata-plugin, - [ --disable-gdata-plugin do not build gdata plugin], - [ac_cv_enable_gdata_plugin=$enableval], [ac_cv_enable_gdata_plugin=yes]) -if test x"$ac_cv_enable_gdata_plugin" = xyes; then - PKG_CHECK_MODULES(GDATA, libgdata >= 0.9.1, [ac_cv_enable_gdata_plugin=yes], [ac_cv_enable_gdata_plugin=no]) - if test x"$ac_cv_enable_gdata_plugin" = xyes; then - AC_DEFINE(HAVE_GDATA_VERSION_0_9_1, 1, [at least version 0.9.1 of libgdata is available]) - AC_DEFINE(HAVE_GDATA_VERSION_0_9, 1, [at least version 0.9.0 of libgdata is available]) - else - PKG_CHECK_MODULES(GDATA, libgdata >= 0.6.4, [ac_cv_enable_gdata_plugin=yes], [ac_cv_enable_gdata_plugin=no]) +if test x"$enable_gdata_plugin" != xno; then + dependancies_missing="" + + if test x"$HAVE_GDATA" = xno; then + dependancies_missing="libgdata $dependancies_missing" fi - if test x"$ac_cv_enable_gdata_plugin" = xyes; then - AC_SUBST(GDATA_CFLAGS) - AC_SUBST(GDATA_LIBS) - AC_DEFINE(CM_GDATA_CLIENT_ID, ["Claws Mail GData plugin"], [client id]) - PLUGINS="gdata $PLUGINS" + if test x"$dependancies_missing" = x; then + PLUGINS="$PLUGINS gdata" AC_MSG_RESULT(yes) + elif test x"$enable_gdata_plugin" = xauto; then + AC_MSG_RESULT(no) + AC_MSG_WARN("Plugin gdata will not be built; missing $dependancies_missing") + enable_gdata_plugin=no + MISSING_DEPS_PLUGINS="$MISSING_DEPS_PLUGINS gdata" else - AC_MSG_ERROR(libgdata is not available) + AC_MSG_RESULT(no) + AC_MSG_ERROR("Plugin gdata can not be built; missing $dependancies_missing") fi else + DISABLED_PLUGINS="$DISABLED_PLUGINS gdata" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_GDATA_PLUGIN, test x"$ac_cv_enable_gdata_plugin" = xyes) -dnl --- mailmbox --- AC_MSG_CHECKING([whether to build mailmbox plugin]) -AC_ARG_ENABLE(mailmbox-plugin, - [ --disable-mailmbox-plugin do not build mailmbox plugin], - [ac_cv_enable_mailmbox_plugin=$enableval], [ac_cv_enable_mailmbox_plugin=yes]) -if test x"$ac_cv_enable_mailmbox_plugin" = xyes; then - PLUGINS="mailmbox $PLUGINS" +if test x"$enable_mailmbox_plugin" != xno; then + PLUGINS="$PLUGINS mailmbox" AC_MSG_RESULT(yes) else + DISABLED_PLUGINS="$DISABLED_PLUGINS mailmbox" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_MAILMBOX_PLUGIN, test x"$ac_cv_enable_mailmbox_plugin" = xyes) -dnl --- newmail --- AC_MSG_CHECKING([whether to build newmail plugin]) -AC_ARG_ENABLE(newmail-plugin, - [ --disable-newmail-plugin do not build newmail plugin], - [ac_cv_enable_newmail_plugin=$enableval], [ac_cv_enable_newmail_plugin=yes]) -if test x"$ac_cv_enable_newmail_plugin" = xyes; then - PLUGINS="newmail $PLUGINS" +if test x"$enable_newmail_plugin" != xno; then + PLUGINS="$PLUGINS newmail" AC_MSG_RESULT(yes) else + DISABLED_PLUGINS="$DISABLED_PLUGINS newmail" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_NEWMAIL_PLUGIN, test x"$ac_cv_enable_newmail_plugin" = xyes) -dnl --- notification - disabled - too many autofoo annoyances for today --- AC_MSG_CHECKING([whether to build notification plugin]) -AC_ARG_ENABLE(notification-plugin, - [ --disable-notification-plugin do not build notification plugin], - [ac_cv_enable_notification_plugin=$enableval], [ac_cv_enable_notification_plugin=yes]) -if test x"$ac_cv_enable_notification_plugin" = xyes; then - LIBNOTIFY_REQUIRED=0.4.3 - PKG_CHECK_MODULES(libnotify, libnotify >= $LIBNOTIFY_REQUIRED, - [AC_DEFINE(HAVE_LIBNOTIFY, 1, [Define if libnotify support is enabled])], - [AC_MSG_ERROR([libnotify not found])]) - AC_SUBST(libnotify_CFLAGS) - AC_SUBST(libnotify_LIBS) +if test x"$enable_notification_plugin" != xno; then + PLUGINS="$PLUGINS notification" + AC_MSG_RESULT(yes) AC_DEFINE(NOTIFICATION_POPUP, 1, Activate notification popup) AC_DEFINE(NOTIFICATION_BANNER, 1, Activate notification banner) AC_DEFINE(NOTIFICATION_COMMAND, 1, Activate notification shell command) AC_DEFINE(NOTIFICATION_TRAYICON, 1, Activate notification trayicon) AC_DEFINE(NOTIFICATION_LCDPROC, 1, Activate lcdproc support) - #AC_DEFINE(NOTIFICATION_INDICATOR, 1, [Activate support for indicators]) - - PLUGINS="notification $PLUGINS" - AC_MSG_RESULT(yes) + + notification_features="(popup:yes banner:yes command:yes trayicon:yes lcdproc:yes" + notification_features="$notification_features libnotify:$HAVE_LIBNOTIFY" + notification_features="$notification_features libindicate:$HAVE_LIBINDICATE" + notification_features="$notification_features libcanberra-gtk:$HAVE_LIBCANBERRA_GTK" + notification_features="$notification_features hotkeys:$HAVE_HOTKEYS)" else + DISABLED_PLUGINS="$DISABLED_PLUGINS notification" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_NOTIFICATION_PLUGIN, test x"$ac_cv_enable_notification_plugin" = xyes) -dnl --- pdf_viewer --- AC_MSG_CHECKING([whether to build pdf_viewer plugin]) -AC_ARG_ENABLE(pdf_viewer-plugin, - [ --disable-pdf_viewer-plugin do not build pdf_viewer plugin], - [ac_cv_enable_pdf_viewer_plugin=$enableval], [ac_cv_enable_pdf_viewer_plugin=yes]) -if test x"$ac_cv_enable_pdf_viewer_plugin" = xyes; then - PKG_CHECK_MODULES(POPPLER, poppler-glib >= 0.4.2, , - AC_MSG_ERROR([Can't find Poppler >= 0.4.2 Glib wrapper])) - AC_SUBST(POPPLER_LIBS) - AC_SUBST(POPPLER_CFLAGS) +if test x"$enable_pdf_viewer_plugin" != xno; then + dependancies_missing="" - OLD_CFLAGS=$CFLAGS - CFLAGS="$POPPLER_CFLAGS $GTK_CFLAGS $GLIB_CFLAGS" - AC_CHECK_DECL(POPPLER_DEST_NAMED, - [AC_DEFINE([HAVE_POPPLER_DEST_NAMED], [], [Description])], - ,[#include <poppler-action.h>]) - AC_CHECK_DECL(POPPLER_DEST_XYZ, - [AC_DEFINE([HAVE_POPPLER_DEST_XYZ], [], [Description])], - ,[#include <poppler-action.h>]) - CFLAGS=$OLD_CFLAGS - PLUGINS="pdf_viewer $PLUGINS" - AC_MSG_RESULT(yes) + if test x"$HAVE_POPPLER" = xno; then + dependancies_missing="libpoppler-glib $dependancies_missing" + fi + + if test x"$dependancies_missing" = x; then + PLUGINS="$PLUGINS pdf_viewer" + AC_MSG_RESULT(yes) + elif test x"$enable_pdf_viewer_plugin" = xauto; then + AC_MSG_RESULT(no) + AC_MSG_WARN("Plugin pdf_viewer will not be built; missing $dependancies_missing") + enable_pdf_viewer_plugin=no + MISSING_DEPS_PLUGINS="$MISSING_DEPS_PLUGINS pdf_viewer" + else + AC_MSG_RESULT(no) + AC_MSG_ERROR("Plugin pdf_viewer can not be built; missing $dependancies_missing") + fi else + DISABLED_PLUGINS="$DISABLED_PLUGINS pdf_viewer" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_PDF_VIEWER_PLUGIN, test x"$ac_cv_enable_pdf_viewer_plugin" = xyes) -dnl --- perl --- AC_MSG_CHECKING([whether to build perl plugin]) -AC_ARG_ENABLE(perl-plugin, - [ --disable-perl-plugin do not build perl plugin], - [ac_cv_enable_perl_plugin=$enableval], [ac_cv_enable_perl_plugin=yes]) -if test x"$ac_cv_enable_perl_plugin" = xyes; then - AC_PATH_PROG(sedpath, sed, no) - if test x$sedpath = xno ; then - AC_MSG_ERROR(Test for sed failed.) - fi +if test x"$enable_perl_plugin" != xno; then + dependancies_missing="" - dnl Perl - AC_PATH_PROG(PERL_PATH, perl, no) - if test x$PERL_PATH = xno ; then - AC_MSG_ERROR(Test for Perl failed) + if test x"$HAVE_PERL" = xno; then + dependancies_missing="perl $dependancies_missing" fi - AC_MSG_CHECKING(for perl >= 5.8.0) - PERL_VER=`$PERL_PATH -e 'print $] > 5.0079999?"yes":"no"'` - if test "$PERL_VER" = "yes"; then - AC_MSG_RESULT(yes) + + if test x"$dependancies_missing" = x; then + PLUGINS="$PLUGINS perl" + AC_MSG_RESULT(yes) + elif test x"$enable_perl_plugin" = xauto; then + AC_MSG_RESULT(no) + AC_MSG_WARN("Plugin perl will not be built; missing $dependancies_missing") + enable_perl_plugin=no + MISSING_DEPS_PLUGINS="$MISSING_DEPS_PLUGINS perl" else - AC_MSG_RESULT(no) - AC_MSG_ERROR(Your Perl version is too old.) + AC_MSG_RESULT(no) + AC_MSG_ERROR("Plugin perl can not be built; missing $dependancies_missing") fi - AC_MSG_CHECKING(for Perl compile flags) - PERL_CFLAGS=`$PERL_PATH -MExtUtils::Embed -e ccopts` - PERL_CFLAGS=`echo $PERL_CFLAGS | $sedpath 's/-D_FILE_OFFSET_BITS=[[0-9]]*//'` - PERL_LDFLAGS=`$PERL_PATH -MExtUtils::Embed -e ldopts |$sedpath 's/-lgdbm//'` - PERL_LDFLAGS=`echo $PERL_LDFLAGS |$sedpath 's/-ldb//'` - PERL_LDFLAGS=`echo $PERL_LDFLAGS |$sedpath 's/-lndbm//'` - PERL_LDFLAGS=`echo $PERL_LDFLAGS |$sedpath 's/-lc//'` - AC_MSG_RESULT(ok) - AC_SUBST(PERL_CFLAGS) - AC_SUBST(PERL_LDFLAGS) - PLUGINS="perl $PLUGINS" - AC_MSG_RESULT(yes) else + DISABLED_PLUGINS="$DISABLED_PLUGINS perl" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_PERL_PLUGIN, test x"$ac_cv_enable_perl_plugin" = xyes) -dnl --- python --- AC_MSG_CHECKING([whether to build python plugin]) -AC_ARG_ENABLE(python-plugin, - [ --disable-python-plugin do not build python plugin], - [ac_cv_enable_python_plugin=$enableval], [ac_cv_enable_python_plugin=yes]) -if test x"$ac_cv_enable_python_plugin" = xyes; then - AM_PATH_PYTHON([2.5], [ - AC_PATH_PROG(PYTHON_CONFIG, python$PYTHON_VERSION-config) - if test x"$PYTHON_CONFIG" = x"" ; then - AC_PATH_PROG(PYTHON_CONFIG, python-config) - fi - if test x"$PYTHON_CONFIG" != x""; then - PYTHON_CFLAGS=`$PYTHON_CONFIG --includes` - PYTHON_LIBS=`$PYTHON_CONFIG --libs` - PYTHON_PREFIX=`$PYTHON_CONFIG --prefix` - else - AC_MSG_ERROR(python-config not found. Maybe you need to install development packages for Python.) - fi +if test x"$enable_python_plugin" != xno; then + dependancies_missing="" - # libpython.so - PYTHON_SO_FILE="libpython${PYTHON_VERSION}.so" - found_libpython_so="no" - if test -f "$PYTHON_PREFIX/lib/$PYTHON_SO_FILE"; then - found_libpython_so="yes" - PYTHON_SHARED_LIB=`python -c "import os,sys; print os.path.basename(os.path.realpath(\"$PYTHON_PREFIX/lib/$PYTHON_SO_FILE\"))"` - fi - if test -f "$PYTHON_PREFIX/lib64/$PYTHON_SO_FILE"; then - found_libpython_so="yes" - PYTHON_SHARED_LIB=`python -c "import os,sys; print os.path.basename(os.path.realpath(\"$PYTHON_PREFIX/lib64/$PYTHON_SO_FILE\"))"` - fi - if test x"$found_libpython_so" != x"yes"; then - AC_MSG_ERROR(Could not find Python shared libary: $PYTHON_SO_FILE does not exist. Maybe you need to install development packages for Python.) - fi - - # PyGTK - PKG_CHECK_MODULES(PYGTK, - [pygtk-2.0 >= 2.10.3], - [ - AC_DEFINE(ENABLE_PYTHON, [1], [Enable Python support]) - ]) - ]) - - AC_SUBST(PYTHON_SHARED_LIB) - AC_SUBST(PYTHON_CFLAGS) - AC_SUBST(PYTHON_LIBS) - AC_SUBST(PYGTK_CFLAGS) - AC_SUBST(PYGTK_LIBS) + if test x"$HAVE_PYTHON" = xno; then + dependancies_missing="python $dependancies_missing" + fi - PLUGINS="python $PLUGINS" - AC_MSG_RESULT(yes) + if test x"$dependancies_missing" = x; then + PLUGINS="$PLUGINS python" + AC_MSG_RESULT(yes) + elif test x"$enable_python_plugin" = xauto; then + AC_MSG_RESULT(no) + AC_MSG_WARN("Plugin python will not be built; missing $dependancies_missing") + enable_python_plugin=no + MISSING_DEPS_PLUGINS="$MISSING_DEPS_PLUGINS python" + else + AC_MSG_RESULT(no) + AC_MSG_ERROR("Plugin python can not be built; missing $dependancies_missing") + fi else + DISABLED_PLUGINS="$DISABLED_PLUGINS python" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_PYTHON_PLUGIN, test x"$ac_cv_enable_python_plugin" = xyes) -dnl --- PGP/CORE --- -AC_MSG_CHECKING([whether to build PGP/CORE plugin]) -AC_ARG_ENABLE(pgpcore-plugin, - [ --disable-pgpcore-plugin do not build PGP/Core plugin], - [ac_cv_enable_pgpcore_plugin=$enableval], [ac_cv_enable_pgpcore_plugin=yes]) -if test x"$ac_cv_enable_pgpcore_plugin" = xyes; then - AC_MSG_RESULT(yes) - AM_PATH_GPGME(1.0.0, AC_DEFINE(USE_GPGME, 1, Define if you use GPGME to support OpenPGP.), - [ac_cv_enable_pgpcore_plugin=no]) - if test x"$ac_cv_enable_pgpcore_plugin" = xyes; then - PLUGINS="pgpcore $PLUGINS" - AM_PATH_GPGME(1.1.1, - AC_DEFINE(HAVE_GPGME_PKA_TRUST, 1, - [Define if GPGME supports PKA.])) - #needed to get GPGME_LIBS and al correctly - AM_PATH_GPGME(1.0.0, AC_DEFINE(USE_GPGME, 1, Define if you use GPGME to support OpenPGP.), - [ac_cv_enable_pgpcore_plugin=no]) +AC_MSG_CHECKING([whether to build pgpcore plugin]) +if test x"$enable_pgpcore_plugin" != xno; then + dependancies_missing="" + + if test x"$HAVE_GPGME" = xno; then + dependancies_missing="libgpgme $dependancies_missing" + fi + + if test x"$dependancies_missing" = x; then + PLUGINS="$PLUGINS pgpcore" + AC_MSG_RESULT(yes) + elif test x"$enable_pgpcore_plugin" = xauto; then + AC_MSG_RESULT(no) + AC_MSG_WARN("Plugin pgpcore will not be built; missing $dependancies_missing") + enable_pgpcore_plugin=no + MISSING_DEPS_PLUGINS="$MISSING_DEPS_PLUGINS pgpcore" else - AC_MSG_WARN([*** PGP/CORE plugin will not be built ***]) + AC_MSG_RESULT(no) + AC_MSG_ERROR("Plugin pgpcore can not be built; missing $dependancies_missing") fi else + DISABLED_PLUGINS="$DISABLED_PLUGINS pgpcore" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_PGPCORE_PLUGIN, test x"$ac_cv_enable_pgpcore_plugin" = xyes) -AC_MSG_CHECKING([whether to build PGP/MIME plugin]) -AC_ARG_ENABLE(pgpmime-plugin, - [ --disable-pgpmime-plugin do not build PGP/MIME plugin], - [ac_cv_enable_pgpmime_plugin=$enableval], [ac_cv_enable_pgpmime_plugin=yes]) -if test x"$ac_cv_enable_pgpmime_plugin" = xyes; then - AC_MSG_RESULT(yes) - if test x"$ac_cv_enable_pgpcore_plugin" = xyes; then - PLUGINS="pgpmime $PLUGINS" +AC_MSG_CHECKING([whether to build pgpmime plugin]) +if test x"$enable_pgpmime_plugin" != xno; then + dependancies_missing="" + + if test x"$HAVE_GPGME" = xno; then + dependancies_missing="libgpgme $dependancies_missing" + fi + if test x"$enable_pgpcore_plugin" = xno; then + dependancies_missing="pgpcore plugin $dependancies_missing" + fi + + if test x"$dependancies_missing" = x; then + PLUGINS="$PLUGINS pgpmime" + AC_MSG_RESULT(yes) + elif test x"$enable_pgpmime_plugin" = xauto; then + AC_MSG_RESULT(no) + AC_MSG_WARN("Plugin pgpmime will not be built; missing $dependancies_missing") + enable_pgpmime_plugin=no + MISSING_DEPS_PLUGINS="$MISSING_DEPS_PLUGINS pgpmime" else - AC_MSG_WARN([*** PGP/MIME plugin cannot be built ***]) - AC_MSG_WARN([*** without the PGP/CORE plugin ***]) + AC_MSG_RESULT(no) + AC_MSG_ERROR("Plugin pgpmime can not be built; missing $dependancies_missing") fi else + DISABLED_PLUGINS="$DISABLED_PLUGINS pgpmime" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_PGPMIME_PLUGIN, test x"$ac_cv_enable_pgpmime_plugin" = xyes) -AC_MSG_CHECKING([whether to build PGP/Inline plugin]) -AC_ARG_ENABLE(pgpinline-plugin, - [ --disable-pgpinline-plugin do not build PGP/Inline plugin], - [ac_cv_enable_pgpinline_plugin=$enableval], [ac_cv_enable_pgpinline_plugin=yes]) -if test x"$ac_cv_enable_pgpinline_plugin" = xyes; then - AC_MSG_RESULT(yes) - if test x"$ac_cv_enable_pgpcore_plugin" = xyes; then - PLUGINS="pgpinline $PLUGINS" +AC_MSG_CHECKING([whether to build pgpinline plugin]) +if test x"$enable_pgpinline_plugin" != xno; then + dependancies_missing="" + + if test x"$HAVE_GPGME" = xno; then + dependancies_missing="libgpgme $dependancies_missing" + fi + if test x"$enable_pgpcore_plugin" = xno; then + dependancies_missing="pgpcore plugin $dependancies_missing" + fi + + if test x"$dependancies_missing" = x; then + PLUGINS="$PLUGINS pgpinline" + AC_MSG_RESULT(yes) + elif test x"$enable_pgpinline_plugin" = xauto; then + AC_MSG_RESULT(no) + AC_MSG_WARN("Plugin pgpinline will not be built; missing $dependancies_missing") + enable_pgpinline_plugin=no + MISSING_DEPS_PLUGINS="$MISSING_DEPS_PLUGINS pgpinline" else - AC_MSG_WARN([*** PGP/Inline plugin cannot be built ***]) - AC_MSG_WARN([*** without the PGP/CORE plugin ***]) + AC_MSG_RESULT(no) + AC_MSG_ERROR("Plugin pgpinline can not be built; missing $dependancies_missing") fi else + DISABLED_PLUGINS="$DISABLED_PLUGINS pgpinline" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_PGPINLINE_PLUGIN, test x"$ac_cv_enable_pgpinline_plugin" = xyes) -dnl --- RSSyl --- -AC_MSG_CHECKING([whether to build RSSyl plugin]) -AC_ARG_ENABLE(rssyl-plugin, - [ --disable-rssyl-plugin do not build rssyl plugin for RSS and Atom feeds], - [ac_cv_enable_rssyl_plugin=$enableval], [ac_cv_enable_rssyl_plugin=yes]) -if test x"$ac_cv_enable_rssyl_plugin" = xyes; then - AC_MSG_RESULT(yes) - PKG_CHECK_MODULES(LIBXML, "libxml-2.0",, - [AC_MSG_ERROR(libxml library is missing)]) - PLUGINS="rssyl $PLUGINS" - AC_SUBST(LIBXML_CFLAGS) - AC_SUBST(LIBXML_LIBS) -fi -AM_CONDITIONAL(BUILD_RSSYL_PLUGIN, test x"$ac_cv_enable_rssyl_plugin" = xyes) +AC_MSG_CHECKING([whether to build rssyl plugin]) +if test x"$enable_rssyl_plugin" != xno; then + dependancies_missing="" -AC_MSG_CHECKING([whether to build S/Mime plugin]) -AC_ARG_ENABLE(smime-plugin, - [ --disable-smime-plugin do not build S/Mime plugin], - [ac_cv_enable_smime_plugin=$enableval], [ac_cv_enable_smime_plugin=yes]) -if test x"$ac_cv_enable_smime_plugin" = xyes; then - AC_MSG_RESULT(yes) - if test x"$ac_cv_enable_pgpcore_plugin" = xyes; then - PLUGINS="smime $PLUGINS" + if test x"$HAVE_LIBXML" = xno; then + dependancies_missing="libxml2 $dependancies_missing" + fi + if test x"$HAVE_CURL" = xno; then + dependancies_missing="libcurl $dependancies_missing" + fi + + if test x"$dependancies_missing" = x; then + PLUGINS="$PLUGINS rssyl" + AC_MSG_RESULT(yes) + elif test x"$enable_rssyl_plugin" = xauto; then + AC_MSG_RESULT(no) + AC_MSG_WARN("Plugin rssyl will not be built; missing $dependancies_missing") + enable_rssyl_plugin=no + MISSING_DEPS_PLUGINS="$MISSING_DEPS_PLUGINS rssyl" else - AC_MSG_WARN([*** S/Mime plugin cannot be built ***]) - AC_MSG_WARN([*** without the PGP/CORE plugin ***]) + AC_MSG_RESULT(no) + AC_MSG_ERROR("Plugin rssyl can not be built; missing $dependancies_missing") fi else + DISABLED_PLUGINS="$DISABLED_PLUGINS rssyl" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_SMIME_PLUGIN, test x"$ac_cv_enable_smime_plugin" = xyes) -dnl --- SpamAssassin --- -AC_MSG_CHECKING([whether to build SpamAssassin plugin]) -AC_ARG_ENABLE(spamassassin-plugin, - [ --disable-spamassassin-plugin do not build SpamAssassin plugin], - [ac_cv_enable_spamassassin_plugin=$enableval], [ac_cv_enable_spamassassin_plugin=yes]) -if test x"$ac_cv_enable_spamassassin_plugin" = xyes; then +AC_MSG_CHECKING([whether to build spamassassin plugin]) +if test x"$enable_spamassassin_plugin" != xno; then + PLUGINS="$PLUGINS spamassassin" AC_MSG_RESULT(yes) AC_SPAMASSASSIN - PLUGINS="spamassassin $PLUGINS" - AC_DEFINE(USE_SPAMASSASSIN_PLUGIN, 1, Define if spamassassin plugin is being built.) else + DISABLED_PLUGINS="$DISABLED_PLUGINS spamassassin" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_SPAMASSASSIN_PLUGIN, test x"$ac_cv_enable_spamassassin_plugin" = xyes) -dnl --- spam_report --- -AC_MSG_CHECKING([whether to build spam_report plugin]) -AC_ARG_ENABLE(spam_report-plugin, - [ --disable-spam_report-plugin do not build spam_report plugin], - [ac_cv_enable_spam_report_plugin=$enableval], [ac_cv_enable_spam_report_plugin=yes]) -if test x"$ac_cv_enable_spam_report_plugin" = xyes; then - if test x"$have_curl" = xyes; then +AC_MSG_CHECKING([whether to build smime plugin]) +if test x"$enable_smime_plugin" != xno; then + dependancies_missing="" + + if test x"$HAVE_GPGME" = xno; then + dependancies_missing="libgpgme $dependancies_missing" + fi + if test x"$enable_pgpcore_plugin" = xno; then + dependancies_missing="pgpcore plugin $dependancies_missing" + fi + + if test x"$dependancies_missing" = x; then + PLUGINS="$PLUGINS smime" AC_MSG_RESULT(yes) - PLUGINS="spam_report $PLUGINS" + elif test x"$enable_smime_plugin" = xauto; then + AC_MSG_RESULT(no) + AC_MSG_WARN("Plugin smime will not be built; missing $dependancies_missing") + enable_smime_plugin=no + MISSING_DEPS_PLUGINS="$MISSING_DEPS_PLUGINS smime" else - AC_MSG_ERROR(spam_report needs libcurl) + AC_MSG_RESULT(no) + AC_MSG_ERROR("Plugin smime can not be built; missing $dependancies_missing") fi else + DISABLED_PLUGINS="$DISABLED_PLUGINS smime" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_SPAM_REPORT_PLUGIN, test x"$ac_cv_enable_spam_report_plugin" = xyes) -dnl --- tnef_parse --- -AC_MSG_CHECKING([whether to build tnef_parse plugin]) -AC_ARG_ENABLE(tnef_parse-plugin, - [ --disable-tnef_parse-plugin do not build tnef_parse plugin], - [ac_cv_enable_tnef_parse_plugin=$enableval], [ac_cv_enable_tnef_parse_plugin=yes]) -if test x"$ac_cv_enable_tnef_parse_plugin" = xyes; then - AC_MSG_RESULT(yes) - PLUGINS="tnef_parse $PLUGINS" -else - AC_MSG_RESULT(no) -fi -AM_CONDITIONAL(BUILD_TNEF_PARSE_PLUGIN, test x"$ac_cv_enable_tnef_parse_plugin" = xyes) +AC_MSG_CHECKING([whether to build spam_report plugin]) +if test x"$enable_spam_report_plugin" != xno; then + dependancies_missing="" -dnl --- vCalendar --- -AC_MSG_CHECKING([whether to build vCalendar plugin]) -AC_ARG_ENABLE(vcalendar-plugin, - [ --disable-vcalendar-plugin do not build vcalendar plugin for ical rendering], - [ac_cv_enable_vcalendar_plugin=$enableval], [ac_cv_enable_vcalendar_plugin=yes]) -if test x"$ac_cv_enable_vcalendar_plugin" = xyes; then - AC_CHECK_PROGS(PERL, perl5 perl) - if test x"$PERL" != x; then + if test x"$HAVE_CURL" = xno; then + dependancies_missing="libcurl $dependancies_missing" + fi + + if test x"$dependancies_missing" = x; then + PLUGINS="$PLUGINS spam_report" AC_MSG_RESULT(yes) - PLUGINS="vcalendar $PLUGINS" + elif test x"$enable_spam_report_plugin" = xauto; then + AC_MSG_RESULT(no) + AC_MSG_WARN("Plugin spam_report will not be built; missing $dependancies_missing") + enable_spam_report_plugin=no + MISSING_DEPS_PLUGINS="$MISSING_DEPS_PLUGINS spam_report" else AC_MSG_RESULT(no) - ac_cv_enable_vcalendar_plugin=no + AC_MSG_ERROR("Plugin spam_report can not be built; missing $dependancies_missing") fi +else + DISABLED_PLUGINS="$DISABLED_PLUGINS spam_report" + AC_MSG_RESULT(no) fi -AM_CONDITIONAL(BUILD_VCALENDAR_PLUGIN, test x"$ac_cv_enable_vcalendar_plugin" = xyes) - -dnl Libetpan -AC_MSG_CHECKING([whether to use libetpan]) -AC_ARG_ENABLE(libetpan, - [ --disable-libetpan disable IMAP4/NNTP (libetpan) support], - [ac_cv_enable_libetpan=$enableval], [ac_cv_enable_libetpan=yes]) -if test x"$ac_cv_enable_libetpan" = xyes; then +AC_MSG_CHECKING([whether to build tnef_parse plugin]) +if test x"$enable_tnef_parse_plugin" != xno; then + PLUGINS="$PLUGINS tnef_parse" AC_MSG_RESULT(yes) - libetpan_result=no - AC_PATH_PROG(libetpanconfig, [libetpan-config]) - if test "x$libetpanconfig" != "x"; then - CPPFLAGS="$CPPFLAGS `$libetpanconfig --cflags 2>/dev/null`" - AC_CHECK_HEADER(libetpan/libetpan.h, [libetpan_result=yes]) - if test "x$libetpan_result" = "xyes"; then - AC_MSG_CHECKING([whether libetpan-config hints compiles and links fine]) - LIBS="$LIBS `$libetpanconfig --libs 2>/dev/null`" - AC_TRY_LINK([#include <libetpan/dbstorage.h>], [db_mailstorage_init(NULL, NULL);], [libetpan_result=yes], [libetpan_result=no]) - AC_MSG_RESULT([$libetpan_result]) - fi - fi - if test "x$libetpan_result" = "xyes"; then - LIBETPAN_CPPFLAGS="`$libetpanconfig --cflags`" - LIBETPAN_LIBS="`$libetpanconfig --libs`" - LIBETPAN_STABLE=`$libetpanconfig --version | grep -v ^0` - LIBETPAN_VERSION=`$libetpanconfig --version | sed "s/\.//g" | sed "s/-.*$//"` - if test x"$LIBETPAN_STABLE" != "x"; then - LIBETPAN_VERSION="100" - fi - if test "$LIBETPAN_VERSION" -lt "057"; then - AC_MSG_RESULT([*** Claws Mail requires libetpan 0.57 or newer. See http://www.etpan.org/]) - AC_MSG_RESULT([*** You can use --disable-libetpan if you don't need IMAP4 and/or NNTP support.]) - AC_MSG_ERROR([libetpan 0.57 not found]) - fi - AC_SUBST(LIBETPAN_FLAGS) - AC_SUBST(LIBETPAN_LIBS) - AC_DEFINE(HAVE_LIBETPAN, 1, Define if you want IMAP and/or NNTP support.) - else - AC_MSG_RESULT([*** Claws Mail requires libetpan 0.57 or newer. See http://www.etpan.org/ ]) - AC_MSG_RESULT([*** You can use --disable-libetpan if you don't need IMAP4 and/or NNTP support.]) - AC_MSG_ERROR([libetpan 0.57 not found]) - fi else + DISABLED_PLUGINS="$DISABLED_PLUGINS tnef_parse" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(CLAWS_LIBETPAN, test "x$libetpan_result" = "xyes") -AC_MSG_CHECKING([whether to use valgrind]) -AC_ARG_ENABLE(valgrind, - [ --disable-valgrind disable valgrind support for debugging], - [ac_cv_enable_valgrind=$enableval], [ac_cv_enable_valgrind=yes]) -if test x$ac_cv_enable_valgrind = xyes; then - AC_MSG_RESULT(yes) - PKG_CHECK_MODULES(VALGRIND, valgrind >= 2.4.0, - ac_cv_enable_valgrind=yes, ac_cv_enable_valgrind=no) - if test x"$ac_cv_enable_valgrind" = xyes; then - AC_DEFINE(HAVE_VALGRIND, 1, Define if you want valgrind support) +AC_MSG_CHECKING([whether to build vcalendar plugin]) +if test x"$enable_vcalendar_plugin" != xno; then + dependancies_missing="" + + if test x"$HAVE_CURL" = xno; then + dependancies_missing="libcurl $dependancies_missing" + fi + + if test x"$HAVE_PERL" = xno; then + dependancies_missing="perl $dependancies_missing" + fi + + if test x"$dependancies_missing" = x; then + PLUGINS="$PLUGINS vcalendar" + AC_MSG_RESULT(yes) + elif test x"$enable_vcalendar_plugin" = xauto; then + AC_MSG_RESULT(no) + AC_MSG_WARN("Plugin vcalendar will not be built; missing $dependancies_missing") + enable_vcalendar_plugin=no + MISSING_DEPS_PLUGINS="$MISSING_DEPS_PLUGINS vcalendar" else - AC_MSG_RESULT(not found) + AC_MSG_RESULT(no) + AC_MSG_ERROR("Plugin vcalendar can not be built; missing $dependancies_missing") fi else + DISABLED_PLUGINS="$DISABLED_PLUGINS vcalendar" AC_MSG_RESULT(no) fi -AM_CONDITIONAL(CLAWS_VALGRIND, test x"$ac_cv_enable_valgrind" = x"yes") + +dnl And finally the automake conditionals. + +AM_CONDITIONAL(BUILD_ACPI_NOTIFIER_PLUGIN, test x"$enable_acpi_notifier_plugin" != xno) +AM_CONDITIONAL(BUILD_ADDRESS_KEEPER_PLUGIN, test x"$enable_address_keeper_plugin" != xno) +AM_CONDITIONAL(BUILD_ARCHIVE_PLUGIN, test x"$enable_archive_plugin" != xno) +AM_CONDITIONAL(BUILD_ATT_REMOVER_PLUGIN, test x"$enable_att_remover_plugin" != xno) +AM_CONDITIONAL(BUILD_ATTACHWARNER_PLUGIN, test x"$enable_attachwarner_plugin" != xno) +AM_CONDITIONAL(BUILD_BOGOFILTER_PLUGIN, test x"$enable_bogofilter_plugin" != xno) +AM_CONDITIONAL(BUILD_BSFILTER_PLUGIN, test x"$enable_bsfilter_plugin" != xno) +AM_CONDITIONAL(BUILD_CLAMD_PLUGIN, test x"$enable_clamd_plugin" != xno) +AM_CONDITIONAL(BUILD_DEMO_PLUGIN, test x"$enable_demo_plugin" != xno) +AM_CONDITIONAL(BUILD_FANCY_PLUGIN, test x"$enable_fancy_plugin" != xno) +AM_CONDITIONAL(BUILD_FETCHINFO_PLUGIN, test x"$enable_fetchinfo_plugin" != xno) +AM_CONDITIONAL(BUILD_GDATA_PLUGIN, test x"$enable_gdata_plugin" != xno) +AM_CONDITIONAL(BUILD_MAILMBOX_PLUGIN, test x"$enable_mailmbox_plugin" != xno) +AM_CONDITIONAL(BUILD_NEWMAIL_PLUGIN, test x"$enable_newmail_plugin" != xno) +AM_CONDITIONAL(BUILD_NOTIFICATION_PLUGIN, test x"$enable_notification_plugin" != xno) +AM_CONDITIONAL(BUILD_HOTKEYS, test x"$enable_notification_plugin" != xno -a x"$HAVE_HOTKEYS" = xyes) +AM_CONDITIONAL(BUILD_PDF_VIEWER_PLUGIN, test x"$enable_pdf_viewer_plugin" != xno) +AM_CONDITIONAL(BUILD_PERL_PLUGIN, test x"$enable_perl_plugin" != xno) +AM_CONDITIONAL(BUILD_PYTHON_PLUGIN, test x"$enable_python_plugin" != xno) +AM_CONDITIONAL(BUILD_PGPCORE_PLUGIN, test x"$enable_pgpcore_plugin" != xno) +AM_CONDITIONAL(BUILD_PGPMIME_PLUGIN, test x"$enable_pgpmime_plugin" != xno) +AM_CONDITIONAL(BUILD_PGPINLINE_PLUGIN, test x"$enable_pgpinline_plugin" != xno) +AM_CONDITIONAL(BUILD_RSSYL_PLUGIN, test x"$enable_rssyl_plugin" != xno) +AM_CONDITIONAL(BUILD_SMIME_PLUGIN, test x"$enable_smime_plugin" != xno) +AM_CONDITIONAL(BUILD_SPAMASSASSIN_PLUGIN, test x"$enable_spamassassin_plugin" != xno) +AM_CONDITIONAL(BUILD_SPAM_REPORT_PLUGIN, test x"$enable_spam_report_plugin" != xno) +AM_CONDITIONAL(BUILD_TNEF_PARSE_PLUGIN, test x"$enable_tnef_parse_plugin" != xno) +AM_CONDITIONAL(BUILD_VCALENDAR_PLUGIN, test x"$enable_vcalendar_plugin" != xno) + dnl **************************** dnl ** Final configure output ** @@ -1479,6 +1803,7 @@ src/plugins/gdata/Makefile src/plugins/mailmbox/Makefile src/plugins/newmail/Makefile src/plugins/notification/Makefile +src/plugins/notification/gtkhotkey/Makefile src/plugins/pdf_viewer/Makefile src/plugins/perl/Makefile src/plugins/python/Makefile @@ -1557,10 +1882,31 @@ echo "LibSM : $ac_cv_enable_libsm" echo "DBUS : $enable_dbus" echo "NetworkManager : $enable_networkmanager_support" echo "Manual : $ac_cv_enable_manual" -echo "Plugins : $PLUGINS" echo "Generic UMPC code : $ac_cv_enable_generic_umpc" -echo "Maemo build : $ac_cv_enable_maemo" +echo "Maemo build : $ac_cv_enable_maemo" echo "Config dir : $ac_cv_with_config_dir" + +echo "Plugins : Built:" +for plugin in $PLUGINS; do +features="" +if test x"$plugin" = xnotification; then + features="$notification_features" +fi +echo " - $plugin $features" +done; +if test "x$DISABLED_PLUGINS" != x; then +echo " Disabled:" +for plugin in $DISABLED_PLUGINS; do +echo " - $plugin" +done; +fi + +if test "x$MISSING_DEPS_PLUGINS" != x; then +echo " Disabled due to missing dependencies:" +for plugin in $MISSING_DEPS_PLUGINS; do +echo " - $plugin" +done; +fi echo "" echo "The binary will be installed in $prefix/bin" echo "" diff --git a/src/plugins/fancy/fancy_viewer.c b/src/plugins/fancy/fancy_viewer.c @@ -27,7 +27,7 @@ #include <fancy_prefs.h> #include <alertpanel.h> -#if USE_PRINTUNIX +#if HAVE_GTKPRINTUNIX #include <printing.h> #if GTK_CHECK_VERSION(2,13,1) #include <gtk/gtkunixprint.h> @@ -78,12 +78,10 @@ static void open_in_browser_cb(GtkWidget *widget, FancyViewer *viewer); static WebKitNavigationResponse fancy_open_uri (FancyViewer *viewer, gboolean external); static void fancy_create_popup_prefs_menu(FancyViewer *viewer); static void fancy_show_notice(FancyViewer *viewer, const gchar *message); -#ifdef HAVE_LIBCURL static size_t download_file_curl_write_cb(void *buffer, size_t size, size_t nmemb, void *data); static void *download_file_curl (void *data); static void download_file_cb(GtkWidget *widget, FancyViewer *viewer); -#endif #if !WEBKIT_CHECK_VERSION (1,5,1) gchar* webkit_web_view_get_selected_text(WebKitWebView* web_view); @@ -181,7 +179,7 @@ static void fancy_show_mimepart(MimeViewer *_viewer, const gchar *infile, viewer->loading = TRUE; g_timeout_add(5, (GtkFunction)fancy_show_mimepart_prepare, viewer); } -#if GTK_CHECK_VERSION(2,10,0) && USE_PRINTUNIX +#if GTK_CHECK_VERSION(2,10,0) && HAVE_GTKPRINTUNIX static void job_complete_cb (GtkPrintJob *print_job, FancyViewer *viewer, GError *error) @@ -737,7 +735,7 @@ static void open_in_browser_cb(GtkWidget *widget, FancyViewer *viewer) debug_print("link: %s\n", viewer->cur_link); open_uri(viewer->cur_link, prefs_common_get_uri_cmd()); } -#ifdef HAVE_LIBCURL + static size_t download_file_curl_write_cb(void *buffer, size_t size, size_t nmemb, void *data) { @@ -805,7 +803,7 @@ static void download_file_cb(GtkWidget *widget, FancyViewer *viewer) download_file_curl((void *)viewer); #endif } -#endif + static void open_image_cb(GtkWidget *widget, FancyViewer *viewer) { debug_print("Not Yet Implemented\n"); @@ -871,7 +869,7 @@ static void viewer_menu_handler(GtkWidget *menuitem, FancyViewer *viewer) "Download Linked File" )) { gtk_label_set_text(GTK_LABEL(menul), _("Download Link")); -#ifdef HAVE_LIBCURL + GtkImageMenuItem *m_dlink = GTK_IMAGE_MENU_ITEM(menuitem); if (!fancy_prefs.block_extern_content) { gtk_widget_set_sensitive(GTK_WIDGET(menul), TRUE); @@ -887,17 +885,13 @@ static void viewer_menu_handler(GtkWidget *menuitem, FancyViewer *viewer) g_signal_connect(G_OBJECT(m_dlink), "activate", G_CALLBACK(download_file_cb), (gpointer *) viewer); -#else - gtk_widget_set_sensitive(GTK_WIDGET(menul), FALSE); -#endif } if (!g_ascii_strcasecmp(gtk_label_get_text(GTK_LABEL(menul)), "Save Image As" )) { gtk_label_set_text(GTK_LABEL(menul), _("Save Image As")); - -#ifdef HAVE_LIBCURL + GtkImageMenuItem *m_simage = GTK_IMAGE_MENU_ITEM(menuitem); if (!fancy_prefs.block_extern_content) { gtk_widget_set_sensitive(GTK_WIDGET(menul), TRUE); @@ -912,9 +906,6 @@ static void viewer_menu_handler(GtkWidget *menuitem, FancyViewer *viewer) } g_signal_connect(G_OBJECT(m_simage), "activate", G_CALLBACK(download_file_cb), (gpointer *) viewer); -#else - gtk_widget_set_sensitive(GTK_WIDGET(menul), FALSE); -#endif } if (!g_ascii_strcasecmp(gtk_label_get_text(GTK_LABEL(menul)), @@ -1013,7 +1004,7 @@ static MimeViewer *fancy_viewer_create(void) viewer->mimeviewer.get_widget = fancy_get_widget; viewer->mimeviewer.get_selection = fancy_get_selection; viewer->mimeviewer.show_mimepart = fancy_show_mimepart; -#if GTK_CHECK_VERSION(2,10,0) && USE_PRINTUNIX +#if GTK_CHECK_VERSION(2,10,0) && HAVE_GTKPRINTUNIX viewer->mimeviewer.print = fancy_print; #endif viewer->mimeviewer.clear_viewer = fancy_clear_viewer; diff --git a/src/plugins/fancy/fancy_viewer.h b/src/plugins/fancy/fancy_viewer.h @@ -53,11 +53,9 @@ #include <pthread.h> #endif -#ifdef HAVE_LIBCURL #include <curl/curl.h> #include <curl/curlver.h> #include "filesel.h" -#endif #ifdef HAVE_LIBSOUP_GNOME #include <libsoup/soup-gnome.h> diff --git a/src/plugins/notification/Makefile.am b/src/plugins/notification/Makefile.am @@ -1,12 +1,12 @@ -#if BUILD_HOTKEYS -#hotkey_lib = libcmnpgtkhotkey.la -#hotkey_lib_path = $(top_builddir)/src/plugins/notification/gtkhotkey/libcmnpgtkhotkey.la -#else +if BUILD_HOTKEYS +hotkey_lib = libcmnpgtkhotkey.la +hotkey_lib_path = $(top_builddir)/src/plugins/notification/gtkhotkey/libcmnpgtkhotkey.la +else hotkey_lib = hotkey_lib_path = -#endif - +endif +SUBDIRS=gtkhotkey EXTRA_DIST = claws.def plugin.def version.rc CFLAGS += "-Wall" diff --git a/src/plugins/notification/gtkhotkey/.cvsignore b/src/plugins/notification/gtkhotkey/.cvsignore @@ -0,0 +1,7 @@ +.deps +.libs +Makefile +Makefile.in +*.la +*.lo +*.o diff --git a/src/plugins/notification/gtkhotkey/Makefile.am b/src/plugins/notification/gtkhotkey/Makefile.am @@ -0,0 +1,37 @@ +noinst_LTLIBRARIES = libcmnpgtkhotkey.la + +libcmnpgtkhotkey_la_SOURCES = \ + gtk-hotkey-info.c \ + gtk-hotkey-error.c \ + gtk-hotkey-listener.c \ + gtk-hotkey-marshal.c \ + gtk-hotkey-x11-listener.c \ + x11/tomboykeybinder.c \ + x11/eggaccelerators.c \ + gtk-hotkey-registry.c \ + gtk-hotkey-key-file-registry.c \ + gtk-hotkey-utils.c + +cmnpgtkhotkeyincludedir = $(includedir)/claws-mail/plugins/@PACKAGE@/gtkhotkey +cmnpgtkhotkeyinclude_HEADERS = \ + gtk-hotkey-error.h \ + gtkhotkey.h \ + gtk-hotkey-info.h \ + gtk-hotkey-key-file-registry.h \ + gtk-hotkey-listener.h \ + gtk-hotkey-registry.h \ + gtk-hotkey-x11-listener.h \ + gtk-hotkey-marshal.h \ + x11/tomboykeybinder.h \ + x11/eggaccelerators.h \ + gtk-hotkey-utils.h + +libcmnpgtkhotkey_la_LIBADD = \ + $(GTK_LIBS) \ + $(CM_NP_HOTKEY_LIBS) + +AM_CPPFLAGS = \ + -DGTK_HOTKEY_COMPILATION \ + $(GLIB_CFLAGS) \ + $(GTK_CFLAGS) \ + $(CM_NP_HOTKEY_CFLAGS) diff --git a/src/plugins/notification/gtkhotkey/gtk-hotkey-error.c b/src/plugins/notification/gtkhotkey/gtk-hotkey-error.c @@ -0,0 +1,31 @@ +/* + * This file is part of GtkHotkey. + * Copyright Mikkel Kamstrup Erlandsen, March, 2008 + * + * GtkHotkey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GtkHotkey 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with GtkHotkey. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "gtk-hotkey-error.h" + +GQuark +gtk_hotkey_listener_error_quark (void) +{ + return g_quark_from_static_string ("gtk-hotkey-listener-error-quark"); +} + +GQuark +gtk_hotkey_registry_error_quark (void) +{ + return g_quark_from_static_string ("gtk-hotkey-storage-error-quark"); +} diff --git a/src/plugins/notification/gtkhotkey/gtk-hotkey-error.h b/src/plugins/notification/gtkhotkey/gtk-hotkey-error.h @@ -0,0 +1,100 @@ +/* + * This file is part of GtkHotkey. + * Copyright Mikkel Kamstrup Erlandsen, March, 2008 + * + * GtkHotkey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GtkHotkey 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with GtkHotkey. If not, see <http://www.gnu.org/licenses/>. + */ + +#if !defined (__GTK_HOTKEY_H__) && !defined (GTK_HOTKEY_COMPILATION) +#error "Only <gtkhotkey.h> can be included directly." +#endif + +#ifndef __GTK_HOTKEY_ERROR_H__ +#define __GTK_HOTKEY_ERROR_H__ + +#include <glib.h> + +G_BEGIN_DECLS + +/** + * GTK_HOTKEY_LISTENER_ERROR: + * + * Error domain for #GtkHotkeyListener. + */ +#define GTK_HOTKEY_LISTENER_ERROR gtk_hotkey_listener_error_quark() +GQuark gtk_hotkey_listener_error_quark (void); + +/** + * GTK_HOTKEY_REGISTRY_ERROR: + * + * Error domain for #GtkHotkeyRegistry. + */ +#define GTK_HOTKEY_REGISTRY_ERROR gtk_hotkey_registry_error_quark() +GQuark gtk_hotkey_registry_error_quark (void); + +/** + * GtkHotkeyListenerError: + * @GTK_HOTKEY_LISTENER_ERROR_BIND: An error occured when binding a hotkey with + * the listener + * @GTK_HOTKEY_LISTENER_ERROR_UNBIND: An error occured when unbinding a hotkey + * with the listener + * + * Error codes for #GError<!-- -->s related to #GtkHotkeyListener<!-- -->s + */ +typedef enum +{ + GTK_HOTKEY_LISTENER_ERROR_BIND, + GTK_HOTKEY_LISTENER_ERROR_UNBIND, +} GtkHotkeyListenerError; + +/** + * GtkHotkeyRegistryError: + * @GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN_APP: The application which is the involved + * in the transaction has not registered + * any hotkeys + * @GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN_KEY: The hotkey key-id (the identifier that + * identifies the hotkey among those + * belonging to an application) is not + * known. + * @GTK_HOTKEY_REGISTRY_ERROR_MALFORMED_MEDIUM: The medium from which to read + * or write is in an unrecoverable + * state. For example a file + * containing syntax errors + * @GTK_HOTKEY_REGISTRY_ERROR_IO: There was some problem with the actual io + * operation. Missing file permissions, disk full, + * etc. + * @GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN: Unexpected and uncharacterized error + * @GTK_HOTKEY_REGISTRY_ERROR_BAD_SIGNATURE: The hotkey signature is not valid. + * See #GtkHotkeyInfo:signature. + * @GTK_HOTKEY_REGISTRY_ERROR_MISSING_APP: A #GtkHotkeyInfo is referring an + * application via its #GtkHotkeyInfo:app-info + * property, but the application can not + * be found. + * + * Error codes for #GError<!-- -->s related to #GtkHotkeyRegistry<!-- -->s + */ +typedef enum +{ + GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN_APP, + GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN_KEY, + GTK_HOTKEY_REGISTRY_ERROR_MALFORMED_MEDIUM, + GTK_HOTKEY_REGISTRY_ERROR_IO, + GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN, + GTK_HOTKEY_REGISTRY_ERROR_BAD_SIGNATURE, + GTK_HOTKEY_REGISTRY_ERROR_MISSING_APP, +} GtkHotkeyRegistryError; + +G_END_DECLS + +#endif /* __GTK_HOTKEY_ERROR_H__ */ diff --git a/src/plugins/notification/gtkhotkey/gtk-hotkey-info.c b/src/plugins/notification/gtkhotkey/gtk-hotkey-info.c @@ -0,0 +1,658 @@ +/* + * This file is part of GtkHotkey. + * Copyright Mikkel Kamstrup Erlandsen, March, 2008 + * + * GtkHotkey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GtkHotkey 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with GtkHotkey. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "gtk-hotkey-info.h" +#include "gtk-hotkey-error.h" +#include "gtk-hotkey-listener.h" + +struct _GtkHotkeyInfoPrivate { + gchar *app_id; + gchar *key_id; + GAppInfo *app_info; + gchar *signature; + gchar *description; + GtkHotkeyListener *listener; +}; +#define GTK_HOTKEY_INFO_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_HOTKEY_TYPE_INFO, GtkHotkeyInfoPrivate)) + +enum { + GTK_HOTKEY_INFO_DUMMY_PROPERTY, + GTK_HOTKEY_INFO_BOUND, + GTK_HOTKEY_INFO_APPLICATION_ID, + GTK_HOTKEY_INFO_KEY_ID, + GTK_HOTKEY_INFO_APP_INFO, + GTK_HOTKEY_INFO_SIGNATURE, + GTK_HOTKEY_INFO_DESCRIPTION, +}; + +enum { + ACTIVATED, + + LAST_SIGNAL +}; + +guint info_signals[LAST_SIGNAL] = { 0 }; + +static gpointer gtk_hotkey_info_parent_class = NULL; + +static void gtk_hotkey_info_finalize (GObject * obj); + +/** + * SECTION:gtk-hotkey-info + * @short_description: Primary representation of a hotkey + * @see_also: #GtkHotkeyRegistry + * + * #GtkHotkeyInfo is the primary object around which the GtkHotkey library + * revolves. + * + * Hotkeys are stored and managed via a #GtkHotkeyRegistry, while the actual + * binding and listening for key-presses is done by a #GtkHotkeyListener. + **/ + + +/** + * gtk_hotkey_info_bind: + * @self: The hotkey to bind + * @error: Place to return a #GError, or %NULL to ignore + * + * Register the hotkey with the system. The #GtkHotkeyInfo::activated signal + * will now be emitted when the user presses the keyboard combination + * matching the hotkey's signature. + * + * Returns: %TRUE on success, and %FALSE on error in which case @error + * is also set + **/ +gboolean +gtk_hotkey_info_bind (GtkHotkeyInfo* self, GError **error) +{ + gboolean result; + + g_return_val_if_fail (GTK_HOTKEY_IS_INFO (self), FALSE); + + if (gtk_hotkey_info_is_bound(self)) { + g_set_error (error, GTK_HOTKEY_LISTENER_ERROR, + GTK_HOTKEY_LISTENER_ERROR_BIND, + "Can not bind hotkey '%s' with signature '%s'. " + "It is already bound", + gtk_hotkey_info_get_key_id(self), + gtk_hotkey_info_get_signature(self)); + return FALSE; + } + + if (!self->priv->listener) + self->priv->listener = gtk_hotkey_listener_get_default (); + + g_return_val_if_fail (GTK_HOTKEY_IS_LISTENER(self->priv->listener), FALSE); + + result = gtk_hotkey_listener_bind_hotkey (self->priv->listener, self, error); + if (!result) { + g_object_unref (self->priv->listener); + self->priv->listener = NULL; + } + + if (result) + g_object_notify (G_OBJECT(self), "bound"); + + return result; +} + +/** + * gtk_hotkey_info_unbind + * @self: The hotkey to unbind + * @error: Place to return a #GError, or %NULL to ignore + * @returns: %TRUE on success, and %FALSE on error in which case @error + * is also set + * + * Remove the hotkey binding from the system. The #GtkHotkeyInfo::activated + * signal will no longer be emitted when the hotkey is pressed. + */ +gboolean +gtk_hotkey_info_unbind (GtkHotkeyInfo* self, GError **error) +{ + gboolean result; + + g_return_val_if_fail (GTK_HOTKEY_IS_INFO (self), FALSE); + + if (!gtk_hotkey_info_is_bound(self)) { + g_set_error (error, GTK_HOTKEY_LISTENER_ERROR, + GTK_HOTKEY_LISTENER_ERROR_UNBIND, + "Can not unbind hotkey '%s' with signature '%s'." + "It is not bound", + gtk_hotkey_info_get_key_id(self), + gtk_hotkey_info_get_signature(self)); + return FALSE; + } + + g_return_val_if_fail (GTK_HOTKEY_IS_LISTENER(self->priv->listener), FALSE); + + result = gtk_hotkey_listener_unbind_hotkey (self->priv->listener, self, + error); + + g_object_unref (self->priv->listener); + self->priv->listener = NULL; + + if (result) + g_object_notify (G_OBJECT(self), "bound"); + + return result; +} + +/** + * gtk_hotkey_info_is_bound + * @self: The hotkey to inspect + * @returns: %TRUE if gtk_hotkey_info_bind() has been called and returned %TRUE + * on this hotkey + * + * Check whether the hotkey has been succesfully bound to a #GtkHotkeyListener. + */ +gboolean +gtk_hotkey_info_is_bound (GtkHotkeyInfo* self) +{ + return (self->priv->listener != NULL); +} + +/** + * gtk_hotkey_info_get_application_id + * @self: + * + * Get the unique system identifier for the hotkey. See + * #GtkHotkeyInfo:application-id for details. + */ +const gchar* +gtk_hotkey_info_get_application_id (GtkHotkeyInfo* self) +{ + g_return_val_if_fail (GTK_HOTKEY_IS_INFO (self), NULL); + return self->priv->app_id; +} + +/** + * gtk_hotkey_info_get_key_id + * @self: + * + * Get the identifier the owning application use to identify this hotkey. + * See #GtkHotkeyInfo:key-id for details. + */ +const gchar* +gtk_hotkey_info_get_key_id (GtkHotkeyInfo* self) +{ + g_return_val_if_fail (GTK_HOTKEY_IS_INFO (self), NULL); + return self->priv->key_id; +} + +/** + * gtk_hotkey_info_get_app_info + * @self: + * + * Not to be confused with the value of the #GtkHotkeyInfo:application-id + * property. The hotkey can be associated with an installed desktop application + * via a #GAppInfo. This is not mandatory and this method returns %NULL + * if no desktop application has been associated with this hotkey. + * + * See the #GtkHotkeyInfo:app-info property for details. + */ +GAppInfo* +gtk_hotkey_info_get_app_info (GtkHotkeyInfo* self) +{ + g_return_val_if_fail (GTK_HOTKEY_IS_INFO (self), NULL); + return self->priv->app_info; +} + +/** + * gtk_hotkey_info_get_signature + * @self: + * + * Get the keyboard signature of the hotkey. This could for example be + * '&lt;Alt&gt;F3' or '&lt;Control&gt;&lt;Shift&gt;G'. + */ +const gchar* +gtk_hotkey_info_get_signature (GtkHotkeyInfo* self) +{ + g_return_val_if_fail (GTK_HOTKEY_IS_INFO (self), NULL); + return self->priv->signature; +} + +/** + * gtk_hotkey_info_get_description + * @self: + * @returns: The description of the hotkey or %NULL if none is set + * + * Get the free form description of the hotkey. The description is not guaranteed + * to be set and may be %NULL. + * + * FIXME: Do we need to take i18n into account here? + */ +const gchar* +gtk_hotkey_info_get_description (GtkHotkeyInfo* self) +{ + g_return_val_if_fail (GTK_HOTKEY_IS_INFO(self), NULL); + return self->priv->description; +} + +/** + * gtk_hotkey_info_set_description + * @self: + * + * Set a description for the hotkey. See also gtk_hotkey_info_get_description(). + */ +void +gtk_hotkey_info_set_description (GtkHotkeyInfo* self, const gchar *description) +{ + g_return_if_fail (GTK_HOTKEY_IS_INFO(self)); + g_object_set (self, "description", description, NULL); +} + +/** + * gtk_hotkey_info_equals + * @hotkey1: The first hotkey to compare + * @hotkey2: Second hotkey to compare to + * @sloppy_equals: If %TRUE sloppy equality will be used. This ignores + * the #GtkHotkeyInfo:description and #GtkHotkeyInfo:app-info + * properties of the objects. + * @returns: %TRUE if all the properties of the hotkeys match. Two %NULL hotkeys + * are also considered equal. + * + * Compare two #GtkHotkeyInfo<!-- -->s to see if they are equal. This method + * allows an optional 'sloppy equality' which ignores #GtkHotkeyInfo:description + * and #GtkHotkeyInfo:app-info. + */ +gboolean +gtk_hotkey_info_equals (GtkHotkeyInfo *hotkey1, + GtkHotkeyInfo *hotkey2, + gboolean sloppy_equals) +{ + if (hotkey1 == hotkey2) return TRUE; + + g_return_val_if_fail (GTK_HOTKEY_IS_INFO (hotkey1), FALSE); + g_return_val_if_fail (GTK_HOTKEY_IS_INFO (hotkey2), FALSE); + + if (!g_str_equal (gtk_hotkey_info_get_application_id (hotkey1), + gtk_hotkey_info_get_application_id (hotkey2))) + return FALSE; + + if (!g_str_equal (gtk_hotkey_info_get_key_id (hotkey1), + gtk_hotkey_info_get_key_id (hotkey2))) + return FALSE; + + if (!g_str_equal (gtk_hotkey_info_get_signature (hotkey1), + gtk_hotkey_info_get_signature (hotkey2))) + return FALSE; + + /* For sloppy equality this is good enough */ + if (sloppy_equals) + return TRUE; + + const gchar *d1, *d2; + d1 = gtk_hotkey_info_get_description (hotkey1); + d2 = gtk_hotkey_info_get_description (hotkey2); + if (d1 != NULL && d2 != NULL) { + if (!g_str_equal (gtk_hotkey_info_get_description (hotkey1), + gtk_hotkey_info_get_description (hotkey2))) + return FALSE; + } else if (d1 != d2) + return FALSE; + /* The case d1 == d2 == NULL will pass through the above */ + + GAppInfo *app1, *app2; + app1 = gtk_hotkey_info_get_app_info (hotkey1); + app2 = gtk_hotkey_info_get_app_info (hotkey2); + if (app1 != NULL && app2 != NULL) { + if (!g_app_info_equal (app1, app2)) + return FALSE; + } else if (app1 != app2) + return FALSE; + /* As above, if app1 == app2 == NULL we count equality */ + + return TRUE; +} + +/** + * gtk_hotkey_info_activated + * @self: #GtkHotkeyInfo to emit the #GtkHotkeyInfo::activated signal + * @event_time: The system time the event happened on. This is useful for + * applications to pass through focus stealing prevention when + * mapping windows + * + * Emit the #GtkHotkeyInfo::activated signal on a hotkey. Mainly called + * by #GtkHotkeyListener implementations. This method should not normally be + * used by applications. + */ +void +gtk_hotkey_info_activated (GtkHotkeyInfo* self, guint event_time) +{ + g_return_if_fail (GTK_HOTKEY_IS_INFO(self)); + + g_signal_emit (self, info_signals[ACTIVATED], 0, event_time); +} + +/** + * gtk_hotkey_info_new: + * @app_id: Unique identifier the running application can choose for it self. + * May be a free form string, but a descriptive name is encouraged + * @key_id: A key the application uses to recognize the hotkey. May be a free + * form string, but a descriptive name is encouraged + * @signature: A key press signature parsable by gtk_accelerator_parse(). For + * examplpe '&lt;Alt&gt;F3' or '&lt;Control&gt;&lt;Shift&gt;G'. + * @app_info: An optional #GAppInfo to associate with the hotkey. Pass %NULL to + * ignore this + * @returns: A new #GtkHotkeyInfo or %NULL on error. Error conditions could for + * example be invalid an invalid @signature, or %NULL arguments. + * + * Create a new hotkey. To actually trigger the hotkey when the user enters + * the right keyboard combination call gtk_hotkey_info_bind(). To save and + * load your hotkey settings use the #GtkHotkeyRegistry provided by + * gtk_hotkey_registry_get_default(). + **/ +GtkHotkeyInfo* +gtk_hotkey_info_new (const gchar *app_id, + const gchar *key_id, + const gchar *signature, + GAppInfo *app_info) +{ + GtkHotkeyInfo * self; + + g_return_val_if_fail (app_id != NULL, NULL); + g_return_val_if_fail (key_id != NULL, NULL); + + /* A NULL app_info is ok, but it better be a GAppInfo then */ + if (app_info != NULL) + g_return_val_if_fail (G_IS_APP_INFO(app_info), NULL); + + self = g_object_new (GTK_HOTKEY_TYPE_INFO, "application-id", app_id, + "key-id", key_id, + "signature", signature, + "app-info", app_info, + NULL); + return self; +} + +static void +gtk_hotkey_info_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) +{ + GtkHotkeyInfo * self; + + self = GTK_HOTKEY_INFO (object); + + switch (property_id) { + case GTK_HOTKEY_INFO_BOUND: + g_value_set_boolean (value, + (self->priv->listener != NULL)); + break; + case GTK_HOTKEY_INFO_APPLICATION_ID: + g_value_set_string (value, + gtk_hotkey_info_get_application_id (self)); + break; + case GTK_HOTKEY_INFO_KEY_ID: + g_value_set_string (value, + gtk_hotkey_info_get_key_id (self)); + break; + case GTK_HOTKEY_INFO_APP_INFO: + g_value_set_object (value, + gtk_hotkey_info_get_app_info (self)); + break; + case GTK_HOTKEY_INFO_SIGNATURE: + g_value_set_string (value, + gtk_hotkey_info_get_signature (self)); + break; + case GTK_HOTKEY_INFO_DESCRIPTION: + g_value_set_string (value, + gtk_hotkey_info_get_description (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +gtk_hotkey_info_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) +{ + GtkHotkeyInfo *self; + GtkHotkeyInfoPrivate *priv; + + self = GTK_HOTKEY_INFO (object); + priv = self->priv; + + switch (property_id) { + case GTK_HOTKEY_INFO_BOUND: + g_critical ("Writing to read only property 'bound'"); + break; + case GTK_HOTKEY_INFO_APPLICATION_ID: + if (priv->app_id) + g_critical ("Overwriting construct only property 'application-id'"); + priv->app_id = g_value_dup_string (value); + break; + case GTK_HOTKEY_INFO_KEY_ID: + if (priv->key_id) + g_critical ("Overwriting construct only property 'key-id'"); + priv->key_id = g_value_dup_string (value); + break; + case GTK_HOTKEY_INFO_APP_INFO: + if (priv->app_info) + g_critical ("Overwriting construct only property 'app-info'"); + priv->app_info = g_value_dup_object (value); + break; + case GTK_HOTKEY_INFO_SIGNATURE: + if (priv->signature) + g_critical ("Overwriting construct only property 'signature'"); + priv->signature = g_value_dup_string (value); + break; + case GTK_HOTKEY_INFO_DESCRIPTION: + if (priv->description) + g_free(priv->description); + priv->description = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +gtk_hotkey_info_class_init (GtkHotkeyInfoClass * klass) +{ + gtk_hotkey_info_parent_class = g_type_class_peek_parent (klass); + g_type_class_add_private (klass, sizeof (GtkHotkeyInfoPrivate)); + + G_OBJECT_CLASS (klass)->get_property = gtk_hotkey_info_get_property; + G_OBJECT_CLASS (klass)->set_property = gtk_hotkey_info_set_property; + G_OBJECT_CLASS (klass)->finalize = gtk_hotkey_info_finalize; + + /** + * GtkHotkeyInfo:bound + * + * Property reflecting whether or not this hotkey has been bound to + * a #GtkHotkeyListener. If this property is %TRUE you will receive + * #GtkHotkeyInfo::activated signals when the hotkey is triggered + * by the user. + */ + g_object_class_install_property (G_OBJECT_CLASS (klass), + GTK_HOTKEY_INFO_BOUND, + g_param_spec_boolean ("bound", + "Is Bound", + "Whether or not the hotkey is bound to a GtkHotkeyListener", + FALSE, + G_PARAM_READABLE)); + + /** + * GtkHotkeyInfo:application-id + * + * A free form string chosen by the application using the hotkey, under + * which the application identifies itself. + */ + g_object_class_install_property (G_OBJECT_CLASS (klass), + GTK_HOTKEY_INFO_APPLICATION_ID, + g_param_spec_string ("application-id", + "Application Id", + "Globally unique application id", + NULL, + G_PARAM_READABLE | G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY)); + + /** + * GtkHotkeyInfo:key-id + * + * A free form string the application using the hotkey has attributed + * the hotkey so that it can be identified later on. Applications are + * encouraged to choose descriptive key ids. + */ + g_object_class_install_property (G_OBJECT_CLASS (klass), + GTK_HOTKEY_INFO_KEY_ID, + g_param_spec_string ("key-id", + "Hotkey Id", + "Globally unique identifier for the hotkey", + NULL, + G_PARAM_READABLE | G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY)); + + /** + * GtkHotkeyInfo:app-info + * + * A #GAppInfo associated with the key. This is mainly useful for external + * applications which can use the information provided by the #GAppInfo + * to display meaningful messages to the user. Like 'The keyboard + * combination &lt;Alt&gt;F3' is already assigned to the application + * "Deskbar Applet", please select another'. + */ + g_object_class_install_property (G_OBJECT_CLASS (klass), + GTK_HOTKEY_INFO_APP_INFO, + g_param_spec_object ("app-info", + "Application Information", + "Object holding metadata about " + "the hotkey's application", + G_TYPE_APP_INFO, + G_PARAM_READABLE | G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY)); + + /** + * GtkHotkeyInfo:signature + * + * The keyboard signature of the hotkey. This could for example by + * '&lt;Alt&gt;F3' or '&lt;Control&gt;&lt;Shift&gt;G'. The signature should be parsable by + * gtk_accelerator_parse(). + */ + g_object_class_install_property (G_OBJECT_CLASS (klass), + GTK_HOTKEY_INFO_SIGNATURE, + g_param_spec_string ("signature", + "Signature", + "String defining the keyboard shortcut", + NULL, + G_PARAM_READABLE | G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY)); + + /** + * GtkHotkeyInfo:description + * + * An optional free form description of the hotkey. + */ + g_object_class_install_property (G_OBJECT_CLASS (klass), + GTK_HOTKEY_INFO_DESCRIPTION, + g_param_spec_string ("description", + "Description", + "Short description of what happens upon activation", + "", + G_PARAM_READABLE | G_PARAM_WRITABLE)); + + /** + * GtkHotkeyInfo::activated: + * @hotkey: a #GtkHotkeyInfo for the hotkey that was activated + * @event_time: Time for event triggering the keypress. This is mainly + * used to pass to window management functions to pass through + * focus stealing prevention + * + * Emitted when a hotkey has been activated. + */ + info_signals[ACTIVATED] = \ + g_signal_new ("activated", + GTK_HOTKEY_TYPE_INFO, + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, + G_TYPE_UINT); +} + + +static void +gtk_hotkey_info_init (GtkHotkeyInfo * self) +{ + self->priv = GTK_HOTKEY_INFO_GET_PRIVATE (self); + + self->priv->app_id = NULL; + self->priv->key_id = NULL; + self->priv->app_info = NULL; +} + + +static void +gtk_hotkey_info_finalize (GObject * obj) +{ + GtkHotkeyInfo *self; + GtkHotkeyInfoPrivate *priv; + + self = GTK_HOTKEY_INFO (obj); + priv = self->priv; + + if (priv->app_id) + g_free (priv->app_id); + if (priv->key_id) + g_free (priv->key_id); + if (priv->app_info) + g_object_unref (priv->app_info); + if (priv->signature) + g_free (priv->signature); + if (priv->description) + g_free (priv->description); + if (GTK_HOTKEY_IS_LISTENER (priv->listener)) + g_object_unref (priv->listener); + + G_OBJECT_CLASS (gtk_hotkey_info_parent_class)->finalize (obj); +} + + +GType +gtk_hotkey_info_get_type (void) +{ + static GType gtk_hotkey_info_type_id = 0; + + if (G_UNLIKELY (gtk_hotkey_info_type_id == 0)) { + static const GTypeInfo g_define_type_info = { + sizeof (GtkHotkeyInfoClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gtk_hotkey_info_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (GtkHotkeyInfo), + 0, + (GInstanceInitFunc) gtk_hotkey_info_init + }; + + gtk_hotkey_info_type_id = g_type_register_static (G_TYPE_OBJECT, + "GtkHotkeyInfo", + &g_define_type_info, + 0); + } + + return gtk_hotkey_info_type_id; +} + + + + diff --git a/src/plugins/notification/gtkhotkey/gtk-hotkey-info.h b/src/plugins/notification/gtkhotkey/gtk-hotkey-info.h @@ -0,0 +1,89 @@ +/* + * This file is part of GtkHotkey. + * Copyright Mikkel Kamstrup Erlandsen, March, 2008 + * + * GtkHotkey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GtkHotkey 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with GtkHotkey. If not, see <http://www.gnu.org/licenses/>. + */ + +#if !defined (__GTK_HOTKEY_H__) && !defined (GTK_HOTKEY_COMPILATION) +#error "Only <gtkhotkey.h> can be included directly." +#endif + +#ifndef __GTK_HOTKEY_INFO_H__ +#define __GTK_HOTKEY_INFO_H__ + +#include <glib.h> +#include <glib-object.h> +#include <gio/gio.h> +#include <stdlib.h> +#include <string.h> + +G_BEGIN_DECLS + + +#define GTK_HOTKEY_TYPE_INFO (gtk_hotkey_info_get_type ()) +#define GTK_HOTKEY_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_HOTKEY_TYPE_INFO, GtkHotkeyInfo)) +#define GTK_HOTKEY_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_HOTKEY_TYPE_INFO, GtkHotkeyInfoClass)) +#define GTK_HOTKEY_IS_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_HOTKEY_TYPE_INFO)) +#define GTK_HOTKEY_IS_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_HOTKEY_TYPE_INFO)) +#define GTK_HOTKEY_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_HOTKEY_TYPE_INFO, GtkHotkeyInfoClass)) + +typedef struct _GtkHotkeyInfo GtkHotkeyInfo; +typedef struct _GtkHotkeyInfoClass GtkHotkeyInfoClass; +typedef struct _GtkHotkeyInfoPrivate GtkHotkeyInfoPrivate; + +struct _GtkHotkeyInfo { + GObject parent; + GtkHotkeyInfoPrivate * priv; +}; +struct _GtkHotkeyInfoClass { + GObjectClass parent; +}; + +gboolean gtk_hotkey_info_bind (GtkHotkeyInfo* self, GError **error); + +gboolean gtk_hotkey_info_unbind (GtkHotkeyInfo* self, GError **error); + +gboolean gtk_hotkey_info_is_bound (GtkHotkeyInfo* self); + +const gchar* gtk_hotkey_info_get_application_id (GtkHotkeyInfo* self); + +const gchar* gtk_hotkey_info_get_key_id (GtkHotkeyInfo* self); + +GAppInfo* gtk_hotkey_info_get_app_info (GtkHotkeyInfo* self); + +const gchar* gtk_hotkey_info_get_application_id (GtkHotkeyInfo* self); + +const gchar* gtk_hotkey_info_get_signature (GtkHotkeyInfo* self); + +const gchar* gtk_hotkey_info_get_key_id (GtkHotkeyInfo* self); + +const gchar* gtk_hotkey_info_get_description (GtkHotkeyInfo* self); + +void gtk_hotkey_info_set_description (GtkHotkeyInfo* self, const gchar *description); + +gboolean gtk_hotkey_info_equals (GtkHotkeyInfo *hotkey1, GtkHotkeyInfo *hotkey2, gboolean sloppy_equals); + +void gtk_hotkey_info_activated (GtkHotkeyInfo* self, guint event_time); + +GtkHotkeyInfo* gtk_hotkey_info_new (const gchar *app_id, + const gchar *key_id, + const gchar *signature, + GAppInfo *app_info); + +GType gtk_hotkey_info_get_type (void); + +G_END_DECLS + +#endif diff --git a/src/plugins/notification/gtkhotkey/gtk-hotkey-key-file-registry.c b/src/plugins/notification/gtkhotkey/gtk-hotkey-key-file-registry.c @@ -0,0 +1,720 @@ +/* + * This file is part of GtkHotkey. + * Copyright Mikkel Kamstrup Erlandsen, March, 2008 + * + * GtkHotkey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GtkHotkey 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with GtkHotkey. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "gtk-hotkey-key-file-registry.h" +#include "gtk-hotkey-utils.h" + +#include <gio/gio.h> +#include <gio/gdesktopappinfo.h> + +enum { + GTK_HOTKEY_KEY_FILE_REGISTRY_DUMMY_PROPERTY +}; + +/* Beware - the lengths of these strings are hardcoded throughout + * this file (sorry) */ +#define HOTKEY_HOME "~/.config/hotkeys" +#define HOTKEY_FILE_EXT ".hotkeys" +#define HOTKEY_GROUP "hotkey:" + +static GtkHotkeyInfo* gtk_hotkey_key_file_registry_real_get_hotkey (GtkHotkeyRegistry *base, + const char *app_id, + const char *key_id, + GError **error); + +static GList* gtk_hotkey_key_file_registry_real_get_application_hotkeys + (GtkHotkeyRegistry *base, + const char *app_id, + GError **error); + +static GList* gtk_hotkey_key_file_registry_real_get_all_hotkeys + (GtkHotkeyRegistry *base); + +static gboolean gtk_hotkey_key_file_registry_real_store_hotkey(GtkHotkeyRegistry *base, + GtkHotkeyInfo *info, + GError **error); + +static gboolean gtk_hotkey_key_file_registry_real_delete_hotkey + (GtkHotkeyRegistry *base, + const gchar *app_id, + const gchar *key_id, + GError **error); + +static gboolean gtk_hotkey_key_file_registry_real_has_hotkey (GtkHotkeyRegistry *base, + const gchar *app_id, + const gchar *key_id); + +static GFile* get_hotkey_home (void); + +static GFile* get_hotkey_file (const gchar *app_id); + +static GKeyFile* get_hotkey_key_file (const gchar *app_id, + GError **error); + +static GtkHotkeyInfo* get_hotkey_info_from_key_file (GKeyFile *keyfile, + const gchar *app_id, + const gchar *key_id, + GError **error); + +static GList* get_all_hotkey_infos_from_key_file (GKeyFile *keyfile, + const gchar *app_id); + +static gpointer gtk_hotkey_key_file_registry_parent_class = NULL; + + +static +GtkHotkeyInfo* +gtk_hotkey_key_file_registry_real_get_hotkey (GtkHotkeyRegistry *base, + const char *app_id, + const char *key_id, + GError **error) +{ + GtkHotkeyKeyFileRegistry *self; + GKeyFile *keyfile = NULL; + GtkHotkeyInfo *info = NULL; + + g_return_val_if_fail (GTK_HOTKEY_IS_KEY_FILE_REGISTRY(base), NULL); + g_return_val_if_fail (app_id != NULL, NULL); + g_return_val_if_fail (key_id != NULL, NULL); + + self = GTK_HOTKEY_KEY_FILE_REGISTRY (base); + + keyfile = get_hotkey_key_file (app_id, error); + if (keyfile == NULL) + goto clean_up; + + info = get_hotkey_info_from_key_file (keyfile, app_id, key_id, error); + + clean_up: + if (keyfile) g_key_file_free (keyfile); + + return info; + +} + + +static GList* +gtk_hotkey_key_file_registry_real_get_application_hotkeys (GtkHotkeyRegistry *base, + const char *app_id, + GError **error) +{ + GtkHotkeyKeyFileRegistry *self; + GKeyFile *keyfile; + + g_return_val_if_fail (app_id != NULL, NULL); + + self = GTK_HOTKEY_KEY_FILE_REGISTRY (base); + keyfile = get_hotkey_key_file (app_id, error); + + if (keyfile == NULL) + return NULL; /* error is set by get_hotkey_key_file() */ + + return get_all_hotkey_infos_from_key_file (keyfile, app_id); +} + + +static GList* +gtk_hotkey_key_file_registry_real_get_all_hotkeys (GtkHotkeyRegistry *base) +{ + GtkHotkeyKeyFileRegistry *self; + GFile *home; + GFileEnumerator *dir; + GFileInfo *file_info; + GError *error; + GList *result = NULL; + + self = GTK_HOTKEY_KEY_FILE_REGISTRY (base); + home = get_hotkey_home (); + + error = NULL; + dir = g_file_enumerate_children (home, G_FILE_ATTRIBUTE_STANDARD_NAME, + 0, NULL, &error); + if (error) { + gchar *path = g_file_get_path (home); + g_critical ("Failed to read hotkey home directory '%s': %s", + path, error->message); + g_free (path); + g_error_free (error); + return NULL; + } + + error = NULL; + while ((file_info = g_file_enumerator_next_file (dir, NULL, &error)) != NULL) { + const gchar *filename; + GFile *file; + GString *app_id; + GList *app_hotkeys; + + filename = g_file_info_get_name(file_info); + + if (g_str_has_suffix (filename, HOTKEY_FILE_EXT)) { + file = g_file_get_child (home, filename); + + /* Extract app_id from file name */ + app_id = g_string_new (filename); + g_string_erase (app_id, app_id->len - 8, 8); + + /* Load all hotkeys from the file, and append it to + * the total result */ + app_hotkeys = gtk_hotkey_registry_get_application_hotkeys (base, + app_id->str, + &error); + if (error) { + g_warning ("Failed to read hotkeys for application '%s': %s", + app_id->str, error->message); + g_error_free (error); + error = NULL; + } else { + result = g_list_concat (result, app_hotkeys); + } + + g_string_free (app_id, TRUE); + g_object_unref (file); + } + + g_object_unref (file_info); + } + + if (error) { + gchar *path = g_file_get_path (home); + g_warning ("Failed to read hotkey home directory '%s': %s", + path, error->message); + g_free (path); + g_error_free (error); + } + + + g_object_unref (dir); + g_object_unref (home); + + return result; +} + + +static gboolean +gtk_hotkey_key_file_registry_real_store_hotkey (GtkHotkeyRegistry *base, + GtkHotkeyInfo *info, + GError **error) +{ + GtkHotkeyKeyFileRegistry *self; + GKeyFile *keyfile; + GFile *file, *home; + GError *tmp_error; + gchar *file_path, *group; + + + self = GTK_HOTKEY_KEY_FILE_REGISTRY (base); + g_return_val_if_fail (GTK_HOTKEY_IS_INFO (info), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* Make sure we have our root dir */ + home = get_hotkey_home (); + if (!g_file_query_exists(home, NULL)) { + tmp_error = NULL; + if (!g_file_make_directory (home, NULL, &tmp_error)) { + g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR, + GTK_HOTKEY_REGISTRY_ERROR_IO, + "Failed to create hotkey configuration dir " + HOTKEY_HOME": %s", tmp_error->message); + g_error_free (tmp_error); + g_object_unref (home); + return FALSE; + } + } + + /* Now load any old contents of the keyfile */ + file = get_hotkey_file (gtk_hotkey_info_get_application_id (info)); + file_path = g_file_get_path (file); + keyfile = g_key_file_new (); + + tmp_error = NULL; + if (!g_key_file_load_from_file (keyfile, file_path, 0, &tmp_error)) { + if (tmp_error->code == G_KEY_FILE_ERROR_PARSE) { + g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR, + GTK_HOTKEY_REGISTRY_ERROR_MALFORMED_MEDIUM, + "The file %s is not in a valid key-file format: %s", + file_path, tmp_error->message); + goto clean_up; + } + /* Ignore other errors */ + g_error_free (tmp_error); + } + + /* Prepare keyfile data */ + group = g_strconcat (HOTKEY_GROUP, gtk_hotkey_info_get_key_id (info), NULL); + + g_key_file_set_string (keyfile, group, "Owner", + gtk_hotkey_info_get_application_id (info)); + g_key_file_set_string (keyfile, group, "Signature", + gtk_hotkey_info_get_signature (info)); + + if (gtk_hotkey_info_get_description (info)) + g_key_file_set_string (keyfile, group, "Description", + gtk_hotkey_info_get_description (info)); + + if (gtk_hotkey_info_get_app_info (info)) { + GAppInfo *ai = gtk_hotkey_info_get_app_info (info); + g_key_file_set_string (keyfile, group, "AppInfo", + g_app_info_get_id (ai)); + } + + gsize size; + gchar *contents; + tmp_error = NULL; + contents = g_key_file_to_data (keyfile, &size, &tmp_error); + if (tmp_error) { + g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR, + GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN, + "Failed to generate keyfile contents: %s", + tmp_error->message); + goto clean_up; + } + + /* Write the actual data */ + g_file_set_contents (file_path, contents, size, &tmp_error); + if (tmp_error) { + g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR, + GTK_HOTKEY_REGISTRY_ERROR_IO, + "Failed to write keyfile '%s': %s", + file_path, tmp_error->message); + goto clean_up; + } + + clean_up: + if (tmp_error) g_error_free (tmp_error); + g_free (file_path); + if (group) g_free (group); + g_key_file_free (keyfile); + g_object_unref (file); + g_object_unref (home); + + if (*error) + return FALSE; + + self = GTK_HOTKEY_KEY_FILE_REGISTRY (base); + g_return_val_if_fail (GTK_HOTKEY_IS_INFO (info), FALSE); + gtk_hotkey_registry_hotkey_stored (base, info); + return TRUE; +} + +static gboolean +gtk_hotkey_key_file_registry_real_delete_hotkey (GtkHotkeyRegistry *base, + const gchar *app_id, + const gchar *key_id, + GError **error) +{ + GtkHotkeyKeyFileRegistry *self; + GtkHotkeyInfo *info = NULL; + GFile *file; + GKeyFile *keyfile; + GError *tmp_error; + gboolean is_error = FALSE; + gchar *path, *group; + + g_return_val_if_fail (app_id != NULL, FALSE); + g_return_val_if_fail (key_id != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + self = GTK_HOTKEY_KEY_FILE_REGISTRY (base); + group = NULL; + + file = get_hotkey_file (app_id); + g_return_val_if_fail (G_IS_FILE(file), FALSE); + + path = g_file_get_path (file); + keyfile = g_key_file_new (); + + /* Load the old keyfile */ + tmp_error = NULL; + g_key_file_load_from_file (keyfile, path, 0, &tmp_error); + if (tmp_error) { + if ((tmp_error->domain == G_FILE_ERROR && + tmp_error->code == G_FILE_ERROR_NOENT) || + (tmp_error->domain == G_KEY_FILE_ERROR && + tmp_error->code == G_KEY_FILE_ERROR_NOT_FOUND)) + g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR, + GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN_APP, + "No such keyfile '%s'. Application '%s' has not " + "registered any hotkeys", + path, app_id); + else + g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR, + GTK_HOTKEY_REGISTRY_ERROR_IO, + "Failed to load keyfile '%s': %s", + app_id, tmp_error->message); + is_error = TRUE; + goto clean_up; + } + + /* Get a ref to the GtkHotkeyInfo so that we can emit it with the + * hotkey-deleted signal */ + tmp_error = NULL; + info = get_hotkey_info_from_key_file (keyfile, app_id, key_id, error); + if (info == NULL) { + is_error = TRUE; + goto clean_up; + } + + /* Remove the group for key_id */ + group = g_strconcat (HOTKEY_GROUP, key_id, NULL); + tmp_error = NULL; + g_key_file_remove_group (keyfile, group, &tmp_error); + if (tmp_error) { + if (tmp_error->domain == G_KEY_FILE_ERROR && + tmp_error->code == G_KEY_FILE_ERROR_GROUP_NOT_FOUND) + g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR, + GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN_APP, + "Application '%s' has not registered a hotkey with" + "id '%s'", app_id, key_id); + else + g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR, + GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN, + "Failed to delete hotkey '%s' from application %s: %s", + key_id, app_id, tmp_error->message); + is_error = TRUE; + goto clean_up; + } + + /* Check if the keyfile is empty. If it is we delete it */ + gsize count; + GStrv groups; + groups = g_key_file_get_groups (keyfile, &count); + g_strfreev (groups); + if (count == 0) { + tmp_error = NULL; + g_file_delete (file, NULL, &tmp_error); + + if (tmp_error) { + g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR, + GTK_HOTKEY_REGISTRY_ERROR_IO, + "Failed to delete empty keyfile '%s': %s", + path, tmp_error->message); + is_error = TRUE; + } + /* File deleted, we should just clean up and exit */ + goto clean_up; + } + + /* Write new keyfile */ + gsize size; + gchar *contents; + tmp_error = NULL; + contents = g_key_file_to_data (keyfile, &size, &tmp_error); + if (tmp_error) { + g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR, + GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN, + "Failed to generate keyfile contents: %s", + tmp_error->message); + is_error = TRUE; + goto clean_up; + } + + tmp_error = NULL; + g_file_set_contents (path, contents, size, &tmp_error); + if (tmp_error) { + g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR, + GTK_HOTKEY_REGISTRY_ERROR_IO, + "Failed to write keyfile '%s': %s", + path, tmp_error->message); + is_error = TRUE; + goto clean_up; + } + + clean_up: + if (tmp_error) g_error_free (tmp_error); + g_object_unref (file); + g_free (path); + if (group) g_free (group); + g_key_file_free (keyfile); + + if (is_error) + return FALSE; + + gtk_hotkey_registry_hotkey_deleted (base, info); + g_object_unref (info); + return TRUE; +} + +static gboolean +gtk_hotkey_key_file_registry_real_has_hotkey (GtkHotkeyRegistry *base, + const gchar *app_id, + const gchar *key_id) +{ + GtkHotkeyKeyFileRegistry *self; + GFile *file; + gboolean exists; + + g_return_val_if_fail (app_id != NULL, FALSE); + g_return_val_if_fail (key_id != NULL, FALSE); + + self = GTK_HOTKEY_KEY_FILE_REGISTRY (base); + + file = get_hotkey_file (app_id); + g_return_val_if_fail (G_IS_FILE(file), FALSE); + + if (g_file_query_exists (file, NULL)) + exists = TRUE; + else + exists = FALSE; + + g_object_unref (file); + return exists; +} + +static void +gtk_hotkey_key_file_registry_class_init (GtkHotkeyKeyFileRegistryClass *klass) +{ + gtk_hotkey_key_file_registry_parent_class = g_type_class_peek_parent (klass); + GTK_HOTKEY_REGISTRY_CLASS (klass)->get_hotkey = gtk_hotkey_key_file_registry_real_get_hotkey; + GTK_HOTKEY_REGISTRY_CLASS (klass)->get_application_hotkeys = gtk_hotkey_key_file_registry_real_get_application_hotkeys; + GTK_HOTKEY_REGISTRY_CLASS (klass)->get_all_hotkeys = gtk_hotkey_key_file_registry_real_get_all_hotkeys; + GTK_HOTKEY_REGISTRY_CLASS (klass)->store_hotkey = gtk_hotkey_key_file_registry_real_store_hotkey; + GTK_HOTKEY_REGISTRY_CLASS (klass)->delete_hotkey = gtk_hotkey_key_file_registry_real_delete_hotkey; + GTK_HOTKEY_REGISTRY_CLASS (klass)->has_hotkey = gtk_hotkey_key_file_registry_real_has_hotkey; +} + + +static void +gtk_hotkey_key_file_registry_init (GtkHotkeyKeyFileRegistry *self) +{ + +} + +static void +gtk_hotkey_key_file_registry_finalize (GtkHotkeyKeyFileRegistry *self) +{ + +} + +GType +gtk_hotkey_key_file_registry_get_type (void) +{ + static GType gtk_hotkey_key_file_registry_type_id = 0; + + if (G_UNLIKELY (gtk_hotkey_key_file_registry_type_id == 0)) { + static const GTypeInfo g_define_type_info = { + sizeof (GtkHotkeyKeyFileRegistryClass), + (GBaseInitFunc) gtk_hotkey_key_file_registry_init, + (GBaseFinalizeFunc) gtk_hotkey_key_file_registry_finalize, + (GClassInitFunc) gtk_hotkey_key_file_registry_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (GtkHotkeyKeyFileRegistry), + 0, + (GInstanceInitFunc) gtk_hotkey_key_file_registry_init + }; + + gtk_hotkey_key_file_registry_type_id = g_type_register_static (GTK_HOTKEY_TYPE_STORAGE, "GtkHotkeyKeyFileRegistry", &g_define_type_info, 0); + } + return gtk_hotkey_key_file_registry_type_id; +} + +static GFile* +get_hotkey_home (void) +{ + GFile *home; + + home = g_file_parse_name (HOTKEY_HOME); + + if (g_file_query_exists(home, NULL) && + !gtk_hotkey_g_file_is_directory(home)) { + g_critical (HOTKEY_HOME" exists but is not a directory"); + g_object_unref (home); + return NULL; + } + + return home; +} + +/* It is not guaranteed that the keyfile exists */ +static GFile* +get_hotkey_file (const gchar *app_id) +{ + GFile *home, *file; + gchar *filename; + + g_return_val_if_fail (app_id != NULL, NULL); + + home = get_hotkey_home(); + g_return_val_if_fail (home != NULL, NULL); + + filename = g_strconcat (app_id, HOTKEY_FILE_EXT, NULL); + file = g_file_get_child (home, filename); + + g_object_unref (home); + g_free (filename); + return file; +} + +static GKeyFile* +get_hotkey_key_file (const gchar *app_id, GError **error) +{ + gchar *path; + GFile *file; + GKeyFile *keyfile = NULL; + GError *tmp_error; + + g_return_val_if_fail (app_id != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + file = get_hotkey_file (app_id); + if (!g_file_query_exists (file, NULL)) { + g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR, + GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN_APP, + "Application '%s' has not registered any hotkeys", app_id); + g_object_unref (file); + return NULL; + } + + path = g_file_get_path (file); + keyfile = g_key_file_new (); + + tmp_error = NULL; + g_key_file_load_from_file (keyfile, path, 0, &tmp_error); + if (tmp_error) { + g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR, + GTK_HOTKEY_REGISTRY_ERROR_IO, + "Failed to load keyfile '%s': %s", path, tmp_error->message); + goto clean_up; + } + + clean_up: + g_free (path); + g_object_unref (file); + if (tmp_error) g_error_free (tmp_error); + + if (*error) { + g_key_file_free (keyfile); + return NULL; + } + + return keyfile; +} + +static GtkHotkeyInfo* +get_hotkey_info_from_key_file (GKeyFile *keyfile, + const gchar *app_id, + const gchar *key_id, + GError **error) +{ + GtkHotkeyInfo *info = NULL; + gchar *group, *description, *app_info_id, *signature; + GAppInfo *app_info = NULL; + + g_return_val_if_fail (keyfile != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_val_if_fail (app_id != NULL, NULL); + g_return_val_if_fail (key_id != NULL, NULL); + + group = g_strconcat (HOTKEY_GROUP, key_id, NULL); + description = g_key_file_get_string (keyfile, group, "Description", NULL); + app_info_id = g_key_file_get_string (keyfile, group, "AppInfo", NULL); + signature = g_key_file_get_string (keyfile, group, "Signature", NULL); + + if (!g_key_file_has_group (keyfile, group)) { + g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR, + GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN_KEY, + "Keyfile has no group "HOTKEY_GROUP"%s", key_id); + goto clean_up; + } + + if (!signature) { + g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR, + GTK_HOTKEY_REGISTRY_ERROR_BAD_SIGNATURE, + "No 'Signature' defined for hotkey '%s' for application '%s'", + key_id, app_id); + goto clean_up; + } + + if (app_info_id) { + app_info = G_APP_INFO(g_desktop_app_info_new (app_info_id)); + if (!G_IS_APP_INFO(app_info)) { + g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR, + GTK_HOTKEY_REGISTRY_ERROR_MISSING_APP, + "Keyfile refering to 'AppInfo = %s', but no application" + "by that id is registered on the system", app_info_id); + goto clean_up; + } + } + + info = gtk_hotkey_info_new (app_id, key_id, signature, app_info); + if (description) + gtk_hotkey_info_set_description (info, description); + + clean_up: + g_free (group); + if (signature) g_free (signature); + if (description) g_free (description); + if (app_info_id) g_free (app_info_id); + if (app_info) g_object_unref (app_info); + + return info; +} + +static GList* +get_all_hotkey_infos_from_key_file (GKeyFile *keyfile, + const gchar *app_id) +{ + GList *hotkeys; + GtkHotkeyInfo *hotkey; + GStrv groups; + gsize count; + gchar *group; + GString *key_id; + GError *error; + + g_return_val_if_fail (keyfile != NULL, NULL); + g_return_val_if_fail (app_id != NULL, NULL); + + hotkeys = NULL; + groups = g_key_file_get_groups (keyfile, &count); + + int i; + for (i = 0; i < count; i++) { + group = groups[i]; + key_id = g_string_new (group); + + /* Ignore non hotkey groups */ + if (!g_str_has_prefix (key_id->str, HOTKEY_GROUP)) { + g_warning ("Hotkey file for %s contains non 'hotkey:' group '%s'", + app_id, group); + g_string_free (key_id, TRUE); + continue; + } + + /* Strip 'hotkey:' prefix from key_id */ + g_string_erase (key_id, 0, 7); + + error = NULL; + hotkey = get_hotkey_info_from_key_file (keyfile, app_id, key_id->str, &error); + if (error) { + g_warning ("Failed to read hotkey '%s' for application '%s': %s", + key_id->str, app_id, error->message); + g_error_free (error); + g_string_free (key_id, TRUE); + continue; + } + + hotkeys = g_list_prepend (hotkeys, hotkey); + + g_string_free (key_id, TRUE); + } + + g_strfreev (groups); + return hotkeys; +} diff --git a/src/plugins/notification/gtkhotkey/gtk-hotkey-key-file-registry.h b/src/plugins/notification/gtkhotkey/gtk-hotkey-key-file-registry.h @@ -0,0 +1,59 @@ +/* + * This file is part of GtkHotkey. + * Copyright Mikkel Kamstrup Erlandsen, March, 2008 + * + * GtkHotkey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GtkHotkey 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with GtkHotkey. If not, see <http://www.gnu.org/licenses/>. + */ + +#if !defined (__GTK_HOTKEY_H__) && !defined (GTK_HOTKEY_COMPILATION) +#error "Only <gtkhotkey.h> can be included directly." +#endif + +#ifndef __GTK_HOTKEY_KEY_FILE_REGISTRY_H__ +#define __GTK_HOTKEY_KEY_FILE_REGISTRY_H__ + +#include <glib.h> +#include <glib-object.h> +#include <stdlib.h> +#include <string.h> +#include "gtk-hotkey-registry.h" +#include "gtk-hotkey-info.h" + +G_BEGIN_DECLS + + +#define GTK_HOTKEY_TYPE_KEY_FILE_REGISTRY (gtk_hotkey_key_file_registry_get_type ()) +#define GTK_HOTKEY_KEY_FILE_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_HOTKEY_TYPE_KEY_FILE_REGISTRY, GtkHotkeyKeyFileRegistry)) +#define GTK_HOTKEY_KEY_FILE_REGISTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_HOTKEY_TYPE_KEY_FILE_REGISTRY, GtkHotkeyKeyFileRegistryClass)) +#define GTK_HOTKEY_IS_KEY_FILE_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_HOTKEY_TYPE_KEY_FILE_REGISTRY)) +#define GTK_HOTKEY_IS_KEY_FILE_REGISTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_HOTKEY_TYPE_KEY_FILE_REGISTRY)) +#define GTK_HOTKEY_KEY_FILE_REGISTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_HOTKEY_TYPE_KEY_FILE_REGISTRY, GtkHotkeyKeyFileRegistryClass)) + +typedef struct _GtkHotkeyKeyFileRegistry GtkHotkeyKeyFileRegistry; +typedef struct _GtkHotkeyKeyFileRegistryClass GtkHotkeyKeyFileRegistryClass; +typedef struct _GtkHotkeyKeyFileRegistryPrivate GtkHotkeyKeyFileRegistryPrivate; + +struct _GtkHotkeyKeyFileRegistry { + GtkHotkeyRegistry parent; + GtkHotkeyKeyFileRegistryPrivate * priv; +}; +struct _GtkHotkeyKeyFileRegistryClass { + GtkHotkeyRegistryClass parent; +}; + +GType gtk_hotkey_key_file_registry_get_type (void); + +G_END_DECLS + +#endif diff --git a/src/plugins/notification/gtkhotkey/gtk-hotkey-listener.c b/src/plugins/notification/gtkhotkey/gtk-hotkey-listener.c @@ -0,0 +1,218 @@ +/* + * This file is part of GtkHotkey. + * Copyright Mikkel Kamstrup Erlandsen, March, 2008 + * + * GtkHotkey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GtkHotkey 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with GtkHotkey. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "gtk-hotkey-listener.h" +#include "gtk-hotkey-x11-listener.h" +#include "gtk-hotkey-marshal.h" + +/* FIXME: The default listener is hardcoded to x11, should be compilation target dependent */ + +enum { + ACTIVATED, + + LAST_SIGNAL +}; + +enum { + GTK_HOTKEY_LISTENER_DUMMY_PROPERTY +}; + +guint listener_signals[LAST_SIGNAL] = { 0 }; + +static gpointer gtk_hotkey_listener_parent_class = NULL; + +static GtkHotkeyListener *default_listener = NULL; +static GType default_listener_type = G_TYPE_INVALID; + +/** + * SECTION:gtk-hotkey-listener + * @short_description: Abstract base class providing platform independent hotkey listening capabilities + * @see_also: #GtkHotkeyRegistry, #GtkHotkeyInfo + * + * #GtkHotkeyListener is an abstract base class for implementing platform + * specific hotkey listeners - ie objects able to register when the user enters + * a certain keyboard combination, regardless of which window has focus. + * + * Unless you have very special needs you should use the factory method + * gtk_hotkey_listener_get_default() to get a reference to a #GtkHotkeyListener + * matching your platform. Although most applications will not need. + * + * This class is part of the advanced API of GtkHotkey. Applications will not + * normally use a #GtkHotkeyListener directly, since gtk_hotkey_info_bind() + * will call into gtk_hotkey_listener_bind() on the default listener for you. + **/ + +/** + * gtk_hotkey_listener_get_default + * @returns: A new reference to the default hotkey listener for the platform + * + * Static factory method to get a reference to the default #GtkHotkeyListener + * for the current platform. + * + * FIXME: Currently hardcoded to X11 + */ +GtkHotkeyListener* +gtk_hotkey_listener_get_default () +{ + /* FIXME: This method should be changedd to use the same approach as + * gtk_hotkey_registry_get_default() */ + + if (default_listener) { + g_return_val_if_fail (GTK_HOTKEY_IS_LISTENER(default_listener), NULL); + return g_object_ref (default_listener); + } + gtk_hotkey_listener_get_type (); /* This call makes sure the default type ise set */ + g_debug ("Listener Type: %s", g_type_name (default_listener_type)); + + default_listener = g_object_new (default_listener_type, NULL); + g_return_val_if_fail (GTK_HOTKEY_IS_LISTENER(default_listener), NULL); + + return g_object_ref (default_listener); +} + +/** + * gtk_hotkey_listener_bind_hotkey + * @self: The hotkey listener on which to bind a hotkey + * @hotkey: The #GtkHotkeyInfo to bind. See #GtkHotkeyInfo:signature + * @error: #GError in which to store errors, or %NULL to ignore + * @returns: %TRUE if the binding succeeded, or %FALSE otherwise. In case of + * runtime errors @error will be set + * + * This method must be implemented by any child class of #GtkHotkeyListener. + * + * Start listening for keypresses matching the signature of @hotkey. + * This method is notmally accessed indirectly by calling gtk_hotkey_info_bind(). + */ +gboolean +gtk_hotkey_listener_bind_hotkey (GtkHotkeyListener *self, + GtkHotkeyInfo *hotkey, + GError **error) +{ + g_return_val_if_fail (GTK_HOTKEY_IS_LISTENER(self), FALSE); + + return GTK_HOTKEY_LISTENER_GET_CLASS (self)->bind_hotkey (self, hotkey, error); +} + +/** + * gtk_hotkey_listener_unbind_hotkey + * @self: The hotkey listener on which to bind a hotkey + * @hotkey: The #GtkHotkeyInfo to bind. See #GtkHotkeyInfo:signature + * @error: #GError in which to store errors, or %NULL to ignore + * @returns: %TRUE if the binding has been removed, or %FALSE otherwise. + * In case of runtime errors @error will be set + * + * This method must be implemented by any child class of #GtkHotkeyListener. + * + * Stop listening for keypresses matching the signature of @hotkey. This method + * is notmally accessed indirectly by calling gtk_hotkey_info_unbind(). + */ +gboolean +gtk_hotkey_listener_unbind_hotkey (GtkHotkeyListener *self, + GtkHotkeyInfo *hotkey, + GError **error) +{ + g_return_val_if_fail (GTK_HOTKEY_IS_LISTENER(self), FALSE); + + return GTK_HOTKEY_LISTENER_GET_CLASS (self)->unbind_hotkey (self, hotkey, error); +} + +/** + * gtk_hotkey_listener_activated + * @self: #GtkHotkeyListener to emit the #GtkHotkeyListener::activated signal + * @hotkey: The #GtkHotkeyInfo the event happened for + * @event_time: The system time the event happened on. This is useful for + * applications to pass through focus stealing prevention when + * mapping windows + * + * Emit the #GtkHotkeyInfo::activated signal on a hotkey listener. + */ +void +gtk_hotkey_listener_activated (GtkHotkeyListener *self, + GtkHotkeyInfo *hotkey, + guint event_time) +{ + g_return_if_fail (GTK_HOTKEY_IS_LISTENER(self)); + g_return_if_fail (GTK_HOTKEY_IS_INFO(hotkey)); + + g_signal_emit (self, listener_signals[ACTIVATED], 0, hotkey, event_time); +} + +static void +gtk_hotkey_listener_class_init (GtkHotkeyListenerClass * klass) +{ + gtk_hotkey_listener_parent_class = g_type_class_peek_parent (klass); + + /** + * GtkHotkeyListener::activated + * @listener: The object that emitted the signal + * @hotkey: a #GtkHotkeyInfo for the hotkey that was activated + * @event_time: Time for event triggering the keypress. This is mainly + * used to pass to window management functions to pass through + * focus stealing prevention + * + * Emitted when a registered hotkey has been activated. + */ + listener_signals[ACTIVATED] = \ + g_signal_new ("activated", + GTK_HOTKEY_TYPE_LISTENER, + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + gtk_hotkey_marshal_VOID__OBJECT_UINT, + G_TYPE_NONE, 2, + GTK_HOTKEY_TYPE_INFO, + G_TYPE_UINT); +} + + +static void +gtk_hotkey_listener_init (GtkHotkeyListener * self) +{ +} + + +GType +gtk_hotkey_listener_get_type (void) +{ + static GType gtk_hotkey_listener_type_id = 0; + + if (G_UNLIKELY (gtk_hotkey_listener_type_id == 0)) { + static const GTypeInfo g_define_type_info = { + sizeof (GtkHotkeyListenerClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gtk_hotkey_listener_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (GtkHotkeyListener), + 0, + (GInstanceInitFunc) gtk_hotkey_listener_init + }; + + gtk_hotkey_listener_type_id = g_type_register_static (G_TYPE_OBJECT, + "GtkHotkeyListener", + &g_define_type_info, + G_TYPE_FLAG_ABSTRACT); + + default_listener_type = gtk_hotkey_x11_listener_get_type (); + } + return gtk_hotkey_listener_type_id; +} + + + + diff --git a/src/plugins/notification/gtkhotkey/gtk-hotkey-listener.h b/src/plugins/notification/gtkhotkey/gtk-hotkey-listener.h @@ -0,0 +1,77 @@ +/* + * This file is part of GtkHotkey. + * Copyright Mikkel Kamstrup Erlandsen, March, 2008 + * + * GtkHotkey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GtkHotkey 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with GtkHotkey. If not, see <http://www.gnu.org/licenses/>. + */ + +#if !defined (__GTK_HOTKEY_H__) && !defined (GTK_HOTKEY_COMPILATION) +#error "Only <gtkhotkey.h> can be included directly." +#endif + +#ifndef __GTK_HOTKEY_LISTENER_H__ +#define __GTK_HOTKEY_LISTENER_H__ + +#include <glib.h> +#include <glib-object.h> +#include "gtk-hotkey-info.h" + +G_BEGIN_DECLS + + +#define GTK_HOTKEY_TYPE_LISTENER (gtk_hotkey_listener_get_type ()) +#define GTK_HOTKEY_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_HOTKEY_TYPE_LISTENER, GtkHotkeyListener)) +#define GTK_HOTKEY_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_HOTKEY_TYPE_LISTENER, GtkHotkeyListenerClass)) +#define GTK_HOTKEY_IS_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_HOTKEY_TYPE_LISTENER)) +#define GTK_HOTKEY_IS_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_HOTKEY_TYPE_LISTENER)) +#define GTK_HOTKEY_LISTENER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_HOTKEY_TYPE_LISTENER, GtkHotkeyListenerClass)) + +typedef struct _GtkHotkeyListener GtkHotkeyListener; +typedef struct _GtkHotkeyListenerClass GtkHotkeyListenerClass; +typedef struct _GtkHotkeyListenerPrivate GtkHotkeyListenerPrivate; + +struct _GtkHotkeyListener { + GObject parent; + GtkHotkeyListenerPrivate *priv; +}; + +struct _GtkHotkeyListenerClass { + GObjectClass parent; + gboolean (*bind_hotkey) (GtkHotkeyListener *self, + GtkHotkeyInfo *hotkey, + GError **error); + gboolean (*unbind_hotkey) (GtkHotkeyListener *self, + GtkHotkeyInfo *hotkey, + GError **error); +}; + +GtkHotkeyListener* gtk_hotkey_listener_get_default (void); + +void gtk_hotkey_listener_activated (GtkHotkeyListener *self, + GtkHotkeyInfo *hotkey, + guint event_time); + +gboolean gtk_hotkey_listener_bind_hotkey (GtkHotkeyListener *self, + GtkHotkeyInfo *hotkey, + GError **error); + +gboolean gtk_hotkey_listener_unbind_hotkey (GtkHotkeyListener *self, + GtkHotkeyInfo *hotkey, + GError **error); + +GType gtk_hotkey_listener_get_type (void); + +G_END_DECLS + +#endif /* __GTK_HOTKEY_LISTENER_H__ */ diff --git a/src/plugins/notification/gtkhotkey/gtk-hotkey-marshal.c b/src/plugins/notification/gtkhotkey/gtk-hotkey-marshal.c @@ -0,0 +1,86 @@ + +#include <glib-object.h> + + +#ifdef G_ENABLE_DEBUG +#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) +#define g_marshal_value_peek_char(v) g_value_get_char (v) +#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) +#define g_marshal_value_peek_int(v) g_value_get_int (v) +#define g_marshal_value_peek_uint(v) g_value_get_uint (v) +#define g_marshal_value_peek_long(v) g_value_get_long (v) +#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) +#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) +#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) +#define g_marshal_value_peek_enum(v) g_value_get_enum (v) +#define g_marshal_value_peek_flags(v) g_value_get_flags (v) +#define g_marshal_value_peek_float(v) g_value_get_float (v) +#define g_marshal_value_peek_double(v) g_value_get_double (v) +#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) +#define g_marshal_value_peek_param(v) g_value_get_param (v) +#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) +#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) +#define g_marshal_value_peek_object(v) g_value_get_object (v) +#else /* !G_ENABLE_DEBUG */ +/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. + * Do not access GValues directly in your code. Instead, use the + * g_value_get_*() functions + */ +#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int +#define g_marshal_value_peek_char(v) (v)->data[0].v_int +#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint +#define g_marshal_value_peek_int(v) (v)->data[0].v_int +#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint +#define g_marshal_value_peek_long(v) (v)->data[0].v_long +#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 +#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 +#define g_marshal_value_peek_enum(v) (v)->data[0].v_long +#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_float(v) (v)->data[0].v_float +#define g_marshal_value_peek_double(v) (v)->data[0].v_double +#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer +#endif /* !G_ENABLE_DEBUG */ + + +/* VOID:OBJECT,UINT (src/marshal.list:2) */ +void +gtk_hotkey_marshal_VOID__OBJECT_UINT (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__OBJECT_UINT) (gpointer data1, + gpointer arg_1, + guint arg_2, + gpointer data2); + register GMarshalFunc_VOID__OBJECT_UINT callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__OBJECT_UINT) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_object (param_values + 1), + g_marshal_value_peek_uint (param_values + 2), + data2); +} + diff --git a/src/plugins/notification/gtkhotkey/gtk-hotkey-marshal.h b/src/plugins/notification/gtkhotkey/gtk-hotkey-marshal.h @@ -0,0 +1,24 @@ + +#if !defined (__GTK_HOTKEY_H__) && !defined (GTK_HOTKEY_COMPILATION) +#error "Only <gtkhotkey.h> can be included directly." +#endif + +#ifndef __gtk_hotkey_marshal_MARSHAL_H__ +#define __gtk_hotkey_marshal_MARSHAL_H__ + +#include <glib-object.h> + +G_BEGIN_DECLS + +/* VOID:OBJECT,UINT (src/marshal.list:2) */ +extern void gtk_hotkey_marshal_VOID__OBJECT_UINT (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +G_END_DECLS + +#endif /* __gtk_hotkey_marshal_MARSHAL_H__ */ + diff --git a/src/plugins/notification/gtkhotkey/gtk-hotkey-registry.c b/src/plugins/notification/gtkhotkey/gtk-hotkey-registry.c @@ -0,0 +1,341 @@ +/* + * This file is part of GtkHotkey. + * Copyright Mikkel Kamstrup Erlandsen, March, 2008 + * + * GtkHotkey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GtkHotkey 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with GtkHotkey. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "gtk-hotkey-registry.h" +#include "gtk-hotkey-key-file-registry.h" + +enum { + GTK_HOTKEY_REGISTRY_DUMMY_PROPERTY +}; + +enum { + HOTKEY_STORED, + HOTKEY_DELETED, + + LAST_SIGNAL +}; + +static gpointer gtk_hotkey_registry_parent_class = NULL; + +static GType default_registry_type = G_TYPE_INVALID; + +static GtkHotkeyRegistry + *default_registry = NULL; + +#define DEFAULT_REGISTRY_TYPE GTK_HOTKEY_TYPE_KEY_FILE_REGISTRY + +guint storage_signals[LAST_SIGNAL] = { 0 }; + +/** + * SECTION:gtk-hotkey-registry + * @short_description: Abstract base class for services storing and loading hotkeys + * @see_also: #GtkHotkeyKeyFileRegistry + * + * #GtkHotkeyRegistry is an abstract base class for implementing a platform + * specific service for storing and loading hotkey configurations. + * + * The actual binding of the hotkey into the environment is done by a + * #GtkHotkeyListener. This class is only meant to do the management part of the + * hotkey handling. + * + * The reasong why applications should use a #GtkHotkeyRegistry and not just a + * flat text file with the hotkey signature is to make sure we don't overwrite + * or interfere with the hotkeys of other applications. And possibly providing + * a unified user interface for managing the hotkeys of all applications. + * + * To obtain a #GtkHotkeyRegistry matching your desktop environment use + * the factory method gtk_hotkey_registry_get_default(). + * + **/ + +/** + * gtk_hotkey_registry_get_default + * @returns: A reference to a #GtkHotkeyRegistry matching your platform + * + * Currently the only implementation of this class is #GtkHotkeyKeyFileRegistry. + */ +GtkHotkeyRegistry* +gtk_hotkey_registry_get_default (void) +{ + if (G_UNLIKELY(default_registry == NULL)) { + + /* Set the default type of registry to create */ + if (default_registry_type == G_TYPE_INVALID) + default_registry_type = DEFAULT_REGISTRY_TYPE; + + default_registry = GTK_HOTKEY_REGISTRY (g_object_new (GTK_HOTKEY_TYPE_KEY_FILE_REGISTRY, + NULL)); + g_return_val_if_fail (GTK_HOTKEY_IS_REGISTRY(default_registry), NULL); + /* We always keep a ref to the registry here */ + } + return g_object_ref(default_registry); +} + +/** + * gtk_hotkey_registry_get_hotkey + * @self: The registry to search in + * @app_id: The name under which the application has registered it self + * when it created the #GtkHotkeyInfo in the first place. + * @key_id: The id assignedd to the actual hotkey on the moment of its creation + * @error: Place to store a #GError in case of errors, or %NULL to ignore + * @returns: The #GtkHotkeyInfo for the requested parameters or %NULL is none + * where found. In the case %NULL is returned @error will be set + * accordingly. Free the hotkey with g_object_unref() when you are done + * using it. + * + * Look up a hotkey given its id and application id. + */ +GtkHotkeyInfo* +gtk_hotkey_registry_get_hotkey (GtkHotkeyRegistry *self, + const char *app_id, + const char *key_id, + GError **error) +{ + g_return_val_if_fail (GTK_HOTKEY_IS_REGISTRY(self), NULL); + return GTK_HOTKEY_REGISTRY_GET_CLASS (self)->get_hotkey (self, app_id, key_id, + error); +} + +/** + * gtk_hotkey_registry_get_application_hotkeys + * @self: The #GtkHotkeyRegistry to look hotkeys up in + * @app_id: Unique application id + * @error: Place to return a #GError or %NULL + * @returns: A list of #GtkHotkeyInfo objects. The list should be with freed with + * g_list_free() and the hotkey objects should be freed with + * g_object_unref(). + * + * Look up all hotkeys registered by a given application. + */ +GList* +gtk_hotkey_registry_get_application_hotkeys (GtkHotkeyRegistry *self, + const char *app_id, + GError **error) +{ + g_return_val_if_fail (GTK_HOTKEY_IS_REGISTRY(self), NULL); + return GTK_HOTKEY_REGISTRY_GET_CLASS (self)->get_application_hotkeys (self, app_id, error); +} + +/** + * gtk_hotkey_registry_get_all_hotkeys + * @self: The #GtkHotkeyRegistry to look hotkeys up in + * @returns: A list of all valid #GtkHotkeyInfo<!-- -->s stored in the registry. + * The list should be with freed with g_list_free() and the hotkey + * objects should be freed with g_object_unref(). + * + * Look up all hotkeys registered by a given application. + */ +GList* +gtk_hotkey_registry_get_all_hotkeys (GtkHotkeyRegistry *self) +{ + g_return_val_if_fail (GTK_HOTKEY_IS_REGISTRY(self), NULL); + return GTK_HOTKEY_REGISTRY_GET_CLASS (self)->get_all_hotkeys (self); +} + +/** + * gtk_hotkey_registry_store_hotkey + * @self: The #GtkHotkeyRegistry in which to store the hotkey + * @info: The #GtkHotkeyInfo to store + * @error: Place to return a #GError or %NULL to ignore + * @returns: %TRUE on success and %FALS otherwise. In case of errors @error + * will be set accordingly. + * + * Store a hotkey in the registry for later usage. In case of success the + * #GtkHotkeyRegistry::hotkey-stored signal will be emitted. + */ +gboolean +gtk_hotkey_registry_store_hotkey (GtkHotkeyRegistry *self, + GtkHotkeyInfo *info, + GError **error) +{ + g_return_val_if_fail (GTK_HOTKEY_IS_REGISTRY(self), FALSE); + return GTK_HOTKEY_REGISTRY_GET_CLASS (self)->store_hotkey (self, info, error); +} + +/** + * gtk_hotkey_registry_delete_hotkey + * @self: The #GtkHotkeyRegistry from which to delete the hotkey + * @app_id: The value of the #GtkHotkeyInfo:application-id property of the stored + * hotkey + * @key_id: The value of the #GtkHotkeyInfo:key-id property of the stored hotkey + * @error: Place to return a #GError or %NULL to ignore + * @returns: %TRUE on success and %FALS otherwise. In case of errors @error + * will be set accordingly. + * + * Delete a hotkey from the registry. In case of success the + * #GtkHotkeyRegistry::hotkey-deleted signal will be emitted. + */ +gboolean +gtk_hotkey_registry_delete_hotkey (GtkHotkeyRegistry *self, + const gchar *app_id, + const gchar *key_id, + GError **error) +{ + g_return_val_if_fail (GTK_HOTKEY_IS_REGISTRY(self), FALSE); + return GTK_HOTKEY_REGISTRY_GET_CLASS (self)->delete_hotkey (self, app_id, + key_id, error); +} + +/** + * gtk_hotkey_registry_has_hotkey + * @self: The #GtkHotkeyRegistry to look hotkeys up in + * @app_id: The value of the #GtkHotkeyInfo:application-id property of the stored + * hotkey + * @key_id: The value of the #GtkHotkeyInfo:key-id property of the stored hotkey + * @returns: %TRUE if the registry has stored a hotkey with with application id + * @app_id and hotkey id @key_id. + * + * Look up all hotkeys registered by a given application. + */ +gboolean +gtk_hotkey_registry_has_hotkey (GtkHotkeyRegistry *self, + const gchar *app_id, + const gchar *key_id) +{ + g_return_val_if_fail (GTK_HOTKEY_IS_REGISTRY(self), FALSE); + return GTK_HOTKEY_REGISTRY_GET_CLASS (self)->has_hotkey (self, app_id, key_id); +} + +/** + * gtk_hotkey_registry_hotkey_stored + * @self: The #GtkHotkeyRegistry to emit the signal on + * @info: The #GtkHotkeyInfo that was stored + * + * Emit the #GtkHotkeyRegistry::hotkey-stored signal on @self. This method should + * only be used by child classes of #GtkHotkeyRegistry. + */ +void +gtk_hotkey_registry_hotkey_stored (GtkHotkeyRegistry *self, + GtkHotkeyInfo *info) +{ + g_return_if_fail (GTK_HOTKEY_IS_REGISTRY(self)); + g_return_if_fail (GTK_HOTKEY_IS_INFO(info)); + + GTK_HOTKEY_REGISTRY_GET_CLASS (self)->hotkey_stored (self, info); +} + +/** + * gtk_hotkey_registry_hotkey_deleted + * @self: The #GtkHotkeyRegistry to emit the signal on + * @info: The #GtkHotkeyInfo that was deleted + * + * Emit the #GtkHotkeyRegistry::hotkey-deleted signal on @self. This method should + * only be used by child classes of #GtkHotkeyRegistry. + */ +void +gtk_hotkey_registry_hotkey_deleted (GtkHotkeyRegistry *self, + GtkHotkeyInfo *info) +{ + g_return_if_fail (GTK_HOTKEY_IS_REGISTRY(self)); + GTK_HOTKEY_REGISTRY_GET_CLASS (self)->hotkey_deleted (self, info); +} + +static void +gtk_hotkey_registry_hotkey_stored_real (GtkHotkeyRegistry *self, + GtkHotkeyInfo *info) +{ + g_return_if_fail (GTK_HOTKEY_IS_INFO(info)); + g_return_if_fail (GTK_HOTKEY_IS_REGISTRY(self)); + + g_signal_emit (self, storage_signals[HOTKEY_STORED], 0, info); +} + +static void +gtk_hotkey_registry_hotkey_deleted_real (GtkHotkeyRegistry *self, + GtkHotkeyInfo *info) +{ + g_return_if_fail (GTK_HOTKEY_IS_INFO(info)); + g_return_if_fail (GTK_HOTKEY_IS_REGISTRY(self)); + + g_signal_emit (self, storage_signals[HOTKEY_DELETED], 0, info); +} + +static void +gtk_hotkey_registry_class_init (GtkHotkeyRegistryClass *klass) +{ + gtk_hotkey_registry_parent_class = g_type_class_peek_parent (klass); + + klass->hotkey_stored = gtk_hotkey_registry_hotkey_stored_real; + klass->hotkey_deleted = gtk_hotkey_registry_hotkey_deleted_real; + + /** + * GtkHotkeyRegistry::hotkey-stored + * @hotkey:The hotkey that was stored + * + * Emitted when a hotkey has been stored in the registry + */ + storage_signals[HOTKEY_STORED] = \ + g_signal_new ("hotkey_stored", + GTK_HOTKEY_TYPE_STORAGE, + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + G_TYPE_OBJECT); + + /** + * GtkHotkeyRegistry::hotkey-deleted + * @hotkey:The hotkey that was deleted + * + * Emitted when a hotkey has been deleted from the registry + */ + storage_signals[HOTKEY_DELETED] = \ + g_signal_new ("hotkey_deleted", + GTK_HOTKEY_TYPE_STORAGE, + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + G_TYPE_OBJECT); +} + + +static void +gtk_hotkey_registry_init (GtkHotkeyRegistry * self) +{ + +} + +static void +gtk_hotkey_registry_finalize (GtkHotkeyRegistry * self) +{ + +} + +GType +gtk_hotkey_registry_get_type (void) +{ + static GType gtk_hotkey_registry_type_id = 0; + + if (G_UNLIKELY (gtk_hotkey_registry_type_id == 0)) { + static const GTypeInfo g_define_type_info = { + sizeof (GtkHotkeyRegistryClass), + (GBaseInitFunc) gtk_hotkey_registry_init, + (GBaseFinalizeFunc) gtk_hotkey_registry_finalize, + (GClassInitFunc) gtk_hotkey_registry_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (GtkHotkeyRegistry), + 0, + (GInstanceInitFunc) gtk_hotkey_registry_init + }; + + gtk_hotkey_registry_type_id = g_type_register_static (G_TYPE_OBJECT, "GtkHotkeyRegistry", &g_define_type_info, G_TYPE_FLAG_ABSTRACT); + } + return gtk_hotkey_registry_type_id; +} diff --git a/src/plugins/notification/gtkhotkey/gtk-hotkey-registry.h b/src/plugins/notification/gtkhotkey/gtk-hotkey-registry.h @@ -0,0 +1,114 @@ +/* + * This file is part of GtkHotkey. + * Copyright Mikkel Kamstrup Erlandsen, March, 2008 + * + * GtkHotkey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GtkHotkey 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with GtkHotkey. If not, see <http://www.gnu.org/licenses/>. + */ + +#if !defined (__GTK_HOTKEY_H__) && !defined (GTK_HOTKEY_COMPILATION) +#error "Only <gtkhotkey.h> can be included directly." +#endif + +#ifndef __GTK_HOTKEY_REGISTRY_H__ +#define __GTK_HOTKEY_REGISTRY_H__ + +#include <glib.h> +#include <glib-object.h> +#include <stdlib.h> +#include <string.h> +#include "gtk-hotkey-info.h" +#include "gtk-hotkey-error.h" + +G_BEGIN_DECLS + + +#define GTK_HOTKEY_TYPE_STORAGE (gtk_hotkey_registry_get_type ()) +#define GTK_HOTKEY_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_HOTKEY_TYPE_STORAGE, GtkHotkeyRegistry)) +#define GTK_HOTKEY_REGISTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_HOTKEY_TYPE_STORAGE, GtkHotkeyRegistryClass)) +#define GTK_HOTKEY_IS_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_HOTKEY_TYPE_STORAGE)) +#define GTK_HOTKEY_IS_REGISTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_HOTKEY_TYPE_STORAGE)) +#define GTK_HOTKEY_REGISTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_HOTKEY_TYPE_STORAGE, GtkHotkeyRegistryClass)) + +typedef struct _GtkHotkeyRegistry GtkHotkeyRegistry; +typedef struct _GtkHotkeyRegistryClass GtkHotkeyRegistryClass; +typedef struct _GtkHotkeyRegistryPrivate GtkHotkeyRegistryPrivate; + +struct _GtkHotkeyRegistry { + GObject parent; + GtkHotkeyRegistryPrivate * priv; +}; +struct _GtkHotkeyRegistryClass { + GObjectClass parent; + GtkHotkeyInfo* (*get_hotkey) (GtkHotkeyRegistry *self, + const char *app_id, + const char *key_id, + GError **error); + GList* (*get_application_hotkeys) (GtkHotkeyRegistry *self, + const char *app_id, + GError **error); + GList* (*get_all_hotkeys) (GtkHotkeyRegistry *self); + gboolean (*store_hotkey) (GtkHotkeyRegistry *self, + GtkHotkeyInfo *info, + GError **error); + gboolean (*delete_hotkey) (GtkHotkeyRegistry *self, + const gchar *app_id, + const gchar *key_id, + GError **error); + gboolean (*has_hotkey) (GtkHotkeyRegistry *self, + const gchar *app_id, + const gchar *key_id); + void (*hotkey_stored) (GtkHotkeyRegistry *self, + GtkHotkeyInfo *info); + void (*hotkey_deleted) (GtkHotkeyRegistry *self, + GtkHotkeyInfo *info); +}; + +GtkHotkeyRegistry* gtk_hotkey_registry_get_default (void); + +GtkHotkeyInfo* gtk_hotkey_registry_get_hotkey (GtkHotkeyRegistry *self, + const char *app_id, + const char *key_id, + GError **error); + +GList* gtk_hotkey_registry_get_application_hotkeys + (GtkHotkeyRegistry *self, + const char *app_id, + GError **error); + +GList* gtk_hotkey_registry_get_all_hotkeys (GtkHotkeyRegistry *self); + +gboolean gtk_hotkey_registry_store_hotkey (GtkHotkeyRegistry *self, + GtkHotkeyInfo *info, + GError **error); + +gboolean gtk_hotkey_registry_delete_hotkey (GtkHotkeyRegistry *self, + const gchar *app_id, + const gchar *key_id, + GError **error); + +gboolean gtk_hotkey_registry_has_hotkey (GtkHotkeyRegistry *self, + const gchar *app_id, + const gchar *key_id); + +void gtk_hotkey_registry_hotkey_stored (GtkHotkeyRegistry *self, + GtkHotkeyInfo *hotkey); + +void gtk_hotkey_registry_hotkey_deleted (GtkHotkeyRegistry *self, + GtkHotkeyInfo *hotkey); + +GType gtk_hotkey_registry_get_type (void); + +G_END_DECLS + +#endif diff --git a/src/plugins/notification/gtkhotkey/gtk-hotkey-utils.c b/src/plugins/notification/gtkhotkey/gtk-hotkey-utils.c @@ -0,0 +1,48 @@ +/* + * This file is part of GtkHotkey. + * Copyright Mikkel Kamstrup Erlandsen, March, 2008 + * + * GtkHotkey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GtkHotkey 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with GtkHotkey. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <gio/gio.h> + +GFileType +gtk_hotkey_g_file_get_type (GFile *file) +{ + GFileInfo *info; + GFileType type; + GError *error; + + g_return_val_if_fail (G_IS_FILE(file), G_FILE_TYPE_UNKNOWN); + + if (!g_file_query_exists(file, NULL)) + return G_FILE_TYPE_UNKNOWN; + + g_return_val_if_fail (G_IS_FILE(file), G_FILE_TYPE_UNKNOWN); + error = NULL; + info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, + 0, NULL, &error); + + if (error) { + g_critical ("Failed to create GFileInfo: %s", error->message); + g_error_free (error); + return G_FILE_TYPE_UNKNOWN; + } + + type = g_file_info_get_file_type (info); + g_object_unref (info); + + return type; +} diff --git a/src/plugins/notification/gtkhotkey/gtk-hotkey-utils.h b/src/plugins/notification/gtkhotkey/gtk-hotkey-utils.h @@ -0,0 +1,37 @@ +/* + * This file is part of GtkHotkey. + * Copyright Mikkel Kamstrup Erlandsen, March, 2008 + * + * GtkHotkey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GtkHotkey 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with GtkHotkey. If not, see <http://www.gnu.org/licenses/>. + */ + +#if !defined (__GTK_HOTKEY_H__) && !defined (GTK_HOTKEY_COMPILATION) +#error "Only <gtkhotkey.h> can be included directly." +#endif + +#ifndef __GTK_HOTKEY_UTILS_H__ +#define __GTK_HOTKEY_UTILS_H__ + +#include <gio/gio.h> + +G_BEGIN_DECLS + +#define gtk_hotkey_g_file_is_directory(file) (gtk_hotkey_g_file_get_type(file) == G_FILE_TYPE_DIRECTORY) +#define gtk_hotkey_g_file_is_regular(file) (gtk_hotkey_g_file_get_type(file) == G_FILE_TYPE_REGULAR) + +GFileType gtk_hotkey_g_file_get_type (GFile *file); + +G_END_DECLS + +#endif /* __GTK_HOTKEY_UTILS_H__ */ diff --git a/src/plugins/notification/gtkhotkey/gtk-hotkey-x11-listener.c b/src/plugins/notification/gtkhotkey/gtk-hotkey-x11-listener.c @@ -0,0 +1,243 @@ +/* + * This file is part of GtkHotkey. + * Copyright Mikkel Kamstrup Erlandsen, March, 2008 + * + * GtkHotkey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GtkHotkey 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with GtkHotkey. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "gtk-hotkey-error.h" +#include "gtk-hotkey-x11-listener.h" +#include "gtk-hotkey-listener.h" +#include "gtk-hotkey-info.h" +#include "x11/tomboykeybinder.h" + +struct _GtkHotkeyX11ListenerPrivate { + GList *hotkeys; +}; + +enum { + GTK_HOTKEY_X11_LISTENER_DUMMY_PROPERTY +}; +static gboolean gtk_hotkey_x11_listener_real_bind_hotkey (GtkHotkeyListener *base, + GtkHotkeyInfo *hotkey, + GError **error); + +static gboolean gtk_hotkey_x11_listener_real_unbind_hotkey (GtkHotkeyListener *base, + GtkHotkeyInfo *hotkey, + GError **error); + +static void hotkey_activated_cb (char *signature, + gpointer user_data); + +static GtkHotkeyInfo* + find_hotkey_from_key_id (GtkHotkeyX11Listener *self, + const gchar *key_id); + +static gpointer gtk_hotkey_x11_listener_parent_class = NULL; + + +/** + * SECTION:gtk-hotkey-x11-listener + * @short_description: Implementation of #GtkHotkeyListener for a standard X11 + * environment + * @see_also: #GtkHotkeyRegistry, #GtkHotkeyInfo + * + * This implementation of a #GtkHotkeyListener should work in any X11 + * environment. + **/ + +static gboolean +gtk_hotkey_x11_listener_real_bind_hotkey (GtkHotkeyListener *base, + GtkHotkeyInfo *hotkey, + GError **error) +{ + GtkHotkeyX11Listener *self; + + g_return_val_if_fail (GTK_HOTKEY_IS_X11_LISTENER(base), FALSE); + g_return_val_if_fail (GTK_HOTKEY_IS_INFO (hotkey), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + self = GTK_HOTKEY_X11_LISTENER (base); + + if (find_hotkey_from_key_id(self, + gtk_hotkey_info_get_key_id (hotkey))) { + g_warning ("Hotkey '%s' already registered. Ignoring register request.", + gtk_hotkey_info_get_key_id (hotkey)); + return FALSE; + } + + if (tomboy_keybinder_bind (gtk_hotkey_info_get_signature(hotkey), + hotkey_activated_cb, + self)) { + self->priv->hotkeys = g_list_prepend (self->priv->hotkeys, hotkey); + g_object_ref (hotkey); + return TRUE; + } + + /* Bugger, we failed to bind */ + g_set_error (error, GTK_HOTKEY_LISTENER_ERROR, + GTK_HOTKEY_LISTENER_ERROR_BIND, + "Failed to register hotkey '%s' with signature '%s'", + gtk_hotkey_info_get_key_id (hotkey), + gtk_hotkey_info_get_signature (hotkey)); + + return FALSE; +} + + +static gboolean +gtk_hotkey_x11_listener_real_unbind_hotkey (GtkHotkeyListener *base, + GtkHotkeyInfo *hotkey, + GError **error) +{ + GtkHotkeyX11Listener *self; + GtkHotkeyInfo *saved_hk; + const gchar *signature; + + g_return_val_if_fail (GTK_HOTKEY_IS_X11_LISTENER (base), FALSE); + g_return_val_if_fail (GTK_HOTKEY_IS_INFO (hotkey), FALSE); + + self = GTK_HOTKEY_X11_LISTENER (base); + signature = gtk_hotkey_info_get_signature (hotkey); + saved_hk = find_hotkey_from_key_id (self, gtk_hotkey_info_get_key_id(hotkey)); + + if (!saved_hk) { + g_set_error (error, GTK_HOTKEY_LISTENER_ERROR, + GTK_HOTKEY_LISTENER_ERROR_UNBIND, + "Failed to unregister hotkey '%s' with signature '%s'. " + "No hotkey with that signature is known", + gtk_hotkey_info_get_key_id (hotkey), + signature); + return FALSE; + } + + /* Remove actual keybinding */ + tomboy_keybinder_unbind (signature, hotkey_activated_cb); + + /* Clean up refs */ + self->priv->hotkeys = g_list_remove (self->priv->hotkeys, saved_hk); + g_object_unref (saved_hk); + + /* Clean up signal handler */ + gulong handler = g_signal_handler_find (self, + G_SIGNAL_MATCH_DATA | G_SIGNAL_MATCH_FUNC, + 0, 0, NULL, gtk_hotkey_info_activated, + hotkey); + if (handler == 0) { + g_warning ("Failed to disconnect signal handler for hotkey '%s'", + gtk_hotkey_info_get_key_id (hotkey)); + } else { + g_signal_handler_disconnect (self, handler); + } + + return TRUE; + +} + +static void +hotkey_activated_cb (char *signature, + gpointer user_data) +{ + GtkHotkeyX11Listener *self; + GtkHotkeyInfo *hotkey; + GList *iter; + guint event_time; + + g_return_if_fail (GTK_HOTKEY_IS_X11_LISTENER(user_data)); + g_return_if_fail (signature != NULL); + + self = GTK_HOTKEY_X11_LISTENER(user_data); + event_time = tomboy_keybinder_get_current_event_time (); + + /* Trigger signals for hotkeys with matching signature */ + for (iter = self->priv->hotkeys; iter; iter = iter->next) { + hotkey = GTK_HOTKEY_INFO (iter->data); + if (g_str_equal (signature, gtk_hotkey_info_get_signature (hotkey))) { + gtk_hotkey_listener_activated (GTK_HOTKEY_LISTENER(self), + hotkey, event_time); + gtk_hotkey_info_activated (hotkey, event_time); + } + } + +} + +static GtkHotkeyInfo* +find_hotkey_from_key_id (GtkHotkeyX11Listener *self, + const gchar *key_id) +{ + GList *iter; + GtkHotkeyInfo *hotkey; + + g_return_val_if_fail (GTK_HOTKEY_IS_X11_LISTENER(self), NULL); + g_return_val_if_fail (key_id != NULL, NULL); + + for (iter = self->priv->hotkeys; iter; iter = iter->next) { + hotkey = GTK_HOTKEY_INFO (iter->data); + + if (g_str_equal (gtk_hotkey_info_get_key_id(hotkey), key_id)) + return hotkey; + } + + return NULL; +} + +static void +gtk_hotkey_x11_listener_class_init (GtkHotkeyX11ListenerClass * klass) +{ + gtk_hotkey_x11_listener_parent_class = g_type_class_peek_parent (klass); + + GTK_HOTKEY_LISTENER_CLASS (klass)->bind_hotkey = + gtk_hotkey_x11_listener_real_bind_hotkey; + GTK_HOTKEY_LISTENER_CLASS (klass)->unbind_hotkey = + gtk_hotkey_x11_listener_real_unbind_hotkey; + + /* Initialize the tomboy keybinder */ + tomboy_keybinder_init (); +} + + +static void +gtk_hotkey_x11_listener_init (GtkHotkeyX11Listener * self) +{ + self->priv = g_new0 (GtkHotkeyX11ListenerPrivate, 1); +} + +static void +gtk_hotkey_x11_listener_finalize (GtkHotkeyX11Listener * self) +{ + g_free(self->priv); +} + +GType +gtk_hotkey_x11_listener_get_type (void) +{ + static GType gtk_hotkey_x11_listener_type_id = 0; + + if (G_UNLIKELY (gtk_hotkey_x11_listener_type_id == 0)) { + static const GTypeInfo g_define_type_info = { + sizeof (GtkHotkeyX11ListenerClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) gtk_hotkey_x11_listener_finalize, + (GClassInitFunc) gtk_hotkey_x11_listener_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (GtkHotkeyX11Listener), + 0, + (GInstanceInitFunc) gtk_hotkey_x11_listener_init + }; + + gtk_hotkey_x11_listener_type_id = g_type_register_static (GTK_HOTKEY_TYPE_LISTENER, "GtkHotkeyX11Listener", &g_define_type_info, 0); + } + return gtk_hotkey_x11_listener_type_id; +} diff --git a/src/plugins/notification/gtkhotkey/gtk-hotkey-x11-listener.h b/src/plugins/notification/gtkhotkey/gtk-hotkey-x11-listener.h @@ -0,0 +1,57 @@ +/* + * This file is part of GtkHotkey. + * Copyright Mikkel Kamstrup Erlandsen, March, 2008 + * + * GtkHotkey is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GtkHotkey 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with GtkHotkey. If not, see <http://www.gnu.org/licenses/>. + */ + +#if !defined (__GTK_HOTKEY_H__) && !defined (GTK_HOTKEY_COMPILATION) +#error "Only <gtkhotkey.h> can be included directly." +#endif + +#ifndef __GTK_HOTKEY_X11_LISTENER_H__ +#define __GTK_HOTKEY_X11_LISTENER_H__ + +#include <glib.h> +#include <glib-object.h> +#include "gtk-hotkey-listener.h" +#include "gtk-hotkey-info.h" + +G_BEGIN_DECLS + + +#define GTK_HOTKEY_TYPE_X11_LISTENER (gtk_hotkey_x11_listener_get_type ()) +#define GTK_HOTKEY_X11_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_HOTKEY_TYPE_X11_LISTENER, GtkHotkeyX11Listener)) +#define GTK_HOTKEY_X11_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_HOTKEY_TYPE_X11_LISTENER, GtkHotkeyX11ListenerClass)) +#define GTK_HOTKEY_IS_X11_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_HOTKEY_TYPE_X11_LISTENER)) +#define GTK_HOTKEY_IS_X11_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_HOTKEY_TYPE_X11_LISTENER)) +#define GTK_HOTKEY_X11_LISTENER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_HOTKEY_TYPE_X11_LISTENER, GtkHotkeyX11ListenerClass)) + +typedef struct _GtkHotkeyX11Listener GtkHotkeyX11Listener; +typedef struct _GtkHotkeyX11ListenerClass GtkHotkeyX11ListenerClass; +typedef struct _GtkHotkeyX11ListenerPrivate GtkHotkeyX11ListenerPrivate; + +struct _GtkHotkeyX11Listener { + GtkHotkeyListener parent; + GtkHotkeyX11ListenerPrivate * priv; +}; +struct _GtkHotkeyX11ListenerClass { + GtkHotkeyListenerClass parent; +}; + +GType gtk_hotkey_x11_listener_get_type (void); + +G_END_DECLS + +#endif diff --git a/src/plugins/notification/gtkhotkey/gtkhotkey.h b/src/plugins/notification/gtkhotkey/gtkhotkey.h @@ -0,0 +1,12 @@ + +#ifndef __GTK_HOTKEY_H__ +#define __GTK_HOTKEY_H__ + +#include <gtk-hotkey-info.h> +#include <gtk-hotkey-registry.h> +#include <gtk-hotkey-key-file-registry.h> +#include <gtk-hotkey-listener.h> +#include <gtk-hotkey-x11-listener.h> +#include <gtk-hotkey-error.h> + +#endif /* __GTK_HOTKEY_H__ */ diff --git a/src/plugins/notification/gtkhotkey/x11/eggaccelerators.c b/src/plugins/notification/gtkhotkey/x11/eggaccelerators.c @@ -0,0 +1,657 @@ +/* eggaccelerators.c + * Copyright (C) 2002 Red Hat, Inc.; Copyright 1998, 2001 Tim Janik + * Developed by Havoc Pennington, Tim Janik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "eggaccelerators.h" + +#include <string.h> +#include <gdk/gdkx.h> +#include <gdk/gdkkeysyms.h> + +enum +{ + EGG_MODMAP_ENTRY_SHIFT = 0, + EGG_MODMAP_ENTRY_LOCK = 1, + EGG_MODMAP_ENTRY_CONTROL = 2, + EGG_MODMAP_ENTRY_MOD1 = 3, + EGG_MODMAP_ENTRY_MOD2 = 4, + EGG_MODMAP_ENTRY_MOD3 = 5, + EGG_MODMAP_ENTRY_MOD4 = 6, + EGG_MODMAP_ENTRY_MOD5 = 7, + EGG_MODMAP_ENTRY_LAST = 8 +}; + +#define MODMAP_ENTRY_TO_MODIFIER(x) (1 << (x)) + +typedef struct +{ + EggVirtualModifierType mapping[EGG_MODMAP_ENTRY_LAST]; + +} EggModmap; + +const EggModmap* egg_keymap_get_modmap (GdkKeymap *keymap); + +static inline gboolean +is_alt (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'a' || string[1] == 'A') && + (string[2] == 'l' || string[2] == 'L') && + (string[3] == 't' || string[3] == 'T') && + (string[4] == '>')); +} + +static inline gboolean +is_ctl (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'c' || string[1] == 'C') && + (string[2] == 't' || string[2] == 'T') && + (string[3] == 'l' || string[3] == 'L') && + (string[4] == '>')); +} + +static inline gboolean +is_modx (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'm' || string[1] == 'M') && + (string[2] == 'o' || string[2] == 'O') && + (string[3] == 'd' || string[3] == 'D') && + (string[4] >= '1' && string[4] <= '5') && + (string[5] == '>')); +} + +static inline gboolean +is_ctrl (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'c' || string[1] == 'C') && + (string[2] == 't' || string[2] == 'T') && + (string[3] == 'r' || string[3] == 'R') && + (string[4] == 'l' || string[4] == 'L') && + (string[5] == '>')); +} + +static inline gboolean +is_shft (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 's' || string[1] == 'S') && + (string[2] == 'h' || string[2] == 'H') && + (string[3] == 'f' || string[3] == 'F') && + (string[4] == 't' || string[4] == 'T') && + (string[5] == '>')); +} + +static inline gboolean +is_shift (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 's' || string[1] == 'S') && + (string[2] == 'h' || string[2] == 'H') && + (string[3] == 'i' || string[3] == 'I') && + (string[4] == 'f' || string[4] == 'F') && + (string[5] == 't' || string[5] == 'T') && + (string[6] == '>')); +} + +static inline gboolean +is_control (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'c' || string[1] == 'C') && + (string[2] == 'o' || string[2] == 'O') && + (string[3] == 'n' || string[3] == 'N') && + (string[4] == 't' || string[4] == 'T') && + (string[5] == 'r' || string[5] == 'R') && + (string[6] == 'o' || string[6] == 'O') && + (string[7] == 'l' || string[7] == 'L') && + (string[8] == '>')); +} + +static inline gboolean +is_release (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'r' || string[1] == 'R') && + (string[2] == 'e' || string[2] == 'E') && + (string[3] == 'l' || string[3] == 'L') && + (string[4] == 'e' || string[4] == 'E') && + (string[5] == 'a' || string[5] == 'A') && + (string[6] == 's' || string[6] == 'S') && + (string[7] == 'e' || string[7] == 'E') && + (string[8] == '>')); +} + +static inline gboolean +is_meta (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'm' || string[1] == 'M') && + (string[2] == 'e' || string[2] == 'E') && + (string[3] == 't' || string[3] == 'T') && + (string[4] == 'a' || string[4] == 'A') && + (string[5] == '>')); +} + +static inline gboolean +is_super (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 's' || string[1] == 'S') && + (string[2] == 'u' || string[2] == 'U') && + (string[3] == 'p' || string[3] == 'P') && + (string[4] == 'e' || string[4] == 'E') && + (string[5] == 'r' || string[5] == 'R') && + (string[6] == '>')); +} + +static inline gboolean +is_hyper (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'h' || string[1] == 'H') && + (string[2] == 'y' || string[2] == 'Y') && + (string[3] == 'p' || string[3] == 'P') && + (string[4] == 'e' || string[4] == 'E') && + (string[5] == 'r' || string[5] == 'R') && + (string[6] == '>')); +} + +/** + * egg_accelerator_parse_virtual: + * @accelerator: string representing an accelerator + * @accelerator_key: return location for accelerator keyval + * @accelerator_mods: return location for accelerator modifier mask + * + * Parses a string representing a virtual accelerator. The format + * looks like "&lt;Control&gt;a" or "&lt;Shift&gt;&lt;Alt&gt;F1" or + * "&lt;Release&gt;z" (the last one is for key release). The parser + * is fairly liberal and allows lower or upper case, and also + * abbreviations such as "&lt;Ctl&gt;" and "&lt;Ctrl&gt;". + * + * If the parse fails, @accelerator_key and @accelerator_mods will + * be set to 0 (zero) and %FALSE will be returned. If the string contains + * only modifiers, @accelerator_key will be set to 0 but %TRUE will be + * returned. + * + * The virtual vs. concrete accelerator distinction is a relic of + * how the X Window System works; there are modifiers Mod2-Mod5 that + * can represent various keyboard keys (numlock, meta, hyper, etc.), + * the virtual modifier represents the keyboard key, the concrete + * modifier the actual Mod2-Mod5 bits in the key press event. + * + * Returns: %TRUE on success. + */ +gboolean +egg_accelerator_parse_virtual (const gchar *accelerator, + guint *accelerator_key, + EggVirtualModifierType *accelerator_mods) +{ + guint keyval; + GdkModifierType mods; + gint len; + gboolean bad_keyval; + + if (accelerator_key) + *accelerator_key = 0; + if (accelerator_mods) + *accelerator_mods = 0; + + g_return_val_if_fail (accelerator != NULL, FALSE); + + bad_keyval = FALSE; + + keyval = 0; + mods = 0; + len = strlen (accelerator); + while (len) + { + if (*accelerator == '<') + { + if (len >= 9 && is_release (accelerator)) + { + accelerator += 9; + len -= 9; + mods |= EGG_VIRTUAL_RELEASE_MASK; + } + else if (len >= 9 && is_control (accelerator)) + { + accelerator += 9; + len -= 9; + mods |= EGG_VIRTUAL_CONTROL_MASK; + } + else if (len >= 7 && is_shift (accelerator)) + { + accelerator += 7; + len -= 7; + mods |= EGG_VIRTUAL_SHIFT_MASK; + } + else if (len >= 6 && is_shft (accelerator)) + { + accelerator += 6; + len -= 6; + mods |= EGG_VIRTUAL_SHIFT_MASK; + } + else if (len >= 6 && is_ctrl (accelerator)) + { + accelerator += 6; + len -= 6; + mods |= EGG_VIRTUAL_CONTROL_MASK; + } + else if (len >= 6 && is_modx (accelerator)) + { + static const guint mod_vals[] = { + EGG_VIRTUAL_ALT_MASK, EGG_VIRTUAL_MOD2_MASK, EGG_VIRTUAL_MOD3_MASK, + EGG_VIRTUAL_MOD4_MASK, EGG_VIRTUAL_MOD5_MASK + }; + + len -= 6; + accelerator += 4; + mods |= mod_vals[*accelerator - '1']; + accelerator += 2; + } + else if (len >= 5 && is_ctl (accelerator)) + { + accelerator += 5; + len -= 5; + mods |= EGG_VIRTUAL_CONTROL_MASK; + } + else if (len >= 5 && is_alt (accelerator)) + { + accelerator += 5; + len -= 5; + mods |= EGG_VIRTUAL_ALT_MASK; + } + else if (len >= 6 && is_meta (accelerator)) + { + accelerator += 6; + len -= 6; + mods |= EGG_VIRTUAL_META_MASK; + } + else if (len >= 7 && is_hyper (accelerator)) + { + accelerator += 7; + len -= 7; + mods |= EGG_VIRTUAL_HYPER_MASK; + } + else if (len >= 7 && is_super (accelerator)) + { + accelerator += 7; + len -= 7; + mods |= EGG_VIRTUAL_SUPER_MASK; + } + else + { + gchar last_ch; + + last_ch = *accelerator; + while (last_ch && last_ch != '>') + { + last_ch = *accelerator; + accelerator += 1; + len -= 1; + } + } + } + else + { + keyval = gdk_keyval_from_name (accelerator); + + if (keyval == 0) + bad_keyval = TRUE; + + accelerator += len; + len -= len; + } + } + + if (accelerator_key) + *accelerator_key = gdk_keyval_to_lower (keyval); + if (accelerator_mods) + *accelerator_mods = mods; + + return !bad_keyval; +} + + +/** + * egg_virtual_accelerator_name: + * @accelerator_key: accelerator keyval + * @accelerator_mods: accelerator modifier mask + * @returns: a newly-allocated accelerator name + * + * Converts an accelerator keyval and modifier mask + * into a string parseable by egg_accelerator_parse_virtual(). + * For example, if you pass in #GDK_q and #EGG_VIRTUAL_CONTROL_MASK, + * this function returns "&lt;Control&gt;q". + * + * The caller of this function must free the returned string. + */ +gchar* +egg_virtual_accelerator_name (guint accelerator_key, + EggVirtualModifierType accelerator_mods) +{ + static const gchar text_release[] = "<Release>"; + static const gchar text_shift[] = "<Shift>"; + static const gchar text_control[] = "<Control>"; + static const gchar text_mod1[] = "<Alt>"; + static const gchar text_mod2[] = "<Mod2>"; + static const gchar text_mod3[] = "<Mod3>"; + static const gchar text_mod4[] = "<Mod4>"; + static const gchar text_mod5[] = "<Mod5>"; + static const gchar text_meta[] = "<Meta>"; + static const gchar text_super[] = "<Super>"; + static const gchar text_hyper[] = "<Hyper>"; + guint l; + gchar *keyval_name; + gchar *accelerator; + + accelerator_mods &= EGG_VIRTUAL_MODIFIER_MASK; + + keyval_name = gdk_keyval_name (gdk_keyval_to_lower (accelerator_key)); + if (!keyval_name) + keyval_name = ""; + + l = 0; + if (accelerator_mods & EGG_VIRTUAL_RELEASE_MASK) + l += sizeof (text_release) - 1; + if (accelerator_mods & EGG_VIRTUAL_SHIFT_MASK) + l += sizeof (text_shift) - 1; + if (accelerator_mods & EGG_VIRTUAL_CONTROL_MASK) + l += sizeof (text_control) - 1; + if (accelerator_mods & EGG_VIRTUAL_ALT_MASK) + l += sizeof (text_mod1) - 1; + if (accelerator_mods & EGG_VIRTUAL_MOD2_MASK) + l += sizeof (text_mod2) - 1; + if (accelerator_mods & EGG_VIRTUAL_MOD3_MASK) + l += sizeof (text_mod3) - 1; + if (accelerator_mods & EGG_VIRTUAL_MOD4_MASK) + l += sizeof (text_mod4) - 1; + if (accelerator_mods & EGG_VIRTUAL_MOD5_MASK) + l += sizeof (text_mod5) - 1; + if (accelerator_mods & EGG_VIRTUAL_META_MASK) + l += sizeof (text_meta) - 1; + if (accelerator_mods & EGG_VIRTUAL_HYPER_MASK) + l += sizeof (text_hyper) - 1; + if (accelerator_mods & EGG_VIRTUAL_SUPER_MASK) + l += sizeof (text_super) - 1; + l += strlen (keyval_name); + + accelerator = g_new (gchar, l + 1); + + l = 0; + accelerator[l] = 0; + if (accelerator_mods & EGG_VIRTUAL_RELEASE_MASK) + { + strcpy (accelerator + l, text_release); + l += sizeof (text_release) - 1; + } + if (accelerator_mods & EGG_VIRTUAL_SHIFT_MASK) + { + strcpy (accelerator + l, text_shift); + l += sizeof (text_shift) - 1; + } + if (accelerator_mods & EGG_VIRTUAL_CONTROL_MASK) + { + strcpy (accelerator + l, text_control); + l += sizeof (text_control) - 1; + } + if (accelerator_mods & EGG_VIRTUAL_ALT_MASK) + { + strcpy (accelerator + l, text_mod1); + l += sizeof (text_mod1) - 1; + } + if (accelerator_mods & EGG_VIRTUAL_MOD2_MASK) + { + strcpy (accelerator + l, text_mod2); + l += sizeof (text_mod2) - 1; + } + if (accelerator_mods & EGG_VIRTUAL_MOD3_MASK) + { + strcpy (accelerator + l, text_mod3); + l += sizeof (text_mod3) - 1; + } + if (accelerator_mods & EGG_VIRTUAL_MOD4_MASK) + { + strcpy (accelerator + l, text_mod4); + l += sizeof (text_mod4) - 1; + } + if (accelerator_mods & EGG_VIRTUAL_MOD5_MASK) + { + strcpy (accelerator + l, text_mod5); + l += sizeof (text_mod5) - 1; + } + if (accelerator_mods & EGG_VIRTUAL_META_MASK) + { + strcpy (accelerator + l, text_meta); + l += sizeof (text_meta) - 1; + } + if (accelerator_mods & EGG_VIRTUAL_HYPER_MASK) + { + strcpy (accelerator + l, text_hyper); + l += sizeof (text_hyper) - 1; + } + if (accelerator_mods & EGG_VIRTUAL_SUPER_MASK) + { + strcpy (accelerator + l, text_super); + l += sizeof (text_super) - 1; + } + + strcpy (accelerator + l, keyval_name); + + return accelerator; +} + +void +egg_keymap_resolve_virtual_modifiers (GdkKeymap *keymap, + EggVirtualModifierType virtual_mods, + GdkModifierType *concrete_mods) +{ + GdkModifierType concrete; + int i; + const EggModmap *modmap; + + g_return_if_fail (GDK_IS_KEYMAP (keymap)); + g_return_if_fail (concrete_mods != NULL); + + modmap = egg_keymap_get_modmap (keymap); + + /* Not so sure about this algorithm. */ + + concrete = 0; + i = 0; + while (i < EGG_MODMAP_ENTRY_LAST) + { + if (modmap->mapping[i] & virtual_mods) + concrete |= (1 << i); + + ++i; + } + + *concrete_mods = concrete; +} + +void +egg_keymap_virtualize_modifiers (GdkKeymap *keymap, + GdkModifierType concrete_mods, + EggVirtualModifierType *virtual_mods) +{ + GdkModifierType virtual; + int i; + const EggModmap *modmap; + + g_return_if_fail (GDK_IS_KEYMAP (keymap)); + g_return_if_fail (virtual_mods != NULL); + + modmap = egg_keymap_get_modmap (keymap); + + /* Not so sure about this algorithm. */ + + virtual = 0; + i = 0; + while (i < EGG_MODMAP_ENTRY_LAST) + { + if ((1 << i) & concrete_mods) + { + EggVirtualModifierType cleaned; + + cleaned = modmap->mapping[i] & ~(EGG_VIRTUAL_MOD2_MASK | + EGG_VIRTUAL_MOD3_MASK | + EGG_VIRTUAL_MOD4_MASK | + EGG_VIRTUAL_MOD5_MASK); + + if (cleaned != 0) + { + virtual |= cleaned; + } + else + { + /* Rather than dropping mod2->mod5 if not bound, + * go ahead and use the concrete names + */ + virtual |= modmap->mapping[i]; + } + } + + ++i; + } + + *virtual_mods = virtual; +} + +static void +reload_modmap (GdkKeymap *keymap, + EggModmap *modmap) +{ + XModifierKeymap *xmodmap; + int map_size; + int i; + + /* FIXME multihead */ + xmodmap = XGetModifierMapping (gdk_x11_get_default_xdisplay ()); + + memset (modmap->mapping, 0, sizeof (modmap->mapping)); + + /* there are 8 modifiers, and the first 3 are shift, shift lock, + * and control + */ + map_size = 8 * xmodmap->max_keypermod; + i = 3 * xmodmap->max_keypermod; + while (i < map_size) + { + /* get the key code at this point in the map, + * see if its keysym is one we're interested in + */ + int keycode = xmodmap->modifiermap[i]; + GdkKeymapKey *keys; + guint *keyvals; + int n_entries; + int j; + EggVirtualModifierType mask; + + keys = NULL; + keyvals = NULL; + n_entries = 0; + + gdk_keymap_get_entries_for_keycode (keymap, + keycode, + &keys, &keyvals, &n_entries); + + mask = 0; + j = 0; + while (j < n_entries) + { + if (keyvals[j] == GDK_Num_Lock) + mask |= EGG_VIRTUAL_NUM_LOCK_MASK; + else if (keyvals[j] == GDK_Scroll_Lock) + mask |= EGG_VIRTUAL_SCROLL_LOCK_MASK; + else if (keyvals[j] == GDK_Meta_L || + keyvals[j] == GDK_Meta_R) + mask |= EGG_VIRTUAL_META_MASK; + else if (keyvals[j] == GDK_Hyper_L || + keyvals[j] == GDK_Hyper_R) + mask |= EGG_VIRTUAL_HYPER_MASK; + else if (keyvals[j] == GDK_Super_L || + keyvals[j] == GDK_Super_R) + mask |= EGG_VIRTUAL_SUPER_MASK; + else if (keyvals[j] == GDK_Mode_switch) + mask |= EGG_VIRTUAL_MODE_SWITCH_MASK; + + ++j; + } + + /* Mod1Mask is 1 << 3 for example, i.e. the + * fourth modifier, i / keyspermod is the modifier + * index + */ + modmap->mapping[i/xmodmap->max_keypermod] |= mask; + + g_free (keyvals); + g_free (keys); + + ++i; + } + + /* Add in the not-really-virtual fixed entries */ + modmap->mapping[EGG_MODMAP_ENTRY_SHIFT] |= EGG_VIRTUAL_SHIFT_MASK; + modmap->mapping[EGG_MODMAP_ENTRY_CONTROL] |= EGG_VIRTUAL_CONTROL_MASK; + modmap->mapping[EGG_MODMAP_ENTRY_LOCK] |= EGG_VIRTUAL_LOCK_MASK; + modmap->mapping[EGG_MODMAP_ENTRY_MOD1] |= EGG_VIRTUAL_ALT_MASK; + modmap->mapping[EGG_MODMAP_ENTRY_MOD2] |= EGG_VIRTUAL_MOD2_MASK; + modmap->mapping[EGG_MODMAP_ENTRY_MOD3] |= EGG_VIRTUAL_MOD3_MASK; + modmap->mapping[EGG_MODMAP_ENTRY_MOD4] |= EGG_VIRTUAL_MOD4_MASK; + modmap->mapping[EGG_MODMAP_ENTRY_MOD5] |= EGG_VIRTUAL_MOD5_MASK; + + XFreeModifiermap (xmodmap); +} + +const EggModmap* +egg_keymap_get_modmap (GdkKeymap *keymap) +{ + EggModmap *modmap; + + /* This is all a hack, much simpler when we can just + * modify GDK directly. + */ + + modmap = g_object_get_data (G_OBJECT (keymap), + "egg-modmap"); + + if (modmap == NULL) + { + modmap = g_new0 (EggModmap, 1); + + /* FIXME modify keymap change events with an event filter + * and force a reload if we get one + */ + + reload_modmap (keymap, modmap); + + g_object_set_data_full (G_OBJECT (keymap), + "egg-modmap", + modmap, + g_free); + } + + g_assert (modmap != NULL); + + return modmap; +} diff --git a/src/plugins/notification/gtkhotkey/x11/eggaccelerators.h b/src/plugins/notification/gtkhotkey/x11/eggaccelerators.h @@ -0,0 +1,87 @@ +/* eggaccelerators.h + * Copyright (C) 2002 Red Hat, Inc. + * Developed by Havoc Pennington + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EGG_ACCELERATORS_H__ +#define __EGG_ACCELERATORS_H__ + +#include <gtk/gtkaccelgroup.h> +#include <gdk/gdk.h> + +G_BEGIN_DECLS + +/* Where a value is also in GdkModifierType we coincide, + * otherwise we don't overlap. + */ +typedef enum +{ + EGG_VIRTUAL_SHIFT_MASK = 1 << 0, + EGG_VIRTUAL_LOCK_MASK = 1 << 1, + EGG_VIRTUAL_CONTROL_MASK = 1 << 2, + + EGG_VIRTUAL_ALT_MASK = 1 << 3, /* fixed as Mod1 */ + + EGG_VIRTUAL_MOD2_MASK = 1 << 4, + EGG_VIRTUAL_MOD3_MASK = 1 << 5, + EGG_VIRTUAL_MOD4_MASK = 1 << 6, + EGG_VIRTUAL_MOD5_MASK = 1 << 7, + +#if 0 + GDK_BUTTON1_MASK = 1 << 8, + GDK_BUTTON2_MASK = 1 << 9, + GDK_BUTTON3_MASK = 1 << 10, + GDK_BUTTON4_MASK = 1 << 11, + GDK_BUTTON5_MASK = 1 << 12, + /* 13, 14 are used by Xkb for the keyboard group */ +#endif + + EGG_VIRTUAL_META_MASK = 1 << 24, + EGG_VIRTUAL_SUPER_MASK = 1 << 25, + EGG_VIRTUAL_HYPER_MASK = 1 << 26, + EGG_VIRTUAL_MODE_SWITCH_MASK = 1 << 27, + EGG_VIRTUAL_NUM_LOCK_MASK = 1 << 28, + EGG_VIRTUAL_SCROLL_LOCK_MASK = 1 << 29, + + /* Also in GdkModifierType */ + EGG_VIRTUAL_RELEASE_MASK = 1 << 30, + + /* 28-31 24-27 20-23 16-19 12-15 8-11 4-7 0-3 + * 7 f 0 0 0 0 f f + */ + EGG_VIRTUAL_MODIFIER_MASK = 0x7f0000ff + +} EggVirtualModifierType; + +gboolean egg_accelerator_parse_virtual (const gchar *accelerator, + guint *accelerator_key, + EggVirtualModifierType *accelerator_mods); +void egg_keymap_resolve_virtual_modifiers (GdkKeymap *keymap, + EggVirtualModifierType virtual_mods, + GdkModifierType *concrete_mods); +void egg_keymap_virtualize_modifiers (GdkKeymap *keymap, + GdkModifierType concrete_mods, + EggVirtualModifierType *virtual_mods); + +gchar* egg_virtual_accelerator_name (guint accelerator_key, + EggVirtualModifierType accelerator_mods); + +G_END_DECLS + + +#endif /* __EGG_ACCELERATORS_H__ */ diff --git a/src/plugins/notification/gtkhotkey/x11/tomboykeybinder.c b/src/plugins/notification/gtkhotkey/x11/tomboykeybinder.c @@ -0,0 +1,328 @@ + +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/socket.h> +#include <gdk/gdk.h> +#include <gdk/gdkwindow.h> +#include <gdk/gdkx.h> +#include <X11/Xlib.h> + +#include "eggaccelerators.h" +#include "tomboykeybinder.h" + +/* Uncomment the next line to print a debug trace. */ +//#define DEBUG 1 + +#ifdef DEBUG +# define TRACE(x) x +#else +# define TRACE(x) do {} while (FALSE); +#endif + +typedef struct _Binding { + TomboyBindkeyHandler handler; + gpointer user_data; + char *keystring; + uint keycode; + uint modifiers; +} Binding; + +static GSList *bindings = NULL; +static guint32 last_event_time = 0; +static gboolean processing_event = FALSE; + +static guint num_lock_mask, caps_lock_mask, scroll_lock_mask; + +static void +lookup_ignorable_modifiers (GdkKeymap *keymap) +{ + egg_keymap_resolve_virtual_modifiers (keymap, + EGG_VIRTUAL_LOCK_MASK, + &caps_lock_mask); + + egg_keymap_resolve_virtual_modifiers (keymap, + EGG_VIRTUAL_NUM_LOCK_MASK, + &num_lock_mask); + + egg_keymap_resolve_virtual_modifiers (keymap, + EGG_VIRTUAL_SCROLL_LOCK_MASK, + &scroll_lock_mask); +} + +static void +grab_ungrab_with_ignorable_modifiers (GdkWindow *rootwin, + Binding *binding, + gboolean grab) +{ + guint mod_masks [] = { + 0, /* modifier only */ + num_lock_mask, + caps_lock_mask, + scroll_lock_mask, + num_lock_mask | caps_lock_mask, + num_lock_mask | scroll_lock_mask, + caps_lock_mask | scroll_lock_mask, + num_lock_mask | caps_lock_mask | scroll_lock_mask, + }; + int i; + + for (i = 0; i < G_N_ELEMENTS (mod_masks); i++) { + if (grab) { + XGrabKey (GDK_WINDOW_XDISPLAY (rootwin), + binding->keycode, + binding->modifiers | mod_masks [i], + GDK_WINDOW_XWINDOW (rootwin), + False, + GrabModeAsync, + GrabModeAsync); + } else { + XUngrabKey (GDK_WINDOW_XDISPLAY (rootwin), + binding->keycode, + binding->modifiers | mod_masks [i], + GDK_WINDOW_XWINDOW (rootwin)); + } + } +} + +static gboolean +do_grab_key (Binding *binding) +{ + GdkKeymap *keymap = gdk_keymap_get_default (); + GdkWindow *rootwin = gdk_get_default_root_window (); + + EggVirtualModifierType virtual_mods = 0; + guint keysym = 0; + + TRACE (g_print ("Preparing to bind %s\n", binding->keystring)); + + g_return_val_if_fail (keymap != NULL, FALSE); + g_return_val_if_fail (rootwin != NULL, FALSE); + + if (!egg_accelerator_parse_virtual (binding->keystring, + &keysym, + &virtual_mods)) { + TRACE (g_print("Failed to parse '%s'", binding->keystring)); + return FALSE; + } + + TRACE (g_print ("Got accel %d, %d\n", keysym, virtual_mods)); + + binding->keycode = XKeysymToKeycode (GDK_WINDOW_XDISPLAY (rootwin), + keysym); + if (binding->keycode == 0) + return FALSE; + + TRACE (g_print ("Got keycode %d\n", binding->keycode)); + + egg_keymap_resolve_virtual_modifiers (keymap, + virtual_mods, + &binding->modifiers); + + TRACE (g_print ("Got modmask %d\n", binding->modifiers)); + + gdk_error_trap_push (); + + grab_ungrab_with_ignorable_modifiers (rootwin, + binding, + TRUE /* grab */); + + gdk_flush (); + + if (gdk_error_trap_pop ()) { + g_warning ("Binding '%s' failed!\n", binding->keystring); + return FALSE; + } + + return TRUE; +} + +static gboolean +do_ungrab_key (Binding *binding) +{ + GdkWindow *rootwin = gdk_get_default_root_window (); + + TRACE (g_print ("Removing grab for '%s'\n", binding->keystring)); + + grab_ungrab_with_ignorable_modifiers (rootwin, + binding, + FALSE /* ungrab */); + + return TRUE; +} + +static GdkFilterReturn +filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) +{ + GdkFilterReturn return_val = GDK_FILTER_CONTINUE; + XEvent *xevent = (XEvent *) gdk_xevent; + guint event_mods; + GSList *iter; + + TRACE (g_print ("Got Event! %d, %d\n", xevent->type, event->type)); + + switch (xevent->type) { + case KeyPress: + TRACE (g_print ("Got KeyPress! keycode: %d, modifiers: %d\n", + xevent->xkey.keycode, + xevent->xkey.state)); + + /* + * Set the last event time for use when showing + * windows to avoid anti-focus-stealing code. + */ + processing_event = TRUE; + last_event_time = xevent->xkey.time; + + event_mods = xevent->xkey.state & ~(num_lock_mask | + caps_lock_mask | + scroll_lock_mask); + + for (iter = bindings; iter != NULL; iter = iter->next) { + Binding *binding = (Binding *) iter->data; + + if (binding->keycode == xevent->xkey.keycode && + binding->modifiers == event_mods) { + + TRACE (g_print ("Calling handler for '%s'...\n", + binding->keystring)); + + (binding->handler) (binding->keystring, + binding->user_data); + } + } + + processing_event = FALSE; + break; + case KeyRelease: + TRACE (g_print ("Got KeyRelease! \n")); + break; + } + + return return_val; +} + +static void +keymap_changed (GdkKeymap *map) +{ + GdkKeymap *keymap = gdk_keymap_get_default (); + GSList *iter; + + TRACE (g_print ("Keymap changed! Regrabbing keys...")); + + for (iter = bindings; iter != NULL; iter = iter->next) { + Binding *binding = (Binding *) iter->data; + do_ungrab_key (binding); + } + + lookup_ignorable_modifiers (keymap); + + for (iter = bindings; iter != NULL; iter = iter->next) { + Binding *binding = (Binding *) iter->data; + do_grab_key (binding); + } +} + +void +tomboy_keybinder_init (void) +{ + GdkKeymap *keymap = gdk_keymap_get_default (); + GdkWindow *rootwin = gdk_get_default_root_window (); + + lookup_ignorable_modifiers (keymap); + + gdk_window_add_filter (rootwin, + filter_func, + NULL); + + g_signal_connect (keymap, + "keys_changed", + G_CALLBACK (keymap_changed), + NULL); +} + +gboolean +tomboy_keybinder_bind (const char *keystring, + TomboyBindkeyHandler handler, + gpointer user_data) +{ + Binding *binding; + gboolean success; + + binding = g_new0 (Binding, 1); + binding->keystring = g_strdup (keystring); + binding->handler = handler; + binding->user_data = user_data; + + /* Sets the binding's keycode and modifiers */ + success = do_grab_key (binding); + + if (success) { + bindings = g_slist_prepend (bindings, binding); + } else { + g_free (binding->keystring); + g_free (binding); + } + return success; +} + +void +tomboy_keybinder_unbind (const char *keystring, + TomboyBindkeyHandler handler) +{ + GSList *iter; + + for (iter = bindings; iter != NULL; iter = iter->next) { + Binding *binding = (Binding *) iter->data; + + if (strcmp (keystring, binding->keystring) != 0 || + handler != binding->handler) + continue; + + do_ungrab_key (binding); + + bindings = g_slist_remove (bindings, binding); + + g_free (binding->keystring); + g_free (binding); + break; + } +} + +/* + * From eggcellrenderkeys.c. + */ +gboolean +tomboy_keybinder_is_modifier (guint keycode) +{ + gint i; + gint map_size; + XModifierKeymap *mod_keymap; + gboolean retval = FALSE; + + mod_keymap = XGetModifierMapping (gdk_display); + + map_size = 8 * mod_keymap->max_keypermod; + + i = 0; + while (i < map_size) { + if (keycode == mod_keymap->modifiermap[i]) { + retval = TRUE; + break; + } + ++i; + } + + XFreeModifiermap (mod_keymap); + + return retval; +} + +guint32 +tomboy_keybinder_get_current_event_time (void) +{ + if (processing_event) + return last_event_time; + else + return GDK_CURRENT_TIME; +} diff --git a/src/plugins/notification/gtkhotkey/x11/tomboykeybinder.h b/src/plugins/notification/gtkhotkey/x11/tomboykeybinder.h @@ -0,0 +1,27 @@ + +#ifndef __TOMBOY_KEY_BINDER_H__ +#define __TOMBOY_KEY_BINDER_H__ + +#include <glib.h> + +G_BEGIN_DECLS + +typedef void (* TomboyBindkeyHandler) (char *keystring, gpointer user_data); + +void tomboy_keybinder_init (void); + +gboolean tomboy_keybinder_bind (const char *keystring, + TomboyBindkeyHandler handler, + gpointer user_data); + +void tomboy_keybinder_unbind (const char *keystring, + TomboyBindkeyHandler handler); + +gboolean tomboy_keybinder_is_modifier (guint keycode); + +guint32 tomboy_keybinder_get_current_event_time (void); + +G_END_DECLS + +#endif /* __TOMBOY_KEY_BINDER_H__ */ + diff --git a/src/plugins/notification/notification_plugin.c b/src/plugins/notification/notification_plugin.c @@ -158,7 +158,7 @@ static gboolean my_folder_item_update_hook(gpointer source, gpointer data) #if defined(NOTIFICATION_LCDPROC) || defined(NOTIFICATION_TRAYICON) || defined(NOTIFICATION_INDICATOR) notification_update_msg_counts(NULL); #else - if(notify_config.urgency_hint) + if(notify_config.urgency_hint_new || notify_config.urgency_hint_unread) notification_update_msg_counts(NULL); #endif diff --git a/src/plugins/spam_report/Makefile.am b/src/plugins/spam_report/Makefile.am @@ -5,8 +5,7 @@ plugin_LTLIBRARIES = spamreport.la spamreport_la_SOURCES = \ spam_report.c \ spam_report_prefs.c \ - spam_report_prefs.h \ - gettext.h + spam_report_prefs.h spamreport_la_LDFLAGS = \ -avoid-version -module \ diff --git a/src/plugins/spam_report/spam_report.c b/src/plugins/spam_report/spam_report.c @@ -342,9 +342,8 @@ gint plugin_init(gchar **error) return -1; spamreport_prefs_init(); -#ifdef HAVE_LIBCURL + curl_global_init(CURL_GLOBAL_DEFAULT); -#endif gtk_action_group_add_actions(mainwin->action_group, spamreport_main_menu, 1, (gpointer)mainwin); @@ -371,9 +370,9 @@ gboolean plugin_done(void) MENUITEM_REMUI_MANAGER(mainwin->ui_manager,mainwin->action_group, "Message/ReportSpam", context_menu_id); context_menu_id = 0; -#ifdef HAVE_LIBCURL + spamreport_prefs_done(); -#endif + return TRUE; } diff --git a/src/plugins/tnef_parse/Makefile.am b/src/plugins/tnef_parse/Makefile.am @@ -49,8 +49,7 @@ tnef_parse_la_SOURCES = \ tnef_parse.c \ tnef_dump.c \ tnef_dump.h \ - ytnef.c \ - gettext.h + ytnef.c tnef_parse_la_LDFLAGS = \ $(plugin_res_ldflag) $(no_undefined) $(export_symbols) \