diff options
author | Jonas Smedegaard <dr@jones.dk> | 2008-10-18 23:39:20 (GMT) |
---|---|---|
committer | Jonas Smedegaard <dr@jones.dk> | 2008-10-18 23:39:20 (GMT) |
commit | b93839e07925181d188b2061cb15ba71de7ff004 (patch) | |
tree | 690fafdeb9547316564c203ddeede60ee1c330d6 | |
parent | d7cb0f34bfbec887072b0465ade35752dee6cba4 (diff) | |
parent | b3fde4a8e9a91425646bf9403dc27f00149a8980 (diff) |
Merge commit 'v0.82.11'
93 files changed, 1906 insertions, 591 deletions
diff --git a/configure.ac b/configure.ac index 1c234d3..f0aaa85 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([sugar-toolkit],[0.82.0],[],[sugar-toolkit]) +AC_INIT([sugar-toolkit],[0.82.11],[],[sugar-toolkit]) AC_PREREQ([2.59]) @@ -10,6 +10,8 @@ AM_INIT_AUTOMAKE([1.9 foreign dist-bzip2 no-dist-gzip]) AC_DISABLE_STATIC AC_PROG_LIBTOOL +GNOME_COMPILE_WARNINGS(maximum) + AC_PATH_PROG([GLIB_GENMARSHAL], [glib-genmarshal]) AM_PATH_PYTHON @@ -17,7 +19,7 @@ AM_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)]) AC_PATH_PROG(PYGTK_CODEGEN, pygtk-codegen-2.0, no) -PKG_CHECK_MODULES(EXT, pygtk-2.0 gtk+-2.0) +PKG_CHECK_MODULES(EXT, pygtk-2.0 gtk+-2.0 sm ice alsa) PYGTK_DEFSDIR=`$PKG_CONFIG --variable=defsdir pygtk-2.0` AC_SUBST(PYGTK_DEFSDIR) diff --git a/m4/gnome-compiler-flags.m4 b/m4/gnome-compiler-flags.m4 new file mode 100644 index 0000000..b9db2fd --- /dev/null +++ b/m4/gnome-compiler-flags.m4 @@ -0,0 +1,141 @@ +dnl GNOME_COMPILE_WARNINGS +dnl Turn on many useful compiler warnings +dnl For now, only works on GCC +AC_DEFUN([GNOME_COMPILE_WARNINGS],[ + dnl ****************************** + dnl More compiler warnings + dnl ****************************** + + AC_ARG_ENABLE(compile-warnings, + AC_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@], + [Turn on compiler warnings]),, + [enable_compile_warnings="m4_default([$1],[yes])"]) + + warnCFLAGS= + if test "x$GCC" != xyes; then + enable_compile_warnings=no + fi + + warning_flags= + realsave_CFLAGS="$CFLAGS" + + case "$enable_compile_warnings" in + no) + warning_flags= + ;; + minimum) + warning_flags="-Wall" + ;; + yes) + warning_flags="-Wall -Wmissing-prototypes" + ;; + maximum|error) + warning_flags="-Wall -Wmissing-prototypes -Wnested-externs -Wpointer-arith" + CFLAGS="$warning_flags $CFLAGS" + for option in -Wno-sign-compare; do + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $option" + AC_MSG_CHECKING([whether gcc understands $option]) + AC_TRY_COMPILE([], [], + has_option=yes, + has_option=no,) + CFLAGS="$SAVE_CFLAGS" + AC_MSG_RESULT($has_option) + if test $has_option = yes; then + warning_flags="$warning_flags $option" + fi + unset has_option + unset SAVE_CFLAGS + done + unset option + if test "$enable_compile_warnings" = "error" ; then + warning_flags="$warning_flags -Werror" + fi + ;; + *) + AC_MSG_ERROR(Unknown argument '$enable_compile_warnings' to --enable-compile-warnings) + ;; + esac + CFLAGS="$realsave_CFLAGS" + AC_MSG_CHECKING(what warning flags to pass to the C compiler) + AC_MSG_RESULT($warning_flags) + + AC_ARG_ENABLE(iso-c, + AC_HELP_STRING([--enable-iso-c], + [Try to warn if code is not ISO C ]),, + [enable_iso_c=no]) + + AC_MSG_CHECKING(what language compliance flags to pass to the C compiler) + complCFLAGS= + if test "x$enable_iso_c" != "xno"; then + if test "x$GCC" = "xyes"; then + case " $CFLAGS " in + *[\ \ ]-ansi[\ \ ]*) ;; + *) complCFLAGS="$complCFLAGS -ansi" ;; + esac + case " $CFLAGS " in + *[\ \ ]-pedantic[\ \ ]*) ;; + *) complCFLAGS="$complCFLAGS -pedantic" ;; + esac + fi + fi + AC_MSG_RESULT($complCFLAGS) + + WARN_CFLAGS="$warning_flags $complCFLAGS" + AC_SUBST(WARN_CFLAGS) +]) + +dnl For C++, do basically the same thing. + +AC_DEFUN([GNOME_CXX_WARNINGS],[ + AC_ARG_ENABLE(cxx-warnings, + AC_HELP_STRING([--enable-cxx-warnings=@<:@no/minimum/yes@:>@] + [Turn on compiler warnings.]),, + [enable_cxx_warnings="m4_default([$1],[minimum])"]) + + AC_MSG_CHECKING(what warning flags to pass to the C++ compiler) + warnCXXFLAGS= + if test "x$GXX" != xyes; then + enable_cxx_warnings=no + fi + if test "x$enable_cxx_warnings" != "xno"; then + if test "x$GXX" = "xyes"; then + case " $CXXFLAGS " in + *[\ \ ]-Wall[\ \ ]*) ;; + *) warnCXXFLAGS="-Wall -Wno-unused" ;; + esac + + ## -W is not all that useful. And it cannot be controlled + ## with individual -Wno-xxx flags, unlike -Wall + if test "x$enable_cxx_warnings" = "xyes"; then + warnCXXFLAGS="$warnCXXFLAGS -Wshadow -Woverloaded-virtual" + fi + fi + fi + AC_MSG_RESULT($warnCXXFLAGS) + + AC_ARG_ENABLE(iso-cxx, + AC_HELP_STRING([--enable-iso-cxx], + [Try to warn if code is not ISO C++ ]),, + [enable_iso_cxx=no]) + + AC_MSG_CHECKING(what language compliance flags to pass to the C++ compiler) + complCXXFLAGS= + if test "x$enable_iso_cxx" != "xno"; then + if test "x$GXX" = "xyes"; then + case " $CXXFLAGS " in + *[\ \ ]-ansi[\ \ ]*) ;; + *) complCXXFLAGS="$complCXXFLAGS -ansi" ;; + esac + + case " $CXXFLAGS " in + *[\ \ ]-pedantic[\ \ ]*) ;; + *) complCXXFLAGS="$complCXXFLAGS -pedantic" ;; + esac + fi + fi + AC_MSG_RESULT($complCXXFLAGS) + + WARN_CXXFLAGS="$CXXFLAGS $warnCXXFLAGS $complCXXFLAGS" + AC_SUBST(WARN_CXXFLAGS) +]) @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals = 2; plural=(n > 1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: sugar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2008-06-24 00:07+0530\n" -"PO-Revision-Date: 2008-08-07 09:05-0400\n" +"PO-Revision-Date: 2008-08-07 17:03-0400\n" "Last-Translator: Khaled Hosny <khaledhosny@eglug.org>\n" "Language-Team: Arabic <doc@arabeyes.org>\n" "MIME-Version: 1.0\n" @@ -133,8 +133,8 @@ msgstr[5] "%d سنة" msgid "%d month" msgid_plural "%d months" msgstr[0] "%d شهر" -msgstr[1] "%.sشهر" -msgstr[2] "%.sشهرين" +msgstr[1] "%.0sشهر" +msgstr[2] "%.0sشهرين" msgstr[3] "%d شهور" msgstr[4] "%d شهرا" msgstr[5] "%d شهر" @@ -144,8 +144,8 @@ msgstr[5] "%d شهر" msgid "%d week" msgid_plural "%d weeks" msgstr[0] "%d أسبوع" -msgstr[1] "%.sأسبوع" -msgstr[2] "%.sأسبوعين" +msgstr[1] "%.0sأسبوع" +msgstr[2] "%.0sأسبوعين" msgstr[3] "%d أسابيع" msgstr[4] "%d أسبوعا" msgstr[5] "%d أسبوع" @@ -155,8 +155,8 @@ msgstr[5] "%d أسبوع" msgid "%d day" msgid_plural "%d days" msgstr[0] "%d يوم" -msgstr[1] "%.sيوم" -msgstr[2] "%.sيومين" +msgstr[1] "%.0sيوم" +msgstr[2] "%.0sيومين" msgstr[3] "%d أيام" msgstr[4] "%d يوما" msgstr[5] "%d يوم" @@ -166,8 +166,8 @@ msgstr[5] "%d يوم" msgid "%d hour" msgid_plural "%d hours" msgstr[0] "%d ساعة" -msgstr[1] "%.sساعة" -msgstr[2] "%.sساعتين" +msgstr[1] "%.0sساعة" +msgstr[2] "%.0sساعتين" msgstr[3] "%d ساعات" msgstr[4] "%d ساعة" msgstr[5] "%d ساعة" @@ -177,8 +177,8 @@ msgstr[5] "%d ساعة" msgid "%d minute" msgid_plural "%d minutes" msgstr[0] "%d دقيقة" -msgstr[1] "%.sدقيقة" -msgstr[2] "%.sدقيقتين" +msgstr[1] "%.0sدقيقة" +msgstr[2] "%.0sدقيقتين" msgstr[3] "%d دقائق" msgstr[4] "%d دقيقة" msgstr[5] "%d دقيقة" @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 diff --git a/po/bn_IN.po b/po/bn_IN.po index 93a56e3..abbddbf 100644 --- a/po/bn_IN.po +++ b/po/bn_IN.po @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -2,152 +2,152 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. -#, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2008-06-24 00:07+0530\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"PO-Revision-Date: 2008-07-05 05:02-0400\n" +"Last-Translator: Γιάννης Κασκαμανίδης <ttnfy17@yahoo.gr>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Translate Toolkit 1.1.1rc4\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" +"X-Generator: Pootle 1.1.0rc2\n" #: ../src/sugar/activity/activity.py:120 msgid "Share with:" -msgstr "" +msgstr "Διαμοιρασμός με:" #: ../src/sugar/activity/activity.py:122 msgid "Private" -msgstr "" +msgstr "Ιδιωτικό" #: ../src/sugar/activity/activity.py:123 msgid "My Neighborhood" -msgstr "" +msgstr "Η γειτονιά μου" #: ../src/sugar/activity/activity.py:130 msgid "Keep" -msgstr "" +msgstr "Διατήρηση" #: ../src/sugar/activity/activity.py:136 msgid "Stop" -msgstr "" +msgstr "Διακοπή" #: ../src/sugar/activity/activity.py:251 msgid "Undo" -msgstr "" +msgstr "Αναίρεση" #: ../src/sugar/activity/activity.py:256 msgid "Redo" -msgstr "" +msgstr "Ακύρωση αναίρεσης" #: ../src/sugar/activity/activity.py:266 msgid "Copy" -msgstr "" +msgstr "Αντιγραφή" #: ../src/sugar/activity/activity.py:271 msgid "Paste" -msgstr "" +msgstr "Επικόλληση" #: ../src/sugar/activity/activity.py:297 msgid "Activity" -msgstr "" +msgstr "Δραστηριότητα" #: ../src/sugar/activity/activity.py:469 #, python-format msgid "%s Activity" -msgstr "" +msgstr "%s Δραστηριότητα" #: ../src/sugar/activity/activity.py:856 msgid "Keep error" -msgstr "" +msgstr "Το σφάλμα εξακολουθεί να υφίσταται" #: ../src/sugar/activity/activity.py:857 msgid "Keep error: all changes will be lost" -msgstr "" +msgstr "Το σφάλμα εξακολουθεί να υφίσταται: όλες οι αλλαγές θα χαθούν" #: ../src/sugar/activity/activity.py:860 msgid "Don't stop" -msgstr "" +msgstr "Αδυναμία διακοπής" #: ../src/sugar/activity/activity.py:863 msgid "Stop anyway" -msgstr "" +msgstr "Διακοπή παρ' όλα αυτά" #: ../src/sugar/graphics/alert.py:166 ../src/sugar/graphics/alert.py:209 msgid "Cancel" -msgstr "" +msgstr "Άκυρο" #: ../src/sugar/graphics/alert.py:170 ../src/sugar/graphics/alert.py:247 msgid "Ok" -msgstr "" +msgstr "Εντάξει" #: ../src/sugar/graphics/alert.py:219 msgid "Continue" -msgstr "" +msgstr "Συνέχεια" #: ../src/sugar/util.py:181 msgid " and " -msgstr "" +msgstr " και " #: ../src/sugar/util.py:182 msgid ", " -msgstr "" +msgstr ", " #. TRANS: Indicating something that just happened, eg. "just now", "moments ago" #: ../src/sugar/util.py:185 msgid "Seconds ago" -msgstr "" +msgstr "Δευτερόλεπτα πριν" #. TRANS: Indicating time passed, eg. "[10 day, 5 hours] ago", #. "[2 minutes] in the past", or "[3 years, 1 month] earlier" #: ../src/sugar/util.py:189 #, python-format msgid "%s ago" -msgstr "" +msgstr "%s πριν" #. TRANS: Relative dates (eg. 1 month and 5 days). #: ../src/sugar/util.py:202 #, python-format msgid "%d year" msgid_plural "%d years" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d έτος" +msgstr[1] "%d έτη" #: ../src/sugar/util.py:203 #, python-format msgid "%d month" msgid_plural "%d months" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d μήνας" +msgstr[1] "%d μήνες" #: ../src/sugar/util.py:204 #, python-format msgid "%d week" msgid_plural "%d weeks" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d εβδομάδα" +msgstr[1] "%d εβδομάδες" #: ../src/sugar/util.py:205 #, python-format msgid "%d day" msgid_plural "%d days" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d ημέρα" +msgstr[1] "%d ημέρες" #: ../src/sugar/util.py:206 #, python-format msgid "%d hour" msgid_plural "%d hours" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d ώρα" +msgstr[1] "%d ώρες" #: ../src/sugar/util.py:207 #, python-format msgid "%d minute" msgid_plural "%d minutes" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d λεπτό" +msgstr[1] "%d λεπτά" @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -7,12 +7,13 @@ msgstr "" "Project-Id-Version: olpc-sugar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2008-06-24 00:07+0530\n" -"PO-Revision-Date: 2008-06-19 03:16-0400\n" -"Last-Translator: Maria del Pilar Saenz Rodriguez <mapisaro@gmail.com>\n" +"PO-Revision-Date: 2008-07-20 14:39-0400\n" +"Last-Translator: Chema Q <jameson.quinn@gmail.com>\n" "Language-Team: Fedora Spanish <fedora-trans-es@redhat.com>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Pootle 1.1.0rc2\n" "X-Poedit-Language: Spanish\n" "X-Poedit-SourceCharset: utf-8\n" @@ -69,11 +70,11 @@ msgstr "Actividad %s" #: ../src/sugar/activity/activity.py:856 msgid "Keep error" -msgstr "Error de guardado" +msgstr "Error al guardar" #: ../src/sugar/activity/activity.py:857 msgid "Keep error: all changes will be lost" -msgstr "Error de guardado: todos los cambios se perderán" +msgstr "Error al guardar: todos los cambios se perderán" #: ../src/sugar/activity/activity.py:860 msgid "Don't stop" @@ -106,57 +107,60 @@ msgstr ", " #. TRANS: Indicating something that just happened, eg. "just now", "moments ago" #: ../src/sugar/util.py:185 msgid "Seconds ago" -msgstr "" +msgstr "Segundos atrás" +# I used an expression, not a literal translation, but I think it's OK. #. TRANS: Indicating time passed, eg. "[10 day, 5 hours] ago", #. "[2 minutes] in the past", or "[3 years, 1 month] earlier" #: ../src/sugar/util.py:189 #, python-format msgid "%s ago" -msgstr "" +msgstr "%s atrás" +# No entiendo porque colocaron el plural igual que el singular. +# Traduction: I don't know why somebody wrote the same for plural and singular traduction. #. TRANS: Relative dates (eg. 1 month and 5 days). #: ../src/sugar/util.py:202 -#, fuzzy, python-format +#, python-format msgid "%d year" msgid_plural "%d years" msgstr[0] "%d año" -msgstr[1] "%d año" +msgstr[1] "%d años" #: ../src/sugar/util.py:203 -#, fuzzy, python-format +#, python-format msgid "%d month" msgid_plural "%d months" msgstr[0] "%d mes" -msgstr[1] "%d mes" +msgstr[1] "%d meses" #: ../src/sugar/util.py:204 -#, fuzzy, python-format +#, python-format msgid "%d week" msgid_plural "%d weeks" msgstr[0] "%d semana" -msgstr[1] "%d semana" +msgstr[1] "%d semanas" #: ../src/sugar/util.py:205 -#, fuzzy, python-format +#, python-format msgid "%d day" msgid_plural "%d days" msgstr[0] "%d día" -msgstr[1] "%d día" +msgstr[1] "%d días" #: ../src/sugar/util.py:206 -#, fuzzy, python-format +#, python-format msgid "%d hour" msgid_plural "%d hours" msgstr[0] "%d hora" -msgstr[1] "%d hora" +msgstr[1] "%d horas" #: ../src/sugar/util.py:207 -#, fuzzy, python-format +#, python-format msgid "%d minute" msgid_plural "%d minutes" msgstr[0] "%d minuto" -msgstr[1] "%d minuto" +msgstr[1] "%d minutos" #~ msgid "Name:" #~ msgstr "Nombre:" @@ -622,23 +626,5 @@ msgstr[1] "%d minuto" #~ msgid "OK" #~ msgstr "OK" -#~ msgid "%d years" -#~ msgstr "%d años" - -#~ msgid "%d months" -#~ msgstr "%d meses" - -#~ msgid "%d weeks" -#~ msgstr "%d semanas" - -#~ msgid "%d days" -#~ msgstr "%d días" - -#~ msgid "%d hours" -#~ msgstr "%d horas" - -#~ msgid "%d minutes" -#~ msgstr "%d minutos" - #~ msgid "%d second" #~ msgstr "%d segundo" @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 diff --git a/po/fa_AF.po b/po/fa_AF.po index 93a56e3..fc6dbcd 100644 --- a/po/fa_AF.po +++ b/po/fa_AF.po @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -13,6 +13,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Pootle 1.1.0rc2\n" #: ../src/sugar/activity/activity.py:120 @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -2,152 +2,152 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. -#, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2008-06-24 00:07+0530\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"PO-Revision-Date: 2008-07-02 08:41-0400\n" +"Last-Translator: Jude Augusma <jayme2901@yahoo.com>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 msgid "Share with:" -msgstr "" +msgstr "Pataje ak:" #: ../src/sugar/activity/activity.py:122 msgid "Private" -msgstr "" +msgstr "Prive" #: ../src/sugar/activity/activity.py:123 msgid "My Neighborhood" -msgstr "" +msgstr "Vwazinaj mwen" #: ../src/sugar/activity/activity.py:130 msgid "Keep" -msgstr "" +msgstr "Kenbe" #: ../src/sugar/activity/activity.py:136 msgid "Stop" -msgstr "" +msgstr "Kanpe" #: ../src/sugar/activity/activity.py:251 msgid "Undo" -msgstr "" +msgstr "Defè" #: ../src/sugar/activity/activity.py:256 msgid "Redo" -msgstr "" +msgstr "Refè" #: ../src/sugar/activity/activity.py:266 msgid "Copy" -msgstr "" +msgstr "Kopye" #: ../src/sugar/activity/activity.py:271 msgid "Paste" -msgstr "" +msgstr "Pase" #: ../src/sugar/activity/activity.py:297 msgid "Activity" -msgstr "" +msgstr "Aktivite" #: ../src/sugar/activity/activity.py:469 #, python-format msgid "%s Activity" -msgstr "" +msgstr "%s Aktivite" #: ../src/sugar/activity/activity.py:856 msgid "Keep error" -msgstr "" +msgstr "Erè anrejistreman" #: ../src/sugar/activity/activity.py:857 msgid "Keep error: all changes will be lost" -msgstr "" +msgstr "Erè anrejistreman: Tout chanjman yo ap pèdi" #: ../src/sugar/activity/activity.py:860 msgid "Don't stop" -msgstr "" +msgstr "Pa kanpe" #: ../src/sugar/activity/activity.py:863 msgid "Stop anyway" -msgstr "" +msgstr "Kanpe kan menm" #: ../src/sugar/graphics/alert.py:166 ../src/sugar/graphics/alert.py:209 msgid "Cancel" -msgstr "" +msgstr "Anile" #: ../src/sugar/graphics/alert.py:170 ../src/sugar/graphics/alert.py:247 msgid "Ok" -msgstr "" +msgstr "Ok" #: ../src/sugar/graphics/alert.py:219 msgid "Continue" -msgstr "" +msgstr "Kontinye" #: ../src/sugar/util.py:181 msgid " and " -msgstr "" +msgstr "ak_" #: ../src/sugar/util.py:182 msgid ", " -msgstr "" +msgstr ",_" #. TRANS: Indicating something that just happened, eg. "just now", "moments ago" #: ../src/sugar/util.py:185 msgid "Seconds ago" -msgstr "" +msgstr "yon segond pase" #. TRANS: Indicating time passed, eg. "[10 day, 5 hours] ago", #. "[2 minutes] in the past", or "[3 years, 1 month] earlier" #: ../src/sugar/util.py:189 #, python-format msgid "%s ago" -msgstr "" +msgstr "Li gen %s" #. TRANS: Relative dates (eg. 1 month and 5 days). #: ../src/sugar/util.py:202 #, python-format msgid "%d year" msgid_plural "%d years" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d ane" +msgstr[1] "%d ane" #: ../src/sugar/util.py:203 #, python-format msgid "%d month" msgid_plural "%d months" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d mwa" +msgstr[1] "%d mwa" #: ../src/sugar/util.py:204 #, python-format msgid "%d week" msgid_plural "%d weeks" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d semèn" +msgstr[1] "%d semèn" #: ../src/sugar/util.py:205 #, python-format msgid "%d day" msgid_plural "%d days" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d jou" +msgstr[1] "%d jou" #: ../src/sugar/util.py:206 #, python-format msgid "%d hour" msgid_plural "%d hours" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d è" +msgstr[1] "%d è" #: ../src/sugar/util.py:207 #, python-format msgid "%d minute" msgid_plural "%d minutes" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d minit" +msgstr[1] "%d minit" @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -14,6 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -12,6 +12,7 @@ msgstr "" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Pootle 1.1.0rc2\n" @@ -7,12 +7,13 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2008-06-24 00:07+0530\n" -"PO-Revision-Date: 2008-07-27 09:55-0400\n" +"PO-Revision-Date: 2008-08-21 10:55-0400\n" "Last-Translator: korakurider <korakurider@gmail.com>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Pootle 1.1.0rc2\n" #: ../src/sugar/activity/activity.py:120 @@ -29,7 +30,7 @@ msgstr "私のお隣さん" #: ../src/sugar/activity/activity.py:130 msgid "Keep" -msgstr "残しておく" +msgstr "ジャーナルに保存" #: ../src/sugar/activity/activity.py:136 msgid "Stop" @@ -106,7 +107,7 @@ msgstr "ちょっと前" #: ../src/sugar/util.py:189 #, python-format msgid "%s ago" -msgstr "だけ前" +msgstr "%s前" #. TRANS: Relative dates (eg. 1 month and 5 days). #: ../src/sugar/util.py:202 @@ -13,6 +13,7 @@ msgstr "" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" +"Plural-Forms: nplurals=1; plural=0;\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" @@ -11,6 +11,7 @@ msgstr "" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" +"Plural-Forms: nplurals=1; plural=0 ;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -11,6 +11,7 @@ msgstr "" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" +"Plural-Forms: nplurals=2; plural=((n % 10 == 1 && n % 100 != 11) ? 0 : 1)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -11,6 +11,7 @@ msgstr "" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -13,6 +13,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Pootle 1.1.0rc2\n" #: ../src/sugar/activity/activity.py:120 @@ -12,6 +12,7 @@ msgstr "" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Pootle 1.1.0rc2\n" @@ -13,6 +13,7 @@ msgstr "" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" @@ -11,6 +11,7 @@ msgstr "" "Last-Translator: Kent Dahl <kentda@pvv.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" @@ -11,6 +11,7 @@ msgstr "" "Last-Translator: Bibek Kafle <oxese.eax@gmail.com>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Pootle 1.1.0rc2\n" @@ -58,7 +59,7 @@ msgstr "क्रियाकलाप" #: ../src/sugar/activity/activity.py:469 #, python-format msgid "%s Activity" -msgstr "%ऽ कृयाकलाप" +msgstr "%s कृयाकलाप" #: ../src/sugar/activity/activity.py:856 msgid "Keep error" @@ -10,6 +10,7 @@ msgstr "" "PO-Revision-Date: 2008-06-25 15:47-0400\n" "Last-Translator: Myckel Habets <myckel@sdf.lonestar.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -12,6 +12,7 @@ msgstr "" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" @@ -2,112 +2,112 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. -#, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2008-06-24 00:07+0530\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"PO-Revision-Date: 2008-06-28 09:54-0400\n" +"Last-Translator: Urso Wieske <uwieske@gmail.com>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Translate Toolkit 1.1.1rc4\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" +"X-Generator: Pootle 1.1.0rc2\n" #: ../src/sugar/activity/activity.py:120 msgid "Share with:" -msgstr "" +msgstr "Komparti ku:" #: ../src/sugar/activity/activity.py:122 msgid "Private" -msgstr "" +msgstr "Privá" #: ../src/sugar/activity/activity.py:123 msgid "My Neighborhood" -msgstr "" +msgstr "Mi Besindario" #: ../src/sugar/activity/activity.py:130 msgid "Keep" -msgstr "" +msgstr "Warda" #: ../src/sugar/activity/activity.py:136 msgid "Stop" -msgstr "" +msgstr "Para" #: ../src/sugar/activity/activity.py:251 msgid "Undo" -msgstr "" +msgstr "Deshasí" #: ../src/sugar/activity/activity.py:256 msgid "Redo" -msgstr "" +msgstr "Rehasí" #: ../src/sugar/activity/activity.py:266 msgid "Copy" -msgstr "" +msgstr "Kopia" #: ../src/sugar/activity/activity.py:271 msgid "Paste" -msgstr "" +msgstr "Pega" #: ../src/sugar/activity/activity.py:297 msgid "Activity" -msgstr "" +msgstr "Aktividad" #: ../src/sugar/activity/activity.py:469 #, python-format msgid "%s Activity" -msgstr "" +msgstr "%s Aktividad" #: ../src/sugar/activity/activity.py:856 msgid "Keep error" -msgstr "" +msgstr "Warda eror" #: ../src/sugar/activity/activity.py:857 msgid "Keep error: all changes will be lost" -msgstr "" +msgstr "Warda eror: tur kambionan lo bai perdí" #: ../src/sugar/activity/activity.py:860 msgid "Don't stop" -msgstr "" +msgstr "No para" #: ../src/sugar/activity/activity.py:863 msgid "Stop anyway" -msgstr "" +msgstr "Stop kon ku para" #: ../src/sugar/graphics/alert.py:166 ../src/sugar/graphics/alert.py:209 msgid "Cancel" -msgstr "" +msgstr "Kanselá" #: ../src/sugar/graphics/alert.py:170 ../src/sugar/graphics/alert.py:247 msgid "Ok" -msgstr "" +msgstr "Ok" #: ../src/sugar/graphics/alert.py:219 msgid "Continue" -msgstr "" +msgstr "Kontinua" #: ../src/sugar/util.py:181 msgid " and " -msgstr "" +msgstr "i " #: ../src/sugar/util.py:182 msgid ", " -msgstr "" +msgstr ", " #. TRANS: Indicating something that just happened, eg. "just now", "moments ago" #: ../src/sugar/util.py:185 msgid "Seconds ago" -msgstr "" +msgstr "Algun seconde pasá" #. TRANS: Indicating time passed, eg. "[10 day, 5 hours] ago", #. "[2 minutes] in the past", or "[3 years, 1 month] earlier" #: ../src/sugar/util.py:189 #, python-format msgid "%s ago" -msgstr "" +msgstr "%s pasá" #. TRANS: Relative dates (eg. 1 month and 5 days). #: ../src/sugar/util.py:202 @@ -11,6 +11,7 @@ msgstr "" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -11,6 +11,7 @@ msgstr "" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -10,6 +10,7 @@ msgstr "" "POT-Creation-Date: 2008-06-24 00:07+0530\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -2,152 +2,152 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. -#, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2008-06-24 00:07+0530\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"PO-Revision-Date: 2008-09-19 15:02-0400\n" +"Last-Translator: Eduardo H. Silva <HoboPrimate@gmail.com>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Translate Toolkit 1.1.1rc4\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Pootle 1.1.0rc2\n" #: ../src/sugar/activity/activity.py:120 msgid "Share with:" -msgstr "" +msgstr "Partilhar com:" #: ../src/sugar/activity/activity.py:122 msgid "Private" -msgstr "" +msgstr "Privado" #: ../src/sugar/activity/activity.py:123 msgid "My Neighborhood" -msgstr "" +msgstr "Minha Vizinhança" #: ../src/sugar/activity/activity.py:130 msgid "Keep" -msgstr "" +msgstr "Guardar uma cópia" #: ../src/sugar/activity/activity.py:136 msgid "Stop" -msgstr "" +msgstr "Parar" #: ../src/sugar/activity/activity.py:251 msgid "Undo" -msgstr "" +msgstr "Desfazer" #: ../src/sugar/activity/activity.py:256 msgid "Redo" -msgstr "" +msgstr "Refazer" #: ../src/sugar/activity/activity.py:266 msgid "Copy" -msgstr "" +msgstr "Copiar" #: ../src/sugar/activity/activity.py:271 msgid "Paste" -msgstr "" +msgstr "Colar" #: ../src/sugar/activity/activity.py:297 msgid "Activity" -msgstr "" +msgstr "Actividade" #: ../src/sugar/activity/activity.py:469 #, python-format msgid "%s Activity" -msgstr "" +msgstr "Actividade %s" #: ../src/sugar/activity/activity.py:856 msgid "Keep error" -msgstr "" +msgstr "Erro ao guardar" #: ../src/sugar/activity/activity.py:857 msgid "Keep error: all changes will be lost" -msgstr "" +msgstr "Erro ao guardar: todas as alterações serão perdidas" #: ../src/sugar/activity/activity.py:860 msgid "Don't stop" -msgstr "" +msgstr "Não parar" #: ../src/sugar/activity/activity.py:863 msgid "Stop anyway" -msgstr "" +msgstr "Parar mesmo assim" #: ../src/sugar/graphics/alert.py:166 ../src/sugar/graphics/alert.py:209 msgid "Cancel" -msgstr "" +msgstr "Cancelar" #: ../src/sugar/graphics/alert.py:170 ../src/sugar/graphics/alert.py:247 msgid "Ok" -msgstr "" +msgstr "Ok" #: ../src/sugar/graphics/alert.py:219 msgid "Continue" -msgstr "" +msgstr "Continuar" #: ../src/sugar/util.py:181 msgid " and " -msgstr "" +msgstr " e " #: ../src/sugar/util.py:182 msgid ", " -msgstr "" +msgstr ", " #. TRANS: Indicating something that just happened, eg. "just now", "moments ago" #: ../src/sugar/util.py:185 msgid "Seconds ago" -msgstr "" +msgstr "Segundos atrás" #. TRANS: Indicating time passed, eg. "[10 day, 5 hours] ago", #. "[2 minutes] in the past", or "[3 years, 1 month] earlier" #: ../src/sugar/util.py:189 #, python-format msgid "%s ago" -msgstr "" +msgstr "%s atrás" #. TRANS: Relative dates (eg. 1 month and 5 days). #: ../src/sugar/util.py:202 #, python-format msgid "%d year" msgid_plural "%d years" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d ano" +msgstr[1] "%d anos" #: ../src/sugar/util.py:203 #, python-format msgid "%d month" msgid_plural "%d months" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d mês" +msgstr[1] "%d meses" #: ../src/sugar/util.py:204 #, python-format msgid "%d week" msgid_plural "%d weeks" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d semana" +msgstr[1] "%d semanas" #: ../src/sugar/util.py:205 #, python-format msgid "%d day" msgid_plural "%d days" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d dia" +msgstr[1] "%d dias" #: ../src/sugar/util.py:206 #, python-format msgid "%d hour" msgid_plural "%d hours" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d hora" +msgstr[1] "%d horas" #: ../src/sugar/util.py:207 #, python-format msgid "%d minute" msgid_plural "%d minutes" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d minuto" +msgstr[1] "%d minutos" diff --git a/po/pt_BR.po b/po/pt_BR.po index 93a56e3..bf97bd6 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -2,14 +2,14 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. -#, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2008-06-24 00:07+0530\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"PO-Revision-Date: 2008-08-30 13:18+0200\n" +"Last-Translator: Juliano Bittencourt <juliano@lec.ufrgs.br>\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,136 +18,139 @@ msgstr "" #: ../src/sugar/activity/activity.py:120 msgid "Share with:" -msgstr "" +msgstr "Compartilhar com:" #: ../src/sugar/activity/activity.py:122 msgid "Private" -msgstr "" +msgstr "Privado" #: ../src/sugar/activity/activity.py:123 msgid "My Neighborhood" -msgstr "" +msgstr "Minha Vizinhança" #: ../src/sugar/activity/activity.py:130 msgid "Keep" -msgstr "" +msgstr "Guardar" #: ../src/sugar/activity/activity.py:136 msgid "Stop" -msgstr "" +msgstr "Parar" #: ../src/sugar/activity/activity.py:251 msgid "Undo" -msgstr "" +msgstr "Desfazer" #: ../src/sugar/activity/activity.py:256 msgid "Redo" -msgstr "" +msgstr "Refazer" #: ../src/sugar/activity/activity.py:266 msgid "Copy" -msgstr "" +msgstr "Copiar" #: ../src/sugar/activity/activity.py:271 msgid "Paste" -msgstr "" +msgstr "Colar" #: ../src/sugar/activity/activity.py:297 msgid "Activity" -msgstr "" +msgstr "Atividade" #: ../src/sugar/activity/activity.py:469 #, python-format msgid "%s Activity" -msgstr "" +msgstr "Atividade %s" #: ../src/sugar/activity/activity.py:856 msgid "Keep error" -msgstr "" +msgstr "Erro ao guardar" #: ../src/sugar/activity/activity.py:857 msgid "Keep error: all changes will be lost" -msgstr "" +msgstr "Erro ao guardar: todas as alterações serão perdidas" #: ../src/sugar/activity/activity.py:860 msgid "Don't stop" -msgstr "" +msgstr "Não pare" #: ../src/sugar/activity/activity.py:863 msgid "Stop anyway" -msgstr "" +msgstr "Parar de qualque forma" -#: ../src/sugar/graphics/alert.py:166 ../src/sugar/graphics/alert.py:209 +#: ../src/sugar/graphics/alert.py:166 +#: ../src/sugar/graphics/alert.py:209 msgid "Cancel" -msgstr "" +msgstr "Cancelar" -#: ../src/sugar/graphics/alert.py:170 ../src/sugar/graphics/alert.py:247 +#: ../src/sugar/graphics/alert.py:170 +#: ../src/sugar/graphics/alert.py:247 msgid "Ok" -msgstr "" +msgstr "Ok" #: ../src/sugar/graphics/alert.py:219 msgid "Continue" -msgstr "" +msgstr "Continuar" #: ../src/sugar/util.py:181 msgid " and " -msgstr "" +msgstr " e " #: ../src/sugar/util.py:182 msgid ", " -msgstr "" +msgstr ", " #. TRANS: Indicating something that just happened, eg. "just now", "moments ago" #: ../src/sugar/util.py:185 msgid "Seconds ago" -msgstr "" +msgstr "Segundos atrás" #. TRANS: Indicating time passed, eg. "[10 day, 5 hours] ago", #. "[2 minutes] in the past", or "[3 years, 1 month] earlier" #: ../src/sugar/util.py:189 #, python-format msgid "%s ago" -msgstr "" +msgstr "%s atrás" #. TRANS: Relative dates (eg. 1 month and 5 days). #: ../src/sugar/util.py:202 #, python-format msgid "%d year" msgid_plural "%d years" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d ano" +msgstr[1] "%d anos" #: ../src/sugar/util.py:203 #, python-format msgid "%d month" msgid_plural "%d months" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d mês" +msgstr[1] "%d meses" #: ../src/sugar/util.py:204 #, python-format msgid "%d week" msgid_plural "%d weeks" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d semana" +msgstr[1] "%d semanas" #: ../src/sugar/util.py:205 #, python-format msgid "%d day" msgid_plural "%d days" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d dia" +msgstr[1] "%d dias" #: ../src/sugar/util.py:206 #, python-format msgid "%d hour" msgid_plural "%d hours" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d hora" +msgstr[1] "%d horas" #: ../src/sugar/util.py:207 #, python-format msgid "%d minute" msgid_plural "%d minutes" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d minuto" +msgstr[1] "%d minutos" + @@ -12,6 +12,7 @@ msgstr "" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" @@ -12,6 +12,7 @@ msgstr "" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" +"Plural-Forms: nplurals=3; plural= (n == 1 ? 0: (((n % 100 > 19) || ((n % 100 == 0) && (n != 0))) ? 2: 1));\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" @@ -12,6 +12,7 @@ msgstr "" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10< =4 && (n%100<10 or n%100>=20) ? 1 : 2);\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" @@ -13,6 +13,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Pootle 1.1.0rc2\n" #: ../src/sugar/activity/activity.py:120 @@ -76,13 +77,11 @@ msgstr "Ntuhagarare" msgid "Stop anyway" msgstr "Hagarara muburyo bwose" -#: ../src/sugar/graphics/alert.py:166 -#: ../src/sugar/graphics/alert.py:209 +#: ../src/sugar/graphics/alert.py:166 ../src/sugar/graphics/alert.py:209 msgid "Cancel" msgstr "Kuraho" -#: ../src/sugar/graphics/alert.py:170 -#: ../src/sugar/graphics/alert.py:247 +#: ../src/sugar/graphics/alert.py:170 ../src/sugar/graphics/alert.py:247 msgid "Ok" msgstr "Nibyo" @@ -12,6 +12,7 @@ msgstr "" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" @@ -2,152 +2,152 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. -#, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2008-06-24 00:07+0530\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"PO-Revision-Date: 2008-07-18 06:59-0400\n" +"Last-Translator: Rashan Anushka <rashan.uoc@gmail.com>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Translate Toolkit 1.1.1rc4\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" +"X-Generator: Pootle 1.1.0rc2\n" #: ../src/sugar/activity/activity.py:120 msgid "Share with:" -msgstr "" +msgstr "බෙදාගත යුත්තේ:" #: ../src/sugar/activity/activity.py:122 msgid "Private" -msgstr "" +msgstr "පුද්ගලික" #: ../src/sugar/activity/activity.py:123 msgid "My Neighborhood" -msgstr "" +msgstr "මගේ වටපිටාව" #: ../src/sugar/activity/activity.py:130 msgid "Keep" -msgstr "" +msgstr "තබාගන්න" #: ../src/sugar/activity/activity.py:136 msgid "Stop" -msgstr "" +msgstr "නවත්වන්න" #: ../src/sugar/activity/activity.py:251 msgid "Undo" -msgstr "" +msgstr "නිශ්ප්රභ කරන්න" #: ../src/sugar/activity/activity.py:256 msgid "Redo" -msgstr "" +msgstr "යළි කරන්න" #: ../src/sugar/activity/activity.py:266 msgid "Copy" -msgstr "" +msgstr "පිටපත් කරන්න" #: ../src/sugar/activity/activity.py:271 msgid "Paste" -msgstr "" +msgstr "අලවන්න" #: ../src/sugar/activity/activity.py:297 msgid "Activity" -msgstr "" +msgstr "ක්රියාකාරකම" #: ../src/sugar/activity/activity.py:469 #, python-format msgid "%s Activity" -msgstr "" +msgstr "%s ක්රියාකාරකම" #: ../src/sugar/activity/activity.py:856 msgid "Keep error" -msgstr "" +msgstr "දෝශය තබාගන්න" #: ../src/sugar/activity/activity.py:857 msgid "Keep error: all changes will be lost" -msgstr "" +msgstr "දෝශය තබාගන්න: සියළු වෙනස්කිරීම් නැතිවනු ඇත" #: ../src/sugar/activity/activity.py:860 msgid "Don't stop" -msgstr "" +msgstr "නවත්වන්න එපා" #: ../src/sugar/activity/activity.py:863 msgid "Stop anyway" -msgstr "" +msgstr "කෙසේ හෝ නවත්වන්න" #: ../src/sugar/graphics/alert.py:166 ../src/sugar/graphics/alert.py:209 msgid "Cancel" -msgstr "" +msgstr "අවලංගු කරන්න" #: ../src/sugar/graphics/alert.py:170 ../src/sugar/graphics/alert.py:247 msgid "Ok" -msgstr "" +msgstr "හරි" #: ../src/sugar/graphics/alert.py:219 msgid "Continue" -msgstr "" +msgstr "පවත්වාගෙන යන්න" #: ../src/sugar/util.py:181 msgid " and " -msgstr "" +msgstr " හා " #: ../src/sugar/util.py:182 msgid ", " -msgstr "" +msgstr ", " #. TRANS: Indicating something that just happened, eg. "just now", "moments ago" #: ../src/sugar/util.py:185 msgid "Seconds ago" -msgstr "" +msgstr "තත්පර කිහිපයකට පෙර" #. TRANS: Indicating time passed, eg. "[10 day, 5 hours] ago", #. "[2 minutes] in the past", or "[3 years, 1 month] earlier" #: ../src/sugar/util.py:189 #, python-format msgid "%s ago" -msgstr "" +msgstr "%s ට පෙර" #. TRANS: Relative dates (eg. 1 month and 5 days). #: ../src/sugar/util.py:202 #, python-format msgid "%d year" msgid_plural "%d years" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "අවුරුද්දයි" +msgstr[1] "අවුරුදු %d " #: ../src/sugar/util.py:203 #, python-format msgid "%d month" msgid_plural "%d months" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "මාසයයි" +msgstr[1] "මාස %d" #: ../src/sugar/util.py:204 #, python-format msgid "%d week" msgid_plural "%d weeks" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "සතියයි" +msgstr[1] "සති %d" #: ../src/sugar/util.py:205 #, python-format msgid "%d day" msgid_plural "%d days" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "දවසයි" +msgstr[1] "දවස් %d" #: ../src/sugar/util.py:206 #, python-format msgid "%d hour" msgid_plural "%d hours" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "පැයයි" +msgstr[1] "පැය %d" #: ../src/sugar/util.py:207 #, python-format msgid "%d minute" msgid_plural "%d minutes" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "මිනිත්තුවයි" +msgstr[1] "මිනිත්තු %d" @@ -13,6 +13,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || " +"n%100==4 ? 3 : 0);\n" "X-Generator: Pootle 1.1.0rc2\n" #: ../src/sugar/activity/activity.py:120 @@ -13,6 +13,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" #: ../src/sugar/activity/activity.py:120 @@ -76,13 +77,11 @@ msgstr "ఆపవద్దు" msgid "Stop anyway" msgstr "ఏదేమైనా ఆపువేయి" -#: ../src/sugar/graphics/alert.py:166 -#: ../src/sugar/graphics/alert.py:209 +#: ../src/sugar/graphics/alert.py:166 ../src/sugar/graphics/alert.py:209 msgid "Cancel" msgstr "రద్దు చేయి" -#: ../src/sugar/graphics/alert.py:170 -#: ../src/sugar/graphics/alert.py:247 +#: ../src/sugar/graphics/alert.py:170 ../src/sugar/graphics/alert.py:247 msgid "Ok" msgstr "సరి" @@ -12,6 +12,7 @@ msgstr "" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" +"Plural-Forms: nplurals=1; plural=0;\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" @@ -12,6 +12,7 @@ msgstr "" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" @@ -2,152 +2,153 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. -#, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2008-06-24 00:07+0530\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"PO-Revision-Date: 2008-08-28 07:53-0400\n" +"Last-Translator: abdullah kocabas <abdullah.kocabas@abcdizustu.com>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Translate Toolkit 1.1.1rc4\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" +"X-Generator: Pootle 1.1.0rc2\n" #: ../src/sugar/activity/activity.py:120 msgid "Share with:" -msgstr "" +msgstr "paylaşınız." #: ../src/sugar/activity/activity.py:122 msgid "Private" -msgstr "" +msgstr "özel" #: ../src/sugar/activity/activity.py:123 msgid "My Neighborhood" -msgstr "" +msgstr "komşularım" #: ../src/sugar/activity/activity.py:130 msgid "Keep" -msgstr "" +msgstr "kaydediniz." #: ../src/sugar/activity/activity.py:136 msgid "Stop" -msgstr "" +msgstr "durdurunuz." #: ../src/sugar/activity/activity.py:251 msgid "Undo" -msgstr "" +msgstr "geri alınız." #: ../src/sugar/activity/activity.py:256 msgid "Redo" -msgstr "" +msgstr "yeniden yapınız." #: ../src/sugar/activity/activity.py:266 msgid "Copy" -msgstr "" +msgstr "kopyalayınız." #: ../src/sugar/activity/activity.py:271 msgid "Paste" -msgstr "" +msgstr "yapıştırınız." #: ../src/sugar/activity/activity.py:297 msgid "Activity" -msgstr "" +msgstr "etkinlik" #: ../src/sugar/activity/activity.py:469 #, python-format msgid "%s Activity" -msgstr "" +msgstr "%s etkinlik" #: ../src/sugar/activity/activity.py:856 msgid "Keep error" -msgstr "" +msgstr "hatayı saklayınız." #: ../src/sugar/activity/activity.py:857 msgid "Keep error: all changes will be lost" -msgstr "" +msgstr "hata devam ediyor, tüm değişiklikleriniz silinecektir." #: ../src/sugar/activity/activity.py:860 msgid "Don't stop" -msgstr "" +msgstr "durmayınız." #: ../src/sugar/activity/activity.py:863 msgid "Stop anyway" -msgstr "" +msgstr "mutlaka durunuz." #: ../src/sugar/graphics/alert.py:166 ../src/sugar/graphics/alert.py:209 msgid "Cancel" -msgstr "" +msgstr "iptal ediniz." #: ../src/sugar/graphics/alert.py:170 ../src/sugar/graphics/alert.py:247 msgid "Ok" -msgstr "" +msgstr "tamam" #: ../src/sugar/graphics/alert.py:219 msgid "Continue" -msgstr "" +msgstr "devam ediniz." #: ../src/sugar/util.py:181 msgid " and " -msgstr "" +msgstr "ve" #: ../src/sugar/util.py:182 msgid ", " -msgstr "" +msgstr ",_" #. TRANS: Indicating something that just happened, eg. "just now", "moments ago" #: ../src/sugar/util.py:185 msgid "Seconds ago" -msgstr "" +msgstr "saniye önce" #. TRANS: Indicating time passed, eg. "[10 day, 5 hours] ago", #. "[2 minutes] in the past", or "[3 years, 1 month] earlier" #: ../src/sugar/util.py:189 #, python-format msgid "%s ago" -msgstr "" +msgstr "%s önce" #. TRANS: Relative dates (eg. 1 month and 5 days). #: ../src/sugar/util.py:202 #, python-format msgid "%d year" msgid_plural "%d years" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d yıl" +msgstr[1] "%d yıllar" #: ../src/sugar/util.py:203 #, python-format msgid "%d month" msgid_plural "%d months" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d ay" +msgstr[1] "%d aylar" #: ../src/sugar/util.py:204 #, python-format msgid "%d week" msgid_plural "%d weeks" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d hafta" +msgstr[1] "%d haftalar" #: ../src/sugar/util.py:205 #, python-format msgid "%d day" msgid_plural "%d days" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d gün" +msgstr[1] "%d günler" #: ../src/sugar/util.py:206 #, python-format msgid "%d hour" msgid_plural "%d hours" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d saat" +msgstr[1] "%d saatler" #: ../src/sugar/util.py:207 #, python-format msgid "%d minute" msgid_plural "%d minutes" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d dakika" +msgstr[1] "%d dakikalar" + @@ -11,6 +11,7 @@ msgstr "" "Last-Translator: salman minhas <sulmanminhas@gmail.com>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Pootle 1.1.0rc2\n" @@ -2,152 +2,147 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. -#, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2008-06-24 00:07+0530\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"PO-Revision-Date: 2008-07-02 08:40-0400\n" +"Last-Translator: Clytie Siddall <clytie@riverland.net.au>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Translate Toolkit 1.1.1rc4\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Pootle 1.1.0rc2\n" #: ../src/sugar/activity/activity.py:120 msgid "Share with:" -msgstr "" +msgstr "Chia sẻ với:" #: ../src/sugar/activity/activity.py:122 msgid "Private" -msgstr "" +msgstr "Riêng" #: ../src/sugar/activity/activity.py:123 msgid "My Neighborhood" -msgstr "" +msgstr "Hàng xóm mình" #: ../src/sugar/activity/activity.py:130 msgid "Keep" -msgstr "" +msgstr "Giữ" #: ../src/sugar/activity/activity.py:136 msgid "Stop" -msgstr "" +msgstr "Dừng" #: ../src/sugar/activity/activity.py:251 msgid "Undo" -msgstr "" +msgstr "Hủy bước" #: ../src/sugar/activity/activity.py:256 msgid "Redo" -msgstr "" +msgstr "Hoàn lại" #: ../src/sugar/activity/activity.py:266 msgid "Copy" -msgstr "" +msgstr "Chép" #: ../src/sugar/activity/activity.py:271 msgid "Paste" -msgstr "" +msgstr "Dán" #: ../src/sugar/activity/activity.py:297 msgid "Activity" -msgstr "" +msgstr "Hoạt động" #: ../src/sugar/activity/activity.py:469 #, python-format msgid "%s Activity" -msgstr "" +msgstr "Hoạt động %s" #: ../src/sugar/activity/activity.py:856 msgid "Keep error" -msgstr "" +msgstr "Giữ lỗi" #: ../src/sugar/activity/activity.py:857 msgid "Keep error: all changes will be lost" -msgstr "" +msgstr "Giữ lỗi: tất cả các thay đổi sẽ bị mất" #: ../src/sugar/activity/activity.py:860 msgid "Don't stop" -msgstr "" +msgstr "Không dừng" #: ../src/sugar/activity/activity.py:863 msgid "Stop anyway" -msgstr "" +msgstr "Vẫn dừng" #: ../src/sugar/graphics/alert.py:166 ../src/sugar/graphics/alert.py:209 msgid "Cancel" -msgstr "" +msgstr "Thôi" #: ../src/sugar/graphics/alert.py:170 ../src/sugar/graphics/alert.py:247 msgid "Ok" -msgstr "" +msgstr "OK" #: ../src/sugar/graphics/alert.py:219 msgid "Continue" -msgstr "" +msgstr "Tiếp" +# Không cần từ. No word needed. #: ../src/sugar/util.py:181 msgid " and " -msgstr "" +msgstr " " #: ../src/sugar/util.py:182 msgid ", " -msgstr "" +msgstr ", " #. TRANS: Indicating something that just happened, eg. "just now", "moments ago" #: ../src/sugar/util.py:185 msgid "Seconds ago" -msgstr "" +msgstr "Giây trước" #. TRANS: Indicating time passed, eg. "[10 day, 5 hours] ago", #. "[2 minutes] in the past", or "[3 years, 1 month] earlier" #: ../src/sugar/util.py:189 #, python-format msgid "%s ago" -msgstr "" +msgstr "%s trước" #. TRANS: Relative dates (eg. 1 month and 5 days). #: ../src/sugar/util.py:202 #, python-format msgid "%d year" msgid_plural "%d years" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d năm" #: ../src/sugar/util.py:203 #, python-format msgid "%d month" msgid_plural "%d months" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d tháng" #: ../src/sugar/util.py:204 #, python-format msgid "%d week" msgid_plural "%d weeks" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d tuần" #: ../src/sugar/util.py:205 #, python-format msgid "%d day" msgid_plural "%d days" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d ngày" #: ../src/sugar/util.py:206 #, python-format msgid "%d hour" msgid_plural "%d hours" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d giờ" #: ../src/sugar/util.py:207 #, python-format msgid "%d minute" msgid_plural "%d minutes" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d phút" @@ -12,6 +12,7 @@ msgstr "" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" diff --git a/po/zh_CN.po b/po/zh_CN.po index 93a56e3..fa67c13 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -12,6 +12,7 @@ msgstr "" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" +"Plural-Forms: nplurals=1; plural=0;\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Translate Toolkit 1.1.1rc4\n" diff --git a/po/zh_TW.po b/po/zh_TW.po index ab47f70..ac0c379 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -11,6 +11,7 @@ msgstr "" "Last-Translator: Yuan Chao <yuanchao@gmail.com>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" +"Plural-Forms: nplurals=1; plural=0;\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Pootle 1.1.0rc2\n" diff --git a/src/sugar/Makefile.am b/src/sugar/Makefile.am index ef91efe..ef7e634 100644 --- a/src/sugar/Makefile.am +++ b/src/sugar/Makefile.am @@ -14,6 +14,8 @@ pkgpyexecdir = $(pythondir)/sugar pkgpyexec_LTLIBRARIES = _sugarext.la _sugarext_la_CFLAGS = \ + -DHAVE_ALSA \ + $(WARN_CFLAGS) \ $(EXT_CFLAGS) \ $(PYTHON_INCLUDES) @@ -23,6 +25,10 @@ _sugarext_la_LIBADD = $(EXT_LIBS) -lSM -lICE _sugarext_la_SOURCES = \ $(BUILT_SOURCES) \ _sugarextmodule.c \ + acme-volume.h \ + acme-volume.c \ + acme-volume-alsa.h \ + acme-volume-alsa.c \ gsm-app.h \ gsm-app.c \ gsm-client.h \ @@ -45,6 +51,8 @@ _sugarext_la_SOURCES = \ sexy-icon-entry.c \ sugar-address-entry.c \ sugar-address-entry.h \ + sugar-grid.c \ + sugar-grid.h \ sugar-key-grabber.c \ sugar-key-grabber.h \ sugar-menu.h \ @@ -63,7 +71,6 @@ _sugarext.c: _sugarext.defs _sugarext.override (cd $(srcdir)\ && $(PYGTK_CODEGEN) \ --register $(PYGTK_DEFSDIR)/gdk-types.defs \ - --register $(PYGTK_DEFSDIR)/gdk-types.defs \ --register $(PYGTK_DEFSDIR)/gtk-types.defs \ --override $*.override \ --prefix py$* $*.defs) > gen-$*.c \ diff --git a/src/sugar/_sugarext.defs b/src/sugar/_sugarext.defs index 6e741dc..32ea18a 100644 --- a/src/sugar/_sugarext.defs +++ b/src/sugar/_sugarext.defs @@ -22,6 +22,13 @@ (gtype-id "SUGAR_TYPE_MENU") ) +(define-object Grid + (in-module "Sugar") + (parent "GObject") + (c-name "SugarGrid") + (gtype-id "SUGAR_TYPE_GRID") +) + (define-object Preview (in-module "Sugar") (parent "GObject") @@ -57,6 +64,20 @@ (gtype-id "GSM_TYPE_SESSION") ) +(define-object Volume + (in-module "Acme") + (parent "GObject") + (c-name "AcmeVolume") + (gtype-id "ACME_TYPE_VOLUME") +) + +(define-object VolumeAlsa + (in-module "Acme") + (parent "AcmeVolume") + (c-name "AcmeVolumeAlsa") + (gtype-id "ACME_TYPE_VOLUME_ALSA") +) + ;; Enumerations and flags ... (define-enum IconEntryPosition @@ -95,6 +116,45 @@ (return-type "none") ) +;; From sugar-grid.h + +(define-method setup + (of-object "SugarGrid") + (c-name "sugar_grid_setup") + (return-type "none") + (parameters + '("gint" "width") + '("gint" "height") + ) +) + +(define-method add_weight + (of-object "SugarGrid") + (c-name "sugar_grid_add_weight") + (return-type "none") + (parameters + '("GdkRectangle*" "rect") + ) +) + +(define-method remove_weight + (of-object "SugarGrid") + (c-name "sugar_grid_remove_weight") + (return-type "none") + (parameters + '("GdkRectangle*" "rect") + ) +) + +(define-method compute_weight + (of-object "SugarGrid") + (c-name "sugar_grid_compute_weight") + (return-type "guint") + (parameters + '("GdkRectangle*" "rect") + ) +) + ;; From sugar-key-grabber.h (define-function sugar_key_grabber_get_type @@ -200,7 +260,7 @@ (c-name "sugar_preview_take_screenshot") (return-type "none") (parameters - '("GdkDrawable" "drawable") + '("GtkWidget" "widget") ) ) @@ -345,3 +405,57 @@ (return-type "GsmSession*") ) +;; From acme-volume.h + +(define-function acme_volume_get_type + (c-name "acme_volume_get_type") + (return-type "GType") +) + +(define-method get_volume + (of-object "AcmeVolume") + (c-name "acme_volume_get_volume") + (return-type "int") +) + +(define-method set_volume + (of-object "AcmeVolume") + (c-name "acme_volume_set_volume") + (return-type "none") + (parameters + '("int" "val") + ) +) + +(define-method get_mute + (of-object "AcmeVolume") + (c-name "acme_volume_get_mute") + (return-type "gboolean") +) + +(define-method set_mute + (of-object "AcmeVolume") + (c-name "acme_volume_set_mute") + (return-type "none") + (parameters + '("gboolean" "val") + ) +) + +(define-method mute_toggle + (of-object "AcmeVolume") + (c-name "acme_volume_mute_toggle") + (return-type "none") +) + +(define-method get_threshold + (of-object "AcmeVolume") + (c-name "acme_volume_get_threshold") + (return-type "int") +) + +(define-function acme_volume_new + (c-name "acme_volume_new") + (is-constructor-of "AcmeVolume") + (return-type "AcmeVolume*") +) diff --git a/src/sugar/_sugarext.override b/src/sugar/_sugarext.override index db49e27..5a0608d 100644 --- a/src/sugar/_sugarext.override +++ b/src/sugar/_sugarext.override @@ -5,13 +5,15 @@ headers #include "pygobject.h" #include "sugar-address-entry.h" +#include "sugar-grid.h" #include "sugar-key-grabber.h" #include "sugar-menu.h" #include "sugar-preview.h" #include "sexy-icon-entry.h" #include "gsm-session.h" +#include "gsm-xsmp.h" +#include "acme-volume-alsa.h" -#define EGG_SM_CLIENT_BACKEND_XSMP #include "eggsmclient.h" #include "eggsmclient-private.h" @@ -22,11 +24,11 @@ headers modulename sugar._sugarext %% import gobject.GObject as PyGObject_Type +import gtk.Widget as PyGtkWidget_Type import gtk.Entry as PyGtkEntry_Type import gtk.Menu as PyGtkMenu_Type import gtk.Container as PyGtkContainer_Type import gtk.gdk.Window as PyGdkWindow_Type -import gtk.gdk.Drawable as PyGdkDrawable_Type import gtk.Image as PyGtkImage_Type %% ignore-glob diff --git a/src/sugar/_sugarextmodule.c b/src/sugar/_sugarextmodule.c index 6f6af6d..1bb8545 100644 --- a/src/sugar/_sugarextmodule.c +++ b/src/sugar/_sugarextmodule.c @@ -23,6 +23,7 @@ /* include this first, before NO_IMPORT_PYGOBJECT is defined */ #include <pygobject.h> +#include <pygtk/pygtk.h> extern PyMethodDef py_sugarext_functions[]; @@ -34,12 +35,13 @@ init_sugarext(void) { PyObject *m, *d; - init_pygobject (); + init_pygobject(); + init_pygtk(); - m = Py_InitModule ("_sugarext", py_sugarext_functions); - d = PyModule_GetDict (m); + m = Py_InitModule("_sugarext", py_sugarext_functions); + d = PyModule_GetDict(m); - py_sugarext_register_classes (d); + py_sugarext_register_classes(d); py_sugarext_add_constants(m, "SEXY_"); if (PyErr_Occurred ()) { diff --git a/src/sugar/acme-volume-alsa.c b/src/sugar/acme-volume-alsa.c new file mode 100644 index 0000000..c1ea5cc --- /dev/null +++ b/src/sugar/acme-volume-alsa.c @@ -0,0 +1,317 @@ +/* acme-volume-alsa.c + + Copyright (C) 2002, 2003 Bastien Nocera + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Bastien Nocera <hadess@hadess.net> + */ + +#ifdef HAVE_CONFIG +#include "config.h" +#endif + +#include "acme-volume-alsa.h" + +#include <alsa/asoundlib.h> + +#ifndef DEFAULT_CARD +#define DEFAULT_CARD "default" +#endif + +#undef LOG +#ifdef LOG +#define D(x...) g_message (x) +#else +#define D(x...) +#endif + +#define ROUND(x) ((x - (int)x > 0.5) ? x+1 : x) + +struct AcmeVolumeAlsaPrivate +{ + long pmin, pmax; + gboolean has_mute, has_master; + snd_mixer_t *handle; + snd_mixer_elem_t *elem; + int saved_volume; + guint timer_id; +}; + +static int acme_volume_alsa_get_volume (AcmeVolume *self); +static void acme_volume_alsa_set_volume (AcmeVolume *self, int val); +static gboolean acme_volume_alsa_open (AcmeVolumeAlsa *self); +static void acme_volume_alsa_close (AcmeVolumeAlsa *self); +static gboolean acme_volume_alsa_close_real (AcmeVolumeAlsa *self); + +G_DEFINE_TYPE (AcmeVolumeAlsa, acme_volume_alsa, ACME_TYPE_VOLUME) + +static void +acme_volume_alsa_finalize (GObject *object) +{ + AcmeVolumeAlsa *self; + + self = ACME_VOLUME_ALSA (object); + + if (self->_priv) + { + if (self->_priv->timer_id != 0) + { + g_source_remove (self->_priv->timer_id); + self->_priv->timer_id = 0; + } + + acme_volume_alsa_close_real (self); + g_free (self->_priv); + self->_priv = NULL; + } + + G_OBJECT_CLASS (acme_volume_alsa_parent_class)->finalize (object); +} + +static void +acme_volume_alsa_set_mute (AcmeVolume *vol, gboolean val) +{ + AcmeVolumeAlsa *self = (AcmeVolumeAlsa *) vol; + + if (acme_volume_alsa_open (self) == FALSE) + return; + + /* If we have a hardware mute */ + if (self->_priv->has_mute) + { + snd_mixer_selem_set_playback_switch_all + (self->_priv->elem, !val); + acme_volume_alsa_close (self); + return; + } + + acme_volume_alsa_close (self); + + /* If we don't */ + if (val == TRUE) + { + self->_priv->saved_volume = acme_volume_alsa_get_volume (vol); + acme_volume_alsa_set_volume (vol, 0); + } else { + if (self->_priv->saved_volume != -1) + acme_volume_alsa_set_volume (vol, + self->_priv->saved_volume); + } +} + +static gboolean +acme_volume_alsa_get_mute (AcmeVolume *vol) +{ + AcmeVolumeAlsa *self = (AcmeVolumeAlsa *) vol; + int ival; + + if (acme_volume_alsa_open (self) == FALSE) + return FALSE; + + if (self->_priv->has_mute) + { + snd_mixer_selem_get_playback_switch(self->_priv->elem, + SND_MIXER_SCHN_FRONT_LEFT, &ival); + + acme_volume_alsa_close (self); + + return !ival; + } else { + acme_volume_alsa_close (self); + + return (acme_volume_alsa_get_volume (vol) == 0); + } +} + +static int +acme_volume_alsa_get_volume (AcmeVolume *vol) +{ + AcmeVolumeAlsa *self = (AcmeVolumeAlsa *) vol; + long lval, rval; + int tmp; + float alsa_vol; + + if (acme_volume_alsa_open (self) == FALSE) + return 0; + + snd_mixer_selem_get_playback_volume(self->_priv->elem, + SND_MIXER_SCHN_FRONT_LEFT, &lval); + snd_mixer_selem_get_playback_volume(self->_priv->elem, + SND_MIXER_SCHN_FRONT_RIGHT, &rval); + + acme_volume_alsa_close (self); + + alsa_vol = (lval + rval) / 2; + alsa_vol = alsa_vol * 100 / (self->_priv->pmax - self->_priv->pmin); + tmp = ROUND (alsa_vol); + + return tmp; +} + +static void +acme_volume_alsa_set_volume (AcmeVolume *vol, int val) +{ + AcmeVolumeAlsa *self = (AcmeVolumeAlsa *) vol; + float volume; + int tmp; + + if (acme_volume_alsa_open (self) == FALSE) + return; + + volume = (float) val / 100 * (self->_priv->pmax - self->_priv->pmin); + volume = CLAMP (volume, self->_priv->pmin, self->_priv->pmax); + tmp = ROUND (volume); + + snd_mixer_selem_set_playback_volume_all (self->_priv->elem, tmp); + + acme_volume_alsa_close (self); +} + +static int +acme_volume_alsa_get_threshold (AcmeVolume *vol) +{ + AcmeVolumeAlsa *self = (AcmeVolumeAlsa *) vol; + int steps; + + if (acme_volume_alsa_open (self) == FALSE) + return 1; + + acme_volume_alsa_close (self); + + steps = self->_priv->pmax - self->_priv->pmin; + return (steps > 0) ? 100 / steps + 1 : 1; +} + +static gboolean +acme_volume_alsa_close_real (AcmeVolumeAlsa *self) +{ + if (self->_priv == NULL) + return FALSE; + + if (self->_priv->handle != NULL) + { + snd_mixer_detach (self->_priv->handle, DEFAULT_CARD); + snd_mixer_free (self->_priv->handle); + self->_priv->handle = NULL; + self->_priv->elem = NULL; + } + + self->_priv->timer_id = 0; + + return FALSE; +} + +static gboolean +acme_volume_alsa_open (AcmeVolumeAlsa *self) +{ + snd_mixer_selem_id_t *sid; + snd_mixer_t *handle; + snd_mixer_elem_t *elem; + + if (self->_priv->timer_id != 0) + { + g_source_remove (self->_priv->timer_id); + self->_priv->timer_id = 0; + return TRUE; + } + + /* open the mixer */ + if (snd_mixer_open (&handle, 0) < 0) + { + D("snd_mixer_open"); + return FALSE; + } + /* attach the handle to the default card */ + if (snd_mixer_attach (handle, DEFAULT_CARD) <0) + { + D("snd_mixer_attach"); + goto bail; + } + /* ? */ + if (snd_mixer_selem_register (handle, NULL, NULL) < 0) + { + D("snd_mixer_selem_register"); + goto bail; + } + if (snd_mixer_load (handle) < 0) + { + D("snd_mixer_load"); + goto bail; + } + + snd_mixer_selem_id_alloca (&sid); + snd_mixer_selem_id_set_name (sid, "Master"); + elem = snd_mixer_find_selem (handle, sid); + if (!elem) + { + snd_mixer_selem_id_alloca (&sid); + snd_mixer_selem_id_set_name (sid, "PCM"); + elem = snd_mixer_find_selem (handle, sid); + if (!elem) + { + D("snd_mixer_find_selem"); + goto bail; + } + } + + if (!snd_mixer_selem_has_playback_volume (elem)) + { + D("snd_mixer_selem_has_playback_volume"); + goto bail; + } + + snd_mixer_selem_get_playback_volume_range (elem, + &(self->_priv->pmin), + &(self->_priv->pmax)); + + self->_priv->has_mute = snd_mixer_selem_has_playback_switch (elem); + self->_priv->handle = handle; + self->_priv->elem = elem; + + return TRUE; + +bail: + acme_volume_alsa_close_real (self); + return FALSE; +} + +static void +acme_volume_alsa_close (AcmeVolumeAlsa *self) +{ + self->_priv->timer_id = g_timeout_add (4000, + (GSourceFunc) acme_volume_alsa_close_real, self); +} + +static void +acme_volume_alsa_init (AcmeVolumeAlsa *self) +{ + self->_priv = g_new0 (AcmeVolumeAlsaPrivate, 1); +} + +static void +acme_volume_alsa_class_init (AcmeVolumeAlsaClass *klass) +{ + AcmeVolumeClass *volume_class = ACME_VOLUME_CLASS (klass); + G_OBJECT_CLASS (klass)->finalize = acme_volume_alsa_finalize; + + volume_class->set_volume = acme_volume_alsa_set_volume; + volume_class->get_volume = acme_volume_alsa_get_volume; + volume_class->set_mute = acme_volume_alsa_set_mute; + volume_class->get_mute = acme_volume_alsa_get_mute; + volume_class->get_threshold = acme_volume_alsa_get_threshold; +} + diff --git a/src/sugar/acme-volume-alsa.h b/src/sugar/acme-volume-alsa.h new file mode 100644 index 0000000..b179a24 --- /dev/null +++ b/src/sugar/acme-volume-alsa.h @@ -0,0 +1,47 @@ +/* acme-volume-alsa.h + + Copyright (C) 2002, 2003 Bastien Nocera + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Bastien Nocera <hadess@hadess.net> + */ + +#include <glib.h> +#include <glib-object.h> +#include "acme-volume.h" + +#define ACME_TYPE_VOLUME_ALSA (acme_volume_alsa_get_type ()) +#define ACME_VOLUME_ALSA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ACME_TYPE_VOLUME_ALSA, AcmeVolumeAlsa)) +#define ACME_VOLUME_ALSA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ACME_TYPE_VOLUME_ALSA, AcmeVolumeAlsaClass)) +#define ACME_IS_VOLUME_ALSA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ACME_TYPE_VOLUME_ALSA)) +#define ACME_VOLUME_ALSA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ACME_TYPE_VOLUME_ALSA, AcmeVolumeAlsaClass)) + +typedef struct AcmeVolumeAlsa AcmeVolumeAlsa; +typedef struct AcmeVolumeAlsaClass AcmeVolumeAlsaClass; +typedef struct AcmeVolumeAlsaPrivate AcmeVolumeAlsaPrivate; + +struct AcmeVolumeAlsa { + AcmeVolume parent; + AcmeVolumeAlsaPrivate *_priv; +}; + +struct AcmeVolumeAlsaClass { + AcmeVolumeClass parent; +}; + +GType acme_volume_alsa_get_type (void); + diff --git a/src/sugar/acme-volume.c b/src/sugar/acme-volume.c new file mode 100644 index 0000000..09ae1d2 --- /dev/null +++ b/src/sugar/acme-volume.c @@ -0,0 +1,127 @@ +/* acme-volume.c + + Copyright (C) 2002, 2003 Bastien Nocera + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Bastien Nocera <hadess@hadess.net> + */ + +#ifdef HAVE_CONFIG +#include "config.h" +#endif +#include "acme-volume.h" +#ifdef HAVE_OSS +#include "acme-volume-oss.h" +#endif +#ifdef HAVE_ALSA +#include "acme-volume-alsa.h" +#endif +#ifdef HAVE_GSTREAMER +#include "acme-volume-gstreamer.h" +#endif + +G_DEFINE_TYPE (AcmeVolume, acme_volume, G_TYPE_OBJECT) + +static void +acme_volume_class_init (AcmeVolumeClass *klass) +{ +} + +static void +acme_volume_init (AcmeVolume *vol) +{ +} + +int +acme_volume_get_volume (AcmeVolume *self) +{ + g_return_val_if_fail (self != NULL, 0); + g_return_val_if_fail (ACME_IS_VOLUME (self), 0); + + return ACME_VOLUME_GET_CLASS (self)->get_volume (self); +} + +void +acme_volume_set_volume (AcmeVolume *self, int val) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (ACME_IS_VOLUME (self)); + + ACME_VOLUME_GET_CLASS (self)->set_volume (self, val); +} + +gboolean +acme_volume_get_mute (AcmeVolume *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (ACME_IS_VOLUME (self), FALSE); + + return ACME_VOLUME_GET_CLASS (self)->get_mute (self); +} + +void +acme_volume_set_mute (AcmeVolume *self, gboolean val) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (ACME_IS_VOLUME (self)); + + ACME_VOLUME_GET_CLASS (self)->set_mute (self, val); +} + +void +acme_volume_mute_toggle (AcmeVolume *self) +{ + gboolean muted; + + g_return_if_fail (self != NULL); + g_return_if_fail (ACME_IS_VOLUME (self)); + + muted = ACME_VOLUME_GET_CLASS (self)->get_mute (self); + ACME_VOLUME_GET_CLASS (self)->set_mute (self, !muted); +} + +int +acme_volume_get_threshold (AcmeVolume *self) +{ + g_return_val_if_fail (self != NULL, 0); + g_return_val_if_fail (ACME_IS_VOLUME (self), 0); + + return ACME_VOLUME_GET_CLASS (self)->get_threshold (self); +} + +AcmeVolume *acme_volume_new (void) +{ + AcmeVolume *vol; + +#ifdef HAVE_GSTREAMER + vol = ACME_VOLUME (g_object_new (acme_volume_gstreamer_get_type (), NULL)); + return vol; +#endif +#ifdef HAVE_ALSA + vol = ACME_VOLUME (g_object_new (acme_volume_alsa_get_type (), NULL)); + if (vol != NULL && ACME_VOLUME_ALSA (vol)->_priv != NULL) + return vol; + if (ACME_VOLUME_ALSA (vol)->_priv == NULL) + g_object_unref (vol); +#endif +#ifdef HAVE_OSS + vol = ACME_VOLUME (g_object_new (acme_volume_oss_get_type (), NULL)); + return vol; +#endif + return NULL; +} + diff --git a/src/sugar/acme-volume.h b/src/sugar/acme-volume.h new file mode 100644 index 0000000..ec5ee3d --- /dev/null +++ b/src/sugar/acme-volume.h @@ -0,0 +1,63 @@ +/* acme-volume.h + + Copyright (C) 2002, 2003 Bastien Nocera + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Bastien Nocera <hadess@hadess.net> + */ + +#ifndef _ACME_VOLUME_H +#define _ACME_VOLUME_H + +#include <glib.h> +#include <glib-object.h> + +G_BEGIN_DECLS + +#define ACME_TYPE_VOLUME (acme_volume_get_type ()) +#define ACME_VOLUME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ACME_TYPE_VOLUME, AcmeVolume)) +#define ACME_VOLUME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ACME_TYPE_VOLUME, AcmeVolumeClass)) +#define ACME_IS_VOLUME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ACME_TYPE_VOLUME)) +#define ACME_VOLUME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ACME_TYPE_VOLUME, AcmeVolumeClass)) + +typedef struct { + GObject parent; +} AcmeVolume; + +typedef struct { + GObjectClass parent; + + void (* set_volume) (AcmeVolume *self, int val); + int (* get_volume) (AcmeVolume *self); + void (* set_mute) (AcmeVolume *self, gboolean val); + int (* get_mute) (AcmeVolume *self); + int (* get_threshold) (AcmeVolume *self); +} AcmeVolumeClass; + +GType acme_volume_get_type (void); +int acme_volume_get_volume (AcmeVolume *self); +void acme_volume_set_volume (AcmeVolume *self, int val); +gboolean acme_volume_get_mute (AcmeVolume *self); +void acme_volume_set_mute (AcmeVolume *self, + gboolean val); +void acme_volume_mute_toggle (AcmeVolume *self); +int acme_volume_get_threshold (AcmeVolume *self); +AcmeVolume *acme_volume_new (void); + +G_END_DECLS + +#endif /* _ACME_VOLUME_H */ diff --git a/src/sugar/activity/Makefile.am b/src/sugar/activity/Makefile.am index 9dfc8de..26a6782 100644 --- a/src/sugar/activity/Makefile.am +++ b/src/sugar/activity/Makefile.am @@ -6,4 +6,5 @@ sugar_PYTHON = \ activityhandle.py \ activityservice.py \ bundlebuilder.py \ + main.py \ registry.py diff --git a/src/sugar/activity/activity.py b/src/sugar/activity/activity.py index 9784b28..6571994 100644 --- a/src/sugar/activity/activity.py +++ b/src/sugar/activity/activity.py @@ -104,7 +104,7 @@ class ActivityToolbar(gtk.Toolbar): if activity.metadata: self.title = gtk.Entry() - self.title.set_size_request(int(gtk.gdk.screen_width() / 6), -1) + self.title.set_size_request(int(gtk.gdk.screen_width() / 3), -1) self.title.set_text(activity.metadata['title']) self.title.connect('changed', self.__title_changed_cb) self._add_widget(self.title) @@ -174,7 +174,6 @@ class ActivityToolbar(gtk.Toolbar): self._activity.copy() def __stop_clicked_cb(self, button): - self._activity.take_screenshot() self._activity.close() def __jobject_updated_cb(self, jobject): @@ -474,6 +473,12 @@ class Activity(Window, gtk.Container): self.connect('realize', self.__realize_cb) self.connect('delete-event', self.__delete_event_cb) + # watch visibility-notify-events to know when we can safely + # take a screenshot of the activity + self.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK) + self.connect('visibility-notify-event', self.__visibility_notify_event_cb) + self._fully_obscured = True + self._active = False self._activity_id = handle.activity_id self._pservice = presenceservice.get_instance() @@ -728,19 +733,12 @@ class Activity(Window, gtk.Container): pixbuf = pixbuf.scale_simple(style.zoom(300), style.zoom(225), gtk.gdk.INTERP_BILINEAR) - # TODO: Find a way of taking a png out of the pixbuf without saving - # to a temp file. Impementing gtk.gdk.Pixbuf.save_to_buffer in pygtk - # would solve this. - fd, file_path = tempfile.mkstemp('.png') - os.close(fd) + preview_data = [] + def save_func(buf, data): + data.append(buf) - pixbuf.save(file_path, 'png') - f = open(file_path) - try: - preview_data = f.read() - finally: - f.close() - os.remove(file_path) + pixbuf.save_to_callback(save_func, 'png', user_data=preview_data) + preview_data = ''.join(preview_data) self._preview.clear() @@ -758,8 +756,8 @@ class Activity(Window, gtk.Container): return {} def take_screenshot(self): - if self.canvas and self.canvas.window: - self._preview.take_screenshot(self.canvas.window) + if self.canvas: + self._preview.take_screenshot(self.canvas) def save(self): """Request that the activity is saved to the Journal. @@ -817,6 +815,8 @@ class Activity(Window, gtk.Container): copy work that needs to be done in write_file() """ logging.debug('Activity.copy: %r' % self._jobject.object_id) + if not self._fully_obscured: + self.take_screenshot() self.save() self._jobject.object_id = None @@ -972,6 +972,8 @@ class Activity(Window, gtk.Container): write_file() to do any state saving instead. If the application wants to control wether it can close, it should override can_close(). """ + if not self._fully_obscured: + self.take_screenshot() if not self.can_close(): return @@ -991,6 +993,15 @@ class Activity(Window, gtk.Container): self.close() return True + def __visibility_notify_event_cb(self, widget, event): + """Visibility state is used when deciding if we can take screenshots. + Currently we allow screenshots whenever the activity window is fully + visible or partially obscured.""" + if event.state is gtk.gdk.VISIBILITY_FULLY_OBSCURED: + self._fully_obscured = True + else: + self._fully_obscured = False + def get_metadata(self): """Returns the jobject metadata or None if there is no jobject. diff --git a/src/sugar/activity/activityfactory.py b/src/sugar/activity/activityfactory.py index c9729d4..90f55cd 100644 --- a/src/sugar/activity/activityfactory.py +++ b/src/sugar/activity/activityfactory.py @@ -54,15 +54,18 @@ _RAINBOW_SERVICE_NAME = "org.laptop.security.Rainbow" _RAINBOW_ACTIVITY_FACTORY_PATH = "/" _RAINBOW_ACTIVITY_FACTORY_INTERFACE = "org.laptop.security.Rainbow" -_children_pid = [] - -def _sigchild_handler(signum, frame): - for child_pid in _children_pid: - pid, status_ = os.waitpid(child_pid, os.WNOHANG) - if pid > 0: - _children_pid.remove(pid) - -signal.signal(signal.SIGCHLD, _sigchild_handler) +# helper method to close all filedescriptors +# borrowed from subprocess.py +try: + MAXFD = os.sysconf("SC_OPEN_MAX") +except: + MAXFD = 256 +def _close_fds(): + for i in xrange(3, MAXFD): + try: + os.close(i) + except: + pass def create_activity_id(): """Generate a new, unique ID for this activity""" @@ -245,9 +248,24 @@ class ActivityCreationHandler(gobject.GObject): self._handle.uri) if not self._use_rainbow: - p = subprocess.Popen(command, env=environ, cwd=activity.path, - stdout=log_file, stderr=log_file) - _children_pid.append(p.pid) + # use gobject spawn functionality, so that zombies are + # automatically reaped by the gobject event loop. + def child_setup(): + # clone logfile.fileno() onto stdout/stderr + os.dup2(log_file.fileno(), 1) + os.dup2(log_file.fileno(), 2) + # close all other fds + _close_fds() + # we need to sanitize and str-ize the various bits which + # dbus gives us. + gobject.spawn_async([str(s) for s in command], + envp=['%s=%s' % (k, str(v)) + for k, v in environ.items()], + working_directory=str(activity.path), + child_setup=child_setup, + flags=(gobject.SPAWN_SEARCH_PATH | + gobject.SPAWN_LEAVE_DESCRIPTORS_OPEN)) + log_file.close() else: log_file.close() system_bus = dbus.SystemBus() diff --git a/src/sugar/activity/bundlebuilder.py b/src/sugar/activity/bundlebuilder.py index b8f87a7..baeb8b6 100644 --- a/src/sugar/activity/bundlebuilder.py +++ b/src/sugar/activity/bundlebuilder.py @@ -16,6 +16,7 @@ # Boston, MA 02111-1307, USA. import os +import sys import zipfile import tarfile import shutil @@ -29,6 +30,9 @@ from fnmatch import fnmatch from sugar import env from sugar.bundle.activitybundle import ActivityBundle +IGNORE_DIRS = ['dist', '.git'] +IGNORE_FILES = ['.gitignore', 'MANIFEST', '*.pyc', '*~', '*.bak', 'pseudo.po'] + def list_files(base_dir, ignore_dirs=None, ignore_files=None): result = [] @@ -51,7 +55,21 @@ def list_files(base_dir, ignore_dirs=None, ignore_files=None): class Config(object): def __init__(self, source_dir=None, dist_dir = None, dist_name = None): self.source_dir = source_dir or os.getcwd() - + self.dist_dir = dist_dir or os.path.join(self.source_dir, 'dist') + self.dist_name = dist_name + self.bundle = None + self.version = None + self.activity_name = None + self.bundle_id = None + self.bundle_name = None + self.bundle_root_dir = None + self.tar_root_dir = None + self.xo_name = None + self.tar_name = None + + self.update() + + def update(self): self.bundle = bundle = ActivityBundle(self.source_dir) self.version = bundle.get_activity_version() self.activity_name = bundle.get_name() @@ -59,14 +77,9 @@ class Config(object): self.bundle_name = reduce(lambda x, y:x+y, self.activity_name.split()) self.bundle_root_dir = self.bundle_name + '.activity' self.tar_root_dir = '%s-%d' % (self.bundle_name, self.version) - - if dist_dir: - self.dist_dir = dist_dir - else: - self.dist_dir = os.path.join(self.source_dir, 'dist') - if dist_name: - self.xo_name = self.tar_name = dist_name + if self.dist_name: + self.xo_name = self.tar_name = self.dist_name else: self.xo_name = '%s-%d.xo' % (self.bundle_name, self.version) self.tar_name = '%s-%d.tar.bz2' % (self.bundle_name, self.version) @@ -85,8 +98,13 @@ class Builder(object): logging.warn("Missing po/ dir, cannot build_locale") return + locale_dir = os.path.join(self.config.source_dir, 'locale') + + if os.path.exists(locale_dir): + shutil.rmtree(locale_dir) + for f in os.listdir(po_dir): - if not f.endswith('.po'): + if not f.endswith('.po') or f == 'pseudo.po': continue file_name = os.path.join(po_dir, f) @@ -110,15 +128,6 @@ class Builder(object): f.write('[Activity]\nname = %s\n' % translated_name) f.close() -class Packager(object): - def __init__(self, config): - self.config = config - self.package_path = None - - if not os.path.exists(self.config.dist_dir): - os.mkdir(self.config.dist_dir) - -class BuildPackager(Packager): def get_files(self): files = self.config.bundle.get_files() @@ -128,28 +137,43 @@ class BuildPackager(Packager): files = self.config.bundle.get_files() return files - - def _list_useful_files(self): - ignore_dirs = ['dist', '.git'] - ignore_files = ['.gitignore', 'MANIFEST', '*.pyc', '*~', '*.bak'] - - return list_files(self.config.source_dir, ignore_dirs, ignore_files) + + def check_manifest(self): + missing_files = [] + + allfiles = list_files(self.config.source_dir, + IGNORE_DIRS, IGNORE_FILES) + for path in allfiles: + if path not in self.config.bundle.manifest: + missing_files.append(path) + + return missing_files def fix_manifest(self): + self.build() + manifest = self.config.bundle.manifest - allfiles = self._list_useful_files() - for path in allfiles: - if path not in manifest: - manifest.append(path) + for path in self.check_manifest(): + manifest.append(path) f = open(os.path.join(self.config.source_dir, "MANIFEST"), "wb") for line in manifest: f.write(line + "\n") -class XOPackager(BuildPackager): +class Packager(object): def __init__(self, config): - BuildPackager.__init__(self, config) + self.config = config + self.package_path = None + + if not os.path.exists(self.config.dist_dir): + os.mkdir(self.config.dist_dir) + +class XOPackager(Packager): + def __init__(self, builder): + Packager.__init__(self, builder.config) + + self.builder = builder self.package_path = os.path.join(self.config.dist_dir, self.config.xo_name) @@ -157,15 +181,22 @@ class XOPackager(BuildPackager): bundle_zip = zipfile.ZipFile(self.package_path, 'w', zipfile.ZIP_DEFLATED) - for f in self.get_files(): + missing_files = self.builder.check_manifest() + if missing_files: + logging.warn('These files are not included in the manifest ' \ + 'and will not be present in the bundle:\n\n' + + '\n'.join(missing_files) + + '\n\nUse fix_manifest if you want to add them.') + + for f in self.builder.get_files(): bundle_zip.write(os.path.join(self.config.source_dir, f), os.path.join(self.config.bundle_root_dir, f)) bundle_zip.close() -class SourcePackager(BuildPackager): +class SourcePackager(Packager): def __init__(self, config): - BuildPackager.__init__(self, config) + Packager.__init__(self, config) self.package_path = os.path.join(self.config.dist_dir, self.config.tar_name) @@ -174,7 +205,8 @@ class SourcePackager(BuildPackager): cwd=self.config.source_dir) if git_ls.wait(): # Fall back to filtered list - return self._list_useful_files() + return list_files(self.config.source_dir, + IGNORE_DIRS, IGNORE_FILES) return [path.strip() for path in git_ls.stdout.readlines()] @@ -185,20 +217,50 @@ class SourcePackager(BuildPackager): os.path.join(self.config.tar_root_dir, f)) tar.close() -def cmd_help(config, options, args): - print 'Usage: \n\ -setup.py build - build generated files \n\ -setup.py dev - setup for development \n\ -setup.py dist_xo - create a xo bundle package \n\ -setup.py dist_source - create a tar source package \n\ -setup.py install [dirname] - install the bundle \n\ -setup.py uninstall [dirname] - uninstall the bundle \n\ -setup.py genpot - generate the gettext pot file \n\ -setup.py release - do a new release of the bundle \n\ -setup.py help - print this message \n\ -' - -def cmd_dev(config, options, args): +class Installer(object): + IGNORES = [ 'po/*', 'MANIFEST', 'AUTHORS' ] + + def __init__(self, builder): + self.config = builder.config + self.builder = builder + + def should_ignore(self, f): + for pattern in self.IGNORES: + if fnmatch(f, pattern): + return True + return False + + def install(self, prefix): + self.builder.build() + + activity_path = os.path.join(prefix, 'share', 'sugar', 'activities', + self.config.bundle_root_dir) + + source_to_dest = {} + for f in self.builder.get_files(): + if self.should_ignore(f): + pass + elif f.startswith('locale/') and f.endswith('.mo'): + source_to_dest[f] = os.path.join(prefix, 'share', f) + else: + source_to_dest[f] = os.path.join(activity_path, f) + + for source, dest in source_to_dest.items(): + print 'Install %s to %s.' % (source, dest) + + path = os.path.dirname(dest) + if not os.path.exists(path): + os.makedirs(path) + + shutil.copy(source, dest) + +def cmd_dev(config, args): + '''Setup for development''' + + if args: + print 'Usage: %prog dev' + return + bundle_path = env.get_user_activities_path() if not os.path.isdir(bundle_path): os.mkdir(bundle_path) @@ -211,47 +273,57 @@ def cmd_dev(config, options, args): else: print 'ERROR - A bundle with the same name is already installed.' -def cmd_dist_xo(config, options, args): - builder = Builder(config) - builder.build() +def cmd_dist_xo(config, args): + '''Create a xo bundle package''' - packager = XOPackager(config) + if args: + print 'Usage: %prog dist_xo' + return + + packager = XOPackager(Builder(config)) packager.package() -def cmd_dist(config, options, args): - logging.warn("dist deprecated, use dist_xo.") - cmd_dist_xo(config, options, args) +def cmd_fix_manifest(config, args): + '''Add missing files to the manifest''' -def cmd_dist_source(config, options, args): - packager = SourcePackager(config) - packager.package() + if args: + print 'Usage: %prog fix_manifest' + return + + builder = Builder(config) + builder.fix_manifest() + +def cmd_dist_source(config, args): + '''Create a tar source package''' -def cmd_install(config, options, args): - path = args[0] + if args: + print 'Usage: %prog dist_source' + return - packager = XOPackager(config) + packager = SourcePackager(config) packager.package() - root_path = os.path.join(args[0], config.bundle_root_dir) - if os.path.isdir(root_path): - shutil.rmtree(root_path) +def cmd_install(config, args): + '''Install the activity in the system''' - if not os.path.exists(path): - os.mkdir(path) + parser = OptionParser(usage='usage: %prog install [options]') + parser.add_option('--prefix', dest='prefix', default=sys.prefix, + help='Prefix to install files to') + (suboptions, subargs) = parser.parse_args(args) + if subargs: + parser.print_help() + return - zf = zipfile.ZipFile(packager.package_path) + installer = Installer(Builder(config)) + installer.install(suboptions.prefix) - for name in zf.namelist(): - full_path = os.path.join(path, name) - if not os.path.exists(os.path.dirname(full_path)): - os.makedirs(os.path.dirname(full_path)) +def cmd_genpot(config, args): + '''Generate the gettext pot file''' - outfile = open(full_path, 'wb') - outfile.write(zf.read(name)) - outfile.flush() - outfile.close() + if args: + print 'Usage: %prog genpot' + return -def cmd_genpot(config, options, args): po_path = os.path.join(config.source_dir, 'po') if not os.path.isdir(po_path): os.mkdir(po_path) @@ -283,7 +355,13 @@ def cmd_genpot(config, options, args): if retcode: print 'ERROR - xgettext failed with return code %i.' % retcode -def cmd_release(config, options, args): +def cmd_release(config, args): + '''Do a new release of the bundle''' + + if args: + print 'Usage: %prog release' + return + if not os.path.isdir('.git'): print 'ERROR - this command works only for git repositories' return @@ -309,6 +387,8 @@ def cmd_release(config, options, args): f.write(info) f.close() + config.update() + news_path = os.path.join(config.source_dir, 'NEWS') if os.environ.has_key('SUGAR_NEWS'): @@ -351,7 +431,7 @@ def cmd_release(config, options, args): f.close() print 'Creating the bundle...' - packager = XOPackager(config) + packager = XOPackager(Builder(config)) packager.package() print 'Committing to git...' @@ -379,22 +459,40 @@ def cmd_release(config, options, args): print 'Done.' -def cmd_build(config, options, args): +def cmd_build(config, args): + '''Build generated files''' + + if args: + print 'Usage: %prog build' + return + builder = Builder(config) builder.build() +def print_commands(): + print 'Available commands:\n' + + for name, func in globals().items(): + if name.startswith('cmd_'): + print "%-20s %s" % (name.replace('cmd_', ''), func.__doc__) + + print '\n(Type "./setup.py <command> --help" for help about a ' \ + 'particular command\'s options.' + def start(bundle_name=None): if bundle_name: logging.warn("bundle_name deprecated, now comes from activity.info") - parser = OptionParser() - (options, args) = parser.parse_args() + + parser = OptionParser(usage='[action] [options]') + parser.disable_interspersed_args() + (options_, args) = parser.parse_args() config = Config() try: - globals()['cmd_' + args[0]](config, options, args[1:]) + globals()['cmd_' + args[0]](config, args[1:]) except (KeyError, IndexError): - cmd_help(config, options, args) + print_commands() if __name__ == '__main__': start() diff --git a/src/sugar/activity/main.py b/src/sugar/activity/main.py new file mode 100644 index 0000000..2175ff3 --- /dev/null +++ b/src/sugar/activity/main.py @@ -0,0 +1,137 @@ +# Copyright (C) 2008 Red Hat, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +import os +import sys +import gettext +from optparse import OptionParser + +import gtk +import dbus +import dbus.service +import dbus.glib + +from sugar.activity import activityhandle +from sugar.bundle.activitybundle import ActivityBundle +from sugar import logger + +def create_activity_instance(constructor, handle): + activity = constructor(handle) + activity.show() + +def get_single_process_name(bundle_id): + return bundle_id + +def get_single_process_path(bundle_id): + return '/' + bundle_id.replace('.', '/') + +class SingleProcess(dbus.service.Object): + def __init__(self, name_service, constructor): + self.constructor = constructor + + bus = dbus.SessionBus() + bus_name = dbus.service.BusName(name_service, bus=bus) + object_path = get_single_process_path(name_service) + dbus.service.Object.__init__(self, bus_name, object_path) + + @dbus.service.method("org.laptop.SingleProcess", in_signature="a{ss}") + def create(self, handle_dict): + handle = activityhandle.create_from_dict(handle_dict) + create_activity_instance(self.constructor, handle) + +def main(): + parser = OptionParser() + parser.add_option("-b", "--bundle-id", dest="bundle_id", + help="identifier of the activity bundle") + parser.add_option("-a", "--activity-id", dest="activity_id", + help="identifier of the activity instance") + parser.add_option("-o", "--object-id", dest="object_id", + help="identifier of the associated datastore object") + parser.add_option("-u", "--uri", dest="uri", + help="URI to load") + parser.add_option('-s', '--single-process', dest='single_process', + action='store_true', + help='start all the instances in the same process') + (options, args) = parser.parse_args() + + logger.start() + + if 'SUGAR_BUNDLE_PATH' not in os.environ: + print 'SUGAR_BUNDLE_PATH is not defined in the environment.' + sys.exit(1) + + if len(args) == 0: + print 'A python class must be specified as first argument.' + sys.exit(1) + + bundle_path = os.environ['SUGAR_BUNDLE_PATH'] + sys.path.append(bundle_path) + + bundle = ActivityBundle(bundle_path) + + os.environ['SUGAR_BUNDLE_ID'] = bundle.get_bundle_id() + os.environ['SUGAR_BUNDLE_NAME'] = bundle.get_name() + os.environ['SUGAR_BUNDLE_VERSION'] = str(bundle.get_activity_version()) + + gtk.icon_theme_get_default().append_search_path(bundle.get_icons_path()) + + gettext.bindtextdomain(bundle.get_bundle_id(), + bundle.get_locale_path()) + gettext.textdomain(bundle.get_bundle_id()) + + splitted_module = args[0].rsplit('.', 1) + module_name = splitted_module[0] + class_name = splitted_module[1] + + module = __import__(module_name) + for comp in module_name.split('.')[1:]: + module = getattr(module, comp) + + activity_constructor = getattr(module, class_name) + activity_handle = activityhandle.ActivityHandle( + activity_id=options.activity_id, + object_id=options.object_id, uri=options.uri) + + if options.single_process is True: + sessionbus = dbus.SessionBus() + + service_name = get_single_process_name(options.bundle_id) + service_path = get_single_process_path(options.bundle_id) + + bus_object = sessionbus.get_object( + 'org.freedesktop.DBus', '/org/freedesktop/DBus') + try: + name = bus_object.GetNameOwner( + service_name, dbus_interface='org.freedesktop.DBus') + except dbus.DBusException: + name = None + + if not name: + service = SingleProcess(service_name, activity_constructor) + else: + single_process = sessionbus.get_object(service_name, service_path) + single_process.create(activity_handle.get_dict()) + + print 'Created %s in a single process.' % service_name + sys.exit(0) + + if hasattr(module, 'start'): + module.start() + + create_activity_instance(activity_constructor, activity_handle) + + gtk.main() diff --git a/src/sugar/bundle/activitybundle.py b/src/sugar/bundle/activitybundle.py index 2c235d8..2cc4da7 100644 --- a/src/sugar/bundle/activitybundle.py +++ b/src/sugar/bundle/activitybundle.py @@ -205,13 +205,13 @@ class ActivityBundle(Bundle): def get_locale_path(self): """Get the locale path inside the (installed) activity bundle.""" - if not self._unpacked: + if self._zip_file is not None: raise NotInstalledException return os.path.join(self._path, 'locale') def get_icons_path(self): """Get the icons path inside the (installed) activity bundle.""" - if not self._unpacked: + if self._zip_file is not None: raise NotInstalledException return os.path.join(self._path, 'icons') @@ -237,7 +237,7 @@ class ActivityBundle(Bundle): def get_icon(self): """Get the activity icon name""" icon_path = os.path.join('activity', self._icon + '.svg') - if self._unpacked: + if self._zip_file is None: return os.path.join(self._path, icon_path) else: icon_data = self.get_file(icon_path).read() @@ -365,7 +365,7 @@ class ActivityBundle(Bundle): raise RegistrationException def uninstall(self, force=False): - if self._unpacked: + if self._zip_file is None: install_path = self._path else: if not self.is_installed(): @@ -396,11 +396,12 @@ class ActivityBundle(Bundle): if mime_types is not None: installed_icons_dir = os.path.join(xdg_data_home, 'icons/sugar/scalable/mimetypes') - for f in os.listdir(installed_icons_dir): - path = os.path.join(installed_icons_dir, f) - if os.path.islink(path) and \ - os.readlink(path).startswith(install_path): - os.remove(path) + if os.path.isdir(installed_icons_dir): + for f in os.listdir(installed_icons_dir): + path = os.path.join(installed_icons_dir, f) + if os.path.islink(path) and \ + os.readlink(path).startswith(install_path): + os.remove(path) self._uninstall(install_path) diff --git a/src/sugar/bundle/bundle.py b/src/sugar/bundle/bundle.py index 3b12932..0319b9e 100644 --- a/src/sugar/bundle/bundle.py +++ b/src/sugar/bundle/bundle.py @@ -19,6 +19,7 @@ import os import logging +import shutil import StringIO import zipfile @@ -59,9 +60,9 @@ class Bundle: self._zip_root_dir = None if os.path.isdir(self._path): - self._unpacked = True + self._zip_file = None else: - self._unpacked = False + self._zip_file = zipfile.ZipFile(self._path) self._check_zip_bundle() # manifest = self._get_file(self._infodir + '/contents') @@ -72,9 +73,12 @@ class Bundle: # if signature is None: # raise MalformedBundleException('No signature file') + def __del__(self): + if self._zip_file is not None: + self._zip_file.close() + def _check_zip_bundle(self): - zip_file = zipfile.ZipFile(self._path) - file_names = zip_file.namelist() + file_names = self._zip_file.namelist() if len(file_names) == 0: raise MalformedBundleException('Empty zip file') @@ -99,48 +103,42 @@ class Bundle: def get_file(self, filename): f = None - if self._unpacked: + if self._zip_file is None: path = os.path.join(self._path, filename) try: f = open(path,"rb") except IOError: return None else: - zip_file = zipfile.ZipFile(self._path) path = os.path.join(self._zip_root_dir, filename) try: - data = zip_file.read(path) + data = self._zip_file.read(path) f = StringIO.StringIO(data) except KeyError: logging.debug('%s not found.' % filename) - zip_file.close() return f def is_file(self, filename): - if self._unpacked: + if self._zip_file is None: path = os.path.join(self._path, filename) return os.path.isfile(path) else: - zip_file = zipfile.ZipFile(self._path) path = os.path.join(self._zip_root_dir, filename) try: - zip_file.getinfo(path) + self._zip_file.getinfo(path) except KeyError: return False - finally: - zip_file.close() return True def is_dir(self, filename): - if self._unpacked: + if self._zip_file is None: path = os.path.join(self._path, filename) return os.path.isdir(path) else: - zip_file = zipfile.ZipFile(self._path) path = os.path.join(self._zip_root_dir, filename, "") - for f in zip_file.namelist(): + for f in self._zip_file.namelist(): if f.startswith(path): return True return False @@ -150,7 +148,7 @@ class Bundle: return self._path def _unzip(self, install_dir): - if self._unpacked: + if self._zip_file is None: raise AlreadyInstalledException if not os.path.isdir(install_dir): @@ -163,10 +161,13 @@ class Bundle: # FIXME: use manifest if os.spawnlp(os.P_WAIT, 'unzip', 'unzip', '-o', self._path, '-x', 'mimetype', '-d', install_dir): + # clean up install dir after failure + shutil.rmtree(install_dir, ignore_errors=True) + # indicate failure. raise ZipExtractException def _zip(self, bundle_path): - if not self._unpacked: + if self._zip_file is not None: raise NotInstalledException raise NotImplementedError diff --git a/src/sugar/bundle/contentbundle.py b/src/sugar/bundle/contentbundle.py index 32f38e3..09521be 100644 --- a/src/sugar/bundle/contentbundle.py +++ b/src/sugar/bundle/contentbundle.py @@ -194,7 +194,7 @@ class ContentBundle(Bundle): return "file://" + urllib.pathname2url(self.get_start_path()) def is_installed(self): - if self._unpacked: + if self._zip_file is None: return True elif os.path.isdir(self.get_root_dir()): return True @@ -206,7 +206,7 @@ class ContentBundle(Bundle): self._run_indexer() def uninstall(self): - if self._unpacked: + if self._zip_file is None: if not self.is_installed(): raise NotInstalledException install_dir = self._path diff --git a/src/sugar/eggsmclient-private.h b/src/sugar/eggsmclient-private.h index 0b4ec40..d2958c9 100644 --- a/src/sugar/eggsmclient-private.h +++ b/src/sugar/eggsmclient-private.h @@ -25,6 +25,8 @@ G_BEGIN_DECLS +#define EGG_SM_CLIENT_BACKEND_XSMP + GKeyFile *egg_sm_client_save_state (EggSMClient *client); void egg_sm_client_quit_requested (EggSMClient *client); void egg_sm_client_quit_cancelled (EggSMClient *client); diff --git a/src/sugar/graphics/alert.py b/src/sugar/graphics/alert.py index fad90bb..39c373c 100644 --- a/src/sugar/graphics/alert.py +++ b/src/sugar/graphics/alert.py @@ -85,7 +85,7 @@ class Alert(gtk.EventBox): self._buttons_box.set_spacing(style.DEFAULT_SPACING) self._hbox.pack_start(self._buttons_box) - gtk.EventBox.__init__(self, **kwargs) + gobject.GObject.__init__(self, **kwargs) self.set_visible_window(True) self.add(self._hbox) @@ -105,6 +105,7 @@ class Alert(gtk.EventBox): if self._msg != value: self._msg = value self._msg_label.set_markup(self._msg) + self._msg_label.set_line_wrap(True) elif pspec.name == 'icon': if self._icon != value: self._icon = value diff --git a/src/sugar/graphics/palette.py b/src/sugar/graphics/palette.py index 2c07389..c0a56fc 100644 --- a/src/sugar/graphics/palette.py +++ b/src/sugar/graphics/palette.py @@ -244,9 +244,7 @@ class Palette(gtk.Window): self._menu_box = None self._content = None self._palette_popup_sid = None - self._enter_invoker_hid = None - self._leave_invoker_hid = None - self._right_click_invoker_hid = None + self._invoker_hids = [] self.set_group_id("default") @@ -274,8 +272,12 @@ class Palette(gtk.Window): self._mouse_detector = MouseSpeedDetector(self, 200, 5) self._mouse_detector.connect('motion-slow', self._mouse_slow_cb) - def __destroy_cb(self, palette): + def __destroy_cb(self, palette): self.set_group_id(None) + + # Break the reference cycle. It looks like the gc is not able to free + # it, possibly because gtk.Menu memory handling is very special. + self.menu = None if self._palette_popup_sid is not None: _palette_observer.disconnect(self._palette_popup_sid) @@ -312,21 +314,27 @@ class Palette(gtk.Window): return gtk.gdk.Rectangle(x, y, width, height) def _set_invoker(self, invoker): - if self._invoker is not None: - self._invoker.disconnect(self._enter_invoker_hid) - self._invoker.disconnect(self._leave_invoker_hid) - self._invoker.disconnect(self._right_click_invoker_hid) + for hid in self._invoker_hids[:]: + self._invoker.disconnect(hid) + self._invoker_hids.remove(hid) self._invoker = invoker if invoker is not None: - self._enter_invoker_hid = self._invoker.connect( - 'mouse-enter', self._invoker_mouse_enter_cb) - self._leave_invoker_hid = self._invoker.connect( - 'mouse-leave', self._invoker_mouse_leave_cb) - self._right_click_invoker_hid = self._invoker.connect( - 'right-click', self._invoker_right_click_cb) + self._invoker_hids.append(self._invoker.connect( + 'mouse-enter', self._invoker_mouse_enter_cb)) + self._invoker_hids.append(self._invoker.connect( + 'mouse-leave', self._invoker_mouse_leave_cb)) + self._invoker_hids.append(self._invoker.connect( + 'right-click', self._invoker_right_click_cb)) if hasattr(invoker.props, 'widget'): - self._label.props.accel_widget = invoker.props.widget + self._update_accel_widget() + logging.debug(('Setup widget', invoker.props.widget)) + self._invoker_hids.append(self._invoker.connect( + 'notify::widget', self._invoker_widget_changed_cb)) + + def _update_accel_widget(self): + assert self.props.invoker is not None + self._label.props.accel_widget = self.props.invoker.props.widget def set_primary_text(self, label, accel_path=None): self._primary_text = label @@ -611,6 +619,9 @@ class Palette(gtk.Window): self.popup(immediate=immediate) + def _invoker_widget_changed_cb(self, invoker, spec): + self._update_accel_widget() + def _invoker_mouse_enter_cb(self, invoker): self._mouse_detector.start() @@ -750,6 +761,9 @@ class Invoker(gobject.GObject): def detach(self): self.parent = None + if self._palette is not None: + self._palette.destroy() + self._palette = None def _get_position_for_alignment(self, alignment, palette_dim): palette_halign = alignment[0] @@ -939,6 +953,8 @@ class WidgetInvoker(Invoker): else: self._widget = parent + self.notify('widget') + self._enter_hid = self._widget.connect('enter-notify-event', self.__enter_notify_event_cb) self._leave_hid = self._widget.connect('leave-notify-event', diff --git a/src/sugar/graphics/radiotoolbutton.py b/src/sugar/graphics/radiotoolbutton.py index abdf54c..e2636dc 100644 --- a/src/sugar/graphics/radiotoolbutton.py +++ b/src/sugar/graphics/radiotoolbutton.py @@ -36,6 +36,12 @@ class RadioToolButton(gtk.RadioToolButton): self._palette_invoker.attach_tool(self) + self.connect('destroy', self.__destroy_cb) + + def __destroy_cb(self, icon): + if self._palette_invoker is not None: + self._palette_invoker.detach() + def set_tooltip(self, tooltip): """ Set a simple palette with just a single label. """ diff --git a/src/sugar/graphics/style.py b/src/sugar/graphics/style.py index 1b510d1..ce2abe8 100644 --- a/src/sugar/graphics/style.py +++ b/src/sugar/graphics/style.py @@ -46,15 +46,6 @@ def _compute_zoom_factor(): return 1.0 -def _compute_font_height(font): - widget = gtk.Label('') - - context = widget.get_pango_context() - pango_font = context.load_font(font.get_pango_desc()) - metrics = pango_font.get_metrics() - - return pango.PIXELS(metrics.get_ascent() + metrics.get_descent()) - class Font(object): def __init__(self, desc): self._desc = desc @@ -124,8 +115,8 @@ XLARGE_ICON_SIZE = zoom(55 * 2.75) FONT_SIZE = zoom(7 * _XO_DPI / _get_screen_dpi()) FONT_NORMAL = Font('Bitstream Vera Sans %d' % FONT_SIZE) FONT_BOLD = Font('Bitstream Vera Sans bold %d' % FONT_SIZE) -FONT_NORMAL_H = _compute_font_height(FONT_NORMAL) -FONT_BOLD_H = _compute_font_height(FONT_BOLD) +FONT_NORMAL_H = zoom(24) +FONT_BOLD_H = zoom(24) TOOLBOX_SEPARATOR_HEIGHT = zoom(9) TOOLBOX_HORIZONTAL_PADDING = zoom(75) diff --git a/src/sugar/graphics/toggletoolbutton.py b/src/sugar/graphics/toggletoolbutton.py index ec622b4..35c4bf1 100644 --- a/src/sugar/graphics/toggletoolbutton.py +++ b/src/sugar/graphics/toggletoolbutton.py @@ -30,6 +30,12 @@ class ToggleToolButton(gtk.ToggleToolButton): self._palette_invoker = ToolInvoker(self) self.set_named_icon(named_icon) + self.connect('destroy', self.__destroy_cb) + + def __destroy_cb(self, icon): + if self._palette_invoker is not None: + self._palette_invoker.detach() + def set_named_icon(self, named_icon): icon = Icon(icon_name=named_icon) self.set_icon_widget(icon) diff --git a/src/sugar/graphics/toolbutton.py b/src/sugar/graphics/toolbutton.py index bf392c8..a80c67a 100644 --- a/src/sugar/graphics/toolbutton.py +++ b/src/sugar/graphics/toolbutton.py @@ -65,6 +65,18 @@ class ToolButton(gtk.ToolButton): self.set_icon(icon_name) self.connect('clicked', self.__button_clicked_cb) + self.get_child().connect('can-activate-accel', + self.__button_can_activate_accel_cb) + + self.connect('destroy', self.__destroy_cb) + + def __destroy_cb(self, icon): + if self._palette_invoker is not None: + self._palette_invoker.detach() + + def __button_can_activate_accel_cb(self, button, signal_id): + # Accept activation via accelerators regardless of this widget's state + return True def set_tooltip(self, tooltip): """ Set a simple palette with just a single label. diff --git a/src/sugar/graphics/tray.py b/src/sugar/graphics/tray.py index 8296a53..d5e9b39 100644 --- a/src/sugar/graphics/tray.py +++ b/src/sugar/graphics/tray.py @@ -358,6 +358,12 @@ class TrayIcon(gtk.ToolItem): self.set_size_request(style.GRID_CELL_SIZE, style.GRID_CELL_SIZE) + self.connect('destroy', self.__destroy_cb) + + def __destroy_cb(self, icon): + if self._palette_invoker is not None: + self._palette_invoker.detach() + def create_palette(self): return None diff --git a/src/sugar/gsm-session.c b/src/sugar/gsm-session.c index 95dd7cb..3f0714c 100644 --- a/src/sugar/gsm-session.c +++ b/src/sugar/gsm-session.c @@ -151,53 +151,6 @@ end_phase (GsmSession *session) } static void -app_condition_changed (GsmApp *app, gboolean condition, gpointer data) -{ - GsmSession *session; - GsmClient *client = NULL; - GSList *cl = NULL; - - g_return_if_fail (data != NULL); - - session = (GsmSession *) data; - - /* Check for an existing session client for this app */ - for (cl = session->clients; cl; cl = cl->next) - { - GsmClient *c = GSM_CLIENT (cl->data); - - if (!strcmp (app->client_id, gsm_client_get_client_id (c))) - client = c; - } - - if (condition) - { - GError *error = NULL; - - if (app->pid <= 0 && client == NULL) - gsm_app_launch (app, &error); - - if (error != NULL) - { - g_warning ("Not able to launch autostart app from its condition: %s", - error->message); - - g_error_free (error); - } - } - else - { - /* Kill client in case condition if false and make sure it won't - * be automatically restarted by adding the client to - * condition_clients */ - session->condition_clients = - g_slist_prepend (session->condition_clients, client); - gsm_client_die (client); - app->pid = -1; - } -} - -static void app_registered (GsmApp *app, gpointer data) { GsmSession *session = data; @@ -241,10 +194,6 @@ phase_timeout (gpointer data) static void start_phase (GsmSession *session) { - GsmApp *app; - GSList *a; - GError *err = NULL; - g_debug ("starting phase %d\n", session->phase); g_slist_free (session->pending_apps); @@ -359,8 +308,6 @@ client_saved_state (GsmClient *client, gpointer data) void gsm_session_initiate_shutdown (GsmSession *session) { - gboolean logout_prompt; - if (session->phase == GSM_SESSION_PHASE_SHUTDOWN) { /* Already shutting down, nothing more to do */ diff --git a/src/sugar/gsm-session.h b/src/sugar/gsm-session.h index 94577c9..d4880a9 100644 --- a/src/sugar/gsm-session.h +++ b/src/sugar/gsm-session.h @@ -73,6 +73,8 @@ typedef enum { GSM_SESSION_LOGOUT_MODE_FORCE } GsmSessionLogoutMode; +GType gsm_session_get_type (void) G_GNUC_CONST; + void gsm_session_set_name (GsmSession *session, const char *name); diff --git a/src/sugar/profile.py b/src/sugar/profile.py index 25b957e..1b08202 100644 --- a/src/sugar/profile.py +++ b/src/sugar/profile.py @@ -24,7 +24,7 @@ from sugar import env from sugar import util from sugar.graphics.xocolor import XoColor -DEFAULT_JABBER_SERVER = 'olpc.collabora.co.uk' +DEFAULT_JABBER_SERVER = '' DEFAULT_VOLUME = 81 DEFAULT_TIMEZONE = 'UTC' DEFAULT_HOT_CORNERS_DELAY = 0.0 @@ -104,7 +104,7 @@ class Profile(object): _set_key(cp, 'Buddy', 'Color', self.color.to_string()) if self.backup1: _set_key(cp, 'Server', 'Backup1', self.backup1) - if self.jabber_server: + if self.jabber_server is not None: _set_key(cp, 'Jabber', 'Server', self.jabber_server) _set_key(cp, 'Date', 'Timezone', self.timezone) diff --git a/src/sugar/sugar-grid.c b/src/sugar/sugar-grid.c new file mode 100644 index 0000000..3fa7de5 --- /dev/null +++ b/src/sugar/sugar-grid.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2008, Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "sugar-grid.h" + +static void sugar_grid_class_init (SugarGridClass *grid_class); +static void sugar_grid_init (SugarGrid *grid); + + +G_DEFINE_TYPE(SugarGrid, sugar_grid, G_TYPE_OBJECT) + +void +sugar_grid_setup(SugarGrid *grid, gint width, gint height) +{ + g_free(grid->weights); + + grid->weights = g_new0(guchar, width * height); + grid->width = width; + grid->height = height; +} + +static gboolean +check_bounds(SugarGrid *grid, GdkRectangle *rect) +{ + return (grid->weights != NULL && + grid->width >= rect->x + rect->width && + grid->height >= rect->y + rect->height); +} + +void +sugar_grid_add_weight(SugarGrid *grid, GdkRectangle *rect) +{ + int i, k; + + if (!check_bounds(grid, rect)) { + g_warning("Trying to add weight outside the grid bounds."); + return; + } + + for (k = rect->y; k < rect->y + rect->height; k++) { + for (i = rect->x; i < rect->x + rect->width; i++) { + grid->weights[i + k * grid->width] += 1; + } + } +} + +void +sugar_grid_remove_weight(SugarGrid *grid, GdkRectangle *rect) +{ + int i, k; + + if (!check_bounds(grid, rect)) { + g_warning("Trying to remove weight outside the grid bounds."); + return; + } + + for (k = rect->y; k < rect->y + rect->height; k++) { + for (i = rect->x; i < rect->x + rect->width; i++) { + grid->weights[i + k * grid->width] -= 1; + } + } +} + +guint +sugar_grid_compute_weight(SugarGrid *grid, GdkRectangle *rect) +{ + int i, k, sum = 0; + + if (!check_bounds(grid, rect)) { + g_warning("Trying to compute weight outside the grid bounds."); + return 0; + } + + for (k = rect->y; k < rect->y + rect->height; k++) { + for (i = rect->x; i < rect->x + rect->width; i++) { + sum += grid->weights[i + k * grid->width]; + } + } + + return sum; +} + +static void +sugar_grid_finalize(GObject *object) +{ + SugarGrid *grid = SUGAR_GRID(object); + + g_free(grid->weights); +} + +static void +sugar_grid_class_init(SugarGridClass *grid_class) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS(grid_class); + gobject_class->finalize = sugar_grid_finalize; +} + +static void +sugar_grid_init(SugarGrid *grid) +{ + grid->weights = NULL; +} diff --git a/src/sugar/sugar-grid.h b/src/sugar/sugar-grid.h new file mode 100644 index 0000000..d493a60 --- /dev/null +++ b/src/sugar/sugar-grid.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008, Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __SUGAR_GRID_H__ +#define __SUGAR_GRID_H__ + +#include <glib-object.h> +#include <gdk/gdk.h> + +G_BEGIN_DECLS + +typedef struct _SugarGrid SugarGrid; +typedef struct _SugarGridClass SugarGridClass; + +#define SUGAR_TYPE_GRID (sugar_grid_get_type()) +#define SUGAR_GRID(object) (G_TYPE_CHECK_INSTANCE_CAST((object), SUGAR_TYPE_GRID, SugarGrid)) +#define SUGAR_GRID_CLASS(klass) (G_TYPE_CHACK_CLASS_CAST((klass), SUGAR_TYPE_GRID, SugarGridClass)) +#define SUGAR_IS_GRID(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), SUGAR_TYPE_GRID)) +#define SUGAR_IS_GRID_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SUGAR_TYPE_GRID)) +#define SUGAR_GRID_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), SUGAR_TYPE_GRID, SugarGridClass)) + +struct _SugarGrid { + GObject base_instance; + + gint width; + gint height; + guchar *weights; +}; + +struct _SugarGridClass { + GObjectClass base_class; +}; + +GType sugar_grid_get_type (void); +void sugar_grid_setup (SugarGrid *grid, + gint width, + gint height); +void sugar_grid_add_weight (SugarGrid *grid, + GdkRectangle *rect); +void sugar_grid_remove_weight (SugarGrid *grid, + GdkRectangle *rect); +guint sugar_grid_compute_weight (SugarGrid *grid, + GdkRectangle *rect); + +G_END_DECLS + +#endif /* __SUGAR_GRID_H__ */ diff --git a/src/sugar/sugar-menu.h b/src/sugar/sugar-menu.h index 8773a31..74ce891 100644 --- a/src/sugar/sugar-menu.h +++ b/src/sugar/sugar-menu.h @@ -50,6 +50,7 @@ void sugar_menu_set_active (SugarMenu *menu, gboolean active); void sugar_menu_embed (SugarMenu *menu, GtkContainer *parent); +void sugar_menu_unembed (SugarMenu *menu); G_END_DECLS diff --git a/src/sugar/sugar-preview.c b/src/sugar/sugar-preview.c index f54045b..44b83e4 100644 --- a/src/sugar/sugar-preview.c +++ b/src/sugar/sugar-preview.c @@ -19,6 +19,7 @@ #include <gdk/gdkx.h> #include <gtk/gtkwindow.h> +#include <X11/extensions/XShm.h> #include "sugar-preview.h" @@ -37,8 +38,6 @@ sugar_preview_set_size(SugarPreview *preview, int width, int height) GdkPixbuf * sugar_preview_get_pixbuf(SugarPreview *preview) { - GdkPixbuf *pixbuf; - if (preview->pixbuf != NULL) { return preview->pixbuf; } @@ -70,16 +69,38 @@ sugar_preview_clear(SugarPreview *preview) } } +static gboolean +widget_is_off_screen(GtkWidget *widget) +{ + GdkScreen *screen; + gint x, y, width, height; + + screen = gtk_widget_get_screen(widget); + + gdk_window_get_geometry(widget->window, &x, &y, &width, &height, NULL); + + return (x < 0 || y < 0 || + x + width > gdk_screen_get_width(screen) || + y + height > gdk_screen_get_height(screen)); +} + void -sugar_preview_take_screenshot(SugarPreview *preview, GdkDrawable *drawable) +sugar_preview_take_screenshot(SugarPreview *preview, GtkWidget *widget) { + GdkDrawable *drawable; GdkScreen *screen; GdkVisual *visual; GdkColormap *colormap; gint width, height; + if (widget->window == NULL || widget_is_off_screen(widget)) { + return; + } + sugar_preview_clear(preview); + drawable = GDK_DRAWABLE(widget->window); + gdk_drawable_get_size(drawable, &width, &height); screen = gdk_drawable_get_screen(drawable); @@ -92,7 +113,7 @@ sugar_preview_take_screenshot(SugarPreview *preview, GdkDrawable *drawable) XShmGetImage(GDK_SCREEN_XDISPLAY(screen), GDK_DRAWABLE_XID(drawable), gdk_x11_image_get_ximage(preview->image), - 0, 0, AllPlanes, ZPixmap); + 0, 0, AllPlanes); } static void diff --git a/src/sugar/sugar-preview.h b/src/sugar/sugar-preview.h index 6029cc1..70ea156 100644 --- a/src/sugar/sugar-preview.h +++ b/src/sugar/sugar-preview.h @@ -50,7 +50,7 @@ struct _SugarPreviewClass { GType sugar_preview_get_type (void); void sugar_preview_take_screenshot (SugarPreview *preview, - GdkDrawable *drawable); + GtkWidget *widget); void sugar_preview_set_size (SugarPreview *preview, int width, int height); diff --git a/src/sugar/util.py b/src/sugar/util.py index 8f81210..ad02d86 100644 --- a/src/sugar/util.py +++ b/src/sugar/util.py @@ -21,9 +21,11 @@ import sha import random import binascii import string -from gettext import gettext as _ import gettext +_ = lambda msg: gettext.dgettext('sugar-toolkit', msg) +_ngettext = lambda msg1, msg2, n: gettext.dngettext('sugar-toolkit', msg1, msg2, n) + def printable_hash(in_hash): """Convert binary hash data into printable characters.""" printable = "" @@ -222,8 +224,8 @@ def timestamp_to_elapsed_string(timestamp, max_levels=2): if levels > 0: time_period += COMMA - time_period += gettext.ngettext(name_singular, name_plural, - elapsed_units) % elapsed_units + time_period += _ngettext(name_singular, name_plural, + elapsed_units) % elapsed_units elapsed_seconds -= elapsed_units * factor |