├── po ├── de.po ├── zh_TW.po ├── zh_CN.po ├── ja.po ├── ko.po ├── he.po ├── ca.po ├── cs.po └── vi.po ├── debug.mk.ex ├── .gitignore ├── easystroke.desktop.in ├── LICENSE ├── water.h ├── annotate.h ├── shape.h ├── main.h ├── fire.h ├── composite.h ├── util.h ├── trace.h ├── stroke.h ├── water.cc ├── easystroke.appdata.xml ├── annotate.cc ├── fire.cc ├── cellrenderertextish.h ├── shape.cc ├── prefs.h ├── handler.h ├── win.h ├── grabber.h ├── cellrenderertextish.vala ├── gesture.cc ├── gesture.h ├── composite.cc ├── var.h ├── prefdb.h ├── Makefile ├── actions.h ├── changelog ├── prefdb.cc ├── stroke.c ├── win.cc ├── stats.cc └── easystroke.svg /po/de.po: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thjaeger/easystroke/HEAD/po/de.po -------------------------------------------------------------------------------- /debug.mk.ex: -------------------------------------------------------------------------------- 1 | DFLAGS = -ggdb #-pg 2 | OFLAGS = 3 | CXX = ccache g++ 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.Po 3 | easystroke 4 | easystroke.1 5 | gui.c 6 | desktop.c 7 | *.swp 8 | debug.mk 9 | po/?? 10 | po/??_?? 11 | po/POTFILES.in 12 | po/*.pot 13 | easystroke.desktop 14 | .clang_complete 15 | -------------------------------------------------------------------------------- /easystroke.desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | _Name=Easystroke Gesture Recognition 4 | Type=Application 5 | Terminal=false 6 | Exec=easystroke 7 | Icon=easystroke 8 | Categories=GTK;Utility;Accessibility; 9 | Actions=About;Enable;Disable;Quit 10 | _Comment=Control your desktop using mouse gestures 11 | 12 | [Desktop Action About] 13 | _Name=About 14 | Exec=easystroke about 15 | 16 | [Desktop Action Enable] 17 | _Name=Enable 18 | Exec=easystroke enable 19 | 20 | [Desktop Action Disable] 21 | _Name=Disable 22 | Exec=easystroke disable 23 | 24 | [Desktop Action Quit] 25 | _Name=Quit 26 | Exec=easystroke quit 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2009, Thomas Jaeger 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 8 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 9 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 10 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 11 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 12 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 13 | PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /water.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __WATER_H__ 17 | #define __WATER_H__ 18 | #include "trace.h" 19 | #include "main.h" 20 | #include 21 | 22 | class Water : public Trace { 23 | DBusGConnection *bus; 24 | DBusGProxy *line_proxy; 25 | 26 | virtual void draw(Point p, Point q); 27 | virtual void start_() {} 28 | virtual void end_() {} 29 | public: 30 | Water(); 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /annotate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __ANNOTATE_H__ 17 | #define __ANNOTATE_H__ 18 | #include "trace.h" 19 | #include "main.h" 20 | #include 21 | 22 | class Annotate : public Trace { 23 | DBusGConnection *bus; 24 | DBusGProxy *draw_proxy; 25 | DBusGProxy *clear_proxy; 26 | 27 | virtual void draw(Point p, Point q); 28 | virtual void start_() {} 29 | virtual void end_(); 30 | public: 31 | Annotate(); 32 | }; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /shape.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __SHAPE_H__ 17 | #define __SHAPE_H__ 18 | #include "util.h" 19 | #include "trace.h" 20 | #include "main.h" 21 | 22 | class Shape : public Trace, protected Timeout { 23 | Window win; 24 | private: 25 | virtual void draw(Point p, Point q); 26 | virtual void start_(); 27 | virtual void end_(); 28 | void clear(); 29 | public: 30 | Shape(); 31 | virtual void timeout(); 32 | virtual ~Shape(); 33 | }; 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /main.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __MAIN_H__ 17 | #define __MAIN_H__ 18 | 19 | #include 20 | #include 21 | 22 | bool is_file(std::string filename); 23 | bool is_dir(std::string dirname); 24 | void quit(); 25 | 26 | extern std::string config_dir; 27 | extern const char *prefs_versions[]; 28 | extern const char *actions_versions[]; 29 | extern int verbosity; 30 | extern bool experimental; 31 | 32 | extern "C" { 33 | struct _XDisplay; 34 | typedef struct _XDisplay Display; 35 | } 36 | 37 | extern Display *dpy; 38 | extern Window ROOT; 39 | 40 | class Win; 41 | extern Win *win; 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /fire.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __FIRE_H__ 17 | #define __FIRE_H__ 18 | #include "util.h" 19 | #include "trace.h" 20 | #include "main.h" 21 | #include 22 | 23 | class Fire : public Trace, public Timeout { 24 | DBusGConnection *bus; 25 | DBusGProxy *point_proxy; 26 | DBusGProxy *clear_proxy; 27 | float leftover; 28 | 29 | virtual void draw(Point p, Point q); 30 | void add_point(float, float); 31 | virtual void start_() { if (remove_timeout()) timeout(); leftover = 0; } 32 | virtual void end_() { set_timeout(250); } 33 | virtual void timeout(); 34 | public: 35 | Fire(); 36 | }; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /composite.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __COMPOSITE_H__ 17 | #define __COMPOSITE_H__ 18 | #include 19 | #include "trace.h" 20 | #include "main.h" 21 | #include 22 | 23 | class Popup : public Gtk::Window { 24 | bool on_draw(const ::Cairo::RefPtr< ::Cairo::Context>& ctx); 25 | void draw_line(Cairo::RefPtr ctx); 26 | Gdk::Rectangle rect; 27 | public: 28 | Popup(int x1, int y1, int x2, int y2); 29 | void invalidate(int x1, int y1, int x2, int y2); 30 | }; 31 | 32 | class Composite : public Trace { 33 | int num_x, num_y; 34 | Popup ***pieces; 35 | virtual void draw(Point p, Point q); 36 | virtual void start_(); 37 | virtual void end_(); 38 | public: 39 | Composite(); 40 | virtual ~Composite(); 41 | }; 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __UTIL_H__ 17 | #define __UTIL_H__ 18 | 19 | #include 20 | 21 | class Timeout { 22 | // Invariant: c == &connection || c == nullptr 23 | sigc::connection *c; 24 | sigc::connection connection; 25 | // We have to account for the possibilty that timeout() destroys the object 26 | bool to() { c = nullptr; timeout(); return false; } 27 | public: 28 | Timeout() : c(0) {} 29 | protected: 30 | virtual void timeout() = 0; 31 | public: 32 | bool remove_timeout() { 33 | if (c) { 34 | c->disconnect(); 35 | c = 0; 36 | return true; 37 | } 38 | return false; 39 | } 40 | void set_timeout(int ms) { 41 | remove_timeout(); 42 | connection = Glib::signal_timeout().connect(sigc::mem_fun(*this, &Timeout::to), ms); 43 | c = &connection; 44 | } 45 | virtual ~Timeout() { 46 | remove_timeout(); 47 | } 48 | }; 49 | #endif 50 | -------------------------------------------------------------------------------- /trace.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __TRACE_H__ 17 | #define __TRACE_H__ 18 | 19 | #include 20 | #include 21 | 22 | struct DBusException: public std::exception { 23 | virtual const char* what() const throw() { return _("Connection to DBus failed"); } 24 | }; 25 | 26 | class Trace { 27 | public: 28 | struct Point { float x; float y; }; 29 | private: 30 | Point last; 31 | bool active; 32 | protected: 33 | virtual void draw(Point p, Point q) = 0; 34 | virtual void start_() = 0; 35 | virtual void end_() = 0; 36 | public: 37 | Trace() : active(false) {} 38 | void draw(Point p) { draw(last, p); last = p; } 39 | void start(Point p); 40 | void end(); 41 | virtual void timeout() {} 42 | virtual ~Trace() {} 43 | }; 44 | 45 | class Trivial : public Trace { 46 | virtual void draw(Point p, Point q) {} 47 | virtual void start_() {} 48 | virtual void end_() {} 49 | public: 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /stroke.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __STROKE_H__ 17 | #define __STROKE_H__ 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | struct _stroke_t; 24 | 25 | typedef struct _stroke_t stroke_t; 26 | 27 | stroke_t *stroke_alloc(int n); 28 | void stroke_add_point(stroke_t *stroke, double x, double y); 29 | void stroke_finish(stroke_t *stroke); 30 | void stroke_free(stroke_t *stroke); 31 | 32 | int stroke_get_size(const stroke_t *stroke); 33 | void stroke_get_point(const stroke_t *stroke, int n, double *x, double *y); 34 | double stroke_get_time(const stroke_t *stroke, int n); 35 | double stroke_get_angle(const stroke_t *stroke, int n); 36 | double stroke_angle_difference(const stroke_t *a, const stroke_t *b, int i, int j); 37 | 38 | double stroke_compare(const stroke_t *a, const stroke_t *b, int *path_x, int *path_y); 39 | 40 | extern const double stroke_infinity; 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | #endif 46 | -------------------------------------------------------------------------------- /water.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #include "water.h" 17 | #include 18 | #include 19 | 20 | Water::Water() { 21 | const char *ofc = "org.freedesktop.compiz"; 22 | GError *error = 0; 23 | bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error); 24 | if (!bus) { 25 | g_error_free(error); 26 | throw DBusException(); 27 | } 28 | char line[256]; 29 | snprintf(line, sizeof(line), "/org/freedesktop/compiz/water/screen%d/line", DefaultScreen(dpy)); 30 | line_proxy = dbus_g_proxy_new_for_name(bus, ofc, line, ofc); 31 | } 32 | 33 | void Water::draw(Point p, Point q) { 34 | dbus_g_proxy_call_no_reply(line_proxy, "activate", 35 | G_TYPE_STRING, "root", G_TYPE_INT, gint(ROOT), 36 | G_TYPE_STRING, "x0", G_TYPE_INT, gint32(p.x), 37 | G_TYPE_STRING, "y0", G_TYPE_INT, gint32(p.y), 38 | G_TYPE_STRING, "x1", G_TYPE_INT, gint32(q.x), 39 | G_TYPE_STRING, "y1", G_TYPE_INT, gint32(q.y), 40 | G_TYPE_INVALID); 41 | } 42 | -------------------------------------------------------------------------------- /easystroke.appdata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | easystroke.desktop 5 | CC0-1.0 6 | ISC 7 | Easystroke 8 | Gesture-recognition application for X11 9 | 10 |

11 | Easystroke is a gesture-recognition application for X11. Gestures or strokes 12 | are movements that you make with you mouse (or your pen, finger etc.) while 13 | holding down a specific mouse button. Easystroke will execute certain actions 14 | if it recognizes the stroke; currently easystroke can emulate key presses, 15 | execute shell commands, hold down modifiers and emulate a scroll wheel. 16 |

17 |

18 | The program was designed with Tablet PCs in mind and can be used effectively 19 | even without access to a keyboard. Easystroke tries to provide an intuitive 20 | and efficient user interface, while at the same time being highly configurable 21 | and offering many advanced features. 22 |

23 |
24 | 25 | 26 | 27 | https://alexpl.fedorapeople.org/AppData/easystroke/screens/easystroke_01.png 28 | 29 | 30 | 31 | 32 | https://alexpl.fedorapeople.org/AppData/easystroke/screens/easystroke_02.png 33 | 34 | 35 | 36 | 37 | https://alexpl.fedorapeople.org/AppData/easystroke/screens/easystroke_03.png 38 | 39 | 40 | 41 | https://github.com/thjaeger/easystroke/wiki 42 | ThJaeger@gmail.com 43 |
44 | -------------------------------------------------------------------------------- /annotate.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #include "annotate.h" 17 | #include 18 | #include 19 | 20 | Annotate::Annotate() { 21 | const char *ofc = "org.freedesktop.compiz"; 22 | GError *error = 0; 23 | bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error); 24 | if (!bus) { 25 | g_error_free(error); 26 | throw DBusException(); 27 | } 28 | 29 | char draw[256]; 30 | char clear[256]; 31 | snprintf(draw, sizeof(draw), "/org/freedesktop/compiz/annotate/screen%d/draw", DefaultScreen(dpy)); 32 | snprintf(clear, sizeof(clear), "/org/freedesktop/compiz/annotate/screen%d/clear_key", DefaultScreen(dpy)); 33 | 34 | draw_proxy = dbus_g_proxy_new_for_name(bus, ofc, draw, ofc); 35 | clear_proxy = dbus_g_proxy_new_for_name(bus, ofc, clear, ofc); 36 | } 37 | 38 | void Annotate::draw(Point p, Point q) { 39 | dbus_g_proxy_call_no_reply(draw_proxy, "activate", 40 | G_TYPE_STRING, "root", G_TYPE_INT, gint(ROOT), 41 | G_TYPE_STRING, "x1", G_TYPE_DOUBLE, gdouble(p.x), 42 | G_TYPE_STRING, "y1", G_TYPE_DOUBLE, gdouble(p.y), 43 | G_TYPE_STRING, "x2", G_TYPE_DOUBLE, gdouble(q.x), 44 | G_TYPE_STRING, "y2", G_TYPE_DOUBLE, gdouble(q.y), 45 | G_TYPE_INVALID); 46 | } 47 | void Annotate::end_() { 48 | dbus_g_proxy_call_no_reply(clear_proxy, "activate", 49 | G_TYPE_STRING, "root", G_TYPE_INT, gint(ROOT), 50 | G_TYPE_INVALID); 51 | } 52 | -------------------------------------------------------------------------------- /fire.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #include "fire.h" 17 | #include 18 | #include 19 | #include 20 | 21 | Fire::Fire() { 22 | const char *ofc = "org.freedesktop.compiz"; 23 | GError *error = 0; 24 | bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error); 25 | if (!bus) { 26 | g_error_free(error); 27 | throw DBusException(); 28 | } 29 | char add[256]; 30 | char clear[256]; 31 | snprintf(add, sizeof(add), "/org/freedesktop/compiz/firepaint/screen%d/add_particle", DefaultScreen(dpy)); 32 | snprintf(clear, sizeof(clear), "/org/freedesktop/compiz/firepaint/screen%d/clear_key", DefaultScreen(dpy)); 33 | 34 | point_proxy = dbus_g_proxy_new_for_name(bus, ofc, add, ofc); 35 | clear_proxy = dbus_g_proxy_new_for_name(bus, ofc, clear, ofc); 36 | } 37 | 38 | void Fire::add_point(float x, float y) { 39 | dbus_g_proxy_call_no_reply(point_proxy, "activate", 40 | G_TYPE_STRING, "root", G_TYPE_INT, gint(ROOT), 41 | G_TYPE_STRING, "x", G_TYPE_DOUBLE, gdouble(x), 42 | G_TYPE_STRING, "y", G_TYPE_DOUBLE, gdouble(y), 43 | G_TYPE_INVALID); 44 | } 45 | 46 | void Fire::draw(Point p, Point q) { 47 | float dist = hypot(p.x-q.x, p.y-q.y); 48 | leftover -= dist; 49 | while (leftover < 0.01) { 50 | add_point(q.x + (q.x-p.x)*leftover/dist, q.y + (q.y-p.y)*leftover/dist); 51 | leftover += 5.0; 52 | } 53 | } 54 | void Fire::timeout() { 55 | dbus_g_proxy_call_no_reply(clear_proxy, "activate", 56 | G_TYPE_STRING, "root", G_TYPE_INT, gint(ROOT), 57 | G_TYPE_INVALID); 58 | } 59 | -------------------------------------------------------------------------------- /cellrenderertextish.h: -------------------------------------------------------------------------------- 1 | /* cellrenderertextish.h generated by valac 0.18.1, the Vala compiler, do not modify */ 2 | 3 | 4 | #ifndef __CELLRENDERERTEXTISH_H__ 5 | #define __CELLRENDERERTEXTISH_H__ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | G_BEGIN_DECLS 13 | 14 | 15 | #define TYPE_CELL_RENDERER_TEXTISH (cell_renderer_textish_get_type ()) 16 | #define CELL_RENDERER_TEXTISH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_CELL_RENDERER_TEXTISH, CellRendererTextish)) 17 | #define CELL_RENDERER_TEXTISH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_CELL_RENDERER_TEXTISH, CellRendererTextishClass)) 18 | #define IS_CELL_RENDERER_TEXTISH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_CELL_RENDERER_TEXTISH)) 19 | #define IS_CELL_RENDERER_TEXTISH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CELL_RENDERER_TEXTISH)) 20 | #define CELL_RENDERER_TEXTISH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_CELL_RENDERER_TEXTISH, CellRendererTextishClass)) 21 | 22 | typedef struct _CellRendererTextish CellRendererTextish; 23 | typedef struct _CellRendererTextishClass CellRendererTextishClass; 24 | typedef struct _CellRendererTextishPrivate CellRendererTextishPrivate; 25 | 26 | #define CELL_RENDERER_TEXTISH_TYPE_MODE (cell_renderer_textish_mode_get_type ()) 27 | 28 | typedef enum { 29 | CELL_RENDERER_TEXTISH_MODE_Text, 30 | CELL_RENDERER_TEXTISH_MODE_Key, 31 | CELL_RENDERER_TEXTISH_MODE_Popup, 32 | CELL_RENDERER_TEXTISH_MODE_Combo 33 | } CellRendererTextishMode; 34 | 35 | struct _CellRendererTextish { 36 | GtkCellRendererText parent_instance; 37 | CellRendererTextishPrivate * priv; 38 | CellRendererTextishMode mode; 39 | gchar** items; 40 | gint items_length1; 41 | }; 42 | 43 | struct _CellRendererTextishClass { 44 | GtkCellRendererTextClass parent_class; 45 | }; 46 | 47 | 48 | GType cell_renderer_textish_get_type (void) G_GNUC_CONST; 49 | GType cell_renderer_textish_mode_get_type (void) G_GNUC_CONST; 50 | CellRendererTextish* cell_renderer_textish_new (void); 51 | CellRendererTextish* cell_renderer_textish_construct (GType object_type); 52 | CellRendererTextish* cell_renderer_textish_new_with_items (gchar** items, int items_length1); 53 | CellRendererTextish* cell_renderer_textish_construct_with_items (GType object_type, gchar** items, int items_length1); 54 | 55 | 56 | G_END_DECLS 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /shape.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #include 17 | #include "prefdb.h" 18 | #include "shape.h" 19 | #include "main.h" 20 | 21 | #include 22 | 23 | Shape::Shape() { 24 | int w = gdk_screen_width(); 25 | int h = gdk_screen_height(); 26 | Gdk::Color col = prefs.color.get().color; 27 | unsigned long bg = ((col.get_red()/257)<<16) + ((col.get_green()/257)<<8) + col.get_blue()/257; 28 | win = XCreateSimpleWindow(dpy, ROOT, 0, 0, w, h, 0, CopyFromParent, bg); 29 | XSetWindowAttributes attr; 30 | attr.override_redirect = True; 31 | XChangeWindowAttributes(dpy, win, CWOverrideRedirect, &attr); 32 | 33 | clear(); 34 | } 35 | 36 | void Shape::draw(Point p, Point q) { 37 | int px = (int)p.x, py = (int)p.y, qx = (int)q.x, qy = (int)q.y; 38 | int width = prefs.trace_width.get(); 39 | int x = (MIN(px, qx) - width); 40 | int y = (MIN(py, qy) - width); 41 | int w = (ABS(px - qx) + 2*width); 42 | int h = (ABS(py - qy) + 2*width); 43 | Pixmap pm = XCreatePixmap(dpy, DefaultRootWindow(dpy), w, h, 1); 44 | 45 | XGCValues gcv; 46 | gcv.foreground = 0; 47 | gcv.line_width = width; 48 | gcv.cap_style = CapRound; 49 | GC gc = XCreateGC(dpy, pm, GCCapStyle | GCForeground | GCLineWidth, &gcv); 50 | XFillRectangle(dpy, pm, gc, 0, 0, w, h); 51 | XSetForeground(dpy, gc, 1); 52 | XDrawLine(dpy, pm, gc, px-x, py-y, qx-x, qy-y); 53 | XFreeGC(dpy, gc); 54 | 55 | XShapeCombineMask(dpy, win, ShapeBounding, x, y, pm, ShapeUnion); 56 | XFreePixmap(dpy, pm); 57 | } 58 | 59 | void Shape::start_() { 60 | if (remove_timeout()) 61 | clear(); 62 | XMapRaised(dpy, win); 63 | } 64 | 65 | void Shape::end_() { 66 | XUnmapWindow(dpy, win); 67 | set_timeout(10); 68 | } 69 | 70 | void Shape::timeout() { 71 | clear(); 72 | XFlush(dpy); 73 | } 74 | 75 | void Shape::clear() { 76 | XShapeCombineRectangles(dpy, win, ShapeBounding, 0, 0, nullptr, 0, ShapeSet, YXBanded); 77 | } 78 | 79 | Shape::~Shape() { 80 | XDestroyWindow(dpy, win); 81 | } 82 | -------------------------------------------------------------------------------- /prefs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __PREFS_H__ 17 | #define __PREFS_H__ 18 | #include "prefdb.h" 19 | 20 | #include 21 | 22 | class Prefs { 23 | public: 24 | Prefs(); 25 | virtual ~Prefs() {} 26 | void update_device_list(); 27 | void update_extra_buttons(); 28 | private: 29 | void set_button_label(); 30 | 31 | void on_add(); 32 | void on_remove(); 33 | void on_add_extra(); 34 | void on_edit_extra(); 35 | void on_remove_extra(); 36 | void on_select_button(); 37 | public: 38 | void on_button_editing_started(GtkCellEditable *editable, const gchar *path); 39 | private: 40 | void on_device_toggled(const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter); 41 | void on_device_timeout_changed(const Glib::ustring& path, const Glib::ustring& new_text); 42 | bool select_row(const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter, std::string name); 43 | 44 | class ExceptionColumns : public Gtk::TreeModel::ColumnRecord { 45 | public: 46 | ExceptionColumns() { add(app); add(user_app); add(button); } 47 | Gtk::TreeModelColumn app; 48 | Gtk::TreeModelColumn user_app, button; 49 | }; 50 | ExceptionColumns cols; 51 | Glib::RefPtr tm; 52 | Gtk::TreeView* tv; 53 | 54 | class Single : public Gtk::TreeModel::ColumnRecord { 55 | public: 56 | Single() { add(name); } 57 | Gtk::TreeModelColumn name; 58 | }; 59 | Single timeout_columns; 60 | 61 | class DeviceColumns : public Gtk::TreeModel::ColumnRecord { 62 | public: 63 | DeviceColumns() { add(enabled); add(name); add(timeout); } 64 | Gtk::TreeModelColumn enabled; 65 | Gtk::TreeModelColumn name; 66 | Gtk::TreeModelColumn timeout; 67 | }; 68 | DeviceColumns dcs; 69 | Gtk::TreeView* dtv; 70 | Glib::RefPtr dtm; 71 | 72 | class ExtraColumns : public Gtk::TreeModel::ColumnRecord { 73 | public: 74 | ExtraColumns() { add(str); add(i); } 75 | Gtk::TreeModelColumn str; 76 | Gtk::TreeModelColumn::iterator> i; 77 | }; 78 | ExtraColumns ecs; 79 | Gtk::TreeView *etv; 80 | Glib::RefPtr etm; 81 | 82 | Gtk::Label* blabel; 83 | Gtk::Frame *frame_tablet; 84 | bool ignore_device_toggled; 85 | }; 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __HANDLER_H__ 17 | #define __HANDLER_H__ 18 | #include "gesture.h" 19 | #include "grabber.h" 20 | #include "actiondb.h" 21 | 22 | class Handler; 23 | 24 | class XState { 25 | friend class Handler; 26 | public: 27 | XState(); 28 | 29 | bool handle(Glib::IOCondition); 30 | void handle_enter_leave(XEvent &ev); 31 | void handle_event(XEvent &ev); 32 | void handle_xi2_event(XIDeviceEvent *event); 33 | void handle_raw_motion(XIRawEvent *event); 34 | void report_xi2_event(XIDeviceEvent *event, const char *type); 35 | 36 | void fake_core_button(guint b, bool press); 37 | void fake_click(guint b); 38 | void update_core_mapping(); 39 | 40 | void remove_device(int deviceid); 41 | void ungrab(int deviceid); 42 | 43 | bool idle(); 44 | void ping(); 45 | void bail_out(); 46 | void select(); 47 | void run_action(RAction act); 48 | void queue(sigc::slot f); 49 | std::string select_window(); 50 | 51 | static void activate_window(Window w, Time t); 52 | static Window get_window(Window w, Atom prop); 53 | static Atom get_atom(Window w, Atom prop); 54 | static bool has_atom(Window w, Atom prop, Atom value); 55 | static void icccm_client_message(Window w, Atom a, Time t); 56 | 57 | Grabber::XiDevice *current_dev; 58 | bool in_proximity; 59 | bool accepted; 60 | std::set xinput_pressed; 61 | guint modifiers; 62 | std::map core_inv_map; 63 | private: 64 | Window ping_window; 65 | Handler *handler; 66 | 67 | static int xErrorHandler(Display *dpy2, XErrorEvent *e); 68 | static int xIOErrorHandler(Display *dpy2); 69 | int (*oldHandler)(Display *, XErrorEvent *); 70 | int (*oldIOHandler)(Display *); 71 | std::list > queued; 72 | std::map opcodes; 73 | }; 74 | 75 | class Handler { 76 | public: 77 | Handler *child; 78 | Handler *parent; 79 | Handler() : child(nullptr), parent(nullptr) {} 80 | Handler *top() { 81 | if (child) 82 | return child->top(); 83 | else 84 | return this; 85 | } 86 | 87 | virtual void motion(RTriple e) {} 88 | virtual void raw_motion(RTriple e, bool, bool) {} 89 | virtual void press(guint b, RTriple e) {} 90 | virtual void release(guint b, RTriple e) {} 91 | virtual void press_master(guint b, Time t) {} 92 | virtual void pong() {} 93 | void replace_child(Handler *c); 94 | virtual void init() {} 95 | virtual ~Handler() { 96 | if (child) 97 | delete child; 98 | } 99 | virtual std::string name() = 0; 100 | virtual Grabber::State grab_mode() = 0; 101 | }; 102 | 103 | extern XState *xstate; 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /win.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __WIN_H__ 17 | #define __WIN_H__ 18 | #include "gesture.h" 19 | #include 20 | #include "util.h" 21 | #include "prefdb.h" 22 | 23 | class Actions; 24 | class Prefs; 25 | class Stats; 26 | class Ranking; 27 | 28 | // Convenience macro for on-the-fly creation of widgets 29 | #define WIDGET(TYPE, NAME, ARGS...) TYPE &NAME = *Gtk::manage(new TYPE(ARGS)) 30 | 31 | extern Glib::RefPtr widgets; 32 | 33 | class Win : Timeout { 34 | public: 35 | Win(); 36 | 37 | Gtk::Window& get_window() { return *win; } 38 | boost::shared_ptr actions; 39 | boost::shared_ptr prefs_tab; 40 | boost::shared_ptr stats; 41 | void show(); 42 | void hide(); 43 | void show_hide(); 44 | void set_icon(RStroke stroke, bool invert); 45 | void show_about(); 46 | private: 47 | bool on_icon_size_changed(int); 48 | virtual void timeout(); 49 | void on_help_toggled(); 50 | void show_popup(guint, guint32); 51 | void show_hide_icon(); 52 | 53 | Gtk::Window *win; 54 | 55 | Gtk::Menu menu; 56 | 57 | Glib::RefPtr icon; 58 | Glib::RefPtr icon_pb[2]; 59 | }; 60 | 61 | extern Win *win; 62 | 63 | class Stats { 64 | public: 65 | Stats(); 66 | bool on_stroke(boost::shared_ptr); 67 | private: 68 | void on_pdf(); 69 | void on_cursor_changed(); 70 | 71 | class ModelColumns : public Gtk::TreeModel::ColumnRecord { 72 | public: 73 | ModelColumns() { add(stroke); add(debug); add(name); add(score); add(child); } 74 | 75 | Gtk::TreeModelColumn > stroke; 76 | Gtk::TreeModelColumn > debug; 77 | Gtk::TreeModelColumn name; 78 | Gtk::TreeModelColumn score; 79 | Gtk::TreeModelColumn > child; 80 | }; 81 | ModelColumns cols; 82 | 83 | Gtk::TreeView *recent_view; 84 | Glib::RefPtr recent_store; 85 | 86 | Gtk::TreeView *ranking_view; 87 | }; 88 | 89 | class SelectButton { 90 | public: 91 | SelectButton(ButtonInfo bi, bool def, bool any); 92 | ~SelectButton(); 93 | bool run(); 94 | ButtonInfo event; 95 | private: 96 | Gtk::MessageDialog *dialog; 97 | bool on_button_press(GdkEventButton *ev); 98 | void on_any_toggled(); 99 | 100 | Gtk::EventBox *eventbox; 101 | Gtk::ToggleButton *toggle_shift, *toggle_control, *toggle_alt, *toggle_super, *toggle_any; 102 | Gtk::ComboBoxText *select_button; 103 | Gtk::RadioButton *radio_timeout_default, *radio_instant, *radio_click_hold; 104 | sigc::connection handler[2]; 105 | }; 106 | 107 | void error_dialog(const Glib::ustring &); 108 | Glib::ustring app_name_hr(Glib::ustring); 109 | #endif 110 | -------------------------------------------------------------------------------- /grabber.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __GRABBER_H__ 17 | #define __GRABBER_H__ 18 | #include "prefdb.h" 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define MAX_BUTTONS 256 25 | 26 | class XAtom { 27 | const char *name; 28 | Atom atom; 29 | 30 | public: 31 | XAtom(const char *name_) : name(name_), atom(0) {} 32 | Atom operator*(); 33 | Atom operator->() { return operator*(); } 34 | }; 35 | 36 | class Children { 37 | Window parent; 38 | public: 39 | Children(Window); 40 | bool handle(XEvent &ev); 41 | void add(Window); 42 | void remove(Window); 43 | void destroy(Window); 44 | }; 45 | 46 | class Grabber; 47 | extern Grabber *grabber; 48 | 49 | class Grabber { 50 | friend class Handler; 51 | friend class StrokeHandler; 52 | friend class Button; 53 | friend class Prefs; 54 | public: 55 | Children children; 56 | enum State { NONE, BUTTON, SELECT, RAW }; 57 | enum GrabState { GrabNo, GrabYes, GrabRaw }; 58 | static const char *state_name[4]; 59 | 60 | struct XiDevice { 61 | int dev; 62 | std::string name; 63 | bool absolute; 64 | bool active; 65 | int proximity_axis; 66 | double scale_x, scale_y; 67 | int num_buttons; 68 | int master; 69 | XiDevice(Grabber *, XIDeviceInfo *); 70 | void grab_device(GrabState grab); 71 | void grab_button(ButtonInfo &bi, bool grab); 72 | }; 73 | 74 | typedef std::map > DeviceMap; 75 | int opcode, event, error; 76 | XiDevice *get_xi_dev(int id); 77 | private: 78 | bool init_xi(); 79 | 80 | DeviceMap xi_devs; 81 | State current, grabbed; 82 | bool xi_grabbed; 83 | GrabState xi_devs_grabbed; 84 | int suspended; 85 | bool active; 86 | Cursor cursor_select; 87 | ButtonInfo grabbed_button; 88 | std::vector buttons; 89 | 90 | void set(); 91 | void grab_xi(bool); 92 | void grab_xi_devs(GrabState); 93 | 94 | void update_excluded(); 95 | 96 | void grab(State s) { current = s; set(); } 97 | void suspend() { suspended++; set(); } 98 | void resume() { if (suspended) suspended--; set(); } 99 | void update(); 100 | public: 101 | Grabber(); 102 | ~Grabber(); 103 | bool handle(XEvent &ev) { return children.handle(ev); } 104 | Out *current_class; 105 | 106 | void queue_suspend(); 107 | void queue_resume(); 108 | std::string select_window(); 109 | 110 | void new_device(XIDeviceInfo *); 111 | 112 | bool is_grabbed(guint b); 113 | bool is_instant(guint b); 114 | bool is_click_hold(guint b); 115 | bool hierarchy_changed(XIHierarchyEvent *); 116 | 117 | int get_default_button() { return grabbed_button.button; } 118 | guint get_default_mods(guint button); 119 | 120 | void unminimize(); 121 | }; 122 | 123 | class GrabFailedException : public std::exception { 124 | char *msg; 125 | public: 126 | GrabFailedException(int code) { if (asprintf(&msg, "Grab Failed: %d", code) == -1) msg = nullptr; } 127 | virtual const char* what() const throw() { return msg ? msg : "Grab Failed"; } 128 | ~GrabFailedException() throw() { free(msg); } 129 | }; 130 | 131 | #endif 132 | -------------------------------------------------------------------------------- /cellrenderertextish.vala: -------------------------------------------------------------------------------- 1 | /* compile with valac -c cellrenderertextish.vala --pkg gtk+-3.0 -C -H cellrenderertextish.h */ 2 | 3 | public class CellRendererTextish : Gtk.CellRendererText { 4 | public enum Mode { Text, Key, Popup, Combo } 5 | public new Mode mode; 6 | public string[] items; 7 | 8 | public signal void key_edited(string path, Gdk.ModifierType mods, uint code); 9 | public signal void combo_edited(string path, uint row); 10 | 11 | private Gtk.CellEditable? cell; 12 | 13 | public CellRendererTextish() { 14 | mode = Mode.Text; 15 | cell = null; 16 | items = null; 17 | } 18 | 19 | public CellRendererTextish.with_items(string[] items) { 20 | mode = Mode.Text; 21 | cell = null; 22 | this.items = items; 23 | } 24 | 25 | public override unowned Gtk.CellEditable start_editing (Gdk.Event? event, Gtk.Widget widget, string path, Gdk.Rectangle background_area, Gdk.Rectangle cell_area, Gtk.CellRendererState flags) { 26 | cell = null; 27 | if (!editable) 28 | return cell; 29 | switch (mode) { 30 | case Mode.Text: 31 | cell = base.start_editing(event, widget, path, background_area, cell_area, flags); 32 | break; 33 | case Mode.Key: 34 | cell = new CellEditableAccel(this, path, widget); 35 | break; 36 | case Mode.Combo: 37 | cell = new CellEditableCombo(this, path, widget, items); 38 | break; 39 | case Mode.Popup: 40 | cell = new CellEditableDummy(); 41 | break; 42 | } 43 | return cell; 44 | } 45 | } 46 | 47 | class CellEditableDummy : Gtk.EventBox, Gtk.CellEditable { 48 | public bool editing_canceled { get; set; } 49 | protected virtual void start_editing(Gdk.Event? event) { 50 | editing_done(); 51 | remove_widget(); 52 | } 53 | } 54 | 55 | class CellEditableAccel : Gtk.EventBox, Gtk.CellEditable { 56 | public bool editing_canceled { get; set; } 57 | new CellRendererTextish parent; 58 | new string path; 59 | 60 | public CellEditableAccel(CellRendererTextish parent, string path, Gtk.Widget widget) { 61 | this.parent = parent; 62 | this.path = path; 63 | editing_done.connect(on_editing_done); 64 | Gtk.Label label = new Gtk.Label(_("Key combination...")); 65 | label.set_alignment(0.0f, 0.5f); 66 | add(label); 67 | override_background_color(Gtk.StateFlags.NORMAL, widget.get_style_context().get_background_color(Gtk.StateFlags.SELECTED)); 68 | label.override_color(Gtk.StateFlags.NORMAL, widget.get_style_context().get_color(Gtk.StateFlags.SELECTED)); 69 | show_all(); 70 | } 71 | 72 | protected virtual void start_editing(Gdk.Event? event) { 73 | Gtk.grab_add(this); 74 | Gdk.keyboard_grab(get_window(), false, event != null ? event.get_time() : Gdk.CURRENT_TIME); 75 | 76 | /* 77 | Gdk.DeviceManager dm = get_window().get_display().get_device_manager(); 78 | foreach (Gdk.Device dev in dm.list_devices(Gdk.DeviceType.SLAVE)) 79 | Gtk.device_grab_add(this, dev, true); 80 | */ 81 | key_press_event.connect(on_key); 82 | } 83 | 84 | bool on_key(Gdk.EventKey event) { 85 | if (event.is_modifier != 0) 86 | return true; 87 | switch (event.keyval) { 88 | case Gdk.Key.Super_L: 89 | case Gdk.Key.Super_R: 90 | case Gdk.Key.Hyper_L: 91 | case Gdk.Key.Hyper_R: 92 | return true; 93 | } 94 | Gdk.ModifierType mods = event.state & Gtk.accelerator_get_default_mod_mask(); 95 | 96 | editing_done(); 97 | remove_widget(); 98 | 99 | parent.key_edited(path, mods, event.hardware_keycode); 100 | return true; 101 | } 102 | void on_editing_done() { 103 | Gtk.grab_remove(this); 104 | Gdk.keyboard_ungrab(Gdk.CURRENT_TIME); 105 | 106 | /* 107 | Gdk.DeviceManager dm = get_window().get_display().get_device_manager(); 108 | foreach (Gdk.Device dev in dm.list_devices(Gdk.DeviceType.SLAVE)) 109 | Gtk.device_grab_remove(this, dev); 110 | */ 111 | } 112 | } 113 | 114 | 115 | class CellEditableCombo : Gtk.ComboBoxText { 116 | new CellRendererTextish parent; 117 | new string path; 118 | 119 | public CellEditableCombo(CellRendererTextish parent, string path, Gtk.Widget widget, string[] items) { 120 | this.parent = parent; 121 | this.path = path; 122 | foreach (string item in items) { 123 | append_text(_(item)); 124 | } 125 | changed.connect(() => parent.combo_edited(path, active)); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /gesture.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #include "gesture.h" 17 | #include "prefdb.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | BOOST_CLASS_EXPORT(Stroke) 25 | 26 | void update_triple(RTriple e, float x, float y, Time t) { 27 | e->x = x; 28 | e->y = y; 29 | e->t = t; 30 | } 31 | 32 | RTriple create_triple(float x, float y, Time t) { 33 | RTriple e(new Triple); 34 | update_triple(e, x, y, t); 35 | return e; 36 | } 37 | 38 | template void Stroke::save(Archive & ar, const unsigned int version) const { 39 | std::vector ps; 40 | for (unsigned int i = 0; i < size(); i++) 41 | ps.push_back(points(i)); 42 | ar & ps; 43 | ar & button; 44 | ar & trigger; 45 | ar & timeout; 46 | ar & modifiers; 47 | } 48 | 49 | template void Stroke::load(Archive & ar, const unsigned int version) { 50 | std::vector ps; 51 | ar & ps; 52 | if (ps.size()) { 53 | stroke_t *s = stroke_alloc(ps.size()); 54 | for (std::vector::iterator i = ps.begin(); i != ps.end(); ++i) 55 | stroke_add_point(s, i->x, i->y); 56 | stroke_finish(s); 57 | stroke.reset(s, &stroke_free); 58 | } 59 | if (version == 0) return; 60 | ar & button; 61 | if (version >= 2) 62 | ar & trigger; 63 | if (version < 4 && (!button || trigger == (int)prefs.button.get().button)) 64 | trigger = 0; 65 | if (version < 3) 66 | return; 67 | ar & timeout; 68 | if (version < 5) 69 | return; 70 | ar & modifiers; 71 | } 72 | 73 | Stroke::Stroke(PreStroke &ps, int trigger_, int button_, unsigned int modifiers_, bool timeout_) : trigger(trigger_), button(button_), modifiers(modifiers_), timeout(timeout_) { 74 | if (ps.valid()) { 75 | stroke_t *s = stroke_alloc(ps.size()); 76 | for (std::vector::iterator i = ps.begin(); i != ps.end(); ++i) 77 | stroke_add_point(s, (*i)->x, (*i)->y); 78 | stroke_finish(s); 79 | stroke.reset(s, &stroke_free); 80 | } 81 | } 82 | 83 | int Stroke::compare(RStroke a, RStroke b, double &score) { 84 | score = 0.0; 85 | if (!a || !b) 86 | return -1; 87 | if (!a->timeout != !b->timeout) 88 | return -1; 89 | if (a->button != b->button) 90 | return -1; 91 | if (a->trigger != b->trigger) 92 | return -1; 93 | if (a->modifiers != b->modifiers) 94 | return -1; 95 | if (!a->stroke || !b->stroke) { 96 | if (!a->stroke && !b->stroke) { 97 | score = 1.0; 98 | return 1; 99 | } 100 | return -1; 101 | } 102 | double cost = stroke_compare(a->stroke.get(), b->stroke.get(), nullptr, nullptr); 103 | if (cost >= stroke_infinity) 104 | return -1; 105 | score = MAX(1.0 - 2.5*cost, 0.0); 106 | if (a->timeout) 107 | return score > 0.85; 108 | else 109 | return score > 0.7; 110 | } 111 | 112 | Glib::RefPtr Stroke::draw(int size, double width, bool inv) const { 113 | if (size != STROKE_SIZE || (width != 2.0 && width != 4.0) || inv) 114 | return draw_(size, width, inv); 115 | int i = width == 2.0; 116 | if (pb[i]) 117 | return pb[i]; 118 | pb[i] = draw_(size, width); 119 | return pb[i]; 120 | } 121 | 122 | Glib::RefPtr Stroke::pbEmpty; 123 | 124 | Glib::RefPtr Stroke::drawEmpty(int size) { 125 | if (size != STROKE_SIZE) 126 | return drawEmpty_(size); 127 | if (pbEmpty) 128 | return pbEmpty; 129 | pbEmpty = drawEmpty_(size); 130 | return pbEmpty; 131 | } 132 | 133 | 134 | RStroke Stroke::trefoil() { 135 | PreStroke s; 136 | const int n = 40; 137 | for (int i = 0; i<=n; i++) { 138 | double phi = M_PI*(-4.0*i/n)-2.7; 139 | double r = exp(1.0 + sin(6.0*M_PI*i/n)) + 2.0; 140 | s.add(create_triple(r*cos(phi), r*sin(phi), i)); 141 | } 142 | return Stroke::create(s, 0, 0, AnyModifier, false); 143 | } 144 | -------------------------------------------------------------------------------- /gesture.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __GESTURE_H__ 17 | #define __GESTURE_H__ 18 | 19 | #include "stroke.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | #define STROKE_SIZE 64 30 | 31 | class Stroke; 32 | class PreStroke; 33 | 34 | typedef boost::shared_ptr RStroke; 35 | typedef boost::shared_ptr RPreStroke; 36 | 37 | struct Triple { 38 | float x; 39 | float y; 40 | Time t; 41 | }; 42 | typedef boost::shared_ptr RTriple; 43 | void update_triple(RTriple e, float x, float y, Time t); 44 | RTriple create_triple(float x, float y, Time t); 45 | 46 | class PreStroke; 47 | class Stroke { 48 | friend class PreStroke; 49 | friend class boost::serialization::access; 50 | friend class Stats; 51 | public: 52 | struct Point { 53 | double x; 54 | double y; 55 | Point operator+(const Point &p) { 56 | Point sum = { x + p.x, y + p.y }; 57 | return sum; 58 | } 59 | Point operator-(const Point &p) { 60 | Point sum = { x - p.x, y - p.y }; 61 | return sum; 62 | } 63 | Point operator*(const double a) { 64 | Point product = { x * a, y * a }; 65 | return product; 66 | } 67 | template void serialize(Archive & ar, const unsigned int version) { 68 | ar & x; ar & y; 69 | if (version == 0) { 70 | double time; 71 | ar & time; 72 | } 73 | } 74 | }; 75 | 76 | private: 77 | Stroke(PreStroke &s, int trigger_, int button_, unsigned int modifiers_, bool timeout_); 78 | 79 | Glib::RefPtr draw_(int size, double width = 2.0, bool inv = false) const; 80 | mutable Glib::RefPtr pb[2]; 81 | 82 | static Glib::RefPtr drawEmpty_(int); 83 | static Glib::RefPtr pbEmpty; 84 | 85 | BOOST_SERIALIZATION_SPLIT_MEMBER() 86 | template void load(Archive & ar, const unsigned int version); 87 | template void save(Archive & ar, const unsigned int version) const; 88 | public: 89 | int trigger; 90 | int button; 91 | unsigned int modifiers; 92 | bool timeout; 93 | boost::shared_ptr stroke; 94 | 95 | Stroke() : trigger(0), button(0), modifiers(AnyModifier), timeout(false) {} 96 | static RStroke create(PreStroke &s, int trigger_, int button_, unsigned int modifiers_, bool timeout_) { 97 | return RStroke(new Stroke(s, trigger_, button_, modifiers_, timeout_)); 98 | } 99 | Glib::RefPtr draw(int size, double width = 2.0, bool inv = false) const; 100 | void draw(Cairo::RefPtr surface, int x, int y, int w, int h, double width = 2.0, bool inv = false) const; 101 | void draw_svg(std::string filename) const; 102 | bool show_icon(); 103 | 104 | static RStroke trefoil(); 105 | static int compare(RStroke, RStroke, double &); 106 | static Glib::RefPtr drawEmpty(int); 107 | static Glib::RefPtr drawDebug(RStroke, RStroke, int); 108 | 109 | unsigned int size() const { return stroke ? stroke_get_size(stroke.get()) : 0; } 110 | bool trivial() const { return size() == 0 && button == 0; } 111 | Point points(int n) const { Point p; stroke_get_point(stroke.get(), n, &p.x, &p.y); return p; } 112 | double time(int n) const { return stroke_get_time(stroke.get(), n); } 113 | bool is_timeout() const { return timeout; } 114 | }; 115 | BOOST_CLASS_VERSION(Stroke, 5) 116 | BOOST_CLASS_VERSION(Stroke::Point, 1) 117 | 118 | class PreStroke : public std::vector { 119 | public: 120 | static RPreStroke create() { return RPreStroke(new PreStroke()); } 121 | void add(RTriple p) { push_back(p); } 122 | bool valid() const { return size() > 2; } 123 | }; 124 | #endif 125 | -------------------------------------------------------------------------------- /composite.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #include "prefdb.h" 17 | #include "composite.h" 18 | #include 19 | #include 20 | 21 | double red, green, blue, alpha, width; 22 | std::list points; 23 | 24 | Popup::Popup(int x1, int y1, int x2, int y2) : Gtk::Window(Gtk::WINDOW_POPUP), rect(x1, y1, x2-x1, y2-y1) { 25 | if (!is_composited()) 26 | throw std::runtime_error(_("'composite' not available")); 27 | 28 | Glib::RefPtr visual = get_screen()->get_rgba_visual(); 29 | gtk_widget_set_visual(Widget::gobj(), visual->gobj()); 30 | gtk_widget_set_app_paintable (Widget::gobj(), TRUE); 31 | signal_draw().connect(sigc::mem_fun(*this, &Popup::on_draw)); 32 | realize(); 33 | move(x1, y1); 34 | resize(x2-x1, y2-y1); 35 | get_window()->input_shape_combine_region(Cairo::Region::create(), 0, 0); 36 | // tell compiz to leave this window the hell alone 37 | get_window()->set_type_hint(Gdk::WINDOW_TYPE_HINT_DESKTOP); 38 | } 39 | 40 | void Popup::invalidate(int x1, int y1, int x2, int y2) { 41 | if (get_mapped()) { 42 | Gdk::Rectangle inv(x1 - rect.get_x(), y1 - rect.get_y(), x2-x1, y2-y1); 43 | get_window()->invalidate_rect(inv, false); 44 | } else 45 | show(); 46 | } 47 | 48 | Composite::Composite() { 49 | #define N 128 50 | int w = gdk_screen_width(); 51 | int h = gdk_screen_height(); 52 | num_x = (gdk_screen_width() - 1)/N + 1; 53 | num_y = (gdk_screen_height() - 1)/N + 1; 54 | pieces = new Popup**[num_x]; 55 | for (int i = 0; i < num_x; i++) { 56 | pieces[i] = new Popup*[num_y]; 57 | for (int j = 0; j < num_y; j++) 58 | pieces[i][j] = new Popup(i*N,j*N,MIN((i+1)*N,w),MIN((j+1)*N,h)); 59 | 60 | } 61 | } 62 | 63 | void Composite::draw(Point p, Point q) { 64 | if (!points.size()) { 65 | points.push_back(p); 66 | } 67 | points.push_back(q); 68 | int x1 = (int)(p.x < q.x ? p.x : q.x); 69 | int x2 = (int)(p.x < q.x ? q.x : p.x); 70 | int y1 = (int)(p.y < q.y ? p.y : q.y); 71 | int y2 = (int)(p.y < q.y ? q.y : p.y); 72 | int bw = (int)(width/2.0) + 2; 73 | x1 -= bw; y1 -= bw; 74 | x2 += bw; y2 += bw; 75 | if (x1 < 0) 76 | x1 = 0; 77 | if (y1 < 0) 78 | y1 = 0; 79 | for (int i = x1/N; iinvalidate(x1, y1, x2, y2); 82 | } 83 | 84 | void Composite::start_() { 85 | RGBA rgba = prefs.color.get(); 86 | red = rgba.color.get_red_p(); 87 | green = rgba.color.get_green_p(); 88 | blue = rgba.color.get_blue_p(); 89 | alpha = ((double)rgba.alpha)/65535.0; 90 | width = prefs.trace_width.get(); 91 | } 92 | 93 | void Popup::draw_line(Cairo::RefPtr ctx) { 94 | if (!points.size()) 95 | return; 96 | std::list::iterator i = points.begin(); 97 | ctx->move_to (i->x, i->y); 98 | for (; i != points.end(); i++) 99 | ctx->line_to (i->x, i->y); 100 | ctx->set_source_rgba((red+0.5)/2.0, (green+0.5)/2.0, (blue+0.5)/2.0, alpha/2.0); 101 | ctx->set_line_width(width+1.0); 102 | ctx->set_line_cap(Cairo::LINE_CAP_ROUND); 103 | ctx->set_line_join(Cairo::LINE_JOIN_ROUND); 104 | ctx->stroke_preserve(); 105 | 106 | ctx->set_source_rgba(red, green, blue, alpha); 107 | ctx->set_line_width(width*0.7); 108 | ctx->stroke(); 109 | 110 | } 111 | 112 | bool Popup::on_draw(const ::Cairo::RefPtr< ::Cairo::Context>& ctx) { 113 | ctx->set_operator(Cairo::OPERATOR_SOURCE); 114 | ctx->set_source_rgba(0.0, 0.0, 0.0, 0.0); 115 | ctx->paint(); 116 | 117 | ctx->translate(-rect.get_x(), -rect.get_y()); 118 | draw_line(ctx); 119 | 120 | return false; 121 | } 122 | 123 | void Composite::end_() { 124 | points.clear(); 125 | for (int i = 0; i < num_x; i++) 126 | for (int j = 0; j < num_y; j++) 127 | pieces[i][j]->hide(); 128 | } 129 | 130 | Composite::~Composite() { 131 | for (int i = 0; i < num_x; i++) { 132 | for (int j = 0; j < num_y; j++) 133 | delete pieces[i][j]; 134 | delete[] pieces[i]; 135 | } 136 | delete[] pieces; 137 | } 138 | -------------------------------------------------------------------------------- /var.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __VAR_H__ 17 | #define __VAR_H__ 18 | 19 | #include 20 | #include 21 | #include 22 | #include "util.h" 23 | 24 | class Base { 25 | public: 26 | virtual void notify() = 0; 27 | virtual ~Base() {} 28 | }; 29 | 30 | class Notifier : public Base { 31 | sigc::slot f; 32 | public: 33 | Notifier(sigc::slot f_) : f(f_) {} 34 | virtual void notify() { f(); } 35 | }; 36 | 37 | class Atomic { 38 | std::set update_queue; 39 | public: 40 | void defer(Base *out) { update_queue.insert(out); } 41 | ~Atomic() { 42 | for (std::set::iterator i = update_queue.begin(); i != update_queue.end(); i++) 43 | (*i)->notify(); 44 | } 45 | }; 46 | 47 | template class Out { 48 | std::set out; 49 | protected: 50 | void update() { 51 | for (std::set::iterator i = out.begin(); i != out.end(); i++) 52 | (*i)->notify(); 53 | } 54 | public: 55 | void connect(Base *s) { out.insert(s); } 56 | virtual T get() const = 0; 57 | virtual ~Out() {} 58 | }; 59 | 60 | template class In { 61 | public: 62 | virtual void set(const T x) = 0; 63 | virtual ~In() {} 64 | }; 65 | 66 | template class IO : public In, public Out {}; 67 | 68 | template class Source : public IO, private Base { 69 | T x; 70 | public: 71 | Source() {} 72 | Source(T x_) : x(x_) {} 73 | virtual void set(const T x_) { 74 | x = x_; 75 | Out::update(); 76 | } 77 | virtual T get() const { return x; } 78 | const T &ref() const { return x; } 79 | // write_refs are evil 80 | T &write_ref(Atomic &a) { 81 | a.defer(this); 82 | return x; 83 | } 84 | virtual void notify() { Out::update(); } 85 | // unsafe_refs even more so 86 | T &unsafe_ref() { return x; } 87 | }; 88 | 89 | template class Var : public IO, private Base { 90 | Out ∈ 91 | T x; 92 | public: 93 | Var(Out &in_) : in(in_), x(in.get()) { in.connect(this); } 94 | virtual void notify() { set(in.get()); } 95 | virtual void set(const T x_) { 96 | x = x_; 97 | Out::update(); 98 | } 99 | virtual T get() const { return x; } 100 | }; 101 | 102 | template class Fun : public Out, private Base { 103 | sigc::slot f; 104 | Out ∈ 105 | public: 106 | Fun(sigc::slot f_, Out &in_) : f(f_), in(in_) { in.connect(this); } 107 | virtual Y get() const { return f(in.get()); } 108 | virtual void notify() { Out::update(); } 109 | }; 110 | 111 | template Fun *fun(Y (*f)(X), Out &in) { 112 | return new Fun(sigc::ptr_fun(f), in); 113 | } 114 | 115 | template class Fun2 : public Out, private Base { 116 | sigc::slot f; 117 | Out &inX; 118 | Out &inY; 119 | public: 120 | Fun2(sigc::slot f_, Out &inX_, Out &inY_) : f(f_), inX(inX_), inY(inY_) { 121 | inX.connect(this); 122 | inY.connect(this); 123 | } 124 | virtual Z get() const { return f(inX.get(), inY.get()); } 125 | virtual void notify() { Out::update(); } 126 | }; 127 | 128 | template Fun2 *fun2(Y (*f)(X1, X2), Out &in1, Out &in2) { 129 | return new Fun2(sigc::ptr_fun(f), in1, in2); 130 | } 131 | 132 | template class Bijection : public IO, private Base { 133 | sigc::slot f; 134 | sigc::slot g; 135 | IO ∈ 136 | public: 137 | Bijection(sigc::slot f_, sigc::slot g_, IO &in_) : f(f_), g(g_), in(in_) { 138 | in.connect(this); 139 | } 140 | virtual Y get() const { return f(in.get()); } 141 | virtual void notify() { Out::update(); } 142 | virtual void set(const Y y) { in.set(g(y)); } 143 | }; 144 | 145 | class Watcher : private Base { 146 | public: 147 | template void watch(Out &v) { v.connect(this); } 148 | }; 149 | 150 | class TimeoutWatcher : public Watcher, Timeout { 151 | int ms; 152 | public: 153 | TimeoutWatcher(int ms_) : ms(ms_) {} 154 | virtual void notify() { set_timeout(ms); } 155 | void execute_now() { 156 | if (remove_timeout()) 157 | timeout(); 158 | } 159 | }; 160 | #endif 161 | -------------------------------------------------------------------------------- /prefdb.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __PREFDB_H__ 17 | #define __PREFDB_H__ 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "var.h" 27 | 28 | enum TraceType { TraceDefault, TraceShape, TraceNone, TraceAnnotate, TraceFire, TraceWater }; 29 | enum TimeoutType { TimeoutOff, TimeoutDefault, TimeoutMedium, TimeoutAggressive, TimeoutFlick, TimeoutCustom, TimeoutConservative }; 30 | 31 | class ButtonInfo { 32 | friend class boost::serialization::access; 33 | template void serialize(Archive & ar, const unsigned int version) { 34 | ar & button; 35 | ar & state; 36 | if (version == 1) { 37 | int special; 38 | ar & special; 39 | return; 40 | } 41 | if (version < 3) 42 | return; 43 | ar & instant; 44 | if (version < 4) 45 | return; 46 | ar & click_hold; 47 | } 48 | public: 49 | guint button; 50 | guint state; 51 | bool instant; 52 | bool click_hold; 53 | bool operator<(const ButtonInfo &bi) const { return button < bi.button; } 54 | bool operator==(const ButtonInfo &bi) const { 55 | return button == bi.button && state == bi.state && !instant == !bi.instant && !click_hold == !bi.click_hold; 56 | } 57 | void press(); 58 | Glib::ustring get_button_text() const; 59 | bool overlap(const ButtonInfo &bi) const; 60 | ButtonInfo(guint button_) : button(button_), state(0), instant(false), click_hold(false) {} 61 | ButtonInfo() : button(0), state(0), instant(false), click_hold(false) {} 62 | }; 63 | BOOST_CLASS_VERSION(ButtonInfo, 4) 64 | 65 | typedef boost::shared_ptr RButtonInfo; 66 | 67 | struct RGBA { 68 | Gdk::Color color; 69 | guint16 alpha; 70 | RGBA() : alpha(65535) {} 71 | RGBA(Gdk::Color c) : color(c), alpha(65535) {} 72 | template void save(Archive &ar, unsigned int version) const { 73 | gushort r, g, b; 74 | r = color.get_red(); 75 | g = color.get_green(); 76 | b = color.get_blue(); 77 | ar & r; 78 | ar & g; 79 | ar & b; 80 | ar & alpha; 81 | } 82 | template void load(Archive &ar, unsigned int version) { 83 | gushort r, g, b; 84 | ar & r; 85 | ar & g; 86 | ar & b; 87 | ar & alpha; 88 | color.set_red(r); 89 | color.set_green(g); 90 | color.set_blue(b); 91 | } 92 | bool operator==(const RGBA rgba) { 93 | return color == rgba.color && alpha == rgba.alpha; 94 | } 95 | BOOST_SERIALIZATION_SPLIT_MEMBER() 96 | }; 97 | 98 | extern const ButtonInfo default_button; 99 | 100 | class PrefDB : public TimeoutWatcher { 101 | friend class boost::serialization::access; 102 | bool good_state; 103 | template void serialize(Archive & ar, const unsigned int version); 104 | 105 | template struct PrefSource : public Source { 106 | PrefSource(); 107 | PrefSource(T x_); 108 | }; 109 | public: 110 | PrefDB(); 111 | 112 | PrefSource > exceptions; 113 | PrefSource button; 114 | PrefSource trace; 115 | PrefSource advanced_ignore; 116 | PrefSource proximity; 117 | PrefSource feedback; 118 | PrefSource left_handed; 119 | PrefSource init_timeout; 120 | PrefSource final_timeout; 121 | PrefSource timeout_profile; 122 | PrefSource timeout_gestures; 123 | PrefSource tray_icon; 124 | PrefSource > excluded_devices; 125 | PrefSource color; 126 | PrefSource trace_width; 127 | PrefSource > extra_buttons; 128 | PrefSource advanced_popups; 129 | PrefSource scroll_invert; 130 | PrefSource scroll_speed; 131 | PrefSource tray_feedback; 132 | PrefSource show_osd; 133 | PrefSource move_back; 134 | PrefSource > device_timeout; 135 | PrefSource whitelist; 136 | 137 | void init(); 138 | virtual void timeout(); 139 | }; 140 | 141 | BOOST_CLASS_VERSION(PrefDB, 18) 142 | 143 | extern PrefDB prefs; 144 | 145 | template PrefDB::PrefSource::PrefSource() : Source() { prefs.watch(*this); } 146 | template PrefDB::PrefSource::PrefSource(T x_) : Source(x_) { prefs.watch(*this); } 147 | #endif 148 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008-2009, Thomas Jaeger 2 | # 3 | # Permission to use, copy, modify, and/or distribute this software for any 4 | # purpose with or without fee is hereby granted, provided that the above 5 | # copyright notice and this permission notice appear in all copies. 6 | # 7 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY 10 | # SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12 | # OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13 | # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | DESTDIR = 16 | PREFIX = /usr/local 17 | BINDIR = $(PREFIX)/bin 18 | ICONDIR = $(PREFIX)/share/icons/hicolor/scalable/apps 19 | MENUDIR = $(PREFIX)/share/applications 20 | LOCALEDIR= $(PREFIX)/share/locale 21 | DFLAGS = 22 | OFLAGS = -O2 23 | AOFLAGS = -O3 24 | STROKEFLAGS = -Wall -std=c11 $(DFLAGS) 25 | CXXSTD = -std=c++11 26 | INCLUDES = $(shell pkg-config gtkmm-3.0 dbus-glib-1 --cflags) 27 | CXXFLAGS = $(CXXSTD) -Wall $(DFLAGS) -DLOCALEDIR=\"$(LOCALEDIR)\" $(INCLUDES) 28 | CFLAGS = -std=c11 -Wall $(DFLAGS) -DLOCALEDIR=\"$(LOCALEDIR)\" $(INCLUDES) -DGETTEXT_PACKAGE='"easystroke"' 29 | LDFLAGS = $(DFLAGS) 30 | 31 | LIBS = $(DFLAGS) -lboost_serialization -lX11 -lXext -lXi -lXfixes -lXtst `pkg-config gtkmm-3.0 dbus-glib-1 --libs` 32 | 33 | BINARY = easystroke 34 | ICON = easystroke.svg 35 | MENU = easystroke.desktop 36 | MANPAGE = easystroke.1 37 | 38 | CCFILES = $(wildcard *.cc) 39 | HFILES = $(wildcard *.h) 40 | OFILES = $(patsubst %.cc,%.o,$(CCFILES)) stroke.o cellrenderertextish.o gui.o desktop.o version.o 41 | POFILES = $(wildcard po/*.po) 42 | MOFILES = $(patsubst po/%.po,po/%/LC_MESSAGES/easystroke.mo,$(POFILES)) 43 | MODIRS = $(patsubst po/%.po,po/%,$(POFILES)) 44 | DEPFILES = $(wildcard *.Po) 45 | GENFILES = gui.c desktop.c po/POTFILES.in easystroke.desktop 46 | GZFILES = $(wildcard *.gz) 47 | 48 | VERSION = $(shell test -e debian/changelog && grep '(.*)' debian/changelog | sed 's/.*(//' | sed 's/).*//' | head -n1 || (test -e version && cat version || git describe)) 49 | GIT = $(wildcard .git/index version) 50 | DIST = easystroke-$(VERSION) 51 | 52 | -include debug.mk 53 | 54 | all: $(BINARY) $(MOFILES) 55 | 56 | .PHONY: all clean translate update-translations compile-translations complete 57 | 58 | clean: 59 | $(RM) $(OFILES) $(BINARY) $(GENFILES) $(DEPFILES) $(MANPAGE) $(GZFILES) po/*.pot 60 | $(RM) -r $(MODIRS) 61 | 62 | include $(DEPFILES) 63 | 64 | $(BINARY): $(OFILES) 65 | $(CXX) $(LDFLAGS) -o $@ $(OFILES) $(LIBS) 66 | 67 | stroke.o: stroke.c 68 | $(CC) $(STROKEFLAGS) $(AOFLAGS) -MT $@ -MMD -MP -MF $*.Po -o $@ -c $< 69 | 70 | %.o: %.c 71 | $(CC) $(CFLAGS) $(OFLAGS) -MT $@ -MMD -MP -MF $*.Po -o $@ -c $< 72 | 73 | %.o: %.cc 74 | $(CXX) $(CXXFLAGS) $(OFLAGS) -MT $@ -MMD -MP -MF $*.Po -o $@ -c $< 75 | 76 | version.o: $(GIT) 77 | echo 'const char *version_string = "$(VERSION)";' | $(CXX) -o $@ -c -xc++ - 78 | 79 | gui.c: gui.glade 80 | echo "const char *gui_buffer = \"\\" > $@ 81 | sed 's/"GtkWindow"/"GtkApplicationWindow"/' $< | sed 's/"/\\"/g' | sed 's/ *\(.*\)/\1\\n\\/' >> $@ 82 | echo "\";" >> $@ 83 | 84 | easystroke.desktop: easystroke.desktop.in $(MOFILES) 85 | intltool-merge po/ -d -u $< $@ 86 | 87 | desktop.c: easystroke.desktop 88 | echo "const char *desktop_file = \"\\" > $@ 89 | sed 's/Exec=easystroke/Exec=%1$$s/' $< | sed 's/"/\\"/g' | sed 's/.*/&\\n\\/' >> $@ 90 | echo "\";" >> $@ 91 | 92 | po/POTFILES.in: $(CCFILES) $(HFILES) 93 | $(RM) $@ 94 | for f in `grep -El "\<_\(" $^`; do echo $$f >> $@; done 95 | echo gui.glade >> $@ 96 | echo easystroke.desktop.in >> $@ 97 | 98 | translate: po/POTFILES.in 99 | cd po && XGETTEXT_ARGS="--package-name=easystroke --copyright-holder='Thomas Jaeger '" intltool-update --pot -g messages 100 | 101 | compile-translations: $(MOFILES) 102 | 103 | update-translations: po/POTFILES.in 104 | cd po && for f in $(POFILES); do \ 105 | intltool-update `echo $$f | sed "s|po/\(.*\)\.po$$|\1|"`; \ 106 | done 107 | 108 | strip-translations: 109 | for f in $(POFILES); do \ 110 | grep -v '^#:' $$f > $$f.out; \ 111 | mv $$f.out $$f; \ 112 | done 113 | 114 | po/%/LC_MESSAGES/easystroke.mo: po/%.po 115 | mkdir -p po/$*/LC_MESSAGES 116 | msgfmt -c $< -o $@ 117 | 118 | man: $(MANPAGE) 119 | 120 | $(MANPAGE): $(BINARY) 121 | help2man -N -n "X11 gesture recognition application" ./$(BINARY) > $@ 122 | 123 | install: all 124 | install -Ds $(BINARY) $(DESTDIR)$(BINDIR)/$(BINARY) 125 | install -D -m 644 $(ICON) $(DESTDIR)$(ICONDIR)/$(ICON) 126 | install -D -m 644 $(MENU) $(DESTDIR)$(MENUDIR)/$(MENU) 127 | for f in $(MOFILES); do \ 128 | install -D -m 644 $$f `echo $$f | sed "s|^po/|$(DESTDIR)$(LOCALEDIR)/|"`; \ 129 | done 130 | 131 | uninstall: 132 | $(RM) $(DESTDIR)$(BINDIR)/$(BINARY) 133 | $(RM) $(DESTDIR)$(ICONDIR)/$(ICON) 134 | $(RM) $(DESTDIR)$(MENUDIR)/$(MENU) 135 | for f in $(MOFILES); do \ 136 | $(RM) `echo $$f | sed "s|^po/|$(DESTDIR)$(LOCALEDIR)/|"`; \ 137 | done 138 | 139 | tarball: $(DIST).tar.gz 140 | 141 | tmp/$(DIST): $(GIT) 142 | $(RM) -r tmp 143 | mkdir tmp 144 | git archive --format=tar --prefix=$(DIST)/ HEAD | (cd tmp && tar x) 145 | echo $(VERSION) > $@/version 146 | $(RM) $@/.gitignore $@/release 147 | 148 | $(DIST).tar.gz: tmp/$(DIST) 149 | tar -czf $@ -C tmp/ $(DIST) 150 | $(RM) -r tmp 151 | 152 | complete: .clang_complete 153 | 154 | .clang_complete: Makefile 155 | @echo $(CXXSTD) > $@ 156 | @$(foreach inc,$(INCLUDES),echo $(inc) >> $@;) 157 | -------------------------------------------------------------------------------- /actions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #ifndef __ACTIONS_H__ 17 | #define __ACTIONS_H__ 18 | 19 | #include 20 | 21 | class Unique; 22 | class Win; 23 | class ActionListDiff; 24 | 25 | class TreeViewMulti : public Gtk::TreeView { 26 | bool pending; 27 | Gtk::TreePath path; 28 | virtual bool on_button_press_event(GdkEventButton* event); 29 | virtual bool on_button_release_event(GdkEventButton* event); 30 | virtual void on_drag_begin(const Glib::RefPtr &context); 31 | public: 32 | TreeViewMulti(); 33 | }; 34 | 35 | class Actions { 36 | public: 37 | Actions(); 38 | private: 39 | void on_button_delete(); 40 | void on_button_new(); 41 | void on_button_record(); 42 | void on_selection_changed(); 43 | void on_name_edited(const Glib::ustring& path, const Glib::ustring& new_text); 44 | void on_type_edited(const Glib::ustring& path, const Glib::ustring& new_text); 45 | void on_something_editing_started(Gtk::CellEditable* editable, const Glib::ustring& path); 46 | void on_something_editing_canceled(); 47 | void on_row_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column); 48 | void on_cell_data_name(Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); 49 | void on_cell_data_type(Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); 50 | public: 51 | void on_accel_edited(const gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode); 52 | void on_combo_edited(const gchar *path_string, guint item); 53 | void on_arg_editing_started(GtkCellEditable *editable, const gchar *path); 54 | void on_text_edited(const gchar *path, const gchar *new_text); 55 | void on_cell_data_arg(GtkCellRenderer *cell, gchar *path); 56 | private: 57 | int compare_ids(const Gtk::TreeModel::iterator &a, const Gtk::TreeModel::iterator &b); 58 | class OnStroke; 59 | Gtk::TreeRow get_selected_row(); 60 | 61 | void focus(Unique *id, int col, bool edit); 62 | bool do_focus(Unique *id, Gtk::TreeViewColumn *col, bool edit); 63 | 64 | bool select_app(const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter, ActionListDiff *actions); 65 | void on_add_app(); 66 | void on_add_group(); 67 | void on_group_name_edited(const Glib::ustring& path, const Glib::ustring& new_text); 68 | void on_apps_selection_changed(); 69 | void on_expanded(); 70 | void load_app_list(const Gtk::TreeNodeChildren &ch, ActionListDiff *actions); 71 | void on_cell_data_apps(Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); 72 | void update_action_list(); 73 | void update_row(const Gtk::TreeRow &row); 74 | bool count_app_actions(const Gtk::TreeIter &i); 75 | void update_counts(); 76 | void on_reset_actions(); 77 | void on_remove_app(); 78 | 79 | class ModelColumns : public Gtk::TreeModel::ColumnRecord { 80 | public: 81 | ModelColumns() { 82 | add(stroke); add(name); add(type); add(arg); add(cmd_save); add(id); 83 | add(name_bold); add(action_bold); add(deactivated); 84 | } 85 | Gtk::TreeModelColumn > stroke; 86 | Gtk::TreeModelColumn name, type, arg, cmd_save; 87 | Gtk::TreeModelColumn id; 88 | Gtk::TreeModelColumn name_bold, action_bold; 89 | Gtk::TreeModelColumn deactivated; 90 | }; 91 | class Store : public Gtk::ListStore { 92 | Actions *parent; 93 | public: 94 | Store(const Gtk::TreeModelColumnRecord &columns, Actions *p) : Gtk::ListStore(columns), parent(p) {} 95 | static Glib::RefPtr create(const Gtk::TreeModelColumnRecord &columns, Actions *parent) { 96 | return Glib::RefPtr(new Store(columns, parent)); 97 | } 98 | protected: 99 | bool row_draggable_vfunc(const Gtk::TreeModel::Path &path) const; 100 | bool row_drop_possible_vfunc(const Gtk::TreeModel::Path &dest, const Gtk::SelectionData &selection) const; 101 | bool drag_data_received_vfunc(const Gtk::TreeModel::Path &dest, const Gtk::SelectionData& selection); 102 | }; 103 | class AppsStore : public Gtk::TreeStore { 104 | Actions *parent; 105 | public: 106 | AppsStore(const Gtk::TreeModelColumnRecord &columns, Actions *p) : Gtk::TreeStore(columns), parent(p) {} 107 | static Glib::RefPtr create(const Gtk::TreeModelColumnRecord &columns, Actions *parent) { 108 | return Glib::RefPtr(new AppsStore(columns, parent)); 109 | } 110 | protected: 111 | bool row_drop_possible_vfunc(const Gtk::TreeModel::Path &dest, const Gtk::SelectionData &selection) const; 112 | bool drag_data_received_vfunc(const Gtk::TreeModel::Path &dest, const Gtk::SelectionData& selection); 113 | }; 114 | ModelColumns cols; 115 | TreeViewMulti tv; 116 | Glib::RefPtr tm; 117 | 118 | Gtk::TreeView *apps_view; 119 | Glib::RefPtr apps_model; 120 | 121 | class Single : public Gtk::TreeModel::ColumnRecord { 122 | public: 123 | Single() { add(type); } 124 | Gtk::TreeModelColumn type; 125 | }; 126 | Single type; 127 | 128 | class Apps : public Gtk::TreeModel::ColumnRecord { 129 | public: 130 | Apps() { add(app); add(actions); add(count); } 131 | Gtk::TreeModelColumn app; 132 | Gtk::TreeModelColumn actions; 133 | Gtk::TreeModelColumn count; 134 | }; 135 | Apps ca; 136 | 137 | struct Focus; 138 | 139 | Glib::RefPtr type_store; 140 | 141 | Gtk::Button *button_record, *button_delete, *button_remove_app, *button_reset_actions; 142 | Gtk::CheckButton *check_show_deleted; 143 | Gtk::Expander *expander_apps; 144 | Gtk::VPaned *vpaned_apps; 145 | 146 | int vpaned_position; 147 | bool editing_new; 148 | bool editing; 149 | 150 | ActionListDiff *action_list; 151 | }; 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /changelog: -------------------------------------------------------------------------------- 1 | 2013-03-27 Release 0.6.0 2 | * Update easystroke to gtk3 3 | * Refactor event handling code 4 | * Port CellRendererTextish to vala to make it work again 5 | * Make unminimize work right 6 | 7 | 2012-10-06 Release 0.5.6 8 | * Keycode translation improvements 9 | * Allow gestures to be distinguished by modifiers 10 | * Improve detection current application 11 | * Minor UI improvements 12 | * Make Bell work again 13 | * Add Hungarian translations 14 | 15 | 2011-08-16 Released 0.5.5.1 16 | * Fix build failure due to missing import 17 | 18 | 2011-08-16 Released 0.5.5 19 | * Different timeout settings for individual devices 20 | * Change the way button action work to make them more touchscreen 21 | friendly 22 | * Improve Application detection 23 | * Use raw events for scrolling 24 | * Add Catalan, Finnish, Korean and Traditional Chinese translations 25 | * Make fire and water work with compiz 0.9 26 | * Add options to not use dbus and to start easystroke disabled 27 | 28 | 2010-07-27 Released 0.5.4 29 | * Don't start with the config dialog unless -g is passed on the 30 | command line 31 | * Key action and cursor position fixes 32 | * Update Russian translations 33 | 34 | 2010-02-13 Released 0.5.3 35 | * Fix a crash when recording gestures 36 | * Report window manager frames as such in the application list 37 | * Improve the recognition algorithm 38 | * Add an option to move the cursor back to the original position 39 | 40 | 2010-01-02 Released 0.5.2 41 | * Add Hebrew Translations 42 | * Fix crasher bug for devices with relative 3rd axis 43 | * Improve keycode handling 44 | 45 | 2009-10-27 Released 0.5.0 46 | * Port easystroke to XI2, simplifying much of the code. Note that 47 | this version of easystroke will not work on X servers < 1.7. 48 | 49 | 2009-08-19 Released 0.4.9 50 | * Fix a bug regarding application groups 51 | * Add Polish translations 52 | 53 | 2009-08-15 Released 0.4.8 54 | * Fix the use-case where only application-dependent gestures are defined 55 | * Set default gesture trail width to 3 56 | * Update Russian translations 57 | 58 | 2009-07-05 Released 0.4.7 59 | * Work around an X server bug causing problems with vertical gestures 60 | * Update Russian translations 61 | 62 | 2009-06-16 Released 0.4.6 63 | * Switch from -Os to -O2 to work around gcc bug 64 | * Add Russian translations 65 | * Build fix for karmic 66 | 67 | 2009-06-01 Released 0.4.5 68 | * Fix bug that caused easystroke to crash on start up if 69 | there were devices that couldn't be opened 70 | * Add Chinese translations 71 | 72 | 2009-05-12 Released 0.4.4 73 | * Fix bug that made it impossible to record gestures if there were no 74 | default actions 75 | * Make editing commands possible again 76 | 77 | 2009-05-09 Released 0.4.3 78 | * Improve DND behavior 79 | 80 | 2009-05-09 Released 0.4.2 81 | * XInput bugfixes 82 | * French & Japanese translations and various translations updates 83 | 84 | 2009-03-16 Released 0.4.1.1 85 | * Allow button remapping when XInput is disabled 86 | * Various bugfixes 87 | * Allow easystroke to only be enabled for specific applications 88 | * Option to hide OSD 89 | * Translation updates 90 | 91 | 2009-02-20 Released 0.4.1 92 | * New stroke matching algorithm 93 | * New timeout algorithm 94 | * Click & Hold gestures 95 | * Kill radius property 96 | * Set environment variables containing start/end point 97 | * Fix 'Command' action 98 | * Option to show last gesture in tray 99 | * Option to change scroll speed/direction 100 | 101 | 2009-02-08 Released 0.4.0 102 | * Support for xserver-1.6 103 | * Additional gesture buttons 104 | * Instant Gestures 105 | * Add Czech, German, Italian and Spanish translations 106 | * Add 'Text' action 107 | * Add "Timeout-Advanced" gestures 108 | * Add conservative timeout profile, rename conservative to default 109 | * Disable easystroke through middle-click 110 | * Show a different icon when disabled 111 | * Show an 'icon hidden' warning when appropriate 112 | * Never show clicks 113 | * Display a warning for 'click' gestures 114 | * Save preferences in version-specific file 115 | * Option to not show popups on advanced gestures 116 | * Don't abort gestures when Escape is pressed, as this was causing 117 | lock-ups 118 | 119 | 2008-12-22 Released 0.3.1 120 | * Better method for drawing strokes on a composited desktop 121 | * Several bug-fixes 122 | * Autostart option 123 | 124 | 2008-11-07 Released 0.3.0 125 | * application-dependent gestures 126 | * application-dependent gesture button 127 | * Timeout gestures 128 | * disable easystroke for specific devices 129 | * easystroke send "foo" to excecute action foo from the command line 130 | * disable easystroke using the tray menu or by a gesture 131 | * 3 new actions: 132 | + "Unminimize" undoes the last minimize actinos 133 | + "Show/Hide" brings up or hides the configuration dialog 134 | + "Disable (Enable)" disables (or enables if invoked from the 135 | command line) the program. 136 | * action list now reorderable 137 | * hot-plugging support 138 | * option to activate gestures with any modifier combination held down 139 | * option to hide tray icon 140 | * higher quality gesture previews 141 | * Feedback in the tray icon whether the gesture succeeded or not 142 | * Ring the bell on failed gestures 143 | * Blue popup to notify user of scroll and ignore mode 144 | * added support for compiz water plugin 145 | * option to change the stroke color 146 | * dropped support for some advanced features when xinput is unavailable 147 | * -c option to start easystroke with config window open 148 | * dropped -n (no gui) option 149 | 150 | 2008-09-18 Released 0.2.2.1 151 | * bug fix release, resolvs a few minor issues 152 | 153 | 2008-08-17 Released 0.2.2 154 | * improved visual feedback 155 | * configurable gesture timeout 156 | * better pointer tracking 157 | * many minor improvements 158 | 159 | 2008-08-06 Released 0.2.1.1. 160 | * add license information to the source files 161 | 162 | 2008-08-03 Released 0.2.1, correcting some silly Makefile mistakes. 163 | 164 | 2008-08-03 Released 0.2.0. 165 | * many tablet-related improvements 166 | * advanced gestures 167 | 168 | 2008-06-22 Released 0.1.2. 169 | * Fixes a few minor UI glitches. 170 | 171 | 2008-06-19 Released 0.1.1. 172 | * "click during stroke" 173 | This feature allows you to emulate a mouse click by clicking a second 174 | button during a stroke (which can essentially turn a one-button tablet pen 175 | into three-button mouse). 176 | 177 | 2008-06-14 Released 0.1 178 | * First public release. 179 | -------------------------------------------------------------------------------- /prefdb.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #include "prefdb.h" 17 | #include "main.h" 18 | #include "win.h" 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | const ButtonInfo default_button(Button2); 32 | 33 | PrefDB::PrefDB() : 34 | TimeoutWatcher(5000), 35 | good_state(true), 36 | button(default_button), 37 | trace(TraceDefault), 38 | advanced_ignore(false), 39 | proximity(false), 40 | feedback(true), 41 | left_handed(false), 42 | init_timeout(250), 43 | final_timeout(250), 44 | timeout_profile(TimeoutDefault), 45 | timeout_gestures(false), 46 | tray_icon(false), 47 | color(Gdk::Color("#980101")), 48 | trace_width(3), 49 | advanced_popups(true), 50 | scroll_invert(true), 51 | scroll_speed(2.0), 52 | tray_feedback(false), 53 | show_osd(true), 54 | move_back(false), 55 | whitelist(false) 56 | {} 57 | 58 | template void PrefDB::serialize(Archive & ar, const unsigned int version) { 59 | if (version < 11) { 60 | std::set old; 61 | ar & old; 62 | for (std::set::iterator i = old.begin(); i != old.end(); i++) 63 | exceptions.unsafe_ref()[*i] = RButtonInfo(); 64 | } else ar & exceptions.unsafe_ref(); 65 | if (version < 14) { 66 | double p = 0.5; 67 | ar & p; 68 | } 69 | ar & button.unsafe_ref(); 70 | if (version < 2) { 71 | bool help; 72 | ar & help; 73 | } 74 | ar & trace.unsafe_ref(); 75 | if (trace.get() == TraceShape) 76 | trace.unsafe_ref() = TraceDefault; 77 | if (version < 3) { 78 | int delay; 79 | ar & delay; 80 | } 81 | if (version == 1) { 82 | ButtonInfo foo; 83 | ar & foo; 84 | ar & foo; 85 | return; 86 | } 87 | if (version < 2) return; 88 | if (version != 6) 89 | ar & advanced_ignore.unsafe_ref(); 90 | int radius = 16; 91 | ar & radius; 92 | if (version < 4) return; 93 | bool ignore_grab = false; 94 | ar & ignore_grab; 95 | bool timing_workaround = false; 96 | ar & timing_workaround; 97 | bool show_clicks = false; 98 | ar & show_clicks; 99 | bool pressure_abort = false; 100 | ar & pressure_abort; 101 | int pressure_threshold = 192; 102 | ar & pressure_threshold; 103 | ar & proximity.unsafe_ref(); 104 | if (version < 5) return; 105 | ar & feedback.unsafe_ref(); 106 | ar & left_handed.unsafe_ref(); 107 | ar & init_timeout.unsafe_ref(); 108 | ar & final_timeout.unsafe_ref(); 109 | if (version < 8) return; 110 | ar & timeout_profile.unsafe_ref(); 111 | if (version < 9) return; 112 | ar & timeout_gestures.unsafe_ref(); 113 | ar & tray_icon.unsafe_ref(); 114 | if (version < 10) return; 115 | ar & excluded_devices.unsafe_ref(); 116 | if (version < 12) { 117 | unsigned long c = 0; 118 | ar & c; 119 | color.unsafe_ref().color.set_rgb(257*(c >> 16), 257*((c >> 8) % 256), 257*(c % 256)); 120 | return; 121 | } else { 122 | ar & color.unsafe_ref(); 123 | } 124 | ar & trace_width.unsafe_ref(); 125 | if (version < 13) return; 126 | ar & extra_buttons.unsafe_ref(); 127 | ar & advanced_popups.unsafe_ref(); 128 | ar & scroll_invert.unsafe_ref(); 129 | ar & scroll_speed.unsafe_ref(); 130 | ar & tray_feedback.unsafe_ref(); 131 | ar & show_osd.unsafe_ref(); 132 | if (version < 16) return; 133 | ar & move_back.unsafe_ref(); 134 | if (version < 17) return; 135 | ar & device_timeout.unsafe_ref(); 136 | if (version < 18) return; 137 | ar & whitelist.unsafe_ref(); 138 | } 139 | 140 | void PrefDB::timeout() { 141 | std::string filename = config_dir+"preferences"+prefs_versions[0]; 142 | std::string tmp = filename + ".tmp"; 143 | try { 144 | std::ofstream ofs(tmp.c_str()); 145 | boost::archive::text_oarchive oa(ofs); 146 | const PrefDB *me = this; 147 | oa << *me; 148 | ofs.close(); 149 | if (rename(tmp.c_str(), filename.c_str())) 150 | throw std::runtime_error("rename() failed"); 151 | if (verbosity >= 2) 152 | printf("Saved preferences.\n"); 153 | } catch (std::exception &e) { 154 | printf(_("Error: Couldn't save preferences: %s.\n"), e.what()); 155 | if (!good_state) 156 | return; 157 | good_state = false; 158 | error_dialog(Glib::ustring::compose(_( "Couldn't save %1. Your changes will be lost. " 159 | "Make sure that \"%2\" is a directory and that you have write access to it. " 160 | "You can change the configuration directory " 161 | "using the -c or --config-dir command line options."), _("preferences"), config_dir)); 162 | } 163 | } 164 | 165 | 166 | bool ButtonInfo::overlap(const ButtonInfo &bi) const { 167 | if (button != bi.button) 168 | return false; 169 | if (state == AnyModifier || bi.state == AnyModifier) 170 | return true; 171 | return !((state ^ bi.state) & ~LockMask & ~Mod2Mask); 172 | } 173 | 174 | void PrefDB::init() { 175 | std::string filename = config_dir+"preferences"; 176 | for (const char **v = prefs_versions; *v; v++) { 177 | if (is_file(filename + *v)) { 178 | filename += *v; 179 | try { 180 | std::ifstream ifs(filename.c_str(), std::ios::binary); 181 | if (!ifs.fail()) { 182 | boost::archive::text_iarchive ia(ifs); 183 | ia >> *this; 184 | if (verbosity >= 2) 185 | std::cout << "Loaded preferences." << std::endl; 186 | } 187 | } catch (...) { 188 | printf(_("Error: Couldn't read preferences.\n")); 189 | } 190 | break; 191 | } 192 | } 193 | std::map::iterator i = exceptions.unsafe_ref().find("(window manager frame)"); 194 | if (i != exceptions.unsafe_ref().end()) { 195 | RButtonInfo bi = i->second; 196 | exceptions.unsafe_ref().erase(i); 197 | exceptions.unsafe_ref()[""] = bi; 198 | } 199 | } 200 | 201 | PrefDB prefs; 202 | -------------------------------------------------------------------------------- /stroke.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #define _GNU_SOURCE 18 | 19 | #include "stroke.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | const double stroke_infinity = 0.2; 26 | #define EPS 0.000001 27 | 28 | struct point { 29 | double x; 30 | double y; 31 | double t; 32 | double dt; 33 | double alpha; 34 | }; 35 | 36 | struct _stroke_t { 37 | int n; 38 | int capacity; 39 | struct point *p; 40 | }; 41 | 42 | stroke_t *stroke_alloc(int n) { 43 | assert(n > 0); 44 | stroke_t *s = malloc(sizeof(stroke_t)); 45 | s->n = 0; 46 | s->capacity = n; 47 | s->p = calloc(n, sizeof(struct point)); 48 | return s; 49 | } 50 | 51 | void stroke_add_point(stroke_t *s, double x, double y) { 52 | assert(s->capacity > s->n); 53 | s->p[s->n].x = x; 54 | s->p[s->n].y = y; 55 | s->n++; 56 | } 57 | 58 | static inline double angle_difference(double alpha, double beta) { 59 | double d = alpha - beta; 60 | if (d < -1.0) 61 | d += 2.0; 62 | else if (d > 1.0) 63 | d -= 2.0; 64 | return d; 65 | } 66 | 67 | void stroke_finish(stroke_t *s) { 68 | assert(s->capacity > 0); 69 | s->capacity = -1; 70 | 71 | int n = s->n - 1; 72 | double total = 0.0; 73 | s->p[0].t = 0.0; 74 | for (int i = 0; i < n; i++) { 75 | total += hypot(s->p[i+1].x - s->p[i].x, s->p[i+1].y - s->p[i].y); 76 | s->p[i+1].t = total; 77 | } 78 | for (int i = 0; i <= n; i++) 79 | s->p[i].t /= total; 80 | double minX = s->p[0].x, minY = s->p[0].y, maxX = minX, maxY = minY; 81 | for (int i = 1; i <= n; i++) { 82 | if (s->p[i].x < minX) minX = s->p[i].x; 83 | if (s->p[i].x > maxX) maxX = s->p[i].x; 84 | if (s->p[i].y < minY) minY = s->p[i].y; 85 | if (s->p[i].y > maxY) maxY = s->p[i].y; 86 | } 87 | double scaleX = maxX - minX; 88 | double scaleY = maxY - minY; 89 | double scale = (scaleX > scaleY) ? scaleX : scaleY; 90 | if (scale < 0.001) scale = 1; 91 | for (int i = 0; i <= n; i++) { 92 | s->p[i].x = (s->p[i].x-(minX+maxX)/2)/scale + 0.5; 93 | s->p[i].y = (s->p[i].y-(minY+maxY)/2)/scale + 0.5; 94 | } 95 | 96 | for (int i = 0; i < n; i++) { 97 | s->p[i].dt = s->p[i+1].t - s->p[i].t; 98 | s->p[i].alpha = atan2(s->p[i+1].y - s->p[i].y, s->p[i+1].x - s->p[i].x)/M_PI; 99 | } 100 | 101 | } 102 | 103 | void stroke_free(stroke_t *s) { 104 | if (s) 105 | free(s->p); 106 | free(s); 107 | } 108 | 109 | int stroke_get_size(const stroke_t *s) { return s->n; } 110 | 111 | void stroke_get_point(const stroke_t *s, int n, double *x, double *y) { 112 | assert(n < s->n); 113 | if (x) 114 | *x = s->p[n].x; 115 | if (y) 116 | *y = s->p[n].y; 117 | } 118 | 119 | double stroke_get_time(const stroke_t *s, int n) { 120 | assert(n < s->n); 121 | return s->p[n].t; 122 | } 123 | 124 | double stroke_get_angle(const stroke_t *s, int n) { 125 | assert(n+1 < s->n); 126 | return s->p[n].alpha; 127 | } 128 | 129 | inline static double sqr(double x) { return x*x; } 130 | 131 | double stroke_angle_difference(const stroke_t *a, const stroke_t *b, int i, int j) { 132 | return fabs(angle_difference(stroke_get_angle(a, i), stroke_get_angle(b, j))); 133 | } 134 | 135 | static inline void step(const stroke_t *a, 136 | const stroke_t *b, 137 | const int N, 138 | double *dist, 139 | int *prev_x, 140 | int *prev_y, 141 | const int x, 142 | const int y, 143 | const double tx, 144 | const double ty, 145 | int *k, 146 | const int x2, 147 | const int y2) 148 | { 149 | double dtx = a->p[x2].t - tx; 150 | double dty = b->p[y2].t - ty; 151 | if (dtx >= dty * 2.2 || dty >= dtx * 2.2 || dtx < EPS || dty < EPS) 152 | return; 153 | (*k)++; 154 | 155 | double d = 0.0; 156 | int i = x, j = y; 157 | double next_tx = (a->p[i+1].t - tx) / dtx; 158 | double next_ty = (b->p[j+1].t - ty) / dty; 159 | double cur_t = 0.0; 160 | 161 | for (;;) { 162 | double ad = sqr(angle_difference(a->p[i].alpha, b->p[j].alpha)); 163 | double next_t = next_tx < next_ty ? next_tx : next_ty; 164 | bool done = next_t >= 1.0 - EPS; 165 | if (done) 166 | next_t = 1.0; 167 | d += (next_t - cur_t)*ad; 168 | if (done) 169 | break; 170 | cur_t = next_t; 171 | if (next_tx < next_ty) 172 | next_tx = (a->p[++i+1].t - tx) / dtx; 173 | else 174 | next_ty = (b->p[++j+1].t - ty) / dty; 175 | } 176 | double new_dist = dist[x*N+y] + d * (dtx + dty); 177 | if (new_dist != new_dist) abort(); 178 | 179 | if (new_dist >= dist[x2*N+y2]) 180 | return; 181 | 182 | prev_x[x2*N+y2] = x; 183 | prev_y[x2*N+y2] = y; 184 | dist[x2*N+y2] = new_dist; 185 | } 186 | 187 | /* To compare two gestures, we use dynamic programming to minimize (an 188 | * approximation) of the integral over square of the angle difference among 189 | * (roughly) all reparametrizations whose slope is always between 1/2 and 2. 190 | */ 191 | double stroke_compare(const stroke_t *a, const stroke_t *b, int *path_x, int *path_y) { 192 | const int M = a->n; 193 | const int N = b->n; 194 | const int m = M - 1; 195 | const int n = N - 1; 196 | 197 | double* dist = malloc(M * N * sizeof(double)); 198 | int* prev_x = malloc(M * N * sizeof(int)); 199 | int* prev_y = malloc(M * N * sizeof(int)); 200 | for (int i = 0; i < m; i++) 201 | for (int j = 0; j < n; j++) 202 | dist[i*N+j] = stroke_infinity; 203 | dist[M*N-1] = stroke_infinity; 204 | dist[0] = 0.0; 205 | 206 | for (int x = 0; x < m; x++) { 207 | for (int y = 0; y < n; y++) { 208 | if (dist[x*N+y] >= stroke_infinity) 209 | continue; 210 | double tx = a->p[x].t; 211 | double ty = b->p[y].t; 212 | int max_x = x; 213 | int max_y = y; 214 | int k = 0; 215 | 216 | while (k < 4) { 217 | if (a->p[max_x+1].t - tx > b->p[max_y+1].t - ty) { 218 | max_y++; 219 | if (max_y == n) { 220 | step(a, b, N, dist, prev_x, prev_y, x, y, tx, ty, &k, m, n); 221 | break; 222 | } 223 | for (int x2 = x+1; x2 <= max_x; x2++) 224 | step(a, b, N, dist, prev_x, prev_y, x, y, tx, ty, &k, x2, max_y); 225 | } else { 226 | max_x++; 227 | if (max_x == m) { 228 | step(a, b, N, dist, prev_x, prev_y, x, y, tx, ty, &k, m, n); 229 | break; 230 | } 231 | for (int y2 = y+1; y2 <= max_y; y2++) 232 | step(a, b, N, dist, prev_x, prev_y, x, y, tx, ty, &k, max_x, y2); 233 | } 234 | } 235 | } 236 | } 237 | double cost = dist[M*N-1]; 238 | if (path_x && path_y) { 239 | if (cost < stroke_infinity) { 240 | int x = m; 241 | int y = n; 242 | int k = 0; 243 | while (x || y) { 244 | int old_x = x; 245 | x = prev_x[x*N+y]; 246 | y = prev_y[old_x*N+y]; 247 | path_x[k] = x; 248 | path_y[k] = y; 249 | k++; 250 | } 251 | } else { 252 | path_x[0] = 0; 253 | path_y[0] = 0; 254 | } 255 | } 256 | 257 | free(prev_y); 258 | free(prev_x); 259 | free(dist); 260 | 261 | return cost; 262 | } 263 | -------------------------------------------------------------------------------- /win.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #include "actions.h" 17 | #include "prefs.h" 18 | #include "win.h" 19 | #include "main.h" 20 | #include 21 | 22 | Glib::RefPtr widgets; 23 | 24 | void Stroke::draw(Cairo::RefPtr surface, int x, int y, int w, int h, double width, bool inv) const { 25 | const Cairo::RefPtr ctx = Cairo::Context::create (surface); 26 | x += width; y += width; w -= 2*width; h -= 2*width; 27 | ctx->save(); 28 | ctx->translate(x,y); 29 | ctx->scale(w,h); 30 | ctx->set_line_width(2.0*width/(w+h)); 31 | if (size()) { 32 | ctx->set_line_cap(Cairo::LINE_CAP_ROUND); 33 | int n = size(); 34 | float lambda = sqrt(3)-2.0; 35 | float sum = lambda / (1 - lambda); 36 | std::vector y(n); 37 | y[0] = points(0) * sum; 38 | for (int j = 0; j < n-1; j++) 39 | y[j+1] = (y[j] + points(j)) * lambda; 40 | std::vector z(n); 41 | z[n-1] = points(n-1) * (-sum); 42 | for (int j = n-1; j > 0; j--) 43 | z[j-1] = (z[j] - points(j)) * lambda; 44 | for (int j = 0; j < n-1; j++) { 45 | // j -> j+1 46 | if (inv) 47 | ctx->set_source_rgba(time(j), 0.0, 1.0-time(j), 1.0); 48 | else 49 | ctx->set_source_rgba(0.0, time(j), 1.0-time(j), 1.0); 50 | Point p[4]; 51 | p[0] = points(j); 52 | p[3] = points(j+1); 53 | p[1] = p[0] + y[j] + z[j]; 54 | p[2] = p[3] - y[j+1] - z[j+1]; 55 | ctx->move_to(p[0].x, p[0].y); 56 | ctx->curve_to(p[1].x, p[1].y, p[2].x, p[2].y, p[3].x, p[3].y); 57 | ctx->stroke(); 58 | } 59 | } else if (!button) { 60 | if (inv) 61 | ctx->set_source_rgba(1.0, 1.0, 0.0, 1.0); 62 | else 63 | ctx->set_source_rgba(0.0, 0.0, 1.0, 1.0); 64 | ctx->move_to(0.33, 0.33); 65 | ctx->line_to(0.67, 0.67); 66 | ctx->move_to(0.33, 0.67); 67 | ctx->line_to(0.67, 0.33); 68 | ctx->stroke(); 69 | } 70 | ctx->restore(); 71 | Glib::ustring str; 72 | if (modifiers != AnyModifier) { 73 | str = Gtk::AccelGroup::get_label(0, (Gdk::ModifierType)modifiers); 74 | if (str == "") 75 | str = "<>"; 76 | else 77 | str = "<" + str.substr(0, str.size()-1) + ">"; 78 | } 79 | if (trigger) 80 | str += Glib::ustring::compose("%1\xE2\x86\x92", trigger); 81 | if (timeout) 82 | str += "x"; 83 | if (button) 84 | str += Glib::ustring::compose("%1", button); 85 | if (str == "") 86 | return; 87 | if (inv) 88 | ctx->set_source_rgba(0.0, 1.0, 1.0, 0.8); 89 | else 90 | ctx->set_source_rgba(1.0, 0.0, 0.0, 0.8); 91 | float font_size = h*0.5; 92 | Cairo::TextExtents te; 93 | for (;;) { 94 | ctx->set_font_size(font_size); 95 | ctx->get_text_extents(str, te); 96 | if (te.width < w) 97 | break; 98 | font_size *= 0.9; 99 | } 100 | ctx->move_to(x+w/2 - te.x_bearing - te.width/2, y+h/2 - te.y_bearing - te.height/2); 101 | ctx->show_text(str); 102 | } 103 | 104 | void Stroke::draw_svg(std::string filename) const { 105 | const int S = 32; 106 | const int B = 1; 107 | Cairo::RefPtr s = Cairo::SvgSurface::create(filename, S, S); 108 | draw(s, B, B, S-2*B, S-2*B); 109 | } 110 | 111 | 112 | Glib::RefPtr Stroke::draw_(int size, double width, bool inv) const { 113 | Glib::RefPtr pb = drawEmpty_(size); 114 | int w = size; 115 | int h = size; 116 | int stride = pb->get_rowstride(); 117 | guint8 *row = pb->get_pixels(); 118 | // This is all pretty messed up 119 | // http://www.archivum.info/gtkmm-list@gnome.org/2007-05/msg00112.html 120 | Cairo::RefPtr surface = Cairo::ImageSurface::create(row, Cairo::FORMAT_ARGB32, w, h, stride); 121 | draw(surface, 0, 0, pb->get_width(), size, width, inv); 122 | for (int i = 0; i < w; i++) { 123 | guint8 *px = row; 124 | for (int j = 0; j < h; j++) { 125 | guint8 a = px[3]; 126 | guint8 r = px[2]; 127 | guint8 g = px[1]; 128 | guint8 b = px[0]; 129 | if (a) { 130 | px[0] = ((((guint)r) << 8) - r) / a; 131 | px[1] = ((((guint)g) << 8) - g) / a; 132 | px[2] = ((((guint)b) << 8) - b) / a; 133 | } 134 | px += 4; 135 | } 136 | row += stride; 137 | } 138 | return pb; 139 | } 140 | 141 | 142 | Glib::RefPtr Stroke::drawEmpty_(int size) { 143 | Glib::RefPtr pb = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB,true,8,size,size); 144 | pb->fill(0x00000000); 145 | return pb; 146 | } 147 | 148 | Source disabled(false); 149 | 150 | class MenuCheck : private Base { 151 | IO &io; 152 | Gtk::CheckMenuItem *check; 153 | virtual void notify() { check->set_active(io.get()); } 154 | void on_changed() { 155 | bool b = check->get_active(); 156 | if (b == io.get()) return; 157 | io.set(b); 158 | } 159 | public: 160 | MenuCheck(IO &io_, Gtk::CheckMenuItem *check_) : io(io_), check(check_) { 161 | io.connect(this); 162 | notify(); 163 | check->signal_toggled().connect(sigc::mem_fun(*this, &MenuCheck::on_changed)); 164 | } 165 | }; 166 | 167 | Win::Win() : actions(new Actions), prefs_tab(new Prefs), stats(new Stats) { 168 | show_hide_icon(); 169 | prefs.tray_icon.connect(new Notifier(sigc::mem_fun(*this, &Win::show_hide_icon))); 170 | disabled.connect(new Notifier(sigc::mem_fun(*this, &Win::timeout))); 171 | 172 | WIDGET(Gtk::CheckMenuItem, menu_disabled, _("D_isabled"), true); 173 | menu.append(menu_disabled); 174 | new MenuCheck(disabled, &menu_disabled); 175 | 176 | WIDGET(Gtk::ImageMenuItem, menu_about, Gtk::Stock::ABOUT); 177 | menu.append(menu_about); 178 | menu_about.signal_activate().connect(sigc::mem_fun(*this, &Win::show_about)); 179 | 180 | WIDGET(Gtk::SeparatorMenuItem, menu_sep); 181 | menu.append(menu_sep); 182 | 183 | WIDGET(Gtk::ImageMenuItem, menu_quit, Gtk::Stock::QUIT); 184 | menu.append(menu_quit); 185 | menu_quit.signal_activate().connect(sigc::ptr_fun(&quit)); 186 | 187 | menu.show_all(); 188 | 189 | widgets->get_widget("main", win); 190 | RStroke trefoil = Stroke::trefoil(); 191 | std::vector > icons; 192 | icons.push_back(trefoil->draw(24)); 193 | icons.push_back(trefoil->draw(64)); 194 | win->set_icon_list(icons); 195 | 196 | Gtk::Button* button_hide[4]; 197 | widgets->get_widget("button_hide1", button_hide[0]); 198 | widgets->get_widget("button_hide2", button_hide[1]); 199 | widgets->get_widget("button_hide3", button_hide[2]); 200 | widgets->get_widget("button_hide4", button_hide[3]); 201 | for (int i = 0; i < 4; i++) 202 | button_hide[i]->signal_clicked().connect(sigc::mem_fun(win, &Gtk::Window::hide)); 203 | } 204 | 205 | extern void icon_warning(); 206 | 207 | static gboolean icon_clicked(GtkStatusIcon *status_icon, GdkEventButton *event, gpointer) { 208 | if (event->button == 2) 209 | disabled.set(!disabled.get()); 210 | return TRUE; 211 | } 212 | 213 | void Win::show_hide_icon() { 214 | bool show = prefs.tray_icon.get(); 215 | if (show) { 216 | if (icon) 217 | return; 218 | icon = Gtk::StatusIcon::create(""); 219 | icon->signal_size_changed().connect(sigc::mem_fun(*this, &Win::on_icon_size_changed)); 220 | icon->signal_activate().connect(sigc::mem_fun(*this, &Win::show_hide)); 221 | icon->signal_popup_menu().connect(sigc::mem_fun(*this, &Win::show_popup)); 222 | if (gtk_major_version > 2 || (gtk_major_version == 2 && gtk_minor_version >= 15)) 223 | g_signal_connect(icon->gobj(), "button-release-event", G_CALLBACK(icon_clicked), nullptr); 224 | } else { 225 | if (icon) 226 | icon.reset(); 227 | icon_warning(); 228 | } 229 | } 230 | 231 | void Win::show_popup(guint button, guint32 activate_time) { 232 | if (icon) 233 | icon->popup_menu_at_position(menu, button, activate_time); 234 | } 235 | 236 | extern const char *version_string; 237 | void Win::show_about() { 238 | Gtk::AboutDialog *about; 239 | widgets->get_widget("aboutdialog", about); 240 | about->set_logo(Stroke::trefoil()->draw(96, 4.0)); 241 | about->set_version(version_string); 242 | about->set_program_name("easystroke\n"); 243 | about->show(); 244 | about->run(); 245 | about->hide(); 246 | } 247 | 248 | void Win::show_hide() { 249 | if (win->get_mapped()) 250 | win->hide(); 251 | else 252 | win->show(); 253 | } 254 | 255 | void Win::show() { 256 | win->show(); 257 | } 258 | 259 | void Win::hide() { 260 | win->hide(); 261 | } 262 | 263 | bool Win::on_icon_size_changed(int size) { 264 | icon_pb[0] = Stroke::trefoil()->draw(size); 265 | icon_pb[1] = Stroke::trefoil()->draw(size); 266 | icon_pb[1]->saturate_and_pixelate(icon_pb[1], 0.0, true); 267 | if (icon) 268 | icon->set(icon_pb[disabled.get() ? 1 : 0]); 269 | return true; 270 | } 271 | 272 | void Win::timeout() { 273 | if (icon) 274 | icon->set(icon_pb[disabled.get() ? 1 : 0]); 275 | } 276 | 277 | void Win::set_icon(RStroke stroke, bool invert) { 278 | if (!icon) 279 | return; 280 | icon->set(stroke->draw(icon->get_size(), 2.0, invert)); 281 | set_timeout(10000); 282 | } 283 | 284 | void error_dialog(const Glib::ustring &text) { 285 | Gtk::MessageDialog dialog(win->get_window(), text, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); 286 | dialog.show(); 287 | dialog.run(); 288 | } 289 | 290 | Glib::ustring app_name_hr(Glib::ustring src) { 291 | return src == "" ? _("") : src; 292 | } 293 | -------------------------------------------------------------------------------- /po/zh_TW.po: -------------------------------------------------------------------------------- 1 | # Chinese (Traditional) translation for easystroke 2 | # Copyright (c) 2010 Rosetta Contributors and Canonical Ltd 2010 3 | # This file is distributed under the same license as the easystroke package. 4 | # FIRST AUTHOR , 2010. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: easystroke\n" 9 | "Report-Msgid-Bugs-To: FULL NAME \n" 10 | "POT-Creation-Date: 2013-03-14 00:24-0400\n" 11 | "PO-Revision-Date: 2010-08-31 15:44+0000\n" 12 | "Last-Translator: 于 \n" 13 | "Language-Team: Chinese (Traditional) \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=1; plural=0;\n" 18 | "X-Launchpad-Export-Date: 2013-03-14 04:28+0000\n" 19 | "X-Generator: Launchpad (build 16532)\n" 20 | 21 | #, c-format 22 | msgid "Error: can't execute command \"%s\": fork() failed\n" 23 | msgstr "錯誤:無法執行命令\"%s\"\n" 24 | 25 | msgid "None" 26 | msgstr "無" 27 | 28 | msgid "Unminimize" 29 | msgstr "恢復最小化" 30 | 31 | msgid "Show/Hide" 32 | msgstr "顯示/隱藏" 33 | 34 | msgid "Disable (Enable)" 35 | msgstr "禁用(啟用)" 36 | 37 | msgid "Default" 38 | msgstr "預設" 39 | 40 | #, c-format 41 | msgid "Error: Couldn't read action database: %s.\n" 42 | msgstr "無法讀取此動作的資料庫:%s\n" 43 | 44 | msgid "rename() failed" 45 | msgstr "重新命名失敗" 46 | 47 | #, c-format 48 | msgid "Error: Couldn't save action database: %s.\n" 49 | msgstr "錯誤:無法儲存此動作的資料庫:%s\n" 50 | 51 | msgid "" 52 | "Couldn't save %1. Your changes will be lost. Make sure that \"%2\" is a " 53 | "directory and that you have write access to it. You can change the " 54 | "configuration directory using the -c or --config-dir command line options." 55 | msgstr "" 56 | "無法儲存%1。您所作的變更將遺失。請確認\"%2\"是一個目錄且您有寫入的權限。您可以使用命令行參數 -c 或 --config-dir 更改設定檔目錄" 57 | 58 | msgid "actions" 59 | msgstr "滑鼠手勢" 60 | 61 | msgid "Command" 62 | msgstr "指令" 63 | 64 | msgid "Key" 65 | msgstr "鍵盤" 66 | 67 | msgid "Text" 68 | msgstr "文本" 69 | 70 | msgid "Scroll" 71 | msgstr "捲動" 72 | 73 | msgid "Ignore" 74 | msgstr "忽略" 75 | 76 | msgid "Button" 77 | msgstr "滑鼠" 78 | 79 | msgid "Misc" 80 | msgstr "其他" 81 | 82 | msgid "Stroke" 83 | msgstr "描繪手勢" 84 | 85 | msgid "Name" 86 | msgstr "名稱" 87 | 88 | msgid "Type" 89 | msgstr "類型" 90 | 91 | msgid "Details" 92 | msgstr "詳細資訊" 93 | 94 | msgid "Application" 95 | msgstr "應用程式" 96 | 97 | msgid "Actions" 98 | msgstr "動作" 99 | 100 | msgid "Action \"%1\" is about to be deleted." 101 | msgstr "滑鼠手勢\"%1\"將被刪除" 102 | 103 | msgid "One action is about to be deleted." 104 | msgid_plural "%1 actions are about to be deleted" 105 | msgstr[0] "該滑鼠手勢將被刪除" 106 | 107 | msgid "Delete an Action" 108 | msgid_plural "Delete Actions" 109 | msgstr[0] "刪除滑鼠手勢" 110 | 111 | msgid "%1 \"%2\" (containing %3 %4) is about to be deleted." 112 | msgstr "%1 \"%2\" (包含 %3 %4)將被刪除" 113 | 114 | msgid "The application" 115 | msgstr "應用程式" 116 | 117 | msgid "The group" 118 | msgstr "群組" 119 | 120 | msgid "action" 121 | msgid_plural "actions" 122 | msgstr[0] "動作" 123 | 124 | msgid "Delete an Application" 125 | msgstr "刪除應用程式" 126 | 127 | msgid "Delete an Application Group" 128 | msgstr "刪除應用程式群組" 129 | 130 | msgid "Group" 131 | msgstr "群組" 132 | 133 | msgid "" 134 | "You are about to bind an action to a single click. This might make it " 135 | "difficult to use Button %1 in the future. Are you sure you want to continue?" 136 | msgstr "您將指定一個手勢動作給滑鼠單點。這將會導致滑鼠按鈕%1變得難以使用。您確定要繼續?" 137 | 138 | msgid "Record a New Stroke" 139 | msgstr "記錄新的滑鼠手勢" 140 | 141 | msgid "" 142 | "The next stroke will be associated with the action \"%1\". You can draw it " 143 | "anywhere on the screen (except for the two buttons below)." 144 | msgstr "接下來的手勢將指定給動作\"%1\"。你可以在螢幕任一地方使用滑鼠手勢(除了底下的兩個按鈕之外)" 145 | 146 | msgid "Gesture %1" 147 | msgstr "手勢 %1" 148 | 149 | msgid "No Modifiers" 150 | msgstr "無組合鍵" 151 | 152 | msgid "(Instantly) " 153 | msgstr "(立即) " 154 | 155 | msgid "(Click & Hold) " 156 | msgstr "(按住不放) " 157 | 158 | msgid "Any Modifier" 159 | msgstr "任一組合鍵" 160 | 161 | msgid "Button %1" 162 | msgstr "按鈕 %1" 163 | 164 | msgid " + Scroll" 165 | msgstr " + 滑動" 166 | 167 | msgid "'composite' not available" 168 | msgstr "組件(composite)無法使用" 169 | 170 | #, c-format 171 | msgid "Error: %s\n" 172 | msgstr "錯誤:%s\n" 173 | 174 | msgid "Tray icon disabled" 175 | msgstr "系統列圖示已禁用" 176 | 177 | msgid "" 178 | "To bring the configuration dialog up again, you should define an action of " 179 | "type Misc...Show/Hide." 180 | msgstr "要重新顯示設定對話視窗,您必須為\"其它…顯示/隱藏\"定義一個操作" 181 | 182 | #, c-format 183 | msgid "Warning: No action \"%s\" defined\n" 184 | msgstr "警告:\"%s\"動作未被定義\n" 185 | 186 | msgid "Enabled" 187 | msgstr "啟用" 188 | 189 | msgid "About" 190 | msgstr "" 191 | 192 | msgid "Quit" 193 | msgstr "" 194 | 195 | #, c-format 196 | msgid "Couldn't open display.\n" 197 | msgstr "無法啟用顯示\n" 198 | 199 | #, c-format 200 | msgid "Error: Couldn't create configuration directory \"%s\"\n" 201 | msgstr "無法建立設定檔目錄\"%s\"\n" 202 | 203 | #, c-format 204 | msgid "Error: \"%s\" is not a directory\n" 205 | msgstr "錯誤:\"%s\" 不是目錄\n" 206 | 207 | #, c-format 208 | msgid "Error: Couldn't save preferences: %s.\n" 209 | msgstr "錯誤:無法儲存偏好設定:%s\n" 210 | 211 | msgid "preferences" 212 | msgstr "偏好設定" 213 | 214 | #, c-format 215 | msgid "Error: Couldn't read preferences.\n" 216 | msgstr "錯誤:無法讀取偏好設定\n" 217 | 218 | msgid "XShape" 219 | msgstr "XShape" 220 | 221 | msgid "Annotate (compiz)" 222 | msgstr "Annotate (compiz)" 223 | 224 | msgid "Fire (compiz)" 225 | msgstr "Fire (compiz)" 226 | 227 | msgid "Water (compiz)" 228 | msgstr "Water (compiz)" 229 | 230 | msgid "Timeout Off" 231 | msgstr "關閉" 232 | 233 | msgid "Conservative" 234 | msgstr "緩慢" 235 | 236 | msgid "Medium" 237 | msgstr "適中" 238 | 239 | msgid "Aggressive" 240 | msgstr "迅捷" 241 | 242 | msgid "Flick" 243 | msgstr "瞬間" 244 | 245 | msgid "Custom" 246 | msgstr "自訂" 247 | 248 | msgid "Application (WM__CLASS)" 249 | msgstr "應用程式(WM__CLASS)" 250 | 251 | msgid "Device" 252 | msgstr "裝置" 253 | 254 | msgid "" 255 | msgstr "" 256 | 257 | msgid "Timeout profile" 258 | msgstr "逾時設定" 259 | 260 | msgid "" 261 | msgstr "應用程式已關閉" 262 | 263 | msgid "Select a Mouse or Pen Button" 264 | msgstr "選擇滑鼠或手寫筆按鈕" 265 | 266 | msgid "" 267 | "Please place your mouse or pen in the box below and press the button that " 268 | "you want to select. You can also hold down additional modifiers." 269 | msgstr "請移動您的滑鼠或觸控筆至下面方框,並按下要使用的按鈕。您也可同時按下額外的組合鍵" 270 | 271 | msgid "Score" 272 | msgstr "相似度" 273 | 274 | msgid "D_isabled" 275 | msgstr "禁用(_i)" 276 | 277 | msgid "" 278 | msgstr "" 279 | 280 | msgid "Connection to DBus failed" 281 | msgstr "連接至DBus失敗" 282 | 283 | msgid "_Delete Current" 284 | msgstr "刪除目前設定(_D)" 285 | 286 | msgid "_Default" 287 | msgstr "預設(_D)" 288 | 289 | msgid "Timeout" 290 | msgstr "逾時" 291 | 292 | msgid "Instant Gestures" 293 | msgstr "滑鼠手勢" 294 | 295 | msgid "Click & Hold" 296 | msgstr "按住不放" 297 | 298 | msgid "_Control" 299 | msgstr "_Control" 300 | 301 | msgid "_Shift" 302 | msgstr "_Shift" 303 | 304 | msgid "_Alt" 305 | msgstr "_Alt" 306 | 307 | msgid "S_uper" 308 | msgstr "S_uper" 309 | 310 | msgid "An_y Modifier" 311 | msgstr "任意組合鍵" 312 | 313 | msgid "Alternatively, you may select button and modifiers below." 314 | msgstr "或者你也可以選擇以下的按鈕和組合鍵" 315 | 316 | msgid "Show deleted rows" 317 | msgstr "顯示刪除行" 318 | 319 | msgid "Add Application" 320 | msgstr "加入應用程式" 321 | 322 | msgid "Remove Application/Group" 323 | msgstr "移除應用程式/群組" 324 | 325 | msgid "Add Group" 326 | msgstr "新增群組" 327 | 328 | msgid "Reset Action(s)" 329 | msgstr "重設操作" 330 | 331 | msgid "Applications" 332 | msgstr "應用程式" 333 | 334 | msgid "_Record Stroke" 335 | msgstr "記錄手勢(_R)" 336 | 337 | msgid "_Add Action" 338 | msgstr "增加動作(_A)" 339 | 340 | msgid "_Delete Action(s)" 341 | msgstr "刪除動作(_D)" 342 | 343 | msgid "_Hide" 344 | msgstr "隱藏(_H)" 345 | 346 | msgid "_Gesture Button" 347 | msgstr "滑鼠手勢按鈕(_G)" 348 | 349 | msgid "Additional Buttons" 350 | msgstr "額外按鈕" 351 | 352 | msgid "Initial Timeout (ms)" 353 | msgstr "初始逾時值(毫秒)" 354 | 355 | msgid " Timeout (ms)" 356 | msgstr " 逾時(毫秒)" 357 | 358 | msgid "Behavior" 359 | msgstr "行為" 360 | 361 | msgid "Method to show gestures" 362 | msgstr "顯示手勢的方式" 363 | 364 | msgid "Color" 365 | msgstr "顏色" 366 | 367 | msgid "Width" 368 | msgstr "寬度" 369 | 370 | msgid "Show popups (" 371 | msgstr "顯示手勢的描繪" 372 | 373 | msgid "to the right of the cursor)" 374 | msgstr "" 375 | 376 | msgid "Show tray icon" 377 | msgstr "顯示系統列圖示" 378 | 379 | msgid "Show last gesture in tray" 380 | msgstr "在系統列顯示上次的滑鼠手勢" 381 | 382 | msgid "Autostart easystroke" 383 | msgstr "自動啟動easystroke" 384 | 385 | msgid "Appearance" 386 | msgstr "外觀" 387 | 388 | msgid "Exceptions" 389 | msgstr "例外" 390 | 391 | msgid "_Add Exception" 392 | msgstr "增加例外(_A)" 393 | 394 | msgid "_Remove Exception" 395 | msgstr "移除例外(_R)" 396 | 397 | msgid "Preferences" 398 | msgstr "偏好設定" 399 | 400 | msgid "Only enable easystroke for applications listed on 'Actions' tab" 401 | msgstr "" 402 | 403 | msgid "Timeout Gestures" 404 | msgstr "滑鼠手勢逾時" 405 | 406 | msgid "Ignore strokes leading up to advanced gestures" 407 | msgstr "忽略會觸發進階操作的滑鼠手勢" 408 | 409 | msgid "(See Documentation)" 410 | msgstr "(檢視說明文件)" 411 | 412 | msgid "Show popups on advanced gestures" 413 | msgstr "顯示進階手勢的描繪" 414 | 415 | msgid "Show OSD" 416 | msgstr "顯示 OSD" 417 | 418 | msgid "Invert Scroll Direction" 419 | msgstr "顛倒滑動方向" 420 | 421 | msgid "Scroll Speed" 422 | msgstr "滑動速度" 423 | 424 | msgid "Move the cursor back to the original position after each gesture" 425 | msgstr "劃出手勢後,滑鼠回到原來位置" 426 | 427 | msgid "Stay in 'scroll' and 'ignore' mode as long as the pen is within range" 428 | msgstr "當觸控筆在指定範圍內,則保持滑動與忽略模式" 429 | 430 | msgid "Tablet Options" 431 | msgstr "平版電腦選項" 432 | 433 | msgid "Devices" 434 | msgstr "裝置" 435 | 436 | msgid "Advanced" 437 | msgstr "進階" 438 | 439 | msgid "_Matrix" 440 | msgstr "矩陣(_M)" 441 | 442 | msgid "_History" 443 | msgstr "歷史(_H)" 444 | 445 | msgid "Easystroke Gesture Recognition" 446 | msgstr "Easystroke 滑鼠手勢辨識" 447 | 448 | msgid "Control your desktop using mouse gestures" 449 | msgstr "使用滑鼠手勢控制您的桌面" 450 | 451 | msgid "Enable" 452 | msgstr "" 453 | 454 | msgid "Disable" 455 | msgstr "" 456 | 457 | #, c-format 458 | #~ msgid "Error: A grab failed. Resetting...\n" 459 | #~ msgstr "錯誤:擷取失敗。重新設定…\n" 460 | 461 | #~ msgid "Key combination..." 462 | #~ msgstr "按鍵組合…" 463 | 464 | #~ msgid "optimize for left-handed operation )" 465 | #~ msgstr "慣用左手操作" 466 | 467 | #~ msgid "(window manager frame)" 468 | #~ msgstr "(視窗邊框管理)" 469 | -------------------------------------------------------------------------------- /stats.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008-2009, Thomas Jaeger 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | #include "win.h" 17 | #include "actiondb.h" 18 | #include "main.h" 19 | #include 20 | #include 21 | #include 22 | 23 | Stats::Stats() { 24 | Gtk::Button *button_matrix; 25 | widgets->get_widget("button_matrix", button_matrix); 26 | widgets->get_widget("treeview_recent", recent_view); 27 | widgets->get_widget("treeview_ranking", ranking_view); 28 | 29 | button_matrix->signal_clicked().connect(sigc::mem_fun(*this, &Stats::on_pdf)); 30 | 31 | recent_store = Gtk::ListStore::create(cols); 32 | recent_view->set_model(recent_store); 33 | recent_view->append_column(_("Stroke"), cols.stroke); 34 | recent_view->append_column(_("Name"), cols.name); 35 | recent_view->append_column(_("Score"), cols.score); 36 | recent_view->signal_cursor_changed().connect(sigc::mem_fun(*this, &Stats::on_cursor_changed)); 37 | 38 | ranking_view->set_model(Gtk::ListStore::create(cols)); 39 | ranking_view->append_column(_("Stroke"), cols.stroke); 40 | if (verbosity >= 4) 41 | ranking_view->append_column("Debug", cols.debug); 42 | ranking_view->append_column(_("Name"), cols.name); 43 | ranking_view->append_column(_("Score"), cols.score); 44 | } 45 | 46 | void Stats::on_cursor_changed() { 47 | Gtk::TreePath path; 48 | Gtk::TreeViewColumn *col; 49 | recent_view->get_cursor(path, col); 50 | Gtk::TreeRow row(*recent_store->get_iter(path)); 51 | 52 | Glib::RefPtr ranking_store = row[cols.child]; 53 | ranking_view->set_model(ranking_store); 54 | } 55 | 56 | class Tooltip : public Gtk::Window { 57 | public: 58 | Tooltip(Gtk::Widget &widget) : Gtk::Window(Gtk::WINDOW_POPUP) { 59 | Glib::RefPtr visual = get_screen()->get_rgba_visual(); 60 | if (visual) 61 | gtk_widget_set_visual(GTK_WIDGET(gobj()), visual->gobj()); 62 | set_type_hint(Gdk::WINDOW_TYPE_HINT_TOOLTIP); 63 | set_app_paintable(); 64 | set_resizable(false); 65 | set_accept_focus(false); 66 | get_style_context()->add_class(GTK_STYLE_CLASS_TOOLTIP); 67 | signal_draw().connect(sigc::mem_fun(*this, &Tooltip::on_early_draw), false); 68 | add(widget); 69 | widget.show(); 70 | } 71 | 72 | private: 73 | bool on_early_draw(const Cairo::RefPtr &cr) { 74 | if (is_composited()) { 75 | cr->save(); 76 | cr->set_source_rgba(0, 0, 0, 0); 77 | cr->set_operator(Cairo::OPERATOR_SOURCE); 78 | cr->paint(); 79 | cr->restore(); 80 | } 81 | int w = get_allocated_width(); 82 | int h = get_allocated_height(); 83 | get_style_context()->render_background(cr, 0, 0, w, h); 84 | get_style_context()->render_frame(cr, 0, 0, w, h); 85 | return false; 86 | } 87 | }; 88 | 89 | class Feedback { 90 | boost::shared_ptr icon; 91 | boost::shared_ptr text; 92 | public: 93 | Feedback(RStroke s, Glib::ustring t, int x, int y) { 94 | x += (prefs.left_handed.get() ? 1 : -1)*3*STROKE_SIZE / 2; 95 | int w,h; 96 | if (s) { 97 | WIDGET(Gtk::Image, image, s->draw(STROKE_SIZE)); 98 | image.set_padding(2,2); 99 | icon.reset(new Tooltip(image)); 100 | icon->get_size(w,h); 101 | icon->move(x - w/2, y - h/2); 102 | y += h/2; 103 | } 104 | 105 | if (t != "") { 106 | WIDGET(Gtk::Label, label, t); 107 | label.set_padding(4,4); 108 | text.reset(new Tooltip(label)); 109 | text->get_size(w,h); 110 | text->move(x - w/2, y + h/2); 111 | } 112 | if (text) { 113 | text->show(); 114 | text->get_window()->input_shape_combine_region(Cairo::Region::create(), 0, 0); 115 | } 116 | if (icon) { 117 | icon->show(); 118 | icon->get_window()->input_shape_combine_region(Cairo::Region::create(), 0, 0); 119 | } 120 | } 121 | }; 122 | 123 | void Ranking::queue_show(RRanking r, RTriple e) { 124 | r->x = (int)e->x; 125 | r->y = (int)e->y; 126 | Glib::signal_idle().connect(sigc::bind(sigc::ptr_fun(&Ranking::show), r)); 127 | } 128 | 129 | bool delete_me(boost::shared_ptr) { 130 | return false; 131 | } 132 | 133 | bool Ranking::show(RRanking r) { 134 | if (prefs.tray_feedback.get()) 135 | win->set_icon(r->stroke, !r->best_stroke); 136 | if (prefs.feedback.get() && r->best_stroke) { 137 | if (prefs.advanced_popups.get() || !(r->best_stroke->button || r->best_stroke->timeout)) { 138 | boost::shared_ptr popup(new Feedback(r->best_stroke, r->name, r->x, r->y)); 139 | Glib::signal_timeout().connect(sigc::bind(sigc::ptr_fun(&delete_me), popup), 600); 140 | } 141 | } 142 | Glib::signal_timeout().connect(sigc::bind(sigc::mem_fun(*win->stats, &Stats::on_stroke), r), 200); 143 | return false; 144 | } 145 | 146 | Glib::ustring format_float(float x) { 147 | return Glib::ustring::format(std::fixed, std::setprecision(2), x); 148 | } 149 | 150 | Glib::RefPtr Stroke::drawDebug(RStroke a, RStroke b, int size) { 151 | // TODO: This is copy'n'paste from win.cc 152 | Glib::RefPtr pb = drawEmpty_(size); 153 | if (!a || !b || !a->stroke || !b->stroke) 154 | return pb; 155 | int w = size; 156 | int h = size; 157 | int stride = pb->get_rowstride(); 158 | guint8 *row = pb->get_pixels(); 159 | // This is all pretty messed up 160 | // http://www.archivum.info/gtkmm-list@gnome.org/2007-05/msg00112.html 161 | Cairo::RefPtr surface = Cairo::ImageSurface::create(row, Cairo::FORMAT_ARGB32, w, h, stride); 162 | const Cairo::RefPtr ctx = Cairo::Context::create(surface); 163 | 164 | for (unsigned int s = 0; s+1 < a->size(); s++) 165 | for (unsigned int t = 0; t+1 < b->size(); t++) { 166 | double col = 1.0 - stroke_angle_difference(a->stroke.get(), b->stroke.get(), s, t); 167 | ctx->set_source_rgba(col,col,col,1.0); 168 | ctx->rectangle(a->time(s)*size, (1.0-b->time(t+1))*size, 169 | (a->time(s+1)-a->time(s))*size, (b->time(t+1)-b->time(t))*size); 170 | ctx->fill(); 171 | } 172 | int path_x[a->size() + b->size()]; 173 | int path_y[a->size() + b->size()]; 174 | stroke_compare(a->stroke.get(), b->stroke.get(), path_x, path_y); 175 | ctx->set_source_rgba(1,0,0,1); 176 | ctx->set_line_width(2); 177 | ctx->move_to(size, 0); 178 | for (int i = 0;; i++) { 179 | ctx->line_to(a->time(path_x[i])*size, (1.0-b->time(path_y[i]))*size); 180 | if (!path_x[i] && !path_y[i]) 181 | break; 182 | } 183 | ctx->stroke(); 184 | 185 | for (int i = 0; i < w; i++) { 186 | guint8 *px = row; 187 | for (int j = 0; j < h; j++) { 188 | guint8 a = px[3]; 189 | guint8 r = px[2]; 190 | guint8 g = px[1]; 191 | guint8 b = px[0]; 192 | if (a) { 193 | px[0] = ((((guint)r) << 8) - r) / a; 194 | px[1] = ((((guint)g) << 8) - g) / a; 195 | px[2] = ((((guint)b) << 8) - b) / a; 196 | } 197 | px += 4; 198 | } 199 | row += stride; 200 | } 201 | return pb; 202 | } 203 | 204 | bool Stats::on_stroke(RRanking r) { 205 | Gtk::TreeModel::Row row = *(recent_store->prepend()); 206 | row[cols.stroke] = r->stroke->draw(STROKE_SIZE); 207 | row[cols.name] = r->name; 208 | row[cols.score] = format_float(r->score*100) + "%"; 209 | Glib::RefPtr ranking_store = Gtk::ListStore::create(cols); 210 | row[cols.child] = ranking_store; 211 | 212 | Gtk::TreePath path = recent_store->get_path(row); 213 | recent_view->scroll_to_row(path); 214 | 215 | Gtk::TreeModel::Children ch = recent_store->children(); 216 | if (ch.size() > 8) { 217 | Gtk::TreeIter last = ch.end(); 218 | last--; 219 | recent_store->erase(last); 220 | 221 | } 222 | 223 | for (std::multimap >::iterator i = r->r.begin(); i != r->r.end(); i++) { 224 | Gtk::TreeModel::Row row2 = *(ranking_store->prepend()); 225 | row2[cols.stroke] = i->second.second->draw(STROKE_SIZE); 226 | if (verbosity >= 4) 227 | row2[cols.debug] = Stroke::drawDebug(r->stroke, i->second.second, STROKE_SIZE); 228 | row2[cols.name] = i->second.first; 229 | row2[cols.score] = format_float(i->first * 100) + "%"; 230 | } 231 | return false; 232 | } 233 | 234 | void Stats::on_pdf() { 235 | struct timeval tv1, tv2; 236 | if (verbosity >= 1) 237 | gettimeofday(&tv1, 0); 238 | const int S = 32; 239 | const int B = 1; 240 | std::list strokes; 241 | actions.get_root()->all_strokes(strokes); 242 | const int n = strokes.size(); 243 | Cairo::RefPtr surface = Cairo::PdfSurface::create("/tmp/strokes.pdf", (n+1)*S, (n+1)*S); 244 | const Cairo::RefPtr ctx = Cairo::Context::create(surface); 245 | int k = 1; 246 | for (std::list::iterator i = strokes.begin(); i != strokes.end(); i++, k++) { 247 | (*i)->draw(surface, k*S+B, B, S-2*B, S-2*B); 248 | (*i)->draw(surface, B, k*S+B, S-2*B, S-2*B); 249 | 250 | ctx->set_source_rgba(0,0,0,1); 251 | ctx->set_line_width(1); 252 | ctx->move_to(k*S, B); 253 | ctx->line_to(k*S, (n+1)*S-B); 254 | ctx->move_to(B, k*S); 255 | ctx->line_to((n+1)*S-B, k*S); 256 | ctx->stroke(); 257 | 258 | int l = 1; 259 | for (std::list::iterator j = strokes.begin(); j != strokes.end(); j++, l++) { 260 | double score; 261 | int match = Stroke::compare(*i, *j, score); 262 | if (match < 0) 263 | continue; 264 | if (match) { 265 | ctx->save(); 266 | ctx->set_source_rgba(0,0,1,score-0.6); 267 | ctx->rectangle(l*S, k*S, S, S); 268 | ctx->fill(); 269 | ctx->restore(); 270 | } 271 | Glib::ustring str = format_float(score); 272 | Cairo::TextExtents te; 273 | ctx->get_text_extents(str, te); 274 | ctx->move_to(l*S+S/2 - te.x_bearing - te.width/2, k*S+S/2 - te.y_bearing - te.height/2); 275 | ctx->show_text(str); 276 | } 277 | } 278 | if (verbosity >= 1) { 279 | gettimeofday(&tv2, 0); 280 | printf("creating table took %ld us\n", (tv2.tv_sec - tv1.tv_sec)*1000000 + tv2.tv_usec - tv1.tv_usec); 281 | } 282 | if (!fork()) { 283 | execlp("xdg-open", "xdg-open", "/tmp/strokes.pdf", nullptr); 284 | exit(EXIT_FAILURE); 285 | } 286 | } 287 | 288 | -------------------------------------------------------------------------------- /po/zh_CN.po: -------------------------------------------------------------------------------- 1 | # Simplified Chinese translation for easystroke 2 | # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 3 | # This file is distributed under the same license as the easystroke package. 4 | # FIRST AUTHOR , 2009. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: easystroke\n" 9 | "Report-Msgid-Bugs-To: FULL NAME \n" 10 | "POT-Creation-Date: 2013-03-14 00:24-0400\n" 11 | "PO-Revision-Date: 2011-04-27 16:53+0000\n" 12 | "Last-Translator: snowdream \n" 13 | "Language-Team: Simplified Chinese \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=1; plural=0;\n" 18 | "X-Launchpad-Export-Date: 2013-03-14 04:28+0000\n" 19 | "X-Generator: Launchpad (build 16532)\n" 20 | 21 | #, c-format 22 | msgid "Error: can't execute command \"%s\": fork() failed\n" 23 | msgstr "错误:\"%s\"不能被执行\n" 24 | 25 | msgid "None" 26 | msgstr "无" 27 | 28 | msgid "Unminimize" 29 | msgstr "恢复窗口" 30 | 31 | msgid "Show/Hide" 32 | msgstr "显示/隐藏" 33 | 34 | msgid "Disable (Enable)" 35 | msgstr "禁用(启用)" 36 | 37 | msgid "Default" 38 | msgstr "默认" 39 | 40 | #, c-format 41 | msgid "Error: Couldn't read action database: %s.\n" 42 | msgstr "错误:不能读取此操作的数据:%s\n" 43 | 44 | msgid "rename() failed" 45 | msgstr "重命名失败" 46 | 47 | #, c-format 48 | msgid "Error: Couldn't save action database: %s.\n" 49 | msgstr "错误:不能保存此操作的数据:%s\n" 50 | 51 | msgid "" 52 | "Couldn't save %1. Your changes will be lost. Make sure that \"%2\" is a " 53 | "directory and that you have write access to it. You can change the " 54 | "configuration directory using the -c or --config-dir command line options." 55 | msgstr "" 56 | "无法保存%1。你当前所作的设置将会丢失。请确认\"%2\"是一个目录,并且你对这个目录具有写入权限。你可以通过命令行参数-c或--config-" 57 | "dir改变配置文件所在目录。" 58 | 59 | msgid "actions" 60 | msgstr "鼠标手势" 61 | 62 | msgid "Command" 63 | msgstr "运行命令" 64 | 65 | msgid "Key" 66 | msgstr "按键" 67 | 68 | msgid "Text" 69 | msgstr "文本" 70 | 71 | msgid "Scroll" 72 | msgstr "滚动" 73 | 74 | msgid "Ignore" 75 | msgstr "忽略" 76 | 77 | msgid "Button" 78 | msgstr "鼠标点击" 79 | 80 | msgid "Misc" 81 | msgstr "其他" 82 | 83 | msgid "Stroke" 84 | msgstr "手势" 85 | 86 | msgid "Name" 87 | msgstr "名称" 88 | 89 | msgid "Type" 90 | msgstr "类別" 91 | 92 | msgid "Details" 93 | msgstr "详细信息" 94 | 95 | msgid "Application" 96 | msgstr "应用" 97 | 98 | msgid "Actions" 99 | msgstr "动作" 100 | 101 | msgid "Action \"%1\" is about to be deleted." 102 | msgstr "鼠标手势\"%1\"将被删除" 103 | 104 | msgid "One action is about to be deleted." 105 | msgid_plural "%1 actions are about to be deleted" 106 | msgstr[0] "该动作将被删除" 107 | 108 | msgid "Delete an Action" 109 | msgid_plural "Delete Actions" 110 | msgstr[0] "删除手势" 111 | 112 | msgid "%1 \"%2\" (containing %3 %4) is about to be deleted." 113 | msgstr "%1 \"%2\" (包括 %3 %4) 将被删除。" 114 | 115 | msgid "The application" 116 | msgstr "应用程序" 117 | 118 | msgid "The group" 119 | msgstr "程序组" 120 | 121 | msgid "action" 122 | msgid_plural "actions" 123 | msgstr[0] "动作" 124 | 125 | msgid "Delete an Application" 126 | msgstr "删除针对此应用程序的动作" 127 | 128 | msgid "Delete an Application Group" 129 | msgstr "删除此应用程序组" 130 | 131 | msgid "Group" 132 | msgstr "组" 133 | 134 | msgid "" 135 | "You are about to bind an action to a single click. This might make it " 136 | "difficult to use Button %1 in the future. Are you sure you want to continue?" 137 | msgstr "你将要绑定某动作到一次鼠标单击上,这样可能导致鼠标按键%1变得难以使用。你确定要这样做吗?" 138 | 139 | msgid "Record a New Stroke" 140 | msgstr "记录新手势" 141 | 142 | msgid "" 143 | "The next stroke will be associated with the action \"%1\". You can draw it " 144 | "anywhere on the screen (except for the two buttons below)." 145 | msgstr "接下来的鼠标手势将会作为动作\"%1\"的手势。你可以在屏幕上的任意地方绘画你的鼠标手势(除了以下的两个按钮)" 146 | 147 | msgid "Gesture %1" 148 | msgstr "手势 %1" 149 | 150 | msgid "No Modifiers" 151 | msgstr "无组合键" 152 | 153 | msgid "(Instantly) " 154 | msgstr "立即 " 155 | 156 | msgid "(Click & Hold) " 157 | msgstr "点击并保持按下 " 158 | 159 | msgid "Any Modifier" 160 | msgstr "任意修饰符" 161 | 162 | msgid "Button %1" 163 | msgstr "按键 %1" 164 | 165 | msgid " + Scroll" 166 | msgstr " + 滚动" 167 | 168 | msgid "'composite' not available" 169 | msgstr "组合扩展('composite')暂时不可用" 170 | 171 | #, c-format 172 | msgid "Error: %s\n" 173 | msgstr "错误: %s\n" 174 | 175 | msgid "Tray icon disabled" 176 | msgstr "托盘图标被禁止使用" 177 | 178 | msgid "" 179 | "To bring the configuration dialog up again, you should define an action of " 180 | "type Misc...Show/Hide." 181 | msgstr "要重新显示配置界面,你必须给“其他”选项中的“显示/隐藏“定义一个操作" 182 | 183 | #, c-format 184 | msgid "Warning: No action \"%s\" defined\n" 185 | msgstr "警告:\"%s\"操作没有被定义\n" 186 | 187 | msgid "Enabled" 188 | msgstr "启用" 189 | 190 | msgid "About" 191 | msgstr "" 192 | 193 | msgid "Quit" 194 | msgstr "" 195 | 196 | #, c-format 197 | msgid "Couldn't open display.\n" 198 | msgstr "X windows不能打开显示\n" 199 | 200 | #, c-format 201 | msgid "Error: Couldn't create configuration directory \"%s\"\n" 202 | msgstr "错误:不能创建配置目录 \"%s\"\n" 203 | 204 | #, c-format 205 | msgid "Error: \"%s\" is not a directory\n" 206 | msgstr "错误:\"%s\"不是有效的路径\n" 207 | 208 | #, c-format 209 | msgid "Error: Couldn't save preferences: %s.\n" 210 | msgstr "错误:不能保存偏好设置: %s。\n" 211 | 212 | msgid "preferences" 213 | msgstr "偏好" 214 | 215 | #, c-format 216 | msgid "Error: Couldn't read preferences.\n" 217 | msgstr "错误:读取参数失败\n" 218 | 219 | msgid "XShape" 220 | msgstr "XShape" 221 | 222 | msgid "Annotate (compiz)" 223 | msgstr "Annotate (compiz)" 224 | 225 | msgid "Fire (compiz)" 226 | msgstr "Fire (compiz)" 227 | 228 | msgid "Water (compiz)" 229 | msgstr "Water (compiz)" 230 | 231 | msgid "Timeout Off" 232 | msgstr "超时关闭" 233 | 234 | msgid "Conservative" 235 | msgstr "保持" 236 | 237 | msgid "Medium" 238 | msgstr "中速" 239 | 240 | msgid "Aggressive" 241 | msgstr "激进的" 242 | 243 | msgid "Flick" 244 | msgstr "交换" 245 | 246 | msgid "Custom" 247 | msgstr "定制" 248 | 249 | msgid "Application (WM__CLASS)" 250 | msgstr "应用程序 (窗口类 WM_CLASS)" 251 | 252 | msgid "Device" 253 | msgstr "设备" 254 | 255 | msgid "" 256 | msgstr "" 257 | 258 | msgid "Timeout profile" 259 | msgstr "超时档案" 260 | 261 | msgid "" 262 | msgstr "应用程序被关闭" 263 | 264 | msgid "Select a Mouse or Pen Button" 265 | msgstr "选择一个鼠标或手写笔按键" 266 | 267 | msgid "" 268 | "Please place your mouse or pen in the box below and press the button that " 269 | "you want to select. You can also hold down additional modifiers." 270 | msgstr "请把你的鼠标或触控笔放在以下的方框中,并按下你所需的按钮。你也可以同时按下更多的修饰键。" 271 | 272 | msgid "Score" 273 | msgstr "相似度" 274 | 275 | msgid "D_isabled" 276 | msgstr "D_isabled" 277 | 278 | msgid "" 279 | msgstr "" 280 | 281 | msgid "Connection to DBus failed" 282 | msgstr "连接至DBus失败" 283 | 284 | msgid "_Delete Current" 285 | msgstr "删除当前设定值" 286 | 287 | msgid "_Default" 288 | msgstr "默认" 289 | 290 | msgid "Timeout" 291 | msgstr "超时" 292 | 293 | msgid "Instant Gestures" 294 | msgstr "鼠标手势" 295 | 296 | msgid "Click & Hold" 297 | msgstr "单击并按住" 298 | 299 | msgid "_Control" 300 | msgstr "_Control" 301 | 302 | msgid "_Shift" 303 | msgstr "_Shift" 304 | 305 | msgid "_Alt" 306 | msgstr "_Alt" 307 | 308 | msgid "S_uper" 309 | msgstr "S_uper" 310 | 311 | msgid "An_y Modifier" 312 | msgstr "任意修饰符" 313 | 314 | msgid "Alternatively, you may select button and modifiers below." 315 | msgstr "或者你也可以选择以下的按键和修饰符" 316 | 317 | msgid "Show deleted rows" 318 | msgstr "显示删除行" 319 | 320 | msgid "Add Application" 321 | msgstr "添加应用程序" 322 | 323 | msgid "Remove Application/Group" 324 | msgstr "移除程序或程序组" 325 | 326 | msgid "Add Group" 327 | msgstr "添加应用程序组" 328 | 329 | msgid "Reset Action(s)" 330 | msgstr "恢复动作" 331 | 332 | msgid "Applications" 333 | msgstr "应用程序" 334 | 335 | msgid "_Record Stroke" 336 | msgstr "已记录的手势(_R)" 337 | 338 | msgid "_Add Action" 339 | msgstr "添加动作" 340 | 341 | msgid "_Delete Action(s)" 342 | msgstr "删除动作" 343 | 344 | msgid "_Hide" 345 | msgstr "隐藏(_H)" 346 | 347 | msgid "_Gesture Button" 348 | msgstr "手势按钮(_G)" 349 | 350 | msgid "Additional Buttons" 351 | msgstr "额外按键" 352 | 353 | msgid "Initial Timeout (ms)" 354 | msgstr "初始的超时值(ms)" 355 | 356 | msgid " Timeout (ms)" 357 | msgstr " 超时 (ms)" 358 | 359 | msgid "Behavior" 360 | msgstr "行为" 361 | 362 | msgid "Method to show gestures" 363 | msgstr "显示鼠标手势的方式" 364 | 365 | msgid "Color" 366 | msgstr "颜色" 367 | 368 | msgid "Width" 369 | msgstr "宽度" 370 | 371 | msgid "Show popups (" 372 | msgstr "显示气球信息" 373 | 374 | msgid "to the right of the cursor)" 375 | msgstr "" 376 | 377 | msgid "Show tray icon" 378 | msgstr "显示托盘图标" 379 | 380 | msgid "Show last gesture in tray" 381 | msgstr "在托盘栏显示上一个触发的鼠标手势" 382 | 383 | msgid "Autostart easystroke" 384 | msgstr "自动启动easystroke" 385 | 386 | msgid "Appearance" 387 | msgstr "外观" 388 | 389 | msgid "Exceptions" 390 | msgstr "例外" 391 | 392 | msgid "_Add Exception" 393 | msgstr "添加例外" 394 | 395 | msgid "_Remove Exception" 396 | msgstr "删除例外" 397 | 398 | msgid "Preferences" 399 | msgstr "偏好设置" 400 | 401 | msgid "Only enable easystroke for applications listed on 'Actions' tab" 402 | msgstr "" 403 | 404 | msgid "Timeout Gestures" 405 | msgstr "鼠标手势超时" 406 | 407 | msgid "Ignore strokes leading up to advanced gestures" 408 | msgstr "忽略会触发高级动作的鼠标手势" 409 | 410 | msgid "(See Documentation)" 411 | msgstr "查看帮助文档" 412 | 413 | msgid "Show popups on advanced gestures" 414 | msgstr "显示高级手势的气球信息" 415 | 416 | msgid "Show OSD" 417 | msgstr "显示OSD" 418 | 419 | msgid "Invert Scroll Direction" 420 | msgstr "相反的滚动方向" 421 | 422 | msgid "Scroll Speed" 423 | msgstr "滚动速度" 424 | 425 | msgid "Move the cursor back to the original position after each gesture" 426 | msgstr "每次作出手势后将光标移回至原来位置" 427 | 428 | msgid "Stay in 'scroll' and 'ignore' mode as long as the pen is within range" 429 | msgstr "只要触控笔在指定范围内即保持滚动和忽略模式" 430 | 431 | msgid "Tablet Options" 432 | msgstr "平板电脑选项" 433 | 434 | msgid "Devices" 435 | msgstr "设备" 436 | 437 | msgid "Advanced" 438 | msgstr "高级" 439 | 440 | msgid "_Matrix" 441 | msgstr "_Matrix" 442 | 443 | msgid "_History" 444 | msgstr "历史(_H)" 445 | 446 | msgid "Easystroke Gesture Recognition" 447 | msgstr "Easystroke 鼠标手势辨认" 448 | 449 | msgid "Control your desktop using mouse gestures" 450 | msgstr "通过鼠标手势控制你的桌面" 451 | 452 | msgid "Enable" 453 | msgstr "" 454 | 455 | msgid "Disable" 456 | msgstr "" 457 | 458 | #, c-format 459 | #~ msgid "Error: A grab failed. Resetting...\n" 460 | #~ msgstr "错误:抓取失败,请重新设置...\n" 461 | 462 | #~ msgid "Key combination..." 463 | #~ msgstr "组合键..." 464 | 465 | #~ msgid "(window manager frame)" 466 | #~ msgstr "窗口管理器帧" 467 | 468 | #~ msgid "optimize for left-handed operation )" 469 | #~ msgstr "为左手操作进行的优化" 470 | -------------------------------------------------------------------------------- /po/ja.po: -------------------------------------------------------------------------------- 1 | # Japanese translation for easystroke 2 | # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 3 | # This file is distributed under the same license as the easystroke package. 4 | # FIRST AUTHOR , 2009. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: easystroke\n" 9 | "Report-Msgid-Bugs-To: FULL NAME \n" 10 | "POT-Creation-Date: 2013-03-14 00:24-0400\n" 11 | "PO-Revision-Date: 2010-05-04 06:50+0000\n" 12 | "Last-Translator: kawaji \n" 13 | "Language-Team: Japanese \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=1; plural=0;\n" 18 | "X-Launchpad-Export-Date: 2013-03-14 04:28+0000\n" 19 | "X-Generator: Launchpad (build 16532)\n" 20 | 21 | #, c-format 22 | msgid "Error: can't execute command \"%s\": fork() failed\n" 23 | msgstr "エラー: コマンド \"%s\" 実行不可: fork() 失敗\n" 24 | 25 | msgid "None" 26 | msgstr "何もしない" 27 | 28 | msgid "Unminimize" 29 | msgstr "最小化解除" 30 | 31 | msgid "Show/Hide" 32 | msgstr "表示/隠す" 33 | 34 | msgid "Disable (Enable)" 35 | msgstr "無効化 (有効化)" 36 | 37 | msgid "Default" 38 | msgstr "デフォルト" 39 | 40 | #, c-format 41 | msgid "Error: Couldn't read action database: %s.\n" 42 | msgstr "エラー: アクションのデータベースが読めませんでした: %s.\n" 43 | 44 | msgid "rename() failed" 45 | msgstr "rename() 失敗" 46 | 47 | #, c-format 48 | msgid "Error: Couldn't save action database: %s.\n" 49 | msgstr "エラー: アクションのデータベースが保存できませんでした: %s.\n" 50 | 51 | msgid "" 52 | "Couldn't save %1. Your changes will be lost. Make sure that \"%2\" is a " 53 | "directory and that you have write access to it. You can change the " 54 | "configuration directory using the -c or --config-dir command line options." 55 | msgstr "" 56 | "%1 の保存ができませんでした。変更内容は失われます。\"%2\" が書き込み権限を有するディレクトリであるか確かめてください。-c または --" 57 | "config-dir コマンドラインオプションを使用して、設定ファイル用のディレクトリを変更することが可能です。" 58 | 59 | msgid "actions" 60 | msgstr "アクション" 61 | 62 | msgid "Command" 63 | msgstr "コマンド" 64 | 65 | msgid "Key" 66 | msgstr "キー" 67 | 68 | msgid "Text" 69 | msgstr "テキスト" 70 | 71 | msgid "Scroll" 72 | msgstr "スクロール" 73 | 74 | msgid "Ignore" 75 | msgstr "無視" 76 | 77 | msgid "Button" 78 | msgstr "ボタン" 79 | 80 | msgid "Misc" 81 | msgstr "その他" 82 | 83 | msgid "Stroke" 84 | msgstr "ストローク" 85 | 86 | msgid "Name" 87 | msgstr "名前" 88 | 89 | msgid "Type" 90 | msgstr "種類" 91 | 92 | msgid "Details" 93 | msgstr "詳細" 94 | 95 | msgid "Application" 96 | msgstr "アプリケーション" 97 | 98 | msgid "Actions" 99 | msgstr "アクション" 100 | 101 | msgid "Action \"%1\" is about to be deleted." 102 | msgstr "アクション \"%1\" が削除されます。" 103 | 104 | msgid "One action is about to be deleted." 105 | msgid_plural "%1 actions are about to be deleted" 106 | msgstr[0] "" 107 | msgstr[1] "" 108 | 109 | msgid "Delete an Action" 110 | msgid_plural "Delete Actions" 111 | msgstr[0] "アクションを削除" 112 | 113 | msgid "%1 \"%2\" (containing %3 %4) is about to be deleted." 114 | msgstr "%1 \"%2\" (含有数 %3 %4 ) が削除されます" 115 | 116 | msgid "The application" 117 | msgstr "アプリケーション" 118 | 119 | msgid "The group" 120 | msgstr "グループ" 121 | 122 | msgid "action" 123 | msgid_plural "actions" 124 | msgstr[0] "アクション" 125 | 126 | msgid "Delete an Application" 127 | msgstr "アプリケーションを削除" 128 | 129 | msgid "Delete an Application Group" 130 | msgstr "アプリケーション・グループを削除" 131 | 132 | msgid "Group" 133 | msgstr "グループ" 134 | 135 | msgid "" 136 | "You are about to bind an action to a single click. This might make it " 137 | "difficult to use Button %1 in the future. Are you sure you want to continue?" 138 | msgstr "" 139 | "シングル・クリックにアクションを割り当てようとしています。これにより、ボタン %1 の使用が今後難しくなる可能性があります。本当に設定を続けますか?" 140 | 141 | msgid "Record a New Stroke" 142 | msgstr "新しいストロークを記録" 143 | 144 | msgid "" 145 | "The next stroke will be associated with the action \"%1\". You can draw it " 146 | "anywhere on the screen (except for the two buttons below)." 147 | msgstr "" 148 | "これから行うストロークが、アクション \"%1\" と関連付けられます。画面のどの場所でもストロークの描画ができます(下の2つのボタンを除く)" 149 | 150 | msgid "Gesture %1" 151 | msgstr "ジェスチャ %1" 152 | 153 | msgid "No Modifiers" 154 | msgstr "修飾キーなし" 155 | 156 | msgid "(Instantly) " 157 | msgstr "(インスタント) " 158 | 159 | msgid "(Click & Hold) " 160 | msgstr "(クリック & ホールド) " 161 | 162 | msgid "Any Modifier" 163 | msgstr "任意の修飾キー" 164 | 165 | msgid "Button %1" 166 | msgstr "ボタン %1" 167 | 168 | msgid " + Scroll" 169 | msgstr " + スクロール" 170 | 171 | msgid "'composite' not available" 172 | msgstr "”コンポジット”が利用できません" 173 | 174 | #, c-format 175 | msgid "Error: %s\n" 176 | msgstr "エラー: %s\n" 177 | 178 | msgid "Tray icon disabled" 179 | msgstr "トレイアイコン無効" 180 | 181 | msgid "" 182 | "To bring the configuration dialog up again, you should define an action of " 183 | "type Misc...Show/Hide." 184 | msgstr "" 185 | 186 | #, c-format 187 | msgid "Warning: No action \"%s\" defined\n" 188 | msgstr "警告: アクション \"%s\" は定義されていません\n" 189 | 190 | msgid "Enabled" 191 | msgstr "有効" 192 | 193 | msgid "About" 194 | msgstr "" 195 | 196 | msgid "Quit" 197 | msgstr "" 198 | 199 | #, c-format 200 | msgid "Couldn't open display.\n" 201 | msgstr "ディスプレイを開けませんでした。\n" 202 | 203 | #, c-format 204 | msgid "Error: Couldn't create configuration directory \"%s\"\n" 205 | msgstr "エラー: 設定ファイル用ディレクトリ \"%s\" の作成ができませんでした\n" 206 | 207 | #, c-format 208 | msgid "Error: \"%s\" is not a directory\n" 209 | msgstr "エラー: \"%s\" はディレクトリではありません\n" 210 | 211 | #, c-format 212 | msgid "Error: Couldn't save preferences: %s.\n" 213 | msgstr "エラー: 設定を保存できませんでした: %s.\n" 214 | 215 | msgid "preferences" 216 | msgstr "設定" 217 | 218 | #, c-format 219 | msgid "Error: Couldn't read preferences.\n" 220 | msgstr "エラー: 設定を読めませんでした。\n" 221 | 222 | msgid "XShape" 223 | msgstr "XShape" 224 | 225 | msgid "Annotate (compiz)" 226 | msgstr "注釈線 (compiz)" 227 | 228 | msgid "Fire (compiz)" 229 | msgstr "炎の描画 (compiz)" 230 | 231 | msgid "Water (compiz)" 232 | msgstr "水効果 (compiz)" 233 | 234 | msgid "Timeout Off" 235 | msgstr "タイムアウトなし" 236 | 237 | msgid "Conservative" 238 | msgstr "長め" 239 | 240 | msgid "Medium" 241 | msgstr "中程度" 242 | 243 | msgid "Aggressive" 244 | msgstr "短め" 245 | 246 | msgid "Flick" 247 | msgstr "フリック" 248 | 249 | msgid "Custom" 250 | msgstr "カスタム" 251 | 252 | msgid "Application (WM__CLASS)" 253 | msgstr "アプリケーション(WM__CLASS)" 254 | 255 | msgid "Device" 256 | msgstr "デバイス" 257 | 258 | msgid "" 259 | msgstr "" 260 | 261 | msgid "Timeout profile" 262 | msgstr "タイムアウトのプロファイル" 263 | 264 | msgid "" 265 | msgstr "<アプリ無効>" 266 | 267 | msgid "Select a Mouse or Pen Button" 268 | msgstr "マウスまたはペンのボタンを選択" 269 | 270 | msgid "" 271 | "Please place your mouse or pen in the box below and press the button that " 272 | "you want to select. You can also hold down additional modifiers." 273 | msgstr "マウスやペンを下のボックスに置いてから、選択したいボタンを押してください。追加の修飾キーをホールドすることも可能です。" 274 | 275 | msgid "Score" 276 | msgstr "スコア" 277 | 278 | msgid "D_isabled" 279 | msgstr "無効(_I)" 280 | 281 | msgid "" 282 | msgstr "" 283 | 284 | msgid "Connection to DBus failed" 285 | msgstr "DBus への接続に失敗" 286 | 287 | msgid "_Delete Current" 288 | msgstr "現在の設定を削除(_D)" 289 | 290 | msgid "_Default" 291 | msgstr "デフォルト(_D)" 292 | 293 | msgid "Timeout" 294 | msgstr "タイムアウト" 295 | 296 | msgid "Instant Gestures" 297 | msgstr "インスタント・ジェスチャ" 298 | 299 | msgid "Click & Hold" 300 | msgstr "クリック & ホールド" 301 | 302 | msgid "_Control" 303 | msgstr "_Control" 304 | 305 | msgid "_Shift" 306 | msgstr "_Shift" 307 | 308 | msgid "_Alt" 309 | msgstr "_Alt" 310 | 311 | msgid "S_uper" 312 | msgstr "S_uper" 313 | 314 | msgid "An_y Modifier" 315 | msgstr "任意の修飾キー(_Y)" 316 | 317 | msgid "Alternatively, you may select button and modifiers below." 318 | msgstr "代わりに、ボタンや修飾キーを下から選択することもできます。" 319 | 320 | msgid "Show deleted rows" 321 | msgstr "削除した行を表示" 322 | 323 | msgid "Add Application" 324 | msgstr "アプリケーションを追加" 325 | 326 | msgid "Remove Application/Group" 327 | msgstr "アプリケーション/グループを削除" 328 | 329 | msgid "Add Group" 330 | msgstr "グループを追加" 331 | 332 | msgid "Reset Action(s)" 333 | msgstr "アクションを再設定" 334 | 335 | msgid "Applications" 336 | msgstr "アプリケーション" 337 | 338 | msgid "_Record Stroke" 339 | msgstr "ストロークを記録(_R)" 340 | 341 | msgid "_Add Action" 342 | msgstr "アクションを追加(_A)" 343 | 344 | msgid "_Delete Action(s)" 345 | msgstr "アクションを削除(_D)" 346 | 347 | msgid "_Hide" 348 | msgstr "隠す(_H)" 349 | 350 | msgid "_Gesture Button" 351 | msgstr "ジェスチャ・ボタン(_G)" 352 | 353 | msgid "Additional Buttons" 354 | msgstr "さらに追加するボタン" 355 | 356 | msgid "Initial Timeout (ms)" 357 | msgstr "初期タイムアウト(ミリ秒)" 358 | 359 | msgid " Timeout (ms)" 360 | msgstr " タイムアウト(ミリ秒)" 361 | 362 | msgid "Behavior" 363 | msgstr "動作" 364 | 365 | msgid "Method to show gestures" 366 | msgstr "ジェスチャを表示する方法" 367 | 368 | msgid "Color" 369 | msgstr "色" 370 | 371 | msgid "Width" 372 | msgstr "幅" 373 | 374 | msgid "Show popups (" 375 | msgstr "ポップアップを表示 (" 376 | 377 | msgid "to the right of the cursor)" 378 | msgstr "" 379 | 380 | msgid "Show tray icon" 381 | msgstr "トレイアイコンを表示" 382 | 383 | msgid "Show last gesture in tray" 384 | msgstr "最後のジェスチャをトレイに表示" 385 | 386 | msgid "Autostart easystroke" 387 | msgstr "Easystroke を自動起動" 388 | 389 | msgid "Appearance" 390 | msgstr "外観" 391 | 392 | msgid "Exceptions" 393 | msgstr "例外" 394 | 395 | msgid "_Add Exception" 396 | msgstr "例外を追加(_A)" 397 | 398 | msgid "_Remove Exception" 399 | msgstr "例外を削除(_R)" 400 | 401 | msgid "Preferences" 402 | msgstr "設定" 403 | 404 | msgid "Only enable easystroke for applications listed on 'Actions' tab" 405 | msgstr "" 406 | 407 | msgid "Timeout Gestures" 408 | msgstr "タイムアウト・ジェスチャ" 409 | 410 | msgid "Ignore strokes leading up to advanced gestures" 411 | msgstr "高度ジェスチャに至ったストロークを無視" 412 | 413 | msgid "(See Documentation)" 414 | msgstr "(説明を参照のこと)" 415 | 416 | msgid "Show popups on advanced gestures" 417 | msgstr "高度ジェスチャ時にポップアップを表示" 418 | 419 | msgid "Show OSD" 420 | msgstr "OSD を表示" 421 | 422 | msgid "Invert Scroll Direction" 423 | msgstr "スクロール方向を反転" 424 | 425 | msgid "Scroll Speed" 426 | msgstr "スクロール速度" 427 | 428 | msgid "Move the cursor back to the original position after each gesture" 429 | msgstr "ジェスチャー毎後にカーソルを元の位置に戻す" 430 | 431 | msgid "Stay in 'scroll' and 'ignore' mode as long as the pen is within range" 432 | msgstr "ペンが読取可能高さの範囲内にある限り「スクロール」や「無視」モードを保つ" 433 | 434 | msgid "Tablet Options" 435 | msgstr "タブレット・オプション" 436 | 437 | msgid "Devices" 438 | msgstr "デバイス" 439 | 440 | msgid "Advanced" 441 | msgstr "高度設定" 442 | 443 | msgid "_Matrix" 444 | msgstr "マトリクス(_M)" 445 | 446 | msgid "_History" 447 | msgstr "履歴(_H)" 448 | 449 | msgid "Easystroke Gesture Recognition" 450 | msgstr "Easystroke ジェスチャ認識" 451 | 452 | msgid "Control your desktop using mouse gestures" 453 | msgstr "マウス・ジェスチャを使用してデスクトップを制御します" 454 | 455 | msgid "Enable" 456 | msgstr "" 457 | 458 | msgid "Disable" 459 | msgstr "" 460 | 461 | #~ msgid "Key combination..." 462 | #~ msgstr "キーの組み合わせ..." 463 | 464 | #~ msgid "optimize for left-handed operation )" 465 | #~ msgstr "左手操作のために最適化 )" 466 | -------------------------------------------------------------------------------- /po/ko.po: -------------------------------------------------------------------------------- 1 | # Korean translation for easystroke 2 | # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 3 | # This file is distributed under the same license as the easystroke package. 4 | # FIRST AUTHOR , 2011. 5 | # jincreator , 2011. 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: easystroke\n" 10 | "Report-Msgid-Bugs-To: FULL NAME \n" 11 | "POT-Creation-Date: 2013-03-14 00:24-0400\n" 12 | "PO-Revision-Date: 2011-01-15 01:54+0000\n" 13 | "Last-Translator: Jinkyu Yi \n" 14 | "Language-Team: Korean \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Plural-Forms: nplurals=1; plural=0;\n" 19 | "X-Launchpad-Export-Date: 2013-03-14 04:28+0000\n" 20 | "X-Generator: Launchpad (build 16532)\n" 21 | 22 | #, c-format 23 | msgid "Error: can't execute command \"%s\": fork() failed\n" 24 | msgstr "오류: 명령 \"%s\"를 실행할 수 없습니다: fork() 실패\n" 25 | 26 | msgid "None" 27 | msgstr "없음" 28 | 29 | msgid "Unminimize" 30 | msgstr "최소화 안함" 31 | 32 | msgid "Show/Hide" 33 | msgstr "보이기/숨기기" 34 | 35 | msgid "Disable (Enable)" 36 | msgstr "비활성화(활성화)" 37 | 38 | msgid "Default" 39 | msgstr "기본값" 40 | 41 | #, c-format 42 | msgid "Error: Couldn't read action database: %s.\n" 43 | msgstr "오류: %s 움직임 데이터베이스를 읽을 수 없습니다.\n" 44 | 45 | msgid "rename() failed" 46 | msgstr "rename() 실패" 47 | 48 | #, c-format 49 | msgid "Error: Couldn't save action database: %s.\n" 50 | msgstr "오류: %s 움직임 데이터베이스를 저장할 수 없습니다.\n" 51 | 52 | msgid "" 53 | "Couldn't save %1. Your changes will be lost. Make sure that \"%2\" is a " 54 | "directory and that you have write access to it. You can change the " 55 | "configuration directory using the -c or --config-dir command line options." 56 | msgstr "" 57 | "%1을(를) 저장하지 못했습니다. 바뀐 점은 없어집니다. \"%2\"이(가) 쓰기 가능한 경로인지 확인하십시오. 명령행에서 -c 또는 --" 58 | "config-dir 옵션을 통해 설정 경로를 바꿀 수 있습니다." 59 | 60 | msgid "actions" 61 | msgstr "활동" 62 | 63 | msgid "Command" 64 | msgstr "명령어" 65 | 66 | msgid "Key" 67 | msgstr "키" 68 | 69 | msgid "Text" 70 | msgstr "글자" 71 | 72 | msgid "Scroll" 73 | msgstr "스크롤" 74 | 75 | msgid "Ignore" 76 | msgstr "무시" 77 | 78 | msgid "Button" 79 | msgstr "단추" 80 | 81 | msgid "Misc" 82 | msgstr "기타" 83 | 84 | msgid "Stroke" 85 | msgstr "선 그리기" 86 | 87 | msgid "Name" 88 | msgstr "이름" 89 | 90 | msgid "Type" 91 | msgstr "종류" 92 | 93 | msgid "Details" 94 | msgstr "자세히" 95 | 96 | msgid "Application" 97 | msgstr "프로그램" 98 | 99 | msgid "Actions" 100 | msgstr "활동" 101 | 102 | msgid "Action \"%1\" is about to be deleted." 103 | msgstr "활동 \"%1\"을(를) 삭제할 것입니다." 104 | 105 | msgid "One action is about to be deleted." 106 | msgid_plural "%1 actions are about to be deleted" 107 | msgstr[0] "활동이 삭제됩니다." 108 | 109 | msgid "Delete an Action" 110 | msgid_plural "Delete Actions" 111 | msgstr[0] "활동 삭제" 112 | 113 | msgid "%1 \"%2\" (containing %3 %4) is about to be deleted." 114 | msgstr "%1 \"%2\" (%3 %4를 포함하는)을(를) 삭제할 것입니다." 115 | 116 | msgid "The application" 117 | msgstr "프로그램" 118 | 119 | msgid "The group" 120 | msgstr "모음" 121 | 122 | msgid "action" 123 | msgid_plural "actions" 124 | msgstr[0] "동작" 125 | 126 | msgid "Delete an Application" 127 | msgstr "프로그램 삭제" 128 | 129 | msgid "Delete an Application Group" 130 | msgstr "프로그램 모음 삭제" 131 | 132 | msgid "Group" 133 | msgstr "" 134 | 135 | msgid "" 136 | "You are about to bind an action to a single click. This might make it " 137 | "difficult to use Button %1 in the future. Are you sure you want to continue?" 138 | msgstr "활동을 한번 클릭과 연결하려 합니다. 이는 나중에 %1 버튼을 사용하기 힘들게 합니다. 계속하시겠습니까?" 139 | 140 | msgid "Record a New Stroke" 141 | msgstr "새 선 그리기를 녹음합니다." 142 | 143 | msgid "" 144 | "The next stroke will be associated with the action \"%1\". You can draw it " 145 | "anywhere on the screen (except for the two buttons below)." 146 | msgstr "다음 선 그리기는 \"%1\" 활동에 연결됩니다. 화면 아무곳에 그리세요(두 버튼 아래 제외)." 147 | 148 | msgid "Gesture %1" 149 | msgstr "동작 %1" 150 | 151 | msgid "No Modifiers" 152 | msgstr "고치기 없음" 153 | 154 | msgid "(Instantly) " 155 | msgstr "(즉시) " 156 | 157 | msgid "(Click & Hold) " 158 | msgstr "(클릭 유지) " 159 | 160 | msgid "Any Modifier" 161 | msgstr "다른 수정" 162 | 163 | msgid "Button %1" 164 | msgstr "버튼 %1" 165 | 166 | msgid " + Scroll" 167 | msgstr " +스크롤" 168 | 169 | msgid "'composite' not available" 170 | msgstr "'컴퍼지트' 사용 불가" 171 | 172 | #, c-format 173 | msgid "Error: %s\n" 174 | msgstr "오류: %s\n" 175 | 176 | msgid "Tray icon disabled" 177 | msgstr "트레이 아이콘이 비활성화됨" 178 | 179 | msgid "" 180 | "To bring the configuration dialog up again, you should define an action of " 181 | "type Misc...Show/Hide." 182 | msgstr "설정 창을 다시 보려면 활동의 없음...보이기/숨기기 형식을 지정해야 합니다." 183 | 184 | #, c-format 185 | msgid "Warning: No action \"%s\" defined\n" 186 | msgstr "경고: 활동 \"%s\"가 정의되지 않음\n" 187 | 188 | msgid "Enabled" 189 | msgstr "활성화" 190 | 191 | msgid "About" 192 | msgstr "" 193 | 194 | msgid "Quit" 195 | msgstr "" 196 | 197 | #, c-format 198 | msgid "Couldn't open display.\n" 199 | msgstr "디스플레이를 열 수 없습니다.\n" 200 | 201 | #, c-format 202 | msgid "Error: Couldn't create configuration directory \"%s\"\n" 203 | msgstr "오류: \"%s\" 설정 경로를 열 수 없습니다.\n" 204 | 205 | #, c-format 206 | msgid "Error: \"%s\" is not a directory\n" 207 | msgstr "오류: \"%s\"은(는) 경로가 아닙니다.\n" 208 | 209 | #, c-format 210 | msgid "Error: Couldn't save preferences: %s.\n" 211 | msgstr "오류: 환경설정:%s을 저장할 수 없습니다.\n" 212 | 213 | msgid "preferences" 214 | msgstr "환경설정" 215 | 216 | #, c-format 217 | msgid "Error: Couldn't read preferences.\n" 218 | msgstr "오류: 환경설정을 읽을 수 없습니다.\n" 219 | 220 | msgid "XShape" 221 | msgstr "XShape" 222 | 223 | msgid "Annotate (compiz)" 224 | msgstr "주석 (컴피즈)" 225 | 226 | msgid "Fire (compiz)" 227 | msgstr "화면에 불꽃으로 그림을 그림 (컴피즈)" 228 | 229 | msgid "Water (compiz)" 230 | msgstr "물결 효과 (컴피즈)" 231 | 232 | msgid "Timeout Off" 233 | msgstr "시간제한 끔" 234 | 235 | msgid "Conservative" 236 | msgstr "조심스러움" 237 | 238 | msgid "Medium" 239 | msgstr "중간" 240 | 241 | msgid "Aggressive" 242 | msgstr "적극적" 243 | 244 | msgid "Flick" 245 | msgstr "경쾌함" 246 | 247 | msgid "Custom" 248 | msgstr "사용자 지정" 249 | 250 | msgid "Application (WM__CLASS)" 251 | msgstr "프로그램 (WM_CLASS)" 252 | 253 | msgid "Device" 254 | msgstr "기기" 255 | 256 | msgid "" 257 | msgstr "" 258 | 259 | msgid "Timeout profile" 260 | msgstr "시간제한 정책" 261 | 262 | msgid "" 263 | msgstr "<프로그램 비활성화>" 264 | 265 | msgid "Select a Mouse or Pen Button" 266 | msgstr "마우스나 펜 버튼을 선택하세요" 267 | 268 | msgid "" 269 | "Please place your mouse or pen in the box below and press the button that " 270 | "you want to select. You can also hold down additional modifiers." 271 | msgstr "박스 안으로 마우스나 펜을 가져가서 선택할 버튼을 누르십시오. 추가 변경자를 억제할 수도 있습니다." 272 | 273 | msgid "Score" 274 | msgstr "점수" 275 | 276 | msgid "D_isabled" 277 | msgstr "사용 안함(_I)" 278 | 279 | msgid "" 280 | msgstr "" 281 | 282 | msgid "Connection to DBus failed" 283 | msgstr "DBus 연결 실패" 284 | 285 | msgid "_Delete Current" 286 | msgstr "현재 것 삭제(_D)" 287 | 288 | msgid "_Default" 289 | msgstr "기본값(_D)" 290 | 291 | msgid "Timeout" 292 | msgstr "시간제한" 293 | 294 | msgid "Instant Gestures" 295 | msgstr "순간 동작" 296 | 297 | msgid "Click & Hold" 298 | msgstr "누른채로 잡고있기" 299 | 300 | msgid "_Control" 301 | msgstr "_Control" 302 | 303 | msgid "_Shift" 304 | msgstr "_Shift" 305 | 306 | msgid "_Alt" 307 | msgstr "_Alt" 308 | 309 | msgid "S_uper" 310 | msgstr "S_uper" 311 | 312 | msgid "An_y Modifier" 313 | msgstr "다른 변경자(_Y)" 314 | 315 | msgid "Alternatively, you may select button and modifiers below." 316 | msgstr "대신, 아래의 버튼과 변경자를 선택할 수 있습니다." 317 | 318 | msgid "Show deleted rows" 319 | msgstr "삭제된 줄 보이기" 320 | 321 | msgid "Add Application" 322 | msgstr "프로그램 추가" 323 | 324 | msgid "Remove Application/Group" 325 | msgstr "프로그램/모음 지우기" 326 | 327 | msgid "Add Group" 328 | msgstr "모음 추가" 329 | 330 | msgid "Reset Action(s)" 331 | msgstr "활동 초기화" 332 | 333 | msgid "Applications" 334 | msgstr "프로그램" 335 | 336 | msgid "_Record Stroke" 337 | msgstr "선 그리기 기록(_R)" 338 | 339 | msgid "_Add Action" 340 | msgstr "활동 추가(_A)" 341 | 342 | msgid "_Delete Action(s)" 343 | msgstr "활동 삭제(_D)" 344 | 345 | msgid "_Hide" 346 | msgstr "숨기기(_H)" 347 | 348 | msgid "_Gesture Button" 349 | msgstr "동작 버튼(_G)" 350 | 351 | msgid "Additional Buttons" 352 | msgstr "보조 버튼" 353 | 354 | msgid "Initial Timeout (ms)" 355 | msgstr "초기 시간제한 (ms)" 356 | 357 | msgid " Timeout (ms)" 358 | msgstr " 시간제한 (ms)" 359 | 360 | msgid "Behavior" 361 | msgstr "동작" 362 | 363 | msgid "Method to show gestures" 364 | msgstr "동작을 보여줄 방법" 365 | 366 | msgid "Color" 367 | msgstr "색" 368 | 369 | msgid "Width" 370 | msgstr "너비" 371 | 372 | msgid "Show popups (" 373 | msgstr "팝업 보이기 (" 374 | 375 | msgid "to the right of the cursor)" 376 | msgstr "" 377 | 378 | msgid "Show tray icon" 379 | msgstr "트레이 아이콘 보이기" 380 | 381 | msgid "Show last gesture in tray" 382 | msgstr "트레이에 마지막 동작 보이기" 383 | 384 | msgid "Autostart easystroke" 385 | msgstr "이지스트로크 자동 실행" 386 | 387 | msgid "Appearance" 388 | msgstr "모양새" 389 | 390 | msgid "Exceptions" 391 | msgstr "예외" 392 | 393 | msgid "_Add Exception" 394 | msgstr "예외 추가(_A)" 395 | 396 | msgid "_Remove Exception" 397 | msgstr "예외 삭제(_R)" 398 | 399 | msgid "Preferences" 400 | msgstr "환경설정" 401 | 402 | msgid "Only enable easystroke for applications listed on 'Actions' tab" 403 | msgstr "" 404 | 405 | msgid "Timeout Gestures" 406 | msgstr "활동 시간제한" 407 | 408 | msgid "Ignore strokes leading up to advanced gestures" 409 | msgstr "고급 동작에 따라 무시" 410 | 411 | msgid "(See Documentation)" 412 | msgstr "(문서 참조)" 413 | 414 | msgid "Show popups on advanced gestures" 415 | msgstr "고급 동작 시 팝업 보이기" 416 | 417 | msgid "Show OSD" 418 | msgstr "OSD 보임" 419 | 420 | msgid "Invert Scroll Direction" 421 | msgstr "스크롤 방향 뒤집기" 422 | 423 | msgid "Scroll Speed" 424 | msgstr "스크롤 빠르기" 425 | 426 | msgid "Move the cursor back to the original position after each gesture" 427 | msgstr "동작 후 커서를 원래 위치로 돌려놓음" 428 | 429 | msgid "Stay in 'scroll' and 'ignore' mode as long as the pen is within range" 430 | msgstr "펜이 범위 안에 있는 동안 '스크롤'과 '무시' 상태 유지하기" 431 | 432 | msgid "Tablet Options" 433 | msgstr "태블릿 선택" 434 | 435 | msgid "Devices" 436 | msgstr "기기" 437 | 438 | msgid "Advanced" 439 | msgstr "고급" 440 | 441 | msgid "_Matrix" 442 | msgstr "표(_M)" 443 | 444 | msgid "_History" 445 | msgstr "기록(_H)" 446 | 447 | msgid "Easystroke Gesture Recognition" 448 | msgstr "이지스트로크 동작 인식" 449 | 450 | msgid "Control your desktop using mouse gestures" 451 | msgstr "마우스 동작을 통해 데스크탑 제어" 452 | 453 | msgid "Enable" 454 | msgstr "" 455 | 456 | msgid "Disable" 457 | msgstr "" 458 | 459 | #~ msgid "Key combination..." 460 | #~ msgstr "키 조합..." 461 | 462 | #, c-format 463 | #~ msgid "Error: A grab failed. Resetting...\n" 464 | #~ msgstr "오류: 잡기 실패. 다시 설정중...\n" 465 | 466 | #~ msgid "(window manager frame)" 467 | #~ msgstr "(창 관리자 프레임)" 468 | 469 | #~ msgid "optimize for left-handed operation )" 470 | #~ msgstr "왼손잡이에 맞게 최적화 )" 471 | -------------------------------------------------------------------------------- /po/he.po: -------------------------------------------------------------------------------- 1 | # Hebrew translation for easystroke 2 | # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 3 | # This file is distributed under the same license as the easystroke package. 4 | # FIRST AUTHOR , 2009. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: easystroke\n" 9 | "Report-Msgid-Bugs-To: FULL NAME \n" 10 | "POT-Creation-Date: 2013-03-14 00:24-0400\n" 11 | "PO-Revision-Date: 2009-11-19 08:54+0000\n" 12 | "Last-Translator: Yaron \n" 13 | "Language-Team: Hebrew \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=2; plural=n != 1;\n" 18 | "X-Launchpad-Export-Date: 2013-03-14 04:28+0000\n" 19 | "X-Generator: Launchpad (build 16532)\n" 20 | 21 | #, c-format 22 | msgid "Error: can't execute command \"%s\": fork() failed\n" 23 | msgstr "שגיאה: לא ניתן להפעיל את הפקודה \"%s\": fork() כשל\n" 24 | 25 | msgid "None" 26 | msgstr "ללא" 27 | 28 | msgid "Unminimize" 29 | msgstr "ביטול המזעור" 30 | 31 | msgid "Show/Hide" 32 | msgstr "הצגה/הסתרה" 33 | 34 | msgid "Disable (Enable)" 35 | msgstr "נטרול (הפעלה)" 36 | 37 | msgid "Default" 38 | msgstr "ברירת מחדל" 39 | 40 | #, c-format 41 | msgid "Error: Couldn't read action database: %s.\n" 42 | msgstr "שגיאה: לא ניתן לקרוא את מסד נתוני הפעילות: %s.\n" 43 | 44 | msgid "rename() failed" 45 | msgstr "rename() כשל" 46 | 47 | #, c-format 48 | msgid "Error: Couldn't save action database: %s.\n" 49 | msgstr "שגיאה: לא ניתן לשמור את מסד נתוני הפעילות: %s.\n" 50 | 51 | msgid "" 52 | "Couldn't save %1. Your changes will be lost. Make sure that \"%2\" is a " 53 | "directory and that you have write access to it. You can change the " 54 | "configuration directory using the -c or --config-dir command line options." 55 | msgstr "" 56 | 57 | msgid "actions" 58 | msgstr "פעולות" 59 | 60 | msgid "Command" 61 | msgstr "פקודה" 62 | 63 | msgid "Key" 64 | msgstr "מקש" 65 | 66 | msgid "Text" 67 | msgstr "טקסט" 68 | 69 | msgid "Scroll" 70 | msgstr "גלילה" 71 | 72 | msgid "Ignore" 73 | msgstr "התעלמות" 74 | 75 | msgid "Button" 76 | msgstr "לחצן" 77 | 78 | msgid "Misc" 79 | msgstr "שונות" 80 | 81 | msgid "Stroke" 82 | msgstr "לחיצה" 83 | 84 | msgid "Name" 85 | msgstr "שם" 86 | 87 | msgid "Type" 88 | msgstr "סוג" 89 | 90 | msgid "Details" 91 | msgstr "פרטים" 92 | 93 | msgid "Application" 94 | msgstr "יישום" 95 | 96 | msgid "Actions" 97 | msgstr "פעולות" 98 | 99 | msgid "Action \"%1\" is about to be deleted." 100 | msgstr "הפעולה \"%1\" עומדת להמחק." 101 | 102 | msgid "One action is about to be deleted." 103 | msgid_plural "%1 actions are about to be deleted" 104 | msgstr[0] "פעולה אחת עומדת להמחק." 105 | msgstr[1] "%1 פעולות עומדות להמחק." 106 | 107 | msgid "Delete an Action" 108 | msgid_plural "Delete Actions" 109 | msgstr[0] "מחיקת פעולה" 110 | msgstr[1] "מחיקת פעולות" 111 | 112 | msgid "%1 \"%2\" (containing %3 %4) is about to be deleted." 113 | msgstr "%1 \"%2\" (המכיל %3 %4) עומד להמחק." 114 | 115 | msgid "The application" 116 | msgstr "היישום" 117 | 118 | msgid "The group" 119 | msgstr "הקבוצה" 120 | 121 | msgid "action" 122 | msgid_plural "actions" 123 | msgstr[0] "פעולה" 124 | msgstr[1] "פעולות" 125 | 126 | msgid "Delete an Application" 127 | msgstr "מחיקת יישום" 128 | 129 | msgid "Delete an Application Group" 130 | msgstr "מחיקת קבוצת יישומים" 131 | 132 | msgid "Group" 133 | msgstr "קבוצה" 134 | 135 | msgid "" 136 | "You are about to bind an action to a single click. This might make it " 137 | "difficult to use Button %1 in the future. Are you sure you want to continue?" 138 | msgstr "" 139 | "אתה עומד לאגד פעולה ללחיצה בודדת. פעולה זו תקשה על שימוש בלחצן %1 בעתיד. האם " 140 | "אתה בטוח שברצונך להמשיך?" 141 | 142 | msgid "Record a New Stroke" 143 | msgstr "הקלדת לחיצה חדשה" 144 | 145 | msgid "" 146 | "The next stroke will be associated with the action \"%1\". You can draw it " 147 | "anywhere on the screen (except for the two buttons below)." 148 | msgstr "" 149 | "הלחיצה הבאה תהיה משוייכת עם הפעולה \"%1\". ניתן לצייר אותה בכל מקום במסך " 150 | "(מלבד שני הלחצנים שלהלן)." 151 | 152 | msgid "Gesture %1" 153 | msgstr "מחווה %1" 154 | 155 | msgid "No Modifiers" 156 | msgstr "אין מקשי החלפה" 157 | 158 | msgid "(Instantly) " 159 | msgstr "(באופן מיידי) " 160 | 161 | msgid "(Click & Hold) " 162 | msgstr "(לחיצה והחזקה) " 163 | 164 | msgid "Any Modifier" 165 | msgstr "כל מקש החלפה שהוא" 166 | 167 | msgid "Button %1" 168 | msgstr "לחצן %1" 169 | 170 | msgid " + Scroll" 171 | msgstr " + גלילה" 172 | 173 | msgid "'composite' not available" 174 | msgstr "'חיבור' אינו זמין" 175 | 176 | #, c-format 177 | msgid "Error: %s\n" 178 | msgstr "שגיאה: %s\n" 179 | 180 | msgid "Tray icon disabled" 181 | msgstr "סמל הדיווח מנוטרל" 182 | 183 | msgid "" 184 | "To bring the configuration dialog up again, you should define an action of " 185 | "type Misc...Show/Hide." 186 | msgstr "" 187 | "כדי להעלות את דו־שיח התצורה שוב, עליך להגדיר פעולה מסוג שונות...הצגה/הסתרה." 188 | 189 | #, c-format 190 | msgid "Warning: No action \"%s\" defined\n" 191 | msgstr "אזהרה: לא הוגדרה פעולה \"%s\"\n" 192 | 193 | msgid "Enabled" 194 | msgstr "פעיל" 195 | 196 | msgid "About" 197 | msgstr "" 198 | 199 | msgid "Quit" 200 | msgstr "" 201 | 202 | #, c-format 203 | msgid "Couldn't open display.\n" 204 | msgstr "לא ניתן לפתוח את התצוגה.\n" 205 | 206 | #, c-format 207 | msgid "Error: Couldn't create configuration directory \"%s\"\n" 208 | msgstr "שגיאה: לא ניתן ליצור את תיקיית התצורה \"%s\"\n" 209 | 210 | #, c-format 211 | msgid "Error: \"%s\" is not a directory\n" 212 | msgstr "שגיאה: \"%s\" איננה תיקייה\n" 213 | 214 | #, c-format 215 | msgid "Error: Couldn't save preferences: %s.\n" 216 | msgstr "שגיאה: לא ניתן לשמור את ההעדפות: %s.\n" 217 | 218 | msgid "preferences" 219 | msgstr "העדפות" 220 | 221 | #, c-format 222 | msgid "Error: Couldn't read preferences.\n" 223 | msgstr "שגיאה: לא ניתן לקרוא את ההעדפות.\n" 224 | 225 | msgid "XShape" 226 | msgstr "XShape" 227 | 228 | msgid "Annotate (compiz)" 229 | msgstr "ציור הערות (compiz)" 230 | 231 | msgid "Fire (compiz)" 232 | msgstr "אש (compiz)" 233 | 234 | msgid "Water (compiz)" 235 | msgstr "מים (compiz)" 236 | 237 | msgid "Timeout Off" 238 | msgstr "פסק זמן כבוי" 239 | 240 | msgid "Conservative" 241 | msgstr "שמרני" 242 | 243 | msgid "Medium" 244 | msgstr "בינוני" 245 | 246 | msgid "Aggressive" 247 | msgstr "תוקפני" 248 | 249 | msgid "Flick" 250 | msgstr "הצלפה" 251 | 252 | msgid "Custom" 253 | msgstr "מותאם אישית" 254 | 255 | msgid "Application (WM__CLASS)" 256 | msgstr "יישום (WM__CLASS)" 257 | 258 | msgid "Device" 259 | msgstr "התקן" 260 | 261 | msgid "" 262 | msgstr "" 263 | 264 | msgid "Timeout profile" 265 | msgstr "" 266 | 267 | msgid "" 268 | msgstr "<היישום מנוטרל>" 269 | 270 | msgid "Select a Mouse or Pen Button" 271 | msgstr "בחירה בעכבר או בלחצן עט" 272 | 273 | msgid "" 274 | "Please place your mouse or pen in the box below and press the button that " 275 | "you want to select. You can also hold down additional modifiers." 276 | msgstr "" 277 | "נא לשים את העכבר או את העט שלך להלן וללחוץ על הלחצן שברצונך לבחור. ניתן " 278 | "להחזיק מקשי החלפה נוספים." 279 | 280 | msgid "Score" 281 | msgstr "ניקוד" 282 | 283 | msgid "D_isabled" 284 | msgstr "מ_נוטרל" 285 | 286 | msgid "" 287 | msgstr "" 288 | 289 | msgid "Connection to DBus failed" 290 | msgstr "החיבור אל DBus נכשל" 291 | 292 | msgid "_Delete Current" 293 | msgstr "מחיקת ה_נוכחית" 294 | 295 | msgid "_Default" 296 | msgstr "_ברירת מחדל" 297 | 298 | msgid "Timeout" 299 | msgstr "תום הזמן" 300 | 301 | msgid "Instant Gestures" 302 | msgstr "מחווה מיידית" 303 | 304 | msgid "Click & Hold" 305 | msgstr "לחיצה והחזקה" 306 | 307 | msgid "_Control" 308 | msgstr "_Control" 309 | 310 | msgid "_Shift" 311 | msgstr "_Shift" 312 | 313 | msgid "_Alt" 314 | msgstr "_Alt" 315 | 316 | msgid "S_uper" 317 | msgstr "_סופר" 318 | 319 | msgid "An_y Modifier" 320 | msgstr "מקש ה_חלפה כלשהו" 321 | 322 | msgid "Alternatively, you may select button and modifiers below." 323 | msgstr "לחילופין, ניתן לבחור לחצנים ומקשי החלפה להלן." 324 | 325 | msgid "Show deleted rows" 326 | msgstr "הצגת שורות שנמחקו" 327 | 328 | msgid "Add Application" 329 | msgstr "הוספת יישום" 330 | 331 | msgid "Remove Application/Group" 332 | msgstr "הסרת יישום/קבוצה" 333 | 334 | msgid "Add Group" 335 | msgstr "הוספת קבוצה" 336 | 337 | msgid "Reset Action(s)" 338 | msgstr "איפוס הפעולה/ות" 339 | 340 | msgid "Applications" 341 | msgstr "יישומים" 342 | 343 | msgid "_Record Stroke" 344 | msgstr "ה_קלטת התנועה" 345 | 346 | msgid "_Add Action" 347 | msgstr "הוספת _פעולה" 348 | 349 | msgid "_Delete Action(s)" 350 | msgstr "מחיקת _פעולה" 351 | 352 | msgid "_Hide" 353 | msgstr "ה_סתרה" 354 | 355 | msgid "_Gesture Button" 356 | msgstr "לחצן ה_מחווה" 357 | 358 | msgid "Additional Buttons" 359 | msgstr "לחצנים נוספים" 360 | 361 | msgid "Initial Timeout (ms)" 362 | msgstr "תום זמן התחלתי (מילישניות)" 363 | 364 | msgid " Timeout (ms)" 365 | msgstr " תום הזמן (מילישניות)" 366 | 367 | msgid "Behavior" 368 | msgstr "התנהגות" 369 | 370 | msgid "Method to show gestures" 371 | msgstr "השיטה להצגת המחוות" 372 | 373 | msgid "Color" 374 | msgstr "צבע" 375 | 376 | msgid "Width" 377 | msgstr "רוחב" 378 | 379 | msgid "Show popups (" 380 | msgstr "הצגת חלוניות מוקפצות (" 381 | 382 | msgid "to the right of the cursor)" 383 | msgstr "" 384 | 385 | msgid "Show tray icon" 386 | msgstr "הצגת סמל באזור הדיווחים" 387 | 388 | msgid "Show last gesture in tray" 389 | msgstr "הצגת המחוהה האחרונה במגשית" 390 | 391 | msgid "Autostart easystroke" 392 | msgstr "הפעלה אוטומטית של easystroke" 393 | 394 | msgid "Appearance" 395 | msgstr "מראה" 396 | 397 | msgid "Exceptions" 398 | msgstr "חריגות" 399 | 400 | msgid "_Add Exception" 401 | msgstr "הוספת _חריגה" 402 | 403 | msgid "_Remove Exception" 404 | msgstr "הסרת ה_חריגה" 405 | 406 | msgid "Preferences" 407 | msgstr "העדפות" 408 | 409 | msgid "Only enable easystroke for applications listed on 'Actions' tab" 410 | msgstr "" 411 | 412 | msgid "Timeout Gestures" 413 | msgstr "" 414 | 415 | msgid "Ignore strokes leading up to advanced gestures" 416 | msgstr "התעלמות מתנועות המובילות למחוות מתקדמות" 417 | 418 | msgid "(See Documentation)" 419 | msgstr "(יש לעיין בתיעוד)" 420 | 421 | msgid "Show popups on advanced gestures" 422 | msgstr "הצגת חלוניות מוקפצות עבור מחוות מתקדמות" 423 | 424 | msgid "Show OSD" 425 | msgstr "הצגת תצוגה על המסך" 426 | 427 | msgid "Invert Scroll Direction" 428 | msgstr "הפיכת כיוון הגלילה" 429 | 430 | msgid "Scroll Speed" 431 | msgstr "מהירות הגלילה" 432 | 433 | msgid "Move the cursor back to the original position after each gesture" 434 | msgstr "" 435 | 436 | msgid "Stay in 'scroll' and 'ignore' mode as long as the pen is within range" 437 | msgstr "" 438 | 439 | msgid "Tablet Options" 440 | msgstr "אפשרויות מחשב הלוח" 441 | 442 | msgid "Devices" 443 | msgstr "התקנים" 444 | 445 | msgid "Advanced" 446 | msgstr "מתקדם" 447 | 448 | msgid "_Matrix" 449 | msgstr "_מטריצה" 450 | 451 | msgid "_History" 452 | msgstr "היס_טוריה" 453 | 454 | msgid "Easystroke Gesture Recognition" 455 | msgstr "זיהוי תנועות עכבר של Easystroke" 456 | 457 | msgid "Control your desktop using mouse gestures" 458 | msgstr "ניתן לשלוט בשולחן העבודה באמצעות תנועות העכבר" 459 | 460 | msgid "Enable" 461 | msgstr "" 462 | 463 | msgid "Disable" 464 | msgstr "" 465 | 466 | #~ msgid "Key combination..." 467 | #~ msgstr "צירוף מקשים" 468 | 469 | #, c-format 470 | #~ msgid "Error: A grab failed. Resetting...\n" 471 | #~ msgstr "שגיאה: הלכידה נכשלה. מתבצע איפוס...\n" 472 | 473 | #~ msgid "(window manager frame)" 474 | #~ msgstr "(מסגרת מנהל החלונות)" 475 | 476 | #~ msgid "optimize for left-handed operation )" 477 | #~ msgstr "התאמה לתפעול על ידי שמאליים (" 478 | -------------------------------------------------------------------------------- /easystroke.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /po/ca.po: -------------------------------------------------------------------------------- 1 | # Catalan translation for easystroke 2 | # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 3 | # This file is distributed under the same license as the easystroke package. 4 | # FIRST AUTHOR , 2009. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: easystroke\n" 9 | "Report-Msgid-Bugs-To: FULL NAME \n" 10 | "POT-Creation-Date: 2013-03-14 00:24-0400\n" 11 | "PO-Revision-Date: 2011-08-07 17:13+0000\n" 12 | "Last-Translator: jordis \n" 13 | "Language-Team: Catalan \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=2; plural=n != 1;\n" 18 | "X-Launchpad-Export-Date: 2013-03-14 04:28+0000\n" 19 | "X-Generator: Launchpad (build 16532)\n" 20 | 21 | #, c-format 22 | msgid "Error: can't execute command \"%s\": fork() failed\n" 23 | msgstr "Error: no es pot executar l'ordre «%s»: fork() ha fallat\n" 24 | 25 | msgid "None" 26 | msgstr "Cap" 27 | 28 | msgid "Unminimize" 29 | msgstr "Restaura" 30 | 31 | msgid "Show/Hide" 32 | msgstr "Mostra/amaga" 33 | 34 | msgid "Disable (Enable)" 35 | msgstr "Inhabilita (Habilita)" 36 | 37 | msgid "Default" 38 | msgstr "Per defecte" 39 | 40 | #, c-format 41 | msgid "Error: Couldn't read action database: %s.\n" 42 | msgstr "Error: No s'ha pogut llegir la base de dades d'accions: %s.\n" 43 | 44 | msgid "rename() failed" 45 | msgstr "rename() ha fallat" 46 | 47 | #, c-format 48 | msgid "Error: Couldn't save action database: %s.\n" 49 | msgstr "Error: No s'ha pogut desar la base de dades d'acciones: %s.\n" 50 | 51 | msgid "" 52 | "Couldn't save %1. Your changes will be lost. Make sure that \"%2\" is a " 53 | "directory and that you have write access to it. You can change the " 54 | "configuration directory using the -c or --config-dir command line options." 55 | msgstr "" 56 | "No s'ha pogut desar %1. Es perdran els canvis que heu fet. Assegureu-vos que " 57 | "«%2» sigui un directori i que hi tingueu accés d'escriptura. Podeu canviar " 58 | "el directori de la configuració mitjançant les opcions -c o --config-dir de " 59 | "la línia d'ordres." 60 | 61 | msgid "actions" 62 | msgstr "accions" 63 | 64 | msgid "Command" 65 | msgstr "Ordre" 66 | 67 | msgid "Key" 68 | msgstr "Tecla" 69 | 70 | msgid "Text" 71 | msgstr "Text" 72 | 73 | msgid "Scroll" 74 | msgstr "Desplaçament" 75 | 76 | msgid "Ignore" 77 | msgstr "Ignora" 78 | 79 | msgid "Button" 80 | msgstr "Botó" 81 | 82 | msgid "Misc" 83 | msgstr "Altres" 84 | 85 | msgid "Stroke" 86 | msgstr "Traç" 87 | 88 | msgid "Name" 89 | msgstr "Nom" 90 | 91 | msgid "Type" 92 | msgstr "Tipus" 93 | 94 | msgid "Details" 95 | msgstr "Detalls" 96 | 97 | msgid "Application" 98 | msgstr "Aplicació" 99 | 100 | msgid "Actions" 101 | msgstr "Accions" 102 | 103 | msgid "Action \"%1\" is about to be deleted." 104 | msgstr "Esteu a punt de suprimir l'acció «%1»." 105 | 106 | msgid "One action is about to be deleted." 107 | msgid_plural "%1 actions are about to be deleted" 108 | msgstr[0] "Se suprimirà una acció" 109 | msgstr[1] "Se suprimiran %1 accions" 110 | 111 | msgid "Delete an Action" 112 | msgid_plural "Delete Actions" 113 | msgstr[0] "Suprimeix una acció" 114 | msgstr[1] "Suprimeix les accions" 115 | 116 | msgid "%1 \"%2\" (containing %3 %4) is about to be deleted." 117 | msgstr "%1 «%2» (que conté %3 %4) se suprimirà." 118 | 119 | msgid "The application" 120 | msgstr "L'aplicació" 121 | 122 | msgid "The group" 123 | msgstr "El grup" 124 | 125 | msgid "action" 126 | msgid_plural "actions" 127 | msgstr[0] "acció" 128 | msgstr[1] "accions" 129 | 130 | msgid "Delete an Application" 131 | msgstr "Suprimeix una aplicació" 132 | 133 | msgid "Delete an Application Group" 134 | msgstr "Suprimeix un grup d'aplicacions" 135 | 136 | msgid "Group" 137 | msgstr "Grup" 138 | 139 | msgid "" 140 | "You are about to bind an action to a single click. This might make it " 141 | "difficult to use Button %1 in the future. Are you sure you want to continue?" 142 | msgstr "" 143 | "Esteu a punt de vincular una acció a un sol clic. Això pot fer que sigui " 144 | "difícil utilitzar el botó %1 en el futur. Segur que voleu continuar?" 145 | 146 | msgid "Record a New Stroke" 147 | msgstr "Enregistra un traç nou" 148 | 149 | msgid "" 150 | "The next stroke will be associated with the action \"%1\". You can draw it " 151 | "anywhere on the screen (except for the two buttons below)." 152 | msgstr "" 153 | "El proper traç s'associarà amb l'acció «%1». Podeu dibuixar-lo on vulgueu de " 154 | "la pantalla (excepte als dos botons de sota)." 155 | 156 | msgid "Gesture %1" 157 | msgstr "Gest %1" 158 | 159 | msgid "No Modifiers" 160 | msgstr "Cap modificador" 161 | 162 | msgid "(Instantly) " 163 | msgstr "(Instantàniament) " 164 | 165 | msgid "(Click & Hold) " 166 | msgstr "(Manté el botó clicat) " 167 | 168 | msgid "Any Modifier" 169 | msgstr "Qualsevol modificador" 170 | 171 | msgid "Button %1" 172 | msgstr "Botó %1" 173 | 174 | msgid " + Scroll" 175 | msgstr " + Desplaçament" 176 | 177 | msgid "'composite' not available" 178 | msgstr "«composite» no està disponible" 179 | 180 | #, c-format 181 | msgid "Error: %s\n" 182 | msgstr "Error: %s\n" 183 | 184 | msgid "Tray icon disabled" 185 | msgstr "S'ha inhabilitat la icona de la safata" 186 | 187 | msgid "" 188 | "To bring the configuration dialog up again, you should define an action of " 189 | "type Misc...Show/Hide." 190 | msgstr "" 191 | "Per tornar a obrir el diàleg de configuració, definiu una acció de tipus " 192 | "Altres - Mostra/Amaga" 193 | 194 | #, c-format 195 | msgid "Warning: No action \"%s\" defined\n" 196 | msgstr "Avís: No s'ha definit cap acció «%s»\n" 197 | 198 | msgid "Enabled" 199 | msgstr "Habilitat" 200 | 201 | msgid "About" 202 | msgstr "" 203 | 204 | msgid "Quit" 205 | msgstr "" 206 | 207 | #, c-format 208 | msgid "Couldn't open display.\n" 209 | msgstr "No s'ha pogut obrir la pantalla.\n" 210 | 211 | #, c-format 212 | msgid "Error: Couldn't create configuration directory \"%s\"\n" 213 | msgstr "Error: No s'ha pogut crear el directori de configuració «%s»\n" 214 | 215 | #, c-format 216 | msgid "Error: \"%s\" is not a directory\n" 217 | msgstr "Error: «%s» no és un directori\n" 218 | 219 | #, c-format 220 | msgid "Error: Couldn't save preferences: %s.\n" 221 | msgstr "Error: No s'han pogut desar les preferències: %s.\n" 222 | 223 | msgid "preferences" 224 | msgstr "preferències" 225 | 226 | #, c-format 227 | msgid "Error: Couldn't read preferences.\n" 228 | msgstr "Error: No s'han pogut llegir les preferències.\n" 229 | 230 | msgid "XShape" 231 | msgstr "" 232 | 233 | msgid "Annotate (compiz)" 234 | msgstr "" 235 | 236 | msgid "Fire (compiz)" 237 | msgstr "Foc (compiz)" 238 | 239 | msgid "Water (compiz)" 240 | msgstr "Aigua (compiz)" 241 | 242 | msgid "Timeout Off" 243 | msgstr "Temps d'espera desactivat" 244 | 245 | msgid "Conservative" 246 | msgstr "Conservador" 247 | 248 | msgid "Medium" 249 | msgstr "Mitjà" 250 | 251 | msgid "Aggressive" 252 | msgstr "Agressiu" 253 | 254 | msgid "Flick" 255 | msgstr "Parpelleig" 256 | 257 | msgid "Custom" 258 | msgstr "Personalitzat" 259 | 260 | msgid "Application (WM__CLASS)" 261 | msgstr "Aplicació (WM__CLASS)" 262 | 263 | msgid "Device" 264 | msgstr "Dispositiu" 265 | 266 | msgid "" 267 | msgstr "" 268 | 269 | msgid "Timeout profile" 270 | msgstr "" 271 | 272 | msgid "" 273 | msgstr "" 274 | 275 | msgid "Select a Mouse or Pen Button" 276 | msgstr "Seleccioneu un botó del ratolí o del llapis" 277 | 278 | msgid "" 279 | "Please place your mouse or pen in the box below and press the button that " 280 | "you want to select. You can also hold down additional modifiers." 281 | msgstr "" 282 | "Situeu el ratolí o el llapis al quadre següent i premeu el botó que voleu " 283 | "seleccionar. També podeu prémer modificadors addicionals." 284 | 285 | msgid "Score" 286 | msgstr "Puntuació" 287 | 288 | msgid "D_isabled" 289 | msgstr "_Inhabilitat" 290 | 291 | msgid "" 292 | msgstr "" 293 | 294 | msgid "Connection to DBus failed" 295 | msgstr "Ha fallat la connexió al DBus" 296 | 297 | msgid "_Delete Current" 298 | msgstr "" 299 | 300 | msgid "_Default" 301 | msgstr "Per _defecte" 302 | 303 | msgid "Timeout" 304 | msgstr "Temps d'espera" 305 | 306 | msgid "Instant Gestures" 307 | msgstr "" 308 | 309 | msgid "Click & Hold" 310 | msgstr "" 311 | 312 | msgid "_Control" 313 | msgstr "_Control" 314 | 315 | msgid "_Shift" 316 | msgstr "Tecla de majú_scules" 317 | 318 | msgid "_Alt" 319 | msgstr "_Alt" 320 | 321 | msgid "S_uper" 322 | msgstr "Sú_per" 323 | 324 | msgid "An_y Modifier" 325 | msgstr "_Qualsevol modificador" 326 | 327 | msgid "Alternatively, you may select button and modifiers below." 328 | msgstr "" 329 | 330 | msgid "Show deleted rows" 331 | msgstr "" 332 | 333 | msgid "Add Application" 334 | msgstr "Afegeix una aplicació" 335 | 336 | msgid "Remove Application/Group" 337 | msgstr "" 338 | 339 | msgid "Add Group" 340 | msgstr "Afegeix un grup" 341 | 342 | msgid "Reset Action(s)" 343 | msgstr "" 344 | 345 | msgid "Applications" 346 | msgstr "Aplicacions" 347 | 348 | msgid "_Record Stroke" 349 | msgstr "" 350 | 351 | msgid "_Add Action" 352 | msgstr "" 353 | 354 | msgid "_Delete Action(s)" 355 | msgstr "" 356 | 357 | msgid "_Hide" 358 | msgstr "A_maga" 359 | 360 | msgid "_Gesture Button" 361 | msgstr "" 362 | 363 | msgid "Additional Buttons" 364 | msgstr "Botons addicionals" 365 | 366 | msgid "Initial Timeout (ms)" 367 | msgstr "" 368 | 369 | msgid " Timeout (ms)" 370 | msgstr " Temps d'espera (ms)" 371 | 372 | msgid "Behavior" 373 | msgstr "Comportament" 374 | 375 | msgid "Method to show gestures" 376 | msgstr "" 377 | 378 | msgid "Color" 379 | msgstr "Color" 380 | 381 | msgid "Width" 382 | msgstr "Amplada" 383 | 384 | msgid "Show popups (" 385 | msgstr "" 386 | 387 | msgid "to the right of the cursor)" 388 | msgstr "" 389 | 390 | msgid "Show tray icon" 391 | msgstr "Mostra la icona a la barra de sistema" 392 | 393 | msgid "Show last gesture in tray" 394 | msgstr "" 395 | 396 | msgid "Autostart easystroke" 397 | msgstr "Inicia l'Easystroke automàticament" 398 | 399 | msgid "Appearance" 400 | msgstr "Aspecte" 401 | 402 | msgid "Exceptions" 403 | msgstr "Excepcions" 404 | 405 | msgid "_Add Exception" 406 | msgstr "" 407 | 408 | msgid "_Remove Exception" 409 | msgstr "" 410 | 411 | msgid "Preferences" 412 | msgstr "Preferències" 413 | 414 | msgid "Only enable easystroke for applications listed on 'Actions' tab" 415 | msgstr "" 416 | 417 | msgid "Timeout Gestures" 418 | msgstr "" 419 | 420 | msgid "Ignore strokes leading up to advanced gestures" 421 | msgstr "" 422 | 423 | msgid "(See Documentation)" 424 | msgstr "(Vegeu la documentació)" 425 | 426 | msgid "Show popups on advanced gestures" 427 | msgstr "" 428 | 429 | msgid "Show OSD" 430 | msgstr "Mostra l'OSD" 431 | 432 | msgid "Invert Scroll Direction" 433 | msgstr "" 434 | 435 | msgid "Scroll Speed" 436 | msgstr "Velocitat de desplaçament" 437 | 438 | msgid "Move the cursor back to the original position after each gesture" 439 | msgstr "" 440 | 441 | msgid "Stay in 'scroll' and 'ignore' mode as long as the pen is within range" 442 | msgstr "" 443 | 444 | msgid "Tablet Options" 445 | msgstr "" 446 | 447 | msgid "Devices" 448 | msgstr "Dispositius" 449 | 450 | msgid "Advanced" 451 | msgstr "Avançat" 452 | 453 | msgid "_Matrix" 454 | msgstr "" 455 | 456 | msgid "_History" 457 | msgstr "_Historial" 458 | 459 | msgid "Easystroke Gesture Recognition" 460 | msgstr "Reconeixement de gestos Easystroke" 461 | 462 | msgid "Control your desktop using mouse gestures" 463 | msgstr "Controla el teu escriptori a través de gestos amb el ratolí" 464 | 465 | msgid "Enable" 466 | msgstr "" 467 | 468 | msgid "Disable" 469 | msgstr "" 470 | 471 | #~ msgid "Key combination..." 472 | #~ msgstr "Combinació de tecles..." 473 | 474 | #, c-format 475 | #~ msgid "Error: A grab failed. Resetting...\n" 476 | #~ msgstr "Error: Ha fallat una captura. Es reiniciarà...\n" 477 | 478 | #~ msgid "(window manager frame)" 479 | #~ msgstr "(marc del gestor de finestres)" 480 | -------------------------------------------------------------------------------- /po/cs.po: -------------------------------------------------------------------------------- 1 | # Czech translation for easystroke 2 | # Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 3 | # This file is distributed under the same license as the easystroke package. 4 | # FIRST AUTHOR , 2009. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: easystroke\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2013-03-14 00:24-0400\n" 11 | "PO-Revision-Date: 2013-03-14 20:01+0000\n" 12 | "Last-Translator: Zbyněk Schwarz \n" 13 | "Language-Team: Czech \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" 18 | "X-Launchpad-Export-Date: 2013-03-27 01:12+0000\n" 19 | "X-Generator: Launchpad (build 16540)\n" 20 | 21 | #, c-format 22 | msgid "Error: can't execute command \"%s\": fork() failed\n" 23 | msgstr "Chyba: nelze spustit příkaz \"%s\": fork() selhalo\n" 24 | 25 | msgid "None" 26 | msgstr "Žádný" 27 | 28 | msgid "Unminimize" 29 | msgstr "Odminimalizovat" 30 | 31 | msgid "Show/Hide" 32 | msgstr "Zobrazit/Skrýt" 33 | 34 | msgid "Disable (Enable)" 35 | msgstr "Zakázat (Povolit)" 36 | 37 | msgid "Default" 38 | msgstr "Výchozí" 39 | 40 | #, c-format 41 | msgid "Error: Couldn't read action database: %s.\n" 42 | msgstr "Chyba: Nelze přečíst databázi akcí: %s.\n" 43 | 44 | msgid "rename() failed" 45 | msgstr "rename() selhalo" 46 | 47 | #, c-format 48 | msgid "Error: Couldn't save action database: %s.\n" 49 | msgstr "Chyba: Nelze zapsat databázi akcí: %s.\n" 50 | 51 | msgid "" 52 | "Couldn't save %1. Your changes will be lost. Make sure that \"%2\" is a " 53 | "directory and that you have write access to it. You can change the " 54 | "configuration directory using the -c or --config-dir command line options." 55 | msgstr "" 56 | "Nelze uložit %1. Vaše změny budou ztraceny. Ujistěte se, že \"%2\" je " 57 | "složka a že do ní máte právo zápisu. Můžete změnit konfigurační složku " 58 | "parametrem -c nebo --config-dir v terminálu." 59 | 60 | msgid "actions" 61 | msgstr "akce" 62 | 63 | msgid "Command" 64 | msgstr "Příkaz" 65 | 66 | msgid "Key" 67 | msgstr "Klávesa" 68 | 69 | msgid "Text" 70 | msgstr "Text" 71 | 72 | msgid "Scroll" 73 | msgstr "Posun" 74 | 75 | msgid "Ignore" 76 | msgstr "Ignorovat" 77 | 78 | msgid "Button" 79 | msgstr "Tlačítko" 80 | 81 | msgid "Misc" 82 | msgstr "Ostatní" 83 | 84 | msgid "Stroke" 85 | msgstr "Gesto" 86 | 87 | msgid "Name" 88 | msgstr "Název" 89 | 90 | msgid "Type" 91 | msgstr "Typ" 92 | 93 | msgid "Details" 94 | msgstr "Detaily" 95 | 96 | msgid "Application" 97 | msgstr "Aplikace" 98 | 99 | msgid "Actions" 100 | msgstr "Akce" 101 | 102 | msgid "Action \"%1\" is about to be deleted." 103 | msgstr "Akce \"%1\" bude smazána." 104 | 105 | msgid "One action is about to be deleted." 106 | msgid_plural "%1 actions are about to be deleted" 107 | msgstr[0] "Jedna akce bude smazána." 108 | msgstr[1] "%1 akce budou smazány." 109 | msgstr[2] "%1 akcí bude smazáno." 110 | 111 | msgid "Delete an Action" 112 | msgid_plural "Delete Actions" 113 | msgstr[0] "Smazat akci" 114 | msgstr[1] "Smazat akce" 115 | msgstr[2] "Smazat akce" 116 | 117 | msgid "%1 \"%2\" (containing %3 %4) is about to be deleted." 118 | msgstr "%1 \"%2\" (obsahující %3 %4) bude smazána." 119 | 120 | msgid "The application" 121 | msgstr "Aplikace" 122 | 123 | msgid "The group" 124 | msgstr "Skupina" 125 | 126 | msgid "action" 127 | msgid_plural "actions" 128 | msgstr[0] "akce" 129 | msgstr[1] "akce" 130 | msgstr[2] "akcí" 131 | 132 | msgid "Delete an Application" 133 | msgstr "Smazat aplikaci" 134 | 135 | msgid "Delete an Application Group" 136 | msgstr "Smazat skupinu aplikací" 137 | 138 | msgid "Group" 139 | msgstr "Skupina" 140 | 141 | msgid "" 142 | "You are about to bind an action to a single click. This might make it " 143 | "difficult to use Button %1 in the future. Are you sure you want to continue?" 144 | msgstr "" 145 | "Chcete nastavit pro akci jedno kliknutí. Toto může v budouctnosti způsobovat " 146 | "problémy při používání tlačítka %1. Opravdu chcete pokračovat?" 147 | 148 | msgid "Record a New Stroke" 149 | msgstr "Zaznamenat nové gesto" 150 | 151 | msgid "" 152 | "The next stroke will be associated with the action \"%1\". You can draw it " 153 | "anywhere on the screen (except for the two buttons below)." 154 | msgstr "" 155 | "Následující gesto bude asociováno s akcí \"%1\". Můžete malovat kdekoliv na " 156 | "obrazovce (s výjimkou dvou tlačítek níže)." 157 | 158 | msgid "Gesture %1" 159 | msgstr "Gesto %1" 160 | 161 | msgid "No Modifiers" 162 | msgstr "Žádné modifikátory" 163 | 164 | msgid "(Instantly) " 165 | msgstr "(Instantně) " 166 | 167 | msgid "(Click & Hold) " 168 | msgstr "(Kliknout & držet) " 169 | 170 | msgid "Any Modifier" 171 | msgstr "Jakékoliv modifikátory" 172 | 173 | msgid "Button %1" 174 | msgstr "Tlačítko %1" 175 | 176 | msgid " + Scroll" 177 | msgstr " + Rolovat" 178 | 179 | msgid "'composite' not available" 180 | msgstr "'composite' není k dispozici" 181 | 182 | #, c-format 183 | msgid "Error: %s\n" 184 | msgstr "Chyba: %s\n" 185 | 186 | msgid "Tray icon disabled" 187 | msgstr "Ikona v oznam. oblasti zakázána" 188 | 189 | msgid "" 190 | "To bring the configuration dialog up again, you should define an action of " 191 | "type Misc...Show/Hide." 192 | msgstr "" 193 | "K zobrazení dialogu nastavení byste měli nadefinovat akci " 194 | "Ostatní....Zobrazit/Skrýt" 195 | 196 | #, c-format 197 | msgid "Warning: No action \"%s\" defined\n" 198 | msgstr "Varování: Nebyla nadefinována akce \"%s\"\n" 199 | 200 | msgid "Enabled" 201 | msgstr "Povoleno" 202 | 203 | msgid "About" 204 | msgstr "O programu" 205 | 206 | msgid "Quit" 207 | msgstr "Konec" 208 | 209 | #, c-format 210 | msgid "Couldn't open display.\n" 211 | msgstr "Nelze otevřít display.\n" 212 | 213 | #, c-format 214 | msgid "Error: Couldn't create configuration directory \"%s\"\n" 215 | msgstr "Chyba: Nelze vytvořit konfigurační složku \"%s\"\n" 216 | 217 | #, c-format 218 | msgid "Error: \"%s\" is not a directory\n" 219 | msgstr "Chyba: \"%s\" není složka\n" 220 | 221 | #, c-format 222 | msgid "Error: Couldn't save preferences: %s.\n" 223 | msgstr "Chyba: Nelze uložit nastavení: %s.\n" 224 | 225 | msgid "preferences" 226 | msgstr "nastavení" 227 | 228 | #, c-format 229 | msgid "Error: Couldn't read preferences.\n" 230 | msgstr "Chyba: Nelze načíst nastavení.\n" 231 | 232 | msgid "XShape" 233 | msgstr "XShape" 234 | 235 | msgid "Annotate (compiz)" 236 | msgstr "Annotate (compiz)" 237 | 238 | msgid "Fire (compiz)" 239 | msgstr "Oheň (compiz)" 240 | 241 | msgid "Water (compiz)" 242 | msgstr "Voda (compiz)" 243 | 244 | msgid "Timeout Off" 245 | msgstr "Timeout vypnutý" 246 | 247 | msgid "Conservative" 248 | msgstr "Konzervativní" 249 | 250 | msgid "Medium" 251 | msgstr "Střední" 252 | 253 | msgid "Aggressive" 254 | msgstr "Agresivní" 255 | 256 | msgid "Flick" 257 | msgstr "Trhnutí" 258 | 259 | msgid "Custom" 260 | msgstr "Vlastní" 261 | 262 | msgid "Application (WM__CLASS)" 263 | msgstr "Aplikace (WM__CLASS)" 264 | 265 | msgid "Device" 266 | msgstr "Zařízení" 267 | 268 | msgid "" 269 | msgstr "" 270 | 271 | msgid "Timeout profile" 272 | msgstr "Profil timeoutu" 273 | 274 | msgid "" 275 | msgstr "" 276 | 277 | msgid "Select a Mouse or Pen Button" 278 | msgstr "Zvolte tlačítko myši nebo pera" 279 | 280 | msgid "" 281 | "Please place your mouse or pen in the box below and press the button that " 282 | "you want to select. You can also hold down additional modifiers." 283 | msgstr "" 284 | "Prosím umístěte myš do náslodujícího okna a stiskněte požadované tlačítko. " 285 | "Můžete také držet libovolné pomocné klávesy (Ctrl, Alt, Shift)." 286 | 287 | msgid "Score" 288 | msgstr "Skóre" 289 | 290 | msgid "D_isabled" 291 | msgstr "Zakázán_o" 292 | 293 | msgid "" 294 | msgstr "" 295 | 296 | msgid "Connection to DBus failed" 297 | msgstr "Spojení s DBus selhalo" 298 | 299 | msgid "_Delete Current" 300 | msgstr "S_mazat aktuální" 301 | 302 | msgid "_Default" 303 | msgstr "_Výchozí" 304 | 305 | msgid "Timeout" 306 | msgstr "Timeout" 307 | 308 | msgid "Instant Gestures" 309 | msgstr "Rychlá gesta" 310 | 311 | msgid "Click & Hold" 312 | msgstr "Kliknout & držet" 313 | 314 | msgid "_Control" 315 | msgstr "_Control" 316 | 317 | msgid "_Shift" 318 | msgstr "_Shift" 319 | 320 | msgid "_Alt" 321 | msgstr "_Alt" 322 | 323 | msgid "S_uper" 324 | msgstr "S_uper" 325 | 326 | msgid "An_y Modifier" 327 | msgstr "J_akýkoliv modifikátor" 328 | 329 | msgid "Alternatively, you may select button and modifiers below." 330 | msgstr "Alternativně můžete zvolit tlačítko a modifikátory níže." 331 | 332 | msgid "Show deleted rows" 333 | msgstr "Zobrazit smazané řady" 334 | 335 | msgid "Add Application" 336 | msgstr "Přidat aplikaci" 337 | 338 | msgid "Remove Application/Group" 339 | msgstr "Odebrat Aplikaci/Skupinu" 340 | 341 | msgid "Add Group" 342 | msgstr "Přidat skupinu" 343 | 344 | msgid "Reset Action(s)" 345 | msgstr "Resetovat Akce" 346 | 347 | msgid "Applications" 348 | msgstr "Aplikace" 349 | 350 | msgid "_Record Stroke" 351 | msgstr "_Zaznamenat gesto" 352 | 353 | msgid "_Add Action" 354 | msgstr "Přid_at akci" 355 | 356 | msgid "_Delete Action(s)" 357 | msgstr "S_mazat akce" 358 | 359 | msgid "_Hide" 360 | msgstr "_Skrýt" 361 | 362 | msgid "_Gesture Button" 363 | msgstr "Tlačítko _Gest" 364 | 365 | msgid "Additional Buttons" 366 | msgstr "Další tlačítka" 367 | 368 | msgid "Initial Timeout (ms)" 369 | msgstr "Počáteční timeout (ms)" 370 | 371 | msgid " Timeout (ms)" 372 | msgstr " Timeout (ms)" 373 | 374 | msgid "Behavior" 375 | msgstr "Chování" 376 | 377 | msgid "Method to show gestures" 378 | msgstr "Metoda zobrazování gest" 379 | 380 | msgid "Color" 381 | msgstr "Barva" 382 | 383 | msgid "Width" 384 | msgstr "Šířka" 385 | 386 | msgid "Show popups (" 387 | msgstr "Zobrazit vyskakovací okna (" 388 | 389 | msgid "to the right of the cursor)" 390 | msgstr "napravo od kurzoru)" 391 | 392 | msgid "Show tray icon" 393 | msgstr "Zobrazovat ikonu v oznamovací oblasti" 394 | 395 | msgid "Show last gesture in tray" 396 | msgstr "Zobrazit poslední gesto v oznam. oblasti" 397 | 398 | msgid "Autostart easystroke" 399 | msgstr "Automaticky spouštět EasyStroke" 400 | 401 | msgid "Appearance" 402 | msgstr "Vzhled" 403 | 404 | msgid "Exceptions" 405 | msgstr "Výjimky" 406 | 407 | msgid "_Add Exception" 408 | msgstr "Přid_at výjimku" 409 | 410 | msgid "_Remove Exception" 411 | msgstr "Odeb_rat výjimku" 412 | 413 | msgid "Preferences" 414 | msgstr "Nastavení" 415 | 416 | msgid "Only enable easystroke for applications listed on 'Actions' tab" 417 | msgstr "Easystroke povolit pouze po aplikace uvedené v kartě 'Akce'" 418 | 419 | msgid "Timeout Gestures" 420 | msgstr "Timeout Gest" 421 | 422 | msgid "Ignore strokes leading up to advanced gestures" 423 | msgstr "Ignorovat čáry, které začínají být složitějšími gesty" 424 | 425 | msgid "(See Documentation)" 426 | msgstr "(Navštivte dokumentaci)" 427 | 428 | msgid "Show popups on advanced gestures" 429 | msgstr "Zobrazit vyskakovací okna u pokročilých gest" 430 | 431 | msgid "Show OSD" 432 | msgstr "Zobrazit OSD" 433 | 434 | msgid "Invert Scroll Direction" 435 | msgstr "Obrátit směr posuvu" 436 | 437 | msgid "Scroll Speed" 438 | msgstr "Rychlost posuvu" 439 | 440 | msgid "Move the cursor back to the original position after each gesture" 441 | msgstr "Po každém gestu přesunout kurzor zpět na původní pozici." 442 | 443 | msgid "Stay in 'scroll' and 'ignore' mode as long as the pen is within range" 444 | msgstr "Zůstat ve 'skrolovacím' a 'ignore' módu dokud je pero v dosahu" 445 | 446 | msgid "Tablet Options" 447 | msgstr "Nastavení Tabletu" 448 | 449 | msgid "Devices" 450 | msgstr "Zařízení" 451 | 452 | msgid "Advanced" 453 | msgstr "Pokročilé" 454 | 455 | msgid "_Matrix" 456 | msgstr "_Matrix" 457 | 458 | msgid "_History" 459 | msgstr "_Historie" 460 | 461 | msgid "Easystroke Gesture Recognition" 462 | msgstr "Easystroke rozeznávání gest" 463 | 464 | msgid "Control your desktop using mouse gestures" 465 | msgstr "Ovládejte počítač pomocí gest myši" 466 | 467 | msgid "Enable" 468 | msgstr "Povolit" 469 | 470 | msgid "Disable" 471 | msgstr "Zakázat" 472 | -------------------------------------------------------------------------------- /po/vi.po: -------------------------------------------------------------------------------- 1 | # Vietnamese translation for easystroke 2 | # Copyright (c) 2010 Rosetta Contributors and Canonical Ltd 2010 3 | # This file is distributed under the same license as the easystroke package. 4 | # FIRST AUTHOR , 2010. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: easystroke\n" 9 | "Report-Msgid-Bugs-To: FULL NAME \n" 10 | "POT-Creation-Date: 2013-03-14 00:24-0400\n" 11 | "PO-Revision-Date: 2010-09-04 14:46+0000\n" 12 | "Last-Translator: Van Diep Duong \n" 13 | "Language-Team: Vietnamese \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=1; plural=0;\n" 18 | "X-Launchpad-Export-Date: 2013-03-14 04:28+0000\n" 19 | "X-Generator: Launchpad (build 16532)\n" 20 | 21 | #, c-format 22 | msgid "Error: can't execute command \"%s\": fork() failed\n" 23 | msgstr "Lỗi: \"%s\" không thể thực hiện\n" 24 | 25 | msgid "None" 26 | msgstr "Không chọn" 27 | 28 | msgid "Unminimize" 29 | msgstr "Phóng to" 30 | 31 | msgid "Show/Hide" 32 | msgstr "Hiện/Ẩn" 33 | 34 | msgid "Disable (Enable)" 35 | msgstr "Tắt (Bật)" 36 | 37 | msgid "Default" 38 | msgstr "Mặc định" 39 | 40 | #, c-format 41 | msgid "Error: Couldn't read action database: %s.\n" 42 | msgstr "Lỗi: Không thể đọc cơ sở dữ liệu thao tác: %s\n" 43 | 44 | msgid "rename() failed" 45 | msgstr "Đổi tên() thất bại" 46 | 47 | #, c-format 48 | msgid "Error: Couldn't save action database: %s.\n" 49 | msgstr "Lỗi: Không thể lưu cơ sở dữ liệu thao tác: %s\n" 50 | 51 | msgid "" 52 | "Couldn't save %1. Your changes will be lost. Make sure that \"%2\" is a " 53 | "directory and that you have write access to it. You can change the " 54 | "configuration directory using the -c or --config-dir command line options." 55 | msgstr "" 56 | "Không thể lưu được 1%. Thay đổi của bạn sẽ bị mất. Hãy chắc chắn rằng \"%2\" " 57 | "là một thư mục và bạn đã viết truy cập vào nó. Bạn có thể thay đổi thư mục " 58 | "cấu hình bằng cách sử dụng các tùy chọn dòng lệnh -c hay --config-dir." 59 | 60 | msgid "actions" 61 | msgstr "thao tác" 62 | 63 | msgid "Command" 64 | msgstr "Câu lệnh" 65 | 66 | msgid "Key" 67 | msgstr "Phím" 68 | 69 | msgid "Text" 70 | msgstr "Văn bản" 71 | 72 | msgid "Scroll" 73 | msgstr "Cuộn" 74 | 75 | msgid "Ignore" 76 | msgstr "Bỏ qua" 77 | 78 | msgid "Button" 79 | msgstr "Nút bấm" 80 | 81 | msgid "Misc" 82 | msgstr "Lặt vặt" 83 | 84 | msgid "Stroke" 85 | msgstr "Nét vẽ" 86 | 87 | msgid "Name" 88 | msgstr "Tên" 89 | 90 | msgid "Type" 91 | msgstr "Kiểu" 92 | 93 | msgid "Details" 94 | msgstr "Chi tiết" 95 | 96 | msgid "Application" 97 | msgstr "Ứng dụng" 98 | 99 | msgid "Actions" 100 | msgstr "Thao tác" 101 | 102 | msgid "Action \"%1\" is about to be deleted." 103 | msgstr "Thao tác \"%1\" sắp được xóa" 104 | 105 | msgid "One action is about to be deleted." 106 | msgid_plural "%1 actions are about to be deleted" 107 | msgstr[0] "Một thao tác sắp được xóa" 108 | 109 | msgid "Delete an Action" 110 | msgid_plural "Delete Actions" 111 | msgstr[0] "Xóa một thao tác" 112 | 113 | msgid "%1 \"%2\" (containing %3 %4) is about to be deleted." 114 | msgstr "%1 \"%2\" (bao gồm %3 %4) sắp được xóa" 115 | 116 | msgid "The application" 117 | msgstr "Ứng dụng" 118 | 119 | msgid "The group" 120 | msgstr "Nhóm" 121 | 122 | msgid "action" 123 | msgid_plural "actions" 124 | msgstr[0] "Thao tác" 125 | 126 | msgid "Delete an Application" 127 | msgstr "Xóa một ứng dụng" 128 | 129 | msgid "Delete an Application Group" 130 | msgstr "Xóa một nhóm ứng dụng" 131 | 132 | msgid "Group" 133 | msgstr "Nhóm" 134 | 135 | msgid "" 136 | "You are about to bind an action to a single click. This might make it " 137 | "difficult to use Button %1 in the future. Are you sure you want to continue?" 138 | msgstr "" 139 | "Bạn sắp chấp nhận một thao tác cho một nhấp chuột duy nhất. Điều này có thể " 140 | "làm cho nó khó sử dụng Nút 1% trong tương lai. Bạn có chắc bạn muốn tiếp tục " 141 | "không?" 142 | 143 | msgid "Record a New Stroke" 144 | msgstr "Ghi lại một nét vẽ mới" 145 | 146 | msgid "" 147 | "The next stroke will be associated with the action \"%1\". You can draw it " 148 | "anywhere on the screen (except for the two buttons below)." 149 | msgstr "" 150 | "Nét vẽ tiếp theo sẽ được kết hợp với thao tác \"%1\". Bạn có thể vẽ nó bất " 151 | "kỳ vị trí nào trên màn hình (ngoại trừ hai nút dưới đây)" 152 | 153 | msgid "Gesture %1" 154 | msgstr "Cử chỉ %1" 155 | 156 | msgid "No Modifiers" 157 | msgstr "Không bổ trợ" 158 | 159 | msgid "(Instantly) " 160 | msgstr "(Ngay lập tức) " 161 | 162 | msgid "(Click & Hold) " 163 | msgstr "(Nhắp & Giữ) " 164 | 165 | msgid "Any Modifier" 166 | msgstr "Tùy ý" 167 | 168 | msgid "Button %1" 169 | msgstr "Nút %1" 170 | 171 | msgid " + Scroll" 172 | msgstr " +Cuộn" 173 | 174 | msgid "'composite' not available" 175 | msgstr "'kết hợp' không có sẵn" 176 | 177 | #, c-format 178 | msgid "Error: %s\n" 179 | msgstr "Lỗi: %s\n" 180 | 181 | msgid "Tray icon disabled" 182 | msgstr "Tắt biểu tượng trên khay hệ thống" 183 | 184 | msgid "" 185 | "To bring the configuration dialog up again, you should define an action of " 186 | "type Misc...Show/Hide." 187 | msgstr "" 188 | "Để đem lại hộp thoại cấu hình lên một lần nữa, bạn nên xác định một hành " 189 | "động của loại Lặt vặt...Hiện/Ẩn." 190 | 191 | #, c-format 192 | msgid "Warning: No action \"%s\" defined\n" 193 | msgstr "Cảnh báo: Thao tác \"%s\" không xác định\n" 194 | 195 | msgid "Enabled" 196 | msgstr "Bật" 197 | 198 | msgid "About" 199 | msgstr "" 200 | 201 | msgid "Quit" 202 | msgstr "" 203 | 204 | #, c-format 205 | msgid "Couldn't open display.\n" 206 | msgstr "Không thể mở sự hiển thị.\n" 207 | 208 | #, c-format 209 | msgid "Error: Couldn't create configuration directory \"%s\"\n" 210 | msgstr "Lỗi: Không thể tạo thư mục cấu hình \"%s\"\n" 211 | 212 | #, c-format 213 | msgid "Error: \"%s\" is not a directory\n" 214 | msgstr "Lỗi: \"%s\" không là một đường dẫn\n" 215 | 216 | #, c-format 217 | msgid "Error: Couldn't save preferences: %s.\n" 218 | msgstr "Lỗi: Không thể lưu các tùy chọn: %s.\n" 219 | 220 | msgid "preferences" 221 | msgstr "tuỳ chọn" 222 | 223 | #, c-format 224 | msgid "Error: Couldn't read preferences.\n" 225 | msgstr "Lỗi: Không thể đọc các tùy chọn\n" 226 | 227 | msgid "XShape" 228 | msgstr "XShape" 229 | 230 | msgid "Annotate (compiz)" 231 | msgstr "Annotate (compiz)" 232 | 233 | msgid "Fire (compiz)" 234 | msgstr "Fire (compiz)" 235 | 236 | msgid "Water (compiz)" 237 | msgstr "Water (compiz)" 238 | 239 | msgid "Timeout Off" 240 | msgstr "Tắt" 241 | 242 | msgid "Conservative" 243 | msgstr "Vừa phải" 244 | 245 | msgid "Medium" 246 | msgstr "Trung bình" 247 | 248 | msgid "Aggressive" 249 | msgstr "Năng nổ" 250 | 251 | msgid "Flick" 252 | msgstr "Vút nhẹ" 253 | 254 | msgid "Custom" 255 | msgstr "Tuỳ chọn" 256 | 257 | msgid "Application (WM__CLASS)" 258 | msgstr "Ứng dụng (WM_CLASS)" 259 | 260 | msgid "Device" 261 | msgstr "Thiết bị" 262 | 263 | msgid "" 264 | msgstr "" 265 | 266 | msgid "Timeout profile" 267 | msgstr "Mô tả timeout" 268 | 269 | msgid "" 270 | msgstr "" 271 | 272 | msgid "Select a Mouse or Pen Button" 273 | msgstr "Chọn nút bấm chuột hoặc bút" 274 | 275 | msgid "" 276 | "Please place your mouse or pen in the box below and press the button that " 277 | "you want to select. You can also hold down additional modifiers." 278 | msgstr "" 279 | "Xin hãy đặt bút hay chuột của bạn vào hộp dưới đây và bấm vào nút mà bạn " 280 | "muốn chọn. Bạn cũng có thể giữ thêm phím bổ trợ." 281 | 282 | msgid "Score" 283 | msgstr "Thành công" 284 | 285 | msgid "D_isabled" 286 | msgstr "Tắ_t" 287 | 288 | msgid "" 289 | msgstr "" 290 | 291 | msgid "Connection to DBus failed" 292 | msgstr "Kết nối với DBUS thất bại" 293 | 294 | msgid "_Delete Current" 295 | msgstr "_Xóa sự hiện hành" 296 | 297 | msgid "_Default" 298 | msgstr "_Mặc định" 299 | 300 | msgid "Timeout" 301 | msgstr "Timeout" 302 | 303 | msgid "Instant Gestures" 304 | msgstr "Cử chỉ tức thời" 305 | 306 | msgid "Click & Hold" 307 | msgstr "Nhắp & Giữ" 308 | 309 | msgid "_Control" 310 | msgstr "_Control" 311 | 312 | msgid "_Shift" 313 | msgstr "_Shift" 314 | 315 | msgid "_Alt" 316 | msgstr "_Alt" 317 | 318 | msgid "S_uper" 319 | msgstr "S_uper" 320 | 321 | msgid "An_y Modifier" 322 | msgstr "Tùy ý" 323 | 324 | msgid "Alternatively, you may select button and modifiers below." 325 | msgstr "Ngoài ra, bạn có thể chọn nút bấm và nút bổ trợ dưới đây." 326 | 327 | msgid "Show deleted rows" 328 | msgstr "Hiện hàng đã xóa" 329 | 330 | msgid "Add Application" 331 | msgstr "Thêm ứng dụng" 332 | 333 | msgid "Remove Application/Group" 334 | msgstr "Hủy bỏ Ứng dụng/Nhóm" 335 | 336 | msgid "Add Group" 337 | msgstr "Thêm nhóm" 338 | 339 | msgid "Reset Action(s)" 340 | msgstr "Thiết lập lại thao tác" 341 | 342 | msgid "Applications" 343 | msgstr "Ứng dụng" 344 | 345 | msgid "_Record Stroke" 346 | msgstr "_Ghi nét vẽ" 347 | 348 | msgid "_Add Action" 349 | msgstr "_Thêm thao tác" 350 | 351 | msgid "_Delete Action(s)" 352 | msgstr "_Xóa thao tác" 353 | 354 | msgid "_Hide" 355 | msgstr "Ẩ_n" 356 | 357 | msgid "_Gesture Button" 358 | msgstr "_Nút bấm" 359 | 360 | msgid "Additional Buttons" 361 | msgstr "Thêm nút bấm" 362 | 363 | msgid "Initial Timeout (ms)" 364 | msgstr "Thời gian trễ ban đầu (ms)" 365 | 366 | msgid " Timeout (ms)" 367 | msgstr " Timeout (ms)" 368 | 369 | msgid "Behavior" 370 | msgstr "Chế độ" 371 | 372 | msgid "Method to show gestures" 373 | msgstr "Cách thể hiện cử chỉ" 374 | 375 | msgid "Color" 376 | msgstr "Màu" 377 | 378 | msgid "Width" 379 | msgstr "Độ rộng" 380 | 381 | msgid "Show popups (" 382 | msgstr "Hiển thị popup" 383 | 384 | msgid "to the right of the cursor)" 385 | msgstr "" 386 | 387 | msgid "Show tray icon" 388 | msgstr "Hiện biểu tượng trên khay" 389 | 390 | msgid "Show last gesture in tray" 391 | msgstr "Hiện cử chỉ mới nhất trong khay" 392 | 393 | msgid "Autostart easystroke" 394 | msgstr "Easystroke tự khởi động" 395 | 396 | msgid "Appearance" 397 | msgstr "Diện mạo" 398 | 399 | msgid "Exceptions" 400 | msgstr "Ngoại lệ" 401 | 402 | msgid "_Add Exception" 403 | msgstr "_Thêm ngoại lệ" 404 | 405 | msgid "_Remove Exception" 406 | msgstr "_Xóa ngoại trừ" 407 | 408 | msgid "Preferences" 409 | msgstr "Tùy chỉnh" 410 | 411 | msgid "Only enable easystroke for applications listed on 'Actions' tab" 412 | msgstr "" 413 | 414 | msgid "Timeout Gestures" 415 | msgstr "Timeout Gestures" 416 | 417 | msgid "Ignore strokes leading up to advanced gestures" 418 | msgstr "Bỏ qua các nét vẽ dẫn đến cử chỉ cao cấp" 419 | 420 | msgid "(See Documentation)" 421 | msgstr "(Xem tài liệu)" 422 | 423 | msgid "Show popups on advanced gestures" 424 | msgstr "Hiển thì popup trong các cử chỉ nâng cao" 425 | 426 | msgid "Show OSD" 427 | msgstr "Hiện OSD" 428 | 429 | msgid "Invert Scroll Direction" 430 | msgstr "Đảo ngược hướng cuộn" 431 | 432 | msgid "Scroll Speed" 433 | msgstr "Tốc độ cuộn" 434 | 435 | msgid "Move the cursor back to the original position after each gesture" 436 | msgstr "Di chuyển con trỏ trở lại vị trí ban đầu sau mỗi cử chỉ" 437 | 438 | msgid "Stay in 'scroll' and 'ignore' mode as long as the pen is within range" 439 | msgstr "Trong chế độ 'cuộn' và 'bỏ qua' miễn là bút vẽ ở trong phạm vi" 440 | 441 | msgid "Tablet Options" 442 | msgstr "Tùy chọn Tablet PC" 443 | 444 | msgid "Devices" 445 | msgstr "Thiết bị" 446 | 447 | msgid "Advanced" 448 | msgstr "Nâng cao" 449 | 450 | msgid "_Matrix" 451 | msgstr "_Bảng" 452 | 453 | msgid "_History" 454 | msgstr "_Lược sử" 455 | 456 | msgid "Easystroke Gesture Recognition" 457 | msgstr "Trình nhận dạng hành vi Easystroke" 458 | 459 | msgid "Control your desktop using mouse gestures" 460 | msgstr "Điều khiển máy tính bằng những hành vi của chuột" 461 | 462 | msgid "Enable" 463 | msgstr "" 464 | 465 | msgid "Disable" 466 | msgstr "" 467 | 468 | #~ msgid "Key combination..." 469 | #~ msgstr "Phím kết hợp..." 470 | 471 | #, c-format 472 | #~ msgid "Error: A grab failed. Resetting...\n" 473 | #~ msgstr "Lỗi: Lấy A thất bại. Làm lại ...\n" 474 | 475 | #~ msgid "optimize for left-handed operation )" 476 | #~ msgstr "tối ưu cho hoạt động thuận tay trái)" 477 | 478 | #~ msgid "(window manager frame)" 479 | #~ msgstr "Quản lý cửa sổ khung" 480 | --------------------------------------------------------------------------------