diff --git a/js/ui/environment.js b/js/ui/environment.js index 0adf3af6e..d6405b3a3 100644 --- a/js/ui/environment.js +++ b/js/ui/environment.js @@ -88,8 +88,6 @@ function init() { _blockMethod('Clutter.Event.get_state', 'Shell.get_event_state', 'gjs\'s handling of Clutter.ModifierType is broken. See bug 597292.'); - _blockMethod('Gdk.Device.get_state', 'global.get_pointer', - 'gjs\'s handling of Gdk.ModifierType is broken. See bug 597292.'); _blockMethod('Gdk.Window.get_device_position', 'global.get_pointer', 'gjs\'s handling of Gdk.ModifierType is broken. See bug 597292.'); diff --git a/js/ui/overview.js b/js/ui/overview.js index 353d769e8..35c1b05c4 100644 --- a/js/ui/overview.js +++ b/js/ui/overview.js @@ -167,6 +167,7 @@ Overview.prototype = { this._windowSwitchTimeoutId = 0; this._windowSwitchTimestamp = 0; this._lastActiveWorkspaceIndex = -1; + this._lastHoveredWindow = null; this._needsFakePointerEvent = false; this.workspaces = null; @@ -186,7 +187,7 @@ Overview.prototype = { global.screen.get_workspace_by_index(this._lastActiveWorkspaceIndex).activate(time); this.hideTemporarily(); } - + this._lastHoveredWindow = null; DND.removeMonitor(this._dragMonitor); }, @@ -200,15 +201,24 @@ Overview.prototype = { }, _onDragMotion: function(dragEvent) { + let targetIsWindow = dragEvent.targetActor && + dragEvent.targetActor._delegate && + dragEvent.targetActor._delegate.metaWindow; + + if (targetIsWindow && + dragEvent.targetActor._delegate.metaWindow == this._lastHoveredWindow) + return DND.DragMotionResult.CONTINUE; + + this._lastHoveredWindow = null; + if (this._windowSwitchTimeoutId != 0) { Mainloop.source_remove(this._windowSwitchTimeoutId); this._windowSwitchTimeoutId = 0; this._needsFakePointerEvent = false; } - if (dragEvent.targetActor && - dragEvent.targetActor._delegate && - dragEvent.targetActor._delegate.metaWindow) { + if (targetIsWindow) { + this._lastHoveredWindow = dragEvent.targetActor._delegate.metaWindow; this._windowSwitchTimestamp = global.get_current_time(); this._windowSwitchTimeoutId = Mainloop.timeout_add(DND_WINDOW_SWITCH_TIMEOUT, Lang.bind(this, function() { @@ -216,6 +226,7 @@ Overview.prototype = { Main.activateWindow(dragEvent.targetActor._delegate.metaWindow, this._windowSwitchTimestamp); this.hideTemporarily(); + this._lastHoveredWindow = null; })); } diff --git a/js/ui/search.js b/js/ui/search.js index f7be6af47..24b411ab6 100644 --- a/js/ui/search.js +++ b/js/ui/search.js @@ -224,8 +224,8 @@ SearchProvider.prototype = { }; Signals.addSignalMethods(SearchProvider.prototype); -function OpenSearchSystem(title) { - this._init(title); +function OpenSearchSystem() { + this._init(); } OpenSearchSystem.prototype = { diff --git a/po/ar.po b/po/ar.po index 444942326..f6f6902b9 100644 --- a/po/ar.po +++ b/po/ar.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: HEAD\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-01-12 11:29+0200\n" -"PO-Revision-Date: 2011-01-12 11:29+0300\n" +"POT-Creation-Date: 2011-01-19 22:47+0200\n" +"PO-Revision-Date: 2011-01-19 22:47+0300\n" "Last-Translator: Khaled Hosny \n" "Language-Team: Arabic \n" "MIME-Version: 1.0\n" @@ -133,6 +133,10 @@ msgstr "" msgid "Whether to collect stats about applications usage" msgstr "" +#: ../data/org.gnome.shell.gschema.xml.in.h:22 +msgid "disabled OpenSearch providers" +msgstr "" + #: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:1 msgid "Clip the crosshairs at the center" msgstr "" @@ -258,6 +262,21 @@ msgstr "" msgid "Width of the vertical and horizontal lines that make up the crosshairs." msgstr "" +#. Replace "Error invoking GLib.shell_parse_argv: " with +#. something nicer +#: ../js/misc/util.js:108 +msgid "Could not parse command:" +msgstr "تعذّر تحليل الأمر:" + +#: ../js/misc/util.js:130 +msgid "No such application" +msgstr "لا تطبيق بهذا الاسم" + +#: ../js/misc/util.js:143 ../js/ui/runDialog.js:351 +#, c-format +msgid "Execution of '%s' failed:" +msgstr "فشل تنفيذ '%s':‏" + #. Translators: Filter to display all applications #: ../js/ui/appDisplay.js:155 msgid "All" @@ -297,118 +316,191 @@ msgstr "أزيل %s من مفضّلتك." msgid "Remove" msgstr "أزِل" -#: ../js/ui/docDisplay.js:494 +#: ../js/ui/docDisplay.js:18 msgid "RECENT ITEMS" msgstr "العناصر الحديثة" -#: ../js/ui/lookingGlass.js:552 +#: ../js/ui/endSessionDialog.js:63 +#, c-format +msgid "Log Out %s" +msgstr "اخرج%.0s" + +#: ../js/ui/endSessionDialog.js:64 ../js/ui/endSessionDialog.js:69 +msgid "Log Out" +msgstr "اخرج" + +#: ../js/ui/endSessionDialog.js:65 +msgid "Click Log Out to quit these applications and log out of the system." +msgstr "انقر على \"اخرج\" لغلق هذه التطبيقات والخروج من النظام." + +#: ../js/ui/endSessionDialog.js:66 +#, c-format +msgid "%s will be logged out automatically in %d seconds." +msgstr "سيُخرج %s تلقائيا بعد %d ثوان." + +#: ../js/ui/endSessionDialog.js:67 +#, c-format +msgid "You will be logged out automatically in %d seconds." +msgstr "ستُخرج تلقائيا بعد %d ثوان." + +#: ../js/ui/endSessionDialog.js:68 +msgid "Logging out of the system." +msgstr "يخرج من النظام." + +#: ../js/ui/endSessionDialog.js:74 ../js/ui/endSessionDialog.js:78 +msgid "Shut Down" +msgstr "أطفئ" + +#: ../js/ui/endSessionDialog.js:75 +msgid "Click Shut Down to quit these applications and shut down the system." +msgstr "انقر على \"أطفئ\" لغلق هذه التطبيقات وإطفاء النظام." + +#: ../js/ui/endSessionDialog.js:76 +#, c-format +msgid "The system will shut down automatically in %d seconds." +msgstr "سيُطفأ النظام تلقائيا خلال %d ثوان." + +#: ../js/ui/endSessionDialog.js:77 +msgid "Shutting down the system." +msgstr "يُغلق النظام." + +#: ../js/ui/endSessionDialog.js:84 ../js/ui/endSessionDialog.js:88 +msgid "Restart" +msgstr "أعِد التشغيل" + +#: ../js/ui/endSessionDialog.js:85 +msgid "Click Restart to quit these applications and restart the system." +msgstr "انقر على \"أعِد التشغيل\" لغلق هذه التطبيقات إعادة تشغيل النظام." + +#: ../js/ui/endSessionDialog.js:86 +#, c-format +msgid "The system will restart automatically in %d seconds." +msgstr "سيُعاد تشغيل النظام تلقائيا خلال %d ثوان." + +#: ../js/ui/endSessionDialog.js:87 +msgid "Restarting the system." +msgstr "يُعيد تشغيل النظام." + +#: ../js/ui/endSessionDialog.js:395 +msgid "Confirm" +msgstr "أكّد" + +#: ../js/ui/endSessionDialog.js:400 ../js/ui/status/bluetooth.js:470 +msgid "Cancel" +msgstr "ألغِ" + +#: ../js/ui/lookingGlass.js:556 msgid "No extensions installed" msgstr "لم تثبّت أية امتدادات" -#: ../js/ui/lookingGlass.js:589 +#: ../js/ui/lookingGlass.js:593 msgid "Enabled" msgstr "مفعّل" #. translators: #. * The device has been disabled -#: ../js/ui/lookingGlass.js:591 ../src/gvc/gvc-mixer-control.c:1087 +#: ../js/ui/lookingGlass.js:595 ../src/gvc/gvc-mixer-control.c:1087 msgid "Disabled" msgstr "معطّل" -#: ../js/ui/lookingGlass.js:593 +#: ../js/ui/lookingGlass.js:597 msgid "Error" msgstr "خطأ" -#: ../js/ui/lookingGlass.js:595 +#: ../js/ui/lookingGlass.js:599 msgid "Out of date" msgstr "غير محدث" -#: ../js/ui/lookingGlass.js:620 +#: ../js/ui/lookingGlass.js:624 msgid "View Source" msgstr "اعرض المصدر" -#: ../js/ui/lookingGlass.js:626 +#: ../js/ui/lookingGlass.js:630 msgid "Web Page" msgstr "صفحة الوب" -#: ../js/ui/overview.js:101 +#: ../js/ui/messageTray.js:1765 +msgid "System Information" +msgstr "معلومات النظام" + +#: ../js/ui/overview.js:75 msgid "Undo" msgstr "تراجع" -#: ../js/ui/overview.js:166 +#: ../js/ui/overview.js:140 msgid "Windows" msgstr "النوافذ" -#: ../js/ui/overview.js:169 +#: ../js/ui/overview.js:143 msgid "Applications" msgstr "التطبيقات" #. TODO - _quit() doesn't really work on apps in state STARTING yet -#: ../js/ui/panel.js:478 +#: ../js/ui/panel.js:479 #, c-format msgid "Quit %s" msgstr "أغلق %s" #. Translators: This is the time format with date used #. in 24-hour mode. -#: ../js/ui/panel.js:563 +#: ../js/ui/panel.js:564 msgid "%a %b %e, %R:%S" msgstr "%A %e %B، %R:%S" -#: ../js/ui/panel.js:564 +#: ../js/ui/panel.js:565 msgid "%a %b %e, %R" msgstr "%A %e %B، %R" #. Translators: This is the time format without date used #. in 24-hour mode. -#: ../js/ui/panel.js:568 +#: ../js/ui/panel.js:569 msgid "%a %R:%S" msgstr "%A %R:%S" -#: ../js/ui/panel.js:569 +#: ../js/ui/panel.js:570 msgid "%a %R" msgstr "%A %R" #. Translators: This is a time format with date used #. for AM/PM. -#: ../js/ui/panel.js:576 +#: ../js/ui/panel.js:577 msgid "%a %b %e, %l:%M:%S %p" msgstr "%A %e %B، %l:%M:%S %p" -#: ../js/ui/panel.js:577 +#: ../js/ui/panel.js:578 msgid "%a %b %e, %l:%M %p" msgstr "%A %e %B، %l:%M %p" #. Translators: This is a time format without date used #. for AM/PM. -#: ../js/ui/panel.js:581 +#: ../js/ui/panel.js:582 msgid "%a %l:%M:%S %p" msgstr "%A %l:%M:%S %p" -#: ../js/ui/panel.js:582 +#: ../js/ui/panel.js:583 msgid "%a %l:%M %p" msgstr "%A %Ol:%OM %p" #. Button on the left side of the panel. #. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview". -#: ../js/ui/panel.js:727 +#: ../js/ui/panel.js:728 msgid "Activities" msgstr "الأنشطة" -#: ../js/ui/placeDisplay.js:111 +#: ../js/ui/placeDisplay.js:106 #, c-format msgid "Failed to unmount '%s'" msgstr "فشل فصْل '%s'" -#: ../js/ui/placeDisplay.js:114 +#: ../js/ui/placeDisplay.js:109 msgid "Retry" msgstr "أعد المحاولة" -#: ../js/ui/placeDisplay.js:159 +#: ../js/ui/placeDisplay.js:150 msgid "Connect to..." msgstr "اتّصل ب‍..." -#: ../js/ui/placeDisplay.js:558 +#: ../js/ui/placeDisplay.js:386 msgid "PLACES & DEVICES" msgstr "الأماكن والأجهزة" @@ -421,84 +513,79 @@ msgstr "الأماكن والأجهزة" msgid "toggle-switch-us" msgstr "toggle-switch-intl" -#: ../js/ui/runDialog.js:238 +#: ../js/ui/runDialog.js:209 msgid "Please enter a command:" msgstr "من فضلك اكتب أمرا:" -#: ../js/ui/runDialog.js:383 -#, c-format -msgid "Execution of '%s' failed:" -msgstr "فشل تنفيذ '%s':‏" - -#: ../js/ui/statusMenu.js:101 +#: ../js/ui/statusMenu.js:102 msgid "Available" msgstr "متاح" -#: ../js/ui/statusMenu.js:106 +#: ../js/ui/statusMenu.js:107 msgid "Busy" msgstr "مشغول" -#: ../js/ui/statusMenu.js:114 +#: ../js/ui/statusMenu.js:115 msgid "My Account" msgstr "حسابي" -#: ../js/ui/statusMenu.js:118 +#: ../js/ui/statusMenu.js:119 msgid "System Settings" msgstr "إعدادات النظام" -#: ../js/ui/statusMenu.js:125 +#: ../js/ui/statusMenu.js:126 msgid "Lock Screen" msgstr "أوصد الشاشة" -#: ../js/ui/statusMenu.js:129 +#: ../js/ui/statusMenu.js:130 msgid "Switch User" msgstr "بدّل المستخدم" -#: ../js/ui/statusMenu.js:134 +#: ../js/ui/statusMenu.js:135 msgid "Log Out..." msgstr "اخرج..." -#: ../js/ui/statusMenu.js:141 +#: ../js/ui/statusMenu.js:142 msgid "Suspend..." msgstr "علّق..." -#: ../js/ui/statusMenu.js:145 +#: ../js/ui/statusMenu.js:146 msgid "Shut Down..." msgstr "أطفئ..." -#: ../js/ui/status/accessibility.js:82 +#: ../js/ui/status/accessibility.js:83 msgid "Zoom" msgstr "تقريب" -#: ../js/ui/status/accessibility.js:88 +#: ../js/ui/status/accessibility.js:89 msgid "Screen Reader" msgstr "قارئ الشاشة" -#: ../js/ui/status/accessibility.js:91 +#: ../js/ui/status/accessibility.js:92 msgid "Screen Keyboard" msgstr "لوحة مفاتيح على الشاشة" -#: ../js/ui/status/accessibility.js:94 +#: ../js/ui/status/accessibility.js:95 msgid "Visual Alerts" msgstr "تنبيهات بصرية" -#: ../js/ui/status/accessibility.js:97 +#: ../js/ui/status/accessibility.js:98 msgid "Sticky Keys" msgstr "مفاتيح لاصقة" -#: ../js/ui/status/accessibility.js:100 +#: ../js/ui/status/accessibility.js:101 msgid "Slow Keys" msgstr "مفاتيح بطيئة" -#: ../js/ui/status/accessibility.js:103 +#: ../js/ui/status/accessibility.js:104 msgid "Bounce Keys" msgstr "مفاتيح لها صوت" -#: ../js/ui/status/accessibility.js:106 +#: ../js/ui/status/accessibility.js:107 msgid "Mouse Keys" msgstr "مفاتيح الفأرة" -#: ../js/ui/status/accessibility.js:110 +#: ../js/ui/status/accessibility.js:111 msgid "Universal Access Settings" msgstr "إعدادات الإتاحة" @@ -510,7 +597,7 @@ msgstr "تباين عال" msgid "Large Text" msgstr "نص كبير" -#: ../js/ui/status/bluetooth.js:42 ../js/ui/status/bluetooth.js:240 +#: ../js/ui/status/bluetooth.js:42 ../js/ui/status/bluetooth.js:241 msgid "Bluetooth" msgstr "بلوتوث" @@ -526,110 +613,106 @@ msgstr "أرسِل ملفات للجهاز..." msgid "Setup a New Device..." msgstr "اضبط جهازا جديدا..." -#: ../js/ui/status/bluetooth.js:94 +#: ../js/ui/status/bluetooth.js:95 msgid "Bluetooth Settings" msgstr "إعدادات بلوتوث" -#: ../js/ui/status/bluetooth.js:191 +#: ../js/ui/status/bluetooth.js:192 msgid "Connection" msgstr "الاتصال" -#: ../js/ui/status/bluetooth.js:227 +#: ../js/ui/status/bluetooth.js:228 msgid "Send Files..." msgstr "أرسل ملفات..." -#: ../js/ui/status/bluetooth.js:232 +#: ../js/ui/status/bluetooth.js:233 msgid "Browse Files..." msgstr "تصفح الملفات..." -#: ../js/ui/status/bluetooth.js:241 +#: ../js/ui/status/bluetooth.js:242 msgid "Error browsing device" msgstr "عطل أثناء تصفّح الجهاز" -#: ../js/ui/status/bluetooth.js:242 +#: ../js/ui/status/bluetooth.js:243 #, c-format msgid "The requested device cannot be browsed, error is '%s'" msgstr "تعذّر تصفح الجهاز، رسالة العطل '%s'" -#: ../js/ui/status/bluetooth.js:250 +#: ../js/ui/status/bluetooth.js:251 ../js/ui/status/keyboard.js:78 msgid "Keyboard Settings" msgstr "إعدادات لوحة المفاتيح" -#: ../js/ui/status/bluetooth.js:255 +#: ../js/ui/status/bluetooth.js:256 msgid "Mouse Settings" msgstr "إعدادات الفأرة" -#: ../js/ui/status/bluetooth.js:262 ../js/ui/status/volume.js:62 +#: ../js/ui/status/bluetooth.js:263 ../js/ui/status/volume.js:63 msgid "Sound Settings" msgstr "إعدادات الصوت" -#: ../js/ui/status/bluetooth.js:336 ../js/ui/status/bluetooth.js:370 -#: ../js/ui/status/bluetooth.js:410 ../js/ui/status/bluetooth.js:443 +#: ../js/ui/status/bluetooth.js:337 ../js/ui/status/bluetooth.js:371 +#: ../js/ui/status/bluetooth.js:411 ../js/ui/status/bluetooth.js:444 msgid "Bluetooth Agent" msgstr "عميل بلوتوث" -#: ../js/ui/status/bluetooth.js:371 +#: ../js/ui/status/bluetooth.js:372 #, c-format msgid "Authorization request from %s" msgstr "طلب تخويل من %s" -#: ../js/ui/status/bluetooth.js:377 +#: ../js/ui/status/bluetooth.js:378 #, c-format msgid "Device %s wants access to the service '%s'" msgstr "يريد الجهاز %s صلاحية الوصول للخدمة '%s'" -#: ../js/ui/status/bluetooth.js:379 +#: ../js/ui/status/bluetooth.js:380 msgid "Always grant access" msgstr "امنح الصلاحية دائما" -#: ../js/ui/status/bluetooth.js:380 +#: ../js/ui/status/bluetooth.js:381 msgid "Grant this time only" msgstr "امنح هذه المرة فقط" -#: ../js/ui/status/bluetooth.js:381 +#: ../js/ui/status/bluetooth.js:382 msgid "Reject" msgstr "أخرج" -#: ../js/ui/status/bluetooth.js:411 +#: ../js/ui/status/bluetooth.js:412 #, c-format msgid "Pairing confirmation for %s" msgstr "تأكيد مزاوجة %s" -#: ../js/ui/status/bluetooth.js:417 ../js/ui/status/bluetooth.js:451 +#: ../js/ui/status/bluetooth.js:418 ../js/ui/status/bluetooth.js:452 #, c-format msgid "Device %s wants to pair with this computer" msgstr "يريد الجهاز %s المزاوجة مع هذا الحاسوب" -#: ../js/ui/status/bluetooth.js:418 +#: ../js/ui/status/bluetooth.js:419 #, c-format msgid "Please confirm whether the PIN '%s' matches the one on the device." msgstr "من فضلك أكد تطابق الرقم '%s' مع الموجود على الجهاز." -#: ../js/ui/status/bluetooth.js:420 +#: ../js/ui/status/bluetooth.js:421 msgid "Matches" msgstr "مطابقات" -#: ../js/ui/status/bluetooth.js:421 +#: ../js/ui/status/bluetooth.js:422 msgid "Does not match" msgstr "لا تتطابق" -#: ../js/ui/status/bluetooth.js:444 +#: ../js/ui/status/bluetooth.js:445 #, c-format msgid "Pairing request for %s" msgstr "طلب مزاوجة من %s" -#: ../js/ui/status/bluetooth.js:452 +#: ../js/ui/status/bluetooth.js:453 msgid "Please enter the PIN mentioned on the device." msgstr "من فضلك أدخل الرقم المذكور على الجهاز." -#: ../js/ui/status/bluetooth.js:468 +#: ../js/ui/status/bluetooth.js:469 msgid "OK" msgstr "حسنا" -#: ../js/ui/status/bluetooth.js:469 -msgid "Cancel" -msgstr "ألغِ" - #: ../js/ui/status/power.js:85 msgid "Power Settings" msgstr "إعدادات الطاقة" @@ -654,7 +737,7 @@ msgstr "بقي %d %s و %d %s" #: ../js/ui/status/power.js:117 msgid "hour" msgid_plural "hours" -msgstr[0] "أقل من ساعة" +msgstr[0] "ساعة" msgstr[1] "ساعة" msgstr[2] "ساعتين" msgstr[3] "ساعات" @@ -664,7 +747,7 @@ msgstr[5] "ساعة" #: ../js/ui/status/power.js:117 msgid "minute" msgid_plural "minutes" -msgstr[0] "أقل من دقيقة" +msgstr[0] "دقيقة" msgstr[1] "دقيقة" msgstr[2] "دقيقتين" msgstr[3] "دقائق" @@ -682,59 +765,59 @@ msgstr[3] "بقي %d دقائق" msgstr[4] "بقي %d دقيقة" msgstr[5] "بقي %d دقيقة" -#: ../js/ui/status/power.js:237 +#: ../js/ui/status/power.js:235 msgid "AC adapter" msgstr "مقبس طاقة" -#: ../js/ui/status/power.js:239 +#: ../js/ui/status/power.js:237 msgid "Laptop battery" msgstr "بطارية حاسوب محمول" -#: ../js/ui/status/power.js:241 +#: ../js/ui/status/power.js:239 msgid "UPS" msgstr "مزود طاقة لا منقطعة" -#: ../js/ui/status/power.js:243 +#: ../js/ui/status/power.js:241 msgid "Monitor" msgstr "شاشة" -#: ../js/ui/status/power.js:245 +#: ../js/ui/status/power.js:243 msgid "Mouse" msgstr "فأرة" -#: ../js/ui/status/power.js:247 +#: ../js/ui/status/power.js:245 msgid "Keyboard" msgstr "لوحة المفاتيح" -#: ../js/ui/status/power.js:249 +#: ../js/ui/status/power.js:247 msgid "PDA" msgstr "مساعد رقمي" -#: ../js/ui/status/power.js:251 +#: ../js/ui/status/power.js:249 msgid "Cell phone" msgstr "هاتف محمول" -#: ../js/ui/status/power.js:253 +#: ../js/ui/status/power.js:251 msgid "Media player" msgstr "مشغل وسائط" -#: ../js/ui/status/power.js:255 +#: ../js/ui/status/power.js:253 msgid "Tablet" msgstr "لوحة" -#: ../js/ui/status/power.js:257 +#: ../js/ui/status/power.js:255 msgid "Computer" msgstr "حاسوب" -#: ../js/ui/status/power.js:259 ../src/shell-app-system.c:1012 +#: ../js/ui/status/power.js:257 ../src/shell-app-system.c:1012 msgid "Unknown" msgstr "مجهول" -#: ../js/ui/status/volume.js:41 +#: ../js/ui/status/volume.js:42 msgid "Volume" msgstr "جزء" -#: ../js/ui/status/volume.js:54 +#: ../js/ui/status/volume.js:55 msgid "Microphone" msgstr "ميكروفون" @@ -819,11 +902,11 @@ msgstr[5] "%u مدخل" msgid "System Sounds" msgstr "أصوات النظام" -#: ../src/shell-global.c:1233 +#: ../src/shell-global.c:1366 msgid "Less than a minute ago" msgstr "منذ أقل من دقيقة" -#: ../src/shell-global.c:1237 +#: ../src/shell-global.c:1370 #, c-format msgid "%d minute ago" msgid_plural "%d minutes ago" @@ -834,7 +917,7 @@ msgstr[3] "منذ %d دقائق" msgstr[4] "منذ %d دقيقة" msgstr[5] "منذ %d دقيقة" -#: ../src/shell-global.c:1242 +#: ../src/shell-global.c:1375 #, c-format msgid "%d hour ago" msgid_plural "%d hours ago" @@ -845,7 +928,7 @@ msgstr[3] "منذ %d ساعات" msgstr[4] "منذ %d ساعة" msgstr[5] "منذ %d ساعة" -#: ../src/shell-global.c:1247 +#: ../src/shell-global.c:1380 #, c-format msgid "%d day ago" msgid_plural "%d days ago" @@ -856,7 +939,7 @@ msgstr[3] "منذ %d أيام" msgstr[4] "منذ %d يوما" msgstr[5] "منذ %d يوم" -#: ../src/shell-global.c:1252 +#: ../src/shell-global.c:1385 #, c-format msgid "%d week ago" msgid_plural "%d weeks ago" @@ -939,12 +1022,6 @@ msgstr "‏%1$s:‏ %2$s" #~ msgid "System Preferences..." #~ msgstr "تفضيلات النظام..." -#~ msgid "Restart..." -#~ msgstr "أعد التشغيل..." - -#~ msgid "Account Information..." -#~ msgstr "معلومات الحساب..." - #~ msgid "%H:%M" #~ msgstr "%OH:%OM" diff --git a/po/es.po b/po/es.po index fd320aa69..0fb03cdb4 100644 --- a/po/es.po +++ b/po/es.po @@ -9,8 +9,8 @@ msgstr "" "Project-Id-Version: gnome-shell.master\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-" "shell&component=general\n" -"POT-Creation-Date: 2011-01-15 00:23+0000\n" -"PO-Revision-Date: 2011-01-16 13:26+0100\n" +"POT-Creation-Date: 2011-01-17 21:45+0000\n" +"PO-Revision-Date: 2011-01-19 16:17+0100\n" "Last-Translator: Daniel Mustieles \n" "Language-Team: Español \n" "MIME-Version: 1.0\n" @@ -88,13 +88,13 @@ msgid "" "'videorate ! theoraenc ! oggmux' and records to Ogg Theora." msgstr "" "Establece la tubería GStreamer usada para codificar grabaciones. Sigue la " -"sintaxis usada para gst-launch. La tubería debería tener un sumidero " -"(«sink») de ensamblaje/sesensamblaje donde el vídeo que se está grabando se " -"graba. Generalmente tendrá un origen de ensamblado/desensamblado; la salida " -"de ese punto se escibirá en el archivo de salida. No obstante la tubería " -"también puede tomar parte en su propia salida; esto se puede usar para " -"enviar la salida a un servidor «icecast» a través de shout2send o similar. " -"Cuando no está establecido o lo está a un valor vacío, se usará la tubería " +"sintaxis usada para gst-launch. La tubería debería tener un sumidero («sink») " +"de ensamblaje/sesensamblaje donde el vídeo que se está grabando se graba. " +"Generalmente tendrá un origen de ensamblado/desensamblado; la salida de ese " +"punto se escibirá en el archivo de salida. No obstante la tubería también " +"puede tomar parte en su propia salida; esto se puede usar para enviar la " +"salida a un servidor «icecast» a través de shout2send o similar. Cuando no " +"está establecido o lo está a un valor vacío, se usará la tubería " "predeterminada. Actualmente es «videorate ! theoraenc ! oggmux» y greba en " "Ogg Theora." @@ -161,6 +161,10 @@ msgid "Whether to collect stats about applications usage" msgstr "" "Indica si se deben recolectar estadísticas acerca del uso de las aplicaciones" +#: ../data/org.gnome.shell.gschema.xml.in.h:22 +msgid "disabled OpenSearch providers" +msgstr "proveedores OpenSearch desactivados" + #: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:1 msgid "Clip the crosshairs at the center" msgstr "Fijar los cursores en el centro" @@ -321,16 +325,14 @@ msgstr "" #. Replace "Error invoking GLib.shell_parse_argv: " with #. something nicer #: ../js/misc/util.js:108 -#| msgid "Please enter a command:" msgid "Could not parse command:" msgstr "No se pudo analizar el comando:" #: ../js/misc/util.js:130 -#| msgid "Applications" msgid "No such application" msgstr "No existe la aplicación" -#: ../js/misc/util.js:143 ../js/ui/runDialog.js:364 +#: ../js/misc/util.js:143 ../js/ui/runDialog.js:351 #, c-format msgid "Execution of '%s' failed:" msgstr "Falló la ejecución de «%s»:" @@ -380,12 +382,10 @@ msgstr "ELEMENTOS RECIENTES" #: ../js/ui/endSessionDialog.js:63 #, c-format -#| msgid "Log Out..." msgid "Log Out %s" msgstr "Cerrar la sesión %s" #: ../js/ui/endSessionDialog.js:64 ../js/ui/endSessionDialog.js:69 -#| msgid "Log Out..." msgid "Log Out" msgstr "Cerrar la sesión" @@ -410,7 +410,6 @@ msgid "Logging out of the system." msgstr "Cerrando la sesión." #: ../js/ui/endSessionDialog.js:74 ../js/ui/endSessionDialog.js:78 -#| msgid "Shut Down..." msgid "Shut Down" msgstr "Apagar" @@ -428,7 +427,6 @@ msgid "Shutting down the system." msgstr "Apagando el sistema." #: ../js/ui/endSessionDialog.js:84 ../js/ui/endSessionDialog.js:88 -#| msgid "Restart..." msgid "Restart" msgstr "Reiniciar" @@ -450,7 +448,7 @@ msgstr "Reiniciando el sistema." msgid "Confirm" msgstr "Confirmar" -#: ../js/ui/endSessionDialog.js:400 ../js/ui/status/bluetooth.js:469 +#: ../js/ui/endSessionDialog.js:400 ../js/ui/status/bluetooth.js:470 msgid "Cancel" msgstr "Cancelar" @@ -485,7 +483,6 @@ msgid "Web Page" msgstr "Página web" #: ../js/ui/messageTray.js:1748 -#| msgid "Account Information..." msgid "System Information" msgstr "Información del sistema" @@ -553,20 +550,20 @@ msgstr "%a %H:%M" msgid "Activities" msgstr "Actividades" -#: ../js/ui/placeDisplay.js:112 +#: ../js/ui/placeDisplay.js:106 #, c-format msgid "Failed to unmount '%s'" msgstr "Falló al desmontar «%s»" -#: ../js/ui/placeDisplay.js:115 +#: ../js/ui/placeDisplay.js:109 msgid "Retry" msgstr "Reintentar" -#: ../js/ui/placeDisplay.js:160 +#: ../js/ui/placeDisplay.js:150 msgid "Connect to..." msgstr "Conectar a…" -#: ../js/ui/placeDisplay.js:559 +#: ../js/ui/placeDisplay.js:386 msgid "PLACES & DEVICES" msgstr "LUGARES Y DISPOSITIVOS" @@ -579,7 +576,7 @@ msgstr "LUGARES Y DISPOSITIVOS" msgid "toggle-switch-us" msgstr "toggle-switch-intl" -#: ../js/ui/runDialog.js:222 +#: ../js/ui/runDialog.js:209 msgid "Please enter a command:" msgstr "Introduzca un comando:" @@ -663,7 +660,7 @@ msgstr "Contraste alto" msgid "Large Text" msgstr "Texto:" -#: ../js/ui/status/bluetooth.js:42 ../js/ui/status/bluetooth.js:240 +#: ../js/ui/status/bluetooth.js:42 ../js/ui/status/bluetooth.js:241 msgid "Bluetooth" msgstr "Bluetooth" @@ -679,103 +676,103 @@ msgstr "Enviar archivos al dispositivo…" msgid "Setup a New Device..." msgstr "Configurar un dispositivo nuevo…" -#: ../js/ui/status/bluetooth.js:94 +#: ../js/ui/status/bluetooth.js:95 msgid "Bluetooth Settings" msgstr "Configuración de Bluetooth" -#: ../js/ui/status/bluetooth.js:191 +#: ../js/ui/status/bluetooth.js:192 msgid "Connection" msgstr "Conexión" -#: ../js/ui/status/bluetooth.js:227 +#: ../js/ui/status/bluetooth.js:228 msgid "Send Files..." msgstr "Enviar archivos…" -#: ../js/ui/status/bluetooth.js:232 +#: ../js/ui/status/bluetooth.js:233 msgid "Browse Files..." msgstr "Examinar archivos…" -#: ../js/ui/status/bluetooth.js:241 +#: ../js/ui/status/bluetooth.js:242 msgid "Error browsing device" msgstr "Error al examinar el dispositivo" -#: ../js/ui/status/bluetooth.js:242 +#: ../js/ui/status/bluetooth.js:243 #, c-format msgid "The requested device cannot be browsed, error is '%s'" msgstr "No se puede examinar el dispositivo solicitado, el error es «%s»" -#: ../js/ui/status/bluetooth.js:250 ../js/ui/status/keyboard.js:78 +#: ../js/ui/status/bluetooth.js:251 ../js/ui/status/keyboard.js:78 msgid "Keyboard Settings" msgstr "Configuración del teclado" -#: ../js/ui/status/bluetooth.js:255 +#: ../js/ui/status/bluetooth.js:256 msgid "Mouse Settings" msgstr "Ajustes del ratón…" -#: ../js/ui/status/bluetooth.js:262 ../js/ui/status/volume.js:63 +#: ../js/ui/status/bluetooth.js:263 ../js/ui/status/volume.js:63 msgid "Sound Settings" msgstr "Configuración del sonido" -#: ../js/ui/status/bluetooth.js:336 ../js/ui/status/bluetooth.js:370 -#: ../js/ui/status/bluetooth.js:410 ../js/ui/status/bluetooth.js:443 +#: ../js/ui/status/bluetooth.js:337 ../js/ui/status/bluetooth.js:371 +#: ../js/ui/status/bluetooth.js:411 ../js/ui/status/bluetooth.js:444 msgid "Bluetooth Agent" msgstr "Agente Bluetooth" -#: ../js/ui/status/bluetooth.js:371 +#: ../js/ui/status/bluetooth.js:372 #, c-format msgid "Authorization request from %s" msgstr "Solicitud de autorización de %s" -#: ../js/ui/status/bluetooth.js:377 +#: ../js/ui/status/bluetooth.js:378 #, c-format msgid "Device %s wants access to the service '%s'" msgstr "El dispositivo %s quiere acceder al servicio «%s»" -#: ../js/ui/status/bluetooth.js:379 +#: ../js/ui/status/bluetooth.js:380 msgid "Always grant access" msgstr "Conceder acceso siempre" -#: ../js/ui/status/bluetooth.js:380 +#: ../js/ui/status/bluetooth.js:381 msgid "Grant this time only" msgstr "Conceder sólo esta vez" -#: ../js/ui/status/bluetooth.js:381 +#: ../js/ui/status/bluetooth.js:382 msgid "Reject" msgstr "Rechazar" -#: ../js/ui/status/bluetooth.js:411 +#: ../js/ui/status/bluetooth.js:412 #, c-format msgid "Pairing confirmation for %s" msgstr "Confirmación de emparejamiento para «%s»" -#: ../js/ui/status/bluetooth.js:417 ../js/ui/status/bluetooth.js:451 +#: ../js/ui/status/bluetooth.js:418 ../js/ui/status/bluetooth.js:452 #, c-format msgid "Device %s wants to pair with this computer" msgstr "El dispositivo «%s» quiere emparejarse con este equipo" -#: ../js/ui/status/bluetooth.js:418 +#: ../js/ui/status/bluetooth.js:419 #, c-format msgid "Please confirm whether the PIN '%s' matches the one on the device." msgstr "Confirme que el PIN mostrado en «%s» coincide con el del dispositivo." -#: ../js/ui/status/bluetooth.js:420 +#: ../js/ui/status/bluetooth.js:421 msgid "Matches" msgstr "Coincide" -#: ../js/ui/status/bluetooth.js:421 +#: ../js/ui/status/bluetooth.js:422 msgid "Does not match" msgstr "No coincide" -#: ../js/ui/status/bluetooth.js:444 +#: ../js/ui/status/bluetooth.js:445 #, c-format msgid "Pairing request for %s" msgstr "Solicitud de emparejamiento para «%s»" -#: ../js/ui/status/bluetooth.js:452 +#: ../js/ui/status/bluetooth.js:453 msgid "Please enter the PIN mentioned on the device." msgstr "Introduzca el PIN mencionado en el dispositivo." -#: ../js/ui/status/bluetooth.js:468 +#: ../js/ui/status/bluetooth.js:469 msgid "OK" msgstr "Aceptar" @@ -946,32 +943,32 @@ msgstr[1] "%u entradas" msgid "System Sounds" msgstr "Sonidos del sistema" -#: ../src/shell-global.c:1233 +#: ../src/shell-global.c:1366 msgid "Less than a minute ago" msgstr "Hace menos de un minuto" -#: ../src/shell-global.c:1237 +#: ../src/shell-global.c:1370 #, c-format msgid "%d minute ago" msgid_plural "%d minutes ago" msgstr[0] "Hace %d minuto" msgstr[1] "Hace %d minutos" -#: ../src/shell-global.c:1242 +#: ../src/shell-global.c:1375 #, c-format msgid "%d hour ago" msgid_plural "%d hours ago" msgstr[0] "Hace %d hora" msgstr[1] "Hace %d horas" -#: ../src/shell-global.c:1247 +#: ../src/shell-global.c:1380 #, c-format msgid "%d day ago" msgid_plural "%d days ago" msgstr[0] "Hace %d día" msgstr[1] "Hace %d días" -#: ../src/shell-global.c:1252 +#: ../src/shell-global.c:1385 #, c-format msgid "%d week ago" msgid_plural "%d weeks ago" @@ -1018,8 +1015,8 @@ msgstr "%1$s: %2$s" #~ "If true and format is either \"12-hour\" or \"24-hour\", display seconds " #~ "in time." #~ msgstr "" -#~ "Si es cierta y el formato es «12-horas» o «24-horas», muestra los " -#~ "segundos en la hora." +#~ "Si es cierta y el formato es «12-horas» o «24-horas», muestra los segundos " +#~ "en la hora." #~ msgid "" #~ "This key specifies the format used by the panel clock when the format key " @@ -1036,19 +1033,18 @@ msgstr "%1$s: %2$s" #~ msgid "" #~ "This key specifies the hour format used by the panel clock. Possible " #~ "values are \"12-hour\", \"24-hour\", \"unix\" and \"custom\". If set to " -#~ "\"unix\", the clock will display time in seconds since Epoch, i.e. " -#~ "1970-01-01. If set to \"custom\", the clock will display time according " -#~ "to the format specified in the custom_format key. Note that if set to " -#~ "either \"unix\" or \"custom\", the show_date and show_seconds keys are " -#~ "ignored." +#~ "\"unix\", the clock will display time in seconds since Epoch, i.e. 1970-" +#~ "01-01. If set to \"custom\", the clock will display time according to the " +#~ "format specified in the custom_format key. Note that if set to either " +#~ "\"unix\" or \"custom\", the show_date and show_seconds keys are ignored." #~ msgstr "" #~ "Esta clave especifica el formato de la hora especificado por el reloj del " -#~ "panel. Los valores posibles son «12-hour» (12 horas), «24-hour» (24 " -#~ "horas), «unix» y «custom» (personalizado).Si se establece a «unix» el " -#~ "reloj mostrará la hora en segundos desde la época (1 de enero de 1970). " -#~ "Si se establece a «custom» el reloj mostrará la hora según el formato " -#~ "especificado en la clave «custom_format». Note que si se establece a " -#~ "«unix» o «custom» se ignoran las claves «show_date» y «show_seconds»." +#~ "panel. Los valores posibles son «12-hour» (12 horas), «24-hour» (24 horas), " +#~ "«unix» y «custom» (personalizado).Si se establece a «unix» el reloj mostrará " +#~ "la hora en segundos desde la época (1 de enero de 1970). Si se establece " +#~ "a «custom» el reloj mostrará la hora según el formato especificado en la " +#~ "clave «custom_format». Note que si se establece a «unix» o «custom» se " +#~ "ignoran las claves «show_date» y «show_seconds»." #~ msgid "Clock Format" #~ msgstr "Formato del reloj" diff --git a/src/Makefile-st.am b/src/Makefile-st.am index e952a4abd..225ff5bc2 100644 --- a/src/Makefile-st.am +++ b/src/Makefile-st.am @@ -98,6 +98,7 @@ st_source_h = \ st/st-tooltip.h \ st/st-types.h \ st/st-widget.h \ + st/st-widget-accessible.h \ $(NULL) st.h: stamp-st.h diff --git a/src/Makefile.am b/src/Makefile.am index 0740f0667..f252e5bc1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -81,6 +81,8 @@ libgnome_shell_la_SOURCES = \ shell-wm-private.h \ gnome-shell-plugin.c \ shell-app.c \ + shell-a11y.h \ + shell-a11y.c \ shell-app-system.c \ shell-app-usage.c \ shell-arrow.c \ diff --git a/src/gnome-shell-plugin.c b/src/gnome-shell-plugin.c index c77cbdae4..96075f41f 100644 --- a/src/gnome-shell-plugin.c +++ b/src/gnome-shell-plugin.c @@ -52,6 +52,7 @@ #include "shell-perf-log.h" #include "shell-wm-private.h" #include "st.h" +#include "shell-a11y.h" static void gnome_shell_plugin_dispose (GObject *object); static void gnome_shell_plugin_finalize (GObject *object); @@ -420,6 +421,8 @@ gnome_shell_plugin_start (MetaPlugin *plugin) bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + shell_a11y_init (); + settings = gtk_settings_get_default (); g_object_connect (settings, "signal::notify::gtk-xft-dpi", diff --git a/src/gnome-shell.in b/src/gnome-shell.in index 8500d98cb..a1610293c 100755 --- a/src/gnome-shell.in +++ b/src/gnome-shell.in @@ -219,12 +219,23 @@ def start_shell(perf_output=None): js_dir = os.path.join('@pkgdatadir@', 'js') # Set up environment + + # About the value of NO_GAIL and NO_AT_BRIDGE: If a11y is enabled, + # gtk_init() will normally load gail and at-bridge. But we don't + # want at-bridge to be loaded until after clutter is initialized + # (which mutter does after initializing gtk) and we don't want + # gail to be loaded at all. So set these flags. shell_a11y_init() + # will clear them so they don't get passed to gnome-shell's + # children. + env = dict(os.environ) env.update({'GNOME_SHELL_JS' : js_dir, 'PATH' : '@MUTTER_BIN_DIR@:' + os.environ.get('PATH', ''), 'XDG_CONFIG_DIRS' : '@sysconfdir@/xdg:' + (os.environ.get('XDG_CONFIG_DIRS') or '/etc/xdg'), 'XDG_DATA_DIRS' : '@datadir@:' + (os.environ.get('XDG_DATA_DIRS') or '/usr/local/share:/usr/share'), - 'GNOME_DISABLE_CRASH_DIALOG' : '1'}) + 'GNOME_DISABLE_CRASH_DIALOG' : '1', + 'NO_GAIL' : '1', + 'NO_AT_BRIDGE' : '1'}) if running_from_source_tree: env.update({'GNOME_SHELL_DATADIR' : data_dir, diff --git a/src/shell-a11y.c b/src/shell-a11y.c new file mode 100644 index 000000000..1715cf649 --- /dev/null +++ b/src/shell-a11y.c @@ -0,0 +1,165 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Igalia, S.L. + * + * Author: Alejandro Piñeiro Iglesias + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include +#include +#include + +#include "shell-a11y.h" + +#define INIT_METHOD "gnome_accessibility_module_init" +#define DESKTOP_SCHEMA "org.gnome.desktop.interface" +#define ACCESSIBILITY_ENABLED_KEY "accessibility" +#define AT_SPI_SCHEMA "org.a11y.atspi" +#define ATK_BRIDGE_LOCATION_KEY "atk-bridge-location" + +static gboolean +should_enable_a11y (void) +{ + GSettings *desktop_settings = NULL; + gboolean value = FALSE; + + desktop_settings = g_settings_new (DESKTOP_SCHEMA); + value = g_settings_get_boolean (desktop_settings, ACCESSIBILITY_ENABLED_KEY); + + g_object_unref (desktop_settings); + + return value; +} + +static char* +get_atk_bridge_path (void) +{ + GSettings *atspi_settings = NULL; + char *value = NULL; + const char * const *schemas = NULL; + gboolean found = FALSE; + int i = 0; + + schemas = g_settings_list_schemas (); + + for (i = 0; schemas [i]; i++) + { + if (!strcmp (schemas[i], AT_SPI_SCHEMA)) + { + found = TRUE; + break; + } + } + + if (!found) + { + g_warning ("Accessibility: %s schema not found. Are you sure that at-spi or" + " at-spi2 is installed on your system?", AT_SPI_SCHEMA); + return NULL; + } + + atspi_settings = g_settings_new (AT_SPI_SCHEMA); + value = g_settings_get_string (atspi_settings, ATK_BRIDGE_LOCATION_KEY); + + g_object_unref (atspi_settings); + + return value; +} + +static gboolean +a11y_invoke_module (const char *module_path) +{ + GModule *handle; + void (*invoke_fn) (void); + + if (!module_path) + { + g_warning ("Accessibility: invalid module path (NULL)"); + + return FALSE; + } + + if (!(handle = g_module_open (module_path, 0))) + { + g_warning ("Accessibility: failed to load module '%s': '%s'", + module_path, g_module_error ()); + + return FALSE; + } + + if (!g_module_symbol (handle, INIT_METHOD, (gpointer *)&invoke_fn)) + { + g_warning ("Accessibility: error library '%s' does not include " + "method '%s' required for accessibility support", + module_path, INIT_METHOD); + g_module_close (handle); + + return FALSE; + } + + invoke_fn (); + + return TRUE; +} + +/* + * It loads the atk-bridge if required. It checks: + * * If the proper gsetting key is set + * * If clutter has already enabled the accessibility + * + * You need to ensure that the atk-bridge was not loaded before this + * call, because in that case the application would be already + * registered on at-spi using the AtkUtil implementation on that + * moment (if any, although without anyone the application would + * crash). Anyway this is the reason of NO_AT_BRIDGE. + * + */ +void +shell_a11y_init (void) +{ + char *bridge_path = NULL; + + g_unsetenv ("NO_AT_BRIDGE"); + g_unsetenv ("NO_GAIL"); + + if (!should_enable_a11y ()) + return; + + if (clutter_get_accessibility_enabled () == FALSE) + { + g_warning ("Accessibility: clutter has no accessibility enabled" + " skipping the atk-bridge load"); + return; + } + + bridge_path = get_atk_bridge_path (); + + if (a11y_invoke_module (bridge_path) == FALSE) + { + g_warning ("Accessibility: error loading the atk-bridge. Although the" + " accessibility on the system is enabled and clutter" + " accessibility is also enabled, accessibility support on" + " GNOME Shell will not work"); + } + + /* NOTE: We avoid to load gail module, as gail-cally interaction is + * not fully supported right now. + */ + + g_free (bridge_path); +} diff --git a/src/shell-a11y.h b/src/shell-a11y.h new file mode 100644 index 000000000..12e77ae41 --- /dev/null +++ b/src/shell-a11y.h @@ -0,0 +1,32 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Igalia, S.L. + * + * Author: Alejandro Piñeiro Iglesias + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __SHELL_A11Y_H_ +#define __SHELL_A11Y_H_ + +G_BEGIN_DECLS + +void shell_a11y_init (void); + +G_END_DECLS + +#endif /* __SHELL_A11Y_H_ */ diff --git a/src/st/st-label.c b/src/st/st-label.c index 38a7d715e..124928e80 100644 --- a/src/st/st-label.c +++ b/src/st/st-label.c @@ -44,6 +44,8 @@ #include "st-private.h" #include "st-widget.h" +#include + enum { PROP_0, @@ -65,6 +67,8 @@ struct _StLabelPrivate G_DEFINE_TYPE (StLabel, st_label, ST_TYPE_WIDGET); +static GType st_label_accessible_get_type (void) G_GNUC_CONST; + static void st_label_set_property (GObject *gobject, guint prop_id, @@ -290,6 +294,7 @@ st_label_class_init (StLabelClass *klass) actor_class->unmap = st_label_unmap; widget_class->style_changed = st_label_style_changed; + widget_class->get_accessible_type = st_label_accessible_get_type; pspec = g_param_spec_object ("clutter-text", "Clutter Text", @@ -403,3 +408,100 @@ st_label_get_clutter_text (StLabel *label) return label->priv->label; } + + +/******************************************************************************/ +/*************************** ACCESSIBILITY SUPPORT ****************************/ +/******************************************************************************/ + +#define ST_TYPE_LABEL_ACCESSIBLE st_label_accessible_get_type () + +#define ST_LABEL_ACCESSIBLE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + ST_TYPE_LABEL_ACCESSIBLE, StLabelAccessible)) + +#define ST_IS_LABEL_ACCESSIBLE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + ST_TYPE_LABEL_ACCESSIBLE)) + +#define ST_LABEL_ACCESSIBLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + ST_TYPE_LABEL_ACCESSIBLE, StLabelAccessibleClass)) + +#define ST_IS_LABEL_ACCESSIBLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + ST_TYPE_LABEL_ACCESSIBLE)) + +#define ST_LABEL_ACCESSIBLE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + ST_TYPE_LABEL_ACCESSIBLE, StLabelAccessibleClass)) + +typedef struct _StLabelAccessible StLabelAccessible; +typedef struct _StLabelAccessibleClass StLabelAccessibleClass; + +struct _StLabelAccessible +{ + StWidgetAccessible parent; +}; + +struct _StLabelAccessibleClass +{ + StWidgetAccessibleClass parent_class; +}; + +static void st_label_accessible_class_init (StLabelAccessibleClass *klass); +static void st_label_accessible_init (StLabelAccessible *label); + +/* AtkObject */ +static void st_label_accessible_initialize (AtkObject *obj, + gpointer data); +static const gchar * st_label_accessible_get_name (AtkObject *obj); + +G_DEFINE_TYPE (StLabelAccessible, st_label_accessible, ST_TYPE_WIDGET_ACCESSIBLE) + +static void +st_label_accessible_class_init (StLabelAccessibleClass *klass) +{ + AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass); + + atk_class->initialize = st_label_accessible_initialize; + atk_class->get_name = st_label_accessible_get_name; +} + +static void +st_label_accessible_init (StLabelAccessible *self) +{ + /* initialization done on AtkObject->initialize */ +} + +static void +st_label_accessible_initialize (AtkObject *obj, + gpointer data) +{ + ATK_OBJECT_CLASS (st_label_accessible_parent_class)->initialize (obj, data); + + obj->role = ATK_ROLE_LABEL; +} + +static const gchar * +st_label_accessible_get_name (AtkObject *obj) +{ + const gchar *name = NULL; + + g_return_val_if_fail (ST_IS_LABEL_ACCESSIBLE (obj), NULL); + + name = ATK_OBJECT_CLASS (st_label_accessible_parent_class)->get_name (obj); + if (name == NULL) + { + ClutterActor *actor = NULL; + + actor = CLUTTER_ACTOR (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (obj))); + + if (actor == NULL) /* State is defunct */ + name = NULL; + else + name = st_label_get_text (ST_LABEL (actor)); + } + + return name; +} diff --git a/src/st/st-widget-accessible.h b/src/st/st-widget-accessible.h new file mode 100644 index 000000000..c60f7787e --- /dev/null +++ b/src/st/st-widget-accessible.h @@ -0,0 +1,76 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * st-widget-accessible.h: Accessible object for StWidget + * + * Copyright 2010 Igalia, S.L. + * Author: Alejandro Piñeiro Iglesias + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU Lesser General Public License, + * version 2.1, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 program. If not, see . + */ + +#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION) +#error "Only can be included directly.h" +#endif + +#ifndef __ST_WIDGET_ACCESSIBLE_H__ +#define __ST_WIDGET_ACCESSIBLE_H__ + +G_BEGIN_DECLS + +#include +#include + +#define ST_TYPE_WIDGET_ACCESSIBLE st_widget_accessible_get_type () + +#define ST_WIDGET_ACCESSIBLE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + ST_TYPE_WIDGET_ACCESSIBLE, StWidgetAccessible)) + +#define ST_IS_WIDGET_ACCESSIBLE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + ST_TYPE_WIDGET_ACCESSIBLE)) + +#define ST_WIDGET_ACCESSIBLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + ST_TYPE_WIDGET_ACCESSIBLE, StWidgetAccessibleClass)) + +#define ST_IS_WIDGET_ACCESSIBLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + ST_TYPE_WIDGET_ACCESSIBLE)) + +#define ST_WIDGET_ACCESSIBLE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + ST_TYPE_WIDGET_ACCESSIBLE, StWidgetAccessibleClass)) + +typedef struct _StWidgetAccessible StWidgetAccessible; +typedef struct _StWidgetAccessibleClass StWidgetAccessibleClass; +typedef struct _StWidgetAccessiblePrivate StWidgetAccessiblePrivate; + +struct _StWidgetAccessible +{ + CallyActor parent; + + /*< private >*/ + StWidgetAccessiblePrivate *priv; +}; + +struct _StWidgetAccessibleClass +{ + CallyActorClass parent_class; +}; + +GType st_widget_accessible_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* __ST_WIDGET_ACCESSIBLE_H__ */ diff --git a/src/st/st-widget.c b/src/st/st-widget.c index 23b591d2f..8ebe1dd27 100644 --- a/src/st/st-widget.c +++ b/src/st/st-widget.c @@ -42,6 +42,8 @@ #include "st-tooltip.h" #include "st-theme-node-transition.h" +#include "st-widget-accessible.h" + /* * Forward declaration for sake of StWidgetChild */ @@ -67,6 +69,8 @@ struct _StWidgetPrivate StTooltip *tooltip; StTextDirection direction; + + AtkObject *accessible; }; /** @@ -117,6 +121,8 @@ static gboolean st_widget_real_navigate_focus (StWidget *widget, ClutterActor *from, GtkDirectionType direction); +static AtkObject * st_widget_get_accessible (ClutterActor *actor); + static void st_widget_set_property (GObject *gobject, guint prop_id, @@ -281,6 +287,12 @@ st_widget_dispose (GObject *gobject) priv->tooltip = NULL; } + /* The real dispose of this accessible is done on + * AtkGObjectAccessible weak ref callback + */ + if (priv->accessible) + priv->accessible = NULL; + G_OBJECT_CLASS (st_widget_parent_class)->dispose (gobject); } @@ -725,8 +737,11 @@ st_widget_class_init (StWidgetClass *klass) actor_class->key_focus_out = st_widget_key_focus_out; actor_class->hide = st_widget_hide; + actor_class->get_accessible = st_widget_get_accessible; + klass->style_changed = st_widget_real_style_changed; klass->navigate_focus = st_widget_real_navigate_focus; + klass->get_accessible_type = st_widget_accessible_get_type; /** * StWidget:pseudo-class: @@ -1948,3 +1963,193 @@ st_get_slow_down_factor () { return st_slow_down_factor; } + +/******************************************************************************/ +/*************************** ACCESSIBILITY SUPPORT ****************************/ +/******************************************************************************/ + +/* GObject */ + +static void st_widget_accessible_class_init (StWidgetAccessibleClass *klass); +static void st_widget_accessible_init (StWidgetAccessible *widget); + +/* AtkObject */ +static AtkStateSet *st_widget_accessible_ref_state_set (AtkObject *obj); +static void st_widget_accessible_initialize (AtkObject *obj, + gpointer data); + +/* Private methods */ +static void on_pseudo_class_notify (GObject *gobject, + GParamSpec *pspec, + gpointer data); +static void on_can_focus_notify (GObject *gobject, + GParamSpec *pspec, + gpointer data); +static void check_selected (StWidgetAccessible *self, + StWidget *widget); + +G_DEFINE_TYPE (StWidgetAccessible, st_widget_accessible, CALLY_TYPE_ACTOR) + +#define ST_WIDGET_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_WIDGET_ACCESSIBLE, \ + StWidgetAccessiblePrivate)) + +struct _StWidgetAccessiblePrivate +{ + /* Cached values (used to avoid extra notifications) */ + gboolean selected; +}; + + +static AtkObject * +st_widget_get_accessible (ClutterActor *actor) +{ + StWidget *widget = NULL; + + g_return_val_if_fail (ST_IS_WIDGET (actor), NULL); + + widget = ST_WIDGET (actor); + + if (widget->priv->accessible == NULL) + { + widget->priv->accessible = + g_object_new (ST_WIDGET_GET_CLASS (widget)->get_accessible_type (), + NULL); + + atk_object_initialize (widget->priv->accessible, actor); + } + + return widget->priv->accessible; +} + + +static void +st_widget_accessible_class_init (StWidgetAccessibleClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass); + + atk_class->ref_state_set = st_widget_accessible_ref_state_set; + atk_class->initialize = st_widget_accessible_initialize; + + g_type_class_add_private (gobject_class, sizeof (StWidgetAccessiblePrivate)); +} + +static void +st_widget_accessible_init (StWidgetAccessible *self) +{ + StWidgetAccessiblePrivate *priv = ST_WIDGET_ACCESSIBLE_GET_PRIVATE (self); + + self->priv = priv; +} + +static void +st_widget_accessible_initialize (AtkObject *obj, + gpointer data) +{ + ATK_OBJECT_CLASS (st_widget_accessible_parent_class)->initialize (obj, data); + + g_signal_connect (data, "notify::pseudo-class", + G_CALLBACK (on_pseudo_class_notify), + obj); + + g_signal_connect (data, "notify::can-focus", + G_CALLBACK (on_can_focus_notify), + obj); + + /* Check the cached selected state and notify the first selection. + * Ie: it is required to ensure a first notification when Alt+Tab + * popup appears + */ + check_selected (ST_WIDGET_ACCESSIBLE (obj), ST_WIDGET (data)); +} + +static AtkStateSet * +st_widget_accessible_ref_state_set (AtkObject *obj) +{ + AtkStateSet *result = NULL; + ClutterActor *actor = NULL; + StWidget *widget = NULL; + StWidgetAccessible *self = NULL; + + result = ATK_OBJECT_CLASS (st_widget_accessible_parent_class)->ref_state_set (obj); + + actor = CLUTTER_ACTOR (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (obj))); + + if (actor == NULL) /* State is defunct */ + return result; + + widget = ST_WIDGET (actor); + self = ST_WIDGET_ACCESSIBLE (obj); + + /* priv->selected should be properly updated on the + * ATK_STATE_SELECTED notification callbacks + */ + if (self->priv->selected) + atk_state_set_add_state (result, ATK_STATE_SELECTED); + + /* On clutter there isn't any tip to know if a actor is focusable or + * not, anyone can receive the key_focus. For this reason + * cally_actor sets any actor as FOCUSABLE. This is not the case on + * St, where we have can_focus. But this means that we need to + * remove the state FOCUSABLE if it is not focusable + */ + if (st_widget_get_can_focus (widget)) + atk_state_set_add_state (result, ATK_STATE_FOCUSABLE); + else + atk_state_set_remove_state (result, ATK_STATE_FOCUSABLE); + + return result; +} + +static void +on_pseudo_class_notify (GObject *gobject, + GParamSpec *pspec, + gpointer data) +{ + check_selected (ST_WIDGET_ACCESSIBLE (data), + ST_WIDGET (gobject)); +} + +/* + * This method checks if the widget is selected, and notify a atk + * state change if required + * + * In order to decide if there was a selection, we use the current + * pseudo-class of the widget searching for "selected", the current + * homogeneus way to check if a item is selected (see bug 637830) + * + * In a ideal world we would have a more standard way to check if the + * item is selected or not, like the widget-context (as in the case of + * gtktreeview-cells), or something like the property "can-focus". But + * for the moment this is enough, and we can update that in the future + * if required. + */ +static void +check_selected (StWidgetAccessible *self, + StWidget *widget) +{ + gboolean found = FALSE; + + found = st_widget_has_style_pseudo_class (widget, + "selected"); + + if (found != self->priv->selected) + { + self->priv->selected = found; + atk_object_notify_state_change (ATK_OBJECT (self), + ATK_STATE_SELECTED, + found); + } +} + +static void +on_can_focus_notify (GObject *gobject, + GParamSpec *pspec, + gpointer data) +{ + gboolean can_focus = st_widget_get_can_focus (ST_WIDGET (gobject)); + + atk_object_notify_state_change (ATK_OBJECT (data), + ATK_STATE_FOCUSABLE, can_focus); +} diff --git a/src/st/st-widget.h b/src/st/st-widget.h index cc3b47c01..894543635 100644 --- a/src/st/st-widget.h +++ b/src/st/st-widget.h @@ -82,6 +82,8 @@ struct _StWidgetClass gboolean (* navigate_focus) (StWidget *self, ClutterActor *from, GtkDirectionType direction); + + GType (*get_accessible_type) (void); }; GType st_widget_get_type (void) G_GNUC_CONST;