diff options
Diffstat (limited to 'khotkeys/shared')
31 files changed, 6941 insertions, 0 deletions
diff --git a/khotkeys/shared/Makefile.am b/khotkeys/shared/Makefile.am new file mode 100644 index 000000000..4e20f6083 --- /dev/null +++ b/khotkeys/shared/Makefile.am @@ -0,0 +1,15 @@ +lib_LTLIBRARIES = libkhotkeys_shared.la + +libkhotkeys_shared_la_SOURCES = action_data.cpp khotkeysglobal.cpp triggers.cpp windows.cpp \ + settings.cpp actions.cpp input.cpp conditions.cpp khlistview.cpp khlistbox.cpp \ + gestures.cpp voices.cpp voicesignature.cpp sound.cpp soundrecorder.cpp +libkhotkeys_shared_la_LIBADD = $(LIB_KIO) $(XTESTLIB) -lXext -lX11 $(X_PRE_LIBS) +libkhotkeys_shared_la_LDFLAGS = $(all_libraries) $(X_LDFLAGS) -version-info 1:0:0 -no-undefined + +INCLUDES = $(all_includes) + +noinst_HEADERS = action_data.h khotkeysglobal.h triggers.h windows.h actions.h input.h \ + settings.h conditions.h khlistview.h khlistbox.h gestures.h voices.h \ + voicesignature.h sound.h soundrecorder.h + +METASOURCES = AUTO diff --git a/khotkeys/shared/action_data.cpp b/khotkeys/shared/action_data.cpp new file mode 100644 index 000000000..96e3e5559 --- /dev/null +++ b/khotkeys/shared/action_data.cpp @@ -0,0 +1,378 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#define _ACTION_DATA_CPP_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "action_data.h" + +#include <kconfig.h> + +#include "actions.h" + +namespace KHotKeys +{ + +// Action_data_base + +Action_data_base::Action_data_base( Action_data_group* parent_P, const QString& name_P, + const QString& comment_P, Condition_list* conditions_P, bool enabled_P ) + : _parent( parent_P ), _conditions( conditions_P ), _name( name_P ), _comment( comment_P ), + _enabled( enabled_P ) + { + if( parent()) + parent()->add_child( this ); + if( _conditions != NULL ) + _conditions->set_data( this ); + } + +Action_data_base::Action_data_base( KConfig& cfg_P, Action_data_group* parent_P ) + : _parent( parent_P ) + { + QString save_cfg_group = cfg_P.group(); + _name = cfg_P.readEntry( "Name" ); + _comment = cfg_P.readEntry( "Comment" ); + _enabled = cfg_P.readBoolEntry( "Enabled", true ); + cfg_P.setGroup( save_cfg_group + "Conditions" ); + _conditions = new Condition_list( cfg_P, this ); + cfg_P.setGroup( save_cfg_group ); + if( parent()) + parent()->add_child( this ); + } + +Action_data_base::~Action_data_base() + { +// kdDebug( 1217 ) << "~Action_data_base() :" << this << endl; + if( parent()) + parent()->remove_child( this ); + delete _conditions; + } + +void Action_data_base::cfg_write( KConfig& cfg_P ) const + { + cfg_P.writeEntry( "Type", "ERROR" ); // derived classes should call with their type + cfg_P.writeEntry( "Name", name()); + cfg_P.writeEntry( "Comment", comment()); + cfg_P.writeEntry( "Enabled", enabled( true )); + QString save_cfg_group = cfg_P.group(); + cfg_P.setGroup( save_cfg_group + "Conditions" ); + assert( conditions() != NULL ); + conditions()->cfg_write( cfg_P ); + cfg_P.setGroup( save_cfg_group ); + } + + +Action_data_base* Action_data_base::create_cfg_read( KConfig& cfg_P, Action_data_group* parent_P ) + { + QString type = cfg_P.readEntry( "Type" ); + if( type == "ACTION_DATA_GROUP" ) + { + if( cfg_P.readBoolEntry( "AllowMerge", false )) + { + for( Action_data_group::Iterator it = parent_P->first_child(); + it; + ++it ) + { + if( Action_data_group* existing = dynamic_cast< Action_data_group* >( *it )) + { + if( cfg_P.readEntry( "Name" ) == existing->name()) + return existing; + } + } + } + return new Action_data_group( cfg_P, parent_P ); + } + if( type == "GENERIC_ACTION_DATA" ) + return new Generic_action_data( cfg_P, parent_P ); + if( type == "COMMAND_URL_SHORTCUT_ACTION_DATA" ) + return new Command_url_shortcut_action_data( cfg_P, parent_P ); + if( type == "MENUENTRY_SHORTCUT_ACTION_DATA" ) + return new Menuentry_shortcut_action_data( cfg_P, parent_P ); + if( type == "DCOP_SHORTCUT_ACTION_DATA" ) + return new Dcop_shortcut_action_data( cfg_P, parent_P ); + if( type == "KEYBOARD_INPUT_SHORTCUT_ACTION_DATA" ) + return new Keyboard_input_shortcut_action_data( cfg_P, parent_P ); + if( type == "KEYBOARD_INPUT_GESTURE_ACTION_DATA" ) + return new Keyboard_input_gesture_action_data( cfg_P, parent_P ); + if( type == "ACTIVATE_WINDOW_SHORTCUT_ACTION_DATA" ) + return new Activate_window_shortcut_action_data( cfg_P, parent_P ); + kdWarning( 1217 ) << "Unknown Action_data_base type read from cfg file\n"; + return NULL; + } + +bool Action_data_base::cfg_is_enabled( KConfig& cfg_P ) + { + return cfg_P.readBoolEntry( "Enabled", true ); + } + +void Action_data_base::reparent( Action_data_group* new_parent_P ) + { + if( parent()) + parent()->remove_child( this ); + _parent = new_parent_P; + if( parent()) + parent()->add_child( this ); + } + +bool Action_data_base::enabled( bool ignore_group_P ) const + { + if( ignore_group_P ) + return _enabled; + else + return _enabled && ( parent() == NULL || parent()->enabled( false )); + } + +bool Action_data_base::conditions_match() const + { + return ( conditions() ? conditions()->match() : true ) + && ( parent() ? parent()->conditions_match() : true ); + } + +// Action_data_group + +Action_data_group::Action_data_group( KConfig& cfg_P, Action_data_group* parent_P ) + : Action_data_base( cfg_P, parent_P ) + { + unsigned int system_group_tmp = cfg_P.readUnsignedNumEntry( "SystemGroup", 0 ); + if( system_group_tmp >= SYSTEM_MAX ) + system_group_tmp = 0; + _system_group = static_cast< system_group_t >( system_group_tmp ); + } + +void Action_data_group::cfg_write( KConfig& cfg_P ) const + { + Action_data_base::cfg_write( cfg_P ); + cfg_P.writeEntry( "SystemGroup", system_group()); + cfg_P.writeEntry( "Type", "ACTION_DATA_GROUP" ); + } + +void Action_data_group::update_triggers() + { + for( Action_data_group::Iterator it = first_child(); + it; + ++it ) + ( *it )->update_triggers(); + } + +// Action_data + +Action_data::Action_data( KConfig& cfg_P, Action_data_group* parent_P ) + : Action_data_base( cfg_P, parent_P ) + { + QString save_cfg_group = cfg_P.group(); + cfg_P.setGroup( save_cfg_group + "Triggers" ); + _triggers = new Trigger_list( cfg_P, this ); + cfg_P.setGroup( save_cfg_group + "Actions" ); + _actions = new Action_list( cfg_P, this ); + cfg_P.setGroup( save_cfg_group ); + } + +Action_data::~Action_data() + { +// kdDebug( 1217 ) << "~Action_data" << this << endl; + delete _triggers; + delete _actions; + // CHECKME jeste remove z parenta ? + } + +void Action_data::cfg_write( KConfig& cfg_P ) const + { + Action_data_base::cfg_write( cfg_P ); + QString save_cfg_group = cfg_P.group(); + cfg_P.setGroup( save_cfg_group + "Triggers" ); + triggers()->cfg_write( cfg_P ); + cfg_P.setGroup( save_cfg_group + "Actions" ); + actions()->cfg_write( cfg_P ); + cfg_P.setGroup( save_cfg_group ); + } + +void Action_data::execute() + { + for( Action_list::Iterator it( *_actions ); + it; + ++it ) + it.current()->execute(); +// CHECKME nebo nejak zpozdeni ? + } + +void Action_data::add_trigger( Trigger* trigger_P ) + { + _triggers->append( trigger_P ); + } + +void Action_data::add_triggers( Trigger_list* triggers_P ) + { + for( Trigger_list::Iterator it = *triggers_P; + it; + ++it ) + _triggers->append( *it ); + triggers_P->setAutoDelete( false ); + delete triggers_P; + } + +void Action_data::set_triggers( Trigger_list* triggers_P ) + { + assert( _triggers == NULL ); + _triggers = triggers_P; + } + +void Action_data::add_action( Action* action_P, Action* after_P ) + { + int index = 0; + for( Action_list::Iterator it = *_actions; + it; + ++it ) + { + ++index; + if( *it == after_P ) + break; + } + _actions->insert( index, action_P ); + } + +void Action_data::add_actions( Action_list* actions_P, Action* after_P ) + { + int index = 0; + for( Action_list::Iterator it = *_actions; + it; + ++it ) + { + ++index; + if( *it == after_P ) + break; + } + for( Action_list::Iterator it = *actions_P; + it; + ++it ) + _actions->insert( index++, *it ); + actions_P->setAutoDelete( false ); + delete actions_P; + } + +void Action_data::set_actions( Action_list* actions_P ) + { + assert( _actions == NULL ); + _actions = actions_P; + } + +void Action_data::update_triggers() + { + bool activate = conditions_match() && enabled( false ); + kdDebug( 1217 ) << "Update triggers: " << name() << ":" << activate << endl; + for( Trigger_list::Iterator it = ( *triggers()); + it; + ++it ) + ( *it )->activate( activate ); + } + +// Generic_action_data + +void Generic_action_data::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Type", "GENERIC_ACTION_DATA" ); + } + +// Command_url_shortcut_action_data + +Command_url_shortcut_action_data::Command_url_shortcut_action_data( Action_data_group* parent_P, + const QString& name_P, const QString& comment_P, + const KShortcut& shortcut_P, const QString& command_url_P, bool enabled_P ) + : Simple_action_data< Shortcut_trigger, Command_url_action >( parent_P, name_P, + comment_P, enabled_P ) + { + set_action( new Command_url_action( this, command_url_P )); + set_trigger( new Shortcut_trigger( this, shortcut_P )); + } + +template<> KDE_EXPORT +void Simple_action_data< Shortcut_trigger, Command_url_action > + ::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Type", "COMMAND_URL_SHORTCUT_ACTION_DATA" ); + } + +// Menuentry_shortcut_action_data + +Menuentry_shortcut_action_data::Menuentry_shortcut_action_data( Action_data_group* parent_P, + const QString& name_P, const QString& comment_P, + const KShortcut& shortcut_P, const QString& menuentry_P, bool enabled_P ) + : Simple_action_data< Shortcut_trigger, Menuentry_action >( parent_P, name_P, + comment_P, enabled_P ) + { + set_action( new Menuentry_action( this, menuentry_P )); + set_trigger( new Shortcut_trigger( this, shortcut_P )); + } + +template<> KDE_EXPORT +void Simple_action_data< Shortcut_trigger, Menuentry_action > + ::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Type", "MENUENTRY_SHORTCUT_ACTION_DATA" ); + } + +// Dcop_shortcut_action_data + +template<> KDE_EXPORT +void Simple_action_data< Shortcut_trigger, Dcop_action > + ::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Type", "DCOP_SHORTCUT_ACTION_DATA" ); + } + +// Keyboard_input_shortcut_action_data + +template<> KDE_EXPORT +void Simple_action_data< Shortcut_trigger, Keyboard_input_action > + ::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Type", "KEYBOARD_INPUT_SHORTCUT_ACTION_DATA" ); + } + +// Activate_window_shortcut_action_data + +template<> KDE_EXPORT +void Simple_action_data< Shortcut_trigger, Activate_window_action > + ::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Type", "ACTIVATE_WINDOW_SHORTCUT_ACTION_DATA" ); + } + +// Keyboard_input_gesture_action_data + +void Keyboard_input_gesture_action_data::set_action( Keyboard_input_action* action_P ) + { + Action_list* tmp = new Action_list( "Keyboard_input_gesture_action_data" ); + tmp->append( action_P ); + set_actions( tmp ); + } + +const Keyboard_input_action* Keyboard_input_gesture_action_data::action() const + { + if( actions() == NULL ) // CHECKME tohle poradne zkontrolovat + return NULL; + return static_cast< Keyboard_input_action* >( const_cast< Action_list* >( actions())->first()); + } + +void Keyboard_input_gesture_action_data::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Type", "KEYBOARD_INPUT_GESTURE_ACTION_DATA" ); + } + +} // namespace KHotKeys diff --git a/khotkeys/shared/action_data.h b/khotkeys/shared/action_data.h new file mode 100644 index 000000000..9d6018c2c --- /dev/null +++ b/khotkeys/shared/action_data.h @@ -0,0 +1,446 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#ifndef _ACTION_DATA_H_ +#define _ACTION_DATA_H_ + +#include <assert.h> +#include <qstring.h> +#include <qptrlist.h> + +#include <kdebug.h> + +class KConfig; + +#include "khotkeysglobal.h" + +#include "windows.h" +#include "conditions.h" +#include "triggers.h" +#include "actions.h" + +namespace KHotKeys +{ + +class Action_data_group; + +class KDE_EXPORT Action_data_base + { + public: + Action_data_base( Action_data_group* parent_P, const QString& name_P, + const QString& comment_P, Condition_list* condition_P, bool enabled_P ); + Action_data_base( KConfig& cfg_P, Action_data_group* parent_P ); + virtual ~Action_data_base(); + virtual void cfg_write( KConfig& cfg_P ) const = 0; + const Condition_list* conditions() const; + Action_data_group* parent() const; + void reparent( Action_data_group* new_parent_P ); + virtual void update_triggers() = 0; + bool conditions_match() const; + const QString& name() const; + void set_name( const QString& name_P ); + const QString& comment() const; + bool enabled( bool ignore_group_P ) const; + static Action_data_base* create_cfg_read( KConfig& cfg_P, Action_data_group* parent_P ); + static bool cfg_is_enabled( KConfig& cfg_P ); + protected: + void set_conditions( Condition_list* conditions_P ); + private: + Action_data_group* _parent; + Condition_list* _conditions; + QString _name; + QString _comment; + bool _enabled; // is not really important, only used in conf. module and when reading cfg. file + KHOTKEYS_DISABLE_COPY( Action_data_base ); + }; + +class KDE_EXPORT Action_data_group + : public Action_data_base + { + public: + enum system_group_t { SYSTEM_NONE, SYSTEM_MENUENTRIES, + SYSTEM_ROOT, /* last one*/ SYSTEM_MAX }; // don't remove entries + Action_data_group( Action_data_group* parent_P, const QString& name_P, + const QString& comment_P, Condition_list* conditions_P, system_group_t system_group_P, + bool enabled_P ); + Action_data_group( KConfig& cfg_P, Action_data_group* parent_P ); + virtual ~Action_data_group(); + virtual void update_triggers(); + virtual void cfg_write( KConfig& cfg_P ) const; + typedef QPtrListIterator< Action_data_base > Iterator; // CHECKME neni const :( + Iterator first_child() const; + bool is_system_group() const; + system_group_t system_group() const; + using Action_data_base::set_conditions; // make public + protected: + QPtrList< Action_data_base > list; + system_group_t _system_group; // e.g. menuedit entries, can't be deleted or renamed + friend class Action_data_base; // CHECKME + void add_child( Action_data_base* child_P ); + void remove_child( Action_data_base* child_P ); + }; + +// this one represents a "whole" action, i.e. triggers, resulting actions, etc. +class KDE_EXPORT Action_data + : public Action_data_base + { + typedef Action_data_base base; + public: + Action_data( Action_data_group* parent_P, const QString& name_P, + const QString& comment_P, Trigger_list* triggers_P, Condition_list* conditions_P, + Action_list* actions_P, bool enabled_P = true ); + Action_data( KConfig& cfg_P, Action_data_group* parent_P ); + virtual ~Action_data(); + virtual void update_triggers(); + virtual void cfg_write( KConfig& cfg_P ) const = 0; + virtual void execute(); + const Trigger_list* triggers() const; + const Action_list* actions() const; + protected: + virtual void add_trigger( Trigger* trigger_P ); + virtual void add_triggers( + Trigger_list* triggers_P ); // Trigger_list instance will be deleted + virtual void set_triggers( Trigger_list* triggers_P ); + virtual void add_action( Action* action_P, Action* after_P = NULL ); + virtual void add_actions( Action_list* actions_P, + Action* after_P = NULL ); // Action_list will be deleted + virtual void set_actions( Action_list* actions_P ); + private: + Trigger_list* _triggers; + Action_list* _actions; +#if 0 + action_type_t _type; + static const char* const types[]; +#endif + }; + +class KDE_EXPORT Generic_action_data + : public Action_data + { + typedef Action_data base; + public: + Generic_action_data( Action_data_group* parent_P, const QString& name_P, + const QString& comment_P, Trigger_list* triggers_P, Condition_list* conditions_P, + Action_list* actions_P, bool enabled_P = true ); + Generic_action_data( KConfig& cfg_P, Action_data_group* parent_P ); + virtual void cfg_write( KConfig& cfg_P ) const; + using Action_data_base::set_conditions; // make public + using Action_data::add_trigger; // make public + using Action_data::add_triggers; // make public + using Action_data::set_triggers; // make public + using Action_data::add_action; // make public + using Action_data::add_actions; // make public + using Action_data::set_actions; // make public + }; + +template< typename T, typename A > +class KDE_EXPORT Simple_action_data + : public Action_data + { + typedef Action_data base; + public: + Simple_action_data( Action_data_group* parent_P, const QString& name_P, + const QString& comment_P, bool enabled_P = true ); + Simple_action_data( KConfig& cfg_P, Action_data_group* parent_P ); + const A* action() const; + const T* trigger() const; + // CHECKME kontrola, ze se dava jen jedna akce ? + void set_action( A* action_P ); + void set_trigger( T* trigger_P ); + virtual void cfg_write( KConfig& cfg_P ) const; + }; + +class KDE_EXPORT Command_url_shortcut_action_data + : public Simple_action_data< Shortcut_trigger, Command_url_action > + { + typedef Simple_action_data< Shortcut_trigger, Command_url_action > base; + public: + Command_url_shortcut_action_data( Action_data_group* parent_P, const QString& name_P, + const QString& comment_P, bool enabled_P = true ); + Command_url_shortcut_action_data( Action_data_group* parent_P, const QString& name_P, + const QString& comment_P, const KShortcut& shortcut_P, const QString& command_url_P, + bool enabled_P = true ); + Command_url_shortcut_action_data( KConfig& cfg_P, Action_data_group* parent_P ); + }; + +class KDE_EXPORT Menuentry_shortcut_action_data + : public Simple_action_data< Shortcut_trigger, Menuentry_action > + { + typedef Simple_action_data< Shortcut_trigger, Menuentry_action > base; + public: + Menuentry_shortcut_action_data( Action_data_group* parent_P, const QString& name_P, + const QString& comment_P, bool enabled_P = true ); + Menuentry_shortcut_action_data( Action_data_group* parent_P, const QString& name_P, + const QString& comment_P, const KShortcut& shortcut_P, const QString& command_url_P, + bool enabled_P = true ); + Menuentry_shortcut_action_data( KConfig& cfg_P, Action_data_group* parent_P ); + }; + +typedef Simple_action_data< Shortcut_trigger, Dcop_action > Dcop_shortcut_action_data; +typedef Simple_action_data< Shortcut_trigger, Keyboard_input_action > + Keyboard_input_shortcut_action_data; +typedef Simple_action_data< Shortcut_trigger, Activate_window_action > + Activate_window_shortcut_action_data; + +class KDE_EXPORT Keyboard_input_gesture_action_data + : public Action_data + { + typedef Action_data base; + public: + Keyboard_input_gesture_action_data( Action_data_group* parent_P, const QString& name_P, + const QString& comment_P, bool enabled_P = true ); + Keyboard_input_gesture_action_data( KConfig& cfg_P, Action_data_group* parent_P ); + const Keyboard_input_action* action() const; + // CHECKME kontrola, ze se dava jen jedna akce ? + void set_action( Keyboard_input_action* action_P ); + enum { NUM_TRIGGERS = 3 }; // needs changing code elsewhere + using Action_data::set_triggers; // make public // CHECKME kontrola poctu? + virtual void cfg_write( KConfig& cfg_P ) const; + }; + + +//*************************************************************************** +// Inline +//*************************************************************************** + +// Action_data_base + +inline +const Condition_list* Action_data_base::conditions() const + { +// assert( _conditions != NULL ); + return _conditions; + } + +inline +void Action_data_base::set_conditions( Condition_list* conditions_P ) + { + assert( _conditions == NULL ); + _conditions = conditions_P; + } + +inline +Action_data_group* Action_data_base::parent() const + { + return _parent; + } + +inline +void Action_data_base::set_name( const QString& name_P ) + { + _name = name_P; + } + +inline +const QString& Action_data_base::name() const + { + return _name; + } + +inline +const QString& Action_data_base::comment() const + { + return _comment; + } + +// Action_data_group + +inline +Action_data_group::Action_data_group( Action_data_group* parent_P, const QString& name_P, + const QString& comment_P, Condition_list* conditions_P, system_group_t system_group_P, + bool enabled_P ) + : Action_data_base( parent_P, name_P, comment_P, conditions_P, enabled_P ), + _system_group( system_group_P ) + { + } + +inline +Action_data_group::~Action_data_group() + { +// kdDebug( 1217 ) << "~Action_data_group() :" << list.count() << endl; + while( list.first()) + delete list.first(); + } + +inline +Action_data_group::Iterator Action_data_group::first_child() const + { + return Iterator( list ); + } + +inline +bool Action_data_group::is_system_group() const + { + return _system_group != SYSTEM_NONE; + } + +inline +Action_data_group::system_group_t Action_data_group::system_group() const + { + return _system_group; + } + +inline +void Action_data_group::add_child( Action_data_base* child_P ) + { + list.append( child_P ); // CHECKME tohle asi znemozni je mit nejak rucne serazene + } + +inline +void Action_data_group::remove_child( Action_data_base* child_P ) + { + list.removeRef( child_P ); // is not auto-delete + } + +// Action_data + +inline +Action_data::Action_data( Action_data_group* parent_P, const QString& name_P, + const QString& comment_P, Trigger_list* triggers_P, Condition_list* conditions_P, + Action_list* actions_P, bool enabled_P ) + : Action_data_base( parent_P, name_P, comment_P, conditions_P, enabled_P ), + _triggers( triggers_P ), _actions( actions_P ) + { + } + +inline +const Trigger_list* Action_data::triggers() const + { +// assert( _triggers != NULL ); + return _triggers; + } + +inline +const Action_list* Action_data::actions() const + { +// assert( _actions != NULL ); + return _actions; + } + +// Generic_action_data + +inline +Generic_action_data::Generic_action_data( Action_data_group* parent_P, const QString& name_P, + const QString& comment_P, Trigger_list* triggers_P, Condition_list* conditions_P, + Action_list* actions_P, bool enabled_P ) + : Action_data( parent_P, name_P, comment_P, triggers_P, conditions_P, actions_P, enabled_P ) + { + } + +inline +Generic_action_data::Generic_action_data( KConfig& cfg_P, Action_data_group* parent_P ) + : Action_data( cfg_P, parent_P ) + { // CHECKME do nothing ? + } + +// Simple_action_data + +template< typename T, typename A > +inline +Simple_action_data< T, A >::Simple_action_data( Action_data_group* parent_P, + const QString& name_P, const QString& comment_P, bool enabled_P ) + : Action_data( parent_P, name_P, comment_P, NULL, + new Condition_list( "", this ), NULL, enabled_P ) + { + } + +template< typename T, typename A > +inline +Simple_action_data< T, A >::Simple_action_data( KConfig& cfg_P, Action_data_group* parent_P ) + : Action_data( cfg_P, parent_P ) + { // CHECKME nothing ? + } + +template< typename T, typename A > +void Simple_action_data< T, A >::set_action( A* action_P ) + { + Action_list* tmp = new Action_list( "Simple_action_data" ); + tmp->append( action_P ); + set_actions( tmp ); + } + +template< typename T, typename A > +void Simple_action_data< T, A >::set_trigger( T* trigger_P ) + { + Trigger_list* tmp = new Trigger_list( "Simple_action" ); + tmp->append( trigger_P ); + set_triggers( tmp ); + } + +template< typename T, typename A > +const A* Simple_action_data< T, A >::action() const + { + if( actions() == NULL || actions()->count() == 0 ) // CHECKME tohle poradne zkontrolovat + return NULL; + return static_cast< A* >( const_cast< Action_list* >( actions())->first()); + } + +template< typename T, typename A > +const T* Simple_action_data< T, A >::trigger() const + { + if( triggers() == NULL || triggers()->count() == 0 ) // CHECKME tohle poradne zkontrolovat + return NULL; + return static_cast< T* >( const_cast< Trigger_list* >( triggers())->first()); + } + +// Command_url_action_data + +inline +Command_url_shortcut_action_data::Command_url_shortcut_action_data( Action_data_group* parent_P, + const QString& name_P, const QString& comment_P, bool enabled_P ) + : Simple_action_data< Shortcut_trigger, Command_url_action >( parent_P, name_P, + comment_P, enabled_P ) + { + } + +inline +Command_url_shortcut_action_data::Command_url_shortcut_action_data( KConfig& cfg_P, + Action_data_group* parent_P ) + : Simple_action_data< Shortcut_trigger, Command_url_action >( cfg_P, parent_P ) + { + } + +// Menuentry_action_data + +inline +Menuentry_shortcut_action_data::Menuentry_shortcut_action_data( Action_data_group* parent_P, + const QString& name_P, const QString& comment_P, bool enabled_P ) + : Simple_action_data< Shortcut_trigger, Menuentry_action >( parent_P, name_P, + comment_P, enabled_P ) + { + } + +inline +Menuentry_shortcut_action_data::Menuentry_shortcut_action_data( KConfig& cfg_P, + Action_data_group* parent_P ) + : Simple_action_data< Shortcut_trigger, Menuentry_action >( cfg_P, parent_P ) + { + } + +// Keyboard_input_gesture_action_data + +inline +Keyboard_input_gesture_action_data::Keyboard_input_gesture_action_data( + Action_data_group* parent_P, const QString& name_P, const QString& comment_P, bool enabled_P ) + : Action_data( parent_P, name_P, comment_P, NULL, + new Condition_list( "", this ), NULL, enabled_P ) + { + } + +inline +Keyboard_input_gesture_action_data::Keyboard_input_gesture_action_data( KConfig& cfg_P, + Action_data_group* parent_P ) + : Action_data( cfg_P, parent_P ) + { // CHECKME nothing ? + } + +} // namespace KHotKeys + +#endif diff --git a/khotkeys/shared/actions.cpp b/khotkeys/shared/actions.cpp new file mode 100644 index 000000000..144a277af --- /dev/null +++ b/khotkeys/shared/actions.cpp @@ -0,0 +1,450 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#define _ACTIONS_CPP_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "actions.h" + +#include <krun.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kurifilter.h> +#include <kglobal.h> +#include <kstandarddirs.h> +#include <kapplication.h> +#include <dcopclient.h> +#include <kdesktopfile.h> +#include <klocale.h> +#include <kaccel.h> +#include <kservice.h> +#include <kprocess.h> + +#include "windows.h" +#include "action_data.h" + +#include <X11/X.h> + +namespace KHotKeys +{ + +// Action + +Action* Action::create_cfg_read( KConfig& cfg_P, Action_data* data_P ) + { + QString type = cfg_P.readEntry( "Type" ); + if( type == "COMMAND_URL" ) + return new Command_url_action( cfg_P, data_P ); + if( type == "MENUENTRY" ) + return new Menuentry_action( cfg_P, data_P ); + if( type == "DCOP" ) + return new Dcop_action( cfg_P, data_P ); + if( type == "KEYBOARD_INPUT" ) + return new Keyboard_input_action( cfg_P, data_P ); + if( type == "ACTIVATE_WINDOW" ) + return new Activate_window_action( cfg_P, data_P ); + kdWarning( 1217 ) << "Unknown Action type read from cfg file\n"; + return NULL; + } + +void Action::cfg_write( KConfig& cfg_P ) const + { + cfg_P.writeEntry( "Type", "ERROR" ); // derived classes should call with their type + } + +// Action_list + +Action_list::Action_list( KConfig& cfg_P, Action_data* data_P ) + : QPtrList< Action >() + { + setAutoDelete( true ); + QString save_cfg_group = cfg_P.group(); + int cnt = cfg_P.readNumEntry( "ActionsCount", 0 ); + for( int i = 0; + i < cnt; + ++i ) + { + cfg_P.setGroup( save_cfg_group + QString::number( i )); + Action* action = Action::create_cfg_read( cfg_P, data_P ); + if( action ) + append( action ); + } + cfg_P.setGroup( save_cfg_group ); + } + +void Action_list::cfg_write( KConfig& cfg_P ) const + { + QString save_cfg_group = cfg_P.group(); + int i = 0; + for( Iterator it( *this ); + it; + ++it, ++i ) + { + cfg_P.setGroup( save_cfg_group + QString::number( i )); + it.current()->cfg_write( cfg_P ); + } + cfg_P.setGroup( save_cfg_group ); + cfg_P.writeEntry( "ActionsCount", i ); + } + +// Command_url_action + +Command_url_action::Command_url_action( KConfig& cfg_P, Action_data* data_P ) + : Action( cfg_P, data_P ) + { + _command_url = cfg_P.readEntry( "CommandURL" ); + } + +void Command_url_action::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "CommandURL", command_url()); + cfg_P.writeEntry( "Type", "COMMAND_URL" ); // overwrites value set in base::cfg_write() + } + +void Command_url_action::execute() + { + if( command_url().isEmpty()) + return; + KURIFilterData uri; + QString cmd = command_url(); + static bool sm_ready = false; + if( !sm_ready ) + { + kapp->propagateSessionManager(); + sm_ready = true; + } +// int space_pos = command_url().find( ' ' ); +// if( command_url()[ 0 ] != '\'' && command_url()[ 0 ] != '"' && space_pos > -1 +// && command_url()[ space_pos - 1 ] != '\\' ) +// cmd = command_url().left( space_pos ); // get first 'word' + uri.setData( cmd ); + KURIFilter::self()->filterURI( uri ); + if( uri.uri().isLocalFile() && !uri.uri().hasRef() ) + cmd = uri.uri().path(); + else + cmd = uri.uri().url(); + switch( uri.uriType()) + { + case KURIFilterData::LOCAL_FILE: + case KURIFilterData::LOCAL_DIR: + case KURIFilterData::NET_PROTOCOL: + case KURIFilterData::HELP: + { + ( void ) new KRun( uri.uri()); + break; + } + case KURIFilterData::EXECUTABLE: + { + if (!kapp->authorize("shell_access")) + return; + if( !uri.hasArgsAndOptions()) + { + KService::Ptr service = KService::serviceByDesktopName( cmd ); + if( service != NULL ) + { + KRun::run( *service, KURL::List()); + break; + } + } + // fall though + } + case KURIFilterData::SHELL: + { + if (!kapp->authorize("shell_access")) + return; + if( !KRun::runCommand( + cmd + ( uri.hasArgsAndOptions() ? uri.argsAndOptions() : "" ), + cmd, uri.iconName())) { + // CHECKME ? + } + break; + } + default: // error + return; + } + timeout.start( 1000, true ); // 1sec timeout + } + +QString Command_url_action::description() const + { + return i18n( "Command/URL : " ) + command_url(); + } + +Action* Command_url_action::copy( Action_data* data_P ) const + { + return new Command_url_action( data_P, command_url()); + } + +// Menuentry_action + +void Menuentry_action::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Type", "MENUENTRY" ); // overwrites value set in base::cfg_write() + } + +KService::Ptr Menuentry_action::service() const + { + if (!_service) + { + const_cast<Menuentry_action *>(this)->_service = KService::serviceByStorageId(command_url()); + } + return _service; + } + +void Menuentry_action::execute() + { + (void) service(); + if (!_service) + return; + KRun::run( *_service, KURL::List()); + timeout.start( 1000, true ); // 1sec timeout + } + +QString Menuentry_action::description() const + { + (void) service(); + return i18n( "Menuentry : " ) + (_service ? _service->name() : QString::null); + } + +Action* Menuentry_action::copy( Action_data* data_P ) const + { + return new Menuentry_action( data_P, command_url()); + } + +// Dcop_action + +Dcop_action::Dcop_action( KConfig& cfg_P, Action_data* data_P ) + : Action( cfg_P, data_P ) + { + app = cfg_P.readEntry( "RemoteApp" ); + obj = cfg_P.readEntry( "RemoteObj" ); + call = cfg_P.readEntry( "Call" ); + args = cfg_P.readEntry( "Arguments" ); + } + +void Dcop_action::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Type", "DCOP" ); // overwrites value set in base::cfg_write() + cfg_P.writeEntry( "RemoteApp", app ); + cfg_P.writeEntry( "RemoteObj", obj ); + cfg_P.writeEntry( "Call", call ); + cfg_P.writeEntry( "Arguments", args ); + } + +void Dcop_action::execute() + { + if( app.isEmpty() || obj.isEmpty() || call.isEmpty()) + return; + QStringList args_list; + QString args_str = args; + while( !args_str.isEmpty()) + { + unsigned int pos = 0; + while( args_str[ pos ] == ' ' ) + ++pos; + if( args_str[ pos ] == '\"' || args_str[ pos ] == '\'' ) + { + QString val = ""; + QChar sep = args_str[ pos ]; + bool skip = false; + ++pos; + for(; + pos < args_str.length(); + ++pos ) + { + if( args_str[ pos ] == '\\' ) + { + skip = true; + continue; + } + if( !skip && args_str[ pos ] == sep ) + break; + skip = false; + val += args_str[ pos ]; + } + if( pos >= args_str.length()) + return; + ++pos; + args_str = args_str.mid( pos ); + args_list.append( val ); + } + else + { + // one word + if( pos != 0 ) + args_str = args_str.mid( pos ); + int nxt_pos = args_str.find( ' ' ); + args_list.append( args_str.left( nxt_pos )); // should be ok if nxt_pos is -1 + args_str = nxt_pos >= 0 ? args_str.mid( nxt_pos ) : ""; + } + } + kdDebug( 1217 ) << "DCOP call:" << app << ":" << obj << ":" << call << ":" << args_list << endl; + KProcess proc; + proc << "dcop" << app << obj << call << args_list; + proc.start( KProcess::DontCare ); + } + +QString Dcop_action::description() const + { + return i18n( "DCOP : " ) + remote_application() + "::" + remote_object() + "::" + + called_function(); + } + +Action* Dcop_action::copy( Action_data* data_P ) const + { + return new Dcop_action( data_P, remote_application(), remote_object(), + called_function(), arguments()); + } + +// Keyboard_input_action + +Keyboard_input_action::Keyboard_input_action( KConfig& cfg_P, Action_data* data_P ) + : Action( cfg_P, data_P ) + { + _input = cfg_P.readEntry( "Input" ); + if( cfg_P.readBoolEntry( "IsDestinationWindow" )) + { + QString save_cfg_group = cfg_P.group(); + cfg_P.setGroup( save_cfg_group + "DestinationWindow" ); + _dest_window = new Windowdef_list( cfg_P ); + _active_window = false; // ignored with _dest_window set anyway + cfg_P.setGroup( save_cfg_group ); + } + else + { + _dest_window = NULL; + _active_window = cfg_P.readBoolEntry( "ActiveWindow" ); + } + } + +Keyboard_input_action::~Keyboard_input_action() + { + delete _dest_window; + } + +void Keyboard_input_action::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Type", "KEYBOARD_INPUT" ); // overwrites value set in base::cfg_write() + cfg_P.writeEntry( "Input", input()); + if( dest_window() != NULL ) + { + cfg_P.writeEntry( "IsDestinationWindow", true ); + QString save_cfg_group = cfg_P.group(); + cfg_P.setGroup( save_cfg_group + "DestinationWindow" ); + dest_window()->cfg_write( cfg_P ); + cfg_P.setGroup( save_cfg_group ); + } + else + cfg_P.writeEntry( "IsDestinationWindow", false ); + cfg_P.writeEntry( "ActiveWindow", _active_window ); + } + +void Keyboard_input_action::execute() + { + if( input().isEmpty()) + return; + Window w = InputFocus; + if( dest_window() != NULL ) + { + w = windows_handler->find_window( dest_window()); + if( w == None ) + w = InputFocus; + } + else + { + if( !_active_window ) + w = windows_handler->action_window(); + if( w == None ) + w = InputFocus; + } + int last_index = -1, start = 0; + while(( last_index = input().find( ':', last_index + 1 )) != -1 ) // find next ';' + { + QString key = input().mid( start, last_index - start ).stripWhiteSpace(); + if( key == "Enter" && KKey( key ).keyCodeQt() == 0 ) + key = "Return"; // CHECKE hack + keyboard_handler->send_macro_key( KKey( key ), w ); + start = last_index + 1; + } + // and the last one + QString key = input().mid( start, input().length()).stripWhiteSpace(); + if( key == "Enter" && KKey( key ).keyCodeQt() == 0 ) + key = "Return"; + keyboard_handler->send_macro_key( KKey( key ), w ); // the rest + XFlush( qt_xdisplay()); + } + +QString Keyboard_input_action::description() const + { + QString tmp = input(); + tmp.replace( '\n', ' ' ); + tmp.truncate( 30 ); + return i18n( "Keyboard input : " ) + tmp; + } + +Action* Keyboard_input_action::copy( Action_data* data_P ) const + { + return new Keyboard_input_action( data_P, input(), + dest_window() ? dest_window()->copy() : NULL, _active_window ); + } + +// Activate_window_action + +Activate_window_action::Activate_window_action( KConfig& cfg_P, Action_data* data_P ) + : Action( cfg_P, data_P ) + { + QString save_cfg_group = cfg_P.group(); + cfg_P.setGroup( save_cfg_group + "Window" ); + _window = new Windowdef_list( cfg_P ); + cfg_P.setGroup( save_cfg_group ); + } + +Activate_window_action::~Activate_window_action() + { + delete _window; + } + +void Activate_window_action::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Type", "ACTIVATE_WINDOW" ); // overwrites value set in base::cfg_write() + QString save_cfg_group = cfg_P.group(); + cfg_P.setGroup( save_cfg_group + "Window" ); + window()->cfg_write( cfg_P ); + cfg_P.setGroup( save_cfg_group ); + } + +void Activate_window_action::execute() + { + if( window()->match( windows_handler->active_window())) + return; // is already active + WId win_id = windows_handler->find_window( window()); + if( win_id != None ) + windows_handler->activate_window( win_id ); + } + +QString Activate_window_action::description() const + { + return i18n( "Activate window : " ) + window()->comment(); + } + +Action* Activate_window_action::copy( Action_data* data_P ) const + { + return new Activate_window_action( data_P, window()->copy()); + } + +} // namespace KHotKeys diff --git a/khotkeys/shared/actions.h b/khotkeys/shared/actions.h new file mode 100644 index 000000000..5295d5be9 --- /dev/null +++ b/khotkeys/shared/actions.h @@ -0,0 +1,305 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#ifndef _ACTIONS_H_ +#define _ACTIONS_H_ + + +#include <qstring.h> +#include <qptrlist.h> +#include <qtimer.h> + +#include <kservice.h> + +class KConfig; + +#include "khotkeysglobal.h" + +namespace KHotKeys +{ + +class Action_data; +class Windowdef_list; + +// this one is a base for all "real" resulting actions, e.g. running a command, +// Action_data instances usually contain at least one Action +class KDE_EXPORT Action + { + public: + Action( Action_data* data_P ); + Action( KConfig& cfg_P, Action_data* data_P ); + virtual ~Action(); + virtual void execute() = 0; + virtual QString description() const = 0; + virtual void cfg_write( KConfig& cfg_P ) const; + virtual Action* copy( Action_data* data_P ) const = 0; + static Action* create_cfg_read( KConfig& cfg_P, Action_data* data_P ); + protected: + Action_data* const data; + KHOTKEYS_DISABLE_COPY( Action ); + }; + +class KDE_EXPORT Action_list + : public QPtrList< Action > + { + public: + Action_list( const QString& comment_P ); // CHECKME nebo i data ? + Action_list( KConfig& cfg_P, Action_data* data_P ); + void cfg_write( KConfig& cfg_P ) const; + typedef QPtrListIterator< Action > Iterator; + const QString& comment() const; + private: + QString _comment; + KHOTKEYS_DISABLE_COPY( Action_list ); + }; + +class KDE_EXPORT Command_url_action + : public Action + { + typedef Action base; + public: + Command_url_action( Action_data* data_P, const QString& command_url_P ); + Command_url_action( KConfig& cfg_P, Action_data* data_P ); + virtual void cfg_write( KConfig& cfg_P ) const; + virtual void execute(); + virtual QString description() const; + const QString& command_url() const; + virtual Action* copy( Action_data* data_P ) const; + protected: + QTimer timeout; + private: + QString _command_url; + }; + +class KDE_EXPORT Menuentry_action + : public Command_url_action + { + typedef Command_url_action base; + public: + Menuentry_action( Action_data* data_P, const QString& menuentry_P ); + Menuentry_action( KConfig& cfg_P, Action_data* data_P ); + virtual void cfg_write( KConfig& cfg_P ) const; + virtual void execute(); + virtual QString description() const; + virtual Action* copy( Action_data* data_P ) const; + KService::Ptr service() const; + private: + KService::Ptr _service; + }; + +class KDE_EXPORT Dcop_action + : public Action + { + typedef Action base; + public: + Dcop_action( Action_data* data_P, const QString& app_P, const QString& obj_P, + const QString& call_P, const QString& args_P ); + Dcop_action( KConfig& cfg_P, Action_data* data_P ); + virtual void cfg_write( KConfig& cfg_P ) const; + virtual void execute(); + const QString& remote_application() const; + const QString& remote_object() const; + const QString& called_function() const; + const QString& arguments() const; + virtual QString description() const; + virtual Action* copy( Action_data* data_P ) const; + private: + QString app; // CHECKME QCString ? + QString obj; + QString call; + QString args; + }; + +class KDE_EXPORT Keyboard_input_action + : public Action + { + typedef Action base; + public: + Keyboard_input_action( Action_data* data_P, const QString& input_P, + const Windowdef_list* dest_window_P, bool active_window_P ); + Keyboard_input_action( KConfig& cfg_P, Action_data* data_P ); + virtual ~Keyboard_input_action(); + virtual void cfg_write( KConfig& cfg_P ) const; + virtual void execute(); + const QString& input() const; + // send to specific window: dest_window != NULL + // send to active window: dest_window == NULL && activeWindow() == true + // send to action window: dest_window == NULL && activeWindow() == false + const Windowdef_list* dest_window() const; + bool activeWindow() const; + virtual QString description() const; + virtual Action* copy( Action_data* data_P ) const; + private: + QString _input; + const Windowdef_list* _dest_window; + bool _active_window; + }; + +class KDE_EXPORT Activate_window_action + : public Action + { + typedef Action base; + public: + Activate_window_action( Action_data* data_P, const Windowdef_list* window_P ); + Activate_window_action( KConfig& cfg_P, Action_data* data_P ); + virtual ~Activate_window_action(); + virtual void cfg_write( KConfig& cfg_P ) const; + virtual void execute(); + const Windowdef_list* window() const; + virtual QString description() const; + virtual Action* copy( Action_data* data_P ) const; + private: + const Windowdef_list* _window; + }; + +//*************************************************************************** +// Inline +//*************************************************************************** + +// Action + +inline +Action::Action( Action_data* data_P ) + : data( data_P ) + { + } + +inline +Action::Action( KConfig&, Action_data* data_P ) + : data( data_P ) + { + } + +inline +Action::~Action() + { + } + +// Action_list + +inline +Action_list::Action_list( const QString& comment_P ) + : QPtrList< Action >(), _comment( comment_P ) + { + setAutoDelete( true ); + } + +inline +const QString& Action_list::comment() const + { + return _comment; + } + +// Command_url_action + +inline +Command_url_action::Command_url_action( Action_data* data_P, const QString& command_url_P ) + : Action( data_P ), _command_url( command_url_P ) + { + } + +inline +const QString& Command_url_action::command_url() const + { + return _command_url; + } + +// Menuentry_action + +inline +Menuentry_action::Menuentry_action( Action_data* data_P, const QString& menuentry_P ) + : Command_url_action( data_P, menuentry_P ) + { + } + +inline +Menuentry_action::Menuentry_action( KConfig& cfg_P, Action_data* data_P ) + : Command_url_action( cfg_P, data_P ) + { + } + +// DCOP_action + +inline +Dcop_action::Dcop_action( Action_data* data_P, const QString& app_P, const QString& obj_P, + const QString& call_P, const QString& args_P ) + : Action( data_P ), app( app_P ), obj( obj_P ), call( call_P ), args( args_P ) + { + } + +inline +const QString& Dcop_action::remote_application() const + { + return app; + } + +inline +const QString& Dcop_action::remote_object() const + { + return obj; + } + +inline +const QString& Dcop_action::called_function() const + { + return call; + } + +inline +const QString& Dcop_action::arguments() const + { + return args; + } + +// Keyboard_input_action + +inline +Keyboard_input_action::Keyboard_input_action( Action_data* data_P, const QString& input_P, + const Windowdef_list* dest_window_P, bool active_window_P ) + : Action( data_P ), _input( input_P ), _dest_window( dest_window_P ), _active_window( active_window_P ) + { + } + +inline +const QString& Keyboard_input_action::input() const + { + return _input; + } + +inline +const Windowdef_list* Keyboard_input_action::dest_window() const + { + return _dest_window; + } + +inline +bool Keyboard_input_action::activeWindow() const + { + return _active_window; + } + +// Activate_window_action + +inline +Activate_window_action::Activate_window_action( Action_data* data_P, + const Windowdef_list* window_P ) + : Action( data_P ), _window( window_P ) + { + } + +inline +const Windowdef_list* Activate_window_action::window() const + { + return _window; + } + +} // namespace KHotKeys + +#endif diff --git a/khotkeys/shared/conditions.cpp b/khotkeys/shared/conditions.cpp new file mode 100644 index 000000000..01d236934 --- /dev/null +++ b/khotkeys/shared/conditions.cpp @@ -0,0 +1,504 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#define _CONDITIONS_CPP_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "conditions.h" + +#ifdef KHOTKEYS_DEBUG +#include <typeinfo> +#endif + +#include <kconfig.h> +#include <kdebug.h> +#include <klocale.h> +#include <assert.h> + +#include <X11/Xlib.h> +#include <fixx11h.h> + +#include "action_data.h" + +namespace KHotKeys +{ + +// Condition + +Condition::Condition( Condition_list_base* parent_P ) + : _parent( parent_P ) + { + if( _parent ) + _parent->append( this ); + } + +Condition::Condition( KConfig&, Condition_list_base* parent_P ) + : _parent( parent_P ) + { + if( _parent ) + _parent->append( this ); + } + +Condition* Condition::create_cfg_read( KConfig& cfg_P, Condition_list_base* parent_P ) + { + QString type = cfg_P.readEntry( "Type" ); + if( type == "ACTIVE_WINDOW" ) + return new Active_window_condition( cfg_P, parent_P ); + if( type == "EXISTING_WINDOW" ) + return new Existing_window_condition( cfg_P, parent_P ); + if( type == "NOT" ) + return new Not_condition( cfg_P, parent_P ); + if( type == "AND" ) + return new And_condition( cfg_P, parent_P ); + if( type == "OR" ) + return new Or_condition( cfg_P, parent_P ); + kdWarning( 1217 ) << "Unknown Condition type read from cfg file\n"; + return NULL; + } + +Condition::~Condition() + { + if( _parent ) + _parent->remove( this ); + } + + +void Condition::cfg_write( KConfig& cfg_P ) const + { + cfg_P.writeEntry( "Type", "ERROR" ); + } + +void Condition::updated() const + { + if( !khotkeys_active()) + return; + assert( _parent != NULL ); + _parent->updated(); + } + +#ifdef KHOTKEYS_DEBUG +void Condition::debug( int depth_P ) + { + char tmp[ 1024 ]; + int i; + for( i = 0; + i < depth_P; + ++i ) + tmp[ i ] = ' '; + tmp[ i ] = '\0'; + kdDebug( 1217 ) << tmp << description() << ":(" << this << ")" << endl; + } + +void Condition::debug_list( const QPtrList< Condition >& list_P, int depth_P ) + { + char tmp[ 1024 ]; + int i; + for( i = 0; + i < depth_P; + ++i ) + tmp[ i ] = ' '; + tmp[ i ] = '\0'; + for( QPtrListIterator< Condition > it( list_P ); + it; + ++it ) + (*it)->debug( depth_P + 1 ); + } +#endif + + +// Condition_list_base + +Condition_list_base::Condition_list_base( KConfig& cfg_P, Condition_list_base* parent_P ) + : Condition( parent_P ) + { + QString save_cfg_group = cfg_P.group(); + int cnt = cfg_P.readNumEntry( "ConditionsCount", 0 ); + for( int i = 0; + i < cnt; + ++i ) + { + cfg_P.setGroup( save_cfg_group + QString::number( i )); + (void) Condition::create_cfg_read( cfg_P, this ); + } + cfg_P.setGroup( save_cfg_group ); + } + +Condition_list_base::~Condition_list_base() + { + while( !isEmpty()) + { + Condition* c = getFirst(); + remove( c ); + delete c; + } + } + +void Condition_list_base::cfg_write( KConfig& cfg_P ) const + { + QString save_cfg_group = cfg_P.group(); + int i = 0; + for( Iterator it( *this ); + it; + ++it, ++i ) + { + cfg_P.setGroup( save_cfg_group + QString::number( i )); + it.current()->cfg_write( cfg_P ); + } + cfg_P.setGroup( save_cfg_group ); + cfg_P.writeEntry( "ConditionsCount", i ); + } + +bool Condition_list_base::accepts_children() const + { + return true; + } + +#ifdef KHOTKEYS_DEBUG +void Condition_list_base::debug( int depth_P ) + { + char tmp[ 1024 ]; + int i; + for( i = 0; + i < depth_P; + ++i ) + tmp[ i ] = ' '; + tmp[ i ] = '\0'; + kdDebug( 1217 ) << tmp << typeid( *this ).name() << ":(" << this << ")" << endl; + debug_list( *this, depth_P + 1 ); + } +#endif + +// Condition_list + +Condition_list::Condition_list( KConfig& cfg_P, Action_data_base* data_P ) + : Condition_list_base( cfg_P, NULL ), data( data_P ) + { + _comment = cfg_P.readEntry( "Comment" ); + } + +void Condition_list::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Comment", comment()); + } + +Condition_list* Condition_list::copy( Action_data_base* data_P ) const + { + Condition_list* ret = new Condition_list( comment(), data_P ); + for( Iterator it( *this ); + it; + ++it ) + ret->append( it.current()->copy( ret )); + return ret; + } + + +bool Condition_list::match() const + { + if( count() == 0 ) // no conditions to match => ok + return true; + for( Iterator it( *this ); + it; + ++it ) + if( it.current()->match()) // OR + return true; + return false; + } + +void Condition_list::updated() const + { + if( !khotkeys_active()) + return; + data->update_triggers(); +// base::updated(); no need to, doesn't have parent + } + +// CHECKME tohle je drobet hack, jeste to zvazit +void Condition_list::set_data( Action_data_base* data_P ) + { + assert( data == NULL || data == data_P ); + data = data_P; + } + +const QString Condition_list::description() const + { + assert( false ); + return QString::null; + } + +Condition_list* Condition_list::copy( Condition_list_base* ) const + { + assert( false ); + return NULL; + } + +// Active_window_condition + +Active_window_condition::Active_window_condition( KConfig& cfg_P, Condition_list_base* parent_P ) + : Condition( cfg_P, parent_P ) + { + QString save_cfg_group = cfg_P.group(); + cfg_P.setGroup( save_cfg_group + "Window" ); + _window = new Windowdef_list( cfg_P ); + cfg_P.setGroup( save_cfg_group ); + init(); + set_match(); + } + +void Active_window_condition::init() + { + connect( windows_handler, SIGNAL( active_window_changed( WId )), + this, SLOT( active_window_changed( WId ))); + } + +bool Active_window_condition::match() const + { + return is_match; + } + +void Active_window_condition::set_match() + { + is_match = window()->match( Window_data( windows_handler->active_window())); + kdDebug( 1217 ) << "Active_window_condition::set_match :" << is_match << endl; + updated(); + } + +void Active_window_condition::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + QString save_cfg_group = cfg_P.group(); + cfg_P.setGroup( save_cfg_group + "Window" ); + window()->cfg_write( cfg_P ); + cfg_P.setGroup( save_cfg_group ); + cfg_P.writeEntry( "Type", "ACTIVE_WINDOW" ); // overwrites value set in base::cfg_write() + } + +#ifndef COVARIANT_RETURN_BROKEN +Active_window_condition* Active_window_condition::copy( Condition_list_base* parent_P ) const +#else +Condition* Active_window_condition::copy( Condition_list_base* parent_P ) const +#endif + { + return new Active_window_condition( window()->copy(), parent_P ); + } + +const QString Active_window_condition::description() const + { + return i18n( "Active window: " ) + window()->comment(); + } + +void Active_window_condition::active_window_changed( WId ) + { + set_match(); + } + +Active_window_condition::~Active_window_condition() + { + disconnect( windows_handler, NULL, this, NULL ); + delete _window; + } + +// Existing_window_condition + +Existing_window_condition::Existing_window_condition( KConfig& cfg_P, Condition_list_base* parent_P ) + : Condition( cfg_P, parent_P ) + { + QString save_cfg_group = cfg_P.group(); + cfg_P.setGroup( save_cfg_group + "Window" ); + _window = new Windowdef_list( cfg_P ); + cfg_P.setGroup( save_cfg_group ); + init(); + set_match(); + } + +void Existing_window_condition::init() + { + connect( windows_handler, SIGNAL( window_added( WId )), this, SLOT( window_added( WId ))); + connect( windows_handler, SIGNAL( window_removed( WId )), this, SLOT( window_removed( WId ))); + } + +bool Existing_window_condition::match() const + { + return is_match; + } + +void Existing_window_condition::set_match( WId w_P ) + { + if( w_P != None && !is_match ) + is_match = window()->match( Window_data( w_P )); + else + is_match = windows_handler->find_window( window()) != None; + kdDebug( 1217 ) << "Existing_window_condition::set_match :" << is_match << endl; + updated(); + } + +void Existing_window_condition::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + QString save_cfg_group = cfg_P.group(); + cfg_P.setGroup( save_cfg_group + "Window" ); + window()->cfg_write( cfg_P ); + cfg_P.setGroup( save_cfg_group ); + cfg_P.writeEntry( "Type", "EXISTING_WINDOW" ); // overwrites value set in base::cfg_write() + } + +#ifndef COVARIANT_RETURN_BROKEN +Existing_window_condition* Existing_window_condition::copy( Condition_list_base* parent_P ) const +#else +Condition* Existing_window_condition::copy( Condition_list_base* parent_P ) const +#endif + { + return new Existing_window_condition( window()->copy(), parent_P ); + } + +const QString Existing_window_condition::description() const + { + return i18n( "Existing window: " ) + window()->comment(); + } + +void Existing_window_condition::window_added( WId w_P ) + { + set_match( w_P ); + } + +void Existing_window_condition::window_removed( WId ) + { + set_match(); + } + +Existing_window_condition::~Existing_window_condition() + { + disconnect( windows_handler, NULL, this, NULL ); + delete _window; + } + +// Not_condition + +Not_condition::Not_condition( KConfig& cfg_P, Condition_list_base* parent_P ) + : Condition_list_base( cfg_P, parent_P ) + { + // CHECKME kontrola poctu ? + } + +bool Not_condition::match() const + { + return condition() ? !condition()->match() : false; + } + +void Not_condition::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Type", "NOT" ); // overwrites value set in base::cfg_write() + } + +Not_condition* Not_condition::copy( Condition_list_base* parent_P ) const + { + Not_condition* ret = new Not_condition( parent_P ); + if( condition()) + ret->append( condition()->copy( ret )); + return ret; + } + +const QString Not_condition::description() const + { + return i18n( "Not_condition", "Not" ); + } + +bool Not_condition::accepts_children() const + { + return count() == 0; + } + +// And_condition + +And_condition::And_condition( KConfig& cfg_P, Condition_list_base* parent_P ) + : Condition_list_base( cfg_P, parent_P ) + { + // CHECKME kontrola poctu ? + } + +bool And_condition::match() const + { + for( Iterator it( *this ); + it; + ++it ) + if( !it.current()->match()) // AND + return false; + return true; // all true (or empty) + } + +void And_condition::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Type", "AND" ); // overwrites value set in base::cfg_write() + } + +And_condition* And_condition::copy( Condition_list_base* parent_P ) const + { + And_condition* ret = new And_condition( parent_P ); + for( Iterator it( *this ); + it; + ++it ) + ret->append( (*it)->copy( ret )); + return ret; + } + +const QString And_condition::description() const + { + return i18n( "And_condition", "And" ); + } + +// Or_condition + +Or_condition::Or_condition( KConfig& cfg_P, Condition_list_base* parent_P ) + : Condition_list_base( cfg_P, parent_P ) + { + // CHECKME kontrola poctu ? + } + +bool Or_condition::match() const + { + if( count() == 0 ) // empty => ok + return true; + for( Iterator it( *this ); + it; + ++it ) + if( it.current()->match()) // OR + return true; + return false; + } + +void Or_condition::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Type", "OR" ); // overwrites value set in base::cfg_write() + } + +Or_condition* Or_condition::copy( Condition_list_base* parent_P ) const + { + Or_condition* ret = new Or_condition( parent_P ); + for( Iterator it( *this ); + it; + ++it ) + ret->append( (*it)->copy( ret )); + return ret; + } + +const QString Or_condition::description() const + { + return i18n( "Or_condition", "Or" ); + } + +} // namespace KHotKeys + +#include "conditions.moc" diff --git a/khotkeys/shared/conditions.h b/khotkeys/shared/conditions.h new file mode 100644 index 000000000..59133f4d3 --- /dev/null +++ b/khotkeys/shared/conditions.h @@ -0,0 +1,296 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#ifndef _CONDITIONS_H_ +#define _CONDITIONS_H_ + +#include <qobject.h> +#include <qptrlist.h> +#include <qstring.h> + +#include "khotkeysglobal.h" +#include "windows.h" + +#include <X11/Xlib.h> +#include <fixx11h.h> + +class KConfig; + +namespace KHotKeys +{ + +class Action_data_base; +class Action_data; +class Condition_list_base; + +class KDE_EXPORT Condition + { + public: + Condition( Condition_list_base* parent_P ); + Condition( KConfig& cfg_P, Condition_list_base* parent_P ); + virtual ~Condition(); + virtual bool match() const = 0; + virtual void updated() const; // called when the condition changes + virtual void cfg_write( KConfig& cfg_P ) const = 0; + virtual const QString description() const = 0; + virtual Condition* copy( Condition_list_base* parent_P ) const = 0; + const Condition_list_base* parent() const; + Condition_list_base* parent(); + static Condition* create_cfg_read( KConfig& cfg_P, Condition_list_base* parent_P ); + protected: + Condition_list_base* const _parent; + KHOTKEYS_DISABLE_COPY( Condition ); + }; + +class KDE_EXPORT Condition_list_base + : public Condition, public QPtrList< Condition > // inheritance ? + { + typedef Condition base; + public: + Condition_list_base( Condition_list_base* parent_P ); + Condition_list_base( const QPtrList< Condition >& children_P, + Condition_list_base* parent_P ); + Condition_list_base( KConfig& cfg_P, Condition_list_base* parent_P ); + virtual ~Condition_list_base(); + virtual void cfg_write( KConfig& cfg_P ) const; + virtual bool accepts_children() const; + typedef QPtrListIterator< Condition > Iterator; + }; + +class KDE_EXPORT Condition_list + : public Condition_list_base + { + typedef Condition_list_base base; + public: + Condition_list( const QString& comment_P, Action_data_base* data_P ); + Condition_list( KConfig& cfg_P, Action_data_base* data_P ); + void cfg_write( KConfig& cfg_P ) const; + Condition_list* copy( Action_data_base* data_P ) const; + virtual bool match() const; + const QString& comment() const; + void set_data( Action_data_base* data_P ); + virtual void updated() const; + virtual Condition_list* copy( Condition_list_base* parent_P ) const; + virtual const QString description() const; + private: + QString _comment; + Action_data_base* data; + }; + +class KDE_EXPORT Active_window_condition + : public QObject, public Condition + { + Q_OBJECT + typedef Condition base; + public: + Active_window_condition( Windowdef_list* window_P, Condition_list_base* parent_P ); + Active_window_condition( KConfig& cfg_P, Condition_list_base* parent_P ); + virtual ~Active_window_condition(); + virtual bool match() const; + virtual void cfg_write( KConfig& cfg_P ) const; + const Windowdef_list* window() const; +#ifndef COVARIANT_RETURN_BROKEN + virtual Active_window_condition* copy( Condition_list_base* parent_P ) const; +#else + virtual Condition* copy( Condition_list_base* parent_P ) const; +#endif + virtual const QString description() const; + public slots: + void active_window_changed( WId ); + private: + void init(); + void set_match(); + Windowdef_list* _window; + bool is_match; + }; + +class KDE_EXPORT Existing_window_condition + : public QObject, public Condition + { + Q_OBJECT + typedef Condition base; + public: + Existing_window_condition( Windowdef_list* window_P, Condition_list_base* parent_P ); + Existing_window_condition( KConfig& cfg_P, Condition_list_base* parent_P ); + virtual ~Existing_window_condition(); + virtual bool match() const; + virtual void cfg_write( KConfig& cfg_P ) const; + const Windowdef_list* window() const; +#ifndef COVARIANT_RETURN_BROKEN + virtual Existing_window_condition* copy( Condition_list_base* parent_P ) const; +#else + virtual Condition* copy( Condition_list_base* parent_P ) const; +#endif + virtual const QString description() const; + public slots: + void window_added( WId w_P ); + void window_removed( WId w_P ); + private: + void init(); + void set_match( WId w_P = None ); + Windowdef_list* _window; + bool is_match; + }; + +class KDE_EXPORT Not_condition + : public Condition_list_base + { + typedef Condition_list_base base; + public: + Not_condition( Condition_list_base* parent_P ); + Not_condition( KConfig& cfg_P, Condition_list_base* parent_P ); + virtual bool match() const; + virtual void cfg_write( KConfig& cfg_P ) const; + virtual Not_condition* copy( Condition_list_base* parent_P ) const; + virtual const QString description() const; + const Condition* condition() const; + virtual bool accepts_children() const; + }; + +class KDE_EXPORT And_condition + : public Condition_list_base + { + typedef Condition_list_base base; + public: + And_condition( Condition_list_base* parent_P ); + And_condition( KConfig& cfg_P, Condition_list_base* parent_P ); + virtual bool match() const; + virtual void cfg_write( KConfig& cfg_P ) const; + virtual And_condition* copy( Condition_list_base* parent_P ) const; + virtual const QString description() const; + }; + +class KDE_EXPORT Or_condition + : public Condition_list_base + { + typedef Condition_list_base base; + public: + Or_condition( Condition_list_base* parent_P ); + Or_condition( KConfig& cfg_P, Condition_list_base* parent_P ); + virtual bool match() const; + virtual void cfg_write( KConfig& cfg_P ) const; + virtual Or_condition* copy( Condition_list_base* parent_P ) const; + virtual const QString description() const; + }; + +//*************************************************************************** +// Inline +//*************************************************************************** + +// Condition + +inline +const Condition_list_base* Condition::parent() const + { + return _parent; + } + +inline +Condition_list_base* Condition::parent() + { + return _parent; + } + +// Condition_list_base + +inline +Condition_list_base::Condition_list_base( Condition_list_base* parent_P ) + : Condition( parent_P ), QPtrList< Condition >() + { + } + +inline +Condition_list_base::Condition_list_base( const QPtrList< Condition >& children_P, + Condition_list_base* parent_P ) + : Condition( parent_P ), QPtrList< Condition >( children_P ) + { + } + +// Condition_list + +inline +Condition_list::Condition_list( const QString& comment_P, Action_data_base* data_P ) + : Condition_list_base( NULL ), _comment( comment_P ), data( data_P ) + { + } + +inline +const QString& Condition_list::comment() const + { + return _comment; + } + +// Active_window_condition + +inline +Active_window_condition::Active_window_condition( Windowdef_list* window_P, + Condition_list_base* parent_P ) + : Condition( parent_P ), _window( window_P ) + { + init(); + set_match(); + } + +inline +const Windowdef_list* Active_window_condition::window() const + { + return _window; + } + +// Existing_window_condition + +inline +Existing_window_condition::Existing_window_condition( Windowdef_list* window_P, + Condition_list_base* parent_P ) + : Condition( parent_P ), _window( window_P ), is_match( false ) + { + init(); + set_match(); + } + +inline +const Windowdef_list* Existing_window_condition::window() const + { + return _window; + } + +// Not_condition + +inline +Not_condition::Not_condition( Condition_list_base* parent_P ) + : Condition_list_base( parent_P ) + { + } + +inline +const Condition* Not_condition::condition() const + { + return getFirst(); + } + +// And_condition + +inline +And_condition::And_condition( Condition_list_base* parent_P ) + : Condition_list_base( parent_P ) + { + } + +// Or_condition + +inline +Or_condition::Or_condition( Condition_list_base* parent_P ) + : Condition_list_base( parent_P ) + { + } + +} // namespace KHotKeys + +#endif diff --git a/khotkeys/shared/gestures.cpp b/khotkeys/shared/gestures.cpp new file mode 100644 index 000000000..11cc44e22 --- /dev/null +++ b/khotkeys/shared/gestures.cpp @@ -0,0 +1,449 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2002 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + + Based on LibStroke : + ( libstroke - an X11 stroke interface library + Copyright (c) 1996,1997,1998,1999 Mark F. Willey, ETLA Technical + There is a reference application available on the LibStroke Home Page: + http://www.etla.net/~willey/projects/libstroke/ ) + +****************************************************************************/ + +#define _GESTURES_CPP_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "gestures.h" + +#include <stdlib.h> +#include <math.h> +#include <assert.h> + +#include <X11/Xlib.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <kxerrorhandler.h> +#include <kkeynative.h> + +#include "input.h" +#include "windows.h" + +#include "voices.h" + +namespace KHotKeys +{ + +Gesture* gesture_handler; + +Gesture::Gesture( bool /*enabled_P*/, QObject* parent_P ) + : _enabled( false ), recording( false ), button( 0 ), exclude( NULL ) + { + (void) new DeleteObject( this, parent_P ); + assert( gesture_handler == NULL ); + gesture_handler = this; + connect( &nostroke_timer, SIGNAL( timeout()), SLOT( stroke_timeout())); + connect( windows_handler, SIGNAL( active_window_changed( WId )), + SLOT( active_window_changed( WId ))); + } + +Gesture::~Gesture() + { + enable( false ); + gesture_handler = NULL; + } + +void Gesture::enable( bool enabled_P ) + { + if( _enabled == enabled_P ) + return; + _enabled = enabled_P; + assert( button != 0 ); + update_grab(); + } + +void Gesture::set_exclude( Windowdef_list* windows_P ) + { + delete exclude; + // check for count() > 0 - empty exclude list means no window is excluded, + // but empty Windowdef_list matches everything + if( windows_P != NULL && windows_P->count() > 0 ) + exclude = windows_P->copy(); + else + exclude = NULL; + update_grab(); + } + +void Gesture::update_grab() + { + if( _enabled && handlers.count() > 0 + && ( exclude == NULL || !exclude->match( Window_data( windows_handler->active_window())))) + { + kapp->removeX11EventFilter( this ); // avoid being installed twice + kapp->installX11EventFilter( this ); + // CHECKME at se grabuje jen kdyz je alespon jedno gesto? + grab_mouse( true ); + } + else + { + grab_mouse( false ); + kapp->removeX11EventFilter( this ); + } + } + +void Gesture::active_window_changed( WId ) + { + update_grab(); + } + +void Gesture::register_handler( QObject* receiver_P, const char* slot_P ) + { + if( handlers.contains( receiver_P )) + return; + handlers[ receiver_P ] = true; + connect( this, SIGNAL( handle_gesture( const QString&, WId )), + receiver_P, slot_P ); + if( handlers.count() == 1 ) + update_grab(); + } + +void Gesture::unregister_handler( QObject* receiver_P, const char* slot_P ) + { + if( !handlers.contains( receiver_P )) + return; + handlers.remove( receiver_P ); + disconnect( this, SIGNAL( handle_gesture( const QString&, WId )), + receiver_P, slot_P ); + if( handlers.count() == 0 ) + update_grab(); + } + +bool Gesture::x11Event( XEvent* ev_P ) + { +/* kdDebug(1217) << k_funcinfo << " ( type = " << ev_P->type << " )" << KeyRelease << " " << KeyPress <<endl; + if( ev_P->type == XKeyPress || ev_P->type == XKeyRelease ) + { + return voice_handler->x11Event( ev_P ); + }*/ + + if( ev_P->type == ButtonPress && ev_P->xbutton.button == button ) + { + kdDebug( 1217 ) << "GESTURE: mouse press" << endl; + stroke.reset(); + stroke.record( ev_P->xbutton.x, ev_P->xbutton.y ); + nostroke_timer.start( timeout, true ); + recording = true; + start_x = ev_P->xbutton.x_root; + start_y = ev_P->xbutton.y_root; + return true; + } + else if( ev_P->type == ButtonRelease && ev_P->xbutton.button == button + && recording ) + { + recording = false; + nostroke_timer.stop(); + stroke.record( ev_P->xbutton.x, ev_P->xbutton.y ); + QString gesture( stroke.translate()); + if( gesture.isEmpty()) + { + kdDebug( 1217 ) << "GESTURE: replay" << endl; + XAllowEvents( qt_xdisplay(), AsyncPointer, CurrentTime ); + XUngrabPointer( qt_xdisplay(), CurrentTime ); + mouse_replay( true ); + return true; + } + kdDebug( 1217 ) << "GESTURE: got: " << gesture << endl; + emit handle_gesture( gesture, windows_handler->window_at_position( start_x, start_y )); + return true; + } + else if( ev_P->type == MotionNotify && recording ) + { // ignore small initial movement + if( nostroke_timer.isActive() + && abs( start_x - ev_P->xmotion.x_root ) < 10 + && abs( start_y - ev_P->xmotion.y_root ) < 10 ) + return true; + nostroke_timer.stop(); + stroke.record( ev_P->xmotion.x, ev_P->xmotion.y ); + } + return false; + } + +void Gesture::stroke_timeout() + { + kdDebug( 1217 ) << "GESTURE: timeout" << endl; + XAllowEvents( qt_xdisplay(), AsyncPointer, CurrentTime ); + XUngrabPointer( qt_xdisplay(), CurrentTime ); + mouse_replay( false ); + recording = false; + } + +void Gesture::mouse_replay( bool release_P ) + { + bool was_enabled = _enabled; + enable( false ); + Mouse::send_mouse_button( button, release_P ); + enable( was_enabled ); + } + +void Gesture::grab_mouse( bool grab_P ) + { + if( grab_P ) + { + KXErrorHandler handler; + static int mask[] = { 0, Button1MotionMask, Button2MotionMask, Button3MotionMask, + Button4MotionMask, Button5MotionMask, ButtonMotionMask, ButtonMotionMask, + ButtonMotionMask, ButtonMotionMask }; +#define XCapL KKeyNative::modXLock() +#define XNumL KKeyNative::modXNumLock() +#define XScrL KKeyNative::modXScrollLock() + unsigned int mods[ 8 ] = + { + 0, XCapL, XNumL, XNumL | XCapL, + XScrL, XScrL | XCapL, + XScrL | XNumL, XScrL | XNumL | XCapL + }; +#undef XCapL +#undef XNumL +#undef XScrL + for( int i = 0; + i < 8; + ++i ) + XGrabButton( qt_xdisplay(), button, mods[ i ], qt_xrootwin(), False, + ButtonPressMask | ButtonReleaseMask | mask[ button ], GrabModeAsync, GrabModeAsync, + None, None ); + bool err = handler.error( true ); + kdDebug( 1217 ) << "Gesture grab:" << err << endl; + } + else + { + kdDebug( 1217 ) << "Gesture ungrab" << endl; + XUngrabButton( qt_xdisplay(), button, AnyModifier, qt_xrootwin()); + } + } + +void Gesture::set_mouse_button( unsigned int button_P ) + { + if( button == button_P ) + return; + if( !_enabled ) + { + button = button_P; + return; + } + grab_mouse( false ); + button = button_P; + grab_mouse( true ); + } + +void Gesture::set_timeout( int timeout_P ) + { + timeout = timeout_P; + } + +Stroke::Stroke() + { + reset(); + points = new point[ MAX_POINTS ]; // CHECKME + } + +Stroke::~Stroke() + { + delete[] points; + } + +void Stroke::reset() + { + min_x = 10000; + min_y = 10000; + max_x = -1; + max_y = -1; + point_count = -1; + } + +bool Stroke::record( int x, int y ) + { + if( point_count >= MAX_POINTS ) + return false; + if( point_count == -1 ) + { + ++point_count; + points[ point_count ].x = x; + points[ point_count ].y = y; + min_x = max_x = x; + min_y = max_y = y; + } + else + { + // interpolate between last and current point + int delx = x - points[ point_count ].x; + int dely = y - points[ point_count ].y; + if( abs( delx ) > abs( dely )) // step by the greatest delta direction + { + float iy = points[ point_count ].y; + // go from the last point to the current, whatever direction it may be + for( int ix = points[ point_count ].x; + ( delx > 0 ) ? ( ix < x ) : ( ix > x ); + ( delx > 0 ) ? ++ix : --ix ) + { + // step the other axis by the correct increment + if( dely < 0 ) + iy -= fabs( dely / ( float ) delx ); + else + iy += fabs( dely / ( float ) delx ); + // add the interpolated point + ++point_count; + if( point_count >= MAX_POINTS ) + return false; + points[ point_count ].x = ix; + points[ point_count ].y = ( int )iy; + } + // add the last point + ++point_count; + if( point_count >= MAX_POINTS ) + return false; + points[ point_count ].x = x; + points[ point_count ].y = y; + // update metrics, it's ok to do it only for the last point + if( x < min_x ) + min_x = x; + if( x > max_x ) + max_x = x; + if( y < min_y ) + min_y = y; + if( y > max_y ) + max_y = y; + } + else + { // same thing, but for dely larger than delx case... + float ix = points[ point_count ].x; + // go from the last point to the current, whatever direction it may be + for( int iy = points[ point_count ].y; + ( dely > 0 ) ? ( iy < y ) : ( iy > y ); + ( dely > 0 ) ? ++iy : --iy ) + { + // step the other axis by the correct increment + if( delx < 0 ) + ix -= fabs( delx / ( float ) dely ); + else + ix += fabs( delx / ( float ) dely ); + // add the interpolated point + ++point_count; + if( point_count >= MAX_POINTS ) + return false; + points[ point_count ].x = ( int )ix; + points[ point_count ].y = iy; + } + // add the last point + ++point_count; + if( point_count >= MAX_POINTS ) + return false; + points[ point_count ].x = x; + points[ point_count ].y = y; + // update metrics, ts's ok to do it only for the last point + if( x < min_x ) + min_x = x; + if( x > max_x ) + max_x = x; + if( y < min_y ) + min_y = y; + if( y > max_y ) + max_y = y; + } + } + return true; + } + +char* Stroke::translate( int min_bin_points_percentage_P, int scale_ratio_P, int min_points_P ) + { + if( point_count < min_points_P ) + return NULL; + // determine size of grid + delta_x = max_x - min_x; + delta_y = max_y - min_y; + if( delta_x > scale_ratio_P * delta_y ) + { + int avg_y = ( max_y + min_y ) / 2; + min_y = avg_y - delta_x / 2; + max_y = avg_y + delta_x / 2; + delta_y = max_y - min_y; + } + else if( delta_y > scale_ratio_P * delta_x ) + { + int avg_x = ( max_x + min_x ) / 2; + min_x = avg_x - delta_y / 2; + max_x = avg_x + delta_y / 2; + delta_x = max_x - min_x; + } + // calculate bin boundary positions + bound_x_1 = min_x + delta_x / 3; + bound_x_2 = min_x + 2 * delta_x / 3; + bound_y_1 = min_y + delta_y / 3; + bound_y_2 = min_y + 2 * delta_y / 3; + + int sequence_count = 0; + // points-->sequence translation scratch variables + int prev_bin = 0; + int current_bin = 0; + int bin_count = 0; +// build string by placing points in bins, collapsing bins and discarding +// those with too few points... + for( int pos = 0; + pos <= point_count; + ++pos ) + { + // figure out which bin the point falls in + current_bin = bin( points[ pos ].x, points[ pos ].y ); + // if this is the first point, consider it the previous bin, too. + if( prev_bin == 0 ) + prev_bin = current_bin; + if( prev_bin == current_bin ) + bin_count++; + else + { // we are moving to a new bin -- consider adding to the sequence + // CHECKME tohle taky konfigurovatelne ? + if( bin_count >= ( min_bin_points_percentage_P * point_count / 100 ) + || sequence_count == 0 ) + { + if( sequence_count >= MAX_SEQUENCE ) + return NULL; + ret_val[ sequence_count++ ] = prev_bin + '0'; + } + // restart counting points in the new bin + bin_count=0; + prev_bin = current_bin; + } + } + + // add the last run of points to the sequence + if( sequence_count >= MAX_SEQUENCE - 1 ) + return NULL; + ret_val[ sequence_count++ ] = current_bin + '0'; + ret_val[ sequence_count ] = 0; // endmark + return ret_val; + } + +/* figure out which bin the point falls in */ +int Stroke::bin( int x, int y ) + { + int bin_num = 1; + if( x > bound_x_1 ) + ++bin_num; + if( x > bound_x_2 ) + ++bin_num; + if( y < bound_y_1 ) + bin_num += 3; + if( y < bound_y_2 ) + bin_num += 3; + return bin_num; + } + +} // namespace KHotKeys + +#include "gestures.moc" diff --git a/khotkeys/shared/gestures.h b/khotkeys/shared/gestures.h new file mode 100644 index 000000000..4c210528a --- /dev/null +++ b/khotkeys/shared/gestures.h @@ -0,0 +1,122 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2002 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#ifndef _GESTURES_H_ +#define _GESTURES_H_ + +#include <qwidget.h> +#include <qtimer.h> + +#include <X11/Xlib.h> +#include <fixx11h.h> + +#include "windows.h" + +namespace KHotKeys +{ + +class Gesture; +KDE_EXPORT extern Gesture* gesture_handler; + +class KDE_EXPORT Stroke + { + public: + // maximum number of numbers in stroke + enum { MAX_SEQUENCE = 25 }; + // largest number of points allowed to be sampled + enum { MAX_POINTS = 5000 }; + // default percentage of sample points in a bin from all points to be valid + enum { MIN_BIN_POINTS_PERCENTAGE = 5 }; + // default threshold of size of smaller axis needed for it to define its own bin size + enum { SCALE_RATIO = 4 }; + // default number of sample points required to have a valid stroke + enum { MIN_POINTS = 10 }; + Stroke(); + ~Stroke(); + bool record( int x, int y ); + char* translate( int min_bin_points_percentage_P = MIN_BIN_POINTS_PERCENTAGE, + int scale_ratio_P = SCALE_RATIO, int min_points_P = MIN_POINTS ); // CHECKME returns ret_val ( see below ) + void reset(); + protected: + int bin( int x, int y ); + // metrics for input stroke + int min_x, min_y; + int max_x, max_y; + int point_count; + int delta_x, delta_y; + int bound_x_1, bound_x_2; + int bound_y_1, bound_y_2; + struct point + { + int x; + int y; + }; + point* points; + char ret_val[ MAX_SEQUENCE ]; + }; + +class KDE_EXPORT Gesture + : public QWidget // not QObject because of x11EventFilter() + { + Q_OBJECT + public: + Gesture( bool enabled_P, QObject* parent_P ); + virtual ~Gesture(); + void enable( bool enable_P ); + void set_mouse_button( unsigned int button_P ); + void set_timeout( int time_P ); + void set_exclude( Windowdef_list* windows_P ); + void register_handler( QObject* receiver_P, const char* slot_P ); + void unregister_handler( QObject* receiver_P, const char* slot_P ); + protected: + virtual bool x11Event( XEvent* ev_P ); + private slots: + void stroke_timeout(); + void active_window_changed( WId window_P ); + signals: + void handle_gesture( const QString &gesture, WId window ); + private: + void update_grab(); + void grab_mouse( bool grab_P ); + void mouse_replay( bool release_P ); + bool _enabled; + Stroke stroke; + int start_x, start_y; + QTimer nostroke_timer; + bool recording; + unsigned int button; + int timeout; + WId gesture_window; + Windowdef_list* exclude; + QMap< QObject*, bool > handlers; // bool is just a dummy + }; + +// Gesture class must be QWidget derived because of x11Event() +// but it should be QObject owned -> use a QObject proxy that will delete it +class DeleteObject + : public QObject + { + Q_OBJECT + public: + DeleteObject( QWidget* widget_P, QObject* parent_P ) + : QObject( parent_P ), widget( widget_P ) {} + virtual ~DeleteObject() { delete widget; } + private: + QWidget* widget; + }; + + +//*************************************************************************** +// Inline +//*************************************************************************** + +} // namespace KHotKeys + +#endif diff --git a/khotkeys/shared/input.cpp b/khotkeys/shared/input.cpp new file mode 100644 index 000000000..021dedf93 --- /dev/null +++ b/khotkeys/shared/input.cpp @@ -0,0 +1,253 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#define _INPUT_CPP_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "input.h" + +#include <assert.h> +#include <qwidget.h> + +#include <kglobalaccel.h> +#include <kdebug.h> +#include <kapplication.h> +#include <kdeversion.h> +#include <qtimer.h> +#include <kkeynative.h> + +#include "khotkeysglobal.h" + +#include <X11/Xlib.h> +#include <X11/keysym.h> + +#include "windows.h" + +namespace KHotKeys +{ + +// Kbd + +Kbd::Kbd( bool grabbing_enabled_P, QObject* parent_P ) + : QObject( parent_P ) + { + assert( keyboard_handler == NULL ); + keyboard_handler = this; + kga = new KGlobalAccel( NULL ); + kga->setEnabled( grabbing_enabled_P ); + } + +Kbd::~Kbd() + { + keyboard_handler = NULL; + delete kga; + } + +void Kbd::insert_item( const KShortcut& shortcut_P, Kbd_receiver* receiver_P ) + { + Receiver_data& rcv = receivers[ receiver_P ]; + rcv.shortcuts.append( shortcut_P ); + if( rcv.active ) + grab_shortcut( shortcut_P ); + } + +void Kbd::remove_item( const KShortcut& shortcut_P, Kbd_receiver* receiver_P ) + { + Receiver_data& rcv = receivers[ receiver_P ]; + rcv.shortcuts.remove( shortcut_P ); + if( rcv.active ) + ungrab_shortcut( shortcut_P ); + if( rcv.shortcuts.count() == 0 ) + receivers.remove( receiver_P ); + } + +void Kbd::activate_receiver( Kbd_receiver* receiver_P ) + { + Receiver_data& rcv = receivers[ receiver_P ]; + if( rcv.active ) + return; + rcv.active = true; + for( QValueList< KShortcut >::ConstIterator it( rcv.shortcuts.begin()); + it != rcv.shortcuts.end(); + ++it ) + grab_shortcut( *it ); + } + +void Kbd::deactivate_receiver( Kbd_receiver* receiver_P ) + { + Receiver_data& rcv = receivers[ receiver_P ]; + if( !rcv.active ) + return; + rcv.active = false; + for( QValueList< KShortcut >::ConstIterator it( rcv.shortcuts.begin()); + it != rcv.shortcuts.end(); + ++it ) + ungrab_shortcut( *it ); + } + +void Kbd::grab_shortcut( const KShortcut& shortcut_P ) + { + if( grabs.contains( shortcut_P )) + ++grabs[ shortcut_P ]; + else + { + grabs[ shortcut_P ] = 1; +#if 0 + // CHECKME ugly ugly hack + QString name = ' ' + QString::number( keycode_P ); + kga->insertItem( "", name, keycode_P ); + kga->connectItem( name, this, SLOT( key_slot( int ))); +#endif + QString name = ' ' + shortcut_P.toStringInternal(); + kga->insert( name, name, QString::null, shortcut_P, shortcut_P, + this, SLOT( key_slot( QString ))); + QTimer::singleShot( 0, this, SLOT( update_connections())); + } + } + +void Kbd::ungrab_shortcut( const KShortcut& shortcut_P ) + { + if( !grabs.contains( shortcut_P )) + return; + if( --grabs[ shortcut_P ] == 0 ) + { +#if 0 + // CHECKME workaround for KGlobalAccel::disconnectItem() not working + kga->setItemEnabled( ' ' + QString::number( keycode_P ), false ); + // kga->disconnectItem( ' ' + QString::number( keycode_P ), NULL, NULL ); + kga->removeItem( ' ' + QString::number( keycode_P )); +#endif + kga->remove( ' ' + shortcut_P.toStringInternal()); + grabs.remove( shortcut_P ); + QTimer::singleShot( 0, this, SLOT( update_connections())); + } + } + +void Kbd::update_connections() + { + kga->updateConnections(); + } + +void Kbd::key_slot( QString key_P ) + { + kdDebug( 1217 ) << "Key pressed:" << key_P << endl; + KShortcut shortcut( key_P ); + if( !grabs.contains( shortcut )) + return; + for( QMap< Kbd_receiver*, Receiver_data >::ConstIterator it = receivers.begin(); + it != receivers.end(); + ++it ) + if( ( *it ).shortcuts.contains( shortcut ) && ( *it ).active + && it.key()->handle_key( shortcut )) + return; + } + + +#ifdef HAVE_XTEST + +} // namespace KHotKeys +#include <X11/extensions/XTest.h> +namespace KHotKeys +{ + +static bool xtest_available = false; +static bool xtest_inited = false; +static bool xtest() + { + if( xtest_inited ) + return xtest_available; + xtest_inited = true; + int dummy1, dummy2, dummy3, dummy4; + xtest_available = + ( XTestQueryExtension( qt_xdisplay(), &dummy1, &dummy2, &dummy3, &dummy4 ) == True ); + return xtest_available; + } +#endif + +// CHECKME nevola XFlush(), musi se pak volat rucne +bool Kbd::send_macro_key( const KKey& key, Window window_P ) + { + unsigned int keysym = KKeyNative( key ).sym(); + KeyCode x_keycode = XKeysymToKeycode( qt_xdisplay(), keysym ); + if( x_keycode == NoSymbol ) + return false; + unsigned int x_mod = KKeyNative( key ).mod(); +#ifdef HAVE_XTEST + if( xtest() && window_P == None ) + { + // CHECKME tohle jeste potrebuje modifikatory + bool ret = XTestFakeKeyEvent( qt_xdisplay(), x_keycode, True, CurrentTime ); + ret = ret && XTestFakeKeyEvent( qt_xdisplay(), x_keycode, False, CurrentTime ); + return ret; + } +#endif + if( window_P == None || window_P == InputFocus ) + window_P = windows_handler->active_window(); + if( window_P == None ) // CHECKME tohle cele je ponekud ... + window_P = InputFocus; + XEvent ev; + ev.type = KeyPress; + ev.xkey.display = qt_xdisplay(); + ev.xkey.window = window_P; + ev.xkey.root = qt_xrootwin(); // I don't know whether these have to be set + ev.xkey.subwindow = None; // to these values, but it seems to work, hmm + ev.xkey.time = CurrentTime; + ev.xkey.x = 0; + ev.xkey.y = 0; + ev.xkey.x_root = 0; + ev.xkey.y_root = 0; + ev.xkey.keycode = x_keycode; + ev.xkey.state = x_mod; + ev.xkey.same_screen = True; + bool ret = XSendEvent( qt_xdisplay(), window_P, True, KeyPressMask, &ev ); +#if 1 + ev.type = KeyRelease; // is this actually really needed ?? + ev.xkey.display = qt_xdisplay(); + ev.xkey.window = window_P; + ev.xkey.root = qt_xrootwin(); + ev.xkey.subwindow = None; + ev.xkey.time = CurrentTime; + ev.xkey.x = 0; + ev.xkey.y = 0; + ev.xkey.x_root = 0; + ev.xkey.y_root = 0; + ev.xkey.state = x_mod; + ev.xkey.keycode = x_keycode; + ev.xkey.same_screen = True; + ret = ret && XSendEvent( qt_xdisplay(), window_P, True, KeyReleaseMask, &ev ); +#endif + // Qt's autorepeat compression is broken and can create "aab" from "aba" + // XSync() should create delay longer than Qt's max autorepeat interval + XSync( qt_xdisplay(), False ); + return ret; + } + +bool Mouse::send_mouse_button( int button_P, bool release_P ) + { +#ifdef HAVE_XTEST + if( xtest()) + { + // CHECKME tohle jeste potrebuje modifikatory + // a asi i spravnou timestamp misto CurrentTime + bool ret = XTestFakeButtonEvent( qt_xdisplay(), button_P, True, CurrentTime ); + if( release_P ) + ret = ret && XTestFakeButtonEvent( qt_xdisplay(), button_P, False, CurrentTime ); + return ret; + } +#endif + return false; + } + +} // namespace KHotKeys + +#include "input.moc" diff --git a/khotkeys/shared/input.h b/khotkeys/shared/input.h new file mode 100644 index 000000000..1983bcf0b --- /dev/null +++ b/khotkeys/shared/input.h @@ -0,0 +1,87 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#ifndef _INPUT_H_ +#define _INPUT_H_ + +#include <qobject.h> +#include <qwindowdefs.h> +#include <qmap.h> +#include <qwidget.h> +#include <qvaluelist.h> +#include <kshortcut.h> + +#include <X11/X.h> +#include <fixx11h.h> + +class KGlobalAccel; + +namespace KHotKeys +{ + +class Kbd_receiver + { + public: + virtual bool handle_key( const KShortcut& shortcut_P ) = 0; + }; + +class Kbd + : public QObject + { + Q_OBJECT + public: + Kbd( bool grabbing_enabled_P, QObject* parent_P ); + virtual ~Kbd(); + void insert_item( const KShortcut& shortcut_P, Kbd_receiver* receiver_P ); + void remove_item( const KShortcut& shortcut_P, Kbd_receiver* receiver_P ); + void activate_receiver( Kbd_receiver* receiver_P ); + void deactivate_receiver( Kbd_receiver* receiver_P ); + static bool send_macro_key( const KKey& key, Window window_P = InputFocus ); + protected: + bool x11EventFilter( const XEvent* ); + void grab_shortcut( const KShortcut& shortcut_P ); + void ungrab_shortcut( const KShortcut& shortcut_P ); + private slots: + void key_slot( QString key_P ); + void update_connections(); + private: + struct Receiver_data + { + Receiver_data(); + QValueList< KShortcut > shortcuts; + bool active; + }; + QMap< Kbd_receiver*, Receiver_data > receivers; + QMap< KShortcut, int > grabs; + KGlobalAccel* kga; + }; + +class Mouse + { + public: + static bool send_mouse_button( int button_P, bool release_P ); + }; + + +//*************************************************************************** +// Inline +//*************************************************************************** + +// Kbd::Receiver_data + +inline +Kbd::Receiver_data::Receiver_data() + : active( false ) + { + } + +} // namespace KHotKeys + +#endif diff --git a/khotkeys/shared/khlistbox.cpp b/khotkeys/shared/khlistbox.cpp new file mode 100644 index 000000000..694fb658b --- /dev/null +++ b/khotkeys/shared/khlistbox.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2002 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#define _KHLISTBOX_CPP_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "khlistbox.h" + +#include <kdebug.h> + +namespace KHotKeys +{ + +KHListBox::KHListBox( QWidget* parent_P, const char* name_P ) + : QListBox( parent_P, name_P ), saved_current_item( NULL ), + in_clear( false ), force_select( false ) + { + connect( this, SIGNAL( selectionChanged( QListBoxItem* )), + SLOT( slot_selection_changed( QListBoxItem* ))); + connect( this, SIGNAL( currentChanged( QListBoxItem* )), + SLOT( slot_current_changed( QListBoxItem* ))); + // CHECKME grrr + connect( this, SIGNAL( selectionChanged()), + SLOT( slot_selection_changed())); + connect( &insert_select_timer, SIGNAL( timeout()), + SLOT( slot_insert_select())); + } + +void KHListBox::slot_selection_changed() + { + if( saved_current_item == NULL ) + slot_selection_changed( NULL ); + else if( !saved_current_item->isSelected()) // no way + setSelected( saved_current_item, true ); + } + +void KHListBox::slot_selection_changed( QListBoxItem* item_P ) + { + if( item_P == saved_current_item ) + return; + saved_current_item = item_P; + setCurrentItem( saved_current_item ); + emit current_changed( saved_current_item ); + } + +void KHListBox::slot_current_changed( QListBoxItem* item_P ) + { + insert_select_timer.stop(); + if( item_P == saved_current_item ) + return; + saved_current_item = item_P; + setSelected( saved_current_item, true ); + emit current_changed( saved_current_item ); + } + +// neni virtual :(( +void KHListBox::clear() + { + in_clear = true; + QListBox::clear(); + in_clear = false; + slot_selection_changed( NULL ); + } + + +// neni virtual :(( a vubec nefunguje +void KHListBox::insertItem( QListBoxItem* item_P ) + { + bool set = false; + if( !in_clear ) + set = count() == 0; + QListBox::insertItem( item_P ); + if( set && force_select ) + { + bool block = signalsBlocked(); + blockSignals( true ); + setCurrentItem( item_P ); + blockSignals( block ); + insert_select_timer.start( 0, true ); + } + } + +// items are often inserted using the QListBoxItem constructor, +// which means that a derived class are not yet fully created +void KHListBox::slot_insert_select() + { + slot_current_changed( item( currentItem())); + } + + +} // namespace KHotKeys + +#include "khlistbox.moc" diff --git a/khotkeys/shared/khlistbox.h b/khotkeys/shared/khlistbox.h new file mode 100644 index 000000000..95bd32963 --- /dev/null +++ b/khotkeys/shared/khlistbox.h @@ -0,0 +1,64 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2002 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#ifndef _KHLISTBOX_H_ +#define _KHLISTBOX_H_ + +#include <qtimer.h> + +#include <klistbox.h> + +namespace KHotKeys +{ + +class KHListBox + : public QListBox + { + Q_OBJECT + Q_PROPERTY( bool forceSelect READ forceSelect WRITE setForceSelect ) + public: + KHListBox( QWidget* parent_P, const char* name_P = NULL ); + virtual void clear(); + virtual void insertItem( QListBoxItem* item_P ); + bool forceSelect() const; + void setForceSelect( bool force_P ); + signals: + void current_changed( QListBoxItem* item_P ); + private slots: + void slot_selection_changed( QListBoxItem* item_P ); + void slot_selection_changed(); + void slot_current_changed( QListBoxItem* item_P ); + void slot_insert_select(); + private: + QListBoxItem* saved_current_item; + bool in_clear; + bool force_select; + QTimer insert_select_timer; + }; + +//*************************************************************************** +// Inline +//*************************************************************************** + +inline +void KHListBox::setForceSelect( bool force_P ) + { + force_select = force_P; + } + +inline +bool KHListBox::forceSelect() const + { + return force_select; + } + +} // namespace KHotKeys + +#endif diff --git a/khotkeys/shared/khlistview.cpp b/khotkeys/shared/khlistview.cpp new file mode 100644 index 000000000..45a1d04f9 --- /dev/null +++ b/khotkeys/shared/khlistview.cpp @@ -0,0 +1,122 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2002 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#define _KHLISTVIEW_CPP_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "khlistview.h" + +#include <kdebug.h> + +namespace KHotKeys +{ + +KHListView::KHListView( QWidget* parent_P, const char* name_P ) + : KListView( parent_P, name_P ), saved_current_item( NULL ), + in_clear( false ), ignore( false ), force_select( false ) + { + connect( this, SIGNAL( selectionChanged( QListViewItem* )), + SLOT( slot_selection_changed( QListViewItem* ))); + connect( this, SIGNAL( currentChanged( QListViewItem* )), + SLOT( slot_current_changed( QListViewItem* ))); + // CHECKME grrr + connect( this, SIGNAL( selectionChanged()), + SLOT( slot_selection_changed())); + connect( &insert_select_timer, SIGNAL( timeout()), + SLOT( slot_insert_select())); + } + +void KHListView::slot_selection_changed() + { + if( ignore ) + return; + if( saved_current_item == NULL ) + slot_selection_changed( NULL ); + else if( !saved_current_item->isSelected()) // no way + setSelected( saved_current_item, true ); + } + +void KHListView::slot_selection_changed( QListViewItem* item_P ) + { + if( ignore ) + return; + if( item_P == saved_current_item ) + return; + saved_current_item = item_P; + setCurrentItem( saved_current_item ); + emit current_changed( saved_current_item ); + } + +void KHListView::slot_current_changed( QListViewItem* item_P ) + { + if( ignore ) + return; + insert_select_timer.stop(); + if( item_P == saved_current_item ) + return; + saved_current_item = item_P; + setSelected( saved_current_item, true ); + emit current_changed( saved_current_item ); + } + +void KHListView::clear() + { + in_clear = true; + KListView::clear(); + in_clear = false; + slot_selection_changed( NULL ); + } + +void KHListView::insertItem( QListViewItem* item_P ) + { + bool set = false; + if( !in_clear ) + set = childCount() == 0; + KListView::insertItem( item_P ); + if( set && force_select ) + { + bool block = signalsBlocked(); + blockSignals( true ); +// SELI tohle spis jen blokovat sebe? + setCurrentItem( item_P ); + blockSignals( block ); + insert_select_timer.start( 0, true ); + } + } + +void KHListView::clearSelection() + { + KListView::clearSelection(); + slot_current_changed( currentItem()); + } + +// items are often inserted using the QListViewItem constructor, +// which means that a derived class are not yet fully created +void KHListView::slot_insert_select() + { + if( ignore ) + return; + slot_current_changed( currentItem()); + } + +void KHListView::contentsDropEvent( QDropEvent* e ) + { + bool save_ignore = ignore; + ignore = true; + KListView::contentsDropEvent( e ); + ignore = save_ignore; + } + +} // namespace KHotKeys + +#include "khlistview.moc" diff --git a/khotkeys/shared/khlistview.h b/khotkeys/shared/khlistview.h new file mode 100644 index 000000000..69986299d --- /dev/null +++ b/khotkeys/shared/khlistview.h @@ -0,0 +1,69 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2002 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#ifndef _KHLISTVIEW_H_ +#define _KHLISTVIEW_H_ + +#include <qtimer.h> + +#include <klistview.h> +#include <kdemacros.h> + +namespace KHotKeys +{ + +class KDE_EXPORT KHListView + : public KListView + { + Q_OBJECT + Q_PROPERTY( bool forceSelect READ forceSelect WRITE setForceSelect ) + public: + KHListView( QWidget* parent_P, const char* name_P = NULL ); + virtual void clear(); + virtual void insertItem( QListViewItem* item_P ); + virtual void clearSelection(); + bool forceSelect() const; + void setForceSelect( bool force_P ); + signals: + void current_changed( QListViewItem* item_P ); + protected: + virtual void contentsDropEvent (QDropEvent*); + private slots: + void slot_selection_changed( QListViewItem* item_P ); + void slot_selection_changed(); + void slot_current_changed( QListViewItem* item_P ); + void slot_insert_select(); + private: + QListViewItem* saved_current_item; + bool in_clear; + bool ignore; + bool force_select; + QTimer insert_select_timer; + }; + +//*************************************************************************** +// Inline +//*************************************************************************** + +inline +void KHListView::setForceSelect( bool force_P ) + { + force_select = force_P; + } + +inline +bool KHListView::forceSelect() const + { + return force_select; + } + +} // namespace KHotKeys + +#endif diff --git a/khotkeys/shared/khotkeysglobal.cpp b/khotkeys/shared/khotkeysglobal.cpp new file mode 100644 index 000000000..2b430fc8c --- /dev/null +++ b/khotkeys/shared/khotkeysglobal.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#define _KHOTKEYSGLOBAL_CPP_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "khotkeysglobal.h" + +#include <assert.h> +#include <kdebug.h> +#include <kstandarddirs.h> +#include <klibloader.h> + +#include "input.h" +#include "windows.h" +#include "triggers.h" +#include "gestures.h" +#include "voices.h" +#include "soundrecorder.h" + +namespace KHotKeys +{ + +Kbd* keyboard_handler; +Windows* windows_handler; +static bool _khotkeys_active = false; + +void init_global_data( bool active_P, QObject* owner_P ) + { + assert( keyboard_handler == NULL ); + assert( windows_handler == NULL ); + assert( gesture_handler == NULL ); + static_cast< void >( new Kbd( active_P, owner_P )); + static_cast< void >( new Windows( active_P, owner_P )); + static_cast< void >( new Gesture( active_P, owner_P )); + static_cast< void >( new Voice( active_P, owner_P )); + khotkeys_set_active( false ); + } + +void khotkeys_set_active( bool active_P ) + { + _khotkeys_active = active_P; + } + +bool khotkeys_active() + { + return _khotkeys_active; + } + +// does the opposite of KStandardDirs::findResource() i.e. e.g. +// "/opt/kde2/share/applnk/System/konsole.desktop" -> "System/konsole.desktop" +QString get_menu_entry_from_path( const QString& path_P ) + { + QStringList dirs = KGlobal::dirs()->resourceDirs( "apps" ); + for( QStringList::ConstIterator it = dirs.begin(); + it != dirs.end(); + ++it ) + if( path_P.find( *it ) == 0 ) + { + QString ret = path_P; + ret.remove( 0, (*it).length()); + if( ret[ 0 ] == '/' ) + ret.remove( 0, 1 ); + return ret; + } + return path_P; + } + +static int have_arts = -1; + +bool haveArts() + { + if( have_arts == -1 ) + { + have_arts = 0; + KLibrary* arts = KLibLoader::self()->library( "khotkeys_arts" ); + if( arts == NULL ) + kdDebug( 1217 ) << "Couldn't load khotkeys_arts:" << KLibLoader::self()->lastErrorMessage() << endl; + if( arts != NULL && SoundRecorder::init( arts )) + have_arts = 1; + } + return have_arts != 0; + } + +void disableArts() + { + have_arts = 0; + } + +} // namespace KHotKeys diff --git a/khotkeys/shared/khotkeysglobal.h b/khotkeys/shared/khotkeysglobal.h new file mode 100644 index 000000000..873473e0f --- /dev/null +++ b/khotkeys/shared/khotkeysglobal.h @@ -0,0 +1,59 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#ifndef _KHOTKEYSGLOBAL_H_ +#define _KHOTKEYSGLOBAL_H_ + +#define KHOTKEYS_VERSION "2.1" +#define KHOTKEYS_CONFIG_FILE "khotkeysrc" + +//#ifndef NDEBUG +//#define KHOTKEYS_DEBUG +//#endif + +#include <qstring.h> + +#include <klocale.h> + +class KConfig; +class QObject; + +namespace KHotKeys +{ + +class Kbd; +class Windows; +class Action_data_group; + +extern Kbd* keyboard_handler; +extern Windows* windows_handler; + +#define KHOTKEYS_DISABLE_COPY( cls ) private: cls( const cls& ); cls& operator=( const cls& ) + +// CHECKME hmms :( +KDE_EXPORT bool khotkeys_active(); +KDE_EXPORT void khotkeys_set_active( bool active_P ); + +QString get_menu_entry_from_path( const QString& path_P ); + +KDE_EXPORT void init_global_data( bool active_P, QObject* owner_P ); + +const char* const MENU_EDITOR_ENTRIES_GROUP_NAME = I18N_NOOP( "Menu Editor entries" ); + +KDE_EXPORT bool haveArts(); +KDE_EXPORT void disableArts(); + +//*************************************************************************** +// Inline +//*************************************************************************** + +} // namespace KHotKeys + +#endif diff --git a/khotkeys/shared/settings.cpp b/khotkeys/shared/settings.cpp new file mode 100644 index 000000000..829c8521a --- /dev/null +++ b/khotkeys/shared/settings.cpp @@ -0,0 +1,265 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#define _SETTINGS_CPP_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "settings.h" + +#include <kconfig.h> +#include <kdebug.h> +#include <klocale.h> +#include <kaccel.h> +#include <kglobal.h> +#include <kmessagebox.h> + +#include "triggers.h" +#include "conditions.h" +#include "action_data.h" + +namespace KHotKeys +{ + +// Settings + +Settings::Settings() + : actions( NULL ), gestures_exclude( NULL ) + { + } + +bool Settings::read_settings( bool include_disabled_P ) + { + KConfig cfg( KHOTKEYS_CONFIG_FILE, true ); + return read_settings( cfg, include_disabled_P, ImportNone ); + } + +bool Settings::import( KConfig& cfg_P, bool ask_P ) + { + return read_settings( cfg_P, true, ask_P ? ImportAsk : ImportSilent ); + } + +bool Settings::read_settings( KConfig& cfg_P, bool include_disabled_P, ImportType import_P ) + { + if( actions == NULL ) + actions = new Action_data_group( NULL, "should never see", "should never see", + NULL, Action_data_group::SYSTEM_ROOT, true ); + if( cfg_P.groupList().count() == 0 ) // empty + return false; + cfg_P.setGroup( "Main" ); // main group + if( import_P == ImportNone ) // reading main cfg file + already_imported = cfg_P.readListEntry( "AlreadyImported" ); + else + { + QString import_id = cfg_P.readEntry( "ImportId" ); + if( !import_id.isEmpty()) + { + if( already_imported.contains( import_id )) + { + if( import_P == ImportSilent + || KMessageBox::warningContinueCancel( NULL, + i18n( "This \"actions\" file has already been imported before. " + "Are you sure you want to import it again?" )) != KMessageBox::Continue ) + return true; // import "successful" + } + else + already_imported.append( import_id ); + } + else + { + if( import_P != ImportSilent + && KMessageBox::warningContinueCancel( NULL, + i18n( "This \"actions\" file has no ImportId field and therefore it cannot be determined " + "whether or not it has been imported already. Are you sure you want to import it?" )) + == KMessageBox::Cancel ) + return true; + } + } + int version = cfg_P.readNumEntry( "Version", -1234576 ); + switch( version ) + { + case 1: + read_settings_v1( cfg_P ); + break; + case 2: + read_settings_v2( cfg_P, include_disabled_P ); + break; + default: + kdWarning( 1217 ) << "Unknown cfg. file version\n"; + return false; + case -1234576: // no config file + if( import_P ) // if importing, this is an error + return false; + break; + } + if( import_P != ImportNone ) + return true; // don't read global settings + cfg_P.setGroup( "Main" ); // main group + daemon_disabled = cfg_P.readBoolEntry( "Disabled", false ); + cfg_P.setGroup( "Gestures" ); + gestures_disabled_globally = cfg_P.readBoolEntry( "Disabled", true ); + gesture_mouse_button = cfg_P.readNumEntry( "MouseButton", 2 ); + gesture_mouse_button = KCLAMP( gesture_mouse_button, 2, 9 ); + gesture_timeout = cfg_P.readNumEntry( "Timeout", 300 ); + cfg_P.setGroup( "GesturesExclude" ); + delete gestures_exclude; + gestures_exclude = new Windowdef_list( cfg_P ); + cfg_P.setGroup( "Voice" ); + voice_shortcut=KShortcut( cfg_P.readEntry("Shortcut" , "") ); + return true; + } + +void Settings::write_settings() + { + KConfig cfg( KHOTKEYS_CONFIG_FILE, false ); +// CHECKME smazat stare sekce ? + QStringList groups = cfg.groupList(); + for( QStringList::ConstIterator it = groups.begin(); + it != groups.end(); + ++it ) + cfg.deleteGroup( *it ); + cfg.setGroup( "Main" ); // main group + cfg.writeEntry( "Version", 2 ); // now it's version 2 cfg. file + cfg.writeEntry( "AlreadyImported", already_imported ); + cfg.setGroup( "Data" ); + int cnt = write_actions_recursively_v2( cfg, actions, true ); + cfg.setGroup( "Main" ); + cfg.writeEntry( "Autostart", cnt != 0 && !daemon_disabled ); + cfg.writeEntry( "Disabled", daemon_disabled ); + cfg.setGroup( "Gestures" ); + cfg.writeEntry( "Disabled", gestures_disabled_globally ); + cfg.writeEntry( "MouseButton", gesture_mouse_button ); + cfg.writeEntry( "Timeout", gesture_timeout ); + if( gestures_exclude != NULL ) + { + cfg.setGroup( "GesturesExclude" ); + gestures_exclude->cfg_write( cfg ); + } + else + cfg.deleteGroup( "GesturesExclude" ); + cfg.setGroup( "Voice" ); + cfg.writeEntry("Shortcut" , voice_shortcut.toStringInternal() ); + + } + + +// return value means the number of enabled actions written in the cfg file +// i.e. 'Autostart' for value > 0 should be on +int Settings::write_actions_recursively_v2( KConfig& cfg_P, Action_data_group* parent_P, bool enabled_P ) + { + int enabled_cnt = 0; + QString save_cfg_group = cfg_P.group(); + int cnt = 0; + for( Action_data_group::Iterator it = parent_P->first_child(); + it; + ++it ) + { + ++cnt; + if( enabled_P && (*it)->enabled( true )) + ++enabled_cnt; + cfg_P.setGroup( save_cfg_group + "_" + QString::number( cnt )); + ( *it )->cfg_write( cfg_P ); + Action_data_group* grp = dynamic_cast< Action_data_group* >( *it ); + if( grp != NULL ) + enabled_cnt += write_actions_recursively_v2( cfg_P, grp, enabled_P && (*it)->enabled( true )); + } + cfg_P.setGroup( save_cfg_group ); + cfg_P.writeEntry( "DataCount", cnt ); + return enabled_cnt; + } + +void Settings::read_settings_v2( KConfig& cfg_P, bool include_disabled_P ) + { + cfg_P.setGroup( "Data" ); + read_actions_recursively_v2( cfg_P, actions, include_disabled_P ); + } + +void Settings::read_actions_recursively_v2( KConfig& cfg_P, Action_data_group* parent_P, + bool include_disabled_P ) + { + QString save_cfg_group = cfg_P.group(); + int cnt = cfg_P.readNumEntry( "DataCount" ); + for( int i = 1; + i <= cnt; + ++i ) + { + cfg_P.setGroup( save_cfg_group + "_" + QString::number( i )); + if( include_disabled_P || Action_data_base::cfg_is_enabled( cfg_P )) + { + Action_data_base* new_action = Action_data_base::create_cfg_read( cfg_P, parent_P ); + Action_data_group* grp = dynamic_cast< Action_data_group* >( new_action ); + if( grp != NULL ) + read_actions_recursively_v2( cfg_P, grp, include_disabled_P ); + } + } + cfg_P.setGroup( save_cfg_group ); + } + +// backward compatibility +void Settings::read_settings_v1( KConfig& cfg_P ) + { + int sections = cfg_P.readNumEntry( "Num_Sections", 0 ); + Action_data_group* menuentries = NULL; + for( Action_data_group::Iterator it( actions->first_child()); + *it; + ++it ) + { + Action_data_group* tmp = dynamic_cast< Action_data_group* >( *it ); + if( tmp == NULL ) + continue; + if( tmp->system_group() == Action_data_group::SYSTEM_MENUENTRIES ) + { + menuentries = tmp; + break; + } + } + for( int sect = 1; + sect <= sections; + ++sect ) + { + QString group = QString( "Section%1" ).arg( sect ); + if( !cfg_P.hasGroup( group )) + continue; + cfg_P.setGroup( group ); + QString name = cfg_P.readEntry( "Name" ); + if( name.isNull() ) + continue; + QString shortcut = cfg_P.readEntry( "Shortcut" ); + if( shortcut.isNull() ) + continue; + QString run = cfg_P.readEntry( "Run" ); + if( run.isNull() ) + continue; + bool menuentry = cfg_P.readBoolEntry( "MenuEntry", false ); + // CHECKME tohle pridavani az pak je trosku HACK + if( menuentry ) + { + if( menuentries == NULL ) + { + menuentries = new Action_data_group( actions, + i18n( MENU_EDITOR_ENTRIES_GROUP_NAME ), + i18n( "These entries were created using Menu Editor." ), NULL, + Action_data_group::SYSTEM_MENUENTRIES, true ); + menuentries->set_conditions( new Condition_list( "", menuentries )); + } + ( void ) new Menuentry_shortcut_action_data( menuentries, name, "", + KShortcut( shortcut ), run ); + } + else + { + ( void ) new Command_url_shortcut_action_data( actions, name, "", + KShortcut( shortcut ), run ); + } + } + } + +} // namespace KHotKeys diff --git a/khotkeys/shared/settings.h b/khotkeys/shared/settings.h new file mode 100644 index 000000000..cf05dcd31 --- /dev/null +++ b/khotkeys/shared/settings.h @@ -0,0 +1,61 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#ifndef _SETTINGS_H_ +#define _SETTINGS_H_ + +#include "actions.h" +#include <kshortcut.h> + +class KConfig; + +namespace KHotKeys +{ + +enum ImportType + { + ImportNone, // no import is done + ImportAsk, // if already imported before, ask (called from GUI) + ImportSilent // if already imported before, ignore (called from the update script) + }; + +class KDE_EXPORT Settings + { + public: + Settings(); + bool read_settings( bool include_disabled_P ); + void write_settings(); + bool import( KConfig& cfg_P, bool ask_P ); + Action_data_group* actions; + bool gestures_disabled_globally; + int gesture_mouse_button; + int gesture_timeout; + bool daemon_disabled; + Windowdef_list* gestures_exclude; + KShortcut voice_shortcut; + protected: + bool read_settings( KConfig& cfg_P, bool include_disabled_P, ImportType import_P ); + void read_settings_v1( KConfig& cfg_P ); + void read_settings_v2( KConfig& cfg_P, bool include_disabled_P ); + int write_actions_recursively_v2( KConfig& cfg_P, Action_data_group* parent_P, bool enabled_P ); + void read_actions_recursively_v2( KConfig& cfg_P, Action_data_group* parent_P, + bool include_disabled_P ); + private: + QStringList already_imported; + KHOTKEYS_DISABLE_COPY( Settings ); + }; + +//*************************************************************************** +// Inline +//*************************************************************************** + +} // namespace KHotKeys + +#endif diff --git a/khotkeys/shared/sound.cpp b/khotkeys/shared/sound.cpp new file mode 100644 index 000000000..e8d4191eb --- /dev/null +++ b/khotkeys/shared/sound.cpp @@ -0,0 +1,343 @@ +/*************************************************************************** + * Copyright (C) 2005 by Olivier Goffart * + * ogoffart@kde.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "sound.h" +#include <qfile.h> +#include <qdatastream.h> +#include <kdebug.h> + + + + +Sound::Sound() +{ +} + + +Sound::~Sound() +{ +} + + +#define READ_FROM_STREAM(FORMAT,NAME) FORMAT NAME; stream >> NAME; +#define MAGIC(CH) { \ + stream >> magic; \ + if( magic != ( (CH)[0] | (CH)[1]<<8 | (CH)[2]<< 16 | (CH)[3] << 24 ) ) \ + { \ + kdWarning() << k_funcinfo << "bad format " << magic << " != " << CH "\n";\ + return;\ + } } + +#define ABS(X) ( (X>0) ? X : -X ) + +void Sound::load(const QString& filename) +{ + kdDebug() << k_funcinfo << filename << endl; + data=QMemArray<Q_INT32>(); + QFile file(filename); + if(!file.open(IO_ReadOnly)) + { + kdWarning() << k_funcinfo <<"unable to open file" << endl; + return; + } + QDataStream stream(&file); + stream.setByteOrder( QDataStream::LittleEndian ); + Q_INT32 magic; + + MAGIC("RIFF"); + READ_FROM_STREAM(Q_UINT32,ChunkSize); + MAGIC("WAVE"); + MAGIC("fmt "); + READ_FROM_STREAM(Q_UINT32,ChunkSize2); + READ_FROM_STREAM(Q_INT16,AudioFormat); + READ_FROM_STREAM(Q_UINT16,NumberOfChannels); + READ_FROM_STREAM(Q_UINT32,SampleRate); + _fs=SampleRate; + READ_FROM_STREAM(Q_UINT32,ByteRate); + READ_FROM_STREAM(Q_UINT16,BlockAlign); + READ_FROM_STREAM(Q_UINT16,BitsPerSample); + MAGIC("data"); + READ_FROM_STREAM(QByteArray,SoundData); + NumberOfChannels=1; //Wav i play are broken + + file.close(); + + uint BytePS=BitsPerSample/8; + uint NumberOfSamples = (SoundData.size())/(NumberOfChannels*BytePS); + + + data.resize(NumberOfSamples); + +// kdDebug() << k_funcinfo << NumberOfSamples << " samples" << endl; + + max=0; + for(unsigned long int f=0;f<NumberOfSamples;f++) + { + Q_INT32 nb=0; + for(uint k=0;k<BytePS;k++) + { + nb |= (SoundData[f*BytePS+k]&0x000000FF) << (k*8); + } + if(nb & (1 << (BytePS*8 -1)) ) + nb = nb-(1<<BytePS*8); + data[f]=nb; + if(ABS(nb)>max) + { + max=ABS(nb); + } + } + +/* static int q=0; + QString name="test" + QString::number(q++) + ".wav"; + save(name);*/ + +} + +#define SMAGIC(CH) { stream << ( Q_INT32) ( (CH)[0] | (CH)[1]<<8 | (CH)[2]<< 16 | (CH)[3] << 24 ) ; } + +void Sound::save(const QString& filename) const +{ + kdDebug( 1217 ) << k_funcinfo << filename << " - " << data.size() << endl; + QFile file(filename); + if(!file.open(IO_WriteOnly)) + { + kdWarning() << k_funcinfo <<"unable to open file" << endl; + return; + } + QDataStream stream(&file); + stream.setByteOrder( QDataStream::LittleEndian ); + + + QByteArray SoundData(data.size()*2); + + for(unsigned long int f=0;f<data.size();f++) + { + Q_UINT16 val= (signed short int) ( (data.at(f) * ((double)(1<<13)/(signed)max) ) ); + SoundData[ 2*f ]= val & 0x00FF; + SoundData[2*f+1]= (val & 0xFF00) >> 8; + +// kdDebug( 1217 ) << k_funcinfo << data.at(f) << " / " << max << " = " << val << " | " << SoundData[ 2*f ] << " "<< SoundData[ 2*f+1 ] << endl; + } + + Q_UINT16 NumberOfChannels=2; + Q_UINT32 SampleRate=_fs; + + SMAGIC("RIFF"); + //READ_FROM_STREAM(Q_UINT32,ChunkSize); + stream << (Q_UINT32)(36+ SoundData.size()); + SMAGIC("WAVE"); + SMAGIC("fmt "); + //READ_FROM_STREAM(Q_UINT32,ChunkSize2); + stream << (Q_UINT32)(16); + //READ_FROM_STREAM(Q_INT16,AudioFormat); + stream << (Q_INT16)(1); + //READ_FROM_STREAM(Q_UINT16,NumberOfChannels); + stream << (Q_UINT16)(NumberOfChannels); + //READ_FROM_STREAM(Q_UINT32,SampleRate); + stream << (Q_UINT32)(SampleRate); + //READ_FROM_STREAM(Q_UINT32,ByteRate); + stream << (Q_UINT32)(NumberOfChannels*SampleRate*16/8); + //READ_FROM_STREAM(Q_UINT16,BlockAlign); + stream << (Q_UINT16)(16/8 *NumberOfChannels); + //READ_FROM_STREAM(Q_UINT16,BitsPerSample); + stream << (Q_UINT16)(16); + SMAGIC("data"); + //READ_FROM_STREAM(QByteArray,SoundData); + stream << SoundData; + + file.close(); + +} + + + + +#if 0 +void Sound::load(const QString& filename) +{ + cout << "saout \n"; + data=QMemArray<long unsigned int>(); + static const int BUFFER_LEN = 4096; + + //code from libtunepimp + //(wav_trm.cpp) + + FILE *source; + unsigned char buffer[100], *copyBuffer; + unsigned int bytes; + unsigned long ulRIFF; + unsigned long ulLength; + unsigned long ulWAVE; + unsigned long ulType; + unsigned long ulCount; + unsigned long ulLimit; + bool haveWaveHeader = false; + unsigned long waveSize = 0; + WAVEFORMAT waveFormat; + int toRead; + mb_int64_t fileLen = 0; + + source = fopen(filename.ascii(), "rb"); + if (source == NULL) + { +// errorString = string("File not found"); +// fclose(source); + cout << "File not found \n"; + return; + } + + fseek(source, 0, SEEK_END); + fileLen = ftell(source); + fseek(source, 0, SEEK_SET); + + if (fread(buffer, 1, 12, source) != 12) + { +// errorString = string("File is too short"); + cout << "File is to short \n"; + fclose(source); + return ; + } + + ulRIFF = (unsigned long)(((unsigned long *)buffer)[0]); + ulLength = (unsigned long)(((unsigned long *)buffer)[1]); + ulWAVE = (unsigned long)(((unsigned long *)buffer)[2]); + + if(ulRIFF != MAKEFOURCC('R', 'I', 'F', 'F') || + ulWAVE != MAKEFOURCC('W', 'A', 'V', 'E')) + { +// errorString = strdup("File is not in WAVE format"); + cout << "File is not WAVE \n"; + fclose(source); + return ; + } + + // Run through the bytes looking for the tags + ulCount = 0; + ulLimit = ulLength - 4; + while (ulCount < ulLimit && waveSize == 0) + { + if (fread(buffer, 1, 8, source) != 8) + { +// errorString = strdup("File is too short"); + cout << "File is to short \n"; + fclose(source); + return; + } + + ulType = (unsigned long)(((unsigned long *)buffer)[0]); + ulLength = (unsigned long)(((unsigned long *)buffer)[1]); + switch (ulType) + { + // format + case MAKEFOURCC('f', 'm', 't', ' '): + if (ulLength < sizeof(WAVEFORMAT)) + { +// errorString = strdup("File is too short"); + cout << "File is to short \n"; + fclose(source); + return ; + } + + if (fread(&waveFormat, 1, ulLength, source) != ulLength) + { +// errorString = strdup("File is too short"); + cout << "File is to short \n"; + fclose(source); + return ; + } + + if (waveFormat.wFormatTag != WAVE_FORMAT_PCM) + { +// errorString = strdup("Unsupported WAV format"); + cout << "Unsupported WAVE \n"; + fclose(source); + return ; + } + haveWaveHeader = true; + + ulCount += ulLength; + break; + + // data + case MAKEFOURCC('d', 'a', 't', 'a'): + waveSize = ulLength; + break; + + default: + fseek(source, ulLength, SEEK_CUR); + break; + + } + } + + + if (!haveWaveHeader) + { +// errorString = strdup("Could not find WAV header"); + cout << "Header nbot found \n"; + fclose(source); + return ; + } + + fileLen -= (mb_int64_t)ftell(source); + fileLen /= waveFormat.nChannels; + fileLen /= (waveFormat.nBlockAlign / waveFormat.nChannels); + + fileLen /= waveFormat.nSamplesPerSec; + + //on ne lit qu'un channel + //waveSize=fileLen; + data.resize(waveSize); + unsigned long pos=0; + + cout << "Weeee "<< waveSize <<"\n"; + + copyBuffer = (unsigned char*)malloc(BUFFER_LEN); + if (copyBuffer == NULL) + { +// errorString = strdup("Cannot allocate buffer space."); + return ; + } + + for(;;) + { + toRead = min(waveSize, (unsigned long)BUFFER_LEN); + if (toRead <= 0) + break; + + bytes = fread(copyBuffer, 1, toRead, source); + if (bytes <= 0) + break; + + for(uint f=0;f<bytes;f+=4) + { + data[pos]=(((unsigned long*)copyBuffer)[f/4]); + pos++; + } + + waveSize -= toRead; + } + free(copyBuffer); + fclose(source); + + return ; +} + +#endif diff --git a/khotkeys/shared/sound.h b/khotkeys/shared/sound.h new file mode 100644 index 000000000..1a38f182f --- /dev/null +++ b/khotkeys/shared/sound.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (C) 2005 by Olivier Goffart * + * ogoffart@kde.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef SOUND_H +#define SOUND_H + +#include <qmemarray.h> +#include <qstring.h> +#include <kdemacros.h> + +/** +@author Olivier Goffart +*/ +class KDE_EXPORT Sound{ +public: + Sound(); + ~Sound(); + + void load(const QString &filename); + void save(const QString &filename) const; + + unsigned int size() const + { + return data.size(); + } + + inline float at(int pos) const + { + return (float)(data.at(pos))/max; + } + + inline uint fs() const + { + return _fs; + } + + QMemArray<Q_INT32> data; + Q_UINT32 max; + uint _fs; +}; + +#endif diff --git a/khotkeys/shared/soundrecorder.cpp b/khotkeys/shared/soundrecorder.cpp new file mode 100644 index 000000000..fc2031113 --- /dev/null +++ b/khotkeys/shared/soundrecorder.cpp @@ -0,0 +1,86 @@ +/*************************************************************************** + * Copyright (C) 2005 by Olivier Goffart * + * ogoffart@kde.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +#include "soundrecorder.h" + +#include <kdebug.h> +#include <klocale.h> +#include <qtimer.h> +#include <klibloader.h> + +#include "khotkeysglobal.h" + +namespace KHotKeys +{ + +SoundRecorder::create_ptr SoundRecorder::create_fun = NULL; + +bool SoundRecorder::init( KLibrary* lib ) +{ +#ifdef HAVE_ARTS + if( create_fun == NULL && lib != NULL ) + create_fun = (create_ptr) lib->symbol( "khotkeys_soundrecorder_create" ); +#endif +// kdDebug( 1217 ) << "soundrecorder:" << create_fun << ":" << lib << endl; + return create_fun != NULL; +} + +SoundRecorder* SoundRecorder::create( QObject* parent, const char* name ) +{ +#ifdef HAVE_ARTS + if( create_fun != NULL ) + return create_fun( parent, name ); +#endif + return new SoundRecorder( parent, name ); +} + +SoundRecorder::SoundRecorder(QObject *parent, const char *name) : QObject(parent, name) {} + +SoundRecorder::~SoundRecorder() +{ +} + +void SoundRecorder::start() +{ +} + +void SoundRecorder::stop() +{ +} + +void SoundRecorder::abort() +{ +} + + +Sound SoundRecorder::sound() +{ + Sound s; + return s; +} + +} + +#include "soundrecorder.moc" diff --git a/khotkeys/shared/soundrecorder.h b/khotkeys/shared/soundrecorder.h new file mode 100644 index 000000000..d9539c4c5 --- /dev/null +++ b/khotkeys/shared/soundrecorder.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2005 by Olivier Goffart * + * ogoffart@kde.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef RECORDER_H +#define RECORDER_H + +#include <qobject.h> +#include "sound.h" +#include <kdemacros.h> + +class KLibrary; + +namespace KHotKeys +{ + + + +/** +@author Olivier Goffart +*/ +class KDE_EXPORT SoundRecorder : public QObject +{ +Q_OBJECT +public: + static SoundRecorder* create( QObject* parent = 0, const char* name = 0 ); + virtual ~SoundRecorder(); + + virtual void start(); + virtual void stop(); + virtual void abort(); + virtual Sound sound(); + + static bool init( KLibrary* ); +signals: + void recorded(const Sound&); + +protected: + SoundRecorder(QObject *parent = 0, const char *name = 0); + typedef SoundRecorder* (*create_ptr)( QObject*, const char* ); +private: + static create_ptr create_fun; +}; + +} + +#endif diff --git a/khotkeys/shared/triggers.cpp b/khotkeys/shared/triggers.cpp new file mode 100644 index 000000000..1febedfa9 --- /dev/null +++ b/khotkeys/shared/triggers.cpp @@ -0,0 +1,435 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#define _TRIGGERS_CPP_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "triggers.h" + +#include <kglobalaccel.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kwinmodule.h> +#include <klocale.h> +#include <netwm_def.h> +#include <kaccel.h> + +#include <X11/Xlib.h> +#include <X11/keysym.h> + +#include "actions.h" +#include "action_data.h" +#include "input.h" +#include "gestures.h" +#include "windows.h" +#include "voices.h" + +namespace KHotKeys +{ + +// Trigger + +void Trigger::cfg_write( KConfig& cfg_P ) const + { + cfg_P.writeEntry( "Type", "ERROR" ); + } + +Trigger* Trigger::create_cfg_read( KConfig& cfg_P, Action_data* data_P ) + { + QString type = cfg_P.readEntry( "Type" ); + if( type == "SHORTCUT" || type == "SINGLE_SHORTCUT" ) + return new Shortcut_trigger( cfg_P, data_P ); + if( type == "WINDOW" ) + return new Window_trigger( cfg_P, data_P ); + if( type == "GESTURE" ) + return new Gesture_trigger(cfg_P, data_P ); + if( type == "VOICE" ) + return new Voice_trigger (cfg_P, data_P ); + + kdWarning( 1217 ) << "Unknown Trigger type read from cfg file\n"; + return NULL; + } + +// Trigger_list + +Trigger_list::Trigger_list( KConfig& cfg_P, Action_data* data_P ) + : QPtrList< Trigger >() + { + setAutoDelete( true ); + _comment = cfg_P.readEntry( "Comment" ); + QString save_cfg_group = cfg_P.group(); + int cnt = cfg_P.readNumEntry( "TriggersCount", 0 ); + for( int i = 0; + i < cnt; + ++i ) + { + cfg_P.setGroup( save_cfg_group + QString::number( i )); + Trigger* trigger = Trigger::create_cfg_read( cfg_P, data_P ); + if( trigger ) + append( trigger ); + } + cfg_P.setGroup( save_cfg_group ); + } + +void Trigger_list::cfg_write( KConfig& cfg_P ) const + { + cfg_P.writeEntry( "Comment", comment()); + QString save_cfg_group = cfg_P.group(); + int i = 0; + for( Iterator it( *this ); + it; + ++it, ++i ) + { + cfg_P.setGroup( save_cfg_group + QString::number( i )); + it.current()->cfg_write( cfg_P ); + } + cfg_P.setGroup( save_cfg_group ); + cfg_P.writeEntry( "TriggersCount", i ); + } + +Trigger_list* Trigger_list::copy( Action_data* data_P ) const + { + Trigger_list* ret = new Trigger_list( comment()); + for( Iterator it( *this ); + it; + ++it ) + ret->append( it.current()->copy( data_P )); + return ret; + } + +void Trigger_list::activate( bool activate_P ) + { + for( Iterator it( *this ); + it; + ++it ) + ( *it )->activate( activate_P ); + } + +// Shortcut_trigger + +Shortcut_trigger::Shortcut_trigger( Action_data* data_P, const KShortcut& shortcut_P ) + : Trigger( data_P ), _shortcut( shortcut_P ) + { + keyboard_handler->insert_item( shortcut(), this ); + } + +Shortcut_trigger::Shortcut_trigger( KConfig& cfg_P, Action_data* data_P ) + : Trigger( cfg_P, data_P ), _shortcut( cfg_P.readEntry( "Key", 0 )) + { + keyboard_handler->insert_item( shortcut(), this ); + } + +Shortcut_trigger::~Shortcut_trigger() + { + keyboard_handler->remove_item( shortcut(), this ); + } + +void Shortcut_trigger::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Key", _shortcut.toStringInternal()); + cfg_P.writeEntry( "Type", "SHORTCUT" ); // overwrites value set in base::cfg_write() + } + +Shortcut_trigger* Shortcut_trigger::copy( Action_data* data_P ) const + { + kdDebug( 1217 ) << "Shortcut_trigger::copy()" << endl; + return new Shortcut_trigger( data_P ? data_P : data, shortcut()); + } + +const QString Shortcut_trigger::description() const + { + // CHECKME vice mods + return i18n( "Shortcut trigger: " ) + _shortcut.toString(); + // CHECKME i18n pro toString() ? + } + +bool Shortcut_trigger::handle_key( const KShortcut& shortcut_P ) + { + if( shortcut() == shortcut_P ) + { + windows_handler->set_action_window( 0 ); // use active window + data->execute(); + return true; + } + return false; + } + +void Shortcut_trigger::activate( bool activate_P ) + { + if( activate_P && khotkeys_active()) + keyboard_handler->activate_receiver( this ); + else + keyboard_handler->deactivate_receiver( this ); + } + +// Window_trigger + +Window_trigger::Window_trigger( KConfig& cfg_P, Action_data* data_P ) + : Trigger( cfg_P, data_P ), active( false ) + { +// kdDebug( 1217 ) << "Window_trigger" << endl; + QString save_cfg_group = cfg_P.group(); + cfg_P.setGroup( save_cfg_group + "Windows" ); + _windows = new Windowdef_list( cfg_P ); + cfg_P.setGroup( save_cfg_group ); + window_actions = cfg_P.readNumEntry( "WindowActions" ); + init(); + } + +Window_trigger::~Window_trigger() + { +// kdDebug( 1217 ) << "~Window_trigger :" << this << endl; + disconnect( windows_handler, NULL, this, NULL ); + delete _windows; + } + +void Window_trigger::init() + { + kdDebug( 1217 ) << "Window_trigger::init()" << endl; + connect( windows_handler, SIGNAL( window_added( WId )), this, SLOT( window_added( WId ))); + connect( windows_handler, SIGNAL( window_removed( WId )), this, SLOT( window_removed( WId ))); + if( window_actions & ( WINDOW_ACTIVATES | WINDOW_DEACTIVATES /*| WINDOW_DISAPPEARS*/ )) + connect( windows_handler, SIGNAL( active_window_changed( WId )), + this, SLOT( active_window_changed( WId ))); + connect( windows_handler, SIGNAL( window_changed( WId, unsigned int )), + this, SLOT( window_changed( WId, unsigned int ))); + } + +void Window_trigger::activate( bool activate_P ) + { + active = activate_P && khotkeys_active(); + } + +void Window_trigger::window_added( WId window_P ) + { + bool matches = windows()->match( Window_data( window_P )); + existing_windows[ window_P ] = matches; + kdDebug( 1217 ) << "Window_trigger::w_added() : " << matches << endl; + if( active && matches && ( window_actions & WINDOW_APPEARS )) + { + windows_handler->set_action_window( window_P ); + data->execute(); + } + } + +void Window_trigger::window_removed( WId window_P ) + { + if( existing_windows.contains( window_P )) + { + bool matches = existing_windows[ window_P ]; + kdDebug( 1217 ) << "Window_trigger::w_removed() : " << matches << endl; + if( active && matches && ( window_actions & WINDOW_DISAPPEARS )) + { + windows_handler->set_action_window( window_P ); + data->execute(); + } + existing_windows.remove( window_P ); + // CHECKME jenze co kdyz se window_removed zavola pred active_window_changed ? + } + else + kdDebug( 1217 ) << "Window_trigger::w_removed()" << endl; + } + +void Window_trigger::active_window_changed( WId window_P ) + { + bool was_match = false; + if( existing_windows.contains( last_active_window )) + was_match = existing_windows[ last_active_window ]; + if( active && was_match && ( window_actions & WINDOW_DEACTIVATES )) + { + windows_handler->set_action_window( window_P ); + data->execute(); + } +/* bool matches = windows()->match( Window_data( window_P )); + existing_windows[ window_P ] = matches;*/ + bool matches = existing_windows.contains( window_P ) + ? existing_windows[ window_P ] : false; + if( active && matches && ( window_actions & WINDOW_ACTIVATES )) + { + windows_handler->set_action_window( window_P ); + data->execute(); + } + kdDebug( 1217 ) << "Window_trigger::a_w_changed() : " << was_match << "|" << matches << endl; + last_active_window = window_P; + } + +void Window_trigger::window_changed( WId window_P, unsigned int dirty_P ) + { // CHECKME snad nebude mit vliv, kdyz budu kaslat na properties_P a zkratka + // kontrolovat kazdou zmenu + // CHECKME kdyz se zmeni okno z match na non-match, asi to nebrat jako DISAPPEAR + if( ! ( dirty_P & ( NET::WMName | NET::WMWindowType ))) + return; + kdDebug( 1217 ) << "Window_trigger::w_changed()" << endl; + bool was_match = false; + if( existing_windows.contains( window_P )) + was_match = existing_windows[ window_P ]; + bool matches = windows()->match( Window_data( window_P )); + existing_windows[ window_P ] = matches; + if( active && matches && !was_match ) + if( window_actions & WINDOW_APPEARS ) + { + windows_handler->set_action_window( window_P ); + data->execute(); + } + else if( window_actions & WINDOW_ACTIVATES && window_P == windows_handler->active_window()) + { + windows_handler->set_action_window( window_P ); + data->execute(); + } + kdDebug( 1217 ) << "Window_trigger::w_changed() : " << was_match << "|" << matches << endl; + } + +void Window_trigger::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + QString save_cfg_group = cfg_P.group(); + cfg_P.setGroup( save_cfg_group + "Windows" ); + windows()->cfg_write( cfg_P ); + cfg_P.setGroup( save_cfg_group ); + cfg_P.writeEntry( "WindowActions", window_actions ); + cfg_P.writeEntry( "Type", "WINDOW" ); // overwrites value set in base::cfg_write() + } + +#ifndef COVARIANT_RETURN_BROKEN // stupid gcc, it doesn't even warn it can't do this +Window_trigger* Window_trigger::copy( Action_data* data_P ) const +#else +Trigger* Window_trigger::copy( Action_data* data_P ) const +#endif + { + Window_trigger* ret = new Window_trigger( data_P ? data_P : data, windows()->copy(), + window_actions ); + ret->existing_windows = existing_windows; // CHECKME je tohle vazne treba ? + return ret; + } + +const QString Window_trigger::description() const + { + return i18n( "Window trigger: " ) + windows()->comment(); + } + +// Gesture_trigger + +Gesture_trigger::Gesture_trigger( Action_data* data_P, const QString &gesturecode_P ) + : Trigger( data_P ), _gesturecode( gesturecode_P ) + { + } + +Gesture_trigger::Gesture_trigger( KConfig& cfg_P, Action_data* data_P ) + : Trigger( cfg_P, data_P ) + { + _gesturecode = cfg_P.readEntry( "Gesture" ); + } + +Gesture_trigger::~Gesture_trigger() + { + gesture_handler->unregister_handler( this, SLOT( handle_gesture( const QString&, WId ))); + } + +void Gesture_trigger::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Gesture", gesturecode()); + cfg_P.writeEntry( "Type", "GESTURE" ); // overwrites value set in base::cfg_write() + } + +Trigger* Gesture_trigger::copy( Action_data* data_P ) const + { + kdDebug( 1217 ) << "Gesture_trigger::copy()" << endl; + return new Gesture_trigger( data_P ? data_P : data, gesturecode()); + } + +const QString Gesture_trigger::description() const + { + return i18n( "Gesture trigger: " ) + gesturecode(); + } + +void Gesture_trigger::handle_gesture( const QString &gesture_P, WId window_P ) + { + if( gesturecode() == gesture_P ) + { + windows_handler->set_action_window( window_P ); + data->execute(); + } + } + +void Gesture_trigger::activate( bool activate_P ) + { + if( activate_P ) + gesture_handler->register_handler( this, SLOT( handle_gesture( const QString&, WId ))); + else + gesture_handler->unregister_handler( this, SLOT( handle_gesture( const QString&, WId ))); + } + + +// Voice_trigger + + Voice_trigger::Voice_trigger( Action_data* data_P, const QString &Voicecode_P, const VoiceSignature& signature1_P, const VoiceSignature& signature2_P ) + : Trigger( data_P ), _voicecode( Voicecode_P ) + { + _voicesignature[0]=signature1_P; + _voicesignature[1]=signature2_P; + } + +Voice_trigger::Voice_trigger( KConfig& cfg_P, Action_data* data_P ) + : Trigger( cfg_P, data_P ) + { + _voicecode = cfg_P.readEntry( "Name" ); + _voicesignature[0].read( &cfg_P , "Signature1" ); + _voicesignature[1].read( &cfg_P , "Signature2" ); + } + +Voice_trigger::~Voice_trigger() + { + voice_handler->unregister_handler( this ); + } + +void Voice_trigger::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Name", voicecode()); + cfg_P.writeEntry( "Type", "VOICE" ); // overwrites value set in base::cfg_write() + _voicesignature[0].write( &cfg_P , "Signature1" ); + _voicesignature[1].write( &cfg_P , "Signature2" ); + } + +Trigger* Voice_trigger::copy( Action_data* data_P ) const + { + kdDebug( 1217 ) << "Voice_trigger::copy()" << endl; + return new Voice_trigger( data_P ? data_P : data, voicecode(), voicesignature(1) , voicesignature(2) ); + } + +const QString Voice_trigger::description() const + { + return i18n( "Voice trigger: " ) + voicecode(); + } + +void Voice_trigger::handle_Voice( ) + { + windows_handler->set_action_window( 0 ); // use active window + data->execute(); + + } + +void Voice_trigger::activate( bool activate_P ) + { + if( activate_P && khotkeys_active()) + voice_handler->register_handler( this ); + else + voice_handler->unregister_handler( this ); + } + + +} // namespace KHotKeys + +#include "triggers.moc" diff --git a/khotkeys/shared/triggers.h b/khotkeys/shared/triggers.h new file mode 100644 index 000000000..2f921beff --- /dev/null +++ b/khotkeys/shared/triggers.h @@ -0,0 +1,260 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#ifndef _TRIGGERS_H_ +#define _TRIGGERS_H_ + +#include <qptrlist.h> +#include <qtimer.h> +#include <qmap.h> +#include <kdemacros.h> + +#include "khotkeysglobal.h" +#include "voicesignature.h" + +#include "input.h" + +class KConfig; + +namespace KHotKeys +{ + +class Windowdef_list; +class Action_data; + +class KDE_EXPORT Trigger + { + public: + Trigger( Action_data* data_P ); + Trigger( KConfig& cfg_P, Action_data* data_P ); + virtual ~Trigger(); + virtual void cfg_write( KConfig& cfg_P ) const = 0; + virtual Trigger* copy( Action_data* data_P ) const = 0; + virtual const QString description() const = 0; + static Trigger* create_cfg_read( KConfig& cfg_P, Action_data* data_P ); + virtual void activate( bool activate_P ) = 0; + protected: + Action_data* const data; + KHOTKEYS_DISABLE_COPY( Trigger ); + }; + +class KDE_EXPORT Trigger_list + : public QPtrList< Trigger > + { + public: + Trigger_list( const QString& comment_P ); // CHECKME nebo i data ? + Trigger_list( KConfig& cfg_P, Action_data* data_P ); + void activate( bool activate_P ); + void cfg_write( KConfig& cfg_P ) const; + typedef QPtrListIterator< Trigger > Iterator; + const QString& comment() const; + Trigger_list* copy( Action_data* data_P ) const; + private: + QString _comment; + KHOTKEYS_DISABLE_COPY( Trigger_list ); + }; + +class KDE_EXPORT Shortcut_trigger + : public Trigger, public Kbd_receiver + { + typedef Trigger base; + public: + Shortcut_trigger( Action_data* data_P, const KShortcut& shortcut_P ); + Shortcut_trigger( KConfig& cfg_P, Action_data* data_P ); + virtual ~Shortcut_trigger(); + virtual void cfg_write( KConfig& cfg_P ) const; + virtual Shortcut_trigger* copy( Action_data* data_P ) const; + virtual const QString description() const; + const KShortcut& shortcut() const; + virtual bool handle_key( const KShortcut& shortcut_P ); + virtual void activate( bool activate_P ); + private: + KShortcut _shortcut; + }; + +class KDE_EXPORT Window_trigger + : public QObject, public Trigger + { + Q_OBJECT + typedef Trigger base; + public: + enum window_action_t + { + WINDOW_APPEARS = ( 1 << 0 ), + WINDOW_DISAPPEARS = ( 1 << 1 ), + WINDOW_ACTIVATES = ( 1 << 2 ), + WINDOW_DEACTIVATES = ( 1 << 3 ) + }; + Window_trigger( Action_data* data_P, Windowdef_list* windows_P, int window_actions_P ); + Window_trigger( KConfig& cfg_P, Action_data* data_P ); + virtual ~Window_trigger(); + virtual void cfg_write( KConfig& cfg_P ) const; +#ifndef COVARIANT_RETURN_BROKEN // stupid gcc, it doesn't even warn it can't do this + virtual Window_trigger* copy( Action_data* data_P ) const; +#else + virtual Trigger* copy( Action_data* data_P ) const; +#endif + virtual const QString description() const; + const Windowdef_list* windows() const; + bool triggers_on( window_action_t w_action_P ) const; + virtual void activate( bool activate_P ); + protected: // CHECKME neco private ? + Windowdef_list* _windows; + int window_actions; + void init(); + typedef QMap< WId, bool > Windows_map; + Windows_map existing_windows; + WId last_active_window; + protected slots: + void window_added( WId window_P ); + void window_removed( WId window_P ); + void active_window_changed( WId window_P ); + void window_changed( WId window_P, unsigned int dirty_P ); + protected: + bool active; + }; + +class KDE_EXPORT Gesture_trigger + : public QObject, public Trigger + { + Q_OBJECT + typedef Trigger base; + public: + Gesture_trigger( Action_data* data_P, const QString& gesture_P ); + Gesture_trigger( KConfig& cfg_P, Action_data* data_P ); + virtual ~Gesture_trigger(); + virtual void cfg_write( KConfig& cfg_P ) const; + virtual Trigger* copy( Action_data* data_P ) const; + virtual const QString description() const; + const QString& gesturecode() const; + virtual void activate( bool activate_P ); + protected slots: + void handle_gesture( const QString& gesture_P, WId window_P ); + private: + QString _gesturecode; + }; + + +class KDE_EXPORT Voice_trigger + : public QObject, public Trigger + { + Q_OBJECT + typedef Trigger base; + public: + Voice_trigger( Action_data* data_P, const QString& Voice_P, const VoiceSignature & signature1_P, const VoiceSignature & signature2_P ); + Voice_trigger( KConfig& cfg_P, Action_data* data_P ); + virtual ~Voice_trigger(); + virtual void cfg_write( KConfig& cfg_P ) const; + virtual Trigger* copy( Action_data* data_P ) const; + virtual const QString description() const; + const QString& voicecode() const; + virtual void activate( bool activate_P ); + VoiceSignature voicesignature( int ech ) const; + public slots: + void handle_Voice( ); + private: + QString _voicecode; + VoiceSignature _voicesignature[2]; + }; + + +//*************************************************************************** +// Inline +//*************************************************************************** + +// Trigger + +inline +Trigger::Trigger( Action_data* data_P ) + : data( data_P ) + { + } + +inline +Trigger::Trigger( KConfig&, Action_data* data_P ) + : data( data_P ) + { + } + +inline +Trigger::~Trigger() + { + } + +// Trigger_list + +inline +Trigger_list::Trigger_list( const QString& comment_P ) + : QPtrList< Trigger >(), _comment( comment_P ) + { + setAutoDelete( true ); + } + +inline +const QString& Trigger_list::comment() const + { + return _comment; + } + +// Shortcut_trigger + +inline +const KShortcut& Shortcut_trigger::shortcut() const + { + return _shortcut; + } + +// Window_trigger + +inline +Window_trigger::Window_trigger( Action_data* data_P, Windowdef_list* windows_P, + int window_actions_P ) + : Trigger( data_P ), _windows( windows_P ), window_actions( window_actions_P ), + last_active_window( None ), active( false ) + { + init(); + } + +inline +const Windowdef_list* Window_trigger::windows() const + { + return _windows; + } + +inline +bool Window_trigger::triggers_on( window_action_t w_action_P ) const + { + return window_actions & w_action_P; + } + +// Gesture_trigger + +inline +const QString& Gesture_trigger::gesturecode() const + { + return _gesturecode; + } + +// Voice_trigger +inline +const QString& Voice_trigger::voicecode() const + { + return _voicecode; + } + +inline +VoiceSignature Voice_trigger::voicesignature(int ech) const + { + return _voicesignature[ech-1]; + } + +} // namespace KHotKeys + +#endif diff --git a/khotkeys/shared/voices.cpp b/khotkeys/shared/voices.cpp new file mode 100644 index 000000000..e0dc95613 --- /dev/null +++ b/khotkeys/shared/voices.cpp @@ -0,0 +1,303 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 2005 Olivier Goffart <ogoffart @ kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "voices.h" +#include "voicesignature.h" +#include "triggers.h" +#include "soundrecorder.h" + +#include <stdlib.h> +#include <math.h> +#include <assert.h> + + +#include <kapplication.h> +#include <kdebug.h> +#include <kxerrorhandler.h> +#include <kkeynative.h> +#include <qtimer.h> +#include <kglobalaccel.h> + + +#include <X11/Xlib.h> +#include <fixx11h.h> + +namespace KHotKeys +{ + +Voice* voice_handler; + +Voice::Voice( bool enabled_P, QObject* parent_P ) + : QObject( parent_P) ,_enabled( enabled_P ), _recording( false ), _recorder(0) + { + assert( voice_handler == NULL ); + voice_handler = this; + + _kga=0L; + _timer=0L; + + kdDebug(1217) << k_funcinfo << endl; + + } + +Voice::~Voice() + { + kdDebug(1217) << k_funcinfo << endl; + enable( false ); + voice_handler = NULL; + } + + +void Voice::enable( bool enabled_P ) + { +#ifndef HAVE_ARTS + enabled_P = false; // never enabled when there's no support +#endif + if( _enabled == enabled_P ) + return; + _enabled = enabled_P; + if( _enabled ) // activate the shortcut + set_shortcut( _shortcut ); + else + { + delete _kga; + _kga = NULL; + } + } + +void Voice::register_handler( Voice_trigger *trigger_P ) + { + if( !_references.contains( trigger_P )) + _references.append(trigger_P); + } + +void Voice::unregister_handler( Voice_trigger *trigger_P ) + { + _references.remove(trigger_P); + } + + +void Voice::record_start() +{ + kdDebug(1217) << k_funcinfo << endl; + if(!_recorder) + { + _recorder= SoundRecorder::create(this); + connect(_recorder, SIGNAL(recorded(const Sound& )), this, SLOT(slot_sound_recorded(const Sound& ))); + } + + _recorder->start(); + _recording=true; +} + +void Voice::record_stop() +{ + if(!_recording) + return; + + kdDebug(1217) << k_funcinfo << endl; + delete _timer; + _timer=0L; + _recording=false; + if(_recorder) + _recorder->stop(); +} + + +void Voice::slot_sound_recorded(const Sound &sound_P) +{ + VoiceSignature signature(sound_P); + + Voice_trigger *trig=0L; + Voice_trigger *sec_trig=0L; + double minimum=800000; + double second_minimum=80000; + int got_count=0; + QValueList<Voice_trigger*>::Iterator it; + for ( it = _references.begin(); it != _references.end(); ++it ) + { + for(int ech=1; ech<=2 ; ech++) + { + Voice_trigger *t=*it; + + double diff=VoiceSignature::diff(signature, t->voicesignature(ech)); + if(minimum>=diff) + { + second_minimum=minimum; + minimum=diff; + sec_trig=trig; + trig=t; + } + else if(second_minimum>=diff) + { + second_minimum=diff; + sec_trig=t; + } + if( diff < REJECT_FACTOR_DIFF ) + got_count++; + kdDebug(1217) << k_funcinfo << ( (diff < REJECT_FACTOR_DIFF) ? "+++" : "---" ) <<t->voicecode() << ech << " : " << diff << endl; + } + } +// double ecart_relatif=(second_minimum-minimum)/minimum; + +// kdDebug(1217) << k_funcinfo << ecart_relatif << endl; + + if(trig) + kdDebug(1217) << k_funcinfo << "**** " << trig->voicecode() << " : " << minimum << endl; + + +// if(trig && ecart_relatif > REJECT_FACTOR_ECART_REL) +// if(trig && got_count==1) + bool selected=trig && (got_count==1 || ( minimum < 1.5*REJECT_FACTOR_DIFF && trig==sec_trig ) ); + + if(selected) + { + trig->handle_Voice(); + } + +} + + +/*bool Voice::x11Event( XEvent* pEvent ) +{ + if( pEvent->type != XKeyPress && pEvent->type != XKeyRelease ) + return false; + + KKeyNative keyNative( pEvent ); + + //kdDebug(1217) << k_funcinfo << keyNative.key().toString() << endl; + + if(_shortcut.contains(keyNative)) + { + if(pEvent->type == XKeyPress && !_recording ) + { + record_start(); + return true; + } + if(pEvent->type == XKeyRelease && _recording ) + { + record_stop(); + return true; + } + } + return false; +} + + +*/ + + +void Voice::set_shortcut( const KShortcut &shortcut) +{ + _shortcut = shortcut; + if( !_enabled ) + return; + if(!_kga) + _kga = new KGlobalAccel( this ); + _kga->remove("voice"); + + _kga->insert( "voice", i18n("Voice"), QString::null, shortcut, 0, this, SLOT(slot_key_pressed())) ; + _kga->updateConnections(); +} + +void Voice::slot_key_pressed() +{ + if( !haveArts()) + return; + if( _recording ) + record_stop(); + else + { + record_start(); + if(!_timer) + { + _timer=new QTimer(this); + connect(_timer, SIGNAL(timeout()) , this, SLOT(slot_timeout())); + } + + _timer->start(1000*20,true); + } +} + + +void Voice::slot_timeout() +{ + if(_recording && _recorder) + { + _recorder->abort(); + _recording=false; + } + _timer->deleteLater(); + _timer=0L; +} + + +QString Voice::isNewSoundFarEnough(const VoiceSignature& signature, const QString ¤tTrigger) +{ + Voice_trigger *trig=0L; + Voice_trigger *sec_trig=0L; + double minimum=800000; + double second_minimum=80000; + int got_count=0; + QValueList<Voice_trigger*>::Iterator it; + for ( it = _references.begin(); it != _references.end(); ++it ) + { + Voice_trigger *t=*it; + if(t->voicecode()==currentTrigger) + continue; + + for(int ech=1; ech<=2 ; ech++) + { + double diff=VoiceSignature::diff(signature, t->voicesignature(ech)); + if(minimum>=diff) + { + second_minimum=minimum; + minimum=diff; + sec_trig=trig; + trig=t; + } + else if(second_minimum>=diff) + { + second_minimum=diff; + sec_trig=t; + } + if( diff < REJECT_FACTOR_DIFF ) + got_count++; + kdDebug(1217) << k_funcinfo << ( (diff < REJECT_FACTOR_DIFF) ? "+++" : "---" ) <<t->voicecode() << ech << " : " << diff << endl; + } + } + + if(trig) + kdDebug(1217) << k_funcinfo << "**** " << trig->voicecode() << " : " << minimum << endl; + + bool selected=trig && ((got_count==1 && minimum < REJECT_FACTOR_DIFF*0.7 ) || ( minimum < REJECT_FACTOR_DIFF && trig==sec_trig ) ); + return selected ? trig->voicecode() : QString::null; +} + +bool Voice::doesVoiceCodeExists(const QString &vc) +{ + QValueList<Voice_trigger*>::Iterator it; + for ( it = _references.begin(); it != _references.end(); ++it ) + { + Voice_trigger *t=*it; + if(t->voicecode()==vc) + return true; + } + return false; +} + +} // namespace KHotKeys + +#include "voices.moc" diff --git a/khotkeys/shared/voices.h b/khotkeys/shared/voices.h new file mode 100644 index 000000000..b0193e7c2 --- /dev/null +++ b/khotkeys/shared/voices.h @@ -0,0 +1,83 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 2005 Olivier Goffart <ogoffart @ kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#ifndef VOICES_H_ +#define VOICES_H_ + +#include <qwidget.h> +#include <kshortcut.h> + +class Sound; +class QTimer; +class KGlobalAccel; + +namespace KHotKeys +{ + +class Voice; +class SoundRecorder; + +class Voice_trigger; +class VoiceSignature; + + +class KDE_EXPORT Voice : public QObject + { + Q_OBJECT + public: + Voice( bool enabled_P, QObject* parent_P ); + virtual ~Voice(); + void enable( bool enable_P ); + + void register_handler( Voice_trigger* ); + void unregister_handler( Voice_trigger* ); +// bool x11Event( XEvent* e ); + + void set_shortcut( const KShortcut &k); + + /** + * return QString::null is a new signature is far enough from others signature + * otherwise, return the stringn which match. + */ + QString isNewSoundFarEnough(const VoiceSignature& s, const QString& currentTrigger); + + bool doesVoiceCodeExists(const QString &s); + + public slots: + void record_start(); + void record_stop(); + + private slots: + void slot_sound_recorded( const Sound & ); + void slot_key_pressed(); + void slot_timeout(); + + signals: + void handle_voice( const QString &voice ); + private: + + bool _enabled; + bool _recording; + + QValueList<Voice_trigger *> _references; + SoundRecorder *_recorder; + + KShortcut _shortcut; + KGlobalAccel *_kga; + + QTimer *_timer; + }; + + +KDE_EXPORT extern Voice* voice_handler; + +} // namespace KHotKeys + +#endif diff --git a/khotkeys/shared/voicesignature.cpp b/khotkeys/shared/voicesignature.cpp new file mode 100644 index 000000000..c77c278b3 --- /dev/null +++ b/khotkeys/shared/voicesignature.cpp @@ -0,0 +1,422 @@ +/*************************************************************************** + * Copyright (C) 2005 by Olivier Goffart * + * ogoffart@kde.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#include "voicesignature.h" +#include "sound.h" +#include <kconfig.h> + +#include <math.h> +#ifdef PI +#undef PI +#endif +#define PI (2.0 * asin(1.0)) + + +#include <kdebug.h> +#include <qdatetime.h> + +#undef Complex + +namespace KHotKeys +{ + + +inline static float ABS(float X) +{ + return (X>0) ? X : -X ; +} +inline static int MAX(int X , int Y) +{ + return (X>Y) ? X : Y ; +} +inline static int MIN(int X , int Y) +{ + return (X<Y) ? X : Y ; +} + + + + + + +class Complex +{ + public: + Complex () {} + Complex (double re): _re(re), _im(0.0) {} + Complex (double re, double im): _re(re), _im(im) {} + double Re () const { return _re; } + double Im () const { return _im; } + void operator += (const Complex& c) + { + _re += c._re; + _im += c._im; + } + void operator -= (const Complex& c) + { + _re -= c._re; + _im -= c._im; + } + void operator *= (const Complex& c) + { + double reT = c._re * _re - c._im * _im; + _im = c._re * _im + c._im * _re; + _re = reT; + } + Complex operator- () + { + return Complex (-_re, -_im); + } + Complex operator- (const Complex& c) const + { + return Complex (_re - c._re, _im - c._im); + } + Complex operator+ (const Complex& c) const + { + return Complex (_re + c._re, _im + c._im); + } + Complex operator* (const Complex& c) const + { + return Complex (_re * c._re - _im * c._im , _im * c._re + _re * c._im); + } + double Mod () const { return sqrt (_re * _re + _im * _im); } + + static Complex fromExp(double mod, double arg) { return Complex(mod*cos(arg) , mod*sin(arg)); } + private: + double _re; + double _im; +}; + +static inline double hamming(uint n, uint size) +{ + return HAMMING ? 0.54-0.46*cos( 2*PI*n /(size-1) ) : 1; +} + + +static QMemArray<double> fft(const Sound& sound, unsigned int start, unsigned int stop) +{ + if(start>=stop || sound.size() == 0) + return QMemArray<double>(); + + //We need a sample with a size of a power of two + uint size=stop-start; + unsigned short log2size=0; + while( (1<<log2size) < size ) + log2size++; + + int diff=(1<<log2size) - size; + if(diff > size/4 || 1<<log2size > sound.size() ) + { + log2size--; + diff=(1<<log2size) - size; + } + size=1<<log2size; + int start2=start-diff/2; + int stop2=start2+ size; + if(start2<0) + { + stop2-=start2; + start2=0; + } + if(stop2>sound.size()) + { + start2-= stop2 - sound.size(); + stop2=sound.size(); + if(start2<0) + { + stop2-=start2; + start2=0; + } + } + + //Generate an array to work in + QMemArray<Complex> samples(size); + + //Fill it with samples in the "reversed carry" order + int rev_carry = 0; + for (uint f = 0; f < size - 1; f++) + { + samples[f]=sound.at(start2+rev_carry)* hamming(rev_carry, size); +// KDEBUG(rev_carry); + int mask = size>>1; // N / 2 + // add 1 backwards + while (rev_carry >= mask) + { + rev_carry -= mask; // turn off this bit + mask >>= 1; + } + rev_carry += mask; + } + samples[size-1]=sound.at(start2+size-1)*hamming(size-1, size); + + //FFT + for(uint level=0; level < log2size; level++) + { + for( int k=0; k< (size>>1) ; k++) + { + uint indice1 = (k << (level+1) ) % (size-1); // (k*2*2^l)%(N-1) + uint indice2 = indice1 + (1<<level); // (k*2*2^l)%(N-1) + 2^l + + uint coefW = ( k << (level+1) ) / (size-1); // (k*2*2^l) div (N-1) + double Wexpn=-2 * PI * coefW / (2 << level); // -2 pi n / 2^(l+1) + Complex W=Complex::fromExp(1, Wexpn) ; + + + //OPERATION BUTTERFLY + Complex a=samples[indice1]; + Complex b=samples[indice2]; + samples[indice1]=a+W*b; + samples[indice2]=a-W*b; + +// kdDebug() << k_funcinfo << "PAPILLON s_" << indice1 << " s_" << indice2 << " W_" << (2<<level) << "^" << coefW << endl; + } + } + + QMemArray<double> result(size); + for(uint f=0;f<size;f++) + { + result[f]=samples[f].Mod() / size; + + } + return result; +} + + + + +QMemArray<double> VoiceSignature::fft(const Sound& sound, unsigned int start, unsigned int stop) +{ + return KHotKeys::fft(sound, start, stop); + /*QMemArray<double> result(8000); + for(int f=0; f<8000;f++) + { + Complex c(0); + + for(uint x=start; x<stop; x++) + { + Complex s(sound.at(x)); + double angle=-2*PI*f*x/8000; + s*= Complex( cos(angle) , sin(angle) ); + c+=s; + } + result[f]= c.Mod()/(stop-start) ; + } + return result;*/ +} + +bool VoiceSignature::window(const Sound& sound, unsigned int *_start, unsigned int *_stop) +{ + bool isNoise=false; + unsigned int length=sound.size(); + uint unit=WINDOW_UNIT; + if(length < unit ) + return false; + + //Fenêtrage + unsigned int start=0 , stop=0; + double moy=0; + for(uint x=0;x<unit;x++) + { + moy+=ABS(sound.at(x)); + } + + if(moy>WINDOW_MINIMUM*unit) + isNoise=true; + + for(uint x=unit; x<length; x++) + { + if(moy<WINDOW_MINIMUM*unit) + { + if(stop==0) + start=x-unit/2; + } + else + stop=x-unit/2; + moy+=ABS(sound.at(x)); + moy-=ABS(sound.at(x-unit)); + + } + + if(moy>WINDOW_MINIMUM*unit && isNoise) + return false; + + stop=MIN(length,stop+WINDOW_MINIMUM_ECART); + start=MAX(0 ,start-WINDOW_MINIMUM_ECART); + + if(_start) + *_start=start; + if(_stop) + *_stop=stop; + return start<stop; +} + +//finally doesn't give better results +/*#define HZ_TO_MEL(F) (1127*log(1+(F)/700.0)) +#define MEL_TO_HZ(M) ( ( exp((M)/1127.0) -1) *700 )*/ +#define HZ_TO_MEL(F) (F) +#define MEL_TO_HZ(F) (F) + + +VoiceSignature::VoiceSignature(const Sound& sound) +{ + static uint temp_wind=0, temp_fft=0, temp_moy=0; + QTime t; + t.start(); + + unsigned int start , stop; + if(!window(sound,&start,&stop)) + { + kdWarning( 1217 ) << k_funcinfo << "No voice found in the sound" << endl ; + return; + } + + temp_wind+=t.restart(); + + uint length=stop-start; + + for(int wind=0; wind<WINDOW_NUMBER; wind++) + { + unsigned int w_start=MAX(start, start+ (int)((wind - WINDOW_SUPER)*length/WINDOW_NUMBER)); + unsigned int w_stop =MIN(stop , start+ (int)((wind+1.0+WINDOW_SUPER)*length/WINDOW_NUMBER)); + + + QMemArray<double> fourrier=fft(sound, w_start,w_stop); + + temp_fft+=t.restart(); + + //MEL conversion + double mel_start=HZ_TO_MEL(FFT_RANGE_INF); + uint mel_stop=HZ_TO_MEL(FFT_RANGE_SUP); + + for(int four=0; four<FOUR_NUMBER; four++) + { + unsigned int wf_start=mel_start + four*(mel_stop-mel_start)/FOUR_NUMBER; + unsigned int wf_stop=mel_start + (four+1)*(mel_stop-mel_start)/FOUR_NUMBER; + + unsigned int f_start=MEL_TO_HZ( wf_start )*fourrier.size()/sound.fs(); + unsigned int f_stop=MEL_TO_HZ( wf_stop )*fourrier.size()/sound.fs(); + unsigned int f_size=f_stop-f_start; + + double nb=0; + for(uint f=f_start; f<f_stop; f++) + { + int freq=f*fourrier.size()/sound.fs(); + nb+=fourrier[f]*FFT_PONDERATION(freq); + } + nb/=(f_size); + data[wind][four]=nb; + } + + temp_moy+=t.restart(); + + } + +// kdDebug( 1217 ) << k_funcinfo << "wind: "<< temp_wind << " - fft: " << temp_fft << " - moy: " << temp_moy << endl; +} + + + +VoiceSignature::~VoiceSignature() +{ +} + + + +float VoiceSignature::diff(const VoiceSignature &s1, const VoiceSignature &s2) +{ + if(s1.isNull() || s2.isNull()) + return 1000000; +#if 0 + double result=0; + for(int x=0;x<WINDOW_NUMBER;x++) + for(int y=0;y<FOUR_NUMBER;y++) + { + double d1=s1.data[x][y]-s2.data[x][y]; + result+= d1*d1;//*pond[x][y]; + } + return result; +#endif + + //DTW + // http://tcts.fpms.ac.be/cours/1005-08/speech/projects/2001/delfabro_henry_poitoux/ + + const int I=WINDOW_NUMBER; + const int J=WINDOW_NUMBER; + double g[I+1][J+1]; + for(int f=1;f<=J;f++) + g[0][f]=10000000; + for(int f=1;f<=I;f++) + g[f][0]=10000000; + g[0][0]=0; + for(int i=1;i<=I;i++) + for(int j=1;j<=J;j++) + { + double d=0; + for(int f=0;f<FOUR_NUMBER;f++) + { + double d1=s1.data[i-1][f]-s2.data[j-1][f]; + d+= d1*d1;//*pond[x][y]; + } + d=sqrt(d); + g[i][j]=QMIN(QMIN( g[i-1][j]+d, g[i][j-1]+d ) , g[i-1][j-1]+d+d ); + } + + return g[I][J]/(I+J); +} + + + + + +int VoiceSignature::size1() +{ + return WINDOW_NUMBER; +} + +int VoiceSignature::size2() +{ + return FOUR_NUMBER; +} + +QMap<int, QMap<int, double> > VoiceSignature::pond; + + + +void VoiceSignature::write(KConfigBase *cfg, const QString &key) const +{ + QStringList sl; + for(int x=0;x<WINDOW_NUMBER;x++) + for(int y=0;y<FOUR_NUMBER;y++) + { + sl.append( QString::number(data[x][y]) ); + } + cfg->writeEntry(key,sl); +} + +void VoiceSignature::read(KConfigBase *cfg, const QString &key) +{ + QStringList sl=cfg->readListEntry(key); + for(int x=0;x<WINDOW_NUMBER;x++) + for(int y=0;y<FOUR_NUMBER;y++) + { + data[x][y]= sl[x*FOUR_NUMBER+y].toDouble(); + } +} + +} diff --git a/khotkeys/shared/voicesignature.h b/khotkeys/shared/voicesignature.h new file mode 100644 index 000000000..b4857efd2 --- /dev/null +++ b/khotkeys/shared/voicesignature.h @@ -0,0 +1,101 @@ +/*************************************************************************** + * Copyright (C) 2005 by Olivier Goffart * + * ogoffart@kde.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef SIGNATURE_H +#define SIGNATURE_H + + +#include <qmemarray.h> +#include <qmap.h> +#include <kdemacros.h> + +class Sound; +class KConfigBase; + + +#define WINDOW_MINIMUM 0.10 +#define WINDOW_MINIMUM_ECART 200 +#define WINDOW_NUMBER 7 +#define WINDOW_SUPER 0.43 +#define WINDOW_UNIT sound.fs()/4 +#define FOUR_NUMBER 7 +#define FOUR_SUPER 0 + + +#define FFT_RANGE_INF 370 +#define FFT_RANGE_SUP 2000 +// #define FFT_PONDERATION(f) ((double)log(1+(f))/log(10)) +#define FFT_PONDERATION(f) 1 + + +// theses settings are better in a 8000Hz fs +/*#define FFT_RANGE_INF 300 +#define FFT_RANGE_SUP 1500*/ + + +//#define REJECT_FACTOR_ECART_REL 0.5 +#define REJECT_FACTOR_DIFF 0.0018 + + + +#define HAMMING false + + + + +namespace KHotKeys +{ + + +/** +@author Olivier Goffart +*/ +class KDE_EXPORT VoiceSignature{ +public: + explicit VoiceSignature(const Sound& s); + + VoiceSignature(){} + ~VoiceSignature(); + + QMap<int, QMap<int, double> > data; + + static QMap<int, QMap<int, double> > pond; + + static float diff(const VoiceSignature &s1, const VoiceSignature &s2); + + + static int size1(); + static int size2(); + + + static QMemArray<double> fft(const Sound& sound, unsigned int start, unsigned int stop); + static bool window(const Sound& sound, unsigned int *start, unsigned int *stop); + + void write(KConfigBase *cfg, const QString &key) const; + void read(KConfigBase *cfg, const QString &key); + + inline bool isNull() const + { + return data.isEmpty(); + } +}; + +} + +#endif diff --git a/khotkeys/shared/windows.cpp b/khotkeys/shared/windows.cpp new file mode 100644 index 000000000..d269ef2fe --- /dev/null +++ b/khotkeys/shared/windows.cpp @@ -0,0 +1,376 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#define _WINDOWS_CPP_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "windows.h" + +#include <assert.h> +#include <qregexp.h> + +#include <kconfig.h> +#include <kdebug.h> +#include <kwinmodule.h> +#include <kwin.h> +#include <klocale.h> + +#include "khotkeysglobal.h" + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +extern Atom qt_window_role; + +namespace KHotKeys +{ + +// Windows + +Windows::Windows( bool enable_signal_P, QObject* parent_P ) + : QObject( parent_P ), signals_enabled( enable_signal_P ), + kwin_module( new KWinModule( this )), _action_window( 0 ) + { + assert( windows_handler == NULL ); + windows_handler = this; + if( signals_enabled ) + { + connect( kwin_module, SIGNAL( windowAdded( WId )), SLOT( window_added_slot( WId ))); + connect( kwin_module, SIGNAL( windowRemoved( WId )), SLOT( window_removed_slot( WId ))); + connect( kwin_module, SIGNAL( activeWindowChanged( WId )), + SLOT( active_window_changed_slot( WId ))); + } + } + +Windows::~Windows() + { + windows_handler = NULL; + } + +void Windows::window_added_slot( WId window_P ) + { + if( signals_enabled ) + emit window_added( window_P ); + // CHECKME tyhle i dalsi by asi mely jit nastavit, jestli aktivuji vsechny, nebo jen jeden + // pripojeny slot ( stejne jako u Kdb, kde by to take melo jit nastavit ) + } + +void Windows::window_removed_slot( WId window_P ) + { + if( signals_enabled ) + emit window_removed( window_P ); + if( window_P == _action_window ) + _action_window = 0; + } + +void Windows::active_window_changed_slot( WId window_P ) + { + if( signals_enabled ) + emit active_window_changed( window_P ); + } + +void Windows::window_changed_slot( WId window_P ) + { + if( signals_enabled ) + emit window_changed( window_P ); + } + +void Windows::window_changed_slot( WId window_P, unsigned int flags_P ) + { + if( signals_enabled ) + emit window_changed( window_P, flags_P ); + } + +QString Windows::get_window_role( WId id_P ) + { + // TODO this is probably just a hack + return KWin::readNameProperty( id_P, qt_window_role ); + } + +QString Windows::get_window_class( WId id_P ) + { + XClassHint hints_ret; + if( XGetClassHint( qt_xdisplay(), id_P, &hints_ret ) == 0 ) // 0 means error + return ""; + QString ret( hints_ret.res_name ); + ret += ' '; + ret += hints_ret.res_class; + XFree( hints_ret.res_name ); + XFree( hints_ret.res_class ); + return ret; + } + +WId Windows::active_window() + { + return kwin_module->activeWindow(); + } + +WId Windows::action_window() + { + return _action_window; + } + +void Windows::set_action_window( WId window_P ) + { + _action_window = window_P; + } + +WId Windows::find_window( const Windowdef_list* window_P ) + { + for( QValueList< WId >::ConstIterator it = kwin_module->windows().begin(); + it != kwin_module->windows().end(); + ++it ) + { + Window_data tmp( *it ); + if( window_P->match( tmp )) + return *it; + } + return None; + } + +WId Windows::window_at_position( int x, int y ) + { + Window child, dummy; + Window parent = qt_xrootwin(); + Atom wm_state = XInternAtom( qt_xdisplay(), "WM_STATE", False ); + for( int i = 0; + i < 10; + ++i ) + { + int destx, desty; + // find child at that position + if( !XTranslateCoordinates( qt_xdisplay(), parent, parent, x, y, &destx, &desty, &child ) + || child == None ) + return 0; + // and now transform coordinates to the child + if( !XTranslateCoordinates( qt_xdisplay(), parent, child, x, y, &destx, &desty, &dummy )) + return 0; + x = destx; + y = desty; + Atom type; + int format; + unsigned long nitems, after; + unsigned char* prop; + if( XGetWindowProperty( qt_xdisplay(), child, wm_state, 0, 0, False, AnyPropertyType, + &type, &format, &nitems, &after, &prop ) == Success ) + { + if( prop != NULL ) + XFree( prop ); + if( type != None ) + return child; + } + parent = child; + } + return 0; + + } + +void Windows::activate_window( WId id_P ) + { + KWin::forceActiveWindow( id_P ); + } + +// Window_data + +Window_data::Window_data( WId id_P ) + : type( NET::Unknown ) + { + KWin::WindowInfo kwin_info = KWin::windowInfo( id_P, NET::WMName | NET::WMWindowType ); // TODO optimize + if( kwin_info.valid()) + { + title = kwin_info.name(); + role = windows_handler->get_window_role( id_P ); + wclass = windows_handler->get_window_class( id_P ); + type = kwin_info.windowType( SUPPORTED_WINDOW_TYPES_MASK ); + if( type == NET::Override ) // HACK consider non-NETWM fullscreens to be normal too + type = NET::Normal; + if( type == NET::Unknown ) + type = NET::Normal; + } + } + +// Windowdef + +void Windowdef::cfg_write( KConfig& cfg_P ) const + { + cfg_P.writeEntry( "Type", "ERROR" ); + cfg_P.writeEntry( "Comment", comment()); + } + +Windowdef::Windowdef( KConfig& cfg_P ) + { + _comment = cfg_P.readEntry( "Comment" ); + } + +Windowdef* Windowdef::create_cfg_read( KConfig& cfg_P ) + { + QString type = cfg_P.readEntry( "Type" ); + if( type == "SIMPLE" ) + return new Windowdef_simple( cfg_P ); + kdWarning( 1217 ) << "Unknown Windowdef type read from cfg file\n"; + return NULL; + } + +// Windowdef_list + +Windowdef_list::Windowdef_list( KConfig& cfg_P ) + : QPtrList< Windowdef >() + { + setAutoDelete( true ); + QString save_cfg_group = cfg_P.group(); + _comment = cfg_P.readEntry( "Comment" ); + int cnt = cfg_P.readNumEntry( "WindowsCount", 0 ); + for( int i = 0; + i < cnt; + ++i ) + { + cfg_P.setGroup( save_cfg_group + QString::number( i )); + Windowdef* window = Windowdef::create_cfg_read( cfg_P ); + if( window ) + append( window ); + } + cfg_P.setGroup( save_cfg_group ); + } + +void Windowdef_list::cfg_write( KConfig& cfg_P ) const + { + QString save_cfg_group = cfg_P.group(); + int i = 0; + for( Iterator it( *this ); + it; + ++it, ++i ) + { + cfg_P.setGroup( save_cfg_group + QString::number( i )); + it.current()->cfg_write( cfg_P ); + } + cfg_P.setGroup( save_cfg_group ); + cfg_P.writeEntry( "WindowsCount", i ); + cfg_P.writeEntry( "Comment", comment()); + } + +Windowdef_list* Windowdef_list::copy() const + { + Windowdef_list* ret = new Windowdef_list( comment()); + for( Iterator it( *this ); + it; + ++it ) + ret->append( it.current()->copy()); + return ret; + } + + +bool Windowdef_list::match( const Window_data& window_P ) const + { + if( count() == 0 ) // CHECKME no windows to match => ok + return true; + for( Iterator it( *this ); + it; + ++it ) + if( it.current()->match( window_P )) + return true; + return false; + } + +// Windowdef_simple + +Windowdef_simple::Windowdef_simple( const QString& comment_P, const QString& title_P, + substr_type_t title_type_P, const QString& wclass_P, substr_type_t wclass_type_P, + const QString& role_P, substr_type_t role_type_P, int window_types_P ) + : Windowdef( comment_P ), _title( title_P ), title_type( title_type_P ), + _wclass( wclass_P ), wclass_type( wclass_type_P ), _role( role_P ), + role_type( role_type_P ), _window_types( window_types_P ) + { + } + +Windowdef_simple::Windowdef_simple( KConfig& cfg_P ) + : Windowdef( cfg_P ) + { + _title = cfg_P.readEntry( "Title" ); + title_type = static_cast< substr_type_t >( cfg_P.readNumEntry( "TitleType" )); + _wclass = cfg_P.readEntry( "Class" ); + wclass_type = static_cast< substr_type_t >( cfg_P.readNumEntry( "ClassType" )); + _role = cfg_P.readEntry( "Role" ); + role_type = static_cast< substr_type_t >( cfg_P.readNumEntry( "RoleType" )); + _window_types = cfg_P.readNumEntry( "WindowTypes" ); + } + +void Windowdef_simple::cfg_write( KConfig& cfg_P ) const + { + base::cfg_write( cfg_P ); + cfg_P.writeEntry( "Title", title()); + cfg_P.writeEntry( "TitleType", title_type ); + cfg_P.writeEntry( "Class", wclass()); + cfg_P.writeEntry( "ClassType", wclass_type ); + cfg_P.writeEntry( "Role", role()); + cfg_P.writeEntry( "RoleType", role_type ); + cfg_P.writeEntry( "WindowTypes", window_types()); + cfg_P.writeEntry( "Type", "SIMPLE" ); // overwrites value set in base::cfg_write() + } + +bool Windowdef_simple::match( const Window_data& window_P ) + { + if( !type_match( window_P.type )) + return false; + if( !is_substr_match( window_P.title, title(), title_type )) + return false; + if( !is_substr_match( window_P.wclass, wclass(), wclass_type )) + return false; + if( !is_substr_match( window_P.role, role(), role_type )) + return false; + kdDebug( 1217 ) << "window match:" << window_P.title << ":OK" << endl; + return true; + } + +bool Windowdef_simple::is_substr_match( const QString& str1_P, const QString& str2_P, + substr_type_t type_P ) + { + switch( type_P ) + { + case NOT_IMPORTANT : + return true; + case CONTAINS : + return str1_P.contains( str2_P ) > 0; + case IS : + return str1_P == str2_P; + case REGEXP : + { + QRegExp rg( str2_P ); + return rg.search( str1_P ) >= 0; + } + case CONTAINS_NOT : + return str1_P.contains( str2_P ) == 0; + case IS_NOT : + return str1_P != str2_P; + case REGEXP_NOT : + { + QRegExp rg( str2_P ); + return rg.search( str1_P ) < 0; + } + } + return false; + } + +Windowdef* Windowdef_simple::copy() const + { + return new Windowdef_simple( comment(), title(), title_match_type(), wclass(), + wclass_match_type(), role(), role_match_type(), window_types()); + } + +const QString Windowdef_simple::description() const + { + return i18n( "Window simple: " ) + comment(); + } + +} // namespace KHotKeys + +#include "windows.moc" diff --git a/khotkeys/shared/windows.h b/khotkeys/shared/windows.h new file mode 100644 index 000000000..f048ce6b9 --- /dev/null +++ b/khotkeys/shared/windows.h @@ -0,0 +1,264 @@ +/**************************************************************************** + + KHotKeys + + Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org> + + Distributed under the terms of the GNU General Public License version 2. + +****************************************************************************/ + +#ifndef _WINDOWS_H_ +#define _WINDOWS_H_ + +#include <sys/types.h> + +#include <qobject.h> +#include <qstring.h> +#include <qptrlist.h> + +#include <netwm_def.h> + +#include "khotkeysglobal.h" + +class KConfig; +class KWinModule; + +namespace KHotKeys +{ + +const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask + | NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask | NET::TopMenuMask + | NET::UtilityMask | NET::SplashMask; + +class Windowdef_list; +/*class Action_data_base;*/ + +class KDE_EXPORT Windows + : public QObject + { + Q_OBJECT + public: + Windows( bool enable_signals_P, QObject* parent_P ); + virtual ~Windows(); + QString get_window_class( WId id_P ); + QString get_window_role( WId id_P ); + WId active_window(); + void set_action_window( WId window ); + WId action_window(); + WId find_window( const Windowdef_list* window_P ); + static WId window_at_position( int x, int y ); + static void activate_window( WId id_P ); + signals: + void window_added( WId window_P ); + void window_removed( WId window_P ); + void active_window_changed( WId window_P ); + void window_changed( WId window_P ); + void window_changed( WId window_P, unsigned int flags_P ); + protected slots: + void window_added_slot( WId window_P ); + void window_removed_slot( WId window_P ); + void active_window_changed_slot( WId window_P ); + void window_changed_slot( WId window_P ); + void window_changed_slot( WId window_P, unsigned int flags_P ); + private: + bool signals_enabled; + KWinModule* kwin_module; + WId _action_window; + }; + +struct KDE_EXPORT Window_data + { + Window_data( WId id_P ); + QString title; // _NET_WM_NAME or WM_NAME + QString role; // WM_WINDOW_ROLE + QString wclass; // WM_CLASS + NET::WindowType type; + }; + +class KDE_EXPORT Windowdef + { + public: + Windowdef( const QString& comment_P ); + Windowdef( KConfig& cfg_P ); + virtual ~Windowdef(); + const QString& comment() const; + virtual bool match( const Window_data& window_P ) = 0; + static Windowdef* create_cfg_read( KConfig& cfg_P/*, Action_data_base* data_P*/ ); + virtual void cfg_write( KConfig& cfg_P ) const = 0; + virtual Windowdef* copy( /*Action_data_base* data_P*/ ) const = 0; + virtual const QString description() const = 0; + private: + QString _comment; + KHOTKEYS_DISABLE_COPY( Windowdef ); // CHECKME asi pak udelat i pro vsechny potomky, at se nezapomene + }; + +class KDE_EXPORT Windowdef_list + : public QPtrList< Windowdef > + { + public: + Windowdef_list( const QString& comment_P ); + Windowdef_list( KConfig& cfg_P/*, Action_data_base* data_P*/ ); + void cfg_write( KConfig& cfg_P ) const; + bool match( const Window_data& window_P ) const; + Windowdef_list* copy( /*Action_data_base* data_P*/ ) const; + typedef QPtrListIterator< Windowdef > Iterator; + const QString& comment() const; + private: + QString _comment; + KHOTKEYS_DISABLE_COPY( Windowdef_list ); + }; + +class KDE_EXPORT Windowdef_simple + : public Windowdef + { + typedef Windowdef base; + public: + enum substr_type_t + { + NOT_IMPORTANT, + CONTAINS, + IS, + REGEXP, + CONTAINS_NOT, + IS_NOT, + REGEXP_NOT + }; + enum window_type_t + { + WINDOW_TYPE_NORMAL = ( 1 << NET::Normal ), + WINDOW_TYPE_DESKTOP = ( 1 << NET::Desktop ), + WINDOW_TYPE_DOCK = ( 1 << NET::Dock ), +// WINDOW_TYPE_TOOL = ( 1 << NET::Tool ), +// WINDOW_TYPE_MENU = ( 1 << NET::Menu ), + WINDOW_TYPE_DIALOG = ( 1 << NET::Dialog ) + }; + Windowdef_simple( const QString& comment_P, const QString& title_P, + substr_type_t title_type_P, const QString& wclass_P, substr_type_t wclass_type_P, + const QString& role_P, substr_type_t role_type_P, int window_types_P ); + Windowdef_simple( KConfig& cfg_P ); + virtual bool match( const Window_data& window_P ); + virtual void cfg_write( KConfig& cfg_P ) const; + const QString& title() const; + substr_type_t title_match_type() const; + const QString& wclass() const; + substr_type_t wclass_match_type() const; + const QString& role() const; + substr_type_t role_match_type() const; + int window_types() const; + bool type_match( window_type_t type_P ) const; + bool type_match( NET::WindowType type_P ) const; + virtual Windowdef* copy( /*Action_data_base* data_P*/ ) const; + virtual const QString description() const; + protected: + bool is_substr_match( const QString& str1_P, const QString& str2_P, + substr_type_t type_P ); + private: + QString _title; + substr_type_t title_type; + QString _wclass; + substr_type_t wclass_type; + QString _role; + substr_type_t role_type; + int _window_types; + }; + +//*************************************************************************** +// Inline +//*************************************************************************** + +// Windowdef + +inline +Windowdef::Windowdef( const QString& comment_P ) + : _comment( comment_P ) + { + } + +inline +const QString& Windowdef::comment() const + { + return _comment; + } + +inline +Windowdef::~Windowdef() + { + } + +// Windowdef_list + +inline +Windowdef_list::Windowdef_list( const QString& comment_P ) + : QPtrList< Windowdef >(), _comment( comment_P ) + { + setAutoDelete( true ); + } + +inline +const QString& Windowdef_list::comment() const + { + return _comment; + } + +// Windowdef_simple + +inline +const QString& Windowdef_simple::title() const + { + return _title; + } + +inline +Windowdef_simple::substr_type_t Windowdef_simple::title_match_type() const + { + return title_type; + } + +inline +const QString& Windowdef_simple::wclass() const + { + return _wclass; + } + +inline +Windowdef_simple::substr_type_t Windowdef_simple::wclass_match_type() const + { + return wclass_type; + } + +inline +const QString& Windowdef_simple::role() const + { + return _role; + } + +inline +Windowdef_simple::substr_type_t Windowdef_simple::role_match_type() const + { + return role_type; + } + +inline +int Windowdef_simple::window_types() const + { + return _window_types; + } + +inline +bool Windowdef_simple::type_match( window_type_t type_P ) const + { + return window_types() & type_P; + } + +inline +bool Windowdef_simple::type_match( NET::WindowType type_P ) const + { + return ( window_types() & ( 1 << type_P )) + || ( type_P == NET::Unknown && ( window_types() & WINDOW_TYPE_NORMAL )); + // CHECKME HACK haaaack ! + } + +} // namespace KHotKeys + +#endif |