[mousetweaks/wayland] Initial commit
- From: Gerd Kohlberger <gerdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mousetweaks/wayland] Initial commit
- Date: Sun, 27 Oct 2013 10:54:24 +0000 (UTC)
commit 2da98c2caccdbd731613ffc54fd4e353284cf134
Author: Gerd Kohlberger <gerdk src gnome org>
Date: Sun Oct 27 11:18:10 2013 +0100
Initial commit
- Use GApplication for single instance checking
- Move the GUI code out of the daemon
- Switch to at-spi2 for receiving and generation mouse events
- Drop gtk+ dependency from the daemon
- Add middle mouse button support
- Add a simple backend system for mouse events
Makefile.am | 5 +-
configure.ac | 49 +-
data/Makefile.am | 30 +-
pixmaps/double-click.png => data/double.png | Bin 595 -> 595 bytes
pixmaps/drag-click.png => data/drag.png | Bin 477 -> 477 bytes
data/mousetweaks.1 | 51 ++
data/mousetweaks.convert | 2 -
data/mousetweaks.gresource.xml | 10 +
data/mousetweaks.ui | 311 ---------
data/org.gnome.mousetweaks.gschema.xml.in | 23 +-
pixmaps/single-click.png => data/primary.png | Bin 480 -> 480 bytes
pixmaps/right-click.png => data/secondary.png | Bin 476 -> 476 bytes
data/window.ui | 151 +++++
man/Makefile.am | 5 -
man/mousetweaks.1 | 73 ---
pixmaps/Makefile.am | 10 -
po/POTFILES.in | 6 +-
po/POTFILES.skip | 2 -
src/Makefile.am | 107 ++--
src/hover_click_window.c | 401 ++++++++++++
src/{mt-ctw.h => main.c} | 30 +-
src/mt-common.c | 137 ----
src/mt-common.h | 103 ---
src/mt-ctw.c | 349 ----------
src/mt-cursor-manager.c | 327 ----------
src/mt-cursor-manager.h | 55 --
src/mt-cursor.c | 146 -----
src/mt-cursor.h | 62 --
src/mt-enum-types.c.template | 96 ---
src/mt-enum-types.h.template | 53 --
src/mt-listener.c | 376 -----------
src/mt-listener.h | 67 --
src/mt-main.c | 843 -------------------------
src/mt-pidfile.c | 260 --------
src/mt-service.c | 289 ---------
src/mt-service.h | 53 --
src/mt-settings.c | 304 ---------
src/mt-settings.h | 64 --
src/mt-sig-handler.c | 209 ------
src/mt-sig-handler.h | 51 --
src/mt_application.c | 450 +++++++++++++
src/{mt-pidfile.h => mt_application.h} | 23 +-
src/mt_click.c | 215 +++++++
src/mt_click.h | 78 +++
src/mt_hover_click.c | 305 +++++++++
src/mt_hover_click.h | 48 ++
src/mt_listener.c | 141 ++++
src/mt_listener.h | 96 +++
src/mt_listener_atspi.c | 201 ++++++
src/{mt-ctw.h => mt_listener_atspi.h} | 24 +-
src/mt_secondary_click.c | 125 ++++
src/{mt-ctw.h => mt_secondary_click.h} | 22 +-
src/{mt-timer.c => mt_timer.c} | 124 ++---
src/{mt-timer.h => mt_timer.h} | 30 +-
54 files changed, 2470 insertions(+), 4522 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 48a0bed..656a8ff 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = src data pixmaps po man
+SUBDIRS = src data po
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
@@ -6,8 +6,7 @@ DISTCHECK_CONFIGURE_FLAGS = \
--disable-schemas-compile
EXTRA_DIST = \
- $(srcdir)/m4 \
- $(srcdir)/MAINTAINERS
+ $(srcdir)/m4
MAINTAINERCLEANFILES = \
$(srcdir)/INSTALL \
diff --git a/configure.ac b/configure.ac
index 5fe0e11..853f75b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,3 @@
-AC_PREREQ([2.64])
AC_INIT([mousetweaks],
[3.10.0],
[https://bugzilla.gnome.org/enter_bug.cgi?product=mousetweaks],
@@ -6,11 +5,11 @@ AC_INIT([mousetweaks],
[https://live.gnome.org/Mousetweaks/Home])
AC_CONFIG_SRCDIR([src])
-AC_CONFIG_HEADER([config.h])
+AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
AC_PREFIX_DEFAULT([/usr])
-AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-bzip2 -Wno-portability])
+AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz])
AM_SILENT_RULES([yes])
AM_MAINTAINER_MODE([enable])
@@ -18,58 +17,36 @@ AC_PROG_CC
AC_PROG_INSTALL
AC_HEADER_STDC
AC_C_CONST
-AM_PROG_CC_C_O
-
-dnl *** GNOME macros ***
GNOME_COMPILE_WARNINGS([maximum])
-GNOME_MAINTAINER_MODE_DEFINES
-
-dnl *** i18n ***
-IT_PROG_INTLTOOL([0.40.0])
+IT_PROG_INTLTOOL([0.41.0])
-GETTEXT_PACKAGE=mousetweaks
-AC_SUBST(GETTEXT_PACKAGE)
-AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext Package])
-AM_GLIB_GNU_GETTEXT
+AC_SUBST([GETTEXT_PACKAGE], [mousetweaks])
+AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], "$GETTEXT_PACKAGE", [Gettext Package])
-dnl *** gsettings ***
+AC_PATH_PROG([GLIB_COMPILE_RESOURCES], [glib-compile-resources])
GLIB_GSETTINGS
-dnl *** dependencies ***
-
-GLIB_REQUIRED=2.25.3
-GIO_REQUIRED=2.25.9
-GTK_REQUIRED=3.0.0
-GDS_REQUIRED=0.1.0
+GIO_REQUIRED=2.38
+GTK_REQUIRED=3.10
+GDS_REQUIRED=0.1
-PKG_CHECK_MODULES(DEPENDENCIES,
- glib-2.0 >= $GLIB_REQUIRED
+PKG_CHECK_MODULES(DAEMON,
+ glib-2.0
gio-2.0 >= $GIO_REQUIRED
gtk+-3.0 >= $GTK_REQUIRED
gsettings-desktop-schemas >= $GDS_REQUIRED
- x11
- xcursor
- xfixes
- xtst)
+ atspi-2)
-dnl *** GLib tools ***
-
-GLIB_MKENUMS="$($PKG_CONFIG --variable=glib_mkenums glib-2.0)"
-AC_SUBST([GLIB_MKENUMS])
-
-dnl *** output ***
+PKG_CHECK_MODULES(WINDOW, gtk+-3.0 >= $GTK_REQUIRED)
AC_CONFIG_FILES([
Makefile
src/Makefile
data/Makefile
- pixmaps/Makefile
po/Makefile.in
- man/Makefile
])
AC_OUTPUT
-
diff --git a/data/Makefile.am b/data/Makefile.am
index ab5fd14..1c225ec 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -1,24 +1,24 @@
-uidir = $(datadir)/mousetweaks
-ui_DATA = mousetweaks.ui
-
-convertdir = $(datadir)/GConf/gsettings
-convert_DATA = mousetweaks.convert
-
-gsettings_ENUM_NAMESPACE = org.gnome.mousetweaks
-gsettings_ENUM_FILES = $(top_srcdir)/src/mt-common.h
-
gsettings_in_files = org.gnome.mousetweaks.gschema.xml.in
gsettings_SCHEMAS = $(gsettings_in_files:.xml.in=.xml)
@INTLTOOL_XML_NOMERGE_RULE@
@GSETTINGS_RULES@
-EXTRA_DIST = \
- $(ui_DATA) \
- $(gsettings_in_files) \
- $(gsettings_ENUM_FILES) \
- $(convert_DATA)
+man_MANS = mousetweaks.1
+
+RESOURCES = \
+ window.ui \
+ primary.png \
+ secondary.png \
+ double.png \
+ drag.png
+
+EXTRA_DIST = \
+ mousetweaks.gresource.xml \
+ $(RESOURCES) \
+ $(gsettings_in_files) \
+ $(man_MANS)
-DISTCLEANFILES = \
+DISTCLEANFILES = \
$(gsettings_SCHEMAS)
-include $(top_srcdir)/git.mk
diff --git a/data/mousetweaks.1 b/data/mousetweaks.1
new file mode 100644
index 0000000..6ee7280
--- /dev/null
+++ b/data/mousetweaks.1
@@ -0,0 +1,51 @@
+.TH "mousetweaks" 1
+.SH NAME
+mousetweaks \- Accessibility enhancements for pointing devices
+.SH SYNOPSIS
+.B mousetweaks
+[\-\-hover\-click] [\-\-hover\-click\-time=FLOAT] [\-\-hover\-click\-time=FLOAT]
[\-\-hover\-click\-threshold=INT]
+[\-\-secondary\-click] [\-\-secondary\-click\-time=FLOAT] [\-\-secondary\-click\-time=FLOAT]
[\-\-secondary\-click\-threshold=INT]
+[\-v|\-\-version] [\-s|\-\-shutdown] [\-?|\-h|\-\-help]
+.SH DESCRIPTION
+.B mousetweaks
+is a collection of accessibility enhancements for pointing devices. This
+manual page describes the mousetweaks daemon.
+
+.SH OPTIONS
+.TP
+.B \-\-hover\-click
+Automatically perform mouse clicks without using a physical button.
+.TP
+.B \-\-hover\-click\-time=FLOAT
+Time to keep the pointer motionless before a Hover Click is performed.
+Range: 0.2\-3.0 seconds.
+.TP
+.B \-\-hover\-click\-threshold=INT
+Ignore small pointer movements. Range: 0\-30 pixels.
+.TP
+.B \-\-secondary\-click
+Trigger the secondary mouse button when the primary mouse button is held down
+for a specified amount of time.
+.TP
+.B \-\-secondary\-click\-time=FLOAT
+Time to hold the primary mouse button before a simulated secondary
+click is performed. Range: 0.5\-3.0 seconds.
+.TP
+.B \-\-secondary\-click\-threshold=INT
+Ignore small pointer movements. Range: 0\-30 pixels.
+.TP
+.B \-v, \-\-version
+Print the mousetweaks version to stdout.
+.TP
+.B \-s, \-\-shutdown
+Stop the mousetweaks daemon.
+
+.SH BUGS
+Report bugs to
+.UR http://bugzilla.gnome.org/
+<http://bugzilla.gnome.org/>
+.UE
+.SH AUTHORS
+This manual page was written by Francesco Fumanti.
+.SH LICENSE
+Licenced under the GNU General Public License v3 or later.
diff --git a/data/mousetweaks.gresource.xml b/data/mousetweaks.gresource.xml
new file mode 100644
index 0000000..a470b7e
--- /dev/null
+++ b/data/mousetweaks.gresource.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gnome/Mousetweaks/">
+ <file preprocess="xml-stripblanks">window.ui</file>
+ <file>primary.png</file>
+ <file>secondary.png</file>
+ <file>double.png</file>
+ <file>drag.png</file>
+ </gresource>
+</gresources>
diff --git a/data/org.gnome.mousetweaks.gschema.xml.in b/data/org.gnome.mousetweaks.gschema.xml.in
index 50edbaf..65ace93 100644
--- a/data/org.gnome.mousetweaks.gschema.xml.in
+++ b/data/org.gnome.mousetweaks.gschema.xml.in
@@ -1,19 +1,18 @@
<schemalist>
- <schema id="org.gnome.mousetweaks" path="/org/gnome/desktop/a11y/mouse/" gettext-domain="mousetweaks">
- <key name="click-type-window-style" enum="org.gnome.mousetweaks.MtClickTypeWindowStyle">
- <default>'both'</default>
- <_summary>Click-type window style</_summary>
- <_description>Button style of the click-type window.</_description>
- </key>
- <key name="click-type-window-orientation" enum="org.gnome.mousetweaks.MtClickTypeWindowOrientation">
+ <enum id="org.gnome.Mousetweaks.Orientation">
+ <value nick="vertical" value="0"/>
+ <value nick="horizontal" value="1"/>
+ </enum>
+ <schema id="org.gnome.Mousetweaks" path="/org/gnome/Mousetweaks/" gettext-domain="mousetweaks">
+ <key name="window-orientation" enum="org.gnome.Mousetweaks.Orientation">
<default>'vertical'</default>
- <_summary>Click-type window orientation</_summary>
- <_description>Orientation of the click-type window.</_description>
+ <_summary>Hover Click window orientation</_summary>
+ <_description>Orientation of the Hover Click window.</_description>
</key>
- <key name="click-type-window-geometry" type="s">
+ <key name="window-geometry" type="s">
<default>''</default>
- <_summary>Click-type window geometry</_summary>
- <_description>Size and position of the click-type window. The format is a standard X Window System
geometry string.</_description>
+ <_summary>Hover Click window geometry</_summary>
+ <_description>Size and position of the Hover Click window.</_description>
</key>
</schema>
</schemalist>
diff --git a/data/window.ui b/data/window.ui
new file mode 100644
index 0000000..c2f0b13
--- /dev/null
+++ b/data/window.ui
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.15.3 on Sun Oct 27 09:16:51 2013 -->
+<interface>
+ <!-- interface-requires gtk+ 3.10 -->
+ <template class="HoverClickWindow" parent="GtkApplicationWindow">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes">Hover Click</property>
+ <property name="resizable">False</property>
+ <property name="icon_name">input-mouse</property>
+ <property name="type_hint">dialog</property>
+ <property name="deletable">False</property>
+ <property name="has_resize_grip">False</property>
+ <property name="show_menubar">False</property>
+ <child>
+ <object class="GtkBox" id="box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="homogeneous">True</property>
+ <style>
+ <class name="linked"/>
+ </style>
+ <child>
+ <object class="GtkRadioButton" id="button_primary">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes">Primary Click</property>
+ <property name="xalign">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">False</property>
+ <child>
+ <object class="GtkImage" id="primary">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="resource">/org/gnome/Mousetweaks/primary.png</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="button_double">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes">Double Click</property>
+ <property name="xalign">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">False</property>
+ <property name="group">button_primary</property>
+ <child>
+ <object class="GtkImage" id="double">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="resource">/org/gnome/Mousetweaks/double.png</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="button_secondary">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes">Secondary Click</property>
+ <property name="xalign">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">False</property>
+ <property name="group">button_primary</property>
+ <child>
+ <object class="GtkImage" id="secondary">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="resource">/org/gnome/Mousetweaks/secondary.png</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="button_drag">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes">Drag</property>
+ <property name="xalign">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">False</property>
+ <property name="group">button_primary</property>
+ <child>
+ <object class="GtkImage" id="drag">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="resource">/org/gnome/Mousetweaks/drag.png</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </template>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="orientation">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Window Orientation</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="vertical">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Vertical</property>
+ <property name="use_underline">True</property>
+ <property name="draw_as_radio">True</property>
+ <property name="group">horizontal</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="horizontal">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Horizontal</property>
+ <property name="use_underline">True</property>
+ <property name="draw_as_radio">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 9cffe02..bcc8a3b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,5 +1,3 @@
-[type: gettext/glade]data/mousetweaks.ui
+[type: gettext/glade]data/window.ui
data/org.gnome.mousetweaks.gschema.xml.in
-src/mt-main.c
-src/mt-ctw.c
-src/mt-common.c
+src/mt_application.c
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index f8f2691..e69de29 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -1,2 +0,0 @@
-data/org.gnome.applets.DwellClickApplet.panel-applet.in
-data/org.gnome.applets.PointerCaptureApplet.panel-applet.in
diff --git a/src/Makefile.am b/src/Makefile.am
index 5e17341..e138358 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,66 +1,55 @@
-AM_CPPFLAGS = \
- $(WARN_CFLAGS) \
- -DDATADIR=\"$(datadir)/mousetweaks\" \
- -DGNOMELOCALEDIR=\"$(datadir)/locale\"
+AM_CPPFLAGS = \
+ $(WARN_CFLAGS) \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
+ -DLIBEXECDIR=\""$(libexecdir)"\"
bin_PROGRAMS = mousetweaks
-mousetweaks_SOURCES = \
- $(BUILT_SOURCES) \
- mt-main.c \
- mt-common.c \
- mt-common.h \
- mt-pidfile.c \
- mt-pidfile.h \
- mt-service.c \
- mt-service.h \
- mt-ctw.c \
- mt-ctw.h \
- mt-timer.c \
- mt-timer.h \
- mt-cursor.c \
- mt-cursor.h \
- mt-cursor-manager.c \
- mt-cursor-manager.h \
- mt-listener.c \
- mt-listener.h \
- mt-sig-handler.c \
- mt-sig-handler.h \
- mt-settings.c \
- mt-settings.h
-
-mousetweaks_CFLAGS = \
- $(AM_CPPFLAGS) \
- $(DEPENDENCIES_CFLAGS)
-
-mousetweaks_LDADD = \
- $(DEPENDENCIES_LIBS)
-
-BUILT_SOURCES = \
- mt-enum-types.c \
- mt-enum-types.h
-
-EXTRA_DIST = \
- mt-enum-types.c.template \
- mt-enum-types.h.template
-
-CLEANFILES = \
- stamp-mt-enum-types.h \
+mousetweaks_SOURCES = \
+ main.c \
+ mt_application.c \
+ mt_application.h \
+ mt_click.c \
+ mt_click.h \
+ mt_hover_click.c \
+ mt_hover_click.h \
+ mt_listener.c \
+ mt_listener.h \
+ mt_listener_atspi.c \
+ mt_listener_atspi.h \
+ mt_secondary_click.c \
+ mt_secondary_click.h \
+ mt_timer.c \
+ mt_timer.h
+
+mousetweaks_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(DAEMON_CFLAGS)
+
+mousetweaks_LDADD = \
+ $(DAEMON_LIBS)
+
+libexec_PROGRAMS = hover-click-window
+
+hover_click_window_SOURCES = \
+ $(BUILT_SOURCES) \
+ hover_click_window.c
+
+hover_click_window_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(WINDOW_CFLAGS)
+
+hover_click_window_LDADD = \
+ $(WINDOW_LIBS)
+
+BUILT_SOURCES = \
+ mousetweaks_resources.c
+
+CLEANFILES = \
$(BUILT_SOURCES)
-# GLib mkenum
-mt-enum-types.h: stamp-mt-enum-types.h
- @true
-
-stamp-mt-enum-types.h: mt-enum-types.h.template mt-common.h
- $(AM_V_GEN) $(GLIB_MKENUMS) --template $< $(filter-out $<,$^) > xgen-gtbh \
- && (cmp -s xgen-gtbh mt-enum-types.h || cp xgen-gtbh mt-enum-types.h) \
- && rm -f xgen-gtbh \
- && echo timestamp > $(@F)
-
-mt-enum-types.c: mt-enum-types.c.template mt-common.h
- $(AM_V_GEN) $(GLIB_MKENUMS) --template $< $(filter-out $<,$^) > xgen-gtbc \
- && (cmp -s xgen-gtbc mt-enum-types.c || cp xgen-gtbc mt-enum-types.c) \
- && rm -f xgen-gtbc
+mousetweaks_resources.c: $(top_srcdir)/data/mousetweaks.gresource.xml
+ $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ \
+ --sourcedir=$(top_srcdir)/data --generate-source $<
-include $(top_srcdir)/git.mk
diff --git a/src/hover_click_window.c b/src/hover_click_window.c
new file mode 100644
index 0000000..d5b5329
--- /dev/null
+++ b/src/hover_click_window.c
@@ -0,0 +1,401 @@
+/*
+ * Copyright 2013, Gerd Kohlberger <gerdko gmail com>
+ *
+ * This file is part of Mousetweaks.
+ *
+ * Mousetweaks is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mousetweaks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "config.h"
+
+#define HOVER_CLICK_TYPE_WINDOW (hover_click_window_get_type ())
+#define HOVER_CLICK_WINDOW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), HOVER_CLICK_TYPE_WINDOW, HoverClickWindow))
+
+typedef GtkApplicationWindowClass HoverClickWindowClass;
+
+typedef struct
+{
+ GSettings *settings;
+ GDBusProxy *proxy;
+ GtkWidget *box;
+
+ GtkMenu *menu;
+ GtkMenuItem *orientation;
+ GtkCheckMenuItem *vertical;
+ GtkCheckMenuItem *horizontal;
+
+ GtkToggleButton *button_primary;
+ GtkToggleButton *button_double;
+ GtkToggleButton *button_secondary;
+ GtkToggleButton *button_drag;
+} HoverClickWindowPrivate;
+
+typedef struct
+{
+ GtkApplicationWindow parent;
+ HoverClickWindowPrivate *priv;
+} HoverClickWindow;
+
+enum
+{
+ MT_CLICK_TYPE_PRIMARY,
+ MT_CLICK_TYPE_MIDDLE,
+ MT_CLICK_TYPE_SECONDARY,
+ MT_CLICK_TYPE_DOUBLE,
+ MT_CLICK_TYPE_DRAG
+};
+
+static GType hover_click_window_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_TYPE_WITH_PRIVATE (HoverClickWindow, hover_click_window, GTK_TYPE_APPLICATION_WINDOW)
+
+static gboolean
+menu_popup (GtkWidget *widget,
+ GdkEventButton *ev,
+ HoverClickWindow *win)
+{
+ if (ev->type == GDK_BUTTON_PRESS && ev->button == GDK_BUTTON_SECONDARY)
+ {
+ gtk_menu_popup_for_device (win->priv->menu,
+ ev->device,
+ NULL, NULL, NULL, NULL, NULL,
+ ev->button,
+ ev->time);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+set_click_type (HoverClickWindow *win,
+ gint click_type)
+{
+ g_dbus_proxy_call (win->priv->proxy,
+ "org.freedesktop.DBus.Properties.Set",
+ g_variant_new ("(ssv)",
+ "org.gnome.Mousetweaks",
+ "ClickType",
+ g_variant_new_int32 (click_type)),
+ G_DBUS_PROXY_FLAGS_NONE,
+ -1, NULL, NULL, NULL);
+}
+
+static void
+button_primary_toggled (GtkToggleButton *button,
+ HoverClickWindow *win)
+{
+ if (gtk_toggle_button_get_active (button))
+ set_click_type (win, MT_CLICK_TYPE_PRIMARY);
+}
+
+static void
+button_double_toggled (GtkToggleButton *button,
+ HoverClickWindow *win)
+{
+ if (gtk_toggle_button_get_active (button))
+ set_click_type (win, MT_CLICK_TYPE_DOUBLE);
+}
+
+static void
+button_secondary_toggled (GtkToggleButton *button,
+ HoverClickWindow *win)
+{
+ if (gtk_toggle_button_get_active (button))
+ set_click_type (win, MT_CLICK_TYPE_SECONDARY);
+}
+
+static void
+button_drag_toggled (GtkToggleButton *button,
+ HoverClickWindow *win)
+{
+ if (gtk_toggle_button_get_active (button))
+ set_click_type (win, MT_CLICK_TYPE_DRAG);
+}
+
+static void
+click_type_changed (GDBusProxy *proxy,
+ GVariant *changed,
+ GStrv invalidated,
+ HoverClickWindow *win)
+{
+ GtkToggleButton *b;
+ GVariant *prop;
+
+ if (!(prop = g_dbus_proxy_get_cached_property (proxy, "ClickType")))
+ return;
+
+ switch (g_variant_get_int32 (prop))
+ {
+ case MT_CLICK_TYPE_PRIMARY:
+ b = win->priv->button_primary;
+
+ g_signal_handlers_block_by_func (b, button_primary_toggled, win);
+ gtk_toggle_button_set_active (b, TRUE);
+ g_signal_handlers_unblock_by_func (b, button_primary_toggled, win);
+ break;
+
+ case MT_CLICK_TYPE_DOUBLE:
+ b = win->priv->button_double;
+
+ g_signal_handlers_block_by_func (b, button_double_toggled, win);
+ gtk_toggle_button_set_active (b, TRUE);
+ g_signal_handlers_unblock_by_func (b, button_double_toggled, win);
+ break;
+
+ case MT_CLICK_TYPE_SECONDARY:
+ b = win->priv->button_secondary;
+
+ g_signal_handlers_block_by_func (b, button_secondary_toggled, win);
+ gtk_toggle_button_set_active (b, TRUE);
+ g_signal_handlers_unblock_by_func (b, button_secondary_toggled, win);
+ break;
+
+ case MT_CLICK_TYPE_DRAG:
+ b = win->priv->button_drag;
+
+ g_signal_handlers_block_by_func (b, button_drag_toggled, win);
+ gtk_toggle_button_set_active (b, TRUE);
+ g_signal_handlers_unblock_by_func (b, button_drag_toggled, win);
+ break;
+
+ default:
+ g_warning ("Unknown 'ClickType' value received.");
+ }
+ g_variant_unref (prop);
+}
+
+static void
+mousetweaks_proxy_ready (GDBusConnection *connection,
+ GAsyncResult *result,
+ HoverClickWindow *win)
+{
+ GError *error = NULL;
+
+ win->priv->proxy = g_dbus_proxy_new_finish (result, &error);
+
+ if (error)
+ {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ g_object_set (win, "application", NULL, NULL);
+ return;
+ }
+
+ g_signal_connect (win->priv->proxy, "g-properties-changed",
+ G_CALLBACK (click_type_changed), win);
+}
+
+static void
+vertical_toggled (GtkCheckMenuItem *item,
+ HoverClickWindow *win)
+{
+ if (gtk_check_menu_item_get_active (item))
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (win->priv->box),
+ GTK_ORIENTATION_VERTICAL);
+}
+
+static void
+horizontal_toggled (GtkCheckMenuItem *item,
+ HoverClickWindow *win)
+{
+ if (gtk_check_menu_item_get_active (item))
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (win->priv->box),
+ GTK_ORIENTATION_HORIZONTAL);
+}
+
+static void
+orientation_notify (GObject *object,
+ GParamSpec *pspec,
+ HoverClickWindow *win)
+{
+ HoverClickWindowPrivate *priv = win->priv;
+ GtkOrientation o;
+
+ o = gtk_orientable_get_orientation (GTK_ORIENTABLE (priv->box));
+ if (o == GTK_ORIENTATION_VERTICAL)
+ gtk_widget_set_size_request (GTK_WIDGET (priv->button_primary), 110, 50);
+ else
+ gtk_widget_set_size_request (GTK_WIDGET (priv->button_primary), 80, 50);
+}
+
+static gboolean
+orientation_get_mapping (GValue *value,
+ GVariant *variant,
+ gpointer data)
+{
+ if (g_strcmp0 ("vertical", g_variant_get_string (variant, NULL)) == 0)
+ g_value_set_enum (value, GTK_ORIENTATION_VERTICAL);
+ else
+ g_value_set_enum (value, GTK_ORIENTATION_HORIZONTAL);
+
+ return TRUE;
+}
+
+static GVariant *
+orientation_set_mapping (const GValue *value,
+ const GVariantType *expected,
+ gpointer data)
+{
+ if (g_value_get_enum (value) == GTK_ORIENTATION_VERTICAL)
+ return g_variant_new_string ("vertical");
+ else
+ return g_variant_new_string ("horizontal");
+}
+
+static void
+hover_click_window_dispose (GObject *object)
+{
+ HoverClickWindowPrivate *priv = HOVER_CLICK_WINDOW (object)->priv;
+
+ g_clear_object (&priv->settings);
+ g_clear_object (&priv->proxy);
+
+ G_OBJECT_CLASS (hover_click_window_parent_class)->dispose (object);
+}
+
+static void
+set_menu_header (HoverClickWindow *win)
+{
+ HoverClickWindowPrivate *priv = win->priv;
+ PangoAttribute *attr;
+ PangoAttrList *list;
+ GtkWidget *child;
+
+ child = gtk_bin_get_child (GTK_BIN (priv->orientation));
+ list = pango_attr_list_new ();
+ attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
+ pango_attr_list_insert (list, attr);
+ gtk_label_set_attributes (GTK_LABEL (child), list);
+ pango_attr_list_unref (list);
+}
+
+static void
+hover_click_window_init (HoverClickWindow *win)
+{
+ HoverClickWindowPrivate *priv;
+
+ win->priv = priv = hover_click_window_get_instance_private (win);
+ win->priv->settings = g_settings_new ("org.gnome.Mousetweaks");
+
+ gtk_widget_init_template (GTK_WIDGET (win));
+
+ gtk_window_set_default_icon_name ("input-mouse");
+
+ g_object_set (gtk_settings_get_default (),
+ "gtk-application-prefer-dark-theme", TRUE, NULL);
+
+ g_signal_connect (priv->box, "notify::orientation",
+ G_CALLBACK (orientation_notify), win);
+
+ g_settings_bind_with_mapping (priv->settings, "window-orientation",
+ priv->box, "orientation",
+ G_SETTINGS_BIND_DEFAULT,
+ orientation_get_mapping,
+ orientation_set_mapping,
+ NULL, NULL);
+
+ g_signal_connect (priv->button_primary, "toggled", G_CALLBACK (button_primary_toggled), win);
+ g_signal_connect (priv->button_double, "toggled", G_CALLBACK (button_double_toggled), win);
+ g_signal_connect (priv->button_secondary, "toggled", G_CALLBACK (button_secondary_toggled), win);
+ g_signal_connect (priv->button_drag, "toggled", G_CALLBACK (button_drag_toggled), win);
+
+ g_signal_connect (priv->button_primary, "button-press-event", G_CALLBACK (menu_popup), win);
+ g_signal_connect (priv->button_double, "button-press-event", G_CALLBACK (menu_popup), win);
+ g_signal_connect (priv->button_secondary, "button-press-event", G_CALLBACK (menu_popup), win);
+ g_signal_connect (priv->button_drag, "button-press-event", G_CALLBACK (menu_popup), win);
+
+ if (!g_settings_get_enum (priv->settings, "window-orientation"))
+ gtk_check_menu_item_set_active (priv->vertical, TRUE);
+ else
+ gtk_check_menu_item_set_active (priv->horizontal, TRUE);
+
+ g_signal_connect (priv->vertical, "toggled", G_CALLBACK (vertical_toggled), win);
+ g_signal_connect (priv->horizontal, "toggled", G_CALLBACK (horizontal_toggled), win);
+
+ set_menu_header (win);
+
+ gtk_window_stick (GTK_WINDOW (win));
+ gtk_window_set_keep_above (GTK_WINDOW (win), TRUE);
+ gtk_window_move (GTK_WINDOW (win), 30, 30);
+}
+
+static void
+hover_click_window_class_init (HoverClickWindowClass *klass)
+{
+ GtkWidgetClass *wc = GTK_WIDGET_CLASS (klass);
+
+ G_OBJECT_CLASS (klass)->dispose = hover_click_window_dispose;
+
+ gtk_widget_class_set_template_from_resource (wc, "/org/gnome/Mousetweaks/window.ui");
+ gtk_widget_class_bind_template_child_private (wc, HoverClickWindow, box);
+ gtk_widget_class_bind_template_child_private (wc, HoverClickWindow, menu);
+ gtk_widget_class_bind_template_child_private (wc, HoverClickWindow, orientation);
+ gtk_widget_class_bind_template_child_private (wc, HoverClickWindow, vertical);
+ gtk_widget_class_bind_template_child_private (wc, HoverClickWindow, horizontal);
+ gtk_widget_class_bind_template_child_private (wc, HoverClickWindow, button_primary);
+ gtk_widget_class_bind_template_child_private (wc, HoverClickWindow, button_double);
+ gtk_widget_class_bind_template_child_private (wc, HoverClickWindow, button_secondary);
+ gtk_widget_class_bind_template_child_private (wc, HoverClickWindow, button_drag);
+}
+
+static void
+application_activate (GApplication *app,
+ gpointer data)
+{
+ GList *windows;
+ GtkWidget *win;
+
+ if ((windows = gtk_application_get_windows (GTK_APPLICATION (app))))
+ {
+ gtk_window_present (windows->data);
+ return;
+ }
+
+ win = g_object_new (HOVER_CLICK_TYPE_WINDOW, NULL);
+ gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (win));
+ gtk_widget_show (win);
+
+ g_dbus_proxy_new (g_application_get_dbus_connection (app),
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.gnome.Mousetweaks",
+ "/org/gnome/Mousetweaks",
+ "org.gnome.Mousetweaks",
+ NULL,
+ (GAsyncReadyCallback) mousetweaks_proxy_ready,
+ win);
+}
+
+int
+main (int argc, char **argv)
+{
+ GtkApplication *app;
+ int status;
+
+ bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ g_set_application_name (_("Hover Click"));
+
+ app = gtk_application_new ("org.gnome.Mousetweaks.HoverClick", 0);
+ g_signal_connect (app, "activate", G_CALLBACK (application_activate), NULL);
+ status = g_application_run (G_APPLICATION (app), argc, argv);
+ g_object_unref (app);
+
+ return status;
+}
diff --git a/src/mt-ctw.h b/src/main.c
similarity index 55%
copy from src/mt-ctw.h
copy to src/main.c
index 027a849..22f8092 100644
--- a/src/mt-ctw.h
+++ b/src/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2007-2010 Gerd Kohlberger <gerdko gmail com>
+ * Copyright 2013, Gerd Kohlberger <gerdko gmail com>
*
* This file is part of Mousetweaks.
*
@@ -17,21 +17,29 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef __MT_CTW_H__
-#define __MT_CTW_H__
+#include <config.h>
+#include <glib/gi18n.h>
-#include <gtk/gtk.h>
+#include "mt_application.h"
-G_BEGIN_DECLS
+int
+main (int argc, char **argv)
+{
+ MtApplication *app;
+ gint status;
-gboolean mt_ctw_init (void);
+ bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+ setlocale (LC_ALL, "");
-void mt_ctw_fini (void);
+ g_set_application_name ("Mousetweaks");
-GtkWidget * mt_ctw_get_window (void);
+ app = mt_application_new ();
-void mt_ctw_save_geometry (void);
+ status = g_application_run (G_APPLICATION (app), argc, argv);
-G_END_DECLS
+ g_object_unref (app);
-#endif /* __MT_CTW_H__ */
+ return status;
+}
diff --git a/src/mt_application.c b/src/mt_application.c
new file mode 100644
index 0000000..ef7b39a
--- /dev/null
+++ b/src/mt_application.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright 2013, Gerd Kohlberger <gerdko gmail com>
+ *
+ * This file is part of Mousetweaks.
+ *
+ * Mousetweaks is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mousetweaks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib/gi18n.h>
+
+#include "config.h"
+#include "mt_application.h"
+#include "mt_hover_click.h"
+#include "mt_secondary_click.h"
+
+typedef struct
+{
+ MtHoverClick *hover_click;
+ MtSecondaryClick *secondary_click;
+
+ guint service_id;
+ guint watch_id;
+
+ /* command-line arguments */
+ gboolean sc_enabled;
+ gdouble sc_time;
+ gint sc_threshold;
+ gboolean hc_enabled;
+ gdouble hc_time;
+ gint hc_threshold;
+ gboolean shutdown;
+} MtApplicationPrivate;
+
+struct _MtApplication
+{
+ GApplication parent;
+ MtApplicationPrivate *priv;
+};
+
+static const gchar introspection[] =
+ "<node>"
+ " <interface name='org.gnome.Mousetweaks'>"
+ " <property type='i' name='ClickType' access='readwrite'/>"
+ " </interface>"
+ "</node>";
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (MtApplication, mt_application, G_TYPE_APPLICATION)
+
+static void
+mt_application_init (MtApplication *app)
+{
+ app->priv = mt_application_get_instance_private (app);
+}
+
+static void
+mt_application_dispose (GObject *object)
+{
+ MtApplicationPrivate *priv = MT_APPLICATION (object)->priv;
+
+ g_clear_object (&priv->hover_click);
+ g_clear_object (&priv->secondary_click);
+
+ G_OBJECT_CLASS (mt_application_parent_class)->dispose (object);
+}
+
+static GVariant *
+handle_get_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *path,
+ const gchar *interface,
+ const gchar *property,
+ GError **error,
+ MtApplication *app)
+{
+ if (g_strcmp0 (property, "ClickType") == 0)
+ {
+ gint click_type;
+
+ g_object_get (app->priv->hover_click, "click-type", &click_type, NULL);
+ return g_variant_new_int32 (click_type);
+ }
+ return NULL;
+}
+
+static gboolean
+handle_set_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *path,
+ const gchar *interface,
+ const gchar *property,
+ GVariant *value,
+ GError **error,
+ MtApplication *app)
+{
+ if (g_strcmp0 (property, "ClickType") == 0)
+ g_object_set (app->priv->hover_click,
+ "click-type",
+ g_variant_get_int32 (value), NULL);
+
+ return TRUE;
+}
+
+static const GDBusInterfaceVTable interface_vtable =
+{
+ (GDBusInterfaceMethodCallFunc) NULL,
+ (GDBusInterfaceGetPropertyFunc) handle_get_property,
+ (GDBusInterfaceSetPropertyFunc) handle_set_property
+};
+
+static void
+emit_property_changed (MtHoverClick *click,
+ GParamSpec *pspec,
+ GApplication *application)
+{
+ GDBusConnection *connection;
+ GVariantBuilder builder;
+ GVariantBuilder inv_builder;
+ GVariant *prop_v;
+ const gchar *path;
+ gint click_type;
+ GError *error = NULL;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_init (&inv_builder, G_VARIANT_TYPE ("as"));
+
+ g_object_get (click, "click-type", &click_type, NULL);
+ g_variant_builder_add (&builder, "{sv}", "ClickType",
+ g_variant_new_int32 (click_type));
+
+ prop_v = g_variant_new ("(sa{sv}as)",
+ "org.gnome.Mousetweaks",
+ &builder, &inv_builder);
+
+ connection = g_application_get_dbus_connection (application);
+ path = g_application_get_dbus_object_path (application);
+
+ if (!g_dbus_connection_emit_signal (connection, NULL, path,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ prop_v, &error))
+ {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+click_selection_appeared (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *owner,
+ gpointer data)
+{
+ MtApplication *app = data;
+ g_object_set (app->priv->hover_click, "show-window", FALSE, NULL);
+}
+
+static void
+click_selection_vanished (GDBusConnection *connection,
+ const gchar *name,
+ gpointer data)
+{
+ MtApplication *app = data;
+ g_object_set (app->priv->hover_click, "show-window", TRUE, NULL);
+}
+
+static gboolean
+mt_application_dbus_register (GApplication *application,
+ GDBusConnection *connection,
+ const gchar *object_path,
+ GError **error)
+{
+ MtApplication *app = MT_APPLICATION (application);
+ MtApplicationPrivate *priv = app->priv;
+ GDBusNodeInfo *info;
+
+ if (!G_APPLICATION_CLASS (mt_application_parent_class)->dbus_register (application,
+ connection,
+ object_path,
+ error))
+ return FALSE;
+
+ if (!(info = g_dbus_node_info_new_for_xml (introspection, error)))
+ return FALSE;
+
+ priv->service_id =
+ g_dbus_connection_register_object (connection,
+ object_path,
+ info->interfaces[0],
+ &interface_vtable,
+ app, NULL, error);
+
+ g_dbus_node_info_unref (info);
+
+ if (!priv->service_id)
+ return FALSE;
+
+ priv->watch_id =
+ g_bus_watch_name_on_connection (connection,
+ "org.gnome.Mousetweaks.ClickSelection",
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ click_selection_appeared,
+ click_selection_vanished,
+ app, NULL);
+ return TRUE;
+}
+
+static void
+mt_application_dbus_unregister (GApplication *application,
+ GDBusConnection *connection,
+ const gchar *object_path)
+{
+ MtApplication *app = MT_APPLICATION (application);
+ MtApplicationPrivate *priv = app->priv;
+
+ if (priv->watch_id)
+ {
+ g_bus_unwatch_name (priv->watch_id);
+ priv->watch_id = 0;
+ }
+
+ if (priv->service_id)
+ {
+ g_dbus_connection_unregister_object (connection, priv->service_id);
+ priv->service_id = 0;
+ }
+
+ G_APPLICATION_CLASS (mt_application_parent_class)->dbus_unregister (application,
+ connection,
+ object_path);
+}
+
+static int
+mt_application_command_line (GApplication *application,
+ GApplicationCommandLine *cmdline)
+{
+ MtApplicationPrivate *priv = MT_APPLICATION (application)->priv;
+ gchar **argv;
+ gint i, argc;
+
+ argv = g_application_command_line_get_arguments (cmdline, &argc);
+
+ for (i = 0; i < argc; i++)
+ {
+ if (g_strcmp0 (argv[i], "-s") == 0)
+ {
+ g_application_release (application);
+ g_application_command_line_print (cmdline, "%s\n", _("Shutdown successful."));
+
+ if (priv->sc_enabled)
+ g_object_set (priv->secondary_click, "enabled", FALSE, NULL);
+
+ if (priv->hc_enabled)
+ g_object_set (priv->hover_click, "enabled", FALSE, NULL);
+
+ break;
+ }
+ }
+
+ g_strfreev (argv);
+
+ return 0;
+}
+
+static gboolean
+mt_application_local_command_line (GApplication *application,
+ gchar ***arguments,
+ gint *exit_status)
+{
+ MtApplicationPrivate *priv = MT_APPLICATION (application)->priv;
+ GError *error = NULL;
+ GOptionContext *context;
+ gchar **argv, **optv;
+ gint argc, optc, i;
+ gboolean version;
+ GOptionEntry entries[] =
+ {
+ { "hover-click", 0, 0, G_OPTION_ARG_NONE, &priv->hc_enabled,
+ N_("Enable Hover Click"), NULL },
+
+ { "hover-click-time", 0, 0, G_OPTION_ARG_DOUBLE, &priv->hc_time,
+ N_("Time to wait before a hover click"), "[0.5-3.0]" },
+
+ { "hover-click-threshold", 0, 0, G_OPTION_ARG_INT, &priv->hc_threshold,
+ N_("Ignore small pointer movements"), "[0-50]" },
+
+ { "secondary-click", 0, 0, G_OPTION_ARG_NONE, &priv->sc_enabled,
+ N_("Enable Secondary Click Emulation"), NULL },
+
+ { "secondary-click-time", 0, 0, G_OPTION_ARG_DOUBLE, &priv->sc_time,
+ N_("Time to wait before a secondary click"), "[0.5-3.0]" },
+
+ { "secondary-click-threshold", 0, 0, G_OPTION_ARG_INT, &priv->sc_threshold,
+ N_("Ignore small pointer movements"), "[0-50]" },
+
+ { "version", 'v', 0, G_OPTION_ARG_NONE, &version,
+ N_("Print version"), NULL },
+
+ { "shutdown", 's', 0, G_OPTION_ARG_NONE, &priv->shutdown,
+ N_("Shut down mousetweaks"), NULL },
+
+ { NULL }
+ };
+
+ priv->hc_threshold = -1;
+ priv->sc_threshold = -1;
+ *exit_status = 0;
+
+ argv = *arguments;
+ argc = g_strv_length (argv);
+
+ optv = g_new0 (gchar *, argc + 1);
+ optc = argc;
+
+ for (i = 0; i < argc; i++)
+ optv[i] = argv[i];
+
+ context = g_option_context_new (_("- GNOME Mouse accessibility service"));
+ g_option_context_add_main_entries (context, entries, NULL);
+
+ if (!g_option_context_parse (context, &optc, &optv, &error))
+ {
+ g_printerr ("%s\n", error->message);
+ g_error_free (error);
+ *exit_status = 1;
+ goto out;
+ }
+
+ if (version)
+ {
+ g_print ("%s\n", VERSION);
+ goto out;
+ }
+
+ if (!g_application_register (application, NULL, &error))
+ {
+ g_printerr ("%s\n", error->message);
+ g_error_free (error);
+ *exit_status = 1;
+ goto out;
+ }
+
+ if (priv->shutdown)
+ {
+ if (g_application_get_is_remote (application))
+ {
+ /* forward to primary instance */
+ for (i = 1; i < argc; i++)
+ {
+ g_free (argv[i]);
+ argv[i] = NULL;
+ }
+
+ argv[1] = g_strdup ("-s");
+
+ g_option_context_free (context);
+ g_free (optv);
+
+ return FALSE;
+ }
+ else
+ g_print ("%s\n", _("Nothing to shut down."));
+ }
+
+ if (g_application_get_is_remote (application))
+ g_print ("%s\n", _("Mousetweaks is already running."));
+
+out:
+ g_option_context_free (context);
+ g_free (optv);
+
+ return TRUE;
+}
+
+static void
+mt_application_startup (GApplication *application)
+{
+ MtApplication *app = MT_APPLICATION (application);
+ MtApplicationPrivate *priv = app->priv;
+
+ G_APPLICATION_CLASS (mt_application_parent_class)->startup (application);
+
+ if (priv->shutdown)
+ return;
+
+ g_application_hold (application);
+
+ priv->hover_click = mt_hover_click_new ();
+ priv->secondary_click = mt_secondary_click_new ();
+
+ g_signal_connect (priv->hover_click, "notify::click-type",
+ G_CALLBACK (emit_property_changed), app);
+
+ /* apply command-line options */
+ if (priv->hc_enabled)
+ {
+ if (priv->hc_time >= 0.2 && priv->hc_time <= 3.0)
+ g_object_set (priv->hover_click, "time", priv->hc_time, NULL);
+
+ if (priv->hc_threshold >= 0 && priv->hc_threshold <= 30)
+ g_object_set (priv->hover_click, "threshold", priv->hc_threshold, NULL);
+
+ g_object_set (priv->hover_click, "enabled", TRUE, NULL);
+ }
+
+ if (priv->sc_enabled)
+ {
+ if (priv->sc_time >= 0.5 && priv->sc_time <= 3.0)
+ g_object_set (priv->secondary_click, "time", priv->sc_time, NULL);
+
+ if (priv->sc_threshold >= 0 && priv->sc_threshold <= 30)
+ g_object_set (priv->secondary_click, "threshold", priv->sc_threshold, NULL);
+
+ g_object_set (priv->secondary_click, "enabled", TRUE, NULL);
+ }
+}
+
+static void
+mt_application_class_init (MtApplicationClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GApplicationClass *app_class = G_APPLICATION_CLASS (klass);
+
+ object_class->dispose = mt_application_dispose;
+
+ app_class->command_line = mt_application_command_line;
+ app_class->local_command_line = mt_application_local_command_line;
+ app_class->dbus_register = mt_application_dbus_register;
+ app_class->dbus_unregister = mt_application_dbus_unregister;
+ app_class->startup = mt_application_startup;
+}
+
+MtApplication *
+mt_application_new (void)
+{
+ return g_object_new (MT_TYPE_APPLICATION,
+ "application-id", "org.gnome.Mousetweaks",
+ NULL);
+}
diff --git a/src/mt-pidfile.h b/src/mt_application.h
similarity index 53%
rename from src/mt-pidfile.h
rename to src/mt_application.h
index 6380e64..3ffd7ff 100644
--- a/src/mt-pidfile.h
+++ b/src/mt_application.h
@@ -1,5 +1,5 @@
/*
- * Copyright © 2007-2010 Gerd Kohlberger <gerdko gmail com>
+ * Copyright 2013, Gerd Kohlberger <gerdko gmail com>
*
* This file is part of Mousetweaks.
*
@@ -17,16 +17,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef __MT_PIDFILE_H__
-#define __MT_PIDFILE_H__
+#ifndef __MT_APPLICATION_H__
+#define __MT_APPLICATION_H__
+
+#include <gio/gio.h>
G_BEGIN_DECLS
-int mt_pidfile_create (void);
-pid_t mt_pidfile_is_running (void);
-int mt_pidfile_kill_wait (int signal, int sec);
-int mt_pidfile_remove (void);
+#define MT_TYPE_APPLICATION (mt_application_get_type ())
+#define MT_APPLICATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MT_TYPE_APPLICATION, MtApplication))
+#define MT_IS_APPLICATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MT_TYPE_APPLICATION))
+
+typedef GApplicationClass MtApplicationClass;
+typedef struct _MtApplication MtApplication;
+
+GType mt_application_get_type (void) G_GNUC_CONST;
+MtApplication * mt_application_new (void);
G_END_DECLS
-#endif /* __MT_PIDFILE_H__ */
+#endif /* __MT_APPLICATION_H__ */
diff --git a/src/mt_click.c b/src/mt_click.c
new file mode 100644
index 0000000..b8708a1
--- /dev/null
+++ b/src/mt_click.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2013, Gerd Kohlberger <gerdko gmail com>
+ *
+ * This file is part of Mousetweaks.
+ *
+ * Mousetweaks is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mousetweaks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gio/gio.h>
+
+#include "mt_click.h"
+
+struct _MtClickPrivate
+{
+ GSettings *settings;
+ MtListener *listener;
+ MtTimer *timer;
+
+ gint threshold;
+ gdouble time;
+ guint enabled : 1;
+};
+
+enum
+{
+ PROP_0,
+ PROP_ENABLED,
+ PROP_TIME,
+ PROP_THRESHOLD
+};
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MtClick, mt_click, G_TYPE_OBJECT)
+
+static void
+timer_finished (MtTimer *timer,
+ MtClick *click)
+{
+ MtClickClass *klass = MT_CLICK_GET_CLASS (click);
+
+ if (click->priv->enabled && klass->timer_finished)
+ klass->timer_finished (click, timer, click->priv->listener);
+}
+
+static void
+listener_motion_event (MtListener *listener,
+ MtEvent *event,
+ MtClick *click)
+{
+ MtClickClass *klass = MT_CLICK_GET_CLASS (click);
+
+ if (click->priv->enabled && klass->motion_event)
+ klass->motion_event (click, listener, event, click->priv->timer);
+}
+
+static void
+listener_button_event (MtListener *listener,
+ MtEvent *event,
+ MtClick *click)
+{
+ MtClickClass *klass = MT_CLICK_GET_CLASS (click);
+
+ if (click->priv->enabled && klass->button_event)
+ klass->button_event (click, listener, event, click->priv->timer);
+}
+
+static void
+mt_click_init (MtClick *click)
+{
+ click->priv = mt_click_get_instance_private (click);
+ click->priv->settings = g_settings_new ("org.gnome.desktop.a11y.mouse");
+ click->priv->listener = mt_listener_get_default ();
+ click->priv->timer = mt_timer_new ();
+
+ g_signal_connect (click->priv->listener, "motion-event",
+ G_CALLBACK (listener_motion_event), click);
+ g_signal_connect (click->priv->listener, "button-event",
+ G_CALLBACK (listener_button_event), click);
+ g_signal_connect (click->priv->timer, "finished",
+ G_CALLBACK (timer_finished), click);
+
+ g_object_bind_property (click, "time", click->priv->timer, "target", 0);
+}
+
+static void
+mt_click_dispose (GObject *object)
+{
+ MtClickPrivate *priv = MT_CLICK (object)->priv;
+
+ g_clear_object (&priv->settings);
+ g_clear_object (&priv->listener);
+ g_clear_object (&priv->timer);
+
+ G_OBJECT_CLASS (mt_click_parent_class)->dispose (object);
+}
+
+static void
+mt_click_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MtClickPrivate *priv = MT_CLICK (object)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_ENABLED:
+ priv->enabled = g_value_get_boolean (value);
+ g_object_notify_by_pspec (object, pspec);
+ break;
+
+ case PROP_TIME:
+ priv->time = g_value_get_double (value);
+ g_object_notify_by_pspec (object, pspec);
+ break;
+
+ case PROP_THRESHOLD:
+ priv->threshold = g_value_get_int (value);
+ g_object_notify_by_pspec (object, pspec);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+mt_click_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MtClickPrivate *priv = MT_CLICK (object)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_ENABLED:
+ g_value_set_boolean (value, priv->enabled);
+ break;
+
+ case PROP_TIME:
+ g_value_set_double (value, (gdouble) priv->time);
+ break;
+
+ case PROP_THRESHOLD:
+ g_value_set_int (value, priv->threshold);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+mt_click_class_init (MtClickClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = mt_click_dispose;
+ object_class->get_property = mt_click_get_property;
+ object_class->set_property = mt_click_set_property;
+
+ g_object_class_install_property (object_class, PROP_ENABLED,
+ g_param_spec_boolean ("enabled", "Enabled",
+ "Enable click feature",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class, PROP_TIME,
+ g_param_spec_double ("time", "Time",
+ "Acceptance delay for a click",
+ 0.2, 3.0, 1.2,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class, PROP_THRESHOLD,
+ g_param_spec_int ("threshold", "Motion threshold",
+ "Ignore pointer movement below this threshold",
+ 0, 30, 10,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+void
+mt_click_bind_setting (MtClick *click,
+ const gchar *prop,
+ const gchar *key)
+{
+ g_return_if_fail (MT_IS_CLICK (click));
+
+ g_settings_bind (click->priv->settings, key, click, prop,
+ G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY);
+}
+
+MtListener *
+mt_click_get_listener (MtClick *click)
+{
+ g_return_val_if_fail (MT_IS_CLICK (click), NULL);
+ return click->priv->listener;
+}
+
+MtTimer *
+mt_click_get_timer (MtClick *click)
+{
+ g_return_val_if_fail (MT_IS_CLICK (click), NULL);
+ return click->priv->timer;
+}
diff --git a/src/mt_click.h b/src/mt_click.h
new file mode 100644
index 0000000..36d3874
--- /dev/null
+++ b/src/mt_click.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2013, Gerd Kohlberger <gerdko gmail com>
+ *
+ * This file is part of Mousetweaks.
+ *
+ * Mousetweaks is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mousetweaks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MT_CLICK_H__
+#define __MT_CLICK_H__
+
+#include <glib-object.h>
+
+#include "mt_listener.h"
+#include "mt_timer.h"
+
+G_BEGIN_DECLS
+
+#define MT_TYPE_CLICK (mt_click_get_type ())
+#define MT_CLICK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MT_TYPE_CLICK, MtClick))
+#define MT_CLICK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), MT_TYPE_CLICK, MtClickClass))
+#define MT_IS_CLICK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MT_TYPE_CLICK))
+#define MT_IS_CLICK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MT_TYPE_CLICK))
+#define MT_CLICK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MT_TYPE_CLICK, MtClickClass))
+
+typedef struct _MtClickPrivate MtClickPrivate;
+typedef struct _MtClickClass MtClickClass;
+typedef struct _MtClick MtClick;
+
+struct _MtClickClass
+{
+ GObjectClass parent;
+
+ void (* button_event) (MtClick *click,
+ MtListener *listener,
+ MtEvent *event,
+ MtTimer *timer);
+
+ void (* motion_event) (MtClick *click,
+ MtListener *listener,
+ MtEvent *event,
+ MtTimer *timer);
+
+ void (* timer_finished) (MtClick *click,
+ MtTimer *timer,
+ MtListener *listener);
+};
+
+struct _MtClick
+{
+ GObject parent;
+ MtClickPrivate *priv;
+};
+
+GType mt_click_get_type (void) G_GNUC_CONST;
+
+void mt_click_bind_setting (MtClick *click,
+ const gchar *prop,
+ const gchar *key);
+
+MtListener * mt_click_get_listener (MtClick *click);
+
+MtTimer * mt_click_get_timer (MtClick *click);
+
+G_END_DECLS
+
+#endif /* __MT_CLICK_H__ */
diff --git a/src/mt_hover_click.c b/src/mt_hover_click.c
new file mode 100644
index 0000000..3619328
--- /dev/null
+++ b/src/mt_hover_click.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2013, Gerd Kohlberger <gerdko gmail com>
+ *
+ * This file is part of Mousetweaks.
+ *
+ * Mousetweaks is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mousetweaks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <signal.h>
+
+#include "config.h"
+#include "mt_hover_click.h"
+
+typedef struct
+{
+ gint x;
+ gint y;
+ gint click_type;
+ GPid window_pid;
+ guint show_window : 1;
+ guint window_launched : 1;
+ guint drag_started : 1;
+} MtHoverClickPrivate;
+
+struct _MtHoverClick
+{
+ MtClick parent;
+ MtHoverClickPrivate *priv;
+};
+
+enum
+{
+ PROP_0,
+ PROP_CLICK_TYPE,
+ PROP_SHOW_WINDOW
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (MtHoverClick, mt_hover_click, MT_TYPE_CLICK)
+
+static void
+mt_hover_click_init (MtHoverClick *click)
+{
+ click->priv = mt_hover_click_get_instance_private (click);
+}
+
+static void
+mt_hover_click_timer_finished (MtClick *click,
+ MtTimer *timer,
+ MtListener *listener)
+{
+ MtHoverClickPrivate *priv = MT_HOVER_CLICK (click)->priv;
+
+ if (priv->drag_started)
+ {
+ priv->drag_started = FALSE;
+ mt_listener_send_event (listener, 1, MT_SEND_BUTTON_RELEASE);
+ g_object_set (click, "click-type", MT_CLICK_TYPE_PRIMARY, NULL);
+ return;
+ }
+
+ switch (priv->click_type)
+ {
+ case MT_CLICK_TYPE_PRIMARY:
+ mt_listener_send_event (listener, 1, MT_SEND_CLICK);
+ break;
+
+ case MT_CLICK_TYPE_MIDDLE:
+ mt_listener_send_event (listener, 2, MT_SEND_CLICK);
+ g_object_set (click, "click-type", MT_CLICK_TYPE_PRIMARY, NULL);
+ break;
+
+ case MT_CLICK_TYPE_SECONDARY:
+ mt_listener_send_event (listener, 3, MT_SEND_CLICK);
+ g_object_set (click, "click-type", MT_CLICK_TYPE_PRIMARY, NULL);
+ break;
+
+ case MT_CLICK_TYPE_DOUBLE:
+ mt_listener_send_event (listener, 1, MT_SEND_CLICK);
+ mt_listener_send_event (listener, 1, MT_SEND_CLICK);
+ g_object_set (click, "click-type", MT_CLICK_TYPE_PRIMARY, NULL);
+ break;
+
+ case MT_CLICK_TYPE_DRAG:
+ mt_listener_send_event (listener, 1, MT_SEND_BUTTON_PRESS);
+ priv->drag_started = TRUE;
+ break;
+
+ default:
+ g_warning ("Unknown click-type selected.");
+ break;
+ }
+}
+
+static void
+mt_hover_click_motion_event (MtClick *click,
+ MtListener *listener,
+ MtEvent *event,
+ MtTimer *timer)
+{
+ MtHoverClickPrivate *priv = MT_HOVER_CLICK (click)->priv;
+ gint t;
+
+ g_object_get (click, "threshold", &t, NULL);
+
+ if (priv->x == -1 && priv->y == -1)
+ {
+ priv->x = event->x;
+ priv->y = event->y;
+ }
+ else if (ABS (priv->x - event->x) > t || ABS (priv->y - event->y) > t)
+ {
+ priv->x = event->x;
+ priv->y = event->y;
+ mt_timer_start (timer);
+ }
+}
+
+static void
+mt_hover_click_button_event (MtClick *click,
+ MtListener *listener,
+ MtEvent *event,
+ MtTimer *timer)
+{
+ MtHoverClickPrivate *priv = MT_HOVER_CLICK (click)->priv;
+
+ if (mt_timer_is_running (timer))
+ {
+ mt_timer_stop (timer);
+
+ if (priv->drag_started)
+ priv->drag_started = FALSE;
+
+ if (priv->click_type != MT_CLICK_TYPE_PRIMARY)
+ g_object_set (click, "click-type", MT_CLICK_TYPE_PRIMARY, NULL);
+ }
+}
+
+static void
+mt_hover_click_window_show (MtHoverClick *click)
+{
+ MtHoverClickPrivate *priv = click->priv;
+
+ if (!priv->window_launched)
+ {
+ gchar *args[2] = { LIBEXECDIR "/hover-click-window", NULL };
+ GError *error = NULL;
+
+ g_spawn_async (NULL, args, NULL, 0, NULL, NULL,
+ &priv->window_pid, &error);
+ if (error)
+ {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ return;
+ }
+ priv->window_launched = TRUE;
+ }
+}
+
+static void
+mt_hover_click_window_hide (MtHoverClick *click)
+{
+ MtHoverClickPrivate *priv = click->priv;
+
+ if (priv->window_launched)
+ {
+ kill (priv->window_pid, SIGHUP);
+ g_spawn_close_pid (priv->window_pid);
+ priv->window_launched = FALSE;
+ }
+}
+
+static void
+mt_hover_click_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MtHoverClickPrivate *priv = MT_HOVER_CLICK (object)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_CLICK_TYPE:
+ priv->click_type = g_value_get_int (value);
+ g_object_notify_by_pspec (object, pspec);
+ break;
+
+ case PROP_SHOW_WINDOW:
+ priv->show_window = g_value_get_boolean (value);
+ g_object_notify_by_pspec (object, pspec);
+ if (priv->show_window)
+ {
+ gboolean enabled;
+
+ g_object_get (object, "enabled", &enabled, NULL);
+
+ if (enabled)
+ mt_hover_click_window_show (MT_HOVER_CLICK (object));
+ }
+ else
+ mt_hover_click_window_hide (MT_HOVER_CLICK (object));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+mt_hover_click_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MtHoverClickPrivate *priv = MT_HOVER_CLICK (object)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_CLICK_TYPE:
+ g_value_set_int (value, priv->click_type);
+ break;
+
+ case PROP_SHOW_WINDOW:
+ g_value_set_boolean (value, priv->show_window);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+mt_hover_click_class_init (MtHoverClickClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MtClickClass *click_class = MT_CLICK_CLASS (klass);
+
+ object_class->get_property = mt_hover_click_get_property;
+ object_class->set_property = mt_hover_click_set_property;
+
+ click_class->button_event = mt_hover_click_button_event;
+ click_class->motion_event = mt_hover_click_motion_event;
+ click_class->timer_finished = mt_hover_click_timer_finished;
+
+ g_object_class_install_property (object_class, PROP_CLICK_TYPE,
+ g_param_spec_int ("click-type", "Click Type",
+ "The active click type",
+ MT_CLICK_TYPE_PRIMARY, MT_CLICK_TYPE_DRAG, MT_CLICK_TYPE_PRIMARY,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class, PROP_SHOW_WINDOW,
+ g_param_spec_boolean ("show-window", "Show Window",
+ "Whether to show the click selection window",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+click_enabled_notify (MtClick *click,
+ GParamSpec *pspec,
+ gpointer data)
+{
+ MtHoverClickPrivate *priv = MT_HOVER_CLICK (click)->priv;
+ gboolean enabled;
+
+ g_object_get (click, "enabled", &enabled, NULL);
+
+ if (enabled)
+ {
+ priv->x = -1;
+ priv->y = -1;
+ if (priv->show_window)
+ mt_hover_click_window_show (MT_HOVER_CLICK (click));
+ }
+ else
+ mt_hover_click_window_hide (MT_HOVER_CLICK (click));
+}
+
+MtHoverClick *
+mt_hover_click_new (void)
+{
+ MtHoverClick *click;
+
+ click = g_object_new (MT_TYPE_HOVER_CLICK, NULL);
+
+ mt_click_bind_setting (MT_CLICK (click), "enabled", "dwell-click-enabled");
+ mt_click_bind_setting (MT_CLICK (click), "threshold", "dwell-threshold");
+ mt_click_bind_setting (MT_CLICK (click), "time", "dwell-time");
+
+ g_signal_connect (click, "notify::enabled",
+ G_CALLBACK (click_enabled_notify), NULL);
+
+ return click;
+}
diff --git a/src/mt_hover_click.h b/src/mt_hover_click.h
new file mode 100644
index 0000000..e979a94
--- /dev/null
+++ b/src/mt_hover_click.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2013, Gerd Kohlberger <gerdko gmail com>
+ *
+ * This file is part of Mousetweaks.
+ *
+ * Mousetweaks is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mousetweaks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MT_HOVER_CLICK_H__
+#define __MT_HOVER_CLICK_H__
+
+#include "mt_click.h"
+
+G_BEGIN_DECLS
+
+#define MT_TYPE_HOVER_CLICK (mt_hover_click_get_type ())
+#define MT_HOVER_CLICK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MT_TYPE_HOVER_CLICK, MtHoverClick))
+#define MT_IS_HOVER_CLICK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MT_TYPE_HOVER_CLICK))
+
+typedef MtClickClass MtHoverClickClass;
+typedef struct _MtHoverClick MtHoverClick;
+
+enum
+{
+ MT_CLICK_TYPE_PRIMARY,
+ MT_CLICK_TYPE_MIDDLE,
+ MT_CLICK_TYPE_SECONDARY,
+ MT_CLICK_TYPE_DOUBLE,
+ MT_CLICK_TYPE_DRAG
+};
+
+GType mt_hover_click_get_type (void) G_GNUC_CONST;
+MtHoverClick * mt_hover_click_new (void);
+
+G_END_DECLS
+
+#endif /* __MT_HOVER_CLICK_H__ */
diff --git a/src/mt_listener.c b/src/mt_listener.c
new file mode 100644
index 0000000..8b0b71b
--- /dev/null
+++ b/src/mt_listener.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright, 2013 Gerd Kohlberger <gerdko gmail com>
+ *
+ * This file is part of Mousetweaks.
+ *
+ * Mousetweaks is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mousetweaks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mt_listener.h"
+#include "mt_listener_atspi.h"
+
+enum
+{
+ MOTION_EVENT,
+ BUTTON_EVENT,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+G_DEFINE_ABSTRACT_TYPE (MtListener, mt_listener, G_TYPE_OBJECT)
+
+static void
+mt_listener_init (MtListener *listener)
+{
+}
+
+static void
+mt_listener_class_init (MtListenerClass *klass)
+{
+ signals[MOTION_EVENT] =
+ g_signal_new ("motion-event",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE,
+ 1, MT_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+ signals[BUTTON_EVENT] =
+ g_signal_new ("button-event",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE,
+ 1, MT_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+}
+
+static MtEvent *
+mt_event_copy (const MtEvent *event)
+{
+ return g_memdup (event, sizeof (MtEvent));
+}
+
+static void
+mt_event_free (MtEvent *event)
+{
+ g_free (event);
+}
+
+G_DEFINE_BOXED_TYPE (MtEvent, mt_event, mt_event_copy, mt_event_free)
+
+MtListener *
+mt_listener_get_default (void)
+{
+ static MtListener *listener = NULL;
+
+ if (listener == NULL)
+ {
+ listener = mt_listener_atspi_new ();
+ g_object_add_weak_pointer (G_OBJECT (listener), (gpointer *) &listener);
+ return listener;
+ }
+ return g_object_ref (listener);
+}
+
+void
+mt_listener_emit_button_event (MtListener *listener,
+ MtEventType type,
+ gint button,
+ gint x,
+ gint y)
+{
+ MtEvent ev;
+
+ ev.type = type;
+ ev.button = button;
+ ev.x = x;
+ ev.y = y;
+
+ g_signal_emit (listener, signals[BUTTON_EVENT], 0, &ev);
+}
+
+void
+mt_listener_emit_motion_event (MtListener *listener,
+ gint x,
+ gint y)
+{
+ MtEvent ev;
+
+ ev.type = MT_EVENT_MOTION;
+ ev.button = 0;
+ ev.x = x;
+ ev.y = y;
+
+ g_signal_emit (listener, signals[MOTION_EVENT], 0, &ev);
+}
+
+void
+mt_listener_query_pointer (MtListener *listener,
+ gint *x,
+ gint *y)
+{
+ MtListenerClass *klass = MT_LISTENER_GET_CLASS (listener);
+
+ if (klass->query_pointer)
+ klass->query_pointer (listener, x, y);
+}
+
+void
+mt_listener_send_event (MtListener *listener,
+ gint button,
+ MtSendType type)
+{
+ MtListenerClass *klass = MT_LISTENER_GET_CLASS (listener);
+
+ if (klass->send_event)
+ klass->send_event (listener, button, type);
+}
diff --git a/src/mt_listener.h b/src/mt_listener.h
new file mode 100644
index 0000000..94e0fd8
--- /dev/null
+++ b/src/mt_listener.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2013, Gerd Kohlberger <gerdko gmail com>
+ *
+ * This file is part of Mousetweaks.
+ *
+ * Mousetweaks is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mousetweaks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MT_LISTENER_H__
+#define __MT_LISTENER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MT_TYPE_EVENT (mt_event_get_type ())
+#define MT_TYPE_LISTENER (mt_listener_get_type ())
+#define MT_LISTENER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MT_TYPE_LISTENER, MtListener))
+#define MT_LISTENER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), MT_TYPE_LISTENER, MtListenerClass))
+#define MT_IS_LISTENER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MT_TYPE_LISTENER))
+#define MT_IS_LISTENER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MT_TYPE_LISTENER))
+#define MT_LISTENER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MT_TYPE_LISTENER, MtListenerClass))
+
+typedef GObject MtListener;
+
+typedef enum
+{
+ MT_SEND_CLICK,
+ MT_SEND_BUTTON_PRESS,
+ MT_SEND_BUTTON_RELEASE
+} MtSendType;
+
+typedef struct
+{
+ GObjectClass parent;
+
+ void (* query_pointer) (MtListener *listener,
+ gint *x,
+ gint *y);
+
+ void (* send_event) (MtListener *listener,
+ gint button,
+ MtSendType type);
+} MtListenerClass;
+
+typedef enum
+{
+ MT_EVENT_MOTION,
+ MT_EVENT_BUTTON_PRESS,
+ MT_EVENT_BUTTON_RELEASE
+} MtEventType;
+
+typedef struct
+{
+ MtEventType type;
+ gint x;
+ gint y;
+ gint button;
+} MtEvent;
+
+GType mt_event_get_type (void) G_GNUC_CONST;
+GType mt_listener_get_type (void) G_GNUC_CONST;
+MtListener * mt_listener_get_default (void);
+
+void mt_listener_emit_button_event (MtListener *listener,
+ MtEventType type,
+ gint button,
+ gint x,
+ gint y);
+
+void mt_listener_emit_motion_event (MtListener *listener,
+ gint x,
+ gint y);
+
+void mt_listener_query_pointer (MtListener *listener,
+ gint *x,
+ gint *y);
+
+void mt_listener_send_event (MtListener *listener,
+ gint button,
+ MtSendType type);
+
+G_END_DECLS
+
+#endif /* __MT_LISTENER_H__ */
diff --git a/src/mt_listener_atspi.c b/src/mt_listener_atspi.c
new file mode 100644
index 0000000..c7a8526
--- /dev/null
+++ b/src/mt_listener_atspi.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2013, Gerd Kohlberger <gerdko gmail com>
+ *
+ * This file is part of Mousetweaks.
+ *
+ * Mousetweaks is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mousetweaks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <atspi/atspi.h>
+
+#include "mt_listener_atspi.h"
+
+typedef struct
+{
+ AtspiEventListener *motion;
+ AtspiEventListener *button;
+ gint x;
+ gint y;
+} MtListenerAtspiPrivate;
+
+struct _MtListenerAtspi
+{
+ MtListener parent;
+ MtListenerAtspiPrivate *priv;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (MtListenerAtspi, mt_listener_atspi, MT_TYPE_LISTENER)
+
+static void
+atspi_motion_event (const AtspiEvent *event,
+ MtListenerAtspi *listener)
+{
+ listener->priv->x = event->detail1;
+ listener->priv->y = event->detail2;
+
+ mt_listener_emit_motion_event (MT_LISTENER (listener),
+ listener->priv->x,
+ listener->priv->y);
+}
+
+static void
+atspi_button_event (const AtspiEvent *event,
+ MtListenerAtspi *listener)
+{
+ if (strlen (event->type) != 15)
+ return;
+
+ listener->priv->x = event->detail1;
+ listener->priv->y = event->detail2;
+
+ mt_listener_emit_button_event (MT_LISTENER (listener),
+ *(event->type + 14) == 'p' ? MT_EVENT_BUTTON_PRESS :
+ MT_EVENT_BUTTON_RELEASE,
+ *(event->type + 13) - 0x30,
+ listener->priv->x,
+ listener->priv->y);
+}
+
+static void
+mt_listener_atspi_init (MtListenerAtspi *listener)
+{
+ GError *error = NULL;
+
+ listener->priv = mt_listener_atspi_get_instance_private (listener);
+
+ atspi_init ();
+
+ listener->priv->motion = atspi_event_listener_new
+ ((AtspiEventListenerCB) atspi_motion_event, listener, NULL);
+
+ atspi_event_listener_register (listener->priv->motion, "mouse:abs", &error);
+ if (error)
+ {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ }
+
+ listener->priv->button = atspi_event_listener_new
+ ((AtspiEventListenerCB) atspi_button_event, listener, NULL);
+
+ atspi_event_listener_register (listener->priv->button, "mouse:button", &error);
+ if (error)
+ {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+mt_listener_atspi_dispose (GObject *object)
+{
+ MtListenerAtspiPrivate *priv = MT_LISTENER_ATSPI (object)->priv;
+
+ if (priv->motion)
+ {
+ atspi_event_listener_deregister (priv->motion, "mouse:abs", NULL);
+ g_clear_object (&priv->motion);
+ }
+
+ if (priv->button)
+ {
+ atspi_event_listener_deregister (priv->button, "mouse:button", NULL);
+ g_clear_object (&priv->motion);
+ }
+
+ G_OBJECT_CLASS (mt_listener_atspi_parent_class)->dispose (object);
+}
+
+static void
+mt_listener_atspi_finalize (GObject *object)
+{
+ gint leaks;
+
+ if ((leaks = atspi_exit ()))
+ g_warning ("AT-SPI reported %i leaks.", leaks);
+
+ G_OBJECT_CLASS (mt_listener_atspi_parent_class)->finalize (object);
+}
+
+static void
+mt_listener_atspi_query_pointer (MtListener *listener,
+ gint *x,
+ gint *y)
+{
+ MtListenerAtspiPrivate *priv = MT_LISTENER_ATSPI (listener)->priv;
+
+ if (x)
+ *x = priv->x;
+
+ if (y)
+ *y = priv->y;
+}
+
+static void
+mt_listener_atspi_send_event (MtListener *listener,
+ gint button,
+ MtSendType type)
+{
+ MtListenerAtspiPrivate *priv = MT_LISTENER_ATSPI (listener)->priv;
+ GError *error = NULL;
+ gchar name[4] = { 'b', '1', 'c', '\0' };
+
+ g_return_if_fail (button >= 1 && button <= 3);
+
+ switch (type)
+ {
+ case MT_SEND_CLICK:
+ name[2] = 'c';
+ break;
+ case MT_SEND_BUTTON_PRESS:
+ name[2] = 'p';
+ break;
+ case MT_SEND_BUTTON_RELEASE:
+ name[2] = 'r';
+ break;
+ default:
+ g_warning ("Unknown SendType.");
+ return;
+ }
+
+ name[1] = (gchar) button + 0x30;
+
+ atspi_generate_mouse_event (priv->x, priv->y, name, &error);
+
+ if (error)
+ {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+mt_listener_atspi_class_init (MtListenerAtspiClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MtListenerClass *listener_class = MT_LISTENER_CLASS (klass);
+
+ object_class->dispose = mt_listener_atspi_dispose;
+ object_class->finalize = mt_listener_atspi_finalize;
+
+ listener_class->query_pointer = mt_listener_atspi_query_pointer;
+ listener_class->send_event = mt_listener_atspi_send_event;
+}
+
+MtListener *
+mt_listener_atspi_new (void)
+{
+ return g_object_new (MT_TYPE_LISTENER_ATSPI, NULL);
+}
diff --git a/src/mt-ctw.h b/src/mt_listener_atspi.h
similarity index 51%
copy from src/mt-ctw.h
copy to src/mt_listener_atspi.h
index 027a849..da8cfd9 100644
--- a/src/mt-ctw.h
+++ b/src/mt_listener_atspi.h
@@ -1,5 +1,5 @@
/*
- * Copyright © 2007-2010 Gerd Kohlberger <gerdko gmail com>
+ * Copyright 2013, Gerd Kohlberger <gerdko gmail com>
*
* This file is part of Mousetweaks.
*
@@ -17,21 +17,27 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef __MT_CTW_H__
-#define __MT_CTW_H__
+#ifndef __MT_LISTENER_ATSPI_H__
+#define __MT_LISTENER_ATSPI_H__
-#include <gtk/gtk.h>
+#include "mt_listener.h"
G_BEGIN_DECLS
-gboolean mt_ctw_init (void);
+#define MT_TYPE_LISTENER_ATSPI (mt_listener_atspi_get_type ())
+#define MT_LISTENER_ATSPI(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MT_TYPE_LISTENER_ATSPI, MtListenerAtspi))
+#define MT_IS_LISTENER_ATSPI(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MT_TYPE_LISTENER_ATSPI))
-void mt_ctw_fini (void);
+typedef struct _MtListenerAtspi MtListenerAtspi;
-GtkWidget * mt_ctw_get_window (void);
+typedef struct
+{
+ MtListenerClass parent;
+} MtListenerAtspiClass;
-void mt_ctw_save_geometry (void);
+GType mt_listener_atspi_get_type (void) G_GNUC_CONST;
+MtListener * mt_listener_atspi_new (void);
G_END_DECLS
-#endif /* __MT_CTW_H__ */
+#endif /* __MT_LISTENER_ATSPI_H__ */
diff --git a/src/mt_secondary_click.c b/src/mt_secondary_click.c
new file mode 100644
index 0000000..0eb81fc
--- /dev/null
+++ b/src/mt_secondary_click.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2013, Gerd Kohlberger <gerdko gmail com>
+ *
+ * This file is part of Mousetweaks.
+ *
+ * Mousetweaks is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mousetweaks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mt_secondary_click.h"
+
+typedef struct
+{
+ gint x;
+ gint y;
+ guint activate : 1;
+} MtSecondaryClickPrivate;
+
+struct _MtSecondaryClick
+{
+ MtClick parent;
+ MtSecondaryClickPrivate *priv;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (MtSecondaryClick, mt_secondary_click, MT_TYPE_CLICK)
+
+static void
+mt_secondary_click_init (MtSecondaryClick *click)
+{
+ click->priv = mt_secondary_click_get_instance_private (click);
+}
+
+static void
+mt_secondary_click_timer_finished (MtClick *click,
+ MtTimer *timer,
+ MtListener *listener)
+{
+ MtSecondaryClickPrivate *priv = MT_SECONDARY_CLICK (click)->priv;
+
+ priv->activate = TRUE;
+}
+
+static void
+mt_secondary_click_motion_event (MtClick *click,
+ MtListener *listener,
+ MtEvent *event,
+ MtTimer *timer)
+{
+ MtSecondaryClickPrivate *priv = MT_SECONDARY_CLICK (click)->priv;
+ gint t;
+
+ if (!mt_timer_is_running (timer))
+ return;
+
+ g_object_get (click, "threshold", &t, NULL);
+
+ if (ABS (priv->x - event->x) > t || ABS (priv->y - event->y) > t)
+ {
+ mt_timer_stop (timer);
+ priv->activate = FALSE;
+ }
+}
+
+static void
+mt_secondary_click_button_event (MtClick *click,
+ MtListener *listener,
+ MtEvent *event,
+ MtTimer *timer)
+{
+ MtSecondaryClickPrivate *priv = MT_SECONDARY_CLICK (click)->priv;
+
+ if (event->button != 1)
+ return;
+
+ if (event->type == MT_EVENT_BUTTON_PRESS)
+ {
+ priv->x = event->x;
+ priv->y = event->y;
+ mt_timer_start (timer);
+ }
+ else
+ {
+ mt_timer_stop (timer);
+ if (priv->activate)
+ {
+ mt_listener_send_event (listener, 3, MT_SEND_CLICK);
+ priv->activate = FALSE;
+ }
+ }
+}
+
+static void
+mt_secondary_click_class_init (MtSecondaryClickClass *klass)
+{
+ MtClickClass *click_class = MT_CLICK_CLASS (klass);
+
+ click_class->button_event = mt_secondary_click_button_event;
+ click_class->motion_event = mt_secondary_click_motion_event;
+ click_class->timer_finished = mt_secondary_click_timer_finished;
+}
+
+MtSecondaryClick *
+mt_secondary_click_new (void)
+{
+ MtSecondaryClick *click;
+ const gint default_threshold = 10;
+
+ click = g_object_new (MT_TYPE_SECONDARY_CLICK, NULL);
+
+ mt_click_bind_setting (MT_CLICK (click), "enabled", "secondary-click-enabled");
+ mt_click_bind_setting (MT_CLICK (click), "time", "secondary-click-time");
+ g_object_set (click, "threshold", default_threshold, NULL);
+
+ return click;
+}
diff --git a/src/mt-ctw.h b/src/mt_secondary_click.h
similarity index 51%
rename from src/mt-ctw.h
rename to src/mt_secondary_click.h
index 027a849..21695ef 100644
--- a/src/mt-ctw.h
+++ b/src/mt_secondary_click.h
@@ -1,5 +1,5 @@
/*
- * Copyright © 2007-2010 Gerd Kohlberger <gerdko gmail com>
+ * Copyright 2013, Gerd Kohlberger <gerdko gmail com>
*
* This file is part of Mousetweaks.
*
@@ -17,21 +17,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef __MT_CTW_H__
-#define __MT_CTW_H__
+#ifndef __MT_SECONDARY_CLICK_H__
+#define __MT_SECONDARY_CLICK_H__
-#include <gtk/gtk.h>
+#include "mt_click.h"
G_BEGIN_DECLS
-gboolean mt_ctw_init (void);
+#define MT_TYPE_SECONDARY_CLICK (mt_secondary_click_get_type ())
+#define MT_SECONDARY_CLICK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MT_TYPE_SECONDARY_CLICK,
MtSecondaryClick))
+#define MT_IS_SECONDARY_CLICK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MT_TYPE_SECONDARY_CLICK))
-void mt_ctw_fini (void);
+typedef MtClickClass MtSecondaryClickClass;
+typedef struct _MtSecondaryClick MtSecondaryClick;
-GtkWidget * mt_ctw_get_window (void);
-
-void mt_ctw_save_geometry (void);
+GType mt_secondary_click_get_type (void) G_GNUC_CONST;
+MtSecondaryClick * mt_secondary_click_new (void);
G_END_DECLS
-#endif /* __MT_CTW_H__ */
+#endif /* __MT_SECONDARY_CLICK_H__ */
diff --git a/src/mt-timer.c b/src/mt_timer.c
similarity index 53%
rename from src/mt-timer.c
rename to src/mt_timer.c
index 8c68154..fedfa1c 100644
--- a/src/mt-timer.c
+++ b/src/mt_timer.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2007-2010 Gerd Kohlberger <gerdko gmail com>
+ * Copyright 2013, Gerd Kohlberger <gerdko gmail com>
*
* This file is part of Mousetweaks.
*
@@ -17,23 +17,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <glib.h>
+#include "mt_timer.h"
-#include "mt-timer.h"
-
-#define DEFAULT_TARGET_TIME 1.2f
-
-struct _MtTimerPrivate
+typedef struct
{
- GTimer *timer;
- guint tid;
- gdouble elapsed;
+ guint id;
+ gint64 stamp;
gdouble target;
+} MtTimerPrivate;
+
+struct _MtTimer
+{
+ GObject parent;
+ MtTimerPrivate *priv;
};
enum
{
- TICK,
FINISHED,
LAST_SIGNAL
};
@@ -41,21 +41,17 @@ enum
enum
{
PROP_0,
- PROP_TARGET_TIME
+ PROP_TARGET
};
static guint signals[LAST_SIGNAL] = { 0, };
-G_DEFINE_TYPE (MtTimer, mt_timer, G_TYPE_OBJECT)
+G_DEFINE_TYPE_WITH_PRIVATE (MtTimer, mt_timer, G_TYPE_OBJECT)
static void
mt_timer_init (MtTimer *timer)
{
- timer->priv = G_TYPE_INSTANCE_GET_PRIVATE (timer,
- MT_TYPE_TIMER,
- MtTimerPrivate);
- timer->priv->timer = g_timer_new ();
- timer->priv->target = DEFAULT_TARGET_TIME;
+ timer->priv = mt_timer_get_instance_private (timer);
}
static void
@@ -68,7 +64,7 @@ mt_timer_get_property (GObject *object,
switch (prop_id)
{
- case PROP_TARGET_TIME:
+ case PROP_TARGET:
g_value_set_double (value, timer->priv->target);
break;
default:
@@ -86,8 +82,9 @@ mt_timer_set_property (GObject *object,
switch (prop_id)
{
- case PROP_TARGET_TIME:
+ case PROP_TARGET:
timer->priv->target = g_value_get_double (value);
+ g_object_notify (object, pspec->name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -97,12 +94,7 @@ mt_timer_set_property (GObject *object,
static void
mt_timer_finalize (GObject *object)
{
- MtTimer *timer = MT_TIMER (object);
-
- if (timer->priv->tid)
- g_source_remove (timer->priv->tid);
-
- g_timer_destroy (timer->priv->timer);
+ mt_timer_stop (MT_TIMER (object));
G_OBJECT_CLASS (mt_timer_parent_class)->finalize (object);
}
@@ -110,56 +102,42 @@ mt_timer_finalize (GObject *object)
static void
mt_timer_class_init (MtTimerClass *klass)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GObjectClass *object_class;
+ object_class = G_OBJECT_CLASS (klass);
object_class->get_property = mt_timer_get_property;
object_class->set_property = mt_timer_set_property;
object_class->finalize = mt_timer_finalize;
- signals[TICK] =
- g_signal_new (g_intern_static_string ("tick"),
- G_OBJECT_CLASS_TYPE (klass),
- G_SIGNAL_RUN_LAST,
- 0, NULL, NULL,
- g_cclosure_marshal_VOID__DOUBLE,
- G_TYPE_NONE, 1, G_TYPE_DOUBLE);
-
signals[FINISHED] =
- g_signal_new (g_intern_static_string ("finished"),
+ g_signal_new ("finished",
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
- g_object_class_install_property (object_class, PROP_TARGET_TIME,
- g_param_spec_double ("target-time", "Target time",
+ g_object_class_install_property (object_class, PROP_TARGET,
+ g_param_spec_double ("target", "Target time",
"Target time of the timer",
- 0.1, 3.0, DEFAULT_TARGET_TIME,
+ 0.1, 3.0, 0.1,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_type_class_add_private (klass, sizeof (MtTimerPrivate));
}
static gboolean
-mt_timer_check_time (gpointer data)
+mt_timer_check (MtTimer *timer)
{
- MtTimer *timer = data;
- MtTimerPrivate *priv = timer->priv;
+ gdouble elapsed;
- priv->elapsed = g_timer_elapsed (priv->timer, NULL);
- g_signal_emit (timer, signals[TICK], 0, priv->elapsed);
+ elapsed = (gdouble) (g_get_monotonic_time () - timer->priv->stamp) / 1e6;
- if (priv->elapsed >= priv->target)
+ if (elapsed > timer->priv->target)
{
- priv->tid = 0;
- priv->elapsed = 0.0;
+ timer->priv->id = 0;
g_signal_emit (timer, signals[FINISHED], 0);
-
- return FALSE;
+ return G_SOURCE_REMOVE;
}
-
- return TRUE;
+ return G_SOURCE_CONTINUE;
}
MtTimer *
@@ -173,10 +151,10 @@ mt_timer_start (MtTimer *timer)
{
g_return_if_fail (MT_IS_TIMER (timer));
- g_timer_start (timer->priv->timer);
+ if (timer->priv->id == 0)
+ timer->priv->id = g_timeout_add (100, (GSourceFunc) mt_timer_check, timer);
- if (timer->priv->tid == 0)
- timer->priv->tid = g_timeout_add (100, mt_timer_check_time, timer);
+ timer->priv->stamp = g_get_monotonic_time ();
}
void
@@ -184,10 +162,10 @@ mt_timer_stop (MtTimer *timer)
{
g_return_if_fail (MT_IS_TIMER (timer));
- if (timer->priv->tid)
+ if (timer->priv->id)
{
- g_source_remove (timer->priv->tid);
- timer->priv->tid = 0;
+ g_source_remove (timer->priv->id);
+ timer->priv->id = 0;
}
}
@@ -196,31 +174,5 @@ mt_timer_is_running (MtTimer *timer)
{
g_return_val_if_fail (MT_IS_TIMER (timer), FALSE);
- return timer->priv->tid != 0;
-}
-
-gdouble
-mt_timer_elapsed (MtTimer *timer)
-{
- g_return_val_if_fail (MT_IS_TIMER (timer), 0.0);
-
- return timer->priv->elapsed;
-}
-
-gdouble
-mt_timer_get_target (MtTimer *timer)
-{
- g_return_val_if_fail (MT_IS_TIMER (timer), 0.0);
-
- return timer->priv->target;
-}
-
-void
-mt_timer_set_target (MtTimer *timer, gdouble target)
-{
- g_return_if_fail (MT_IS_TIMER (timer));
- g_return_if_fail (target >= 0.1);
-
- timer->priv->target = target;
- g_object_notify (G_OBJECT (timer), "target-time");
+ return timer->priv->id != 0;
}
diff --git a/src/mt-timer.h b/src/mt_timer.h
similarity index 57%
rename from src/mt-timer.h
rename to src/mt_timer.h
index 6abfc61..0ca69ba 100644
--- a/src/mt-timer.h
+++ b/src/mt_timer.h
@@ -1,5 +1,5 @@
/*
- * Copyright © 2007-2010 Gerd Kohlberger <gerdko gmail com>
+ * Copyright 2013, Gerd Kohlberger <gerdko gmail com>
*
* This file is part of Mousetweaks.
*
@@ -28,28 +28,14 @@ G_BEGIN_DECLS
#define MT_TIMER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MT_TYPE_TIMER, MtTimer))
#define MT_IS_TIMER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MT_TYPE_TIMER))
-typedef GObjectClass MtTimerClass;
-typedef struct _MtTimer MtTimer;
-typedef struct _MtTimerPrivate MtTimerPrivate;
+typedef GObjectClass MtTimerClass;
+typedef struct _MtTimer MtTimer;
-struct _MtTimer
-{
- GObject parent;
- MtTimerPrivate *priv;
-};
-
-GType mt_timer_get_type (void) G_GNUC_CONST;
-
-MtTimer * mt_timer_new (void);
-
-void mt_timer_start (MtTimer *timer);
-void mt_timer_stop (MtTimer *timer);
-gboolean mt_timer_is_running (MtTimer *timer);
-
-gdouble mt_timer_elapsed (MtTimer *timer);
-gdouble mt_timer_get_target (MtTimer *timer);
-void mt_timer_set_target (MtTimer *timer,
- gdouble target);
+GType mt_timer_get_type (void) G_GNUC_CONST;
+MtTimer * mt_timer_new (void);
+void mt_timer_start (MtTimer *timer);
+void mt_timer_stop (MtTimer *timer);
+gboolean mt_timer_is_running (MtTimer *timer);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]