Compare commits

...

353 Commits

Author SHA1 Message Date
33100cd204 Bump version to 2.91.6 2011-02-01 14:08:29 -05:00
39a8243f27 [l10n] Updated Estonian translation 2011-02-01 19:35:37 +02:00
5f50922d32 Build: Correct version numbers for eds-3.0/1.2
The respective version numbers got swapped in commit 703092f.
2011-02-01 16:37:17 +01:00
1137ca0fce main.js: fix variable naming style for css_stylesheet
Change css_stylesheet to cssStylesheet in various places.
2011-02-01 10:13:35 -05:00
36f3429ad2 Better API for extensions changing CSS
Rename the setter to reflect the fact that it's the stylesheet which is
changing

Add a getter to allow some useful checks
2011-02-01 10:13:35 -05:00
703092f2c9 build: Default to libedataserverui-3.0 instead of 1.2
The official GNOME moduleset builds evolution and e-d-s against
GTK+-3, so libedataserverui-1.2 is no longer part of the release.
As GNOME Shell can actually be build with either version, prefer
libedataserverui-3.0 if it is available and allow falling back
to 1.2. if it isn't.

https://bugzilla.gnome.org/show_bug.cgi?id=641085
2011-02-01 16:12:11 +01:00
fd75c7c7b4 Add an alternate bubble arrow drawing
When the bubble is near the screen border, draw a half arrow at the
corner of the bubble.

https://bugzilla.gnome.org/show_bug.cgi?id=639979
2011-02-01 10:07:05 -05:00
8abbd5dacb tray: Fix handling of SYSTEM_TRAY_CANCEL_MESSAGE
We were not looking at the right field for the message ID: the ID is in
the 4th field for BEGIN_MESSAGE, but 2nd field for CANCEL_MESSAGE.
2011-02-01 12:13:47 +01:00
ed0fa7e1b7 tray: Stop using gdk_display_add_client_message_filter()
It just got removed in GTK+ 3, and we actually don't need it since we
look for ClientMessage in na_tray_manager_window_filter() anyway.
2011-02-01 12:13:12 +01:00
15f1245927 Updating Galician translations 2011-02-01 02:45:13 +01:00
25434e42d0 calendar: Fix grid non-US week layouts
http://people.freedesktop.org/~david/calendar-grid-non-US-locale-collapse-bug.png

This was discovered when working on bug 641049:

 https://bugzilla.gnome.org/show_bug.cgi?id=641049

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-31 15:53:56 -05:00
d6749589e8 calendar: Fix event list for week starts other than Sunday
In non-US locales, Monday is generally considered the first day
of the week. Take this into account when building the event
lists displayed under "This week"/"Next week".

https://bugzilla.gnome.org/show_bug.cgi?id=641049

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-31 15:47:05 -05:00
8fea88879a calendar: Fix prev/next buttons to not skip months
When the current day does not exist in the next/prev month (like 31 Feb),
the next/prev buttons end up skipping the month.

Fix that by going to the last day of the month instead.

https://bugzilla.gnome.org/show_bug.cgi?id=641067
2011-01-31 21:31:17 +01:00
d9e778f501 Calendar: Fix UTC/local mixup
See https://bugzilla.gnome.org/show_bug.cgi?id=632109#c56

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-31 11:52:27 -05:00
885b6ffaef Calendar: Implement new mockup
https://bugzilla.gnome.org/show_bug.cgi?id=632109

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-31 11:52:27 -05:00
4c64920f45 build: Remove gtk-theme-engine-clearlooks
The default engine is now Adwaita in gnome-themes-standard, so
remove it from the moduleset. It has already been removed from the
gnome-suites-core-3.0 set.
2011-01-31 16:08:59 +01:00
7369ea6125 Make sure we only emit 'destroy' for a notification once
There are multiple code passes that can result in Notification::destroy()
being called, such as a notification being closed by the application
when it exits and the associated source being removed at the same time.
However, we should only emit 'destroy' for the notification and
do the associated work once.
2011-01-30 18:53:19 -05:00
20b7d34577 Avoid passing 'source' as an argument to Notification::destroy()
Notification::destroy() now takes 'reason' as an optional argument.
Calling Notification::destroy() directly when connecting to 'destroy'
on Source, as we did before, was inadvertently passing 'source' as an
argument to the function.

https://bugzilla.gnome.org/show_bug.cgi?id=640976
2011-01-30 18:53:07 -05:00
6cc4c33b13 Updated Hebrew translation. 2011-01-30 23:04:00 +02:00
5abf9a0425 Add an API to allow extension to set a theme
Add a setTheme function to Main that allows to set a CSS stylesheet
which overrides the GNOME Shell default one

https://bugzilla.gnome.org/show_bug.cgi?id=630428
2011-01-30 16:01:15 -05:00
17a0b27109 appSwitcher: Use shorter icon hover timeout
Using a timeout of 750ms seems to be too long,
a shorter one like 200ms still solves the original problem
without getting in the way of other uses.
2011-01-30 20:29:27 +01:00
2bcdae4d5d Include new GTK+ header for X11 extensions
Due to recent GTK+ changes X11 specific code was moved into different
headers. As Socket/Plug is X11 only this broke our calls to GtkSocket
in the tray code. Fix this by including the new gtkx.h header.
2011-01-30 13:53:03 -05:00
0244c6d5b8 Revert "KeyboardStatus: handle modifier key indicators"
The 'show-keyboard-leds-indicator' key has been removed from
the schema.

This reverts commit 20f49e8c89.
2011-01-29 19:34:12 +01:00
bc6be40fdd Updated Italian translation 2011-01-29 16:07:10 +01:00
8c22b58611 update Punjabi Translation by A S Alam 2011-01-29 07:42:22 +05:30
074fe3ea70 Updated Spanish translation 2011-01-28 19:50:02 +01:00
5666fdefce Add a missing colon
Fixes a syntax error.
2011-01-28 13:31:16 -05:00
e9613b0340 Emit NotificationClosed for a notification iff we destroy it
This fixes emitting NotificationClosed for resident notifications
that are clicked, but are not actually destroyed.

This also ensures that we emit NotificationClosed in all cases when
a notification is destroyed, which can happen when:
- a non-resident notification is clicked
- an action is invoked on a non-resident notification
- an application the notification was associated with is focused
- a transient notification is done showing
- a notification was requested to be closed by the application
- a tray icon the notification was associated with is removed

https://bugzilla.gnome.org/show_bug.cgi?id=638071
2011-01-28 13:02:20 -05:00
8a030e8fc4 Mark lock indicator icons as keyboard ones
Those 3 possible status icons from gnome-settings-daemon should
not be showing up in gnome-shell, as they already have native versions.
2011-01-28 01:47:38 +00:00
9c23bf02bd Prevent a11y-kdb status icon from showing 2011-01-28 01:47:15 +00:00
8468fe87eb gnome-settings-daemon's xrandr icon went away
There's no xrandr icon in gnome-settings-daemon any more.
2011-01-28 01:19:01 +00:00
9617e83d88 run-dialog: Center error message vertically
Commit 912a30c56 left error message and icon aligned to the top,
but it looks better when the message is centered vertically.
2011-01-27 22:05:46 +01:00
912a30c566 Clean up the presentation of errors in the run dialog
Removes redundant text, better icon, and shows are better error when
a command isn't found than "No such file or directory".
2011-01-27 15:46:03 -05:00
2cd84da835 desktop-file: Remove "Utility" from categories
GNOME Shell is a core component of the desktop rather than a
utility, so adjust the desktop file to reflect that.

https://bugzilla.gnome.org/show_bug.cgi?id=640688
2011-01-27 11:37:39 +01:00
64fad9a394 QA of Galician translations 2011-01-27 03:33:43 +01:00
3b797b32bc Bump required clutter version to 1.5.15
This is required for Clutter.BindCoordinate.POSITION
2011-01-26 20:46:46 +01:00
f6ae48ec70 XDND: Use only one constraint for the cursor window position
ClutterBindConstraint now supports POSITION, so use that instead
of separate X and Y constraints.
2011-01-26 20:41:26 +01:00
61869d7db1 Unselect search button if there is search result
https://bugzilla.gnome.org/show_bug.cgi?id=640464
2011-01-26 04:38:18 +03:00
e2e90a550e Overview: Adjust to window size changes
Windows may change their size while the overview is open, e.g. when
switching panels in the control center. Make sure that the preview's
position and overlay are updated in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=640560
2011-01-25 21:53:33 +01:00
80ceead18d Updated Norwegian bokmål translation. 2011-01-25 20:47:57 +01:00
ed8884e192 [l10n] Updated Estonian translation 2011-01-25 20:41:22 +02:00
3f6165799f gs-menu: Do not exclude "Core" category
With the current rule set, we exclude applications in the "Core"
category - this includes Nautilus, which we want to show up at
least until "Finding and Reminding" is implemented, so remove
the exclude rule for now.
2011-01-25 19:39:58 +01:00
d2a40d6885 appSwitcher: Make sure we don't leave a stale timeout handler 2011-01-25 15:32:43 +01:00
eb8fc738af swipe-scrolling: Take threshold into account during drag
On button-release, a threshold is used to determine if the gesture
should be considered a click and thus ignored. While the drag is
active though, the controlled actor is dragged immediately. As a
result, dragging by a tiny amount does not trigger a snap back when
the action is interpreted as a click. As a fix, do not update the
dragged actor's position until the same threshold is passed.

https://bugzilla.gnome.org/show_bug.cgi?id=640494
2011-01-25 10:31:52 +01:00
b9e1d917da swipe-scroll: Don't eat button-release events on click
The main overview group starts capturing events on button-press
events to implement swipe-scrolling. While reactive children of
the group which handle both button-press and button-release events
don't trigger swipe-scrolling, children that only rely on
button-release have stopped working - at least the primary/secondary
icons of the search entry are affected. While the capture handler
already checks the pointer movement between press and release to
determine whether the action should be considered a click rather
than a drag, it still blocks the release event from propagating.
Instead, only block release events for drag actions, but not for
clicks.

https://bugzilla.gnome.org/show_bug.cgi?id=640493
2011-01-25 10:31:52 +01:00
f721e80685 Modifying Colin Walters UID. (cwalters to walters) into gnome-shell.doap.
This was causing some 'no route to host' mail sent to RT. AndreaVeri on
behalf of the AccountsTeam
2011-01-25 00:06:58 +01:00
361a115729 recorder: Call cairo_surface_mark_dirty on the cursor surface
Cairo surfaces have to be marked dirty after directly accessing
them.

This fixes the problem of the cursor not being in the recordings.
2011-01-24 23:03:59 +01:00
d107b84be4 view-selector: Prelight view titles on hover
The titles are clickable, indicate this to the user by prelighting
them on hover.
2011-01-24 20:36:25 +01:00
4cb967f3ac shell-app-usage: fix tracking code
We were checking if the app was running, but then marking it as
recently-seen either way. Fix it to only update it when the app is
running.

https://bugzilla.gnome.org/show_bug.cgi?id=640447
2011-01-24 13:35:03 -05:00
6f070319a0 shell-doc-system: fix %-escaping code in shell_doc_system_open()
It was escaping app_exec into app_exec_quoted, but then forgot about
it and went back to using app_exec.

https://bugzilla.gnome.org/show_bug.cgi?id=640447
2011-01-24 13:35:03 -05:00
13edecde6c Remove set-but-unused variables, to appease gcc 4.6
https://bugzilla.gnome.org/show_bug.cgi?id=640447
2011-01-24 13:35:03 -05:00
75d1230dd1 AppSwitcher: Delay activating appIcons when the thumbnail list is open
When aiming for the thumbnails with the mouse one might cross an
icon by accident which causes the thumbnail list to be closed, which is
frustrating.

Fix this by delaying the icon activation when the thumbnail list is
open.

https://bugzilla.gnome.org/show_bug.cgi?id=636650
2011-01-24 19:33:22 +01:00
779d5462f2 StThemeDrawing: clip background to border
Previously, trying to use a background image and border on
the same node resulted in the background drawing over the border.

This commit adds support for background images to

st_theme_node_render_background_with_border

and changes the code to call that function when appropriate.

https://bugzilla.gnome.org/show_bug.cgi?id=636976
2011-01-24 12:23:11 -05:00
03757c1fcb st-private: add cairo code for drawing shadow
This does the same thing as the cogl equivalent
code, but for handling fallbacks.

https://bugzilla.gnome.org/show_bug.cgi?id=636976
2011-01-24 12:23:11 -05:00
1faee65a68 st-private: split pixel blurring code out
The guts are somewhat complicated, and
are potentially reusable for future cairo
fallback code.

https://bugzilla.gnome.org/show_bug.cgi?id=636976
2011-01-24 12:23:11 -05:00
f7ab90b93b StTextureCache: add api to load image to cairo surface
Loading a pixbuf in a way that cairo can use it is a
pretty involved process that involves a lot of code, and pixel
fiddling.

This commit adds the mechanism to StTextureCache so we can reuse
the existing pixbuf handling code there, and also get caching.

https://bugzilla.gnome.org/show_bug.cgi?id=636976
2011-01-24 12:23:11 -05:00
a7fa7d748d StThemeNodeDrawing: generalize render_gradient to render_background_with_border
A lot of the border drawing logic in st_theme_node_render_gradient is
applicable to other non-solid background types than gradients.

This commit refactors that code so that support for other non-solid
background types can be more easily integrated later.

https://bugzilla.gnome.org/show_bug.cgi?id=636976
2011-01-24 12:23:11 -05:00
2b6d4ff279 StThemeNodeDrawing: clip background image shadow to outline
When drawing the background image shadow, we need to clip it
to the node's background color, gradient, or borders if present.

If the background color is transparent, and there aren't any
borders, then we don't clip the shadow since there is nothing
to confine it.

https://bugzilla.gnome.org/show_bug.cgi?id=636976
2011-01-24 12:23:11 -05:00
06cea89dae StThemeNodeDrawing: clip background image to node allocation
When drawing the background image, we need to make sure
we don't draw outside the bounding rectangle of the node.

https://bugzilla.gnome.org/show_bug.cgi?id=636976
2011-01-24 12:23:11 -05:00
260ca64e94 StThemeNode: Don't make border images and gradients mutually exclusive
Since we no longer use the same material for both purposes,
we can now remove the restriction that they are mutually exclusive.

https://bugzilla.gnome.org/show_bug.cgi?id=636976
2011-01-24 12:23:11 -05:00
6dc4adfc13 StThemeNode: split border_texture into two vars
The border_texture (and border_material) variable is being
overloaded for two purposes: it's used as a source
to 9-slice the border from, and it's used as place to prerender
the background and border together for gradients.

While we only do one or the other for any given node, the two cases
are distinct, and should use distinct variables for readability.

https://bugzilla.gnome.org/show_bug.cgi?id=636976
2011-01-24 12:23:11 -05:00
e727c184ef StThemeNode: Split -st-shadow into three attributes
Currently, "-st-shadow" can mean one of three very
different things:

1) shadow based on alpha of the background image
2) shadow the "border box" of the node
3) shadow applied to the content of a StIcon

It isn't well defined which of the above 3 cases
-st-shadow will mean for any given node, however.

This commit splits the property into three
different properties, "box-shadow",
"-st-background-image-shadow", and "icon-shadow"
to make it all very explicit.

https://bugzilla.gnome.org/show_bug.cgi?id=636976
2011-01-24 12:23:11 -05:00
412c50b939 tests: showcase borders with non-solid backgrounds
This commit adds a few more examples to borders.js
that render borders with various combinations of
gradients, background images, shadows, and
border-images.

https://bugzilla.gnome.org/show_bug.cgi?id=636976
2011-01-24 12:23:11 -05:00
8dcd70edbe St: Use clutter_actor_get_request_mode
Use clutter_actor_get_request_mode rather than g_object_get
since we have it in the required clutter version.

https://bugzilla.gnome.org/show_bug.cgi?id=640415
2011-01-24 14:41:52 +01:00
1b383c7285 search-display: Enable swipe scrolling
If a search gives many results from various providers, the result
area will be scrollable, so enable swipe-scrolling here as well.

https://bugzilla.gnome.org/show_bug.cgi?id=635034
2011-01-24 02:59:46 +01:00
e96a90b161 app-display: Enable swipe-scrolling in the app view
With general support for swipe-scrolling in the overview, there is
no reason to limit the behavior to workspaces. It is equally useful
for scrolling through the grid of available applications, so enable
swipe-scrolling for the app view.

https://bugzilla.gnome.org/show_bug.cgi?id=635034
2011-01-24 02:59:46 +01:00
d64d491f63 workspaces-view: Use overview swipe-scrolling
Remove the swipe-scrolling implementation in WorkspacesView and
use the new overview facility.

https://bugzilla.gnome.org/show_bug.cgi?id=635034
2011-01-24 02:59:39 +01:00
a6da22fa70 overview: Add a facility for swipe-scrolling
The workspaces view allows to drag the active workspace to swipe-scroll
to the next or previous workspace. While this behavior can come in handy
in general, there are good reasons to move the functionality to the
overview:

 - Finding a spot on a workspace to start a drag can be hard,
   especially when the workspace contains a single window
 - With the new layout, workspaces have no visible border, making
   it hard to predict where a drag can be initiated
 - The same behavior is equally useful for other elements

So add setScrollAdjustment() to the overview, which allows setting
an adjustment controlled with swipe-scrolling (either horizontally
or vertically); only a single adjustment can be controlled at a
time. A swipe-scroll can be initiated on any part of the background that
is not occupied by a reactive actor. For cases where further control
is needed, 'swipe-scroll-start' and 'swipe-scroll-end' signals are
emitted.

https://bugzilla.gnome.org/show_bug.cgi?id=635034
2011-01-24 02:59:32 +01:00
56cf7a6628 Updated Arabic translation 2011-01-23 13:29:55 +02:00
5b71788a84 Updated Hebrew translation. 2011-01-23 02:43:13 +02:00
39f7aa8457 Updated Spanish translation 2011-01-22 16:41:46 +01:00
c6baee2622 recorder: Switch to webm
The vp8 codec provides better performance in pretty much all cases compared
to theora while still being free (as in not patent encumbered).

Also add a %T placeholder to the pipeline string which will be replaced
with the a thread count based on the target system.

https://bugzilla.gnome.org/show_bug.cgi?id=632595
2011-01-21 19:46:38 +01:00
20f49e8c89 KeyboardStatus: handle modifier key indicators
Introduce a generic framework for on/off indicators that are shown
in the panel, next to the system status area, and use it for
showing the status of modifier keys.

https://bugzilla.gnome.org/show_bug.cgi?id=600771
2011-01-21 19:38:30 +01:00
d6a6e6220a recorder: Force full stage redraws during recording
Partial redraws can result into artifacts in the recording,
so disable them while recording.

https://bugzilla.gnome.org/show_bug.cgi?id=640206
2011-01-21 19:10:31 +01:00
3b333c37fd Updated Italian translation 2011-01-21 01:18:36 +01:00
289d577bc1 st: Report correct paint volumes during transitions
StWidget reports a paint volume large enough to paint the current
theme node. As CSS transitions also paint the previous theme node,
the reported paint volume may be incorrect, resulting in screen
artifacts when painting outside the reported volume.

Add st_theme_node_transition_get_paint_box() to calculate an allocation
large enough to paint both theme nodes, and use it to report the correct
paint volume during transitions.

https://bugzilla.gnome.org/show_bug.cgi?id=640085
2011-01-20 23:24:41 +01:00
00ba937171 StScrollView: Implement real fade effect
Implement an edge fade effect (top/bottom) using a
ClutterOffscreenEffect subclass, replacing the former
shadow hack.

https://bugzilla.gnome.org/show_bug.cgi?id=639460
2011-01-20 20:53:20 +01:00
df3560143d overview: Always return a value in _onDragMotion()
Drag monitor functions are supposed to return a value, but
_onDragMotion() does not always do so. Add the missing return
value and remove unnecessary else.
2011-01-20 17:04:38 +01:00
bdeb20f7c9 open-search-system: Remove unused parameter
Remove the 'title' parameter from the OpenSearchSystem constructor,
as the prototype's _init() method does not use it.
2011-01-20 17:04:37 +01:00
1dd35b7d08 environment: Fix runtime crash due to GTK+ change
As Gdk.Device.get_state() does not work properly from Javascript,
we used to block it in the environment. The method now has been
annotated with (skip), causing shell to crash on startup as only
existing methods may be blocked.
Just remove the block in question, as the annotation prevents the
use of that method anyway.
2011-01-20 16:44:16 +01:00
450291b856 Adding StLabel a11y support
Right now is just redefine atk_object_get_name.

If someone wonders why not implement AtkText interface, or expose the
internal ClutterText, here a extract from AtkText doc:

"AtkText should be implemented by AtkObjects on behalf of widgets that
have text content which is either attributed or otherwise
non-trivial. AtkObjects whose text content is simple, unattributed,
and very brief may expose that content via atk_object_get_name
instead;"

StLabel is attributed, but is still simple and brief. In the same way
the atk_object_get_name redefinition is required, so this patch is the
first step. We can implement AtkText in the future.

https://bugzilla.gnome.org/show_bug.cgi?id=626658
2011-01-20 13:02:14 +01:00
125adb4d32 StWidgetAccessible: accessibility support for StWidget
It includes:

 * Expose a proper focusable state, instead of the default one from
   cally, using StWidget::can_focus, and also notifying the state change

 * Management of the selected stated, using the current pseudo_class.

 * Defines a new virtual method on StWidget: get_accessible_type. In
   this way it is not required to reimplement get_accessible just for
   a accessible type change. get_accessible is reimplemented using this.
   You can see that as a substitute of the atk object factory

https://bugzilla.gnome.org/show_bug.cgi?id=636716
2011-01-20 12:56:46 +01:00
13cc58937e Added a11y initialization code
This basically:
  * Checks a11y configuration properties
  * Checks if clutter has a11y enabled
  * Loads atk-bridge

It also ensure proper NO_GAIL and NO_AT_BRIDGE values on gnome-shell
startup script

https://bugzilla.gnome.org/show_bug.cgi?id=612599
2011-01-20 12:56:36 +01:00
ee6a852996 XDND: Don't reset switch timeout when pointer is over the same window
Currently we reset the timeout on every mouse movement which means
the user has to keep the mouse at the exact same position for 1.25
seconds.

Be more tolerant and allow the user to move the mouse over the
window without reseting the timeout, which should make activating
windows easier.

https://bugzilla.gnome.org/show_bug.cgi?id=638896
2011-01-20 09:57:50 +01:00
2cfe978e1f Updated Arabic translation 2011-01-19 22:47:57 +02:00
0625655456 Updated Arabic translation 2011-01-19 22:40:24 +02:00
39a1f5cfe0 Updated Spanish translation 2011-01-19 20:27:21 +01:00
961fdd861f Hard code Cantarell as the default UI font.
- specify an overall font-family for all children of the stage and
  for places where we just want to use a size, use font-size.
- also shrink the humongous 16px panel and menu size to a reasonable 14.
- scale up the icons to be 16px by default again

Based on a patch by Jakub Steiner <jimmac@gmail.com>

https://bugzilla.gnome.org/show_bug.cgi?id=634226
2011-01-19 11:54:03 -05:00
28adc03cce StIcon: round icon size to an integer
Instead of converting a CSS-specified length to an integer by truncation,
round. This means that sizes specified by converting a pixel value into
non-px terms will work reliably instead of potentially being off-by-one.
2011-01-19 11:54:03 -05:00
68c482ec32 notification: be compatible with various names of the icon data hint
The hint changed its name during various iterations of the
notification daemon spec; be compatible with all of them.

https://bugzilla.gnome.org/show_bug.cgi?id=639959
2011-01-19 17:31:23 +01:00
a739f89dd1 texture-cache: add a missing array annotation 2011-01-19 16:43:50 +01:00
5c7042cff3 Updated Galician translations 2011-01-19 15:01:58 +01:00
255d4634a9 util: Fix regex used to match for URLs
Commit a65a0f03d4 changed the literal RegExp to a string-based
RegExp(). As backslashes are treated specially inside strings,
translating an expression as /\s/ to '\s' results in a faulty
regex of /s/, so escape backslashes where necessary.
https://bugzilla.gnome.org/show_bug.cgi?id=639914
2011-01-19 05:06:53 +03:00
cb4c2ab824 Don't reset y position of expanded notifications when updating them
This fixes the problem of chat notifications collapsing and then expanding
again when receiving multiple messages in the expanded new notification.

https://bugzilla.gnome.org/show_bug.cgi?id=629557
2011-01-18 15:08:46 -05:00
4c449124ee windowManager: Skip disposed windows in _switchWorkspaceDone
Avoid reparenting already disposed windows.

https://bugzilla.gnome.org/show_bug.cgi?id=639853
2011-01-18 19:35:01 +01:00
c74536c9b3 configure.ac: remove an old reference to Tidy 2011-01-18 11:49:09 -05:00
df10ef532f build: Add cups development package to dependencies
Needed by gnome-control-center.
2011-01-18 17:20:19 +01:00
6e18d18a81 Updated Hebrew translation. 2011-01-18 13:05:41 +02:00
4bc078b5fd StTextureCache: Fix compilation warning 2011-01-18 01:32:02 +03:00
cf49882e96 search: Use Util.spawn rather then Shell.Process
Shell.Process has been removed in favor of Util.spawn* so use that
instead.
2011-01-17 23:11:06 +01:00
b0c6cf3fc5 add ability to search in web from search view
It use OpenSearch to define the search engines.
https://bugzilla.gnome.org/show_bug.cgi?id=623708
2011-01-18 00:41:59 +03:00
883f51be93 runDialog: use fileUtils.listDirAsync in CommandCompleter
https://bugzilla.gnome.org/show_bug.cgi?id=623708
2011-01-18 00:41:50 +03:00
ad52d783bd places: Do not use nautilus' 'desktop-is-home-dir' setting
g_settings_schema_new() aborts if the requested schema is not found,
so the previous approach of handling the case of unstable nautilus
not being installed did not work.
Instead, remove the use of the setting altogether - the original intent
was to not have separate items for Desktop and Home in the places
section if the nautilus key was set. As the section has been removed
anyway, the impact of always adding the desktop folder is minimal
(e.g. searching for "desktop" will match the desktop folder even
if it's set to the home folder).
2011-01-17 21:05:13 +01:00
05f9be046f BluetoothStatus: add a separator above Settings menu entry
Close bug #639704
2011-01-17 21:02:03 +01:00
26aaecc33d places: Fail gracefully when not using unstable nautilus
The latest development version of nautilus has been ported to
GSettings, which we now use as well for the desktop-is-home-dir
preference. Obviously, the required schema is only available if
a recent enough nautilus version is installed. Instead of adding
yet another module to the moduleset, catch the exception and
ignore the preference in case the schema is not available.

https://bugzilla.gnome.org/show_bug.cgi?id=639689
2011-01-17 17:46:37 +01:00
f91138d0a2 places: Port to GSettings
'Places' follows the nautilus preference of whether the Desktop
should be a separate directory or the home folder should be used.
Nautilus has been ported to GSettings a while ago, so follow suit.

https://bugzilla.gnome.org/show_bug.cgi?id=639689
2011-01-17 15:54:24 +01:00
89d89ae1cf places: Remove obsolete code
The dash no longer contains a places section, so remove the now
unused code.

https://bugzilla.gnome.org/show_bug.cgi?id=639689
2011-01-17 10:33:28 +01:00
e67fbcdc79 Updated Spanish translation 2011-01-16 21:28:44 +01:00
f4572eedd0 altTab: Query the correct monitor's size
We always display the appSwitcher on the primary monitor,
so always query for its size rather than that of the focused
one.
2011-01-16 20:38:43 +01:00
988b515ad2 Updated Galician translations 2011-01-16 17:10:21 +01:00
2205a395e7 update for translation 2011-01-16 11:08:08 +05:30
108b582f0d [l10n] Updated Estonian translation 2011-01-16 10:20:20 +02:00
6ebd808e8b [Build] Bump vala to 0.11.4 2011-01-15 21:57:31 +01:00
343c1133f4 Updated Norwegian bokmål translation 2011-01-15 12:44:30 +01:00
fea2044eb8 Updated Greek translation 2011-01-15 11:51:02 +02:00
6b353ece82 [l10n] updated Italian translation 2011-01-15 01:22:47 +01:00
5b3f40102f kbd-status: s/Preferences/Settings in menu entry
In order to match similar menu entries from other menus.
2011-01-15 01:04:06 +01:00
b2ab3de80e [l10n] updates POTFILES.in 2011-01-15 00:59:43 +01:00
56f6c9c5f6 genericDisplay: Remove unused module
GenericDisplay used to provide a common base class for places and
recent items, none of which exists anymore. As of current mockups,
display items in "Finding and Reminding" should be based on
BaseIcon / IconGrid instead.
2011-01-14 22:30:02 +01:00
39b0c88c76 doc-display: Remove UI of the old dash display
Currently recent items only show up in search results. It is planned
to bring them back in the context of "Finding and Reminding", but
the UI in the corresponding mockups differs significantly from the
removed UI, so that it doesn't seem useful to keep it around.
2011-01-14 22:29:32 +01:00
1fca8a8b95 css: Remove places and recent items
They no longer exist so they should be removed from css as well.
2011-01-14 22:04:32 +01:00
d442494f3a Dash: Remove unused properties 2011-01-14 21:25:06 +01:00
1f1fe36b89 Updated Galician translations 2011-01-14 16:33:17 +01:00
d21f04b8b4 kbd-status: Close the menu when switching layouts
Layout items in the menu overwrite PopupBaseMenuItem.activate(),
so the menu stays open when selecting a layout from the menu.
Chain up to the parent class' method to make the items behave properly.

https://bugzilla.gnome.org/show_bug.cgi?id=639474
2011-01-14 07:18:39 +01:00
e73e4375b8 endSessionDialog: Add logout/shutdown dialog
This commit adds a dialog for gnome-session to
privately use when initiating log outs and shut
downs.

Coordination is done over the bus.

https://bugzilla.gnome.org/show_bug.cgi?id=637187
2011-01-14 00:11:17 -05:00
2905b0318d runDialog: animate to new height on error
When an error message is displayed the run dialog
pops to the new height instantly.  It needs a
a transition.

This commit makes the dialog quickly grow to its
ultimate height, making room for the error message,
before showing it.

https://bugzilla.gnome.org/show_bug.cgi?id=637187
2011-01-14 00:11:17 -05:00
ab1ecb5ba2 runDialog: subclass from modalDialog
Now that we have a modalDialog base class in gnome-shell,
it makes sense to use it for the run dialog.

Note, the run dialog doesn't currently have buttons, so
it isn't exercising all the API of the base class.

https://bugzilla.gnome.org/show_bug.cgi?id=637187
2011-01-14 00:11:17 -05:00
47b8d16067 modalDialog: Add modal dialog base class
This is a base class to make it easier to
gain a consistent look for system modal dialogs.

It handles creating a darkened backdrop behind the dialog, setting
up buttons in the dialog, keynav, etc.

https://bugzilla.gnome.org/show_bug.cgi?id=637187
2011-01-14 00:11:10 -05:00
dc020628b5 main: add timestamp parameter to push/popModal
Right now popModal() passes global.get_current_time() for
its begin_modal() call.  global.get_current_time() is the
timestamp of the last gdk or clutter event processed by the
shell's mutter process.  These values could potentially be
be too stale to use if pushModal() were to get called in
response to an event by another process.

This commit changes pushModal() to have an optional timestamp
argument, which can be used to associate the call with the
event that initiated it.

https://bugzilla.gnome.org/show_bug.cgi?id=637187
2011-01-13 23:36:22 -05:00
bed063eea1 generic-container: Queue a redraw in skip_paint()
When changing a child's visibility with skip_paint(), the change
will not be visible until a redraw is triggered. Queue a redraw,
so that the function has an immediate effect.

https://bugzilla.gnome.org/show_bug.cgi?id=639461
2011-01-14 01:07:42 +01:00
ed76e52918 Revert "kbd-status: Close the menu when switching layouts"
This reverts commit e0f58c615b.

Pushed accidentally.
2011-01-14 01:06:49 +01:00
e0f58c615b kbd-status: Close the menu when switching layouts
Layout items in the menu overwrite PopupBaseMenuItem.activate(),
so the menu stays open when selecting a layout from the menu.
Chain up to the parent class' method to make the items behave properly.

https://bugzilla.gnome.org/show_bug.cgi?id=639474
2011-01-14 01:01:30 +01:00
a681a2ba02 Remove _onKeyPress() function in Notification
Its usage was removed in commit 4dd4c9f99f -
"Use more actor.grab_key_focus() and less stage.connect('key-press-event')".
2011-01-13 18:33:01 -05:00
856207c154 LookingGlass: fix a Clutter warning
After destroying an actor, it is no more parented anywhere, so we
cannot allocate it.

https://bugzilla.gnome.org/show_bug.cgi?id=633028
2011-01-13 22:55:20 +01:00
00d897f282 Require gjs 0.7.8
We use the js-version property, among other things.
2011-01-13 16:38:30 -05:00
49a09657c5 Updated Hebrew translation. 2011-01-13 23:23:16 +02:00
38fb51a99e app-display: Expose BaseIcon params in AppWellIcon
AppWellIcon is used both in the dash and view selector. As the dash
requires manual sizing, it is not possible to set the icon size used
in the view selector in the CSS, but icons will use the default size
(unless set manually as in the dash).

Expose the params parameter of BaseIcon and enable manual resizing
only for AppWellIcons in the dash.

https://bugzilla.gnome.org/show_bug.cgi?id=639428
2011-01-13 18:27:23 +01:00
99a865fb0f ShellApp: is_on_workspace() should be TRUE for workspaceless apps
If a starting-up app has not requested a particular workspace, then
shell_app_is_on_workspace() should return TRUE for any workspace.

Otherwise we will never get startup notification for them, since the
app menu only shows apps that are starting on the current workspace.

https://bugzilla.gnome.org/show_bug.cgi?id=635089
2011-01-13 12:16:38 -05:00
b919dd7271 shell-app-system.h: clean up (indentation, order, etc)
https://bugzilla.gnome.org/show_bug.cgi?id=635089
2011-01-13 12:16:37 -05:00
9ddf19a1a4 shell: remove ShellProcess
ShellProcess only existed to work around gjs bugs that have long since
been fixed, and has now been obsoleted by Util.spawn*. Kill it.

https://bugzilla.gnome.org/show_bug.cgi?id=635089
2011-01-13 12:14:40 -05:00
23353fb77a Util.killall: add utility for killing unwanted processes
Since we have to use pkill, kludgily, for the right combination of
portability and featurefulness, put the code in one place rather than
duplicating it everywhere.

https://bugzilla.gnome.org/show_bug.cgi?id=635089
2011-01-13 12:14:40 -05:00
8bdfb8df68 util: add Util.spawn and friends
Add Util.spawn, Util.spawnCommandLine, and Util.spawnDesktop for
spawning a command/argv/.desktop file in the background, automatically
handling errors via MessageTray.SystemNotificationSource(), and
Util.trySpawn, Util.trySpawnCommandLine, and Utils.trySpawnDesktop
that don't do automatic error handling (but do at least clean up the
error message in the exception a bit).

Update various other bits of code around the shell to use the new
methods.

https://bugzilla.gnome.org/show_bug.cgi?id=635089
2011-01-13 12:14:40 -05:00
a65a0f03d4 util: rename from utils, avoid RegExp literal
Rename imports.misc.utils to imports.misc.util for more consistency
(eg, with shell-util).

Also, use the string-based RegExp() constructor rather than a RegExp
literal, since the literal is extremely difficult to parse correctly,
and confuses emacs and probably other editors and thus messes up
autoindentation, etc.

https://bugzilla.gnome.org/show_bug.cgi?id=635089
2011-01-13 12:14:40 -05:00
7322a4e4ef messageTray: add SystemNotificationSource, moved from overview.js
Move the overview's "System Information" source here, so it can be
used by non-overview code as well.

https://bugzilla.gnome.org/show_bug.cgi?id=635089
2011-01-13 12:14:40 -05:00
870be026d8 Install a GDK event handler to catch events queued by IBus
With IBus, key events sometimes get sent to the server than
redelivered via gdk_event_put(). Since we expect all key events to
be delivered via the GDK event filter Mutter installs, this results
in key input not working.

To fix this, install an event handler with gdk_event_handler_set()
to intercept events being set from GDK to GTK+, pull out the
key events and send them back to Clutter.

Partially based on a patch by Daiki Ueno

https://bugzilla.gnome.org/show_bug.cgi?id=621659
2011-01-13 12:00:55 -05:00
e4fc899aca Require the latest g-i
Necessary for correct handling of (out caller-allocates) among
other things.
2011-01-12 16:33:01 -05:00
5412ce276c ExtensionSystem: introduce versioning
Require that all extensions have a "shell-version" property in their
metadata, which is an array of supported Shell versions.
Extensions can target a specific version triple or an entire stable
version.
Optionally, they can also require a specific GJS version, to ensure
compatibility.

https://bugzilla.gnome.org/show_bug.cgi?id=639255
2011-01-12 20:34:25 +01:00
6200daa5bb Propagate version to Javascript files
Add an entry in config.js.in for PACKAGE_VERSION and GJS_VERSION,
to be used by the notification daemon and in the future by the
extension system.

https://bugzilla.gnome.org/show_bug.cgi?id=639255
2011-01-12 20:32:30 +01:00
4207536377 Status Area: add keyboard layout selector
Add an indicator for the current keyboard layout, based on
libgnomekbd. The indicator is shown when more than one group
is loaded in X and it is not disabled in GSettings.

https://bugzilla.gnome.org/show_bug.cgi?id=600771
2011-01-12 20:27:25 +01:00
90e042e30c Updated Arabic translation 2011-01-12 11:29:54 +02:00
4e45e28ea0 shell: disable libgnome-bluetooth debug spew
Centralize all the debug-spew-disabling here, and add
libgnome-bluetooth to the list.

https://bugzilla.gnome.org/show_bug.cgi?id=639236
2011-01-11 19:06:55 -05:00
d7a19fdd1b Bump version to 2.91.5 2011-01-11 18:13:36 -05:00
428d2fdb76 gnome-shell-build-setup.sh: Add libgtop
Add libgtop, a new build dependency for gnome-control-center.
2011-01-11 18:10:08 -05:00
d77409876c Clean generated stamp-st.h 2011-01-11 18:05:08 -05:00
81714ce1a3 Notifications with CRITICAL urgency are no longer timed out
Notifications with CRITICAL urgency should not pop down until the user interacts with them.

https://bugzilla.gnome.org/show_bug.cgi?id=630942
2011-01-11 16:38:46 -05:00
6bae9ed20d gnome-shell.css: specify font size for overview view selector area
Previously this was inheriting the default size, which is specified in
pts, and so would make the text larger than its 16px containing box if
you have high DPI.

https://bugzilla.gnome.org/show_bug.cgi?id=639213
2011-01-11 09:18:15 -05:00
44f70646d3 main: clean up handling of metacity keybindings during grabs
Although certain keys (like Ctrl-Alt-Tab and Alt-F2) should work in
the overview, we generally don't want them to work from inside each
others grabs. In particular, typing Left or Right from inside
Ctrl-Alt-Tab should navigate among focus groups, not switch
workspaces.

https://bugzilla.gnome.org/show_bug.cgi?id=636971
2011-01-10 15:24:54 -05:00
ed83b5494c main: allow Alt-F1 to exit the overview
Also, change _globalKeyPressHandler to handle KEY_PRESS, not
KEY_RELEASE, for consistency with other code (and so that the
combination of an Alt-F1 press and release doesn't first enter the
overview and then immediately exit it).

https://bugzilla.gnome.org/show_bug.cgi?id=636371
2011-01-10 15:24:54 -05:00
84bac4414c ShellGtkEmbed: revert to old actor/window position-syncing code
Synchronizing the actor and window position on paint resulted in lots
of syncing, and also resulted in the window mistakenly being left at
0,0 if the actor wasn't visible when the window first mapped.

Revert back to the old way of doing it, by tying into
clutter_actor_allocate, which was only failing before because of a bug
elsewhere.

https://bugzilla.gnome.org/show_bug.cgi?id=635695
2011-01-10 15:22:50 -05:00
4c4a703e63 messageTray: use alignment rather than gravity to position the summary
Actors in clutter are supposed to be re-allocated with
Clutter.AllocationFlags.ABSOLUTE_ORIGIN_CHANGED if they move relative
to the screen, even if they don't move relative to their parent.
Currently this does not work correctly for actors inside containers
with non-northwest gravity. This is probably a fixable bug, but
gravity has messed up other things in the past too, so let's just not
use it.

This change ensures that summary trayicons are re-allocated when the
summary animates, and is part of the fix for
https://bugzilla.gnome.org/show_bug.cgi?id=635695
2011-01-10 15:22:50 -05:00
c08021d91f [l10n] Updated Estonian translation 2011-01-09 20:38:25 +02:00
df5ec16842 Updated Hebrew translation. 2011-01-09 18:51:03 +02:00
055a34877e Favorites: Refine default list
Change the default list to:

Firefox, Evolution, Empathy, Rhythmbox, Shotwell, OOWriter, Nautilus

https://bugzilla.gnome.org/show_bug.cgi?id=638990
2011-01-08 15:14:25 +01:00
a538027fe7 Translation: update Punjabi 2011-01-08 08:25:16 +05:30
77289737c5 Add an 'rt' command to the Run dialog to reload the theme
This should be useful for theme authors who want to quickly reload
the theme without restarting the whole shell.

Signed-off-by: Federico Mena Quintero <federico@gnome.org>

https://bugzilla.gnome.org/show_bug.cgi?id=630428
2011-01-07 15:21:48 -05:00
512798f9c6 Factor out a function to load the default theme
We will use this function elsewhere when the theme needs to be reloaded.

https://bugzilla.gnome.org/show_bug.cgi?id=630428
2011-01-07 15:21:48 -05:00
5322e9a643 notificationDaemon: Fix trayIcon check
Correctly detect non tray icons and use the ShellApp's icon in that case.
2011-01-07 16:24:44 +01:00
34f8568547 [l10n] Updated Estonian translation 2011-01-07 13:34:46 +02:00
66e0e5b370 Updated Traditional Chinese translation(Hong Kong and Taiwan) 2011-01-07 09:44:17 +08:00
960af783f7 Updated galician translations 2011-01-06 23:33:55 +01:00
1a884535ad BluetoothStatus: fix typo
The function to hide a menu item is .actor.hide(), not just .hide()
2011-01-06 20:35:21 +01:00
b2bb0bf10f BluetoothStatus: hide the icon when no adapter is present
There is no point in showing the bluetooth status, when the required
hardware is missing. Just hide in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=638306
2011-01-06 19:54:28 +01:00
4de15b2b57 PopupMenuManager: only navigate visible menus
When doing keyboard navigation, ignore menus whose sourceActor is
hidden.
This is needed to hide status icons, as otherwise the menu would
appear despite having no icon.

https://bugzilla.gnome.org/show_bug.cgi?id=638306
2011-01-06 19:54:28 +01:00
493844d005 PopupMenu: fix addMenuItem with explicit position
Only real menu items should be considered, fix this using the new
API in StBoxLayout.

https://bugzilla.gnome.org/show_bug.cgi?id=637681
2011-01-06 19:50:53 +01:00
046308c582 StBoxLayout: add insert_before
Add st_container_move_before internal API, and
st_box_layout_insert_before, that inserts an actor before another
in the container.

https://bugzilla.gnome.org/show_bug.cgi?id=637681
2011-01-06 19:50:53 +01:00
cedcbc5fcf BluetoothStatus: hide the device separator if no devices are shown
When BluetoothApplet::show-full-menu property is notified (when you
switch from a disabled adapter / no adapter to an active one), we
would show all the menu, including the device separator, without
checking if any devices actually existed.

https://bugzilla.gnome.org/show_bug.cgi?id=637690
2011-01-06 19:48:28 +01:00
a46baeed0b altTab: fix destroy-without-showing case
If the switcher is destroyed without ever being fully shown (either
because it couldn't get a keyboard grab, or just because there are no
apps to display), destroy it immediately rather than tweening it
towards destruction, since its contents haven't been built yet and
_allocate() will throw errors if it runs.
2011-01-06 13:38:41 -05:00
cff503922c DashDND: Don't allow positioning before or after self
Don't allow the icon to be dropped immediately next to
itself.

https://bugzilla.gnome.org/show_bug.cgi?id=637104
2011-01-06 14:31:45 +01:00
ce2efc6a67 Overview: Change tab title style to match mockups
https://bugzilla.gnome.org/show_bug.cgi?id=638815
2011-01-06 14:08:43 +01:00
778aa6be09 Updated Spanish translation 2011-01-06 10:58:45 +01:00
0052657a22 Overview: Update warping code to new gdk api 2011-01-05 23:45:02 +01:00
f60b995236 Chats should jump to the top of the notification queue.
This is to ensure users get notified as soon as chats are received.
Notifications with critical urgency still have the highest priority.

https://bugzilla.gnome.org/show_bug.cgi?id=630934
2011-01-05 17:23:01 -05:00
ceedc7e32c Implement cross overview drag & drop
The gnome-panel allows the user to hover over a tasklist entry
while draging to activate a minimized or obscured window and drop onto it.

Implement a similar behaviour by allowing draging to the activities button or
the hotcorner (and thus opening the overview), which allows the user to
activate any window (even on different workspaces) as a drop target.

https://bugzilla.gnome.org/show_bug.cgi?id=601731
2011-01-05 23:19:56 +01:00
62507c9759 Add a facility to show the stage without grabbing
When the user is doing a drag-and-drop, we want to temporarily show the
stage to allow them to drag to a different window. But we're not "really"
in the overview, and getting a grab would conflict with the X client doing
the drag and drop.

So add a showTemporarily()/hideTemporarily() pair of methods that show
the overview without grabbing.

This adds a lot more possibilities for asynchronous race conditions, so
rework the code to be more robust against multiple calls to show*()
and hide*(). The interpretation is now that all calls to show*() and
hide*() affect the state, but if we have conflicting calls to show and
hide we wait until the current animation is finished before correcting
to the right visual state.

https://bugzilla.gnome.org/show_bug.cgi?id=601731
2011-01-05 23:19:51 +01:00
7beb7e0f65 gnome-shell.in: Really never add empty elements to LD_LIBRARY_PATH
This complements the fix from c6eb2761, to make sure that we don't use
the pre-existing $LD_LIBRARY_PATH if it's set but empty.

Both commits fix CVE-2010-4000.

https://bugzilla.gnome.org/show_bug.cgi?id=638728
2011-01-05 10:54:38 +01:00
ad67225bf8 Updated Norwegian bokmål translation 2011-01-04 19:43:32 +01:00
dd0f721694 calendar: Use AlignConstraint to center the popup
This fixes warnings like:

(mutter:12238): Clutter-WARNING **: The actor 'calendarPopup' is
currently inside an allocation cycle; calling clutter_actor_queue_relayout()
is not recommended

https://bugzilla.gnome.org/show_bug.cgi?id=637829
2011-01-04 17:20:16 +01:00
24f1e87813 clock: Use settings from gsettings-desktop-schemas
A key for 12hr/24hr clock format has been added to gsettings-desktop-schemas,
so use that instead of the one from the shell clock schema.

As the setting can be controlled from the Date and Time panel of
gnome-control-center now, drop the temporary preference dialog
as well.

https://bugzilla.gnome.org/show_bug.cgi?id=633200
2011-01-04 17:14:00 +01:00
68a0d7897f Build: stop updating timestamp of st.h when not needed
Use the same approach as other generated headers (a temporary file,
compare to the existing, then copy), to avoid touching st.h, so
that other dependent objects are not rebuilt, if not needed.
It should speed up building when switching git branches, as often
config.status or automake are run, causing Makefiles to be recreated.

https://bugzilla.gnome.org/show_bug.cgi?id=638453
2011-01-04 00:17:26 +01:00
d9d56b7492 [l10n] Updated Estonian translation 2011-01-02 20:24:26 +02:00
96a0b9d416 Updated Norwegian bokmål translation from Torstein Adolf Winterseth 2011-01-02 19:20:31 +01:00
d48f064636 [l10n] Updated German translation 2011-01-01 23:21:35 +01:00
4e0a1c1152 Updated Swedish translation 2010-12-31 12:58:28 +01:00
272cbc1485 Updated Swedish translation 2010-12-31 12:58:22 +01:00
0ba7188625 Remove Gtk 2 compatibility code
It is useless now that we require Gtk 3.

https://bugzilla.gnome.org/show_bug.cgi?id=638315
2010-12-30 21:36:37 +01:00
6a2f038515 Updated Vietnamese translation 2010-12-29 21:29:16 +07:00
9f04009f80 po/vi.po: import from Damned Lies 2010-12-29 21:26:17 +07:00
2763d8dcc1 Fix error from blocking removed Gdk.Display.get_device_state.
Gdk.Display.get_device_state() was removed in favor of a
non-GdkModifierType returning Gdk.Device.get_position(). But block
Gdk.Device.get_state() which does return a GdkModifierType mask.

https://bugzilla.gnome.org/show_bug.cgi?id=638158
2010-12-28 07:53:39 -05:00
f8eb881728 Update Punjabi Translation 2010-12-27 07:13:19 +05:30
0406b91bd5 Update Simlified Chinese translation. 2010-12-25 12:55:31 +00:00
e6678dadd8 Updated Spanish translation 2010-12-23 19:54:37 +01:00
a2fb8a8dce Added UG translation 2010-12-23 19:08:24 +01:00
5f212b1ae2 BluetoothStatus: update only devices that actually changed
When receiving a "devices-changed" signal from BluetoothApplet,
check if some device item corresponds to an existing one, destroy
the remaining and add the new ones.
With this patch, signal emission when no device actually changed
(which happen due to bluetoothd creating temporary devices) result
in a no-op.

https://bugzilla.gnome.org/show_bug.cgi?id=637690
2010-12-23 18:29:58 +01:00
23432e616d BluetoothStatus: move the sendto item to the bottom
Kill one separator by merging all global actions items at the end
of the menu, which ends up divided in three sections: status,
devices and actions.

https://bugzilla.gnome.org/show_bug.cgi?id=637690
2010-12-23 18:29:58 +01:00
7d44c666ff altTab: use 'selected' pseudo-style for selected item
This makes it consistent with other parts of the UI and will let the
a11y code use the rule "has_style_pseudo_class('selected') =>
ATK_STATE_SELECTED"

https://bugzilla.gnome.org/show_bug.cgi?id=637830
2010-12-23 09:50:40 -05:00
ca09595350 Bump version to 2.91.4 2010-12-22 18:44:11 -05:00
b1dc2d967e Bump GTK+ minimum version to 2.91.7
Needed for new gdk_x11_window_* functions.
2010-12-22 16:38:17 -05:00
c546ad9720 Fix for gdk/x11 changes
Handle the move of gdk_window_lookup() and gdk_window_foreign_new()
into the gdk_x11_ namespace.
2010-12-22 16:26:08 -05:00
53f53c5a91 TelepathyClient: make chat notifications resident
This ensures that chat notifications don't get removed from
the message tray when clicked.

https://bugzilla.gnome.org/show_bug.cgi?id=637810
2010-12-22 15:27:46 -05:00
d2f675e41c Remove check for GTK+-3.0 compiled Mutter
Mutter no longer optionally builds with GTK+-2.0, so we don't
need to check for it. And the specific form of the check broke
with recent changes to the naming of libraries for GTK+.
2010-12-22 14:37:03 -05:00
d66370aecb gnome-shell.modules: Build vala 0.11.2
Now required by dconf
2010-12-22 13:49:36 -05:00
1694148bdb popupMenu: don't animate menus when switching from one to another
Don't do the "slide" effect when moving from one menu to another; only
do it when opening the first menu, or closing a menu without opening
another one.

https://bugzilla.gnome.org/show_bug.cgi?id=634755
2010-12-21 17:11:38 -05:00
7d0eeef90a panel: fix up calendar-vs-menu handling on clock
Give the clock's right-click menu its own PopupMenuManager so that if
you drop down another menu and then mouseover the clock it doesn't
pop up the right-click menu.

https://bugzilla.gnome.org/show_bug.cgi?id=634755
2010-12-21 17:10:36 -05:00
23f3af832c StIcon: fix typo
After having freed pending_texture, we should nullify it, not an
unrelated actor.
2010-12-21 22:54:27 +01:00
52a87a22ec appDisplay: Add translator comment for "All" filter
The correct translation for "All" depends on context in some
languages, so add a translator comment.

https://bugzilla.gnome.org/show_bug.cgi?id=637559
2010-12-21 20:10:16 +01:00
ea63f7562f Updated Hebrew translation. 2010-12-21 12:59:40 +02:00
d3de4e3fbd ctrlAltTabManager: implement Ctrl-Alt-Tab
Add CtrlAltTabManager, which allows tabbing between StFocusManager
groups, and fix up the panel to be keyboard navigable.

https://bugzilla.gnome.org/show_bug.cgi?id=618885
2010-12-20 17:43:01 -05:00
f326595202 popupMenu: fix up grab/ungrab handling
Fix the panel menus to avoid unnecessarily bouncing out of modal (bug
634194) and to do a better job of keeping the keyboard focus in the
right place

https://bugzilla.gnome.org/show_bug.cgi?id=618885
2010-12-20 17:43:00 -05:00
4dd4c9f99f Use more actor.grab_key_focus() and less stage.connect('key-press-event')
Until recently, the clutter keyboard focus was almost always kept on
the stage, and bits of code that wanted to do stuff with the keyboard
would just watch for key-press-events on the stage. In several places,
the code wasn't even bothering to ensure that the focus was on the
stage, which caused problems with other actors that explicitly grabbed
focus.

A previous fix for this (f21403fd) was to always reset the focus to
the stage after calling pushModal(), but a better fix is to just
actually make use of the keyboard focus everywhere rather than having
everyone try to read events off the stage.

Now pushModal(actor) also does actor.grab_key_focus(), and various
bits of code have been changed to read key events off their own
toplevels rather than off the stage, meaning there's no chance of them
accidentally getting someone else's events.

https://bugzilla.gnome.org/show_bug.cgi?id=618885
2010-12-20 17:32:07 -05:00
69bed929af l10n: Updated Italian translation 2010-12-20 22:55:45 +01:00
db457db060 BluetoothStatus: s/Ok/OK in user visible button 2010-12-20 22:07:28 +01:00
12c113a7a7 l10n: add missing bluetooth.js to POTFILES.in 2010-12-20 21:41:21 +01:00
be96cb9291 Make gnome-shell-clock-preferences work again
Thanks Owen and Colin for debugging this:

<davidz> does anyone have a clue about this cryptic error message: http://fpaste.org/aWgh/ ?
<owen> davidz: well, I'd guess some sort of syntax error...
<walters> hmm
 possibly but unlikely fallout from my js versioning
<owen> oh, it's happening here too
 walters: exactly
 Adding --js-version=1.8 to the wrapper script fixes
 walters: I thought you were defaulting to allowing extensions?
<walters> actually, let's do that now anyways

Signed-off-by: David Zeuthen <davidz@redhat.com>
2010-12-20 15:07:10 -05:00
bfc7b98e1d PopupMenu: restore the arrow when fast closing the menu
When closing a submenu because the parent is closing, we skip the
animation, but we need to restore the arrow anyway.
2010-12-20 18:16:59 +01:00
054f498201 BluetoothStatus: hide the additional separator if no devices are shown
Sometimes devices are reported by BluetoothApplet, but are not shown,
so we should not count them to decide whether to show the device
separator.
2010-12-20 17:58:12 +01:00
6024b87d27 PopupMenu: handle submenus inline
Instead of showing submenus on the left side, make PopupSubMenuMenuItem
act like an expander. The sub menu is toggled on click, opened on
right/enter/space on the parent item, closed on left on any item
or when closing the parent menu.

https://bugzilla.gnome.org/show_bug.cgi?id=633476
2010-12-20 17:46:31 +01:00
59b1aa26bb [l10n] Updated Estonian translation 2010-12-20 14:30:54 +02:00
f96bc5c052 Updated Spanish translation 2010-12-19 13:14:51 +01:00
67c05e07b1 Updated Hebrew translation. 2010-12-19 01:04:51 +02:00
dafaab66b1 iconGrid: Exclude hidden children from the layout
As all children were considered for the grid's layout, hidden items showed up as
empty space. Instead, exclude hidden children from the layout, so that the grid is
only made up of visible items.

https://bugzilla.gnome.org/show_bug.cgi?id=631537
2010-12-18 22:23:38 +03:00
4fd24da4e4 app-display: Implement filtering applications by category
Add a list of filters to the application view of the view selector, as in the latest mockups

https://bugzilla.gnome.org/show_bug.cgi?id=631537
2010-12-18 22:23:33 +03:00
bdfc516715 StTextureCache: Plug leaks in tiled image loading
We weren't freeing the whole pixbuf, nor were we the GList of
subpixbufs.  Plug both of these leaks in the error handling path
and in the default case.

All of the unreffing/cleanup should happen in the GDestroyNotify
for the result, not some in the handler.

https://bugzilla.gnome.org/show_bug.cgi?id=636489
2010-12-18 13:44:37 -05:00
94da2531e7 configure: Fix case if HAVE_BLUETOOTH is false
We still need to AC_SUBST here.
2010-12-18 13:39:07 -05:00
9e99a8c25a Bluetooth status indicator
Introduce the new Bluetooth indicator in the System Status area. It
is written in JS with St and uses the new GnomeBluetoothApplet library.

https://bugzilla.gnome.org/show_bug.cgi?id=618312
2010-12-18 19:10:15 +01:00
bc83890c39 Updated Spanish translation 2010-12-18 14:37:27 +01:00
2d55eab62e Remove 'What's using power...' menu option
The dialog brought up by the "what's using power.." option is currently
more confusing than useful to the user. n

https://bugzilla.gnome.org/show_bug.cgi?id=636982
2010-12-17 14:18:28 -05:00
d66207bc68 Updated Norwegian bokmål translation 2010-12-17 14:19:35 +01:00
9f39ce5d27 Explicitly specify JS version
See bug 636652 for rationale.

https://bugzilla.gnome.org/show_bug.cgi?id=636983
2010-12-16 17:40:17 -05:00
eef194c3aa shell-info: Use transient notifications
According to the designers, system notifications should be transient;
so now that transient notifications are supported properly, make use
of it instead of using a timeout to remove the associated source.
2010-12-16 22:55:11 +01:00
22f4aabadf NotificationDaemon: add support for transient notifications
Transient notifications are removed after being shown. If the summary
is being shown while they appear, they are represented in it by a new
source icon.

We always create a new source for new transient notifications to
ensure that they don't replace the latest persistent notification
associated with the source. Because we generally don't want any
new or resident notifications to be replaced by others, associating
multiple notifications with a source is the next thing we will
implement.

https://bugzilla.gnome.org/show_bug.cgi?id=633412
2010-12-16 15:50:29 -05:00
2a19d5f143 NotificationDaemon: add support for resident notifications
Resident notifications don't get removed when they are clicked or
one of their actions is invoked, and are only removed when the app
that created them requests them to be removed or sends another
notification.

Remove the source when a notification associated with it is removed.
Except if the source is a tray icon.

Make sure that we pop down the tray when a notification is clicked
or one of the actions of a non-resident notification is selected.

Based on the initial patch by Jonathan Matthew.

https://bugzilla.gnome.org/show_bug.cgi?id=633412
2010-12-16 15:49:47 -05:00
7279cc1db8 Overview: Remove invisible animations
Given that the grid view is gone there is no point in animating the
window previews on all workspaces anymore so just do it for the current
one avoid taking a slow down caused by animating windows on other workspaces.

https://bugzilla.gnome.org/show_bug.cgi?id=637353
2010-12-16 20:24:08 +01:00
e41b0bc16d Remove unused workspace._visible property 2010-12-16 20:23:45 +01:00
e3aab2a90f tests: Fix scrolling in border.js and border-radius.js
In both tests the scrolled actor's width was fixed to the stage
width, so that the scroll bars ended up outside the visible area.

Fix by adding an outer container with a fixed width and expanding
the scroll view to fill the available area.
2010-12-16 18:09:03 +01:00
7eec8a899a popupMenu: Improve menu item layout
Mixing submenu menuitems and toggle menuitems results in poor layout.
The fix is to right-align the submenu arrows. Since we already need to
right-align the battery percentages as well, add alignment support to
PopupBaseMenuItem.addActor(), and update stuff for that.

Also remove the "column" param from addActor() since it hadn't
actually been implemented correctly before.

https://bugzilla.gnome.org/show_bug.cgi?id=633476
2010-12-16 09:01:24 -05:00
3262b63325 overview: mark Windows and Application as translatable 2010-12-16 00:30:21 +01:00
be59876c60 Updated Spanish translation 2010-12-15 21:59:37 +01:00
26f395bb84 [l10n] force no-c-format for "sent at ..." message
"Sent at %X on %A" was incorrectly marked as c-format in PO files;
forcing the no-c-format to allow custom format in translations.
2010-12-13 23:12:51 +01:00
7653cf6ad0 Updated Hebrew translation. 2010-12-13 23:52:06 +02:00
3203dc549c Updated Italian translation 2010-12-13 22:40:28 +01:00
4ae9c978ce Add missing telepathyClient.js to POTFILES.in 2010-12-13 21:47:28 +01:00
cb5c18c783 st-theme-node: Support non-uniform border widths
While non-uniform border widths were parsed correctly, an arbitrary
side's width was picked when painting, so that each border ended up
with the same width and the widths specified in CSS were ignored.

At least for sides between non-rounded corners, using a different
border width can be reasonable, for instance at screen edges.

Different border widths around rounded corners are kind of crack,
but then it would be lame not to support it ...

https://bugzilla.gnome.org/show_bug.cgi?id=607500
2010-12-13 18:15:00 +01:00
cb2babb1a0 st-theme-node: Improve borders with gradient backgrounds
For gradient backgrounds, borders were implemented by filling the
background shape with the border color first, and then scaling down
the path to draw the background.

The result is not correct[0], which is especially visible if the border
width is greater than the border radius - so instead of scaling down
the original path, use a separate path for the background.

The result is consistent with the borders we draw for non-gradient
backgrounds, and much closer to the correct standard behavior.

[0] http://www.w3.org/TR/css3-background/#the-border-radius

https://bugzilla.gnome.org/show_bug.cgi?id=607500
2010-12-13 18:15:00 +01:00
c648a5f117 StThemeNode: handle url() in inline styles better
non-absolute paths specified as url()'s in
stylesheets are resolved to be relative to the location
of the stylesheets they are in.

Inline styles don't have physical styleshseets sitting on disk,
which leads to a crash in the url resolving code.

This commit ensures that we don't try to use the stylesheet associated
with a url, if there isn't one to use.

This commit doesn't try to handle relative paths in inline styles.
It only prevents crashes when absolute paths are used.

https://bugzilla.gnome.org/show_bug.cgi?id=636975
2010-12-13 11:48:36 -05:00
e562c863f7 Update Simplified Chinese translation. 2010-12-12 15:45:36 +08:00
cdaf8f3d19 Updated Slovenian translation 2010-12-11 20:41:16 +01:00
a33aab07e6 Updated Spanish translation 2010-12-11 16:45:05 +01:00
26a5197d33 Updated Galician translations 2010-12-10 23:30:32 +01:00
8be2800486 ShellGlobal: Remove root_pixmap left-over
Still had a few references to the root_pixmap actor that was removed
when we switched to using the root actor support in Mutter.
2010-12-09 19:14:26 -05:00
a2528a7a98 StIcon: fill the structure corretly in _init
GSlice already fills with zeros when allocating, but we need to
set the shadow_material field appropriately.

https://bugzilla.gnome.org/show_bug.cgi?id=634814
2010-12-09 22:27:32 +01:00
2332e2b0c5 StIcon: remove implementation of ::map and ::unmap
They're not needed since Clutter 1.5.8, which internally
keeps a list of children, used by the default implementations of
::map and ::unmap.

https://bugzilla.gnome.org/show_bug.cgi?id=634814
2010-12-09 22:27:11 +01:00
a70f1f449b StIcon: don't show the icon until fully loaded
When updating the texture, keep the old one until the new one is
loaded.

https://bugzilla.gnome.org/show_bug.cgi?id=634814
2010-12-09 17:59:28 +01:00
e425a183f7 gdm: pull async fix from upstream
This prevents a race at start up that could prevent the user
from getting loaded properly.

In the near future we need to drop the gdm user code entirely
and switch to using the accountsservice library.
2010-12-07 14:31:35 -05:00
0bbeb733a2 Updated Brazilian Portuguese translation 2010-12-07 09:01:21 -02:00
ff77994204 Add missing deps for st-enum-types.h
st-enum-types.h needs to be regenerated when the St header files
change.
2010-12-06 17:33:33 -05:00
563951b789 Updated Norwegian bokmål translation 2010-12-06 19:06:24 +01:00
ea65f5e795 Updated Hebrew translation. 2010-12-05 01:42:58 +02:00
670048e555 StScrollView: Remove default shadow style
Remove the default shadow style but still allow StScrollView users to use a shadow by explicitly setting it.

https://bugzilla.gnome.org/show_bug.cgi?id=635647
2010-12-04 12:16:58 +01:00
35b5cb9860 magnifier: Fix DND when the magnifier is active
Hide the zoom regions from pick so that they do not interfere with
the picking done by DND in search for _delegate objects.

https://bugzilla.gnome.org/show_bug.cgi?id=634560
2010-12-03 20:38:25 +01:00
978cf9d3ab Fix redundant calls to global.get_pointer()
Since we are keeping a current pointer position anyways, we
don't have to continually call global.get_pointer() which is
a round trip to the magnifier; make ZoomRegion simply fetch
a current position stored in the Magnifier object.

https://bugzilla.gnome.org/show_bug.cgi?id=633553
2010-12-03 14:21:57 -05:00
96fb6d8f16 Improve the algorithm for proportional mouse tracking
Change the proportional algorithm so stop moving the zoom region
when cursor is in a "padding region" at the edge of the screen.
(The padding region is a 10th of the screen at 2x zoom, and smaller
for higher zooms.)

Based on earlier versions from Jon McCann and Florian Muellner.

https://bugzilla.gnome.org/show_bug.cgi?id=629950
2010-12-03 14:21:57 -05:00
c5c66ceb98 Refactor Magnifier.ZoomRegion to avoid permanent Clutter.Clone
This basic point of this change is to avoid always creating a
hidden Clutter.Clone actor for the default present-but-not-active
zoom region. The position of the viewport and region of interest
are now stored in member variables, and the actors are only created
and updated when the region is active.

Other significant changes:

 * Unused public functions are removed or made private
 * The mouse tracking position is immediately  updated when options
   like the zoom are changed, not just on the next mouse motion.
 * ZoomRegion.setROI() now updates the zoom, not just the position;
   a FIXME is added to the D-Bus interface for a place where the
   D-Bus interface contains duplicate possibly conflicting information
 * Lens-mode is now only effectively off when the magnifier is
   fullscreen, instead of actually modifying the member variable;
   this makes things work properly when changing out of full-screen
   mode.
 * When the clamping to screen edges is turned on, we now immediately
   clamp.
 * The handling of setting the position to fullscreen as compared
   to just setting the viewport to fullscreen is untangled.

https://bugzilla.gnome.org/show_bug.cgi?id=633582
2010-12-03 14:21:57 -05:00
1efb0213c5 window-manager: Swap workspace order for RTL locales
Workspaces should be aligned from right to left in RTL locales, so
take the text direction into account when switching workspaces.

https://bugzilla.gnome.org/show_bug.cgi?id=634691
2010-12-03 18:25:49 +01:00
1a466cfce4 gnome-shell.modules: add libcanberra as a dependency of Mutter
libcanberra is an (optional) dependency of Mutter; since we have
it in the moduleset we need to mark the dependency so things get
built in the right order.
2010-12-03 11:14:29 -05:00
46ba718ab2 LookingGlass: Use GSettings for monospace-font-name
Convert code to look up and watch the configured monospace font
to use GSettings instead of GConf.

https://bugzilla.gnome.org/show_bug.cgi?id=636155
2010-12-03 11:14:29 -05:00
b40cc2c294 statusMenu: Force the overview mode of the settings
When launching gnome-control-center, request it to show
the overview rather than just presenting the current window.

https://bugzilla.gnome.org/show_bug.cgi?id=636317
2010-12-03 14:43:56 +00:00
c86da9afbd Updated Tamil translation 2010-12-03 18:45:22 +05:30
d00933f044 adding fa to LINGUAS 2010-12-03 13:46:34 +03:30
172f78daad Updating Persian Translation 2010-12-03 13:45:51 +03:30
d7cc82909a a11y-status: Use single quotes for non-translatable strings
Fix the usage of single vs double quotes according to our coding
conventions.
2010-12-03 00:20:16 +01:00
7ce65e421b Fix compilation against latest GTK+-3 changes
GDK_WINDOW_XWINDOW has been removed. All calls should use
gdk_x11_window_get_xid() instead.
2010-12-02 17:12:07 -06:00
0c8941715d Rename side-by-side tiling key
It's now called edge_tiling since it can do more than
just side-by-side tiling.

https://bugzilla.gnome.org/show_bug.cgi?id=630548
2010-12-02 17:19:25 -05:00
5ba9bb7a67 Updated Spanish translation 2010-12-02 19:09:57 +01:00
7b73df78c6 Fix display of remaining time
When there is less than an hour remaining, there was a format() call missing
which made the power status menu display "%d minutes remaining".

https://bugzilla.gnome.org/show_bug.cgi?id=635728
2010-12-01 18:50:16 -05:00
43d479c786 Don't pass an (out) argument to meta_window_get_outer_rect()
Mutter now has the needed (out) annotation, so we have to use the
return value instead of passing a reference to a rectangle.
2010-12-01 22:43:02 +01:00
b9eca84d34 telepathyClient: Implement Sent signals.
This will allow us to update our notifications when
someone uses a different Telepathy client to send
messages.

https://bugzilla.gnome.org/show_bug.cgi?id=635991
2010-12-01 13:46:07 -05:00
aef005f451 PowerStatus: show separate hour and minutes for primary device
Show "%d hours %d minutes" instead of "%d minutes", for better
readability.

https://bugzilla.gnome.org/show_bug.cgi?id=635728
2010-12-01 19:12:11 +01:00
24669e3ba7 a11y-status: Use GSettings to access the magnifier
The magnifier should be enabled/disabled via the appropriate
GSettings key - otherwise the setting gets out of sync with the
actual state of the magnifier.

https://bugzilla.gnome.org/show_bug.cgi?id=636151
2010-12-01 14:26:16 +01:00
e99eefbb00 update for Punjabi by A S Alam 2010-12-01 08:24:25 +05:30
08b84b1449 app-display: Popup menus to the left in RTL locales
The popup menus of application icons in both the dash and the app view
are positioned on the right of the icon. In the case of the dash this
results in the menu being displayed off-screen in RTL locales, so move it
to the opposite side instead.

https://bugzilla.gnome.org/show_bug.cgi?id=635645
2010-12-01 00:02:16 +01:00
7c980f42c9 message-tray: Fix typo
At one place, we set State.SHOWNING instead of State.SHOWING.

Thanks to Jasper St. Pierre for spotting this.
2010-11-30 17:56:59 +01:00
42366e4be4 overview: Use a symbolic icon for notifications
Notifications from the system should use symbolic icons.

Also fix up the summary area CSS so the icon gets the right colors.

https://bugzilla.gnome.org/show_bug.cgi?id=636137
2010-11-30 11:26:30 -05:00
991a0c642b PowerStatus: make the primary device activatable
If the primary device is not virtual, make it open
gnome-power-statistics on activate.

https://bugzilla.gnome.org/show_bug.cgi?id=635880
2010-11-30 15:49:09 +01:00
6aac51a2a7 popupMenu: give sliders a minimum width
The simpler volume menu resulted in a slider that was too short. Fix
that.

https://bugzilla.gnome.org/show_bug.cgi?id=635393
2010-11-30 07:16:36 -05:00
6adc12368c boxpointer: don't draw the arrow overlapping the corners
In some circumstances, a boxpointer would draw itself with the arrow
partially overlapping the rounded corner, causing things to not line
up correctly. Don't do that.

And while we're at it, don't draw the pointer very very close to the
corner either, since it looks odd if the corner flows directly into
the arrow.

https://bugzilla.gnome.org/show_bug.cgi?id=635393
2010-11-30 07:14:20 -05:00
eb2ee3f259 Bump version to 2.91.3 2010-11-29 17:58:04 -05:00
8b5cd4ef0f calendar: Take week start and month/year ordering from GTK+-3
Despite of switching to GTK+-3 unconditionally, those settings were
still taken from GTK+-2.
2010-11-29 22:47:14 +01:00
4517f60630 environment: Get text direction from GTK+-3
Despite of switching to GTK+-3 unconditionally, the default text
direction was still taken from GTK+-2.
2010-11-29 22:00:37 +01:00
b25bad9995 notificationDaemon: fix escaping in xchat rewrite rules
https://bugzilla.gnome.org/show_bug.cgi?id=635712
2010-11-29 14:31:20 -05:00
c9b178b193 Touch up padding again this time with the correct box 2010-11-29 14:03:07 -05:00
6b0fe1b0b0 Add padding on the left of the notification scrollbar
It looks better that way.

https://bugzilla.gnome.org/show_bug.cgi?id=630752
2010-11-29 13:29:57 -05:00
c908a060b8 Touch up the spacing and style of the app view
Adds more padding between app icons, left aligns the view,
removes the ugly separator, adds some margin on the right.
2010-11-29 13:16:20 -05:00
063fc8e29c Updated Galician translations 2010-11-29 17:33:20 +01:00
d870fef122 StBoxLayout: report correct paint volume when scrolled
When scrolled, st_box_layout_apply_transform() includes the scroll
offset and affects paint volumes. This is right for our children, but
our paint volume is determined by our allocation and borders and
doesn't scroll, so we need to reverse-compensate, the same as we do
when painting.

https://bugzilla.gnome.org/show_bug.cgi?id=630932
2010-11-29 11:23:47 -05:00
6b723ed72a StImText: add get_paint_volume()
Since StImText isn't a StWidget, it needs it's own implementation
of get_paint_volume() to enable clipped redraws.

https://bugzilla.gnome.org/show_bug.cgi?id=630932
2010-11-29 11:23:47 -05:00
56fb7e2c58 St: Take advantage of clipped redraws
In order to take advantage of clipped redraws (only redraw the
parts that actually changed), we have to inform clutter about
our paint_volume by implementing the get_paint_volume virtual
method.

As this feature had been added in in clutter 1.5.x we now require
that.

https://bugzilla.gnome.org/show_bug.cgi?id=630932
2010-11-29 11:23:47 -05:00
41a5282b7e gnome-shell.css: don't override the chat-response entry's height
We were forcing the chat-response entry to have too small a height,
making underscores not show up. We're already setting the font size,
so we should just let the entry request the height it needs based on
that.

https://bugzilla.gnome.org/show_bug.cgi?id=635471
2010-11-29 11:13:15 -05:00
6f9ede569e workspace-indicators: Add hover indication
Scale up indicators on hover to hint at their clickability.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:54 +01:00
e2e11b1a29 overview: Update animation
Update the animation on entering/leaving the overview to only zoom
the window previews and fade other elements.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:54 +01:00
b59daac6f3 dash: Improve DND to dash and allow reordering
Show a positional indicator where a new favorite will be added and
make the favorites re-orderable. Also allow the removal of favorites
using drag-and-drop according to the mockups.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:54 +01:00
5fef9188c9 workspaces: Change handling of window-drag signals
Delegate the emission of the window-drag-begin/window-drag-end
signals to overview functions, as done already for other items.
This will enable objects to react to those signals without having
access to the workspace objects / the workspaces view.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:54 +01:00
2c5d825c87 search-display: Change the default display to use iconGrid
Current mockups display all search results as icons as used by
application results, so change the default result display to use
iconGrid/BaseIcon. Remove the custom application results display,
as it is no longer needed.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:53 +01:00
d5d7d8a391 overview: Add ViewSelector to the overview
Add the view selector and adjust the positioning of elements in the
overview. Unlike the old dash, the view selector is made public to
indicate that extensions may add additional views or search providers.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:53 +01:00
7811632e6f workspaces: Rework workspace controls for the view selector
As workspaces will appear as a particular view in the view selector,
merge WorkspacesControls and WorkspacesManager to control workspaces
and related controls, so that a single actor can be added to the
selector instead of positioning the elements from the overview.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:53 +01:00
6c5c3bedbe workspaces-view: Swap workspace ordering for RTL locales
Make the first workspace the right-most one in RTL locales, as one
would expect. Update all dragging/scrolling functions to behave
correctly.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:53 +01:00
0942f50781 workspaces-view: Remove MosaicView
The new layout does no longer support view switching, so merge
GenericWorkspacesView and SingleView, and remove MosaicView.
Also rename or remove workspace properties and functions which
are now unused.
The grid will have a comeback with the new DND behavior.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:53 +01:00
1eb6dfe1b8 app-display: Slight cleanup and style update
Being no longer an independent menu pane, both the toggle() and
close() functions are no longer needed, and the view's structure
can be simplified a bit.

Also update the style to fit into the view selector.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:53 +01:00
1a77acfda6 Fake workspaces tab
https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:53 +01:00
ffd7eaede5 view-selector: Add keyboard shortcut for view switching
As the view selector is a tabbed interface, use the default keyboard
shortcut of Ctrl-PageUp/PageDown of GtkNotebook for switching between
views.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:53 +01:00
688a315cbf view-selector: Move search logic into SearchTab
The view selector should only deal with view switching, so move the
logic to deal with search (find-as-you-type, cancelling a search,
navigating/activating results) into the SearchTab.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:53 +01:00
48fff0e96b Use the old dash code to implement the view selector
The view selector is a tabbed interface with a search entry. Starting
a search switches focus to the results' tab, ending a search moves the
focus back to the previously selected tab. Activating a normal tab
while a search is active cancels the search.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:53 +01:00
e6bb06a7cc search-display: Move SearchResults to a separate file
With the new layout, search results will be displayed in an independent
view like window previews, applications and possible future additions;
it does not make much sense keeping it with the switching logic, so move
the code to its own file.

Also remove the dash-prefix from the relevant style classes.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:53 +01:00
26225f0bfb dash: Move padding into the icon for Fittsability
With this change, the icons' reactive area extends to the screen
edge, making them good targets according to Fitts' law.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:53 +01:00
3e4f744e56 dash: Reimplement the dash based on AppWell code
The new dash implementation is a single-column vertical sidebar,
whose items are scaled dynamically to fit the available height.
If the height is still exceeded after scaling down to a minimum
item size, excess items are cut off.
The now unused old dash implementation is renamed to OldDash, as
its code will be used as a base for the new view selector element.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 16:35:47 +01:00
2d2ac5b3f6 linear-view: Remove NewWorkspaceArea
As the button to add workspaces will move to the same position as
the new workspace drop area in drag mode, the latter is redundant
and can be removed.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 02:25:15 +01:00
e06b608b10 linear-view: Remove shadows when zoomed out
Overlaying inactive workspaces with a gradient to fade out the actors
does no longer work when re-using the normal desktop background. If
we keep the current DND behavior, we probably want to implement a real
fade effect - for now, just remove the visually disruptive shadows.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 02:25:15 +01:00
f24e567dc4 overview: Do not zoom the desktop background
While scaling the desktop background with the window previews represents
workspaces quite intuitively, the approach is not without problems.
As window previews in the overview behave quite differently to "real"
windows, the representation of workspaces as miniature versions of
"real" workspaces is flawed. The scaling also makes the transitions
to and from the overview much more visually expensive, without adding
much benefit.
Leaving the background in place provides more visual stability to the
transitions and emphasizes the distinctive behavior of elements in the
overview.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 02:25:15 +01:00
1ea488bb3d overview: Replace InfoBar with message tray notifications
The layout of recent mockups occupies the space previously reserved
for the info bar with the view selector. As the bar's purpose is
mainly to provide the user with feedback, it makes sense to use the
existing message tray facility instead of moving the bar elsewhere.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 02:25:15 +01:00
8d47a150df linear-view: Remove the scrollbar
The scrollbar is the main culprit for cluttered controls in the
linear view - all its functionality is already provided by the
workspace indicators, so it is save to remove the scrollbar in
order to clean up the interface.

https://bugzilla.gnome.org/show_bug.cgi?id=634948
2010-11-29 02:25:15 +01:00
dc24252e82 Updated Galician translations 2010-11-27 01:43:13 +01:00
2167be053d Added UG translation 2010-11-26 14:28:16 +01:00
926ddc2bdf Show timestamp in expanded chat
When the last message is older than SCROLLBACK_IMMEDIATE_TIME (1
minutes), show a timestamp in the middle, indicating the time it
was sent.
Use the same style for presence changes, but show them on the left.

https://bugzilla.gnome.org/show_bug.cgi?id=617228
2010-11-25 15:31:46 +01:00
4f7a28863c st-icon: Add support for -st-shadow property
Add a drop shadow to the icon texture if the -st-shadow property is
specified.

https://bugzilla.gnome.org/show_bug.cgi?id=635608
2010-11-25 05:38:20 +01:00
6e902f5fec Add development packages needed to build on Ubuntu 2010-11-25 01:18:06 +01:00
01e7d6f30e workspace: Simplify the close button's timeout handler
Clutter actor gained a :has_pointer property after the original
code was written, so use this instead of picking.
2010-11-24 19:04:15 +01:00
d6f1c10b1b messageTray: fix handling of markup vs non-markup notifications
NotificationDaemon-based notifications have markup in the banner/body,
but Telepathy-based notifications don't. (Eg, an XMPP message
containing "<b>foo</b>" should show up angle brackets and all, not as
bold.) Fix MessageTray.Notification to allow explicitly specifying
where there should and shouldn't be markup, and use that
appropriately.

https://bugzilla.gnome.org/show_bug.cgi?id=610219
2010-11-24 02:38:17 +03:00
65f0b483f8 messageTray: make links in message banners clickable
https://bugzilla.gnome.org/show_bug.cgi?id=610219
2010-11-24 02:38:08 +03:00
6a52deec7d Add function for finding urls in string
https://bugzilla.gnome.org/show_bug.cgi?id=610219
2010-11-24 02:24:43 +03:00
3d468c26b0 Updated Thai translation. 2010-11-23 10:26:22 +07:00
a5e61e27c7 [statusMenu] Fix ellipsis in menu entries
According to the HIG we should use ellipsis when:

"Label the menu item with a trailing ellipsis ("...") only if the command requires further
input from the user before it can be performed. Do not add an ellipsis to items that only
present a confirmation dialog (such as Delete), or that do not require further input
(such as Properties, Preferences or About)"

So adjust the use of ellipsis to match that.

Pointed out by Michael Monreal.
2010-11-22 21:19:37 +01:00
59ba112959 Complete porting to new gnome-power-manager API
We updated the normal devices part, but we forgot the part about
the primary device (possibly because it is not reported as such
in case it is fully charged). Update that as well, to avoid showing
weird GIcon serializations.

https://bugzilla.gnome.org/show_bug.cgi?id=635288
2010-11-22 18:05:11 +01:00
4800f63c3a Correct and simplify setting the GJS module path
We were going to great effort to include the normal directories in the
GJS search path and the code to to do this broke recently when
jsdir and jsnativedir were moved to gjs-internals-1.0.pc. However, it
was actually unnecessary since the standard directories are appended
to the default path.

(We continue to use a GNOME_SHELL_JS envvar separate from GJS_PATH
for the Shell to enable the somewhat unlikely case where someone wants
to invoke the shell specifying a GJS_PATH.)

https://bugzilla.gnome.org/show_bug.cgi?id=635367
2010-11-22 10:21:45 -05:00
1fce237538 StThemeNode: suppress compiler warnings and fix minor bugs
Aggressive compiler flags can cause the compiler to be smart enough
to inline functions and detect variables not being set on certain
code paths but not smart enough to understand the overall logic;
add some extra initializations to suppress the warnings.

Fix several minor bugs in the logic found when double checking the
logic before adding the initializations.

Based on a patch by Marc-Antoine Perennou <Marc-Antoine@Perennou.com>.

https://bugzilla.gnome.org/show_bug.cgi?id=634225
2010-11-20 14:14:57 -05:00
71685a3b48 Fix this up 2010-11-20 14:40:40 +01:00
c0b9ce16a7 Updated Norwegian bokmål translation 2010-11-20 14:40:33 +01:00
d1407d0026 Added UG translation 2010-11-20 11:47:22 +01:00
d5bfc503fe Sound Menu: only show the slider
Reimplement UI without any indication of percentage or mutedness,
and whitout switches. The only interaction point is slider, but
it still supports mute changing for applications that track it,
and will react appropriately to external changes.

https://bugzilla.gnome.org/show_bug.cgi?id=634329
2010-11-19 23:13:32 +01:00
de50cf80a8 PowerStatus: Update for gnome-power-manager API changes
g-p-m no longer exports a summary, and instead exports a GIcon to
show. Update for that.

https://bugzilla.gnome.org/show_bug.cgi?id=635288
2010-11-19 22:31:37 +01:00
5086bfedac Fix dependencies for gnome-power-manager
Merging the g-p-m branch with the one adding gnome-settings-daemon
for A11y, a lot of modules were duplicated. Also, gnome-keyring is
not needed, the distro provided one is enough.

https://bugzilla.gnome.org/show_bug.cgi?id=635199
2010-11-19 22:27:44 +01:00
f67ad23033 statusMenu: Fix launching gnome-control-center with an option
This isn't how you launch an app with an option...
2010-11-19 20:34:32 +00:00
b7c1400eb3 dnd: fix a case where ungrabEvents wasn't being called
If the drag actor is destroyed as part of a drag target accepting it,
we were not calling ungrabEvents, meaning the mouse/keyboard remained
grabbed until you clicked somewhere to cancel it.

This fixes that without trying to improve the extremely confusing
control flow...

https://bugzilla.gnome.org/show_bug.cgi?id=635278
2010-11-19 15:09:57 -05:00
b956c6f093 dnd: when snapping back, deal with moved/rescaled parents
Previously, when snapping back a drag actor, we moved it back to its
original stage-relative position and scale. This worked fine if its
parent was still in the same place it was when the drag started, but
failed in cases like the linear workspace layout window drag-and-drop,
where dragging a window would "zoom out" its parent workspace, causing
the snapback to send it to the wrong place.

Fix this by instead snapping the actor back to "where the actor would
have been right now if it were still at its original scale and
position within its original parent actor" rather than "where it was
before the drag started"

https://bugzilla.gnome.org/show_bug.cgi?id=635272
2010-11-19 15:09:57 -05:00
bfc850a94d statusMenu: Make "My Account" menu item work again
For GNOME 3.x. gnome-about-me is dead, so we should be using the
user-accounts panel of gnome-control-center instead.

https://bugzilla.gnome.org/show_bug.cgi?id=635264
2010-11-19 13:39:25 +00:00
178 changed files with 26928 additions and 11617 deletions

6
.gitignore vendored
View File

@ -18,13 +18,12 @@ config
configure
data/gnome-shell.desktop
data/gnome-shell.desktop.in
data/gnome-shell-clock-preferences.desktop
data/gnome-shell-clock-preferences.desktop.in
data/gschemas.compiled
data/org.gnome.shell.gschema.xml
data/org.gnome.shell.gschema.valid
data/org.gnome.accessibility.magnifier.gschema.xml
data/org.gnome.accessibility.magnifier.gschema.valid
js/misc/config.js
intltool-extract.in
intltool-merge.in
intltool-update.in
@ -45,12 +44,13 @@ src/Makefile
src/Makefile.in
src/gnomeshell-taskpanel
src/gnome-shell
src/gnome-shell-clock-preferences
src/run-js-test
src/test-recorder
src/test-recorder.ogg
src/test-theme
src/st.h
src/stamp-st.h
src/stamp-st.h.tmp
stamp-h1
tests/run-test.sh
xmldocs.make

View File

@ -1,11 +1,14 @@
AC_PREREQ(2.63)
AC_INIT([gnome-shell],[2.91.2],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[2.91.6],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([src/shell-global.c])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_AUX_DIR([config])
AC_SUBST([PACKAGE_NAME], ["$PACKAGE_NAME"])
AC_SUBST([PACKAGE_VERSION], ["$PACKAGE_VERSION"])
AM_INIT_AUTOMAKE([1.10 dist-bzip2 no-dist-gzip foreign])
AM_MAINTAINER_MODE
@ -57,16 +60,21 @@ fi
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
CLUTTER_MIN_VERSION=1.3.14
GOBJECT_INTROSPECTION_MIN_VERSION=0.6.11
GJS_MIN_VERSION=0.7
MUTTER_MIN_VERSION=2.91.0
GTK_MIN_VERSION=2.91.0
CLUTTER_MIN_VERSION=1.5.15
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
GJS_MIN_VERSION=0.7.8
MUTTER_MIN_VERSION=2.91.4
GTK_MIN_VERSION=2.91.7
GIO_MIN_VERSION=2.25.9
LIBECAL_REQUIRED=1.6.0
LIBEDATASERVER_REQUIRED=1.2.0
LIBEDATASERVERUI2_REQUIRED=1.2.0
LIBEDATASERVERUI3_REQUIRED=2.91.6
# Collect more than 20 libraries for a prize!
PKG_CHECK_MODULES(MUTTER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION
gio-unix-2.0 dbus-glib-1
gio-unix-2.0 dbus-glib-1 libxml-2.0
gtk+-3.0 >= $GTK_MIN_VERSION
mutter-plugins >= $MUTTER_MIN_VERSION
gjs-internals-1.0 >= $GJS_MIN_VERSION
@ -78,6 +86,10 @@ PKG_CHECK_MODULES(MUTTER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION
gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION
libcanberra)
GJS_VERSION=`$PKG_CONFIG --modversion gjs-internals-1.0`
AC_DEFINE_UNQUOTED([GJS_VERSION], ["$GJS_VERSION"], [The version of GJS we're linking to])
AC_SUBST([GJS_VERSION], ["$GJS_VERSION"])
saved_CFLAGS=$CFLAGS
saved_LIBS=$LIBS
CFLAGS=$MUTTER_PLUGIN_CFLAGS
@ -87,14 +99,35 @@ AC_CHECK_FUNCS(JS_NewGlobalObject sn_startup_sequence_get_application_id)
CFLAGS=$saved_CFLAGS
LIBS=$saved_LIBS
PKG_CHECK_MODULES(TIDY, clutter-1.0)
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 gnome-desktop-3.0 >= 2.90.0)
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-3.0)
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
PKG_CHECK_MODULES(JS_TEST, clutter-x11-1.0 gjs-1.0 gobject-introspection-1.0 gtk+-3.0)
AC_MSG_CHECKING([for bluetooth support])
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 2.90.0],
[BLUETOOTH_DIR=`$PKG_CONFIG --variable=libdir gnome-bluetooth-1.0`/gnome-bluetooth
BLUETOOTH_LIBS="-L'$BLUETOOTH_DIR' -lgnome-bluetooth-applet"
AC_SUBST([BLUETOOTH_LIBS],["$BLUETOOTH_LIBS"])
AC_DEFINE_UNQUOTED([BLUETOOTH_DIR],["$BLUETOOTH_DIR"],[Path to installed GnomeBluetooth typelib and library])
AC_DEFINE([HAVE_BLUETOOTH],[1],[Define if you have libgnome-bluetooth-applet])
AC_SUBST([HAVE_BLUETOOTH],[1])
AC_MSG_RESULT([yes])],
[AC_DEFINE([HAVE_BLUETOOTH],[0])
AC_SUBST([HAVE_BLUETOOTH],[0])
AC_MSG_RESULT([no])])
# Default to libedataserverui-3.0, but allow falling back to 1.2
PKG_CHECK_EXISTS(libedataserverui-3.0,
[EDS_API=3.0
LIBEDATASERVERUI_REQUIRED=$LIBEDATASERVERUI3_REQUIRED],
[EDS_API=1.2
LIBEDATASERVERUI_REQUIRED=$LIBEDATASERVERUI2_REQUIRED])
PKG_CHECK_MODULES(LIBECAL, libecal-1.2 >= $LIBECAL_REQUIRED libedataserver-1.2 >= $LIBEDATASERVER_REQUIRED libedataserverui-$EDS_API >= $LIBEDATASERVERUI_REQUIRED)
AC_SUBST(LIBECAL_CFLAGS)
AC_SUBST(LIBECAL_LIBS)
MUTTER_BIN_DIR=`$PKG_CONFIG --variable=exec_prefix mutter-plugins`/bin
# FIXME: metacity-plugins.pc should point directly to its .gir file
MUTTER_LIB_DIR=`$PKG_CONFIG --variable=libdir mutter-plugins`
@ -103,11 +136,7 @@ AC_SUBST(MUTTER_BIN_DIR)
AC_SUBST(MUTTER_LIB_DIR)
AC_SUBST(MUTTER_PLUGIN_DIR)
GJS_JS_DIR=`$PKG_CONFIG --variable=jsdir gjs-1.0`
GJS_JS_NATIVE_DIR=`$PKG_CONFIG --variable=jsnativedir gjs-1.0`
GJS_CONSOLE=`$PKG_CONFIG --variable=gjs_console gjs-1.0`
AC_SUBST(GJS_JS_DIR)
AC_SUBST(GJS_JS_NATIVE_DIR)
AC_SUBST(GJS_CONSOLE)
AC_CHECK_FUNCS(fdwalk)
@ -157,18 +186,11 @@ changequote([,])dnl
AC_PATH_PROG(mutter, [mutter])
AC_SUBST(mutter)
AC_MSG_CHECKING([if mutter was compiled with GTK+-3.0])
if $PKG_CONFIG --libs libmutter-private | grep gtk-x11-3 >/dev/null; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_ERROR([GNOME Shell requires Mutter to be compiled against GTK+-3.0])
fi
AC_CONFIG_FILES([
Makefile
data/Makefile
js/Makefile
js/misc/config.js
src/Makefile
tests/Makefile
po/Makefile.in

View File

@ -1,5 +1,5 @@
desktopdir=$(datadir)/applications
desktop_DATA = gnome-shell.desktop gnome-shell-clock-preferences.desktop
desktop_DATA = gnome-shell.desktop
# We substitute in bindir so it works as an autostart
# file when built in a non-system prefix
@ -12,7 +12,10 @@ desktop_DATA = gnome-shell.desktop gnome-shell-clock-preferences.desktop
%.desktop:%.desktop.in
$(AM_V_GEN) sed s/^_// < $< > $@ || rm $@
dist_pkgdata_DATA = clock-preferences.ui
searchprovidersdir = $(pkgdatadir)/search_providers
dist_searchproviders_DATA = \
search_providers/google.xml \
search_providers/wikipedia.xml
imagesdir = $(pkgdatadir)/images
dist_images_DATA = \
@ -22,16 +25,20 @@ dist_images_DATA = \
themedir = $(pkgdatadir)/theme
dist_theme_DATA = \
theme/add-workspace.svg \
theme/calendar-arrow-left.svg \
theme/calendar-arrow-right.svg \
theme/close-window.svg \
theme/close.svg \
theme/corner-ripple.png \
theme/dialog-error.svg \
theme/dash-placeholder.svg \
theme/filter-selected.svg \
theme/gnome-shell.css \
theme/mosaic-view-active.svg \
theme/mosaic-view.svg \
theme/move-window-on-new.svg \
theme/process-working.png \
theme/remove-workspace.svg \
theme/running-indicator.svg \
theme/scroll-button-down-hover.png \
theme/scroll-button-down.png \
theme/scroll-button-up-hover.png \
@ -85,7 +92,6 @@ install-data-local:
EXTRA_DIST = \
gnome-shell.desktop.in.in \
gnome-shell-clock-preferences.desktop.in.in \
$(menu_DATA) \
$(gconfschema_DATA) \
$(shaders_DATA) \
@ -94,7 +100,6 @@ EXTRA_DIST = \
CLEANFILES = \
gnome-shell.desktop.in \
gnome-shell-clock-preferences.desktop.in \
$(desktop_DATA) \
$(gsettings_SCHEMAS) \
gschemas.compiled

View File

@ -1,188 +0,0 @@
<?xml version="1.0"?>
<interface domain="gnome-shell">
<requires lib="gtk+" version="2.16"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkDialog" id="prefs-dialog">
<property name="border_width">5</property>
<property name="title" translatable="yes">Clock Preferences</property>
<property name="window_position">center</property>
<property name="type_hint">normal</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<child>
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="top_padding">6</property>
<property name="left_padding">12</property>
<property name="right_padding">6</property>
<child>
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="spacing">12</property>
<child>
<object class="GtkRadioButton" id="12hr_radio">
<property name="label" translatable="yes">_12 hour format</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="24hr_radio">
<property name="label" translatable="yes">_24 hour format</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<property name="group">12hr_radio</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label_format">
<property name="visible">True</property>
<property name="label" translatable="yes">Clock Format</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame2">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="top_padding">6</property>
<property name="left_padding">12</property>
<child>
<object class="GtkVBox" id="vbox2">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkCheckButton" id="date_check">
<property name="label" translatable="yes">Show the _date</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="seconds_check">
<property name="label" translatable="yes">Show seco_nds</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label_display">
<property name="visible">True</property>
<property name="label" translatable="yes">Panel Display</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="padding">6</property>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkButton" id="prefs_close_button">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="0">prefs_close_button</action-widget>
</action-widgets>
</object>
</interface>

View File

@ -1,15 +0,0 @@
[Desktop Entry]
_Name=Clock
_Comment=Customize the panel clock
Exec=@bindir@/gnome-shell-clock-preferences
Icon=gnome-panel-clock
Terminal=false
Type=Application
StartupNotify=true
Categories=GNOME;GTK;Settings;DesktopSettings;
OnlyShowIn=GNOME;
X-GNOME-ShellOnly=true
X-GNOME-Bugzilla-Bugzilla=GNOME
X-GNOME-Bugzilla-Product=gnome-shell
X-GNOME-Bugzilla-Component=general
X-GNOME-Bugzilla-Version=@VERSION@

View File

@ -7,7 +7,7 @@ X-GNOME-Bugzilla-Bugzilla=GNOME
X-GNOME-Bugzilla-Product=gnome-shell
X-GNOME-Bugzilla-Component=general
X-GNOME-Bugzilla-Version=@VERSION@
Categories=GNOME;GTK;Utility;Core;
Categories=GNOME;GTK;Core;
OnlyShowIn=GNOME;
NoDisplay=true
X-GNOME-Autostart-Phase=WindowManager

View File

@ -44,19 +44,20 @@
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/windows/side_by_side_tiling</key>
<applyto>/desktop/gnome/shell/windows/side_by_side_tiling</applyto>
<key>/schemas/desktop/gnome/shell/windows/edge_tiling</key>
<applyto>/desktop/gnome/shell/windows/edge_tiling</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>true</default>
<locale name="C">
<short>enable side-by-side tiling when dropping windows on screen edges</short>
<short>enable edge tiling when dropping windows on screen edges</short>
<long>
If enabled, dropping windows on screen edges maximizes them
If enabled, dropping windows on vertical screen edges maximizes them
vertically and resizes them horizontally to cover half of the
available area.
available area. Dropping windows on the top screen edge maximizes them
completely.
This key overrides /apps/metacity/general/side_by_side_tiling when
This key overrides /apps/metacity/general/edge_tiling when
running GNOME Shell.
</long>
</locale>

View File

@ -1,12 +1,30 @@
<Menu>
<DefaultLayout>
<Menuname>Apps</Menuname>
<Menuname>Games</Menuname>
<Menuname>Tools</Menuname>
</DefaultLayout>
<DefaultLayout>
<Menuname>Accessories</Menuname>
<Menuname>Games</Menuname>
<Menuname>Graphics</Menuname>
<Menuname>Internet</Menuname>
<Menuname>Multimedia</Menuname>
<Menuname>Office</Menuname>
<Menuname>Other</Menuname>
</DefaultLayout>
<Name>Applications</Name>
<AppDir>/usr/local/share/applications</AppDir>
<DefaultAppDirs/>
<Menu>
<Name>Accessories</Name>
<Include>
<And>
<Category>Utility</Category>
<Not>
<Category>System</Category>
</Not>
</And>
</Include>
</Menu>
<Menu>
<Name>Games</Name>
<Include>
@ -15,28 +33,50 @@
</And>
</Include>
</Menu>
<Menu>
<Name>Tools</Name>
<Name>Graphics</Name>
<Include>
<Category>Development</Category>
<And>
<Category>System</Category>
<Not>
<Category>Settings</Category>
</Not>
<Category>Graphics</Category>
</And>
<Category>Utility</Category>
</Include>
</Menu>
<Menu>
<Name>Apps</Name>
<Name>Internet</Name>
<Include>
<And>
<Category>Network</Category>
<Not><Category>Settings</Category></Not>
</And>
</Include>
</Menu>
<Menu>
<Name>Multimedia</Name>
<Include>
<And>
<Category>AudioVideo</Category>
<Not><Category>Settings</Category></Not>
</And>
</Include>
</Menu>
<Menu>
<Name>Office</Name>
<Include>
<And>
<Category>Office</Category>
</And>
</Include>
</Menu>
<Menu>
<Name>Other</Name>
<OnlyUnallocated/>
<Include>
<And>
<Or>
<Category>Documentation</Category>
<Not><Category>Core</Category></Not>
</Or>
<Not><Category>Settings</Category></Not>
<Not><Category>Screensaver</Category></Not>
</And>

View File

@ -30,29 +30,21 @@
</_description>
</key>
<key name="favorite-apps" type="as">
<default>[ 'mozilla-firefox.desktop', 'evolution.desktop', 'openoffice.org-writer.desktop' ]</default>
<default>[ 'mozilla-firefox.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'openoffice.org-writer.desktop', 'nautilus.desktop' ]</default>
<_summary>List of desktop file IDs for favorite applications</_summary>
<_description>
The applications corresponding to these identifiers
will be displayed in the favorites area.
</_description>
</key>
<key name="disabled-open-search-providers" type="as">
<default>[]</default>
<_summary>disabled OpenSearch providers</_summary>
</key>
<key name="command-history" type="as">
<default>[]</default>
<_summary>History for command (Alt-F2) dialog</_summary>
</key>
<key name="workspaces-view" type="s">
<default>'single'</default>
<_summary>Overview workspace view mode</_summary>
<_description>
The selected workspace view mode in the overview.
Supported values are "single" and "grid".
</_description>
<choices>
<choice value="single"/>
<choice value="grid"/>
</choices>
</key>
<child name="clock" schema="org.gnome.shell.clock"/>
<child name="calendar" schema="org.gnome.shell.calendar"/>
<child name="recorder" schema="org.gnome.shell.recorder"/>
@ -71,51 +63,18 @@
<schema id="org.gnome.shell.clock" path="/apps/gnome-shell/clock/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="format" type="s">
<default l10n="messages" context="hour_format">
<!-- TRANSLATORS: This is the default hour format, choose ONLY '12-hour' or '24-hour'. -->
"12-hour"
</default>
<_summary>Hour format</_summary>
<_description>
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.
</_description>
<choices>
<choice value="12-hour"/>
<choice value="24-hour"/>
<choice value="unix"/>
<choice value="custom"/>
</choices>
</key>
<key name="custom-format" type="s">
<default>''</default>
<_summary>Custom format of the clock</_summary>
<_description>
This key specifies the format used by the panel clock when the format
key is set to "custom". You can use conversion specifiers understood
by strftime() to obtain a specific format. See the strftime() manual
for more information.
</_description>
</key>
<key name="show-seconds" type="b">
<default>false</default>
<_summary>Show time with seconds</_summary>
<_description>
If true and format is either "12-hour" or "24-hour", display seconds in time.
If true, display seconds in time.
</_description>
</key>
<key name="show-date" type="b">
<default>false</default>
<_summary>Show date in clock</_summary>
<_description>
If true and format is either "12-hour" or "24-hour",
display date in the clock, in addition to time.
If true, display date in the clock, in addition to time.
</_description>
</key>
</schema>
@ -142,11 +101,13 @@
take care of its own output - this might be used to send the output
to an icecast server via shout2send or similar. When unset or set
to an empty value, the default pipeline will be used. This is currently
'videorate ! theoraenc ! oggmux' and records to Ogg Theora.
'videorate ! vp8enc quality=10 speed=2 threads=%T ! queue ! webmmux'
and records to WEBM using the VP8 codec. %T is used as a placeholder
for a guess at the optimal thread count on the system.
</_description>
</key>
<key name="file-extension" type="s">
<default>'ogv'</default>
<default>'webm'</default>
<_summary>File extension used for storing the screencast</_summary>
<_description>
The filename for recorded screencasts will be a unique filename

View File

@ -0,0 +1,7 @@
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
<ShortName>Google</ShortName>
<Description>Google Search</Description>
<InputEncoding>UTF-8</InputEncoding>
<Image width="16" height="16">data:image/x-icon;base64,AAABAAEAEBAAAAEAGABoAwAAFgAAACgAAAAQAAAAIAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs9Pt8xetPtu9FsfFNtu%2BTzvb2%2B%2Fne4dFJeBw0egA%2FfAJAfAA8ewBBegAAAAD%2B%2FPtft98Mp%2BwWsfAVsvEbs%2FQeqvF8xO7%2F%2F%2F63yqkxdgM7gwE%2FggM%2BfQA%2BegBDeQDe7PIbotgQufcMufEPtfIPsvAbs%2FQvq%2Bfz%2Bf%2F%2B%2B%2FZKhR05hgBBhQI8hgBAgAI9ewD0%2B%2Fg3pswAtO8Cxf4Kw%2FsJvvYAqupKsNv%2B%2Fv7%2F%2FP5VkSU0iQA7jQA9hgBDgQU%2BfQH%2F%2Ff%2FQ6fM4sM4KsN8AteMCruIqqdbZ7PH8%2Fv%2Fg6Nc%2Fhg05kAA8jAM9iQI%2BhQA%2BgQDQu6b97uv%2F%2F%2F7V8Pqw3eiWz97q8%2Ff%2F%2F%2F%2F7%2FPptpkkqjQE4kwA7kAA5iwI8iAA8hQCOSSKdXjiyflbAkG7u2s%2F%2B%2F%2F39%2F%2F7r8utrqEYtjQE8lgA7kwA7kwA9jwA9igA9hACiWSekVRyeSgiYSBHx6N%2F%2B%2Fv7k7OFRmiYtlAA5lwI7lwI4lAA7kgI9jwE9iwI4iQCoVhWcTxCmb0K%2BooT8%2Fv%2F7%2F%2F%2FJ2r8fdwI1mwA3mQA3mgA8lAE8lAE4jwA9iwE%2BhwGfXifWvqz%2B%2Ff%2F58u%2Fev6Dt4tr%2B%2F%2F2ZuIUsggA7mgM6mAM3lgA5lgA6kQE%2FkwBChwHt4dv%2F%2F%2F728ei1bCi7VAC5XQ7kz7n%2F%2F%2F6bsZkgcB03lQA9lgM7kwA2iQktZToPK4r9%2F%2F%2F9%2F%2F%2FSqYK5UwDKZAS9WALIkFn%2B%2F%2F3%2F%2BP8oKccGGcIRJrERILYFEMwAAuEAAdX%2F%2Ff7%2F%2FP%2B%2BfDvGXQLIZgLEWgLOjlf7%2F%2F%2F%2F%2F%2F9QU90EAPQAAf8DAP0AAfMAAOUDAtr%2F%2F%2F%2F7%2B%2Fu2bCTIYwDPZgDBWQDSr4P%2F%2Fv%2F%2F%2FP5GRuABAPkAA%2FwBAfkDAPAAAesAAN%2F%2F%2B%2Fz%2F%2F%2F64g1C5VwDMYwK8Yg7y5tz8%2Fv%2FV1PYKDOcAAP0DAf4AAf0AAfYEAOwAAuAAAAD%2F%2FPvi28ymXyChTATRrIb8%2F%2F3v8fk6P8MAAdUCAvoAAP0CAP0AAfYAAO4AAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAA</Image>
<Url type="text/html" method="GET" template="http://www.google.com/search?q={searchTerms}"/>
</OpenSearchDescription>

View File

@ -0,0 +1,44 @@
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
<ShortName>Wikipedia</ShortName>
<Description>Wikipedia, the free encyclopedia</Description>
<InputEncoding>UTF-8</InputEncoding>
<Image width="16" height="16">data:image/x-icon;base64,AAABAAEAEBAQAAEABAAoAQAAFgAAACgAAAAQAAAAIAAAAAEABAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAEAgQAhIOEAMjHyABIR0gA6ejpAGlqaQCpqKkAKCgoAPz9%2FAAZGBkAmJiYANjZ2ABXWFcAent6ALm6uQA8OjwAiIiIiIiIiIiIiI4oiL6IiIiIgzuIV4iIiIhndo53KIiIiB%2FWvXoYiIiIfEZfWBSIiIEGi%2FfoqoiIgzuL84i9iIjpGIoMiEHoiMkos3FojmiLlUipYliEWIF%2BiDe0GoRa7D6GPbjcu1yIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</Image>
<Url type="text/html" method="GET" template="http://{language}.wikipedia.org/wiki/Special:Search?search={searchTerms}"/>
<!-- The criterion for being below is being listed with more than 100,000
articles on http://meta.wikimedia.org/wiki/List_of_Wikipedias -->
<Language>ar</Language>
<Language>bg</Language>
<Language>ca</Language>
<Language>cs</Language>
<Language>da</Language>
<Language>de</Language>
<Language>en</Language>
<Language>eo</Language>
<Language>es</Language>
<Language>fa</Language>
<Language>fi</Language>
<Language>fr</Language>
<Language>he</Language>
<Language>hu</Language>
<Language>id</Language>
<Language>it</Language>
<Language>ja</Language>
<Language>ko</Language>
<Language>lt</Language>
<Language>nl</Language>
<Language>no</Language>
<Language>pl</Language>
<Language>pt</Language>
<Language>ro</Language>
<Language>ru</Language>
<Language>sk</Language>
<Language>sl</Language>
<Language>sr</Language>
<Language>sv</Language>
<Language>tr</Language>
<Language>uk</Language>
<Language>vi</Language>
<Language>vo</Language>
<Language>war</Language>
<Language>zh</Language>
</OpenSearchDescription>

View File

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
id="svg2"
version="1.1"
inkscape:version="0.48+devel r9942 custom"
sodipodi:docname="New document 4">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="8.984481"
inkscape:cy="5.6224906"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:window-width="930"
inkscape:window-height="681"
inkscape:window-x="1892"
inkscape:window-y="272"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid17403"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1036.3622)">
<path
sodipodi:type="star"
style="fill:#5f5f5f;fill-opacity:1;stroke:#5f5f5f;stroke-width:0.43015847;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
id="path18028"
sodipodi:sides="3"
sodipodi:cx="84.5"
sodipodi:cy="337.5"
sodipodi:r1="5"
sodipodi:r2="2.5"
sodipodi:arg1="0.52359878"
sodipodi:arg2="1.5707963"
inkscape:flatsided="true"
inkscape:rounded="0"
inkscape:randomized="0"
d="M 88.830127,340 80.169873,340 84.5,332.5 z"
transform="matrix(0,1.3621708,0.99186247,0,-325.48222,929.32667)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
id="svg2"
version="1.1"
inkscape:version="0.48+devel r9942 custom"
sodipodi:docname="arrow-left.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="7.7366092"
inkscape:cy="6.4536271"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:window-width="930"
inkscape:window-height="681"
inkscape:window-x="1892"
inkscape:window-y="272"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid17403"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1036.3622)">
<path
sodipodi:type="star"
style="fill:#5f5f5f;fill-opacity:1;stroke:#5f5f5f;stroke-width:0.43015847;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
id="path18028"
sodipodi:sides="3"
sodipodi:cx="84.5"
sodipodi:cy="337.5"
sodipodi:r1="5"
sodipodi:r2="2.5"
sodipodi:arg1="0.52359878"
sodipodi:arg2="1.5707963"
inkscape:flatsided="true"
inkscape:rounded="0"
inkscape:randomized="0"
d="M 88.830127,340 80.169873,340 84.5,332.5 z"
transform="matrix(0,1.3621708,-0.99186247,0,342.48324,929.32667)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="76"
height="27"
id="svg11252"
version="1.1">
<defs
id="defs11254">
<radialGradient
xlink:href="#linearGradient39563-4-2"
id="radialGradient68155-2-3"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,0.3486842,0,317.8421)"
cx="49"
cy="488"
fx="49"
fy="488"
r="38" />
<linearGradient
id="linearGradient39563-4-2">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop39565-1-4" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop39567-7-9" />
</linearGradient>
<radialGradient
xlink:href="#linearGradient39573-6-1"
id="radialGradient68157-0-8"
gradientUnits="userSpaceOnUse"
cx="50.5"
cy="487.5"
fx="50.5"
fy="487.5"
r="10.5" />
<linearGradient
id="linearGradient39573-6-1">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop39575-5-6" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop39577-1-2" />
</linearGradient>
</defs>
<g
id="layer1"
transform="translate(-337,-518.86218)">
<g
id="g99967"
style="display:inline"
transform="translate(326,44.862171)">
<rect
style="opacity:0.49375;color:#000000;fill:url(#radialGradient68155-2-3);fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect99969"
width="76"
height="2"
x="11"
y="487"
rx="0"
ry="0" />
<path
style="opacity:0.43125;color:#000000;fill:url(#radialGradient68157-0-8);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path99971"
d="M 61,487.5 C 61,493.29899 56.29899,498 50.5,498 44.70101,498 40,493.29899 40,487.5 40,481.70101 44.70101,477 50.5,477 c 5.79899,0 10.5,4.70101 10.5,10.5 z"
transform="matrix(1.2857143,0,0,1.2857143,-14.428572,-139.28571)" />
<path
transform="matrix(0.43589747,0,0,0.43589747,28.487179,275)"
d="M 61,487.5 C 61,493.29899 56.29899,498 50.5,498 44.70101,498 40,493.29899 40,487.5 40,481.70101 44.70101,477 50.5,477 c 5.79899,0 10.5,4.70101 10.5,10.5 z"
id="path99973"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1,222 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="24"
id="svg4908"
sodipodi:version="0.32"
inkscape:version="0.47 r22583"
sodipodi:docname="dialog-error.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
inkscape:export-filename="/home/andreas/project/gnome-icon-theme/scalable/actions/process-stop.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
version="1.0">
<defs
id="defs4910">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 24 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="48 : 24 : 1"
inkscape:persp3d-origin="24 : 16 : 1"
id="perspective25" />
<radialGradient
gradientTransform="matrix(1.349881,0,0,1.349881,-3.498814,-1.810859)"
gradientUnits="userSpaceOnUse"
r="9.7183542"
fy="4.9892726"
fx="9.6893959"
cy="4.9892726"
cx="9.6893959"
id="radialGradient5177"
xlink:href="#linearGradient5171"
inkscape:collect="always" />
<radialGradient
gradientTransform="matrix(2.417917,0,0,2.417917,-14.17917,-4.903184)"
gradientUnits="userSpaceOnUse"
r="9.7785711"
fy="3.458019"
fx="10"
cy="3.458019"
cx="10"
id="radialGradient5157"
xlink:href="#linearGradient5151"
inkscape:collect="always" />
<radialGradient
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.928125,0,0,0.3143011,0.7718789,12.358015)"
r="9.0598059"
fy="18.022524"
fx="10.739184"
cy="18.022524"
cx="10.739184"
id="radialGradient5145"
xlink:href="#linearGradient5139"
inkscape:collect="always" />
<linearGradient
id="linearGradient5139"
inkscape:collect="always">
<stop
id="stop5141"
offset="0"
style="stop-color:black;stop-opacity:1;" />
<stop
id="stop5143"
offset="1"
style="stop-color:black;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient5151"
inkscape:collect="always">
<stop
id="stop5153"
offset="0"
style="stop-color:white;stop-opacity:1;" />
<stop
id="stop5155"
offset="1"
style="stop-color:white;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient5171">
<stop
id="stop5173"
offset="0"
style="stop-color:#fe3a00;stop-opacity:1" />
<stop
id="stop5175"
offset="1"
style="stop-color:#c00;stop-opacity:1;" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.627417"
inkscape:cx="24.442987"
inkscape:cy="10.142308"
inkscape:current-layer="g7001"
showgrid="false"
inkscape:grid-bbox="true"
inkscape:document-units="px"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1674"
inkscape:window-height="970"
inkscape:window-x="0"
inkscape:window-y="26"
width="48px"
height="48px"
inkscape:window-maximized="0" />
<metadata
id="metadata4913">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Stop Process</dc:title>
<dc:date>December 2006</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Jakub Steiner</dc:title>
</cc:Agent>
</dc:creator>
<dc:contributor>
<cc:Agent>
<dc:title>Andreas Nilsson</dc:title>
</cc:Agent>
</dc:contributor>
<cc:license
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
<dc:subject>
<rdf:Bag>
<rdf:li>stop</rdf:li>
<rdf:li>halt</rdf:li>
</rdf:Bag>
</dc:subject>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
<cc:permits
rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits
rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Notice" />
<cc:permits
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
<cc:requires
rdf:resource="http://web.resource.org/cc/ShareAlike" />
<cc:requires
rdf:resource="http://web.resource.org/cc/SourceCode" />
</cc:License>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,-24)">
<g
inkscape:label="Layer 1"
id="g7001"
transform="matrix(1.4566048,0,0,1.4455352,0.4112881,1.2324709)">
<path
transform="matrix(0.91468137,0,0,0.70055266,-1.8812476,17.474032)"
d="m 19.79899,18.022524 a 9.0598059,3.0935922 0 1 1 -18.1196115,0 9.0598059,3.0935922 0 1 1 18.1196115,0 z"
sodipodi:ry="3.0935922"
sodipodi:rx="9.0598059"
sodipodi:cy="18.022524"
sodipodi:cx="10.739184"
id="path5137"
style="color:#000000;fill:url(#radialGradient5145);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
sodipodi:type="arc" />
<path
transform="matrix(0.87347736,0,0,0.83068052,-0.79308842,15.602788)"
d="m 19.25,9.625 a 9.25,9.25 0 1 1 -18.5,0 9.25,9.25 0 1 1 18.5,0 z"
sodipodi:ry="9.25"
sodipodi:rx="9.25"
sodipodi:cy="9.625"
sodipodi:cx="10"
id="path4262"
style="color:#000000;fill:url(#radialGradient5177);fill-opacity:1;fill-rule:nonzero;stroke:#a40000;stroke-width:0.47435912;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
sodipodi:type="arc" />
<path
sodipodi:type="arc"
style="opacity:0.35393258;color:#000000;fill:none;stroke:url(#radialGradient5157);stroke-width:0.49999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
id="path5149"
sodipodi:cx="10"
sodipodi:cy="9.625"
sodipodi:rx="9.25"
sodipodi:ry="9.25"
d="m 19.25,9.625 a 9.25,9.25 0 1 1 -18.5,0 9.25,9.25 0 1 1 18.5,0 z"
transform="matrix(0.82868359,0,0,0.78808147,-0.34515141,16.012803)" />
<path
sodipodi:nodetypes="cc"
id="path5159"
d="m 4.834121,20.642783 6.215127,5.91061"
style="color:#000000;fill:none;stroke:#ffffff;stroke-width:1.21219134;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
<path
style="color:#000000;fill:none;stroke:#ffffff;stroke-width:1.21219146;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
d="M 11.04925,20.622826 4.8159529,26.553393"
id="path5161"
sodipodi:nodetypes="cc" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.0 KiB

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="10"
height="20"
id="svg10003"
version="1.1"
inkscape:version="0.47 r22583"
sodipodi:docname="filter-selected.svg">
<defs
id="defs10005">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective10011" />
<inkscape:perspective
id="perspective9998"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.5"
inkscape:cx="32"
inkscape:cy="10.181818"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1680"
inkscape:window-height="994"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="1" />
<metadata
id="metadata10008">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,-44)">
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/app-picker.png"
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="rect34320"
d="m -0.18726572,54.181804 10.55634072,10.55636 10e-6,-21.11269 z"
style="opacity:0.21000001;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.99999988;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="74.01342"
height="74.006706"
id="svg7355"
version="1.1">
<defs
id="defs7357">
<radialGradient
xlink:href="#linearGradient36429"
id="radialGradient7461"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0525552,0,0,1.0525552,-2.5162753,-9.0000838)"
cx="47.878681"
cy="171.25"
fx="47.878681"
fy="171.25"
r="37" />
<linearGradient
id="linearGradient36429">
<stop
id="stop36431"
offset="0"
style="stop-color:#ffffff;stop-opacity:1;" />
<stop
id="stop36433"
offset="1"
style="stop-color:#ffffff;stop-opacity:0;" />
</linearGradient>
<radialGradient
xlink:href="#linearGradient36471"
id="radialGradient7463"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1891549,0,0,0.55513246,-9.281289,36.12653)"
cx="49.067139"
cy="242.50381"
fx="49.067139"
fy="242.50381"
r="37.00671" />
<linearGradient
id="linearGradient36471">
<stop
id="stop36473"
offset="0"
style="stop-color:#ffffff;stop-opacity:1;" />
<stop
id="stop36475"
offset="1"
style="stop-color:#ffffff;stop-opacity:0;" />
</linearGradient>
<radialGradient
r="37.00671"
fy="242.50381"
fx="49.067139"
cy="242.50381"
cx="49.067139"
gradientTransform="matrix(1.1891549,0,0,0.55513246,-9.281289,36.12653)"
gradientUnits="userSpaceOnUse"
id="radialGradient7488"
xlink:href="#linearGradient36471" />
</defs>
<g
id="layer1"
transform="translate(-266.21629,-168.11809)">
<g
style="display:inline"
id="g30864"
transform="translate(255.223,70.118091)">
<rect
ry="3.5996203"
rx="3.5996203"
y="98"
x="11"
height="74"
width="74"
id="rect14000"
style="opacity:0.371875;fill:url(#radialGradient7461);fill-opacity:1;stroke:none" />
<path
id="rect34520"
d="m 84.506708,167.95508 c 6e-6,1.96759 -1.584022,3.55162 -3.551629,3.55163 l -65.910146,0 c -1.967608,-1e-5 -3.551648,-1.58402 -3.551643,-3.55164"
style="opacity:0.2;fill:none;stroke:url(#radialGradient7488);stroke-width:1;stroke-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -33,7 +33,7 @@
<foaf:Person>
<foaf:name>Colin Walters</foaf:name>
<foaf:mbox rdf:resource="mailto:walters@verbum.org" />
<gnome:userid>cwalters</gnome:userid>
<gnome:userid>walters</gnome:userid>
</foaf:Person>
</maintainer>
<maintainer>

View File

@ -2,26 +2,29 @@
jsdir = $(pkgdatadir)/js
nobase_dist_js_DATA = \
misc/config.js \
misc/docInfo.js \
misc/fileUtils.js \
misc/format.js \
misc/gnomeSession.js \
misc/params.js \
misc/telepathy.js \
misc/util.js \
perf/core.js \
prefs/clockPreferences.js \
ui/altTab.js \
ui/appDisplay.js \
ui/appFavorites.js \
ui/boxpointer.js \
ui/calendar.js \
ui/chrome.js \
ui/ctrlAltTab.js \
ui/dash.js \
ui/dateMenu.js \
ui/dnd.js \
ui/docDisplay.js \
ui/endSessionDialog.js \
ui/environment.js \
ui/extensionSystem.js \
ui/genericDisplay.js \
ui/iconGrid.js \
ui/lightbox.js \
ui/link.js \
@ -30,6 +33,7 @@ nobase_dist_js_DATA = \
ui/magnifierDBus.js \
ui/main.js \
ui/messageTray.js \
ui/modalDialog.js \
ui/notificationDaemon.js \
ui/overview.js \
ui/panel.js \
@ -39,16 +43,21 @@ nobase_dist_js_DATA = \
ui/runDialog.js \
ui/scripting.js \
ui/search.js \
ui/searchDisplay.js \
ui/shellDBus.js \
ui/statusIconDispatcher.js \
ui/statusMenu.js \
ui/status/accessibility.js \
ui/status/keyboard.js \
ui/status/power.js \
ui/status/volume.js \
ui/status/bluetooth.js \
ui/telepathyClient.js \
ui/tweener.js \
ui/viewSelector.js \
ui/windowAttentionHandler.js \
ui/windowManager.js \
ui/workspace.js \
ui/workspacesView.js \
ui/workspaceSwitcherPopup.js
ui/workspaceSwitcherPopup.js \
ui/xdndHandler.js

10
js/misc/config.js.in Normal file
View File

@ -0,0 +1,10 @@
/* mode: js2; indent-tabs-mode: nil; tab-size: 4 */
/* The name of this package (not localized) */
const PACKAGE_NAME = '@PACKAGE_NAME@';
/* The version of this package */
const PACKAGE_VERSION = '@PACKAGE_VERSION@';
/* The version of GJS we're linking to */
const GJS_VERSION = '@GJS_VERSION@';
/* 1 if gnome-bluetooth is available, 0 otherwise */
const HAVE_BLUETOOTH = @HAVE_BLUETOOTH@;

View File

@ -60,8 +60,7 @@ function getDocManager() {
}
/**
* DocManager wraps the DocSystem, primarily to expose DocInfo objects
* which conform to the GenericDisplay item API.
* DocManager wraps the DocSystem, primarily to expose DocInfo objects.
*/
function DocManager() {
this._init();

View File

@ -2,6 +2,7 @@
const DBus = imports.dbus;
const Lang = imports.lang;
const Signals = imports.signals;
const PresenceIface = {
name: 'org.gnome.SessionManager.Presence',
@ -43,3 +44,60 @@ Presence.prototype = {
}
};
DBus.proxifyPrototype(Presence.prototype, PresenceIface);
// Note inhibitors are immutable objects, so they don't
// change at runtime (changes always come in the form
// of new inhibitors)
const InhibitorIface = {
name: 'org.gnome.SessionManager.Inhibitor',
properties: [{ name: 'app_id',
signature: 's',
access: 'readonly' },
{ name: 'client_id',
signature: 's',
access: 'readonly' },
{ name: 'reason',
signature: 's',
access: 'readonly' },
{ name: 'flags',
signature: 'u',
access: 'readonly' },
{ name: 'toplevel_xid',
signature: 'u',
access: 'readonly' },
{ name: 'cookie',
signature: 'u',
access: 'readonly' }],
};
function Inhibitor(objectPath) {
this._init(objectPath);
}
Inhibitor.prototype = {
_init: function(objectPath) {
DBus.session.proxifyObject(this,
"org.gnome.SessionManager",
objectPath);
this.isLoaded = false;
this._loadingPropertiesCount = InhibitorIface.properties.length;
for (let i = 0; i < InhibitorIface.properties.length; i++) {
let propertyName = InhibitorIface.properties[i].name;
this.GetRemote(propertyName, Lang.bind(this,
function(value, exception) {
if (exception)
return;
this[propertyName] = value;
this._loadingPropertiesCount--;
if (this._loadingPropertiesCount == 0) {
this.isLoaded = true;
this.emit("is-loaded");
}
}));
}
},
};
DBus.proxifyPrototype(Inhibitor.prototype, InhibitorIface);
Signals.addSignalMethods(Inhibitor.prototype);

View File

@ -272,7 +272,9 @@ const ChannelTextIface = {
],
signals: [
{ name: 'Received',
inSignature: 'uuuuus' }
inSignature: 'uuuuus' },
{ name: 'Sent',
inSignature: 'uus' }
]
};
let ChannelText = DBus.makeProxyClass(ChannelTextIface);

180
js/misc/util.js Normal file
View File

@ -0,0 +1,180 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Gdk = imports.gi.Gdk;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Shell = imports.gi.Shell;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
/* http://daringfireball.net/2010/07/improved_regex_for_matching_urls */
const _urlRegexp = new RegExp('\\b(([a-z][\\w-]+:(/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)([^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:\'\\".,<>?«»“”‘’]))', 'gi');
// findUrls:
// @str: string to find URLs in
//
// Searches @str for URLs and returns an array of objects with %url
// properties showing the matched URL string, and %pos properties indicating
// the position within @str where the URL was found.
//
// Return value: the list of match objects, as described above
function findUrls(str) {
let res = [], match;
while ((match = _urlRegexp.exec(str)))
res.push({ url: match[0], pos: match.index });
return res;
}
// spawn:
// @argv: an argv array
//
// Runs @argv in the background, handling any errors that occur
// when trying to start the program.
function spawn(argv) {
try {
trySpawn(argv);
} catch (err) {
_handleSpawnError(argv[0], err);
}
}
// spawnCommandLine:
// @command_line: a command line
//
// Runs @command_line in the background, handling any errors that
// occur when trying to parse or start the program.
function spawnCommandLine(command_line) {
try {
let [success, argc, argv] = GLib.shell_parse_argv(command_line);
trySpawn(argv);
} catch (err) {
_handleSpawnError(command_line, err);
}
}
// spawnDesktop:
// @id: a desktop file ID
//
// Spawns the desktop file identified by @id using startup notification,
// etc, handling any errors that occur when trying to find or start
// the program.
function spawnDesktop(id) {
try {
trySpawnDesktop(id);
} catch (err) {
_handleSpawnError(id, err);
}
}
// trySpawn:
// @argv: an argv array
//
// Runs @argv in the background. If launching @argv fails,
// this will throw an error.
function trySpawn(argv)
{
try {
GLib.spawn_async(null, argv, null,
GLib.SpawnFlags.SEARCH_PATH,
null, null);
} catch (err) {
if (err.code == GLib.SpawnError.G_SPAWN_ERROR_NOENT) {
err.message = _("Command not found");
} else {
// The exception from gjs contains an error string like:
// Error invoking GLib.spawn_command_line_async: Failed to
// execute child process "foo" (No such file or directory)
// We are only interested in the part in the parentheses. (And
// we can't pattern match the text, since it gets localized.)
err.message = err.message.replace(/.*\((.+)\)/, '$1');
}
throw err;
}
}
// trySpawnCommandLine:
// @command_line: a command line
//
// Runs @command_line in the background. If launching @command_line
// fails, this will throw an error.
function trySpawnCommandLine(command_line) {
let success, argc, argv;
try {
[success, argc, argv] = GLib.shell_parse_argv(command_line);
} catch (err) {
// Replace "Error invoking GLib.shell_parse_argv: " with
// something nicer
err.message = err.message.replace(/[^:]*: /, _("Could not parse command:") + "\n");
throw err;
}
trySpawn(argv);
}
// trySpawnDesktop:
// @id: a desktop file ID
//
// Spawns the desktop file identified by @id using startup notification.
// On error, throws an exception.
function trySpawnDesktop(id) {
let app;
// shell_app_system_load_from_desktop_file() will end up returning
// a stupid error message if the desktop file doesn't exist, but
// that's the only case it returns an error for, so we just
// substitute our own error in instead
try {
app = Shell.AppSystem.get_default().load_from_desktop_file(id + '.desktop');
} catch (err) {
throw new Error(_("No such application"));
}
try {
app.launch();
} catch(err) {
// see trySpawn
err.message = err.message.replace(/.*\((.+)\)/, '$1');
throw err;
}
}
function _handleSpawnError(command, err) {
let title = _("Execution of '%s' failed:").format(command);
let source = new MessageTray.SystemNotificationSource();
Main.messageTray.add(source);
let notification = new MessageTray.Notification(source, title, err.message);
notification.setTransient(true);
source.notify(notification);
}
// killall:
// @processName: a process name
//
// Kills @processName. If no process with the given name is found,
// this will fail silently.
function killall(processName) {
try {
// pkill is more portable than killall, but on Linux at least
// it won't match if you pass more than 15 characters of the
// process name... However, if you use the '-f' flag to match
// the entire command line, it will work, but we have to be
// careful in that case that we can match
// '/usr/bin/processName' but not 'gedit processName.c' or
// whatever...
let argv = ['pkill', '-f', '^([^ ]*/)?' + processName + '($| )'];
GLib.spawn_sync(null, argv, null, GLib.SpawnFlags.SEARCH_PATH, null, null);
// It might be useful to return success/failure, but we'd need
// a wrapper around WIFEXITED and WEXITSTATUS. Since none of
// the current callers care, we don't bother.
} catch (e) {
logError(e, 'Failed to kill ' + processName);
}
}

View File

@ -1,97 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Signals = imports.signals;
const Gettext = imports.gettext;
const FORMAT_KEY = 'format';
const SHOW_DATE_KEY = 'show-date';
const SHOW_SECONDS_KEY = 'show-seconds';
function ClockPreferences(uiFile) {
this._init(uiFile);
};
ClockPreferences.prototype = {
_init: function(uiFile) {
let builder = new Gtk.Builder();
builder.add_from_file(uiFile);
this._dialog = builder.get_object('prefs-dialog');
this._dialog.connect('response', Lang.bind(this, this._onResponse));
this._12hrRadio = builder.get_object('12hr_radio');
this._24hrRadio = builder.get_object('24hr_radio');
this._dateCheck = builder.get_object('date_check');
this._secondsCheck = builder.get_object('seconds_check');
delete builder;
this._settings = new Gio.Settings({ schema: 'org.gnome.shell.clock' });
this._notifyId = this._settings.connect('changed',
Lang.bind(this,
this._updateDialog));
this._12hrRadio.connect('toggled', Lang.bind(this,
function() {
let format = this._12hrRadio.active ? '12-hour' : '24-hour';
this._settings.set_string(FORMAT_KEY, format);
}));
this._dateCheck.connect('toggled', Lang.bind(this,
function() {
this._settings.set_boolean(SHOW_DATE_KEY,
this._dateCheck.active);
}));
this._secondsCheck.connect('toggled', Lang.bind(this,
function() {
this._settings.set_boolean(SHOW_SECONDS_KEY,
this._secondsCheck.active);
}));
this._updateDialog();
},
show: function() {
this._dialog.show_all();
},
_updateDialog: function() {
let format = this._settings.get_string(FORMAT_KEY);
this._12hrRadio.active = (format == "12-hour");
this._24hrRadio.active = (format == "24-hour");
this._dateCheck.active = this._settings.get_boolean(SHOW_DATE_KEY);
this._secondsCheck.active = this._settings.get_boolean(SHOW_SECONDS_KEY);
},
_onResponse: function() {
this._dialog.destroy();
this._settings.disconnect(this._notifyId);
this.emit('destroy');
}
};
Signals.addSignalMethods(ClockPreferences.prototype);
function main(params) {
if ('progName' in params)
GLib.set_prgname(params['progName']);
if ('localeDir' in params)
Gettext.bindtextdomain('gnome-shell', params['localeDir']);
Gtk.init(null, null);
let clockPrefs = new ClockPreferences(params['uiFile']);
clockPrefs.connect('destroy',
function() {
Gtk.main_quit();
});
clockPrefs.show();
Gtk.main();
}

View File

@ -15,6 +15,8 @@ const POPUP_APPICON_SIZE = 96;
const POPUP_SCROLL_TIME = 0.10; // seconds
const POPUP_FADE_TIME = 0.1; // seconds
const APP_ICON_HOVER_TIMEOUT = 200; // milliseconds
const DISABLE_HOVER_TIMEOUT = 500; // milliseconds
const THUMBNAIL_DEFAULT_SIZE = 256;
@ -34,7 +36,8 @@ function AltTabPopup() {
AltTabPopup.prototype = {
_init : function() {
this.actor = new Shell.GenericContainer({ name: 'altTabPopup',
reactive: true });
reactive: true,
visible: false });
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
@ -49,6 +52,8 @@ AltTabPopup.prototype = {
this._thumbnailTimeoutId = 0;
this._motionTimeoutId = 0;
this.thumbnailsVisible = false;
// Initially disable hover so we ignore the enter-event if
// the switcher appears underneath the current pointer location
this._disableHover();
@ -126,13 +131,13 @@ AltTabPopup.prototype = {
return false;
this._haveModal = true;
this._keyPressEventId = global.stage.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
this._keyReleaseEventId = global.stage.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
this.actor.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
this.actor.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
this.actor.connect('button-press-event', Lang.bind(this, this._clickedOutside));
this.actor.connect('scroll-event', Lang.bind(this, this._onScroll));
this._appSwitcher = new AppSwitcher(apps);
this._appSwitcher = new AppSwitcher(apps, this);
this.actor.add_actor(this._appSwitcher.actor);
this._appSwitcher.connect('item-activated', Lang.bind(this, this._appActivated));
this._appSwitcher.connect('item-entered', Lang.bind(this, this._appEntered));
@ -365,15 +370,18 @@ AltTabPopup.prototype = {
},
destroy : function() {
Tweener.addTween(this.actor,
{ opacity: 0,
time: POPUP_FADE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this.actor.destroy();
})
});
if (this.actor.visible) {
Tweener.addTween(this.actor,
{ opacity: 0,
time: POPUP_FADE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this.actor.destroy();
})
});
} else
this.actor.destroy();
},
_onDestroy : function() {
@ -383,11 +391,6 @@ AltTabPopup.prototype = {
if (this._thumbnails)
this._destroyThumbnails();
if (this._keyPressEventId)
global.stage.disconnect(this._keyPressEventId);
if (this._keyReleaseEventId)
global.stage.disconnect(this._keyReleaseEventId);
if (this._motionTimeoutId != 0)
Mainloop.source_remove(this._motionTimeoutId);
if (this._thumbnailTimeoutId != 0)
@ -458,11 +461,15 @@ AltTabPopup.prototype = {
},
_destroyThumbnails : function() {
Tweener.addTween(this._thumbnails.actor,
let thumbnailsActor = this._thumbnails.actor;
Tweener.addTween(thumbnailsActor,
{ opacity: 0,
time: THUMBNAIL_FADE_TIME,
transition: 'easeOutQuad',
onComplete: function() { this.destroy(); }
onComplete: Lang.bind(this, function() {
thumbnailsActor.destroy();
this.thumbnailsVisible = false;
})
});
this._thumbnails = null;
},
@ -478,7 +485,8 @@ AltTabPopup.prototype = {
Tweener.addTween(this._thumbnails.actor,
{ opacity: 255,
time: THUMBNAIL_FADE_TIME,
transition: 'easeOutQuad'
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function () { this.thumbnailsVisible = true; })
});
}
};
@ -592,16 +600,20 @@ SwitcherList.prototype = {
this._list.add_actor(bbox);
let n = this._items.length;
bbox.connect('clicked', Lang.bind(this, function () {
this._itemActivated(n);
}));
bbox.connect('enter-event', Lang.bind(this, function () {
this._itemEntered(n);
}));
bbox.connect('clicked', Lang.bind(this, function() { this._onItemClicked(n); }));
bbox.connect('enter-event', Lang.bind(this, function() { this._onItemEnter(n); }));
this._items.push(bbox);
},
_onItemClicked: function (index) {
this._itemActivated(index);
},
_onItemEnter: function (index) {
this._itemEntered(index);
},
addSeparator: function () {
let box = new St.Bin({ style_class: 'separator' });
this._separator = box;
@ -609,16 +621,18 @@ SwitcherList.prototype = {
},
highlight: function(index, justOutline) {
if (this._highlighted != -1)
this._items[this._highlighted].style_class = 'item-box';
if (this._highlighted != -1) {
this._items[this._highlighted].remove_style_pseudo_class('outlined');
this._items[this._highlighted].remove_style_pseudo_class('selected');
}
this._highlighted = index;
if (this._highlighted != -1) {
if (justOutline)
this._items[this._highlighted].style_class = 'outlined-item-box';
this._items[this._highlighted].add_style_pseudo_class('outlined');
else
this._items[this._highlighted].style_class = 'selected-item-box';
this._items[this._highlighted].add_style_pseudo_class('selected');
}
let monitor = global.get_primary_monitor();
@ -818,14 +832,14 @@ AppIcon.prototype = {
}
};
function AppSwitcher(apps) {
this._init(apps);
function AppSwitcher(apps, altTabPopup) {
this._init(apps, altTabPopup);
}
AppSwitcher.prototype = {
__proto__ : SwitcherList.prototype,
_init : function(apps) {
_init : function(apps, altTabPopup) {
SwitcherList.prototype._init.call(this, true);
// Construct the AppIcons, sort by time, add to the popup
@ -857,6 +871,8 @@ AppSwitcher.prototype = {
this._curApp = -1;
this._iconSize = 0;
this._altTabPopup = altTabPopup;
this._mouseTimeOutId = 0;
},
_getPreferredHeight: function (actor, forWidth, alloc) {
@ -864,17 +880,19 @@ AppSwitcher.prototype = {
while(this._items.length > 1 && this._items[j].style_class != 'item-box') {
j++;
}
let iconPadding = this._items[j].get_theme_node().get_horizontal_padding();
let themeNode = this._items[j].get_theme_node();
let iconPadding = themeNode.get_horizontal_padding();
let iconBorder = themeNode.get_border_width(St.Side.LEFT) + themeNode.get_border_width(St.Side.RIGHT);
let [iconMinHeight, iconNaturalHeight] = this.icons[j].label.get_preferred_height(-1);
let iconSpacing = iconNaturalHeight + iconPadding;
let iconSpacing = iconNaturalHeight + iconPadding + iconBorder;
let totalSpacing = this._list.spacing * (this._items.length - 1);
if (this._separator)
totalSpacing += this._separator.width + this._list.spacing;
// We just assume the whole screen here due to weirdness happing with the passed width
let focus = global.get_focus_monitor();
let primary = global.get_primary_monitor();
let parentPadding = this.actor.get_parent().get_theme_node().get_horizontal_padding();
let availWidth = focus.width - parentPadding - this.actor.get_theme_node().get_horizontal_padding();
let availWidth = primary.width - parentPadding - this.actor.get_theme_node().get_horizontal_padding();
let height = 0;
for(let i = 0; i < iconSizes.length; i++) {
@ -919,6 +937,29 @@ AppSwitcher.prototype = {
}
},
// We override SwitcherList's _onItemEnter method to delay
// activation when the thumbnail list is open
_onItemEnter: function (index) {
if (this._mouseTimeOutId != 0)
Mainloop.source_remove(this._mouseTimeOutId);
if (this._altTabPopup.thumbnailsVisible) {
this._mouseTimeOutId = Mainloop.timeout_add(APP_ICON_HOVER_TIMEOUT,
Lang.bind(this, function () {
this._enterItem(index);
this._mouseTimeOutId = 0;
return false;
}));
} else
this._itemEntered(index);
},
_enterItem: function(index) {
let [x, y, mask] = global.get_pointer();
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y);
if (this._items[index].contains(pickedActor))
this._itemEntered(index);
},
// We override SwitcherList's highlight() method to also deal with
// the AppSwitcher->ThumbnailList arrows. Apps with only 1 window
// will hide their arrows by default, but show them when their

View File

@ -21,8 +21,6 @@ const Tweener = imports.ui.tweener;
const Workspace = imports.ui.workspace;
const Params = imports.misc.params;
const WELL_MAX_COLUMNS = 16;
const WELL_MAX_SEARCH_ROWS = 1;
const MENU_POPUP_TIMEOUT = 600;
function AlphabeticalView() {
@ -31,10 +29,29 @@ function AlphabeticalView() {
AlphabeticalView.prototype = {
_init: function() {
this.actor = new St.BoxLayout({ vertical: true });
this._grid = new IconGrid.IconGrid();
this._grid = new IconGrid.IconGrid({ xAlign: St.Align.START });
this._appSystem = Shell.AppSystem.get_default();
this.actor.add(this._grid.actor, { y_align: St.Align.START, expand: true });
this._filterApp = null;
let box = new St.BoxLayout({ vertical: true });
box.add(this._grid.actor, { y_align: St.Align.START, expand: true });
this.actor = new St.ScrollView({ x_fill: true,
y_fill: false,
y_align: St.Align.START,
vfade: true });
this.actor.add_actor(box);
this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
this.actor.connect('notify::mapped', Lang.bind(this,
function() {
if (!this.actor.mapped)
return;
let adjustment = this.actor.vscroll.adjustment;
let direction = Overview.SwipeScrollDirection.VERTICAL;
Main.overview.setScrollAdjustment(adjustment, direction);
}));
},
_removeAll: function() {
@ -42,20 +59,24 @@ AlphabeticalView.prototype = {
this._apps = [];
},
_addApp: function(app) {
let appIcon = new AppWellIcon(this._appSystem.get_app(app.get_id()));
appIcon.connect('launching', Lang.bind(this, function() {
this.emit('launching');
}));
appIcon._draggable.connect('drag-begin', Lang.bind(this, function() {
this.emit('drag-begin');
}));
_addApp: function(appInfo) {
let appIcon = new AppWellIcon(this._appSystem.get_app(appInfo.get_id()));
this._grid.addItem(appIcon.actor);
appIcon._appInfo = appInfo;
if (this._filterApp && !this._filterApp(appInfo))
appIcon.actor.hide();
this._apps.push(appIcon);
},
setFilter: function(filter) {
this._filterApp = filter;
for (let i = 0; i < this._apps.length; i++)
this._apps[i].actor.visible = filter(this._apps[i]._appInfo);
},
refresh: function(apps) {
let ids = [];
for (let i in apps)
@ -72,8 +93,6 @@ AlphabeticalView.prototype = {
}
};
Signals.addSignalMethods(AlphabeticalView.prototype);
function ViewByCategories() {
this._init();
}
@ -81,59 +100,79 @@ function ViewByCategories() {
ViewByCategories.prototype = {
_init: function() {
this._appSystem = Shell.AppSystem.get_default();
this.actor = new St.BoxLayout({ vertical: true });
this.actor = new St.BoxLayout({ style_class: 'all-app' });
this.actor._delegate = this;
this._view = new AlphabeticalView();
this._filters = new St.BoxLayout({ vertical: true });
this.actor.add(this._view.actor, { expand: true, x_fill: true, y_fill: true });
this.actor.add(this._filters, { expand: false, y_fill: false, y_align: St.Align.START });
this._sections = [];
},
_updateSections: function(apps) {
this._removeAll();
_selectCategory: function(num) {
if (num != -1)
this._allFilter.remove_style_pseudo_class('selected');
else
this._allFilter.add_style_pseudo_class('selected');
let sections = this._appSystem.get_sections();
if (!sections)
return;
for (let i = 0; i < sections.length; i++) {
if (i) {
let actor = new St.Bin({ style_class: 'app-section-divider' });
let divider = new St.Bin({ style_class: 'app-section-divider-container',
child: actor,
x_fill: true });
this._view.setFilter(Lang.bind(this, function(app) {
if (num == -1)
return true;
return this._sections[num].name == app.get_section();
}));
this.actor.add(divider, { y_fill: false, expand: true });
}
let _apps = apps.filter(function(app) {
return app.get_section() == sections[i];
});
this._sections[i] = { view: new AlphabeticalView(),
apps: _apps,
name: sections[i] };
this._sections[i].view.connect('launching', Lang.bind(this, function() {
this.emit('launching');
}));
this._sections[i].view.connect('drag-begin', Lang.bind(this, function() {
this.emit('drag-begin');
}));
this.actor.add(this._sections[i].view.actor, { y_align: St.Align.START, expand: true });
for (let i = 0; i < this._sections.length; i++) {
if (i == num)
this._sections[i].filterActor.add_style_pseudo_class('selected');
else
this._sections[i].filterActor.remove_style_pseudo_class('selected');
}
},
_addFilter: function(name, num) {
let button = new St.Button({ label: name,
style_class: 'app-filter',
x_align: St.Align.START });
this._filters.add(button, { expand: true, x_fill: true, y_fill: false });
button.connect('clicked', Lang.bind(this, function() {
this._selectCategory(num);
}));
if (num != -1)
this._sections[num] = { filterActor: button,
name: name };
else
this._allFilter = button;
},
_removeAll: function() {
this.actor.destroy_children();
this._sections.forEach(function (section) { section.view.disconnectAll(); });
this._sections = [];
this._filters.destroy_children();
},
refresh: function(apps) {
this._updateSections(apps);
for (let i = 0; i < this._sections.length; i++) {
this._sections[i].view.refresh(this._sections[i].apps);
}
this._removeAll();
let sections = this._appSystem.get_sections();
this._apps = apps;
this._view.refresh(apps);
/* Translators: Filter to display all applications */
this._addFilter(_("All"), -1);
if (!sections)
return;
for (let i = 0; i < sections.length; i++)
this._addFilter(sections[i], i);
this._selectCategory(-1);
}
};
Signals.addSignalMethods(ViewByCategories.prototype);
/* This class represents a display containing a collection of application items.
* The applications are sorted based on their name.
*/
@ -148,25 +187,8 @@ AllAppDisplay.prototype = {
Main.queueDeferredWork(this._workId);
}));
let bin = new St.BoxLayout({ style_class: 'all-app-controls-panel',
reactive: true });
this.actor = new St.BoxLayout({ style_class: 'all-app', vertical: true });
this.actor.hide();
let view = new St.ScrollView({ x_fill: true,
y_fill: false,
style_class: 'all-app-scroll-view',
vshadows: true });
this._scrollView = view;
this.actor.add(bin);
this.actor.add(view, { expand: true, y_fill: false, y_align: St.Align.START });
this._appView = new ViewByCategories();
this._appView.connect('launching', Lang.bind(this, this.close));
this._appView.connect('drag-begin', Lang.bind(this, this.close));
this._scrollView.add_actor(this._appView.actor);
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
this.actor = new St.Bin({ child: this._appView.actor, x_fill: true, y_fill: true });
this._workId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay));
},
@ -177,99 +199,6 @@ AllAppDisplay.prototype = {
});
this._appView.refresh(apps);
},
toggle: function() {
if (this.actor.visible) {
Tweener.addTween(this.actor,
{ opacity: 0,
time: Overview.PANE_FADE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this.actor.hide();
this.emit('open-state-changed',
this.actor.visible);
})
});
} else {
this.actor.show();
this.emit('open-state-changed', this.actor.visible);
this.actor.opacity = 0;
Tweener.addTween(this.actor,
{ opacity: 255,
time: Overview.PANE_FADE_TIME,
transition: 'easeOutQuad'
});
}
},
close: function() {
if (!this.actor.visible)
return;
this.toggle();
}
};
Signals.addSignalMethods(AllAppDisplay.prototype);
function AppSearchResultDisplay(provider) {
this._init(provider);
}
AppSearchResultDisplay.prototype = {
__proto__: Search.SearchResultDisplay.prototype,
_init: function (provider) {
Search.SearchResultDisplay.prototype._init.call(this, provider);
this._grid = new IconGrid.IconGrid({ rowLimit: WELL_MAX_SEARCH_ROWS });
this.actor = new St.Bin({ name: 'dashAppSearchResults',
x_align: St.Align.START });
this.actor.set_child(this._grid.actor);
},
renderResults: function(results, terms) {
let appSys = Shell.AppSystem.get_default();
let maxItems = WELL_MAX_SEARCH_ROWS * WELL_MAX_COLUMNS;
for (let i = 0; i < results.length && i < maxItems; i++) {
let result = results[i];
let app = appSys.get_app(result);
let display = new AppWellIcon(app);
this._grid.addItem(display.actor);
}
},
clear: function () {
this._grid.removeAll();
this.selectionIndex = -1;
},
getVisibleResultCount: function() {
return this._grid.visibleItemsCount();
},
selectIndex: function (index) {
let nVisible = this.getVisibleResultCount();
if (this.selectionIndex >= 0) {
let prevActor = this._grid.getItemAtIndex(this.selectionIndex);
prevActor._delegate.setSelected(false);
}
this.selectionIndex = -1;
if (index >= nVisible)
return false;
else if (index < 0)
return false;
let targetActor = this._grid.getItemAtIndex(index);
targetActor._delegate.setSelected(true);
this.selectionIndex = index;
return true;
},
activateSelected: function() {
if (this.selectionIndex < 0)
return;
let targetActor = this._grid.getItemAtIndex(this.selectionIndex);
this.provider.activateResult(targetActor._delegate.app.get_id());
}
};
@ -324,12 +253,10 @@ AppSearchProvider.prototype = {
return this._appSys.subsearch(false, previousResults, terms);
},
createResultContainerActor: function () {
return new AppSearchResultDisplay(this);
},
createResultActor: function (resultMeta, terms) {
return new AppIcon(resultMeta.id);
let app = this._appSys.get_app(resultMeta['id']);
let icon = new AppWellIcon(app);
return icon.actor;
},
expandSearch: function(terms) {
@ -363,19 +290,21 @@ PrefsSearchProvider.prototype = {
}
};
function AppIcon(app) {
this._init(app);
function AppIcon(app, params) {
this._init(app, params);
}
AppIcon.prototype = {
__proto__: IconGrid.BaseIcon.prototype,
_init : function(app) {
_init : function(app, params) {
this.app = app;
let label = this.app.get_name();
IconGrid.BaseIcon.prototype._init.call(this, label);
IconGrid.BaseIcon.prototype._init.call(this,
label,
params);
},
createIcon: function(iconSize) {
@ -383,12 +312,12 @@ AppIcon.prototype = {
}
};
function AppWellIcon(app) {
this._init(app);
function AppWellIcon(app, iconParams) {
this._init(app, iconParams);
}
AppWellIcon.prototype = {
_init : function(app) {
_init : function(app, iconParams) {
this.app = app;
this.actor = new St.Clickable({ style_class: 'app-well-app',
reactive: true,
@ -396,8 +325,8 @@ AppWellIcon.prototype = {
y_fill: true });
this.actor._delegate = this;
this._icon = new AppIcon(app);
this.actor.set_child(this._icon.actor);
this.icon = new AppIcon(app, iconParams);
this.actor.set_child(this.icon.actor);
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
@ -526,14 +455,6 @@ AppWellIcon.prototype = {
}
},
setSelected: function (isSelected) {
this._selected = isSelected;
if (this._selected)
this.actor.add_style_class_name('selected');
else
this.actor.remove_style_class_name('selected');
},
_onMenuPoppedUp: function() {
if (this._getRunning()) {
Main.overview.getWorkspacesForWindow(null).setApplicationWindowSelection(this.app.get_id());
@ -581,13 +502,13 @@ AppWellIcon.prototype = {
},
getDragActor: function() {
return this.app.create_icon_texture(this._icon.iconSize);
return this.app.create_icon_texture(this.icon.iconSize);
},
// Returns the original actor that should align with the actor
// we show as the item is being dragged.
getDragActorSource: function() {
return this._icon.icon;
return this.icon.icon;
}
};
Signals.addSignalMethods(AppWellIcon.prototype);
@ -600,7 +521,11 @@ AppIconMenu.prototype = {
__proto__: PopupMenu.PopupMenu.prototype,
_init: function(source) {
PopupMenu.PopupMenu.prototype._init.call(this, source.actor, St.Align.MIDDLE, St.Side.LEFT, 0);
let side = St.Side.LEFT;
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
side = St.Side.RIGHT;
PopupMenu.PopupMenu.prototype._init.call(this, source.actor, St.Align.MIDDLE, side, 0);
this._source = source;
@ -756,135 +681,3 @@ AppIconMenu.prototype = {
}
};
Signals.addSignalMethods(AppIconMenu.prototype);
function AppWell() {
this._init();
}
AppWell.prototype = {
_init : function() {
this._placeholderText = null;
this._menus = [];
this._menuDisplays = [];
this._favorites = [];
this._grid = new IconGrid.IconGrid();
this.actor = this._grid.actor;
this.actor._delegate = this;
this._workId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay));
this._tracker = Shell.WindowTracker.get_default();
this._appSystem = Shell.AppSystem.get_default();
this._appSystem.connect('installed-changed', Lang.bind(this, this._queueRedisplay));
AppFavorites.getAppFavorites().connect('changed', Lang.bind(this, this._queueRedisplay));
this._tracker.connect('app-state-changed', Lang.bind(this, this._queueRedisplay));
},
_appIdListToHash: function(apps) {
let ids = {};
for (let i = 0; i < apps.length; i++)
ids[apps[i].get_id()] = apps[i];
return ids;
},
_queueRedisplay: function () {
Main.queueDeferredWork(this._workId);
},
_redisplay: function () {
this._grid.removeAll();
let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
/* hardcode here pending some design about how exactly desktop contexts behave */
let contextId = '';
let running = this._tracker.get_running_apps(contextId);
let runningIds = this._appIdListToHash(running);
let nFavorites = 0;
for (let id in favorites) {
let app = favorites[id];
let display = new AppWellIcon(app);
this._grid.addItem(display.actor);
nFavorites++;
}
for (let i = 0; i < running.length; i++) {
let app = running[i];
if (app.get_id() in favorites)
continue;
let display = new AppWellIcon(app);
this._grid.addItem(display.actor);
}
if (this._placeholderText) {
this._placeholderText.destroy();
this._placeholderText = null;
}
if (running.length == 0 && nFavorites == 0) {
this._placeholderText = new St.Label({ text: _("Drag here to add favorites") });
this.actor.add_actor(this._placeholderText);
}
},
handleDragOver : function(source, actor, x, y, time) {
let app = null;
if (source instanceof AppWellIcon)
app = this._appSystem.get_app(source.getId());
else if (source instanceof Workspace.WindowClone)
app = this._tracker.get_window_app(source.metaWindow);
// Don't allow favoriting of transient apps
if (app == null || app.is_transient())
return DND.DragMotionResult.NO_DROP;
let id = app.get_id();
let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
let srcIsFavorite = (id in favorites);
if (srcIsFavorite)
return DND.DragMotionResult.NO_DROP;
return DND.DragMotionResult.COPY_DROP;
},
// Draggable target interface
acceptDrop : function(source, actor, x, y, time) {
let app = null;
if (source instanceof AppWellIcon) {
app = this._appSystem.get_app(source.getId());
} else if (source instanceof Workspace.WindowClone) {
app = this._tracker.get_window_app(source.metaWindow);
}
// Don't allow favoriting of transient apps
if (app == null || app.is_transient()) {
return false;
}
let id = app.get_id();
let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
let srcIsFavorite = (id in favorites);
if (srcIsFavorite) {
return false;
} else {
Mainloop.idle_add(Lang.bind(this, function () {
AppFavorites.getAppFavorites().addFavorite(id);
return false;
}));
}
return true;
}
};
Signals.addSignalMethods(AppWell.prototype);

View File

@ -63,7 +63,7 @@ AppFavorites.prototype = {
return appId in this._favorites;
},
_addFavorite: function(appId) {
_addFavorite: function(appId, pos) {
if (appId in this._favorites)
return false;
@ -73,23 +73,35 @@ AppFavorites.prototype = {
return false;
let ids = this._getIds();
ids.push(appId);
if (pos == -1)
ids.push(appId);
else
ids.splice(pos, 0, appId);
global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
this._favorites[appId] = app;
return true;
},
addFavorite: function(appId) {
if (!this._addFavorite(appId))
addFavoriteAtPos: function(appId, pos) {
if (!this._addFavorite(appId, pos))
return;
let app = Shell.AppSystem.get_default().get_app(appId);
Main.overview.infoBar.setMessage(_("%s has been added to your favorites.").format(app.get_name()), Lang.bind(this, function () {
Main.overview.shellInfo.setMessage(_("%s has been added to your favorites.").format(app.get_name()), Lang.bind(this, function () {
this._removeFavorite(appId);
}));
},
addFavorite: function(appId) {
this.addFavoriteAtPos(appId, -1);
},
moveFavoriteToPos: function(appId, pos) {
this._removeFavorite(appId);
this._addFavorite(appId, pos);
},
_removeFavorite: function(appId) {
if (!appId in this._favorites)
return false;
@ -100,13 +112,16 @@ AppFavorites.prototype = {
},
removeFavorite: function(appId) {
let ids = this._getIds();
let pos = ids.indexOf(appId);
let app = this._favorites[appId];
if (!this._removeFavorite(appId))
return;
Main.overview.infoBar.setMessage(_("%s has been removed from your favorites.").format(app.get_name()),
Main.overview.shellInfo.setMessage(_("%s has been removed from your favorites.").format(app.get_name()),
Lang.bind(this, function () {
this._addFavorite(appId);
this._addFavorite(appId, pos);
}));
}
};

View File

@ -11,7 +11,7 @@ const POPUP_ANIMATION_TIME = 0.15;
/**
* BoxPointer:
* @side: A St.Side type; currently only St.Side.TOP is implemented
* @side: side to draw the arrow on
* @binProperties: Properties to set on contained bin
*
* An actor which displays a triangle "arrow" pointing to a given
@ -27,6 +27,7 @@ BoxPointer.prototype = {
_init: function(arrowSide, binProperties) {
this._arrowSide = arrowSide;
this._arrowOrigin = 0;
this._arrowCorner = null;
this.actor = new St.Bin({ x_fill: true,
y_fill: true });
this._container = new Shell.GenericContainer();
@ -42,7 +43,7 @@ BoxPointer.prototype = {
this.bin.raise(this._border);
},
animateAppear: function(onComplete) {
show: function(animate, onComplete) {
let x = this.actor.x;
let y = this.actor.y;
let themeNode = this.actor.get_theme_node();
@ -51,19 +52,21 @@ BoxPointer.prototype = {
this.actor.opacity = 0;
this.actor.show();
switch (this._arrowSide) {
case St.Side.TOP:
this.actor.y -= rise;
break;
case St.Side.BOTTOM:
this.actor.y += rise;
break;
case St.Side.LEFT:
this.actor.x -= rise;
break;
case St.Side.RIGHT:
this.actor.x += rise;
break;
if (animate) {
switch (this._arrowSide) {
case St.Side.TOP:
this.actor.y -= rise;
break;
case St.Side.BOTTOM:
this.actor.y += rise;
break;
case St.Side.LEFT:
this.actor.x -= rise;
break;
case St.Side.RIGHT:
this.actor.x += rise;
break;
}
}
Tweener.addTween(this.actor, { opacity: 255,
@ -74,7 +77,7 @@ BoxPointer.prototype = {
time: POPUP_ANIMATION_TIME });
},
animateDisappear: function(onComplete) {
hide: function(animate, onComplete) {
let x = this.actor.x;
let y = this.actor.y;
let originalX = this.actor.x;
@ -82,19 +85,21 @@ BoxPointer.prototype = {
let themeNode = this.actor.get_theme_node();
let rise = themeNode.get_length('-arrow-rise');
switch (this._arrowSide) {
case St.Side.TOP:
y += rise;
break;
case St.Side.BOTTOM:
y -= rise;
break;
case St.Side.LEFT:
x += rise;
break;
case St.Side.RIGHT:
x -= rise;
break;
if (animate) {
switch (this._arrowSide) {
case St.Side.TOP:
y += rise;
break;
case St.Side.BOTTOM:
y -= rise;
break;
case St.Side.LEFT:
x += rise;
break;
case St.Side.RIGHT:
x -= rise;
break;
}
}
Tweener.addTween(this.actor, { opacity: 0,
@ -208,47 +213,140 @@ BoxPointer.prototype = {
cr.translate(rise, 0);
}
cr.moveTo(borderRadius, halfBorder);
let [x1, y1] = [halfBorder, halfBorder];
let [x2, y2] = [boxWidth - halfBorder, boxHeight - halfBorder];
cr.moveTo(x1 + borderRadius, y1);
if (this._arrowSide == St.Side.TOP) {
cr.lineTo(this._arrowOrigin - halfBase, halfBorder);
cr.lineTo(this._arrowOrigin, halfBorder - rise);
cr.lineTo(this._arrowOrigin + halfBase, halfBorder);
}
cr.lineTo(boxWidth - borderRadius, halfBorder);
if (this._arrowCorner == St.Corner.TOPLEFT) {
cr.moveTo(x1, y1);
cr.lineTo(x1, y1 - rise);
cr.lineTo(x1 + halfBase, y1);
cr.lineTo(x2 - borderRadius, y1);
} else if (this._arrowCorner == St.Corner.TOPRIGHT) {
cr.lineTo(x2 - halfBase, y1);
cr.lineTo(x2, y1 - rise);
} else if (this._arrowOrigin < (x1 + (borderRadius + halfBase))) {
cr.lineTo(this._arrowOrigin, y1);
cr.lineTo(this._arrowOrigin, y1 - rise);
cr.lineTo(this._arrowOrigin + halfBase, y1);
cr.lineTo(x2 - borderRadius, y1);
} else if (this._arrowOrigin > (x2 - (borderRadius + halfBase))) {
cr.lineTo(this._arrowOrigin - halfBase, y1);
cr.lineTo(this._arrowOrigin, y1 - rise);
cr.lineTo(this._arrowOrigin, y1);
cr.lineTo(x2 - borderRadius, y1);
} else {
cr.lineTo(this._arrowOrigin - halfBase, y1);
cr.lineTo(this._arrowOrigin, y1 - rise);
cr.lineTo(this._arrowOrigin + halfBase, y1);
cr.lineTo(x2 - borderRadius, y1);
}
} else
cr.lineTo(x2 - borderRadius, y1);
cr.arc(boxWidth - borderRadius - halfBorder, borderRadius + halfBorder, borderRadius,
3*Math.PI/2, Math.PI*2);
// top-right corner
if (this._arrowCorner != St.Corner.TOPRIGHT)
cr.arc(x2 - borderRadius, y1 + borderRadius, borderRadius,
3*Math.PI/2, Math.PI*2);
if (this._arrowSide == St.Side.RIGHT) {
cr.lineTo(boxWidth - halfBorder, this._arrowOrigin - halfBase);
cr.lineTo(boxWidth - halfBorder + rise, this._arrowOrigin);
cr.lineTo(boxWidth - halfBorder, this._arrowOrigin + halfBase);
}
cr.lineTo(boxWidth - halfBorder, boxHeight - borderRadius);
if (this._arrowCorner == St.Corner.TOPRIGHT) {
cr.lineTo(x2, y1);
cr.lineTo(x2 + rise, y1);
cr.lineTo(x2, y1 + halfBase);
cr.lineTo(x2, y2 - borderRadius);
} else if (this._arrowCorner == St.Corner.BOTTOMRIGHT) {
cr.moveTo(x2, y2 - halfBase);
cr.lineTo(x2 + rise, y2);
} else if (this._arrowOrigin < (y1 + (borderRadius + halfBase))) {
cr.lineTo(x2, this._arrowOrigin);
cr.lineTo(x2 + rise, this._arrowOrigin);
cr.lineTo(x2, this._arrowOrigin + halfBase);
cr.lineTo(x2, y2 - borderRadius);
} else if (this._arrowOrigin > (y2 - (borderRadius + halfBase))) {
cr.lineTo(x2, this._arrowOrigin - halfBase);
cr.lineTo(x2 + rise, this._arrowOrigin);
cr.lineTo(x2, this._arrowOrigin);
cr.lineTo(x2, y2 - borderRadius);
} else {
cr.lineTo(x2, this._arrowOrigin - halfBase);
cr.lineTo(x2 + rise, this._arrowOrigin);
cr.lineTo(x2, this._arrowOrigin + halfBase);
cr.lineTo(x2, y2 - borderRadius);
}
} else
cr.lineTo(x2, y2 - borderRadius);
cr.arc(boxWidth - borderRadius - halfBorder, boxHeight - borderRadius - halfBorder, borderRadius,
0, Math.PI/2);
// bottom-right corner
if (this._arrowCorner != St.Corner.BOTTOMRIGHT)
cr.arc(x2 - borderRadius, y2 - borderRadius, borderRadius,
0, Math.PI/2);
if (this._arrowSide == St.Side.BOTTOM) {
cr.lineTo(this._arrowOrigin + halfBase, boxHeight - halfBorder);
cr.lineTo(this._arrowOrigin, boxHeight - halfBorder + rise);
cr.lineTo(this._arrowOrigin - halfBase, boxHeight - halfBorder);
}
cr.lineTo(borderRadius, boxHeight - halfBorder);
if (this._arrowCorner == St.Corner.BOTTOMLEFT) {
cr.lineTo(x1 + halfBase, y2);
cr.lineTo(x1, y2 + rise);
} else if (this._arrowCorner == St.Corner.BOTTOMRIGHT) {
cr.lineTo(x2, y2 + rise);
cr.lineTo(x2 - halfBase, y2);
cr.lineTo(x1 + borderRadius, y2);
} else if (this._arrowOrigin < (x1 + (borderRadius + halfBase))) {
cr.lineTo(this._arrowOrigin + halfBase, y2);
cr.lineTo(this._arrowOrigin, y2 + rise);
cr.lineTo(this._arrowOrigin, y2);
cr.lineTo(x1 + borderRadius, y2);
} else if (this._arrowOrigin > (x2 - (borderRadius + halfBase))) {
cr.lineTo(this._arrowOrigin, y2);
cr.lineTo(this._arrowOrigin, y2 + rise);
cr.lineTo(this._arrowOrigin - halfBase, y2);
cr.lineTo(x1 + borderRadius, y2);
} else {
cr.lineTo(this._arrowOrigin + halfBase, y2);
cr.lineTo(this._arrowOrigin, y2 + rise);
cr.lineTo(this._arrowOrigin - halfBase, y2);
cr.lineTo(x1 + borderRadius, y2);
}
} else
cr.lineTo(x1 + borderRadius, y2);
cr.arc(borderRadius + halfBorder, boxHeight - borderRadius - halfBorder, borderRadius,
Math.PI/2, Math.PI);
// bottom-left corner
if (this._arrowCorner != St.Corner.BOTTOMLEFT)
cr.arc(x1 + borderRadius, y2 - borderRadius, borderRadius,
Math.PI/2, Math.PI);
if (this._arrowSide == St.Side.LEFT) {
cr.lineTo(halfBorder, this._arrowOrigin + halfBase);
cr.lineTo(halfBorder - rise, this._arrowOrigin);
cr.lineTo(halfBorder, this._arrowOrigin - halfBase);
}
cr.lineTo(halfBorder, borderRadius);
if (this._arrowCorner == St.Corner.TOPLEFT) {
cr.lineTo(x2, y1 + halfBase);
cr.lineTo(x1 - rise, y1);
} else if (this._arrowCorner == St.Corner.BOTTOMLEFT) {
cr.lineTo(x1 + rise, y2);
cr.moveTo(x1, y2 - halfBase);
} else if (this._arrowOrigin < (y1 + (borderRadius + halfBase))) {
cr.lineTo(x1, this._arrowOrigin + halfBase);
cr.lineTo(x1 - rise, this._arrowOrigin);
cr.lineTo(x1, this._arrowOrigin);
cr.lineTo(x1, y1 + borderRadius);
} else if (this._arrowOrigin > (y2 - (borderRadius + halfBase))) {
cr.lineTo(x1, this._arrowOrigin);
cr.lineTo(x1 - rise, this._arrowOrigin);
cr.lineTo(x1, this._arrowOrigin - halfBase);
cr.lineTo(x1, y1 + borderRadius);
} else {
cr.lineTo(x1, this._arrowOrigin + halfBase);
cr.lineTo(x1 - rise, this._arrowOrigin);
cr.lineTo(x1, this._arrowOrigin - halfBase);
cr.lineTo(x1, y1 + borderRadius);
}
} else
cr.lineTo(x1, y1 + borderRadius);
cr.arc(borderRadius + halfBorder, borderRadius + halfBorder, borderRadius,
Math.PI, 3*Math.PI/2);
// top-left corner
if (this._arrowCorner != St.Corner.TOPLEFT)
cr.arc(x1 + borderRadius, y1 + borderRadius, borderRadius,
Math.PI, 3*Math.PI/2);
else
cr.lineTo(x1, y1);
Clutter.cairo_set_source_color(cr, backgroundColor);
cr.fillPreserve();
@ -265,16 +363,22 @@ BoxPointer.prototype = {
// Position correctly relative to the sourceActor
let [sourceX, sourceY] = sourceActor.get_transformed_position();
let [sourceWidth, sourceHeight] = sourceActor.get_transformed_size();
let [sourceCenterX, sourceCenterY] = [sourceX + (sourceWidth / 2), sourceY + (sourceHeight / 2)];
let [minWidth, minHeight, natWidth, natHeight] = this.actor.get_preferred_size();
// We also want to keep it onscreen, and separated from the
// edge by the same distance as the main part of the box is
// separated from its sourceActor
let primary = global.get_primary_monitor();
let arrowRise = this.actor.get_theme_node().get_length('-arrow-rise');
let themeNode = this.actor.get_theme_node();
let halfBorder = themeNode.get_length('-arrow-border-width') / 2;
let halfBase = themeNode.get_length('-arrow-base') / 2;
let borderRadius = themeNode.get_length('-arrow-border-radius');
let margin = 2 * borderRadius + halfBorder;
let resX, resY;
this._arrowCorner = null;
switch (this._arrowSide) {
case St.Side.TOP:
@ -298,40 +402,59 @@ BoxPointer.prototype = {
case St.Side.BOTTOM:
switch (alignment) {
case St.Align.START:
resX = sourceX;
resX = sourceCenterX - (halfBase + borderRadius + halfBorder);
break;
case St.Align.MIDDLE:
resX = sourceX - Math.floor((natWidth - sourceWidth) / 2);
resX = sourceCenterX - (natWidth / 2);
break;
case St.Align.END:
resX = sourceX - (natWidth - sourceWidth);
resX = sourceCenterX - natWidth + (halfBase + borderRadius + halfBorder);
break;
}
if (sourceCenterX < margin) {
// Not enough space to the top
this._arrowCorner = (this._arrowSide == St.Side.TOP) ? St.Corner.TOPLEFT : St.Corner.BOTTOMLEFT;
resX = 10;
} else if (sourceCenterX > (primary.width - margin)) {
// Not enough space to the botom
this._arrowCorner = (this._arrowSide == St.Side.TOP) ? St.Corner.TOPRIGHT : St.Corner.BOTTOMRIGHT;
resX = primary.width - (10 + natWidth);
}
resX = Math.min(resX, primary.x + primary.width - natWidth - arrowRise - gap);
resX = Math.max(resX, primary.x);
resX = Math.max(resX, 10);
resX = Math.min(resX, primary.width - (10 + natWidth));
this.setArrowOrigin((sourceX - resX) + Math.floor(sourceWidth / 2));
this.setArrowOrigin(sourceCenterX - resX);
break;
case St.Side.LEFT:
case St.Side.RIGHT:
switch (alignment) {
case St.Align.START:
resY = sourceY;
resY = sourceCenterY - (halfBase + borderRadius + halfBorder);
break;
case St.Align.MIDDLE:
resY = sourceY - Math.floor((natHeight - sourceHeight) / 2);
resY = sourceCenterY - (natHeight / 2);
break;
case St.Align.END:
resY = sourceY - (natHeight - sourceHeight);
resY = sourceCenterY - natHeight + (halfBase + borderRadius + halfBorder);
break;
}
if (sourceCenterY < margin) {
// Not enough space to the left
this._arrowCorner = (this._arrowSide == St.Side.LEFT) ? St.Corner.TOPLEFT : St.Corner.TORIGHT;
resY = 10;
}
else if (sourceCenterY > (primary.height - margin)) {
// Not enough space to the right
this._arrowCorner = (this._arrowSide == St.Side.LEFT) ? St.Corner.BOTTOMLEFT : St.Corner.BOTTOMRIGHT;
resY = primary.height - (10 + natHeight);
}
resY = Math.min(resY, primary.y + primary.height - natHeight - arrowRise - gap);
resY = Math.max(resY, primary.y);
resY = Math.max(resY, 10);
resY = Math.min(resY, primary.height - (10 + natHeight));
this.setArrowOrigin((sourceY - resY) + Math.floor(sourceHeight / 2));
this.setArrowOrigin(sourceCenterY - resY);
break;
}

View File

@ -4,19 +4,78 @@ const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const St = imports.gi.St;
const Signals = imports.signals;
const Pango = imports.gi.Pango;
const Gettext_gtk20 = imports.gettext.domain('gtk20');
const Gettext_gtk30 = imports.gettext.domain('gtk30');
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
const WEEKDATE_HEADER_WIDTH_DIGITS = 3;
const SHOW_WEEKDATE_KEY = 'show-weekdate';
// in org.gnome.desktop.interface
const CLOCK_FORMAT_KEY = 'clock-format';
function _sameDay(dateA, dateB) {
return (dateA.getDate() == dateB.getDate() &&
dateA.getMonth() == dateB.getMonth() &&
dateA.getYear() == dateB.getYear());
}
function _sameYear(dateA, dateB) {
return (dateA.getYear() == dateB.getYear());
}
/* TODO: maybe needs config - right now we assume that Saturday and
* Sunday are non-work days (not true in e.g. Israel, it's Sunday and
* Monday there)
*/
function _isWorkDay(date) {
return date.getDay() != 0 && date.getDay() != 6;
}
function _getBeginningOfDay(date) {
let ret = new Date(date.getTime());
ret.setHours(0);
ret.setMinutes(0);
ret.setSeconds(0);
ret.setMilliseconds(0);
return ret;
}
function _getEndOfDay(date) {
let ret = new Date(date.getTime());
ret.setHours(23);
ret.setMinutes(59);
ret.setSeconds(59);
ret.setMilliseconds(999);
return ret;
}
function _formatEventTime(event, clockFormat) {
let ret;
if (event.allDay) {
/* Translators: Shown in calendar event list for all day events */
ret = _("All Day");
} else {
switch (clockFormat) {
case '24h':
ret = event.date.toLocaleFormat('%H:%M');
break;
default:
/* explicit fall-through */
case '12h':
ret = event.date.toLocaleFormat('%l:%M %p');
break;
}
}
return ret;
}
function _getCalendarWeekForDate(date) {
// Based on the algorithms found here:
// http://en.wikipedia.org/wiki/Talk:ISO_week_date
@ -43,12 +102,259 @@ function _getDigitWidth(actor){
return width;
}
function Calendar() {
function _getCalendarDayAbbreviation(dayNumber) {
let abbreviations = [
/* Translators: Calendar grid abbreviation for Sunday.
*
* NOTE: These abbreviations are always shown together and in
* order, e.g. "S M T W T F S".
*/
_("S"),
/* Translators: Calendar grid abbreviation for Monday */
_("M"),
/* Translators: Calendar grid abbreviation for Tuesday */
_("T"),
/* Translators: Calendar grid abbreviation for Wednesday */
_("W"),
/* Translators: Calendar grid abbreviation for Thursday */
_("T"),
/* Translators: Calendar grid abbreviation for Friday */
_("F"),
/* Translators: Calendar grid abbreviation for Saturday */
_("S")
];
return abbreviations[dayNumber];
}
function _getEventDayAbbreviation(dayNumber) {
let abbreviations = [
/* Translators: Event list abbreviation for Sunday.
*
* NOTE: These abbreviations are normally not shown together
* so they need to be unique (e.g. Tuesday and Thursday cannot
* both be 'T').
*/
_("Su"),
/* Translators: Event list abbreviation for Monday */
_("M"),
/* Translators: Event list abbreviation for Tuesday */
_("T"),
/* Translators: Event list abbreviation for Wednesday */
_("W"),
/* Translators: Event list abbreviation for Thursday */
_("Th"),
/* Translators: Event list abbreviation for Friday */
_("F"),
/* Translators: Event list abbreviation for Saturday */
_("S")
];
return abbreviations[dayNumber];
}
// Abstraction for an appointment/event in a calendar
function CalendarEvent(date, summary, allDay) {
this._init(date, summary, allDay);
}
CalendarEvent.prototype = {
_init: function(date, summary, allDay) {
this.date = date;
this.summary = summary;
this.allDay = allDay;
}
};
// Interface for appointments/events - e.g. the contents of a calendar
//
// First, an implementation with no events
function EmptyEventSource() {
this._init();
}
Calendar.prototype = {
EmptyEventSource.prototype = {
_init: function() {
},
requestRange: function(begin, end) {
},
getEvents: function(begin, end) {
let result = [];
return result;
},
hasEvents: function(day) {
return false;
}
};
Signals.addSignalMethods(EmptyEventSource.prototype);
// Second, wrap native Evolution event source
function EvolutionEventSource() {
this._init();
}
EvolutionEventSource.prototype = {
_init: function() {
this._native = new Shell.EvolutionEventSource();
this._native.connect('changed', Lang.bind(this, function() {
this.emit('changed');
}));
},
requestRange: function(begin, end) {
this._native.request_range(begin.getTime(), end.getTime());
},
getEvents: function(begin, end) {
let result = [];
let nativeEvents = this._native.get_events(begin.getTime(), end.getTime());
for (let n = 0; n < nativeEvents.length; n++) {
let nativeEvent = nativeEvents[n];
result.push(new CalendarEvent(new Date(nativeEvent.msec_begin), nativeEvent.summary, nativeEvent.all_day));
}
return result;
},
hasEvents: function(day) {
let dayBegin = _getBeginningOfDay(day);
let dayEnd = _getEndOfDay(day);
let events = this.getEvents(dayBegin, dayEnd);
if (events.length == 0)
return false;
return true;
}
};
Signals.addSignalMethods(EvolutionEventSource.prototype);
// Finally, an implementation with fake events
function FakeEventSource() {
this._init();
}
FakeEventSource.prototype = {
_init: function() {
this._fakeEvents = [];
// Generate fake events
//
let midnightToday = _getBeginningOfDay(new Date());
let summary = '';
// '10-oclock pow-wow' is an event occuring IN THE PAST every four days at 10am
for (let n = 0; n < 10; n++) {
let t = new Date(midnightToday.getTime() - n * 4 * 86400 * 1000);
t.setHours(10);
summary = '10-oclock pow-wow (n=' + n + ')';
this._fakeEvents.push(new CalendarEvent(t, summary, false));
}
// '11-oclock thing' is an event occuring every three days at 11am
for (let n = 0; n < 10; n++) {
let t = new Date(midnightToday.getTime() + n * 3 * 86400 * 1000);
t.setHours(11);
summary = '11-oclock thing (n=' + n + ')';
this._fakeEvents.push(new CalendarEvent(t, summary, false));
}
// 'Weekly Meeting' is an event occuring every seven days at 1:45pm (two days displaced)
for (let n = 0; n < 5; n++) {
let t = new Date(midnightToday.getTime() + (n * 7 + 2) * 86400 * 1000);
t.setHours(13);
t.setMinutes(45);
summary = 'Weekly Meeting (n=' + n + ')';
this._fakeEvents.push(new CalendarEvent(t, summary, false));
}
// 'Fun All Day' is an all-day event occuring every fortnight (three days displayed)
for (let n = 0; n < 10; n++) {
let t = new Date(midnightToday.getTime() + (n * 14 + 3) * 86400 * 1000);
summary = 'Fun All Day (n=' + n + ')';
this._fakeEvents.push(new CalendarEvent(t, summary, true));
}
// 'Get Married' is an event that actually reflects reality (Dec 4, 2010) :-)
this._fakeEvents.push(new CalendarEvent(new Date(2010, 11, 4, 16, 0), 'Get Married', false));
// ditto for 'NE Patriots vs NY Jets'
this._fakeEvents.push(new CalendarEvent(new Date(2010, 11, 6, 20, 30), 'NE Patriots vs NY Jets', false));
// An event for tomorrow @6:30pm that is added/removed every five
// seconds (to check that the ::changed signal works)
let transientEventDate = new Date(midnightToday.getTime() + 86400 * 1000);
transientEventDate.setHours(18);
transientEventDate.setMinutes(30);
transientEventDate.setSeconds(0);
Mainloop.timeout_add(5000, Lang.bind(this, this._updateTransientEvent));
this._includeTransientEvent = false;
this._transientEvent = new CalendarEvent(transientEventDate, 'A Transient Event', false);
this._transientEventCounter = 1;
},
_updateTransientEvent: function() {
this._includeTransientEvent = !this._includeTransientEvent;
this._transientEventCounter = this._transientEventCounter + 1;
this._transientEvent.summary = 'A Transient Event (' + this._transientEventCounter + ')';
this.emit('changed');
Mainloop.timeout_add(5000, Lang.bind(this, this._updateTransientEvent));
},
requestRange: function(begin, end) {
},
getEvents: function(begin, end) {
let result = [];
//log('begin:' + begin);
//log('end: ' + end);
for(let n = 0; n < this._fakeEvents.length; n++) {
let event = this._fakeEvents[n];
if (event.date >= begin && event.date <= end) {
result.push(event);
}
//log('when:' + event.date + ' summary:' + event.summary);
}
if (this._includeTransientEvent && this._transientEvent.date >= begin && this._transientEvent.date <= end)
result.push(this._transientEvent);
result.sort(function(event1, event2) {
return event1.date.getTime() - event2.date.getTime();
});
return result;
},
hasEvents: function(day) {
let dayBegin = _getBeginningOfDay(day);
let dayEnd = _getEndOfDay(day);
let events = this.getEvents(dayBegin, dayEnd);
if (events.length == 0)
return false;
return true;
}
};
Signals.addSignalMethods(FakeEventSource.prototype);
// Calendar:
// @eventSource: is an object implementing the EventSource API, e.g. the
// requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
function Calendar(eventSource) {
this._init(eventSource);
}
Calendar.prototype = {
_init: function(eventSource) {
this._eventSource = eventSource;
this._eventSource.connect('changed', Lang.bind(this, this._update));
// FIXME: This is actually the fallback method for GTK+ for the week start;
// GTK+ by preference uses nl_langinfo (NL_TIME_FIRST_WEEKDAY). We probably
// should add a C function so we can do the full handling.
@ -60,7 +366,7 @@ Calendar.prototype = {
this._settings.connect('changed::' + SHOW_WEEKDATE_KEY, Lang.bind(this, this._onSettingsChange));
this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY);
let weekStartString = Gettext_gtk20.gettext('calendar:week_start:0');
let weekStartString = Gettext_gtk30.gettext('calendar:week_start:0');
if (weekStartString.indexOf('calendar:week_start:') == 0) {
this._weekStart = parseInt(weekStartString.substring(20));
}
@ -71,7 +377,8 @@ Calendar.prototype = {
}
// Find the ordering for month/year in the calendar heading
switch (Gettext_gtk20.gettext('calendar:MY')) {
this._headerFormatWithoutYear = '%B';
switch (Gettext_gtk30.gettext('calendar:MY')) {
case 'calendar:MY':
this._headerFormat = '%B %Y';
break;
@ -85,7 +392,7 @@ Calendar.prototype = {
}
// Start off with the current date
this.date = new Date();
this._selectedDate = new Date();
this.actor = new St.Table({ homogeneous: false,
style_class: 'calendar',
@ -100,9 +407,10 @@ Calendar.prototype = {
// Sets the calendar to show a specific date
setDate: function(date) {
if (!_sameDay(date, this.date)) {
this.date = date;
if (!_sameDay(date, this._selectedDate)) {
this._selectedDate = date;
this._update();
this.emit('selected-date-changed', new Date(this._selectedDate));
}
},
@ -116,45 +424,36 @@ Calendar.prototype = {
{ row: 0, col: 0, col_span: offsetCols + 7 });
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChange));
let [backlabel, forwardlabel] = ['&lt;', '&gt;'];
if (St.Widget.get_default_direction () == St.TextDirection.RTL) {
[backlabel, forwardlabel] = [forwardlabel, backlabel];
}
let back = new St.Button({ label: backlabel, style_class: 'calendar-change-month' });
let back = new St.Button({ style_class: 'calendar-change-month-back' });
this._topBox.add(back);
back.connect('clicked', Lang.bind(this, this._prevMonth));
back.connect('clicked', Lang.bind(this, this._onPrevMonthButtonClicked));
this._dateLabel = new St.Label();
this._topBox.add(this._dateLabel, { expand: true, x_fill: false, x_align: St.Align.MIDDLE });
this._monthLabel = new St.Label({style_class: 'calendar-month-label'});
this._topBox.add(this._monthLabel, { expand: true, x_fill: false, x_align: St.Align.MIDDLE });
let forward = new St.Button({ label: forwardlabel, style_class: 'calendar-change-month' });
let forward = new St.Button({ style_class: 'calendar-change-month-forward' });
this._topBox.add(forward);
forward.connect('clicked', Lang.bind(this, this._nextMonth));
forward.connect('clicked', Lang.bind(this, this._onNextMonthButtonClicked));
// Add weekday labels...
//
// We need to figure out the abbreviated localized names for the days of the week;
// we do this by just getting the next 7 days starting from right now and then putting
// them in the right cell in the table. It doesn't matter if we add them in order
let iter = new Date(this.date);
let iter = new Date(this._selectedDate);
iter.setSeconds(0); // Leap second protection. Hah!
iter.setHours(12);
if (this._useWeekdate) {
this._weekdateHeader = new St.Label();
this.actor.add(this._weekdateHeader,
{ row: 1,
col: 0,
x_fill: false, x_align: St.Align.MIDDLE });
this._setWeekdateHeaderWidth();
} else {
this._weekdateHeader = null;
}
for (let i = 0; i < 7; i++) {
this.actor.add(new St.Label({ text: iter.toLocaleFormat('%a') }),
// Could use iter.toLocaleFormat('%a') but that normally gives three characters
// and we want, ideally, a single character for e.g. S M T W T F S
let customDayAbbrev = _getCalendarDayAbbreviation(iter.getDay());
let label = new St.Label({ style_class: 'calendar-day-base calendar-day-heading',
text: customDayAbbrev });
this.actor.add(label,
{ row: 1,
col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7,
x_fill: false, x_align: St.Align.END });
x_fill: false, x_align: St.Align.MIDDLE });
iter.setTime(iter.getTime() + MSECS_IN_DAY);
}
@ -178,33 +477,57 @@ Calendar.prototype = {
switch (event.get_scroll_direction()) {
case Clutter.ScrollDirection.UP:
case Clutter.ScrollDirection.LEFT:
this._prevMonth();
this._onPrevMonthButtonClicked();
break;
case Clutter.ScrollDirection.DOWN:
case Clutter.ScrollDirection.RIGHT:
this._nextMonth();
this._onNextMonthButtonClicked();
break;
}
},
_prevMonth: function() {
if (this.date.getMonth() == 0) {
this.date.setMonth(11);
this.date.setFullYear(this.date.getFullYear() - 1);
} else {
this.date.setMonth(this.date.getMonth() - 1);
_onPrevMonthButtonClicked: function() {
let newDate = new Date(this._selectedDate);
let oldMonth = newDate.getMonth();
if (oldMonth == 0) {
newDate.setMonth(11);
newDate.setFullYear(newDate.getFullYear() - 1);
if (newDate.getMonth() != 11) {
let day = 32 - new Date(newDate.getFullYear() - 1, 11, 32).getDate();
newDate = new Date(newDate.getFullYear() - 1, 11, day);
}
}
this._update();
else {
newDate.setMonth(oldMonth - 1);
if (newDate.getMonth() != oldMonth - 1) {
let day = 32 - new Date(newDate.getFullYear(), oldMonth - 1, 32).getDate();
newDate = new Date(newDate.getFullYear(), oldMonth - 1, day);
}
}
this.setDate(newDate);
},
_nextMonth: function() {
if (this.date.getMonth() == 11) {
this.date.setMonth(0);
this.date.setFullYear(this.date.getFullYear() + 1);
} else {
this.date.setMonth(this.date.getMonth() + 1);
_onNextMonthButtonClicked: function() {
let newDate = new Date(this._selectedDate);
let oldMonth = newDate.getMonth();
if (oldMonth == 11) {
newDate.setMonth(0);
newDate.setFullYear(newDate.getFullYear() + 1);
if (newDate.getMonth() != 0) {
let day = 32 - new Date(newDate.getFullYear() + 1, 0, 32).getDate();
newDate = new Date(newDate.getFullYear() + 1, 0, day);
}
}
this._update();
else {
newDate.setMonth(oldMonth + 1);
if (newDate.getMonth() != oldMonth + 1) {
let day = 32 - new Date(newDate.getFullYear(), oldMonth + 1, 32).getDate();
newDate = new Date(newDate.getFullYear(), oldMonth + 1, day);
}
}
this.setDate(newDate);
},
_onSettingsChange: function() {
@ -214,7 +537,12 @@ Calendar.prototype = {
},
_update: function() {
this._dateLabel.text = this.date.toLocaleFormat(this._headerFormat);
let now = new Date();
if (_sameYear(this._selectedDate, now))
this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormatWithoutYear);
else
this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormat);
// Remove everything but the topBox and the weekday labels
let children = this.actor.get_children();
@ -222,45 +550,215 @@ Calendar.prototype = {
children[i].destroy();
// Start at the beginning of the week before the start of the month
let iter = new Date(this.date);
iter.setDate(1);
iter.setSeconds(0);
iter.setHours(12);
let daysToWeekStart = (7 + iter.getDay() - this._weekStart) % 7;
iter.setTime(iter.getTime() - daysToWeekStart * MSECS_IN_DAY);
let now = new Date();
let beginDate = new Date(this._selectedDate);
beginDate.setDate(1);
beginDate.setSeconds(0);
beginDate.setHours(12);
let daysToWeekStart = (7 + beginDate.getDay() - this._weekStart) % 7;
beginDate.setTime(beginDate.getTime() - daysToWeekStart * MSECS_IN_DAY);
let iter = new Date(beginDate);
let row = 2;
while (true) {
let label = new St.Label({ text: iter.getDate().toString() });
if (_sameDay(now, iter))
label.style_class = 'calendar-day calendar-today';
else if (iter.getMonth() != this.date.getMonth())
label.style_class = 'calendar-day calendar-other-month-day';
let button = new St.Button({ label: iter.getDate().toString() });
let iterStr = iter.toUTCString();
button.connect('clicked', Lang.bind(this, function() {
let newlySelectedDate = new Date(iterStr);
this.setDate(newlySelectedDate);
}));
let hasEvents = this._eventSource.hasEvents(iter);
let styleClass = 'calendar-day-base calendar-day';
if (_isWorkDay(iter))
styleClass += ' calendar-work-day'
else
label.style_class = 'calendar-day';
styleClass += ' calendar-nonwork-day'
// Hack used in lieu of border-collapse - see gnome-shell.css
if (row == 2)
styleClass = 'calendar-day-top ' + styleClass;
if (iter.getDay() == this._weekStart)
styleClass = 'calendar-day-left ' + styleClass;
if (_sameDay(now, iter))
styleClass += ' calendar-today';
else if (iter.getMonth() != this._selectedDate.getMonth())
styleClass += ' calendar-other-month-day';
if (_sameDay(this._selectedDate, iter))
button.add_style_pseudo_class('active');
if (hasEvents)
styleClass += ' calendar-day-with-events'
button.style_class = styleClass;
let offsetCols = this._useWeekdate ? 1 : 0;
this.actor.add(label,
{ row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7,
x_fill: false, x_align: St.Align.END });
this.actor.add(button,
{ row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7 });
if (this._useWeekdate && iter.getDay() == 4) {
let label = new St.Label({ text: _getCalendarWeekForDate(iter).toString(),
style_class: 'calendar-day calendar-calendarweek'});
style_class: 'calendar-day-base calendar-week-number'});
this.actor.add(label,
{ row: row, col: 0,
x_fill: false, x_align: St.Align.MIDDLE });
{ row: row, col: 0, y_align: St.Align.MIDDLE });
}
iter.setTime(iter.getTime() + MSECS_IN_DAY);
if (iter.getDay() == this._weekStart) {
// We stop on the first "first day of the week" after the month we are displaying
if (iter.getMonth() > this.date.getMonth() || iter.getYear() > this.date.getYear())
if (iter.getMonth() > this._selectedDate.getMonth() || iter.getYear() > this._selectedDate.getYear())
break;
row++;
}
}
// Signal to the event source that we are interested in events
// only from this date range
this._eventSource.requestRange(beginDate, iter);
}
};
Signals.addSignalMethods(Calendar.prototype);
function EventsList(eventSource) {
this._init(eventSource);
}
EventsList.prototype = {
_init: function(eventSource) {
this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'});
this._date = new Date();
this._eventSource = eventSource;
this._eventSource.connect('changed', Lang.bind(this, this._update));
this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
this._desktopSettings.connect('changed', Lang.bind(this, this._update));
let weekStartString = Gettext_gtk30.gettext('calendar:week_start:0');
if (weekStartString.indexOf('calendar:week_start:') == 0) {
this._weekStart = parseInt(weekStartString.substring(20));
}
if (isNaN(this._weekStart) ||
this._weekStart < 0 ||
this._weekStart > 6) {
log('Translation of "calendar:week_start:0" in GTK+ is not correct');
this._weekStart = 0;
}
this._update();
},
_addEvent: function(dayNameBox, timeBox, eventTitleBox, includeDayName, day, time, desc) {
if (includeDayName) {
dayNameBox.add(new St.Label( { style_class: 'events-day-dayname',
text: day } ),
{ x_fill: true } );
}
timeBox.add(new St.Label( { style_class: 'events-day-time',
text: time} ),
{ x_fill: true } );
eventTitleBox.add(new St.Label( { style_class: 'events-day-task',
text: desc} ));
},
_addPeriod: function(header, begin, end, includeDayName, showNothingScheduled) {
let events = this._eventSource.getEvents(begin, end);
let clockFormat = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);;
if (events.length == 0 && !showNothingScheduled)
return;
let vbox = new St.BoxLayout( {vertical: true} );
this.actor.add(vbox);
vbox.add(new St.Label({ style_class: 'events-day-header', text: header }));
let box = new St.BoxLayout({style_class: 'events-header-hbox'});
let dayNameBox = new St.BoxLayout({ vertical: true, style_class: 'events-day-name-box' });
let timeBox = new St.BoxLayout({ vertical: true, style_class: 'events-time-box' });
let eventTitleBox = new St.BoxLayout({ vertical: true, style_class: 'events-event-box' });
box.add(dayNameBox, {x_fill: false});
box.add(timeBox, {x_fill: false});
box.add(eventTitleBox, {expand: true});
vbox.add(box);
for (let n = 0; n < events.length; n++) {
let event = events[n];
let dayString = _getEventDayAbbreviation(event.date.getDay());
let timeString = _formatEventTime(event, clockFormat);
let summaryString = event.summary;
this._addEvent(dayNameBox, timeBox, eventTitleBox, includeDayName, dayString, timeString, summaryString);
}
if (events.length == 0 && showNothingScheduled) {
let now = new Date();
/* Translators: Text to show if there are no events */
let nothingEvent = new CalendarEvent(now, _("Nothing Scheduled"), true);
let timeString = _formatEventTime(nothingEvent, clockFormat);
this._addEvent(dayNameBox, timeBox, eventTitleBox, false, "", timeString, nothingEvent.summary);
}
},
_showOtherDay: function(day) {
this.actor.destroy_children();
let dayBegin = _getBeginningOfDay(day);
let dayEnd = _getEndOfDay(day);
let dayString;
let now = new Date();
if (_sameYear(day, now))
dayString = day.toLocaleFormat('%A, %B %d');
else
dayString = day.toLocaleFormat('%A, %B %d, %Y');
this._addPeriod(dayString, dayBegin, dayEnd, false, true);
},
_showToday: function() {
this.actor.destroy_children();
let now = new Date();
let dayBegin = _getBeginningOfDay(now);
let dayEnd = _getEndOfDay(now);
this._addPeriod(_("Today"), dayBegin, dayEnd, false, true);
let tomorrowBegin = new Date(dayBegin.getTime() + 86400 * 1000);
let tomorrowEnd = new Date(dayEnd.getTime() + 86400 * 1000);
this._addPeriod(_("Tomorrow"), tomorrowBegin, tomorrowEnd, false, true);
if (dayEnd.getDay() <= 4 + this._weekStart) {
/* If now is within the first 5 days we show "This week" and
* include events up until and including Saturday/Sunday
* (depending on whether a week starts on Sunday/Monday).
*/
let thisWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000);
let thisWeekEnd = new Date(dayEnd.getTime() + (6 + this._weekStart - dayEnd.getDay()) * 86400 * 1000);
this._addPeriod(_("This week"), thisWeekBegin, thisWeekEnd, true, false);
} else {
/* otherwise it's one of the two last days of the week ... show
* "Next week" and include events up until and including *next*
* Saturday/Sunday
*/
let nextWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000);
let nextWeekEnd = new Date(dayEnd.getTime() + (13 + this._weekStart - dayEnd.getDay()) * 86400 * 1000);
this._addPeriod(_("Next week"), nextWeekBegin, nextWeekEnd, true, false);
}
},
// Sets the event list to show events from a specific date
setDate: function(date) {
if (!_sameDay(date, this._date)) {
this._date = date;
this._update();
}
},
_update: function() {
let today = new Date();
if (_sameDay (this._date, today)) {
this._showToday();
} else {
this._showOtherDay(this._date);
}
}
};

254
js/ui/ctrlAltTab.js Normal file
View File

@ -0,0 +1,254 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Gdk = imports.gi.Gdk;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const AltTab = imports.ui.altTab;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const POPUP_APPICON_SIZE = 96;
const POPUP_FADE_TIME = 0.1; // seconds
function CtrlAltTabManager() {
this._init();
}
CtrlAltTabManager.prototype = {
_init: function() {
this._items = [];
this._focusManager = St.FocusManager.get_for_stage(global.stage);
Main.wm.setKeybindingHandler('switch_panels', Lang.bind(this,
function (shellwm, binding, window, backwards) {
this.popup(backwards);
}));
},
addGroup: function(root, name, icon) {
this._items.push({ root: root, name: name, iconName: icon });
root.connect('destroy', Lang.bind(this, function() { this.removeGroup(root); }));
this._focusManager.add_group(root);
},
removeGroup: function(root) {
this._focusManager.remove_group(root);
for (let i = 0; i < this._items.length; i++) {
if (this._items[i].root == root) {
this._items.splice(i, 1);
return;
}
}
},
focusGroup: function(root) {
if (global.stage_input_mode == Shell.StageInputMode.NONREACTIVE ||
global.stage_input_mode == Shell.StageInputMode.NORMAL)
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
root.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
},
popup: function(backwards) {
// Start with the set of focus groups that are currently mapped
let items = this._items.filter(function (item) { return item.root.mapped; });
// And add the windows metacity would show in its Ctrl-Alt-Tab list
let screen = global.screen;
let display = screen.get_display();
let windows = display.get_tab_list(Meta.TabList.DOCKS, screen, screen.get_active_workspace ());
let windowTracker = Shell.WindowTracker.get_default();
let textureCache = St.TextureCache.get_default();
for (let i = 0; i < windows.length; i++) {
let icon;
let app = windowTracker.get_window_app(windows[i]);
if (app)
icon = app.create_icon_texture(POPUP_APPICON_SIZE);
else
icon = textureCache.bind_pixbuf_property(windows[i], 'icon');
items.push({ window: windows[i],
name: windows[i].title,
iconActor: icon });
}
if (!items.length)
return;
new CtrlAltTabPopup().show(items, backwards);
}
};
function mod(a, b) {
return (a + b) % b;
}
function CtrlAltTabPopup() {
this._init();
}
CtrlAltTabPopup.prototype = {
_init : function() {
let primary = global.get_primary_monitor();
this.actor = new St.BoxLayout({ name: 'ctrlAltTabPopup',
reactive: true,
x: primary.x + primary.width / 2,
y: primary.y + primary.height / 2,
anchor_gravity: Clutter.Gravity.CENTER });
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._haveModal = false;
this._selection = 0;
Main.uiGroup.add_actor(this.actor);
},
show : function(items, startBackwards) {
if (!Main.pushModal(this.actor))
return false;
this._haveModal = true;
this._keyPressEventId = this.actor.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
this._keyReleaseEventId = this.actor.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
this._items = items;
this._switcher = new CtrlAltTabSwitcher(items);
this.actor.add_actor(this._switcher.actor);
if (startBackwards)
this._selection = this._items.length - 1;
this._select(this._selection);
let [x, y, mods] = global.get_pointer();
if (!(mods & Gdk.ModifierType.MOD1_MASK)) {
this._finish();
return false;
}
this.actor.opacity = 0;
this.actor.show();
Tweener.addTween(this.actor,
{ opacity: 255,
time: POPUP_FADE_TIME,
transition: 'easeOutQuad'
});
return true;
},
_next : function() {
return mod(this._selection + 1, this._items.length);
},
_previous : function() {
return mod(this._selection - 1, this._items.length);
},
_keyPressEvent : function(actor, event) {
let keysym = event.get_key_symbol();
let shift = (Shell.get_event_state(event) & Clutter.ModifierType.SHIFT_MASK);
if (shift && keysym == Clutter.KEY_Tab)
keysym = Clutter.ISO_Left_Tab;
if (keysym == Clutter.KEY_Escape)
this.destroy();
else if (keysym == Clutter.KEY_Tab)
this._select(this._next());
else if (keysym == Clutter.KEY_ISO_Left_Tab)
this._select(this._previous());
else if (keysym == Clutter.KEY_Left)
this._select(this._previous());
else if (keysym == Clutter.KEY_Right)
this._select(this._next());
return true;
},
_keyReleaseEvent : function(actor, event) {
let [x, y, mods] = global.get_pointer();
let state = mods & Clutter.ModifierType.MOD1_MASK;
if (state == 0)
this._finish();
return true;
},
_finish : function() {
this.destroy();
let item = this._items[this._selection];
if (item.root)
Main.ctrlAltTabManager.focusGroup(item.root);
else
Main.activateWindow(item.window);
},
_popModal: function() {
if (this._haveModal) {
Main.popModal(this.actor);
this._haveModal = false;
}
},
destroy : function() {
this._popModal();
Tweener.addTween(this.actor,
{ opacity: 0,
time: POPUP_FADE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this.actor.destroy();
})
});
},
_onDestroy : function() {
if (this._keyPressEventId)
this.actor.disconnect(this._keyPressEventId);
if (this._keyReleaseEventId)
this.actor.disconnect(this._keyReleaseEventId);
},
_select : function(num) {
this._selection = num;
this._switcher.highlight(num);
}
};
function CtrlAltTabSwitcher(items) {
this._init(items);
}
CtrlAltTabSwitcher.prototype = {
__proto__ : AltTab.SwitcherList.prototype,
_init : function(items) {
AltTab.SwitcherList.prototype._init.call(this, true);
for (let i = 0; i < items.length; i++)
this._addIcon(items[i]);
},
_addIcon : function(item) {
let box = new St.BoxLayout({ style_class: 'alt-tab-app',
vertical: true });
let icon = item.iconActor;
if (!icon) {
icon = new St.Icon({ icon_name: item.iconName,
icon_type: St.IconType.SYMBOLIC,
icon_size: POPUP_APPICON_SIZE });
}
box.add(icon, { x_fill: false, y_fill: false } );
let text = new St.Label({ text: item.name });
box.add(text, { x_fill: false });
this.addItem(box);
}
};

File diff suppressed because it is too large Load Diff

212
js/ui/dateMenu.js Normal file
View File

@ -0,0 +1,212 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Util = imports.misc.util;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Calendar = imports.ui.calendar;
// in org.gnome.desktop.interface
const CLOCK_FORMAT_KEY = 'clock-format';
// in org.gnome.shell.clock
const CLOCK_SHOW_DATE_KEY = 'show-date';
const CLOCK_SHOW_SECONDS_KEY = 'show-seconds';
function _onVertSepRepaint (area)
{
let cr = area.get_context();
let themeNode = area.get_theme_node();
let [width, height] = area.get_surface_size();
let stippleColor = new Clutter.Color();
let stippleWidth = themeNode.get_length('-stipple-width');
let x = Math.floor(width/2) + 0.5;
themeNode.lookup_color('-stipple-color', false, stippleColor);
cr.moveTo(x, 0);
cr.lineTo(x, height);
Clutter.cairo_set_source_color(cr, stippleColor);
cr.setDash([1, 3], 1); // Hard-code for now
cr.setLineWidth(stippleWidth);
cr.stroke();
};
function DateMenuButton() {
this._init();
}
DateMenuButton.prototype = {
__proto__: PanelMenu.Button.prototype,
_init: function() {
let item;
let hbox;
let vbox;
//this._eventSource = new Calendar.EmptyEventSource();
//this._eventSource = new Calendar.FakeEventSource();
this._eventSource = new Calendar.EvolutionEventSource();
PanelMenu.Button.prototype._init.call(this, St.Align.START);
this._clock = new St.Label();
this.actor.set_child(this._clock);
hbox = new St.BoxLayout({name: 'calendarArea'});
this.menu.addActor(hbox);
// Fill up the first column
vbox = new St.BoxLayout({vertical: true});
hbox.add(vbox);
// Date
this._date = new St.Label();
this._date.style_class = 'datemenu-date-label';
vbox.add(this._date);
this._eventList = new Calendar.EventsList(this._eventSource);
// Calendar
this._calendar = new Calendar.Calendar(this._eventSource);
this._calendar.connect('selected-date-changed',
Lang.bind(this, function(calendar, date) {
this._eventList.setDate(date);
}));
vbox.add(this._calendar.actor);
item = new PopupMenu.PopupSeparatorMenuItem();
item.setColumnWidths(1);
vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
item = new PopupMenu.PopupMenuItem(_("Date and Time Settings"));
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
vbox.add(item.actor);
// Add vertical separator
item = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
pseudo_class: 'highlighted' });
item.connect('repaint', Lang.bind(this, _onVertSepRepaint));
hbox.add(item);
// Fill up the second column
vbox = new St.BoxLayout({vertical: true});
hbox.add(vbox);
// Event list
vbox.add(this._eventList.actor);
item = new PopupMenu.PopupMenuItem(_("Open Calendar"));
item.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
// Whenever the menu is opened, select today
this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
if (isOpen) {
let now = new Date();
this._calendar.setDate(now);
// No need to update this._eventList as ::selected-date-changed
// signal will fire
}
}));
// Done with hbox for calendar and event list
// Track changes to clock settings
this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
this._clockSettings = new Gio.Settings({ schema: 'org.gnome.shell.clock' });
this._desktopSettings.connect('changed', Lang.bind(this, this._updateClockAndDate));
this._clockSettings.connect('changed', Lang.bind(this, this._updateClockAndDate));
// Start the clock
this._updateClockAndDate();
},
_updateClockAndDate: function() {
let format = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);
let showDate = this._clockSettings.get_boolean(CLOCK_SHOW_DATE_KEY);
let showSeconds = this._clockSettings.get_boolean(CLOCK_SHOW_SECONDS_KEY);
let clockFormat;
let dateFormat;
switch (format) {
case '24h':
if (showDate)
/* Translators: This is the time format with date used
in 24-hour mode. */
clockFormat = showSeconds ? _("%a %b %e, %R:%S")
: _("%a %b %e, %R");
else
/* Translators: This is the time format without date used
in 24-hour mode. */
clockFormat = showSeconds ? _("%a %R:%S")
: _("%a %R");
break;
case '12h':
default:
if (showDate)
/* Translators: This is a time format with date used
for AM/PM. */
clockFormat = showSeconds ? _("%a %b %e, %l:%M:%S %p")
: _("%a %b %e, %l:%M %p");
else
/* Translators: This is a time format without date used
for AM/PM. */
clockFormat = showSeconds ? _("%a %l:%M:%S %p")
: _("%a %l:%M %p");
break;
}
let displayDate = new Date();
let msecRemaining;
if (showSeconds) {
msecRemaining = 1000 - displayDate.getMilliseconds();
if (msecRemaining < 50) {
displayDate.setSeconds(displayDate.getSeconds() + 1);
msecRemaining += 1000;
}
} else {
msecRemaining = 60000 - (1000 * displayDate.getSeconds() +
displayDate.getMilliseconds());
if (msecRemaining < 500) {
displayDate.setMinutes(displayDate.getMinutes() + 1);
msecRemaining += 60000;
}
}
this._clock.set_text(displayDate.toLocaleFormat(clockFormat));
/* Translators: This is the date format to use when the calendar popup is
* shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
*/
dateFormat = _("%A %B %e, %Y");
this._date.set_text(displayDate.toLocaleFormat(dateFormat));
Mainloop.timeout_add(msecRemaining, Lang.bind(this, this._updateClockAndDate));
return false;
},
_onPreferencesActivate: function() {
this.menu.close();
Util.spawnDesktop('gnome-datetime-panel');
},
_onOpenCalendarActivate: function() {
this.menu.close();
// TODO: pass '-c calendar' (to force the calendar at startup)
// TODO: pass the selected day
Util.spawnDesktop('evolution');
},
};

View File

@ -26,9 +26,9 @@ const DragMotionResult = {
};
const DRAG_CURSOR_MAP = {
0: Shell.Cursor.UNSUPPORTED_TARGET,
1: Shell.Cursor.COPY,
2: Shell.Cursor.MOVE
0: Shell.Cursor.DND_UNSUPPORTED_TARGET,
1: Shell.Cursor.DND_COPY,
2: Shell.Cursor.DND_MOVE
};
const DragDropResult = {
@ -100,6 +100,8 @@ _Draggable.prototype = {
this._buttonDown = false; // The mouse button has been pressed and has not yet been released.
this._dragInProgress = false; // The drag has been started, and has not been dropped or cancelled yet.
this._animationInProgress = false; // The drag is over and the item is in the process of animating to its original position (snapping back or reverting).
this._eventsGrabbed = false;
},
_onButtonPress : function (actor, event) {
@ -147,13 +149,19 @@ _Draggable.prototype = {
},
_grabEvents: function() {
Clutter.grab_pointer(_getEventHandlerActor());
Clutter.grab_keyboard(_getEventHandlerActor());
if (!this._eventsGrabbed) {
Clutter.grab_pointer(_getEventHandlerActor());
Clutter.grab_keyboard(_getEventHandlerActor());
this._eventsGrabbed = true;
}
},
_ungrabEvents: function() {
Clutter.ungrab_pointer();
Clutter.ungrab_keyboard();
if (this._eventsGrabbed) {
Clutter.ungrab_pointer();
Clutter.ungrab_keyboard();
this._eventsGrabbed = false;
}
},
_onEvent: function(actor, event) {
@ -213,7 +221,7 @@ _Draggable.prototype = {
if (this._onEventId)
this._ungrabActor();
this._grabEvents();
global.set_cursor(Shell.Cursor.IN_DRAG);
global.set_cursor(Shell.Cursor.DND_IN_DRAG);
this._dragX = this._dragStartX = stageX;
this._dragY = this._dragStartY = stageY;
@ -374,7 +382,7 @@ _Draggable.prototype = {
}
target = target.get_parent();
}
global.set_cursor(Shell.Cursor.IN_DRAG);
global.set_cursor(Shell.Cursor.DND_IN_DRAG);
}
return true;
@ -440,24 +448,44 @@ _Draggable.prototype = {
return true;
},
// Get position of the drag actor's source if the source is still around,
// or return the original location if the actor itself was being dragged
// or the source is no longer around.
_getRestoreLocation: function() {
let locX = this._snapBackX;
let locY = this._snapBackY;
let x, y, scale;
if (this._dragActorSource && this._dragActorSource.visible)
[locX, locY] = this._dragActorSource.get_transformed_position();
return [locX, locY];
if (this._dragActorSource && this._dragActorSource.visible) {
// Snap the clone back to its source
[x, y] = this._dragActorSource.get_transformed_position();
let [sourceScaledWidth, sourceScaledHeight] = this._dragActorSource.get_transformed_size();
scale = this._dragActor.width / sourceScaledWidth;
} else if (this._dragOrigParent) {
// Snap the actor back to its original position within
// its parent, adjusting for the fact that the parent
// may have been moved or scaled
let [parentX, parentY] = this._dragOrigParent.get_transformed_position();
x = parentX + this._dragOrigParent.scale_x * this._dragOrigX;
y = parentY + this._dragOrigParent.scale_y * this._dragOrigY;
let [parentWidth, parentHeight] = this._dragOrigParent.get_size();
let [parentScaledWidth, parentScaledHeight] = this._dragOrigParent.get_transformed_size();
let parentScale = parentScaledWidth / parentWidth;
scale = this._dragOrigScale * parentScale;
} else {
// Snap back actor to its original stage position
x = this._snapBackX;
y = this._snapBackY;
scale = this._snapBackScale;
}
return [x, y, scale];
},
_cancelDrag: function(eventTime) {
this._dragInProgress = false;
let [snapBackX, snapBackY] = this._getRestoreLocation();
let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation();
if (this._actorDestroyed) {
global.unset_cursor();
if (!this._buttonDown)
this._ungrabEvents();
this.emit('drag-end', eventTime, false);
return;
}
@ -467,8 +495,8 @@ _Draggable.prototype = {
Tweener.addTween(this._dragActor,
{ x: snapBackX,
y: snapBackY,
scale_x: this._snapBackScale,
scale_y: this._snapBackScale,
scale_x: snapBackScale,
scale_y: snapBackScale,
opacity: this._dragOrigOpacity,
time: SNAP_BACK_ANIMATION_TIME,
transition: 'easeOutQuad',
@ -480,11 +508,11 @@ _Draggable.prototype = {
_restoreDragActor: function(eventTime) {
this._dragInProgress = false;
[restoreX, restoreY] = this._getRestoreLocation();
[restoreX, restoreY, restoreScale] = this._getRestoreLocation();
// fade the actor back in at its original location
this._dragActor.set_position(restoreX, restoreY);
this._dragActor.set_scale(this._snapBackScale, this._snapBackScale);
this._dragActor.set_scale(restoreScale, restoreScale);
this._dragActor.opacity = 0;
this._animationInProgress = true;

View File

@ -1,487 +1,11 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const Mainloop = imports.mainloop;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const DocInfo = imports.misc.docInfo;
const DND = imports.ui.dnd;
const GenericDisplay = imports.ui.genericDisplay;
const Main = imports.ui.main;
const Search = imports.ui.search;
const MAX_DASH_DOCS = 50;
const DASH_DOCS_ICON_SIZE = 16;
const DEFAULT_SPACING = 4;
/* This class represents a single display item containing information about a document.
* We take the current number of seconds in the constructor to avoid looking up the current
* time for every item when they are created in a batch.
*
* docInfo - DocInfo object containing information about the document
* currentSeconds - current number of seconds since the epoch
*/
function DocDisplayItem(docInfo, currentSecs) {
this._init(docInfo, currentSecs);
}
DocDisplayItem.prototype = {
__proto__: GenericDisplay.GenericDisplayItem.prototype,
_init : function(docInfo, currentSecs) {
GenericDisplay.GenericDisplayItem.prototype._init.call(this);
this._docInfo = docInfo;
this._setItemInfo(docInfo.name, '');
this._timeoutTime = -1;
this._resetTimeDisplay(currentSecs);
},
//// Public methods ////
getUpdateTimeoutTime: function() {
return this._timeoutTime;
},
// Update any relative-time based displays for this item.
redisplay: function(currentSecs) {
this._resetTimeDisplay(currentSecs);
},
//// Public method overrides ////
// Opens a document represented by this display item.
launch : function() {
this._docInfo.launch();
},
//// Protected method overrides ////
// Returns an icon for the item.
_createIcon : function() {
return this._docInfo.createIcon(GenericDisplay.ITEM_DISPLAY_ICON_SIZE);
},
// Returns a preview icon for the item.
_createPreviewIcon : function() {
return this._docInfo.createIcon(GenericDisplay.PREVIEW_ICON_SIZE);
},
// Creates and returns a large preview icon, but only if this._docInfo is an image file
// and we were able to generate a pixbuf from it successfully.
_createLargePreviewIcon : function() {
if (this._docInfo.mimeType == null || this._docInfo.mimeType.indexOf('image/') != 0)
return null;
try {
return St.TextureCache.get_default().load_uri_sync(St.TextureCachePolicy.NONE,
this._docInfo.uri, -1, -1);
} catch (e) {
// An exception will be raised when the image format isn't know
/* FIXME: http://bugzilla.gnome.org/show_bug.cgi?id=591480: should
* only ignore GDK_PIXBUF_ERROR_UNKNOWN_TYPE. */
return null;
}
},
//// Drag and Drop ////
shellWorkspaceLaunch: function() {
this.launch();
},
//// Private Methods ////
// Updates the last visited time displayed in the description text for the item.
_resetTimeDisplay: function(currentSecs) {
let lastSecs = this._docInfo.timestamp;
let timeDelta = currentSecs - lastSecs;
let [text, nextUpdate] = global.format_time_relative_pretty(timeDelta);
this._timeoutTime = currentSecs + nextUpdate;
this._setDescriptionText(text);
}
};
/* This class represents a display containing a collection of document items.
* The documents are sorted by how recently they were last visited.
*/
function DocDisplay() {
this._init();
}
DocDisplay.prototype = {
__proto__: GenericDisplay.GenericDisplay.prototype,
_init : function() {
GenericDisplay.GenericDisplay.prototype._init.call(this);
// We keep a single timeout callback for updating last visited times
// for all the items in the display. This avoids creating individual
// callbacks for each item in the display. So proper time updates
// for individual items and item details depend on the item being
// associated with one of the displays.
this._updateTimeoutTargetTime = -1;
this._updateTimeoutId = 0;
this._docManager = DocInfo.getDocManager();
this._docsStale = true;
this._docManager.connect('changed', Lang.bind(this, function(mgr, userData) {
this._docsStale = true;
// Changes in local recent files should not happen when we are in the Overview mode,
// but redisplaying right away is cool when we use Zephyr.
// Also, we might be displaying remote documents, like Google Docs, in the future
// which might be edited by someone else.
this._redisplay(GenericDisplay.RedisplayFlags.NONE);
}));
this.connect('destroy', Lang.bind(this, function (o) {
if (this._updateTimeoutId > 0)
Mainloop.source_remove(this._updateTimeoutId);
}));
},
//// Protected method overrides ////
// Gets the list of recent items from the recent items manager.
_refreshCache : function() {
if (!this._docsStale)
return true;
this._allItems = {};
Lang.copyProperties(this._docManager.getInfosByUri(), this._allItems);
this._docsStale = false;
return false;
},
// Sets the list of the displayed items based on how recently they were last visited.
_setDefaultList : function() {
// It seems to be an implementation detail of the Mozilla JavaScript that object
// properties are returned during the iteration in the same order in which they were
// defined, but it is not a guarantee according to this
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Statements/for...in
// While this._allItems associative array seems to always be ordered by last added,
// as the results of this._recentManager.get_items() based on which it is constructed are,
// we should do the sorting manually because we want the order to be based on last visited.
//
// This function is called each time the search string is set back to '' or we display
// the Overview, so we are doing the sorting over the same items multiple times if the list
// of recent items didn't change. We could store an additional array of doc ids and sort
// them once when they are returned by this._recentManager.get_items() to avoid having to do
// this sorting each time, but the sorting seems to be very fast anyway, so there is no need
// to introduce an additional class variable.
this._matchedItems = {};
this._matchedItemKeys = [];
let docIdsToRemove = [];
for (docId in this._allItems) {
this._matchedItems[docId] = 1;
this._matchedItemKeys.push(docId);
}
for (docId in docIdsToRemove) {
delete this._allItems[docId];
}
this._matchedItemKeys.sort(Lang.bind(this, this._compareItems));
},
// Compares items associated with the item ids based on how recently the items
// were last visited.
// Returns an integer value indicating the result of the comparison.
_compareItems : function(itemIdA, itemIdB) {
let docA = this._allItems[itemIdA];
let docB = this._allItems[itemIdB];
return docB.timestamp - docA.timestamp;
},
// Checks if the item info can be a match for the search string by checking
// the name of the document. Item info is expected to be GtkRecentInfo.
// Returns a boolean flag indicating if itemInfo is a match.
_isInfoMatching : function(itemInfo, search) {
if (!itemInfo.exists())
return false;
if (search == null || search == '')
return true;
let name = itemInfo.name.toLowerCase();
if (name.indexOf(search) >= 0)
return true;
// TODO: we can also check doc URIs, so that
// if you search for a directory name, we display recent files from it
return false;
},
// Creates a DocDisplayItem based on itemInfo, which is expected to be a DocInfo object.
_createDisplayItem: function(itemInfo) {
let currentSecs = new Date().getTime() / 1000;
let docDisplayItem = new DocDisplayItem(itemInfo, currentSecs);
this._updateTimeoutCallback(docDisplayItem, currentSecs);
return docDisplayItem;
},
//// Private Methods ////
// A callback function that redisplays the items, updating their descriptions,
// and sets up a new timeout callback.
_docTimeout: function () {
let currentSecs = new Date().getTime() / 1000;
this._updateTimeoutId = 0;
this._updateTimeoutTargetTime = -1;
for (let docId in this._displayedItems) {
let docDisplayItem = this._displayedItems[docId];
docDisplayItem.redisplay(currentSecs);
this._updateTimeoutCallback(docDisplayItem, currentSecs);
}
return false;
},
// Updates the timeout callback if the timeout time for the docDisplayItem
// is earlier than the target time for the current timeout callback.
_updateTimeoutCallback: function (docDisplayItem, currentSecs) {
let timeoutTime = docDisplayItem.getUpdateTimeoutTime();
if (this._updateTimeoutTargetTime < 0 || timeoutTime < this._updateTimeoutTargetTime) {
if (this._updateTimeoutId > 0)
Mainloop.source_remove(this._updateTimeoutId);
this._updateTimeoutId = Mainloop.timeout_add_seconds(timeoutTime - currentSecs, Lang.bind(this, this._docTimeout));
this._updateTimeoutTargetTime = timeoutTime;
}
}
};
Signals.addSignalMethods(DocDisplay.prototype);
function DashDocDisplayItem(docInfo) {
this._init(docInfo);
}
DashDocDisplayItem.prototype = {
_init: function(docInfo) {
this._info = docInfo;
this._icon = docInfo.createIcon(DASH_DOCS_ICON_SIZE);
this.actor = new St.Clickable({ style_class: 'recent-docs-item',
reactive: true,
x_align: St.Align.START });
let box = new St.BoxLayout({ style_class: 'recent-docs-item-box' });
this.actor.set_child(box);
box.add(this._icon);
let text = new St.Label({ text: docInfo.name });
box.add(text);
this.actor.connect('clicked', Lang.bind(this, function () {
docInfo.launch();
Main.overview.hide();
}));
this.actor._delegate = this;
let draggable = DND.makeDraggable(this.actor);
draggable.connect('drag-begin',
Lang.bind(this, function() {
Main.overview.beginItemDrag(this);
}));
draggable.connect('drag-end',
Lang.bind(this, function() {
Main.overview.endItemDrag(this);
}));
},
getUri: function() {
return this._info.uri;
},
getDragActorSource: function() {
return this._icon;
},
getDragActor: function(stageX, stageY) {
this.dragActor = this._info.createIcon(DASH_DOCS_ICON_SIZE);
return this.dragActor;
},
//// Drag and drop functions ////
shellWorkspaceLaunch: function () {
this._info.launch();
}
};
/**
* Class used to display two column recent documents in the dash
*/
function DashDocDisplay() {
this._init();
}
DashDocDisplay.prototype = {
_init: function() {
this.actor = new Shell.GenericContainer();
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
this.actor.connect('allocate', Lang.bind(this, this._allocate));
this._workId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay));
this._actorsByUri = {};
this._docManager = DocInfo.getDocManager();
this._docManager.connect('changed', Lang.bind(this, this._onDocsChanged));
this._pendingDocsChange = true;
this._checkDocExistence = false;
},
_getPreferredWidth: function(actor, forHeight, alloc) {
let children = actor.get_children();
// We use two columns maximum. Just take the min and natural size of the
// first two items, even though strictly speaking it's not correct; we'd
// need to calculate how many items we could fit for the height, then
// take the biggest preferred width for each column.
// In practice the dash gets a fixed width anyways.
// If we have one child, add its minimum and natural size
if (children.length > 0) {
let [minSize, naturalSize] = children[0].get_preferred_width(forHeight);
alloc.min_size += minSize;
alloc.natural_size += naturalSize;
}
// If we have two, add its size, plus DEFAULT_SPACING
if (children.length > 1) {
let [minSize, naturalSize] = children[1].get_preferred_width(forHeight);
alloc.min_size += DEFAULT_SPACING + minSize;
alloc.natural_size += DEFAULT_SPACING + naturalSize;
}
},
_getPreferredHeight: function(actor, forWidth, alloc) {
let children = actor.get_children();
// The width of an item is our allocated width, minus spacing, divided in half.
this._itemWidth = Math.floor((forWidth - DEFAULT_SPACING) / 2);
let maxNatural = 0;
for (let i = 0; i < children.length; i++) {
let child = children[i];
let [minSize, naturalSize] = child.get_preferred_height(this._itemWidth);
maxNatural = Math.max(maxNatural, naturalSize);
}
this._itemHeight = maxNatural;
let firstColumnChildren = Math.ceil(children.length / 2);
alloc.natural_size = (firstColumnChildren * maxNatural +
(firstColumnChildren - 1) * DEFAULT_SPACING);
},
_allocate: function(actor, box, flags) {
let width = box.x2 - box.x1;
let height = box.y2 - box.y1;
// Make sure this._itemWidth/Height have been computed, even
// if the parent actor didn't check our size before allocating.
// (Not clear if that is required or not as a Clutter
// invariant; this is safe and cheap because of caching.)
actor.get_preferred_height(width);
let children = actor.get_children();
let x = 0;
let y = 0;
let columnIndex = 0;
let i = 0;
// Loop over the children, going vertically down first. When we run
// out of vertical space (our y variable is bigger than box.y2), switch
// to the second column.
while (i < children.length) {
let child = children[i];
if (y + this._itemHeight > box.y2) {
// Is this the second column, or we're in
// the first column and can't even fit one
// item? In that case, break.
if (columnIndex == 1 || i == 0) {
break;
}
// Set x to the halfway point.
columnIndex += 1;
x = x + this._itemWidth + DEFAULT_SPACING;
// And y is back to the top.
y = 0;
// Retry this same item, now that we're in the second column.
// By looping back to the top here, we re-test the size
// again for the second column.
continue;
}
let childBox = new Clutter.ActorBox();
childBox.x1 = x;
childBox.y1 = y;
childBox.x2 = childBox.x1 + this._itemWidth;
childBox.y2 = y + this._itemHeight;
y = childBox.y2 + DEFAULT_SPACING;
child.allocate(childBox, flags);
this.actor.set_skip_paint(child, false);
i++;
}
if (this._checkDocExistence) {
// Now we know how many docs we are displaying, queue a check to see if any of them
// have been deleted. If they are deleted, then we'll get a 'changed' signal; since
// we'll now be displaying items we weren't previously, we'll check again to see
// if they were deleted, and so forth and so on.
// TODO: We should change this to ask for as many as we can fit in the given space:
// https://bugzilla.gnome.org/show_bug.cgi?id=603522#c23
this._docManager.queueExistenceCheck(i);
this._checkDocExistence = false;
}
for (; i < children.length; i++)
this.actor.set_skip_paint(children[i], true);
},
_onDocsChanged: function() {
this._checkDocExistence = true;
Main.queueDeferredWork(this._workId);
},
_redisplay: function() {
// Should be kept alive by the _actorsByUri
this.actor.remove_all();
let docs = this._docManager.getTimestampOrderedInfos();
for (let i = 0; i < docs.length && i < MAX_DASH_DOCS; i++) {
let doc = docs[i];
let display = this._actorsByUri[doc.uri];
if (display) {
this.actor.add_actor(display.actor);
} else {
let display = new DashDocDisplayItem(doc);
this.actor.add_actor(display.actor);
this._actorsByUri[doc.uri] = display;
}
}
// Any unparented actors must have been deleted
for (let uri in this._actorsByUri) {
let display = this._actorsByUri[uri];
if (display.actor.get_parent() == null) {
display.actor.destroy();
delete this._actorsByUri[uri];
}
}
this.emit('changed');
}
};
Signals.addSignalMethods(DashDocDisplay.prototype);
function DocSearchProvider() {
this._init();

504
js/ui/endSessionDialog.js Normal file
View File

@ -0,0 +1,504 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*-
*
* Copyright 2010 Red Hat, Inc
*
* 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, 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.
*/
const DBus = imports.dbus;
const Lang = imports.lang;
const Signals = imports.signals;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Clutter = imports.gi.Clutter;
const Gdm = imports.gi.Gdm;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Pango = imports.gi.Pango;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const GnomeSession = imports.misc.gnomeSession
const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const Tweener = imports.ui.tweener;
let _endSessionDialog = null;
const _ITEM_ICON_SIZE = 48;
const _DIALOG_ICON_SIZE = 32;
const GSM_SESSION_MANAGER_LOGOUT_FORCE = 2;
const EndSessionDialogIface = {
name: 'org.gnome.SessionManager.EndSessionDialog',
methods: [{ name: 'Open',
inSignature: 'uuuao',
outSignature: ''
}
],
signals: [{ name: 'Canceled',
outSignature: '',
}],
properties: []
};
const logoutDialogContent = {
subjectWithUser: _("Log Out %s"),
subject: _("Log Out"),
inhibitedDescription: _("Click Log Out to quit these applications and log out of the system."),
uninhibitedDescriptionWithUser: _("%s will be logged out automatically in %d seconds."),
uninhibitedDescription: _("You will be logged out automatically in %d seconds."),
endDescription: _("Logging out of the system."),
confirmButtonText: _("Log Out"),
iconStyleClass: 'end-session-dialog-logout-icon'
};
const shutdownDialogContent = {
subject: _("Shut Down"),
inhibitedDescription: _("Click Shut Down to quit these applications and shut down the system."),
uninhibitedDescription: _("The system will shut down automatically in %d seconds."),
endDescription: _("Shutting down the system."),
confirmButtonText: _("Shut Down"),
iconName: 'system-shutdown',
iconStyleClass: 'end-session-dialog-shutdown-icon'
};
const restartDialogContent = {
subject: _("Restart"),
inhibitedDescription: _("Click Restart to quit these applications and restart the system."),
uninhibitedDescription: _("The system will restart automatically in %d seconds."),
endDescription: _("Restarting the system."),
confirmButtonText: _("Restart"),
iconName: 'system-shutdown',
iconStyleClass: 'end-session-dialog-shutdown-icon'
};
const DialogContent = {
0 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_LOGOUT */: logoutDialogContent,
1 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_SHUTDOWN */: shutdownDialogContent,
2 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_RESTART */: restartDialogContent
};
function findAppFromInhibitor(inhibitor) {
let desktopFile = inhibitor.app_id;
if (!GLib.str_has_suffix(desktopFile, '.desktop'))
desktopFile += '.desktop';
let candidateDesktopFiles = [];
candidateDesktopFiles.push(desktopFile);
candidateDesktopFiles.push('gnome-' + desktopFile);
let appSystem = Shell.AppSystem.get_default();
let app = null;
for (let i = 0; i < candidateDesktopFiles.length; i++) {
try {
app = appSystem.get_app(candidateDesktopFiles[i]);
if (app)
break;
} catch(e) {
// ignore errors
}
}
return app;
}
function ListItem(app, reason) {
this._init(app, reason);
}
ListItem.prototype = {
_init: function(app, reason) {
this._app = app;
this._reason = reason;
if (this._reason == null)
this._reason = '';
let layout = new St.BoxLayout({ vertical: false});
this.actor = new St.Clickable({ style_class: 'end-session-dialog-app-list-item',
can_focus: true,
child: layout,
reactive: true,
x_align: St.Align.START,
x_fill: true });
this._icon = this._app.create_icon_texture(_ITEM_ICON_SIZE);
let iconBin = new St.Bin({ style_class: 'end-session-dialog-app-list-item-icon',
child: this._icon });
layout.add(iconBin);
let textLayout = new St.BoxLayout({ style_class: 'end-session-dialog-app-list-item-text-box',
vertical: true });
layout.add(textLayout);
this._nameLabel = new St.Label({ text: this._app.get_name(),
style_class: 'end-session-dialog-app-list-item-name' });
textLayout.add(this._nameLabel,
{ expand: false,
x_fill: true });
this._descriptionLabel = new St.Label({ text: this._reason,
style_class: 'end-session-dialog-app-list-item-description' });
textLayout.add(this._descriptionLabel,
{ expand: true,
x_fill: true });
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
},
_onClicked: function() {
this.emit('activate');
this._app.activate();
}
};
Signals.addSignalMethods(ListItem.prototype);
// The logout timer only shows updates every 10 seconds
// until the last 10 seconds, then it shows updates every
// second. This function takes a given time and returns
// what we should show to the user for that time.
function _roundSecondsToInterval(totalSeconds, secondsLeft, interval) {
let time;
time = Math.ceil(secondsLeft);
// Final count down is in decrements of 1
if (time <= interval)
return time;
// Round up higher than last displayable time interval
time += interval - 1;
// Then round down to that time interval
if (time > totalSeconds)
time = Math.ceil(totalSeconds);
else
time -= time % interval;
return time;
}
function _setLabelText(label, text) {
if (text) {
label.set_text(text);
label.show();
} else {
label.set_text('');
label.hide();
}
}
function EndSessionDialog() {
if (_endSessionDialog == null) {
this._init();
DBus.session.exportObject('/org/gnome/SessionManager/EndSessionDialog',
this);
_endSessionDialog = this;
}
return _endSessionDialog;
}
function init() {
// This always returns the same singleton object
// By instantiating it initially, we register the
// bus object, etc.
let dialog = new EndSessionDialog();
}
EndSessionDialog.prototype = {
__proto__: ModalDialog.ModalDialog.prototype,
_init: function() {
ModalDialog.ModalDialog.prototype._init.call(this);
this._user = Gdm.UserManager.ref_default().get_user(GLib.get_user_name());
this._secondsLeft = 0;
this._totalSecondsToStayOpen = 0;
this._inhibitors = [];
this.connect('destroy',
Lang.bind(this, this._onDestroy));
this.connect('opened',
Lang.bind(this, this._onOpened));
this._userLoadedId = this._user.connect('notify::is_loaded',
Lang.bind(this, this._updateContent));
this._userChangedId = this._user.connect('changed',
Lang.bind(this, this._updateContent));
let mainContentLayout = new St.BoxLayout({ vertical: false });
this.contentLayout.add(mainContentLayout,
{ x_fill: true,
y_fill: false });
this._iconBin = new St.Bin();
mainContentLayout.add(this._iconBin,
{ x_fill: true,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.START });
let messageLayout = new St.BoxLayout({ vertical: true });
mainContentLayout.add(messageLayout,
{ y_align: St.Align.START });
this._subjectLabel = new St.Label({ style_class: 'end-session-dialog-subject' });
messageLayout.add(this._subjectLabel,
{ y_fill: false,
y_align: St.Align.START });
this._descriptionLabel = new St.Label({ style_class: 'end-session-dialog-description' });
this._descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._descriptionLabel.clutter_text.line_wrap = true;
messageLayout.add(this._descriptionLabel,
{ y_fill: true,
y_align: St.Align.START });
let scrollView = new St.ScrollView({ style_class: 'end-session-dialog-app-list'});
scrollView.set_policy(Gtk.PolicyType.NEVER,
Gtk.PolicyType.AUTOMATIC);
this.contentLayout.add(scrollView,
{ x_fill: true,
y_fill: true });
this._applicationList = new St.BoxLayout({ vertical: true });
scrollView.add_actor(this._applicationList,
{ x_fill: true,
y_fill: true,
x_align: St.Align.START,
y_align: St.Align.MIDDLE });
},
_onDestroy: function() {
this._user.disconnect(this._userLoadedId);
this._user.disconnect(this._userChangedId);
},
_setIconFromFile: function(iconFile, styleClass) {
if (styleClass)
this._iconBin.set_style_class_name(styleClass);
this._iconBin.set_style(null);
this._iconBin.child = null;
if (iconFile) {
this._iconBin.show();
this._iconBin.set_style('background-image: url("' + iconFile + '");');
} else {
this._iconBin.hide();
}
},
_setIconFromName: function(iconName, styleClass) {
if (styleClass)
this._iconBin.set_style_class_name(styleClass);
this._iconBin.set_style(null);
if (iconName != null) {
let textureCache = St.TextureCache.get_default();
let icon = textureCache.load_icon_name(this._iconBin.get_theme_node(),
iconName,
St.IconType.SYMBOLIC,
_DIALOG_ICON_SIZE);
this._iconBin.child = icon;
this._iconBin.show();
} else {
this._iconBin.child = null;
this._iconBin.hide();
}
},
_updateContent: function() {
if (this.state != ModalDialog.State.OPENING &&
this.state != ModalDialog.State.OPENED)
return;
let dialogContent = DialogContent[this._type];
let subject = dialogContent.subject;
let description;
if (this._user.is_loaded && !dialogContent.iconName) {
let iconFile = this._user.get_icon_file();
this._setIconFromFile(iconFile, dialogContent.iconStyleClass);
} else if (dialogContent.iconName) {
this._setIconFromName(dialogContent.iconName,
dialogContent.iconStyleClass);
}
if (this._inhibitors.length > 0) {
this._stopTimer();
description = dialogContent.inhibitedDescription;
} else if (this._secondsLeft > 0 && this._inhibitors.length == 0) {
let displayTime = _roundSecondsToInterval(this._totalSecondsToStayOpen,
this._secondsLeft,
10);
if (this._user.is_loaded) {
let realName = this._user.get_real_name();
if (realName != null) {
if (dialogContent.subjectWithUser)
subject = dialogContent.subjectWithUser.format(realName);
if (dialogContent.uninhibitedDescriptionWithUser)
description = dialogContent.uninhibitedDescriptionWithUser.format(realName, displayTime);
else
description = dialogContent.uninhibitedDescription.format(displayTime);
}
}
if (!description)
description = dialogContent.uninhibitedDescription.format(displayTime);
} else {
description = dialogContent.endDescription;
}
_setLabelText(this._subjectLabel, subject);
_setLabelText(this._descriptionLabel, description);
},
_updateButtons: function() {
if (this.state != ModalDialog.State.OPENING &&
this.state != ModalDialog.State.OPENED)
return;
let dialogContent = DialogContent[this._type];
let confirmButtonText = _("Confirm");
if (dialogContent.confirmButtonText)
confirmButtonText = dialogContent.confirmButtonText;
this.setButtons([{ label: _("Cancel"),
action: Lang.bind(this, this.cancel),
key: Clutter.Escape
},
{ label: confirmButtonText,
action: Lang.bind(this, this._confirm)
}]);
},
cancel: function() {
this._stopTimer();
DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
'org.gnome.SessionManager.EndSessionDialog',
'Canceled', '', []);
this.close(global.get_current_time());
},
_confirm: function() {
this._fadeOutDialog();
this._stopTimer();
DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
'org.gnome.SessionManager.EndSessionDialog',
'Confirmed', '', []);
},
_onOpened: function() {
if (this._inhibitors.length == 0)
this._startTimer();
},
_startTimer: function() {
this._secondsLeft = this._totalSecondsToStayOpen;
Tweener.addTween(this,
{ _secondsLeft: 0,
time: this._secondsLeft,
transition: 'linear',
onUpdate: Lang.bind(this, this._updateContent),
onComplete: Lang.bind(this, this._confirm),
});
},
_stopTimer: function() {
Tweener.removeTweens(this);
this._secondsLeft = 0;
},
_onInhibitorLoaded: function(inhibitor) {
if (this._inhibitors.indexOf(inhibitor) < 0) {
// Stale inhibitor
return;
}
let app = findAppFromInhibitor(inhibitor);
if (app) {
let item = new ListItem(app, inhibitor.reason);
item.connect('activate',
Lang.bind(this, function() {
this.close(global.get_current_time());
}));
this._applicationList.add(item.actor, { x_fill: true });
this._stopTimer();
} else {
// inhibiting app is a service, not an application
this._inhibitors.splice(this._inhibitors.indexOf(inhibitor), 1);
}
this._updateContent();
},
OpenAsync: function(type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths, callback) {
this._totalSecondsToStayOpen = totalSecondsToStayOpen;
this._inhibitors = [];
this._applicationList.remove_all();
this._type = type;
if (!(this._type in DialogContent))
throw new DBus.DBusError('org.gnome.Shell.ModalDialog.TypeError',
"Unknown dialog type requested");
for (let i = 0; i < inhibitorObjectPaths.length; i++) {
let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i]);
inhibitor.connect('is-loaded',
Lang.bind(this, function() {
this._onInhibitorLoaded(inhibitor);
}));
this._inhibitors.push(inhibitor);
}
if (!this.open(timestamp))
throw new DBus.DBusError('org.gnome.Shell.ModalDialog.GrabError',
"Cannot grab pointer and keyboard");
this._updateButtons();
this._updateContent();
let signalId = this.connect('opened',
Lang.bind(this, function() {
callback();
this.disconnect(signalId);
}));
}
};
DBus.conformExport(EndSessionDialog.prototype, EndSessionDialogIface);

View File

@ -4,7 +4,7 @@ const Clutter = imports.gi.Clutter;;
const GLib = imports.gi.GLib;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Gettext_gtk20 = imports.gettext.domain('gtk20');
const Gettext_gtk30 = imports.gettext.domain('gtk30');
const Tweener = imports.ui.tweener;
@ -65,7 +65,7 @@ function init() {
String.prototype.format = Format.format;
// Set the default direction for St widgets (this needs to be done before any use of St)
if (Gettext_gtk20.gettext('default:LTR') == 'default:RTL') {
if (Gettext_gtk30.gettext('default:LTR') == 'default:RTL') {
St.Widget.set_default_direction(St.TextDirection.RTL);
}
@ -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.Display.get_device_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.');

View File

@ -4,6 +4,8 @@ const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const St = imports.gi.St;
const Config = imports.misc.config;
const ExtensionState = {
ENABLED: 1,
DISABLED: 2,
@ -25,6 +27,36 @@ var disabledExtensions;
// GFile for user extensions
var userExtensionsDir = null;
/**
* versionCheck:
* @required: an array of versions we're compatible with
* @current: the version we have
*
* Check if a component is compatible for an extension.
* @required is an array, and at least one version must match.
* @current must be in the format <major>.<minor>.<point>.<micro>
* <micro> is always ignored
* <point> is ignored if <minor> is even (so you can target the
* whole stable release)
* <minor> and <major> must match
* Each target version must be at least <major> and <minor>
*/
function versionCheck(required, current) {
let currentArray = current.split('.');
let major = currentArray[0];
let minor = currentArray[1];
let point = currentArray[2];
for (let i = 0; i < required.length; i++) {
let requiredArray = required[i].split('.');
if (requiredArray[0] == major &&
requiredArray[1] == minor &&
(requiredArray[2] == point ||
(requiredArray[2] == undefined && parseInt(minor) % 2 == 0)))
return true;
}
return false;
}
function loadExtension(dir, enabled, type) {
let info;
let baseErrorString = 'While loading extension from "' + dir.get_parse_name() + '": ';
@ -43,8 +75,8 @@ function loadExtension(dir, enabled, type) {
global.logError(baseErrorString + 'Failed to parse metadata.json: ' + e);
return;
}
let requiredProperties = ['uuid', 'name', 'description'];
for (let i = 0; i < requiredProperties; i++) {
let requiredProperties = ['uuid', 'name', 'description', 'shell-version'];
for (let i = 0; i < requiredProperties.length; i++) {
let prop = requiredProperties[i];
if (!meta[prop]) {
global.logError(baseErrorString + 'missing "' + prop + '" property in metadata.json');
@ -68,6 +100,12 @@ function loadExtension(dir, enabled, type) {
return;
}
if (!versionCheck(meta['shell-version'], Config.PACKAGE_VERSION) ||
(meta['js-version'] && !versionCheck(meta['js-version'], Config.GJS_VERSION))) {
global.logError(baseErrorString + 'extension is not compatible with current GNOME Shell and/or GJS version');
return;
}
extensionMeta[meta.uuid] = meta;
extensionMeta[meta.uuid].type = type;
extensionMeta[meta.uuid].path = dir.get_path();

View File

@ -1,693 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Signals = imports.signals;
const St = imports.gi.St;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
const RedisplayFlags = { NONE: 0,
FULL: 1 << 1,
SUBSEARCH: 1 << 2,
IMMEDIATE: 1 << 3 };
// Used by subclasses
const ITEM_DISPLAY_ICON_SIZE = 48;
const PREVIEW_ICON_SIZE = 96;
/* This is a virtual class that represents a single display item containing
* a name, a description, and an icon. It allows selecting an item and represents
* it by highlighting it with a different background color than the default.
*/
function GenericDisplayItem() {
this._init();
}
GenericDisplayItem.prototype = {
_init: function() {
this.actor = new St.BoxLayout({ style_class: 'generic-display-item',
reactive: true });
this.actor._delegate = this;
this.actor.connect('button-release-event',
Lang.bind(this,
function() {
// Activates the item by launching it
this.emit('activate');
return true;
}));
let draggable = DND.makeDraggable(this.actor);
draggable.connect('drag-begin',
Lang.bind(this, function() {
Main.overview.beginItemDrag(this);
}));
draggable.connect('drag-end',
Lang.bind(this, function() {
Main.overview.endItemDrag(this);
}));
this._iconBin = new St.Bin();
this.actor.add(this._iconBin);
this._infoText = new St.BoxLayout({ style_class: 'generic-display-item-text',
vertical: true });
this.actor.add(this._infoText, { expand: true, y_fill: false });
this._name = null;
this._description = null;
this._icon = null;
this._initialLoadComplete = false;
// An array of details description actors that we create over time for the item.
// It is used for updating the description text inside the details actor when
// the description text for the item is updated.
this._detailsDescriptions = [];
},
//// Draggable object interface ////
// Returns a cloned texture of the item's icon to represent the item as it
// is being dragged.
getDragActor: function(stageX, stageY) {
return this._createIcon();
},
// Returns the item icon, a separate copy of which is used to
// represent the item as it is being dragged. This is used to
// determine a snap-back location for the drag icon if it does
// not get accepted by any drop target.
getDragActorSource: function() {
return this._icon;
},
//// Public methods ////
// Highlights the item by setting a different background color than the default
// if isSelected is true, removes the highlighting otherwise.
markSelected: function(isSelected) {
if (isSelected)
this.actor.add_style_pseudo_class('selected');
else
this.actor.remove_style_pseudo_class('selected');
},
/*
* Returns an actor containing item details. In the future details can have more information than what
* the preview pop-up has and be item-type specific.
*/
createDetailsActor: function() {
let details = new St.BoxLayout({ style_class: 'generic-display-container',
vertical: true });
let mainDetails = new St.BoxLayout({ style_class: 'generic-display-container' });
// Inner box with name and description
let textDetails = new St.BoxLayout({ style_class: 'generic-display-details',
vertical: true });
let detailsName = new St.Label({ style_class: 'generic-display-details-name',
text: this._name.text });
textDetails.add(detailsName);
let detailsDescription = new St.Label({ text: this._description.text });
textDetails.add(detailsDescription);
this._detailsDescriptions.push(detailsDescription);
mainDetails.add(textDetails, { expand: true });
let previewIcon = this._createPreviewIcon();
let largePreviewIcon = this._createLargePreviewIcon();
if (previewIcon != null && largePreviewIcon == null) {
mainDetails.insert_actor(previewIcon, 0);
}
details.add(mainDetails);
if (largePreviewIcon != null) {
details.add(largePreviewIcon);
}
return details;
},
// Destroys the item.
destroy: function() {
this.actor.destroy();
},
//// Pure virtual public methods ////
// Performes an action associated with launching this item, such as opening a file or an application.
launch: function() {
throw new Error('Not implemented');
},
//// Protected methods ////
/*
* Creates the graphical elements for the item based on the item information.
*
* nameText - name of the item
* descriptionText - short description of the item
*/
_setItemInfo: function(nameText, descriptionText) {
if (this._name != null) {
// this also removes this._name from the parent container,
// so we don't need to call this.actor.remove_actor(this._name) directly
this._name.destroy();
this._name = null;
}
if (this._description != null) {
this._description.destroy();
this._description = null;
}
if (this._icon != null) {
// though we get the icon from elsewhere, we assume its ownership here,
// and therefore should be responsible for distroying it
this._icon.destroy();
this._icon = null;
}
this._icon = this._createIcon();
this._iconBin.set_child(this._icon);
this._name = new St.Label({ style_class: 'generic-display-item-name',
text: nameText });
this._infoText.add(this._name);
this._description = new St.Label({ style_class: 'generic-display-item-description',
text: descriptionText ? descriptionText : '' });
this._infoText.add(this._description);
},
// Sets the description text for the item, including the description text
// in the details actors that have been created for the item.
_setDescriptionText: function(text) {
this._description.text = text;
for (let i = 0; i < this._detailsDescriptions.length; i++) {
let detailsDescription = this._detailsDescriptions[i];
if (detailsDescription != null) {
detailsDescription.text = text;
}
}
},
//// Virtual protected methods ////
// Creates and returns a large preview icon, but only if we have a detailed image.
_createLargePreviewIcon : function() {
return null;
},
//// Pure virtual protected methods ////
// Returns an icon for the item.
_createIcon: function() {
throw new Error('Not implemented');
},
// Returns a preview icon for the item.
_createPreviewIcon: function() {
throw new Error('Not implemented');
}
//// Private methods ////
};
Signals.addSignalMethods(GenericDisplayItem.prototype);
/* This is a virtual class that represents a display containing a collection of items
* that can be filtered with a search string.
*/
function GenericDisplay() {
this._init();
}
GenericDisplay.prototype = {
_init : function() {
this._search = '';
this._expanded = false;
this.actor = new St.ScrollView({ x_fill: true,
y_fill: false,
vshadows: true });
this._list = new St.BoxLayout({ style_class: 'generic-display-container',
vertical: true });
this.actor.add_actor(this._list);
this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
this._pendingRedisplay = RedisplayFlags.NONE;
this.actor.connect('notify::mapped', Lang.bind(this, this._onMappedNotify));
// map<itemId, Object> where Object represents the item info
this._allItems = {};
// set<itemId>
this._matchedItems = {};
// sorted array of items matched by search
this._matchedItemKeys = [];
// map<itemId, GenericDisplayItem>
this._displayedItems = {};
this._openDetailIndex = -1;
this._selectedIndex = -1;
},
//// Public methods ////
// Sets the search string and displays the matching items.
setSearch: function(text) {
let lowertext = text.toLowerCase();
if (lowertext == this._search) {
return;
}
let flags = RedisplayFlags.IMMEDIATE;
if (this._search != '') {
// Because we combine search terms with OR, we have to be sure that no new term
// was introduced before deciding that the new search results will be a subset of
// the existing search results.
if (lowertext.indexOf(this._search) == 0 &&
lowertext.split(/\s+/).length == this._search.split(/\s+/).length) {
flags |= RedisplayFlags.SUBSEARCH;
}
}
this._search = lowertext;
this._redisplay(flags);
},
// Launches the item that is currently selected, closing the Overview
activateSelected: function() {
if (this._selectedIndex != -1) {
let selected = this._findDisplayedByIndex(this._selectedIndex);
selected.launch();
this.unsetSelected();
Main.overview.hide();
}
},
// Moves the selection one up. If the selection was already on the top item, it's moved
// to the bottom one. Returns true if the selection actually moved up, false if it wrapped
// around to the bottom.
selectUp: function() {
let count = this._getVisibleCount();
let selectedUp = true;
let prev = this._selectedIndex - 1;
if (this._selectedIndex <= 0) {
prev = count - 1;
selectedUp = false;
}
this._selectIndex(prev);
return selectedUp;
},
// Moves the selection one down. If the selection was already on the bottom item, it's moved
// to the top one. Returns true if the selection actually moved down, false if it wrapped
// around to the top.
selectDown: function() {
let count = this._getVisibleCount();
let selectedDown = true;
let next = this._selectedIndex + 1;
if (this._selectedIndex == count - 1) {
next = 0;
selectedDown = false;
}
this._selectIndex(next);
return selectedDown;
},
// Selects the first item among the displayed items.
selectFirstItem: function() {
if (this.hasItems())
this._selectIndex(0);
},
// Selects the last item among the displayed items.
selectLastItem: function() {
let count = this._getVisibleCount();
if (this.hasItems())
this._selectIndex(count - 1);
},
// Returns true if the display has some item selected.
hasSelected: function() {
return this._selectedIndex != -1;
},
// Removes selection if some display item is selected.
unsetSelected: function() {
this._selectIndex(-1);
},
// Returns true if the display has any displayed items.
hasItems: function() {
// TODO: figure out why this._list.displayedCount is returning a
// positive number when this._mathedItems.length is 0
// This can be triggered if a search string is entered for which there are no matches.
// log('this._mathedItems.length: ' + this._matchedItems.length + ' this._list.displayedCount ' + this._list.displayedCount);
return this._matchedItemKeys.length > 0;
},
getMatchedItemsCount: function() {
return this._matchedItemKeys.length;
},
// Load the initial state
load: function() {
this._redisplay(RedisplayFlags.FULL);
},
// Should be called when the display is closed
resetState: function() {
this._filterReset();
this._openDetailIndex = -1;
this.actor.get_vscroll_bar().get_adjustment().value = 0;
},
// Returns an actor which acts as a sidebar; this is used for
// the applications category view
getNavigationArea: function () {
return null;
},
createDetailsForIndex: function(index) {
let item = this._findDisplayedByIndex(index);
return item.createDetailsActor();
},
//// Protected methods ////
_recreateDisplayItems: function() {
this._removeAllDisplayItems();
this._setDefaultList();
for (let itemId in this._allItems) {
this._addDisplayItem(itemId);
}
},
// Creates a display item based on the information associated with itemId
// and adds it to the list of displayed items, but does not yet display it.
_addDisplayItem : function(itemId) {
if (this._displayedItems.hasOwnProperty(itemId)) {
log('Tried adding a display item for ' + itemId + ', but an item with this item id is already among displayed items.');
return;
}
let itemInfo = this._allItems[itemId];
let displayItem = this._createDisplayItem(itemInfo);
displayItem.connect('activate',
Lang.bind(this,
function() {
// update the selection
this._selectIndex(this._list.get_children().indexOf(displayItem.actor));
this.activateSelected();
}));
displayItem.connect('show-details',
Lang.bind(this,
function() {
let index = this._list.get_children().indexOf(displayItem.actor);
/* Close the details pane if already open */
if (index == this._openDetailIndex) {
this._openDetailIndex = -1;
this.emit('show-details', -1);
} else {
this._openDetailIndex = index;
this.emit('show-details', index);
}
}));
this._displayedItems[itemId] = displayItem;
},
// Removes an item identifed by the itemId from the displayed items.
_removeDisplayItem: function(itemId) {
let children = this._list.get_children();
let count = children.length;
let displayItem = this._displayedItems[itemId];
let displayItemIndex = children.indexOf(displayItem.actor);
if (this.hasSelected() && count == 1) {
this.unsetSelected();
} else if (this.hasSelected() && displayItemIndex < this._selectedIndex) {
this.selectUp();
}
displayItem.destroy();
delete this._displayedItems[itemId];
},
// Removes all displayed items.
_removeAllDisplayItems: function() {
this.unsetSelected();
for (itemId in this._displayedItems)
this._removeDisplayItem(itemId);
},
// Return true if there's an active search or other constraint
// on the list
_filterActive: function() {
return this._search != '';
},
// Called when we are resetting state
_filterReset: function() {
this.unsetSelected();
},
_compareSearchMatch: function(a, b) {
let countA = this._matchedItems[a];
let countB = this._matchedItems[b];
if (countA > countB)
return -1;
else if (countA < countB)
return 1;
else
return this._compareItems(a, b);
},
_setMatches: function(matches) {
this._matchedItems = matches;
this._matchedItemKeys = [];
for (let itemId in this._matchedItems) {
this._matchedItemKeys.push(itemId);
}
this._matchedItemKeys.sort(Lang.bind(this, this._compareSearchMatch));
},
/**
* _redisplaySubSearch:
* A somewhat more optimized function called when we know
* that we're going to be displaying a subset of the items
* we already had, in the same order. In that case, we can
* just hide the actors that shouldn't be shown.
*/
_redisplaySubSearch: function() {
let matches = this._getSearchMatchedItems(true);
// Just hide all from the old set,
// we'll show the ones we want below
for (let itemId in this._displayedItems) {
let item = this._displayedItems[itemId];
item.actor.hide();
}
this._setMatches(matches);
for (let itemId in matches) {
let item = this._displayedItems[itemId];
item.actor.show();
}
this._list.queue_relayout();
},
_redisplayReordering: function() {
if (!this._filterActive()) {
this._setDefaultList();
} else {
this._setMatches(this._getSearchMatchedItems(false));
}
this._list.remove_all();
for (let i = 0; i < this._matchedItemKeys.length; i++) {
let itemId = this._matchedItemKeys[i];
let item = this._displayedItems[itemId];
item.actor.show();
this._list.add_actor(item.actor);
}
},
/*
* Updates the displayed items, applying the search string if one exists.
* @flags: Flags controlling redisplay behavior as follows:
* SUBSEARCH - Indicates that the current _search is a superstring of the previous
* one, which implies we only need to re-search through previous results.
* FULL - Indicates that we need recreate all displayed items.
* IMMEDIATE - Do the full redisplay even if we're not mapped. This is useful
* if you want to get the number of matched items and show/hide a section based on
* that number.
*/
_redisplay: function(flags) {
let immediate = (flags & RedisplayFlags.IMMEDIATE) != 0;
if (!immediate && !this.actor.mapped) {
this._pendingRedisplay |= flags;
return;
}
let isSubSearch = (flags & RedisplayFlags.SUBSEARCH) != 0;
let fullReload = (flags & RedisplayFlags.FULL) != 0;
let hadSelected = this.hasSelected();
this.unsetSelected();
if (!this._initialLoadComplete)
fullReload = true;
if (!this._refreshCache())
fullReload = true;
if (fullReload) {
this._recreateDisplayItems();
this._initialLoadComplete = true;
}
if (isSubSearch) {
this._redisplaySubSearch();
} else {
this._redisplayReordering();
}
if (hadSelected) {
this._selectedIndex = -1;
this.selectFirstItem();
}
this.emit('redisplayed');
},
//// Pure virtual protected methods ////
// Performs the steps needed to have the latest information about the items.
// Implementation should return %true if we are up to date, and %false
// if a full reload occurred.
_refreshCache: function() {
throw new Error('Not implemented');
},
// Sets the list of the displayed items based on the default sorting order.
// The default sorting order is specific to each implementing class.
_setDefaultList: function() {
throw new Error('Not implemented');
},
// Compares items associated with the item ids based on the order in which the
// items should be displayed.
// Intended to be used as a compareFunction for array.sort().
// Returns an integer value indicating the result of the comparison.
_compareItems: function(itemIdA, itemIdB) {
throw new Error('Not implemented');
},
// Checks if the item info can be a match for the search string.
// Returns a boolean flag indicating if that's the case.
_isInfoMatching: function(itemInfo, search) {
throw new Error('Not implemented');
},
// Creates a display item based on itemInfo.
_createDisplayItem: function(itemInfo) {
throw new Error('Not implemented');
},
//// Private methods ////
_getItemSearchScore: function(itemId, terms) {
let item = this._allItems[itemId];
let score = 0;
for (let i = 0; i < terms.length; i++) {
let term = terms[i];
if (this._isInfoMatching(item, term)) {
score++;
}
}
return score;
},
_getSearchMatchedItems: function(isSubSearch) {
// Break the search up into terms, and search for each
// individual term. Keep track of the number of terms
// each item matched.
let terms = this._search.split(/\s+/);
let matchScores = {};
if (isSubSearch) {
for (let i = 0; i < this._matchedItemKeys.length; i++) {
let itemId = this._matchedItemKeys[i];
let score = this._getItemSearchScore(itemId, terms);
if (score > 0)
matchScores[itemId] = score;
}
} else {
for (let itemId in this._displayedItems) {
let score = this._getItemSearchScore(itemId, terms);
if (score > 0)
matchScores[itemId] = score;
}
}
return matchScores;
},
// Returns a display item based on its index in the ordering of the
// display children.
_findDisplayedByIndex: function(index) {
let actor = this._list.get_children()[index];
return this._findDisplayedByActor(actor);
},
// Returns a display item based on the actor that represents it in
// the display.
_findDisplayedByActor: function(actor) {
for (itemId in this._displayedItems) {
let item = this._displayedItems[itemId];
if (item.actor == actor) {
return item;
}
}
return null;
},
// Selects (e.g. highlights) a display item at the provided index,
// updates this.selectedItemDetails actor, and emits 'selected' signal.
_selectIndex: function(index) {
// Cleanup from the previous item
if (this.hasSelected()) {
this._findDisplayedByIndex(this._selectedIndex).markSelected(false);
}
this._selectedIndex = index;
if (index < 0)
return;
// Mark the new item as selected and create its details pane
let item = this._findDisplayedByIndex(index);
item.markSelected(true);
this.emit('selected');
},
_getVisibleCount: function() {
return this._list.get_n_children();
},
_onMappedNotify: function () {
let mapped = this.actor.mapped;
if (mapped && this._pendingRedisplay > RedisplayFlags.NONE)
this._redisplay(this._pendingRedisplay);
this._pendingRedisplay = RedisplayFlags.NONE;
}
};
Signals.addSignalMethods(GenericDisplay.prototype);

View File

@ -165,8 +165,16 @@ IconGrid.prototype = {
alloc.natural_size = nColumns * this._item_size + totalSpacing;
},
_getPreferredHeight: function (grid, forWidth, alloc) {
_getVisibleChildren: function() {
let children = this._grid.get_children();
children = children.filter(function(actor) {
return actor.visible;
});
return children;
},
_getPreferredHeight: function (grid, forWidth, alloc) {
let children = this._getVisibleChildren();
let [nColumns, usedWidth] = this._computeLayout(forWidth);
let nRows;
if (nColumns > 0)
@ -182,7 +190,7 @@ IconGrid.prototype = {
},
_allocate: function (grid, box, flags) {
let children = this._grid.get_children();
let children = this._getVisibleChildren();
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;

View File

@ -398,6 +398,9 @@ Inspector.prototype = {
},
_allocate: function(actor, box, flags) {
if (!this._eventHandler)
return;
let primary = global.get_primary_monitor();
let [minWidth, minHeight, natWidth, natHeight] =
@ -415,6 +418,7 @@ Inspector.prototype = {
Clutter.ungrab_pointer(this._eventHandler);
Clutter.ungrab_keyboard(this._eventHandler);
this._eventHandler.destroy();
this._eventHandler = null;
this.emit('closed');
},
@ -663,11 +667,11 @@ LookingGlass.prototype = {
style_class: 'lg-dialog',
vertical: true,
visible: false });
this.actor.connect('key-press-event', Lang.bind(this, this._globalKeyPressEvent));
let gconf = GConf.Client.get_default();
gconf.add_dir('/desktop/gnome/interface', GConf.ClientPreloadType.PRELOAD_NONE);
gconf.notify_add('/desktop/gnome/interface/monospace_font_name',
Lang.bind(this, this._updateFont));
this._interfaceSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
this._interfaceSettings.connect('changed::monospace-font-name',
Lang.bind(this, this._updateFont));
this._updateFont();
Main.uiGroup.add_actor(this.actor);
@ -778,8 +782,7 @@ LookingGlass.prototype = {
},
_updateFont: function() {
let gconf = GConf.Client.get_default();
let fontName = gconf.get_string('/desktop/gnome/interface/monospace_font_name');
let fontName = this._interfaceSettings.get_string('monospace-font-name');
// This is mishandled by the scanner - should by Pango.FontDescription_from_string(fontName);
// https://bugzilla.gnome.org/show_bug.cgi?id=595889
let fontDesc = Pango.font_description_from_string(fontName);
@ -925,20 +928,15 @@ LookingGlass.prototype = {
if (this._open)
return;
if (!Main.pushModal(this.actor))
if (!Main.pushModal(this._entry))
return;
this._keyPressEventId = global.stage.connect('key-press-event',
Lang.bind(this, this._globalKeyPressEvent));
this.actor.show();
this.actor.lower(Main.chrome.actor);
this._open = true;
Tweener.removeTweens(this.actor);
global.stage.set_key_focus(this._entry);
// We inverse compensate for the slow-down so you can change the factor
// through LookingGlass without long waits.
Tweener.addTween(this.actor, { time: 0.5 / St.get_slow_down_factor(),
@ -951,9 +949,6 @@ LookingGlass.prototype = {
if (!this._open)
return;
if (this._keyPressEventId)
global.stage.disconnect(this._keyPressEventId);
this._objInspector.actor.hide();
this._historyNavIndex = -1;
@ -966,7 +961,7 @@ LookingGlass.prototype = {
this._borderPaintTarget = null;
}
Main.popModal(this.actor);
Main.popModal(this._entry);
Tweener.addTween(this.actor, { time: 0.5 / St.get_slow_down_factor(),
transition: 'easeOutQuad',

View File

@ -10,6 +10,7 @@ const Signals = imports.signals;
const Main = imports.ui.main;
const MagnifierDBus = imports.ui.magnifierDBus;
const Params = imports.misc.params;
// Keep enums in sync with GSettings schemas
const MouseTrackingMode = {
@ -65,11 +66,14 @@ Magnifier.prototype = {
// Create the first ZoomRegion and initialize it according to the
// magnification settings.
let [xMouse, yMouse, mask] = global.get_pointer();
let mask;
[this.xMouse, this.yMouse, mask] = global.get_pointer();
let aZoomRegion = new ZoomRegion(this, this._cursorRoot);
this._zoomRegions.push(aZoomRegion);
let showAtLaunch = this._settingsInit(aZoomRegion);
aZoomRegion.scrollContentsTo(xMouse, yMouse);
aZoomRegion.scrollContentsTo(this.xMouse, this.yMouse);
xfixesCursor.connect('cursor-change', Lang.bind(this, this._updateMouseSprite));
this._xfixesCursor = xfixesCursor;
@ -137,12 +141,10 @@ Magnifier.prototype = {
* Turn on mouse tracking, if not already doing so.
*/
startTrackingMouse: function() {
// initialize previous mouse coord to undefined.
let prevCoord = { x: NaN, y: NaN };
if (!this._mouseTrackingId)
this._mouseTrackingId = Mainloop.timeout_add(
MOUSE_POLL_FREQUENCY,
Lang.bind(this, this.scrollToMousePos, prevCoord)
Lang.bind(this, this.scrollToMousePos)
);
},
@ -169,14 +171,15 @@ Magnifier.prototype = {
* scrollToMousePos:
* Position all zoom regions' ROI relative to the current location of the
* system pointer.
* @prevCoord: The previous mouse coordinates. Used to stop scrolling if
* the new position is the same as the last one (optional).
* @return true.
*/
scrollToMousePos: function(prevCoord) {
scrollToMousePos: function() {
let [xMouse, yMouse, mask] = global.get_pointer();
if (!prevCoord || prevCoord.x != xMouse || prevCoord.y != yMouse) {
if (xMouse != this.xMouse || yMouse != this.yMouse) {
this.xMouse = xMouse;
this.yMouse = yMouse;
let sysMouseOverAny = false;
this._zoomRegions.forEach(function(zoomRegion, index, array) {
if (zoomRegion.scrollToMousePos())
@ -186,11 +189,6 @@ Magnifier.prototype = {
this.hideSystemCursor();
else
this.showSystemCursor();
if (prevCoord) {
prevCoord.x = xMouse;
prevCoord.y = yMouse;
}
}
return true;
},
@ -212,9 +210,14 @@ Magnifier.prototype = {
*/
createZoomRegion: function(xMagFactor, yMagFactor, roi, viewPort) {
let zoomRegion = new ZoomRegion(this, this._cursorRoot);
zoomRegion.setMagFactor(xMagFactor, yMagFactor);
zoomRegion.setViewPort(viewPort);
zoomRegion.setROI(roi);
// We ignore the redundant width/height on the ROI
let fixedROI = new Object(roi);
fixedROI.width = viewPort.width / xMagFactor;
fixedROI.height = viewPort.height / yMagFactor;
zoomRegion.setROI(fixedROI);
zoomRegion.addCrosshairs(this._crossHairs);
return zoomRegion;
},
@ -247,22 +250,9 @@ Magnifier.prototype = {
* Remove all the zoom regions from this Magnfier's ZoomRegion list.
*/
clearAllZoomRegions: function() {
// First ZoomRegion is special since its magnified mouse and crosshairs
// are the original -- all the others are Clutter.Clone's. Deal with
// all but first zoom region.
for (let i = 1; i < this._zoomRegions.length; i++) {
for (let i = 0; i < this._zoomRegions.length; i++)
this._zoomRegions[i].setActive(false);
this._zoomRegions[i].removeFromStage();
}
this._zoomRegions[0].setActive(false);
// Detach the (original) magnified mouse and cross hair for later reuse
// before removing ZoomRegion from the stage.
this._cursorRoot.get_parent().remove_actor(this._cursorRoot);
if (this._crossHairs)
this._crossHairs.removeFromParent();
this._zoomRegions[0].removeFromStage();
this._zoomRegions.length = 0;
this.stopTrackingMouse();
this.showSystemCursor();
@ -567,44 +557,35 @@ Magnifier.prototype = {
};
Signals.addSignalMethods(Magnifier.prototype);
function ZoomRegion(magnifier, mouseRoot) {
this._init(magnifier, mouseRoot);
function ZoomRegion(magnifier, mouseSourceActor) {
this._init(magnifier, mouseSourceActor);
}
ZoomRegion.prototype = {
_init: function(magnifier, mouseRoot) {
_init: function(magnifier, mouseSourceActor) {
this._magnifier = magnifier;
// The root actor for the zoom region
this._magView = new St.Bin({ style_class: 'magnifier-zoom-region', x_fill: true, y_fill: true });
global.stage.add_actor(this._magView);
this._magView.hide();
this._mouseTrackingMode = MouseTrackingMode.NONE;
this._clampScrollingAtEdges = false;
this._lensMode = false;
this._screenPosition = ScreenPosition.FULL_SCREEN;
// Append a Clutter.Group to clip the contents of the magnified view.
this._mainGroup = new Clutter.Group({ clip_to_allocation: true });
this._magView.set_child(this._mainGroup);
// Add a background for when the magnified uiGroup is scrolled
// out of view (don't want to see desktop showing through).
let background = new Clutter.Rectangle({ color: Main.DEFAULT_BACKGROUND_COLOR });
this._mainGroup.add_actor(background);
// Clone the group that contains all of UI on the screen. This is the
// chrome, the windows, etc.
this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup });
this._mainGroup.add_actor(this._uiGroupClone);
Main.uiGroup.set_size(global.screen_width, global.screen_height);
background.set_size(global.screen_width, global.screen_height);
this._uiGroupClone.set_size(global.screen_width, global.screen_height);
// Add either the given mouseRoot to the ZoomRegion, or a clone of
// it.
if (mouseRoot.get_parent() != null)
this._mouseRoot = new Clutter.Clone({ source: mouseRoot });
else
this._mouseRoot = mouseRoot;
this._mainGroup.add_actor(this._mouseRoot);
this._magView = null;
this._uiGroupClone = null;
this._mouseSourceActor = mouseSourceActor;
this._mouseActor = null;
this._crossHairs = null;
this._crossHairsActor = null;
this._viewPortX = 0;
this._viewPortY = 0;
this._viewPortWidth = global.screen_width;
this._viewPortWidth = global.screen_height;
this._xCenter = this._viewPortWidth / 2;
this._yCenter = this._viewPortHeight / 2;
this._xMagFactor = 1;
this._yMagFactor = 1;
this._followingCursor = false;
},
/**
@ -612,14 +593,16 @@ ZoomRegion.prototype = {
* @activate: Boolean to show/hide the ZoomRegion.
*/
setActive: function(activate) {
if (activate) {
this._magView.show();
if (this.isMouseOverRegion())
if (activate && !this.isActive()) {
this._createActors();
if (this._isMouseOverRegion())
this._magnifier.hideSystemCursor();
this._updateMousePosition(false /* mouse didn't move */);
this._updateMagViewGeometry();
this._updateCloneGeometry();
this._updateMousePosition();
} else if (!activate && this.isActive()) {
this._destroyActors();
}
else
this._magView.hide();
},
/**
@ -627,18 +610,7 @@ ZoomRegion.prototype = {
* @return Whether this ZoomRegion is active (boolean).
*/
isActive: function() {
return this._magView.visible;
},
/**
* removeFromStage:
* Remove the magnified view from the stage.
*/
removeFromStage: function() {
global.stage.remove_actor(this._magView);
this._mouseRoot = null;
this._uiGroupClone = null;
this._magView = null;
return this._magView != null;
},
/**
@ -650,19 +622,9 @@ ZoomRegion.prototype = {
* of the magnified view.
*/
setMagFactor: function(xMagFactor, yMagFactor) {
if (xMagFactor > 0 && yMagFactor > 0) {
// Changing the mag factor moves the pixels along the axes of
// magnification. Set the view back to the point that was at the centre
// of the region of interest.
let [x, y, width, height] = this.getROI();
let xCentre = x + width / 2;
let yCentre = y + height / 2;
this._uiGroupClone.set_scale(xMagFactor, yMagFactor);
this._mouseRoot.set_scale(xMagFactor, yMagFactor);
this._calcRightBottomStops();
this._scrollToPosition(xCentre, yCentre);
this._updateMousePosition(false /* mouse didn't move */);
}
this._changeROI({ xMagFactor: xMagFactor,
yMagFactor: yMagFactor,
redoCursorTracking: this._followingCursor });
},
/**
@ -673,7 +635,7 @@ ZoomRegion.prototype = {
* in size, and so on.
*/
getMagFactor: function() {
return this._uiGroupClone.get_scale();
return [this._xMagFactor, this._yMagFactor];
},
/**
@ -696,29 +658,12 @@ ZoomRegion.prototype = {
/**
* setViewPort
* Sets the position and size of the ZoomRegion on screen.
* @viewPort: Object defining the position and size of the view port. It
* has the form { x, y, width, height }. The values are in
* @viewPort: Object defining the position and size of the view port.
* It has members x, y, width, height. The values are in
* stage coordinate space.
*/
setViewPort: function(viewPort) {
let [xRoi, yRoi, wRoi, hRoi] = this.getROI();
// Remove border if the view port is the entire screen. Otherwise,
// ensure that the border is there.
if (viewPort.x == 0 && viewPort.y == 0 && viewPort.width == global.screen_width && viewPort.height == global.screen_height)
this._magView.add_style_class_name('full-screen');
else
this._magView.remove_style_class_name('full-screen');
this.setSize(viewPort.width, viewPort.height);
this.setPosition(viewPort.x, viewPort.y);
if (this._crossHairs)
this._crossHairs.reCenter();
this.scrollContentsTo(xRoi + wRoi / 2, yRoi + hRoi / 2);
if (this.isMouseOverRegion())
this._magnifier.hideSystemCursor();
this._setViewPort(viewPort);
this._screenPosition = ScreenPosition.NONE;
},
@ -726,88 +671,18 @@ ZoomRegion.prototype = {
* setROI
* Sets the "region of interest" that the ZoomRegion is magnifying.
* @roi: Object that defines the region of the screen to magnify. It
* has the form { x, y, width, height }. The values are in
* has members x, y, width, height. The values are in
* screen (unmagnified) coordinate space.
*/
setROI: function(roi) {
let xRoiCenter = roi.x + roi.width / 2;
let yRoiCenter = roi.y + roi.height / 2;
this.scrollContentsTo(xRoiCenter, yRoiCenter);
},
if (roi.width <= 0 || roi.height <= 0)
return;
/**
* setSize:
* @width: The width to set the magnified view to.
* @height: The height to set the magnified view to.
*/
setSize: function(width, height) {
this._magView.set_size(width, height);
this._calcRightBottomStops();
},
/**
* getSize:
* @return an array, [width, height], that specifies the size of the
* magnified view.
*/
getSize: function() {
return this._magView.get_size();
},
/**
* setPosition:
* Position the magnified view at the given coordinates.
* @x: The x-coord of the new position.
* @y: The y-coord of the new position.
*/
setPosition: function(x, y) {
let [width, height] = this._magView.get_size();
if (this._clampScrollingAtEdges) {
// Restrict positioning so view doesn't go beyond any edge of the
// screen.
if (x < 0)
x = 0;
if (x + width > global.screen_width)
x = global.screen_width - width;
if (y < 0)
y = 0;
if (y + height > global.screen_height)
y = global.screen_height - height;
}
this._magView.set_position(x, y);
},
/**
* getPosition:
* @return an array, [x, y], that gives the position of the
* magnified view on screen.
*/
getPosition: function() {
return this._magView.get_position();
},
/**
* getCenter:
* @return an array, [x, y], that is half the width and height of the
* magnified view (the center of the magnified view).
*/
getCenter: function() {
let [width, height] = this._magView.get_size();
return [width / 2, height / 2];
},
/**
* isFullScreenMode:
* Does the magnified view occupy the whole screen?
*/
isFullScreenMode: function() {
let [x, y] = this._magView.get_position();
if (x != 0 || y != 0)
return false;
[width, height] = this._magView.get_size();
if (width != global.screen_width || height != global.screen_height)
return false;
return true;
this._followingCursor = false;
this._changeROI({ xMagFactor: this._viewPortWidth / roi.width,
yMagFactor: this._viewPortHeight / roi.height,
xCenter: roi.x + roi.width / 2,
yCenter: roi.y + roi.height / 2 });
},
/**
@ -819,24 +694,23 @@ ZoomRegion.prototype = {
* rectangle of what is shown in the magnified view.
*/
getROI: function() {
let [xMagnified, yMagnified] = this._uiGroupClone.get_position();
let [xMagFactor, yMagFactor] = this.getMagFactor();
let [width, height] = this.getSize();
let x = (0 - xMagnified) / xMagFactor;
let y = (0 - yMagnified) / yMagFactor;
return [x, y, width / xMagFactor, height / yMagFactor];
let roiWidth = this._viewPortWidth / this._xMagFactor;
let roiHeight = this._viewPortHeight / this._yMagFactor;
return [this._xCenter - roiWidth / 2,
this._yCenter - roiHeight / 2,
roiWidth, roiHeight];
},
/**
* setLensMode:
* Turn lens mode on/off. In full screen mode, lens mode is alway off since
* Turn lens mode on/off. In full screen mode, lens mode does nothing since
* a lens the size of the screen is pointless.
* @lensMode: A boolean to set the sense of lens mode.
*/
setLensMode: function(lensMode) {
let fullScreen = this.isFullScreenMode();
this._lensMode = (lensMode && !fullScreen);
if (!this._lensMode && !fullScreen)
this._lensMode = lensMode;
if (!this._lensMode)
this.setScreenPosition (this._screenPosition);
},
@ -857,6 +731,8 @@ ZoomRegion.prototype = {
*/
setClampScrollingAtEdges: function(clamp) {
this._clampScrollingAtEdges = clamp;
if (clamp)
this._changeROI();
},
/**
@ -869,7 +745,7 @@ ZoomRegion.prototype = {
viewPort.y = 0;
viewPort.width = global.screen_width;
viewPort.height = global.screen_height/2;
this.setViewPort(viewPort);
this._setViewPort(viewPort);
this._screenPosition = ScreenPosition.TOP_HALF;
},
@ -883,7 +759,7 @@ ZoomRegion.prototype = {
viewPort.y = global.screen_height/2;
viewPort.width = global.screen_width;
viewPort.height = global.screen_height/2;
this.setViewPort(viewPort);
this._setViewPort(viewPort);
this._screenPosition = ScreenPosition.BOTTOM_HALF;
},
@ -897,7 +773,7 @@ ZoomRegion.prototype = {
viewPort.y = 0;
viewPort.width = global.screen_width/2;
viewPort.height = global.screen_height;
this.setViewPort(viewPort);
this._setViewPort(viewPort);
this._screenPosition = ScreenPosition.LEFT_HALF;
},
@ -911,62 +787,24 @@ ZoomRegion.prototype = {
viewPort.y = 0;
viewPort.width = global.screen_width/2;
viewPort.height = global.screen_height;
this.setViewPort(viewPort);
this._setViewPort(viewPort);
this._screenPosition = ScreenPosition.RIGHT_HALF;
},
/**
* getScreenPosition:
* Tell the outside world what the current mode is -- magnifiying the
* top half, bottom half, etc.
* @return: the current mode.
*/
getScreenPosition: function() {
return this._screenPosition;
},
/**
* scrollToMousePos:
* Set the region of interest based on the position of the system pointer.
* @return: Whether the system mouse pointer is over the magnified view.
*/
scrollToMousePos: function() {
let [xMouse, yMouse, mask] = global.get_pointer();
if (this._mouseTrackingMode == MouseTrackingMode.PROPORTIONAL) {
this._setROIProportional(xMouse, yMouse);
}
else if (this._mouseTrackingMode == MouseTrackingMode.PUSH) {
this._setROIPush(xMouse, yMouse);
}
else if (this._mouseTrackingMode == MouseTrackingMode.CENTERED) {
this._setROICentered(xMouse, yMouse);
}
this._updateMousePosition(true);
// Determine whether the system mouse pointer is over this zoom region.
return this.isMouseOverRegion(xMouse, yMouse);
},
/**
* setFullScreenMode:
* Set the ZoomRegion to full-screen mode.
* Note: disallows lens mode.
*/
setFullScreenMode: function() {
if (!this.isFullScreenMode()) {
let viewPort = {};
viewPort.x = 0;
viewPort.y = 0;
viewPort.width = global.screen_width;
viewPort.height = global.screen_height;
this.setViewPort(viewPort);
this.setLensMode(false);
if (this.isActive())
this._magnifier.hideSystemCursor();
let viewPort = {};
viewPort.x = 0;
viewPort.y = 0;
viewPort.width = global.screen_width;
viewPort.height = global.screen_height;
this.setViewPort(viewPort);
this._screenPosition = ScreenPosition.FULL_SCREEN;
}
this._screenPosition = ScreenPosition.FULL_SCREEN;
},
/**
@ -997,111 +835,241 @@ ZoomRegion.prototype = {
}
},
/**
* getScreenPosition:
* Tell the outside world what the current mode is -- magnifiying the
* top half, bottom half, etc.
* @return: the current mode.
*/
getScreenPosition: function() {
return this._screenPosition;
},
/**
* scrollToMousePos:
* Set the region of interest based on the position of the system pointer.
* @return: Whether the system mouse pointer is over the magnified view.
*/
scrollToMousePos: function() {
this._followingCursor = true;
if (this._mouseTrackingMode != MouseTrackingMode.NONE)
this._changeROI({ redoCursorTracking: true });
else
this._updateMousePosition();
// Determine whether the system mouse pointer is over this zoom region.
return this._isMouseOverRegion();
},
/**
* scrollContentsTo:
* Shift the contents of the magnified view such it is centered on the given
* coordinate. Also, update the position of the magnified mouse image after
* the shift.
* coordinate.
* @x: The x-coord of the point to center on.
* @y: The y-coord of the point to center on.
*/
scrollContentsTo: function(x, y) {
this._scrollToPosition(x, y);
this._updateMousePosition(false /* mouse didn't move */);
},
/**
* isMouseOverRegion:
* Return whether the system mouse sprite is over this ZoomRegion. If the
* mouse's position is not given, then it is fetched.
* @xMouse: The system mouse's x-coord. Optional.
* @yMouse: The system mouse's y-coord. Optional.
* @return: Boolean: true if the mouse is over the zoom region; false
* otherwise.
*/
isMouseOverRegion: function(xMouse, yMouse) {
let mouseIsOver = false;
if (this.isActive()) {
if (!xMouse || !yMouse) {
let [x, y, mask] = global.get_pointer();
xMouse = x;
yMouse = y;
}
let [x, y] = this.getPosition();
let [width, height] = this.getSize();
mouseIsOver = (
xMouse >= x && xMouse < (x + width) &&
yMouse >= y && yMouse < (y + height)
);
}
return mouseIsOver;
this._followingCursor = false;
this._changeROI({ xCenter: x,
yCenter: y });
},
/**
* addCrosshairs:
* Add crosshairs centered on the magnified mouse.
* @crossHairs Clutter.Group that contains the actors for the crosshairs.
* @crossHairs: Crosshairs instance
*/
addCrosshairs: function(crossHairs) {
this._crossHairs = crossHairs;
// If the crossHairs is not already within a larger container, add it
// to this zoom region. Otherwise, add a clone.
if (crossHairs) {
this._crosshairsActor = crossHairs.addToZoomRegion(this, this._mouseRoot);
this._crossHairs = crossHairs;
if (crossHairs && this.isActive()) {
this._crossHairsActor = crossHairs.addToZoomRegion(this, this._mouseActor);
}
},
//// Private methods ////
_scrollToPosition: function(x, y) {
// Given the point (x, y) in non-magnified coordinates, scroll the
// magnified contenst such that the point is at the centre of the
// magnified view.
let [xMagFactor, yMagFactor] = this.getMagFactor();
let xMagnified = x * xMagFactor;
let yMagnified = y * yMagFactor;
_createActors: function() {
// The root actor for the zoom region
this._magView = new St.Bin({ style_class: 'magnifier-zoom-region', x_fill: true, y_fill: true });
global.stage.add_actor(this._magView);
let [xCenterMagView, yCenterMagView] = this.getCenter();
let newX = xCenterMagView - xMagnified;
let newY = yCenterMagView - yMagnified;
// hide the magnified region from CLUTTER_PICK_ALL
Shell.util_set_hidden_from_pick (this._magView, true);
// Append a Clutter.Group to clip the contents of the magnified view.
let mainGroup = new Clutter.Group({ clip_to_allocation: true });
this._magView.set_child(mainGroup);
// Add a background for when the magnified uiGroup is scrolled
// out of view (don't want to see desktop showing through).
let background = new Clutter.Rectangle({ color: Main.DEFAULT_BACKGROUND_COLOR });
mainGroup.add_actor(background);
// Clone the group that contains all of UI on the screen. This is the
// chrome, the windows, etc.
this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup });
mainGroup.add_actor(this._uiGroupClone);
Main.uiGroup.set_size(global.screen_width, global.screen_height);
background.set_size(global.screen_width, global.screen_height);
// Add either the given mouseSourceActor to the ZoomRegion, or a clone of
// it.
if (this._mouseSourceActor.get_parent() != null)
this._mouseActor = new Clutter.Clone({ source: this._mouseSourceActor });
else
this._mouseActor = this._mouseSourceActor;
mainGroup.add_actor(this._mouseActor);
if (this._crossHairs)
this._crossHairsActor = this._crossHairs.addToZoomRegion(this, this._mouseActor);
else
this._crossHairsActor = null;
},
_destroyActors: function() {
if (this._mouseActor == this._mouseSourceActor)
this._mouseActor.get_parent().remove_actor (this._mouseActor);
if (this._crossHairs)
this._crossHairs.removeFromParent(this._crossHairsActor);
this._magView.destroy();
this._magView = null;
this._uiGroupClone = null;
this._mouseActor = null;
this._crossHairsActor = null;
},
_setViewPort: function(viewPort, fromROIUpdate) {
// Sets the position of the zoom region on the screen
let width = Math.round(Math.min(viewPort.width, global.screen_width));
let height = Math.round(Math.min(viewPort.height, global.screen_height));
let x = Math.max(viewPort.x, 0);
let y = Math.max(viewPort.y, 0);
x = Math.round(Math.min(x, global.screen_width - width));
y = Math.round(Math.min(y, global.screen_height - height));
this._viewPortX = x;
this._viewPortY = y;
this._viewPortWidth = width;
this._viewPortHeight = height;
this._updateMagViewGeometry();
if (!fromROIUpdate)
this._changeROI({ redoCursorTracking: this._followingCursor }); // will update mouse
if (this.isActive() && this._isMouseOverRegion())
this._magnifier.hideSystemCursor();
},
_changeROI: function(params) {
// Updates the area we are viewing; the magnification factors
// and center can be set explicitly, or we can recompute
// the position based on the mouse cursor position
params = Params.parse(params, { xMagFactor: this._xMagFactor,
yMagFactor: this._yMagFactor,
xCenter: this._xCenter,
yCenter: this._yCenter,
redoCursorTracking: false });
if (params.xMagFactor <= 0)
params.xMagFactor = this._xMagFactor;
if (params.yMagFactor <= 0)
params.yMagFactor = this._yMagFactor;
this._xMagFactor = params.xMagFactor;
this._yMagFactor = params.yMagFactor;
if (params.redoCursorTracking &&
this._mouseTrackingMode != MouseTrackingMode.NONE) {
// This depends on this.xMagFactor/yMagFactor already being updated
[params.xCenter, params.yCenter] = this._centerFromMousePosition();
}
if (this._clampScrollingAtEdges) {
if (newX > 0)
newX = 0;
else if (newX < this._rightStop)
newX = this._rightStop;
if (newY > 0)
newY = 0;
else if (newY < this._bottomStop)
newY = this._bottomStop;
this._uiGroupClone.set_position(newX, newY);
let roiWidth = this._viewPortWidth / this._xMagFactor;
let roiHeight = this._viewPortHeight / this._yMagFactor;
params.xCenter = Math.min(params.xCenter, global.screen_width - roiWidth / 2);
params.xCenter = Math.max(params.xCenter, roiWidth / 2);
params.yCenter = Math.min(params.yCenter, global.screen_height - roiHeight / 2);
params.yCenter = Math.max(params.yCenter, roiHeight / 2);
}
else
this._uiGroupClone.set_position(newX, newY);
this._xCenter = params.xCenter;
this._yCenter = params.yCenter;
// If in lens mode, move the magnified view such that it is centered
// over the actual mouse. However, in full screen mode, the "lens" is
// the size of the screen -- pointless to move such a large lens around.
if (this._lensMode && !this.isFullScreenMode())
this.setPosition(x - xCenterMagView, y - yCenterMagView);
if (this._lensMode && !this._isFullScreen())
this._setViewPort({ x: this._xCenter - this._viewPortWidth / 2,
y: this._yCenter - this._viewPortHeight / 2,
width: this._viewPortWidth,
height: this._viewPortHeight }, true);
this._updateCloneGeometry();
this._updateMousePosition();
},
_calcRightBottomStops: function() {
// Calculate the location of the top-left corner of _uiGroupClone
// when its right and bottom edges are coincident with the right and
// bottom edges of the _magView.
let [contentWidth, contentHeight] = this._uiGroupClone.get_size();
let [viewWidth, viewHeight] = this.getSize();
let [xMagFactor, yMagFactor] = this.getMagFactor();
let rightStop = viewWidth - (contentWidth * xMagFactor);
let bottomStop = viewHeight - (contentHeight * yMagFactor);
this._rightStop = parseInt(rightStop.toFixed(1));
this._bottomStop = parseInt(bottomStop.toFixed(1));
_isMouseOverRegion: function() {
// Return whether the system mouse sprite is over this ZoomRegion. If the
// mouse's position is not given, then it is fetched.
let mouseIsOver = false;
if (this.isActive()) {
let xMouse = this._magnifier.xMouse;
let yMouse = this._magnifier.yMouse;
mouseIsOver = (
xMouse >= this._viewPortX && xMouse < (this._viewPortX + this._viewPortWidth) &&
yMouse >= this._viewPortY && yMouse < (this._viewPortY + this._viewPortHeight)
);
}
return mouseIsOver;
},
_setROIPush: function(xMouse, yMouse) {
_isFullScreen: function() {
// Does the magnified view occupy the whole screen? Note that this
// doesn't necessarily imply
// this._screenPosition = ScreenPosition.FULL_SCREEN;
if (this._viewPortX != 0 || this._viewPortY != 0)
return false;
if (this._viewPortWidth != global.screen_width ||
this._viewPortHeight != global.screen_height)
return false;
return true;
},
_centerFromMousePosition: function() {
// Determines where the center should be given the current cursor
// position and mouse tracking mode
let xMouse = this._magnifier.xMouse;
let yMouse = this._magnifier.yMouse;
if (this._mouseTrackingMode == MouseTrackingMode.PROPORTIONAL) {
return this._centerFromMouseProportional(xMouse, yMouse);
}
else if (this._mouseTrackingMode == MouseTrackingMode.PUSH) {
return this._centerFromMousePush(xMouse, yMouse);
}
else if (this._mouseTrackingMode == MouseTrackingMode.CENTERED) {
return this._centerFromMouseCentered(xMouse, yMouse);
}
return null; // Should never be hit
},
_centerFromMousePush: function(xMouse, yMouse) {
let [xRoi, yRoi, widthRoi, heightRoi] = this.getROI();
let [cursorWidth, cursorHeight] = this._mouseRoot.get_size();
let [cursorWidth, cursorHeight] = this._mouseSourceActor.get_size();
let xPos = xRoi + widthRoi / 2;
let yPos = yRoi + heightRoi / 2;
let xRoiRight = xRoi + widthRoi - cursorWidth;
@ -1117,58 +1085,79 @@ ZoomRegion.prototype = {
else if (yMouse > yRoiBottom)
yPos += (yMouse - yRoiBottom);
this._scrollToPosition(xPos, yPos);
return [xPos, yPos];
},
_setROIProportional: function(xMouse, yMouse) {
_centerFromMouseProportional: function(xMouse, yMouse) {
let [xRoi, yRoi, widthRoi, heightRoi] = this.getROI();
let halfScreenWidth = global.screen_width / 2;
let halfScreenHeight = global.screen_height / 2;
let xProportion = (halfScreenWidth - xMouse) / halfScreenWidth;
let yProportion = (halfScreenHeight - yMouse) / halfScreenHeight;
let xPos = xMouse + xProportion * widthRoi / 2;
let yPos = yMouse + yProportion * heightRoi / 2;
// We want to pad with a constant distance after zooming, so divide
// by the magnification factor.
let unscaledPadding = Math.min(this._viewPortWidth, this._viewPortHeight) / 5;
let xPadding = unscaledPadding / this._xMagFactor;
let yPadding = unscaledPadding / this._yMagFactor;
let xProportion = (xMouse - halfScreenWidth) / halfScreenWidth; // -1 ... 1
let yProportion = (yMouse - halfScreenHeight) / halfScreenHeight; // -1 ... 1
let xPos = xMouse - xProportion * (widthRoi / 2 - xPadding);
let yPos = yMouse - yProportion * (heightRoi /2 - yPadding);
this._scrollToPosition(xPos, yPos);
return [xPos, yPos];
},
_setROICentered: function(xMouse, yMouse) {
this._scrollToPosition(xMouse, yMouse);
_centerFromMouseCentered: function(xMouse, yMouse) {
return [xMouse, yMouse];
},
_updateMousePosition: function(mouseMoved) {
let [x, y] = this._uiGroupClone.get_position();
x = parseInt(x.toFixed(1));
y = parseInt(y.toFixed(1));
let [xCenterMagView, yCenterMagView] = this.getCenter();
let [xMouse, yMouse, mask] = global.get_pointer();
let [xMagFactor, yMagFactor] = this.getMagFactor();
let xMagMouse = xMouse * xMagFactor + x;
let yMagMouse = yMouse * yMagFactor + y;
if (mouseMoved) {
if (x == 0)
xMagMouse = xMouse * xMagFactor;
else if (x == this._rightStop)
xMagMouse = (xMouse * xMagFactor) + this._rightStop;
else if (this._mouseTrackingMode == MouseTrackingMode.CENTERED)
xMagMouse = xCenterMagView;
if (y == 0)
yMagMouse = yMouse * yMagFactor;
else if (y == this._bottomStop)
yMagMouse = (yMouse * yMagFactor) + this._bottomStop;
else if (this._mouseTrackingMode == MouseTrackingMode.CENTERED)
yMagMouse = yCenterMagView;
}
this._mouseRoot.set_position(xMagMouse, yMagMouse);
this._updateCrosshairsPosition(xMagMouse, yMagMouse);
_screenToViewPort: function(screenX, screenY) {
// Converts coordinates relative to the (unmagnified) screen to coordinates
// relative to the origin of this._magView
return [this._viewPortWidth / 2 + (screenX - this._xCenter) * this._xMagFactor,
this._viewPortHeight / 2 + (screenY - this._yCenter) * this._yMagFactor];
},
_updateCrosshairsPosition: function(x, y) {
if (this._crosshairsActor) {
let [groupWidth, groupHeight] = this._crosshairsActor.get_size();
this._crosshairsActor.set_position(x - groupWidth / 2, y - groupHeight / 2);
_updateMagViewGeometry: function() {
if (!this.isActive())
return;
if (this._isFullScreen())
this._magView.add_style_class_name('full-screen');
else
this._magView.remove_style_class_name('full-screen');
this._magView.set_size(this._viewPortWidth, this._viewPortHeight);
this._magView.set_position(this._viewPortX, this._viewPortY);
},
_updateCloneGeometry: function() {
if (!this.isActive())
return;
this._uiGroupClone.set_scale(this._xMagFactor, this._yMagFactor);
this._mouseActor.set_scale(this._xMagFactor, this._yMagFactor);
let [x, y] = this._screenToViewPort(0, 0);
this._uiGroupClone.set_position(x, y);
this._updateMousePosition();
},
_updateMousePosition: function() {
if (!this.isActive())
return;
let [xMagMouse, yMagMouse] = this._screenToViewPort(this._magnifier.xMouse,
this._magnifier.yMouse);
xMagMouse = Math.round(xMagMouse);
yMagMouse = Math.round(yMagMouse);
this._mouseActor.set_position(xMagMouse, yMagMouse);
if (this._crossHairsActor) {
let [groupWidth, groupHeight] = this._crossHairsActor.get_size();
this._crossHairsActor.set_position(xMagMouse - groupWidth / 2,
yMagMouse - groupHeight / 2);
}
}
};
@ -1243,10 +1232,15 @@ Crosshairs.prototype = {
/**
* removeFromParent:
* Remove the crosshairs actor from its parent container.
* @childActor: the actor returned from addToZoomRegion
* Remove the crosshairs actor from its parent container, or destroy the
* child actor if it was just a clone of the crosshairs actor.
*/
removeFromParent: function() {
this._actor.get_parent().remove_actor(this._actor);
removeFromParent: function(childActor) {
if (childActor == this._actor)
childActor.get_parent().remove_actor(childActor);
else
childActor.destroy();
},
/**

View File

@ -112,6 +112,11 @@ ShellMagnifier.prototype = {
* [left, top, right, bottom].
* @viewPort Array of integers, [left, top, right, bottom] that defines
* the position of the ZoomRegion on screen.
*
* FIXME: The arguments here are redundant, since the width and height of
* the ROI are determined by the viewport and magnification factors.
* We ignore the passed in width and height.
*
* @return The newly created ZoomRegion.
*/
createZoomRegion: function(xMagFactor, yMagFactor, roi, viewPort) {

View File

@ -17,8 +17,12 @@ const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Chrome = imports.ui.chrome;
const CtrlAltTab = imports.ui.ctrlAltTab;
const EndSessionDialog = imports.ui.endSessionDialog;
const Environment = imports.ui.environment;
const ExtensionSystem = imports.ui.extensionSystem;
const MessageTray = imports.ui.messageTray;
@ -34,7 +38,9 @@ const ShellDBus = imports.ui.shellDBus;
const TelepathyClient = imports.ui.telepathyClient;
const WindowManager = imports.ui.windowManager;
const Magnifier = imports.ui.magnifier;
const XdndHandler = imports.ui.xdndHandler;
const StatusIconDispatcher = imports.ui.statusIconDispatcher;
const Util = imports.misc.util;
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
@ -50,15 +56,19 @@ let messageTray = null;
let notificationDaemon = null;
let windowAttentionHandler = null;
let telepathyClient = null;
let ctrlAltTabManager = null;
let recorder = null;
let shellDBusService = null;
let modalCount = 0;
let modalActorFocusStack = [];
let uiGroup = null;
let magnifier = null;
let xdndHandler = null;
let statusIconDispatcher = null;
let _errorLogStack = [];
let _startDate;
let _defaultCssStylesheet = null;
let _cssStylesheet = null;
let background = null;
@ -103,10 +113,8 @@ function start() {
global.stage.color = DEFAULT_BACKGROUND_COLOR;
global.stage.no_clear_hint = true;
let themeContext = St.ThemeContext.get_for_stage (global.stage);
let stylesheetPath = global.datadir + '/theme/gnome-shell.css';
let theme = new St.Theme ({ application_stylesheet: stylesheetPath });
themeContext.set_theme (theme);
_defaultCssStylesheet = global.datadir + '/theme/gnome-shell.css';
loadTheme();
let shellwm = global.window_manager;
shellwm.takeover_keybinding('panel_main_menu');
@ -125,6 +133,7 @@ function start() {
global.stage.add_actor(uiGroup);
placesManager = new PlaceDisplay.PlacesManager();
xdndHandler = new XdndHandler.XdndHandler();
overview = new Overview.Overview();
chrome = new Chrome.Chrome();
magnifier = new Magnifier.Magnifier();
@ -135,6 +144,10 @@ function start() {
notificationDaemon = new NotificationDaemon.NotificationDaemon();
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
telepathyClient = new TelepathyClient.Client();
panel.startStatusArea();
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
ctrlAltTabManager.addGroup(panel.actor, _("Panel"), 'gnome-panel');
_startDate = new Date();
@ -162,6 +175,10 @@ function start() {
}
});
// Provide the bus object for gnome-session to
// initiate logouts.
EndSessionDialog.init();
global.gdk_screen.connect('monitors-changed', _relayout);
ExtensionSystem.init();
@ -190,6 +207,47 @@ function start() {
}
}
/**
* getThemeStylesheet:
*
* Get the theme CSS file that the shell will load
*
* Returns: A file path that contains the theme CSS,
* null if using the default
*/
function getThemeStylesheet()
{
return _cssStylesheet;
}
/**
* setThemeStylesheet:
* @cssStylesheet: A file path that contains the theme CSS,
* set it to null to use the default
*
* Set the theme CSS file that the shell will load
*/
function setThemeStylesheet(cssStylesheet)
{
_cssStylesheet = cssStylesheet;
}
/**
* loadTheme:
*
* Reloads the theme CSS file
*/
function loadTheme() {
let themeContext = St.ThemeContext.get_for_stage (global.stage);
let cssStylesheet = _defaultCssStylesheet;
if (_cssStylesheet != null)
cssStylesheet = _cssStylesheet;
let theme = new St.Theme ({ application_stylesheet: cssStylesheet });
themeContext.set_theme (theme);
}
/**
* _log:
* @category: string message type ('info', 'error')
@ -239,10 +297,8 @@ function _relayout() {
// To avoid updating the position and size of the workspaces
// in the overview, we just hide the overview. The positions
// will be updated when it is next shown. We do the same for
// the calendar popdown.
// will be updated when it is next shown.
overview.hide();
panel.hideCalendar();
}
// metacity-clutter currently uses the same prefs as plain metacity,
@ -278,47 +334,42 @@ function _removeUnusedWorkspaces() {
// are disabled with a global grab. (When there is a global grab, then
// all key events will be delivered to the stage, so ::captured-event
// on the stage can be used for global keybindings.)
//
// We expect to need to conditionally enable just a few keybindings
// depending on circumstance; the main hackiness here is that we are
// assuming that keybindings have their default values; really we
// should be asking Mutter to resolve the key into an action and then
// base our handling based on the action.
function _globalKeyPressHandler(actor, event) {
if (modalCount == 0)
return false;
if (event.type() != Clutter.EventType.KEY_RELEASE)
if (event.type() != Clutter.EventType.KEY_PRESS)
return false;
let symbol = event.get_key_symbol();
let keyCode = event.get_key_code();
let modifierState = Shell.get_event_state(event);
// Check the overview key first, this isn't a Meta.KeyBindingAction yet
if (symbol == Clutter.Super_L || symbol == Clutter.Super_R) {
// The super key is the default for triggering the overview, and should
// get us out of the overview when we are already in it.
if (overview.visible)
overview.hide();
let display = global.screen.get_display();
// This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType
let action = display.get_keybinding_action(keyCode, modifierState);
// The screenshot action should always be available (even if a
// modal dialog is present)
if (action == Meta.KeyBindingAction.COMMAND_SCREENSHOT) {
let gconf = GConf.Client.get_default();
let command = gconf.get_string('/apps/metacity/keybinding_commands/command_screenshot');
if (command != null && command != '')
Util.spawnCommandLine(command);
return true;
}
// Whitelist some of the Metacity actions
let display = global.screen.get_display();
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
// Other bindings are only available when the overview is up and
// no modal dialog is present.
if (!overview.visible || modalCount > 1)
return false;
// This isn't a Meta.KeyBindingAction yet
if (symbol == Clutter.Super_L || symbol == Clutter.Super_R) {
overview.hide();
return true;
}
// This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType
let action = display.get_keybinding_action(keyCode, modifierState);
switch (action) {
case Meta.KeyBindingAction.COMMAND_SCREENSHOT:
let gconf = GConf.Client.get_default();
let command = gconf.get_string('/apps/metacity/keybinding_commands/command_screenshot');
if (command != null && command != '') {
let [ok, len, args] = GLib.shell_parse_argv(command);
let p = new Shell.Process({'args' : args});
p.run();
}
return true;
case Meta.KeyBindingAction.WORKSPACE_LEFT:
wm.actionMoveWorkspaceLeft();
return true;
@ -329,6 +380,12 @@ function _globalKeyPressHandler(actor, event) {
case Meta.KeyBindingAction.COMMAND_2:
getRunDialog().open();
return true;
case Meta.KeyBindingAction.PANEL_MAIN_MENU:
overview.hide();
return true;
case Meta.KeyBindingAction.SWITCH_PANELS:
ctrlAltTabManager.popup(modifierState & Clutter.ModifierType.SHIFT_MASK);
return true;
}
return false;
@ -347,21 +404,30 @@ function _findModal(actor) {
/**
* pushModal:
* @actor: #ClutterActor which will be given keyboard focus
* @timestamp: optional timestamp
*
* Ensure we are in a mode where all keyboard and mouse input goes to
* the stage. Multiple calls to this function act in a stacking fashion;
* the effect will be undone when an equal number of popModal() invocations
* have been made.
* the stage, and focus @actor. Multiple calls to this function act in
* a stacking fashion; the effect will be undone when an equal number
* of popModal() invocations have been made.
*
* Next, record the current Clutter keyboard focus on a stack. If the modal stack
* returns to this actor, reset the focus to the actor which was focused
* at the time pushModal() was invoked.
* Next, record the current Clutter keyboard focus on a stack. If the
* modal stack returns to this actor, reset the focus to the actor
* which was focused at the time pushModal() was invoked.
*
* @timestamp is optionally used to associate the call with a specific user
* initiated event. If not provided then the value of
* global.get_current_time() is assumed.
*
* Returns: true iff we successfully acquired a grab or already had one
*/
function pushModal(actor) {
function pushModal(actor, timestamp) {
if (timestamp == undefined)
timestamp = global.get_current_time();
if (modalCount == 0) {
if (!global.begin_modal(global.get_current_time())) {
if (!global.begin_modal(timestamp)) {
log('pushModal: invocation of begin_modal failed');
return false;
}
@ -385,19 +451,28 @@ function pushModal(actor) {
}
modalActorFocusStack.push([actor, curFocus]);
global.stage.set_key_focus(null);
global.stage.set_key_focus(actor);
return true;
}
/**
* popModal:
* @actor: #ClutterActor passed to original invocation of pushModal().
* @timestamp: optional timestamp
*
* Reverse the effect of pushModal(). If this invocation is undoing
* the topmost invocation, then the focus will be restored to the
* previous focus at the time when pushModal() was invoked.
*
* @timestamp is optionally used to associate the call with a specific user
* initiated event. If not provided then the value of
* global.get_current_time() is assumed.
*/
function popModal(actor) {
function popModal(actor, timestamp) {
if (timestamp == undefined)
timestamp = global.get_current_time();
modalCount -= 1;
let focusIndex = _findModal(actor);
if (focusIndex >= 0) {
@ -415,7 +490,8 @@ function popModal(actor) {
if (modalCount > 0)
return;
global.end_modal(global.get_current_time());
global.stage.set_key_focus(null);
global.end_modal(timestamp);
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
}

View File

@ -1,6 +1,8 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
@ -14,6 +16,10 @@ const Tweener = imports.ui.tweener;
const Main = imports.ui.main;
const BoxPointer = imports.ui.boxpointer;
const Params = imports.misc.params;
const Util = imports.misc.util;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const ANIMATION_TIME = 0.2;
const NOTIFICATION_TIMEOUT = 4;
@ -35,15 +41,153 @@ const State = {
HIDING: 3
};
function _cleanMarkup(text) {
// Support &amp;, &quot;, &apos;, &lt; and &gt;, escape all other
// occurrences of '&'.
let _text = text.replace(/&(?!amp;|quot;|apos;|lt;|gt;)/g, '&amp;');
// Support <b>, <i>, and <u>, escape anything else
// so it displays as raw markup.
return _text.replace(/<(\/?[^biu]>|[^>\/][^>])/g, '&lt;$1');
// These reasons are useful when we destroy the notifications received through
// the notification daemon. We use EXPIRED for transient notifications that the
// user did not interact with, DISMISSED for all other notifications that were
// destroyed as a result of a user action, and SOURCE_CLOSED for the notifications
// that were requested to be destroyed by the associated source.
const NotificationDestroyedReason = {
EXPIRED: 1,
DISMISSED: 2,
SOURCE_CLOSED: 3
};
// Message tray has its custom Urgency enumeration. LOW, NORMAL and CRITICAL
// urgency values map to the corresponding values for the notifications received
// through the notification daemon. HIGH urgency value is used for chats received
// through the Telepathy client.
const Urgency = {
LOW: 0,
NORMAL: 1,
HIGH: 2,
CRITICAL: 3
}
function _fixMarkup(text, allowMarkup) {
if (allowMarkup) {
// Support &amp;, &quot;, &apos;, &lt; and &gt;, escape all other
// occurrences of '&'.
let _text = text.replace(/&(?!amp;|quot;|apos;|lt;|gt;)/g, '&amp;');
// Support <b>, <i>, and <u>, escape anything else
// so it displays as raw markup.
return _text.replace(/<(\/?[^biu]>|[^>\/][^>])/g, '&lt;$1');
} else {
// Escape everything
let _text = text.replace(/&/g, '&amp;');
return _text.replace(/</g, '&lt;');
}
}
function URLHighlighter(text, lineWrap, allowMarkup) {
this._init(text, lineWrap, allowMarkup);
}
URLHighlighter.prototype = {
_init: function(text, lineWrap, allowMarkup) {
if (!text)
text = '';
this.actor = new St.Label({ reactive: true, style_class: 'url-highlighter' });
this._linkColor = '#ccccff';
this.actor.connect('style-changed', Lang.bind(this, function() {
let color = new Clutter.Color();
let hasColor = this.actor.get_theme_node().get_color('link-color', color);
if (hasColor) {
let linkColor = color.to_string().substr(0, 7);
if (linkColor != this._linkColor) {
this._linkColor = linkColor;
this._highlightUrls();
}
}
}));
if (lineWrap) {
this.actor.clutter_text.line_wrap = true;
this.actor.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
this.actor.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
}
this.setMarkup(text, allowMarkup);
this.actor.connect('button-release-event', Lang.bind(this, function (actor, event) {
let urlId = this._findUrlAtPos(event);
if (urlId != -1) {
let url = this._urls[urlId].url;
if (url.indexOf(':') == -1)
url = 'http://' + url;
try {
Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context());
return true;
} catch (e) {
// TODO: remove this after gnome 3 release
Util.spawn(['gvfs-open', url]);
return true;
}
}
return false;
}));
this.actor.connect('motion-event', Lang.bind(this, function(actor, event) {
let urlId = this._findUrlAtPos(event);
if (urlId != -1 && !this._cursorChanged) {
global.set_cursor(Shell.Cursor.POINTING_HAND);
this._cursorChanged = true;
} else if (urlId == -1) {
global.unset_cursor();
this._cursorChanged = false;
}
return false;
}));
this.actor.connect('leave-event', Lang.bind(this, function() {
if (this._cursorChanged) {
this._cursorChanged = false;
global.unset_cursor();
}
}));
},
setMarkup: function(text, allowMarkup) {
text = text ? _fixMarkup(text, allowMarkup) : '';
this._text = text;
this.actor.clutter_text.set_markup(text);
/* clutter_text.text contain text without markup */
this._urls = Util.findUrls(this.actor.clutter_text.text);
this._highlightUrls();
},
_highlightUrls: function() {
// text here contain markup
let urls = Util.findUrls(this._text);
let markup = '';
let pos = 0;
for (let i = 0; i < urls.length; i++) {
let url = urls[i];
let str = this._text.substr(pos, url.pos - pos);
markup += str + '<span foreground="' + this._linkColor + '"><u>' + url.url + '</u></span>';
pos = url.pos + url.url.length;
}
markup += this._text.substr(pos);
this.actor.clutter_text.set_markup(markup);
},
_findUrlAtPos: function(event) {
let success;
let [x, y] = event.get_coords();
[success, x, y] = this.actor.transform_stage_point(x, y);
let find_pos = -1;
for (let i = 0; i < this.actor.clutter_text.text.length; i++) {
let [success, px, py, line_height] = this.actor.clutter_text.position_to_coords(i);
if (py > y || py + line_height < y || x < px)
continue;
find_pos = i;
}
if (find_pos != -1) {
for (let i = 0; i < this._urls.length; i++)
if (find_pos >= this._urls[i].pos &&
this._urls[i].pos + this._urls[i].url.length > find_pos)
return i;
}
return -1;
}
};
// Notification:
// @source: the notification's Source
// @title: the title
@ -73,7 +217,8 @@ function _cleanMarkup(text) {
// area.
//
// @params can contain values for 'customContent', 'body', 'icon',
// and 'clear' parameters.
// 'titleMarkup', 'bannerMarkup', 'bodyMarkup', and 'clear'
// parameters.
//
// If @params contains a 'customContent' parameter with the value %true,
// then @banner will not be shown in the body of the notification when the
@ -87,6 +232,12 @@ function _cleanMarkup(text) {
// source.createNotificationIcon(). However, if @params contains an 'icon'
// parameter, the passed in icon will be used.
//
// If @params contains a 'titleMarkup', 'bannerMarkup', or
// 'bodyMarkup' parameter with the value %true, then the corresponding
// element is assumed to use pango markup. If the parameter is not
// present for an element, then anything that looks like markup in
// that element will appear literally in the output.
//
// If @params contains a 'clear' parameter with the value %true, then
// the content and the action area of the notification will be cleared.
// The content area is also always cleared if 'customContent' is false
@ -98,11 +249,16 @@ function Notification(source, title, banner, params) {
Notification.prototype = {
_init: function(source, title, banner, params) {
this.source = source;
this.urgent = false;
this.urgency = Urgency.NORMAL;
this.resident = false;
// 'transient' is a reserved keyword in JS, so we have to use an alternate variable name
this.isTransient = false;
this.expanded = false;
this._destroyed = false;
this._useActionIcons = false;
this._customContent = false;
this._bannerBodyText = null;
this._bannerBodyMarkup = false;
this._titleFitsInBannerMode = true;
this._spacing = 0;
@ -114,13 +270,16 @@ Notification.prototype = {
this._prevFocusedWindow = null;
this._prevKeyFocusActor = null;
this._focusWindowChangedId = 0;
this._focusActorChangedId = 0;
this._stageInputModeChangedId = 0;
this._capturedEventId = 0;
this._keyPressId = 0;
source.connect('destroy', Lang.bind(this, this.destroy));
source.connect('destroy', Lang.bind(this,
// Avoid passing 'source' as an argument to this.destroy()
function () {
this.destroy();
}));
this.actor = new St.Table({ name: 'notification',
reactive: true });
@ -129,7 +288,7 @@ Notification.prototype = {
function (actor, event) {
if (!this._actionArea ||
!this._actionArea.contains(event.get_source()))
this.emit('clicked');
this._onClicked();
}));
// The first line should have the title, followed by the
@ -148,7 +307,8 @@ Notification.prototype = {
this._titleLabel = new St.Label();
this._bannerBox.add_actor(this._titleLabel);
this._bannerLabel = new St.Label();
this._bannerUrlHighlighter = new URLHighlighter();
this._bannerLabel = this._bannerUrlHighlighter.actor;
this._bannerBox.add_actor(this._bannerLabel);
this.update(title, banner, params);
@ -175,6 +335,9 @@ Notification.prototype = {
params = Params.parse(params, { customContent: false,
body: null,
icon: null,
titleMarkup: false,
bannerMarkup: false,
bodyMarkup: false,
clear: false });
this._customContent = params.customContent;
@ -205,7 +368,7 @@ Notification.prototype = {
y_fill: false,
y_align: St.Align.START });
title = title ? _cleanMarkup(title.replace(/\n/g, ' ')) : '';
title = title ? _fixMarkup(title.replace(/\n/g, ' '), params.titleMarkup) : '';
this._titleLabel.clutter_text.set_markup('<b>' + title + '</b>');
// Unless the notification has custom content, we save this._bannerBodyText
@ -213,9 +376,11 @@ Notification.prototype = {
// expandable due to other elements in its content area or due to the banner
// not fitting fully in the single-line mode.
this._bannerBodyText = this._customContent ? null : banner;
this._bannerBodyMarkup = params.bannerMarkup;
banner = banner ? _cleanMarkup(banner.replace(/\n/g, ' ')) : '';
this._bannerLabel.clutter_text.set_markup(banner);
banner = banner ? banner.replace(/\n/g, ' ') : '';
this._bannerUrlHighlighter.setMarkup(banner, params.bannerMarkup);
this._bannerLabel.queue_relayout();
// Add the bannerBody now if we know for sure we'll need it
@ -223,7 +388,7 @@ Notification.prototype = {
this._addBannerBody();
if (params.body)
this.addBody(params.body);
this.addBody(params.body, params.bodyMarkup);
this._updated();
},
@ -231,13 +396,13 @@ Notification.prototype = {
// @actor: actor to add to the body of the notification
//
// Appends @actor to the notification's body
addActor: function(actor) {
addActor: function(actor, style) {
if (!this._scrollArea) {
this.actor.add_style_class_name('multi-line-notification');
this._scrollArea = new St.ScrollView({ name: 'notification-scrollview',
vscrollbar_policy: Gtk.PolicyType.AUTOMATIC,
hscrollbar_policy: Gtk.PolicyType.NEVER,
vshadows: true });
vfade: true });
this.actor.add(this._scrollArea, { row: 1,
col: 1 });
this._contentArea = new St.BoxLayout({ name: 'notification-body',
@ -248,34 +413,30 @@ Notification.prototype = {
this._addBannerBody();
}
this._contentArea.add(actor);
this._contentArea.add(actor, style ? style : {});
this._updated();
},
// addBody:
// @text: the text
// @markup: %true if @text contains pango markup
// @style: style to use when adding the actor containing the text
//
// Adds a multi-line label containing @text to the notification.
//
// Return value: the newly-added label
addBody: function(text) {
let body = new St.Label();
body.clutter_text.line_wrap = true;
body.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
body.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
addBody: function(text, markup, style) {
let label = new URLHighlighter(text, true, markup);
text = text ? _cleanMarkup(text) : '';
body.clutter_text.set_markup(text);
this.addActor(body);
return body;
this.addActor(label.actor, style);
return label.actor;
},
_addBannerBody: function() {
if (this._bannerBodyText) {
let text = this._bannerBodyText;
this._bannerBodyText = null;
this.addBody(text);
this.addBody(text, this._bannerBodyMarkup);
}
},
@ -354,12 +515,20 @@ Notification.prototype = {
}
this._buttonBox.add(button);
button.connect('clicked', Lang.bind(this, function() { this.emit('action-invoked', id); }));
button.connect('clicked', Lang.bind(this, this._onActionInvoked, id));
this._updated();
},
setUrgent: function(urgent) {
this.urgent = urgent;
setUrgency: function(urgency) {
this.urgency = urgency;
},
setResident: function(resident) {
this.resident = resident;
},
setTransient: function(isTransient) {
this.isTransient = isTransient;
},
setUseActionIcons: function(useIcons) {
@ -483,29 +652,16 @@ Notification.prototype = {
let metaDisplay = global.screen.get_display();
this._prevFocusedWindow = metaDisplay.focus_window;
this._prevKeyFocus = global.stage.get_key_focus();
this._prevKeyFocusActor = global.stage.get_key_focus();
// We need to use the captured event in the overview, because we don't want to change the stage input mode to
// FOCUSED there. On the other hand, using the captured event doesn't work correctly in the main view because
// it doesn't allow focusing the windows again correctly. So we are using the FOCUSED stage input mode in the
// main view.
if (Main.overview.visible) {
if (!Main.pushModal(this.actor))
return;
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
} else {
if (!Main.overview.visible)
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
this._focusWindowChangedId = metaDisplay.connect('notify::focus-window', Lang.bind(this, this._focusWindowChanged));
this._stageInputModeChangedId = global.connect('notify::stage-input-mode', Lang.bind(this, this._stageInputModeChanged));
// Use captured-event to notice clicks outside the notification
// without consuming them.
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
this._keyPressId = global.stage.connect('key-press-event', Lang.bind(this, this._onKeyPress));
}
// We need to listen to this signal in the overview, as well as in the main view, to make the key bindings such as
// Alt+F2 work. When a notification has key focus, which is the case with chat notifications, all captured KEY_PRESS
// events have the actor with the key focus as their source. This makes it impossible to distinguish between the chat
// window input and the key bindings based solely on the KEY_PRESS event.
this._stageInputModeChangedId = global.connect('notify::stage-input-mode', Lang.bind(this, this._stageInputModeChanged));
this._focusActorChangedId = global.stage.connect('notify::key-focus', Lang.bind(this, this._focusActorChanged));
this._hasFocus = true;
@ -513,19 +669,6 @@ Notification.prototype = {
Main.messageTray.lock();
},
_focusWindowChanged: function() {
let metaDisplay = global.screen.get_display();
// this._focusWindowChanged() will be called when we call
// global.set_stage_input_mode(Shell.StageInputMode.FOCUSED) ,
// however metaDisplay.focus_window will be null in that case. We only
// want to ungrab focus if the focus has been moved to an application
// window.
if (metaDisplay.focus_window) {
this._prevFocusedWindow = null;
this.ungrabFocus();
}
},
_focusActorChanged: function() {
let focusedActor = global.stage.get_key_focus();
if (!focusedActor || !this.actor.contains(focusedActor)) {
@ -535,15 +678,6 @@ Notification.prototype = {
},
_stageInputModeChanged: function() {
let focusedActor = global.stage.get_key_focus();
// TODO: We need to set this._prevFocusedWindow to null in order to
// get the cursor in the run dialog. However, that also means it's
// set to null when the application menu is activated, which defeats
// the point of keeping the name of the previously focused application
// in the panel. It'd be good to be able to distinguish between these
// two cases.
this._prevFocusedWindow = null;
this._prevKeyFocusActor = null;
this.ungrabFocus();
},
@ -566,13 +700,26 @@ Notification.prototype = {
return false;
},
_onKeyPress: function(actor, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.Escape) {
Main.messageTray.escapeTray();
return true;
_onActionInvoked: function(actor, id) {
this.emit('action-invoked', id);
if (!this.resident) {
// We don't hide a resident notification when the user invokes one of its actions,
// because it is common for such notifications to update themselves with new
// information based on the action. We'd like to display the updated information
// in place, rather than pop-up a new notification.
this.emit('done-displaying');
this.destroy();
}
return false;
},
_onClicked: function() {
this.emit('clicked');
// We hide all types of notifications once the user clicks on them because the common
// outcome of clicking should be the relevant window being brought forward and the user's
// attention switching to the window.
this.emit('done-displaying');
if (!this.resident)
this.destroy();
},
ungrabFocus: function() {
@ -580,10 +727,6 @@ Notification.prototype = {
return;
let metaDisplay = global.screen.get_display();
if (this._focusWindowChangedId > 0) {
metaDisplay.disconnect(this._focusWindowChangedId);
this._focusWindowChangedId = 0;
}
if (this._focusActorChangedId > 0) {
global.stage.disconnect(this._focusActorChangedId);
@ -596,20 +739,14 @@ Notification.prototype = {
}
if (this._capturedEventId > 0) {
Main.popModal(this.actor);
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
if (this._keyPressId > 0) {
global.stage.disconnect(this._keyPressId);
this._keyPressId = 0;
}
this._hasFocus = false;
Main.messageTray.unlock();
if (this._prevFocusedWindow) {
if (this._prevFocusedWindow && !metaDisplay.focus_window) {
metaDisplay.set_input_focus_window(this._prevFocusedWindow, false, global.get_current_time());
this._prevFocusedWindow = null;
}
@ -634,8 +771,13 @@ Notification.prototype = {
}
},
destroy: function() {
this.emit('destroy');
destroy: function(reason) {
if (this._destroyed)
return;
this._destroyed = true;
if (!reason)
reason = NotificationDestroyedReason.DISMISSED;
this.emit('destroy', reason);
}
};
Signals.addSignalMethods(Notification.prototype);
@ -651,6 +793,11 @@ Source.prototype = {
this.title = title;
this._iconBin = new St.Bin({ width: this.ICON_SIZE,
height: this.ICON_SIZE });
this.isTransient = false;
},
setTransient: function(isTransient) {
this.isTransient = isTransient;
},
// Called to create a new icon actor (of size this.ICON_SIZE).
@ -681,6 +828,7 @@ Source.prototype = {
this.notification = null;
this._notificationDestroyedId = 0;
this._notificationClickedId = 0;
this._notificationRemoved();
}
}));
@ -700,8 +848,13 @@ Source.prototype = {
this._iconBin.child = icon;
},
// Default implementation is to do nothing, but subclass can override
// Default implementation is to do nothing, but subclasses can override
_notificationClicked: function(notification) {
},
// Default implementation is to destroy this source, but subclasses can override
_notificationRemoved: function() {
this.destroy();
}
};
Signals.addSignalMethods(Source.prototype);
@ -775,8 +928,9 @@ MessageTray.prototype = {
this._notificationBin.hide();
this._notificationQueue = [];
this._notification = null;
this._notificationClickedId = 0;
this._summaryBin = new St.Bin({ anchor_gravity: Clutter.Gravity.NORTH_EAST });
this._summaryBin = new St.Bin({ x_align: St.Align.END });
this.actor.add_actor(this._summaryBin);
this._summary = new St.BoxLayout({ name: 'summary-mode',
reactive: true,
@ -796,6 +950,7 @@ MessageTray.prototype = {
this._summaryNotificationBoxPointer.actor.hide();
this._summaryNotification = null;
this._summaryNotificationClickedId = 0;
this._clickedSummaryItem = null;
this._clickedSummaryItemAllocationChangedId = 0;
this._expandedSummaryItem = null;
@ -867,9 +1022,8 @@ MessageTray.prototype = {
this.actor.width = primary.width;
this._notificationBin.x = 0;
this._notificationBin.width = primary.width;
// These work because of their anchor_gravity
this._summaryBin.x = primary.width;
this._summaryBin.x = 0;
this._summaryBin.width = primary.width;
},
contains: function(source) {
@ -903,7 +1057,15 @@ MessageTray.prototype = {
}
this._summaryItems.push(summaryItem);
this._newSummaryItems.push(summaryItem);
// We keep this._newSummaryItems to track any new sources that were added to the
// summary and show the summary with them to the user for a short period of time
// after notifications are done showing. However, we don't want that to happen for
// transient sources, which are removed after the notification is shown, but are
// not removed fast enough because of the callbacks to avoid the summary popping up.
// So we just don't add transient sources to this._newSummaryItems .
if (!source.isTransient)
this._newSummaryItems.push(summaryItem);
source.connect('notify', Lang.bind(this, this._onNotify));
@ -1028,13 +1190,11 @@ MessageTray.prototype = {
} else if (this._notificationQueue.indexOf(notification) < 0) {
notification.connect('destroy',
Lang.bind(this, this.removeNotification));
if (notification.urgent)
this._notificationQueue.unshift(notification);
else
this._notificationQueue.push(notification);
this._notificationQueue.push(notification);
this._notificationQueue.sort(function(notification1, notification2) {
return (notification2.urgency - notification1.urgency);
});
}
this._updateState();
},
@ -1233,7 +1393,7 @@ MessageTray.prototype = {
let notificationsPending = this._notificationQueue.length > 0;
let notificationPinned = this._pointerInTray && !this._pointerInSummary && !this._notificationRemoved;
let notificationExpanded = this._notificationBin.y < 0;
let notificationExpired = (this._notificationTimeoutId == 0 && !this._pointerInTray && !this._locked) || this._notificationRemoved;
let notificationExpired = (this._notificationTimeoutId == 0 && !(this._notification && this._notification.urgency == Urgency.CRITICAL) && !this._pointerInTray && !this._locked) || this._notificationRemoved;
if (this._notificationState == State.HIDDEN) {
if (notificationsPending)
@ -1335,6 +1495,8 @@ MessageTray.prototype = {
_showNotification: function() {
this._notification = this._notificationQueue.shift();
this._notificationClickedId = this._notification.connect('done-displaying',
Lang.bind(this, this.escapeTray));
this._notificationBin.child = this._notification.actor;
this._notificationBin.opacity = 0;
@ -1359,27 +1521,45 @@ MessageTray.prototype = {
_updateShowingNotification: function() {
Tweener.removeTweens(this._notificationBin);
this._tween(this._notificationBin, '_notificationState', State.SHOWN,
{ y: 0,
opacity: 255,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._showNotificationCompleted,
onCompleteScope: this
});
// We auto-expand urgent notifications.
// We call _expandNotification() again on the notifications that
// are expanded in case they were in the process of hiding and need
// to re-expand.
if (this._notification.urgent || this._notification.expanded)
// This will overwrite the y tween, but leave the opacity
// tween, and so the onComplete will remain as well.
// We auto-expand notifications with CRITICAL urgency.
// We use Tweener.removeTweens() to remove a tween that was hiding the notification we are
// updating, in case that notification was in the process of being hidden. However,
// Tweener.removeTweens() would also remove a tween that was updating the position of the
// notification we are updating, in case that notification was already expanded and its height
// changed. Therefore we need to call this._expandNotification() for expanded notifications
// to make sure their position is updated.
if (this._notification.urgency == Urgency.CRITICAL || this._notification.expanded)
this._expandNotification(true);
// We tween all notifications to full opacity. This ensures that both new notifications and
// notifications that might have been in the process of hiding get full opacity.
//
// We tween any notification showing in the banner mode to banner height (this._notificationBin.y = 0).
// This ensures that both new notifications and notifications in the banner mode that might
// have been in the process of hiding are shown with the banner height.
//
// We use this._showNotificationCompleted() onComplete callback to extend the time the updated
// notification is being shown.
//
// We don't set the y parameter for the tween for expanded notifications because
// this._expandNotification() will result in getting this._notificationBin.y set to the appropriate
// fully expanded value.
let tweenParams = { opacity: 255,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._showNotificationCompleted,
onCompleteScope: this
};
if (!this._notification.expanded)
tweenParams.y = 0;
this._tween(this._notificationBin, '_notificationState', State.SHOWN, tweenParams);
},
_showNotificationCompleted: function() {
this._updateNotificationTimeout(NOTIFICATION_TIMEOUT * 1000);
if (this._notification.urgency != Urgency.CRITICAL)
this._updateNotificationTimeout(NOTIFICATION_TIMEOUT * 1000);
},
_updateNotificationTimeout: function(timeout) {
@ -1432,7 +1612,12 @@ MessageTray.prototype = {
this._notificationBin.hide();
this._notificationBin.child = null;
this._notification.collapseCompleted();
this._notification.disconnect(this._notificationClickedId);
this._notificationClickedId = 0;
let notification = this._notification;
this._notification = null;
if (notification.isTransient)
notification.destroy(NotificationDestroyedReason.EXPIRED);
},
_expandNotification: function(autoExpanding) {
@ -1459,7 +1644,7 @@ MessageTray.prototype = {
},
// We use this function to grab focus when the user moves the pointer
// to an urgent notification that was already auto-expanded.
// to a notification with CRITICAL urgency that was already auto-expanded.
_ensureNotificationFocused: function() {
this._notification.grabFocus(false);
},
@ -1506,7 +1691,8 @@ MessageTray.prototype = {
_showSummaryNotification: function() {
this._summaryNotification = this._clickedSummaryItem.source.notification;
this._summaryNotificationClickedId = this._summaryNotification.connect('done-displaying',
Lang.bind(this, this.escapeTray));
let index = this._notificationQueue.indexOf(this._summaryNotification);
if (index != -1)
this._notificationQueue.splice(index, 1);
@ -1529,8 +1715,8 @@ MessageTray.prototype = {
this._summaryNotificationBoxPointer.actor.show();
this._adjustNotificationBoxPointerPosition();
this._summaryNotificationState = State.SHOWNING;
this._summaryNotificationBoxPointer.animateAppear(Lang.bind(this, function() {
this._summaryNotificationState = State.SHOWING;
this._summaryNotificationBoxPointer.show(true, Lang.bind(this, function() {
this._summaryNotificationState = State.SHOWN;
}));
},
@ -1569,18 +1755,46 @@ MessageTray.prototype = {
this._summaryNotification.ungrabFocus();
this._summaryNotificationState = State.HIDING;
this._summaryNotificationBoxPointer.animateDisappear(Lang.bind(this, this._hideSummaryNotificationCompleted));
this._summaryNotificationBoxPointer.hide(true, Lang.bind(this, this._hideSummaryNotificationCompleted));
},
_hideSummaryNotificationCompleted: function() {
this._summaryNotificationState = State.HIDDEN;
this._summaryNotificationBoxPointer.bin.child = null;
this._summaryNotification.collapseCompleted();
this._summaryNotification.disconnect(this._summaryNotificationClickedId);
this._summaryNotificationClickedId = 0;
let summaryNotification = this._summaryNotification;
this._summaryNotification = null;
if (summaryNotification.isTransient && !this._reNotifyWithSummaryNotificationAfterHide)
summaryNotification.destroy(NotificationDestroyedReason.EXPIRED);
if (this._reNotifyWithSummaryNotificationAfterHide) {
this._onNotify(summaryNotification.source, summaryNotification);
this._reNotifyWithSummaryNotificationAfterHide = false;
}
}
};
function SystemNotificationSource() {
this._init();
}
SystemNotificationSource.prototype = {
__proto__: Source.prototype,
_init: function() {
Source.prototype._init.call(this, _("System Information"));
this._setSummaryIcon(this.createNotificationIcon());
},
createNotificationIcon: function() {
return new St.Icon({ icon_name: 'dialog-information',
icon_type: St.IconType.SYMBOLIC,
icon_size: this.ICON_SIZE });
},
_notificationClicked: function() {
this.destroy();
}
};

233
js/ui/modalDialog.js Normal file
View File

@ -0,0 +1,233 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Gdk = imports.gi.Gdk;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Pango = imports.gi.Pango;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Params = imports.misc.params;
const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const OPEN_AND_CLOSE_TIME = 0.1;
const FADE_OUT_DIALOG_TIME = 1.0;
const State = {
OPENED: 0,
CLOSED: 1,
OPENING: 2,
CLOSING: 3,
FADED_OUT: 4
};
function ModalDialog() {
this._init();
}
ModalDialog.prototype = {
_init: function(params) {
params = Params.parse(params, { styleClass: null });
this.state = State.CLOSED;
this._group = new St.Group({ visible: false,
x: 0,
y: 0 });
Main.uiGroup.add_actor(this._group);
global.focus_manager.add_group(this._group);
this._initialKeyFocus = this._group;
this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy));
this._actionKeys = {};
this._group.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
this._lightbox = new Lightbox.Lightbox(this._group,
{ inhibitEvents: true });
this._backgroundBin = new St.Bin();
this._group.add_actor(this._backgroundBin);
this._lightbox.highlight(this._backgroundBin);
this._dialogLayout = new St.BoxLayout({ style_class: 'modal-dialog',
vertical: true });
if (params.styleClass != null) {
this._dialogLayout.add_style_class_name(params.styleClass);
}
this._backgroundBin.child = this._dialogLayout;
this.contentLayout = new St.BoxLayout({ vertical: true });
this._dialogLayout.add(this.contentLayout,
{ x_fill: true,
y_fill: true,
x_align: St.Align.MIDDLE,
y_align: St.Align.START });
this._buttonLayout = new St.BoxLayout({ opacity: 220,
vertical: false });
this._dialogLayout.add(this._buttonLayout,
{ expand: true,
x_align: St.Align.MIDDLE,
y_align: St.Align.END });
},
setButtons: function(buttons) {
this._buttonLayout.remove_all();
let i = 0;
for (let index in buttons) {
let buttonInfo = buttons[index];
let label = buttonInfo['label'];
let action = buttonInfo['action'];
let key = buttonInfo['key'];
let button = new St.Button({ style_class: 'modal-dialog-button',
reactive: true,
can_focus: true,
label: label });
let x_alignment;
if (buttons.length == 1)
x_alignment = St.Align.END;
else if (i == 0)
x_alignment = St.Align.START;
else if (i == buttons.length - 1)
x_alignment = St.Align.END;
else
x_alignment = St.Align.MIDDLE;
this._initialKeyFocus = button;
this._buttonLayout.add(button,
{ expand: true,
x_fill: false,
y_fill: false,
x_align: x_alignment,
y_align: St.Align.MIDDLE });
button.connect('clicked', action);
if (key)
this._actionKeys[key] = action;
i++;
}
},
_onKeyPressEvent: function(object, keyPressEvent) {
let symbol = keyPressEvent.get_key_symbol();
let action = this._actionKeys[symbol];
if (action)
action();
},
_onGroupDestroy: function() {
this.emit('destroy');
},
_fadeOpen: function() {
let monitor = global.get_focus_monitor();
this._backgroundBin.set_position(monitor.x, monitor.y);
this._backgroundBin.set_size(monitor.width, monitor.height);
this.state = State.OPENING;
this._dialogLayout.opacity = 255;
this._lightbox.show();
this._group.opacity = 0;
this._group.show();
Tweener.addTween(this._group,
{ opacity: 255,
time: OPEN_AND_CLOSE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this._initialKeyFocus.grab_key_focus();
this.state = State.OPENED;
this.emit('opened');
}),
});
},
open: function(timestamp) {
if (this.state == State.OPENED || this.state == State.OPENING)
return true;
if (!Main.pushModal(this._group, timestamp))
return false;
global.stage.set_key_focus(this._group);
this._fadeOpen();
return true;
},
close: function(timestamp) {
if (this.state == State.CLOSED || this.state == State.CLOSING)
return;
let needsPopModal;
if (this.state == State.OPENED || this.state == State.OPENING)
needsPopModal = true;
else
needsPopModal = false;
this.state = State.CLOSING;
Tweener.addTween(this._group,
{ opacity: 0,
time: OPEN_AND_CLOSE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this.state = State.CLOSED;
this._group.hide();
if (needsPopModal)
Main.popModal(this._group, timestamp);
})
});
},
// This method is like close, but fades the dialog out much slower,
// and leaves the lightbox in place. Once in the faded out state,
// the dialog can be brought back by an open call, or the lightbox
// can be dismissed by a close call.
//
// The main point of this method is to give some indication to the user
// that the dialog reponse has been acknowledged but will take a few
// moments before being processed.
// e.g., if a user clicked "Log Out" then the dialog should go away
// imediately, but the lightbox should remain until the logout is
// complete.
_fadeOutDialog: function(timestamp) {
if (this.state == State.CLOSED || this.state == State.CLOSING)
return;
if (this.state == State.FADED_OUT)
return;
Tweener.addTween(this._dialogLayout,
{ opacity: 0,
time: FADE_OUT_DIALOG_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this.state = State.FADED_OUT;
Main.popModal(this._group, timestamp);
})
});
}
};
Signals.addSignalMethods(ModalDialog.prototype);

View File

@ -9,9 +9,11 @@ const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Config = imports.misc.config;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const Params = imports.misc.params;
const Util = imports.misc.util;
let nextNotificationId = 1;
@ -75,11 +77,11 @@ const Urgency = {
const rewriteRules = {
'XChat': [
{ pattern: /^XChat: Private message from: (\S*) \(.*\)$/,
replacement: '&lt;$1&gt;' },
replacement: '<$1>' },
{ pattern: /^XChat: New public message from: (\S*) \((.*)\)$/,
replacement: '$2 &lt;$1&gt;' },
replacement: '$2 <$1>' },
{ pattern: /^XChat: Highlighted message from: (\S*) \((.*)\)$/,
replacement: '$2 &lt;$1&gt;' }
replacement: '$2 <$1>' }
]
};
@ -126,17 +128,8 @@ NotificationDaemon.prototype = {
log('Failed to acquire org.freedesktop.Notifications');
else {
log('Failed to acquire org.freedesktop.Notifications; trying again');
// kill the notification-daemon. pkill is more portable
// than killall, but on Linux at least it won't match if
// you pass more than 15 characters of the process name...
// However, if you use the '-f' flag to match the entire
// command line, it will work, but we have to be careful
// in that case that we don't match 'gedit
// notification-daemon.c' or whatever...
let p = new Shell.Process({ args: ['pkill', '-f',
'^([^ ]*/)?(notification-daemon|notify-osd)$']});
p.run();
Util.killall('notification-daemon');
Util.killall('notify-osd');
}
},
@ -153,9 +146,9 @@ NotificationDaemon.prototype = {
return new St.Icon({ icon_name: icon,
icon_type: St.IconType.FULLCOLOR,
icon_size: size });
} else if (hints.icon_data) {
} else if (hints['image-data']) {
let [width, height, rowStride, hasAlpha,
bitsPerSample, nChannels, data] = hints.icon_data;
bitsPerSample, nChannels, data] = hints['image-data'];
return textureCache.load_from_raw(data, data.length, hasAlpha,
width, height, rowStride, size);
} else {
@ -175,14 +168,43 @@ NotificationDaemon.prototype = {
}
},
_newSource: function(title, pid) {
let source = new Source(title, pid);
this._sources[pid] = source;
// Returns the source associated with ndata.notification if it is set.
// Otherwise, returns the source associated with the pid if one is
// stored in this._sources and the notification is not transient.
// Otherwise, creates a new source as long as pid is provided.
//
// Either a pid or ndata.notification is needed to retrieve or
// create a source.
_getSource: function(title, pid, ndata) {
if (!pid && !(ndata && ndata.notification))
return null;
source.connect('destroy', Lang.bind(this,
function() {
delete this._sources[pid];
}));
// We use notification's source for the notifications we still have
// around that are getting replaced because we don't keep sources
// for transient notifications in this._sources, but we still want
// the notification associated with them to get replaced correctly.
if (ndata && ndata.notification)
return ndata.notification.source;
let isForTransientNotification = (ndata && ndata.hints['transient'] == true);
// We don't want to override a persistent notification
// with a transient one from the same sender, so we
// always create a new source object for new transient notifications
// and never add it to this._sources .
if (!isForTransientNotification && this._sources[pid])
return this._sources[pid];
let source = new Source(title, pid);
source.setTransient(isForTransientNotification);
if (!isForTransientNotification) {
this._sources[pid] = source;
source.connect('destroy', Lang.bind(this,
function() {
delete this._sources[pid];
}));
}
Main.messageTray.add(source);
return source;
@ -205,8 +227,6 @@ NotificationDaemon.prototype = {
return id;
}
summary = GLib.markup_escape_text(summary, -1);
let rewrites = rewriteRules[appName];
if (rewrites) {
for (let i = 0; i < rewrites.length; i++) {
@ -218,6 +238,15 @@ NotificationDaemon.prototype = {
hints = Params.parse(hints, { urgency: Urgency.NORMAL }, true);
// Be compatible with the various hints for image data
// 'image-data' is the latest name of this hint, introduced in 1.2
if (!hints['image-data']) {
if (hints['image_data'])
hints['image-data'] = hints['image_data']; // version 1.1 of the spec
else if (hints['icon_data'])
hints['image-data'] = hints['icon_data']; // previous versions of the spec
}
let ndata = { appName: appName,
icon: icon,
summary: summary,
@ -236,7 +265,8 @@ NotificationDaemon.prototype = {
let sender = DBus.getCurrentMessageContext().sender;
let pid = this._senderToPid[sender];
let source = pid ? this._sources[pid] : null;
let source = this._getSource(appName, pid, ndata);
if (source) {
this._notifyForSource(source, ndata);
@ -257,16 +287,23 @@ NotificationDaemon.prototype = {
if (!ndata)
return;
this._senderToPid[sender] = pid;
source = this._sources[pid];
if (!source)
source = this._newSource(appName, pid);
source.connect('destroy', Lang.bind(this,
function() {
delete this._senderToPid[sender];
}));
source = this._getSource(appName, pid, ndata);
// We only store sender-pid entries for persistent sources.
// Removing the entries once the source is destroyed
// would result in the entries associated with transient
// sources removed once the notification is shown anyway.
// However, keeping these pairs would mean that we would
// possibly remove an entry associated with a persistent
// source when a transient source for the same sender is
// distroyed.
if (!source.isTransient) {
this._senderToPid[sender] = pid;
source.connect('destroy', Lang.bind(this,
function() {
delete this._senderToPid[sender];
}));
}
this._notifyForSource(source, ndata);
}));
@ -281,19 +318,34 @@ NotificationDaemon.prototype = {
let iconActor = this._iconForNotificationData(icon, hints, source.ICON_SIZE);
if (notification == null) {
notification = new MessageTray.Notification(source, summary, body, { icon: iconActor });
notification = new MessageTray.Notification(source, summary, body,
{ icon: iconActor,
bannerMarkup: true });
ndata.notification = notification;
notification.connect('clicked', Lang.bind(this,
function(n) {
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
}));
notification.connect('destroy', Lang.bind(this,
function(n) {
function(n, reason) {
delete this._notifications[id];
let notificationClosedReason;
switch (reason) {
case MessageTray.NotificationDestroyedReason.EXPIRED:
notificationClosedReason = NotificationClosedReason.EXPIRED;
break;
case MessageTray.NotificationDestroyedReason.DISMISSED:
notificationClosedReason = NotificationClosedReason.DISMISSED;
break;
case MessageTray.NotificationDestroyedReason.SOURCE_CLOSED:
notificationClosedReason = NotificationClosedReason.APP_CLOSED;
break;
}
this._emitNotificationClosed(id, notificationClosedReason);
}));
notification.connect('action-invoked', Lang.bind(this,
function(n, actionId) {
this._emitActionInvoked(id, actionId);
}));
notification.connect('action-invoked', Lang.bind(this, this._actionInvoked, source, id));
} else {
notification.update(summary, body, { icon: iconActor,
bannerMarkup: true,
clear: true });
}
@ -302,8 +354,21 @@ NotificationDaemon.prototype = {
for (let i = 0; i < actions.length - 1; i += 2)
notification.addButton(actions[i], actions[i + 1]);
}
notification.setUrgent(hints.urgency == Urgency.CRITICAL);
switch (hints.urgency) {
case Urgency.LOW:
notification.setUrgency(MessageTray.Urgency.LOW);
break;
case Urgency.NORMAL:
notification.setUrgency(MessageTray.Urgency.NORMAL);
break;
case Urgency.CRITICAL:
notification.setUrgency(MessageTray.Urgency.CRITICAL);
break;
}
notification.setResident(hints.resident == true);
// 'transient' is a reserved keyword in JS, so we have to retrieve the value
// of the 'transient' hint with hints['transient'] rather than hints.transient
notification.setTransient(hints['transient'] == true);
let sourceIconActor = source.useNotificationIcon ? this._iconForNotificationData(icon, hints, source.ICON_SIZE) : null;
source.notify(notification, sourceIconActor);
@ -313,10 +378,9 @@ NotificationDaemon.prototype = {
let ndata = this._notifications[id];
if (ndata) {
if (ndata.notification)
ndata.notification.destroy();
ndata.notification.destroy(MessageTray.NotificationDestroyedReason.SOURCE_CLOSED);
delete this._notifications[id];
}
this._emitNotificationClosed(id, NotificationClosedReason.APP_CLOSED);
},
GetCapabilities: function() {
@ -336,10 +400,10 @@ NotificationDaemon.prototype = {
GetServerInformation: function() {
return [
'GNOME Shell',
Config.PACKAGE_NAME,
'GNOME',
'0.1', // FIXME, get this from somewhere
'1.0'
Config.PACKAGE_VERSION,
'1.2'
];
},
@ -351,17 +415,13 @@ NotificationDaemon.prototype = {
for (let id in this._sources) {
let source = this._sources[id];
if (source.app == tracker.focus_app) {
source.activated();
if (source.notification && !source.notification.resident)
source.notification.destroy();
return;
}
}
},
_actionInvoked: function(notification, action, source, id) {
source.activated();
this._emitActionInvoked(id, action);
},
_emitNotificationClosed: function(id, reason) {
DBus.session.emit_signal('/org/freedesktop/Notifications',
'org.freedesktop.Notifications',
@ -377,9 +437,7 @@ NotificationDaemon.prototype = {
},
_onTrayIconAdded: function(o, icon) {
let source = this._sources[icon.pid];
if (!source)
source = this._newSource(icon.title || icon.wm_class || _("Unknown"), icon.pid);
let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null);
source.setTrayIcon(icon);
},
@ -420,13 +478,16 @@ Source.prototype = {
},
_setApp: function() {
if (this.app)
return;
this.app = Shell.WindowTracker.get_default().get_app_from_pid(this._pid);
if (!this.app)
return;
// Only override the icon if we were previously using
// notification-based icons (ie, not a trayicon)
if (this.useNotificationIcon) {
// notification-based icons (ie, not a trayicon) or if it was unset before
if (!this._isTrayIcon) {
this.useNotificationIcon = false;
this._setSummaryIcon(this.app.create_icon_texture (this.ICON_SIZE));
}
@ -439,12 +500,10 @@ Source.prototype = {
},
_notificationClicked: function(notification) {
notification.destroy();
this.openApp();
this.activated();
},
activated: function() {
_notificationRemoved: function() {
if (!this._isTrayIcon)
this.destroy();
},

File diff suppressed because it is too large Load Diff

View File

@ -12,10 +12,12 @@ const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Calendar = imports.ui.calendar;
const Config = imports.misc.config;
const Overview = imports.ui.overview;
const PopupMenu = imports.ui.popupMenu;
const PanelMenu = imports.ui.panelMenu;
const StatusMenu = imports.ui.statusMenu;
const DateMenu = imports.ui.dateMenu;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
@ -25,6 +27,8 @@ const PANEL_ICON_SIZE = 24;
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
const BUTTON_DND_ACTIVATION_TIMEOUT = 250;
const ANIMATED_ICON_UPDATE_TIMEOUT = 100;
const SPINNER_UPDATE_TIMEOUT = 130;
const SPINNER_SPEED = 0.02;
@ -33,11 +37,17 @@ const STANDARD_TRAY_ICON_ORDER = ['a11y', 'display', 'keyboard', 'volume', 'blue
const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
'a11y': imports.ui.status.accessibility.ATIndicator,
'volume': imports.ui.status.volume.Indicator,
'battery': imports.ui.status.power.Indicator
'battery': imports.ui.status.power.Indicator,
'keyboard': imports.ui.status.keyboard.XKBIndicator
};
const CLOCK_FORMAT_KEY = 'format';
const CLOCK_CUSTOM_FORMAT_KEY = 'custom-format';
if (Config.HAVE_BLUETOOTH)
STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION['bluetooth'] = imports.ui.status.bluetooth.Indicator;
// in org.gnome.desktop.interface
const CLOCK_FORMAT_KEY = 'clock-format';
// in org.gnome.shell.clock
const CLOCK_SHOW_DATE_KEY = 'show-date';
const CLOCK_SHOW_SECONDS_KEY = 'show-seconds';
@ -483,147 +493,6 @@ AppMenuButton.prototype = {
Signals.addSignalMethods(AppMenuButton.prototype);
function ClockButton() {
this._init();
}
ClockButton.prototype = {
__proto__: PanelMenu.Button.prototype,
_init: function() {
PanelMenu.Button.prototype._init.call(this, St.Align.START);
this.menu.addAction(_("Preferences"), Lang.bind(this, this._onPrefs));
this._clock = new St.Label();
this.actor.set_child(this._clock);
this._calendarPopup = null;
this._clockSettings = new Gio.Settings({ schema: 'org.gnome.shell.clock' });
this._clockSettings.connect('changed', Lang.bind(this, this._updateClock));
// Start the clock
this._updateClock();
},
_onButtonPress: function(actor, event) {
let button = event.get_button();
if (button == 3 &&
(!this._calendarPopup || !this._calendarPopup.isOpen))
this.menu.toggle();
else
this._toggleCalendar();
},
closeCalendar: function() {
if (!this._calendarPopup || !this._calendarPopup.isOpen)
return;
this._calendarPopup.hide();
this.menu.isOpen = false;
this.actor.remove_style_pseudo_class('pressed');
},
openCalendar: function() {
this._calendarPopup.show();
// simulate an open menu, so it won't appear beneath the calendar
this.menu.isOpen = true;
this.actor.add_style_pseudo_class('pressed');
},
_onPrefs: function() {
let args = ['gnome-shell-clock-preferences'];
let p = new Shell.Process({ args: args });
p.run();
},
_toggleCalendar: function() {
if (this._calendarPopup == null) {
this._calendarPopup = new CalendarPopup();
this._calendarPopup.actor.hide();
}
if (this.menu.isOpen && !this._calendarPopup.isOpen) {
this.menu.close();
return;
}
if (!this._calendarPopup.isOpen)
this.openCalendar();
else
this.closeCalendar();
},
_updateClock: function() {
let format = this._clockSettings.get_string(CLOCK_FORMAT_KEY);
let showDate = this._clockSettings.get_boolean(CLOCK_SHOW_DATE_KEY);
let showSeconds = this._clockSettings.get_boolean(CLOCK_SHOW_SECONDS_KEY);
let clockFormat;
switch (format) {
case 'unix':
// force updates every second
showSeconds = true;
clockFormat = '%s';
break;
case 'custom':
// force updates every second
showSeconds = true;
clockFormat = this._clockSettings.get_string(CLOCK_CUSTOM_FORMAT_KEY);
break;
case '24-hour':
if (showDate)
/* Translators: This is the time format with date used
in 24-hour mode. */
clockFormat = showSeconds ? _("%a %b %e, %R:%S")
: _("%a %b %e, %R");
else
/* Translators: This is the time format without date used
in 24-hour mode. */
clockFormat = showSeconds ? _("%a %R:%S")
: _("%a %R");
break;
case '12-hour':
default:
if (showDate)
/* Translators: This is a time format with date used
for AM/PM. */
clockFormat = showSeconds ? _("%a %b %e, %l:%M:%S %p")
: _("%a %b %e, %l:%M %p");
else
/* Translators: This is a time format without date used
for AM/PM. */
clockFormat = showSeconds ? _("%a %l:%M:%S %p")
: _("%a %l:%M %p");
break;
}
let displayDate = new Date();
let msecRemaining;
if (showSeconds) {
msecRemaining = 1000 - displayDate.getMilliseconds();
if (msecRemaining < 50) {
displayDate.setSeconds(displayDate.getSeconds() + 1);
msecRemaining += 1000;
}
} else {
msecRemaining = 60000 - (1000 * displayDate.getSeconds() +
displayDate.getMilliseconds());
if (msecRemaining < 500) {
displayDate.setMinutes(displayDate.getMinutes() + 1);
msecRemaining += 60000;
}
}
this._clock.set_text(displayDate.toLocaleFormat(clockFormat));
Mainloop.timeout_add(msecRemaining, Lang.bind(this, this._updateClock));
return false;
}
};
function Panel() {
this._init();
}
@ -748,7 +617,20 @@ Panel.prototype = {
reactive: true,
can_focus: true });
this.button.set_child(label);
this.button._delegate = this.button;
this.button._xdndTimeOut = 0;
this.button.handleDragOver = Lang.bind(this,
function(source, actor, x, y, time) {
if (source == Main.xdndHandler) {
if (this.button._xdndTimeOut != 0)
Mainloop.source_remove(this.button._xdndTimeOut);
this.button._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT,
Lang.bind(this,
function() {
this._xdndShowOverview(actor);
}));
}
});
this._leftBox.add(this.button);
// We use this flag to mark the case where the user has entered the
@ -786,6 +668,18 @@ Panel.prototype = {
this._hotCorner.connect('leave-event',
Lang.bind(this, this._onHotCornerLeft));
this._hotCorner._delegate = this._hotCorner;
this._hotCorner.handleDragOver = Lang.bind(this,
function(source, actor, x, y, time) {
if (source == Main.xdndHandler) {
if(!Main.overview.visible && !Main.overview.animationInProgress) {
this.rippleAnimation();
Main.overview.showTemporarily();
Main.overview.beginItemDrag(actor);
}
}
});
this._boxContainer.add_actor(this._hotCornerEnvirons);
this._boxContainer.add_actor(this._hotCorner);
@ -795,45 +689,25 @@ Panel.prototype = {
this._menus.addMenu(appMenuButton.menu);
/* center */
this._clockButton = new ClockButton();
this._centerBox.add(this._clockButton.actor, { y_fill: true });
this._menus.addMenu(this._clockButton.menu);
this._dateMenu = new DateMenu.DateMenuButton();
this._centerBox.add(this._dateMenu.actor, { y_fill: true });
this._menus.addMenu(this._dateMenu.menu);
/* right */
// System status applets live in statusBox, while legacy tray icons
// live in trayBox
// The trayBox is hidden when there are no tray icons.
let statusBox = new St.BoxLayout({ name: 'statusTray' });
let trayBox = new St.BoxLayout({ name: 'legacyTray' });
this._trayBox = trayBox;
this._statusBox = statusBox;
this._trayBox = new St.BoxLayout({ name: 'legacyTray' });
this._statusBox = new St.BoxLayout({ name: 'statusTray' });
trayBox.hide();
this._rightBox.add(trayBox);
this._rightBox.add(statusBox);
for (let i = 0; i < STANDARD_TRAY_ICON_ORDER.length; i++) {
let role = STANDARD_TRAY_ICON_ORDER[i];
let constructor = STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION[role];
if (!constructor) {
// This icon is not implemented (this is a bug)
continue;
}
let indicator = new constructor();
statusBox.add(indicator.actor);
this._menus.addMenu(indicator.menu);
}
this._trayBox.hide();
this._rightBox.add(this._trayBox);
this._rightBox.add(this._statusBox);
Main.statusIconDispatcher.connect('status-icon-added', Lang.bind(this, this._onTrayIconAdded));
Main.statusIconDispatcher.connect('status-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
this._statusmenu = new StatusMenu.StatusMenuButton();
this._menus.addMenu(this._statusmenu.menu);
this._rightBox.add(this._statusmenu.actor);
// TODO: decide what to do with the rest of the panel in the Overview mode (make it fade-out, become non-reactive, etc.)
// We get into the Overview mode on button-press-event as opposed to button-release-event because eventually we'll probably
// have the Overview act like a menu that allows the user to release the mouse on the activity the user wants
@ -859,8 +733,41 @@ Panel.prototype = {
Main.chrome.addActor(this.actor, { visibleInOverview: true });
},
hideCalendar: function() {
this._clockButton.closeCalendar();
_xdndShowOverview: function (actor) {
let [x, y, mask] = global.get_pointer();
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
if (pickedActor != this.button) {
Mainloop.source_remove(this.button._xdndTimeOut);
this.button._xdndTimeOut = 0;
return;
}
if(!Main.overview.visible && !Main.overview.animationInProgress) {
Main.overview.showTemporarily();
Main.overview.beginItemDrag(actor);
}
Mainloop.source_remove(this.button._xdndTimeOut);
this.button._xdndTimeOut = 0;
},
startStatusArea: function() {
for (let i = 0; i < STANDARD_TRAY_ICON_ORDER.length; i++) {
let role = STANDARD_TRAY_ICON_ORDER[i];
let constructor = STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION[role];
if (!constructor) {
// This icon is not implemented (this is a bug)
continue;
}
let indicator = new constructor();
this._statusBox.add(indicator.actor);
this._menus.addMenu(indicator.menu);
}
this._statusmenu = new StatusMenu.StatusMenuButton();
this._menus.addMenu(this._statusmenu.menu);
this._rightBox.add(this._statusmenu.actor);
},
startupAnimation: function() {
@ -935,6 +842,17 @@ Panel.prototype = {
Main.uiGroup.add_actor(ripple);
},
rippleAnimation: function() {
// Show three concentric ripples expanding outwards; the exact
// parameters were found by trial and error, so don't look
// for them to make perfect sense mathematically
// delay time scale opacity => scale opacity
this._addRipple(0.0, 0.83, 0.25, 1.0, 1.5, 0.0);
this._addRipple(0.05, 1.0, 0.0, 0.7, 1.25, 0.0);
this._addRipple(0.35, 1.0, 0.0, 0.3, 1, 0.0);
},
_onHotCornerEntered : function() {
if (this._menus.grabbed)
return false;
@ -943,14 +861,7 @@ Panel.prototype = {
if (!Main.overview.animationInProgress) {
this._hotCornerActivationTime = Date.now() / 1000;
// Show three concentric ripples expanding outwards; the exact
// parameters were found by trial and error, so don't look
// for them to make perfect sense mathematically
// delay time scale opacity => scale opacity
this._addRipple(0.0, 0.83, 0.25, 1.0, 1.5, 0.0);
this._addRipple(0.05, 1.0, 0.0, 0.7, 1.25, 0.0);
this._addRipple(0.35, 1.0, 0.0, 0.3, 1, 0.0);
this.rippleAnimation();
Main.overview.toggle();
}
}
@ -997,6 +908,9 @@ function CalendarPopup() {
CalendarPopup.prototype = {
_init: function() {
let panelActor = Main.panel.actor;
let alignConstraint = new Clutter.AlignConstraint({ source: panelActor,
align_axis: Clutter.AlignAxis.X_AXIS,
factor: 0.5 });
this.actor = new St.Bin({ name: 'calendarPopup' });
@ -1008,7 +922,7 @@ CalendarPopup.prototype = {
Main.chrome.addActor(this.actor, { visibleInOverview: true,
affectsStruts: false });
this.actor.y = (panelActor.y + panelActor.height - this.actor.height);
this.calendar.actor.connect('notify::width', Lang.bind(this, this._centerPopup));
this.actor.add_constraint(alignConstraint);
},
show: function() {
@ -1021,7 +935,6 @@ CalendarPopup.prototype = {
// Reset the calendar to today's date
this.calendar.setDate(new Date());
this._centerPopup();
this.actor.lower(panelActor);
this.actor.show();
Tweener.addTween(this.actor,
@ -1045,10 +958,5 @@ CalendarPopup.prototype = {
onComplete: function() { this.actor.hide(); },
onCompleteScope: this
});
},
_centerPopup: function() {
let panelActor = Main.panel.actor;
this.actor.x = Math.round(panelActor.x + (panelActor.width - this.actor.width) / 2);
}
};

View File

@ -47,12 +47,9 @@ Button.prototype = {
},
_onOpenStateChanged: function(menu, open) {
if (open) {
if (open)
this.actor.add_style_pseudo_class('pressed');
let focus = global.stage.get_key_focus();
if (!focus || (focus != this.actor && !menu.contains(focus)))
this.actor.grab_key_focus();
} else
else
this.actor.remove_style_pseudo_class('pressed');
}
};

View File

@ -1,6 +1,5 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const GConf = imports.gi.GConf;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Shell = imports.gi.Shell;
@ -14,11 +13,7 @@ const _ = Gettext.gettext;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
const Search = imports.ui.search;
const NAUTILUS_PREFS_DIR = '/apps/nautilus/preferences';
const DESKTOP_IS_HOME_KEY = NAUTILUS_PREFS_DIR + '/desktop_is_home_dir';
const PLACES_ICON_SIZE = 16;
const Util = imports.misc.util;
/**
* Represents a place object, which is most normally a bookmark entry,
@ -109,7 +104,7 @@ PlaceDeviceInfo.prototype = {
this._mount.unmount_finish(res);
} catch (e) {
let message = _("Failed to unmount '%s'").format(o.get_name());
Main.overview.infoBar.setMessage(message,
Main.overview.shellInfo.setMessage(message,
Lang.bind(this, this.remove),
_("Retry"));
}
@ -123,13 +118,9 @@ function PlacesManager() {
PlacesManager.prototype = {
_init: function() {
let gconf = GConf.Client.get_default();
gconf.add_dir(NAUTILUS_PREFS_DIR, GConf.ClientPreloadType.PRELOAD_NONE);
this._defaultPlaces = [];
this._mounts = [];
this._bookmarks = [];
this._isDesktopHome = gconf.get_bool(DESKTOP_IS_HOME_KEY);
let homeFile = Gio.file_new_for_path (GLib.get_home_dir());
let homeUri = homeFile.get_uri();
@ -163,7 +154,7 @@ PlacesManager.prototype = {
icon_size: size });
},
function () {
new Shell.Process({ args: ['nautilus-connect-server'] }).run();
Util.spawn(['nautilus-connect-server']);
});
let networkApp = null;
@ -188,10 +179,7 @@ PlacesManager.prototype = {
}
this._defaultPlaces.push(this._home);
this._desktopMenuIndex = this._defaultPlaces.length;
if (!this._isDesktopHome)
this._defaultPlaces.push(this._desktopMenu);
this._defaultPlaces.push(this._desktopMenu);
if (this._network)
this._defaultPlaces.push(this._network);
@ -229,9 +217,6 @@ PlacesManager.prototype = {
}));
this._reloadBookmarks();
gconf.notify_add(DESKTOP_IS_HOME_KEY, Lang.bind(this, this._updateDesktopMenuVisibility));
},
_updateDevices: function() {
@ -340,21 +325,6 @@ PlacesManager.prototype = {
this.emit('places-updated');
},
_updateDesktopMenuVisibility: function() {
let gconf = GConf.Client.get_default();
this._isDesktopHome = gconf.get_boolean(DESKTOP_IS_HOME_KEY);
if (this._isDesktopHome)
this._removeById(this._defaultPlaces, 'special:desktop');
else
this._defaultPlaces.splice(this._desktopMenuIndex, 0,
this._desktopMenu);
/* See comment in _updateDevices for explanation why there are two signals. */
this.emit('defaults-updated');
this.emit('places-updated');
},
_addMount: function(mount) {
let devItem = new PlaceDeviceInfo(mount);
this._mounts.push(devItem);
@ -402,150 +372,8 @@ PlacesManager.prototype = {
sourceArray.splice(this._lookupIndexById(sourceArray, id), 1);
}
};
Signals.addSignalMethods(PlacesManager.prototype);
/**
* An entry in the places menu.
* @info The corresponding PlaceInfo to populate this entry.
*/
function DashPlaceDisplayItem(info) {
this._init(info);
}
DashPlaceDisplayItem.prototype = {
_init: function(info) {
this.name = info.name;
this._info = info;
this._icon = info.iconFactory(PLACES_ICON_SIZE);
this.actor = new St.Clickable({ style_class: 'places-item',
reactive: true,
x_align: St.Align.START,
x_fill: true });
let box = new St.BoxLayout({ style_class: 'places-item-box' });
this.actor.set_child(box);
let bin = new St.Bin({ child: this._icon });
box.add(bin);
let text = new St.Label({ text: info.name });
box.add(text, { expand: true, x_fill: true });
if (info.isRemovable()) {
let removeIcon = new St.Icon({ icon_name: 'media-eject',
icon_type: St.IconType.FULLCOLOR,
icon_size: PLACES_ICON_SIZE });
let removeIconBox = new St.Clickable({ child: removeIcon,
reactive: true });
box.add(removeIconBox);
removeIconBox.connect('clicked',
Lang.bind(this, function() {
this._info.remove();
}));
}
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
this.actor._delegate = this;
this._draggable = DND.makeDraggable(this.actor);
this._draggable.connect('drag-begin',
Lang.bind(this, function() {
Main.overview.beginItemDrag(this);
}));
this._draggable.connect('drag-end',
Lang.bind(this, function() {
Main.overview.endItemDrag(this);
}));
},
_onClicked: function(b) {
this._info.launch();
Main.overview.hide();
},
getDragActorSource: function() {
return this._icon;
},
getDragActor: function(stageX, stageY) {
return this._info.iconFactory(PLACES_ICON_SIZE);
},
//// Drag and drop methods ////
shellWorkspaceLaunch: function() {
this._info.launch();
}
};
function DashPlaceDisplay() {
this._init();
}
DashPlaceDisplay.prototype = {
_init: function() {
// Places is divided semi-arbitrarily into left and right; a grid would
// look better in that there would be an even number of items left+right,
// but it seems like we want some sort of differentiation between actions
// like "Connect to server..." and regular folders
this.actor = new St.Table({ style_class: 'places-section',
homogeneous: true });
this._defaultsList = [];
this._bookmarksList = [];
this._mountsList = [];
Main.placesManager.connect('defaults-updated', Lang.bind(this, this._updateDefaults));
Main.placesManager.connect('bookmarks-updated', Lang.bind(this, this._updateBookmarks));
Main.placesManager.connect('mounts-updated', Lang.bind(this, this._updateMounts));
this._updateDefaults();
this._updateMounts();
this._updateBookmarks();
},
_updateDefaults: function() {
for (let i = 0; i < this._defaultsList.length; i++)
this._defaultsList[i].destroy();
this._defaultsList = [];
let places = Main.placesManager.getDefaultPlaces();
for (let i = 0; i < places.length; i++) {
this._defaultsList[i] = new DashPlaceDisplayItem(places[i]).actor;
this.actor.add(this._defaultsList[i], {row: i, col: 0});
}
this._updateMounts();
},
_updateMounts: function() {
for (let i = 0; i < this._mountsList.length; i++)
this._mountsList[i].destroy();
this._mountsList = [];
let places = Main.placesManager.getMounts();
for (let i = 0; i < places.length; i++) {
this._mountsList[i] = new DashPlaceDisplayItem(places[i]).actor;
this.actor.add(this._mountsList[i], {row: this._defaultsList.length + i, col: 0});
}
},
_updateBookmarks: function() {
for (let i = 0; i < this._bookmarksList.length; i++)
this._bookmarksList[i].destroy();
this._bookmarksList = [];
let places = Main.placesManager.getBookmarks();
for (let i = 0; i < places.length; i ++) {
this._bookmarksList[i] = new DashPlaceDisplayItem(places[i]).actor;
this.actor.add(this._bookmarksList[i], {row: i, col: 1});
}
}
};
Signals.addSignalMethods(DashPlaceDisplay.prototype);
function PlaceSearchProvider() {
this._init();

View File

@ -87,7 +87,7 @@ PopupBaseMenuItem.prototype = {
},
_onButtonReleaseEvent: function (actor, event) {
this.emit('activate', event);
this.activate(event);
return true;
},
@ -95,7 +95,7 @@ PopupBaseMenuItem.prototype = {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
this.emit('activate', event);
this.activate(event);
return true;
}
return false;
@ -132,29 +132,16 @@ PopupBaseMenuItem.prototype = {
this.emit('destroy');
},
// true if non descendant content includes @actor
contains: function(actor) {
return false;
},
// adds an actor to the menu item; @column defaults to the next
// open column, @span defaults to 1. If @span is -1, the actor
// will span the width of the menu item. Children are not
// allowed to overlap each other.
addActor: function(child, column, span) {
if (column == null) {
if (this._children.length) {
let lastChild = this._children[this._children.length - 1];
column = lastChild.column + lastChild.span;
} else
column = 0;
span = 1;
} else if (span == null)
span = 1;
this._children.push({ actor: child,
column: column,
span: span });
// adds an actor to the menu item; @params can contain %span
// (column span; defaults to 1, -1 means "all the remaining width"),
// %expand (defaults to #false), and %align (defaults to
// #St.Align.START)
addActor: function(child, params) {
params = Params.parse(params, { span: 1,
expand: false,
align: St.Align.START });
params.actor = child;
this._children.push(params);
this.actor.connect('destroy', Lang.bind(this, function () { this._removeChild(child); }));
this.actor.add_actor(child);
},
@ -272,39 +259,58 @@ PopupBaseMenuItem.prototype = {
for (let i = 0, col = 0; i < this._children.length; i++) {
let child = this._children[i];
let childBox = new Clutter.ActorBox();
childBox.x1 = x;
let [minWidth, naturalWidth] = child.actor.get_preferred_width(-1);
let availWidth, extraWidth;
if (this._columnWidths) {
if (child.span == -1)
childBox.x2 = box.x2;
availWidth = box.x2 - x;
else {
childBox.x2 = x;
availWidth = 0;
for (let j = 0; j < child.span; j++)
childBox.x2 += this._columnWidths[col++];
availWidth += this._columnWidths[col++];
}
extraWidth = availWidth - naturalWidth;
} else {
let [min, natural] = child.actor.get_preferred_width(-1);
childBox.x2 = x + natural;
availWidth = naturalWidth;
extraWidth = 0;
}
let [min, natural] = child.actor.get_preferred_height(-1);
childBox.y1 = Math.round(box.y1 + (height - natural) / 2);
childBox.y2 = childBox.y1 + natural;
if (child.expand) {
childBox.x1 = x;
childBox.x2 = x + availWidth;
} else if (child.align === St.Align.CENTER) {
childBox.x1 = x + Math.round(extraWidth / 2);
childBox.x2 = childBox.x1 + naturalWidth;
} else if (child.align === St.Align.END) {
childBox.x2 = x + availWidth;
childBox.x1 = childBox.x2 - naturalWidth;
} else {
childBox.x1 = x;
childBox.x2 = x + naturalWidth;
}
let [minHeight, naturalHeight] = child.actor.get_preferred_height(-1);
childBox.y1 = Math.round(box.y1 + (height - naturalHeight) / 2);
childBox.y2 = childBox.y1 + naturalHeight;
child.actor.allocate(childBox, flags);
x = childBox.x2 + this._spacing;
x += availWidth + this._spacing;
}
}
};
Signals.addSignalMethods(PopupBaseMenuItem.prototype);
function PopupMenuItem(text) {
this._init(text);
function PopupMenuItem() {
this._init.apply(this, arguments);
}
PopupMenuItem.prototype = {
__proto__: PopupBaseMenuItem.prototype,
_init: function (text) {
PopupBaseMenuItem.prototype._init.call(this);
_init: function (text, params) {
PopupBaseMenuItem.prototype._init.call(this, params);
this.label = new St.Label({ text: text });
this.addActor(this.label);
@ -322,7 +328,7 @@ PopupSeparatorMenuItem.prototype = {
PopupBaseMenuItem.prototype._init.call(this, { reactive: false });
this._drawingArea = new St.DrawingArea({ style_class: 'popup-separator-menu-item' });
this.addActor(this._drawingArea, 0, -1);
this.addActor(this._drawingArea, { span: -1, expand: true });
this._drawingArea.connect('repaint', Lang.bind(this, this._onRepaint));
},
@ -367,7 +373,7 @@ PopupSliderMenuItem.prototype = {
this._value = Math.max(Math.min(value, 1), 0);
this._slider = new St.DrawingArea({ style_class: 'popup-slider-menu-item', reactive: true });
this.addActor(this._slider, 0, -1);
this.addActor(this._slider, { span: -1, expand: true });
this._slider.connect('repaint', Lang.bind(this, this._sliderRepaint));
this._slider.connect('button-press-event', Lang.bind(this, this._startDragging));
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
@ -534,7 +540,7 @@ PopupSwitchMenuItem.prototype = {
this._switch = new Switch(active);
this.addActor(this.label);
this.addActor(this._switch.actor);
this.addActor(this._switch.actor, { align: St.Align.END });
this.connect('activate', Lang.bind(this,function(from) {
this.toggle();
@ -569,7 +575,7 @@ PopupImageMenuItem.prototype = {
this.label = new St.Label({ text: text });
this.addActor(this.label);
this._icon = new St.Icon({ style_class: 'popup-menu-icon' });
this.addActor(this._icon);
this.addActor(this._icon, { align: St.Align.END });
this.setIcon(iconName);
},
@ -601,76 +607,21 @@ function findNextInCycle(items, current, direction) {
return items[mod(cur + direction, items.length)];
}
function PopupMenu() {
this._init.apply(this, arguments);
function PopupMenuBase() {
throw new TypeError('Trying to instantiate abstract class PopupMenuBase');
}
PopupMenu.prototype = {
_init: function(sourceActor, alignment, arrowSide, gap) {
PopupMenuBase.prototype = {
_init: function(sourceActor, styleClass) {
this.sourceActor = sourceActor;
this._alignment = alignment;
this._arrowSide = arrowSide;
this._gap = gap;
this._boxPointer = new BoxPointer.BoxPointer(arrowSide,
{ x_fill: true,
y_fill: true,
x_align: St.Align.START });
this.actor = this._boxPointer.actor;
this.actor.style_class = 'popup-menu-boxpointer';
this._boxWrapper = new Shell.GenericContainer();
this._boxWrapper.connect('get-preferred-width', Lang.bind(this, this._boxGetPreferredWidth));
this._boxWrapper.connect('get-preferred-height', Lang.bind(this, this._boxGetPreferredHeight));
this._boxWrapper.connect('allocate', Lang.bind(this, this._boxAllocate));
this._boxPointer.bin.set_child(this._boxWrapper);
this._box = new St.BoxLayout({ style_class: 'popup-menu-content',
vertical: true });
this._boxWrapper.add_actor(this._box);
this.actor.add_style_class_name('popup-menu');
global.focus_manager.add_group(this.actor);
if (sourceActor._delegate instanceof PopupSubMenuMenuItem) {
this._isSubMenu = true;
this.actor.reactive = true;
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
}
this.box = new St.BoxLayout({ style_class: styleClass,
vertical: true });
this.isOpen = false;
this._activeMenuItem = null;
},
_boxGetPreferredWidth: function (actor, forHeight, alloc) {
// Update the menuitem column widths
let columnWidths = [];
let items = this._box.get_children();
for (let i = 0; i < items.length; i++) {
if (items[i]._delegate instanceof PopupBaseMenuItem) {
let itemColumnWidths = items[i]._delegate.getColumnWidths();
for (let j = 0; j < itemColumnWidths.length; j++) {
if (j >= columnWidths.length || itemColumnWidths[j] > columnWidths[j])
columnWidths[j] = itemColumnWidths[j];
}
}
}
for (let i = 0; i < items.length; i++) {
if (items[i]._delegate instanceof PopupBaseMenuItem)
items[i]._delegate.setColumnWidths(columnWidths);
}
// Now they will request the right sizes
[alloc.min_size, alloc.natural_size] = this._box.get_preferred_width(forHeight);
},
_boxGetPreferredHeight: function (actor, forWidth, alloc) {
[alloc.min_size, alloc.natural_size] = this._box.get_preferred_height(forWidth);
},
_boxAllocate: function (actor, box, flags) {
this._box.allocate(box, flags);
},
addAction: function(title, callback) {
var menuItem = new PopupMenuItem(title);
this.addMenuItem(menuItem);
@ -680,10 +631,37 @@ PopupMenu.prototype = {
},
addMenuItem: function(menuItem, position) {
if (position == undefined)
this._box.add(menuItem.actor);
else
this._box.insert_actor(menuItem.actor, position);
let before_item = null;
if (position == undefined) {
this.box.add(menuItem.actor);
} else {
let items = this.getMenuItems();
if (position < items.length) {
before_item = items[position].actor;
this.box.insert_before(menuItem.actor, before_item);
} else
this.box.add(menuItem.actor);
}
if (menuItem instanceof PopupSubMenuMenuItem) {
if (before_item == null)
this.box.add(menuItem.menu.actor);
else
this.box.insert_before(menuItem.menu.actor, before_item);
menuItem._subMenuActivateId = menuItem.menu.connect('activate', Lang.bind(this, function() {
this.emit('activate');
this.close(true);
}));
menuItem._subMenuActiveChangeId = menuItem.menu.connect('active-changed', Lang.bind(this, function(submenu, submenuItem) {
if (this._activeMenuItem && this._activeMenuItem != submenuItem)
this._activeMenuItem.setActive(false);
this._activeMenuItem = submenuItem;
this.emit('active-changed', submenuItem);
}));
menuItem._closingId = this.connect('open-state-changed', function(self, open) {
if (!open)
menuItem.menu.close(false);
});
}
menuItem._activeChangeId = menuItem.connect('active-changed', Lang.bind(this, function (menuItem, active) {
if (active && this._activeMenuItem != menuItem) {
if (this._activeMenuItem)
@ -697,22 +675,50 @@ PopupMenu.prototype = {
}));
menuItem._activateId = menuItem.connect('activate', Lang.bind(this, function (menuItem, event) {
this.emit('activate', menuItem);
this.close();
this.close(true);
}));
menuItem.connect('destroy', Lang.bind(this, function(emitter) {
menuItem.disconnect(menuItem._activateId);
menuItem.disconnect(menuItem._activeChangeId);
if (menuItem.menu) {
menuItem.menu.disconnect(menuItem._subMenuActivateId);
menuItem.menu.disconnect(menuItem._subMenuActiveChangeId);
this.disconnect(menuItem._closingId);
}
if (menuItem == this._activeMenuItem)
this._activeMenuItem = null;
}));
},
getColumnWidths: function() {
let columnWidths = [];
let items = this.box.get_children();
for (let i = 0; i < items.length; i++) {
if (items[i]._delegate instanceof PopupBaseMenuItem || items[i]._delegate instanceof PopupMenuBase) {
let itemColumnWidths = items[i]._delegate.getColumnWidths();
for (let j = 0; j < itemColumnWidths.length; j++) {
if (j >= columnWidths.length || itemColumnWidths[j] > columnWidths[j])
columnWidths[j] = itemColumnWidths[j];
}
}
}
return columnWidths;
},
setColumnWidths: function(widths) {
let items = this.box.get_children();
for (let i = 0; i < items.length; i++) {
if (items[i]._delegate instanceof PopupBaseMenuItem || items[i]._delegate instanceof PopupMenuBase)
items[i]._delegate.setColumnWidths(widths);
}
},
addActor: function(actor) {
this._box.add(actor);
this.box.add(actor);
},
getMenuItems: function() {
return this._box.get_children().map(function (actor) { return actor._delegate; });
return this.box.get_children().map(function (actor) { return actor._delegate; }).filter(function(item) { return item instanceof PopupBaseMenuItem; });
},
removeAll: function() {
@ -723,110 +729,22 @@ PopupMenu.prototype = {
}
},
setArrowOrigin: function(origin) {
this._boxPointer.setArrowOrigin(origin);
},
activateFirst: function() {
let children = this._box.get_children();
let children = this.box.get_children();
for (let i = 0; i < children.length; i++) {
let actor = children[i];
if (actor._delegate && actor.visible && actor.reactive) {
if (actor._delegate && actor._delegate instanceof PopupBaseMenuItem && actor.visible && actor.reactive) {
actor._delegate.setActive(true);
break;
}
}
},
open: function() {
if (this.isOpen)
return;
let primary = global.get_primary_monitor();
// We need to show it now to force an allocation,
// so that we can query the correct size.
this.actor.show();
// Position correctly relative to the sourceActor
let [sourceX, sourceY] = this.sourceActor.get_transformed_position();
let [sourceWidth, sourceHeight] = this.sourceActor.get_transformed_size();
let [minWidth, minHeight, natWidth, natHeight] = this.actor.get_preferred_size();
let menuWidth = natWidth, menuHeight = natHeight;
// Position the non-pointing axis
if (this._isSubmenu) {
if (this._arrowSide == St.Side.TOP || this._arrowSide == St.Side.BOTTOM) {
// vertical submenu
if (sourceY + sourceHeigth + menuHeight + this._gap < primary.y + primary.height)
this._boxPointer._arrowSide = this._arrowSide = St.Side.TOP;
else if (primary.y + menuHeight + this._gap < sourceY)
this._boxPointer._arrowSide = this._arrowSide = St.Side.BOTTOM;
else
this._boxPointer._arrowSide = this._arrowSide = St.Side.TOP;
} else {
// horizontal submenu
if (sourceX + sourceWidth + menuWidth + this._gap < primary.x + primary.width)
this._boxPointer._arrowSide = this._arrowSide = St.Side.LEFT;
else if (primary.x + menuWidth + this._gap < sourceX)
this._boxPointer._arrowSide = this._arrowSide = St.Side.RIGHT;
else
this._boxPointer._arrowSide = this._arrowSide = St.Side.LEFT;
}
}
this._boxPointer.setPosition(this.sourceActor, this._gap, this._alignment);
// Now show it
this.actor.reactive = true;
this._boxPointer.animateAppear();
this.isOpen = true;
this.emit('open-state-changed', true);
},
close: function() {
if (!this.isOpen)
return;
if (this._activeMenuItem)
this._activeMenuItem.setActive(false);
this.actor.reactive = false;
this._boxPointer.animateDisappear();
this.isOpen = false;
this.emit('open-state-changed', false);
},
toggle: function() {
if (this.isOpen)
this.close();
this.close(true);
else
this.open();
},
_onKeyPressEvent: function(actor, event) {
// Move focus back to parent menu if the user types Left.
// (This handler is only connected if the PopupMenu is a
// submenu.)
if (this.isOpen &&
this._activeMenuItem &&
event.get_key_symbol() == Clutter.KEY_Left) {
this._activeMenuItem.setActive(false);
return true;
}
return false;
},
// return true if the actor is inside the menu or
// any actor related to the active submenu
contains: function(actor) {
if (this.actor.contains(actor))
return true;
if (this._activeMenuItem)
return this._activeMenuItem.contains(actor);
return false;
this.open(true);
},
destroy: function() {
@ -836,7 +754,184 @@ PopupMenu.prototype = {
this.emit('destroy');
}
};
Signals.addSignalMethods(PopupMenu.prototype);
Signals.addSignalMethods(PopupMenuBase.prototype);
function PopupMenu() {
this._init.apply(this, arguments);
}
PopupMenu.prototype = {
__proto__: PopupMenuBase.prototype,
_init: function(sourceActor, alignment, arrowSide, gap) {
PopupMenuBase.prototype._init.call (this, sourceActor, 'popup-menu-content');
this._alignment = alignment;
this._arrowSide = arrowSide;
this._gap = gap;
this._boxPointer = new BoxPointer.BoxPointer(arrowSide,
{ x_fill: true,
y_fill: true,
x_align: St.Align.START });
this.actor = this._boxPointer.actor;
this.actor._delegate = this;
this.actor.style_class = 'popup-menu-boxpointer';
this._boxWrapper = new Shell.GenericContainer();
this._boxWrapper.connect('get-preferred-width', Lang.bind(this, this._boxGetPreferredWidth));
this._boxWrapper.connect('get-preferred-height', Lang.bind(this, this._boxGetPreferredHeight));
this._boxWrapper.connect('allocate', Lang.bind(this, this._boxAllocate));
this._boxPointer.bin.set_child(this._boxWrapper);
this._boxWrapper.add_actor(this.box);
this.actor.add_style_class_name('popup-menu');
global.focus_manager.add_group(this.actor);
this.actor.reactive = true;
},
_boxGetPreferredWidth: function (actor, forHeight, alloc) {
let columnWidths = this.getColumnWidths();
this.setColumnWidths(columnWidths);
// Now they will request the right sizes
[alloc.min_size, alloc.natural_size] = this.box.get_preferred_width(forHeight);
},
_boxGetPreferredHeight: function (actor, forWidth, alloc) {
[alloc.min_size, alloc.natural_size] = this.box.get_preferred_height(forWidth);
},
_boxAllocate: function (actor, box, flags) {
this.box.allocate(box, flags);
},
setArrowOrigin: function(origin) {
this._boxPointer.setArrowOrigin(origin);
},
open: function(animate) {
if (this.isOpen)
return;
this.isOpen = true;
this._boxPointer.setPosition(this.sourceActor, this._gap, this._alignment);
this._boxPointer.show(animate);
this.emit('open-state-changed', true);
},
close: function(animate) {
if (!this.isOpen)
return;
if (this._activeMenuItem)
this._activeMenuItem.setActive(false);
this._boxPointer.hide(animate);
this.isOpen = false;
this.emit('open-state-changed', false);
}
};
function PopupSubMenu() {
this._init.apply(this, arguments);
}
PopupSubMenu.prototype = {
__proto__: PopupMenuBase.prototype,
_init: function(sourceActor, sourceArrow) {
PopupMenuBase.prototype._init.call(this, sourceActor, 'popup-sub-menu');
this._arrow = sourceArrow;
this._arrow.rotation_center_z_gravity = Clutter.Gravity.CENTER;
this.actor = this.box;
this.actor._delegate = this;
this.actor.clip_to_allocation = true;
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
this.actor.hide();
},
open: function(animate) {
if (this.isOpen)
return;
this.isOpen = true;
// we don't implement the !animate case because that doesn't
// currently get used...
let [naturalHeight, minHeight] = this.actor.get_preferred_height(-1);
this.actor.height = 0;
this.actor.show();
this.actor._arrow_rotation = this._arrow.rotation_angle_z;
Tweener.addTween(this.actor,
{ _arrow_rotation: 90,
height: naturalHeight,
time: 0.25,
onUpdateScope: this,
onUpdate: function() {
this._arrow.rotation_angle_z = this.actor._arrow_rotation;
},
onCompleteScope: this,
onComplete: function() {
this.actor.set_height(-1);
this.emit('open-state-changed', true);
}
});
},
close: function(animate) {
if (!this.isOpen)
return;
this.isOpen = false;
if (this._activeMenuItem)
this._activeMenuItem.setActive(false);
if (animate) {
this.actor._arrow_rotation = this._arrow.rotation_angle_z;
Tweener.addTween(this.actor,
{ _arrow_rotation: 0,
height: 0,
time: 0.25,
onCompleteScope: this,
onComplete: function() {
this.actor.hide();
this.actor.set_height(-1);
this.emit('open-state-changed', false);
},
onUpdateScope: this,
onUpdate: function() {
this._arrow.rotation_angle_z = this.actor._arrow_rotation;
}
});
} else {
this._arrow.rotation_angle_z = 0;
this.actor.hide();
this.isOpen = false;
this.emit('open-state-changed', false);
}
},
_onKeyPressEvent: function(actor, event) {
// Move focus back to parent menu if the user types Left.
if (this.isOpen && event.get_key_symbol() == Clutter.KEY_Left) {
this.close(true);
this.sourceActor._delegate.setActive(true);
return true;
}
return false;
}
};
function PopupSubMenuMenuItem() {
this._init.apply(this, arguments);
@ -846,77 +941,46 @@ PopupSubMenuMenuItem.prototype = {
__proto__: PopupBaseMenuItem.prototype,
_init: function(text) {
PopupBaseMenuItem.prototype._init.call(this, { activate: false, hover: false });
this.actor.connect('enter-event', Lang.bind(this, this._mouseEnter));
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
PopupBaseMenuItem.prototype._init.call(this);
this.actor.add_style_class_name('popup-submenu-menu-item');
this.label = new St.Label({ text: text });
this.addActor(this.label);
this.addActor(new St.Label({ text: '>' }));
this._triangle = new St.Label({ text: '\u25B8' });
this.addActor(this._triangle, { align: St.Align.END });
this.menu = new PopupMenu(this.actor, St.Align.MIDDLE, St.Side.LEFT, 0, true);
Main.chrome.addActor(this.menu.actor, { visibleInOverview: true,
affectsStruts: false });
this.menu.actor.hide();
this._openStateChangedId = this.menu.connect('open-state-changed', Lang.bind(this, this._subMenuOpenStateChanged));
this._activateId = this.menu.connect('activate', Lang.bind(this, this._subMenuActivate));
this.menu = new PopupSubMenu(this.actor, this._triangle);
this.menu.connect('open-state-changed', Lang.bind(this, this._subMenuOpenStateChanged));
},
_subMenuOpenStateChanged: function(menu, open) {
PopupBaseMenuItem.prototype.setActive.call(this, open);
},
_subMenuActivate: function(menu, menuItem) {
this.emit('activate', null);
},
setMenu: function(newmenu) {
if (this.menu) {
this.menu.close();
this.menu.disconnect(this._openStateChangedId);
this.menu.disconnect(this._activateId);
}
if (newmenu) {
this._openStateChangedId = newmenu.connect('open-state-changed', Lang.bind(this, this._subMenuOpenStateChanged));
this._activateId = newmenu.connect('activate', Lang.bind(this, this._subMenuActivate));
}
this.menu = newmenu;
if (open)
this.actor.add_style_pseudo_class('open');
else
this.actor.remove_style_pseudo_class('open');
},
destroy: function() {
if (this.menu)
this.menu.destroy();
this.menu.destroy();
PopupBaseMenuItem.prototype.destroy.call(this);
},
setActive: function(active) {
if (this.menu) {
if (active)
this.menu.open();
else
this.menu.close();
}
PopupBaseMenuItem.prototype.setActive.call(this, active);
},
_onKeyPressEvent: function(actor, event) {
if (!this.menu)
return false;
if (event.get_key_symbol() == Clutter.KEY_Right) {
this.menu.open(true);
this.menu.activateFirst();
return true;
}
return false;
return PopupBaseMenuItem.prototype._onKeyPressEvent.call(this, actor, event);
},
contains: function(actor) {
return this.menu && this.menu.contains(actor);
activate: function(event) {
this.menu.open(true);
},
_mouseEnter: function(event) {
this.setActive(true);
_onButtonReleaseEvent: function(actor) {
this.menu.toggle();
}
};
@ -939,23 +1003,24 @@ PopupMenuManager.prototype = {
this._leaveEventId = 0;
this._activeMenu = null;
this._menus = [];
this._delayedMenus = [];
this._preGrabInputMode = null;
},
addMenu: function(menu, position) {
let menudata = {
menu: menu,
openStateChangeId: menu.connect('open-state-changed', Lang.bind(this, this._onMenuOpenState)),
activateId: menu.connect('activate', Lang.bind(this, this._onMenuActivated)),
destroyId: menu.connect('destroy', Lang.bind(this, this._onMenuDestroy)),
enterId: 0,
focusId: 0
focusInId: 0,
focusOutId: 0
};
let source = menu.sourceActor;
if (source) {
menudata.enterId = source.connect('enter-event', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
menudata.focusId = source.connect('key-focus-in', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
menudata.focusInId = source.connect('key-focus-in', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
menudata.focusOutId = source.connect('key-focus-out', Lang.bind(this, function() { this._onKeyFocusOut(menu); }));
}
if (position == undefined)
@ -974,18 +1039,19 @@ PopupMenuManager.prototype = {
let menudata = this._menus[position];
menu.disconnect(menudata.openStateChangeId);
menu.disconnect(menudata.activateId);
menu.disconnect(menudata.destroyId);
if (menudata.enterId)
menu.sourceActor.disconnect(menudata.enterId);
if (menudata.focusId)
menu.sourceActor.disconnect(menudata.focusId);
if (menudata.focusInId)
menu.sourceActor.disconnect(menudata.focusInId);
if (menudata.focusOutId)
menu.sourceActor.disconnect(menudata.focusOutId);
this._menus.splice(position, 1);
},
grab: function() {
_grab: function() {
Main.pushModal(this._owner.actor);
this._eventCaptureId = global.stage.connect('captured-event', Lang.bind(this, this._onEventCapture));
@ -997,7 +1063,7 @@ PopupMenuManager.prototype = {
this.grabbed = true;
},
ungrab: function() {
_ungrab: function() {
global.stage.disconnect(this._eventCaptureId);
this._eventCaptureId = 0;
global.stage.disconnect(this._keyPressEventId);
@ -1013,40 +1079,100 @@ PopupMenuManager.prototype = {
_onMenuOpenState: function(menu, open) {
if (open) {
if (!this.grabbed) {
this._preGrabInputMode = global.stage_input_mode;
this._grab();
}
this._activeMenu = menu;
if (!this.grabbed)
this.grab();
// if the focus is not already associated with the menu,
// then focus the menu
let focus = global.stage.key_focus;
if (!this._activeMenuContains(focus))
menu.sourceActor.grab_key_focus();
} else if (menu == this._activeMenu) {
this._activeMenu = null;
let focus = global.stage.key_focus;
let fromActive = this._activeMenuContains(focus);
if (this.grabbed)
this.ungrab();
this._ungrab();
this._activeMenu = null;
// If keynav was in effect before we grabbed, then we need
// to properly re-establish it after we ungrab. (popModal
// will have unset the focus.) If some part of the menu
// was focused at the time of the ungrab then focus its
// sourceActor. Otherwise just reset the focus to where it
// was right before the ungrab.
if (this._preGrabInputMode == Shell.StageInputMode.FOCUSED) {
global.stage_input_mode = Shell.StageInputMode.FOCUSED;
if (fromActive)
menu.sourceActor.grab_key_focus();
else
focus.grab_key_focus();
}
}
},
// change the currently-open menu without dropping grab
_changeMenu: function(newMenu) {
if (this._activeMenu) {
// _onOpenMenuState will drop the grab if it sees
// this._activeMenu being closed; so clear _activeMenu
// before closing it to keep that from happening
let oldMenu = this._activeMenu;
this._activeMenu = null;
oldMenu.close(false);
newMenu.open(false);
} else
newMenu.open(true);
},
_onMenuSourceEnter: function(menu) {
if (!this.grabbed || menu == this._activeMenu)
return false;
if (this._activeMenu != null)
this._activeMenu.close();
menu.open();
this._changeMenu(menu);
return false;
},
_onMenuActivated: function(menu, item) {
if (this.grabbed)
this.ungrab();
_onKeyFocusOut: function(menu) {
if (!this.grabbed || menu != this._activeMenu)
return;
// We want to close the menu if the focus has moved somewhere
// other than inside the menu or to another menu's sourceActor.
// Unfortunately, when key-focus-out is emitted,
// stage.key_focus will be null. So we have to wait until
// after it emits the key-focus-in as well.
let id = global.stage.connect('notify::key-focus', Lang.bind(this,
function () {
global.stage.disconnect(id);
if (menu != this._activeMenu)
return;
let focus = global.stage.key_focus;
if (!focus || this._activeMenuContains(focus))
return;
if (focus._delegate && this._findMenu(focus._delegate.menu) != -1)
return;
menu.close(true);
}));
},
_onMenuDestroy: function(menu) {
this.removeMenu(menu);
},
_eventIsOnActiveMenu: function(event) {
let src = event.get_source();
_activeMenuContains: function(actor) {
return this._activeMenu != null
&& (this._activeMenu.contains(src) ||
(this._activeMenu.sourceActor && this._activeMenu.sourceActor.contains(src)));
&& (this._activeMenu.actor.contains(actor) ||
(this._activeMenu.sourceActor && this._activeMenu.sourceActor.contains(actor)));
},
_eventIsOnActiveMenu: function(event) {
return this._activeMenuContains(event.get_source());
},
_eventIsOnAnyMenuSource: function(event) {
@ -1068,6 +1194,18 @@ PopupMenuManager.prototype = {
return -1;
},
_nextMenu: function(pos, direction) {
for (let i = 1; i < this._menus.length; i++) {
let candidate = mod(pos + i * direction, this._menus.length);
let menu = this._menus[candidate].menu;
if (!menu.sourceActor || menu.sourceActor.visible)
return menu;
}
// no menu is found? this should not happen
// anyway stay on current menu
return this._menus[pos];
},
_onEventCapture: function(actor, event) {
if (!this.grabbed)
return false;
@ -1106,12 +1244,9 @@ PopupMenuManager.prototype = {
if (symbol == Clutter.Left || symbol == Clutter.Right) {
let direction = symbol == Clutter.Right ? 1 : -1;
let pos = this._findMenu(this._activeMenu);
let next = this._menus[mod(pos + direction, this._menus.length)].menu;
let next = this._nextMenu(pos, direction);
if (next != this._activeMenu) {
let oldMenu = this._activeMenu;
this._activeMenu = next;
oldMenu.close();
next.open();
this._changeMenu(next);
next.activateFirst();
}
return true;
@ -1122,6 +1257,6 @@ PopupMenuManager.prototype = {
_closeMenu: function() {
if (this._activeMenu != null)
this._activeMenu.close();
this._activeMenu.close(true);
}
};

View File

@ -11,16 +11,18 @@ const Signals = imports.signals;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Lightbox = imports.ui.lightbox;
const FileUtils = imports.misc.fileUtils;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const Tweener = imports.ui.tweener;
const Util = imports.misc.util;
const MAX_FILE_DELETED_BEFORE_INVALID = 10;
const HISTORY_KEY = 'command-history';
const HISTORY_LIMIT = 512;
const DIALOG_FADE_TIME = 0.1;
const DIALOG_GROW_TIME = 0.1;
function CommandCompleter() {
this._init();
@ -62,25 +64,6 @@ CommandCompleter.prototype = {
this._update(0);
},
_onGetEnumerateComplete : function(obj, res) {
this._enumerator = obj.enumerate_children_finish(res);
this._enumerator.next_files_async(100, GLib.PRIORITY_LOW, null, Lang.bind(this, this._onNextFileComplete));
},
_onNextFileComplete : function(obj, res) {
let files = obj.next_files_finish(res);
for (let i = 0; i < files.length; i++) {
this._childs[this._i].push(files[i].get_name());
}
if (files.length) {
this._enumerator.next_files_async(100, GLib.PRIORITY_LOW, null, Lang.bind(this, this._onNextFileComplete));
} else {
this._enumerator.close(null);
this._enumerator = null;
this._update(this._i + 1);
}
},
update : function() {
if (this._valid)
return;
@ -100,7 +83,12 @@ CommandCompleter.prototype = {
}
let file = Gio.file_new_for_path(this._paths[i]);
this._childs[this._i] = [];
file.enumerate_children_async(Gio.FILE_ATTRIBUTE_STANDARD_NAME, Gio.FileQueryInfoFlags.NONE, GLib.PRIORITY_LOW, null, Lang.bind(this, this._onGetEnumerateComplete));
FileUtils.listDirAsync(file, Lang.bind(this, function (files) {
for (let i = 0; i < files.length; i++) {
this._childs[this._i].push(files[i].get_name());
}
this._update(this._i + 1);
}));
},
_onChanged : function(m, f, of, type) {
@ -175,8 +163,9 @@ function RunDialog() {
}
RunDialog.prototype = {
__proto__: ModalDialog.ModalDialog.prototype,
_init : function() {
this._isOpen = false;
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'run-dialog' });
global.settings.connect('changed::development-tools', Lang.bind(this, function () {
this._enableInternalCommands = global.settings.get_boolean('development-tools');
@ -207,52 +196,45 @@ RunDialog.prototype = {
'debugexit': Lang.bind(this, function() {
Meta.exit(Meta.ExitCode.ERROR);
}),
// rt is short for "reload theme"
'rt': Lang.bind(this, function() {
Main.loadTheme();
})
};
// All actors are inside _group. We create it initially
// hidden then show it in show()
this._group = new Clutter.Group({ visible: false,
x: 0, y: 0 });
Main.uiGroup.add_actor(this._group);
this._lightbox = new Lightbox.Lightbox(this._group,
{ inhibitEvents: true });
this._box = new St.Bin({ x_align: St.Align.MIDDLE,
y_align: St.Align.MIDDLE });
this._group.add_actor(this._box);
this._lightbox.highlight(this._box);
let dialogBox = new St.BoxLayout({ style_class: 'run-dialog', vertical: true });
this._box.set_child(dialogBox);
let label = new St.Label({ style_class: 'run-dialog-label',
text: _("Please enter a command:") });
dialogBox.add(label, { expand: true, y_fill: false });
this.contentLayout.add(label, { y_align: St.Align.START });
let entry = new St.Entry({ style_class: 'run-dialog-entry' });
this._entryText = entry.clutter_text;
dialogBox.add(entry, { expand: true });
this.contentLayout.add(entry, { y_align: St.Align.START });
this.connect('opened',
Lang.bind(this, function() {
this._entryText.grab_key_focus();
}));
this._errorBox = new St.BoxLayout();
this._errorBox = new St.BoxLayout({ style_class: 'run-dialog-error-box' });
dialogBox.add(this._errorBox, { expand: true });
this.contentLayout.add(this._errorBox, { expand: true });
let errorIcon = new St.Button({ style_class: 'run-dialog-error-icon' });
let errorIcon = new St.Icon({ icon_name: 'dialog-error', icon_size: 24, style_class: 'run-dialog-error-icon' });
this._errorBox.add(errorIcon);
this._errorBox.add(errorIcon, { y_align: St.Align.MIDDLE });
this._commandError = false;
this._errorMessage = new St.Label({ style_class: 'run-dialog-error-label' });
this._errorMessage.clutter_text.line_wrap = true;
this._errorBox.add(this._errorMessage, { expand: true });
this._errorBox.add(this._errorMessage, { expand: true,
y_align: St.Align.MIDDLE,
y_fill: false });
this._errorBox.hide();
@ -275,10 +257,10 @@ RunDialog.prototype = {
else
this._run(o.get_text(), false);
if (!this._commandError)
this.close();
this.close(global.get_current_time());
}
if (symbol == Clutter.Escape) {
this.close();
this.close(global.get_current_time());
return true;
}
if (symbol == Clutter.slash) {
@ -349,9 +331,7 @@ RunDialog.prototype = {
try {
if (inTerminal)
command = 'gnome-terminal -x ' + input;
let [ok, len, args] = GLib.shell_parse_argv(command);
let p = new Shell.Process({ 'args' : args });
p.run();
Util.trySpawnCommandLine(command);
} catch (e) {
// Mmmh, that failed - see if @input matches an existing file
let path = null;
@ -369,16 +349,24 @@ RunDialog.prototype = {
global.create_app_launch_context());
} else {
this._commandError = true;
// The exception contains an error string like:
// Error invoking Shell.run: Failed to execute child
// process "foo" (No such file or directory)
// We are only interested in the actual error, so parse
//that out.
let m = /.+\((.+)\)/.exec(e);
let errorStr = _("Execution of '%s' failed:").format(command) + '\n' + m[1];
this._errorMessage.set_text(errorStr);
this._errorBox.show();
this._errorMessage.set_text(e.message);
if (!this._errorBox.visible) {
let [errorBoxMinHeight, errorBoxNaturalHeight] = this._errorBox.get_preferred_height(-1);
let parentActor = this._errorBox.get_parent();
Tweener.addTween(parentActor,
{ height: parentActor.height + errorBoxNaturalHeight,
time: DIALOG_GROW_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
parentActor.set_height(-1);
this._errorBox.show();
})
});
}
}
}
}
@ -400,53 +388,14 @@ RunDialog.prototype = {
this._entryText.set_text('');
},
open : function() {
if (this._isOpen) // Already shown
return;
if (!Main.pushModal(this._group))
return;
// Position the dialog on the current monitor
let monitor = global.get_focus_monitor();
open: function() {
this._historyIndex = this._history.length;
this._box.set_position(monitor.x, monitor.y);
this._box.set_size(monitor.width, monitor.height);
this._isOpen = true;
this._lightbox.show();
this._group.opacity = 0;
this._group.show();
Tweener.addTween(this._group,
{ opacity: 255,
time: DIALOG_FADE_TIME,
transition: 'easeOutQuad'
});
global.stage.set_key_focus(this._entryText);
},
close : function() {
if (!this._isOpen)
return;
this._isOpen = false;
this._errorBox.hide();
this._entryText.set_text('');
this._commandError = false;
Main.popModal(this._group);
ModalDialog.ModalDialog.prototype.open.call(this);
},
Tweener.addTween(this._group,
{ opacity: 0,
time: DIALOG_FADE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this._errorBox.hide();
this._group.hide();
this._entryText.set_text('');
})
});
}
};
Signals.addSignalMethods(RunDialog.prototype);

View File

@ -1,8 +1,21 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Signals = imports.signals;
const Shell = imports.gi.Shell;
const Util = imports.misc.util;
const RESULT_ICON_SIZE = 24;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const FileUtils = imports.misc.fileUtils;
const Main = imports.ui.main;
const DISABLED_OPEN_SEARCH_PROVIDERS_KEY = 'disabled-open-search-providers';
const RESULT_ICON_SIZE = 48;
// Not currently referenced by the search API, but
// this enumeration can be useful for provider
@ -182,7 +195,7 @@ SearchProvider.prototype = {
* implementation will show the icon next to the name.
*
* The actor should be an instance of St.Widget, with the style class
* 'dash-search-result-content'.
* 'search-result-content'.
*/
createResultActor: function(resultMeta, terms) {
return null;
@ -211,6 +224,107 @@ SearchProvider.prototype = {
};
Signals.addSignalMethods(SearchProvider.prototype);
function OpenSearchSystem() {
this._init();
}
OpenSearchSystem.prototype = {
_init: function() {
this._providers = [];
global.settings.connect('changed::' + DISABLED_OPEN_SEARCH_PROVIDERS_KEY, Lang.bind(this, this._refresh));
this._refresh();
},
getProviders: function() {
let res = [];
for (let i = 0; i < this._providers.length; i++)
res.push({ id: i, name: this._providers[i].name });
return res;
},
setSearchTerms: function(terms) {
this._terms = terms;
},
_checkSupportedProviderLanguage: function(provider) {
if (provider.url.search(/{language}/) == -1)
return true;
let langs = GLib.get_language_names();
langs.push('en');
let lang = null;
for (let i = 0; i < langs.length; i++) {
for (let k = 0; k < provider.langs.length; k++) {
if (langs[i] == provider.langs[k])
lang = langs[i];
}
if (lang)
break;
}
provider.lang = lang;
return lang != null;
},
activateResult: function(id) {
let searchTerms = this._terms.join(' ');
let url = this._providers[id].url.replace('{searchTerms}', encodeURIComponent(searchTerms));
if (url.match('{language}'))
url = url.replace('{language}', this._providers[id].lang);
try {
Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context());
} catch (e) {
// TODO: remove this after glib will be removed from moduleset
// In the default jhbuild, gio is in our prefix but gvfs is not
Util.spawn(['gvfs-open', url])
}
Main.overview.hide();
},
_addProvider: function(fileName) {
let file = Gio.file_new_for_path(global.datadir + '/search_providers/' + fileName);
let source = '';
file.load_contents_async(null, Lang.bind(this, function (obj, res) {
let [success, source] = file.load_contents_finish(res);
if (source) {
let [success, name, url, langs, icon_uri] = global.parse_search_provider(source);
let provider ={ name: name,
url: url,
id: this._providers.length,
icon_uri: icon_uri,
langs: langs };
if (this._checkSupportedProviderLanguage(provider)) {
this._providers.push(provider);
this.emit('changed');
}
}
}));
},
_refresh: function() {
this._providers = [];
let names = global.settings.get_strv(DISABLED_OPEN_SEARCH_PROVIDERS_KEY);
let file = Gio.file_new_for_path(global.datadir + '/search_providers');
FileUtils.listDirAsync(file, Lang.bind(this, function(files) {
for (let i = 0; i < files.length; i++) {
let enabled = true;
let name = files[i].get_name();
for (let k = 0; k < names.length; k++)
if (names[k] == name)
enabled = false;
if (enabled)
this._addProvider(name);
}
}));
}
}
Signals.addSignalMethods(OpenSearchSystem.prototype);
function SearchSystem() {
this._init();
}

425
js/ui/searchDisplay.js Normal file
View File

@ -0,0 +1,425 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Gtk = imports.gi.Gtk;
const St = imports.gi.St;
const DND = imports.ui.dnd;
const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const Search = imports.ui.search;
const MAX_SEARCH_RESULTS_ROWS = 2;
function SearchResult(provider, metaInfo, terms) {
this._init(provider, metaInfo, terms);
}
SearchResult.prototype = {
_init: function(provider, metaInfo, terms) {
this.provider = provider;
this.metaInfo = metaInfo;
this.actor = new St.Clickable({ style_class: 'search-result',
reactive: true,
x_align: St.Align.START,
y_fill: true });
this.actor._delegate = this;
let content = provider.createResultActor(metaInfo, terms);
if (content == null) {
content = new St.Bin({ style_class: 'search-result-content',
reactive: true,
track_hover: true });
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
{ createIcon: Lang.bind(this, function(size) {
return this.metaInfo['icon'];
})});
content.set_child(icon.actor);
}
this._content = content;
this.actor.set_child(content);
this.actor.connect('clicked', Lang.bind(this, this._onResultClicked));
let draggable = DND.makeDraggable(this.actor);
draggable.connect('drag-begin',
Lang.bind(this, function() {
Main.overview.beginItemDrag(this);
}));
draggable.connect('drag-end',
Lang.bind(this, function() {
Main.overview.endItemDrag(this);
}));
},
setSelected: function(selected) {
if (selected)
this._content.add_style_pseudo_class('selected');
else
this._content.remove_style_pseudo_class('selected');
},
activate: function() {
this.provider.activateResult(this.metaInfo.id);
Main.overview.toggle();
},
_onResultClicked: function(actor, event) {
this.activate();
},
getDragActorSource: function() {
return this.metaInfo['icon'];
},
getDragActor: function(stageX, stageY) {
return new Clutter.Clone({ source: this.metaInfo['icon'] });
},
shellWorkspaceLaunch: function() {
if (this.provider.dragActivateResult)
this.provider.dragActivateResult(this.metaInfo.id);
else
this.provider.activateResult(this.metaInfo.id);
}
};
function GridSearchResults(provider) {
this._init(provider);
}
GridSearchResults.prototype = {
__proto__: Search.SearchResultDisplay.prototype,
_init: function(provider) {
Search.SearchResultDisplay.prototype._init.call(this, provider);
this._grid = new IconGrid.IconGrid({ rowLimit: MAX_SEARCH_RESULTS_ROWS,
xAlign: St.Align.START });
this.actor = new St.Bin({ x_align: St.Align.START });
this.actor.set_child(this._grid.actor);
this.selectionIndex = -1;
},
getVisibleResultCount: function() {
return this._grid.visibleItemsCount();
},
renderResults: function(results, terms) {
for (let i = 0; i < results.length; i++) {
let result = results[i];
let meta = this.provider.getResultMeta(result);
let display = new SearchResult(this.provider, meta, terms);
this._grid.addItem(display.actor);
}
},
clear: function () {
this._grid.removeAll();
this.selectionIndex = -1;
},
selectIndex: function (index) {
let nVisible = this.getVisibleResultCount();
if (this.selectionIndex >= 0) {
let prevActor = this._grid.getItemAtIndex(this.selectionIndex);
prevActor._delegate.setSelected(false);
}
this.selectionIndex = -1;
if (index >= nVisible)
return false;
else if (index < 0)
return false;
let targetActor = this._grid.getItemAtIndex(index);
targetActor._delegate.setSelected(true);
this.selectionIndex = index;
return true;
},
activateSelected: function() {
if (this.selectionIndex < 0)
return;
let targetActor = this._grid.getItemAtIndex(this.selectionIndex);
targetActor._delegate.activate();
}
};
function SearchResults(searchSystem, openSearchSystem) {
this._init(searchSystem, openSearchSystem);
}
SearchResults.prototype = {
_init: function(searchSystem, openSearchSystem) {
this._searchSystem = searchSystem;
this._openSearchSystem = openSearchSystem;
this.actor = new St.BoxLayout({ name: 'searchResults',
vertical: true });
this._content = new St.BoxLayout({ name: 'searchResultsContent',
vertical: true });
let scrollView = new St.ScrollView({ x_fill: true,
y_fill: false,
vfade: true });
scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
scrollView.add_actor(this._content);
this.actor.add(scrollView, { x_fill: true,
y_fill: false,
expand: true,
x_align: St.Align.START,
y_align: St.Align.START });
this.actor.connect('notify::mapped', Lang.bind(this,
function() {
if (!this.actor.mapped)
return;
let adjustment = scrollView.vscroll.adjustment;
let direction = Overview.SwipeScrollDirection.VERTICAL;
Main.overview.setScrollAdjustment(adjustment, direction);
}));
this._statusText = new St.Label({ style_class: 'search-statustext' });
this._content.add(this._statusText);
this._selectedProvider = -1;
this._providers = this._searchSystem.getProviders();
this._providerMeta = [];
for (let i = 0; i < this._providers.length; i++)
this.createProviderMeta(this._providers[i]);
this._searchProvidersBox = new St.BoxLayout({ style_class: 'search-providers-box' });
this.actor.add(this._searchProvidersBox);
this._openSearchProviders = [];
this._openSearchSystem.connect('changed', Lang.bind(this, this._updateOpenSearchProviderButtons));
this._updateOpenSearchProviderButtons();
},
_updateOpenSearchProviderButtons: function() {
this._selectedOpenSearchButton = -1;
for (let i = 0; i < this._openSearchProviders.length; i++)
this._openSearchProviders[i].actor.destroy();
this._openSearchProviders = this._openSearchSystem.getProviders();
for (let i = 0; i < this._openSearchProviders.length; i++)
this._createOpenSearchProviderButton(this._openSearchProviders[i]);
},
_updateOpenSearchButtonState: function() {
for (let i = 0; i < this._openSearchProviders.length; i++) {
if (i == this._selectedOpenSearchButton)
this._openSearchProviders[i].actor.add_style_pseudo_class('selected');
else
this._openSearchProviders[i].actor.remove_style_pseudo_class('selected');
}
},
_createOpenSearchProviderButton: function(provider) {
let clickable = new St.Clickable({ style_class: 'dash-search-button',
reactive: true,
x_fill: true,
y_align: St.Align.MIDDLE });
let bin = new St.Bin({ x_fill: false,
x_align:St.Align.MIDDLE });
clickable.connect('clicked', Lang.bind(this, function() {
this._openSearchSystem.activateResult(provider.id);
}));
let title = new St.Label({ text: provider.name,
style_class: 'dash-search-button-label' });
bin.set_child(title);
clickable.set_child(bin);
provider.actor = clickable;
this._searchProvidersBox.add(clickable);
},
createProviderMeta: function(provider) {
let providerBox = new St.BoxLayout({ style_class: 'search-section',
vertical: true });
let titleButton = new St.Button({ style_class: 'search-section-header',
reactive: true,
x_fill: true,
y_fill: true });
titleButton.connect('clicked', Lang.bind(this, function () { this._onHeaderClicked(provider); }));
providerBox.add(titleButton);
let titleBox = new St.BoxLayout();
titleButton.set_child(titleBox);
let title = new St.Label({ text: provider.title });
let count = new St.Label();
titleBox.add(title, { expand: true });
titleBox.add(count);
let resultDisplayBin = new St.Bin({ style_class: 'search-section-results',
x_fill: true,
y_fill: true });
providerBox.add(resultDisplayBin, { expand: true });
let resultDisplay = provider.createResultContainerActor();
if (resultDisplay == null) {
resultDisplay = new GridSearchResults(provider);
}
resultDisplayBin.set_child(resultDisplay.actor);
this._providerMeta.push({ actor: providerBox,
resultDisplay: resultDisplay,
count: count });
this._content.add(providerBox);
},
_clearDisplay: function() {
this._selectedProvider = -1;
this._visibleResultsCount = 0;
for (let i = 0; i < this._providerMeta.length; i++) {
let meta = this._providerMeta[i];
meta.resultDisplay.clear();
meta.actor.hide();
}
},
reset: function() {
this._searchSystem.reset();
this._statusText.hide();
this._clearDisplay();
this._selectedOpenSearchButton = -1;
this._updateOpenSearchButtonState();
},
startingSearch: function() {
this.reset();
this._statusText.set_text(_("Searching..."));
this._statusText.show();
},
_metaForProvider: function(provider) {
return this._providerMeta[this._providers.indexOf(provider)];
},
updateSearch: function (searchString) {
let results = this._searchSystem.updateSearch(searchString);
this._clearDisplay();
if (results.length == 0) {
this._statusText.set_text(_("No matching results."));
this._statusText.show();
} else {
this._selectedOpenSearchButton = -1;
this._updateOpenSearchButtonState();
this._statusText.hide();
}
let terms = this._searchSystem.getTerms();
this._openSearchSystem.setSearchTerms(terms);
for (let i = 0; i < results.length; i++) {
let [provider, providerResults] = results[i];
let meta = this._metaForProvider(provider);
meta.actor.show();
meta.resultDisplay.renderResults(providerResults, terms);
meta.count.set_text('' + providerResults.length);
}
if (this._selectedOpenSearchButton == -1)
this.selectDown(false);
return true;
},
_onHeaderClicked: function(provider) {
provider.expandSearch(this._searchSystem.getTerms());
},
_modifyActorSelection: function(resultDisplay, up) {
let success;
let index = resultDisplay.getSelectionIndex();
if (up && index == -1)
index = resultDisplay.getVisibleResultCount() - 1;
else if (up)
index = index - 1;
else
index = index + 1;
return resultDisplay.selectIndex(index);
},
selectUp: function(recursing) {
if (this._selectedOpenSearchButton == -1) {
for (let i = this._selectedProvider; i >= 0; i--) {
let meta = this._providerMeta[i];
if (!meta.actor.visible)
continue;
let success = this._modifyActorSelection(meta.resultDisplay, true);
if (success) {
this._selectedProvider = i;
return;
}
}
}
if (this._selectedOpenSearchButton == -1)
this._selectedOpenSearchButton = this._openSearchProviders.length;
this._selectedOpenSearchButton--;
this._updateOpenSearchButtonState();
if (this._selectedOpenSearchButton >= 0)
return;
if (this._providerMeta.length > 0 && !recursing) {
this._selectedProvider = this._providerMeta.length - 1;
this.selectUp(true);
}
},
selectDown: function(recursing) {
let current = this._selectedProvider;
if (this._selectedOpenSearchButton == -1) {
if (current == -1)
current = 0;
for (let i = current; i < this._providerMeta.length; i++) {
let meta = this._providerMeta[i];
if (!meta.actor.visible)
continue;
let success = this._modifyActorSelection(meta.resultDisplay, false);
if (success) {
this._selectedProvider = i;
return;
}
}
}
this._selectedOpenSearchButton++;
if (this._selectedOpenSearchButton < this._openSearchProviders.length) {
this._updateOpenSearchButtonState();
return;
}
this._selectedOpenSearchButton = -1;
this._updateOpenSearchButtonState();
if (this._providerMeta.length > 0 && !recursing) {
this._selectedProvider = 0;
this.selectDown(true);
}
},
activateSelected: function() {
if (this._selectedOpenSearchButton != -1) {
let provider = this._openSearchProviders[this._selectedOpenSearchButton];
this._openSearchSystem.activateResult(provider.id);
Main.overview.hide();
return;
}
let current = this._selectedProvider;
if (current < 0)
return;
let meta = this._providerMeta[current];
let resultDisplay = meta.resultDisplay;
resultDisplay.activateSelected();
Main.overview.hide();
}
};

View File

@ -10,24 +10,25 @@ const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const A11Y_SCHEMA = "org.gnome.desktop.a11y.keyboard";
const KEY_STICKY_KEYS_ENABLED = "stickykeys-enable";
const KEY_BOUNCE_KEYS_ENABLED = "bouncekeys-enable";
const KEY_SLOW_KEYS_ENABLED = "slowkeys-enable";
const KEY_MOUSE_KEYS_ENABLED = "mousekeys-enable";
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
const KEY_STICKY_KEYS_ENABLED = 'stickykeys-enable';
const KEY_BOUNCE_KEYS_ENABLED = 'bouncekeys-enable';
const KEY_SLOW_KEYS_ENABLED = 'slowkeys-enable';
const KEY_MOUSE_KEYS_ENABLED = 'mousekeys-enable';
const AT_SCREEN_KEYBOARD_SCHEMA = "org.gnome.desktop.default-applications.at.mobility";
const AT_SCREEN_READER_SCHEMA = "org.gnome.desktop.default-applications.at.visual";
const MAGNIFIER_SCHEMA = 'org.gnome.accessibility.magnifier';
const AT_SCREEN_KEYBOARD_SCHEMA = 'org.gnome.desktop.default-applications.at.mobility';
const AT_SCREEN_READER_SCHEMA = 'org.gnome.desktop.default-applications.at.visual';
const XSETTINGS_SCHEMA = "org.gnome.settings-daemon.plugins.xsettings";
const KEY_DPI = "dpi";
const XSETTINGS_SCHEMA = 'org.gnome.settings-daemon.plugins.xsettings';
const KEY_DPI = 'dpi';
const DPI_LOW_REASONABLE_VALUE = 50;
const DPI_HIGH_REASONABLE_VALUE = 500;
@ -37,14 +38,14 @@ const DPI_FACTOR_LARGER = 1.5;
const DPI_FACTOR_LARGEST = 2.0;
const DPI_DEFAULT = 96;
const KEY_META_DIR = "/apps/metacity/general";
const KEY_VISUAL_BELL = KEY_META_DIR + "/visual_bell";
const KEY_META_DIR = '/apps/metacity/general';
const KEY_VISUAL_BELL = KEY_META_DIR + '/visual_bell';
const DESKTOP_INTERFACE_SCHEMA = "org.gnome.desktop.interface";
const KEY_GTK_THEME = "gtk-theme";
const KEY_ICON_THEME = "icon-theme";
const DESKTOP_INTERFACE_SCHEMA = 'org.gnome.desktop.interface';
const KEY_GTK_THEME = 'gtk-theme';
const KEY_ICON_THEME = 'icon-theme';
const HIGH_CONTRAST_THEME = "HighContrast";
const HIGH_CONTRAST_THEME = 'HighContrast';
function getDPIFromX() {
let screen = global.get_gdk_screen();
@ -79,7 +80,7 @@ ATIndicator.prototype = {
let highContrast = this._buildHCItem();
this.menu.addMenuItem(highContrast);
let magnifier = this._buildMagItem();
let magnifier = this._buildItem(_("Zoom"), MAGNIFIER_SCHEMA, 'show-magnifier');
this.menu.addMenuItem(magnifier);
let textZoom = this._buildFontItem();
@ -108,8 +109,7 @@ ATIndicator.prototype = {
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Universal Access Settings"), function() {
let p = new Shell.Process({ args: ['gnome-control-center','universal-access'] });
p.run();
Util.spawnDesktop('gnome-universal-access-panel');
});
},
@ -219,18 +219,6 @@ ATIndicator.prototype = {
return widget;
},
_buildMagItem: function() {
let mag = Main.magnifier;
let widget = this._buildItemExtended(_("Zoom"),
mag.isActive(),
true,
Lang.bind(mag, mag.setActive));
mag.connect('active-changed', function(magnifier, active) {
widget.setToggleState(active);
});
return widget;
},
_keyChanged: function() {
this.emit('gconf-changed');
}

492
js/ui/status/bluetooth.js Normal file
View File

@ -0,0 +1,492 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Gdk = imports.gi.Gdk;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const GnomeBluetoothApplet = imports.gi.GnomeBluetoothApplet;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const ConnectionState = {
DISCONNECTED: 0,
CONNECTED: 1,
DISCONNECTING: 2,
CONNECTING: 3
}
function Indicator() {
this._init.apply(this, arguments);
}
Indicator.prototype = {
__proto__: PanelMenu.SystemStatusButton.prototype,
_init: function() {
PanelMenu.SystemStatusButton.prototype._init.call(this, 'bluetooth-disabled', null);
GLib.spawn_command_line_sync ('pkill -f "^bluetooth-applet$"');
this._applet = new GnomeBluetoothApplet.Applet();
this._killswitch = new PopupMenu.PopupSwitchMenuItem(_("Bluetooth"), false);
this._applet.connect('notify::killswitch-state', Lang.bind(this, this._updateKillswitch));
this._killswitch.connect('toggled', Lang.bind(this, function() {
let current_state = this._applet.killswitch_state;
if (current_state != GnomeBluetoothApplet.KillswitchState.HARD_BLOCKED &&
current_state != GnomeBluetoothApplet.KillswitchState.NO_ADAPTER) {
this._applet.killswitch_state = this._killswitch.state ?
GnomeBluetoothApplet.KillswitchState.UNBLOCKED:
GnomeBluetoothApplet.KillswitchState.SOFT_BLOCKED;
} else
this._killswitch.setToggleState(false);
}));
this._discoverable = new PopupMenu.PopupSwitchMenuItem(_("Visibility"), this._applet.discoverable);
this._applet.connect('notify::discoverable', Lang.bind(this, function() {
this._discoverable.setToggleState(this._applet.discoverable);
}));
this._discoverable.connect('toggled', Lang.bind(this, function() {
this._applet.discoverable = this._discoverable.state;
}));
this._updateKillswitch();
this.menu.addMenuItem(this._killswitch);
this.menu.addMenuItem(this._discoverable);
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this._fullMenuItems = [new PopupMenu.PopupSeparatorMenuItem(),
new PopupMenu.PopupMenuItem(_("Send Files to Device...")),
new PopupMenu.PopupMenuItem(_("Setup a New Device...")),
new PopupMenu.PopupSeparatorMenuItem()];
this._hasDevices = false;
this._deviceSep = this._fullMenuItems[0]; // hidden if no device exists
this._fullMenuItems[1].connect('activate', function() {
GLib.spawn_command_line_async('bluetooth-sendto');
});
this._fullMenuItems[2].connect('activate', function() {
GLib.spawn_command_line_async('bluetooth-wizard');
});
for (let i = 0; i < this._fullMenuItems.length; i++) {
let item = this._fullMenuItems[i];
this.menu.addMenuItem(item);
}
this._deviceItemPosition = 3;
this._deviceItems = [];
this._applet.connect('devices-changed', Lang.bind(this, this._updateDevices));
this._updateDevices();
this._applet.connect('notify::show-full-menu', Lang.bind(this, this._updateFullMenu));
this._updateFullMenu();
this.menu.addAction(_("Bluetooth Settings"), function() {
GLib.spawn_command_line_async('gnome-control-center bluetooth');
});
this._applet.connect('pincode-request', Lang.bind(this, this._pinRequest));
this._applet.connect('confirm-request', Lang.bind(this, this._confirmRequest));
this._applet.connect('auth-request', Lang.bind(this, this._authRequest));
this._applet.connect('cancel-request', Lang.bind(this, this._cancelRequest));
},
_updateKillswitch: function() {
let current_state = this._applet.killswitch_state;
let on = current_state == GnomeBluetoothApplet.KillswitchState.UNBLOCKED;
let has_adapter = current_state != GnomeBluetoothApplet.KillswitchState.NO_ADAPTER;
let can_toggle = current_state != GnomeBluetoothApplet.KillswitchState.NO_ADAPTER &&
current_state != GnomeBluetoothApplet.KillswitchState.HARD_BLOCKED;
this._killswitch.setToggleState(on);
this._killswitch.actor.reactive = can_toggle;
if (has_adapter)
this.actor.show();
else
this.actor.hide();
if (on) {
this._discoverable.actor.show();
this.setIcon('bluetooth-active');
} else {
this._discoverable.actor.hide();
this.setIcon('bluetooth-disabled');
}
},
_deviceCompare: function(d1, d2) {
return d1.device_path == d2.device_path &&
d1.bdaddr == d2.bdaddr &&
d1.can_connect == d2.can_connect &&
d1.capabilities == d2.capabilities;
},
_updateDevices: function() {
let devices = this._applet.get_devices();
for (let i = 0; i < this._deviceItems.length; i++) {
let item = this._deviceItems[i];
let destroy = true;
for (let j = 0; j < devices.length; j++) {
// we need to deep compare because BluetoothSimpleDevice is a boxed type
// (but we take advantage of that, because _skip will disappear the next
// time get_devices() is called)
if (this._deviceCompare(item._device, devices[i])) {
item.label.text = devices[i].alias;
devices[i]._skip = true;
destroy = false;
}
}
if (destroy) {
item.destroy();
item._destroyed = true;
}
}
let newlist = [ ];
for (let i = 0; i < this._deviceItems.length; i++) {
let item = this._deviceItems[i];
if (!item._destroyed)
newlist.push(item);
}
this._deviceItems = newlist;
this._hasDevices = newlist.length > 0;
for (let i = 0; i < devices.length; i++) {
let d = devices[i];
if (d._skip)
continue;
let item = this._createDeviceItem(d);
if (item) {
this.menu.addMenuItem(item, this._deviceItemPosition + this._deviceItems.length);
this._deviceItems.push(item);
this._hasDevices = true;
}
}
if (this._hasDevices)
this._deviceSep.actor.show();
else
this._deviceSep.actor.hide();
},
_createDeviceItem: function(device) {
if (!device.can_connect && device.capabilities == GnomeBluetoothApplet.Capabilities.NONE)
return null;
let item = new PopupMenu.PopupSubMenuMenuItem(device.alias);
item._device = device;
if (device.can_connect) {
item._connected = device.connected;
let menuitem = new PopupMenu.PopupSwitchMenuItem(_("Connection"), device.connected);
menuitem.connect('toggled', Lang.bind(this, function() {
if (item._connected > ConnectionState.CONNECTED) {
// operation already in progress, revert
menuitem.setToggleState(menuitem.state);
}
if (item._connected) {
item._connected = ConnectionState.DISCONNECTING;
this._applet.disconnect_device(item._device.device_path, function(applet, success) {
if (success) { // apply
item._connected = ConnectionState.DISCONNECTED;
menuitem.setToggleState(false);
} else { // revert
item._connected = ConnectionState.CONNECTED;
menuitem.setToggleState(true);
}
});
} else {
item._connected = ConnectionState.CONNECTING;
this._applet.connect_device(item._device.device_path, function(applet, success) {
if (success) { // apply
item._connected = ConnectionState.CONNECTED;
menuitem.setToggleState(true);
} else { // revert
item._connected = ConnectionState.DISCONNECTED;
menuitem.setToggleState(false);
}
});
}
}));
item.menu.addMenuItem(menuitem);
}
if (device.capabilities & GnomeBluetoothApplet.Capabilities.OBEX_PUSH) {
item.menu.addAction(_("Send Files..."), Lang.bind(this, function() {
this._applet.send_to_address(device.bdaddr, device.alias);
}));
}
if (device.capabilities & GnomeBluetoothApplet.Capabilities.OBEX_FILE_TRANSFER) {
item.menu.addAction(_("Browse Files..."), Lang.bind(this, function(event) {
this._applet.browse_address(device.bdaddr, event.get_time(),
Lang.bind(this, function(applet, result) {
try {
applet.browse_address_finish(result);
} catch (e) {
this._ensureSource();
this._source.notify(new MessageTray.Notification(this._source,
_("Bluetooth"),
_("Error browsing device"),
{ body: _("The requested device cannot be browsed, error is '%s'").format(e) }));
}
}));
}));
}
switch (device.type) {
case GnomeBluetoothApplet.Type.KEYBOARD:
item.menu.addAction(_("Keyboard Settings"), function() {
GLib.spawn_command_line_async('gnome-control-center keyboard');
});
break;
case GnomeBluetoothApplet.Type.MOUSE:
item.menu.addAction(_("Mouse Settings"), function() {
GLib.spawn_command_line_async('gnome-control-center mouse');
});
break;
case GnomeBluetoothApplet.Type.HEADSET:
case GnomeBluetoothApplet.Type.HEADPHONES:
case GnomeBluetoothApplet.Type.OTHER_AUDIO:
item.menu.addAction(_("Sound Settings"), function() {
GLib.spawn_command_line_async('gnome-control-center sound');
});
break;
default:
break;
}
return item;
},
_updateFullMenu: function() {
if (this._applet.show_full_menu) {
this._showAll(this._fullMenuItems);
if (this._hasDevices)
this._showAll(this._deviceItems);
else
this._deviceSep.actor.hide();
} else {
this._hideAll(this._fullMenuItems);
this._hideAll(this._deviceItems);
}
},
_showAll: function(items) {
for (let i = 0; i < items.length; i++)
items[i].actor.show();
},
_hideAll: function(items) {
for (let i = 0; i < items.length; i++)
items[i].actor.hide();
},
_destroyAll: function(items) {
for (let i = 0; i < items.length; i++)
items[i].destroy();
},
_ensureSource: function() {
if (!this._source) {
this._source = new Source();
Main.messageTray.add(this._source);
}
},
_authRequest: function(applet, device_path, name, long_name, uuid) {
this._ensureSource();
this._source.notify(new AuthNotification(this._source, this._applet, device_path, name, long_name, uuid));
},
_confirmRequest: function(applet, device_path, name, long_name, pin) {
this._ensureSource();
this._source.notify(new ConfirmNotification(this._source, this._applet, device_path, name, long_name, pin));
},
_pinRequest: function(applet, device_path, name, long_name, numeric) {
this._ensureSource();
this._source.notify(new PinNotification(this._source, this._applet, device_path, name, long_name, numeric));
},
_cancelRequest: function() {
this._source.destroy();
}
}
function Source() {
this._init.apply(this, arguments);
}
Source.prototype = {
__proto__: MessageTray.Source.prototype,
_init: function() {
MessageTray.Source.prototype._init.call(this, _("Bluetooth Agent"));
this._setSummaryIcon(this.createNotificationIcon());
},
notify: function(notification) {
this._private_destroyId = notification.connect('destroy', Lang.bind(this, function(notification) {
if (this.notification == notification) {
// the destroyed notification is the last for this source
this.notification.disconnect(this._private_destroyId);
this.destroy();
}
}));
MessageTray.Source.prototype.notify.call(this, notification);
},
createNotificationIcon: function() {
return new St.Icon({ icon_name: 'bluetooth-active',
icon_type: St.IconType.SYMBOLIC,
icon_size: this.ICON_SIZE });
}
}
function AuthNotification() {
this._init.apply(this, arguments);
}
AuthNotification.prototype = {
__proto__: MessageTray.Notification.prototype,
_init: function(source, applet, device_path, name, long_name, uuid) {
MessageTray.Notification.prototype._init.call(this,
source,
_("Bluetooth Agent"),
_("Authorization request from %s").format(name),
{ customContent: true });
this.setResident(true);
this._applet = applet;
this._devicePath = device_path;
this.addBody(_("Device %s wants access to the service '%s'").format(long_name, uuid));
this.addButton('always-grant', _("Always grant access"));
this.addButton('grant', _("Grant this time only"));
this.addButton('reject', _("Reject"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
switch (action) {
case 'always-grant':
this._applet.agent_reply_auth(this._devicePath, true, true);
break;
case 'grant':
this._applet.agent_reply_auth(this._devicePath, true, false);
break;
case 'reject':
default:
this._applet.agent_reply_auth(this._devicePath, false, false);
}
this.destroy();
}));
}
}
function ConfirmNotification() {
this._init.apply(this, arguments);
}
ConfirmNotification.prototype = {
__proto__: MessageTray.Notification.prototype,
_init: function(source, applet, device_path, name, long_name, pin) {
MessageTray.Notification.prototype._init.call(this,
source,
_("Bluetooth Agent"),
_("Pairing confirmation for %s").format(name),
{ customContent: true });
this.setResident(true);
this._applet = applet;
this._devicePath = device_path;
this.addBody(_("Device %s wants to pair with this computer").format(long_name));
this.addBody(_("Please confirm whether the PIN '%s' matches the one on the device.").format(pin));
this.addButton('matches', _("Matches"));
this.addButton('does-not-match', _("Does not match"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
if (action == 'matches')
this._applet.agent_reply_confirm(this._devicePath, true);
else
this._applet.agent_reply_confirm(this._devicePath, false);
this.destroy();
}));
}
}
function PinNotification() {
this._init.apply(this, arguments);
}
PinNotification.prototype = {
__proto__: MessageTray.Notification.prototype,
_init: function(source, applet, device_path, name, long_name, numeric) {
MessageTray.Notification.prototype._init.call(this,
source,
_("Bluetooth Agent"),
_("Pairing request for %s").format(name),
{ customContent: true });
this.setResident(true);
this._applet = applet;
this._devicePath = device_path;
this._numeric = numeric;
this.addBody(_("Device %s wants to pair with this computer").format(long_name));
this.addBody(_("Please enter the PIN mentioned on the device."));
this._entry = new St.Entry();
this._entry.connect('key-release-event', Lang.bind(this, function(entry, event) {
let key = event.get_key_symbol();
if (key == Clutter.KEY_Return) {
this.emit('action-invoked', 'ok');
return true;
} else if (key == Clutter.KEY_Escape) {
this.emit('action-invoked', 'cancel');
return true;
}
return false;
}));
this.addActor(this._entry);
this.addButton('ok', _("OK"));
this.addButton('cancel', _("Cancel"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
if (action == 'ok') {
if (this._numeric)
this._applet.agent_reply_passkey(this._devicePath, parseInt(this._entry.text));
else
this._applet.agent_reply_pincode(this._devicePath, this._entry.text);
} else {
if (this._numeric)
this._applet.agent_reply_passkey(this._devicePath, -1);
else
this._applet.agent_reply_pincode(this._devicePath, null);
}
this.destroy();
}));
},
grabFocus: function(lockTray) {
MessageTray.Notification.prototype.grabFocus.call(this, lockTray);
global.stage.set_key_focus(this._entry);
}
}

206
js/ui/status/keyboard.js Normal file
View File

@ -0,0 +1,206 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const GdkPixbuf = imports.gi.GdkPixbuf;
const Gkbd = imports.gi.Gkbd;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const PopupMenu = imports.ui.popupMenu;
const PanelMenu = imports.ui.panelMenu;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const INDICATOR_SCHEMA = 'org.gnome.settings-daemon.plugins.keyboard';
function LayoutMenuItem() {
this._init.apply(this, arguments);
}
LayoutMenuItem.prototype = {
__proto__: PopupMenu.PopupBaseMenuItem.prototype,
_init: function(config, id, indicator, long_name) {
PopupMenu.PopupBaseMenuItem.prototype._init.call(this);
this._config = config;
this._id = id;
this.label = new St.Label({ text: long_name });
this.indicator = indicator;
this.addActor(this.label);
this.addActor(this.indicator);
},
activate: function(event) {
PopupMenu.PopupBaseMenuItem.prototype.activate.call(this);
this._config.lock_group(this._id);
}
};
function XKBIndicator() {
this._init.call(this);
}
XKBIndicator.prototype = {
__proto__: PanelMenu.Button.prototype,
_init: function() {
PanelMenu.Button.prototype._init.call(this, St.Align.START);
this._container = new Shell.GenericContainer();
this._container.connect('get-preferred-width', Lang.bind(this, this._get_preferred_width));
this._container.connect('get-preferred-height', Lang.bind(this, this._get_preferred_height));
this._container.connect('allocate', Lang.bind(this, this._allocate));
this.actor.set_child(this._container);
this._iconActor = new St.Icon({ icon_name: 'keyboard', icon_type: St.IconType.SYMBOLIC, style_class: 'system-status-icon' });
this._container.add_actor(this._iconActor);
this._labelActors = [ ];
this._layoutItems = [ ];
this._indicatorSettings = new Gio.Settings({ schema: INDICATOR_SCHEMA });
this._indicatorSettings.connect('changed::disable-indicator', Lang.bind(this, this._sync_config));
this._disableIndicator = false;
this._showFlags = false;
this._config = Gkbd.Configuration.get();
this._config.connect('changed', Lang.bind(this, this._sync_config));
this._config.connect('group-changed', Lang.bind(this, this._sync_group));
this._config.start_listen();
this._sync_config();
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Localization Settings"), function() {
GLib.spawn_command_line_async('gnome-control-center region');
});
},
_sync_config: function() {
this._disableIndicator = this._indicatorSettings.get_boolean('disable-indicator');
this._showFlags = this._config.if_flags_shown();
if (this._showFlags) {
this._container.set_skip_paint(this._iconActor, false);
} else {
this._container.set_skip_paint(this._iconActor, true);
}
let groups = this._config.get_group_names();
if (groups.length > 1 && !this._disableIndicator) {
this.actor.show();
} else {
this.menu.close();
this.actor.hide();
}
for (let i = 0; i < this._layoutItems.length; i++)
this._layoutItems[i].destroy();
for (let i = 0; i < this._labelActors.length; i++)
this._labelActors[i].destroy();
let short_names = this._config.get_short_group_names();
this._selectedLayout = null;
this._layoutItems = [ ];
this._selectedLabel = null;
this._labelActors = [ ];
for (let i = 0; i < groups.length; i++) {
let icon_name = this._config.get_group_name(i);
let actor;
if (this._showFlags)
actor = new St.Icon({ icon_name: icon_name, icon_type: St.IconType.SYMBOLIC, style_class: 'popup-menu-icon' });
else
actor = new St.Label({ text: short_names[i] });
let item = new LayoutMenuItem(this._config, i, actor, groups[i]);
item._short_group_name = short_names[i];
item._icon_name = icon_name;
this._layoutItems.push(item);
this.menu.addMenuItem(item, i);
let shortLabel = new St.Label({ text: short_names[i] });
this._labelActors.push(shortLabel);
this._container.add_actor(shortLabel);
this._container.set_skip_paint(shortLabel, true);
}
this._sync_group();
},
_sync_group: function() {
let selected = this._config.get_current_group();
if (this._selectedLayout) {
this._selectedLayout.setShowDot(false);
this._selectedLayout = null;
}
if (this._selectedLabel) {
this._container.set_skip_paint(this._selectedLabel, true);
this._selectedLabel = null;
}
let item = this._layoutItems[selected];
item.setShowDot(true);
this._iconActor.icon_name = item._icon_name;
this._selectedLabel = this._labelActors[selected];
this._container.set_skip_paint(this._selectedLabel, this._showFlags);
this._selectedLayout = item;
},
_get_preferred_width: function(container, for_height, alloc) {
/* Here, and in _get_preferred_height, we need to query for the
height of all children, but we ignore the results for those
we don't actually display. */
let max_min_width = 0, max_natural_width = 0;
if (this._showFlags)
[max_min_width, max_natural_width] = this._iconActor.get_preferred_width(for_height);
for (let i = 0; i < this._labelActors.length; i++) {
let [min_width, natural_width] = this._labelActors[i].get_preferred_width(for_height);
if (!this._showFlags) {
max_min_width = Math.max(max_min_width, min_width);
max_natural_width = Math.max(max_natural_width, natural_width);
}
}
alloc.min_size = max_min_width;
alloc.natural_size = max_natural_width;
},
_get_preferred_height: function(container, for_width, alloc) {
let max_min_height = 0, max_natural_height = 0;
if (this._showFlags)
[max_min_height, max_natural_height] = this._iconActor.get_preferred_height(for_width);
for (let i = 0; i < this._labelActors.length; i++) {
let [min_height, natural_height] = this._labelActors[i].get_preferred_height(for_width);
if (!this._showFlags) {
max_min_height = Math.max(max_min_height, min_height);
max_natural_height = Math.max(max_natural_height, natural_height);
}
}
alloc.min_size = max_min_height;
alloc.natural_size = max_natural_height;
},
_allocate: function(container, box, flags) {
// translate box to (0, 0)
box.x2 -= box.x1;
box.x1 = 0;
box.y2 -= box.y1;
box.y1 = 0;
this._iconActor.allocate_align_fill(box, 0.5, 0, false, false, flags);
for (let i = 0; i < this._labelActors.length; i++)
this._labelActors[i].allocate_align_fill(box, 0.5, 0, false, false, flags);
}
};

View File

@ -1,7 +1,6 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const DBus = imports.dbus;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
@ -10,6 +9,7 @@ const St = imports.gi.St;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
@ -26,7 +26,10 @@ const UPDeviceType = {
MOUSE: 5,
KEYBOARD: 6,
PDA: 7,
PHONE: 8
PHONE: 8,
MEDIA_PLAYER: 9,
TABLET: 10,
COMPUTER: 11
};
const UPDeviceState = {
@ -68,17 +71,19 @@ Indicator.prototype = {
this._deviceItems = [ ];
this._hasPrimary = false;
this._primaryDeviceId = null;
this._batteryItem = new PopupMenu.PopupMenuItem('');
this._primaryPercentage = new St.Label();
this._batteryItem.addActor(this._primaryPercentage, { align: St.Align.END });
this.menu.addMenuItem(this._batteryItem);
this._deviceSep = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(this._deviceSep);
this._otherDevicePosition = 2;
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("What's using power..."),function() {
GLib.spawn_command_line_async('gnome-power-statistics --device wakeups');
});
this.menu.addAction(_("Power Settings"),function() {
GLib.spawn_command_line_async('gnome-control-center power');
Util.spawnDesktop('gnome-power-panel');
});
this._proxy.connect('Changed', Lang.bind(this, this._devicesChanged));
@ -95,10 +100,26 @@ Indicator.prototype = {
this._deviceSep.actor.hide();
return;
}
let [device_id, device_type, summary, percentage, state, time] = device;
let [device_id, device_type, icon, percentage, state, seconds] = device;
if (device_type == UPDeviceType.BATTERY) {
this._hasPrimary = true;
this._batteryItem.label.text = summary;
let time = Math.round(seconds / 60);
let minutes = time % 60;
let hours = Math.floor(time / 60);
let timestring;
if (time > 60) {
if (minutes == 0) {
timestring = Gettext.ngettext("%d hour remaining", "%d hours remaining", hours).format(hours);
} else {
/* TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining" */
let template = _("%d %s %d %s remaining");
timestring = template.format (hours, Gettext.ngettext("hour", "hours", hours), minutes, Gettext.ngettext("minute", "minutes", minutes));
}
} else
timestring = Gettext.ngettext("%d minute remaining", "%d minutes remaining", minutes).format(minutes);
this._batteryItem.label.text = timestring;
this._primaryPercentage.text = Math.round(percentage) + '%';
this._batteryItem.actor.show();
if (this._deviceItems.length > 0)
this._deviceSep.actor.show();
@ -109,6 +130,17 @@ Indicator.prototype = {
}
this._primaryDeviceId = device_id;
if (this._primaryDeviceId) {
this._batteryItem.actor.reactive = true;
this._batteryItem.actor.can_focus = true;
this._batteryItem.connect('activate', function(item) {
Util.spawn(['gnome-power-statistics', '--device', device_id]);
});
} else {
// virtual device
this._batteryItem.actor.reactive = false;
this._batteryItem.actor.can_focus = false;
}
}));
},
@ -131,8 +163,7 @@ Indicator.prototype = {
let item = new DeviceItem (devices[i]);
item.connect('activate', function() {
let p = new Shell.Process({ args: ['gnome-power-statistics', '--device', device_id] });
p.run();
Util.spawn(['gnome-power-statistics', '--device', device_id]);
});
this._deviceItems.push(item);
this.menu.addMenuItem(item, this._otherDevicePosition + position);
@ -164,8 +195,8 @@ Indicator.prototype = {
_checkError: function(error) {
if (!this._restarted && error && error.message.match(/org\.freedesktop\.DBus\.Error\.(UnknownMethod|InvalidArgs)/)) {
GLib.spawn_command_line_sync('pkill -f "^gnome-power-manager$"');
GLib.spawn_command_line_async('gnome-power-manager');
Util.killall('gnome-power-manager');
Util.spawn(['gnome-power-manager']);
this._restarted = true;
}
}
@ -181,24 +212,12 @@ DeviceItem.prototype = {
_init: function(device) {
PopupMenu.PopupBaseMenuItem.prototype._init.call(this);
let [device_id, device_type, summary, percentage, state, time] = device;
let [device_id, device_type, icon, percentage, state, time] = device;
this._box = new St.BoxLayout({ style_class: 'popup-device-menu-item' });
this._label = new St.Label({ text: summary });
this._label = new St.Label({ text: this._deviceTypeToString(device_type) });
let icon;
switch (state) {
case UPDeviceState.FULLY_CHARGED:
icon = 'battery-full-charged';
break;
case UPDeviceState.UNKNOWN:
icon = 'battery-missing';
break;
default:
icon = this._percentageToIcon(percentage) + (state == UPDeviceState.CHARGING ? '-charging' : '');
}
this._icon = new St.Icon({ icon_name: icon,
this._icon = new St.Icon({ gicon: Shell.util_icon_from_string(icon),
icon_type: St.IconType.SYMBOLIC,
style_class: 'popup-menu-icon' });
@ -206,21 +225,36 @@ DeviceItem.prototype = {
this._box.add_actor(this._label);
this.addActor(this._box);
let percentBin = new St.Bin({ x_align: St.Align.END });
let percentLabel = new St.Label({ text: '%d%%'.format(Math.round(percentage)) });
percentBin.child = percentLabel;
this.addActor(percentBin);
this.addActor(percentLabel, { align: St.Align.END });
},
_percentageToIcon: function(p) {
if (p > 60)
return 'battery-full';
if (p > 30)
return 'battery-good';
if (p > 10)
return 'battery-low';
if (p > 0)
return 'battery-caution';
return 'battery-empty';
_deviceTypeToString: function(type) {
switch (type) {
case UPDeviceType.AC_POWER:
return _("AC adapter");
case UPDeviceType.BATTERY:
return _("Laptop battery");
case UPDeviceType.UPS:
return _("UPS");
case UPDeviceType.MONITOR:
return _("Monitor");
case UPDeviceType.MOUSE:
return _("Mouse");
case UPDeviceType.KEYBOARD:
return _("Keyboard");
case UPDeviceType.PDA:
return _("PDA");
case UPDeviceType.PHONE:
return _("Cell phone");
case UPDeviceType.MEDIA_PLAYER:
return _("Media player");
case UPDeviceType.TABLET:
return _("Tablet");
case UPDeviceType.COMPUTER:
return _("Computer");
default:
return _("Unknown");
}
}
}

View File

@ -11,6 +11,7 @@ const St = imports.gi.St;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
@ -38,12 +39,11 @@ Indicator.prototype = {
this._output = null;
this._outputVolumeId = 0;
this._outputMutedId = 0;
this._outputSwitch = new PopupMenu.PopupSwitchMenuItem(_("Volume: Muted"), false);
this._outputSwitch.connect('toggled', Lang.bind(this, this._switchToggled, '_output'));
this._outputTitle = new PopupMenu.PopupMenuItem(_("Volume"), { reactive: false });
this._outputSlider = new PopupMenu.PopupSliderMenuItem(0);
this._outputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_output'));
this._outputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
this.menu.addMenuItem(this._outputSwitch);
this.menu.addMenuItem(this._outputTitle);
this.menu.addMenuItem(this._outputSlider);
this._separator = new PopupMenu.PopupSeparatorMenuItem();
@ -52,18 +52,16 @@ Indicator.prototype = {
this._input = null;
this._inputVolumeId = 0;
this._inputMutedId = 0;
this._inputSwitch = new PopupMenu.PopupSwitchMenuItem(_("Microphone: Muted"), false);
this._inputSwitch.connect('toggled', Lang.bind(this, this._switchToggled, '_input'));
this._inputTitle = new PopupMenu.PopupMenuItem(_("Microphone"), { reactive: false });
this._inputSlider = new PopupMenu.PopupSliderMenuItem(0);
this._inputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_input'));
this._inputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
this.menu.addMenuItem(this._inputSwitch);
this.menu.addMenuItem(this._inputTitle);
this.menu.addMenuItem(this._inputSlider);
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Sound Settings"), function() {
let p = new Shell.Process({ args: ['gnome-control-center', 'sound'] });
p.run();
Util.spawnDesktop('gnome-sound-panel');
});
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
@ -75,11 +73,18 @@ Indicator.prototype = {
let currentVolume = this._output.volume;
if (direction == Clutter.ScrollDirection.DOWN) {
let prev_muted = this._output.is_muted;
this._output.volume = Math.max(0, currentVolume - VOLUME_MAX * VOLUME_ADJUSTMENT_STEP);
if (this._output.volume < 1) {
this._output.volume = 0;
if (!prev_muted)
this._output.change_is_muted(true);
}
this._output.push_volume();
}
else if (direction == Clutter.ScrollDirection.UP) {
this._output.volume = Math.min(VOLUME_MAX, currentVolume + VOLUME_MAX * VOLUME_ADJUSTMENT_STEP);
this._output.change_is_muted(false);
this._output.push_volume();
}
},
@ -103,8 +108,7 @@ Indicator.prototype = {
this._mutedChanged (null, null, '_output');
this._volumeChanged (null, null, '_output');
} else {
this._outputSwitch.label.text = _("Volume: Muted");
this._outputSwitch.setToggleState(false);
this._outputSlider.setValue(0);
this.setIcon('audio-volume-muted-symbolic');
}
},
@ -124,7 +128,7 @@ Indicator.prototype = {
this._volumeChanged (null, null, '_input');
} else {
this._separator.actor.hide();
this._inputSwitch.actor.hide();
this._inputTitle.actor.hide();
this._inputSlider.actor.hide();
}
},
@ -147,11 +151,11 @@ Indicator.prototype = {
}
if (showInput) {
this._separator.actor.show();
this._inputSwitch.actor.show();
this._inputTitle.actor.show();
this._inputSlider.actor.show();
} else {
this._separator.actor.hide();
this._inputSwitch.actor.hide();
this._inputTitle.actor.hide();
this._inputSlider.actor.hide();
}
},
@ -174,7 +178,17 @@ Indicator.prototype = {
log ('Volume slider changed for %s, but %s does not exist'.format(property, property));
return;
}
this[property].volume = value * VOLUME_MAX;
let volume = value * VOLUME_MAX;
let prev_muted = this[property].is_muted;
if (volume < 1) {
this[property].volume = 0;
if (!prev_muted)
this[property].change_is_muted(true);
} else {
this[property].volume = volume;
if (prev_muted)
this[property].change_is_muted(false);
}
this[property].push_volume();
},
@ -182,20 +196,10 @@ Indicator.prototype = {
global.play_theme_sound('audio-volume-change');
},
_switchToggled: function(switchItem, state, property) {
if (this[property] == null) {
log ('Volume mute switch toggled for %s, but %s does not exist'.format(property, property));
return;
}
this[property].change_is_muted(!state);
this._notifyVolumeChange();
},
_mutedChanged: function(object, param_spec, property) {
let muted = this[property].is_muted;
let toggleSwitch = this[property+'Switch'];
toggleSwitch.setToggleState(!muted);
this._updateLabel(property);
let slider = this[property+'Slider'];
slider.setValue(muted ? 0 : (this[property].volume / VOLUME_MAX));
if (property == '_output') {
if (muted)
this.setIcon('audio-volume-muted');
@ -206,17 +210,7 @@ Indicator.prototype = {
_volumeChanged: function(object, param_spec, property) {
this[property+'Slider'].setValue(this[property].volume / VOLUME_MAX);
this._updateLabel(property);
if (property == '_output' && !this._output.is_muted)
this.setIcon(this._volumeToIcon(this._output.volume));
},
_updateLabel: function(property) {
let label;
if (this[property].is_muted)
label = (property == '_output' ? _("Volume: Muted") : _("Microphone: Muted"));
else
label = (property == '_output' ? _("Volume: %3.0f%%") : _("Microphone: %3.0f%%")).format(this[property].volume / VOLUME_MAX * 100);
this[property+'Switch'].label.text = label;
}
};

View File

@ -6,6 +6,7 @@ const Signals = imports.signals;
const MessageTray = imports.ui.messageTray;
const NotificationDaemon = imports.ui.notificationDaemon;
const Util = imports.misc.util;
const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
'bluetooth-applet': 'bluetooth',
@ -15,7 +16,10 @@ const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
'nm-applet': 'network',
'gnome-power-manager': 'battery',
'keyboard': 'keyboard',
'gnome-settings-daemon': 'display'
'a11y-keyboard': 'a11y',
'kbd-scrolllock': 'keyboard',
'kbd-numlock': 'keyboard',
'kbd-capslock': 'keyboard'
};
function StatusIconDispatcher() {
@ -33,8 +37,7 @@ StatusIconDispatcher.prototype = {
// app-indicators, so that applications fall back to normal
// status icons
// http://bugzilla.gnome.org/show_bug.cgi=id=621382
let p = new Shell.Process({ args: ['pkill', '-f', '^([^ ]*/)?indicator-application-service$']});
p.run();
Util.killall('indicator-application-service');
},
_onTrayIconAdded: function(o, icon) {

View File

@ -12,6 +12,7 @@ const GnomeSession = imports.misc.gnomeSession;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
// Adapted from gdm/gui/user-switch-applet/applet.c
//
@ -31,7 +32,7 @@ StatusMenuButton.prototype = {
this.actor.set_child(box);
this._gdm = Gdm.UserManager.ref_default();
this._gdm.queue_load()
this._gdm.queue_load();
this._user = this._gdm.get_user(GLib.get_user_name());
this._presence = new GnomeSession.Presence();
@ -111,11 +112,11 @@ StatusMenuButton.prototype = {
item = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(item);
item = new PopupMenu.PopupMenuItem(_("My Account..."));
item = new PopupMenu.PopupMenuItem(_("My Account"));
item.connect('activate', Lang.bind(this, this._onMyAccountActivate));
this.menu.addMenuItem(item);
item = new PopupMenu.PopupMenuItem(_("System Settings..."));
item = new PopupMenu.PopupMenuItem(_("System Settings"));
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
this.menu.addMenuItem(item);
@ -138,7 +139,7 @@ StatusMenuButton.prototype = {
item = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(item);
item = new PopupMenu.PopupMenuItem(_("Suspend"));
item = new PopupMenu.PopupMenuItem(_("Suspend..."));
item.connect('activate', Lang.bind(this, this._onShutDownActivate));
this.menu.addMenuItem(item);
@ -153,17 +154,17 @@ StatusMenuButton.prototype = {
_onMyAccountActivate: function() {
Main.overview.hide();
this._spawn(['gnome-about-me']);
Util.spawnDesktop('gnome-user-accounts-panel');
},
_onPreferencesActivate: function() {
Main.overview.hide();
this._spawn(['gnome-control-center']);
Util.spawnDesktop('gnome-control-center');
},
_onLockScreenActivate: function() {
Main.overview.hide();
this._spawn(['gnome-screensaver-command', '--lock']);
Util.spawn(['gnome-screensaver-command', '--lock']);
},
_onLoginScreenActivate: function() {
@ -174,19 +175,11 @@ StatusMenuButton.prototype = {
_onQuitSessionActivate: function() {
Main.overview.hide();
this._spawn(['gnome-session-save', '--logout-dialog']);
Util.spawn(['gnome-session-save', '--logout-dialog']);
},
_onShutDownActivate: function() {
Main.overview.hide();
this._spawn(['gnome-session-save', '--shutdown-dialog']);
},
_spawn: function(args) {
// FIXME: once Shell.Process gets support for signalling
// errors we should pop up an error dialog or something here
// on failure
let p = new Shell.Process({'args' : args});
p.run();
Util.spawn(['gnome-session-save', '--shutdown-dialog']);
}
};

View File

@ -3,6 +3,7 @@
const DBus = imports.dbus;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
@ -16,6 +17,7 @@ let contactManager;
let channelDispatcher;
// See Notification.appendMessage
const SCROLLBACK_IMMEDIATE_TIME = 60; // 1 minute
const SCROLLBACK_RECENT_TIME = 15 * 60; // 15 minutes
const SCROLLBACK_RECENT_LENGTH = 20;
const SCROLLBACK_IDLE_LENGTH = 5;
@ -42,6 +44,10 @@ subscribedContactsChannel[Telepathy.CHANNEL_NAME + '.ChannelType'] = Telepathy.C
subscribedContactsChannel[Telepathy.CHANNEL_NAME + '.TargetHandleType'] = Telepathy.HandleType.LIST;
subscribedContactsChannel[Telepathy.CHANNEL_NAME + '.TargetID'] = 'subscribe';
const NotificationDirection = {
SENT: 'chat-sent',
RECEIVED: 'chat-received'
};
// This is GNOME Shell's implementation of the Telepathy 'Client'
// interface. Specifically, the shell is a Telepathy 'Observer', which
@ -469,11 +475,15 @@ Source.prototype = {
}));
}
this._notification = new Notification(this);
this._notification.setUrgency(MessageTray.Urgency.HIGH);
// Since we only create sources when receiving a message, this
// is a plausible default
this._presence = Telepathy.ConnectionPresenceType.AVAILABLE;
this._channelText = new Telepathy.ChannelText(DBus.session, connName, channelPath);
this._sentId = this._channelText.connect('Sent', Lang.bind(this, this._messageSent));
this._receivedId = this._channelText.connect('Received', Lang.bind(this, this._messageReceived));
this._channelText.ListPendingMessagesRemote(false, Lang.bind(this, this._gotPendingMessages));
@ -517,22 +527,27 @@ Source.prototype = {
_channelClosed: function() {
this._channel.disconnect(this._closedId);
this._channelText.disconnect(this._receivedId);
this._channelText.disconnect(this._sentId);
this.destroy();
},
_ensureNotification: function() {
if (!Main.messageTray.contains(this))
Main.messageTray.add(this);
if (!this._notification)
this._notification = new Notification(this);
},
_messageReceived: function(channel, id, timestamp, sender,
type, flags, text) {
this._ensureNotification();
this._notification.appendMessage(text);
this.notify(this._notification);
this._notification.appendMessage(text, timestamp, NotificationDirection.RECEIVED);
this.notify();
},
// This is called for both messages we send from
// our client and other clients as well.
_messageSent: function(channel, timestamp, type, text) {
this._notification.appendMessage(text, timestamp, NotificationDirection.SENT);
},
notify: function() {
if (!Main.messageTray.contains(this))
Main.messageTray.add(this);
MessageTray.Source.prototype.notify.call(this, this._notification);
},
respond: function(text) {
@ -540,22 +555,22 @@ Source.prototype = {
},
setPresence: function(presence, message) {
let msg, notify;
let msg, shouldNotify;
if (presence == Telepathy.ConnectionPresenceType.AVAILABLE) {
msg = _("%s is online.").format(this.title);
notify = (this._presence == Telepathy.ConnectionPresenceType.OFFLINE);
shouldNotify = (this._presence == Telepathy.ConnectionPresenceType.OFFLINE);
} else if (presence == Telepathy.ConnectionPresenceType.OFFLINE ||
presence == Telepathy.ConnectionPresenceType.EXTENDED_AWAY) {
presence = Telepathy.ConnectionPresenceType.OFFLINE;
msg = _("%s is offline.").format(this.title);
notify = (this._presence != Telepathy.ConnectionPresenceType.OFFLINE);
shouldNotify = (this._presence != Telepathy.ConnectionPresenceType.OFFLINE);
} else if (presence == Telepathy.ConnectionPresenceType.AWAY) {
msg = _("%s is away.").format(this.title);
notify = false;
shouldNotify = false;
} else if (presence == Telepathy.ConnectionPresenceType.BUSY) {
msg = _("%s is busy.").format(this.title);
notify = false;
shouldNotify = false;
} else
return;
@ -564,10 +579,9 @@ Source.prototype = {
if (message)
msg += ' <i>(' + GLib.markup_escape_text(message, -1) + ')</i>';
this._ensureNotification();
this._notification.appendMessage(msg, true);
if (notify)
this.notify(this._notification);
this._notification.appendPresence(msg, shouldNotify);
if (shouldNotify)
this.notify();
}
};
@ -580,29 +594,47 @@ Notification.prototype = {
_init: function(source) {
MessageTray.Notification.prototype._init.call(this, source, source.title, null, { customContent: true });
this.setResident(true);
this._responseEntry = new St.Entry({ style_class: 'chat-response' });
this._responseEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivated));
this.setActionArea(this._responseEntry);
this._history = [];
this._timestampTimeoutId = 0;
},
appendMessage: function(text, asTitle) {
if (asTitle)
this.update(text, null, { customContent: true });
else
this.update(this.source.title, text, { customContent: true });
this._append(text, 'chat-received');
appendMessage: function(text, timestamp, direction) {
this.update(this.source.title, text, { customContent: true });
this._append(text, direction, timestamp);
},
_append: function(text, style) {
_append: function(text, style, timestamp) {
let currentTime = (Date.now() / 1000);
if (!timestamp)
timestamp = currentTime;
let lastMessageTime = -1;
if (this._history.length > 0)
lastMessageTime = this._history[0].time;
// Reset the old message timeout
if (this._timestampTimeoutId)
Mainloop.source_remove(this._timestampTimeoutId);
let body = this.addBody(text);
body.add_style_class_name(style);
this.scrollTo(St.Side.BOTTOM);
let now = new Date().getTime() / 1000;
this._history.unshift({ actor: body, time: now });
this._history.unshift({ actor: body, time: timestamp, realMessage: true });
if (timestamp < currentTime - SCROLLBACK_IMMEDIATE_TIME)
this._appendTimestamp();
else
// Schedule a new timestamp in SCROLLBACK_IMMEDIATE_TIME
// from the timestamp of the message.
this._timestampTimeoutId = Mainloop.timeout_add_seconds(
SCROLLBACK_IMMEDIATE_TIME - (currentTime - timestamp),
Lang.bind(this, this._appendTimestamp));
if (this._history.length > 1) {
// Keep the scrollback from growing too long. If the most
@ -611,17 +643,44 @@ Notification.prototype = {
// SCROLLBACK_RECENT_LENGTH previous messages. Otherwise
// we'll keep SCROLLBACK_IDLE_LENGTH messages.
let lastMessageTime = this._history[1].time;
let maxLength = (lastMessageTime < now - SCROLLBACK_RECENT_TIME) ?
let maxLength = (lastMessageTime < currentTime - SCROLLBACK_RECENT_TIME) ?
SCROLLBACK_IDLE_LENGTH : SCROLLBACK_RECENT_LENGTH;
if (this._history.length > maxLength) {
let expired = this._history.splice(maxLength);
let filteredHistory = this._history.filter(function(item) { return item.realMessage });
if (filteredHistory.length > maxLength) {
let lastMessageToKeep = filteredHistory[maxLength];
let expired = this._history.splice(this._history.indexOf(lastMessageToKeep));
for (let i = 0; i < expired.length; i++)
expired[i].actor.destroy();
}
}
},
_appendTimestamp: function() {
let lastMessageTime = this._history[0].time;
let lastMessageDate = new Date(lastMessageTime * 1000);
/* Translators: this is a time format string followed by a date.
If applicable, replace %X with a strftime format valid for your
locale, without seconds. */
// xgettext:no-c-format
let timeLabel = this.addBody(lastMessageDate.toLocaleFormat(_("Sent at %X on %A")), false, { expand: true, x_fill: false, x_align: St.Align.END });
timeLabel.add_style_class_name('chat-meta-message');
this._history.unshift({ actor: timeLabel, time: lastMessageTime, realMessage: false });
this._timestampTimeoutId = 0;
return false;
},
appendPresence: function(text, asTitle) {
if (asTitle)
this.update(text, null, { customContent: true });
else
this.update(this.source.title, null, { customContent: true });
let label = this.addBody(text);
label.add_style_class_name('chat-meta-message');
this._history.unshift({ actor: label, time: (Date.now() / 1000), realMessage: false});
},
grabFocus: function(lockTray) {
// Need to call the base class function first so that
// it saves where the key focus was before.
@ -634,8 +693,9 @@ Notification.prototype = {
if (text == '')
return;
// Telepathy sends out the Sent signal for us.
// see Source._messageSent
this._responseEntry.set_text('');
this._append(text, 'chat-sent');
this.source.respond(text);
}
};

617
js/ui/viewSelector.js Normal file
View File

@ -0,0 +1,617 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Signals = imports.signals;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Main = imports.ui.main;
const Search = imports.ui.search;
const SearchDisplay = imports.ui.searchDisplay;
const Tweener = imports.ui.tweener;
function SearchEntry(focusBase) {
this._init(focusBase);
}
SearchEntry.prototype = {
_init : function(focusBase) {
this.actor = new St.Entry({ name: 'searchEntry',
hint_text: _("Search your computer") });
this.entry = this.actor.clutter_text;
this.actor.clutter_text.connect('text-changed', Lang.bind(this,
function() {
if (this.isActive())
this.actor.set_secondary_icon_from_file(global.imagedir +
'close-black.svg');
else
this.actor.set_secondary_icon_from_file(null);
}));
this.actor.connect('secondary-icon-clicked', Lang.bind(this,
function() {
this.reset();
}));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
global.stage.connect('notify::key-focus', Lang.bind(this, this._updateCursorVisibility));
this.pane = null;
this._capturedEventId = 0;
this._focusBase = focusBase;
},
_updateCursorVisibility: function() {
let focus = global.stage.get_key_focus();
if (focus == this._focusBase || focus == this.entry)
this.entry.set_cursor_visible(true);
else
this.entry.set_cursor_visible(false);
},
show: function() {
if (this._capturedEventId == 0)
this._capturedEventId = global.stage.connect('captured-event',
Lang.bind(this, this._onCapturedEvent));
this.entry.set_cursor_visible(true);
this.entry.set_selection(0, 0);
},
hide: function() {
if (this._capturedEventId > 0) {
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
},
reset: function () {
let [x, y, mask] = global.get_pointer();
let actor = global.stage.get_actor_at_pos (Clutter.PickMode.REACTIVE,
x, y);
// this.actor is never hovered directly, only its clutter_text and icon
let hovered = this.actor == actor.get_parent();
this.actor.set_hover(hovered);
this.entry.text = '';
// Return focus to the viewSelector
global.stage.set_key_focus(this._focusBase);
this.entry.set_cursor_visible(true);
this.entry.set_selection(0, 0);
},
getText: function () {
return this.entry.get_text().replace(/^\s+/g, '').replace(/\s+$/g, '');
},
// some search term has been entered
isActive: function() {
return this.actor.get_text() != '';
},
// the entry does not show the hint
_isActivated: function() {
return this.entry.text == this.actor.get_text();
},
_onCapturedEvent: function(actor, event) {
let source = event.get_source();
let panelEvent = source && Main.panel.actor.contains(source);
switch (event.type()) {
case Clutter.EventType.BUTTON_PRESS:
// the user clicked outside after activating the entry, but
// with no search term entered - cancel the search
if (source != this.entry && this.entry.text == '') {
this.reset();
// allow only panel events to continue
return !panelEvent;
}
return false;
case Clutter.EventType.KEY_PRESS:
// If some "special" actor grabbed the focus (run
// dialog, looking glass); we don't want to interfere
// with that
let focus = global.stage.get_key_focus();
if (focus != this._focusBase && focus != this.entry)
return false;
let sym = event.get_key_symbol();
// If we have an active search, Escape cancels it - if we
// haven't, the key is ignored
if (sym == Clutter.Escape)
if (this._isActivated()) {
this.reset();
return true;
} else {
return false;
}
// Ignore non-printable keys
if (!Clutter.keysym_to_unicode(sym))
return false;
// Search started - move the key focus to the entry and
// "repeat" the event
if (!this._isActivated()) {
global.stage.set_key_focus(this.entry);
this.entry.event(event, false);
}
return false;
default:
// Suppress all other events outside the panel while the entry
// is activated and no search has been entered - any click
// outside the entry will cancel the search
return (this.entry.text == '' && !panelEvent);
}
},
_onDestroy: function() {
if (this._capturedEventId > 0) {
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
}
};
Signals.addSignalMethods(SearchEntry.prototype);
function BaseTab(titleActor, pageActor) {
this._init(titleActor, pageActor);
}
BaseTab.prototype = {
_init: function(titleActor, pageActor) {
this.title = titleActor;
this.page = new St.Bin({ child: pageActor,
x_align: St.Align.START,
y_align: St.Align.START,
x_fill: true,
y_fill: true,
style_class: 'view-tab-page' });
this.visible = false;
},
show: function() {
this.visible = true;
this.page.opacity = 0;
this.page.show();
Tweener.addTween(this.page,
{ opacity: 255,
time: 0.1,
transition: 'easeOutQuad' });
},
hide: function() {
this.visible = false;
Tweener.addTween(this.page,
{ opacity: 0,
time: 0.1,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this.page.hide();
})
});
},
_activate: function() {
this.emit('activated');
}
};
Signals.addSignalMethods(BaseTab.prototype);
function ViewTab(label, pageActor) {
this._init(label, pageActor);
}
ViewTab.prototype = {
__proto__: BaseTab.prototype,
_init: function(label, pageActor) {
let titleActor = new St.Button({ label: label,
style_class: 'view-tab-title' });
titleActor.connect('clicked', Lang.bind(this, this._activate));
BaseTab.prototype._init.call(this, titleActor, pageActor);
}
};
function SearchTab(focusBase) {
this._init(focusBase);
}
SearchTab.prototype = {
__proto__: BaseTab.prototype,
_init: function(focusBase) {
this._searchActive = false;
this._searchPending = false;
this._keyPressId = 0;
this._searchTimeoutId = 0;
this._focusBase = focusBase;
this._searchSystem = new Search.SearchSystem();
this._openSearchSystem = new Search.OpenSearchSystem();
this._searchEntry = new SearchEntry(focusBase);
this._searchResults = new SearchDisplay.SearchResults(this._searchSystem, this._openSearchSystem);
BaseTab.prototype._init.call(this,
this._searchEntry.actor,
this._searchResults.actor);
this._searchEntry.entry.connect('text-changed',
Lang.bind(this, this._onTextChanged));
this._searchEntry.entry.connect('activate', Lang.bind(this, function (se) {
if (this._searchTimeoutId > 0) {
Mainloop.source_remove(this._searchTimeoutId);
this._doSearch();
}
this._searchResults.activateSelected();
return true;
}));
},
setFindAsYouType: function(enabled) {
if (enabled)
this._searchEntry.show();
else
this._searchEntry.hide();
},
show: function() {
BaseTab.prototype.show.call(this);
if (this._keyPressId == 0)
this._keyPressId = this._searchEntry.entry.connect('key-press-event',
Lang.bind(this, this._onKeyPress));
},
hide: function() {
BaseTab.prototype.hide.call(this);
if (this._keyPressId > 0) {
this._searchEntry.entry.disconnect(this._keyPressId);
this._keyPressId = 0;
}
this._searchEntry.reset();
},
addSearchProvider: function(provider) {
this._searchSystem.registerProvider(provider);
this._searchResults.createProviderMeta(provider);
},
_onTextChanged: function (se, prop) {
let searchPreviouslyActive = this._searchActive;
this._searchActive = this._searchEntry.isActive();
this._searchPending = this._searchActive && !searchPreviouslyActive;
if (this._searchPending) {
this._searchResults.startingSearch();
}
if (this._searchActive) {
this._activate();
} else {
this.emit('search-cancelled');
}
if (!this._searchActive) {
if (this._searchTimeoutId > 0) {
Mainloop.source_remove(this._searchTimeoutId);
this._searchTimeoutId = 0;
}
return;
}
if (this._searchTimeoutId > 0)
return;
this._searchTimeoutId = Mainloop.timeout_add(150, Lang.bind(this, this._doSearch));
},
_onKeyPress: function(entry, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.Up) {
if (!this._searchActive)
return true;
this._searchResults.selectUp(false);
return true;
} else if (symbol == Clutter.Down) {
if (!this._searchActive)
return true;
this._searchResults.selectDown(false);
return true;
}
return false;
},
_doSearch: function () {
this._searchTimeoutId = 0;
let text = this._searchEntry.getText();
this._searchResults.updateSearch(text);
return false;
}
};
function ViewSelector() {
this._init();
}
ViewSelector.prototype = {
_init : function() {
this.actor = new St.BoxLayout({ name: 'viewSelector',
vertical: true });
// The tab bar is located at the top of the view selector and
// holds both "normal" tab labels and the search entry. The former
// is left aligned, the latter right aligned - unless the text
// direction is RTL, in which case the order is reversed.
this._tabBar = new Shell.GenericContainer();
this._tabBar.connect('get-preferred-width',
Lang.bind(this, this._getPreferredTabBarWidth));
this._tabBar.connect('get-preferred-height',
Lang.bind(this, this._getPreferredTabBarHeight));
this._tabBar.connect('allocate',
Lang.bind(this, this._allocateTabBar));
this.actor.add(this._tabBar);
// Box to hold "normal" tab labels
this._tabBox = new St.BoxLayout({ name: 'viewSelectorTabBar' });
this._tabBar.add_actor(this._tabBox);
// The searchArea just holds the entry
this._searchArea = new St.Bin({ name: 'searchArea' });
this._tabBar.add_actor(this._searchArea);
// The page area holds the tab pages. Every page is given the
// area's full allocation, so that the pages would appear on top
// of each other if the inactive ones weren't hidden.
this._pageArea = new Shell.Stack();
this.actor.add(this._pageArea, { x_fill: true,
y_fill: true,
expand: true });
this._tabs = [];
this._activeTab = null;
this._searchTab = new SearchTab(this.actor);
this._searchArea.set_child(this._searchTab.title);
this._addTab(this._searchTab);
this._searchTab.connect('search-cancelled', Lang.bind(this,
function() {
this._switchTab(this._activeTab);
}));
this._keyPressId = 0;
this._itemDragBeginId = 0;
this._overviewHidingId = 0;
// Public constraints which may be used to tie actors' height or
// vertical position to the current tab's content; as the content's
// height and position depend on the view selector's style properties
// (e.g. font size, padding, spacing, ...) it would be extremely hard
// and ugly to get these from the outside. While it would be possible
// to use position and height properties directly, outside code would
// need to ensure that the content is properly allocated before
// accessing the properties.
this.constrainY = new Clutter.BindConstraint({ source: this._pageArea,
coordinate: Clutter.BindCoordinate.Y });
this.constrainHeight = new Clutter.BindConstraint({ source: this._pageArea,
coordinate: Clutter.BindCoordinate.HEIGHT });
},
_addTab: function(tab) {
tab.page.hide();
this._pageArea.add_actor(tab.page);
tab.connect('activated', Lang.bind(this, function(tab) {
this._switchTab(tab);
}));
},
addViewTab: function(title, pageActor) {
let viewTab = new ViewTab(title, pageActor);
this._tabs.push(viewTab);
this._tabBox.add(viewTab.title);
this._addTab(viewTab);
},
_switchTab: function(tab) {
if (this._activeTab && this._activeTab.visible) {
if (this._activeTab == tab)
return;
this._activeTab.title.remove_style_pseudo_class('selected');
this._activeTab.hide();
}
if (tab != this._searchTab) {
tab.title.add_style_pseudo_class('selected');
this._activeTab = tab;
if (this._searchTab.visible) {
this._searchTab.hide();
}
}
if (!tab.visible)
tab.show();
// Pull a Meg Ryan:
if (Main.overview && Main.overview.workspaces) {
if (tab != this._tabs[0]) {
Tweener.addTween(Main.overview.workspaces.actor,
{ opacity: 0,
time: 0.1,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
Main.overview.workspaces.actor.hide();
Main.overview.workspaces.actor.opacity = 255;
})
});
} else {
Main.overview.workspaces.actor.opacity = 0;
Main.overview.workspaces.actor.show();
Tweener.addTween(Main.overview.workspaces.actor,
{ opacity: 255,
time: 0.1,
transition: 'easeOutQuad' });
}
}
},
_switchDefaultTab: function() {
if (this._tabs.length > 0)
this._switchTab(this._tabs[0]);
},
_nextTab: function() {
if (this._tabs.length == 0 ||
this._tabs[this._tabs.length - 1] == this._activeTab)
return;
for (let i = 0; i < this._tabs.length; i++)
if (this._tabs[i] == this._activeTab) {
this._switchTab(this._tabs[i + 1]);
return;
}
},
_prevTab: function() {
if (this._tabs.length == 0 || this._tabs[0] == this._activeTab)
return;
for (let i = 0; i < this._tabs.length; i++)
if (this._tabs[i] == this._activeTab) {
this._switchTab(this._tabs[i - 1]);
return;
}
},
_getPreferredTabBarWidth: function(box, forHeight, alloc) {
let children = box.get_children();
for (let i = 0; i < children.length; i++) {
let [childMin, childNat] = children[i].get_preferred_width(forHeight);
alloc.min_size += childMin;
alloc.natural_size += childNat;
}
},
_getPreferredTabBarHeight: function(box, forWidth, alloc) {
let children = box.get_children();
for (let i = 0; i < children.length; i++) {
let [childMin, childNatural] = children[i].get_preferred_height(forWidth);
if (childMin > alloc.min_size)
alloc.min_size = childMin;
if (childNatural > alloc.natural_size)
alloc.natural_size = childNatural;
}
},
_allocateTabBar: function(container, box, flags) {
let allocWidth = box.x2 - box.x1;
let allocHeight = box.y2 - box.y1;
let [searchMinWidth, searchNatWidth] = this._searchArea.get_preferred_width(-1);
let [barMinWidth, barNatWidth] = this._tabBox.get_preferred_width(-1);
let childBox = new Clutter.ActorBox();
childBox.y1 = 0;
childBox.y2 = allocHeight;
if (this.actor.get_direction() == St.TextDirection.RTL) {
childBox.x1 = allocWidth - barNatWidth;
childBox.x2 = allocWidth;
} else {
childBox.x1 = 0;
childBox.x2 = barNatWidth;
}
this._tabBox.allocate(childBox, flags);
if (this.actor.get_direction() == St.TextDirection.RTL) {
childBox.x1 = 0;
childBox.x2 = searchNatWidth;
} else {
childBox.x1 = allocWidth - searchNatWidth;
childBox.x2 = allocWidth;
}
this._searchArea.allocate(childBox, flags);
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
function() {
this.constrainY.offset = this.actor.y;
}));
},
_onKeyPress: function(actor, event) {
let modifiers = Shell.get_event_state(event);
let symbol = event.get_key_symbol();
if (symbol == Clutter.Escape) {
Main.overview.hide();
return true;
} else if (modifiers & Clutter.ModifierType.CONTROL_MASK) {
if (symbol == Clutter.Page_Up) {
if (!this._searchActive)
this._prevTab();
return true;
} else if (symbol == Clutter.Page_Down) {
if (!this._searchActive)
this._nextTab();
return true;
}
}
return false;
},
addSearchProvider: function(provider) {
this._searchTab.addSearchProvider(provider);
},
show: function() {
this._searchTab.setFindAsYouType(true);
if (this._itemDragBeginId == 0)
this._itemDragBeginId = Main.overview.connect('item-drag-begin',
Lang.bind(this, this._switchDefaultTab));
if (this._overviewHidingId == 0)
this._overviewHidingId = Main.overview.connect('hiding',
Lang.bind(this, this._switchDefaultTab));
if (this._keyPressId == 0)
this._keyPressId = this.actor.connect('key-press-event',
Lang.bind(this, this._onKeyPress));
this._switchDefaultTab();
},
hide: function() {
this._searchTab.setFindAsYouType(false);
if (this._keyPressId > 0) {
this.actor.disconnect(this._keyPressId);
this._keyPressId = 0;
}
if (this._itemDragBeginId > 0) {
Main.overview.disconnect(this._itemDragBeginId);
this._itemDragBeginId = 0;
}
if (this._overviewHidingId > 0) {
Main.overview.disconnect(this._overviewHidingId);
this._overviewHidingId = 0;
}
}
};
Signals.addSignalMethods(ViewSelector.prototype);

View File

@ -497,6 +497,8 @@ WindowManager.prototype = {
for (let i = 0; i < switchData.windows.length; i++) {
let w = switchData.windows[i];
if (w.window.is_destroyed()) // Window gone
continue;
if (w.window.get_parent() == switchData.outGroup) {
w.window.reparent(w.parent);
w.window.hide();
@ -543,24 +545,34 @@ WindowManager.prototype = {
},
actionMoveWorkspaceLeft: function() {
let rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL);
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
if (activeWorkspaceIndex > 0) {
global.screen.get_workspace_by_index(activeWorkspaceIndex - 1).activate(global.get_current_time());
if (!Main.overview.visible)
this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.LEFT, activeWorkspaceIndex - 1);
} else if (!Main.overview.visible) {
this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.LEFT, activeWorkspaceIndex);
}
let indexToActivate = activeWorkspaceIndex;
if (rtl && activeWorkspaceIndex < global.screen.n_workspaces - 1)
indexToActivate++;
else if (!rtl && activeWorkspaceIndex > 0)
indexToActivate--;
if (indexToActivate != activeWorkspaceIndex)
global.screen.get_workspace_by_index(indexToActivate).activate(global.get_current_time());
if (!Main.overview.visible)
this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.LEFT, indexToActivate);
},
actionMoveWorkspaceRight: function() {
let rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL);
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
if (activeWorkspaceIndex < global.screen.n_workspaces - 1) {
global.screen.get_workspace_by_index(activeWorkspaceIndex + 1).activate(global.get_current_time());
if (!Main.overview.visible)
this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.RIGHT, activeWorkspaceIndex + 1);
} else if (!Main.overview.visible) {
this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.RIGHT, activeWorkspaceIndex);
}
let indexToActivate = activeWorkspaceIndex;
if (rtl && activeWorkspaceIndex > 0)
indexToActivate--;
else if (!rtl && activeWorkspaceIndex < global.screen.n_workspaces - 1)
indexToActivate++;
if (indexToActivate != activeWorkspaceIndex)
global.screen.get_workspace_by_index(indexToActivate).activate(global.get_current_time());
if (!Main.overview.visible)
this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.RIGHT, indexToActivate);
}
};

View File

@ -20,9 +20,6 @@ const FOCUS_ANIMATION_TIME = 0.15;
const WINDOW_DND_SIZE = 256;
const FRAME_COLOR = new Clutter.Color();
FRAME_COLOR.from_pixel(0xffffffff);
const SCROLL_SCALE_AMOUNT = 100 / 5;
const LIGHTBOX_FADE_TIME = 0.1;
@ -54,11 +51,6 @@ function _clamp(value, min, max) {
return Math.max(min, Math.min(max, value));
}
// Spacing between workspaces. At the moment, the same spacing is used
// in both zoomed-in and zoomed-out views; this is slightly
// metaphor-breaking, but the alternatives are also weird.
const GRID_SPACING = 15;
const FRAME_SIZE = GRID_SPACING / 3;
function ScaledPoint(x, y, scaleX, scaleY) {
[this.x, this.y, this.scaleX, this.scaleY] = arguments;
@ -140,7 +132,10 @@ WindowClone.prototype = {
if (this.inDrag || this._zooming)
// We'll fix up the stack after the drag/zooming
return;
this.actor.raise(this._stackAbove);
if (this._stackAbove == null)
this.actor.lower_bottom();
else
this.actor.raise(this._stackAbove);
},
destroy: function () {
@ -247,11 +242,13 @@ WindowClone.prototype = {
this.emit('zoom-end');
this.actor.reparent(this._origParent);
if (this._stackAbove == null)
this.actor.lower_bottom();
// If the workspace has been destroyed while we were reparented to
// the stage, _stackAbove will be unparented and we can't raise our
// actor above it - as we are bound to be destroyed anyway in that
// case, we can skip that step
if (this._stackAbove && this._stackAbove.get_parent())
else if (this._stackAbove.get_parent())
this.actor.raise(this._stackAbove);
[this.actor.x, this.actor.y] = this._zoomLocalOrig.getPosition();
@ -283,82 +280,20 @@ WindowClone.prototype = {
// We may not have a parent if DnD completed successfully, in
// which case our clone will shortly be destroyed and replaced
// with a new one on the target workspace.
if (this.actor.get_parent() != null)
this.actor.raise(this._stackAbove);
if (this.actor.get_parent() != null) {
if (this._stackAbove == null)
this.actor.lower_bottom();
else
this.actor.raise(this._stackAbove);
}
this.emit('drag-end');
}
};
Signals.addSignalMethods(WindowClone.prototype);
function DesktopClone(window) {
this._init(window);
}
DesktopClone.prototype = {
_init : function(window) {
this.actor = new Clutter.Group({ reactive: true });
let background = new Clutter.Clone({ source: global.background_actor });
this.actor.add_actor(background);
if (window) {
this._desktop = new Clutter.Clone({ source: window.get_texture() });
this.actor.add_actor(this._desktop);
this._desktop.hide();
} else {
this._desktop = null;
}
this.actor.connect('button-release-event',
Lang.bind(this, this._onButtonRelease));
},
zoomFromOverview: function(fadeInIcons) {
if (this._desktop == null)
return;
if (fadeInIcons) {
this._desktop.opacity = 0;
this._desktop.show();
Tweener.addTween(this._desktop,
{ opacity: 255,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad' });
}
},
zoomToOverview: function(fadeOutIcons) {
if (this._desktop == null)
return;
if (fadeOutIcons) {
this._desktop.opacity = 255;
this._desktop.show();
Tweener.addTween(this._desktop,
{ opacity: 0,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this._desktop.hide();
})
});
} else {
this._desktop.hide();
}
},
_onButtonRelease : function (actor, event) {
this.emit('selected', event.get_time());
}
};
Signals.addSignalMethods(DesktopClone.prototype);
/**
* @windowClone: Corresponding window clone
* @parentActor: The actor which will be the parent of all overlay items
@ -461,7 +396,7 @@ WindowOverlay.prototype = {
// These parameters are not the values retrieved with
// get_transformed_position() and get_transformed_size(),
// as windowClone might be moving.
// See Workspace._fadeInWindowOverlay
// See Workspace._showWindowOverlay
updatePositions: function(cloneX, cloneY, cloneWidth, cloneHeight) {
let button = this.closeButton;
let title = this.title;
@ -534,12 +469,10 @@ WindowOverlay.prototype = {
_idleToggleCloseButton: function() {
this._idleToggleCloseId = 0;
let [x, y, mask] = global.get_pointer();
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE,
x, y);
if (actor != this._windowClone.actor && actor != this.closeButton) {
if (!this._windowClone.actor.has_pointer &&
!this.closeButton.has_pointer)
this.closeButton.hide();
}
return false;
},
@ -561,7 +494,6 @@ WindowOverlay.prototype = {
this._parentActor.queue_relayout();
}
};
Signals.addSignalMethods(WindowOverlay.prototype);
const WindowPositionFlags = {
@ -604,35 +536,10 @@ Workspace.prototype = {
let windows = global.get_window_actors().filter(this._isMyWindow, this);
// Find the desktop window
for (let i = 0; i < windows.length; i++) {
if (windows[i].meta_window.get_window_type() == Meta.WindowType.DESKTOP) {
this._desktop = new DesktopClone(windows[i]);
break;
}
}
// If there wasn't one, fake it
if (!this._desktop)
this._desktop = new DesktopClone();
this._desktop.connect('selected',
Lang.bind(this,
function(clone, time) {
// Only switch to the workspace when there's no application windows
// open (we always have one window for the desktop). The problem
// is that it's too easy to miss an app window and get the wrong
// one focused.
if (this._windows.length == 1) {
this.metaWorkspace.activate(time);
Main.overview.hide();
}
}));
this.actor.add_actor(this._desktop.actor);
// Create clones for remaining windows that should be
// visible in the Overview
this._windows = [this._desktop];
this._windowOverlays = [ null ];
this._windows = [];
this._windowOverlays = [];
for (let i = 0; i < windows.length; i++) {
if (this._isOverviewWindow(windows[i])) {
this._addWindowClone(windows[i]);
@ -649,10 +556,6 @@ Workspace.prototype = {
Lang.bind(this, this._windowRemoved));
this._repositionWindowsId = 0;
this._visible = false;
this._frame = null;
this.leavingOverview = false;
},
@ -692,6 +595,10 @@ Workspace.prototype = {
return this._lookupIndex(metaWindow) >= 0;
},
isEmpty: function() {
return this._windows.length == 0;
},
setShowOnlyWindows: function(showOnlyWindows, reposition) {
this._showOnlyWindows = showOnlyWindows;
this._resetCloneVisibility();
@ -714,9 +621,6 @@ Workspace.prototype = {
this._lightbox.show();
else
this._lightbox.hide();
if (this._frame)
this._frame.set_opacity(showLightbox ? 150 : 255);
},
/**
@ -737,32 +641,6 @@ Workspace.prototype = {
this._lightbox.highlight(actor);
},
// Mark the workspace selected/not-selected
setSelected : function(selected) {
// Don't draw a frame if we only have one workspace
if (selected && global.screen.n_workspaces > 1) {
if (this._frame)
return;
// FIXME: do something cooler-looking using clutter-cairo
this._frame = new Clutter.Rectangle({ color: FRAME_COLOR });
this.actor.add_actor(this._frame);
this._frame.set_position(this._desktop.actor.x - FRAME_SIZE / this.actor.scale_x,
this._desktop.actor.y - FRAME_SIZE / this.actor.scale_y);
this._frame.set_size(this._desktop.actor.width + 2 * FRAME_SIZE / this.actor.scale_x,
this._desktop.actor.height + 2 * FRAME_SIZE / this.actor.scale_y);
this._frame.lower_bottom();
this._framePosHandler = this.actor.connect('notify::scale-x', Lang.bind(this, this._updateFramePosition));
} else {
if (!this._frame)
return;
this.actor.disconnect(this._framePosHandler);
this._frame.destroy();
this._frame = null;
}
},
/**
* setReactive:
* @reactive: %true iff the workspace should be reactive
@ -770,14 +648,7 @@ Workspace.prototype = {
* Set the workspace (desktop) reactive
**/
setReactive: function(reactive) {
this._desktop.actor.reactive = reactive;
},
_updateFramePosition : function() {
this._frame.set_position(this._desktop.actor.x - FRAME_SIZE / this.actor.scale_x,
this._desktop.actor.y - FRAME_SIZE / this.actor.scale_y);
this._frame.set_size(this._desktop.actor.width + 2 * FRAME_SIZE / this.actor.scale_x,
this._desktop.actor.height + 2 * FRAME_SIZE / this.actor.scale_y);
this.actor.reactive = reactive;
},
_isCloneVisible: function(clone) {
@ -788,7 +659,7 @@ Workspace.prototype = {
* _getVisibleClones:
*
* Returns a list WindowClone objects where the clone isn't filtered
* out by any application filter. The clone for the desktop is excluded.
* out by any application filter.
* The returned array will always be newly allocated; it is not in any
* defined order, and thus it's convenient to call .sort() with your
* choice of sorting function.
@ -796,7 +667,7 @@ Workspace.prototype = {
_getVisibleClones: function() {
let visible = [];
for (let i = 1; i < this._windows.length; i++) {
for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i];
if (!this._isCloneVisible(clone))
@ -808,7 +679,7 @@ Workspace.prototype = {
},
_resetCloneVisibility: function () {
for (let i = 1; i < this._windows.length; i++) {
for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i];
let overlay = this._windowOverlays[i];
@ -1002,14 +873,13 @@ Workspace.prototype = {
xCenter = xCenter * global.screen_width;
let rect = new Meta.Rectangle();
metaWindow.get_outer_rect(rect);
let rect = metaWindow.get_outer_rect();
let buttonOuterHeight, captionHeight;
let buttonOuterWidth = 0;
if (this._windowOverlays[1]) {
[buttonOuterHeight, captionHeight] = this._windowOverlays[1].chromeHeights();
buttonOuterWidth = this._windowOverlays[1].chromeWidth() / this.scale;
if (this._windowOverlays[0]) {
[buttonOuterHeight, captionHeight] = this._windowOverlays[0].chromeHeights();
buttonOuterWidth = this._windowOverlays[0].chromeWidth() / this.scale;
} else
[buttonOuterHeight, captionHeight] = [0, 0];
buttonOuterHeight /= this.scale;
@ -1070,6 +940,9 @@ Workspace.prototype = {
let slots = this._computeAllWindowSlots(visibleClones.length);
visibleClones = this._orderWindowsByMotionAndStartup(visibleClones, slots);
let currentWorkspace = global.screen.get_active_workspace();
let isOnCurrentWorkspace = this.metaWorkspace == currentWorkspace;
for (let i = 0; i < visibleClones.length; i++) {
let slot = slots[i];
let clone = visibleClones[i];
@ -1086,7 +959,7 @@ Workspace.prototype = {
if (overlay)
overlay.hide();
if (animate) {
if (animate && isOnCurrentWorkspace) {
if (!metaWindow.showing_on_its_workspace()) {
/* Hidden windows should fade in and grow
* therefore we need to resize them now so they
@ -1116,20 +989,18 @@ Workspace.prototype = {
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this._fadeInWindowOverlay(clone, overlay);
this._showWindowOverlay(clone, overlay, true);
})
});
} else {
clone.actor.set_position(x, y);
clone.actor.set_scale(scale, scale);
this._fadeInWindowOverlay(clone, overlay);
this._showWindowOverlay(clone, overlay, isOnCurrentWorkspace);
}
}
},
syncStacking: function(stackIndices) {
let desktopClone = this._windows[0];
let visibleClones = this._getVisibleClones();
visibleClones.sort(function (a, b) { return stackIndices[a.metaWindow.get_stable_sequence()] - stackIndices[b.metaWindow.get_stable_sequence()]; });
@ -1137,7 +1008,7 @@ Workspace.prototype = {
let clone = visibleClones[i];
let metaWindow = clone.metaWindow;
if (i == 0) {
clone.setStackAbove(desktopClone.actor);
clone.setStackAbove(null);
} else {
let previousClone = visibleClones[i - 1];
clone.setStackAbove(previousClone.actor);
@ -1145,7 +1016,7 @@ Workspace.prototype = {
}
},
_fadeInWindowOverlay: function(clone, overlay) {
_showWindowOverlay: function(clone, overlay, fade) {
if (clone.inDrag)
return;
@ -1157,8 +1028,8 @@ Workspace.prototype = {
// be after the workspace animation finishes.
let [cloneX, cloneY] = clone.actor.get_position();
let [cloneWidth, cloneHeight] = clone.actor.get_size();
cloneX = this.gridX + this.scale * cloneX;
cloneY = this.gridY + this.scale * cloneY;
cloneX = this.x + this.scale * cloneX;
cloneY = this.y + this.scale * cloneY;
cloneWidth = this.scale * clone.actor.scale_x * cloneWidth;
cloneHeight = this.scale * clone.actor.scale_y * cloneHeight;
@ -1167,22 +1038,26 @@ Workspace.prototype = {
if (overlay) {
overlay.updatePositions(cloneX, cloneY, cloneWidth, cloneHeight);
overlay.fadeIn();
if (fade)
overlay.fadeIn();
else
overlay.show();
}
},
_fadeInAllOverlays: function() {
for (let i = 1; i < this._windows.length; i++) {
_showAllOverlays: function() {
let currentWorkspace = global.screen.get_active_workspace();
for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i];
let overlay = this._windowOverlays[i];
if (this._showOnlyWindows != null && !(clone.metaWindow in this._showOnlyWindows))
continue;
this._fadeInWindowOverlay(clone, overlay);
this._showWindowOverlay(clone, overlay, this.metaWorkspace == currentWorkspace);
}
},
_hideAllOverlays: function() {
for (let i = 1; i< this._windows.length; i++) {
for (let i = 0; i < this._windows.length; i++) {
let overlay = this._windowOverlays[i];
overlay.hide();
}
@ -1197,8 +1072,8 @@ Workspace.prototype = {
let wsHeight = this.actor.height * this.scale;
let pointerHasMoved = (this._cursorX != x && this._cursorY != y);
let inWorkspace = (this.gridX < x && x < this.gridX + wsWidth &&
this.gridY < y && y < this.gridY + wsHeight);
let inWorkspace = (this.x < x && x < this.x + wsWidth &&
this.y < y && y < this.y + wsHeight);
if (pointerHasMoved && inWorkspace) {
// store current cursor position
@ -1213,7 +1088,7 @@ Workspace.prototype = {
showWindowsOverlays: function() {
this._windowOverlaysGroup.show();
this._fadeInAllOverlays();
this._showAllOverlays();
},
hideWindowsOverlays: function() {
@ -1309,8 +1184,8 @@ Workspace.prototype = {
},
// check for maximized windows on the workspace
_haveMaximizedWindows: function() {
for (let i = 1; i < this._windows.length; i++) {
hasMaximizedWindows: function() {
for (let i = 0; i < this._windows.length; i++) {
let metaWindow = this._windows[i].metaWindow;
if (metaWindow.showing_on_its_workspace() &&
metaWindow.maximized_horizontally &&
@ -1322,7 +1197,7 @@ Workspace.prototype = {
// Animate the full-screen to Overview transition.
zoomToOverview : function() {
this.actor.set_position(this.gridX, this.gridY);
this.actor.set_position(this.x, this.y);
this.actor.set_scale(this.scale, this.scale);
// Position and scale the windows.
@ -1330,18 +1205,12 @@ Workspace.prototype = {
this.positionWindows(WindowPositionFlags.ANIMATE | WindowPositionFlags.ZOOM);
else
this.positionWindows(WindowPositionFlags.ZOOM);
let active = global.screen.get_active_workspace();
let fadeInIcons = (Main.overview.animationInProgress &&
active == this.metaWorkspace &&
!this._haveMaximizedWindows());
this._desktop.zoomToOverview(fadeInIcons);
this._visible = true;
},
// Animates the return from Overview mode
zoomFromOverview : function() {
let currentWorkspace = global.screen.get_active_workspace();
this.leavingOverview = true;
this._hideAllOverlays();
@ -1353,8 +1222,11 @@ Workspace.prototype = {
this._overviewHiddenId = Main.overview.connect('hidden', Lang.bind(this,
this._doneLeavingOverview));
if (this._metaWorkspace == currentWorkspace)
return;
// Position and scale the windows.
for (let i = 1; i < this._windows.length; i++) {
for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i];
clone.zoomFromOverview();
@ -1383,75 +1255,6 @@ Workspace.prototype = {
}
}
let active = global.screen.get_active_workspace();
let fadeOutIcons = (active == this.metaWorkspace &&
!this._haveMaximizedWindows());
this._desktop.zoomFromOverview(fadeOutIcons);
this._visible = false;
},
// Animates grid shrinking/expanding when a row or column
// of workspaces is added or removed
resizeToGrid : function (oldScale) {
this._hideAllOverlays();
Tweener.addTween(this.actor,
{ x: this.gridX,
y: this.gridY,
scale_x: this.scale,
scale_y: this.scale,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, this._fadeInAllOverlays)
});
},
// Animates the addition of a new (empty) workspace
slideIn : function(oldScale) {
if (this.gridCol > this.gridRow) {
this.actor.set_position(global.screen_width, this.gridY);
this.actor.set_scale(oldScale, oldScale);
} else {
this.actor.set_position(this.gridX, global.screen_height);
this.actor.set_scale(this.scale, this.scale);
}
Tweener.addTween(this.actor,
{ x: this.gridX,
y: this.gridY,
scale_x: this.scale,
scale_y: this.scale,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad'
});
this._visible = true;
},
// Animates the removal of a workspace
slideOut : function(onComplete) {
let destX = this.actor.x, destY = this.actor.y;
this._hideAllOverlays();
if (this.gridCol > this.gridRow)
destX = global.screen_width;
else
destY = global.screen_height;
Tweener.addTween(this.actor,
{ x: destX,
y: destY,
scale_x: this.scale,
scale_y: this.scale,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: onComplete
});
this._visible = false;
// Don't let the user try to select this workspace as it's
// making its exit.
this._desktop.reactive = false;
},
destroy : function() {
@ -1475,7 +1278,7 @@ Workspace.prototype = {
// their parent (this.actor), but we might have a zoomed window
// which has been reparented to the stage - _windows[0] holds
// the desktop window, which is never reparented
for (let w = 1; w < this._windows.length; w++)
for (let w = 0; w < this._windows.length; w++)
this._windows[w].destroy();
this._windows = [];
},
@ -1506,12 +1309,12 @@ Workspace.prototype = {
Lang.bind(this, this._onCloneSelected));
clone.connect('drag-begin',
Lang.bind(this, function(clone) {
this.emit('window-drag-begin', clone.actor);
Main.overview.beginWindowDrag();
overlay.hide();
}));
clone.connect('drag-end',
Lang.bind(this, function(clone) {
this.emit('window-drag-end', clone.actor);
Main.overview.endWindowDrag();
overlay.show();
}));
clone.connect('zoom-start',
@ -1522,6 +1325,10 @@ Workspace.prototype = {
Lang.bind(this, function() {
this._windowIsZooming = false;
}));
win.connect('size-changed',
Lang.bind(this, function() {
this.positionWindows(0);
}));
this.actor.add_actor(clone.actor);
@ -1534,7 +1341,7 @@ Workspace.prototype = {
},
_onShowOverlayClose: function (windowOverlay) {
for (let i = 1; i < this._windowOverlays.length; i++) {
for (let i = 0; i < this._windowOverlays.length; i++) {
let overlay = this._windowOverlays[i];
if (overlay == windowOverlay)
continue;
@ -1643,11 +1450,11 @@ function _workspaceRelativeModifier(workspace) {
}
return [ { name: 'x',
parameters: { workspacePos: workspace.gridX,
parameters: { workspacePos: workspace.x,
overviewPos: overviewPosX,
overviewScale: overviewScale } },
{ name: 'y',
parameters: { workspacePos: workspace.gridY,
parameters: { workspacePos: workspace.y,
overviewPos: overviewPosY,
overviewScale: overviewScale } }
];

View File

@ -89,6 +89,7 @@ WorkspaceSwitcherPopup.prototype = {
let children = this._list.get_children();
let childBox = new Clutter.ActorBox();
let rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL);
let x = box.x1;
let prevChildBoxX2 = box.x1 - this._itemSpacing;
for (let i = 0; i < children.length; i++) {
@ -98,6 +99,11 @@ WorkspaceSwitcherPopup.prototype = {
childBox.y2 = box.y1 + this._childHeight;
x += this._childWidth + this._itemSpacing;
prevChildBoxX2 = childBox.x2;
if (rtl) {
let ltrChildBoxX1 = childBox.x1;
childBox.x1 = box.x2 - (childBox.x2 - box.x1);
childBox.x2 = box.x2 - (ltrChildBoxX1 - box.x1);
}
children[i].allocate(childBox, flags);
}
},

File diff suppressed because it is too large Load Diff

127
js/ui/xdndHandler.js Normal file
View File

@ -0,0 +1,127 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Mainloop = imports.mainloop;
const DND = imports.ui.dnd;
function XdndHandler() {
this._init();
}
XdndHandler.prototype = {
_init: function() {
// Used to display a clone of the cursor window when the
// window group is hidden (like it happens in the overview)
this._cursorWindowClone = null;
// Used as a drag actor in case we don't have a cursor window clone
this._dummy = new Clutter.Rectangle({ width: 1, height: 1, opacity: 0 });
global.stage.add_actor(this._dummy);
this._dummy.hide();
// Mutter delays the creation of the output window as long
// as possible to avoid flicker. In case a plugin wants to
// access it directly it has to connect to the stage's show
// signal. (see comment in compositor.c:meta_compositor_manage_screen)
global.stage.connect('show', function () {
global.init_xdnd();
return false;
});
global.connect('xdnd-enter', Lang.bind(this, this._onEnter));
global.connect('xdnd-position-changed', Lang.bind(this, this._onPositionChanged));
global.connect('xdnd-leave', Lang.bind(this, this._onLeave));
this._windowGroupVisibilityHandlerId = 0;
},
// Called when the user cancels the drag (i.e release the button)
_onLeave: function() {
if (this._windowGroupVisibilityHandlerId != 0) {
Mainloop.source_remove(this._windowGroupVisibilityHandlerId);
this._windowGroupVisibilityHandlerId = 0;
}
this.emit('drag-end');
},
_onEnter: function() {
this._windowGroupVisibilityHandlerId =
global.window_group.connect('notify::visible',
Lang.bind(this, this._onWindowGroupVisibilityChanged));
this.emit('drag-begin', global.get_current_time());
},
_onWindowGroupVisibilityChanged: function() {
if (!global.window_group.visible) {
if (this._cursorWindowClone)
return;
let windows = global.get_window_actors();
let cursorWindow = windows[windows.length - 1];
// FIXME: more reliable way?
if (!cursorWindow.is_override_redirect())
return;
let constraint_position = new Clutter.BindConstraint({ coordinate : Clutter.BindCoordinate.POSITION,
source: cursorWindow});
this._cursorWindowClone = new Clutter.Clone({ source: cursorWindow });
global.overlay_group.add_actor(this._cursorWindowClone);
Shell.util_set_hidden_from_pick(this._cursorWindowClone, true);
// Make sure that the clone has the same position as the source
this._cursorWindowClone.add_constraint(constraint_position);
} else {
if (this._cursorWindowClone)
{
this._cursorWindowClone.destroy();
this._cursorWindowClone = null;
}
}
},
_onPositionChanged: function(obj, x, y) {
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y);
// Make sure that the cursor window is on top
if (this._cursorWindowClone)
this._cursorWindowClone.raise_top();
let dragEvent = {
x: x,
y: y,
dragActor: this._cursorWindowClone ? this._cursorWindowClone : this._dummy,
source: this,
targetActor: pickedActor
};
for (let i = 0; i < DND.dragMonitors.length; i++) {
let motionFunc = DND.dragMonitors[i].dragMotion;
if (motionFunc) {
let result = motionFunc(dragEvent);
if (result != DND.DragMotionResult.CONTINUE)
return;
}
}
while (pickedActor) {
if (pickedActor._delegate && pickedActor._delegate.handleDragOver) {
let result = pickedActor._delegate.handleDragOver(this,
dragEvent.dragActor,
x,
y,
global.get_current_time());
if (result != DND.DragMotionResult.CONTINUE)
return;
}
pickedActor = pickedActor.get_parent();
}
}
}
Signals.addSignalMethods(XdndHandler.prototype);

View File

@ -8,6 +8,7 @@ el
en_GB
es
et
fa
fi
fr
ga

View File

@ -1,13 +1,14 @@
data/gnome-shell.desktop.in.in
data/gnome-shell-clock-preferences.desktop.in.in
data/org.gnome.shell.gschema.xml.in
data/org.gnome.accessibility.magnifier.gschema.xml.in
[type: gettext/glade]data/clock-preferences.ui
js/misc/util.js
js/ui/appDisplay.js
js/ui/appFavorites.js
js/ui/dash.js
js/ui/docDisplay.js
js/ui/endSessionDialog.js
js/ui/lookingGlass.js
js/ui/messageTray.js
js/ui/overview.js
js/ui/panel.js
js/ui/placeDisplay.js
@ -15,9 +16,17 @@ js/ui/popupMenu.js
js/ui/runDialog.js
js/ui/statusMenu.js
js/ui/status/accessibility.js
js/ui/status/bluetooth.js
js/ui/status/keyboard.js
js/ui/status/power.js
js/ui/status/volume.js
js/ui/telepathyClient.js
js/ui/viewSelector.js
js/ui/windowAttentionHandler.js
js/ui/workspacesView.js
src/gvc/gvc-mixer-control.c
src/gdmuser/gdm-user.c
src/shell-app-system.c
src/shell-global.c
src/shell-uri-util.c
src/shell-util.c

725
po/ar.po

File diff suppressed because it is too large Load Diff

567
po/de.po
View File

@ -6,19 +6,21 @@
#
# Hendrik Brandt <heb@gnome-de.org>, 2009.
# Hendrik Richter <hendrikr@gnome.org>, 2009.
# Mario Blättermann <mariobl@gnome.org>, 2009, 2010.
# Mario Blättermann <mariobl@gnome.org>, 2009, 2010, 2011.
# Mario Klug <mario@klug.me>, 2010.
# Christian Kirbach <Christian.Kirbach@googlemail.com>, 2009, 2010.
# Jakob Kramer <jakob.kramer@gmx.de>, 2010.
# Paul Seyfert <pseyfert@mathphys.fsk.uni-heidelberg.de>, 2010.
# Christian Kirbach <Christian.Kirbach@googlemail.com>, 2009, 2010, 2011.
#
msgid ""
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: 2010-10-10 03:14+0000\n"
"PO-Revision-Date: 2010-10-10 20:23+0200\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-01-01 23:21+0100\n"
"PO-Revision-Date: 2011-01-01 16:25+0100\n"
"Last-Translator: Christian Kirbach <Christian.Kirbach@googlemail.com>\n"
"Language-Team: Deutsch <gnome-de@gnome.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@ -105,12 +107,8 @@ msgstr ""
msgid "List of desktop file IDs for favorite applications"
msgstr "Liste der Kennungen der Desktop-Dateien für bevorzugte Anwendungen"
#: ../data/org.gnome.shell.gschema.xml.in.h:13
msgid "Overview workspace view mode"
msgstr "Modus des Arbeitsflächen-Überblicks"
# Hier blicke ich überhaupt nicht durch.
#: ../data/org.gnome.shell.gschema.xml.in.h:14
#: ../data/org.gnome.shell.gschema.xml.in.h:13
msgid ""
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
"used for gst-launch. The pipeline should have an unconnected sink pad where "
@ -130,22 +128,22 @@ msgstr ""
"Das kann zum Senden der Ausgabe über shout2send an einen Icecast-Server oder "
"Ähnliches verwendet werden. Falls nicht (oder auf einen leeren Wert) "
"gesetzt, so wird die vorgegebene Weiterleitung verwendet, welche derzeit "
"»videorate ! theoraenc ! oggmux« lautet und die Aufnahme im Ogg-Theora-Format "
"speichert."
"»videorate ! theoraenc ! oggmux« lautet und die Aufnahme im Ogg-Theora-"
"Format speichert."
#: ../data/org.gnome.shell.gschema.xml.in.h:15
#: ../data/org.gnome.shell.gschema.xml.in.h:14
msgid "Show date in clock"
msgstr "Datum in der Uhr anzeigen"
#: ../data/org.gnome.shell.gschema.xml.in.h:16
#: ../data/org.gnome.shell.gschema.xml.in.h:15
msgid "Show the week date in the calendar"
msgstr "Wochentag im Kalender anzeigen"
#: ../data/org.gnome.shell.gschema.xml.in.h:17
#: ../data/org.gnome.shell.gschema.xml.in.h:16
msgid "Show time with seconds"
msgstr "Zeit sekundengenau anzeigen"
#: ../data/org.gnome.shell.gschema.xml.in.h:18
#: ../data/org.gnome.shell.gschema.xml.in.h:17
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
@ -153,7 +151,7 @@ msgstr ""
"Programme, welche auf diese Bezeichner zutreffen, werden im Favoriten-"
"Bereich angezeigt."
#: ../data/org.gnome.shell.gschema.xml.in.h:19
#: ../data/org.gnome.shell.gschema.xml.in.h:18
msgid ""
"The filename for recorded screencasts will be a unique filename based on the "
"current date, and use this extension. It should be changed when recording to "
@ -164,7 +162,7 @@ msgstr ""
"Dateiname sollte geändert werden, wenn Sie in einem anderen Containerformat "
"aufnehmen."
#: ../data/org.gnome.shell.gschema.xml.in.h:20
#: ../data/org.gnome.shell.gschema.xml.in.h:19
msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames-per-second."
@ -173,19 +171,11 @@ msgstr ""
"der GNOME-Shell aufgezeichnet werden soll, in Einzelbildern pro Sekunde."
# hmm Enkodieren oder Kodieren?
#: ../data/org.gnome.shell.gschema.xml.in.h:21
#: ../data/org.gnome.shell.gschema.xml.in.h:20
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "Die GStreamer-Weiterleitung zur Enkodierung des Screencasts"
#: ../data/org.gnome.shell.gschema.xml.in.h:22
msgid ""
"The selected workspace view mode in the overview. Supported values are "
"\"single\" and \"grid\"."
msgstr ""
"Die gewählte Ansicht des Arbeitsflächen-Überblicks. Mögliche Werte sind "
"»single« (einfach) und »grid« (Raster)."
#: ../data/org.gnome.shell.gschema.xml.in.h:23
#: ../data/org.gnome.shell.gschema.xml.in.h:21
msgid ""
"The shell normally monitors active applications in order to present the most "
"used ones (e.g. in launchers). While this data will be kept private, you may "
@ -198,7 +188,7 @@ msgstr ""
"deaktivieren, um Ihre Privatsphäre zu schützen. Bitte beachten Sie, dass "
"bereits gespeicherte Daten hiervon nicht beeinflusst werden."
#: ../data/org.gnome.shell.gschema.xml.in.h:24
#: ../data/org.gnome.shell.gschema.xml.in.h:22
msgid ""
"This key specifies the format used by the panel clock when the format key is "
"set to \"custom\". You can use conversion specifiers understood by strftime"
@ -211,7 +201,7 @@ msgstr ""
"Format zu erhalten. Weitere Informationen finden Sie in der Handbuchseite zu "
"strftime()."
#: ../data/org.gnome.shell.gschema.xml.in.h:25
#: ../data/org.gnome.shell.gschema.xml.in.h:23
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\", "
@ -221,18 +211,18 @@ msgid ""
"the show_date and show_seconds keys are ignored."
msgstr ""
"Dieser Schlüssel legt das Stundenformat für die Anzeige der Panel-Uhr fest. "
"Mögliche Werte sind »12-hour«, »24-hour«, »unix« und »custom«. Wenn Sie »unix« "
"verwenden, zeigt die Uhr die Sekunden seit Epoch, dem Beginn der Unix-"
"Mögliche Werte sind »12-hour«, »24-hour«, »unix« und »custom«. Wenn Sie "
"»unix« verwenden, zeigt die Uhr die Sekunden seit Epoch, dem Beginn der Unix-"
"Zeitrechnung am 1. Januar 1970 an. Wenn Sie »custom« (benutzerdefiniert) "
"verwenden, zeigt die Uhr die Zeit gemäß dem im Schlüssel »custom_format« "
"angegebenen Format an. Beachten Sie, dass bei »unix« oder »custom« die "
"Schlüssel »show_date« und »show_seconds« ignoriert werden."
#: ../data/org.gnome.shell.gschema.xml.in.h:26
#: ../data/org.gnome.shell.gschema.xml.in.h:24
msgid "Uuids of extensions to disable"
msgstr "UUIDs der zu deaktivierenden Erweiterungen"
#: ../data/org.gnome.shell.gschema.xml.in.h:27
#: ../data/org.gnome.shell.gschema.xml.in.h:25
msgid "Whether to collect stats about applications usage"
msgstr "Legt fest, ob der Status der Anwendungsnutzung erfasst werden soll"
@ -266,14 +256,14 @@ msgid ""
msgstr ""
"Legt die Position des vergrößerten Bildes der Maus innerhalb der "
"vergrößerten Ansicht fest, und wie die Maus auf die Mausbewegungen des "
"Systems reagiert. Folgende Werte sind möglich: »none« - keine Mausverfolgung; "
"»centered« - das Mausbild wird in der Mitte des vergrößerten Bereiches "
"dargestellt (welche auch den Zeiger der Systemmaus darstellt), wobei der "
"vergrößerte Inhalt gerollt wird, sobald die Systemmaus bewegt wird; "
"»proportional« - die Position der vergrößerten Maus im vergrößerten Bereich "
"ist proportional zur Position der Systemmaus auf dem Bildschirm; »push« - "
"wenn die vergrößerte Maus einen der Ränder des vergrößerten Bereichs "
"berührt, wird der entsprechende Inhalt in die Ansicht geschoben."
"Systems reagiert. Folgende Werte sind möglich: »none« - keine "
"Mausverfolgung; »centered« - das Mausbild wird in der Mitte des vergrößerten "
"Bereiches dargestellt (welche auch den Zeiger der Systemmaus darstellt), "
"wobei der vergrößerte Inhalt gerollt wird, sobald die Systemmaus bewegt "
"wird; »proportional« - die Position der vergrößerten Maus im vergrößerten "
"Bereich ist proportional zur Position der Systemmaus auf dem Bildschirm; "
"»push« - wenn die vergrößerte Maus einen der Ränder des vergrößerten "
"Bereichs berührt, wird der entsprechende Inhalt in die Ansicht geschoben."
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:5
msgid ""
@ -422,62 +412,46 @@ msgstr "_12-Stunden-Format"
msgid "_24 hour format"
msgstr "_24-Stunden-Format"
#. **** Applications ****
#: ../js/ui/appDisplay.js:316 ../js/ui/dash.js:778
#. Translators: Filter to display all applications
#: ../js/ui/appDisplay.js:155
msgid "All"
msgstr "Alle"
#: ../js/ui/appDisplay.js:236
msgid "APPLICATIONS"
msgstr "ANWENDUNGEN"
#: ../js/ui/appDisplay.js:348
#: ../js/ui/appDisplay.js:266
msgid "PREFERENCES"
msgstr "EINSTELLUNGEN"
#: ../js/ui/appDisplay.js:648
#: ../js/ui/appDisplay.js:563
msgid "New Window"
msgstr "Neues Fenster"
#: ../js/ui/appDisplay.js:652
#: ../js/ui/appDisplay.js:567
msgid "Remove from Favorites"
msgstr "Aus Favoriten entfernen"
#: ../js/ui/appDisplay.js:653
#: ../js/ui/appDisplay.js:568
msgid "Add to Favorites"
msgstr "Zu Favoriten hinzufügen"
#: ../js/ui/appDisplay.js:830
msgid "Drag here to add favorites"
msgstr "Hier ablegen, um zu Favoriten hinzuzufügen"
#: ../js/ui/appFavorites.js:88
#: ../js/ui/appFavorites.js:91
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s wurde zu Ihren Favoriten hinzugefügt"
#: ../js/ui/appFavorites.js:107
#: ../js/ui/appFavorites.js:122
#, c-format
msgid "%s has been removed from your favorites."
msgstr "%s wurde aus Ihren Favoriten entfernt"
#: ../js/ui/dash.js:142
msgid "Find"
msgstr "Suchen"
#: ../js/ui/dash.js:27
msgid "Remove"
msgstr "Entfernen"
#: ../js/ui/dash.js:473
msgid "Searching..."
msgstr "Suche läuft …"
#: ../js/ui/dash.js:487
msgid "No matching results."
msgstr "Keine passenden Ergebnisse."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:797 ../js/ui/placeDisplay.js:554
msgid "PLACES & DEVICES"
msgstr "ORTE UND GERÄTE"
#. **** Documents ****
#: ../js/ui/dash.js:804 ../js/ui/docDisplay.js:494
#: ../js/ui/docDisplay.js:494
msgid "RECENT ITEMS"
msgstr "ZULETZT GEÖFFNETE DOKUMENTE"
@ -489,7 +463,9 @@ msgstr "Keine Erweiterungen installiert"
msgid "Enabled"
msgstr "Aktiviert"
#: ../js/ui/lookingGlass.js:591
#. translators:
#. * The device has been disabled
#: ../js/ui/lookingGlass.js:591 ../src/gvc/gvc-mixer-control.c:1087
msgid "Disabled"
msgstr "Deaktiviert"
@ -509,63 +485,71 @@ msgstr "Quelle zeigen"
msgid "Web Page"
msgstr "Webseite"
#: ../js/ui/overview.js:160
#: ../js/ui/overview.js:96
msgid "Undo"
msgstr "Rückgängig"
#: ../js/ui/overview.js:158
msgid "Windows"
msgstr "Fenster"
#: ../js/ui/overview.js:161
msgid "Applications"
msgstr "Anwendungen"
#. TODO - _quit() doesn't really work on apps in state STARTING yet
#: ../js/ui/panel.js:468
#: ../js/ui/panel.js:474
#, c-format
msgid "Quit %s"
msgstr "%s beenden"
#: ../js/ui/panel.js:493
#: ../js/ui/panel.js:499
msgid "Preferences"
msgstr "Einstellungen"
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:579
#: ../js/ui/panel.js:585
msgid "%a %b %e, %R:%S"
msgstr "%a, %e. %b, %R:%S"
#: ../js/ui/panel.js:580
#: ../js/ui/panel.js:586
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:584
#: ../js/ui/panel.js:590
msgid "%a %R:%S"
msgstr "%a %R:%S"
#: ../js/ui/panel.js:585
#: ../js/ui/panel.js:591
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:592
#: ../js/ui/panel.js:598
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a, %e. %b, %H:%M:%S"
#: ../js/ui/panel.js:593
#: ../js/ui/panel.js:599
msgid "%a %b %e, %l:%M %p"
msgstr "%a, %e. %b, %H:%M"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:597
#: ../js/ui/panel.js:603
msgid "%a %l:%M:%S %p"
msgstr "%a %H:%M:%S"
#: ../js/ui/panel.js:598
#: ../js/ui/panel.js:604
msgid "%a %l:%M %p"
msgstr "%a %H:%M"
#. 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:743
#: ../js/ui/panel.js:749
msgid "Activities"
msgstr "Aktivitäten"
@ -582,6 +566,10 @@ msgstr "Erneut versuchen"
msgid "Connect to..."
msgstr "Verbinden mit …"
#: ../js/ui/placeDisplay.js:558
msgid "PLACES & DEVICES"
msgstr "ORTE UND GERÄTE"
#. Translators: this MUST be either "toggle-switch-us"
#. (for toggle switches containing the English words
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
@ -600,42 +588,332 @@ msgstr "Bitte geben Sie einen Befehl ein:"
msgid "Execution of '%s' failed:"
msgstr "Ausführung von »%s« ist gescheitert:"
#: ../js/ui/statusMenu.js:91
#: ../js/ui/statusMenu.js:101
msgid "Available"
msgstr "Verfügbar"
#: ../js/ui/statusMenu.js:95
#: ../js/ui/statusMenu.js:106
msgid "Busy"
msgstr "Beschäftigt"
#: ../js/ui/statusMenu.js:99
msgid "Invisible"
msgstr "Unsichtbar"
#: ../js/ui/statusMenu.js:114
msgid "My Account"
msgstr "Eigenes Konto"
#: ../js/ui/statusMenu.js:106
msgid "Account Information..."
msgstr "Benutzerinformationen …"
#: ../js/ui/statusMenu.js:118
msgid "System Settings"
msgstr "Systemeinstellungen"
#: ../js/ui/statusMenu.js:110
msgid "System Settings..."
msgstr "Systemeinstellungen …"
#: ../js/ui/statusMenu.js:117
#: ../js/ui/statusMenu.js:125
msgid "Lock Screen"
msgstr "Bildschirm sperren"
#: ../js/ui/statusMenu.js:121
#: ../js/ui/statusMenu.js:129
msgid "Switch User"
msgstr "Benutzer wechseln"
#: ../js/ui/statusMenu.js:126
#: ../js/ui/statusMenu.js:134
msgid "Log Out..."
msgstr "Abmelden …"
#: ../js/ui/statusMenu.js:130
#: ../js/ui/statusMenu.js:141
msgid "Suspend..."
msgstr "Bereitschaft …"
#: ../js/ui/statusMenu.js:145
msgid "Shut Down..."
msgstr "Ausschalten …"
#: ../js/ui/status/accessibility.js:82
msgid "Zoom"
msgstr "Vergrößern"
#: ../js/ui/status/accessibility.js:88
msgid "Screen Reader"
msgstr "Bildschirmleser"
#: ../js/ui/status/accessibility.js:91
msgid "Screen Keyboard"
msgstr "Bildschirmtastatur"
#: ../js/ui/status/accessibility.js:94
msgid "Visual Alerts"
msgstr "Visuelle Warnungen"
#: ../js/ui/status/accessibility.js:97
msgid "Sticky Keys"
msgstr "Klebrige Tasten"
#: ../js/ui/status/accessibility.js:100
msgid "Slow Keys"
msgstr "Tastenverzögerung"
#: ../js/ui/status/accessibility.js:103
msgid "Bounce Keys"
msgstr "Springende Tasten"
#: ../js/ui/status/accessibility.js:106
msgid "Mouse Keys"
msgstr "Maustasten"
#: ../js/ui/status/accessibility.js:110
msgid "Universal Access Settings"
msgstr "Einstellungen zur Barrierefreiheit"
#: ../js/ui/status/accessibility.js:163
msgid "High Contrast"
msgstr "Hoher Kontrast"
#: ../js/ui/status/accessibility.js:205
msgid "Large Text"
msgstr "Große Schrift"
#: ../js/ui/status/bluetooth.js:42 ../js/ui/status/bluetooth.js:234
msgid "Bluetooth"
msgstr "Bluetooth"
#: ../js/ui/status/bluetooth.js:55
msgid "Visibility"
msgstr "Sichtbarkeit"
#: ../js/ui/status/bluetooth.js:69
msgid "Send Files to Device..."
msgstr "Dateien an Gerät senden …"
#: ../js/ui/status/bluetooth.js:70
msgid "Setup a New Device..."
msgstr "Ein neues Gerät einrichten …"
#: ../js/ui/status/bluetooth.js:94
msgid "Bluetooth Settings"
msgstr "Bluetooth-Einstellungen"
#: ../js/ui/status/bluetooth.js:185
msgid "Connection"
msgstr "Verbindung"
#: ../js/ui/status/bluetooth.js:221
msgid "Send Files..."
msgstr "Dateien senden …"
#: ../js/ui/status/bluetooth.js:226
msgid "Browse Files..."
msgstr "Dateien durchsuchen …"
#: ../js/ui/status/bluetooth.js:235
msgid "Error browsing device"
msgstr "Fehler beim Durchsuchen des Geräts"
#: ../js/ui/status/bluetooth.js:236
#, c-format
msgid "The requested device cannot be browsed, error is '%s'"
msgstr ""
"Das angesprochene Gerät kann nicht durchsucht werden. Der Fehler lautet »%s«"
#: ../js/ui/status/bluetooth.js:244
msgid "Keyboard Settings"
msgstr "Tastatureinstellungen"
#: ../js/ui/status/bluetooth.js:249
msgid "Mouse Settings"
msgstr "Maus-Einstellungen"
#: ../js/ui/status/bluetooth.js:256 ../js/ui/status/volume.js:62
msgid "Sound Settings"
msgstr "Klangeinstellungen"
#: ../js/ui/status/bluetooth.js:327 ../js/ui/status/bluetooth.js:361
#: ../js/ui/status/bluetooth.js:401 ../js/ui/status/bluetooth.js:434
msgid "Bluetooth Agent"
msgstr "Bluetooth-Agent"
#: ../js/ui/status/bluetooth.js:362
#, c-format
msgid "Authorization request from %s"
msgstr "Legitimierungsanfrage von %s"
#: ../js/ui/status/bluetooth.js:368
#, c-format
msgid "Device %s wants access to the service '%s'"
msgstr "Gerät »%s« bittet um Zugriff auf den Dienst »%s«"
#: ../js/ui/status/bluetooth.js:370
msgid "Always grant access"
msgstr "Immer Zugriff gewähren"
#: ../js/ui/status/bluetooth.js:371
msgid "Grant this time only"
msgstr "Nur dieses Mal gewähren"
#: ../js/ui/status/bluetooth.js:372
msgid "Reject"
msgstr "Abweisen"
#: ../js/ui/status/bluetooth.js:402
#, c-format
msgid "Pairing confirmation for %s"
msgstr "Koppelungsbestätigung für %s"
#: ../js/ui/status/bluetooth.js:408 ../js/ui/status/bluetooth.js:442
#, c-format
msgid "Device %s wants to pair with this computer"
msgstr "Gerät »%s« möchte mit diesem Rechner gekoppelt werden"
#: ../js/ui/status/bluetooth.js:409
#, c-format
msgid "Please confirm whether the PIN '%s' matches the one on the device."
msgstr ""
"Bitte bestätigen Sie, ob die PIN »%s« mit der des Gerätes übereinstimmt."
#: ../js/ui/status/bluetooth.js:411
msgid "Matches"
msgstr "Stimmt überein"
#: ../js/ui/status/bluetooth.js:412
msgid "Does not match"
msgstr "Stimmt nicht überein"
#: ../js/ui/status/bluetooth.js:435
#, c-format
msgid "Pairing request for %s"
msgstr "Koppelungsanfrage für %s"
#: ../js/ui/status/bluetooth.js:443
msgid "Please enter the PIN mentioned on the device."
msgstr "Bitte geben Sie die auf dem Gerät angezeigte PIN ein."
#: ../js/ui/status/bluetooth.js:459
msgid "OK"
msgstr "OK"
#: ../js/ui/status/bluetooth.js:460
msgid "Cancel"
msgstr "Abbrechen"
#: ../js/ui/status/power.js:85
msgid "Power Settings"
msgstr "Energieeinstellungen"
#: ../js/ui/status/power.js:112
#, c-format
msgid "%d hour remaining"
msgid_plural "%d hours remaining"
msgstr[0] "%d Stunde verbleibend"
msgstr[1] "%d Stunden verbleibend"
#. TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining"
#: ../js/ui/status/power.js:115
#, c-format
msgid "%d %s %d %s remaining"
msgstr "%d %s %d %s verbleibend"
#: ../js/ui/status/power.js:117
msgid "hour"
msgid_plural "hours"
msgstr[0] "Stunde"
msgstr[1] "Stunden"
#: ../js/ui/status/power.js:117
msgid "minute"
msgid_plural "minutes"
msgstr[0] "Minute"
msgstr[1] "Minuten"
#: ../js/ui/status/power.js:120
#, c-format
msgid "%d minute remaining"
msgid_plural "%d minutes remaining"
msgstr[0] "%d Minute verbleibend"
msgstr[1] "%d Minuten verbleibend"
#: ../js/ui/status/power.js:237
msgid "AC adapter"
msgstr "Netzteil"
#: ../js/ui/status/power.js:239
msgid "Laptop battery"
msgstr "Laptop-Akku"
#: ../js/ui/status/power.js:241
msgid "UPS"
msgstr "Notstromversorgung"
#: ../js/ui/status/power.js:243
msgid "Monitor"
msgstr "Bildschirm"
#: ../js/ui/status/power.js:245
msgid "Mouse"
msgstr "Maus"
#: ../js/ui/status/power.js:247
msgid "Keyboard"
msgstr "Tastatur"
#: ../js/ui/status/power.js:249
msgid "PDA"
msgstr "PDA"
#: ../js/ui/status/power.js:251
msgid "Cell phone"
msgstr "Mobiltelefon"
#: ../js/ui/status/power.js:253
msgid "Media player"
msgstr "Medienwiedergabegerät"
#: ../js/ui/status/power.js:255
msgid "Tablet"
msgstr "Tablet"
#: ../js/ui/status/power.js:257
msgid "Computer"
msgstr "Rechner"
#: ../js/ui/status/power.js:259 ../src/shell-app-system.c:1012
msgid "Unknown"
msgstr "Unbekannt"
#: ../js/ui/status/volume.js:41
msgid "Volume"
msgstr "Lautstärke"
#: ../js/ui/status/volume.js:54
msgid "Microphone"
msgstr "Mikrofon"
#: ../js/ui/telepathyClient.js:560
#, c-format
msgid "%s is online."
msgstr "%s ist angemeldet."
#: ../js/ui/telepathyClient.js:565
#, c-format
msgid "%s is offline."
msgstr "%s ist abgemeldet."
#: ../js/ui/telepathyClient.js:568
#, c-format
msgid "%s is away."
msgstr "»%s« ist abwesend."
#: ../js/ui/telepathyClient.js:571
#, c-format
msgid "%s is busy."
msgstr "%s ist beschäftigt."
#. Translators: this is a time format string followed by a date.
#. If applicable, replace %X with a strftime format valid for your
#. locale, without seconds.
#: ../js/ui/telepathyClient.js:665
#, no-c-format
msgid "Sent at %X on %A"
msgstr "Gesendet am %A um %X "
#: ../js/ui/viewSelector.js:26
msgid "Search your computer"
msgstr "Ihren Rechner durchsuchen"
#: ../js/ui/windowAttentionHandler.js:43
#, c-format
msgid "%s has finished starting"
@ -646,60 +924,82 @@ msgstr "Start von %s ist abgeschlossen"
msgid "'%s' is ready"
msgstr "»%s« ist bereit"
#: ../js/ui/workspacesView.js:230
#: ../js/ui/workspacesView.js:244
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
msgstr ""
"Es kann keine weitere Arbeitsfläche hinzugefügt werden, weil das Maximum an "
"Arbeitsflächen erreicht worden ist."
#: ../js/ui/workspacesView.js:247
#: ../js/ui/workspacesView.js:260
msgid "Can't remove the first workspace."
msgstr "Die erste Arbeitsfläche kann nicht entfernt werden."
#: ../src/shell-global.c:1196
#. translators:
#. * The number of sound outputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1094
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] "%u Ausgang"
msgstr[1] "%u Ausgänge"
#. translators:
#. * The number of sound inputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1104
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] "%u Eingang"
msgstr[1] "%u Eingänge"
#: ../src/gvc/gvc-mixer-control.c:1402
msgid "System Sounds"
msgstr "Systemklänge"
#: ../src/shell-global.c:1156
msgid "Less than a minute ago"
msgstr "Vor weniger als einer Minute"
#: ../src/shell-global.c:1200
#: ../src/shell-global.c:1160
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "Vor %d Minute"
msgstr[1] "Vor %d Minuten"
#: ../src/shell-global.c:1205
#: ../src/shell-global.c:1165
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "Vor %d Stunde"
msgstr[1] "Vor %d Stunden"
#: ../src/shell-global.c:1210
#: ../src/shell-global.c:1170
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "Vor %d Tag"
msgstr[1] "Vor %d Tagen"
#: ../src/shell-global.c:1215
#: ../src/shell-global.c:1175
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "Vor %d Woche"
msgstr[1] "Vor %d Wochen"
#: ../src/shell-uri-util.c:89
#: ../src/shell-util.c:89
msgid "Home Folder"
msgstr "Persönlicher Ordner"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:104
#: ../src/shell-util.c:104
msgid "File System"
msgstr "Dateisystem"
#: ../src/shell-uri-util.c:250
#: ../src/shell-util.c:250
msgid "Search"
msgstr "Suchen"
@ -708,11 +1008,42 @@ msgstr "Suchen"
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:300
#: ../src/shell-util.c:300
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "What's using power..."
#~ msgstr "Energieverbraucher …"
#~ msgid "Overview workspace view mode"
#~ msgstr "Modus des Arbeitsflächen-Überblicks"
#~ msgid ""
#~ "The selected workspace view mode in the overview. Supported values are "
#~ "\"single\" and \"grid\"."
#~ msgstr ""
#~ "Die gewählte Ansicht des Arbeitsflächen-Überblicks. Mögliche Werte sind "
#~ "»single« (einfach) und »grid« (Raster)."
#~ msgid "Drag here to add favorites"
#~ msgstr "Hier ablegen, um zu Favoriten hinzuzufügen"
#~ msgid "Find"
#~ msgstr "Suchen"
#~ msgid "Searching..."
#~ msgstr "Suche läuft …"
#~ msgid "No matching results."
#~ msgstr "Keine passenden Ergebnisse."
#~ msgid "Invisible"
#~ msgstr "Unsichtbar"
#~ msgid "Account Information..."
#~ msgstr "Benutzerinformationen …"
#~ msgid "ON"
#~ msgstr "EIN"
@ -725,9 +1056,6 @@ msgstr "%1$s: %2$s"
#~ msgid "%H:%M"
#~ msgstr "%H:%M"
#~ msgid "Applications"
#~ msgstr "Anwendungen"
#~ msgid "Recent Documents"
#~ msgstr "Zuletzt geöffnete Dokumente"
@ -746,9 +1074,6 @@ msgstr "%1$s: %2$s"
#~ msgid "SEARCH RESULTS"
#~ msgstr "SUCHERGEBNISSE"
#~ msgid "Unknown"
#~ msgstr "Unbekannt"
#~ msgid "Can't lock screen: %s"
#~ msgstr "Bildschirm kann nicht gesperrt werden: %s"

915
po/el.po

File diff suppressed because it is too large Load Diff

808
po/es.po

File diff suppressed because it is too large Load Diff

520
po/et.po
View File

@ -1,15 +1,20 @@
# GNOME kesta eesti keele tõlge.
# Estonian translation for gnome-shell.
# Copyright (C) 2010 The Gnome Project
#
# Copyright (C) 2010, 2011 The Gnome Project
#
# This file is distributed under the same license as the gnome-shell package.
# Mattias Põldaru <mahfiaz gmail com>, 2010.
#
# Mattias Põldaru <mahfiaz gmail com>, 2010, 2011.
# Ivar Smolin <okul linux ee>, 2011.
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"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: 2010-10-16 19:24+0000\n"
"PO-Revision-Date: 2010-10-17 17:16+0300\n"
"POT-Creation-Date: 2011-01-29 18:34+0000\n"
"PO-Revision-Date: 2011-02-01 13:51+0300\n"
"Last-Translator: Mattias Põldaru <mahfiaz gmail com>\n"
"Language-Team: Estonian <gnome-et@linux.ee>\n"
"Language: et\n"
@ -26,12 +31,6 @@ msgstr "GNOME kest"
msgid "Window management and application launching"
msgstr "Aknahaldur ja rakenduste käivitaja"
msgid "Clock"
msgstr "Kell"
msgid "Customize the panel clock"
msgstr "Paneelikella kohandamine"
msgid ""
"Allows access to internal debugging and monitoring tools using the Alt-F2 "
"dialog."
@ -39,15 +38,12 @@ msgstr ""
"Lubab ligipääsu sisemistele silumise ja monitoorimise tööriistadele Alt-F2 "
"dialoogi kaudu."
msgid "Custom format of the clock"
msgstr "Kellaaaja kohandatud vorming"
msgid "Enable internal tools useful for developers and testers from Alt-F2"
msgstr ""
"Arendajate ja testijate jaoks sisemiste tööriistade lubamine Alt-F2 alt"
msgid "File extension used for storing the screencast"
msgstr "Faililaiend, mida kasutatakse ekraanivideo salvestamisel"
msgstr "Ekraanivideo salvestamisel kasutatav faililaiend"
msgid "Framerate used for recording screencasts."
msgstr "Ekraanivideo lindistamisel kasutatav kaadrikiirus."
@ -56,36 +52,25 @@ msgid ""
"GNOME Shell extensions have a uuid property; this key lists extensions which "
"should not be loaded."
msgstr ""
"GNOME Shelli laiendustel on omadus UUID. Selle võtmega määratakse "
"laiendused, mida ei peaks laaditama."
msgid "History for command (Alt-F2) dialog"
msgstr "Käsudialoogi (Alt-F2) ajalugu"
msgid "Hour format"
msgstr "Tundide vorming"
msgid "If true, display date in the clock, in addition to time."
msgstr "Kui määratud, siis kuvatakse kellaaja kõrval ka kuupäeva."
msgid ""
"If true and format is either \"12-hour\" or \"24-hour\", display date in the "
"clock, in addition to time."
msgstr ""
"Kui tõene ja vorming on kas \"12-tundi\" või \"24-tundi\", kuvatakse "
"kellaaja kõrval ka kuupäeva."
msgid ""
"If true and format is either \"12-hour\" or \"24-hour\", display seconds in "
"time."
msgstr ""
"Kui tõene ja vorming on kas \"12-tundi\" või \"24-tundi\", kuvatakse "
"kellaaega koos sekunditega."
msgid "If true, display seconds in time."
msgstr "Kui määratud, siis kuvatakse aja juures ka sekundeid."
msgid "If true, display the ISO week date in the calendar."
msgstr "Kui tõene, kuvatakse kalendris kuupäeva ISO nädalate järgi."
msgstr "Kui määratud, kuvatakse kalendris kuupäeva ISO nädalavormingus."
msgid "List of desktop file IDs for favorite applications"
msgstr "Lemmikrakenduste töölauafailide ID-de loend"
msgid "Overview workspace view mode"
msgstr ""
#, no-c-format
msgid ""
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
"used for gst-launch. The pipeline should have an unconnected sink pad where "
@ -94,14 +79,16 @@ msgid ""
"pipeline can also take care of its own output - this might be used to send "
"the output to an icecast server via shout2send or similar. When unset or set "
"to an empty value, the default pipeline will be used. This is currently "
"'videorate ! theoraenc ! oggmux' and records to Ogg Theora."
"'videorate ! vp8enc quality=10 speed=2 threads=%T ! queue ! webmmux' and "
"records to WEBM using the VP8 codec. %T is used as a placeholder for a guess "
"at the optimal thread count on the system."
msgstr ""
msgid "Show date in clock"
msgstr "Kell näitab kuupäeva"
msgid "Show the week date in the calendar"
msgstr "Kalendris näidatakse nädala kuupäeva"
msgstr "Kalendris näidatakse kuupäeva nädalavormingus"
msgid "Show time with seconds"
msgstr "Kellaaega näidatakse sekunditega"
@ -116,6 +103,10 @@ msgid ""
"current date, and use this extension. It should be changed when recording to "
"a different container format."
msgstr ""
"Ekraanivideo jaoks kasutatav failinimi on unikaalne, see sisaldab "
"salvestamise kuupäeva ja ka käesoleva võtmega määratud laiendit. Mõnda teise "
"konteinervormingusse salvestades tuleks ka sellele vormingule vastav laiend "
"määrata."
msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
@ -125,11 +116,6 @@ msgstr ""
msgid "The gstreamer pipeline used to encode the screencast"
msgstr ""
msgid ""
"The selected workspace view mode in the overview. Supported values are "
"\"single\" and \"grid\"."
msgstr ""
msgid ""
"The shell normally monitors active applications in order to present the most "
"used ones (e.g. in launchers). While this data will be kept private, you may "
@ -137,28 +123,15 @@ msgid ""
"remove already saved data."
msgstr ""
msgid ""
"This key specifies the format used by the panel clock when the format key is "
"set to \"custom\". You can use conversion specifiers understood by strftime"
"() to obtain a specific format. See the strftime() manual for more "
"information."
msgstr ""
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."
msgstr ""
msgid "Uuids of extensions to disable"
msgstr "Keelatavate laienduste UUID-d"
msgid "Whether to collect stats about applications usage"
msgstr ""
msgid "disabled OpenSearch providers"
msgstr ""
msgid "Clip the crosshairs at the center"
msgstr "Niitristi keskel on auk"
@ -269,28 +242,25 @@ msgstr ""
msgid "Width of the vertical and horizontal lines that make up the crosshairs."
msgstr "Niitristi moodustavate püst- ja rõhtjoone laius"
msgid "Clock Format"
msgstr "Kella formaat"
msgid "Command not found"
msgstr ""
msgid "Clock Preferences"
msgstr "Kella eelistused"
#. Replace "Error invoking GLib.shell_parse_argv: " with
#. something nicer
msgid "Could not parse command:"
msgstr "Käsku pole võimalik analüüsida:"
msgid "Panel Display"
msgstr "Paneelikuva"
msgid "No such application"
msgstr "Sellist rakendust ei ole"
msgid "Show seco_nds"
msgstr "_Sekundeid näidatakse"
#, c-format
msgid "Execution of '%s' failed:"
msgstr "'%s' käivitamine nurjus:"
msgid "Show the _date"
msgstr "_Kuupäeva näidatakse"
#. Translators: Filter to display all applications
msgid "All"
msgstr "Kõik"
msgid "_12 hour format"
msgstr "_12 tunni vorming"
msgid "_24 hour format"
msgstr "_24 tunni vorming"
#. **** Applications ****
msgid "APPLICATIONS"
msgstr "Rakendused"
@ -306,9 +276,6 @@ msgstr "Eemalda lemmikutest"
msgid "Add to Favorites"
msgstr "Lisa lemmikutesse"
msgid "Drag here to add favorites"
msgstr "Lemmikute lisamiseks lohista need siia"
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s lisati lemmikutesse."
@ -317,31 +284,75 @@ msgstr "%s lisati lemmikutesse."
msgid "%s has been removed from your favorites."
msgstr "%s eemaldati lemmikutest."
msgid "Find"
msgstr "Otsi"
msgid "Remove"
msgstr "Eemalda"
msgid "Searching..."
msgstr "Otsimine..."
msgid "No matching results."
msgstr "Tulemused puuduvad."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
msgid "PLACES & DEVICES"
msgstr "Asukohad ja seadmed"
#. **** Documents ****
msgid "RECENT ITEMS"
msgstr "Hiljutised dokumendid"
#, c-format
msgid "Log Out %s"
msgstr "Logi %s välja"
msgid "Log Out"
msgstr "Logi välja"
msgid "Click Log Out to quit these applications and log out of the system."
msgstr ""
#, c-format
msgid "%s will be logged out automatically in %d seconds."
msgstr "%s logitakse %d sekundi pärast automaatselt välja."
#, c-format
msgid "You will be logged out automatically in %d seconds."
msgstr "Sind logitakse %d sekundi pärast automaatselt välja."
msgid "Logging out of the system."
msgstr "Süsteemist väljalogimine"
msgid "Shut Down"
msgstr "Lülita välja"
msgid "Click Shut Down to quit these applications and shut down the system."
msgstr ""
#, c-format
msgid "The system will shut down automatically in %d seconds."
msgstr "%d sekundi pärast lülitub süsteem automaatselt välja."
msgid "Shutting down the system."
msgstr "Süsteemi väljalülitamine."
msgid "Restart"
msgstr "Taaskäivita"
msgid "Click Restart to quit these applications and restart the system."
msgstr ""
"Nende rakenduste sulgemiseks ja süsteemi taaskäivitamiseks klõpsa "
"\"Taaskäivita\"."
#, c-format
msgid "The system will restart automatically in %d seconds."
msgstr "Süsteem taaskäivitatakse automaatselt %d sekundi pärast."
msgid "Restarting the system."
msgstr "Süsteemi taaskäivitamine."
msgid "Confirm"
msgstr "Kinnita"
msgid "Cancel"
msgstr "Katkesta"
msgid "No extensions installed"
msgstr "Ühtegi laiendust pole paigaldatud"
msgid "Enabled"
msgstr "Lubatud"
#. translators:
#. * The device has been disabled
msgid "Disabled"
msgstr "Keelatud"
@ -357,17 +368,23 @@ msgstr "Kuva lähtekoodi"
msgid "Web Page"
msgstr "Veebileht"
msgid "System Information"
msgstr "Süsteemi andmed"
msgid "Undo"
msgstr "Võta tagasi"
msgid "Windows"
msgstr "Aknad"
msgid "Applications"
msgstr "Rakendused"
#. TODO - _quit() doesn't really work on apps in state STARTING yet
#, c-format
msgid "Quit %s"
msgstr "Lõpeta %s"
msgid "Preferences"
msgstr "Eelistused"
#. Translators: This is the time format with date used
#. in 24-hour mode.
msgid "%a %b %e, %R:%S"
@ -415,6 +432,9 @@ msgstr "Proovi uuesti"
msgid "Connect to..."
msgstr "Ühendumine..."
msgid "PLACES & DEVICES"
msgstr "Asukohad ja seadmed"
#. Translators: this MUST be either "toggle-switch-us"
#. (for toggle switches containing the English words
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
@ -426,24 +446,17 @@ msgstr "toggle-switch-intl"
msgid "Please enter a command:"
msgstr "Palun sisesta käsk:"
#, c-format
msgid "Execution of '%s' failed:"
msgstr "'%s' käivitamine nurjus:"
msgid "Available"
msgstr "Saadaval"
msgid "Busy"
msgstr "Hõivatud"
msgid "Invisible"
msgstr "Nähtamatu"
msgid "My Account"
msgstr "Minu konto"
msgid "Account Information..."
msgstr "Konto andmed..."
msgid "System Settings..."
msgstr "Süsteemi sätted..."
msgid "System Settings"
msgstr "Süsteemi sätted"
msgid "Lock Screen"
msgstr "Lukusta ekraan"
@ -454,9 +467,234 @@ msgstr "Vaheta kasutajat"
msgid "Log Out..."
msgstr "Logi välja..."
msgid "Suspend..."
msgstr "Peata..."
msgid "Shut Down..."
msgstr "Lülita välja..."
msgid "Zoom"
msgstr ""
msgid "Screen Reader"
msgstr "Ekraanilugeja"
msgid "Screen Keyboard"
msgstr "Ekraaniklaviatuur"
msgid "Visual Alerts"
msgstr "Visuaalsed märguanded"
msgid "Sticky Keys"
msgstr "Kleepuvad klahvid"
msgid "Slow Keys"
msgstr "Aeglased klahvid"
msgid "Bounce Keys"
msgstr "Põrkeklahvid"
msgid "Mouse Keys"
msgstr "Hiireklahvid"
msgid "Universal Access Settings"
msgstr "Universaalse ligipääsu sätted"
msgid "High Contrast"
msgstr ""
msgid "Large Text"
msgstr ""
msgid "Bluetooth"
msgstr "Bluetooth"
msgid "Visibility"
msgstr "Nähtavus"
msgid "Send Files to Device..."
msgstr "Failide saatmine seadmesse..."
msgid "Setup a New Device..."
msgstr ""
msgid "Bluetooth Settings"
msgstr "Bluetoothi sätted"
msgid "Connection"
msgstr "Ühendus"
msgid "Send Files..."
msgstr "Failide saatmine..."
msgid "Browse Files..."
msgstr "Failide sirvimine..."
msgid "Error browsing device"
msgstr "Viga seadme sirvimisel"
#, c-format
msgid "The requested device cannot be browsed, error is '%s'"
msgstr ""
msgid "Keyboard Settings"
msgstr "Klaviatuurisätted"
msgid "Mouse Settings"
msgstr "Hiiresätted"
msgid "Sound Settings"
msgstr "Helisätted"
msgid "Bluetooth Agent"
msgstr "Bluetoothi agent"
#, c-format
msgid "Authorization request from %s"
msgstr "Autoriseerimise päring seadmelt %s"
#, c-format
msgid "Device %s wants access to the service '%s'"
msgstr "Seade %s soovib ligipääsu teenusele '%s'"
msgid "Always grant access"
msgstr "Luba alati"
msgid "Grant this time only"
msgstr "Luba ainult seekord"
msgid "Reject"
msgstr "Lükka tagasi"
#, c-format
msgid "Pairing confirmation for %s"
msgstr "Paardumise kinnitus seadmele %s"
#, c-format
msgid "Device %s wants to pair with this computer"
msgstr "Seade '%s' tahab selle arvutiga paarduda"
#, c-format
msgid "Please confirm whether the PIN '%s' matches the one on the device."
msgstr "Palun kontrolli, et PIN-kood '%s' kattuks seadme parooliga."
msgid "Matches"
msgstr "Kattub"
msgid "Does not match"
msgstr "Ei kattu"
#, c-format
msgid "Pairing request for %s"
msgstr "Seadmega %s paardumise päring"
msgid "Please enter the PIN mentioned on the device."
msgstr "Palun sisesta seadme poolt öeldav PIN-kood."
msgid "OK"
msgstr "Olgu"
msgid "Localization Settings"
msgstr "Lokaliseerimissätted"
msgid "Power Settings"
msgstr "Toitesätted..."
#, c-format
msgid "%d hour remaining"
msgid_plural "%d hours remaining"
msgstr[0] "jäänud %d tund"
msgstr[1] "jäänud %d tundi"
#. TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining"
#, c-format
msgid "%d %s %d %s remaining"
msgstr "jäänud %d %s ja %d %s"
msgid "hour"
msgid_plural "hours"
msgstr[0] "tund"
msgstr[1] "tundi"
msgid "minute"
msgid_plural "minutes"
msgstr[0] "minut"
msgstr[1] "minutit"
#, c-format
msgid "%d minute remaining"
msgid_plural "%d minutes remaining"
msgstr[0] "jäänud %d minut"
msgstr[1] "jäänud %d minutit"
msgid "AC adapter"
msgstr "Võrgutoite adapter"
msgid "Laptop battery"
msgstr "Sülearvuti aku"
msgid "UPS"
msgstr "UPS"
msgid "Monitor"
msgstr "Monitor"
msgid "Mouse"
msgstr "Hiir"
msgid "Keyboard"
msgstr "Klaviatuur"
msgid "PDA"
msgstr "Elektronmärkmik"
msgid "Cell phone"
msgstr "Mobiiltelefon"
msgid "Media player"
msgstr "Meediaesitaja"
msgid "Tablet"
msgstr "Graafikalaud"
msgid "Computer"
msgstr "Arvuti"
msgid "Unknown"
msgstr "Tundmatu"
msgid "Volume"
msgstr "Helivaljus"
msgid "Microphone"
msgstr "Mikrofon"
#, c-format
msgid "%s is online."
msgstr "%s on ühendatud."
#, c-format
msgid "%s is offline."
msgstr "%s on ühendamata."
#, c-format
msgid "%s is away."
msgstr "%s on eemal."
#, c-format
msgid "%s is busy."
msgstr "%s on hõivatud."
#. Translators: this is a time format string followed by a date.
#. If applicable, replace %X with a strftime format valid for your
#. locale, without seconds.
#, no-c-format
msgid "Sent at %X on %A"
msgstr "Saadetud: %a, kell %X"
msgid "Search your computer"
msgstr ""
#, c-format
msgid "%s has finished starting"
msgstr "%s läks käima"
@ -472,6 +710,25 @@ msgstr "Pole võimalik uut tööala lisada, kuna tööalade piir on saavutatud."
msgid "Can't remove the first workspace."
msgstr "Esimest tööala pole võimalik eemaldada."
#. translators:
#. * The number of sound outputs on a particular device
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] ""
msgstr[1] ""
#. translators:
#. * The number of sound inputs on a particular device
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] ""
msgstr[1] ""
msgid "System Sounds"
msgstr "Süsteemi helid"
msgid "Less than a minute ago"
msgstr "Vähem kui minuti eest"
@ -518,3 +775,54 @@ msgstr "Otsing"
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Clock"
#~ msgstr "Kell"
#~ msgid "Customize the panel clock"
#~ msgstr "Paneelikella kohandamine"
#~ msgid "Custom format of the clock"
#~ msgstr "Kellaaaja kohandatud vorming"
#~ msgid "Hour format"
#~ msgstr "Tundide vorming"
#~ msgid "Clock Format"
#~ msgstr "Kellaaja vorming"
#~ msgid "Clock Preferences"
#~ msgstr "Kella eelistused"
#~ msgid "Panel Display"
#~ msgstr "Paneelikuva"
#~ msgid "Show seco_nds"
#~ msgstr "_Sekundeid näidatakse"
#~ msgid "Show the _date"
#~ msgstr "_Kuupäeva näidatakse"
#~ msgid "_12 hour format"
#~ msgstr "_12 tunni vorming"
#~ msgid "_24 hour format"
#~ msgstr "_24 tunni vorming"
#~ msgid "Preferences"
#~ msgstr "Eelistused"
#~ msgid "Drag here to add favorites"
#~ msgstr "Lemmikute lisamiseks lohista need siia"
#~ msgid "Find"
#~ msgstr "Otsi"
#~ msgid "Searching..."
#~ msgstr "Otsimine..."
#~ msgid "No matching results."
#~ msgstr "Tulemused puuduvad."
#~ msgid "Invisible"
#~ msgstr "Nähtamatu"

730
po/fa.po Normal file
View File

@ -0,0 +1,730 @@
# Persian translation for gnome-shell.
# Copyright (C) 2010 Iranian Free Software Users Group (IFSUG.org)translation team.
# This file is distributed under the same license as the gnome-shell package.
# Arash Mousavi <mousavi.arash@gmail.com>, 2010.
# Mahyar Moghimi <mahyar.moqimi@gmail.com>, 2010.
#
msgid ""
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: 2010-12-01 18:12+0000\n"
"PO-Revision-Date: 2010-12-03 13:24+0330\n"
"Last-Translator: Mahyar Moghimi <mahyar.moqimi@gmail.com>\n"
"Language-Team: Persian <translate@ifsug.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-Poedit-Language: Persian\n"
"X-Poedit-Country: IRAN\n"
"X-Poedit-SourceCharset: utf-8\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "پوسته‌ی گنوم"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "مدیریت پنجره‌ها و اجرا کننده‌ی برنامه‌ها"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:1
msgid "Clock"
msgstr "ساعت"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:2
msgid "Customize the panel clock"
msgstr "سفارشی‌سازی ساعت تابلو"
#: ../data/org.gnome.shell.gschema.xml.in.h:1
msgid "Allows access to internal debugging and monitoring tools using the Alt-F2 dialog."
msgstr "اجازه دسترسی به ابزارهای اشکال‌زدا و پایشگر داخلی با استفاده از محاوره‌ی Alt-F2."
#: ../data/org.gnome.shell.gschema.xml.in.h:2
msgid "Custom format of the clock"
msgstr "قالب سفارشی برای ساعت"
#: ../data/org.gnome.shell.gschema.xml.in.h:3
msgid "Enable internal tools useful for developers and testers from Alt-F2"
msgstr "فعال کردن ابزارهای داخلی مفید برای توسعه دهندگان و آزمایش کنندگان از طریق Alt-F2"
#: ../data/org.gnome.shell.gschema.xml.in.h:4
msgid "File extension used for storing the screencast"
msgstr "پسوند پرونده‌ی قابل استفاده برای ذخیره تصویربرداری از صفحه‌نمایش"
#: ../data/org.gnome.shell.gschema.xml.in.h:5
msgid "Framerate used for recording screencasts."
msgstr "سرعت فریم استفاده شده در تصویربرداری از صفحه‌نمایش."
#: ../data/org.gnome.shell.gschema.xml.in.h:6
msgid "GNOME Shell extensions have a uuid property; this key lists extensions which should not be loaded."
msgstr "افزونه‌های پوسته‌ی گنوم مشخصه‌ی uuid دارند؛ این کلید افزونه‌هایی که نباید بار شوند را فهرست می‌کند."
#: ../data/org.gnome.shell.gschema.xml.in.h:7
msgid "History for command (Alt-F2) dialog"
msgstr "تاریخچه‌ی فرمان برای محاوره‌ی (Alt-F2)"
#: ../data/org.gnome.shell.gschema.xml.in.h:8
msgid "Hour format"
msgstr "قالب ساعت"
#: ../data/org.gnome.shell.gschema.xml.in.h:9
msgid "If true and format is either \"12-hour\" or \"24-hour\", display date in the clock, in addition to time."
msgstr "اگر روی «درست» تنظیم شود و قالب ساعت هر یک از حالت‌های «۱۲ ساعته» و یا «۲۴ ساعته» باشد، تاریخ را در کنار ساعت نشان می‌دهد."
#: ../data/org.gnome.shell.gschema.xml.in.h:10
msgid "If true and format is either \"12-hour\" or \"24-hour\", display seconds in time."
msgstr "اگر بر روی «درست» تنظیم شود و قالب ساعت هر یک از جالت‌های «۱۲ ساعته» و یا «۲۴ ساعته» باشد، ثانیه را در کنار ساعت نشان می‌دهد."
#: ../data/org.gnome.shell.gschema.xml.in.h:11
msgid "If true, display the ISO week date in the calendar."
msgstr "در صورت تنظیم بر روی «درست»، تاریخ هفتگی ایزو را در تقویم نشان می‌دهد."
#: ../data/org.gnome.shell.gschema.xml.in.h:12
msgid "List of desktop file IDs for favorite applications"
msgstr "فهرست شناسه‌های پرونده‌ی رومیزی برای برنامه‌های مورد پسند"
#: ../data/org.gnome.shell.gschema.xml.in.h:13
msgid "Sets the GStreamer pipeline used to encode recordings. It follows the syntax used for gst-launch. The pipeline should have an unconnected sink pad where the recorded video is recorded. It will normally have a unconnected source pad; output from that pad will be written into the output file. However the pipeline can also take care of its own output - this might be used to send the output to an icecast server via shout2send or similar. When unset or set to an empty value, the default pipeline will be used. This is currently 'videorate ! theoraenc ! oggmux' and records to Ogg Theora."
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:14
msgid "Show date in clock"
msgstr "نمایش تاریخ در ساعت"
#: ../data/org.gnome.shell.gschema.xml.in.h:15
msgid "Show the week date in the calendar"
msgstr "نمایش هفته در تقویم"
#: ../data/org.gnome.shell.gschema.xml.in.h:16
msgid "Show time with seconds"
msgstr "نمایش ساعت همراه با ثانیه"
#: ../data/org.gnome.shell.gschema.xml.in.h:17
msgid "The applications corresponding to these identifiers will be displayed in the favorites area."
msgstr "برنامه‌های مشابه این شناسه‌ها در قسمت مورد پسندها نمایش داده می‌شود."
#: ../data/org.gnome.shell.gschema.xml.in.h:18
msgid "The filename for recorded screencasts will be a unique filename based on the current date, and use this extension. It should be changed when recording to a different container format."
msgstr "نام پرونده‌ی ضبط شده برای تصویربرداری از صفحه‌نمایش یکتا و براساس تاریخ جاری خواهد بود و از این افزونه استفاده خواهد کرد. اگر در زمان ضبط از قالب دیگری استفاده کنید باید تغییر کند."
#: ../data/org.gnome.shell.gschema.xml.in.h:19
msgid "The framerate of the resulting screencast recordered by GNOME Shell's screencast recorder in frames-per-second."
msgstr "سرعت فریم حاصل از تصویربرداری از صفحه نمایش با استفاده از ضبط کننده نمایشگر پوسته‌ی گنوم بر اساس فریم بر ثانیه"
#: ../data/org.gnome.shell.gschema.xml.in.h:20
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "مجرای ارتباطی gstreamer برای کدگذاری تصویربرداری از صفحه نمایش"
#: ../data/org.gnome.shell.gschema.xml.in.h:21
msgid "The shell normally monitors active applications in order to present the most used ones (e.g. in launchers). While this data will be kept private, you may want to disable this for privacy reasons. Please note that doing so won't remove already saved data."
msgstr "پوسته گنوم در حالت عادی برنامه‌های فعال را جهت ارائه برنامه‌های بیشتر استفاده شده پایش می کند. (برای مثال در اجرا کننده‌ها). با اینکه که این اطلاعات به صورت خصوصی نگاه‌داری می‌شود، ممکن است شما بخواهید این امکان را به دلایل امنیتی غیرفعال کنید. لطفا توجه کنید این کار باعث پاک شدن اطلاعاتی که تاکنون ذخیره شده‌اند نمی‌شود."
#: ../data/org.gnome.shell.gschema.xml.in.h:22
msgid "This key specifies the format used by the panel clock when the format key is set to \"custom\". You can use conversion specifiers understood by strftime() to obtain a specific format. See the strftime() manual for more information."
msgstr "این کلید قالب ساعتِ قاب را هنگامی که بر روی «سفارشی» تنظیم شده باشد تعیین می‌کند. شما می‌توانید از مبدل‌های قابل فهم در تابع ()strftime برای اختصاص قالب مشخص استفاده کنید. برای اطلاعات بیشتر مستندات ()strftime را مشاهده کنید."
#: ../data/org.gnome.shell.gschema.xml.in.h:23
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."
msgstr "این کلید قالب ساعت را در تابلو مشخص می‌کند. مقادیر ممکن عبارتند از: «۱۲ ساعته»، «۲۴ ساعته»، «یونیکس» و «سفارشی». چنانچه بر روی «یونیکس» تنظیم گردد، ساعت زمان را به ثانیه از زمان مبدا تاریخ نشان می‌دهد، برای مثال ۰۱-۰۱-۱۹۷۰. اگر بر روی «سفارشی» تنظیم شود ساعت زمان را با توجه به قالب معرفی شده در کلید custom_format نمایش خواهد داد. توجه کنید که چنانچه بر روی یکی از حالت‌های «یونیکس» و یا «سفارشی» تنظیم شود، کلیدهای show_date و show_seconds نادیده گرفته خواهند شد."
#: ../data/org.gnome.shell.gschema.xml.in.h:24
msgid "Uuids of extensions to disable"
msgstr "شناسه‌های Uuid مربوط به افزونه‌ها که غیرفعال شود"
#: ../data/org.gnome.shell.gschema.xml.in.h:25
msgid "Whether to collect stats about applications usage"
msgstr "اینکه اطلاعات برنامه‌ها درباره‌ی میزان استفاده از منابع جمع‌آوری شود یا خیر"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:1
msgid "Clip the crosshairs at the center"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:2
msgid "Color of the crosshairs"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:3
msgid "Determines the length of the vertical and horizontal lines that make up the crosshairs."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:4
msgid "Determines the position of the magnified mouse image within the magnified view and how it reacts to system mouse movement. The values are - none: no mouse tracking; - centered: the mouse image is displayed at the center of the zoom region (which also represents the point under the system mouse) and the magnified contents are scrolled as the system mouse moves; - proportional: the position of the magnified mouse in the zoom region is proportionally the same as the position of the system mouse on screen; - push: when the magnified mouse intersects a boundary of the zoom region, the contents are scrolled into view."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:5
msgid "Determines the transparency of the crosshairs, from fully opaque to fully transparent."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:6
msgid "Determines whether the crosshairs intersect the magnified mouse sprite, or are clipped such that the ends of the horizontal and vertical lines surround the mouse image."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:7
#| msgid "Enabled"
msgid "Enable lens mode"
msgstr "به کار انداختن حالت لنز"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:8
msgid "Enables/disables display of crosshairs centered on the magnified mouse sprite."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:9
msgid "For centered mouse tracking, when the system pointer is at or near the edge of the screen, the magnified contents continue to scroll such that the screen edge moves into the magnified view."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:10
msgid "Length of the crosshairs"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:11
msgid "Magnification factor"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:12
msgid "Mouse Tracking Mode"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:13
msgid "Opacity of the crosshairs"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:14
msgid "Screen position"
msgstr "مکان روی صفحه نمایش"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:15
msgid "Scroll magnified contents beyond the edges of the desktop"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:16
msgid "Show or hide crosshairs"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:17
msgid "Show or hide the magnifier"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:18
msgid "Show or hide the magnifier and all of its zoom regions."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:19
msgid "The color of the the vertical and horizontal lines that make up the crosshairs."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:20
msgid "The magnified view either fills the entire screen, or occupies the top-half, bottom-half, left-half, or right-half of the screen."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:21
msgid "The power of the magnification. A value of 1.0 means no magnification. A value of 2.0 doubles the size."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:22
msgid "Thickness of the crosshairs"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:23
msgid "Whether the magnified view should be centered over the location of the system mouse and move with it."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:24
msgid "Width of the vertical and horizontal lines that make up the crosshairs."
msgstr ""
#: ../data/clock-preferences.ui.h:1
msgid "Clock Format"
msgstr "قالب ساعت"
#: ../data/clock-preferences.ui.h:2
msgid "Clock Preferences"
msgstr "ترجیحات ساعت"
#: ../data/clock-preferences.ui.h:3
msgid "Panel Display"
msgstr "نمایش تابلو"
#: ../data/clock-preferences.ui.h:4
msgid "Show seco_nds"
msgstr "نمایش _ثانیهها"
#: ../data/clock-preferences.ui.h:5
msgid "Show the _date"
msgstr "نمایش _تاریخ"
#: ../data/clock-preferences.ui.h:6
msgid "_12 hour format"
msgstr "فالب _۱۲ ساعته"
#: ../data/clock-preferences.ui.h:7
msgid "_24 hour format"
msgstr "قالب _۲۴ ساعته"
#: ../js/ui/appDisplay.js:215
msgid "APPLICATIONS"
msgstr "برنامه‌ها"
#: ../js/ui/appDisplay.js:245
msgid "PREFERENCES"
msgstr "ترجیحات"
#: ../js/ui/appDisplay.js:542
msgid "New Window"
msgstr "پنجره‌ی جدید"
#: ../js/ui/appDisplay.js:546
msgid "Remove from Favorites"
msgstr "حذف از مورد پسندها"
#: ../js/ui/appDisplay.js:547
msgid "Add to Favorites"
msgstr "اضافه کردن به مورد پسندها"
#: ../js/ui/appFavorites.js:91
#, c-format
msgid "%s has been added to your favorites."
msgstr "مورد %s به مورد پسندهای شما اضافه شد."
#: ../js/ui/appFavorites.js:122
#, c-format
msgid "%s has been removed from your favorites."
msgstr "مورد %s ازمورد پسندهای شما حذف شد."
#: ../js/ui/dash.js:27
msgid "Remove"
msgstr "حذف"
#: ../js/ui/docDisplay.js:494
msgid "RECENT ITEMS"
msgstr "موارد اخیر"
#: ../js/ui/lookingGlass.js:552
msgid "No extensions installed"
msgstr "هیچ افزونه‌ای نصب نشده است"
#: ../js/ui/lookingGlass.js:589
msgid "Enabled"
msgstr "به کار انداختن"
#. translators:
#. * The device has been disabled
#: ../js/ui/lookingGlass.js:591
#: ../src/gvc/gvc-mixer-control.c:1087
msgid "Disabled"
msgstr "از کار انداختن"
#: ../js/ui/lookingGlass.js:593
msgid "Error"
msgstr "خطا"
#: ../js/ui/lookingGlass.js:595
msgid "Out of date"
msgstr "قدیمی"
#: ../js/ui/lookingGlass.js:620
msgid "View Source"
msgstr "نمایش کدمنبع"
#: ../js/ui/lookingGlass.js:626
msgid "Web Page"
msgstr "صفحه‌ی وب"
#: ../js/ui/overview.js:112
msgid "Undo"
msgstr "برگردان"
#. TODO - _quit() doesn't really work on apps in state STARTING yet
#: ../js/ui/panel.js:470
#, c-format
msgid "Quit %s"
msgstr "خروج از %s"
#: ../js/ui/panel.js:495
msgid "Preferences"
msgstr "ترجیحات"
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:581
msgid "%a %b %e, %R:%S"
msgstr "%a %b %e, %R:%S"
#: ../js/ui/panel.js:582
msgid "%a %b %e, %R"
msgstr "%a %b %e, %R"
#. Translators: This is the time format without date used
#. in 24-hour mode.
#: ../js/ui/panel.js:586
msgid "%a %R:%S"
msgstr "%a %R:%S"
#: ../js/ui/panel.js:587
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:594
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a %b %e, %l:%M:%S %p"
#: ../js/ui/panel.js:595
msgid "%a %b %e, %l:%M %p"
msgstr "%a %b %e, %l:%M %p"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:599
msgid "%a %l:%M:%S %p"
msgstr "%a %l:%M:%S %p"
#: ../js/ui/panel.js:600
msgid "%a %l:%M %p"
msgstr "%a %l:%M %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:745
msgid "Activities"
msgstr "فعالیت‌ها"
#: ../js/ui/placeDisplay.js:111
#, c-format
msgid "Failed to unmount '%s'"
msgstr "عدم توانایی در پیاده کردن «%s»"
#: ../js/ui/placeDisplay.js:114
msgid "Retry"
msgstr "سعی مجدد"
#: ../js/ui/placeDisplay.js:159
msgid "Connect to..."
msgstr "اتصال به..."
#: ../js/ui/placeDisplay.js:558
msgid "PLACES & DEVICES"
msgstr "محل‌ها و ابزارها"
#. Translators: this MUST be either "toggle-switch-us"
#. (for toggle switches containing the English words
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
#. switches containing "◯" and "|"). Other values will
#. simply result in invisible toggle switches.
#: ../js/ui/popupMenu.js:33
msgid "toggle-switch-us"
msgstr "toggle-switch-intl"
#: ../js/ui/runDialog.js:233
msgid "Please enter a command:"
msgstr "لطفا یک فرمان وارد کنید:"
#: ../js/ui/runDialog.js:378
#, c-format
msgid "Execution of '%s' failed:"
msgstr "اجرای «%s» شکست خورد:"
#: ../js/ui/statusMenu.js:101
msgid "Available"
msgstr "در دسترس"
#: ../js/ui/statusMenu.js:106
msgid "Busy"
msgstr "مشغول"
#: ../js/ui/statusMenu.js:114
msgid "My Account"
msgstr "حساب من"
#: ../js/ui/statusMenu.js:118
#| msgid "System Settings..."
msgid "System Settings"
msgstr "تنظیمات سیستم"
#: ../js/ui/statusMenu.js:125
msgid "Lock Screen"
msgstr "قفل کردن صفحه"
#: ../js/ui/statusMenu.js:129
msgid "Switch User"
msgstr "تعویض کاربر"
#: ../js/ui/statusMenu.js:134
msgid "Log Out..."
msgstr "خروج از سیستم..."
#: ../js/ui/statusMenu.js:141
msgid "Suspend..."
msgstr "معلق کردن..."
#: ../js/ui/statusMenu.js:145
msgid "Shut Down..."
msgstr "خاموش کردن..."
#: ../js/ui/status/accessibility.js:82
msgid "Zoom"
msgstr "بزرگنمایی"
#: ../js/ui/status/accessibility.js:88
msgid "Screen Reader"
msgstr "صفحه خوان"
#: ../js/ui/status/accessibility.js:91
msgid "Screen Keyboard"
msgstr "صفحه‌کلید مجازی"
#: ../js/ui/status/accessibility.js:94
msgid "Visual Alerts"
msgstr ""
#: ../js/ui/status/accessibility.js:97
msgid "Sticky Keys"
msgstr ""
#: ../js/ui/status/accessibility.js:100
msgid "Slow Keys"
msgstr ""
#: ../js/ui/status/accessibility.js:103
msgid "Bounce Keys"
msgstr ""
#: ../js/ui/status/accessibility.js:106
msgid "Mouse Keys"
msgstr "کلیدهای موشی"
#: ../js/ui/status/accessibility.js:110
msgid "Universal Access Settings"
msgstr ""
#: ../js/ui/status/accessibility.js:163
msgid "High Contrast"
msgstr ""
#: ../js/ui/status/accessibility.js:205
msgid "Large Text"
msgstr "متن درشت"
#: ../js/ui/status/power.js:87
msgid "What's using power..."
msgstr ""
#: ../js/ui/status/power.js:90
#| msgid "System Settings..."
msgid "Power Settings"
msgstr "تنظیمات برق"
#: ../js/ui/status/power.js:117
#, c-format
#| msgid "%d hour ago"
#| msgid_plural "%d hours ago"
msgid "%d hour remaining"
msgid_plural "%d hours remaining"
msgstr[0] "%Id ساعت مانده"
#. TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining"
#: ../js/ui/status/power.js:120
#, c-format
msgid "%d %s %d %s remaining"
msgstr "%d %s %d %s مانده"
#: ../js/ui/status/power.js:122
msgid "hour"
msgid_plural "hours"
msgstr[0] "ساعت"
#: ../js/ui/status/power.js:122
#| msgid "%d minute ago"
#| msgid_plural "%d minutes ago"
msgid "minute"
msgid_plural "minutes"
msgstr[0] "%Id دقیقه‌"
#: ../js/ui/status/power.js:125
#, c-format
#| msgid "%d minute ago"
#| msgid_plural "%d minutes ago"
msgid "%d minute remaining"
msgid_plural "%d minutes remaining"
msgstr[0] "%Id دقیقه‌ی مانده"
#: ../js/ui/status/power.js:244
msgid "AC adapter"
msgstr "آداپتور برق مستقیم"
#: ../js/ui/status/power.js:246
msgid "Laptop battery"
msgstr "باتری لپتاپ"
#: ../js/ui/status/power.js:248
msgid "UPS"
msgstr "UPS"
#: ../js/ui/status/power.js:250
msgid "Monitor"
msgstr "صفحه نمایش"
#: ../js/ui/status/power.js:252
msgid "Mouse"
msgstr "موشی"
#: ../js/ui/status/power.js:254
msgid "Keyboard"
msgstr "صفحه‌کلید"
#: ../js/ui/status/power.js:256
msgid "PDA"
msgstr "دستیار دیجیتال شخصی"
#: ../js/ui/status/power.js:258
msgid "Cell phone"
msgstr "تلفن سلولی"
#: ../js/ui/status/power.js:260
msgid "Media player"
msgstr "پخش کننده‌ی رسانه"
#: ../js/ui/status/power.js:262
#| msgid "Enabled"
msgid "Tablet"
msgstr "لوح‌رایانه"
#: ../js/ui/status/power.js:264
msgid "Computer"
msgstr "رایانه"
#: ../js/ui/status/power.js:266
#: ../src/shell-app-system.c:1012
msgid "Unknown"
msgstr "ناشناخته"
#: ../js/ui/status/volume.js:41
msgid "Volume"
msgstr "بلندی صدا"
#: ../js/ui/status/volume.js:54
msgid "Microphone"
msgstr "میکروفون"
#: ../js/ui/status/volume.js:62
#| msgid "System Settings..."
msgid "Sound Settings"
msgstr "تنظیمات صدا"
#: ../js/ui/viewSelector.js:26
msgid "Search your computer"
msgstr "جستجوی رایانه‌ی شما"
#: ../js/ui/windowAttentionHandler.js:43
#, c-format
msgid "%s has finished starting"
msgstr "راه‌اندازی %s پایان یافته است"
#: ../js/ui/windowAttentionHandler.js:45
#, c-format
msgid "'%s' is ready"
msgstr "«%s» آماده است"
#: ../js/ui/workspacesView.js:244
msgid "Can't add a new workspace because maximum workspaces limit has been reached."
msgstr "نمی‌توان میزکار جدیدی اضافه کرد زیرا به مرز بیشترین تعداد میزکار رسیده‌ایم."
#: ../js/ui/workspacesView.js:260
msgid "Can't remove the first workspace."
msgstr "نمی‌توان اولین میزکار را حذف کرد."
#. translators:
#. * The number of sound outputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1094
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] "%u خروجی"
#. translators:
#. * The number of sound inputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1104
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] "%u ورودی"
#: ../src/gvc/gvc-mixer-control.c:1402
#| msgid "System Settings..."
msgid "System Sounds"
msgstr "صداهای سیستم"
#: ../src/shell-global.c:1163
msgid "Less than a minute ago"
msgstr "کمتر از یک دقیقه قبل"
#: ../src/shell-global.c:1167
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%Id دقیقه‌ی پیش"
#: ../src/shell-global.c:1172
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%Id ساعت پیش"
#: ../src/shell-global.c:1177
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%Id روز پیش"
#: ../src/shell-global.c:1182
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%Id هفته‌ی پیش"
#: ../src/shell-util.c:89
msgid "Home Folder"
msgstr "پوشه‌ی آغازه"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-util.c:104
msgid "File System"
msgstr "سیستم پرونده‌ها"
#: ../src/shell-util.c:250
msgid "Search"
msgstr "جستجو"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-util.c:300
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Overview workspace view mode"
#~ msgstr "حالت بررسی اجمالی میزکار"
#~ msgid ""
#~ "The selected workspace view mode in the overview. Supported values are "
#~ "\"single\" and \"grid\"."
#~ msgstr ""
#~ "میزکار انتخاب شده در حال مشاهده اجمالی. مقادیر قابل پشتیبانی عبارتند از "
#~ "«تکی» و «شبکه‌ای»."
#~ msgid "Drag here to add favorites"
#~ msgstr "به اینجا بکشید تا به مجبوب‌ها اضافه شود"
#~ msgid "Find"
#~ msgstr "جستجو"
#~ msgid "Searching..."
#~ msgstr "درحال حستجو..."
#~ msgid "No matching results."
#~ msgstr "نتیجه‌ی منطبقی پیدا نشد."
#~ msgid "Invisible"
#~ msgstr "نامرئی"
#~ msgid "Account Information..."
#~ msgstr "اطلاعات جساب"

858
po/gl.po

File diff suppressed because it is too large Load Diff

818
po/he.po

File diff suppressed because it is too large Load Diff

727
po/it.po

File diff suppressed because it is too large Load Diff

668
po/nb.po

File diff suppressed because it is too large Load Diff

828
po/pa.po

File diff suppressed because it is too large Load Diff

View File

@ -5,16 +5,17 @@
# Rodrigo Flores <mail@rodrigoflores.org>, 2009.
# Felipe Borges <felipe10borges@gmail.com>, 2010.
# Henrique P. Machado <hpmachado@gnome.org>, 2010.
# Jonh Wendell <wendell@bani.com.br>, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&component=general\n"
"POT-Creation-Date: 2010-10-30 17:51+0000\n"
"PO-Revision-Date: 2010-09-02 17:36-0300\n"
"Last-Translator: Henrique P. Machado <hpmachado@gnome.org>\n"
"Language-Team: Brazilian Portuguese <gnome-pt_br-list@gnome.org>\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-12-07 08:59-0200\n"
"PO-Revision-Date: 2010-12-06 16:03+0100\n"
"Last-Translator: Jonh Wendell <wendell@bani.com.br>\n"
"Language-Team: Brazilian Portuguese <pt_BR>\n"
"Language: pt_BR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@ -104,10 +105,6 @@ msgstr ""
"Lista dos IDs de arquivo de área de trabalho para os aplicativos favoritos"
#: ../data/org.gnome.shell.gschema.xml.in.h:13
msgid "Overview workspace view mode"
msgstr "Resumo do modo de visão de áreas de trabalho"
#: ../data/org.gnome.shell.gschema.xml.in.h:14
msgid ""
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
"used for gst-launch. The pipeline should have an unconnected sink pad where "
@ -128,19 +125,19 @@ msgstr ""
"o fluxo de processamento padrão será usado. Atualmente é 'videorate ! "
"theoraenc ! oggmux' e gravação no formato Ogg Theora."
#: ../data/org.gnome.shell.gschema.xml.in.h:15
#: ../data/org.gnome.shell.gschema.xml.in.h:14
msgid "Show date in clock"
msgstr "Mostrar data no relógio"
#: ../data/org.gnome.shell.gschema.xml.in.h:16
#: ../data/org.gnome.shell.gschema.xml.in.h:15
msgid "Show the week date in the calendar"
msgstr "Mostrar o número da semana no calendário"
#: ../data/org.gnome.shell.gschema.xml.in.h:17
#: ../data/org.gnome.shell.gschema.xml.in.h:16
msgid "Show time with seconds"
msgstr "Mostrar horário com segundos"
#: ../data/org.gnome.shell.gschema.xml.in.h:18
#: ../data/org.gnome.shell.gschema.xml.in.h:17
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
@ -148,7 +145,7 @@ msgstr ""
"Os aplicativos correspondentes a estes identificadores serão exibidos na "
"área de favoritos."
#: ../data/org.gnome.shell.gschema.xml.in.h:19
#: ../data/org.gnome.shell.gschema.xml.in.h:18
msgid ""
"The filename for recorded screencasts will be a unique filename based on the "
"current date, and use this extension. It should be changed when recording to "
@ -158,7 +155,7 @@ msgstr ""
"baseado na data atual e usará esta extensão. Ele deve ser alterado ao gravar "
"para um contêiner de formato diferente."
#: ../data/org.gnome.shell.gschema.xml.in.h:20
#: ../data/org.gnome.shell.gschema.xml.in.h:19
msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames-per-second."
@ -166,19 +163,11 @@ msgstr ""
"A taxa de quadros do screencast resultante gravado pelo gravador de "
"screencastsdo GNOME Shell em quadros por segundo."
#: ../data/org.gnome.shell.gschema.xml.in.h:21
#: ../data/org.gnome.shell.gschema.xml.in.h:20
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "A fila de processamento gstreamer usada para codificar o screencast"
#: ../data/org.gnome.shell.gschema.xml.in.h:22
msgid ""
"The selected workspace view mode in the overview. Supported values are "
"\"single\" and \"grid\"."
msgstr ""
"O o modo de visão do espaço de trabalho na visão geral. Valores aceitos são: "
"\"single\" e \"grid\"."
#: ../data/org.gnome.shell.gschema.xml.in.h:23
#: ../data/org.gnome.shell.gschema.xml.in.h:21
msgid ""
"The shell normally monitors active applications in order to present the most "
"used ones (e.g. in launchers). While this data will be kept private, you may "
@ -190,7 +179,7 @@ msgstr ""
"segurança, você pode querer desabilitá-los por razões de privacidade. Por "
"favor, note que que ao fazer isso não removerá os dado já salvos."
#: ../data/org.gnome.shell.gschema.xml.in.h:24
#: ../data/org.gnome.shell.gschema.xml.in.h:22
msgid ""
"This key specifies the format used by the panel clock when the format key is "
"set to \"custom\". You can use conversion specifiers understood by strftime"
@ -202,7 +191,7 @@ msgstr ""
"especificadores de conversão entendidos pela função strftime() para obter um "
"formato específico. Veja o manual da strftime() para maiores informações."
#: ../data/org.gnome.shell.gschema.xml.in.h:25
#: ../data/org.gnome.shell.gschema.xml.in.h:23
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\", "
@ -219,11 +208,11 @@ msgstr ""
"custom_format. Note que se definida tanto como \"unix\" ou \"custom\", as "
"chaves show_date e show_seconds serão igoradas."
#: ../data/org.gnome.shell.gschema.xml.in.h:26
#: ../data/org.gnome.shell.gschema.xml.in.h:24
msgid "Uuids of extensions to disable"
msgstr "Uuids das extensões a desabilitar"
#: ../data/org.gnome.shell.gschema.xml.in.h:27
#: ../data/org.gnome.shell.gschema.xml.in.h:25
msgid "Whether to collect stats about applications usage"
msgstr "Quando coletar dados sobre uso de aplicativos"
@ -269,7 +258,6 @@ msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:7
#, fuzzy
#| msgid "Enabled"
msgid "Enable lens mode"
msgstr "Habilitado"
@ -382,62 +370,41 @@ msgstr "Formato de _12 horas"
msgid "_24 hour format"
msgstr "Formato de _24 horas"
#. **** Applications ****
#: ../js/ui/appDisplay.js:316 ../js/ui/dash.js:778
#: ../js/ui/appDisplay.js:215
msgid "APPLICATIONS"
msgstr "APLICATIVOS"
#: ../js/ui/appDisplay.js:348
#: ../js/ui/appDisplay.js:245
msgid "PREFERENCES"
msgstr "PREFERÊNCIAS"
#: ../js/ui/appDisplay.js:647
#: ../js/ui/appDisplay.js:542
msgid "New Window"
msgstr "Nova janela"
#: ../js/ui/appDisplay.js:651
#: ../js/ui/appDisplay.js:546
msgid "Remove from Favorites"
msgstr "Remover dos Favoritos"
msgstr "Remover dos favoritos"
#: ../js/ui/appDisplay.js:652
#: ../js/ui/appDisplay.js:547
msgid "Add to Favorites"
msgstr "Adicionar aos Favoritos"
msgstr "Adicionar aos favoritos"
#: ../js/ui/appDisplay.js:829
msgid "Drag here to add favorites"
msgstr "Arraste até aqui para adicionar aos favoritos"
#: ../js/ui/appFavorites.js:88
#: ../js/ui/appFavorites.js:91
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s foi adicionado aos seus favoritos."
#: ../js/ui/appFavorites.js:107
#: ../js/ui/appFavorites.js:122
#, c-format
msgid "%s has been removed from your favorites."
msgstr "%s foi removido dos seus favoritos."
#: ../js/ui/dash.js:142
msgid "Find"
msgstr "Localizar"
#: ../js/ui/dash.js:27
msgid "Remove"
msgstr "Remover"
#: ../js/ui/dash.js:473
msgid "Searching..."
msgstr "Pesquisando..."
#: ../js/ui/dash.js:487
msgid "No matching results."
msgstr "Nenhum resultado encontrado."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:797 ../js/ui/placeDisplay.js:554
msgid "PLACES & DEVICES"
msgstr "LOCAIS & DISPOSITIVOS"
#. **** Documents ****
#: ../js/ui/dash.js:804 ../js/ui/docDisplay.js:494
#: ../js/ui/docDisplay.js:494
msgid "RECENT ITEMS"
msgstr "DOCUMENTOS RECENTES"
@ -471,63 +438,63 @@ msgstr "Ver fonte"
msgid "Web Page"
msgstr "Página Web"
#: ../js/ui/overview.js:160
#: ../js/ui/overview.js:112
msgid "Undo"
msgstr "Desfazer"
#. TODO - _quit() doesn't really work on apps in state STARTING yet
#: ../js/ui/panel.js:469
#: ../js/ui/panel.js:470
#, c-format
msgid "Quit %s"
msgstr "Sair de %s"
#: ../js/ui/panel.js:494
#: ../js/ui/panel.js:495
msgid "Preferences"
msgstr "Preferências"
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:580
#: ../js/ui/panel.js:581
msgid "%a %b %e, %R:%S"
msgstr "%a %b %e, %R:%S"
#: ../js/ui/panel.js:581
#: ../js/ui/panel.js:582
msgid "%a %b %e, %R"
msgstr "%a %b %e, %R"
#. Translators: This is the time format without date used
#. in 24-hour mode.
#: ../js/ui/panel.js:585
#: ../js/ui/panel.js:586
msgid "%a %R:%S"
msgstr "%a %R:%S"
#: ../js/ui/panel.js:586
#: ../js/ui/panel.js:587
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:593
#: ../js/ui/panel.js:594
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a %e de %b, %H:%M:%S"
#: ../js/ui/panel.js:594
#: ../js/ui/panel.js:595
msgid "%a %b %e, %l:%M %p"
msgstr "%a %e de %b, %H:%M"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:598
#: ../js/ui/panel.js:599
msgid "%a %l:%M:%S %p"
msgstr "%a %H:%M:%S"
#: ../js/ui/panel.js:599
#: ../js/ui/panel.js:600
msgid "%a %l:%M %p"
msgstr "%a %H:%M"
#. 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:744
#: ../js/ui/panel.js:745
msgid "Activities"
msgstr "Atividades"
@ -544,6 +511,10 @@ msgstr "Tentar novamente"
msgid "Connect to..."
msgstr "Conectar ao..."
#: ../js/ui/placeDisplay.js:558
msgid "PLACES & DEVICES"
msgstr "LOCAIS & DISPOSITIVOS"
#. Translators: this MUST be either "toggle-switch-us"
#. (for toggle switches containing the English words
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
@ -551,7 +522,7 @@ msgstr "Conectar ao..."
#. simply result in invisible toggle switches.
#: ../js/ui/popupMenu.js:33
msgid "toggle-switch-us"
msgstr ""
msgstr "toggle-switch-us"
#: ../js/ui/runDialog.js:233
msgid "Please enter a command:"
@ -570,86 +541,181 @@ msgstr "Disponível"
msgid "Busy"
msgstr "Ocupado"
#: ../js/ui/statusMenu.js:111
msgid "Invisible"
msgstr "Invisível"
#: ../js/ui/statusMenu.js:114
msgid "My Account"
msgstr "Minha conta"
#: ../js/ui/statusMenu.js:119
msgid "My Account..."
msgstr ""
#: ../js/ui/statusMenu.js:118
msgid "System Settings"
msgstr "Configurações do sistema"
#: ../js/ui/statusMenu.js:123
#| msgid "System Preferences..."
msgid "System Settings..."
msgstr "Configurações do sistema..."
#: ../js/ui/statusMenu.js:130
#: ../js/ui/statusMenu.js:125
msgid "Lock Screen"
msgstr "Travar a tela"
msgstr "Bloquear a tela"
#: ../js/ui/statusMenu.js:134
#: ../js/ui/statusMenu.js:129
msgid "Switch User"
msgstr "Alternar usuário"
#: ../js/ui/statusMenu.js:139
#: ../js/ui/statusMenu.js:134
msgid "Log Out..."
msgstr "Encerrar sessão..."
#: ../js/ui/statusMenu.js:146
msgid "Suspend"
msgstr ""
#: ../js/ui/statusMenu.js:141
msgid "Suspend..."
msgstr "Suspender..."
#: ../js/ui/statusMenu.js:150
msgid "Restart..."
msgstr ""
#: ../js/ui/statusMenu.js:154
#: ../js/ui/statusMenu.js:145
msgid "Shut Down..."
msgstr "Desligar..."
#: ../js/ui/status/accessibility.js:82
msgid "Zoom"
msgstr "Ampliador"
#: ../js/ui/status/accessibility.js:88
msgid "Screen Reader"
msgstr ""
msgstr "Leitor de tela"
#: ../js/ui/status/accessibility.js:91
msgid "Screen Keyboard"
msgstr ""
msgstr "Teclado na tela"
#: ../js/ui/status/accessibility.js:94
msgid "Visual Alerts"
msgstr ""
msgstr "Alertas visuais"
#: ../js/ui/status/accessibility.js:97
msgid "Sticky Keys"
msgstr ""
msgstr "Teclas de aderência"
#: ../js/ui/status/accessibility.js:100
msgid "Slow Keys"
msgstr ""
msgstr "Teclas lentas"
#: ../js/ui/status/accessibility.js:103
msgid "Bounce Keys"
msgstr ""
msgstr "Teclas de repercussão"
#: ../js/ui/status/accessibility.js:106
msgid "Mouse Keys"
msgstr ""
msgstr "Teclas do mouse"
#: ../js/ui/status/accessibility.js:110
msgid "Universal Access Settings"
msgstr ""
msgstr "Configurações de acesso universal"
#: ../js/ui/status/accessibility.js:163
msgid "High Contrast"
msgstr ""
msgstr "Alto contraste"
#: ../js/ui/status/accessibility.js:202
#: ../js/ui/status/accessibility.js:205
msgid "Large Text"
msgstr ""
msgstr "Texto grande"
#: ../js/ui/status/accessibility.js:223
msgid "Zoom"
msgstr ""
#: ../js/ui/status/power.js:87
msgid "What's using power..."
msgstr "Onde a energia está sendo gasta..."
#: ../js/ui/status/power.js:90
msgid "Power Settings"
msgstr "Gerenciamento de energia..."
#: ../js/ui/status/power.js:117
#, c-format
msgid "%d hour remaining"
msgid_plural "%d hours remaining"
msgstr[0] "%d hora restante"
msgstr[1] "%d horas restantes"
#. TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining"
#: ../js/ui/status/power.js:120
#, c-format
msgid "%d %s %d %s remaining"
msgstr "%d %s e %d %s restantes"
#: ../js/ui/status/power.js:122
msgid "hour"
msgid_plural "hours"
msgstr[0] "hora"
msgstr[1] "horas"
#: ../js/ui/status/power.js:122
msgid "minute"
msgid_plural "minutes"
msgstr[0] "minuto"
msgstr[1] "minutos"
#: ../js/ui/status/power.js:125
#, c-format
msgid "%d minute remaining"
msgid_plural "%d minutes remaining"
msgstr[0] "%d minuto restante"
msgstr[1] "%d minutos restantes"
#: ../js/ui/status/power.js:244
msgid "AC adapter"
msgstr "Tomada"
#: ../js/ui/status/power.js:246
msgid "Laptop battery"
msgstr "Bateria do laptop"
#: ../js/ui/status/power.js:248
msgid "UPS"
msgstr "UPS"
#: ../js/ui/status/power.js:250
msgid "Monitor"
msgstr "Monitor"
#: ../js/ui/status/power.js:252
msgid "Mouse"
msgstr "Mouse"
#: ../js/ui/status/power.js:254
msgid "Keyboard"
msgstr "Teclado"
#: ../js/ui/status/power.js:256
msgid "PDA"
msgstr "PDA"
#: ../js/ui/status/power.js:258
msgid "Cell phone"
msgstr "Telefone celular"
#: ../js/ui/status/power.js:260
msgid "Media player"
msgstr "Reprodutor de música"
#: ../js/ui/status/power.js:262
msgid "Tablet"
msgstr "Tablet"
#: ../js/ui/status/power.js:264
msgid "Computer"
msgstr "Computador"
#: ../js/ui/status/power.js:266 ../src/shell-app-system.c:1012
msgid "Unknown"
msgstr "Desconhecido"
#: ../js/ui/status/volume.js:41
msgid "Volume"
msgstr "Volume"
#: ../js/ui/status/volume.js:54
msgid "Microphone"
msgstr "Microfone"
#: ../js/ui/status/volume.js:62
msgid "Sound Settings"
msgstr "Configurações de som"
#: ../js/ui/viewSelector.js:26
msgid "Search your computer"
msgstr "Pesquise no seu computador"
#: ../js/ui/windowAttentionHandler.js:43
#, c-format
@ -661,14 +727,14 @@ msgstr "%s terminou sua inicialização"
msgid "'%s' is ready"
msgstr "\"%s\" está pronto"
#: ../js/ui/workspacesView.js:229
#: ../js/ui/workspacesView.js:244
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
msgstr ""
"Não é possível adicionar um novo espaço de trabalho porque foi atingido o "
"limite."
#: ../js/ui/workspacesView.js:246
#: ../js/ui/workspacesView.js:260
msgid "Can't remove the first workspace."
msgstr "Não é possível remover o primeiro espaço de trabalho."
@ -678,8 +744,8 @@ msgstr "Não é possível remover o primeiro espaço de trabalho."
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%u saída"
msgstr[1] "%u saídas"
#. translators:
#. * The number of sound inputs on a particular device
@ -687,56 +753,56 @@ msgstr[1] ""
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%u entrada"
msgstr[1] "%u entradas"
#: ../src/gvc/gvc-mixer-control.c:1402
msgid "System Sounds"
msgstr ""
msgstr "Sons do sistema"
#: ../src/shell-global.c:1219
#: ../src/shell-global.c:1163
msgid "Less than a minute ago"
msgstr "Há menos de um minuto"
#: ../src/shell-global.c:1223
#: ../src/shell-global.c:1167
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "Há %d minuto"
msgstr[1] "Há %d minutos"
#: ../src/shell-global.c:1228
#: ../src/shell-global.c:1172
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "Há %d hora"
msgstr[1] "Há %d horas"
#: ../src/shell-global.c:1233
#: ../src/shell-global.c:1177
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "Há %d dia"
msgstr[1] "Há %d dias"
#: ../src/shell-global.c:1238
#: ../src/shell-global.c:1182
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "Há %d semana"
msgstr[1] "Há %d semanas"
#: ../src/shell-uri-util.c:89
#: ../src/shell-util.c:89
msgid "Home Folder"
msgstr "Pasta pessoal"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:104
#: ../src/shell-util.c:104
msgid "File System"
msgstr "Sistema de arquivos"
#: ../src/shell-uri-util.c:250
#: ../src/shell-util.c:250
msgid "Search"
msgstr "Pesquisar"
@ -745,11 +811,36 @@ msgstr "Pesquisar"
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:300
#: ../src/shell-util.c:300
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Overview workspace view mode"
#~ msgstr "Resumo do modo de visão de áreas de trabalho"
#~ msgid ""
#~ "The selected workspace view mode in the overview. Supported values are "
#~ "\"single\" and \"grid\"."
#~ msgstr ""
#~ "O o modo de visão do espaço de trabalho na visão geral. Valores aceitos "
#~ "são: \"single\" e \"grid\"."
#~ msgid "Drag here to add favorites"
#~ msgstr "Arraste até aqui para adicionar aos favoritos"
#~ msgid "Find"
#~ msgstr "Localizar"
#~ msgid "Searching..."
#~ msgstr "Pesquisando..."
#~ msgid "No matching results."
#~ msgstr "Nenhum resultado encontrado."
#~ msgid "Invisible"
#~ msgstr "Invisível"
#~ msgid "ON"
#~ msgstr "⚪"
@ -777,9 +868,6 @@ msgstr "%1$s: %2$s"
#~ msgid "SEARCH RESULTS"
#~ msgstr "RESULTADOS DA BUSCA"
#~ msgid "Unknown"
#~ msgstr "Desconhecido"
#~ msgid "Can't lock screen: %s"
#~ msgstr "Não foi possível travar a tela: %s"

348
po/sl.po
View File

@ -8,8 +8,8 @@ msgid ""
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: 2010-10-26 14:37+0000\n"
"PO-Revision-Date: 2010-10-26 19:29+0100\n"
"POT-Creation-Date: 2010-12-11 15:45+0000\n"
"PO-Revision-Date: 2010-12-11 20:40+0100\n"
"Last-Translator: Matej Urbančič <mateju@svn.gnome.org>\n"
"Language-Team: Slovenian GNOME Translation Team <gnome-si@googlegroups.com>\n"
"Language: Slovenian\n"
@ -86,62 +86,54 @@ msgid "List of desktop file IDs for favorite applications"
msgstr "Seznam določil ID namiznih datotek priljubljenih programov"
#: ../data/org.gnome.shell.gschema.xml.in.h:13
msgid "Overview workspace view mode"
msgstr "Način pregleda predogleda delovnih površin"
#: ../data/org.gnome.shell.gschema.xml.in.h:14
msgid "Sets the GStreamer pipeline used to encode recordings. It follows the syntax used for gst-launch. The pipeline should have an unconnected sink pad where the recorded video is recorded. It will normally have a unconnected source pad; output from that pad will be written into the output file. However the pipeline can also take care of its own output - this might be used to send the output to an icecast server via shout2send or similar. When unset or set to an empty value, the default pipeline will be used. This is currently 'videorate ! theoraenc ! oggmux' and records to Ogg Theora."
msgstr "Določa cevovod programa GStreamer, ki se uporablja za kodiranje posnetkov. Ta sledi skladnji, ki je uporabljena za gst-launch. Cevovod mora imeti nepovezano korito, kamor se posnetek snema. Običajno je za to namenjen nepovezan izvorni pomnilnik, katerega odvod se zapiše v odvodno datoteko. Vendar pa lahko cevovod ta korak naredi v lastni odvod - možnost se lahko uporabi pri pošiljanju odvoda na strežnik icecast preko shout2send ali podobno. Nedoločena ali prazna možnost se odrazi kot privzeti cevovod. Trenutno je to 'videorate ! theoraenc ! oggmux' in omogoča snemanje v zapis Ogg Theora."
#: ../data/org.gnome.shell.gschema.xml.in.h:15
#: ../data/org.gnome.shell.gschema.xml.in.h:14
msgid "Show date in clock"
msgstr "Pokaži datum v uri"
#: ../data/org.gnome.shell.gschema.xml.in.h:16
#: ../data/org.gnome.shell.gschema.xml.in.h:15
msgid "Show the week date in the calendar"
msgstr "Pokaži tedenski datum v koledarju"
#: ../data/org.gnome.shell.gschema.xml.in.h:17
#: ../data/org.gnome.shell.gschema.xml.in.h:16
msgid "Show time with seconds"
msgstr "Pokaži čas s sekundami"
#: ../data/org.gnome.shell.gschema.xml.in.h:18
#: ../data/org.gnome.shell.gschema.xml.in.h:17
msgid "The applications corresponding to these identifiers will be displayed in the favorites area."
msgstr "Programi določeni s temi določili bodo prikazani v območju priljubljenih programov"
#: ../data/org.gnome.shell.gschema.xml.in.h:19
#: ../data/org.gnome.shell.gschema.xml.in.h:18
msgid "The filename for recorded screencasts will be a unique filename based on the current date, and use this extension. It should be changed when recording to a different container format."
msgstr "Ime datoteke zaslonskega posnetka bo enoznačno ime, kateremu bo dodan datum in določena pripona. Pripona mora ustrezati zapisu zabojnika."
#: ../data/org.gnome.shell.gschema.xml.in.h:20
#: ../data/org.gnome.shell.gschema.xml.in.h:19
msgid "The framerate of the resulting screencast recordered by GNOME Shell's screencast recorder in frames-per-second."
msgstr "Hitrost sličic shranjenega končnega zaslonskega posnetka v sličicah na sekundo."
#: ../data/org.gnome.shell.gschema.xml.in.h:21
#: ../data/org.gnome.shell.gschema.xml.in.h:20
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "Uporabljen GStreamer cevovod za kodiranje zaslonskega posnetka."
#: ../data/org.gnome.shell.gschema.xml.in.h:22
msgid "The selected workspace view mode in the overview. Supported values are \"single\" and \"grid\"."
msgstr "Izbrani pogled delovnih površin v predogledu. Podprte vrednosti sta \"enojno\" in \"mrežno\"."
#: ../data/org.gnome.shell.gschema.xml.in.h:23
#: ../data/org.gnome.shell.gschema.xml.in.h:21
msgid "The shell normally monitors active applications in order to present the most used ones (e.g. in launchers). While this data will be kept private, you may want to disable this for privacy reasons. Please note that doing so won't remove already saved data."
msgstr "Lupina običajno nadzira dejavne programe zaradi možnosti prikazovanja najpogosteje uporabljenih v zaganjalniku. Čeprav so podatki krajevni, jih je dobro onemogočiti zaradi varovanja zasebnosti. Z onemogočenje ne bodo odstranjeni že shranjeni podatki."
#: ../data/org.gnome.shell.gschema.xml.in.h:24
#: ../data/org.gnome.shell.gschema.xml.in.h:22
msgid "This key specifies the format used by the panel clock when the format key is set to \"custom\". You can use conversion specifiers understood by strftime() to obtain a specific format. See the strftime() manual for more information."
msgstr "Ključ določa zapis, ki naj ga uporablja vstavek ure, kadar je ključ zapisa nastavljen kot \"prikrojen\". Za določitev zapisa lahko uporabite tudi oznake funkcije strftime(), ki so podrobneje zapisane v priročniku funkcije."
#: ../data/org.gnome.shell.gschema.xml.in.h:25
#: ../data/org.gnome.shell.gschema.xml.in.h:23
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."
msgstr "Ključ določa zapis ure. Mogoče vrednosti so \"12-urni\", \"24-urni\", \"unix\" in \"po meri\". Možnost \"unix\" prikazuje čas v sekundah od začetka ere, torej od 01.01.1970, možnost \"po meri\" pa omogoča prikrojen zapis. Pri izbiri zapisa \"unix\" ali \"po meri\" sta izbiri pokaži datum in pokaži sekunde, prezrti."
#: ../data/org.gnome.shell.gschema.xml.in.h:26
#: ../data/org.gnome.shell.gschema.xml.in.h:24
msgid "Uuids of extensions to disable"
msgstr "Določila UUID razširitev za onemogočenje"
#: ../data/org.gnome.shell.gschema.xml.in.h:27
#: ../data/org.gnome.shell.gschema.xml.in.h:25
msgid "Whether to collect stats about applications usage"
msgstr "Ali naj se beleži statistika uporabe programov"
@ -179,7 +171,7 @@ msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:9
msgid "For centered mouse tracking, when the system pointer is at or near the edge of the screen, the magnified contents continue to scroll such that the screen edge moves into the magnified view."
msgstr ""
msgstr "Pri usredinjenem sledenju miški, ko je sistemski kazalnik ob robu zaslona, približanje vsebine drsi naprej tako, da je rob zaslona v približanem pogledu."
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:10
msgid "Length of the crosshairs"
@ -223,11 +215,11 @@ msgstr "Barva navpične in vodoravne črte, ki določata merek."
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:20
msgid "The magnified view either fills the entire screen, or occupies the top-half, bottom-half, left-half, or right-half of the screen."
msgstr ""
msgstr "Približan pogled lahko zapolni celoten zaslon, lahko pa zasede zgornjo, spodnjo, levo ali pa desno polovico zaslona."
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:21
msgid "The power of the magnification. A value of 1.0 means no magnification. A value of 2.0 doubles the size."
msgstr ""
msgstr "Vrednost približanja. Vrednost 1.0 pomeni brez približanja, vrednost 2.0 pa podvoji učinek približanja."
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:22
msgid "Thickness of the crosshairs"
@ -235,7 +227,7 @@ msgstr "Debelina merka"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:23
msgid "Whether the magnified view should be centered over the location of the system mouse and move with it."
msgstr ""
msgstr "Ali naj bo približan pogled usredinjen na mesto sistemske miške in se z njo premika."
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:24
msgid "Width of the vertical and horizontal lines that make up the crosshairs."
@ -269,64 +261,40 @@ msgstr "_12-urni zapis časa"
msgid "_24 hour format"
msgstr "_24-urni zapis časa"
#. **** Applications ****
#: ../js/ui/appDisplay.js:316
#: ../js/ui/dash.js:778
#: ../js/ui/appDisplay.js:215
msgid "APPLICATIONS"
msgstr "Programi"
#: ../js/ui/appDisplay.js:348
#: ../js/ui/appDisplay.js:245
msgid "PREFERENCES"
msgstr "Možnosti"
#: ../js/ui/appDisplay.js:648
#: ../js/ui/appDisplay.js:542
msgid "New Window"
msgstr "Novo okno"
#: ../js/ui/appDisplay.js:652
#: ../js/ui/appDisplay.js:546
msgid "Remove from Favorites"
msgstr "Odstrani iz priljubljenih"
#: ../js/ui/appDisplay.js:653
#: ../js/ui/appDisplay.js:547
msgid "Add to Favorites"
msgstr "Dodaj med priljubljene"
#: ../js/ui/appDisplay.js:830
msgid "Drag here to add favorites"
msgstr "S potegom na to mesto se izbor doda med priljubljene"
#: ../js/ui/appFavorites.js:88
#: ../js/ui/appFavorites.js:91
#, c-format
msgid "%s has been added to your favorites."
msgstr "Program \"%s\" je dodan med priljubljeno."
#: ../js/ui/appFavorites.js:107
#: ../js/ui/appFavorites.js:122
#, c-format
msgid "%s has been removed from your favorites."
msgstr "Program \"%s\" je odstranjen iz priljubljenih."
#: ../js/ui/dash.js:142
msgid "Find"
msgstr "Najdi"
#: ../js/ui/dash.js:27
msgid "Remove"
msgstr "Odstrani"
#: ../js/ui/dash.js:473
msgid "Searching..."
msgstr "Iskanje ..."
#: ../js/ui/dash.js:487
msgid "No matching results."
msgstr "Ni zadetkov iskanja"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:797
#: ../js/ui/placeDisplay.js:554
msgid "PLACES & DEVICES"
msgstr "Mesta in naprave"
#. **** Documents ****
#: ../js/ui/dash.js:804
#: ../js/ui/docDisplay.js:494
msgid "RECENT ITEMS"
msgstr "Nedavni predmeti"
@ -339,7 +307,10 @@ msgstr "Ni nameščenih razširitev"
msgid "Enabled"
msgstr "Omogočeno"
#. translators:
#. * The device has been disabled
#: ../js/ui/lookingGlass.js:591
#: ../src/gvc/gvc-mixer-control.c:1087
msgid "Disabled"
msgstr "Onemogočeno"
@ -359,63 +330,63 @@ msgstr "Poglej vir"
msgid "Web Page"
msgstr "Spletna stran"
#: ../js/ui/overview.js:160
#: ../js/ui/overview.js:112
msgid "Undo"
msgstr "Razveljavi"
#. TODO - _quit() doesn't really work on apps in state STARTING yet
#: ../js/ui/panel.js:469
#: ../js/ui/panel.js:470
#, c-format
msgid "Quit %s"
msgstr "Končaj %s"
#: ../js/ui/panel.js:494
#: ../js/ui/panel.js:495
msgid "Preferences"
msgstr "Možnosti"
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:580
#: ../js/ui/panel.js:581
msgid "%a %b %e, %R:%S"
msgstr "%a. %e. %b., %R:%S"
#: ../js/ui/panel.js:581
#: ../js/ui/panel.js:582
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:585
#: ../js/ui/panel.js:586
msgid "%a %R:%S"
msgstr "%a. %R:%S"
#: ../js/ui/panel.js:586
#: ../js/ui/panel.js:587
msgid "%a %R"
msgstr "%a. %R"
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:593
#: ../js/ui/panel.js:594
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a. %e. %b., %H:%M:%S"
#: ../js/ui/panel.js:594
#: ../js/ui/panel.js:595
msgid "%a %b %e, %l:%M %p"
msgstr "%a. %e. %b., %H:%M"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:598
#: ../js/ui/panel.js:599
msgid "%a %l:%M:%S %p"
msgstr "%a, %H:%M:%S"
#: ../js/ui/panel.js:599
#: ../js/ui/panel.js:600
msgid "%a %l:%M %p"
msgstr "%a, %H:%M"
#. 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:744
#: ../js/ui/panel.js:745
msgid "Activities"
msgstr "Dejavnosti"
@ -432,6 +403,10 @@ msgstr "Poskusi znova"
msgid "Connect to..."
msgstr "Povezava z ..."
#: ../js/ui/placeDisplay.js:558
msgid "PLACES & DEVICES"
msgstr "Mesta in naprave"
#. Translators: this MUST be either "toggle-switch-us"
#. (for toggle switches containing the English words
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
@ -458,42 +433,38 @@ msgstr "Na voljo"
msgid "Busy"
msgstr "Zaposleno"
#: ../js/ui/statusMenu.js:111
msgid "Invisible"
msgstr "Nevidno"
#: ../js/ui/statusMenu.js:114
msgid "My Account"
msgstr "Račun"
#: ../js/ui/statusMenu.js:119
msgid "My Account..."
msgstr "Račun ..."
#: ../js/ui/statusMenu.js:118
msgid "System Settings"
msgstr "Sistemske nastavitve"
#: ../js/ui/statusMenu.js:123
msgid "System Preferences..."
msgstr "Sistemske možnosti ..."
#: ../js/ui/statusMenu.js:130
#: ../js/ui/statusMenu.js:125
msgid "Lock Screen"
msgstr "Zakleni zaslon"
#: ../js/ui/statusMenu.js:134
#: ../js/ui/statusMenu.js:129
msgid "Switch User"
msgstr "Preklopi uporabnika"
#: ../js/ui/statusMenu.js:139
#: ../js/ui/statusMenu.js:134
msgid "Log Out..."
msgstr "Odjava ..."
#: ../js/ui/statusMenu.js:146
msgid "Suspend"
msgstr "V mirovanje"
#: ../js/ui/statusMenu.js:141
msgid "Suspend..."
msgstr "V pripravljenost"
#: ../js/ui/statusMenu.js:150
msgid "Restart..."
msgstr "Ponoven zagon ..."
#: ../js/ui/statusMenu.js:154
#: ../js/ui/statusMenu.js:145
msgid "Shut Down..."
msgstr "Izklopi ..."
#: ../js/ui/status/accessibility.js:82
msgid "Zoom"
msgstr "Približanje"
#: ../js/ui/status/accessibility.js:88
msgid "Screen Reader"
msgstr "Zaslonski bralnik"
@ -530,13 +501,122 @@ msgstr "Splošne nastavitve dostopa"
msgid "High Contrast"
msgstr "Visok kontrast"
#: ../js/ui/status/accessibility.js:202
#: ../js/ui/status/accessibility.js:205
msgid "Large Text"
msgstr "Veliko besedilo"
#: ../js/ui/status/accessibility.js:223
msgid "Zoom"
msgstr "Približanje"
#: ../js/ui/status/power.js:87
msgid "What's using power..."
msgstr "Kaj porablja napetost ..."
#: ../js/ui/status/power.js:90
msgid "Power Settings"
msgstr "Upravljanje napajanja"
#: ../js/ui/status/power.js:117
#, c-format
msgid "%d hour remaining"
msgid_plural "%d hours remaining"
msgstr[0] "preostaja še %d ur"
msgstr[1] "preostaja še %d ura"
msgstr[2] "preostajata še %d uri"
msgstr[3] "preostajajo še %d ure"
#. TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining"
#: ../js/ui/status/power.js:120
#, c-format
msgid "%d %s %d %s remaining"
msgstr "Preostaja še %d %s %d %s"
#: ../js/ui/status/power.js:122
msgid "hour"
msgid_plural "hours"
msgstr[0] "ur"
msgstr[1] "ura"
msgstr[2] "uri"
msgstr[3] "ure"
#: ../js/ui/status/power.js:122
msgid "minute"
msgid_plural "minutes"
msgstr[0] "minut"
msgstr[1] "minuta"
msgstr[2] "minuti"
msgstr[3] "minute"
#: ../js/ui/status/power.js:125
#, c-format
msgid "%d minute remaining"
msgid_plural "%d minutes remaining"
msgstr[0] "preostaja še %d minut"
msgstr[1] "preostaja še %d minuta"
msgstr[2] "preostajata še %d minuti"
msgstr[3] "preostajajo še %d minute"
#: ../js/ui/status/power.js:244
msgid "AC adapter"
msgstr "Električni prilagodilnik"
#: ../js/ui/status/power.js:246
msgid "Laptop battery"
msgstr "Baterija prenosnika"
#: ../js/ui/status/power.js:248
msgid "UPS"
msgstr "UPS"
#: ../js/ui/status/power.js:250
msgid "Monitor"
msgstr "Zaslon"
#: ../js/ui/status/power.js:252
msgid "Mouse"
msgstr "Miška"
#: ../js/ui/status/power.js:254
msgid "Keyboard"
msgstr "Tipkovnica"
#: ../js/ui/status/power.js:256
msgid "PDA"
msgstr "Dlančnik"
#: ../js/ui/status/power.js:258
msgid "Cell phone"
msgstr "Mobilni telefon"
#: ../js/ui/status/power.js:260
msgid "Media player"
msgstr "Predstavni predvajalnik"
#: ../js/ui/status/power.js:262
msgid "Tablet"
msgstr "Tablični računalnik"
#: ../js/ui/status/power.js:264
msgid "Computer"
msgstr "Računalnik"
#: ../js/ui/status/power.js:266
#: ../src/shell-app-system.c:1012
msgid "Unknown"
msgstr "Neznano"
#: ../js/ui/status/volume.js:41
msgid "Volume"
msgstr "Glasnost"
#: ../js/ui/status/volume.js:54
msgid "Microphone"
msgstr "Mikrofon"
#: ../js/ui/status/volume.js:62
msgid "Sound Settings"
msgstr "Nastavitve zvoka"
#: ../js/ui/viewSelector.js:26
msgid "Search your computer"
msgstr "Iskanje po računalniku"
#: ../js/ui/windowAttentionHandler.js:43
#, c-format
@ -548,19 +628,45 @@ msgstr "%s je končal začenjanje"
msgid "'%s' is ready"
msgstr "'%s' storitev je pripravljena"
#: ../js/ui/workspacesView.js:229
#: ../js/ui/workspacesView.js:244
msgid "Can't add a new workspace because maximum workspaces limit has been reached."
msgstr "Ni mogoče dodati nove delovne površine, ker je doseženo njihovo največje dovoljeno število."
#: ../js/ui/workspacesView.js:246
#: ../js/ui/workspacesView.js:260
msgid "Can't remove the first workspace."
msgstr "Ni mogoče odstraniti prve delovne površine."
#: ../src/shell-global.c:1204
#. translators:
#. * The number of sound outputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1094
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] "%u odvodov naprave"
msgstr[1] "%u odvod naprave"
msgstr[2] "%u odvoda naprave"
msgstr[3] "%u odvodi naprave"
#. translators:
#. * The number of sound inputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1104
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] "%u dovodov naprave"
msgstr[1] "%u dovod naprave"
msgstr[2] "%u dovoda naprave"
msgstr[3] "%u dovodi naprave"
#: ../src/gvc/gvc-mixer-control.c:1402
msgid "System Sounds"
msgstr "Sistemski zvoki"
#: ../src/shell-global.c:1155
msgid "Less than a minute ago"
msgstr "Pred manj kot eno minuto"
#: ../src/shell-global.c:1208
#: ../src/shell-global.c:1159
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
@ -569,7 +675,7 @@ msgstr[1] "Pred %d minuto"
msgstr[2] "Pred %d minutama"
msgstr[3] "Pred %d minutami"
#: ../src/shell-global.c:1213
#: ../src/shell-global.c:1164
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
@ -578,7 +684,7 @@ msgstr[1] "Pred %d uro"
msgstr[2] "Pred %d urama"
msgstr[3] "Pred %d urami"
#: ../src/shell-global.c:1218
#: ../src/shell-global.c:1169
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
@ -587,7 +693,7 @@ msgstr[1] "Pred %d dnevom"
msgstr[2] "Pred %d dnevoma"
msgstr[3] "Pred %d dnevi"
#: ../src/shell-global.c:1223
#: ../src/shell-global.c:1174
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
@ -596,17 +702,17 @@ msgstr[1] "Pred %d tednom"
msgstr[2] "Pred %d tednoma"
msgstr[3] "Pred %d tedni"
#: ../src/shell-uri-util.c:89
#: ../src/shell-util.c:89
msgid "Home Folder"
msgstr "Domača mapa"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:104
#: ../src/shell-util.c:104
msgid "File System"
msgstr "Datotečni sistem"
#: ../src/shell-uri-util.c:250
#: ../src/shell-util.c:250
msgid "Search"
msgstr "Poišči"
@ -615,15 +721,35 @@ msgstr "Poišči"
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:300
#: ../src/shell-util.c:300
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Overview workspace view mode"
#~ msgstr "Način pregleda predogleda delovnih površin"
#~ msgid ""
#~ "The selected workspace view mode in the overview. Supported values are "
#~ "\"single\" and \"grid\"."
#~ msgstr ""
#~ "Izbrani pogled delovnih površin v predogledu. Podprte vrednosti sta "
#~ "\"enojno\" in \"mrežno\"."
#~ msgid "Drag here to add favorites"
#~ msgstr "S potegom na to mesto se izbor doda med priljubljene"
#~ msgid "Find"
#~ msgstr "Najdi"
#~ msgid "Searching..."
#~ msgstr "Iskanje ..."
#~ msgid "No matching results."
#~ msgstr "Ni zadetkov iskanja"
#~ msgid "Invisible"
#~ msgstr "Nevidno"
#~ msgid "System Preferences..."
#~ msgstr "Sistemske možnosti ..."
#~ msgid "Restart..."
#~ msgstr "Ponoven zagon ..."
#~ msgid "Account Information..."
#~ msgstr "Podrobnosti računa ..."
#~ msgid "System Settings..."
#~ msgstr "Sistemske nastavitve ..."
#~ msgid "ON"
#~ msgstr "⚪"
#~ msgid "OFF"
@ -640,8 +766,6 @@ msgstr "%1$s: %2$s"
#~ msgstr "Mesta"
#~ msgid "SEARCH RESULTS"
#~ msgstr "Rezultati iskanja"
#~ msgid "Unknown"
#~ msgstr "Neznano"
#~ msgid "Can't lock screen: %s"
#~ msgstr "Ni mogoče zakleniti zaslona: %s"
#~ msgid "Can't temporarily set screensaver to blank screen: %s"

765
po/sv.po

File diff suppressed because it is too large Load Diff

544
po/ta.po
View File

@ -6,17 +6,17 @@
msgid ""
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: 2010-08-04 19:41+0000\n"
"PO-Revision-Date: 2010-08-05 21:37+0530\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-11-30 14:13+0530\n"
"PO-Revision-Date: 2010-12-01 12:57+0530\n"
"Last-Translator: Dr.T.Vasudevan <agnihot3@gmail.com>\n"
"Language-Team: Tamil <<Ubuntu-l10n-tam@lists.ubuntu.com>>\n"
"Language-Team: Tamil <kde-i18n-doc@kde.org>\n"
"Language: ta\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: Lokalize 1.0\n"
"X-Generator: Lokalize 1.1\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
@ -39,8 +39,8 @@ msgid ""
"Allows access to internal debugging and monitoring tools using the Alt-F2 "
"dialog."
msgstr ""
"உள்ளமை வழி நீக்கம் மற்றும் Alt-F2 உரையாடல் மூலம் கருவிகள் கண்காணிப்பு "
"ஆகியவற்றை அணுக உதவும்."
"உள்ளமை வழி நீக்கம் மற்றும் Alt-F2 உரையாடல் மூலம் கருவிகள் கண்காணிப்பு ஆகியவற்றை அணுக "
"உதவும்."
#: ../data/org.gnome.shell.gschema.xml.in.h:2
msgid "Custom format of the clock"
@ -49,8 +49,8 @@ msgstr "கடிகாரத்தின் தனிப்பயன் வட
#: ../data/org.gnome.shell.gschema.xml.in.h:3
msgid "Enable internal tools useful for developers and testers from Alt-F2"
msgstr ""
"உருவாக்குவோர் மற்றூம் சோதிப்போருக்கு பயன்படுமாறு Alt-F2 வழியாக உள்ளமை "
"கருவிகளை செயலாக்கு"
"உருவாக்குவோர் மற்றூம் சோதிப்போருக்கு பயன்படுமாறு Alt-F2 வழியாக உள்ளமை கருவிகளை "
"செயலாக்கு"
#: ../data/org.gnome.shell.gschema.xml.in.h:4
msgid "File extension used for storing the screencast"
@ -65,8 +65,8 @@ msgid ""
"GNOME Shell extensions have a uuid property; this key lists extensions which "
"should not be loaded."
msgstr ""
"க்னோம் ஷெல் நீட்சிகளுக்கு ஒரு யூயூஐடி பண்பு உண்டு. இந்த விசை எந்த நீட்சிகள் "
"ஏற்றப்பட வேண்டும் என பட்டியலிடுகிறது."
"க்னோம் ஷெல் நீட்சிகளுக்கு ஒரு யூயூஐடி பண்பு உண்டு. இந்த விசை எந்த நீட்சிகள் ஏற்றப்பட வேண்டும் "
"என பட்டியலிடுகிறது."
#: ../data/org.gnome.shell.gschema.xml.in.h:7
msgid "History for command (Alt-F2) dialog"
@ -81,8 +81,8 @@ msgid ""
"If true and format is either \"12-hour\" or \"24-hour\", display date in the "
"clock, in addition to time."
msgstr ""
"உண்மையெனில், அமைப்பு \"12 மணி\" அல்லது \"24 மணி\" என இருப்பின் நேரத்துடன் "
"நாளையும் காட்டு"
"உண்மையெனில், அமைப்பு \"12 மணி\" அல்லது \"24 மணி\" என இருப்பின் நேரத்துடன் நாளையும் "
"காட்டு"
#: ../data/org.gnome.shell.gschema.xml.in.h:10
msgid ""
@ -101,10 +101,6 @@ msgid "List of desktop file IDs for favorite applications"
msgstr "விருப்ப பயன்பாடுகளுக்கு மேல்மேசை கோப்பு அடையாளங்கள்."
#: ../data/org.gnome.shell.gschema.xml.in.h:13
msgid "Overview workspace view mode"
msgstr "பணி இட மேல்பார்வை காட்சிப் பாங்கு."
#: ../data/org.gnome.shell.gschema.xml.in.h:14
msgid ""
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
"used for gst-launch. The pipeline should have an unconnected sink pad where "
@ -115,93 +111,76 @@ msgid ""
"to an empty value, the default pipeline will be used. This is currently "
"'videorate ! theoraenc ! oggmux' and records to Ogg Theora."
msgstr ""
"பதிவுகளை குறியாக்க ஜிஸ்ட்ரீமர் குழாயை அமைக்கிறது. ஜிஎஸ்டி லான்ஸ் க்கு "
"பயன்படும் அதே இலக்கணத்தை பின் பற்றும். குழாய்க்கு இணைப்பில்லா பதிவுக்குழி "
"இருத்தல் வேண்டும். இதில் விடியோ பதிவாகும். சாதாரணமாக இதில் ஒரு மூல பதிவேடு "
"இருக்கும்; இதன் வெளியீடு வெளியீட்டு கோப்பாக பதிவாகும். எனினும் குழாய் தன் "
"வெளியீட்டை தானே கவனித்துக்கொள்ள இயலும். இது வெளியீட்டை ஐஸ்காஸ்ட் அல்லது "
"ஷௌட்2சென்ட் போன்றவற்றுக்கு நேரடியாக அனுப்ப இயலும். அமைப்பை அன்செட் "
"செய்தாலல்லது காலி மதிப்புக்கு அமைத்தாலும் முன்னிருப்பு குழாய் "
"பயன்படுத்தப்படும். நடப்பில் இது 'விடியோரேட்!தியோரேங்க்!ஆக்மக்ஸ்' ஆகும்; இது "
"ஆக் தியோராவுக்கு பதிவுசெய்யும்."
"பதிவுகளை குறியாக்க ஜிஸ்ட்ரீமர் குழாயை அமைக்கிறது. ஜிஎஸ்டி லான்ஸ் க்கு பயன்படும் அதே "
"இலக்கணத்தை பின் பற்றும். குழாய்க்கு இணைப்பில்லா பதிவுக்குழி இருத்தல் வேண்டும். இதில் விடியோ "
"பதிவாகும். சாதாரணமாக இதில் ஒரு மூல பதிவேடு இருக்கும்; இதன் வெளியீடு வெளியீட்டு "
"கோப்பாக பதிவாகும். எனினும் குழாய் தன் வெளியீட்டை தானே கவனித்துக்கொள்ள இயலும். இது "
"வெளியீட்டை ஐஸ்காஸ்ட் அல்லது ஷௌட்2சென்ட் போன்றவற்றுக்கு நேரடியாக அனுப்ப இயலும். அமைப்பை "
"அன்செட் செய்தாலல்லது காலி மதிப்புக்கு அமைத்தாலும் முன்னிருப்பு குழாய் பயன்படுத்தப்படும். "
"நடப்பில் இது 'விடியோரேட்!தியோரேங்க்!ஆக்மக்ஸ்' ஆகும்; இது ஆக் தியோராவுக்கு பதிவுசெய்யும்."
#: ../data/org.gnome.shell.gschema.xml.in.h:15
#: ../data/org.gnome.shell.gschema.xml.in.h:14
msgid "Show date in clock"
msgstr "தேதியை கடிகாரத்தில் காட்டுக"
#: ../data/org.gnome.shell.gschema.xml.in.h:16
#: ../data/org.gnome.shell.gschema.xml.in.h:15
msgid "Show the week date in the calendar"
msgstr "நாட்காட்டியில் வார நாளை காட்டவும்"
#: ../data/org.gnome.shell.gschema.xml.in.h:17
#: ../data/org.gnome.shell.gschema.xml.in.h:16
msgid "Show time with seconds"
msgstr "நொடிகளுடன் நேரம் காட்டுக"
#: ../data/org.gnome.shell.gschema.xml.in.h:18
#: ../data/org.gnome.shell.gschema.xml.in.h:17
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
msgstr ""
"இந்த அடையாளங் காட்டிகளுக்கு பொருத்தமான பயன்பாடுகள் விருப்ப இடத்தில் "
"காட்டப்படும்."
msgstr "இந்த அடையாளங் காட்டிகளுக்கு பொருத்தமான பயன்பாடுகள் விருப்ப இடத்தில் காட்டப்படும்."
#: ../data/org.gnome.shell.gschema.xml.in.h:19
#: ../data/org.gnome.shell.gschema.xml.in.h:18
msgid ""
"The filename for recorded screencasts will be a unique filename based on the "
"current date, and use this extension. It should be changed when recording to "
"a different container format."
msgstr ""
"ஸ்க்ரீன்காஸ்ட் இல் பதிவாவனக்கான கோப்புப்பெயர் தனித்தன்மை வாய்ந்தது. இது "
"நடப்பு தேதியை அடிப்படையாக கொண்டது; இந்த பின்னொட்டை பயன்படுத்தும். பதிவதை "
"வேறு கொள்கலத்தின் ஒழுங்கில் மாற்றுகையில் இதையும் மாற்ற வேண்டும்."
"ஸ்க்ரீன்காஸ்ட் இல் பதிவாவனக்கான கோப்புப்பெயர் தனித்தன்மை வாய்ந்தது. இது நடப்பு தேதியை "
"அடிப்படையாக கொண்டது; இந்த பின்னொட்டை பயன்படுத்தும். பதிவதை வேறு கொள்கலத்தின் ஒழுங்கில் "
"மாற்றுகையில் இதையும் மாற்ற வேண்டும்."
#: ../data/org.gnome.shell.gschema.xml.in.h:20
#: ../data/org.gnome.shell.gschema.xml.in.h:19
msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames-per-second."
msgstr ""
"க்னோம்ஷெல் இன் ஸ்க்ரீன்காஸ்ட் பதிவரில் ஸ்க்ரீன்காட் ஐ பதிகையில் வினாடிக்கு "
"சட்டங்களின் விகிதம்."
"க்னோம்ஷெல் இன் ஸ்க்ரீன்காஸ்ட் பதிவரில் ஸ்க்ரீன்காட் ஐ பதிகையில் வினாடிக்கு சட்டங்களின் விகிதம்."
#: ../data/org.gnome.shell.gschema.xml.in.h:21
#: ../data/org.gnome.shell.gschema.xml.in.h:20
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "ஸ்க்ரீன்காஸ்டை குறியாக்க பயனாகும் ஜிஸ்ட்ரீமர் குழாய்."
#: ../data/org.gnome.shell.gschema.xml.in.h:22
msgid ""
"The selected workspace view mode in the overview. Supported values are "
"\"single\" and \"grid\"."
msgstr ""
"மேல்பார்வையில் தேர்ந்தெடுத்த பணீட காட்சி பாங்கு. ஆதரவுள்ள மதிப்புகள் 'ஒன்று' "
"மற்றும் 'வலை'"
#: ../data/org.gnome.shell.gschema.xml.in.h:23
#: ../data/org.gnome.shell.gschema.xml.in.h:21
msgid ""
"The shell normally monitors active applications in order to present the most "
"used ones (e.g. in launchers). While this data will be kept private, you may "
"want to disable this for privacy reasons. Please note that doing so won't "
"remove already saved data."
msgstr ""
"ஷெல் சாதாரணமாக செயலிலுள்ள நிரல்களை மேற்பார்வை இடுகிறது. அதனால் அடிக்கடி "
"பயனாகும் நிரல்கள் (எ-டு: துவக்கிகள்) முன் வைக்கப்படும். இந்த தரவு "
"அந்தரங்கமாக வைக்கப்பட்டாலும் நீங்கள் இதை நீக்க விரும்பலாம். அப்படிச் செய்வது "
"முன்னே சேகரித்த தரவை நீக்காஅது என் அறியவும்."
"ஷெல் சாதாரணமாக செயலிலுள்ள நிரல்களை மேற்பார்வை இடுகிறது. அதனால் அடிக்கடி பயனாகும் "
"நிரல்கள் (எ-டு: துவக்கிகள்) முன் வைக்கப்படும். இந்த தரவு அந்தரங்கமாக வைக்கப்பட்டாலும் நீங்கள் "
"இதை நீக்க விரும்பலாம். அப்படிச் செய்வது முன்னே சேகரித்த தரவை நீக்காஅது என் அறியவும்."
#: ../data/org.gnome.shell.gschema.xml.in.h:24
#: ../data/org.gnome.shell.gschema.xml.in.h:22
msgid ""
"This key specifies the format used by the panel clock when the format key is "
"set to \"custom\". You can use conversion specifiers understood by strftime"
"() to obtain a specific format. See the strftime() manual for more "
"information."
msgstr ""
"வடிவமைப்பு விசை \"தனிப்பயன்\" என்று அமைக்கப்படும் போது பலக கடிகாரம் இந்த "
"விசையை "
"பயன்படுத்தும். குறிப்பிட்ட அமைப்பை பெற்றுக்கொள்ள strftime() ஆல் "
"புரிந்துகொள்ளக்கூடிய மாற்று "
"குறிப்புகளை தரவும். மேலும் அதிக விவரங்களுக்கு strftime() கையேட்டை "
"பார்க்கவும்."
"வடிவமைப்பு விசை \"தனிப்பயன்\" என்று அமைக்கப்படும் போது பலக கடிகாரம் இந்த விசையை "
"பயன்படுத்தும். குறிப்பிட்ட அமைப்பை பெற்றுக்கொள்ள strftime() ஆல் புரிந்துகொள்ளக்கூடிய "
"மாற்று குறிப்புகளை தரவும். மேலும் அதிக விவரங்களுக்கு strftime() கையேட்டை பார்க்கவும்."
#: ../data/org.gnome.shell.gschema.xml.in.h:25
#: ../data/org.gnome.shell.gschema.xml.in.h:23
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\", "
@ -211,21 +190,159 @@ msgid ""
"the show_date and show_seconds keys are ignored."
msgstr ""
"இந்த விசை பலக கடிகாரம் பயன்படுத்த வேண்டிய மணி ஒழுங்கை குறிக்கிறது. தரக்கூடிய "
"மதிப்புகள் \"12-மணி\", \"24-மணி\", \"யூனிக்ஸ்\" மற்றும் \"தனிப்பயன்\". "
"\"யூனிக்ஸ்\" எனில் அது எபோக் அதாவது 1970-01-01 முதல் நடந்த காலத்தை "
"வினாடிகளில் காட்டும். \"தனிப்பயன்\" எனில் தனிப்பயன்_ஒழுங்கு இல் காட்டப்பட்ட "
"ஒழுங்கில் நேரத்தைக் காட்டும். \"யூனிக்ஸ்\" அல்லது \"தனிப்பயன்\" என "
"மைக்கும்போது தேதி_காட்டு, வினாடிகளை_காட்டு விசைகள் உதாசீனப்படுத்தப்படும் என "
"அறிக."
"மதிப்புகள் \"12-மணி\", \"24-மணி\", \"யூனிக்ஸ்\" மற்றும் \"தனிப்பயன்\". \"யூனிக்ஸ்\" "
"எனில் அது எபோக் அதாவது 1970-01-01 முதல் நடந்த காலத்தை வினாடிகளில் காட்டும். \"தனிப்பயன்"
"\" எனில் தனிப்பயன்_ஒழுங்கு இல் காட்டப்பட்ட ஒழுங்கில் நேரத்தைக் காட்டும். \"யூனிக்ஸ்\" அல்லது "
"\"தனிப்பயன்\" என மைக்கும்போது தேதி_காட்டு, வினாடிகளை_காட்டு விசைகள் "
"உதாசீனப்படுத்தப்படும் என அறிக."
#: ../data/org.gnome.shell.gschema.xml.in.h:26
#: ../data/org.gnome.shell.gschema.xml.in.h:24
msgid "Uuids of extensions to disable"
msgstr "செயல்நீக்க வேண்டிய நீட்சிகளின் யூயூஐடிக்கள்."
#: ../data/org.gnome.shell.gschema.xml.in.h:27
#: ../data/org.gnome.shell.gschema.xml.in.h:25
msgid "Whether to collect stats about applications usage"
msgstr "நிரல்களின் பயன்பாடு குறித்த புள்ளிவிவரம் சேகரிக்க வேண்டுமா"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:1
msgid "Clip the crosshairs at the center"
msgstr "குறுக்கு இழைகளை மையத்தில் வெட்டிவிடுக"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:2
msgid "Color of the crosshairs"
msgstr "குறுக்கு இழைகளின் நிறம்"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:3
msgid ""
"Determines the length of the vertical and horizontal lines that make up the "
"crosshairs."
msgstr "குறுக்கு இழைகளை சொடுக்கியின் அடையாளத்தில் மையப்படுத்தி காட்டுகிறது/ மறைக்கிறது"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:4
msgid ""
"Determines the position of the magnified mouse image within the magnified "
"view and how it reacts to system mouse movement. The values are - none: no "
"mouse tracking; - centered: the mouse image is displayed at the center of "
"the zoom region (which also represents the point under the system mouse) and "
"the magnified contents are scrolled as the system mouse moves; - "
"proportional: the position of the magnified mouse in the zoom region is "
"proportionally the same as the position of the system mouse on screen; - "
"push: when the magnified mouse intersects a boundary of the zoom region, the "
"contents are scrolled into view."
msgstr ""
"பெரிதாக்கப்பட்ட காட்சியில் பெரிதாக்கப்பட்ட சொடுக்கியின் பிம்பம் எங்கு இருக்க வேண்டும், அது "
"கணினி சொடுக்கி நகர்தலுடன் எப்படி நகர வேண்டும் என நிர்ணயிக்கிறது. மதிப்புகள் - ஏதுமில்லை: "
"சொடுக்கி தடம் தொடரப்பட மாட்டாது; -மையம்: சொடுக்கி பிம்பம் பெரிதாக்கப்பட்ட இடத்தின் மையத்தில் "
"காட்டப்படும் (இது சொடுக்கியின் கீழ் காணப்படும் இடம்தான்) பெரிதாக்கப்பட்ட பிம்பம் சொடுக்கி "
"நகரும் திசையின் தானும் நகரும்; - விகிதாசாரம்: அணுகல் பரப்பில் உள்ள பெரிதாக்கபட்ட சொடுக்கியின் "
"இடம் திரையில் விகிதாசாரப்படி கணினி சொடுக்கி இருக்கும் அதே இடம்தான்; - தள்ளு: பெரிதாக்கப்பட்ட "
"சொடுக்கி அணுகல் பரப்பின் விளிம்புக்கு வருமானால் அடக்கங்கள் உருண்டு பார்வைக்கு வரும்."
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:5
msgid ""
"Determines the transparency of the crosshairs, from fully opaque to fully "
"transparent."
msgstr "குறுக்கு இழைகளின் ஊடுருவும் தனமியை முழு மறைப்பிலிருந்து முழு ஊடுருவல் வரை நிர்ணயிக்கிறது"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:6
msgid ""
"Determines whether the crosshairs intersect the magnified mouse sprite, or "
"are clipped such that the ends of the horizontal and vertical lines surround "
"the mouse image."
msgstr ""
"குறுக்கு இழைகளை சொடுக்கியின் அடையாளத்தில் மையப்படுத்தி காட்டுவதா அல்லது செங்குத்து கிடை மட்ட "
"கோடுகளின் முனைகள் சொடுக்கி அடையாளத்தை சூழ்ந்து இருப்பதாக வெட்டுவதா என நிர்ணயிக்கிறது."
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:7
msgid "Enable lens mode"
msgstr "பூத கண்ணாடி முறைமையை செயல்படுத்து"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:8
msgid ""
"Enables/disables display of crosshairs centered on the magnified mouse "
"sprite."
msgstr "குறுக்கு இழைகளை சொடுக்கியின் அடையாளத்தில் மையப்படுத்தி காட்டுகிறது/ மறைக்கிறது"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:9
msgid ""
"For centered mouse tracking, when the system pointer is at or near the edge "
"of the screen, the magnified contents continue to scroll such that the "
"screen edge moves into the magnified view."
msgstr ""
"மையப்படுத்திய சொடுக்கி தடம் தொடர்வதில், கணினியின் சுட்டி திரையின் விளிம்பில் அல்லது அதன் "
"அருகில் இர்ந்தால், பெரிதாக்கப்பட்ட உள்ளடக்கங்கள் உருண்டு திரையின் விளிம்பு பெரிதாக்கப்பட்ட "
"பார்வைக்கு வரும்."
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:10
msgid "Length of the crosshairs"
msgstr "குறுக்கு இழைகளின் நீளம்"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:11
msgid "Magnification factor"
msgstr "உருபெருக்க விகிதம்"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:12
msgid "Mouse Tracking Mode"
msgstr "சொடுக்கி தொடர்வு பாங்கு"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:13
msgid "Opacity of the crosshairs"
msgstr "குறுக்கிழைகள் இன் ஒளிபுகாதன்மை"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:14
msgid "Screen position"
msgstr "திரை நிலை"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:15
msgid "Scroll magnified contents beyond the edges of the desktop"
msgstr "மேல்மேசையின் விளிம்புகளுக்கு வெளீயே இருக்கும் அடக்கத்தை உருளை மூலம் காட்டு"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:16
msgid "Show or hide crosshairs"
msgstr "குறுக்கிழைகள் காட்டு அல்லது மறை"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:17
msgid "Show or hide the magnifier"
msgstr "உருப்பெருக்கியை காட்டு அல்லது மறை"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:18
msgid "Show or hide the magnifier and all of its zoom regions."
msgstr "உருப்பெருக்கி மற்றும் அதன் அணுகல் வட்டாரங்களை காட்டு அல்லது மறை"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:19
msgid ""
"The color of the the vertical and horizontal lines that make up the "
"crosshairs."
msgstr "குறுக்கு இழைகளின் செங்குத்து , கிடைமட்ட கோடுகளின் நிறம்"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:20
msgid ""
"The magnified view either fills the entire screen, or occupies the top-half, "
"bottom-half, left-half, or right-half of the screen."
msgstr ""
"பெரிதாக்கப்பட்ட காட்சி முழுத்திரையயும் ஆக்ரமிக்கலாம் அல்லது மேல் பாதி, கீழ் பாதி, வலது பாதி, "
"இடது பாதி என இருக்கலாம்."
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:21
msgid ""
"The power of the magnification. A value of 1.0 means no magnification. A "
"value of 2.0 doubles the size."
msgstr "பெரிதாக்கும் அளவு. 1.0 எனில் பெரிதாக்கம் இல்லை. மதிப்பு 2.0 எனில் இரண்டு மடங்கு."
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:22
msgid "Thickness of the crosshairs"
msgstr "குறுக்கிழைகளின் தடிமன்"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:23
msgid ""
"Whether the magnified view should be centered over the location of the "
"system mouse and move with it."
msgstr "பெரிதாக்கிய காட்சியின் மையம் சொடுக்கியின் இடத்தில் இருந்து கொண்டு அதனுடன் நகர வேண்டுமா/"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:24
msgid "Width of the vertical and horizontal lines that make up the crosshairs."
msgstr "குறுக்கு இழைகளின் செங்குத்து , கிடைமட்ட கோடுகளின் அகலம்"
#: ../data/clock-preferences.ui.h:1
msgid "Clock Format"
msgstr "கடிகார வடிவம்"
@ -254,177 +371,159 @@ msgstr "_12 மணி வடிவமைப்பு"
msgid "_24 hour format"
msgstr "_24 மணி வடிவமைப்பு"
#. **** Applications ****
#: ../js/ui/appDisplay.js:384 ../js/ui/dash.js:776
#: ../js/ui/appDisplay.js:215
msgid "APPLICATIONS"
msgstr "பயன்பாடுகள்"
#: ../js/ui/appDisplay.js:416
#: ../js/ui/appDisplay.js:245
msgid "PREFERENCES"
msgstr "விருப்பங்கள்"
#: ../js/ui/appDisplay.js:721
#: ../js/ui/appDisplay.js:538
msgid "New Window"
msgstr "புதிய சாளரம்"
#: ../js/ui/appDisplay.js:725
#: ../js/ui/appDisplay.js:542
msgid "Remove from Favorites"
msgstr "விருப்பத்தில் இருந்து நீக்கு"
#: ../js/ui/appDisplay.js:726
#: ../js/ui/appDisplay.js:543
msgid "Add to Favorites"
msgstr "விருப்பங்களுக்கு சேர்"
#: ../js/ui/appDisplay.js:1033
msgid "Drag here to add favorites"
msgstr "விருப்பங்களுக்கு சேர்க்க இங்கு இழுத்துவிடு"
#: ../js/ui/appFavorites.js:88
#: ../js/ui/appFavorites.js:91
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s உங்கள் விருப்பங்களில் சேர்க்கப்பட்டது"
#: ../js/ui/appFavorites.js:107
#: ../js/ui/appFavorites.js:122
#, c-format
msgid "%s has been removed from your favorites."
msgstr "%s உங்கள் விருப்பங்களில் இருந்து நீக்கப்பட்டது"
#: ../js/ui/dash.js:142
msgid "Find"
msgstr "தேடு"
#: ../js/ui/dash.js:27
msgid "Remove"
msgstr "நீக்கு"
#: ../js/ui/dash.js:471
msgid "Searching..."
msgstr "தேடுகிறது..."
#: ../js/ui/dash.js:485
msgid "No matching results."
msgstr "பொருத்தமான விடைகள் இல்லை"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:795 ../js/ui/placeDisplay.js:550
msgid "PLACES & DEVICES"
msgstr "PLACES & DEVICES"
#. **** Documents ****
#: ../js/ui/dash.js:802 ../js/ui/docDisplay.js:494
#: ../js/ui/docDisplay.js:494
msgid "RECENT ITEMS"
msgstr "RECENT ITEMS"
#: ../js/ui/lookingGlass.js:471
#: ../js/ui/lookingGlass.js:552
msgid "No extensions installed"
msgstr "நீட்சிகள் ஏதும் நிறுவப்படவில்லை"
#: ../js/ui/lookingGlass.js:508
#: ../js/ui/lookingGlass.js:589
msgid "Enabled"
msgstr "செயலாக்கப்பட்டது"
#: ../js/ui/lookingGlass.js:510
#. translators:
#. * The device has been disabled
#: ../js/ui/lookingGlass.js:591 ../src/gvc/gvc-mixer-control.c:1087
msgid "Disabled"
msgstr "செயல்நீக்கப்பட்டது"
#: ../js/ui/lookingGlass.js:512
#: ../js/ui/lookingGlass.js:593
msgid "Error"
msgstr "பிழை"
#: ../js/ui/lookingGlass.js:514
#: ../js/ui/lookingGlass.js:595
msgid "Out of date"
msgstr "காலாவதியானது"
#: ../js/ui/lookingGlass.js:539
#: ../js/ui/lookingGlass.js:620
msgid "View Source"
msgstr "மூலத்தை பார்க்க"
#: ../js/ui/lookingGlass.js:545
#: ../js/ui/lookingGlass.js:626
msgid "Web Page"
msgstr "இணைய பக்கம்"
#: ../js/ui/overview.js:159
#: ../js/ui/overview.js:112
msgid "Undo"
msgstr "மறை"
#. TODO - _quit() doesn't really work on apps in state STARTING yet
#: ../js/ui/panel.js:473
#: ../js/ui/panel.js:470
#, c-format
msgid "Quit %s"
msgstr "%s லிருந்து வெளியேறு"
#: ../js/ui/panel.js:498
#: ../js/ui/panel.js:495
msgid "Preferences"
msgstr "விருப்பங்கள்"
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:584
#: ../js/ui/panel.js:581
msgid "%a %b %e, %R:%S"
msgstr "%a %b %e, %R:%S"
#: ../js/ui/panel.js:585
#: ../js/ui/panel.js:582
msgid "%a %b %e, %R"
msgstr "%a %b %e, %R"
#. Translators: This is the time format without date used
#. in 24-hour mode.
#: ../js/ui/panel.js:589
#: ../js/ui/panel.js:586
msgid "%a %R:%S"
msgstr "%a %R:%S"
#: ../js/ui/panel.js:590
#: ../js/ui/panel.js:587
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:597
#: ../js/ui/panel.js:594
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a %b %e, %l:%M:%S %p"
#: ../js/ui/panel.js:598
#: ../js/ui/panel.js:595
msgid "%a %b %e, %l:%M %p"
msgstr "%a %b %e, %l:%M %p"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:602
#: ../js/ui/panel.js:599
msgid "%a %l:%M:%S %p"
msgstr "%a %l:%M:%S %p"
#: ../js/ui/panel.js:603
#: ../js/ui/panel.js:600
msgid "%a %l:%M %p"
msgstr "%a %l:%M %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:741
#: ../js/ui/panel.js:745
msgid "Activities"
msgstr "செயல்பாடுகள்"
#: ../js/ui/placeDisplay.js:107
#: ../js/ui/placeDisplay.js:111
#, c-format
msgid "Failed to unmount '%s'"
msgstr "'%s' ஐ இறக்க முடியவில்லை"
#: ../js/ui/placeDisplay.js:110
#: ../js/ui/placeDisplay.js:114
msgid "Retry"
msgstr "மறு முயற்சி"
#: ../js/ui/placeDisplay.js:155
#: ../js/ui/placeDisplay.js:159
msgid "Connect to..."
msgstr "இணைக்கவும்..."
#. Translators: the "ON" and "OFF" strings are used in the
#. toggle switches in the status area menus, and must be SHORT.
#. If you don't have suitable short words, consider initials,
#. "0"/"1", "⚪"/"⚫", etc.
#: ../js/ui/popupMenu.js:30 ../js/ui/popupMenu.js:40
msgid "ON"
msgstr "இயக்கத்தில்"
#: ../js/ui/placeDisplay.js:558
msgid "PLACES & DEVICES"
msgstr "PLACES & DEVICES"
#: ../js/ui/popupMenu.js:31 ../js/ui/popupMenu.js:45
msgid "OFF"
msgstr "செயல் நீக்கு"
#. Translators: this MUST be either "toggle-switch-us"
#. (for toggle switches containing the English words
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
#. switches containing "◯" and "|"). Other values will
#. simply result in invisible toggle switches.
#: ../js/ui/popupMenu.js:33
msgid "toggle-switch-us"
msgstr "முறைமை-மாற்றி-யூஎஸ்"
#: ../js/ui/runDialog.js:233
msgid "Please enter a command:"
@ -435,106 +534,177 @@ msgstr "தயை செய்து ஒரு கட்டளையை உள
msgid "Execution of '%s' failed:"
msgstr "'%s' ஐ நிறைவேற்றுதல் தோல்வி அடைந்தது:"
#: ../js/ui/statusMenu.js:91
#: ../js/ui/statusMenu.js:101
msgid "Available"
msgstr "இருப்பவை"
#: ../js/ui/statusMenu.js:95
#: ../js/ui/statusMenu.js:106
msgid "Busy"
msgstr "வேலையில்"
#: ../js/ui/statusMenu.js:99
msgid "Invisible"
msgstr "பார்க்கமுடியாதது"
#: ../js/ui/statusMenu.js:114
msgid "My Account"
msgstr "என் கணக்கு"
#: ../js/ui/statusMenu.js:106
msgid "Account Information..."
msgstr "கணக்கு தகவல்..."
#: ../js/ui/statusMenu.js:118
msgid "System Settings"
msgstr "கணினி அமைப்புகள்"
#: ../js/ui/statusMenu.js:110
msgid "System Preferences..."
msgstr "கணினி முன்னுரிமைகள்..."
#: ../js/ui/statusMenu.js:117
#: ../js/ui/statusMenu.js:125
msgid "Lock Screen"
msgstr "திரையைப் பூட்டுக."
#: ../js/ui/statusMenu.js:121
#: ../js/ui/statusMenu.js:129
msgid "Switch User"
msgstr "பயனர் மாற்று"
#: ../js/ui/statusMenu.js:126
#: ../js/ui/statusMenu.js:134
msgid "Log Out..."
msgstr "வெளியேறு..."
#: ../js/ui/statusMenu.js:130
#: ../js/ui/statusMenu.js:141
msgid "Suspend..."
msgstr "இடைநிறுத்தம்..."
#: ../js/ui/statusMenu.js:145
msgid "Shut Down..."
msgstr "நிறுத்தவும்... "
#: ../js/ui/windowAttentionHandler.js:45
#: ../js/ui/status/accessibility.js:88
msgid "Screen Reader"
msgstr "திரைபடிப்பான்"
#: ../js/ui/status/accessibility.js:91
msgid "Screen Keyboard"
msgstr "திரை விசைப்பலகை"
#: ../js/ui/status/accessibility.js:94
msgid "Visual Alerts"
msgstr "காட்சி எச்சரிக்கைகள்"
#: ../js/ui/status/accessibility.js:97
msgid "Sticky Keys"
msgstr "ஒட்டு விசைகள்"
#: ../js/ui/status/accessibility.js:100
msgid "Slow Keys"
msgstr "மெது விசைகள்"
#: ../js/ui/status/accessibility.js:103
msgid "Bounce Keys"
msgstr "எதிரொலிப்பு விசைகள்"
#: ../js/ui/status/accessibility.js:106
msgid "Mouse Keys"
msgstr "சொடுக்கி விசைகள்"
#: ../js/ui/status/accessibility.js:110
msgid "Universal Access Settings"
msgstr "உலகளாவிய அணுகல் அமைப்பு"
#: ../js/ui/status/accessibility.js:163
msgid "High Contrast"
msgstr "அதிக முறண்"
#: ../js/ui/status/accessibility.js:205
msgid "Large Text"
msgstr "பெரிய உரை"
#: ../js/ui/status/accessibility.js:224
msgid "Zoom"
msgstr "பெரிதாக்கு"
#: ../js/ui/viewSelector.js:26
msgid "Search your computer"
msgstr "உங்கள் கணினியில் தேடுக"
#: ../js/ui/windowAttentionHandler.js:43
#, c-format
msgid "%s has finished starting"
msgstr "%s இன் துவக்கம் முடிந்துவிட்டது"
#: ../js/ui/windowAttentionHandler.js:47
#: ../js/ui/windowAttentionHandler.js:45
#, c-format
msgid "'%s' is ready"
msgstr "'%s' தயாராக உள்ளது"
#: ../js/ui/workspacesView.js:230
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
msgstr ""
"பணிக்களத்தை சேர்க்க முடியாது; ஏனெனில் பணிக்களங்களின் உச்ச வரம்பு "
"எட்டப்பட்டுவிட்டது."
#: ../js/ui/workspacesView.js:244
msgid "Can't add a new workspace because maximum workspaces limit has been reached."
msgstr "பணிக்களத்தை சேர்க்க முடியாது; ஏனெனில் பணிக்களங்களின் உச்ச வரம்பு எட்டப்பட்டுவிட்டது."
#: ../js/ui/workspacesView.js:247
#: ../js/ui/workspacesView.js:260
msgid "Can't remove the first workspace."
msgstr "முதல் பணிக்களத்தை நீக்க முடியாது"
#: ../src/shell-global.c:1105
#. translators:
#. * The number of sound outputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1094
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] "%u வெளிப்பாடு"
msgstr[1] "%u வெளிப்பாடுகள்"
#. translators:
#. * The number of sound inputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1104
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] "%u உள்ளீடு"
msgstr[1] "%u உள்ளீடுகள்"
#: ../src/gvc/gvc-mixer-control.c:1402
msgid "System Sounds"
msgstr "கணினி ஒலிகள்"
#: ../src/shell-app-system.c:1012
msgid "Unknown"
msgstr "தெரியாத"
#: ../src/shell-global.c:1163
msgid "Less than a minute ago"
msgstr "ஒரு நிமிடத்திற்கும் குறைவாக"
#: ../src/shell-global.c:1109
#: ../src/shell-global.c:1167
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d minutes ago"
msgstr[1] "%d நிமிடங்களுக்கு முன்"
#: ../src/shell-global.c:1114
#: ../src/shell-global.c:1172
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d மணிநேரத்துக்கு முன்"
msgstr[1] "%d மணிகள் முன்"
#: ../src/shell-global.c:1119
#: ../src/shell-global.c:1177
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d நாளைக்கு முன்"
msgstr[1] "%d நாட்களுக்கு முன்"
#: ../src/shell-global.c:1124
#: ../src/shell-global.c:1182
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d வாரம் முன்"
msgstr[1] "%d வாரங்கள் முன்"
#: ../src/shell-uri-util.c:89
#: ../src/shell-util.c:89
msgid "Home Folder"
msgstr "இல்ல அடைவு"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:104
#: ../src/shell-util.c:104
msgid "File System"
msgstr "கோப்பு அமைப்பு"
#: ../src/shell-uri-util.c:250
#: ../src/shell-util.c:250
msgid "Search"
msgstr "தேடு"
@ -543,8 +713,44 @@ msgstr "தேடு"
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:300
#: ../src/shell-util.c:300
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Overview workspace view mode"
#~ msgstr "பணி இட மேல்பார்வை காட்சிப் பாங்கு."
#~ msgid ""
#~ "The selected workspace view mode in the overview. Supported values are "
#~ "\"single\" and \"grid\"."
#~ msgstr ""
#~ "மேல்பார்வையில் தேர்ந்தெடுத்த பணீட காட்சி பாங்கு. ஆதரவுள்ள மதிப்புகள் 'ஒன்று' மற்றும் "
#~ "'வலை'"
#~ msgid "Drag here to add favorites"
#~ msgstr "விருப்பங்களுக்கு சேர்க்க இங்கு இழுத்துவிடு"
#~ msgid "Find"
#~ msgstr "தேடு"
#~ msgid "Searching..."
#~ msgstr "தேடுகிறது..."
#~ msgid "No matching results."
#~ msgstr "பொருத்தமான விடைகள் இல்லை"
#~ msgid "ON"
#~ msgstr "இயக்கத்தில்"
#~ msgid "OFF"
#~ msgstr "செயல் நீக்கு"
#~ msgid "Invisible"
#~ msgstr "பார்க்கமுடியாதது"
#~ msgid "Account Information..."
#~ msgstr "கணக்கு தகவல்..."
#~ msgid "System Preferences..."
#~ msgstr "கணினி முன்னுரிமைகள்..."

549
po/th.po
View File

@ -8,8 +8,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: 2010-06-13 23:04+0000\n"
"PO-Revision-Date: 2010-06-14 20:22+0700\n"
"POT-Creation-Date: 2010-11-20 13:40+0000\n"
"PO-Revision-Date: 2010-11-23 10:04+0700\n"
"Last-Translator: Sira Nokyoongtong <gumaraa@gmail.com>\n"
"Language-Team: Thai <thai-l10n@googlegroups.com>\n"
"MIME-Version: 1.0\n"
@ -19,11 +19,11 @@ msgstr ""
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr ""
msgstr "เชลล์ GNOME"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr ""
msgstr "การจัดการหน้าต่างและการเรียกใช้โปรแกรม"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:1
msgid "Clock"
@ -33,6 +33,294 @@ msgstr "นาฬิกา"
msgid "Customize the panel clock"
msgstr "ปรับแต่งนาฬิกาบนพาเนล"
#: ../data/org.gnome.shell.gschema.xml.in.h:1
msgid ""
"Allows access to internal debugging and monitoring tools using the Alt-F2 "
"dialog."
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:2
msgid "Custom format of the clock"
msgstr "รูปแบบนาฬิกากำหนดเอง"
#: ../data/org.gnome.shell.gschema.xml.in.h:3
msgid "Enable internal tools useful for developers and testers from Alt-F2"
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:4
msgid "File extension used for storing the screencast"
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:5
msgid "Framerate used for recording screencasts."
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:6
msgid ""
"GNOME Shell extensions have a uuid property; this key lists extensions which "
"should not be loaded."
msgstr ""
"ส่วนขยายต่างๆ ของเชลล์ GNOME จะมี uuid ประจำตัว ค่านี้จะเก็บรายชื่อของส่วนขยายที่จะไม่เรียกใช้"
#: ../data/org.gnome.shell.gschema.xml.in.h:7
msgid "History for command (Alt-F2) dialog"
msgstr "ประวัติคำสั่งของกล่องโต้ตอบเรียกโปรแกรม (Alt-F2)"
#: ../data/org.gnome.shell.gschema.xml.in.h:8
msgid "Hour format"
msgstr "รูปแบบชั่วโมง"
#: ../data/org.gnome.shell.gschema.xml.in.h:9
msgid ""
"If true and format is either \"12-hour\" or \"24-hour\", display date in the "
"clock, in addition to time."
msgstr ""
"ถ้าเลือก และรูปแบบเวลาเป็น \"12-hour\" หรือ \"24-hour\" "
"ก็จะแสดงวันที่ในนาฬิกาควบคู่กับเวลาด้วย"
#: ../data/org.gnome.shell.gschema.xml.in.h:10
msgid ""
"If true and format is either \"12-hour\" or \"24-hour\", display seconds in "
"time."
msgstr ""
"ถ้าเลือก และรูปแบบเวลาเป็น \"12-hour\" หรือ \"24-hour\" ก็จะแสดงวินาทีในเวลาด้วย"
# See http://en.wikipedia.org/wiki/ISO_week_date
#: ../data/org.gnome.shell.gschema.xml.in.h:11
msgid "If true, display the ISO week date in the calendar."
msgstr "ถ้าเลือก จะแสดงวันที่แบบสัปดาห์ของ ISO ในปฏิทิน"
#: ../data/org.gnome.shell.gschema.xml.in.h:12
msgid "List of desktop file IDs for favorite applications"
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:13
msgid "Overview workspace view mode"
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:14
msgid ""
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
"used for gst-launch. The pipeline should have an unconnected sink pad where "
"the recorded video is recorded. It will normally have a unconnected source "
"pad; output from that pad will be written into the output file. However the "
"pipeline can also take care of its own output - this might be used to send "
"the output to an icecast server via shout2send or similar. When unset or set "
"to an empty value, the default pipeline will be used. This is currently "
"'videorate ! theoraenc ! oggmux' and records to Ogg Theora."
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:15
msgid "Show date in clock"
msgstr "แสดงวันที่ในนาฬิกา"
# See http://en.wikipedia.org/wiki/ISO_week_date
#: ../data/org.gnome.shell.gschema.xml.in.h:16
msgid "Show the week date in the calendar"
msgstr "แสดงวันที่แบบสัปดาห์ในปฏิทิน"
#: ../data/org.gnome.shell.gschema.xml.in.h:17
msgid "Show time with seconds"
msgstr "แสดงเวลาพร้อมวินาที"
#: ../data/org.gnome.shell.gschema.xml.in.h:18
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:19
msgid ""
"The filename for recorded screencasts will be a unique filename based on the "
"current date, and use this extension. It should be changed when recording to "
"a different container format."
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:20
msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames-per-second."
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:21
msgid "The gstreamer pipeline used to encode the screencast"
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:22
msgid ""
"The selected workspace view mode in the overview. Supported values are "
"\"single\" and \"grid\"."
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:23
msgid ""
"The shell normally monitors active applications in order to present the most "
"used ones (e.g. in launchers). While this data will be kept private, you may "
"want to disable this for privacy reasons. Please note that doing so won't "
"remove already saved data."
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:24
msgid ""
"This key specifies the format used by the panel clock when the format key is "
"set to \"custom\". You can use conversion specifiers understood by strftime"
"() to obtain a specific format. See the strftime() manual for more "
"information."
msgstr ""
"ค่านี้กำหนดรูปแบบของเวลาในแอพเพล็ตนาฬิกาเมื่อกำหนดรูปแบบเป็น \"custom\" "
"คุณสามารถใช้รหัสการแปลงของ strftime() เพื่อระบุรูปแบบที่ต้องการได้ "
"ดูข้อมูลเพิ่มเติมได้จากคู่มือของ strftime()"
#: ../data/org.gnome.shell.gschema.xml.in.h:25
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."
msgstr ""
"ค่านี้กำหนดรูปแบบชั่วโมงที่จะใช้ในแอพเพล็ตนาฬิกา ค่าที่เป็นไปได้คือ\"12-hour\", \"24-hour\", "
"\"unix\" และ \"custom\" ถ้ากำหนดเป็น \"unix\" นาฬิกาจะแสดงเวลาเป็นวินาทีนับจาก 1970-"
"01-01 ถ้ากำหนดเป็น \"custom\" นาฬิกาจะแสดงตามรูปแบบที่กำหนดใน custom_format "
"สังเกตว่าถ้ากำหนดเป็น \"unix\" หรือ \"custom\" ค่า show_date และ show_seconds "
"ก็จะไม่มีผล"
#: ../data/org.gnome.shell.gschema.xml.in.h:26
msgid "Uuids of extensions to disable"
msgstr "uuid ของส่วนขยายที่จะปิดใช้"
#: ../data/org.gnome.shell.gschema.xml.in.h:27
msgid "Whether to collect stats about applications usage"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:1
msgid "Clip the crosshairs at the center"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:2
msgid "Color of the crosshairs"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:3
msgid ""
"Determines the length of the vertical and horizontal lines that make up the "
"crosshairs."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:4
msgid ""
"Determines the position of the magnified mouse image within the magnified "
"view and how it reacts to system mouse movement. The values are - none: no "
"mouse tracking; - centered: the mouse image is displayed at the center of "
"the zoom region (which also represents the point under the system mouse) and "
"the magnified contents are scrolled as the system mouse moves; - "
"proportional: the position of the magnified mouse in the zoom region is "
"proportionally the same as the position of the system mouse on screen; - "
"push: when the magnified mouse intersects a boundary of the zoom region, the "
"contents are scrolled into view."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:5
msgid ""
"Determines the transparency of the crosshairs, from fully opaque to fully "
"transparent."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:6
msgid ""
"Determines whether the crosshairs intersect the magnified mouse sprite, or "
"are clipped such that the ends of the horizontal and vertical lines surround "
"the mouse image."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:7
msgid "Enable lens mode"
msgstr "เปิดใช้โหมดแว่นขยาย"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:8
msgid ""
"Enables/disables display of crosshairs centered on the magnified mouse "
"sprite."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:9
msgid ""
"For centered mouse tracking, when the system pointer is at or near the edge "
"of the screen, the magnified contents continue to scroll such that the "
"screen edge moves into the magnified view."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:10
msgid "Length of the crosshairs"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:11
msgid "Magnification factor"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:12
msgid "Mouse Tracking Mode"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:13
msgid "Opacity of the crosshairs"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:14
msgid "Screen position"
msgstr "ตำแหน่งของหน้าจอ"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:15
msgid "Scroll magnified contents beyond the edges of the desktop"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:16
msgid "Show or hide crosshairs"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:17
msgid "Show or hide the magnifier"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:18
msgid "Show or hide the magnifier and all of its zoom regions."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:19
msgid ""
"The color of the the vertical and horizontal lines that make up the "
"crosshairs."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:20
msgid ""
"The magnified view either fills the entire screen, or occupies the top-half, "
"bottom-half, left-half, or right-half of the screen."
msgstr ""
"ช่องแสดงภาพขยายอาจจะใหญ่เต็มจอภาพ (full-screen) หรืออาจจะกินที่แค่ครึ่งบน (top-half) "
"ครึ่งล่าง (bottom-half) ครึ่งซ้าย (left-half) หรือครึ่งขวา (right-half)"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:21
msgid ""
"The power of the magnification. A value of 1.0 means no magnification. A "
"value of 2.0 doubles the size."
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:22
msgid "Thickness of the crosshairs"
msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:23
msgid ""
"Whether the magnified view should be centered over the location of the "
"system mouse and move with it."
msgstr "กำหนดว่าจะให้ภาพขยายหน้าจอวางตำแหน่งกึ่งกลางที่เมาส์และเคลื่อนย้ายไปตามเมาส์หรือไม่"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:24
msgid "Width of the vertical and horizontal lines that make up the crosshairs."
msgstr ""
#: ../data/clock-preferences.ui.h:1
msgid "Clock Format"
msgstr "รูปแบบนาฬิกา"
@ -62,31 +350,31 @@ msgid "_24 hour format"
msgstr "แบบ _24 ขั่วโมง"
#. **** Applications ****
#: ../js/ui/appDisplay.js:388 ../js/ui/dash.js:872
#: ../js/ui/appDisplay.js:316 ../js/ui/dash.js:778
msgid "APPLICATIONS"
msgstr "โปรแกรม"
#: ../js/ui/appDisplay.js:420
#: ../js/ui/appDisplay.js:348
msgid "PREFERENCES"
msgstr "ปรับแต่ง"
#: ../js/ui/appDisplay.js:726
#: ../js/ui/appDisplay.js:647
msgid "New Window"
msgstr "หน้าต่างใหม่"
#: ../js/ui/appDisplay.js:730
#: ../js/ui/appDisplay.js:651
msgid "Remove from Favorites"
msgstr "ลบออกจากรายการโปรด"
#: ../js/ui/appDisplay.js:731
#: ../js/ui/appDisplay.js:652
msgid "Add to Favorites"
msgstr "เพิ่มเข้าในรายการโปรด"
#: ../js/ui/appDisplay.js:1038
#: ../js/ui/appDisplay.js:829
msgid "Drag here to add favorites"
msgstr "ลากมาที่นี่เพื่อเพิ่มเป็นรายการโปรด"
#: ../js/ui/appFavorites.js:89
#: ../js/ui/appFavorites.js:88
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s ถูกเพิ่มเข้าในรายการโปรดของคุณแล้ว"
@ -96,233 +384,313 @@ msgstr "%s ถูกเพิ่มเข้าในรายการโปร
msgid "%s has been removed from your favorites."
msgstr "%s ถูกลบออกจากรายการโปรดของคุณแล้ว"
#: ../js/ui/dash.js:204
#: ../js/ui/dash.js:142
msgid "Find"
msgstr "หา"
#: ../js/ui/dash.js:527
#: ../js/ui/dash.js:473
msgid "Searching..."
msgstr "กำลังค้นหา..."
#: ../js/ui/dash.js:541
#: ../js/ui/dash.js:487
msgid "No matching results."
msgstr "ไม่มีผลลัพธ์ที่ตรงกัน"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:891 ../js/ui/placeDisplay.js:551
#: ../js/ui/dash.js:797 ../js/ui/placeDisplay.js:558
msgid "PLACES & DEVICES"
msgstr ""
msgstr "ที่หลักๆ และอุปกรณ์"
#. **** Documents ****
#: ../js/ui/dash.js:898 ../js/ui/docDisplay.js:497
#: ../js/ui/dash.js:804 ../js/ui/docDisplay.js:494
msgid "RECENT ITEMS"
msgstr ""
msgstr "รายการล่าสุด"
#: ../js/ui/lookingGlass.js:475
#: ../js/ui/lookingGlass.js:552
msgid "No extensions installed"
msgstr "ไม่มีส่วนขยายติดตั้งอยู่"
#: ../js/ui/lookingGlass.js:512
#: ../js/ui/lookingGlass.js:589
msgid "Enabled"
msgstr ""
msgstr "เปิดใช้งาน"
#: ../js/ui/lookingGlass.js:514
#. translators:
#. * The device has been disabled
#: ../js/ui/lookingGlass.js:591 ../src/gvc/gvc-mixer-control.c:1087
msgid "Disabled"
msgstr ""
msgstr "ปิดใช้"
#: ../js/ui/lookingGlass.js:516
#: ../js/ui/lookingGlass.js:593
msgid "Error"
msgstr "ผิดพลาด"
#: ../js/ui/lookingGlass.js:518
#: ../js/ui/lookingGlass.js:595
msgid "Out of date"
msgstr ""
msgstr "ตกรุ่น"
#: ../js/ui/lookingGlass.js:543
#: ../js/ui/lookingGlass.js:620
msgid "View Source"
msgstr ""
msgstr "ดูซอร์ส"
#: ../js/ui/lookingGlass.js:549
#: ../js/ui/lookingGlass.js:626
msgid "Web Page"
msgstr "หน้าเว็บ"
#: ../js/ui/overview.js:165
#: ../js/ui/overview.js:160
msgid "Undo"
msgstr "เรียกคืน"
#: ../js/ui/panel.js:334
#. TODO - _quit() doesn't really work on apps in state STARTING yet
#: ../js/ui/panel.js:470
#, c-format
msgid "Quit %s"
msgstr "ออกจาก %s"
#: ../js/ui/panel.js:354
#: ../js/ui/panel.js:495
msgid "Preferences"
msgstr "ปรับแต่ง"
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:441
#: ../js/ui/panel.js:581
msgid "%a %b %e, %R:%S"
msgstr ""
msgstr "%a %d %b, %R:%S"
#: ../js/ui/panel.js:442
#: ../js/ui/panel.js:582
msgid "%a %b %e, %R"
msgstr ""
msgstr "%a %d %b, %R"
#. Translators: This is the time format without date used
#. in 24-hour mode.
#: ../js/ui/panel.js:446
#: ../js/ui/panel.js:586
msgid "%a %R:%S"
msgstr ""
msgstr "%a %R:%S"
#: ../js/ui/panel.js:447
#: ../js/ui/panel.js:587
msgid "%a %R"
msgstr ""
msgstr "%a %R"
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:454
#: ../js/ui/panel.js:594
msgid "%a %b %e, %l:%M:%S %p"
msgstr ""
msgstr "%a %d %b, %l:%M:%S %p"
#: ../js/ui/panel.js:455
#: ../js/ui/panel.js:595
msgid "%a %b %e, %l:%M %p"
msgstr ""
msgstr "%a %d %b, %l:%M %p"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:459
#: ../js/ui/panel.js:599
msgid "%a %l:%M:%S %p"
msgstr ""
msgstr "%a %l:%M:%S %p"
#: ../js/ui/panel.js:460
#: ../js/ui/panel.js:600
msgid "%a %l:%M %p"
msgstr ""
msgstr "%a %l:%M %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:562
#: ../js/ui/panel.js:745
msgid "Activities"
msgstr "กิจกรรม"
#: ../js/ui/placeDisplay.js:108
#: ../js/ui/placeDisplay.js:111
#, c-format
msgid "Failed to unmount '%s'"
msgstr "เลิกเมานท์ '%s' ไม่สำเร็จ"
#: ../js/ui/placeDisplay.js:111
#: ../js/ui/placeDisplay.js:114
msgid "Retry"
msgstr "ลองใหม่"
#: ../js/ui/placeDisplay.js:156
#: ../js/ui/placeDisplay.js:159
msgid "Connect to..."
msgstr "เชื่อมต่อไปยัง..."
#: ../js/ui/runDialog.js:235
#. Translators: this MUST be either "toggle-switch-us"
#. (for toggle switches containing the English words
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
#. switches containing "◯" and "|"). Other values will
#. simply result in invisible toggle switches.
#: ../js/ui/popupMenu.js:33
msgid "toggle-switch-us"
msgstr ""
#: ../js/ui/runDialog.js:233
msgid "Please enter a command:"
msgstr "โปรดป้อนคำสั่ง:"
#: ../js/ui/runDialog.js:380
#: ../js/ui/runDialog.js:378
#, c-format
msgid "Execution of '%s' failed:"
msgstr ""
msgstr "คำสั่ง '%s' ทำงานล้มเหลว:"
#: ../js/ui/statusMenu.js:91
#: ../js/ui/statusMenu.js:101
msgid "Available"
msgstr ""
#: ../js/ui/statusMenu.js:95
msgid "Busy"
msgstr ""
#: ../js/ui/statusMenu.js:99
msgid "Invisible"
msgstr ""
msgstr "อยู่"
#: ../js/ui/statusMenu.js:106
msgid "Account Information..."
msgstr "ข้อมูลบัญชี..."
msgid "Busy"
msgstr "ไม่ว่าง"
#: ../js/ui/statusMenu.js:110
msgid "System Preferences..."
msgstr "ปรับแต่งระบบ..."
#: ../js/ui/statusMenu.js:114
msgid "My Account..."
msgstr "บัญชีของฉัน..."
#: ../js/ui/statusMenu.js:117
#: ../js/ui/statusMenu.js:118
msgid "System Settings..."
msgstr "ตั้งค่าระบบ..."
#: ../js/ui/statusMenu.js:125
msgid "Lock Screen"
msgstr "ล็อคหน้าจอ"
#: ../js/ui/statusMenu.js:121
#: ../js/ui/statusMenu.js:129
msgid "Switch User"
msgstr "สลับผู้ใช้"
#: ../js/ui/statusMenu.js:126
#: ../js/ui/statusMenu.js:134
msgid "Log Out..."
msgstr "ออกจากระบบ..."
#: ../js/ui/statusMenu.js:130
#: ../js/ui/statusMenu.js:141
msgid "Suspend"
msgstr "พักเครื่อง"
#: ../js/ui/statusMenu.js:145
msgid "Shut Down..."
msgstr "ปิดเครื่อง..."
#: ../js/ui/windowAttentionHandler.js:47
#: ../js/ui/status/accessibility.js:88
msgid "Screen Reader"
msgstr "โปรแกรมอ่านหน้าจอ"
#: ../js/ui/status/accessibility.js:91
msgid "Screen Keyboard"
msgstr "แป้นพิมพ์บนหน้าจอ"
#: ../js/ui/status/accessibility.js:94
msgid "Visual Alerts"
msgstr "แจ้งเหตุด้วยภาพ"
#: ../js/ui/status/accessibility.js:97
msgid "Sticky Keys"
msgstr "ค้างปุ่มกด"
#: ../js/ui/status/accessibility.js:100
msgid "Slow Keys"
msgstr "พิมพ์แบบช้า"
#: ../js/ui/status/accessibility.js:103
msgid "Bounce Keys"
msgstr "ป้องกันการกดแป้นรัว"
#: ../js/ui/status/accessibility.js:106
msgid "Mouse Keys"
msgstr "บังคับเมาส์ด้วยแป้น"
#: ../js/ui/status/accessibility.js:110
msgid "Universal Access Settings"
msgstr "ตั้งค่าสิ่งอำนวยความสะดวก"
#: ../js/ui/status/accessibility.js:163
msgid "High Contrast"
msgstr "สีตัดกัน"
#: ../js/ui/status/accessibility.js:205
msgid "Large Text"
msgstr "อักษรขนาดใหญ่"
#: ../js/ui/status/accessibility.js:224
msgid "Zoom"
msgstr "ซูม"
#: ../js/ui/windowAttentionHandler.js:43
#, c-format
msgid "%s has finished starting"
msgstr ""
msgstr "%s เปิดเสร็จแล้ว"
#: ../js/ui/windowAttentionHandler.js:49
#: ../js/ui/windowAttentionHandler.js:45
#, c-format
msgid "'%s' is ready"
msgstr "'%s' พร้อมแล้ว"
#: ../js/ui/workspacesView.js:237
#: ../js/ui/workspacesView.js:229
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
msgstr ""
#: ../js/ui/workspacesView.js:254
#: ../js/ui/workspacesView.js:246
msgid "Can't remove the first workspace."
msgstr "ไม่สามารถลบพื้นที่ทำงานแรกได้"
#: ../src/shell-global.c:1025
#. translators:
#. * The number of sound outputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1094
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] ""
#. translators:
#. * The number of sound inputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1104
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] ""
#: ../src/gvc/gvc-mixer-control.c:1402
msgid "System Sounds"
msgstr "เสียงของระบบ"
#: ../src/shell-app-system.c:1012
msgid "Unknown"
msgstr ""
#: ../src/shell-global.c:1158
msgid "Less than a minute ago"
msgstr "ไม่ถึงหนึ่งนาทีก่อน"
#: ../src/shell-global.c:1029
#: ../src/shell-global.c:1162
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d นาทีก่อน"
#: ../src/shell-global.c:1034
#: ../src/shell-global.c:1167
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d ชั่วโมงก่อน"
#: ../src/shell-global.c:1039
#: ../src/shell-global.c:1172
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d วันก่อน"
#: ../src/shell-global.c:1044
#: ../src/shell-global.c:1177
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d สัปดาห์ก่อน"
#: ../src/shell-uri-util.c:89
#: ../src/shell-util.c:89
msgid "Home Folder"
msgstr "โฟลเดอร์บ้าน"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:104
#: ../src/shell-util.c:104
msgid "File System"
msgstr "ระบบแฟ้ม"
#: ../src/shell-uri-util.c:250
#: ../src/shell-util.c:250
msgid "Search"
msgstr "ค้นหา"
@ -331,7 +699,10 @@ msgstr "ค้นหา"
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:300
#: ../src/shell-util.c:300
#, c-format
msgid "%1$s: %2$s"
msgstr ""
msgstr "%1$s: %2$s"
#~ msgid "Account Information..."
#~ msgstr "ข้อมูลบัญชี..."

583
po/ug.po
View File

@ -4,14 +4,14 @@
# Gheyret Kenji<gheyret@yahoo.com>,2010.
# Sahran <sahran.ug@gmail.com>, 2010.
# Zeper <zeper@msn.com>, 2010.
#
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell&component=general\n"
"POT-Creation-Date: 2010-11-11 00:43+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Gheyret Kenji<gheyret@yahoo.com>\n"
"POT-Creation-Date: 2010-12-20 21:07+0000\n"
"PO-Revision-Date: 2010-11-25 14:28+0600\n"
"Last-Translator: Sahran <sahran@live.com>\n"
"Language-Team: Uyghur Computer Science Association <UKIJ@yahoogroups.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -20,7 +20,7 @@ msgstr ""
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "GNOME چاپان"
msgstr "GNOME Shell"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
@ -32,7 +32,7 @@ msgstr "سائەت"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:2
msgid "Customize the panel clock"
msgstr "ئىختىيارىچە تاختا سائەت"
msgstr "تاختا سائەتنى ئۆزلەشتۈرىدۇ"
#: ../data/org.gnome.shell.gschema.xml.in.h:1
msgid ""
@ -42,7 +42,7 @@ msgstr "ئىچكى سازلاش ۋە كۆزىتىش قورالىنى زىيار
#: ../data/org.gnome.shell.gschema.xml.in.h:2
msgid "Custom format of the clock"
msgstr "ئىختىيارىي سائەت فورماتى"
msgstr "سائەتنىڭ ئىختىيارىي فورماتى"
#: ../data/org.gnome.shell.gschema.xml.in.h:3
msgid "Enable internal tools useful for developers and testers from Alt-F2"
@ -50,11 +50,11 @@ msgstr "ئىچكى قورال قوزغىتىلسا ئىجادكارلار ۋە
#: ../data/org.gnome.shell.gschema.xml.in.h:4
msgid "File extension used for storing the screencast"
msgstr "ھۆججەت كېڭەيتىلگەن ئاتى ئېكران كەسمىسى (screencasts) ساقلاشقا ئىشلىتىلىدۇ"
msgstr "ئېكران كەسمىسى (screencasts) ساقلاشتا ئىشلىتىلىدىغان ھۆججەتنىڭ كېڭەيتىلگەن ئاتى"
#: ../data/org.gnome.shell.gschema.xml.in.h:5
msgid "Framerate used for recording screencasts."
msgstr "كاندۇك نىسبىتى ئېكران كەسمىسى (screencasts) خاتىرىلەشكە ئىشلىتىلىدۇ"
msgstr "ئېكران كەسمىسى (screencasts) خاتىرىلەشتە ئىشلىتىلىدىغان كاندۇك تېزلىكى."
#: ../data/org.gnome.shell.gschema.xml.in.h:6
msgid ""
@ -88,13 +88,9 @@ msgstr "ئەگەر راست(true) بولسا يىلنامىدىكى ISO ھەپت
#: ../data/org.gnome.shell.gschema.xml.in.h:12
msgid "List of desktop file IDs for favorite applications"
msgstr "ئامراق پروگراممىلارنىڭ ئۈستەل ئۈستى ھۆججەت ID تىزىملىكى"
msgstr "ئامراق پروگراممىلارنىڭ ئۈستەلئۈستى ھۆججەت ID تىزىملىكى"
#: ../data/org.gnome.shell.gschema.xml.in.h:13
msgid "Overview workspace view mode"
msgstr "قىسقىچە بايان خىزمەت رايون كۆرۈنۈش ھالىتى"
#: ../data/org.gnome.shell.gschema.xml.in.h:14
msgid ""
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
"used for gst-launch. The pipeline should have an unconnected sink pad where "
@ -104,50 +100,44 @@ msgid ""
"the output to an icecast server via shout2send or similar. When unset or set "
"to an empty value, the default pipeline will be used. This is currently "
"'videorate ! theoraenc ! oggmux' and records to Ogg Theora."
msgstr ""
msgstr "ئۈن ئېلىشنى كودلاشتا ئىشلىتىلىدىغان GStreamer ئاقما لىنىيىنى تەڭشەيدۇ. ئۇ gst-launch گرامماتىكىسىغا بوي سۇنىدۇ. بۇ ئاقما لىنىيىدە ئۇلانمىغان sink pad بولۇشى لازىم، خاتىرىلىنىدىغان سىن مۇشۇ جايدا خاتىرىلىنىدۇ. بۇ لىنىيىدە ئادەتتە يەنە بىر ئۇلانمىغان مەنبە pad بولىدۇ؛ بۇ pad چىقارغان ئۇچۇرلار ھۆججەتكە يېزىلىدۇ. ئەمما ئاقما لىنىيە ئۆزىنىڭ چىقىرىشىنى بىر تەرەپ قىلالايدۇ، بۇنداق بولغاندا shout2send ئارقىلىق ياكى شۇنىڭغا ئوخشاش ئۇسۇلدا چىقىرىشنى icecast مۇلازىمېتىرىغا يوللايدۇ. ئاقما لىنىيە تەڭشەلمىگەن ياكى بوش قىممەتكە تەڭشەلگەندە كۆڭۈلدىكى ئاقما لىنىيە قوزغىتىلىدۇ. ئۇنىڭ نۆۋەتتىكى قىممىتى 'videorate ! theoraenc ! oggmux' بولۇپ، فورماتى Ogg شەكلىدە خاتىرىلىنىدۇ."
#: ../data/org.gnome.shell.gschema.xml.in.h:15
#: ../data/org.gnome.shell.gschema.xml.in.h:14
msgid "Show date in clock"
msgstr "سائەت ئىچىدە چېسلا كۆرسەت"
#: ../data/org.gnome.shell.gschema.xml.in.h:16
#: ../data/org.gnome.shell.gschema.xml.in.h:15
msgid "Show the week date in the calendar"
msgstr "يىلنامىدە ھەپتە كۆرسەت"
msgstr "يىلنامىدە ھەپتىنى كۆرسىتىدۇ"
#: ../data/org.gnome.shell.gschema.xml.in.h:17
#: ../data/org.gnome.shell.gschema.xml.in.h:16
msgid "Show time with seconds"
msgstr "ۋاقىت ئىچىدە سېكۇنتنى بىللە كۆرسەت"
#: ../data/org.gnome.shell.gschema.xml.in.h:18
#: ../data/org.gnome.shell.gschema.xml.in.h:17
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
msgstr "مۇناسىپ پروگرامما بەلگىسى يىغقۇچ رايونىدا كۆرسىتىلىدۇ."
#: ../data/org.gnome.shell.gschema.xml.in.h:19
#: ../data/org.gnome.shell.gschema.xml.in.h:18
msgid ""
"The filename for recorded screencasts will be a unique filename based on the "
"current date, and use this extension. It should be changed when recording to "
"a different container format."
msgstr "خاتىرىلەنگەن ئېكراننىڭ ھۆججەت ئاتى نۆۋەتتىكى چېسلا ئاساسىدا بىردىنبىر بولۇپ بۇ كېڭەيتىلگەن ئاتىنى ئىشلىتىدۇ. ئۇ ئۆزگەرسە ئوخشاش بولمىغان قاچا فورماتىدا خاتىرىلەيدۇ."
#: ../data/org.gnome.shell.gschema.xml.in.h:20
#: ../data/org.gnome.shell.gschema.xml.in.h:19
msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames-per-second."
msgstr "GNOME Shell ئېكران خاتىرىلىگۈچ ھەر سېكۇنتتا خاتىرىلەيدىغان ئېكران كەسمىسى كاندۇك نىسبىتى"
msgstr "GNOME Shell ئېكران خاتىرىلىگۈچ ھەر سېكۇنتتا خاتىرىلەيدىغان ئېكران كەسمىسى كاندۇك سۈرىتى(ھەر سېكۇنتتىكى كاندۇك سانى)."
#: ../data/org.gnome.shell.gschema.xml.in.h:20
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "ئېكران كەسمىسىنى كودلاشتا ئىشلىتىلىدىغان gstreamer ئاقما لىنىيىسى"
#: ../data/org.gnome.shell.gschema.xml.in.h:21
msgid "The gstreamer pipeline used to encode the screencast"
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:22
msgid ""
"The selected workspace view mode in the overview. Supported values are "
"\"single\" and \"grid\"."
msgstr "تاللانغان قىسقىچە مەزمۇن خىزمەت رايونى كۆرۈنۈشىدە قوللايدىغان قىممەت «يەككە» ۋە «سېتكا»"
#: ../data/org.gnome.shell.gschema.xml.in.h:23
msgid ""
"The shell normally monitors active applications in order to present the most "
"used ones (e.g. in launchers). While this data will be kept private, you may "
@ -155,7 +145,7 @@ msgid ""
"remove already saved data."
msgstr "چاپان (shell) ئادەتتىكى ئەھۋالدا كۆپ ئىشلىتىلىدىغان ئاكتىپ پروگراممىلار(مەسىلەن، ئىجرا قىلىنىۋاتقان)نى كۆزىتىدۇ. گەرچە بۇ سانلىق مەلۇماتلار مەخپىي ساقلانسىمۇ، شەخسىي سىر سەۋەبىدىن بۇنى چەكلىشىڭىز مۇمكىن. دىققەت بۇنداق قىلغاندا ئاللىبۇرۇن ساقلانغان سانلىق مەلۇماتلار چىقىرىۋېتىلمەيدۇ."
#: ../data/org.gnome.shell.gschema.xml.in.h:24
#: ../data/org.gnome.shell.gschema.xml.in.h:22
msgid ""
"This key specifies the format used by the panel clock when the format key is "
"set to \"custom\". You can use conversion specifiers understood by strftime"
@ -163,7 +153,7 @@ msgid ""
"information."
msgstr "format (فورمات) كۇنۇپكىسى \"custom\" (ئىختىيارى) قىلىپ تەڭشەلسە بۇ كۇنۇپكا تاختا سائەت ئىشلىتىدىغان فورماتنى بەلگىلەيدۇ. سىز strftime()نىڭ فورمات بەلگىسىنى ئىشلىتىپ بەلگىلەنگەن فورماتقا ئېرىشەلەيسىز. تەپسىلاتىنى strftime() نىڭ قوللانمىسىدىن كۆرۈڭ."
#: ../data/org.gnome.shell.gschema.xml.in.h:25
#: ../data/org.gnome.shell.gschema.xml.in.h:23
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\", "
@ -173,27 +163,27 @@ msgid ""
"the show_date and show_seconds keys are ignored."
msgstr "بۇ كۇنۇپكا تاختا سائەت ئىشلەتكەن سائەت فورماتىنى بەلگىلىگەن. ئىشلەتكىلى بولىدىغان قىممىتى \"12-hour\" يەنى (12 سائەت)، \"24-hour\" يەنى (24 سائەت)، \"unix\" ۋە \"custom\" (ئىختىيارى). ئەگەر \"unix\" قىلىپ تەڭشەلسە سائەت ئۆزلۈكىدىن يېڭى ئېرا (يەنى، 1970-01-01) دىن ئۆتكەن سېكۇنتنى ئاساس قىلىدۇ. ئەگەر \"custom\" قىلىپ تەڭشەلسە سائەت custom_format كۇنۇپكا قىممىتىگە ئاساسەن ۋاقىتنى كۆرسىتىدۇ. ئەگەر \"unix\" ياكى \"custom\" قىلىپ تەڭشەلسە show_date ۋە show_seconds قىممىتىگە پەرۋا قىلمايدۇ"
#: ../data/org.gnome.shell.gschema.xml.in.h:26
#: ../data/org.gnome.shell.gschema.xml.in.h:24
msgid "Uuids of extensions to disable"
msgstr "كېڭەيتىلمىنىڭ Uuid چەكلەندى"
msgstr "چەكلىنىدىغان كېڭەيتىلمىنىڭ Uuid سى"
#: ../data/org.gnome.shell.gschema.xml.in.h:27
#: ../data/org.gnome.shell.gschema.xml.in.h:25
msgid "Whether to collect stats about applications usage"
msgstr "پروگراممىنىڭ ئىشلىتىلىشى ھەققىدىكى ستاتىستىكىنى توپلامدۇ يوق"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:1
msgid "Clip the crosshairs at the center"
msgstr ""
msgstr "نىشانلىغۇچنى ئوتتۇرىغا توغرىلا"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:2
msgid "Color of the crosshairs"
msgstr ""
msgstr "نىشانلىغۇچنىڭ رەڭگى"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:3
msgid ""
"Determines the length of the vertical and horizontal lines that make up the "
"crosshairs."
msgstr ""
msgstr "نىشانلىغۇچنى ھاسىل قىلىدىغان توغرا ۋە بوي سىزىقنىڭ ئۇزۇنلۇقى بەلگىلىنىدۇ."
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:4
msgid ""
@ -212,7 +202,7 @@ msgstr ""
msgid ""
"Determines the transparency of the crosshairs, from fully opaque to fully "
"transparent."
msgstr ""
msgstr "نىشانلىغۇچنىڭ سۈزۈكلۈكى تولۇق سۈزۈكتىن تولۇق تۇتۇققىچە بەلگىلىنىدۇ."
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:6
msgid ""
@ -223,7 +213,7 @@ msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:7
msgid "Enable lens mode"
msgstr ""
msgstr "لېنزا ھالىتىنى قوزغات"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:8
msgid ""
@ -240,19 +230,19 @@ msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:10
msgid "Length of the crosshairs"
msgstr ""
msgstr "نىشانلىغۇچنىڭ ئېگىزلىكى"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:11
msgid "Magnification factor"
msgstr ""
msgstr "چوڭايتىش-كىچىكلىتىش نىسبىتى"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:12
msgid "Mouse Tracking Mode"
msgstr ""
msgstr "چاشقىنەك ئىزلاش ھالىتى"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:13
msgid "Opacity of the crosshairs"
msgstr ""
msgstr "نىشانلىغۇچنىڭ سۈزۈكلۈكى"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:14
msgid "Screen position"
@ -260,25 +250,25 @@ msgstr "ئېكران ئورنى"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:15
msgid "Scroll magnified contents beyond the edges of the desktop"
msgstr "دومىلىما چوڭايتقۇچ ئۈستەل ئۈستى گىرۋەك مەزمۇنىدىن ھالقىپ كەتتى"
msgstr "دومىلىما چوڭايتقۇچ ئۈستەلئۈستى گىرۋەك مەزمۇنىدىن ھالقىپ كەتتى"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:16
msgid "Show or hide crosshairs"
msgstr ""
msgstr "نىشانلىغۇچنى كۆرسەت ياكى يوشۇر"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:17
msgid "Show or hide the magnifier"
msgstr ""
msgstr "لوپا ئەينەكنى كۆرسەت ياكى يوشۇر"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:18
msgid "Show or hide the magnifier and all of its zoom regions."
msgstr ""
msgstr "لوپا ئەينەك ۋە ئۇنىڭ ھەممە چوڭايتىش دائىرىسىنى كۆرسەت ياكى يوشۇرىدۇ."
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:19
msgid ""
"The color of the the vertical and horizontal lines that make up the "
"crosshairs."
msgstr ""
msgstr "نىشانلىغۇچنى ھاسىل قىلىدىغان توغرا ۋە بوي سىزىقنىڭ رەڭگى."
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:20
msgid ""
@ -290,11 +280,11 @@ msgstr ""
msgid ""
"The power of the magnification. A value of 1.0 means no magnification. A "
"value of 2.0 doubles the size."
msgstr ""
msgstr "چوڭايتىش كۈچى. 1.0 چوڭايتمايدۇ، 2.0 چوڭلۇقىنى ھەسسىلەيدۇ دېگەن مەنىدە."
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:22
msgid "Thickness of the crosshairs"
msgstr ""
msgstr "نىشانلىغۇچنىڭ قېلىنلىقى"
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:23
msgid ""
@ -304,7 +294,7 @@ msgstr ""
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:24
msgid "Width of the vertical and horizontal lines that make up the crosshairs."
msgstr ""
msgstr "نىشانلىغۇچنى ھاسىل قىلىدىغان توغرا ۋە بوي سىزىقنىڭ كەڭلىكى."
#: ../data/clock-preferences.ui.h:1
msgid "Clock Format"
@ -316,11 +306,11 @@ msgstr "سائەت مايىللىقى"
#: ../data/clock-preferences.ui.h:3
msgid "Panel Display"
msgstr "تاختا كۆرسەت"
msgstr "تاختا كۆرسىتىش"
#: ../data/clock-preferences.ui.h:4
msgid "Show seco_nds"
msgstr "سېكۇنت كۆرسەت(_N)"
msgstr "سېكۇنتنى كۆرسەت(_N)"
#: ../data/clock-preferences.ui.h:5
msgid "Show the _date"
@ -334,62 +324,45 @@ msgstr "_12 سائەت فورماتى"
msgid "_24 hour format"
msgstr "_24 سائەت فورماتى"
#. **** Applications ****
#: ../js/ui/appDisplay.js:316 ../js/ui/dash.js:778
#: ../js/ui/appDisplay.js:154
msgid "All"
msgstr "ھەممىسى"
#: ../js/ui/appDisplay.js:235
msgid "APPLICATIONS"
msgstr "پروگراممىلار"
#: ../js/ui/appDisplay.js:348
#: ../js/ui/appDisplay.js:265
msgid "PREFERENCES"
msgstr "مايىللىق"
#: ../js/ui/appDisplay.js:647
#: ../js/ui/appDisplay.js:562
msgid "New Window"
msgstr "يېڭى كۆزنەك"
#: ../js/ui/appDisplay.js:651
#: ../js/ui/appDisplay.js:566
msgid "Remove from Favorites"
msgstr "يىغقۇچتىن چىقىرىۋەت"
#: ../js/ui/appDisplay.js:652
#: ../js/ui/appDisplay.js:567
msgid "Add to Favorites"
msgstr "يىغقۇچقا قوش"
#: ../js/ui/appDisplay.js:829
msgid "Drag here to add favorites"
msgstr "بۇ جايغا سۆرەپ قىسقۇچقا قوش"
#: ../js/ui/appFavorites.js:88
#: ../js/ui/appFavorites.js:91
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s يىغقۇچىڭىزغا قوشۇلىدۇ."
msgstr "%s يىغقۇچىڭىزغا قوشۇلدى."
#: ../js/ui/appFavorites.js:107
#: ../js/ui/appFavorites.js:122
#, c-format
msgid "%s has been removed from your favorites."
msgstr "%s يىغقۇچىڭىزدىن چىقىرىۋېتىلىدۇ."
#: ../js/ui/dash.js:142
msgid "Find"
msgstr "ئىزدە"
#: ../js/ui/dash.js:27
msgid "Remove"
msgstr "چىقىرىۋەت"
#: ../js/ui/dash.js:473
msgid "Searching..."
msgstr "ئىزدەۋاتىدۇ…"
#: ../js/ui/dash.js:487
msgid "No matching results."
msgstr "ماس كېلىدىغان نەتىجە يوق."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:797 ../js/ui/placeDisplay.js:554
msgid "PLACES & DEVICES"
msgstr "ئورۇن ۋە ئۈسكۈنىلەر"
#. **** Documents ****
#: ../js/ui/dash.js:804 ../js/ui/docDisplay.js:494
#: ../js/ui/docDisplay.js:494
msgid "RECENT ITEMS"
msgstr "يېقىنقى تۈرلەر"
@ -421,72 +394,81 @@ msgstr "مەنبەنى كۆرسەت"
#: ../js/ui/lookingGlass.js:626
msgid "Web Page"
msgstr "تور بەت"
msgstr "توربەت"
#: ../js/ui/overview.js:160
#: ../js/ui/overview.js:96
msgid "Undo"
msgstr "يېنىۋال"
#: ../js/ui/overview.js:158
#| msgid "New Window"
msgid "Windows"
msgstr "كۆزنەكلەر"
#: ../js/ui/overview.js:161
msgid "Applications"
msgstr "پروگراممىلار"
#. TODO - _quit() doesn't really work on apps in state STARTING yet
#: ../js/ui/panel.js:469
#: ../js/ui/panel.js:474
#, c-format
msgid "Quit %s"
msgstr "%s چېكىن"
#: ../js/ui/panel.js:494
#: ../js/ui/panel.js:499
msgid "Preferences"
msgstr "مايىللىق"
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:580
#: ../js/ui/panel.js:585
msgid "%a %b %e, %R:%S"
msgstr "%a %b %e، %R:%S"
#: ../js/ui/panel.js:581
#: ../js/ui/panel.js:586
msgid "%a %b %e, %R"
msgstr "%a %b %e، %R"
#. Translators: This is the time format without date used
#. in 24-hour mode.
#: ../js/ui/panel.js:585
#: ../js/ui/panel.js:590
msgid "%a %R:%S"
msgstr "%a %R:%S"
#: ../js/ui/panel.js:586
#: ../js/ui/panel.js:591
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:593
#: ../js/ui/panel.js:598
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a %b %e, %l:%M:%S %p"
msgstr "%a %b %e، %l:%M:%S %p"
#: ../js/ui/panel.js:594
#: ../js/ui/panel.js:599
msgid "%a %b %e, %l:%M %p"
msgstr "%a %b %e, %l:%M %p"
msgstr "%a %b %e، %l:%M %p"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:598
#: ../js/ui/panel.js:603
msgid "%a %l:%M:%S %p"
msgstr "%a %l:%M:%S %p"
#: ../js/ui/panel.js:599
#: ../js/ui/panel.js:604
msgid "%a %l:%M %p"
msgstr "%p%l:%M (%a)"
#. 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:744
#: ../js/ui/panel.js:749
msgid "Activities"
msgstr "ھەرىكەتچان"
msgstr "پائالىيەتلەر"
#: ../js/ui/placeDisplay.js:111
#, c-format
msgid "Failed to unmount '%s'"
msgstr "%s نىڭ ئېگەرنى يېشىش مەغلۇپ بولدى."
msgstr "«%s» نى ئېگەرسىزلەش مەغلۇپ بولدى"
#: ../js/ui/placeDisplay.js:114
msgid "Retry"
@ -494,7 +476,11 @@ msgstr "قايتا سىنا"
#: ../js/ui/placeDisplay.js:159
msgid "Connect to..."
msgstr "باغلانماق..."
msgstr "باغلىنىش…"
#: ../js/ui/placeDisplay.js:558
msgid "PLACES & DEVICES"
msgstr "ئورۇن ۋە ئۈسكۈنىلەر"
#. Translators: this MUST be either "toggle-switch-us"
#. (for toggle switches containing the English words
@ -503,7 +489,7 @@ msgstr "باغلانماق..."
#. simply result in invisible toggle switches.
#: ../js/ui/popupMenu.js:33
msgid "toggle-switch-us"
msgstr ""
msgstr "toggle-switch-us"
#: ../js/ui/runDialog.js:233
msgid "Please enter a command:"
@ -512,52 +498,51 @@ msgstr "بۇيرۇق كىرگۈزۈڭ:"
#: ../js/ui/runDialog.js:378
#, c-format
msgid "Execution of '%s' failed:"
msgstr "'%s' ئىجرا قىلالمىدى:"
msgstr "«%s» ئىجرا قىلىش مەغلۇپ بولدى:"
#: ../js/ui/statusMenu.js:101
msgid "Available"
msgstr "ئىشلىتىلىشچان"
msgstr "بار"
#: ../js/ui/statusMenu.js:106
msgid "Busy"
msgstr "ئالدىراش"
#: ../js/ui/statusMenu.js:111
msgid "Invisible"
msgstr "يوشۇرۇن"
#: ../js/ui/statusMenu.js:114
#| msgid "My Account..."
msgid "My Account"
msgstr "ھېساباتىم"
#: ../js/ui/statusMenu.js:119
msgid "My Account..."
msgstr ""
#: ../js/ui/statusMenu.js:118
#| msgid "System Settings..."
msgid "System Settings"
msgstr "سىستېما تەڭشىكى"
#: ../js/ui/statusMenu.js:123
msgid "System Settings..."
msgstr "سىستېما تەڭشەكلىرى"
#: ../js/ui/statusMenu.js:130
#: ../js/ui/statusMenu.js:125
msgid "Lock Screen"
msgstr "ئېكراننى قۇلۇپلا"
msgstr "ئېكراننى قۇلۇپلاش"
#: ../js/ui/statusMenu.js:129
msgid "Switch User"
msgstr "ئىشلەتكۈچى ئالماشتۇرۇش"
#: ../js/ui/statusMenu.js:134
msgid "Switch User"
msgstr "ئىشلەتكۈچى ئالماشتۇر"
#: ../js/ui/statusMenu.js:139
msgid "Log Out..."
msgstr "تىزىمدىن چىق…"
msgstr "تىزىمدىن چىقىش…"
#: ../js/ui/statusMenu.js:146
msgid "Suspend"
msgstr "ۋاقىتلىق توختىتىش"
#: ../js/ui/statusMenu.js:150
msgid "Restart..."
#: ../js/ui/statusMenu.js:141
#| msgid "Suspend"
msgid "Suspend..."
msgstr ""
#: ../js/ui/statusMenu.js:154
#: ../js/ui/statusMenu.js:145
msgid "Shut Down..."
msgstr "تاقا…"
#: ../js/ui/status/accessibility.js:82
msgid "Zoom"
msgstr "كېڭەيت تارايت"
#: ../js/ui/status/accessibility.js:88
msgid "Screen Reader"
msgstr "ئېكران ئوقۇغۇچ"
@ -572,35 +557,288 @@ msgstr "كۆرۈنمە ئاگاھلاندۇرۇش"
#: ../js/ui/status/accessibility.js:97
msgid "Sticky Keys"
msgstr "چاپلاش كۇنۇپكىسى"
msgstr "Sticky Keys"
#: ../js/ui/status/accessibility.js:100
msgid "Slow Keys"
msgstr "ئاستا كۇنۇپكا"
msgstr "Slow Keys"
#: ../js/ui/status/accessibility.js:103
msgid "Bounce Keys"
msgstr "قاڭقىش كۇنۇپكىسى"
msgstr "Bounce Keys"
#: ../js/ui/status/accessibility.js:106
msgid "Mouse Keys"
msgstr "چاشقىنەك كۇنۇپكا"
msgstr "Mouse Keys"
#: ../js/ui/status/accessibility.js:110
msgid "Universal Access Settings"
msgstr "ھەممىباب زىيارەت تەڭشىكى"
msgstr "ئۇنىۋېرسال زىيارەت تەڭشىكى"
#: ../js/ui/status/accessibility.js:163
msgid "High Contrast"
msgstr "يۇقىرى ئاق-قارىلىقى"
#: ../js/ui/status/accessibility.js:202
#: ../js/ui/status/accessibility.js:205
msgid "Large Text"
msgstr "چوڭ تېكىست"
#: ../js/ui/status/accessibility.js:223
msgid "Zoom"
msgstr "كېڭەيت تارايت"
#: ../js/ui/status/bluetooth.js:42 ../js/ui/status/bluetooth.js:200
msgid "Bluetooth"
msgstr "كۆكچىش"
#: ../js/ui/status/bluetooth.js:55
msgid "Visibility"
msgstr "كۆرۈشچانلىقى"
#: ../js/ui/status/bluetooth.js:68
msgid "Send Files to Device..."
msgstr ""
#: ../js/ui/status/bluetooth.js:71
msgid "Setup a New Device..."
msgstr ""
#: ../js/ui/status/bluetooth.js:94
#| msgid "System Settings..."
msgid "Bluetooth Settings"
msgstr ""
#: ../js/ui/status/bluetooth.js:151
#| msgid "Connect to..."
msgid "Connection"
msgstr "باغلىنىش"
#: ../js/ui/status/bluetooth.js:187
#| msgid "Suspend"
msgid "Send Files..."
msgstr ""
#: ../js/ui/status/bluetooth.js:192
msgid "Browse Files..."
msgstr ""
#: ../js/ui/status/bluetooth.js:201
msgid "Error browsing device"
msgstr ""
#: ../js/ui/status/bluetooth.js:202
#, c-format
msgid "The requested device cannot be browsed, error is '%s'"
msgstr ""
#: ../js/ui/status/bluetooth.js:210
#| msgid "System Settings..."
msgid "Keyboard Settings"
msgstr ""
#: ../js/ui/status/bluetooth.js:215
#| msgid "System Settings..."
msgid "Mouse Settings"
msgstr ""
#: ../js/ui/status/bluetooth.js:222 ../js/ui/status/volume.js:62
#| msgid "System Settings..."
msgid "Sound Settings"
msgstr ""
#: ../js/ui/status/bluetooth.js:293 ../js/ui/status/bluetooth.js:327
#: ../js/ui/status/bluetooth.js:367 ../js/ui/status/bluetooth.js:400
msgid "Bluetooth Agent"
msgstr ""
#: ../js/ui/status/bluetooth.js:328
#, c-format
msgid "Authorization request from %s"
msgstr ""
#: ../js/ui/status/bluetooth.js:334
#, c-format
msgid "Device %s wants access to the service '%s'"
msgstr ""
#: ../js/ui/status/bluetooth.js:336
msgid "Always grant access"
msgstr ""
#: ../js/ui/status/bluetooth.js:337
msgid "Grant this time only"
msgstr ""
#: ../js/ui/status/bluetooth.js:338
msgid "Reject"
msgstr "رەت قىل"
#: ../js/ui/status/bluetooth.js:368
#, c-format
msgid "Pairing confirmation for %s"
msgstr ""
#: ../js/ui/status/bluetooth.js:374 ../js/ui/status/bluetooth.js:408
#, c-format
msgid "Device %s wants to pair with this computer"
msgstr ""
#: ../js/ui/status/bluetooth.js:375
#, c-format
msgid "Please confirm whether the PIN '%s' matches the one on the device."
msgstr ""
#: ../js/ui/status/bluetooth.js:377
msgid "Matches"
msgstr "جۈپلەش تۈرى"
#: ../js/ui/status/bluetooth.js:378
msgid "Does not match"
msgstr "جۈپلىمە"
#: ../js/ui/status/bluetooth.js:401
#, c-format
msgid "Pairing request for %s"
msgstr ""
#: ../js/ui/status/bluetooth.js:409
msgid "Please enter the PIN mentioned on the device."
msgstr ""
#: ../js/ui/status/bluetooth.js:425
msgid "OK"
msgstr "جەزملە"
#: ../js/ui/status/bluetooth.js:426
msgid "Cancel"
msgstr "ۋاز كەچ"
#: ../js/ui/status/power.js:85
#| msgid "System Settings..."
msgid "Power Settings"
msgstr ""
#: ../js/ui/status/power.js:112
#, c-format
#| msgid "%d hour ago"
#| msgid_plural "%d hours ago"
msgid "%d hour remaining"
msgid_plural "%d hours remaining"
msgstr[0] ""
#. TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining"
#: ../js/ui/status/power.js:115
#, c-format
msgid "%d %s %d %s remaining"
msgstr ""
#: ../js/ui/status/power.js:117
msgid "hour"
msgid_plural "hours"
msgstr[0] "سائەت"
#: ../js/ui/status/power.js:117
#| msgid "%d minute ago"
#| msgid_plural "%d minutes ago"
msgid "minute"
msgid_plural "minutes"
msgstr[0] "مىنۇت"
#: ../js/ui/status/power.js:120
#, c-format
#| msgid "%d minute ago"
#| msgid_plural "%d minutes ago"
msgid "%d minute remaining"
msgid_plural "%d minutes remaining"
msgstr[0] ""
#: ../js/ui/status/power.js:237
msgid "AC adapter"
msgstr ""
#: ../js/ui/status/power.js:239
msgid "Laptop battery"
msgstr ""
#: ../js/ui/status/power.js:241
msgid "UPS"
msgstr "UPS"
#: ../js/ui/status/power.js:243
msgid "Monitor"
msgstr "ئېكران"
#: ../js/ui/status/power.js:245
#| msgid "Mouse Keys"
msgid "Mouse"
msgstr "چاشقىنەك"
#: ../js/ui/status/power.js:247
#| msgid "Screen Keyboard"
msgid "Keyboard"
msgstr "ھەرپتاختا"
#: ../js/ui/status/power.js:249
msgid "PDA"
msgstr "PDA"
#: ../js/ui/status/power.js:251
msgid "Cell phone"
msgstr ""
#: ../js/ui/status/power.js:253
msgid "Media player"
msgstr "Media چالغۇ"
#: ../js/ui/status/power.js:255
#| msgid "Enabled"
msgid "Tablet"
msgstr "سەزمە تاختا"
#: ../js/ui/status/power.js:257
msgid "Computer"
msgstr "كومپيۇتېر"
#: ../js/ui/status/power.js:259 ../src/shell-app-system.c:1012
msgid "Unknown"
msgstr "نامەلۇم"
#: ../js/ui/status/volume.js:41
msgid "Volume"
msgstr "دىسكا"
#: ../js/ui/status/volume.js:54
msgid "Microphone"
msgstr ""
#: ../js/ui/telepathyClient.js:560
#, c-format
msgid "%s is online."
msgstr ""
#: ../js/ui/telepathyClient.js:565
#, c-format
msgid "%s is offline."
msgstr ""
#: ../js/ui/telepathyClient.js:568
#, c-format
#| msgid "'%s' is ready"
msgid "%s is away."
msgstr ""
#: ../js/ui/telepathyClient.js:571
#, c-format
msgid "%s is busy."
msgstr ""
#. Translators: this is a time format string followed by a date.
#. If applicable, replace %X with a strftime format valid for your
#. locale, without seconds.
#: ../js/ui/telepathyClient.js:664
#, no-c-format
msgid "Sent at %X on %A"
msgstr ""
#: ../js/ui/viewSelector.js:26
msgid "Search your computer"
msgstr ""
#: ../js/ui/windowAttentionHandler.js:43
#, c-format
@ -610,16 +848,16 @@ msgstr "%s باشلاشنى تاماملىدى"
#: ../js/ui/windowAttentionHandler.js:45
#, c-format
msgid "'%s' is ready"
msgstr "'%s' تەييار بولدى"
msgstr "«%s» تەييار"
#: ../js/ui/workspacesView.js:229
#: ../js/ui/workspacesView.js:244
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
msgstr "يېڭى خىزمەت رايونى قوشالمايدۇ چۈنكى ئەڭ كۆپ خىزمەت رايون چېكىگە يەتتى."
#: ../js/ui/workspacesView.js:246
#: ../js/ui/workspacesView.js:260
msgid "Can't remove the first workspace."
msgstr "بىرىنچى خىزمەت رايونىنى چىقىرىۋېتەلمەيدۇ."
msgstr "بىرىنچى خىزمەت رايونىنى چىقىرىۋەتكىلى بولمايدۇ."
#. translators:
#. * The number of sound outputs on a particular device
@ -627,7 +865,7 @@ msgstr "بىرىنچى خىزمەت رايونىنى چىقىرىۋېتەلمە
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] "%u چىقار"
msgstr[0] "%u چىقىرىلما"
#. translators:
#. * The number of sound inputs on a particular device
@ -635,51 +873,51 @@ msgstr[0] "%u چىقار"
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] "%u كىرگۈز"
msgstr[0] "%u كىرگۈزۈلمە"
#: ../src/gvc/gvc-mixer-control.c:1402
msgid "System Sounds"
msgstr "سىستېما ئاۋازى"
#: ../src/shell-global.c:1219
#: ../src/shell-global.c:1155
msgid "Less than a minute ago"
msgstr "بىر مىنۇتتىنمۇ ئىلگىرى"
#: ../src/shell-global.c:1223
#: ../src/shell-global.c:1159
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d مىنۇت ئىلگىرى"
#: ../src/shell-global.c:1228
#: ../src/shell-global.c:1164
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d سائەت ئىلگىرى"
#: ../src/shell-global.c:1233
#: ../src/shell-global.c:1169
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d كۈن ئىلگىرى"
#: ../src/shell-global.c:1238
#: ../src/shell-global.c:1174
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d ھەپتە ئىلگىرى"
#: ../src/shell-uri-util.c:89
#: ../src/shell-util.c:89
msgid "Home Folder"
msgstr "باش مۇندەرىجە"
msgstr "ماكان مۇندەرىجە"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:104
#: ../src/shell-util.c:104
msgid "File System"
msgstr "ھۆججەت سىستېمىسى"
#: ../src/shell-uri-util.c:250
#: ../src/shell-util.c:250
msgid "Search"
msgstr "ئىزدە"
@ -688,7 +926,32 @@ msgstr "ئىزدە"
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:300
#: ../src/shell-util.c:300
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Overview workspace view mode"
#~ msgstr "خىزمەت رايون كۆرۈنۈش ھالىتى ھەققىدە قىسقىچە بايان"
#~ msgid ""
#~ "The selected workspace view mode in the overview. Supported values are "
#~ "\"single\" and \"grid\"."
#~ msgstr ""
#~ "قىسقىچە باياندىكى تاللانغان خىزمەت رايونىنىڭ كۆرۈنۈش ھالىتى. ئىشلىتىشكە "
#~ "بولىدىغان قىممەتلەر «يەككە» ۋە «سېتكا»"
#~ msgid "Drag here to add favorites"
#~ msgstr "بۇ جايغا سۆرەپ يىغقۇچقا قوش"
#~ msgid "Find"
#~ msgstr "ئىزدە"
#~ msgid "Searching..."
#~ msgstr "ئىزدەۋاتىدۇ..."
#~ msgid "No matching results."
#~ msgstr "ماس كېلىدىغان نەتىجە يوق."
#~ msgid "Invisible"
#~ msgstr "يوشۇرۇن"

893
po/vi.po

File diff suppressed because it is too large Load Diff

View File

@ -6,19 +6,22 @@
# Aron Xu <aronxu@gnome.org>, 2010.
# Jessica Ban <bancage@gmail.com>, 2010.
# YunQiang Su <wzssyqa@gmail.com>, 2010.
# zhang ping <zhangping159@gmail.com>, 2010.
# 指冷玉笙寒 (dhyang) <dhyang555@gmail.com>, 2010
#
msgid ""
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: 2010-10-30 17:51+0000\n"
"PO-Revision-Date: 2010-10-28 01:24+0800\n"
"Last-Translator: YunQiang Su <wzssyqa@gmail.com>\n"
"POT-Creation-Date: 2010-12-23 17:30+0000\n"
"PO-Revision-Date: 2010-12-25 20:54+0800\n"
"Last-Translator: Aron Xu <happyaron.xu@gmail.com>\n"
"Language-Team: Chinese (simplified) <i18n-zh@googlegroups.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: zh_CN\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: ../data/gnome-shell.desktop.in.in.h:1
@ -94,10 +97,6 @@ msgid "List of desktop file IDs for favorite applications"
msgstr "收藏夹中的应用程序的 desktop 文件 ID 的列表"
#: ../data/org.gnome.shell.gschema.xml.in.h:13
msgid "Overview workspace view mode"
msgstr "工作区视图模式的总览"
#: ../data/org.gnome.shell.gschema.xml.in.h:14
msgid ""
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
"used for gst-launch. The pipeline should have an unconnected sink pad where "
@ -115,25 +114,25 @@ msgstr ""
"器。当管道未被设置或者设置为空值时,默认的管道将被启用。其值当前"
"为“videorate ! theoraenc ! oggmux”并记录为 Ogg Theora 格式。"
#: ../data/org.gnome.shell.gschema.xml.in.h:15
#: ../data/org.gnome.shell.gschema.xml.in.h:14
msgid "Show date in clock"
msgstr "显示日期"
#: ../data/org.gnome.shell.gschema.xml.in.h:16
#: ../data/org.gnome.shell.gschema.xml.in.h:15
msgid "Show the week date in the calendar"
msgstr "在日历中显示星期"
#: ../data/org.gnome.shell.gschema.xml.in.h:17
#: ../data/org.gnome.shell.gschema.xml.in.h:16
msgid "Show time with seconds"
msgstr "显示秒"
#: ../data/org.gnome.shell.gschema.xml.in.h:18
#: ../data/org.gnome.shell.gschema.xml.in.h:17
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
msgstr "符合这些标示的应用程序将显示在收藏区中。"
#: ../data/org.gnome.shell.gschema.xml.in.h:19
#: ../data/org.gnome.shell.gschema.xml.in.h:18
msgid ""
"The filename for recorded screencasts will be a unique filename based on the "
"current date, and use this extension. It should be changed when recording to "
@ -142,25 +141,17 @@ msgstr ""
"录制的屏幕录像的文件名将是根据当前时间得到的独特值,并使用这个扩展名。录制另"
"外一个不同容器格式的录像时,它应该被更改。"
#: ../data/org.gnome.shell.gschema.xml.in.h:20
#: ../data/org.gnome.shell.gschema.xml.in.h:19
msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames-per-second."
msgstr "GNOME Shell 的屏幕录像程序录制的屏幕录像的帧率,以 帧/秒 为格式。"
#: ../data/org.gnome.shell.gschema.xml.in.h:21
#: ../data/org.gnome.shell.gschema.xml.in.h:20
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "用于编码屏幕录像的 GStreamer 管线"
#: ../data/org.gnome.shell.gschema.xml.in.h:22
msgid ""
"The selected workspace view mode in the overview. Supported values are "
"\"single\" and \"grid\"."
msgstr ""
"总览中,选中的工作区的试图模式。支持的值有 \"single\"(单独) 和 \"grid\"(网"
"格)。"
#: ../data/org.gnome.shell.gschema.xml.in.h:23
#: ../data/org.gnome.shell.gschema.xml.in.h:21
msgid ""
"The shell normally monitors active applications in order to present the most "
"used ones (e.g. in launchers). While this data will be kept private, you may "
@ -171,7 +162,7 @@ msgstr ""
"时,此数据将保持私密,您可能因为隐私原因想要禁用此项。请注意,这么做,并不会"
"移除已经保存的数据。"
#: ../data/org.gnome.shell.gschema.xml.in.h:24
#: ../data/org.gnome.shell.gschema.xml.in.h:22
msgid ""
"This key specifies the format used by the panel clock when the format key is "
"set to \"custom\". You can use conversion specifiers understood by strftime"
@ -182,7 +173,7 @@ msgstr ""
"以被 strftime() 理解的转义符获取特定的格式。请查看 strftime() 的文档获取更多"
"信息。"
#: ../data/org.gnome.shell.gschema.xml.in.h:25
#: ../data/org.gnome.shell.gschema.xml.in.h:23
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\", "
@ -197,11 +188,11 @@ msgstr ""
"示时间。注意,如果设置为 \"unix\" 或 \"custom\"show_date 和 show_seconds 键"
"将被忽略。"
#: ../data/org.gnome.shell.gschema.xml.in.h:26
#: ../data/org.gnome.shell.gschema.xml.in.h:24
msgid "Uuids of extensions to disable"
msgstr "要禁用的扩展的 uuid"
#: ../data/org.gnome.shell.gschema.xml.in.h:27
#: ../data/org.gnome.shell.gschema.xml.in.h:25
msgid "Whether to collect stats about applications usage"
msgstr "是否收集应用程序的使用情况"
@ -366,62 +357,46 @@ msgstr "_12 时格式"
msgid "_24 hour format"
msgstr "_24 小时格式"
#. **** Applications ****
#: ../js/ui/appDisplay.js:316 ../js/ui/dash.js:778
#. Translators: Filter to display all applications
#: ../js/ui/appDisplay.js:155
msgid "All"
msgstr "全部"
#: ../js/ui/appDisplay.js:236
msgid "APPLICATIONS"
msgstr "应用程序"
#: ../js/ui/appDisplay.js:348
#: ../js/ui/appDisplay.js:266
msgid "PREFERENCES"
msgstr "首选项"
#: ../js/ui/appDisplay.js:647
#: ../js/ui/appDisplay.js:563
msgid "New Window"
msgstr "新窗口"
#: ../js/ui/appDisplay.js:651
#: ../js/ui/appDisplay.js:567
msgid "Remove from Favorites"
msgstr "从收藏夹中移除"
#: ../js/ui/appDisplay.js:652
#: ../js/ui/appDisplay.js:568
msgid "Add to Favorites"
msgstr "添加到收藏夹"
#: ../js/ui/appDisplay.js:829
msgid "Drag here to add favorites"
msgstr "拖到这里加入收藏夹"
#: ../js/ui/appFavorites.js:88
#: ../js/ui/appFavorites.js:91
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s 已经添加到了您的收藏夹。"
#: ../js/ui/appFavorites.js:107
#: ../js/ui/appFavorites.js:122
#, c-format
msgid "%s has been removed from your favorites."
msgstr "%s 已经从您的收藏夹移除。"
#: ../js/ui/dash.js:142
msgid "Find"
msgstr "查找"
#: ../js/ui/dash.js:27
msgid "Remove"
msgstr "移除"
#: ../js/ui/dash.js:473
msgid "Searching..."
msgstr "正在搜索..."
#: ../js/ui/dash.js:487
msgid "No matching results."
msgstr "无匹配结果。"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:797 ../js/ui/placeDisplay.js:554
msgid "PLACES & DEVICES"
msgstr "位置和设备"
#. **** Documents ****
#: ../js/ui/dash.js:804 ../js/ui/docDisplay.js:494
#: ../js/ui/docDisplay.js:494
msgid "RECENT ITEMS"
msgstr "最近的项目"
@ -455,63 +430,71 @@ msgstr "查看源"
msgid "Web Page"
msgstr "网页"
#: ../js/ui/overview.js:160
#: ../js/ui/overview.js:96
msgid "Undo"
msgstr "撤销"
#: ../js/ui/overview.js:158
msgid "Windows"
msgstr "窗口"
#: ../js/ui/overview.js:161
msgid "Applications"
msgstr "应用程序"
#. TODO - _quit() doesn't really work on apps in state STARTING yet
#: ../js/ui/panel.js:469
#: ../js/ui/panel.js:474
#, c-format
msgid "Quit %s"
msgstr "退出 %s"
#: ../js/ui/panel.js:494
#: ../js/ui/panel.js:499
msgid "Preferences"
msgstr "首选项"
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:580
#: ../js/ui/panel.js:585
msgid "%a %b %e, %R:%S"
msgstr "%A %b %e, %R:%S"
#: ../js/ui/panel.js:581
#: ../js/ui/panel.js:586
msgid "%a %b %e, %R"
msgstr "%A %m月%d日 %R"
#. Translators: This is the time format without date used
#. in 24-hour mode.
#: ../js/ui/panel.js:585
#: ../js/ui/panel.js:590
msgid "%a %R:%S"
msgstr "%A %R:%S"
#: ../js/ui/panel.js:586
#: ../js/ui/panel.js:591
msgid "%a %R"
msgstr "%A %R"
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:593
#: ../js/ui/panel.js:598
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%A %m月%d日 %p%I:%M:%S"
#: ../js/ui/panel.js:594
#: ../js/ui/panel.js:599
msgid "%a %b %e, %l:%M %p"
msgstr "%A %m月%d日 %p%I:%M"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:598
#: ../js/ui/panel.js:603
msgid "%a %l:%M:%S %p"
msgstr "%A %p%I:%M:%S"
#: ../js/ui/panel.js:599
#: ../js/ui/panel.js:604
msgid "%a %l:%M %p"
msgstr "%a %l:%M %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:744
#: ../js/ui/panel.js:749
msgid "Activities"
msgstr "活动"
@ -528,6 +511,10 @@ msgstr "重试"
msgid "Connect to..."
msgstr "连接到..."
#: ../js/ui/placeDisplay.js:558
msgid "PLACES & DEVICES"
msgstr "位置和设备"
#. Translators: this MUST be either "toggle-switch-us"
#. (for toggle switches containing the English words
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
@ -554,44 +541,38 @@ msgstr "可用"
msgid "Busy"
msgstr "忙碌"
#: ../js/ui/statusMenu.js:111
msgid "Invisible"
msgstr "隐身"
#: ../js/ui/statusMenu.js:114
msgid "My Account"
msgstr "我的帐户"
#: ../js/ui/statusMenu.js:119
msgid "My Account..."
msgstr "我的帐户..."
#: ../js/ui/statusMenu.js:118
msgid "System Settings"
msgstr "系统设置"
#: ../js/ui/statusMenu.js:123
#, fuzzy
#| msgid "System Preferences..."
msgid "System Settings..."
msgstr "系统首选项..."
#: ../js/ui/statusMenu.js:130
#: ../js/ui/statusMenu.js:125
msgid "Lock Screen"
msgstr "锁住屏幕"
#: ../js/ui/statusMenu.js:134
#: ../js/ui/statusMenu.js:129
msgid "Switch User"
msgstr "切换用户"
#: ../js/ui/statusMenu.js:139
#: ../js/ui/statusMenu.js:134
msgid "Log Out..."
msgstr "退出..."
#: ../js/ui/statusMenu.js:146
msgid "Suspend"
msgstr "休眠"
#: ../js/ui/statusMenu.js:141
msgid "Suspend..."
msgstr "休眠..."
#: ../js/ui/statusMenu.js:150
msgid "Restart..."
msgstr "重启..."
#: ../js/ui/statusMenu.js:154
#: ../js/ui/statusMenu.js:145
msgid "Shut Down..."
msgstr "关机..."
#: ../js/ui/status/accessibility.js:82
msgid "Zoom"
msgstr "缩放"
#: ../js/ui/status/accessibility.js:88
msgid "Screen Reader"
msgstr "屏幕阅读器"
@ -628,13 +609,249 @@ msgstr "通用访问设置"
msgid "High Contrast"
msgstr "高对比度"
#: ../js/ui/status/accessibility.js:202
#: ../js/ui/status/accessibility.js:205
msgid "Large Text"
msgstr "大号文本"
#: ../js/ui/status/accessibility.js:223
msgid "Zoom"
msgstr "缩放"
#: ../js/ui/status/bluetooth.js:42 ../js/ui/status/bluetooth.js:234
msgid "Bluetooth"
msgstr "蓝牙"
#: ../js/ui/status/bluetooth.js:55
msgid "Visibility"
msgstr "可见性"
#: ../js/ui/status/bluetooth.js:69
msgid "Send Files to Device..."
msgstr "发送文件到设备..."
#: ../js/ui/status/bluetooth.js:70
msgid "Setup a New Device..."
msgstr "安装新设备..."
#: ../js/ui/status/bluetooth.js:94
msgid "Bluetooth Settings"
msgstr "蓝牙设置"
#: ../js/ui/status/bluetooth.js:185
msgid "Connection"
msgstr "连接"
#: ../js/ui/status/bluetooth.js:221
msgid "Send Files..."
msgstr "发送文件..."
#: ../js/ui/status/bluetooth.js:226
msgid "Browse Files..."
msgstr "浏览文件..."
#: ../js/ui/status/bluetooth.js:235
msgid "Error browsing device"
msgstr "浏览设备出错"
#: ../js/ui/status/bluetooth.js:236
#, c-format
msgid "The requested device cannot be browsed, error is '%s'"
msgstr "无法浏览请求的设备,错误为 %s"
#: ../js/ui/status/bluetooth.js:244
msgid "Keyboard Settings"
msgstr "键盘设置"
#: ../js/ui/status/bluetooth.js:249
msgid "Mouse Settings"
msgstr "鼠标设置"
#: ../js/ui/status/bluetooth.js:256 ../js/ui/status/volume.js:62
msgid "Sound Settings"
msgstr "声音设置"
#: ../js/ui/status/bluetooth.js:327 ../js/ui/status/bluetooth.js:361
#: ../js/ui/status/bluetooth.js:401 ../js/ui/status/bluetooth.js:434
msgid "Bluetooth Agent"
msgstr "蓝牙助手"
#: ../js/ui/status/bluetooth.js:362
#, c-format
msgid "Authorization request from %s"
msgstr "来自 %s 的认证请求"
#: ../js/ui/status/bluetooth.js:368
#, c-format
msgid "Device %s wants access to the service '%s'"
msgstr "设备 %s 希望访问 %s 服务"
#: ../js/ui/status/bluetooth.js:370
msgid "Always grant access"
msgstr "始终允许"
#: ../js/ui/status/bluetooth.js:371
msgid "Grant this time only"
msgstr "允许一次"
#: ../js/ui/status/bluetooth.js:372
msgid "Reject"
msgstr "拒绝"
#: ../js/ui/status/bluetooth.js:402
#, c-format
msgid "Pairing confirmation for %s"
msgstr "%s 的配对确认"
#: ../js/ui/status/bluetooth.js:408 ../js/ui/status/bluetooth.js:442
#, c-format
msgid "Device %s wants to pair with this computer"
msgstr "设备 %s 希望与此电脑配对"
#: ../js/ui/status/bluetooth.js:409
#, c-format
msgid "Please confirm whether the PIN '%s' matches the one on the device."
msgstr "请确认 PIN 码 %s 和要配对的设备是否相同。"
#: ../js/ui/status/bluetooth.js:411
msgid "Matches"
msgstr "相同"
#: ../js/ui/status/bluetooth.js:412
msgid "Does not match"
msgstr "不同"
#: ../js/ui/status/bluetooth.js:435
#, c-format
msgid "Pairing request for %s"
msgstr "%s 的配对请求"
#: ../js/ui/status/bluetooth.js:443
msgid "Please enter the PIN mentioned on the device."
msgstr "请输入设备上的 PIN 码。"
#: ../js/ui/status/bluetooth.js:459
msgid "OK"
msgstr "确定"
#: ../js/ui/status/bluetooth.js:460
msgid "Cancel"
msgstr "取消"
#: ../js/ui/status/power.js:85
msgid "Power Settings"
msgstr "电源设置"
#: ../js/ui/status/power.js:112
#, c-format
msgid "%d hour remaining"
msgid_plural "%d hours remaining"
msgstr[0] "剩余 %d 小时"
#. TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining"
#: ../js/ui/status/power.js:115
#, c-format
msgid "%d %s %d %s remaining"
msgstr "剩余 %d %s %d %s"
#: ../js/ui/status/power.js:117
msgid "hour"
msgid_plural "hours"
msgstr[0] "小时"
#: ../js/ui/status/power.js:117
msgid "minute"
msgid_plural "minutes"
msgstr[0] "分钟"
#: ../js/ui/status/power.js:120
#, c-format
msgid "%d minute remaining"
msgid_plural "%d minutes remaining"
msgstr[0] "剩余 %d 分钟"
#: ../js/ui/status/power.js:237
msgid "AC adapter"
msgstr "AC 适配器"
#: ../js/ui/status/power.js:239
msgid "Laptop battery"
msgstr "笔记本电池"
#: ../js/ui/status/power.js:241
msgid "UPS"
msgstr "UPS"
#: ../js/ui/status/power.js:243
msgid "Monitor"
msgstr "显示器"
#: ../js/ui/status/power.js:245
msgid "Mouse"
msgstr "鼠标"
#: ../js/ui/status/power.js:247
msgid "Keyboard"
msgstr "键盘"
#: ../js/ui/status/power.js:249
msgid "PDA"
msgstr "PDA"
#: ../js/ui/status/power.js:251
msgid "Cell phone"
msgstr "手机"
#: ../js/ui/status/power.js:253
msgid "Media player"
msgstr "媒体播放器"
#: ../js/ui/status/power.js:255
msgid "Tablet"
msgstr "触摸板"
#: ../js/ui/status/power.js:257
msgid "Computer"
msgstr "计算机"
#: ../js/ui/status/power.js:259 ../src/shell-app-system.c:1012
msgid "Unknown"
msgstr "未知"
#: ../js/ui/status/volume.js:41
msgid "Volume"
msgstr "音量"
#: ../js/ui/status/volume.js:54
msgid "Microphone"
msgstr "麦克风"
#: ../js/ui/telepathyClient.js:560
#, c-format
msgid "%s is online."
msgstr "%s 在线。"
#: ../js/ui/telepathyClient.js:565
#, c-format
msgid "%s is offline."
msgstr "%s 离线。"
#: ../js/ui/telepathyClient.js:568
#, c-format
msgid "%s is away."
msgstr "%s 离开。"
#: ../js/ui/telepathyClient.js:571
#, c-format
msgid "%s is busy."
msgstr "%s 忙碌。"
#. Translators: this is a time format string followed by a date.
#. If applicable, replace %X with a strftime format valid for your
#. locale, without seconds.
#: ../js/ui/telepathyClient.js:665
#, no-c-format
msgid "Sent at %X on %A"
msgstr "发送于 %X on %A"
#: ../js/ui/viewSelector.js:26
msgid "Search your computer"
msgstr "搜索您的计算机"
#: ../js/ui/windowAttentionHandler.js:43
#, c-format
@ -646,12 +863,12 @@ msgstr "%s 已启动"
msgid "'%s' is ready"
msgstr "%s 已就绪"
#: ../js/ui/workspacesView.js:229
#: ../js/ui/workspacesView.js:244
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
msgstr "无法添加新工作区,因为已经达到了工作区数量限制。"
#: ../js/ui/workspacesView.js:246
#: ../js/ui/workspacesView.js:260
msgid "Can't remove the first workspace."
msgstr "不能移除第一个工作区。"
@ -661,7 +878,7 @@ msgstr "不能移除第一个工作区。"
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] ""
msgstr[0] "%u 个输出"
#. translators:
#. * The number of sound inputs on a particular device
@ -669,51 +886,51 @@ msgstr[0] ""
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] ""
msgstr[0] "%u 个输入"
#: ../src/gvc/gvc-mixer-control.c:1402
msgid "System Sounds"
msgstr ""
msgstr "系统声音"
#: ../src/shell-global.c:1219
#: ../src/shell-global.c:1156
msgid "Less than a minute ago"
msgstr "少于一分钟前"
#: ../src/shell-global.c:1223
#: ../src/shell-global.c:1160
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d 分钟前"
#: ../src/shell-global.c:1228
#: ../src/shell-global.c:1165
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d 小时前"
#: ../src/shell-global.c:1233
#: ../src/shell-global.c:1170
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d 天前"
#: ../src/shell-global.c:1238
#: ../src/shell-global.c:1175
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d 周前"
#: ../src/shell-uri-util.c:89
#: ../src/shell-util.c:89
msgid "Home Folder"
msgstr "主文件夹"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:104
#: ../src/shell-util.c:104
msgid "File System"
msgstr "文件系统"
#: ../src/shell-uri-util.c:250
#: ../src/shell-util.c:250
msgid "Search"
msgstr "搜索"
@ -722,11 +939,42 @@ msgstr "搜索"
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:300
#: ../src/shell-util.c:300
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "What's using power..."
#~ msgstr "哪些设备在用电..."
#~ msgid "Overview workspace view mode"
#~ msgstr "工作区视图模式的总览"
#~ msgid ""
#~ "The selected workspace view mode in the overview. Supported values are "
#~ "\"single\" and \"grid\"."
#~ msgstr ""
#~ "总览中,选中的工作区的试图模式。支持的值有 \"single\"(单独) 和 \"grid\"(网"
#~ "格)。"
#~ msgid "Drag here to add favorites"
#~ msgstr "拖到这里加入收藏夹"
#~ msgid "Find"
#~ msgstr "查找"
#~ msgid "Searching..."
#~ msgstr "正在搜索..."
#~ msgid "No matching results."
#~ msgstr "无匹配结果。"
#~ msgid "Invisible"
#~ msgstr "隐身"
#~ msgid "Restart..."
#~ msgstr "重启..."
#~ msgid "ON"
#~ msgstr "开"
@ -739,9 +987,6 @@ msgstr "%1$s: %2$s"
#~ msgid "%H:%M"
#~ msgstr "%H:%M"
#~ msgid "Applications"
#~ msgstr "应用程序"
#~ msgid "Recent Documents"
#~ msgstr "最近文档"
@ -757,9 +1002,6 @@ msgstr "%1$s: %2$s"
#~ msgid "SEARCH RESULTS"
#~ msgstr "搜索结果"
#~ msgid "Unknown"
#~ msgstr "未知"
#~ msgid "Can't lock screen: %s"
#~ msgstr "不能锁住屏幕:%s"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
noinst_LTLIBRARIES += libcalendar-client.la
libcalendar_client_la_SOURCES = \
calendar-client/calendar-client.h calendar-client/calendar-client.c \
calendar-client/calendar-debug.h \
calendar-client/calendar-sources.c calendar-client/calendar-sources.h \
$(NULL)
libcalendar_client_la_CFLAGS = \
-I$(top_srcdir)/src \
-DPREFIX=\""$(prefix)"\" \
-DLIBDIR=\""$(libdir)"\" \
-DDATADIR=\""$(datadir)"\" \
-DG_DISABLE_DEPRECATED \
-DG_LOG_DOMAIN=\"CalendarClient\" \
$(LIBECAL_CFLAGS) \
$(NULL)
libcalendar_client_la_LIBADD = $(LIBECAL_LIBS)
EXTRA_DIST += calendar-client/README

View File

@ -47,7 +47,7 @@ st-marshal.c: Makefile st/st-marshal.list
st-enum-types.h: stamp-st-enum-types.h Makefile
@true
stamp-st-enum-types.h: $(source_h) st/st-enum-types.h.in
stamp-st-enum-types.h: $(source_h) st/st-enum-types.h.in $(st_source_h)
$(AM_V_GEN) ( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template st/st-enum-types.h.in \
@ -98,15 +98,22 @@ st_source_h = \
st/st-tooltip.h \
st/st-types.h \
st/st-widget.h \
st/st-widget-accessible.h \
$(NULL)
st.h: Makefile
st.h: stamp-st.h
@true
stamp-st.h: Makefile
$(AM_V_GEN) (echo "#define ST_H_INSIDE 1"; \
for name in $(st_source_h); do \
echo "#include <"$$name">"; \
done; echo "#undef ST_H_INSIDE") > st.h.tmp && mv st.h.tmp st.h
done; echo "#undef ST_H_INSIDE") > $@.tmp && \
(cmp -s $@.tmp st.h || cp $@.tmp st.h) && \
rm -f $@.tmp && \
echo timestamp > $(@F)
BUILT_SOURCES += st.h
CLEANFILES += stamp-st.h
st_source_private_h = \
st/st-private.h \
@ -152,11 +159,17 @@ st_source_c = \
st/st-widget.c \
$(NULL)
st_non_gir_sources = \
st/st-scroll-view-fade.c \
st/st-scroll-view-fade.h \
$(NULL)
noinst_LTLIBRARIES += libst-1.0.la
libst_1_0_la_LIBADD = -lm $(ST_LIBS)
libst_1_0_la_SOURCES = \
$(st_source_c) \
$(st_source_c) \
$(st_non_gir_sources) \
$(st_source_private_h) \
$(st_source_private_c) \
$(st_source_h) \

View File

@ -15,7 +15,6 @@ TRAY_STAMP_FILES = stamp-na-marshal.h
# please, keep this sorted alphabetically
tray_source = \
gtk-compat.h \
tray/na-tray-child.c \
tray/na-tray-child.h \
tray/na-tray-manager.c \

View File

@ -8,13 +8,11 @@ noinst_PROGRAMS =
.AUTOPARALLEL:
bin_SCRIPTS = gnome-shell gnome-shell-clock-preferences
bin_SCRIPTS = gnome-shell
gnome-shell: gnome-shell.in
$(AM_V_GEN) sed -e "s|@MUTTER_BIN_DIR[@]|$(MUTTER_BIN_DIR)|" \
-e "s|@datadir[@]|$(datadir)|" \
-e "s|@GJS_JS_DIR[@]|$(GJS_JS_DIR)|" \
-e "s|@GJS_JS_NATIVE_DIR[@]|$(GJS_JS_NATIVE_DIR)|" \
-e "s|@libexecdir[@]|$(libexecdir)|" \
-e "s|@libdir[@]|$(libdir)|" \
-e "s|@pkgdatadir[@]|$(pkgdatadir)|" \
@ -25,19 +23,11 @@ gnome-shell: gnome-shell.in
CLEANFILES += gnome-shell
EXTRA_DIST += gnome-shell.in
gnome-shell-clock-preferences: gnome-shell-clock-preferences.in
$(AM_V_GEN) sed -e "s|@datadir[@]|$(datadir)|" \
-e "s|@pkgdatadir[@]|$(pkgdatadir)|" \
-e "s|@localedir[@]|$(datadir)/locale|" \
-e "s|@GJS_CONSOLE[@]|$(GJS_CONSOLE)|" \
$< > $@ && chmod a+x $@
CLEANFILES += gnome-shell-clock-preferences
EXTRA_DIST += gnome-shell-clock-preferences.in
include Makefile-gdmuser.am
include Makefile-st.am
include Makefile-tray.am
include Makefile-gvc.am
include Makefile-calendar-client.am
gnome_shell_cflags = \
$(MUTTER_PLUGIN_CFLAGS) \
@ -70,7 +60,6 @@ shell_public_headers_h = \
shell-embedded-window.h \
shell-generic-container.h \
shell-gtk-embed.h \
shell-process.h \
shell-global.h \
shell-perf-log.h \
shell-slicer.h \
@ -92,17 +81,19 @@ libgnome_shell_la_SOURCES = \
shell-window-tracker-private.h \
shell-wm-private.h \
gnome-shell-plugin.c \
gtk-compat.h \
shell-app.c \
shell-a11y.h \
shell-a11y.c \
shell-app-system.c \
shell-app-usage.c \
shell-arrow.c \
shell-doc-system.c \
shell-drawing.c \
shell-embedded-window.c \
shell-evolution-event-source.h \
shell-evolution-event-source.c \
shell-generic-container.c \
shell-gtk-embed.c \
shell-process.c \
shell-global.c \
shell-perf-log.c \
shell-slicer.c \
@ -220,10 +211,14 @@ libgnome_shell_la_LIBADD = \
-lm \
$(MUTTER_PLUGIN_LIBS) \
$(LIBGNOMEUI_LIBS) \
$(BLUETOOTH_LIBS) \
libst-1.0.la \
libgdmuser-1.0.la \
libtray.la \
libgvc.la
libgvc.la \
libcalendar-client.la \
$(NULL)
libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
typelibdir = $(pkglibdir)
@ -272,7 +267,7 @@ St-1.0.gir: $(mutter) $(G_IR_SCANNER) libst-1.0.la Makefile
--libtool="$(LIBTOOL)" \
--library=libst-1.0.la \
-DST_COMPILATION \
$(filter-out %-private.h, $(addprefix $(srcdir)/,$(st_source_h))) \
$(filter-out %-private.h $(st_non_gir_sources), $(addprefix $(srcdir)/,$(st_source_h))) \
$(addprefix $(srcdir)/,$(st_source_c)) \
$(srcdir)/st-enum-types.h \
$(st_cflags) \

View File

@ -0,0 +1 @@
Please keep in sync with gnome-panel.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,149 @@
/*
* Copyright (C) 2004 Free Software Foundation, Inc.
*
* 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.
*
* Authors:
* Mark McLoughlin <mark@skynet.ie>
* William Jon McCann <mccann@jhu.edu>
* Martin Grimme <martin@pycage.de>
* Christian Kellner <gicmo@xatom.net>
*/
#ifndef __CALENDAR_CLIENT_H__
#define __CALENDAR_CLIENT_H__
#include <glib-object.h>
G_BEGIN_DECLS
typedef enum
{
CALENDAR_EVENT_APPOINTMENT = 1 << 0,
CALENDAR_EVENT_TASK = 1 << 1,
CALENDAR_EVENT_ALL = (1 << 2) - 1
} CalendarEventType;
#define CALENDAR_TYPE_CLIENT (calendar_client_get_type ())
#define CALENDAR_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CALENDAR_TYPE_CLIENT, CalendarClient))
#define CALENDAR_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), CALENDAR_TYPE_CLIENT, CalendarClientClass))
#define CALENDAR_IS_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CALENDAR_TYPE_CLIENT))
#define CALENDAR_IS_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CALENDAR_TYPE_CLIENT))
#define CALENDAR_CLIENT_GET_CLASS(o)(G_TYPE_INSTANCE_GET_CLASS ((o), CALENDAR_TYPE_CLIENT, CalendarClientClass))
typedef struct _CalendarClient CalendarClient;
typedef struct _CalendarClientClass CalendarClientClass;
typedef struct _CalendarClientPrivate CalendarClientPrivate;
struct _CalendarClient
{
GObject parent;
CalendarClientPrivate *priv;
};
struct _CalendarClientClass
{
GObjectClass parent_class;
void (* appointments_changed) (CalendarClient *client);
void (* tasks_changed) (CalendarClient *client);
};
typedef struct
{
time_t start_time;
time_t end_time;
} CalendarOccurrence;
typedef struct
{
char *uid;
char *rid;
char *uri;
char *summary;
char *description;
char *color_string;
time_t start_time;
time_t end_time;
guint is_all_day : 1;
/* Only used internally */
GSList *occurrences;
} CalendarAppointment;
typedef struct
{
char *uid;
char *summary;
char *description;
char *color_string;
char *url;
time_t start_time;
time_t due_time;
guint percent_complete;
time_t completed_time;
int priority;
} CalendarTask;
typedef struct
{
union
{
CalendarAppointment appointment;
CalendarTask task;
} event;
CalendarEventType type;
} CalendarEvent;
#define CALENDAR_EVENT(e) ((CalendarEvent *)(e))
#define CALENDAR_APPOINTMENT(e) ((CalendarAppointment *)(e))
#define CALENDAR_TASK(e) ((CalendarTask *)(e))
typedef void (* CalendarDayIter) (CalendarClient *client,
guint day,
gpointer user_data);
GType calendar_client_get_type (void) G_GNUC_CONST;
CalendarClient *calendar_client_new (void);
void calendar_client_get_date (CalendarClient *client,
guint *year,
guint *month,
guint *day);
void calendar_client_select_month (CalendarClient *client,
guint month,
guint year);
void calendar_client_select_day (CalendarClient *client,
guint day);
GSList *calendar_client_get_events (CalendarClient *client,
CalendarEventType event_mask);
void calendar_client_foreach_appointment_day (CalendarClient *client,
CalendarDayIter iter_func,
gpointer user_data);
void calendar_client_set_task_completed (CalendarClient *client,
char *task_uid,
gboolean task_completed,
guint percent_complete);
void calendar_event_free (CalendarEvent *event);
G_END_DECLS
#endif /* __CALENDAR_CLIENT_H__ */

Some files were not shown because too many files have changed in this diff Show More