Compare commits

...

785 Commits

Author SHA1 Message Date
2be92900b6 Merge branch 'master' into datetime 2011-01-28 14:47:34 -05:00
e82cbf3cc8 Simplify code for 'This week' / 'Next week' logic
Also make the calendar work when there are many all-day events shown. See

 http://people.freedesktop.org/~david/many-all-day-events.png

for details.

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-28 14:30:52 -05:00
074fe3ea70 Updated Spanish translation 2011-01-28 19:50:02 +01:00
0b05280e03 Merge branch 'master' into datetime 2011-01-28 13:32:19 -05:00
5666fdefce Add a missing colon
Fixes a syntax error.
2011-01-28 13:31:16 -05:00
cd468021e2 Merge branch 'master' into datetime 2011-01-28 13:26:05 -05:00
57ebfb596b Add Evolution Data Server to required packages
Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-28 13:21:27 -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
8a1313be71 Update for comments from code review
See https://bugzilla.gnome.org/show_bug.cgi?id=632109#c41 for the review.

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-28 12:05:17 -05:00
803e74101c Merge branch 'master' into datetime 2011-01-28 11:06:58 -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
858e1b7f5b Hard-code width of calendar popup to 600px and fix ellipsis for events
We might want the width to be expressed in em or in % of the available
monitor width. Or perhaps a combination of all three. I don't know.

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-26 14:34:13 -05:00
a922db0398 Align day name to "This week"
Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-26 14:26:05 -05:00
bbd2b89df3 Collapse two-pixel borders inside the table
It's a hack, but it works

 http://people.freedesktop.org/~david/calendar-table-collapse-hack.png

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-26 14:10:34 -05:00
505b9047d7 Adjust alignment in event list
As per this comment

 https://bugzilla.gnome.org/show_bug.cgi?id=632109#c38

See

 http://people.freedesktop.org/~david/calendar-today-align-fixes.png

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-26 13:39:04 -05:00
dd8716e5d9 Don't show "[All Day] Nothing Scheduled" for "This week" or "Next week"
Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-26 13:22:46 -05: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
18f2f6f938 Forgot to add file
Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-25 15:53:07 -05:00
41b0e0832e Get events from Evolution
This commit copies existing and deployed (thus, working!) GPLv2 code
from gnome-panel into src/calendar-client. Please keep in sync.

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-25 15:42:10 -05: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
374a88366b Set up glue for native Evolution Data Server event source
Right now it's just native code returning a fake event.

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-25 12:17:32 -05:00
a71c82863e Merge branch 'master' into datetime 2011-01-25 10:10:22 -05:00
a1440bdec7 Calendar updates
- Reshuffle items to make it look more like the mockup
 - Increase vertical spacing between event section ("Today") headings
   and the event items (see mockup)
 - Don't show the year in month-switcher and event list unless it's
   a different year
 - Include the day in the date heading
 - Sort events in event list according to start time
 - Respect 12h/24h setting in event list
 - Support "All Day" events in CalendarTask abstraction
 - Show "Nothing Scheduled" if there are no events
 - Add a "Open Calendar" button
 - Refactor some of the code

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-25 10:07:54 -05: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
b10458e57a Use stippled line instead of gradient in calendar
See

 http://people.freedesktop.org/~david/shell-calendar-with-dash.png

We still have to move around some stuff to make it look like the mock-up, see

 https://live.gnome.org/GnomeShell/Design/Whiteboards/DateNTime

Thanks to Colin for binding Cairo's, set_dash() method.

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-24 16:01:08 -05:00
50c5591ec2 Merge branch 'master' into datetime 2011-01-24 15:27:13 -05: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
bce2cf9164 Switch to empty event source
We are leaving in the fake event source so it's easy to debug the
UI. This is helpful because the fake event source has a transient
event that is being added/removed every five seconds.

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-20 13:17:57 -05:00
2f52b87451 Merge branch 'master' into datetime 2011-01-20 13:11:13 -05:00
ba5a28023e Update comment about work days
Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-20 13:08:58 -05: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
0a87e28d1a Rework interaction between Calendar, EventList and EventSource abstractions
As proposed by Florian in the review.

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-19 13:55:04 -05:00
d7ad949ecb Remove separator comment lines
Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-19 13:33:19 -05:00
fd49fe6915 Use camelCase for naming
Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-19 13:31:29 -05:00
c3c34890ce Merge branch 'master' into datetime 2011-01-19 12:46:00 -05:00
af68881a94 Partial update for code review
This addresses some of the comments in

 https://bugzilla.gnome.org/show_bug.cgi?id=632109#c22

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-19 12:44:40 -05: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
0d9095d2d4 Catch up with master 2011-01-19 11:09:57 -05:00
8bc396a7e0 Adjust for merging commit 24f1e87
Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-01-19 11:08:36 -05: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
71851a58e5 Minor updates
Signed-off-by: David Zeuthen <davidz@redhat.com>
2010-12-20 15:29:14 -05:00
70f50d61e0 Merge branch 'master' into datetime 2010-12-20 15:07:50 -05: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
f3ad82442d Remove remaining references to EDS/ical
We can add this back using the Calendar.EventSource abstraction once
we are ready for it.

Signed-off-by: David Zeuthen <davidz@redhat.com>
2010-12-20 14:49:20 -05:00
6c80a35f8f Minor changes to event source code
Signed-off-by: David Zeuthen <davidz@redhat.com>
2010-12-20 14:36:29 -05:00
a2932250a7 Refactor calendar code
Signed-off-by: David Zeuthen <davidz@redhat.com>
2010-12-20 13:51:44 -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
1d5cce679a Neuter debug output 2010-12-20 11:58:56 -05: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
137ea12109 Fix merge conflicts 2010-12-20 11:55:36 -05: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
0b866a620f Rework some of the visual layout
Signed-off-by: David Zeuthen <davidz@redhat.com>
2010-12-15 17:32:35 -05:00
be59876c60 Updated Spanish translation 2010-12-15 21:59:37 +01:00
397386c761 Use SVGs from Jimmac for arrows instead of '<' and '>' glyphs
Signed-off-by: David Zeuthen <davidz@redhat.com>
2010-12-15 15:37:28 -05:00
f51984b20c Merge branch 'master' into datetime 2010-12-15 13:12:54 -05: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
8e9bc6019c Rework how fake events work
Also draw days with events with bold in the calendar view.

Signed-off-by: David Zeuthen <davidz@redhat.com>
2010-11-30 14:31:37 -05: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
51481bed82 Fix merge conflicts
Signed-off-by: David Zeuthen <davidz@redhat.com>
2010-11-30 11:11:10 -05:00
8dd05f9e7b Use fake events
Signed-off-by: David Zeuthen <davidz@redhat.com>
2010-11-30 10:50:20 -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
b7fe72e74a Merge branch 'master' into datetime 2010-11-19 07:22:28 -05:00
be6e189b49 dnd: Hide drag actor from pick
Instead of hiding the drag actor temporarily to determine the actor
beneath it, make it invisible to picks while dragging using the new
shell_util_set_hidden_from_pick().

https://bugzilla.gnome.org/show_bug.cgi?id=634560
2010-11-18 20:27:55 +01:00
1c8955b34a shell-util: Add helper to hide actors from pick
At times it is desireable to hide actors from being picked even
with a mode of CLUTTER_PICK_ALL.

Currently we use a pattern of
    clutter_actor_hide();
    clutter_stage_get_actor_at_pos();
    clutter_actor_show();
in these cases, which gets hideous if the actor we want to exclude
from the pick is located in another module.

A more elegant solution is to connect a handler to the ::pick signal,
which stops further emission.

Credit for the idea goes to Owen Taylor.

https://bugzilla.gnome.org/show_bug.cgi?id=634560
2010-11-18 20:27:55 +01:00
e5a802bf99 Use the new "background actor" functionality in Mutter
The code to draw the root background has now been moved into Mutter,
with added smarts to not draw obscured portions. Remove the old
version of the code and clone the Mutter background actor to draw
the background in the overview.

https://bugzilla.gnome.org/show_bug.cgi?id=634836
2010-11-18 14:03:37 -05:00
55f290bc96 Disable clearing the color buffer
Since we always cover the stage, we don't need to clear it to a
constant color before painting the scene.

https://bugzilla.gnome.org/show_bug.cgi?id=634769
2010-11-18 14:03:37 -05:00
909f2e670a ShellTrayManager: fix icon actor memory management
We weren't actually referencing the ShellTrayIcon actors at all
on creation, but would unreference them when they were removed,
causing crashes.

When we reference the actors, use g_object_ref_sink() so that
memory management is consistent whether or not the actors are
subsequently added to a parent actor.

Thanks for Jon McCann for help in tracking this down.

https://bugzilla.gnome.org/show_bug.cgi?id=635141
2010-11-18 13:52:35 -05:00
fa44289dd0 [PowerIcon] Fix percent label to be in sync with the description 2010-11-17 22:58:00 +01:00
deb7e7317e power-status: Remove tooltip
Status icons should not have tooltips according to the design.
2010-11-17 20:38:02 +01:00
5f1a2e3cec gnome-shell-build-setup.sh: add more deps for gnome-keyring 2010-11-17 09:44:46 -05:00
8b3f05b6e3 Status area: introduce battery & power indicator
Add an indicator for battery charge and power indication in the
system status area, using the newly exported DBus API from
gnome-power-manager.

https://bugzilla.gnome.org/show_bug.cgi?id=622451
2010-11-17 14:52:39 +01:00
21ac225981 StIcon: add support for GIcon
Add a "gicon" property so that a GIcon can be used instead of an
icon name, while still getting icon recoloring from the theme.
Also include a compatibility wrapper in libshell until GJS has
support for interface static methods.

https://bugzilla.gnome.org/show_bug.cgi?id=622451
2010-11-16 22:11:27 +01:00
0c5d87d79b PopupMenu: allow insertion of items at any point
Add a "position" argument to addMenuItem, and pass it to the
underlying box layout. If undefined or null, it adds at the end.
2010-11-16 20:42:53 +01:00
c224e019fe telepathyClient: add a missing "new" 2010-11-16 14:08:52 -05:00
aa91491730 StTooltip: Rework to use StLabel
Replaces the internal ClutterText with StLabel, so full CSS
styling is supported.

https://bugzilla.gnome.org/show_bug.cgi?id=622450
2010-11-16 19:22:01 +01:00
7bc77a23b4 build: Add libnotify to module set
libnotify is required by gnome-settings-daemon.
2010-11-16 15:33:56 +01:00
7aa3aba0c2 Merge branch 'master' into datetime 2010-11-16 09:16:38 -05:00
b8a5d3fd9b Handle new name for gnome-volume-control-applet
gnome-volume-control-applet was renamed to gnome-sound-applet when
moved to the control-center module, so we need to check for both names
when identifying the legacy status icon.
2010-11-15 18:45:36 -05:00
8734a59cd7 Handle icon theme changes
Connect to the "changed" signal on the default icon theme, and
when it triggers:

 - Evict all cached looked up icons from the StTextureCache
 - Fake a style change on all StThemeContext; this will result
   in StIcon looking up icons again.

https://bugzilla.gnome.org/show_bug.cgi?id=633866
2010-11-15 18:45:36 -05:00
e90504953f gnome-shell: When creating an extension, print where we created it
This makes it easier to find.
2010-11-15 18:43:15 -05:00
d67aa39bb1 Updated Romanian translation 2010-11-15 23:36:41 +02:00
1dc559740f Updated Romanian translation 2010-11-15 22:22:14 +02:00
a3e3d61d58 Updated Romanian translation 2010-11-15 22:22:03 +02:00
f6e9ae35fd gnome-shell-build-setup.sh: Conditionally check for autopoint on Debian/Ubuntu.
autopoint was split out into its own package in Debian lenny and thus Ubuntu 10.10

https://bugzilla.gnome.org/show_bug.cgi?id=632824
2010-11-15 08:49:06 -05:00
3c33cf425e gnome-shell-build-setup.sh: add libxklavier-devel & expat-devel to deps
Add to deps for Fedora and Debian:

 expat: needed by polkit
 libxklavier-devel: need by libgnomekbd

Based on a patch by Kiyoshi Aman <kiyoshi.aman@gmail.com>.

https://bugzilla.gnome.org/show_bug.cgi?id=634865
2010-11-14 19:31:21 -05:00
141b4ffe87 StFocusManager: don't unref removed groups
It is not referencing them when adding, and also it is connecting
to the "destroy" signal, emitted on dispose, so there is no risk
of storing finalized objects.

https://bugzilla.gnome.org/show_bug.cgi?id=634781
2010-11-14 20:51:27 +01:00
35d8780186 Added UG translation 2010-11-14 00:05:37 +01:00
d11ea7d6cd Added UG translation 2010-11-13 22:26:32 +01:00
3138b20b11 Skip drawing transparent borders and backgrounds
We were always drawing the border and background of each
StThemeNode, even if they were transparent. The simple
optimization of checking the alpha provides a significant
performance boost (in a quick test, it increased the
overviewFpsSubsequent metric in the core performance test
from 28fps to 35fps).

https://bugzilla.gnome.org/show_bug.cgi?id=634752
2010-11-13 10:12:40 -05:00
c3fb3a98b8 Remove invisible status from menu
It was decided at GNOME Summit that we would remove the invisible
setting until we have a better story for how it works with chat
and other sharing/messaging applications.  We'd also need to
figure out how it relates to busy.
2010-11-13 09:30:16 -05:00
32cc136563 Remove Restart option from session menu
The action is far less common than powering off.  It is mostly
used for performing system updates so the update tool should
offer the option directly.  Also, currently the Shut Down option
dialog offers Restart anyway.  We would like to keep the number
of entries in this menu as limited (close to 7) as we can.
2010-11-13 08:43:45 -05:00
63e89482fe Use Settings and not Preferences for sound menu
To match the tool that it launches.
2010-11-13 08:43:45 -05:00
e8917e2d6f Fix build of run-js-test
https://bugzilla.gnome.org/show_bug.cgi?id=634736

Signed-off-by: Adel Gadllah <adel.gadllah@gmail.com>
2010-11-13 10:26:48 +01:00
a2f4e196a1 Icon test case fixes
put a border around the "16px icon in 48px icon widget" test, to
verify that the icon is being centered correctly

add spacing and fix alignment for general prettiness

https://bugzilla.gnome.org/show_bug.cgi?id=633865
2010-11-12 22:28:22 -05:00
dc1e23501c Remove _for_theme() variant of st_texture_cache_load_icon_name()
Now that we're using St.Icon in the Javascript, there is no reason
to have separate st_texture_cache_load_icon_name() and
st_texture_cache_load_icon_name_for_theme(), instead just add
the StThemeNode argument to st_texture_cache_load_icon_name().

https://bugzilla.gnome.org/show_bug.cgi?id=633866
2010-11-12 17:36:26 -05:00
0e3431ac47 Use St.Icon for named icons
Switch from St.TextureCache.load_named_icon() to using St.Icon for named
icons. Along with the advantage of getting colorization right for symbolic
icons, this allows moving some icon sizes into the CSS.

In the CSS, the system status icon size is changed to be 1em (=16px for the
default font size), at the request of the artists. See bug 613448.

https://bugzilla.gnome.org/show_bug.cgi?id=633865
2010-11-12 17:36:26 -05:00
af7ba00e97 StIcon: pass in the StThemeNode to get colorized symbolic icons
Use st_texture_cache_load_icon_name_for_theme() so that we get the
right colors for symbolic icons. The code refactoring to achieve this
also avoids constantly starting a new icon load each time we set
a property on initialization ... the icon is loaded only after we
have a #StThemeNode assigned.

https://bugzilla.gnome.org/show_bug.cgi?id=633865
2010-11-12 17:36:26 -05:00
8d6ab6fe84 Add st_widget_peek_theme_node()
Sometimes it's useful to get the theme node if there is one and do
nothing and wait for the ::style-changed signal if there is no theme
node. Add st_widget_peek_theme_node() that just gets the current
theme node if available. The caller must handle a %NULL return.

https://bugzilla.gnome.org/show_bug.cgi?id=633865
2010-11-12 17:36:26 -05:00
4917c79d09 StTextureCache: support loading a named icon with colors from a theme node
Add st_texture_cache_load_icon_name_for_theme() which, when loading a
symbolic icon, gets a #StIconColors from the theme node and uses that
to colorize the icon.

https://bugzilla.gnome.org/show_bug.cgi?id=633865
2010-11-12 17:36:26 -05:00
04da2a61db Add StIconColors object, compute in StThemeNode
A new StIconColors object is used to efficiently track the colors
we need to colorize a symbolic icon.
st_theme_node_compute_icon_colors() is added to compute the
StIconColors for a theme node. (Refcounting of StIconColors means
that we'll typically share the colors object of the parent node.)

https://bugzilla.gnome.org/show_bug.cgi?id=633865
2010-11-12 17:36:26 -05:00
3ca86b2197 StIcon: Center the icon rather than scaling it up
Scaling up icons from the loaded size to a larger size is uniformly
ugly and results in a long series of "fuzzy icon" bugs. It's better
to just load at the specified size and center. (Centering can be
overridden by packing not-fill in the parent container.)

https://bugzilla.gnome.org/show_bug.cgi?id=633865
2010-11-12 17:36:25 -05:00
35400238aa StIcon: Always request a square icon size
We don't want the layout to change when we say, change from
battery-full to battery-full-charging, so we should request a square
based on the icon size unconditionally and not try to adapt to the
size of the texture we loaded. This also means that our layout is
independent of the loaded texure which, if we switch away from
using a ClutterActor child will allow us not queue a relayout when
the icon finishes loading.

https://bugzilla.gnome.org/show_bug.cgi?id=633865
2010-11-12 17:36:25 -05:00
439d7f036f Port StIcon from MX framework to St framework
Make StIcon compile and work in St.

Changes:

 * ::icon-type and st_icon_set_icon_type are added to allow
   specifying SYMBOLIC/FULLCOLOR for an icon.
 * Ability to set the icon name from the theme is removed; it
   wouldn't easily fit into our framework and two levels of
   abstraction between code and image doesn't seem that useful.
 * size CSS property is renamed from x-st-icon-size to icon-size
   to correspond to what we are doing elsewhere.
 * CSS and property based icon sizing are cleanly layered - if
   you set the icon-size property, the CSS size is ignored.
 * Add a simple JS test of StIcon.

https://bugzilla.gnome.org/show_bug.cgi?id=633865
2010-11-12 17:36:25 -05:00
aed6375a2d Move StIconType to st-types.h from st-texture-cache.h
StIconType will be used by a new StIcon class, so move it to the
header file of common enumerations. Including st-types.h which had
the St single-include check revealed that st-texture-cache.h didn't
have that check and several places were including that directly.
Fix that up.

https://bugzilla.gnome.org/show_bug.cgi?id=633865
2010-11-12 17:36:25 -05:00
a9a8b1ec6a StIcon: Remove content-image capability
The ability to set a "content image" on an icon relies on the ability
to have custom theme properties of a "border image" (9-slice) type.
We don't have this, and the capability of a bordered image specified
by the theme can be achieved more naturally with standard CSS facilities.

https://bugzilla.gnome.org/show_bug.cgi?id=633865
2010-11-12 17:36:25 -05:00
b0e713b775 StIcon: use g_strcmp0()
Simplify a check for an unchanged string with g_strcmp0().

https://bugzilla.gnome.org/show_bug.cgi?id=633865
2010-11-12 17:36:25 -05:00
32fc25a3ac StIcon: Adopt copyright notice to standard
- Replace FSF address with URL
- Remove explicit Authors: list

https://bugzilla.gnome.org/show_bug.cgi?id=633865
2010-11-12 17:36:25 -05:00
839492f15b Import MxIcon as StIcon
https://bugzilla.gnome.org/show_bug.cgi?id=633865
2010-11-12 17:36:25 -05:00
c98103ffc8 Add run-js-test executable to run tests
ST makes use of GTK+ for input methods and for icon themes; therefore
we have need to initialize GTK+ in order to test these parts of Clutter.

Instead of LD_PRELOADING our module, use a separately compiled executable
that links to the UI components in GNOME Shell, initializes Clutter and
GTK+ and hooks them together.

Getting all the symbols from St and the GUI components exported for
use via GJS requires a bit of contortion: we need to actually link the
St convenience library into a shared library and link the executable
to that since there is no way with libtool to take a convenience library
and put all its symbols into an executable --whole-archive style.

https://bugzilla.gnome.org/show_bug.cgi?id=633657
2010-11-12 17:36:20 -05:00
86f3a637f1 st_texture_cache_load_from_raw: Don't pointlessly include size in cache key
The texture is independent of the size that the user passed in; so there
is no obvious reason to include the texture in the cache key.

https://bugzilla.gnome.org/show_bug.cgi?id=633595
2010-11-12 17:34:16 -05:00
e381f0f492 build-setup: Add missing build-dependency
polkit requires pam-devel to build. Add the package to the list
of dependencies in the setup script.
2010-11-12 21:35:07 +01:00
ce72aaf008 Fix up copyright and license notices for St
* Make sure all source files have a LGPL copyright header, and standardize
  non-standard variations of the header to a common form.

* Check and update all copyright notices.

* Remove 'Written By:' lines. They are universally incomplete and
  typically indicate only who started a particular file.

https://bugzilla.gnome.org/show_bug.cgi?id=634550
2010-11-12 15:23:28 -05:00
d79cae07a4 Depend on master gnome-settings-daemon
The new Universal Access menu uses GSettings schema from master
g-s-d. Ensure that these are installed, or we crash.

https://bugzilla.gnome.org/show_bug.cgi?id=634693
2010-11-12 20:26:20 +01:00
b2495a0e25 a11y-status: Fix left over GConf usage
Commit f0c6e96e82 updated the "Large Text" action to use a GSettings
key, but left some code accessing the setting via GConf.

https://bugzilla.gnome.org/show_bug.cgi?id=634693
2010-11-12 19:43:52 +01:00
f0c6e96e82 Status area: update accessibility menu
gnome-settings-daemon has moved to GSettings for most settings, we
should adapt as well. The only remaining GConf key is for metacity
(visual bell).

https://bugzilla.gnome.org/show_bug.cgi?id=634693
2010-11-12 18:44:52 +01:00
ac1b814851 Revert "Transition the ShellApp state when ready."
This reverts commit c171ea12df.
2010-11-12 18:41:54 +01:00
614bcd8016 Update volume indicator labels
It turns out 'Output' and 'Input' are too technical for the novice
user. Use 'Volume' and 'Microphone' instead.

https://bugzilla.gnome.org/show_bug.cgi?id=634329
2010-11-12 17:47:19 +01:00
c171ea12df Transition the ShellApp state when ready.
shell_app_state_transition emits a signal, so invoke it only when
ready, or signal handlers will see an object which is in an invalid
state.

https://bugzilla.gnome.org/show_bug.cgi?id=632501
2010-11-12 17:43:05 +01:00
b856e2990b StScrollView: null out the right variable in dispose
We weren't properly nulling out the vadjustment variable in dispose()
which meant in the case of explicit-destroy followed some time later
by garbage collection and disposing the actor again we would crash.
2010-11-11 08:41:07 -05:00
e4cf3f144d Mark gsettings-desktop-schemas as a dependency of gnome-desktop-3
gsettings-desktop-schemas is required by, so needs to be built before
gnome-desktop-3.

https://bugzilla.gnome.org/show_bug.cgi?id=634552
2010-11-11 08:41:06 -05:00
f25e6916bd Remove unused StSubtexture 2010-11-10 22:00:11 -05:00
ad624d546f st-texture-cache: Fix include
The file gnome-desktop-thumbnail.h was moved from libgnomeui to
libgnome-desktop.

https://bugzilla.gnome.org/show_bug.cgi?id=634555
2010-11-11 01:42:30 +01:00
6df21fd5ff never fall back to the window title as application name
https://bugzilla.gnome.org/show_bug.cgi?id=624935
2010-11-10 01:32:55 +03:00
392999bc43 Make opening and closing LookingGlass slow-down independent
Waiting for LookingGlass to close after calling St.set_slow_down_factor()
is annoying so divide the time for opening and closing by the slow-down
factor.
2010-11-09 14:39:36 -05:00
013f07278b Bump version to 2.91.2 2010-11-08 15:14:20 -05:00
35f806df4e St: add keyboard support to StClickable and StButton
Allow triggering clicks with space/return

https://bugzilla.gnome.org/show_bug.cgi?id=633853
2010-11-08 13:06:41 -05:00
4f1f226828 StButton: fix hover and grab tracking
Use StWidget:track-hover rather than doing it ourselves. Don't assume
that hover is always TRUE after an enter_event or FALSE after a
leave_event, since we have a pointer grab and will be getting other
actors' events.

Don't ungrab the pointer when it leaves the button, since that
destroys the whole point of getting a grab in the first place.

Only consider the button to have been clicked when it has both grab
(meaning the mouse was pressed over the button) and hover (meaning the
mouse was released over the button).

Also remove the virtual pressed/released methods, which weren't being
used anyway.

https://bugzilla.gnome.org/show_bug.cgi?id=633853
2010-11-08 13:06:41 -05:00
4c6dd64e87 StButton: fix code style
https://bugzilla.gnome.org/show_bug.cgi?id=633853
2010-11-08 13:06:41 -05:00
a381017e83 Updated Brazilian Portuguese translation 2010-11-08 15:21:44 -02:00
34aa46a844 app-menu: Fix quit menu item
As popup menus now take focus for keyboard navigation, no application
is focused when activating the menu. Use the target application instead,
which keeps track of the application currently associated with the menu.

https://bugzilla.gnome.org/show_bug.cgi?id=634103
2010-11-05 19:02:53 +01:00
dc58a4f407 Update Simplified Chinese translation. 2010-11-03 16:18:31 +08:00
0428234c67 Updated Galician translations 2010-11-03 00:28:57 +01:00
0155226c73 telepathy: makeProxyClass has been migrated to gjs's dbus module
https://bugzilla.gnome.org/show_bug.cgi?id=633490
2010-11-02 11:11:29 -04:00
9585c823d5 MessageTray: only create icon buttons if specifically requested
Action names sometimes unintentionally overlap with icon names, so
we should only create icon buttons if the message tray source requests
it.  For the notification daemon, this is done by setting the
'action-icons' hint on the notification.

The previous notification server capability used to advertise this
feature, "x-gnome-icon-buttons", has been removed in favour of the
new capability described in the notification spec, "action-icons".

https://bugzilla.gnome.org/show_bug.cgi?id=624584
2010-11-02 19:17:29 +10:00
31df386fed build: fix syntax error in setup script 2010-11-01 14:28:56 -04:00
11794e3da9 build: Add missing libcanberra build deps on Debian 2010-11-01 13:30:18 -04:00
c6f6ac926e build: Add missing libcanberra build deps on Fedora 2010-11-01 13:30:05 -04:00
79a33fa7fb gnome-shell.modules: add libcanberra
The volume status icon requires libcanberra; we could get by with
packages so far, but we will need a very very recent libcanberra soon
anyway, so just require that.

https://bugzilla.gnome.org/show_bug.cgi?id=633418
2010-11-01 11:34:09 -04:00
909ec7a709 Fix cursor image tracking on 64-bit systems
Like all X API, XFixesGetCursorImage returns arrays of 32-bit
quantities as arrays of long; on 64-bit systems we need to
convert to an array of 32-bit words before creating a texture
from the result.

https://bugzilla.gnome.org/show_bug.cgi?id=633591
2010-11-01 11:11:01 -04:00
576376a21b magnifier: Change default values
mccann: we should default to full screen with mouse position as
"proportional"

https://bugzilla.gnome.org/show_bug.cgi?id=629884
2010-11-01 16:03:28 +01:00
0c2aa1437d magnifier: Sync MouseTrackingMode values with the gsettings enum
The tracking modes "push" and "proportional" are swapped.

https://bugzilla.gnome.org/show_bug.cgi?id=629884
2010-11-01 16:03:28 +01:00
bff553e978 PopupSliderMenuItem: connect to scroll-event on the whole actor
Connect to scroll-event on .actor, not ._slider, so you can scroll
on the whole menu item.

https://bugzilla.gnome.org/show_bug.cgi?id=633668
2010-11-01 14:25:59 +01:00
ab206ff82a Updated Hebrew translation. 2010-11-01 07:48:16 +02:00
75e608f039 Updated Spanish translation 2010-10-31 21:50:18 +01:00
2fe7507689 Use the GNOME 3 WM theme by default
Set up an override to specify the metacity window decoration
theme.  Use the GNOME 3 standard theme as the default.
2010-10-31 11:58:44 -04:00
cbed9f956a Explicitly set the repos for the new modules just added
We don't set a default repo for the moduleset.
2010-10-31 11:40:47 -04:00
6d115dd23b Add new standard GNOME 3 themes
Replaces gtk-engines-3.
2010-10-31 11:37:10 -04:00
8bbfa913cb Adjust appSwitcher and workspaceSwitcher popup to match mockups 2010-10-31 17:16:20 +01:00
65a7b042ed Update Czech translation 2010-10-31 12:10:40 +01:00
3640a4dd1e Increase the timeout for hiding the tray if the mouse didn't move far from it
We shouldn't hide the tray as quickly if the user might have left it
unintentionally, such as when moving the mouse over to a different tray item or
using the scroll bar in the chat notification.

https://bugzilla.gnome.org/show_bug.cgi?id=630767
2010-10-30 17:20:13 -04:00
d5f1cd667b Use System Settings instead of Preferences in the user menu (again)
This matches the terminology used in the result of the action.

also see commit 4a316fbc66
2010-10-30 13:50:10 -04:00
8f307c858c Updated Arabic translation 2010-10-30 13:33:43 +02:00
f21403fd9f pushModal: clear focus after pushing a new level
This way the new modal level is independent of whatever may have been
happening before. Fixes a problem with status menus becoming active
again from inside the app switcher, etc.
2010-10-29 15:06:01 -04:00
a19e8d58f5 Do not remove destroyed actors from their container
The container already connects to destroy and will do that for us,
preventing a warning.

https://bugzilla.gnome.org/show_bug.cgi?id=633028
2010-10-29 20:05:32 +02:00
08f7ecad35 Don't remove the tray icons we don't add
Tray icons replaced by a shell version are automatically filtered
and never make to the tray container, but when removed by the client
we were still trying to remove them from the tray, causing a warning.

https://bugzilla.gnome.org/show_bug.cgi?id=633028
2010-10-29 20:05:31 +02:00
548a23a969 PopupMenu: redo keynav using St.FocusManager
Each menu is a focus manager group, but there is also some explicit
focus handling between non-hierarchically-related widgets. Eg, to move
between menus, or from a menubutton into its menu.

https://bugzilla.gnome.org/show_bug.cgi?id=621671
2010-10-29 08:38:05 -04:00
5a83ef8325 St: add StFocusManager, to handle keyboard navigation
StFocusManager allows setting up "focus groups" in which it will
automatically handle navigation between can_focus widgets.

https://bugzilla.gnome.org/show_bug.cgi?id=621671
2010-10-29 08:38:05 -04:00
d2b968a7df St: add keyboard focus navigation support
Add StWidget:can-focus, st_widget_navigate_focus(), and
st_container_get_focus_chain(), and implement as needed to allow
keyboard navigation of widgets.

https://bugzilla.gnome.org/show_bug.cgi?id=621671
2010-10-29 08:38:05 -04:00
58001563d9 update translation and completed 2010-10-29 08:13:46 +05:30
8872913665 StThemeNode: Fix the confusion between border and background
In d66e7dd49 I got confused between border_texture and
background_texture. The background_texture was being created as normal
but in the one place that it gets drawn I accidentally made it use the
border_material instead. This patch makes it create a
background_material similar to the border_material and uses it to
paint.
2010-10-28 21:51:13 +01:00
d66e7dd49e st-theme-node-drawing: Don't create lots of one-shot materials
A few places in st-theme-node-drawing create one-shot material, paint
with it and then free it. This is suboptimal with current Cogl because
it will end up compiling an ARBfp program just for that single paint
and then it will throw it away when the material is destroyed.

There is a new function in st-private.c called
_st_create_texture_material. This creates a simple material for a
texture based on a common parent material that points to a dummy
texture. Any materials created with this function are likely to be
able to share the same program unless the material is further modified
to contain a different number of layers. It would be possible to use
cogl_set_source_texture for this instead except that it's not possible
to modify the material's color in that case so we couldn't render the
texture with opacity.

The corner textures are now stored as a handle to a material that
references the texture rather than storing the texure directly. There
is also a separate border_material member which always points to
border_texture as the only layer.

https://bugzilla.gnome.org/show_bug.cgi?id=633340
2010-10-28 20:02:41 +01:00
f365484a5c popupMenu: fix spacing between columns
This patch didn't get updated for the st_theme_node_get_spacing() change.
2010-10-28 14:03:45 -04:00
eb66993447 Merge branch 'master' into datetime 2010-10-28 13:34:27 -04:00
7d5b4511cd Update datetime branch for latest changes
Signed-off-by: David Zeuthen <davidz@redhat.com>
2010-10-28 13:33:12 -04:00
c3e557b162 Updated Norwegian bokmål translation. 2010-10-28 17:38:52 +02:00
b411425e1e build: Remove --with-gtk=3.0 argument for mutter
Mutter does now depend unconditionally on GTK+-3.0, so the configure
switch has been removed.
2010-10-28 12:15:37 +02:00
e18d8b2fe8 Updated Hebrew translation. 2010-10-28 08:58:22 +02:00
81982beef4 Updated Spanish translation 2010-10-28 01:46:47 +02:00
0cdad5ac02 Bump version to 2.91.1 2010-10-27 19:09:37 -04:00
1c3bddda41 Add gvc-mixer-control.c to POTFILES.in 2010-10-27 19:09:37 -04:00
5d9b109f06 notificationDaemon: add missing gettext import 2010-10-27 16:00:51 -04:00
4d0480bfea Small update of Simplified Chinese translation. 2010-10-27 16:27:51 +00:00
580e3d2b74 Updated Slovenian translation 2010-10-26 19:39:03 +02:00
3d1063dacb Merge branch 'master' into datetime
Conflicts:
	configure.ac
2010-10-26 11:48:34 -04:00
ec018a000e Updated Galician translations 2010-10-26 16:37:39 +02:00
e5dd86276d PopupSwitchMenuItem: don't misuse this.active
The constructor was setting this.active to reflect the switch state,
which is wrong; this.active indicates whether or not the item is
highlighted.

https://bugzilla.gnome.org/show_bug.cgi?id=621671
2010-10-26 10:16:03 -04:00
9ae1238038 Updated Spanish translation 2010-10-26 10:45:02 +02:00
f8dc32c366 Updated Hebrew translation. 2010-10-26 08:20:57 +02:00
2b3c31a503 boxpointer: keep a margin between the box and the screen edge
per the mockups

https://bugzilla.gnome.org/show_bug.cgi?id=631193
2010-10-25 17:04:30 -04:00
9d94da83d7 statusMenu: show a radio button-style dot next to the presence status
Adding a "PopupMenuRadioButtonItem" wouldn't work well, because we'll
need radio-button indicators on multiple different styles of menu
item. Also, the current design draws the indicator in the menu item's
padding, so it's sort of special anyway. So just add support at the
BaseMenuItem level.

Also, redo the menu/menuitem padding so that all the horizontal
padding is in the menu item, or else the indicator dot will show up in
the wrong spot.

https://bugzilla.gnome.org/show_bug.cgi?id=631193
2010-10-25 17:04:30 -04:00
5661946de1 popupMenu: make menu layout more table-like
When there are menu items with right-aligned items, all the
right-aligned items should appear to the right of all the left-aligned
items.

Clutter doesn't have an equivalent of GtkSizeGroup, so hack something up
using ShellGenericContainer and some javascript.

https://bugzilla.gnome.org/show_bug.cgi?id=631193
2010-10-25 17:01:10 -04:00
fa752110f3 statusMenu: fix menu items to match latest mockups
Rename a few, and add Suspend and Restart, although currently they do
the same thing as Shut Down (ie, they bring up a dialog that lets you
do any of those three). This will be fixed later when we have the
in-shell modal dialogs for these features.

https://bugzilla.gnome.org/show_bug.cgi?id=631193
2010-10-25 16:54:45 -04:00
86efdc906a PopupImageMenuItem: always show icon, on the right, not the left
In the new mockups, the user menu icons are on the right, not the
left.

Also, get rid of the idea of optional icons; the design doesn't have
icons on those items, and there probably aren't going to be symbolic
versions of some of those icons anyway. So if the caller specifies
PopupImageMenuItem, then always show an icon, and just use regular
PopupMenuItems for the items that don't have icons in the current
design.

https://bugzilla.gnome.org/show_bug.cgi?id=631193
2010-10-25 16:54:45 -04:00
c217377114 main: use Meta.Display.get_keybinding_action for PrintScreen as well
(and trigger it on keyrelease rather than keypress, like the other
bindings)

https://bugzilla.gnome.org/show_bug.cgi?id=632151
2010-10-25 16:40:44 -04:00
6064661de9 gnome-shell.modules: order GConf after gtk3
GConf has test programs that link against GTK+, and defaults to
using gtk3 if found, so build GConf after gtk3.
2010-10-25 15:23:02 -04:00
ef544f6e06 add /usr/local/share/applications to gs-applications.menu
https://bugzilla.gnome.org/show_bug.cgi?id=630866
2010-10-25 19:49:26 +04:00
c48c80e4e9 Allow for empty WM_CLASS and _NET_WM_NAME in tray icons
The system tray specification says the hint should be set, but some
icons leave it empty anyway. Don't throw exceptions in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=633028
2010-10-25 16:01:32 +02:00
a915af4b30 Avoid warnings on leave-event for widgets tracking hover
ClutterCrossingEvent->related can be NULL if the pointer is not under
any actor. Unconditionally set hover to FALSE in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=633028
2010-10-25 15:18:07 +02:00
bc22109130 Avoid warnings on null actors for tray icons
Plugging the GtkSocket icon can fail, in which case NaTrayManager emits
tray-icon-removed but the icon has never emitted plug-added, thus the
ShellTrayIcon has not been created. This results in various criticals
and exceptions in the tray-icon-removed handler.

https://bugzilla.gnome.org/show_bug.cgi?id=633028
2010-10-25 15:18:07 +02:00
17055023db Updated galician translations 2010-10-25 01:02:24 +02:00
95ac478f87 dnd: Handle destruction of drag actor during drag
The shell crashes if the drag actor is destroyed during the drag
operation. Cancel the drag gracefully in this case.
https://bugzilla.gnome.org/show_bug.cgi?id=620389
2010-10-24 05:47:54 +04:00
2fa6f7ba7e Adapt to removal of Mutter namespace
MutterWindow and MutterPlugin have been renamed to MetaWindowActor
and MetaPlugin, mutter_plugin_list_windows() to
meta_plugin_list_window_actors(). Adapt to those changes.

https://bugzilla.gnome.org/show_bug.cgi?id=632500
2010-10-23 14:02:45 -04:00
6b47b78d4d Fix audio volume icon
_volumeChanged should not update the icon if the sink is muted.
Fixes the case when shell is started with a muted sink (_mutedChanged
is called before _volumeChanged).

https://bugzilla.gnome.org/show_bug.cgi?id=632868
2010-10-22 15:52:59 +02:00
3dbee0b833 PopupSliderMenuItem: Implement mousewheel support
Allow changing the slider's value using the mousewheel.

https://bugzilla.gnome.org/show_bug.cgi?id=632743
2010-10-21 22:48:39 +02:00
8886b7433c StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.

So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)

And update the code to use either the old or new methods as appropriate.

https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-10-21 15:02:33 -04:00
85d3336245 Use gjs-internals.pc
Gjs changed to separate the "basic" API from "embedder" API.  Unfortunately
due to our use of the importer API and a few other bits, we need to use
the "module" one.  In the future I plan to extend the core API to
support this use case.
2010-10-21 10:56:11 -04:00
33e955770c st_theme_node_get_color: fix inheritance
This wasn't actually recursing if you passed the "inherit" flag

https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-10-21 09:13:30 -04:00
be7b9729a2 Updated Hebrew translation. 2010-10-20 23:50:59 +02:00
10e59c0840 volumeIndicator: Add mousewheel support
Allow changing the volume by moving the mousewheel over the volume indicato
to restore the old gnome-volume-control-applet behaviour.

https://bugzilla.gnome.org/show_bug.cgi?id=632733
2010-10-20 22:05:14 +02:00
fe1a9c2b4b Fix showing input volume
Fix two typos in code that decided whether to show input volume and
mute switch.
2010-10-20 21:30:26 +02:00
ac470b44ef Fix control center panel for audio.
It is "sound", not "volume".
2010-10-20 21:24:15 +02:00
b4c038c036 calendar: implement Events List
Signed-off-by: David Zeuthen <davidz@redhat.com>
2010-10-20 14:30:35 -04:00
1ca1a2712d Merge branch 'master' into datetime 2010-10-20 13:55:41 -04:00
0547a582d1 Add volume indicator
Add volume control indicator which uses API from gnome-volume-control
to interact with PulseAudio and shows both input and output volumes.
Also adds a small wrapper around libcanberra in ShellGlobal, used by the
volume indicator to provide auditive feedback.

https://bugzilla.gnome.org/show_bug.cgi?id=629455
2010-10-20 16:59:12 +02:00
a1389a0730 Updated Dutch translation by Reinout van Schouwen 2010-10-19 23:19:24 +02:00
ee7e46fbf6 Solve spacing issue in system status area
Shell implemented indicators got padding from default button style,
and also spacing from their container, so too much space was left
between them. This only became apparent when more than one was
implemented, though.
2010-10-19 22:42:25 +02:00
13229a6d86 MessageTray: use boxpointer for summary notification
https://bugzilla.gnome.org/show_bug.cgi?id=624900
2010-10-19 23:23:10 +04:00
3efc7bf7f1 boxpointer: add setPosition method
split out this function from popupMenu
https://bugzilla.gnome.org/show_bug.cgi?id=624900
2010-10-19 23:23:05 +04:00
4d18d54d9d boxpointer: add animateDisappear/animateAppear methods
https://bugzilla.gnome.org/show_bug.cgi?id=624900
2010-10-19 23:23:00 +04:00
ccaa3f4ebf gnome-shell-build-setup.sh: add libpulse to package lists 2010-10-19 15:18:38 -04:00
8064c6c827 Add private gnome-volume-control library
The library is introspected, and should not require using
Pulseaudio directly.

With help from Giovanni Campagna <scampa.giovanni@gmail.com>
(introspection annotations, build fixes)

https://bugzilla.gnome.org/show_bug.cgi?id=629455
2010-10-19 15:24:04 +01:00
a5d4abda00 st-theme: ref items in custom stylesheets list
st-theme stores some loaded stylesheets in a custom
stylesheets list.  When removing items from this list
it unrefs them, but when adding items to the list it
neglects to ref them.  This means that under certain
circumstances the list will contain items that have
already been freed.

https://bugzilla.gnome.org/show_bug.cgi?id=632477
2010-10-18 15:52:38 -04:00
6df48b68fa extensionSystem: Don't load extensions multiple times
Right now if XDG_DATA_DIRS is set to have duplicate entries,
then the extension system will try to load all extensions
more than once.

This commit prevents an extension from getting repeatedly
loaded by checking if its uuid is already registered.

https://bugzilla.gnome.org/show_bug.cgi?id=632477
2010-10-18 12:28:36 -04:00
20b10b4d16 [l10n] Updated Italian traslation 2010-10-18 11:23:06 +02:00
6bdfe638c5 Updated Spanish translation 2010-10-18 11:17:13 +02:00
67543775e9 [l10n] Added missing accessibility.js to POTFILES.in 2010-10-18 10:57:55 +02:00
25c6acf44b [l10n] Updated Estonian translation 2010-10-17 17:31:04 +03:00
83aa23b274 [l10n] Updated Estonian translation 2010-10-17 17:03:20 +03:00
4333b829eb Updated Norwegian bokmål translation 2010-10-16 21:24:19 +02:00
42c736614c st-drawing-area: Avoid unnecessary repaints
StDrawingArea uses the member variable needs_repaint to keep track
of whether it needs repainting. The variable is set to TRUE correctly,
e.g. on allocation or style changes - alas, it is never set to FALSE,
resulting in the area being repainted continuously.

https://bugzilla.gnome.org/show_bug.cgi?id=632197
2010-10-15 12:31:34 +02:00
700911ca5f gdm: mute debug messages
Since we're just using a cut-and-paste of gdm code there's a
slight impedance mismatch between how that code and the rest of
the shell manage debug messages.  In GDM, they're out of sight by
default, but in gnome-shell they're visible and quite verbose.
This muddies up and masks the useful messages that other parts
of the code generate.

This commit just mutes the messages unconditionally by default,
since they aren't that useful anyway.
2010-10-14 13:35:04 -04:00
627f1cb59a iconGrid: Add alignment parameter
Currently the grid's content is centered, which is not appropriate
for all use cases. Add an optional parameter to control the alignment.

https://bugzilla.gnome.org/show_bug.cgi?id=632147
2010-10-14 17:41:54 +02:00
ba0a038247 statusMenu: port to new gdmuser api
https://bugzilla.gnome.org/show_bug.cgi?id=631888
2010-10-13 19:05:54 -04:00
7ce5ea4142 gdm: resync cut-and-paste code from gdm tree.
The GDM code upstream talks to the account service now,
has better introspection annotations, and is more
asynchronous.

This commit updates the shell's copy to the latest
upstream.

Note, the API changed somewhat and so the callers will
need to be fixed up subsequently.

https://bugzilla.gnome.org/show_bug.cgi?id=631888
2010-10-13 19:05:54 -04:00
85ec4d86f3 Start implementing the Date and Time mockups 2010-10-13 17:53:26 -04:00
9bfda11f0d Updated Spanish translation 2010-10-13 14:30:04 +02:00
1facd85981 Updated Spanish translation 2010-10-13 01:25:39 +02:00
630227f6b6 configure: Require GTK+ 2.91.0
We don't build with earlier any longer.
2010-10-12 18:24:01 -04:00
bbdf88cf94 NotificationDaemon: don't destroy trayicons when dismissing their notifications
Tray icons control their own lifespan; they're not supposed to
disappear when you dismiss their notifications like non-trayicon
notification sources do.

https://bugzilla.gnome.org/show_bug.cgi?id=631042
2010-10-12 17:21:58 -04:00
de16108dff MessageTray: untangle click notifications
Previously, when you clicked on a notification, it would call
this.source.clicked(), which would emit a 'clicked' signal on the
source, and then various other stuff would happen from there. This
used to make a little bit of sense, when clicking on a notification
was supposed to do the same thing as clicking on its source, but makes
less sense now, when clicking on the source itself *doesn't* call
source.clicked()...

Change it so that when you click on a notification, the notification
emits 'clicked' itself, and the source notices that and calls its
notificationClicked() method, and the various source subclasses do
what they need to do with that, and Source no longer has a clicked
method/signal.

https://bugzilla.gnome.org/show_bug.cgi?id=631042
2010-10-12 17:21:58 -04:00
80f23841e4 Updated Spanish translation 2010-10-12 21:56:28 +02:00
df65d3d58c Updated Slovenian translation 2010-10-12 20:08:25 +02:00
66f6fff54e Add "persistence" server capability
This will allow clients to determine that the server has notification persistence.

https://bugzilla.gnome.org/show_bug.cgi?id=631722
2010-10-11 14:48:36 -04:00
ad557a3515 ShellRecorder: Include math.h for M_PI
https://bugzilla.gnome.org/show_bug.cgi?id=631510
2010-10-11 14:29:46 -04:00
0215a449ad MessageTray: fix wobbling during summaryitem animation
Redo the way that the summary item expand/collapse animation works so
that the items all resize in unison so that when moving from one to
another, the summary area as a whole stays a constant width rather
than wobbling slightly.

(Also rename all references to the "minimum" summary item title width,
since it's not a minimum, it's just the width.)

https://bugzilla.gnome.org/show_bug.cgi?id=630546
2010-10-11 11:51:56 -04:00
bd250e188b [ShellAppSystem] Don't use g_desktop_app_info_new
It doesn't fully support convert id to path. For example: multiply
subdirs, "LegacyDir prefix" in .menu files...
https://bugzilla.gnome.org/show_bug.cgi?id=614879
2010-10-11 18:37:21 +04:00
826e9c5dbf [i18n] Updated German translation 2010-10-10 20:49:47 +02:00
30f628d1eb Updated Spanish translation 2010-10-10 05:13:41 +02:00
bf978c61af Updated Spanish translation 2010-10-08 16:51:02 +02:00
5ebbd72d1c Updated Spanish translation 2010-10-07 18:02:43 +02:00
47c80d4d55 Updated Galician translations 2010-10-07 13:20:43 +02:00
4e14f18a58 Add the banner to the body if the notification is expandable because it has an action area
This fixes the bug when the body would be missing from the expanded notification
that has a short body that used to fit in the one-line banner and is expandable
because it has action buttons.

We always want to add the banner to the body of an expandable notification,
unless the notification has custom content. We used to only do that when
creating this._scrollArea for the content. We should also do that when creating
this._actionArea .

https://bugzilla.gnome.org/show_bug.cgi?id=631566
2010-10-06 17:43:59 -04:00
4456954d30 [panel] Only show starting applications for current workspace
Add the workspace we started on to ShellApp.  Use it inside panel.js
to filter the list.
https://bugzilla.gnome.org/show_bug.cgi?id=623688
2010-10-07 01:31:22 +04:00
6925a82204 [ShellApp] refactor handling startup sequence
1. move logic to shell-app.c
2. change state to RUNNING only after startup sequence complete
3. correct handle state for applications with several .desktop files
https://bugzilla.gnome.org/show_bug.cgi?id=623688
2010-10-07 01:30:30 +04:00
64efa61dc2 Updated Norwegian bokmål translation 2010-10-06 16:07:49 +02:00
3ce25296e1 Updated Hebrew translation. Changed to 3 Plural Forms instead of 2. 2010-10-06 02:29:46 +02:00
b017a2187b Don't show the summary if a new item got removed before we had a chance to show it
It's possible that an item that was added to the summary got removed before
we had a chance to show the summary because the user has interacted with
the notification (e.g. clicked on an application ready notification). We should
not be showing the summary with an unchanged set of items in this case.

However, it is possible that multiple items were added to the summary before
we had a chance to show the summary, and only some of them got removed. In view
of this scenario, we can't just use a boolean flag to indicate if the summary
needs to be shown, but have to maintain an array of new summary items instead.

https://bugzilla.gnome.org/show_bug.cgi?id=630939
2010-10-05 16:14:05 -04:00
dd155e2f87 src: remove no-longer-used file
fix-meta-rectangle.py is not needed with current gobject-introspection
2010-10-05 12:24:56 -04:00
38a69f56b4 src: consistentify Makefile indentation/alignment 2010-10-05 10:15:22 -04:00
3d2d396c09 st-theme-node: Support non-uniform border-radii
Non-uniform border-radii are already supported when using a gradient
background, this patch adds support for solid colors as well.

The currently applied technique of using corner textures and filling
the remaining area with rectangles is extended, so that each corner is
padded with rectangles to the size of the largest corner.

Add border-radius.js to test cases, to test non-uniform border-radii
with both solid color and gradient backgrounds.

https://bugzilla.gnome.org/show_bug.cgi?id=631091
2010-10-05 00:18:49 +02:00
b33ebb450a tests: Fix environment
Environment.init() uses Shell.Global, which is not accessible outside
the mutter process; allowing to run the function when window.global is
undefined fixes the environment for tests.

https://bugzilla.gnome.org/show_bug.cgi?id=631091
2010-10-05 00:05:57 +02:00
560da76387 gnome-shell.modules: Disable dconf-editor
dconf-editor requires GTK+-2.22, which is still not available in most
major distributions. Building against GTK+-3 requires a more recent
version of vala, so just disable dconf-editor for now.
2010-10-04 23:21:21 +02:00
5b3c086ec3 Bump version to 2.91.0 2010-10-04 15:51:18 -04:00
8273de6bfa Add org.gnome.accessibility.magnifier.gschema.xml.in to POTFILES.in 2010-10-04 15:43:28 -04:00
e15e202e11 Support and require Mutter 2.91.0 2010-10-04 15:07:53 -04:00
c4edba042a [i18n] Updated German translation 2010-10-04 20:32:25 +02:00
8e25a1eb3b Updated Slovenian translation 2010-10-04 15:01:17 +02:00
1babf10e58 updating translation for Punjabi 2010-10-04 07:22:02 +05:30
8f9ef3f8f8 Add icon-naming-utils to build packages
icon-naming-utils is needed to build gnome-icon-theme(-symbolic).
Fedora already has it (commit 4b781a), add it to other
distributions.
2010-10-03 15:02:59 +02:00
446e97bf12 CSS: Remove overwritten style left over from a previous design 2010-10-03 14:13:30 +02:00
4a316fbc66 Use System Settings instead of Preferences in the user menu
This matches the terminology used in the result of the action.
2010-10-02 16:42:06 -04:00
8a7c1eebc0 Updated French translation 2010-10-01 23:19:46 +02:00
f336564e19 PopupMenu: add horizontal sliders
Introduce Cairo-drawn sliders to be used in PopupMenus (for example for
volume). They are stylable to some extent (colors, border width, slider
height) and have the standard behaviour of a slider, except they are
completely modal (once you start dragging, all events are intercepted by
the slider, which thus is kept active and highlighted at all times).
They show numeric values between 0 and 1 (scaling must be performed outside)
and emit value-changed on button release, but no activate, keeping the
menu open.

https://bugzilla.gnome.org/show_bug.cgi?id=625029
2010-10-01 15:18:36 -04:00
aebdf79430 Connect PopupMenuManager to destroy signal
PopupMenuManager now connects to the destroy signal of PopupMenu, so
that destroying a PopupMenu is now enough for removing it from the
relevant manager. Useful if menu come and go on-the-fly (like in
app views or sidebars).

https://bugzilla.gnome.org/show_bug.cgi?id=630914
2010-10-01 12:37:06 -04:00
25fe730d16 Add Clutter dependency on gdk-pixbuf in moduleset
Clutter also depends on gdk-pixbuf so build gdk-pixbuf
before Clutter.

https://bugzilla.gnome.org/show_bug.cgi?id=631086
2010-10-01 16:12:52 +02:00
61b029207d [windowDimmer] handle changing of window_type
dim/undim parent window when window_type changed to/from MODAL_DIALOG
https://bugzilla.gnome.org/show_bug.cgi?id=630363
2010-10-01 01:09:15 +04:00
4c068c135b [misc] add fileUtils.listDirAsync
Request information for a files from the directory asynchronously.
https://bugzilla.gnome.org/show_bug.cgi?id=623708
2010-10-01 01:08:22 +04:00
734d93087a Remove use of octal constants
New spidermonkey warns on octal constants, so we can't
even use them for file permissions. Switch to hex plus a comment.
2010-09-30 12:43:12 -04:00
e22fbda689 telepathy: Use string.replace in a way compatible with newer Spidermonkey
The semantics of the first argument changed from literal -> regexp
if the 'g' option was specified.  To remove ambiguity, stop using
the spidermonkey extension and create a standard RegExp object.

https://bugzilla.gnome.org/show_bug.cgi?id=630539
2010-09-30 12:43:12 -04:00
11db188fe9 Support xulrunner 1.9.3+
Add small wrappers around JS_AddValueRoot.
Add JS_BeginRequest in our custom code.

https://bugzilla.gnome.org/show_bug.cgi?id=630539
2010-09-30 12:43:12 -04:00
61c906807b Don't use mutter_window_get_window_type / MetaCompWindowType
They have been removed so we have to use meta_window_get_window_type()
and MetaWindowType instead.

https://bugzilla.gnome.org/show_bug.cgi?id=630363
2010-09-30 18:36:28 +02:00
c6eb2761c7 gnome-shell.in: Never add empty elements to LD_LIBRARY_PATH
An empty element means the current directory, and is insecure.

https://bugzilla.gnome.org/show_bug.cgi?id=631004
2010-09-30 15:25:21 +02:00
109de6a356 messageTray: Do not show the summary when removing a source
Having the summary pop up automatically after a source icon has been
removed is pretty useless ("Hey, there was something interesting going
on, but you missed it and it's gone now, kthxbye").

https://bugzilla.gnome.org/show_bug.cgi?id=630939
2010-09-29 23:11:24 +02:00
fe5a289460 Fix compilation against latest GTK+-3 changes
Adjust to GDK/GTK+ API changes:
 - removal of GdkColormap
 - expose-event -> draw transition

https://bugzilla.gnome.org/show_bug.cgi?id=630641
2010-09-28 22:56:45 +02:00
1b2a1a3a3d [i18n] Updated German translation 2010-09-28 20:57:42 +02:00
e967807acf shell-gtk-embed: Use GtkWidget instead of GtkObject
GtkObject has been deprecated and removed from GTK+.
2010-09-27 17:05:40 +02:00
4aee584850 Updated Hebrew translation. 2010-09-27 00:01:54 +02:00
ab8984e1ce Updated Spanish translation 2010-09-25 10:43:42 +02:00
b96cf2042a [StatusIconDispatcher] Add keyboard and display icons to tray icon list 2010-09-24 14:53:50 -05:00
1413fa6e03 Revert "StThemeNodeTransition: work around Cogl bug"
This reverts commit 8f0f159960.

Cogl has been fixed, so it is no longer needed.

https://bugzilla.gnome.org/show_bug.cgi?id=629616
2010-09-24 17:31:41 +02:00
a6e4bab990 Add symbolic icons to TextureCache's load_icon_name()
Icons can be loaded as St.Icon.SYMBOLIC, FULLCOLOR, APPLICATION or
DOCUMENT. The first will look for a symbolic equivalent, the second
looks for a full-color version (and does fallback, eg, from
"drive-harddisk-usb" to "drive-harddisk"). APPLICATION and DOCUMENT do
full-color icons without fallback (as specified by the icon spec).

And update various callers to use the right flags.

Based on a patch from Matt Novenstern.

https://bugzilla.gnome.org/show_bug.cgi?id=621311
2010-09-24 10:57:27 -04:00
4b781ae7e6 gnome-shell.modules: add gnome-icon-theme, gnome-icon-theme-symbolic
https://bugzilla.gnome.org/show_bug.cgi?id=621311
2010-09-24 09:48:15 -04:00
702b8e78e4 accessibility-status: Remove left-over debug message 2010-09-24 10:49:12 +02:00
4571a0ea0d Add basic error handling to search system.
If a search provider misbehaves, the search system fails to return any
results from any providers. Work around this.

https://bugzilla.gnome.org/show_bug.cgi?id=627950
2010-09-24 10:01:33 +02:00
437538644e introspection: Fix annotation
The scanner now warns about unknown annotations, which catched this
invalid 'type' annotation.
2010-09-24 02:08:32 +02:00
dc5ceffe40 Remove Alt+W/A/S/D hack
This was just for use within Xephyr, and gnome-shell doesn't work in
Xephyr any more anyway.

https://bugzilla.gnome.org/show_bug.cgi?id=624858
2010-09-23 15:17:06 -04:00
1c7592b4b1 Updated Polish translation 2010-09-23 20:44:12 +02:00
fc8c93b2ed build: Add missing file statusIconDispatcher.js 2010-09-23 19:17:43 +02:00
9708b68540 [baseIcon] Tie the icon's width to its height
Both current design and new mockups use square icons. Currently this
is implemented by setting a fixed width and height in the CSS, which
does not work for the growing/shrinking items in the new sidebar.
By moving the assumption of square items into the code, the size will
adjust according to icon size, spacing, padding and font size if not
explicitly overwritten in the CSS.

https://bugzilla.gnome.org/show_bug.cgi?id=625887
2010-09-23 19:08:43 +02:00
01f4dc68b8 [baseIcon] Allow setting the icon size from code
The current design features a sidebar where the icon size shrinks
automatically to fit more items. Add a setSizeManually parameter
to BaseIcon, which disables sizes read from CSS and allows to use
BaseIcon.setIconSize() to support this.

https://bugzilla.gnome.org/show_bug.cgi?id=625887
2010-09-23 19:08:43 +02:00
8c1bf346a9 [appDisplay] Factor out WellGrid/AppIcon
All mockups now use a representation for documents/places similar to
the one used for applications. Rename AppIcon to BaseIcon and move its
code together with WellGrid out of appDisplay to stress their general
usefulness.

https://bugzilla.gnome.org/show_bug.cgi?id=625887
2010-09-23 19:08:43 +02:00
8f0f159960 StThemeNodeTransition: work around Cogl bug
Switch to using the layer combine constant rather than the material
primary color for representing the opacity of the material; this
avoids triggering a Cogl bug where changing the primary color corrupts
the layer state.

https://bugzilla.gnome.org/show_bug.cgi?id=629616
2010-09-23 12:44:07 -04:00
cbf2cbac61 [StatusIconDispatcher] Move non-system-tray icons to message tray
New StatusIconDispatcher dispatches icons to the system or message tray.

Based on a patch from Matt Novenstern
https://bugzilla.gnome.org/show_bug.cgi?id=608869
2010-09-23 09:49:47 -04:00
82e6f9c8d6 [MessageTray] show newly-added sources even if they don't post notifications
eg, when a trayicon is added, show the summary briefly

https://bugzilla.gnome.org/show_bug.cgi?id=608869
2010-09-23 09:49:47 -04:00
ae9360659d [ShellTrayIcon] add ShellTrayIcon, make ShellTrayManager use it
The actor emitted by ShellTrayManager is now ShellTrayIcon, a subclass
of ShellGtkEmbed which has several properties on it which are (or will
soon be) useful to the shell.

Part of the rearranging to use ShellTrayIcon means that we now show
the ShellEmbeddedWindow before creating its ShellGtkEmbed, which
requires a few modifications to ShellEmbeddedWindow (notably, telling
it at construct time what stage it will be drawn on, since it needs to
know that before it has a ShellGtkEmbed now).

https://bugzilla.gnome.org/show_bug.cgi?id=608869
2010-09-23 09:49:47 -04:00
63f2066135 [ShellGtkEmbed] do a better job of tracking the actor's position
Previously the code to keep the X window aligned with its actor made
various assumptions that were true in the panel status tray area but
that are not true in the message tray. Fix it up by repositioning the
X window at clutter_actor_paint() time, which will definitely be
called every time the actor moves, whether it's because of its own or
its parent/ancestor's changes.

https://bugzilla.gnome.org/show_bug.cgi?id=608869
2010-09-23 09:49:47 -04:00
745e8f608f [ShellGtkEmbed] base this on ClutterX11TexturePixmap, not ClutterGLX
As of 1.4, ClutterGLXTexturePixmap is identical to
ClutterX11TexturePixmap (with the differences having been moved into
the cogl layer). So make ShellGtkEmbed use the (introspected) X11
version, which then allows us to make the instance and class structs
public as well.

https://bugzilla.gnome.org/show_bug.cgi?id=608869
2010-09-23 09:49:47 -04:00
c9a7c9d491 [NotificationDaemon] always resolve a notification's ShellApp first
Resolve a notification's ShellApp before posting the notification, so
that notification sources now always have an app associated (assuming
they came from an app as opposed to the command line). Index sources
by PID rather than by appName (so that, eg, multiple calls to
notify-send now show up as separate sources).

For Sources that have an associated app, use the app's icon for the
source, rather than tracking the notification icon.

This change also lets us get rid of appNameMap, since we can just use
shell_app_get_name() now.

https://bugzilla.gnome.org/show_bug.cgi?id=629090
2010-09-23 09:49:47 -04:00
ad8a97dfe0 Updated Slovenian translation 2010-09-23 15:10:25 +02:00
8591a2fc09 gnome-shell.in: Make xephr available within the scope of run_shell
https://bugzilla.gnome.org/show_bug.cgi?id=629304
2010-09-22 20:42:01 +02:00
d188a7b32a PopupSwitchMenuItem: use SVG switches
https://bugzilla.gnome.org/show_bug.cgi?id=629954
2010-09-22 11:12:31 -04:00
52d9cebcef Added Norwegian Nynorsk translation. 2010-09-22 15:10:30 +02:00
f18e57dc38 data/Makefile.am: fix indentation 2010-09-21 09:02:08 -04:00
828ad348ce [MessageTray] fix allocation in the title-too-long case
Previously we were hiding the banner label if the title was too long,
but this causes queue_relayout() warnings. Instead, just set its
opacity to 0.

https://bugzilla.gnome.org/show_bug.cgi?id=629308
2010-09-21 08:12:34 -04:00
516fe49bb0 Style fixes for the popup menu
https://bugzilla.gnome.org/show_bug.cgi?id=629954
2010-09-20 17:20:58 -04:00
555409aba2 Add spacing between label and switch for menu items
Currently there is no spacing between items packed into the switch
menu item layout box.  Add some.

https://bugzilla.gnome.org/show_bug.cgi?id=629954
2010-09-20 17:20:00 -04:00
7298831f54 Fix the universal access menu text to match mockups
This makes the menu label text more closely match the mockups
http://live.gnome.org/GnomeShell/Design/Guidelines/SystemStatus/UniversalAccess

https://bugzilla.gnome.org/show_bug.cgi?id=629954
2010-09-20 13:00:04 -04:00
fd5f30ab0d Use gdk_error_trap_pop_ignore() where appropriate
gdk_error_trap_pop() has been marked with G_GNUC_WARN_UNUSED_RESULT,
so use gdk_error_trap_pop_ignore() whenever the return value is ignored.
2010-09-20 14:54:26 +02:00
a2553f48e2 Enable side-by-side tiling
Override the metacity schema for side-by-side tiling to change the
default behavior when running mutter in GNOME Shell.

https://bugzilla.gnome.org/show_bug.cgi?id=606260
2010-09-17 16:02:37 +02:00
6f75c8c172 Add ORBit2-devel to required packages
GConf requires it to build, it's been forgotten when we introduced
it into the moduleset. Debian uses 'liborbit2-dev', Fedora
and Mandriva 'ORBit2-devel', and SuSE 'orbit2-devel'.

https://bugzilla.gnome.org/show_bug.cgi?id=629882
2010-09-17 15:52:54 +02:00
0cb8953232 accessibility.js: Fix use of non-existent gconf_client_get_value()
gconf_client_get_value() doesn't exist; apparently
gconf_client_get_float() was meant instead.
2010-09-16 15:35:13 -04:00
6ea18136ac Add Universal Access status indicator
Introduce the Universal Access status indicator as designed, modeled
after the similar UI provided by g-s-d. This indicator allows the user
to change rapidly the keyboard and mouse behaviour (sticky keys, slow
keys, bounce keys, mouse keys), as well as the enabled ATs (magnifier,
screen reader, screen keyboard) and the HighContrast Gtk theme.

https://bugzilla.gnome.org/show_bug.cgi?id=624916
2010-09-16 15:03:26 -04:00
e43f10c8ed Bump the required clutter version to 1.3.14 2010-09-16 19:28:15 +02:00
bbbce5f12f build: cairo-1.10.0 is stable, not a devel snapshot 2010-09-16 18:46:57 +02:00
6cdc2c26df build: bump cairo and pixman to latest stable releases 2010-09-16 18:36:47 +02:00
4e1de26a02 PopupMenu: Add support for submenus
Adds class PopupSubMenuMenuItem, which is an item holding a submenu,
that is opened when the corresponding item is active, and is keyboard
and mouse navigable like its Gtk counterpart.

https://bugzilla.gnome.org/show_bug.cgi?id=623498
2010-09-15 14:02:22 -04:00
b5ee89459a Support setting the image after construction
This patch allows the icon in PopupImageMenuItems to be changed at
any time, while preserving the item and all other properties (style,
signals) attached and without rebuilding the whole menu. This is useful
for images reflecting a dynamic status (e.g. cellular strength
indicator or battery level)

https://bugzilla.gnome.org/show_bug.cgi?id=623652
2010-09-15 13:34:28 -04:00
2adfca0582 Use non recursive automake for JS
Use only one Makefile for all JS module, to make faster builds and
to increase maintenability.

https://bugzilla.gnome.org/show_bug.cgi?id=629775
2010-09-15 18:38:46 +02:00
5ccc763385 Cancel Destroy effect of modal windows when the parent has gone away
Modal dialogs slide back into the titlebar of the parent window when destroyed.
This looks weird if the parent window itself has been destroyed, so cancel the
effect in this case.
https://bugzilla.gnome.org/show_bug.cgi?id=629560
2010-09-15 15:55:33 +04:00
652ce3ce8c introspection: Fix annotations
The scanner got more strict, now some annotations need fixing.
2010-09-15 03:02:26 +02:00
1bd0ad11d8 Use WellGrid for application results
Extend WellGrid with an optional rowLimit parameter and an accessor
function for the grid's items, then use it to replace the custom
container used to display the application search results.
Also adjust the spacing of the search results slightly to make it
consistent with the app well.

https://bugzilla.gnome.org/show_bug.cgi?id=622446
2010-09-15 00:18:22 +02:00
27e71d9a6c Fix shell_global_format_time_relative_pretty() parameter name
An out parameter annotation was missed due to a difference
in the parameter name between the declaration and the implementation.

https://bugzilla.gnome.org/show_bug.cgi?id=629595
2010-09-14 16:16:02 -04:00
7f2fce2684 .gitignore: add magnifier schema stuff 2010-09-14 11:32:34 -04:00
25f907ffb1 St: Use a local material template
To be consistent with what we do with the shadow
material, use the same pattern in setup_framebuffer().
2010-09-14 00:00:34 +02:00
1034798969 st-shadows: Use a template material when creating shadows
To avoid recompiling shadows each time a new shadow is created,
use a copy of a static template material.

See http://bugzilla.clutter-project.org/show_bug.cgi?id=2280#c5.

https://bugzilla.gnome.org/show_bug.cgi?id=629383
2010-09-13 18:11:03 +02:00
862f1ea18c st: Use template material for transitions
To avoid compiling a new shader each time a transition is started,
use a copy of a static template material.

See http://bugzilla.clutter-project.org/show_bug.cgi?id=2280#c5.

https://bugzilla.gnome.org/show_bug.cgi?id=629384
2010-09-13 17:50:05 +02:00
7c65643eed Added Estonian ('et') to LINGUAS 2010-09-12 17:47:20 +03:00
e9da061558 [l10n] Updated Estonian translation 2010-09-12 17:46:45 +03:00
45dcfa9a70 [Overview] Don't dim window previews
Undim windows when going to the overview and
restore their state when leaving.
https://bugzilla.gnome.org/show_bug.cgi?id=629371
2010-09-12 13:39:52 +04:00
907dd4381b [appSwitcher] Check the modifier state rather than assuming Meta
It isn't guaranteed that Alt+Shift equals to Meta, so we have to check
the modifier instead.

https://bugzilla.gnome.org/show_bug.cgi?id=629368
2010-09-11 22:41:59 +02:00
687bfbb081 [windowDimmer] Bump GLSL version to 1.10
The shader currently forces GLSL 1.0 to avoid being incompatible with older hardware but is still using features not available in 1.0.

Strict compilers fail to compile the shader:

error C7506: OpenGL/ES does not define the global variable gl_TexCoord

As every hardware/driver that supports 1.0 also supports 1.10 bumping the version to fix it is safe.

https://bugzilla.gnome.org/show_bug.cgi?id=629343
2010-09-11 21:41:47 +02:00
246d9f1357 [appSwitcher] Close the switcher on Meta_L/R release
The keyReleaseEvent handler does not take into account that a
user might release Alt while still holding shift
(the keycode becomes Meta_L/R in that case).

The result is that the switcher stays open which is unexpected.

https://bugzilla.gnome.org/show_bug.cgi?id=629368
2010-09-11 19:01:42 +02:00
e37f17be2b [build]Add shader_DATA to EXTRA_DIST 2010-09-11 15:56:53 +02:00
3c2ec3c770 Fix wrong filename in data/Makefile.am 2010-09-11 15:44:33 +02:00
a969e82954 Attach dialogs to windows with visual effects
Override the new mutter preference /apps/mutter/general/attach_modal_dialogs
to attach modal dialogs to their parent window. Animate the modal dialogs
expanding from the top of the parent window. Slowly dim the parent window
after the dialog comes up.
https://bugzilla.gnome.org/show_bug.cgi?id=612726
2010-09-11 05:39:57 +04:00
509ad5ed9a Updated Portuguese translation 2010-09-10 21:45:58 +01:00
afd3b76970 Fix various details of how notifications are shown
This patch ensures the following notifications behavior:
- Urgent notifications that have long title or banner text are auto-expanded
  correctly.
- Single-line notifications that have _expandNotification() called (e.g.
  because the user mouses over to them), are treated as expanded, which means
  they get fully expanded if they are updated with more content and the user
  can escape them.
- The position of expanded notifications is updated when they are updated.
- Notification banner is shown again on the first line if it can fully fit
  there after a notification is updated, even if it was previously hidden
  because the notification was expanded and the old banner did not fully fit.
- New notifications are immediately hidden if the user mouses away from them.
- If a new notification is updated while it is shown, we extend the time it
  will be shown.
- If a new notification is updated while it is hiding, we stop hiding it and
  show it again.
- If a summary notification is updated while it is hiding, we let it finish
  hiding and show a new notification with the updated information.

Implementation details:
- Single-line notifications now have 4px bottom padding instead of 8px, which
  means that their height matches the tray height, they are fully shown in the
  banner mode, and don't pop out by 4px when the notification is expanded.
- Notification keeps a flag that indicates whether it is expanded, updates
  its expanded look when it is updated, and emits an 'expanded' signal
  indicating that its layout has possibly changed. The message tray connects
  to this 'expanded' signal when it is showing a notification in the expanded
  state and updates the position of the notification accordingly when this
  signal is received so that the notification is fully shown. This is better
  than connecting to 'notify::height' signal on the notification bin, since
  it results in fewer callbacks.

https://bugzilla.gnome.org/show_bug.cgi?id=617209
2010-09-10 15:47:12 -04:00
399ebcc049 Some Magnifier DBus methods incorrectly interpret rectangles.
Modified methods to use [left, top, right, bottom] instead of
[left, top, width, height].

https://bugzilla.gnome.org/show_bug.cgi?id=626123
2010-09-10 12:03:40 -04:00
e88f08072c Bug 622414 - Port magnifier to GSettings
The Shell is the only user of the magnifier, so there's no
reason to keep using GConf for its settings. Since it's a
session-wide tool, use a distinct schema,
org.gnome.accessibility.magnifier, stored in
/desktop/gnome/accessibility/magnifier just like before.
Put these settings in a separate schema file for clarity.

Old enums in GConf were stored as integers, we now use the
facilities provided by GSettings to save them as strings,
and convert them to integers automatically thanks to the
mapping stored in the schemas. Remove hard-coded default values,
which we can get from the schemas.

https://bugzilla.gnome.org/show_bug.cgi?id=622414
2010-09-10 16:38:09 +02:00
38c3422331 [DND] change cursor when dragging
Return a DND.DragMotionResult constant from delegate _handleDragMotion
methods as well as the existing return value from the drag monitor method dragMotion.
https://bugzilla.gnome.org/show_bug.cgi?id=607821
2010-09-10 06:00:28 +04:00
0e2ed0fb0b add shell_global_[un]set_cursor
This functions set/unset the cursor on the stage window.
https://bugzilla.gnome.org/show_bug.cgi?id=607821
2010-09-10 05:58:19 +04:00
4f61f9a43d remove scrollbar-[width/height]
1. They are useless
2. We can get its value from get_preferred_[width/height] in StScrollBar
https://bugzilla.gnome.org/show_bug.cgi?id=624893
2010-09-10 05:57:36 +04:00
d6995194dd add get_preferred_[width/height] to StScrollBar
https://bugzilla.gnome.org/show_bug.cgi?id=624893
2010-09-10 05:57:15 +04:00
0a9ebf62b3 property for StScrollBar.trough should be set directly
We were previously putting the decorations for the trough on the StScrollBar itself,
which won't work if the scroll bar has padding.
https://bugzilla.gnome.org/show_bug.cgi?id=624893
2010-09-10 05:56:37 +04:00
ab25b8ab69 change parent class of StScrollBar from StBin to StWidget
1. It doesn't have child
2. It work like StWidget without child
https://bugzilla.gnome.org/show_bug.cgi?id=624893
2010-09-10 05:56:07 +04:00
d2290cc3e2 build: clutter deps on atk 2010-09-09 18:31:40 -04:00
e5e8590024 Updated Polish translation 2010-09-09 19:52:30 +02:00
178c8c50a0 Fix build with recent gtk3
use new keysyms names
https://bugzilla.gnome.org/show_bug.cgi?id=629128
2010-09-09 18:34:09 +04:00
b7212a4e8f Updated French translation
Contributed by Pablo Martin-Gomez, Claude Paroz and Bruno Brouard
2010-09-08 16:16:59 +02:00
177a136adc introspection: Fix use of pango_font_description_from_string() 2010-09-08 15:37:33 +02:00
dddd97f6df introspection: Build with --warn-all --warn-error
* Use --warn-all, --warn-error
* Fix various broken gtk-doc
* Drop unused shell_get_event_related
* For header defines, we currently require them to end in _H to be skipped
* Drop the no-longer-necessary fix-meta-rectangle.py hack
* Move to the convention of using -private.h for headers that are,
  well, private.
* Add shell-wm-private.h
2010-09-07 13:07:52 -04:00
86feb674ee Updated Swedish translation 2010-09-06 22:56:12 +02:00
0f8da7d24f [build] Remove libgee from moduleset
It is no longer a dependency of dconf.
2010-09-06 16:51:39 +02:00
8efaa798a9 [l10n] Updated German translation 2010-09-04 16:15:48 +02:00
a243ba6693 [StLabel] Implement text-shadow property
Use the existing shadow code to add a drop shadow to the underlying
ClutterText actor if the text-shadow property is specified.

https://bugzilla.gnome.org/show_bug.cgi?id=624384
2010-09-02 21:49:59 +02:00
ba1da9deb9 [StThemeNode] Make shadow helper functions semi-public
Move shadow helper functions from st-theme-node-drawing to st-private
to make them available to widgets which want to add shadows to internal
actors.
Also add a new helper function for creating the shadow material from a
ClutterActor.

https://bugzilla.gnome.org/show_bug.cgi?id=624384
2010-09-02 21:49:59 +02:00
29781b2e5c [StThemeNode] Add text-shadow property
Reorganize the existing code which parses the -st-shadow property
to allow parsing different shadow properties and add support for
the text-shadow property.

https://bugzilla.gnome.org/show_bug.cgi?id=624384
2010-09-02 21:49:59 +02:00
e942444630 [StShadow] Add reference counting
If a shadow property is inherited from a parent, multiple StThemeNodes
share a common StShadow. It would be possible to use st_shadow_copy()
for this purpose, but proper reference counting is nicer.

https://bugzilla.gnome.org/show_bug.cgi?id=624384
2010-09-02 21:49:59 +02:00
c3b88d4113 [l10n] Updated Italian translation 2010-09-02 21:30:52 +02:00
6d2d4fcc77 Don't expand notifications that pop up over the pointer
Expanding notifications automatically just because they popped up where
the pointer is positioned distracts the user. It can also lead to a behavior
that is surprising to the user by, for example, making the user's input
switch to the notification's text entry box.

It is possible to expand a notification that popped up over the pointer
by mousing away from it and then mousing back in immediately.

https://bugzilla.gnome.org/show_bug.cgi?id=617209
2010-09-02 14:48:36 -04:00
9f9067e29b [StThemeNode] Add basic background-position support
Add basic support for background-position, which only supports absolute
values.

Also don't require an unit to be specified for 0 (because the unit does not
really matter here 0 is 0 regardless of the unit).

https://bugzilla.gnome.org/show_bug.cgi?id=624375
2010-09-01 18:13:43 +02:00
c779dcb608 l10n: Updated Greek translation for gnome-shell 2010-08-31 23:35:35 +03:00
1c4d53eec3 l10n: Updated Greek translation for gnome-shell 2010-08-31 22:06:00 +03:00
a25f7df626 Fully show long titles when a notification is expanded
We used to keep long titles ellipsized when a notification was expanded,
which was a bug. We now show them fully by line wrapping them.

Based on the original patch from Steven Van Bael.

https://bugzilla.gnome.org/show_bug.cgi?id=623970
2010-08-31 13:47:17 -04:00
f8dc3b88f8 Use 'customContent' flag instead of 'bannerBody'
We used 'bannerBody' flag to differentiate the case when we move the banner to
the body when the notification is expanded from the one when we don't do that
and only use the custom content set for the notification, as is the case for
Telepathy notifications. We also always cleared the content of the notification
on update when bannerBody was set to true.

Flag named 'customContent' reflects the use case for it more clearly. The
comments that accompany it were also updated and improved.

We now always add the banner text as the first element in the expanded
notification unless 'customContent' flag is set to true.

If the 'body' parameter is specified, we use it in addition to the banner
text. The earlier version of the code had a bug that resulted in the 'body'
parameter not being set only in the case when the 'bannerBody' was set to
true and the banner text had newlines in it.

https://bugzilla.gnome.org/show_bug.cgi?id=623970
2010-08-31 13:47:10 -04:00
539b8ae9f6 Don't show the banner when hiding the notification or showing it in the summary mode
The banner should not be appearing briefly when we are hiding the notification.
For that, we should only restore the opacity of the banner in popInCompleted()
when we are done hiding the notification. We do need to restore the opacity
in case the notification is updated and is shown in the banner mode again.

The banner should not be appearing briefly when we are showing the notification
in the summary mode. For that, we should not use the animation time to fade out
the banner in popOut() for summary notifications.

These two problems were particularly visible when the ANIMATION_TIME was increased.

https://bugzilla.gnome.org/show_bug.cgi?id=623970
2010-08-31 13:47:01 -04:00
cc06916811 Update British English translation 2010-08-31 09:33:26 +01:00
5e7c25e136 Notice style transitions that don't change how StThemeNode paints
Add st_theme_node_paint_equal() and use that to do two things:

 1) Avoid animating transitions where nothing changes.
 2) Copy cached painting state from the old theme node to the new
    theme node.

https://bugzilla.gnome.org/show_bug.cgi?id=627083
2010-08-30 13:40:12 -04:00
b9f9dd948a [AltTab] fix Alt-Shift-Tab again
In Clutter 1.2, clutter_event_get_keysym() ignored the state of the
Shift key. In 1.4, it does not, so we have to adjust our comparisons
accordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=627782
2010-08-30 12:28:00 -04:00
d1f0a1e33a Updated Hungarian translation 2010-08-29 19:43:27 +02:00
93d3270566 Calculate whether we need an expansion row for the banner correctly
The old calculation did not take into account the icon and the spacing
between columns. This resulted in the notifications that had a slightly
longer title/banner combination than could actually fit not being expandable.

The new calculation is done in _bannerBoxAllocate() so
that we don't need to hardcode which other elements are present.

https://bugzilla.gnome.org/show_bug.cgi?id=627985
2010-08-26 16:07:51 -04:00
6f57f07214 [MessageTray] Clean up source-vs-notification icon handling
A Source needs exactly one summary icon (which in the case of a
trayicon-based source won't even be just an image), but possibly many
notification icons, which may vary for successive notifications
(particularly in the case of NotificationDaemon notifications). So
differentiate these cases in the API.

https://bugzilla.gnome.org/show_bug.cgi?id=627303
2010-08-26 11:00:54 -04:00
1951812a47 [MessageTray] use Params.parse in Notification
https://bugzilla.gnome.org/show_bug.cgi?id=627303
2010-08-26 10:52:01 -04:00
8f6a7f393d [MessageTray] remove Notification IDs
Notification daemon notifications have IDs, but other kinds don't
necessarily, and the generic code doesn't need to bother with it.

https://bugzilla.gnome.org/show_bug.cgi?id=627303
2010-08-26 10:52:01 -04:00
d3031b406a [MessageTray] remove Source IDs
The tray itself does not actually need them, and to make status icon
sources work correctly the NotificationDaemon will need to be tracking
its sources by two separate IDs, so the existing system won't work.

Also remove MessageTray.removeSourceByApp(), which is
NotificationDaemon-specific, and implement the functionality in
notificationDaemon.js instead.

https://bugzilla.gnome.org/show_bug.cgi?id=627303
2010-08-26 10:52:01 -04:00
2915319602 gnome-shell.modules: Disable librsvg theme engine
The librsvg theme engine uses now-gone GTK+ drawing functions so doesn't
compile with GTK+ 3. Since we don't need the theme engine anyways,
skip bulding it.
2010-08-24 15:04:29 -04:00
0751d122d7 Updated Serbian translation 2010-08-24 05:40:53 +02:00
957b3b69dc [lg] fix queue_relayout warnings
https://bugzilla.gnome.org/show_bug.cgi?id=624940
2010-08-23 13:03:58 -04:00
083b1c9d8b [lg] Close inspector on Esc
https://bugzilla.gnome.org/show_bug.cgi?id=624940
2010-08-23 13:03:58 -04:00
09edf4ba59 [lg] Use scroll wheel in inspector to select parent actors
scroll-up selects the parent actor, then grandparent, etc. scroll-down
moves the selection back towards the frontmost actor.

https://bugzilla.gnome.org/show_bug.cgi?id=624940
2010-08-23 13:03:15 -04:00
1a50b94b19 [lg] split inspector event handlers out into separate functions
https://bugzilla.gnome.org/show_bug.cgi?id=624940
2010-08-23 13:00:39 -04:00
5bd977dd3c [transitions] Do not recreate FBOs on opacity changes
Creating an FBO may be expensive, so we should avoid the operation
if possible. When transitioning between theme nodes, the widget's
opacity is used to paint to the offscreen textures which are blended
together - this means that the textures have to be recreated each time
the widget's opacity changes. It is much more effective to paint the
textures at full opacity and respect the widget's paint opacity when
blending the textures together.

https://bugzilla.gnome.org/show_bug.cgi?id=627085
2010-08-23 18:41:34 +02:00
c3cb0be011 Fix copy / paste error in previous commit 2010-08-23 18:37:25 +02:00
63ee20dc17 Bump vala version to 0.9.7
https://bugzilla.gnome.org/show_bug.cgi?id=627740
2010-08-23 18:32:38 +02:00
9284e96a48 Added Japanese translation. 2010-08-23 01:25:27 +09:00
bdd4e68422 Updated Traditional Chinese translation(Hong Kong and Taiwan) 2010-08-21 20:43:24 +08:00
5c60d8982e [Overview] Fix zoom when dragging items from the dash
Commit 4632db177 removed a required include statement, re-add it to
fix DND from the dash.
2010-08-21 11:25:20 +02:00
50ed2f45af [build] add gnome-menus-devel to openSUSE packages list
https://bugzilla.gnome.org/show_bug.cgi?id=627390
2010-08-20 16:29:19 +02:00
9debefd7ca [build] Requires xulrunner 1.9.1.x on openSUSE, required by gjs
gjs needs xulrunner 1.9.1 (see bug 627383), install the right package
on openSUSE distributions.

https://bugzilla.gnome.org/show_bug.cgi?id=627384
2010-08-20 16:29:18 +02:00
c18ff91030 [panel] Add a style class while the overview is active
Designers have asked for the possibility to style the panel
differently in the overview.

https://bugzilla.gnome.org/show_bug.cgi?id=624381
2010-08-20 12:06:48 +02:00
039229f340 Make it possible to register new search providers for the dash after it has been created.
Factors out meta creation from SearchResults._init to SearchResults.createProviderMeta(provider).

Adds Dash.addSearchProvider(provider).

https://bugzilla.gnome.org/show_bug.cgi?id=625954
2010-08-19 18:04:30 -04:00
d9169d27f5 [ShellTrayManager] a few updates
Use the new na_tray_child_get_wm_class() method.
Add the trayicon title to the signal.

https://bugzilla.gnome.org/show_bug.cgi?id=627306
2010-08-19 10:14:18 -04:00
7ff7ec0e7a [tray] sync NaTray code from gnome-panel
Our copies and gnome-panel's had been ported for GSEAL independently.
Sync them back up again.

https://bugzilla.gnome.org/show_bug.cgi?id=627306
2010-08-19 10:14:10 -04:00
a9c0dcbd6b [search] Use 'AND' instead of 'OR' on search terms
The current search system uses the OR operator to concatenate search
terms. While results which are matched multiple times sort before
other matches, it is almost guaranteed that adding an additional term
to the search increments the number of results, which is rather
surprising.

https://bugzilla.gnome.org/show_bug.cgi?id=610955
2010-08-18 23:59:27 +02:00
8258c01d5c [build] add missing packages for openSUSE
Add missing packages for build on openSUSE

https://bugzilla.gnome.org/show_bug.cgi?id=627175
2010-08-17 17:58:27 +02:00
6c6527b66d [gnome-shell-build-setup.sh] Fix for lsb_release system value containing space
On SLED11, lsb_release system is "SUSE LINUX", breaking the script.
Adding quotes fixes this issue.

https://bugzilla.gnome.org/show_bug.cgi?id=627172
2010-08-17 17:54:59 +02:00
cac0848316 Remove usage of gdk_screen_get_rgb_colormap()
gdk_screen_get_rgb_colormap() has been removed from GTK+; there's
no longer a special visual that is used for drawing true-color
images distinct from the system visual. So, we don't need to
check for it; if the visual isn't the system visual, we just
fall through to the case where we create a new GdkColormap.
2010-08-12 20:12:00 -04:00
26c9453b3a [gnome-shell.modules] Upgrade moduleset to cairo-1.9.14
The 1.9.14 snapshot, along with many other things, fixes a major bug in
painting images that was causing the cairo-converted Metacity theme cod
not to work properly.
2010-08-12 20:02:24 -04:00
4e283cf419 Reuse same labels and containers on notification updates
When calling Notification.update, reuse the previous _bannerBox and
related labels (only changing the label content and relayouting), so
that the opacity set on popOut is preserved. As a consequence, updating
an opened notification no longer shows (or flicker) the banner at the
top.

https://bugzilla.gnome.org/show_bug.cgi?id=625502
2010-08-11 16:55:06 -04:00
e96a76edf4 Revert "[gnome-shell.modules] Work around problem of git with 'gtk+'"
This reverts commit b76fe12209.

We now have a workaround symlink server side for the git 1.7.2 handling
of '+', and also there's a patch in git upstream and in some distros, so
we don't need the workaround around in our moduleset anymore.

https://bugzilla.gnome.org/show_bug.cgi?id=626302
2010-08-11 14:29:30 -04:00
766b5b801c [St] Remove _st_actor_contains()
The function has been upstreamed as clutter_actor_contains() - with
the switch to clutter-1.4 it is now available to the Shell, so it
is no longer necessary to keep a copy in-tree.

https://bugzilla.gnome.org/show_bug.cgi?id=626512
2010-08-10 15:03:13 +02:00
3fb7cce80f Drop custom ClutterActor.contains
Clutter 1.4 does provides a native implementation

https://bugzilla.gnome.org/show_bug.cgi?id=624571
2010-08-10 08:41:50 +02:00
a0d9c9b65a [gnome-shell.modules] Switch Clutter to master (Clutter 1.4 branch)
Build the Clutter 1.4 development branch instead of against Clutter 1.2;
this seems to work fine with GNOME Shell at this point, with various
fixes having been applied Mutter, GNOME Shell, and Clutter.
2010-08-09 17:18:06 -04:00
597cd9c7ab [messageTray] fix padding/spacing around summary items
The space between the rightmost item and the edge of the screen should
be considered part of the rightmost item, and the space between items
should be considered part of the adjacent items, to prevent excess
jitter when moving between them.

https://bugzilla.gnome.org/show_bug.cgi?id=626112
2010-08-09 12:30:18 -04:00
1f7f3715cc Updated Swedish translation 2010-08-06 01:24:34 +02:00
0905940ef8 [StContainer] Add :first-child, :last-child pseudo classes
Add support for the CSS :first-child and :last-child properties to
StContainer, and thus to all containers in St and ShellGenericContainer.

The internal ordering of the container's children is used to determine
the child to which to attach the pseudo class, not the children's
positions. This means that containers where positions can differ from
the ordering (ShellGenericContainer / StGroup) may behave unexpectedly,
so some caution is required.

https://bugzilla.gnome.org/show_bug.cgi?id=625316
2010-08-05 19:05:18 +02:00
0573cbfbac Added ta translation 2010-08-05 21:48:21 +05:30
65e37b1d6b [gnome-shell.modules] Update vala to 0.9.4.
dconf now requires vala 0.9.4, update the moduleset.

https://bugzilla.gnome.org/show_bug.cgi?id=626000
2010-08-04 15:39:56 -04:00
e7fb2c50a3 [Calendar] Fix wrong start date in corner case
The start date is shifted by a week if the day number of the month's
first day is smaller than the week start's day number. Probably the
only real world examples are months starting on a Sunday with locales
using Monday as start of week.

https://bugzilla.gnome.org/show_bug.cgi?id=625756
2010-08-02 16:48:10 +02:00
09374b08a3 Updated Norwegian bokmål translation 2010-08-01 14:09:35 +02:00
7fa9e88294 [St] Remove unused width/height from st_theme_node_transition_paint
We query the texture size here but never actually use it.

https://bugzilla.gnome.org/show_bug.cgi?id=625713
2010-08-01 12:10:53 +02:00
b76fe12209 [gnome-shell.modules] Work around problem of git with 'gtk+'
Use gtk%2b in the checkout URL, since recent versions of GIT have
trouble with the '+' in gtk+.

https://bugzilla.gnome.org/show_bug.cgi?id=625135
2010-07-28 17:09:18 -04:00
911e71542b Set LD_LIBRARY_PATH before running dconf
When we are manually starting dconf in the case where it can't
be activated via D-Bus, we need to set LD_LIBRARY_PATH in its
environment, since dconf is no longer linked with a rpath.
(Unlike the rest of GNOME, it doesn't use libtool.)
2010-07-28 15:31:16 -04:00
43de15c3fc Updated Spanish translation 2010-07-28 19:49:05 +02:00
5cb2ea04f7 MoreLink: Ignore calls to activate() if the actor isn't visible
This fixes (another time) the bug about the "Recent Items" label
being clickable when there are no items.

https://bugzilla.gnome.org/show_bug.cgi?id=582037
2010-07-27 16:54:58 +02:00
e287aa10e3 [notifications] Make the whole notification clickable
It is not obvious that only the icon is clickable to activate the
default action - in fact, with the area being that tiny, many don't
even know that notifications can be clicked.
Just extend the clickable area to the whole notification.

https://bugzilla.gnome.org/show_bug.cgi?id=613932
2010-07-27 00:11:09 +02:00
b237cf9a63 Use CoglHandle rather than CoglHandle*
This breaks building on 1.4, and has always been wrong anyway.

https://bugzilla.gnome.org/show_bug.cgi?id=624571
2010-07-26 21:55:25 +02:00
c0d4f11510 Updated Spanish translation 2010-07-26 21:16:19 +02:00
1850c93785 Updated Slovenian translation 2010-07-25 21:41:56 +02:00
cd0e31cd30 Updated Bulgarian translation 2010-07-25 18:40:43 +03:00
02ebd44851 [shadows] Fix shadows with small blur radius
There's an assertion in calculate_gaussian_kernel() to avoid a division
by zero - due to an unnecessary cast from float to int this assertion
is triggered incorrectly for small (but non-zero) values, e.g. a blur
radius of 1px.
2010-07-25 00:37:12 +02:00
29c4742383 [gdmuser] Annotate gdm_list_users()
Recently, g-ir-scanner got a little stricter with regard to
GSList, marking functions not introspectable if the element
type is not annotated. This fixes a visible JS Error by g-ir
and gdmuser/gdm-user-manager.c
2010-07-24 13:25:51 +02:00
d059d1fedc Update Simplified Chinese translation. 2010-07-24 18:00:28 +08:00
7cac4ee1ae [i18n] Updated German translation 2010-07-22 19:08:41 +02:00
0c38f49dde Fix typo inside Switch class
Corrects setToogleState into setToggleState, slipped from 4dfc869e

https://bugzilla.gnome.org/show_bug.cgi?id=621880
2010-07-22 12:49:48 -04:00
2e77724341 Updated Galician translations 2010-07-22 16:39:13 +02:00
13c10b1e27 Updated Hebrew translation. 2010-07-22 16:30:25 +03:00
229604690b [gnome-shell.in] set $XDG_DATA_DIRS too
This is needed to find gsettings schemas that are installed in
the jhbuild prefix.
2010-07-22 09:23:34 -04:00
4dfc869e9d Add support for toggle switches in menus
Adds class PopupSwitchMenuItem, which is a two-state switch similar
to those in system status indicators mockups. Also adds class Switch,
which represents the switch itself, in case it is useful somewhere
else.

https://bugzilla.gnome.org/show_bug.cgi?id=621880
2010-07-22 09:06:01 -04:00
7bde88a6e2 Complete Simplified Chinese translation. 2010-07-22 20:38:02 +08:00
73ecdbd6da Add API for system status indicators
Add a container in the panel for holding them, a fast method for
loading and a simple base class to be subclassed by specific
implementations.

https://bugzilla.gnome.org/show_bug.cgi?id=621705
2010-07-21 12:31:06 -04:00
6eb90434f0 Update the look of various message tray components
The following changes make message tray look more polished:
 - all notifications are now same width (no min and max width)
 - there is an equal padding all around the notification (which resulted in
   the increased tray height)
 - action buttons are now nicely styled
 - chat text box glows when focused (nevermind the unfocused look because
   we'll soon always have it focused when it is showing)
 - chat text has padding on the left and rounded background
 - summary source buttons no longer have a border

https://bugzilla.gnome.org/show_bug.cgi?id=624584
2010-07-21 02:42:17 -04:00
65991cc057 Make Esc hide the tray when a notification has focus
It's convenient to have Esc working for expanded new notifications that
have focus and for summary notifications.

https://bugzilla.gnome.org/show_bug.cgi?id=617224
2010-07-21 01:27:21 -04:00
95d438b86d Grab focus in expanded notifications on hover
In addition to already grabbing focus in the summary notifications,
we also want to grab focus in the new notifications when the user
hovers over them and expands them.

The notifications that expand automatically will only get focus once
the user hovers over them. The notifications that don't expand will
never grab focus because they don't need it.

Make sure that we toggle the way we grab focus when switching between
the overview and the main mode. This is necessary because, unlike
summary notifications that pop down when the user moves between the two
modes, new notifications keep being shown as long as the user hovers
over them or until they time out.

https://bugzilla.gnome.org/show_bug.cgi?id=617224
2010-07-21 01:20:37 -04:00
46906eef43 Grab focus in the summary notification
Because clicking on the summary item to have it display its notification
is a more deliberate action than hovering, we can now grab focus in that
notification. This makes chat notifications in the summary more convenient
to use because you don't need to click on the text entry there.

We pop down the notification when the user clicks anywhere outside of it,
triggers the overview, or the run dialog.

https://bugzilla.gnome.org/show_bug.cgi?id=617224
2010-07-21 00:44:04 -04:00
b2185eb2b1 Always show the summary if it is summoned
This ensures that the summary appears when we are showing a new
notification and switch to the overview at the same time.

Another effect of this patch is that the summary is shown if the
user moves the mouse to the bottom right corner while a notification
is being shown, which is ok.
2010-07-21 00:18:54 -04:00
539ad8196e [panel] don't empty out the app menu when the panel itself gets focus
https://bugzilla.gnome.org/show_bug.cgi?id=623429
2010-07-20 15:03:17 -04:00
adbf3b1c37 [ShellGlobal] add SHELL_STAGE_INPUT_MODE_FOCUSED
Add SHELL_STAGE_INPUT_MODE_FOCUSED, to move the keyboard focus to the
shell without grabbing the keyboard or mouse, and make
stage_input_mode into a GObject property so that (among other things),
callers can tell when MODE_FOCUSED reverts back to MODE_NORMAL.

https://bugzilla.gnome.org/show_bug.cgi?id=623429
2010-07-20 15:03:17 -04:00
6259513b0f [build] Use dpkg-checkbuilddeps to check for installed packages
This is required to handle Provides header, as used by lib*-dev packages
(for example libtiff5-dev provides libtiff-dev), this allows the build
setup script to specify the "generic" package names.

https://bugzilla.gnome.org/show_bug.cgi?id=624009
2010-07-20 16:29:01 +02:00
d8df46d4a1 Enable insertion and removal of menus
This patch adds the method "removeMenu" to PopupMenuManager, to allow
for removal of menus after they're inserted. In order to do this, it
needs to store along with the menu all the relevant signal connections,
that are disconnected when the menu is removed.
Also adds a parameter "position" to "addMenu", so that menus can added
in arbitrary order (in particular to reintroduce those which were removed).
This patch is intended towards dynamic menu users, like extensions for
application lists, docks, sidebars showing recent documents or favourites,
as well as advanced system tray implementations.

https://bugzilla.gnome.org/show_bug.cgi?id=622730
2010-07-20 09:35:12 -04:00
4aa80105ca Fix possible property access on undefined object
PopupMenuManager allows the insertion of menu without a sourceActor
(or with a null one), but never checks before calling contains() on
it.

https://bugzilla.gnome.org/show_bug.cgi?id=622730
2010-07-20 09:35:12 -04:00
13a1175792 fix "undo remove from favorites"
In GSettings, a change notification is generated immediately from context of the _set() call.
In GConf, The "value_changed" signal is emitted whenever the server
notifies your client program that a value has changed in the database (100% NOT from context of the _set() call).
https://bugzilla.gnome.org/show_bug.cgi?id=624296
2010-07-20 16:24:24 +04:00
ed065fc4ea Updated Galician translations 2010-07-20 13:03:31 +02:00
4632db177a Clean up unused includes
Some late spring cleaning ...
2010-07-19 01:46:01 +02:00
cc0de39725 [panel] Fix translatable string
Fix a string which is not extracted correctly by marking it
correctly with double quotes.
2010-07-19 01:46:01 +02:00
f8a5728615 Update vala to 0.9.3
Fixes incompatbility between the .gir files generated by Vala and the
current g-ir-compiler.

https://bugzilla.gnome.org/show_bug.cgi?id=624301
2010-07-15 10:22:36 -04:00
5695c8b0aa Fix invoking actions on notifications
We need to only connect to 'action-invoked' on notification once
when the notification is created. We were accumulating callbacks
otherwise, which resulted, for example, in the Rhythmbox skipping
through multiple tracks when the 'Next' button was hit.

Always be sure to destroy the notification when its source is
destroyed, which is the case when an action is invoked.

Note that in the future, we might not want to destroy the source
for some notifications when an action is invoked. For example,
it makes sense to keep Rhythmbox in the tray while the music is
playing and allow the user to use the controls from the summary
notification too.
2010-07-14 17:16:35 -04:00
11c73fcbc3 [i18n] Updated German translation 2010-07-14 22:21:30 +02:00
5a7201ef4d Resolve cyclic dependency on StatusMenu
Solved by splitting the base class (PanelMenuButton) in a separate
module, ui.panelMenu, which is meant to hold also other reusable
button classes.

https://bugzilla.gnome.org/show_bug.cgi?id=621705
2010-07-13 11:58:13 -04:00
d2902cb70f Updated Norwegian bokmål translation 2010-07-13 15:28:59 +02:00
1b03d5cb45 [St] fix a bug noticed by gcc -O3
https://bugzilla.gnome.org/show_bug.cgi?id=623295
2010-07-12 14:24:16 -04:00
51caecc1b3 Bump version to 2.31.5 2010-07-12 12:58:00 -04:00
ef1d3c56d8 [gnome-shell-build-setup.sh] Pull in autopoint for gdk-pixbuf
The gdk-pixbuf autogen.sh uses autopoint. This is part of
gettext on most systems, but Fedora 14 splits autopoint
into a separate subpackage, so we need to add a version
check.

For completeness, system version extraction is added generally,
though we are only using it on Fedora currently.

https://bugzilla.gnome.org/show_bug.cgi?id=624175
2010-07-12 12:45:22 -04:00
aa8f386b7d Added Traditional Chinese translation (Hong Kong and Taiwan) 2010-07-12 19:26:41 +08:00
43b751e27a Update Czech translation 2010-07-11 21:54:47 +02:00
69fde6822c [StartupNotification] Do not bounce the animation
The spinner animation moving from left-to-right to indicate a starting
application changes its direction on reaching the end of the movement.
Instead, keep the spinner at the right of the app name until startup
has finished.

https://bugzilla.gnome.org/show_bug.cgi?id=623687
2010-07-10 02:25:58 +02:00
b28c4dcd81 [docInfo] Fix recent items
GJS no longer translates time_t values into Date objects, update
the code where we relied on the previous behavior.
2010-07-10 00:23:23 +02:00
5014d16647 [configure] Use pkg-config --libs instead of --print-requires
The latter was added in version 0.23 (0.25 is current), but
distributions using version 0.22 are still out there ...
2010-07-09 22:18:44 +02:00
a5f9039e12 [configure] Do not use grep -q
Although mandated by POSIX, not all implementions[0] support this
option. Use redirection to /dev/null instead.

[0] http://docs.sun.com/app/docs/doc/816-5165/grep-1?a=view
2010-07-09 20:11:58 +02:00
d9eb4702b2 [configure] Check that mutter was compiled with GTK+-3.0
If mutter was compiled with GTK+-2.0, the build will fail with a
rather cryptic message - better fail early during configure with
a proper error message.

https://bugzilla.gnome.org/show_bug.cgi?id=623889
2010-07-09 18:27:16 +02:00
a19047fa3a [build] Fix typo in dependency list 2010-07-08 00:11:24 +02:00
edba3e843f Updated Galician translations 2010-07-08 00:09:46 +02:00
e48d119801 Build the full GTK+ 3.0 stack
Now that we are targetting GTK+ 3.0, always build the full GTK+ stack,
along with librsvg and gtk-engines (so we have an SVG loader, and maybe
the user's GTK+ theme engine.)

New modules:

 gtk+-3, gtk-engines-3, gnome-desktop-3, gdk-pixbuf, pixman, cairo, librsvg

Removed modules:

 gir-repository

Add new requirements to gnome-shell-build-setup.sh and remove some
older requirements we no longer need.

Based on a patch from Colin Walters

https://bugzilla.gnome.org/show_bug.cgi?id=621845
2010-07-07 13:05:09 -04:00
643c7fdb3a Switch build to Gtk+-3.0
Update the build dependencies to gtk+-3.0 and adjust the javascript
to run on gtk+-3. Obviously depends on mutter compiled with gtk+-3
as well.

https://bugzilla.gnome.org/show_bug.cgi?id=621845
2010-07-07 12:57:59 -04:00
174caf0016 Work around g-ir-scanner problem with Gdk.Rectangle
g-ir-scanner is currently buggy and confuses the Gdk.Rectangle alias
with MetaRectangle. Since this is moderately hard to fix in
gobject-introspection and the fix would conflict with in-progress
changes, work around by doing a 'sed job' on the generated Meta.gir.

https://bugzilla.gnome.org/show_bug.cgi?id=623640
2010-07-07 12:57:59 -04:00
ab0d57d6ca Use MetaRectangle for allocated returns
The conversion of GdkRectangle to a typedef for cairo_rectangle_int_t
in GTK+-3 makes it no longer a proper boxed type (it's still registered
boxed, but gobject-introspection doesn't know that.) So, switch to using
MetaRectangle, which is now registered as a boxed type by Mutter.

https://bugzilla.gnome.org/show_bug.cgi?id=621845
2010-07-07 12:56:47 -04:00
a45021bd60 Replace deprecated GDK symbols
The fix depends on API introduced in this cycle, so the required
GTK+ version is bumped to 2.21.1.

https://bugzilla.gnome.org/show_bug.cgi?id=621845
2010-07-05 20:25:50 -04:00
7b79e2e35c [TelepathyClient] Fix notification of presence change
When renaming Source.name to Source.title in commit 83689e4 some
references were missed, which broke presence change notifications.

https://bugzilla.gnome.org/show_bug.cgi?id=623494
2010-07-04 02:06:06 +02:00
fdbda8e731 Updated Spanish translation 2010-07-03 12:51:32 +02:00
4c6c6d8658 update for Punjabi by A S Alam 2010-07-03 06:43:53 +05:30
c405cce700 Updated Spanish translation 2010-07-02 08:59:22 +02:00
8ade2fc116 Make pango be built before clutter in moduleset
If pango is built, do it before clutter since it will
use it instead of the system version.
2010-06-29 19:52:59 +02:00
40c7d3763b Remove the cursor from the search entry when it doesn't have focus
We should not be showing the cursor in the search entry in the overview
if the user's input will be appearing elsewhere, such as in the run dialog,
in the Looking Glass console, or in the notification's response field.
2010-06-28 18:13:45 -04:00
71bbd4ed5c Updated Spanish translation 2010-06-28 20:57:40 +02:00
a2617fe06a Update Simplified Chinese translations. 2010-06-27 11:06:42 +08:00
d1e1afdaab Add icon buttons to notifications
Now if an id is passed to Notification.addButton that matches a theme icon,
it will be displayed as an icon.  This is another in the implement the
music player mockups series.
http://live.gnome.org/GnomeShell/Design/Guidelines/MessageTray/MusicPlayer

https://bugzilla.gnome.org/show_bug.cgi?id=621014
2010-06-26 20:25:23 +02:00
296 changed files with 56916 additions and 15937 deletions

9
.gitignore vendored
View File

@ -18,11 +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
@ -43,11 +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.31.4],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[2.91.5],[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,40 +60,66 @@ fi
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
CLUTTER_MIN_VERSION=1.2.8
GOBJECT_INTROSPECTION_MIN_VERSION=0.6.11
GJS_MIN_VERSION=0.7
MUTTER_MIN_VERSION=2.31.4
GTK_MIN_VERSION=2.18.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
LIBEDATASERVERUI_REQUIRED=1.2.0
# 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
gtk+-2.0 >= $GTK_MIN_VERSION
gio-unix-2.0 dbus-glib-1 libxml-2.0
gtk+-3.0 >= $GTK_MIN_VERSION
mutter-plugins >= $MUTTER_MIN_VERSION
gjs-gi-1.0 >= $GJS_MIN_VERSION
gjs-internals-1.0 >= $GJS_MIN_VERSION
libgnome-menu $recorder_modules gconf-2.0
gdk-x11-2.0
gdk-x11-3.0
clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
libstartup-notification-1.0
gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_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"])
# This is for the newly added application id bits, we can replace this with
# a version check later
saved_CFLAGS=$CFLAGS
saved_LIBS=$LIBS
CFLAGS=$MUTTER_PLUGIN_CFLAGS
LIBS=$MUTTER_PLUGIN_LIBS
AC_CHECK_FUNCS(sn_startup_sequence_get_application_id)
# sn_startup_sequence_get_application_id, we can replace with a version check later
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+-2.0 libcroco-0.6 gnome-desktop-2.0 >= 2.26)
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-2.0)
PKG_CHECK_MODULES(TRAY, gtk+-2.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])])
PKG_CHECK_MODULES(LIBECAL, libecal-1.2 >= $LIBECAL_REQUIRED libedataserver-1.2 >= $LIBEDATASERVER_REQUIRED libedataserverui-1.2 >= $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
@ -100,11 +129,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)
@ -158,10 +183,7 @@ AC_CONFIG_FILES([
Makefile
data/Makefile
js/Makefile
js/misc/Makefile
js/ui/Makefile
js/perf/Makefile
js/prefs/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,31 +25,42 @@ 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/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/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 \
theme/scroll-button-up.png \
theme/scroll-hhandle.svg \
theme/scroll-vhandle.svg \
theme/section-more.svg \
theme/section-more-open.svg \
theme/separator-white.png \
theme/single-view-active.svg \
theme/single-view.svg \
theme/scroll-hhandle.svg \
theme/scroll-vhandle.svg \
theme/section-more.svg \
theme/section-more-open.svg \
theme/separator-white.png \
theme/single-view-active.svg \
theme/single-view.svg \
theme/toggle-off-us.svg \
theme/toggle-off-intl.svg \
theme/toggle-on-us.svg \
theme/toggle-on-intl.svg \
theme/ws-switch-arrow-left.svg \
theme/ws-switch-arrow-right.svg
gsettings_SCHEMAS = org.gnome.shell.gschema.xml
gsettings_SCHEMAS = \
org.gnome.accessibility.magnifier.gschema.xml \
org.gnome.shell.gschema.xml
@INTLTOOL_XML_NOMERGE_RULE@
@GSETTINGS_RULES@
@ -67,6 +81,10 @@ menudir = $(sysconfdir)/xdg/menus
menu_DATA = \
gs-applications.menu
shadersdir = $(pkgdatadir)/shaders
shaders_DATA = \
shaders/dim-window.glsl
install-data-local:
GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(srcdir)/$(gconfschema_DATA)
@ -74,14 +92,14 @@ install-data-local:
EXTRA_DIST = \
gnome-shell.desktop.in.in \
gnome-shell-clock-preferences.desktop.in.in \
$(menu_DATA) \
$(gconfschema_DATA) \
$(shaders_DATA) \
org.gnome.accessibility.magnifier.gschema.xml.in \
org.gnome.shell.gschema.xml.in
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

@ -2,6 +2,21 @@
<schemalist>
<!-- Metacity overrides -->
<schema>
<key>/schemas/desktop/gnome/shell/windows/attach_modal_dialogs</key>
<applyto>/desktop/gnome/shell/windows/attach_modal_dialogs</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>true</default>
<locale name="C">
<short>Attach modal dialog to the parent window</short>
<long>
This key overrides /apps/mutter/general/attach_modal_dialogs when
running GNOME Shell.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/windows/button_layout</key>
<applyto>/desktop/gnome/shell/windows/button_layout</applyto>
@ -28,197 +43,41 @@
</locale>
</schema>
<!-- Magnifier -->
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/show_magnifier</key>
<applyto>/desktop/gnome/accessibility/magnifier/show_magnifier</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>false</default>
<default>true</default>
<locale name="C">
<short>Show or hide the magnifier</short>
<long>
Show or hide the magnifier and all of its zoom regions.
</long>
<short>enable edge tiling when dropping windows on screen edges</short>
<long>
If enabled, dropping windows on vertical screen edges maximizes them
vertically and resizes them horizontally to cover half of the
available area. Dropping windows on the top screen edge maximizes them
completely.
This key overrides /apps/metacity/general/edge_tiling when
running GNOME Shell.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/mouse_tracking</key>
<applyto>/desktop/gnome/accessibility/magnifier/mouse_tracking</applyto>
<owner>gnome-shell</owner>
<type>int</type>
<default>1</default>
<locale name="C">
<short>Mouse Tracking Mode</short>
<long>
Determines the position of the magnified mouse image within
the magnified view and how it reacts to system mouse movement.
The values are 0 - none: no mouse tracking; 1 - 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; 2 -
proportional: the position of the magnified mouse in the zoom
region is proportionally the same as the position of the system
mouse on screen; or 3 - push: when the magnified mouse
intersects a boundary of the zoom region, the contents are
scrolled into view.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/screen_position</key>
<applyto>/desktop/gnome/accessibility/magnifier/screen_position</applyto>
<owner>gnome-shell</owner>
<type>int</type>
<default>3</default>
<locale name="C">
<short>Screen position</short>
<long>
The magnified view either fills the entire screen (1), or
occupies the top-half (2), bottom-half (3), left-half (4), or
right-half (5) of the screen.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/mag_factor</key>
<applyto>/desktop/gnome/accessibility/magnifier/mag_factor</applyto>
<owner>gnome-shell</owner>
<type>float</type>
<default>2.0</default>
<locale name="C">
<short>Magnification factor</short>
<long>
The power of the magnification. A value of 1.0 means no
magnification. A value of 2.0 doubles the size.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/lens_mode</key>
<applyto>/desktop/gnome/accessibility/magnifier/lens_mode</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>false</default>
<locale name="C">
<short>Enable lens mode</short>
<long>
Whether the magnified view should be centered over the location
of the system mouse and move with it.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/scroll_at_edges</key>
<applyto>/desktop/gnome/accessibility/magnifier/scroll_at_edges</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>false</default>
<locale name="C">
<short>Scroll magnified contents beyond the edges of the desktop</short>
<long>
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.
</long>
</locale>
</schema>
<!-- Magnifier: Crosshairs -->
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/show_cross_hairs</key>
<applyto>/desktop/gnome/accessibility/magnifier/show_cross_hairs</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>false</default>
<locale name="C">
<short>Show or hide crosshairs</short>
<long>
Enables/disables display of crosshairs centered on the magnified mouse
sprite.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/cross_hairs_thickness</key>
<applyto>/desktop/gnome/accessibility/magnifier/cross_hairs_thickness</applyto>
<owner>gnome-shell</owner>
<type>int</type>
<default>8</default>
<locale name="C">
<short>Thickness of the crosshairs</short>
<long>
Width of the vertical and horizontal lines that make up the
crosshairs.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/cross_hairs_color</key>
<applyto>/desktop/gnome/accessibility/magnifier/cross_hairs_color</applyto>
<key>/schemas/desktop/gnome/shell/windows/theme</key>
<applyto>/desktop/gnome/shell/windows/theme</applyto>
<owner>gnome-shell</owner>
<type>string</type>
<default>#ff0000</default>
<default>Adwaita</default>
<locale name="C">
<short>Color of the crosshairs</short>
<long>
The color of the the vertical and horizontal lines that make up
the crosshairs.
</long>
</locale>
</schema>
<short>Current theme</short>
<long>
The theme determines the appearance of window borders,
titlebar, and so forth.
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/cross_hairs_opacity</key>
<applyto>/desktop/gnome/accessibility/magnifier/cross_hairs_opacity</applyto>
<owner>gnome-shell</owner>
<type>int</type>
<default>169</default>
<locale name="C">
<short>Opacity of the crosshairs</short>
<long>
Determines the transparency of the crosshairs, from fully opaque
to fully transparent.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/cross_hairs_length</key>
<applyto>/desktop/gnome/accessibility/magnifier/cross_hairs_length</applyto>
<owner>gnome-shell</owner>
<type>int</type>
<default>4096</default>
<locale name="C">
<short>Length of the crosshairs</short>
<long>
Determines the length of the vertical and horizontal lines that
make up the crosshairs.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/cross_hairs_clip</key>
<applyto>/desktop/gnome/accessibility/magnifier/cross_hairs_clip</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>false</default>
<locale name="C">
<short>Clip the crosshairs at the center</short>
<long>
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.
</long>
This key overrides /apps/metacity/general/theme when
running GNOME Shell.
</long>
</locale>
</schema>

View File

@ -1,11 +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>
@ -14,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

@ -0,0 +1,133 @@
<schemalist>
<enum id="MouseTrackingMode">
<value nick="none" value="0"/>
<value nick="centered" value="1"/>
<value nick="proportional" value="2"/>
<value nick="push" value="3"/>
</enum>
<enum id="ScreenPosition">
<value nick="none" value="0"/>
<value nick="full-screen" value="1"/>
<value nick="top-half" value="2"/>
<value nick="bottom-half" value="3"/>
<value nick="left-half" value="4"/>
<value nick="right-half" value="5"/>
</enum>
<schema id="org.gnome.accessibility.magnifier"
path="/desktop/gnome/accessibility/magnifier/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="show-magnifier" type="b">
<default>false</default>
<_summary>Show or hide the magnifier</_summary>
<_description>
Show or hide the magnifier and all of its zoom regions.
</_description>
</key>
<key name="mouse-tracking" enum="MouseTrackingMode">
<default>'proportional'</default>
<_summary>Mouse Tracking Mode</_summary>
<_description>
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.
</_description>
</key>
<key name="screen-position" enum="ScreenPosition">
<default>'full-screen'</default>
<_summary>Screen position</_summary>
<_description>
The magnified view either fills the entire screen, or occupies the
top-half, bottom-half, left-half, or right-half of the screen.
</_description>
</key>
<key name="mag-factor" type="d">
<default>2.0</default>
<_summary>Magnification factor</_summary>
<_description>
The power of the magnification. A value of 1.0 means no magnification.
A value of 2.0 doubles the size.
</_description>
</key>
<key name="lens-mode" type="b">
<default>false</default>
<_summary>Enable lens mode</_summary>
<_description>
Whether the magnified view should be centered over the location of
the system mouse and move with it.
</_description>
</key>
<key name="scroll-at-edges" type="b">
<default>false</default>
<_summary>
Scroll magnified contents beyond the edges of the desktop
</_summary>
<_description>
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.
</_description>
</key>
<!-- Cross-hairs -->
<key name="show-cross-hairs" type="b">
<default>false</default>
<_summary>Show or hide crosshairs</_summary>
<_description>
Enables/disables display of crosshairs centered on the magnified
mouse sprite.
</_description>
</key>
<key name="cross-hairs-thickness" type="i">
<default>8</default>
<_summary>Thickness of the crosshairs</_summary>
<_description>
Width of the vertical and horizontal lines that make up the crosshairs.
</_description>
</key>
<key name="cross-hairs-color" type="s">
<default>'#ff0000'</default>
<_summary>Color of the crosshairs</_summary>
<_description>
The color of the the vertical and horizontal lines that make up
the crosshairs.
</_description>
</key>
<key name="cross-hairs-opacity" type="i">
<default>169</default>
<_summary>Opacity of the crosshairs</_summary>
<_description>
Determines the transparency of the crosshairs, from fully opaque
to fully transparent.
</_description>
</key>
<key name="cross-hairs-length" type="i">
<default>4096</default>
<_summary>Length of the crosshairs</_summary>
<_description>
Determines the length of the vertical and horizontal lines that
make up the crosshairs.
</_description>
</key>
<key name="cross-hairs-clip" type="b">
<default>false</default>
<_summary>Clip the crosshairs at the center</_summary>
<_description>
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.
</_description>
</key>
</schema>
</schemalist>

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,26 @@
#version 110
uniform sampler2D sampler0;
uniform float fraction;
uniform float height;
const float c = -0.2;
const float border_max_height = 60.0;
mat4 contrast = mat4 (1.0 + c, 0.0, 0.0, 0.0,
0.0, 1.0 + c, 0.0, 0.0,
0.0, 0.0, 1.0 + c, 0.0,
0.0, 0.0, 0.0, 1.0);
vec4 off = vec4(0.633, 0.633, 0.633, 0);
void main()
{
vec4 color = texture2D(sampler0, gl_TexCoord[0].st);
float y = height * gl_TexCoord[0][1];
// To reduce contrast, blend with a mid gray
gl_FragColor = color * contrast - off * c;
// We only fully dim at a distance of BORDER_MAX_HEIGHT from the edge and
// when the fraction is 1.0. For other locations and fractions we linearly
// interpolate back to the original undimmed color.
gl_FragColor = color + (gl_FragColor - color) * min(y / border_max_height, 1.0);
gl_FragColor = color + (gl_FragColor - color) * fraction;
}

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

@ -0,0 +1,126 @@
<?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="64"
height="22"
id="svg3273"
version="1.1"
inkscape:version="0.47 r22583"
sodipodi:docname="New document 14">
<defs
id="defs3275">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective3281" />
<inkscape:perspective
id="perspective3261"
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="0.35"
inkscape:cx="32.000004"
inkscape:cy="10.999997"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="609"
inkscape:window-height="501"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="0" />
<metadata
id="metadata3278">
<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(-343,-521.36218)">
<g
id="g17454"
transform="translate(-453,448.36218)"
style="display:inline">
<rect
transform="scale(-1,1)"
ry="4"
rx="4"
y="74.5"
x="-859.5"
height="19"
width="63.000004"
id="rect17456"
style="color:#000000;fill:none;stroke:#2e3436;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<rect
transform="scale(-1,1)"
ry="4"
rx="4"
y="74"
x="-828"
height="20"
width="31"
id="rect17458"
style="fill:#000000;fill-opacity:1;stroke:#5f5f5f;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" />
<g
transform="matrix(-1,0,0,1,1619.1239,-33.986291)"
id="g17460"
style="display:inline">
<path
style="fill:none;stroke:#5f5f5f;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
d="m 803.6322,115.48629 0,4.29495"
id="path17462"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#5f5f5f;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m 806.62805,115.48629 0,4.29495"
id="path17464"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#5f5f5f;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m 809.6239,115.48629 0,4.29495"
id="path17466"
inkscape:connector-curvature="0" />
</g>
<path
sodipodi:type="arc"
style="color:#000000;fill:none;stroke:#ffffff;stroke-width:1.96875012;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path18722"
sodipodi:cx="47.6875"
sodipodi:cy="11.5625"
sodipodi:rx="3.9375"
sodipodi:ry="3.9375"
d="m 51.625,11.5625 c 0,2.174621 -1.762879,3.9375 -3.9375,3.9375 -2.174621,0 -3.9375,-1.762879 -3.9375,-3.9375 0,-2.1746212 1.762879,-3.9375 3.9375,-3.9375 2.174621,0 3.9375,1.7628788 3.9375,3.9375 z"
transform="matrix(1.0158729,0,0,1.0158729,795.55556,72.25399)" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1,138 @@
<?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="64"
height="22"
id="svg3012"
version="1.1"
inkscape:version="0.47 r22583"
sodipodi:docname="New document 6">
<defs
id="defs3014">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective3020" />
<inkscape:perspective
id="perspective2997"
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="0.35"
inkscape:cx="32.000004"
inkscape:cy="10.999997"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="609"
inkscape:window-height="501"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="0" />
<metadata
id="metadata3017">
<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(-343,-521.36218)">
<g
id="g17454"
transform="translate(-453,448.36218)"
style="display:inline">
<rect
transform="scale(-1,1)"
ry="4"
rx="4"
y="74.5"
x="-859.5"
height="19"
width="63.000004"
id="rect17456"
style="color:#000000;fill:none;stroke:#2e3436;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<rect
transform="scale(-1,1)"
ry="4"
rx="4"
y="74"
x="-828"
height="20"
width="31"
id="rect17458"
style="fill:#000000;fill-opacity:1;stroke:#5f5f5f;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" />
<g
transform="matrix(-1,0,0,1,1619.1239,-33.986291)"
id="g17460"
style="display:inline">
<path
style="fill:none;stroke:#5f5f5f;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
d="m 803.6322,115.48629 0,4.29495"
id="path17462"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#5f5f5f;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m 806.62805,115.48629 0,4.29495"
id="path17464"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#5f5f5f;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m 809.6239,115.48629 0,4.29495"
id="path17466"
inkscape:connector-curvature="0" />
</g>
<g
style="font-size:8.95877075px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:125%;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold"
id="text17468"
transform="translate(0.34375,0)">
<path
d="m 837.28518,80.750726 c 0.63282,6e-6 1.19566,0.123947 1.68852,0.371824 0.49284,0.247888 0.8807,0.609505 1.16359,1.084851 0.28287,0.472439 0.42431,1.022155 0.42431,1.649149 0,0.635748 -0.13853,1.200045 -0.41556,1.692892 -0.27706,0.489934 -0.66638,0.870507 -1.16797,1.141719 -0.5016,0.271213 -1.07756,0.406819 -1.72789,0.406819 -0.42869,0 -0.83551,-0.06562 -1.22045,-0.196848 -0.38495,-0.134148 -0.73053,-0.32808 -1.03674,-0.581795 -0.30329,-0.256631 -0.54534,-0.589085 -0.72615,-0.997363 -0.17789,-0.408276 -0.26684,-0.869045 -0.26683,-1.382311 -10e-6,-0.638658 0.13997,-1.200039 0.41994,-1.684144 0.27996,-0.487011 0.66782,-0.858835 1.16359,-1.115472 0.49576,-0.259541 1.06297,-0.389315 1.70164,-0.389321 m 0.57305,1.089225 c -0.20123,-0.05249 -0.40683,-0.07873 -0.61679,-0.07874 -0.20998,5e-6 -0.41412,0.02625 -0.61242,0.07874 -0.19831,0.04958 -0.38933,0.129779 -0.57305,0.240592 -0.18081,0.107907 -0.33974,0.242055 -0.47681,0.402445 -0.13706,0.160399 -0.24642,0.358705 -0.32808,0.594918 -0.0816,0.233306 -0.12248,0.491395 -0.12248,0.774269 0,0.67366 0.20851,1.214627 0.62554,1.622903 0.41702,0.408278 0.93758,0.612416 1.56166,0.612416 0.25954,0 0.51034,-0.04229 0.7524,-0.126858 0.24496,-0.08457 0.47097,-0.20997 0.67803,-0.376198 0.20705,-0.166226 0.37328,-0.392236 0.49868,-0.678032 0.12539,-0.285792 0.18809,-0.610956 0.1881,-0.975492 -10e-6,-0.297455 -0.0437,-0.568668 -0.13123,-0.813638 -0.0875,-0.247878 -0.20415,-0.453475 -0.34995,-0.61679 -0.14291,-0.163307 -0.31059,-0.301829 -0.50306,-0.415568 -0.18956,-0.11373 -0.38641,-0.195385 -0.59054,-0.244967"
style="line-height:125%;fill:#ffffff;fill-opacity:1;marker:none;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold"
id="path18599"
inkscape:connector-curvature="0" />
<path
d="m 843.5362,81.831203 0,1.17917 2.94834,0 0,1.014861 -2.94834,0 0,3.00713 -1.10673,0 0,-6.216022 4.31754,0 0,1.014861 -3.21081,0"
style="line-height:125%;fill:#ffffff;fill-opacity:1;marker:none;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold"
id="path18601"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccc" />
<path
d="m 849.71285,81.831203 0,1.17917 2.94834,0 0,1.014861 -2.94834,0 0,3.00713 -1.10672,0 0,-6.216022 4.31753,0 0,1.014861 -3.21081,0"
style="line-height:125%;fill:#ffffff;fill-opacity:1;marker:none;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold"
id="path18603"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccc" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -0,0 +1,122 @@
<?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="65"
height="22"
id="svg3199"
version="1.1"
inkscape:version="0.47 r22583"
sodipodi:docname="New document 11">
<defs
id="defs3201">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective3207" />
<inkscape:perspective
id="perspective3187"
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="0.35"
inkscape:cx="32.500004"
inkscape:cy="10.999997"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="609"
inkscape:window-height="501"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="0" />
<metadata
id="metadata3204">
<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(-342.5,-521.36218)">
<g
style="display:inline"
transform="translate(-453.5,448.36218)"
id="g16453">
<rect
style="color:#000000;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect16256-9-4"
width="63.000004"
height="19"
x="-859.5"
y="74.5"
rx="4"
ry="4"
transform="scale(-1,1)" />
<rect
style="fill:#000000;fill-opacity:1;stroke:#5f5f5f;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
id="rect16258-5-4"
width="31"
height="20"
x="-860"
y="74"
rx="4"
ry="4"
transform="scale(-1,1)" />
<g
style="display:inline"
id="g16298-3-6"
transform="matrix(-1,0,0,1,1651.1322,-33.986291)">
<path
inkscape:connector-curvature="0"
id="path16265-3-5"
d="m 803.6322,115.48629 0,4.29495"
style="fill:none;stroke:#5f5f5f;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path16265-0-2-0"
d="m 806.62805,115.48629 0,4.29495"
style="fill:none;stroke:#5f5f5f;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
<path
inkscape:connector-curvature="0"
id="path16265-8-7-1"
d="m 809.6239,115.48629 0,4.29495"
style="fill:none;stroke:#5f5f5f;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
</g>
<path
style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 16,27.9375 0,10.125"
id="path19232"
inkscape:connector-curvature="0"
transform="translate(796,51.00002)" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

128
data/theme/toggle-on-us.svg Normal file
View File

@ -0,0 +1,128 @@
<?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="65"
height="22"
id="svg2857"
version="1.1"
inkscape:version="0.47 r22583"
sodipodi:docname="New document 2">
<defs
id="defs2859">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective2865" />
<inkscape:perspective
id="perspective2843"
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="1"
inkscape:cx="-69.642856"
inkscape:cy="42.428569"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="609"
inkscape:window-height="501"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="0" />
<metadata
id="metadata2862">
<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(-444.64286,-781.36218)">
<g
style="display:inline"
transform="translate(-351.35714,708.36218)"
id="g16453">
<rect
style="color:#000000;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect16256-9-4"
width="63.000004"
height="19"
x="-859.5"
y="74.5"
rx="4"
ry="4"
transform="scale(-1,1)" />
<rect
style="fill:#000000;fill-opacity:1;stroke:#5f5f5f;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
id="rect16258-5-4"
width="31"
height="20"
x="-860"
y="74"
rx="4"
ry="4"
transform="scale(-1,1)" />
<g
style="display:inline"
id="g16298-3-6"
transform="matrix(-1,0,0,1,1651.1322,-33.986291)">
<path
inkscape:connector-curvature="0"
id="path16265-3-5"
d="m 803.6322,115.48629 0,4.29495"
style="fill:none;stroke:#5f5f5f;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path16265-0-2-0"
d="m 806.62805,115.48629 0,4.29495"
style="fill:none;stroke:#5f5f5f;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
<path
inkscape:connector-curvature="0"
id="path16265-8-7-1"
d="m 809.6239,115.48629 0,4.29495"
style="fill:none;stroke:#5f5f5f;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
</g>
<g
style="font-size:8.95877075px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:125%;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold"
id="text42229-3-0">
<path
d="m 808.01473,80.573953 c 0.63283,6e-6 1.19567,0.123947 1.68852,0.371824 0.49284,0.247888 0.88071,0.609505 1.16359,1.084851 0.28287,0.472439 0.42431,1.022155 0.42432,1.649149 -10e-6,0.635748 -0.13853,1.200045 -0.41557,1.692892 -0.27705,0.489934 -0.66637,0.870506 -1.16796,1.141719 -0.50161,0.271212 -1.07757,0.406819 -1.72789,0.406819 -0.4287,0 -0.83552,-0.06562 -1.22046,-0.196848 -0.38495,-0.134148 -0.73053,-0.32808 -1.03673,-0.581795 -0.3033,-0.256631 -0.54535,-0.589085 -0.72615,-0.997363 -0.1779,-0.408276 -0.26684,-0.869045 -0.26684,-1.382311 0,-0.638658 0.13998,-1.200039 0.41994,-1.684144 0.27996,-0.487011 0.66782,-0.858835 1.16359,-1.115472 0.49576,-0.259541 1.06298,-0.389315 1.70164,-0.389321 m 0.57305,1.089225 c -0.20123,-0.05249 -0.40682,-0.07873 -0.61679,-0.07874 -0.20998,5e-6 -0.41411,0.02625 -0.61242,0.07874 -0.19831,0.04958 -0.38932,0.129779 -0.57304,0.240592 -0.18081,0.107907 -0.33975,0.242055 -0.47681,0.402445 -0.13707,0.160399 -0.24643,0.358705 -0.32808,0.594918 -0.0817,0.233305 -0.12249,0.491395 -0.12249,0.774269 0,0.67366 0.20851,1.214627 0.62554,1.622902 0.41703,0.408279 0.93758,0.612417 1.56166,0.612416 0.25955,10e-7 0.51035,-0.04228 0.7524,-0.126857 0.24496,-0.08457 0.47097,-0.20997 0.67803,-0.376199 0.20705,-0.166225 0.37328,-0.392236 0.49868,-0.678031 0.1254,-0.285792 0.1881,-0.610956 0.1881,-0.975492 0,-0.297455 -0.0437,-0.568668 -0.13123,-0.813638 -0.0875,-0.247878 -0.20414,-0.453475 -0.34995,-0.61679 -0.1429,-0.163307 -0.31059,-0.301829 -0.50306,-0.415568 -0.18956,-0.11373 -0.38641,-0.195385 -0.59054,-0.244967"
style="line-height:125%;fill:#ffffff;fill-opacity:1;marker:none;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold"
id="path18606" />
<path
d="m 813.15903,80.639569 1.21608,0 3.4689,4.776844 0,-4.776844 1.10235,0 0,6.216022 -1.22921,0 -3.45577,-4.785594 0,4.785594 -1.10235,0 0,-6.216022"
style="line-height:125%;fill:#ffffff;fill-opacity:1;marker:none;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold"
id="path18608" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.7 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

@ -1 +1,63 @@
SUBDIRS = misc ui perf prefs
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 \
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/iconGrid.js \
ui/lightbox.js \
ui/link.js \
ui/lookingGlass.js \
ui/magnifier.js \
ui/magnifierDBus.js \
ui/main.js \
ui/messageTray.js \
ui/modalDialog.js \
ui/notificationDaemon.js \
ui/overview.js \
ui/panel.js \
ui/panelMenu.js \
ui/placeDisplay.js \
ui/popupMenu.js \
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/xdndHandler.js

View File

@ -1,8 +0,0 @@
jsmiscdir = $(pkgdatadir)/js/misc
dist_jsmisc_DATA = \
docInfo.js \
format.js \
gnomeSession.js \
params.js \
telepathy.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

@ -1,15 +1,10 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Lang = imports.lang;
const Signals = imports.signals;
const Search = imports.ui.search;
const Main = imports.ui.main;
const THUMBNAIL_ICON_MARGIN = 2;
@ -23,7 +18,7 @@ DocInfo.prototype = {
// We actually used get_modified() instead of get_visited()
// here, as GtkRecentInfo doesn't updated get_visited()
// correctly. See http://bugzilla.gnome.org/show_bug.cgi?id=567094
this.timestamp = recentInfo.get_modified().getTime() / 1000;
this.timestamp = recentInfo.get_modified();
this.name = recentInfo.get_display_name();
this._lowerName = this.name.toLowerCase();
this.uri = recentInfo.get_uri();
@ -44,15 +39,12 @@ DocInfo.prototype = {
let term = terms[i];
let idx = this._lowerName.indexOf(term);
if (idx == 0) {
if (mtype != Search.MatchType.NONE)
return Search.MatchType.MULTIPLE;
mtype = Search.MatchType.PREFIX;
} else if (idx > 0) {
if (mtype != Search.MatchType.NONE)
return Search.MatchType.MULTIPLE;
mtype = Search.MatchType.SUBSTRING;
if (mtype == Search.MatchType.NONE)
mtype = Search.MatchType.SUBSTRING;
} else {
continue;
return Search.MatchType.NONE;
}
}
return mtype;
@ -68,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();
@ -114,39 +105,35 @@ DocManager.prototype = {
return this._docSystem.queue_existence_check(count);
},
initialSearch: function(terms) {
let multipleMatches = [];
_searchDocs: function(items, terms) {
let multiplePrefixMatches = [];
let prefixMatches = [];
let multipleSubtringMatches = [];
let substringMatches = [];
for (let i = 0; i < this._infosByTimestamp.length; i++) {
let item = this._infosByTimestamp[i];
for (let i = 0; i < items.length; i++) {
let item = items[i];
let mtype = item.matchTerms(terms);
if (mtype == Search.MatchType.MULTIPLE)
multipleMatches.push(item.uri);
if (mtype == Search.MatchType.MULTIPLE_PREFIX)
multiplePrefixMatches.push(item.uri);
else if (mtype == Search.MatchType.PREFIX)
prefixMatches.push(item.uri);
else if (mtype == Search.MatchType.MULTIPLE_SUBSTRING)
multipleSubtringMatches.push(item.uri);
else if (mtype == Search.MatchType.SUBSTRING)
substringMatches.push(item.uri);
}
return multipleMatches.concat(prefixMatches.concat(substringMatches));
return multiplePrefixMatches.concat(prefixMatches.concat(multipleSubtringMatches.concat(substringMatches)));
},
initialSearch: function(terms) {
return this._searchDocs(this._infosByTimestamp, terms);
},
subsearch: function(previousResults, terms) {
let multipleMatches = [];
let prefixMatches = [];
let substringMatches = [];
for (let i = 0; i < previousResults.length; i++) {
let uri = previousResults[i];
let item = this._infosByUri[uri];
let mtype = item.matchTerms(terms);
if (mtype == Search.MatchType.MULTIPLE)
multipleMatches.push(uri);
else if (mtype == Search.MatchType.PREFIX)
prefixMatches.push(uri);
else if (mtype == Search.MatchType.SUBSTRING)
substringMatches.push(uri);
}
return multipleMatches.concat(prefixMatches.concat(substringMatches));
return this._searchDocs(previousResults.map(Lang.bind(this,
function(url) {
return this._infosByUri[url];
})), terms);
}
};

22
js/misc/fileUtils.js Normal file
View File

@ -0,0 +1,22 @@
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
function listDirAsync(file, callback) {
let allFiles = [];
file.enumerate_children_async(Gio.FILE_ATTRIBUTE_STANDARD_NAME,
Gio.FileQueryInfoFlags.NONE,
GLib.PRIORITY_LOW, null, function (obj, res) {
let enumerator = obj.enumerate_children_finish(res);
function onNextFileComplete(obj, res) {
let files = obj.next_files_finish(res);
if (files.length) {
allFiles = allFiles.concat(files);
enumerator.next_files_async(100, GLib.PRIORITY_LOW, null, onNextFileComplete);
} else {
enumerator.close(null);
callback(allFiles);
}
}
enumerator.next_files_async(100, GLib.PRIORITY_LOW, null, onNextFileComplete);
});
}

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

@ -2,28 +2,15 @@
const DBus = imports.dbus;
// D-Bus utils; should eventually move to gjs.
// https://bugzilla.gnome.org/show_bug.cgi?id=610859
function makeProxyClass(iface) {
let constructor = function() { this._init.apply(this, arguments); };
constructor.prototype._init = function(bus, name, path) {
bus.proxifyObject(this, name, path);
};
DBus.proxifyPrototype(constructor.prototype, iface);
return constructor;
}
// D-Bus utils
function nameToPath(name) {
return '/' + name.replace('.', '/', 'g');
return '/' + name.replace(/\./g, '/');
};
function pathToName(path) {
if (path[0] != '/')
throw new Error('not a D-Bus path: ' + path);
return path.substr(1).replace('/', '.', 'g');
return path.substr(1).replace(/\//g, '.');
};
// This is tp_escape_as_identifier() from telepathy-glib
@ -118,7 +105,7 @@ const ChannelDispatchOperationIface = {
outSignature: '' }
]
};
let ChannelDispatchOperation = makeProxyClass(ChannelDispatchOperationIface);
let ChannelDispatchOperation = DBus.makeProxyClass(ChannelDispatchOperationIface);
const CONNECTION_NAME = TELEPATHY + '.Connection';
const ConnectionIface = {
@ -128,7 +115,7 @@ const ConnectionIface = {
inSignature: 'uu' }
]
};
let Connection = makeProxyClass(ConnectionIface);
let Connection = DBus.makeProxyClass(ConnectionIface);
const ConnectionStatus = {
CONNECTED: 0,
@ -150,7 +137,7 @@ const ConnectionAliasingIface = {
inSignature: 'a(us)' }
]
};
let ConnectionAliasing = makeProxyClass(ConnectionAliasingIface);
let ConnectionAliasing = DBus.makeProxyClass(ConnectionAliasingIface);
const CONNECTION_AVATARS_NAME = CONNECTION_NAME + '.Interface.Avatars';
const ConnectionAvatarsIface = {
@ -174,7 +161,7 @@ const ConnectionAvatarsIface = {
}
]
};
let ConnectionAvatars = makeProxyClass(ConnectionAvatarsIface);
let ConnectionAvatars = DBus.makeProxyClass(ConnectionAvatarsIface);
const CONNECTION_CONTACTS_NAME = CONNECTION_NAME + '.Interface.Contacts';
const ConnectionContactsIface = {
@ -186,7 +173,7 @@ const ConnectionContactsIface = {
}
]
};
let ConnectionContacts = makeProxyClass(ConnectionContactsIface);
let ConnectionContacts = DBus.makeProxyClass(ConnectionContactsIface);
const CONNECTION_REQUESTS_NAME = CONNECTION_NAME + '.Interface.Requests';
const ConnectionRequestsIface = {
@ -215,7 +202,7 @@ const ConnectionRequestsIface = {
}
]
};
let ConnectionRequests = makeProxyClass(ConnectionRequestsIface);
let ConnectionRequests = DBus.makeProxyClass(ConnectionRequestsIface);
const CONNECTION_SIMPLE_PRESENCE_NAME = CONNECTION_NAME + '.Interface.SimplePresence';
const ConnectionSimplePresenceIface = {
@ -234,7 +221,7 @@ const ConnectionSimplePresenceIface = {
inSignature: 'a{u(uss)}' }
]
};
let ConnectionSimplePresence = makeProxyClass(ConnectionSimplePresenceIface);
let ConnectionSimplePresence = DBus.makeProxyClass(ConnectionSimplePresenceIface);
const ConnectionPresenceType = {
UNSET: 0,
@ -264,7 +251,7 @@ const ChannelIface = {
inSignature: '' }
]
};
let Channel = makeProxyClass(ChannelIface);
let Channel = DBus.makeProxyClass(ChannelIface);
const CHANNEL_TEXT_NAME = CHANNEL_NAME + '.Type.Text';
const ChannelTextIface = {
@ -285,10 +272,12 @@ const ChannelTextIface = {
],
signals: [
{ name: 'Received',
inSignature: 'uuuuus' }
inSignature: 'uuuuus' },
{ name: 'Sent',
inSignature: 'uus' }
]
};
let ChannelText = makeProxyClass(ChannelTextIface);
let ChannelText = DBus.makeProxyClass(ChannelTextIface);
const ChannelTextMessageType = {
NORMAL: 0,
@ -315,7 +304,7 @@ const ChannelGroupIface = {
inSignature: 'sauauauauuu' }
]
};
let ChannelGroup = makeProxyClass(ChannelGroupIface);
let ChannelGroup = DBus.makeProxyClass(ChannelGroupIface);
const ACCOUNT_MANAGER_NAME = TELEPATHY + '.AccountManager';
const AccountManagerIface = {
@ -330,7 +319,7 @@ const AccountManagerIface = {
inSignature: 'ob' }
]
};
let AccountManager = makeProxyClass(AccountManagerIface);
let AccountManager = DBus.makeProxyClass(AccountManagerIface);
const ACCOUNT_NAME = TELEPATHY + '.Account';
const AccountIface = {
@ -341,7 +330,7 @@ const AccountIface = {
access: 'read' }
]
};
let Account = makeProxyClass(AccountIface);
let Account = DBus.makeProxyClass(AccountIface);
const CHANNEL_DISPATCHER_NAME = TELEPATHY + '.ChannelDispatcher';
const ChannelDispatcherIface = {
@ -352,7 +341,7 @@ const ChannelDispatcherIface = {
outSignature: 'o' }
]
};
let ChannelDispatcher = makeProxyClass(ChannelDispatcherIface);
let ChannelDispatcher = DBus.makeProxyClass(ChannelDispatcherIface);
const CHANNEL_REQUEST_NAME = TELEPATHY + '.ChannelRequest';
const ChannelRequestIface = {
@ -369,4 +358,4 @@ const ChannelRequestIface = {
signature: '' }
]
};
let ChannelRequest = makeProxyClass(ChannelRequestIface);
let ChannelRequest = DBus.makeProxyClass(ChannelRequestIface);

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,4 +0,0 @@
jsperfdir = $(pkgdatadir)/js/perf
dist_jsperf_DATA = \
core.js

View File

@ -1,4 +0,0 @@
jsprefsdir = $(pkgdatadir)/js/prefs
dist_jsprefs_DATA = \
clockPreferences.js

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

@ -1,39 +0,0 @@
jsuidir = $(pkgdatadir)/js/ui
dist_jsui_DATA = \
altTab.js \
appDisplay.js \
appFavorites.js \
boxpointer.js \
calendar.js \
chrome.js \
dash.js \
dnd.js \
docDisplay.js \
environment.js \
extensionSystem.js \
genericDisplay.js \
lightbox.js \
link.js \
lookingGlass.js \
magnifier.js \
magnifierDBus.js \
main.js \
messageTray.js \
notificationDaemon.js \
overview.js \
panel.js \
placeDisplay.js \
popupMenu.js \
runDialog.js \
scripting.js \
search.js \
shellDBus.js \
statusMenu.js \
telepathyClient.js \
tweener.js \
windowAttentionHandler.js \
windowManager.js \
workspacesView.js \
workspaceSwitcherPopup.js \
workspace.js

View File

@ -4,8 +4,6 @@ const Clutter = imports.gi.Clutter;
const Gdk = imports.gi.Gdk;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
@ -17,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 = 750; // milliseconds
const DISABLE_HOVER_TIMEOUT = 500; // milliseconds
const THUMBNAIL_DEFAULT_SIZE = 256;
@ -36,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));
@ -51,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();
@ -104,9 +107,7 @@ AltTabPopup.prototype = {
childBox.x1 = Math.max(primary.x + leftPadding, childBox.x1 - offset - hPadding);
}
let [found, spacing] = this.actor.get_theme_node().get_length('spacing', false);
if (!found)
spacing = 0;
let spacing = this.actor.get_theme_node().get_length('spacing');
childBox.x2 = childBox.x1 + childNaturalWidth;
if (childBox.x2 > primary.x + primary.width - rightPadding)
@ -130,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));
@ -217,38 +218,45 @@ AltTabPopup.prototype = {
_keyPressEvent : function(actor, event) {
let keysym = event.get_key_symbol();
let shift = (Shell.get_event_state(event) & Clutter.ModifierType.SHIFT_MASK);
// X allows servers to represent Shift+Tab in two different ways
if (shift && keysym == Clutter.Tab)
keysym = Clutter.ISO_Left_Tab;
this._disableHover();
// The WASD stuff is for debugging in Xephyr, where the arrow
// keys aren't mapped correctly
if (keysym == Clutter.grave)
this._select(this._currentApp, shift ? this._previousWindow() : this._nextWindow());
this._select(this._currentApp, this._nextWindow());
else if (keysym == Clutter.asciitilde)
this._select(this._currentApp, this._previousWindow());
else if (keysym == Clutter.Escape)
this.destroy();
else if (this._thumbnailsFocused) {
if (keysym == Clutter.Tab) {
if (shift && (this._currentWindow == 0 || this._currentWindow == -1))
this._select(this._previousApp());
else if (!shift && this._currentWindow == this._appIcons[this._currentApp].cachedWindows.length - 1)
if (this._currentWindow == this._appIcons[this._currentApp].cachedWindows.length - 1)
this._select(this._nextApp());
else
this._select(this._currentApp, shift ? this._previousWindow() : this._nextWindow());
} else if (keysym == Clutter.Left || keysym == Clutter.a)
this._select(this._currentApp, this._nextWindow());
} else if (keysym == Clutter.ISO_Left_Tab) {
if (this._currentWindow == 0 || this._currentWindow == -1)
this._select(this._previousApp());
else
this._select(this._currentApp, this._previousWindow());
} else if (keysym == Clutter.Left)
this._select(this._currentApp, this._previousWindow());
else if (keysym == Clutter.Right || keysym == Clutter.d)
else if (keysym == Clutter.Right)
this._select(this._currentApp, this._nextWindow());
else if (keysym == Clutter.Up || keysym == Clutter.w)
else if (keysym == Clutter.Up)
this._select(this._currentApp, null, true);
} else {
if (keysym == Clutter.Tab)
this._select(shift ? this._previousApp() : this._nextApp());
else if (keysym == Clutter.Left || keysym == Clutter.a)
this._select(this._previousApp());
else if (keysym == Clutter.Right || keysym == Clutter.d)
this._select(this._nextApp());
else if (keysym == Clutter.Down || keysym == Clutter.s)
else if (keysym == Clutter.ISO_Left_Tab)
this._select(this._previousApp());
else if (keysym == Clutter.Left)
this._select(this._previousApp());
else if (keysym == Clutter.Right)
this._select(this._nextApp());
else if (keysym == Clutter.Down)
this._select(this._currentApp, 0);
}
@ -256,9 +264,10 @@ AltTabPopup.prototype = {
},
_keyReleaseEvent : function(actor, event) {
let keysym = event.get_key_symbol();
let [x, y, mods] = global.get_pointer();
let state = mods & Clutter.ModifierType.MOD1_MASK;
if (keysym == Clutter.Alt_L || keysym == Clutter.Alt_R)
if (state == 0)
this._finish();
return true;
@ -361,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() {
@ -379,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)
@ -454,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;
},
@ -474,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; })
});
}
};
@ -495,8 +507,7 @@ SwitcherList.prototype = {
this._list = new Shell.GenericContainer({ style_class: 'switcher-list-item-container' });
this._list.spacing = 0;
this._list.connect('style-changed', Lang.bind(this, function() {
let [found, spacing] = this._list.get_theme_node().get_length('spacing', false);
this._list.spacing = (found) ? spacing : 0;
this._list.spacing = this._list.get_theme_node().get_length('spacing');
}));
this._list.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
@ -589,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;
@ -606,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();
@ -815,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
@ -854,6 +871,8 @@ AppSwitcher.prototype = {
this._curApp = -1;
this._iconSize = 0;
this._altTabPopup = altTabPopup;
this._mouseTimeOutId = 0;
},
_getPreferredHeight: function (actor, forWidth, alloc) {
@ -861,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++) {
@ -916,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
@ -1029,9 +1073,7 @@ ThumbnailList.prototype = {
let totalPadding = this._items[0].get_theme_node().get_horizontal_padding() + this._items[0].get_theme_node().get_vertical_padding();
totalPadding += this.actor.get_theme_node().get_horizontal_padding() + this.actor.get_theme_node().get_vertical_padding();
let [labelMinHeight, labelNaturalHeight] = this._labels[0].get_preferred_height(-1);
let [found, spacing] = this._items[0].child.get_theme_node().get_length('spacing', false);
if (!found)
spacing = 0;
let spacing = this._items[0].child.get_theme_node().get_length('spacing');
availHeight = Math.min(availHeight - labelNaturalHeight - totalPadding - spacing, THUMBNAIL_DEFAULT_SIZE);
let binHeight = availHeight + this._items[0].get_theme_node().get_vertical_padding() + this.actor.get_theme_node().get_vertical_padding() - spacing;

View File

@ -1,9 +1,6 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Pango = imports.gi.Pango;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Shell = imports.gi.Shell;
const Lang = imports.lang;
@ -15,16 +12,15 @@ const _ = Gettext.gettext;
const AppFavorites = imports.ui.appFavorites;
const DND = imports.ui.dnd;
const GenericDisplay = imports.ui.genericDisplay;
const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const PopupMenu = imports.ui.popupMenu;
const Search = imports.ui.search;
const Tweener = imports.ui.tweener;
const Workspace = imports.ui.workspace;
const Params = imports.misc.params;
const APPICON_SIZE = 48;
const WELL_MAX_COLUMNS = 8;
const MENU_POPUP_TIMEOUT = 600;
function AlphabeticalView() {
@ -33,10 +29,29 @@ function AlphabeticalView() {
AlphabeticalView.prototype = {
_init: function() {
this.actor = new St.BoxLayout({ vertical: true });
this._grid = new WellGrid(true);
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() {
@ -44,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)
@ -74,8 +93,6 @@ AlphabeticalView.prototype = {
}
};
Signals.addSignalMethods(AlphabeticalView.prototype);
function ViewByCategories() {
this._init();
}
@ -83,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.
*/
@ -150,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));
},
@ -179,169 +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._spacing = 0;
this.actor = new St.Bin({ name: 'dashAppSearchResults',
x_align: St.Align.START });
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
let container = new Shell.GenericContainer();
this._container = container;
this.actor.set_child(container);
container.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
container.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
container.connect('allocate', Lang.bind(this, this._allocate));
},
_getPreferredWidth: function (actor, forHeight, alloc) {
let children = actor.get_children();
for (let i = 0; i < children.length; i++) {
let [minSize, natSize] = children[i].get_preferred_width(forHeight);
alloc.natural_size += natSize;
}
},
_getPreferredHeight: function (actor, forWidth, alloc) {
let children = actor.get_children();
for (let i = 0; i < children.length; i++) {
let [minSize, natSize] = children[i].get_preferred_height(forWidth);
if (minSize > alloc.min_size)
alloc.min_size = minSize;
if (natSize > alloc.natural_size)
alloc.natural_size = natSize;
}
},
_allocate: function (actor, box, flags) {
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
let children = actor.get_children();
let x = 0;
let i;
for (i = 0; i < children.length; i++) {
let child = children[i];
let childBox = new Clutter.ActorBox();
let [minWidth, minHeight, natWidth, natHeight] = child.get_preferred_size();
if (x + natWidth > availWidth) {
actor.set_skip_paint(child, true);
continue;
}
let yPadding = Math.max(0, availHeight - natHeight);
childBox.x1 = x;
childBox.x2 = childBox.x1 + natWidth;
childBox.y1 = Math.floor(yPadding / 2);
childBox.y2 = availHeight - childBox.y1;
x = childBox.x2 + this._spacing;
child.allocate(childBox, flags);
actor.set_skip_paint(child, false);
}
},
_onStyleChanged: function () {
let themeNode = this.actor.get_theme_node();
let [success, len] = themeNode.get_length('spacing', false);
if (success)
this._spacing = len;
this._container.queue_relayout();
},
renderResults: function(results, terms) {
let appSys = Shell.AppSystem.get_default();
for (let i = 0; i < results.length && i < WELL_MAX_COLUMNS; i++) {
let result = results[i];
let app = appSys.get_app(result);
let display = new AppWellIcon(app);
this._container.add_actor(display.actor);
}
},
clear: function () {
this._container.get_children().forEach(function (actor) { actor.destroy(); });
this.selectionIndex = -1;
},
getVisibleResultCount: function() {
let nChildren = this._container.get_children().length;
return nChildren - this._container.get_n_skip_paint();
},
selectIndex: function (index) {
let nVisible = this.getVisibleResultCount();
let children = this._container.get_children();
if (this.selectionIndex >= 0) {
let prevActor = children[this.selectionIndex];
prevActor._delegate.setSelected(false);
}
this.selectionIndex = -1;
if (index >= nVisible)
return false;
else if (index < 0)
return false;
let targetActor = children[index];
targetActor._delegate.setSelected(true);
this.selectionIndex = index;
return true;
},
activateSelected: function() {
if (this.selectionIndex < 0)
return;
let children = this._container.get_children();
let targetActor = children[this.selectionIndex];
this.provider.activateResult(targetActor._delegate.app.get_id());
}
};
@ -396,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) {
@ -435,37 +290,34 @@ PrefsSearchProvider.prototype = {
}
};
function AppIcon(app) {
this._init(app);
function AppIcon(app, params) {
this._init(app, params);
}
AppIcon.prototype = {
_init : function(app) {
__proto__: IconGrid.BaseIcon.prototype,
_init : function(app, params) {
this.app = app;
this.actor = new St.Bin({ style_class: 'app-icon',
x_fill: true,
y_fill: true });
this.actor._delegate = this;
let label = this.app.get_name();
let box = new St.BoxLayout({ vertical: true });
this.actor.set_child(box);
IconGrid.BaseIcon.prototype._init.call(this,
label,
params);
},
this.icon = this.app.create_icon_texture(APPICON_SIZE);
box.add(this.icon, { expand: true, x_fill: false, y_fill: false });
this._name = new St.Label({ text: this.app.get_name() });
box.add_actor(this._name);
createIcon: function(iconSize) {
return this.app.create_icon_texture(iconSize);
}
};
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,
@ -473,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));
@ -578,11 +430,10 @@ AppWellIcon.prototype = {
}
}));
this._menuManager.addMenu(this._menu, true);
this._menuManager.addMenu(this._menu);
}
this._menu.popup();
this._menuManager.grab();
return false;
},
@ -604,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());
@ -659,13 +502,13 @@ AppWellIcon.prototype = {
},
getDragActor: function() {
return this.app.create_icon_texture(APPICON_SIZE);
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);
@ -678,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;
@ -834,242 +681,3 @@ AppIconMenu.prototype = {
}
};
Signals.addSignalMethods(AppIconMenu.prototype);
function WellGrid() {
this._init();
}
WellGrid.prototype = {
_init: function() {
this.actor = new St.BoxLayout({ name: 'dashAppWell', vertical: true });
// Pulled from CSS, but hardcode some defaults here
this._spacing = 0;
this._item_size = 48;
this._grid = new Shell.GenericContainer();
this.actor.add(this._grid, { expand: true, y_align: St.Align.START });
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
this._grid.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this._grid.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
this._grid.connect('allocate', Lang.bind(this, this._allocate));
},
_getPreferredWidth: function (grid, forHeight, alloc) {
let children = this._grid.get_children();
let nColumns = children.length;
let totalSpacing = Math.max(0, nColumns - 1) * this._spacing;
// Kind of a lie, but not really an issue right now. If
// we wanted to support some sort of hidden/overflow that would
// need higher level design
alloc.min_size = this._item_size;
alloc.natural_size = nColumns * this._item_size + totalSpacing;
},
_getPreferredHeight: function (grid, forWidth, alloc) {
let children = this._grid.get_children();
let [nColumns, usedWidth] = this._computeLayout(forWidth);
let nRows;
if (nColumns > 0)
nRows = Math.ceil(children.length / nColumns);
else
nRows = 0;
let totalSpacing = Math.max(0, nRows - 1) * this._spacing;
let height = nRows * this._item_size + totalSpacing;
alloc.min_size = height;
alloc.natural_size = height;
},
_allocate: function (grid, box, flags) {
let children = this._grid.get_children();
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
let [nColumns, usedWidth] = this._computeLayout(availWidth);
let overallPaddingX = Math.floor((availWidth - usedWidth) / 2);
let x = box.x1 + overallPaddingX;
let y = box.y1;
let columnIndex = 0;
for (let i = 0; i < children.length; i++) {
let [childMinWidth, childMinHeight, childNaturalWidth, childNaturalHeight]
= children[i].get_preferred_size();
/* Center the item in its allocation horizontally */
let width = Math.min(this._item_size, childNaturalWidth);
let childXSpacing = Math.max(0, width - childNaturalWidth) / 2;
let height = Math.min(this._item_size, childNaturalHeight);
let childYSpacing = Math.max(0, height - childNaturalHeight) / 2;
let childBox = new Clutter.ActorBox();
if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
let _x = box.x2 - (x + width);
childBox.x1 = Math.floor(_x - childXSpacing);
} else {
childBox.x1 = Math.floor(x + childXSpacing);
}
childBox.y1 = Math.floor(y + childYSpacing);
childBox.x2 = childBox.x1 + width;
childBox.y2 = childBox.y1 + height;
children[i].allocate(childBox, flags);
columnIndex++;
if (columnIndex == nColumns) {
columnIndex = 0;
}
if (columnIndex == 0) {
y += this._item_size + this._spacing;
x = box.x1 + overallPaddingX;
} else {
x += this._item_size + this._spacing;
}
}
},
_computeLayout: function (forWidth) {
let children = this._grid.get_children();
let nColumns = 0;
let usedWidth = 0;
while (nColumns < WELL_MAX_COLUMNS &&
(usedWidth + this._item_size <= forWidth)) {
usedWidth += this._item_size + this._spacing;
nColumns += 1;
}
if (nColumns > 0)
usedWidth -= this._spacing;
return [nColumns, usedWidth];
},
_onStyleChanged: function() {
let themeNode = this.actor.get_theme_node();
let [success, len] = themeNode.get_length('spacing', false);
if (success)
this._spacing = len;
[success, len] = themeNode.get_length('-shell-grid-item-size', false);
if (success)
this._item_size = len;
this._grid.queue_relayout();
},
removeAll: function () {
this._grid.get_children().forEach(Lang.bind(this, function (child) {
child.destroy();
}));
},
addItem: function(actor) {
this._grid.add_actor(actor);
}
};
function AppWell() {
this._init();
}
AppWell.prototype = {
_init : function() {
this._placeholderText = null;
this._menus = [];
this._menuDisplays = [];
this._favorites = [];
this._grid = new WellGrid();
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);
}
},
// 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,12 +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(this._favorites[appId].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

@ -1,14 +1,17 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Tweener = imports.ui.tweener;
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
@ -39,15 +42,88 @@ BoxPointer.prototype = {
this.bin.raise(this._border);
},
show: function(animate, onComplete) {
let x = this.actor.x;
let y = this.actor.y;
let themeNode = this.actor.get_theme_node();
let rise = themeNode.get_length('-arrow-rise');
this.actor.opacity = 0;
this.actor.show();
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,
x: x,
y: y,
transition: "linear",
onComplete: onComplete,
time: POPUP_ANIMATION_TIME });
},
hide: function(animate, onComplete) {
let x = this.actor.x;
let y = this.actor.y;
let originalX = this.actor.x;
let originalY = this.actor.y;
let themeNode = this.actor.get_theme_node();
let rise = themeNode.get_length('-arrow-rise');
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,
x: x,
y: y,
transition: "linear",
time: POPUP_ANIMATION_TIME,
onComplete: Lang.bind(this, function () {
this.actor.hide();
this.actor.x = originalX;
this.actor.y = originalY;
if (onComplete)
onComplete();
})
});
},
_adjustAllocationForArrow: function(isWidth, alloc) {
let themeNode = this.actor.get_theme_node();
let found, borderWidth, base, rise;
[found, borderWidth] = themeNode.get_length('-arrow-border-width', false);
let borderWidth = themeNode.get_length('-arrow-border-width');
alloc.min_size += borderWidth * 2;
alloc.natural_size += borderWidth * 2;
if ((!isWidth && (this._arrowSide == St.Side.TOP || this._arrowSide == St.Side.BOTTOM))
|| (isWidth && (this._arrowSide == St.Side.LEFT || this._arrowSide == St.Side.RIGHT))) {
let [found, rise] = themeNode.get_length('-arrow-rise', false);
let rise = themeNode.get_length('-arrow-rise');
alloc.min_size += rise;
alloc.natural_size += rise;
}
@ -69,9 +145,8 @@ BoxPointer.prototype = {
_allocate: function(actor, box, flags) {
let themeNode = this.actor.get_theme_node();
let found, borderWidth, borderRadius, rise, base;
[found, borderWidth] = themeNode.get_length('-arrow-border-width', false);
[found, rise] = themeNode.get_length('-arrow-rise', false);
let borderWidth = themeNode.get_length('-arrow-border-width');
let rise = themeNode.get_length('-arrow-rise');
let childBox = new Clutter.ActorBox();
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
@ -106,19 +181,18 @@ BoxPointer.prototype = {
_drawBorder: function(area) {
let themeNode = this.actor.get_theme_node();
let found, borderWidth, borderRadius, rise, base;
[found, borderWidth] = themeNode.get_length('-arrow-border-width', false);
[found, base] = themeNode.get_length('-arrow-base', false);
[found, rise] = themeNode.get_length('-arrow-rise', false);
[found, borderRadius] = themeNode.get_length('-arrow-border-radius', false);
let borderWidth = themeNode.get_length('-arrow-border-width');
let base = themeNode.get_length('-arrow-base');
let rise = themeNode.get_length('-arrow-rise');
let borderRadius = themeNode.get_length('-arrow-border-radius');
let halfBorder = borderWidth / 2;
let halfBase = Math.floor(base/2);
let borderColor = new Clutter.Color();
themeNode.get_color('-arrow-border-color', false, borderColor);
themeNode.get_color('-arrow-border-color', borderColor);
let backgroundColor = new Clutter.Color();
themeNode.get_color('-arrow-background-color', false, backgroundColor);
themeNode.get_color('-arrow-background-color', backgroundColor);
let [width, height] = area.get_surface_size();
let [boxWidth, boxHeight] = [width, height];
@ -187,6 +261,98 @@ BoxPointer.prototype = {
cr.stroke();
},
setPosition: function(sourceActor, gap, alignment) {
// 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] = sourceActor.get_transformed_position();
let [sourceWidth, sourceHeight] = sourceActor.get_transformed_size();
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 themeNode = this.actor.get_theme_node();
let arrowRise = themeNode.get_length('-arrow-rise');
let borderRadius = themeNode.get_length('-arrow-border-radius');
let resX, resY;
switch (this._arrowSide) {
case St.Side.TOP:
resY = sourceY + sourceHeight + gap;
break;
case St.Side.BOTTOM:
resY = sourceY - natHeight - gap;
break;
case St.Side.LEFT:
resX = sourceX + sourceWidth + gap;
break;
case St.Side.RIGHT:
resX = sourceX - natWidth - gap;
break;
}
// Now align and position the pointing axis, making sure
// it fits on screen
switch (this._arrowSide) {
case St.Side.TOP:
case St.Side.BOTTOM:
switch (alignment) {
case St.Align.START:
resX = sourceX - 2 * borderRadius;
break;
case St.Align.MIDDLE:
resX = sourceX - Math.floor((natWidth - sourceWidth) / 2);
break;
case St.Align.END:
resX = sourceX - (natWidth - sourceWidth) + 2 * borderRadius;
break;
}
resX = Math.min(resX, primary.x + primary.width - natWidth - arrowRise - gap);
resX = Math.max(resX, primary.x);
this.setArrowOrigin((sourceX - resX) + Math.floor(sourceWidth / 2));
break;
case St.Side.LEFT:
case St.Side.RIGHT:
switch (alignment) {
case St.Align.START:
resY = sourceY - 2 * borderRadius;
break;
case St.Align.MIDDLE:
resY = sourceY - Math.floor((natHeight - sourceHeight) / 2);
break;
case St.Align.END:
resY = sourceY - (natHeight - sourceHeight) + 2 * borderRadius;
break;
}
resY = Math.min(resY, primary.y + primary.height - natHeight - arrowRise - gap);
resY = Math.max(resY, primary.y);
this.setArrowOrigin((sourceY - resY) + Math.floor(sourceHeight / 2));
break;
}
let parent = this.actor.get_parent();
let success, x, y;
while (!success) {
[success, x, y] = parent.transform_stage_point(resX, resY);
parent = parent.get_parent();
}
// Actually set the position
this.actor.x = Math.floor(x);
this.actor.y = Math.floor(y);
},
// @origin: Coordinate specifying middle of the arrow, along
// the Y axis for St.Side.LEFT, St.Side.RIGHT from the top and X axis from
// the left for St.Side.TOP and St.Side.BOTTOM.

View File

@ -4,20 +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_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 Gettext_gtk20 = imports.gettext.domain('gtk20');
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
@ -44,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.
@ -61,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));
}
@ -72,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;
@ -86,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',
@ -101,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));
}
},
@ -117,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);
}
@ -179,33 +477,35 @@ 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);
_onPrevMonthButtonClicked: function() {
let newDate = new Date(this._selectedDate);
if (newDate.getMonth() == 0) {
newDate.setMonth(11);
newDate.setFullYear(newDate.getFullYear() - 1);
} else {
this.date.setMonth(this.date.getMonth() - 1);
newDate.setMonth(newDate.getMonth() - 1);
}
this._update();
this.setDate(newDate);
},
_nextMonth: function() {
if (this.date.getMonth() == 11) {
this.date.setMonth(0);
this.date.setFullYear(this.date.getFullYear() + 1);
_onNextMonthButtonClicked: function() {
let newDate = new Date(this._selectedDate);
if (newDate.getMonth() == 11) {
newDate.setMonth(0);
newDate.setFullYear(newDate.getFullYear() + 1);
} else {
this.date.setMonth(this.date.getMonth() + 1);
newDate.setMonth(newDate.getMonth() + 1);
}
this._update();
this.setDate(newDate);
},
_onSettingsChange: function() {
@ -215,7 +515,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();
@ -223,44 +528,201 @@ 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);
iter.setTime(iter.getTime() - (iter.getDay() - this._weekStart) * 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() == 0)
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));
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) {
/* if now is Sunday through Thursday show "This week" and include events up until
* and including Saturday
*/
let thisWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000);
let thisWeekEnd = new Date(dayEnd.getTime() + (6 - dayEnd.getDay()) * 86400 * 1000);
this._addPeriod(_("This week"), thisWeekBegin, thisWeekEnd, true, false);
} else {
/* otherwise it's a Friday or Saturday... show "Next week" and include events up
* until and including *next* Saturday
*/
let nextWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000);
let nextWeekEnd = new Date(dayEnd.getTime() + (13 - 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);
}
}
};

View File

@ -1,6 +1,5 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
@ -234,7 +233,7 @@ Chrome.prototype = {
},
_windowsRestacked: function() {
let windows = global.get_windows();
let windows = global.get_window_actors();
let primary = global.get_primary_monitor();
// The chrome layer should be visible unless there is a window

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

@ -4,6 +4,7 @@ const Clutter = imports.gi.Clutter;
const Gtk = imports.gi.Gtk;
const St = imports.gi.St;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Tweener = imports.ui.tweener;
const Main = imports.ui.main;
@ -24,6 +25,12 @@ const DragMotionResult = {
CONTINUE: 3
};
const DRAG_CURSOR_MAP = {
0: Shell.Cursor.DND_UNSUPPORTED_TARGET,
1: Shell.Cursor.DND_COPY,
2: Shell.Cursor.DND_MOVE
};
const DragDropResult = {
FAILURE: 0,
SUCCESS: 1,
@ -79,6 +86,9 @@ _Draggable.prototype = {
Lang.bind(this, this._onButtonPress));
this.actor.connect('destroy', Lang.bind(this, function() {
this._actorDestroyed = true;
if (this._dragInProgress)
this._cancelDrag(global.get_current_time());
this.disconnectAll();
}));
this._onEventId = null;
@ -90,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) {
@ -137,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) {
@ -203,6 +221,7 @@ _Draggable.prototype = {
if (this._onEventId)
this._ungrabActor();
this._grabEvents();
global.set_cursor(Shell.Cursor.DND_IN_DRAG);
this._dragX = this._dragStartX = stageX;
this._dragY = this._dragStartY = stageY;
@ -256,6 +275,7 @@ _Draggable.prototype = {
this._dragActor.reparent(this.actor.get_stage());
this._dragActor.raise_top();
Shell.util_set_hidden_from_pick(this._dragActor, true);
this._dragOrigOpacity = this._dragActor.opacity;
if (this._dragActorOpacity != undefined)
@ -321,12 +341,8 @@ _Draggable.prototype = {
this._dragActor.set_position(stageX + this._dragOffsetX,
stageY + this._dragOffsetY);
// Because we want to find out what other actor is located at the current position of this._dragActor,
// we have to temporarily hide this._dragActor.
this._dragActor.hide();
let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
stageX, stageY);
this._dragActor.show();
// We call observers only once per motion with the innermost
// target actor. If necessary, the observer can walk the
@ -335,49 +351,47 @@ _Draggable.prototype = {
x: stageX,
y: stageY,
dragActor: this._dragActor,
source: this.actor._delegate,
targetActor: target
};
for (let i = 0; i < dragMonitors.length; i++) {
let motionFunc = dragMonitors[i].dragMotion;
if (motionFunc)
switch (motionFunc(dragEvent)) {
case DragMotionResult.NO_DROP:
case DragMotionResult.COPY_DROP:
case DragMotionResult.MOVE_DROP:
// TODO: set a special cursor or something ;)
return true;
case DragMotionResult.CONTINUE:
continue;
if (motionFunc) {
let result = motionFunc(dragEvent);
if (result != DragMotionResult.CONTINUE) {
global.set_cursor(DRAG_CURSOR_MAP[result]);
return true;
}
}
}
while (target) {
if (target._delegate && target._delegate.handleDragOver) {
let [r, targX, targY] = target.transform_stage_point(stageX, stageY);
// We currently loop through all parents on drag-over even if one of the children has handled it.
// We can check the return value of the function and break the loop if it's true if we don't want
// to continue checking the parents.
target._delegate.handleDragOver(this.actor._delegate,
this._dragActor,
targX,
targY,
event.get_time());
let result = target._delegate.handleDragOver(this.actor._delegate,
this._dragActor,
targX,
targY,
event.get_time());
if (result != DragMotionResult.CONTINUE) {
global.set_cursor(DRAG_CURSOR_MAP[result]);
return true;
}
}
target = target.get_parent();
}
global.set_cursor(Shell.Cursor.DND_IN_DRAG);
}
return true;
},
_dragActorDropped: function(event) {
// Find a drop target. Because we want to find out what other actor is located at
// the current position of this._dragActor, we have to temporarily hide this._dragActor.
this._dragActor.hide();
let [dropX, dropY] = event.get_coords();
let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
dropX, dropY);
this._dragActor.show();
// We call observers only once per motion with the innermost
// target actor. If necessary, the observer can walk the
@ -407,6 +421,8 @@ _Draggable.prototype = {
targX,
targY,
event.get_time())) {
if (this._actorDestroyed)
return true;
// If it accepted the drop without taking the actor,
// handle it ourselves.
if (this._dragActor.get_parent() == this._dragActor.get_stage()) {
@ -418,6 +434,7 @@ _Draggable.prototype = {
}
this._dragInProgress = false;
global.unset_cursor();
this.emit('drag-end', event.get_time(), true);
this._dragComplete();
return true;
@ -431,29 +448,55 @@ _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;
}
this._animationInProgress = true;
// No target, so snap back
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',
@ -465,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;
@ -491,6 +534,7 @@ _Draggable.prototype = {
} else {
dragActor.destroy();
}
global.unset_cursor();
this.emit('drag-end', eventTime, false);
this._animationInProgress = false;
@ -499,6 +543,8 @@ _Draggable.prototype = {
},
_dragComplete: function() {
Shell.util_set_hidden_from_pick(this._dragActor, false);
this._dragActor = undefined;
currentDraggable = null;
this._ungrabEvents();

View File

@ -1,490 +1,11 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Pango = imports.gi.Pango;
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);
}
@ -82,17 +82,13 @@ function init() {
Clutter.Actor.prototype.toString = function() {
return St.describe_actor(this);
};
Clutter.Actor.prototype.contains = function(child) {
while (child != null && child != this)
child = child.get_parent();
return child != null;
};
if (window.global === undefined) // test environment
return;
_blockMethod('Clutter.Event.get_state', 'Shell.get_event_state',
'gjs\'s handling of Clutter.ModifierType is broken. See bug 597292.');
_blockMethod('Gdk.Display.get_pointer', 'global.get_pointer',
'gjs\'s handling of Gdk.ModifierType is broken. See bug 597292.');
_blockMethod('Gdk.Window.get_pointer', 'global.get_pointer',
_blockMethod('Gdk.Window.get_device_position', 'global.get_pointer',
'gjs\'s handling of Gdk.ModifierType is broken. See bug 597292.');
// Now close the back door to prevent extensions from trying to

View File

@ -3,7 +3,8 @@
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Config = imports.misc.config;
const ExtensionState = {
ENABLED: 1,
@ -26,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() + '": ';
@ -44,14 +75,20 @@ 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');
return;
}
}
if (extensions[meta.uuid] != undefined) {
global.logError(baseErrorString + "extension already loaded");
return;
}
// Encourage people to add this
if (!meta['url']) {
global.log(baseErrorString + 'Warning: Missing "url" property in metadata.json');
@ -63,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,700 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Gdk = imports.gi.Gdk;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Pango = imports.gi.Pango;
const Signals = imports.signals;
const Shell = imports.gi.Shell;
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);

298
js/ui/iconGrid.js Normal file
View File

@ -0,0 +1,298 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Lang = imports.lang;
const Params = imports.misc.params;
const ICON_SIZE = 48;
function BaseIcon(label, createIcon) {
this._init(label, createIcon);
}
BaseIcon.prototype = {
_init : function(label, params) {
params = Params.parse(params, { createIcon: null,
setSizeManually: false });
this.actor = new St.Bin({ style_class: 'overview-icon',
x_fill: true,
y_fill: true });
this.actor._delegate = this;
this.actor.connect('style-changed',
Lang.bind(this, this._onStyleChanged));
this._spacing = 0;
let box = new Shell.GenericContainer();
box.connect('allocate', Lang.bind(this, this._allocate));
box.connect('get-preferred-width',
Lang.bind(this, this._getPreferredWidth));
box.connect('get-preferred-height',
Lang.bind(this, this._getPreferredHeight));
this.actor.set_child(box);
this.iconSize = ICON_SIZE;
this._iconBin = new St.Bin();
box.add_actor(this._iconBin);
this._name = new St.Label({ text: label });
box.add_actor(this._name);
if (params.createIcon)
this.createIcon = params.createIcon;
this._setSizeManually = params.setSizeManually;
this.icon = this.createIcon(this.iconSize);
this._iconBin.set_child(this.icon);
},
_allocate: function(actor, box, flags) {
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
let [labelMinHeight, labelNatHeight] = this._name.get_preferred_height(-1);
let [iconMinHeight, iconNatHeight] = this._iconBin.get_preferred_height(-1);
let preferredHeight = labelNatHeight + this._spacing + iconNatHeight;
let labelHeight = availHeight >= preferredHeight ? labelNatHeight
: labelMinHeight;
let iconSize = availHeight - this._spacing - labelHeight;
let iconPadding = (availWidth - iconSize) / 2;
let childBox = new Clutter.ActorBox();
childBox.x1 = iconPadding;
childBox.y1 = 0;
childBox.x2 = availWidth - iconPadding;
childBox.y2 = iconSize;
this._iconBin.allocate(childBox, flags);
childBox.x1 = 0;
childBox.x2 = availWidth;
childBox.y1 = iconSize + this._spacing;
childBox.y2 = childBox.y1 + labelHeight;
this._name.allocate(childBox, flags);
},
_getPreferredWidth: function(actor, forHeight, alloc) {
this._getPreferredHeight(actor, -1, alloc);
},
_getPreferredHeight: function(actor, forWidth, alloc) {
let [iconMinHeight, iconNatHeight] = this._iconBin.get_preferred_height(forWidth);
let [labelMinHeight, labelNatHeight] = this._name.get_preferred_height(forWidth);
alloc.min_size = iconMinHeight + this._spacing + labelMinHeight;
alloc.natural_size = iconNatHeight + this._spacing + labelNatHeight;
},
// This can be overridden by a subclass, or by the createIcon
// parameter to _init()
createIcon: function(size) {
throw new Error('no implementation of createIcon in ' + this);
},
setIconSize: function(size) {
if (!this._setSizeManually)
throw new Error('setSizeManually has to be set to use setIconsize');
this._setIconSize(size);
},
_setIconSize: function(size) {
if (size == this.iconSize)
return;
this.icon.destroy();
this.iconSize = size;
this.icon = this.createIcon(this.iconSize);
this._iconBin.child = this.icon;
},
_onStyleChanged: function() {
let node = this.actor.get_theme_node();
this._spacing = node.get_length('spacing');
if (this._setSizeManually)
return;
let len = node.get_length('icon-size');
if (len > 0)
this._setIconSize(len);
}
};
function IconGrid(params) {
this._init(params);
}
IconGrid.prototype = {
_init: function(params) {
params = Params.parse(params, { rowLimit: null,
columnLimit: null,
xAlign: St.Align.MIDDLE });
this._rowLimit = params.rowLimit;
this._colLimit = params.columnLimit;
this._xAlign = params.xAlign;
this.actor = new St.BoxLayout({ style_class: 'icon-grid',
vertical: true });
// Pulled from CSS, but hardcode some defaults here
this._spacing = 0;
this._item_size = ICON_SIZE;
this._grid = new Shell.GenericContainer();
this.actor.add(this._grid, { expand: true, y_align: St.Align.START });
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
this._grid.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this._grid.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
this._grid.connect('allocate', Lang.bind(this, this._allocate));
},
_getPreferredWidth: function (grid, forHeight, alloc) {
let children = this._grid.get_children();
let nColumns = this._colLimit ? Math.min(this._colLimit,
children.length)
: children.length;
let totalSpacing = Math.max(0, nColumns - 1) * this._spacing;
// Kind of a lie, but not really an issue right now. If
// we wanted to support some sort of hidden/overflow that would
// need higher level design
alloc.min_size = this._item_size;
alloc.natural_size = nColumns * this._item_size + totalSpacing;
},
_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)
nRows = Math.ceil(children.length / nColumns);
else
nRows = 0;
if (this._rowLimit)
nRows = Math.min(nRows, this._rowLimit);
let totalSpacing = Math.max(0, nRows - 1) * this._spacing;
let height = nRows * this._item_size + totalSpacing;
alloc.min_size = height;
alloc.natural_size = height;
},
_allocate: function (grid, box, flags) {
let children = this._getVisibleChildren();
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
let [nColumns, usedWidth] = this._computeLayout(availWidth);
let leftPadding;
switch(this._xAlign) {
case St.Align.START:
leftPadding = 0;
break;
case St.Align.MIDDLE:
leftPadding = Math.floor((availWidth - usedWidth) / 2);
break;
case St.Align.END:
leftPadding = availWidth - usedWidth;
}
let x = box.x1 + leftPadding;
let y = box.y1;
let columnIndex = 0;
let rowIndex = 0;
for (let i = 0; i < children.length; i++) {
let [childMinWidth, childMinHeight, childNaturalWidth, childNaturalHeight]
= children[i].get_preferred_size();
/* Center the item in its allocation horizontally */
let width = Math.min(this._item_size, childNaturalWidth);
let childXSpacing = Math.max(0, width - childNaturalWidth) / 2;
let height = Math.min(this._item_size, childNaturalHeight);
let childYSpacing = Math.max(0, height - childNaturalHeight) / 2;
let childBox = new Clutter.ActorBox();
if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
let _x = box.x2 - (x + width);
childBox.x1 = Math.floor(_x - childXSpacing);
} else {
childBox.x1 = Math.floor(x + childXSpacing);
}
childBox.y1 = Math.floor(y + childYSpacing);
childBox.x2 = childBox.x1 + width;
childBox.y2 = childBox.y1 + height;
if (this._rowLimit && rowIndex >= this._rowLimit) {
this._grid.set_skip_paint(children[i], true);
} else {
children[i].allocate(childBox, flags);
this._grid.set_skip_paint(children[i], false);
}
columnIndex++;
if (columnIndex == nColumns) {
columnIndex = 0;
rowIndex++;
}
if (columnIndex == 0) {
y += this._item_size + this._spacing;
x = box.x1 + leftPadding;
} else {
x += this._item_size + this._spacing;
}
}
},
_computeLayout: function (forWidth) {
let children = this._grid.get_children();
let nColumns = 0;
let usedWidth = 0;
while ((this._colLimit == null || nColumns < this._colLimit) &&
(usedWidth + this._item_size <= forWidth)) {
usedWidth += this._item_size + this._spacing;
nColumns += 1;
}
if (nColumns > 0)
usedWidth -= this._spacing;
return [nColumns, usedWidth];
},
_onStyleChanged: function() {
let themeNode = this.actor.get_theme_node();
this._spacing = themeNode.get_length('spacing');
this._item_size = themeNode.get_length('-shell-grid-item-size');
this._grid.queue_relayout();
},
removeAll: function () {
this._grid.get_children().forEach(Lang.bind(this, function (child) {
child.destroy();
}));
},
addItem: function(actor) {
this._grid.add_actor(actor);
},
getItemAtIndex: function(index) {
return this._grid.get_children()[index];
},
visibleItemsCount: function() {
return this._grid.get_children().length - this._grid.get_n_skip_paint();
}
};

View File

@ -1,6 +1,5 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const St = imports.gi.St;

View File

@ -1,6 +1,5 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Signals = imports.signals;
const St = imports.gi.St;

View File

@ -220,7 +220,7 @@ WindowList.prototype = {
_updateWindowList: function() {
this.actor.get_children().forEach(function (actor) { actor.destroy(); });
let windows = global.get_windows();
let windows = global.get_window_actors();
let tracker = Shell.WindowTracker.get_default();
for (let i = 0; i < windows.length; i++) {
let metaWindow = windows[i].metaWindow;
@ -365,54 +365,139 @@ function Inspector() {
Inspector.prototype = {
_init: function() {
let width = 150;
let primary = global.get_primary_monitor();
let container = new Shell.GenericContainer({ width: 0,
height: 0 });
container.connect('allocate', Lang.bind(this, this._allocate));
Main.uiGroup.add_actor(container);
let eventHandler = new St.BoxLayout({ name: 'LookingGlassDialog',
vertical: false,
y: primary.y + Math.floor(primary.height / 2),
reactive: true });
eventHandler.connect('notify::allocation', Lang.bind(this, function () {
eventHandler.x = primary.x + Math.floor((primary.width - eventHandler.width) / 2);
}));
Main.uiGroup.add_actor(eventHandler);
let displayText = new St.Label();
eventHandler.add(displayText, { expand: true });
this._eventHandler = eventHandler;
container.add_actor(eventHandler);
this._displayText = new St.Label();
eventHandler.add(this._displayText, { expand: true });
let borderPaintTarget = null;
let borderPaintId = null;
eventHandler.connect('destroy', Lang.bind(this, function() {
if (borderPaintTarget != null)
borderPaintTarget.disconnect(borderPaintId);
}));
eventHandler.connect('button-press-event', Lang.bind(this, function (actor, event) {
Clutter.ungrab_pointer(eventHandler);
let [stageX, stageY] = event.get_coords();
let target = global.stage.get_actor_at_pos(Clutter.PickMode.ALL,
stageX,
stageY);
this.emit('target', target, stageX, stageY);
eventHandler.destroy();
this.emit('closed');
return true;
}));
eventHandler.connect('motion-event', Lang.bind(this, function (actor, event) {
let [stageX, stageY] = event.get_coords();
let target = global.stage.get_actor_at_pos(Clutter.PickMode.ALL,
stageX,
stageY);
let position = '[inspect x: ' + stageX + ' y: ' + stageY + ']';
displayText.text = '';
displayText.text = position + ' ' + target;
if (borderPaintTarget != null)
borderPaintTarget.disconnect(borderPaintId);
borderPaintTarget = target;
borderPaintId = Shell.add_hook_paint_red_border(target);
return true;
}));
this._borderPaintTarget = null;
this._borderPaintId = null;
eventHandler.connect('destroy', Lang.bind(this, this._onDestroy));
eventHandler.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
eventHandler.connect('button-press-event', Lang.bind(this, this._onButtonPressEvent));
eventHandler.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
eventHandler.connect('motion-event', Lang.bind(this, this._onMotionEvent));
Clutter.grab_pointer(eventHandler);
Clutter.grab_keyboard(eventHandler);
// this._target is the actor currently shown by the inspector.
// this._pointerTarget is the actor directly under the pointer.
// Normally these are the same, but if you use the scroll wheel
// to drill down, they'll diverge until you either scroll back
// out, or move the pointer outside of _pointerTarget.
this._target = null;
this._pointerTarget = null;
},
_allocate: function(actor, box, flags) {
if (!this._eventHandler)
return;
let primary = global.get_primary_monitor();
let [minWidth, minHeight, natWidth, natHeight] =
this._eventHandler.get_preferred_size();
let childBox = new Clutter.ActorBox();
childBox.x1 = primary.x + Math.floor((primary.width - natWidth) / 2);
childBox.x2 = childBox.x1 + natWidth;
childBox.y1 = primary.y + Math.floor((primary.height - natHeight) / 2);
childBox.y2 = childBox.y1 + natHeight;
this._eventHandler.allocate(childBox, flags);
},
_close: function() {
Clutter.ungrab_pointer(this._eventHandler);
Clutter.ungrab_keyboard(this._eventHandler);
this._eventHandler.destroy();
this._eventHandler = null;
this.emit('closed');
},
_onDestroy: function() {
if (this._borderPaintTarget != null)
this._borderPaintTarget.disconnect(this._borderPaintId);
},
_onKeyPressEvent: function (actor, event) {
if (event.get_key_symbol() == Clutter.Escape)
this._close();
return true;
},
_onButtonPressEvent: function (actor, event) {
if (this._target) {
let [stageX, stageY] = event.get_coords();
this.emit('target', this._target, stageX, stageY);
}
this._close();
return true;
},
_onScrollEvent: function (actor, event) {
switch (event.get_scroll_direction()) {
case Clutter.ScrollDirection.UP:
// select parent
let parent = this._target.get_parent();
if (parent != null) {
this._target = parent;
this._update(event);
}
break;
case Clutter.ScrollDirection.DOWN:
// select child
if (this._target != this._pointerTarget) {
let child = this._pointerTarget;
while (child) {
let parent = child.get_parent();
if (parent == this._target)
break;
child = parent;
}
if (child) {
this._target = child;
this._update(event);
}
}
break;
default:
break;
}
return true;
},
_onMotionEvent: function (actor, event) {
this._update(event);
return true;
},
_update: function(event) {
let [stageX, stageY] = event.get_coords();
let target = global.stage.get_actor_at_pos(Clutter.PickMode.ALL,
stageX,
stageY);
if (target != this._pointerTarget)
this._target = target;
this._pointerTarget = target;
let position = '[inspect x: ' + stageX + ' y: ' + stageY + ']';
this._displayText.text = '';
this._displayText.text = position + ' ' + this._target;
if (this._borderPaintTarget != null)
this._borderPaintTarget.disconnect(this._borderPaintId);
this._borderPaintTarget = this._target;
this._borderPaintId = Shell.add_hook_paint_red_border(this._target);
}
};
@ -582,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);
@ -597,8 +682,8 @@ LookingGlass.prototype = {
let toolbar = new St.BoxLayout({ name: 'Toolbar' });
this.actor.add_actor(toolbar);
let inspectIcon = St.TextureCache.get_default().load_gicon(new Gio.ThemedIcon({ name: 'gtk-color-picker' }),
24);
let inspectIcon = new St.Icon({ icon_name: 'gtk-color-picker',
icon_size: 24 });
toolbar.add_actor(inspectIcon);
inspectIcon.reactive = true;
inspectIcon.connect('button-press-event', Lang.bind(this, function () {
@ -697,11 +782,10 @@ 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);
let fontDesc = Pango.font_description_from_string(fontName);
// We ignore everything but size and style; you'd be crazy to set your system-wide
// monospace font to be bold/oblique/etc. Could easily be added here.
this.actor.style =
@ -844,21 +928,18 @@ 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);
Tweener.addTween(this.actor, { time: 0.5,
// 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(),
transition: 'easeOutQuad',
y: this._targetY
});
@ -868,9 +949,6 @@ LookingGlass.prototype = {
if (!this._open)
return;
if (this._keyPressEventId)
global.stage.disconnect(this._keyPressEventId);
this._objInspector.actor.hide();
this._historyNavIndex = -1;
@ -883,9 +961,9 @@ LookingGlass.prototype = {
this._borderPaintTarget = null;
}
Main.popModal(this.actor);
Main.popModal(this._entry);
Tweener.addTween(this.actor, { time: 0.5,
Tweener.addTween(this.actor, { time: 0.5 / St.get_slow_down_factor(),
transition: 'easeOutQuad',
y: this._hiddenY,
onComplete: Lang.bind(this, function () {

File diff suppressed because it is too large Load Diff

View File

@ -109,14 +109,19 @@ ShellMagnifier.prototype = {
* ZoomRegion.
* @roi Array of integers defining the region of the
* screen/desktop to magnify. The array has the form
* [x, y, width, height].
* @viewPort Array of integers, [ x, y, width, height ] that defines
* [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) {
let ROI = { x: roi[0], y: roi[1], width: roi[2], height: roi[3] };
let viewBox = { x: viewPort[0], y: viewPort[1], width: viewPort[2], height: viewPort[3] };
let ROI = { x: roi[0], y: roi[1], width: roi[2] - roi[0], height: roi[3] - roi[1] };
let viewBox = { x: viewPort[0], y: viewPort[1], width: viewPort[2] - viewPort[0], height: viewPort[3] - viewPort[1] };
let realZoomRegion = Main.magnifier.createZoomRegion(xMagFactor, yMagFactor, ROI, viewBox);
let objectPath = ZOOM_SERVICE_PATH + '/zoomer' + _zoomRegionInstanceCount;
_zoomRegionInstanceCount++;
@ -325,12 +330,12 @@ ShellMagnifierZoomRegion.prototype = {
/**
* setRoi:
* Sets the "region of interest" that the ZoomRegion is magnifying.
* @roi Array, [x, y, width, height], defining the region of the screen to
* magnify. The values are in screen (unmagnified) coordinate
* space.
* @roi Array, [left, top, right, bottom], defining the region of the
* screen to magnify. The values are in screen (unmagnified)
* coordinate space.
*/
setRoi: function(roi) {
let roiObject = { x: roi[0], y: roi[1], width: roi[2], height: roi[3] };
let roiObject = { x: roi[0], y: roi[1], width: roi[2] - roi[0], height: roi[3] - roi[1] };
this._zoomRegion.setROI(roiObject);
},
@ -339,11 +344,14 @@ ShellMagnifierZoomRegion.prototype = {
* Retrieves the "region of interest" -- the rectangular bounds of that part
* of the desktop that the magnified view is showing (x, y, width, height).
* The bounds are given in non-magnified coordinates.
* @return an array, [x, y, width, height], representing the bounding
* @return an array, [left, top, right, bottom], representing the bounding
* rectangle of what is shown in the magnified view.
*/
getRoi: function() {
return this._zoomRegion.getROI();
let roi = this._zoomRegion.getROI();
roi[2] += roi[0];
roi[3] += roi[1];
return roi;
},
/**
@ -362,11 +370,11 @@ ShellMagnifierZoomRegion.prototype = {
/**
* moveResize
* Sets the position and size of the ZoomRegion on screen.
* @viewPort Array, [x, y, width, height], defining the position and size
* on screen to place the zoom region.
* @viewPort Array, [left, top, right, bottom], defining the position and
* size on screen to place the zoom region.
*/
moveResize: function(viewPort) {
let viewRect = { x: viewPort[0], y: viewPort[1], width: viewPort[2], height: viewPort[3] };
let viewRect = { x: viewPort[0], y: viewPort[1], width: viewPort[2] - viewPort[0], height: viewPort[3] - viewPort[1] };
this._zoomRegion.setViewPort(viewRect);
}
};

View File

@ -2,9 +2,9 @@
imports.gi.versions.Clutter = '1.0';
imports.gi.versions.Gio = '2.0';
imports.gi.versions.Gdk = '2.0';
imports.gi.versions.Gdk = '3.0';
imports.gi.versions.GdkPixbuf = '2.0';
imports.gi.versions.Gtk = '2.0';
imports.gi.versions.Gtk = '3.0';
const Clutter = imports.gi.Clutter;
const DBus = imports.dbus;
@ -16,10 +16,13 @@ const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
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;
@ -35,6 +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,12 +56,15 @@ 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;
@ -96,15 +105,13 @@ function start() {
Shell.WindowTracker.get_default();
Shell.AppUsage.get_default();
// The background color really only matters if there is no desktop
// window (say, nautilus) running. We set it mostly so things look good
// when we are running inside Xephyr.
// The stage is always covered so Clutter doesn't need to clear it; however
// the color is used as the default contents for the Mutter root background
// actor so set it anyways.
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);
loadTheme();
let shellwm = global.window_manager;
shellwm.takeover_keybinding('panel_main_menu');
@ -123,14 +130,21 @@ 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();
statusIconDispatcher = new StatusIconDispatcher.StatusIconDispatcher();
panel = new Panel.Panel();
wm = new WindowManager.WindowManager();
messageTray = new MessageTray.MessageTray();
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();
@ -158,9 +172,9 @@ function start() {
}
});
background = global.create_root_pixmap_actor();
global.stage.add_actor(background);
background.lower_bottom();
// Provide the bus object for gnome-session to
// initiate logouts.
EndSessionDialog.init();
global.gdk_screen.connect('monitors-changed', _relayout);
@ -174,9 +188,6 @@ function start() {
global.stage.connect('captured-event', _globalKeyPressHandler);
// Install magnifier.
magnifier = new Magnifier.Magnifier();
// Perform initial relayout here
_relayout();
@ -193,6 +204,18 @@ function start() {
}
}
/**
* loadTheme:
*
* Reloads the theme CSS file from the default theme.
*/
function loadTheme() {
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);
}
/**
* _log:
* @category: string message type ('info', 'error')
@ -240,24 +263,20 @@ function _relayout() {
panel.actor.set_size(primary.width, Panel.PANEL_HEIGHT);
overview.relayout();
background.set_size(global.screen_width, global.screen_height);
// 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,
// which probably means we'll be starting out with multiple workspaces;
// remove any unused ones. (We do this from an idle handler, because
// global.get_windows() still returns NULL at the point when start()
// global.get_window_actors() still returns NULL at the point when start()
// is called.)
function _removeUnusedWorkspaces() {
let windows = global.get_windows();
let windows = global.get_window_actors();
let maxWorkspace = 0;
for (let i = 0; i < windows.length; i++) {
let win = windows[i];
@ -283,64 +302,58 @@ 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_PRESS)
return false;
let type = event.type();
let symbol = event.get_key_symbol();
let keyCode = event.get_key_code();
let modifierState = Shell.get_event_state(event);
if (type == Clutter.EventType.KEY_PRESS) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.Print) {
// We want to be able to take screenshots of the shell at all times
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();
}
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;
}
// 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;
}
switch (action) {
case Meta.KeyBindingAction.WORKSPACE_LEFT:
wm.actionMoveWorkspaceLeft();
return true;
}
} else if (type == Clutter.EventType.KEY_RELEASE) {
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();
case Meta.KeyBindingAction.WORKSPACE_RIGHT:
wm.actionMoveWorkspaceRight();
return true;
case Meta.KeyBindingAction.PANEL_RUN_DIALOG:
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;
}
// Whitelist some of the Metacity actions
let display = global.screen.get_display();
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
// This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType
let action = display.get_keybinding_action(symbol, keyCode, modifierState);
switch (action) {
case Meta.KeyBindingAction.WORKSPACE_LEFT:
wm.actionMoveWorkspaceLeft();
return true;
case Meta.KeyBindingAction.WORKSPACE_RIGHT:
wm.actionMoveWorkspaceRight();
return true;
case Meta.KeyBindingAction.PANEL_RUN_DIALOG:
case Meta.KeyBindingAction.COMMAND_2:
getRunDialog().open();
return true;
}
}
return false;
@ -359,21 +372,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;
}
@ -397,18 +419,28 @@ function pushModal(actor) {
}
modalActorFocusStack.push([actor, curFocus]);
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) {
@ -426,7 +458,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);
}

File diff suppressed because it is too large Load Diff

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

@ -6,10 +6,14 @@ const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Mainloop = imports.mainloop;
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;
@ -73,22 +77,14 @@ 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>' }
]
};
// The notification spec stipulates using formal names for the appName the applications
// pass in. However, not all applications do that. Here is a list of the offenders we
// encountered so far.
const appNameMap = {
'evolution-mail-notification': 'Evolution Mail',
'rhythmbox': 'Rhythmbox'
};
function NotificationDaemon() {
this._init();
}
@ -107,7 +103,13 @@ NotificationDaemon.prototype = {
Lang.bind(this, this._acquiredName),
Lang.bind(this, this._lostName));
this._currentNotifications = {};
this._sources = {};
this._senderToPid = {};
this._notifications = {};
this._busProxy = new Bus();
Main.statusIconDispatcher.connect('message-icon-added', Lang.bind(this, this._onTrayIconAdded));
Main.statusIconDispatcher.connect('message-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
Shell.WindowTracker.get_default().connect('notify::focus-app',
Lang.bind(this, this._onFocusAppChanged));
@ -126,32 +128,97 @@ 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');
}
},
_sourceId: function(id) {
return 'source-' + id;
_iconForNotificationData: function(icon, hints, size) {
let textureCache = St.TextureCache.get_default();
if (icon) {
if (icon.substr(0, 7) == 'file://')
return textureCache.load_uri_async(icon, size, size);
else if (icon[0] == '/') {
let uri = GLib.filename_to_uri(icon, null);
return textureCache.load_uri_async(uri, size, size);
} else
return new St.Icon({ icon_name: icon,
icon_type: St.IconType.FULLCOLOR,
icon_size: size });
} else if (hints['image-data']) {
let [width, height, rowStride, hasAlpha,
bitsPerSample, nChannels, data] = hints['image-data'];
return textureCache.load_from_raw(data, data.length, hasAlpha,
width, height, rowStride, size);
} else {
let stockIcon;
switch (hints.urgency) {
case Urgency.LOW:
case Urgency.NORMAL:
stockIcon = 'gtk-dialog-info';
break;
case Urgency.CRITICAL:
stockIcon = 'gtk-dialog-error';
break;
}
return new St.Icon({ icon_name: stockIcon,
icon_type: St.IconType.FULLCOLOR,
icon_size: size });
}
},
// 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;
// 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;
},
Notify: function(appName, replacesId, icon, summary, body,
actions, hints, timeout) {
let source = Main.messageTray.getSource(this._sourceId(appName));
let id = null;
let id;
// Filter out notifications from Empathy, since we
// handle that information from telepathyClient.js
if (appName == 'Empathy') {
// Ignore replacesId since we already sent back a
// NotificationClosed for that id.
id = nextNotificationId++;
Mainloop.idle_add(Lang.bind(this,
function () {
@ -160,34 +227,6 @@ NotificationDaemon.prototype = {
return id;
}
hints = Params.parse(hints, { urgency: Urgency.NORMAL }, true);
// Source may be null if we have never received a notification
// from this app or if all notifications from this app have
// been acknowledged.
if (source == null) {
let title = appNameMap[appName] || appName;
source = new Source(this._sourceId(appName), title, icon, hints);
Main.messageTray.add(source);
source.connect('clicked', Lang.bind(this,
function() {
source.destroy();
}));
let sender = DBus.getCurrentMessageContext().sender;
let busProxy = new Bus();
busProxy.GetConnectionUnixProcessIDRemote(sender, function (result, excp) {
let app = Shell.WindowTracker.get_default().get_app_from_pid(result);
if (app)
source.setApp(app);
});
} else {
source.update(icon, hints);
}
summary = GLib.markup_escape_text(summary, -1);
let rewrites = rewriteRules[appName];
if (rewrites) {
for (let i = 0; i < rewrites.length; i++) {
@ -197,81 +236,193 @@ NotificationDaemon.prototype = {
}
}
let notification;
if (replacesId != 0) {
id = replacesId;
notification = this._currentNotifications[id];
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
}
if (notification == null) {
id = nextNotificationId++;
notification = new MessageTray.Notification(id, source, summary, body, true);
this._currentNotifications[id] = notification;
notification.connect('dismissed', Lang.bind(this,
function(n) {
n.destroy();
this._emitNotificationClosed(n.id, NotificationClosedReason.DISMISSED);
}));
let ndata = { appName: appName,
icon: icon,
summary: summary,
body: body,
actions: actions,
hints: hints,
timeout: timeout };
if (replacesId != 0 && this._notifications[replacesId]) {
ndata.id = id = replacesId;
ndata.notification = this._notifications[replacesId].notification;
} else {
// passing in true as the last parameter will clear out extra actors,
// such as actions
notification.update(summary, body, true);
replacesId = 0;
ndata.id = id = nextNotificationId++;
}
this._notifications[id] = ndata;
let sender = DBus.getCurrentMessageContext().sender;
let pid = this._senderToPid[sender];
let source = this._getSource(appName, pid, ndata);
if (source) {
this._notifyForSource(source, ndata);
return id;
}
if (actions.length) {
for (let i = 0; i < actions.length - 1; i += 2)
notification.addButton(actions[i], actions[i + 1]);
notification.connect('action-invoked', Lang.bind(this, this._actionInvoked, source, id));
if (replacesId) {
// There's already a pending call to GetConnectionUnixProcessID,
// which will see the new notification data when it finishes,
// so we don't have to do anything.
return id;
}
notification.setUrgent(hints.urgency == Urgency.CRITICAL);
this._busProxy.GetConnectionUnixProcessIDRemote(sender, Lang.bind(this,
function (pid, ex) {
// The app may have updated or removed the notification
ndata = this._notifications[id];
if (!ndata)
return;
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);
}));
source.notify(notification);
return id;
},
_notifyForSource: function(source, ndata) {
let [id, icon, summary, body, actions, hints, notification] =
[ndata.id, ndata.icon, ndata.summary, ndata.body,
ndata.actions, ndata.hints, ndata.notification];
let iconActor = this._iconForNotificationData(icon, hints, source.ICON_SIZE);
if (notification == null) {
notification = new MessageTray.Notification(source, summary, body,
{ icon: iconActor,
bannerMarkup: true });
ndata.notification = notification;
notification.connect('destroy', Lang.bind(this,
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);
}));
} else {
notification.update(summary, body, { icon: iconActor,
bannerMarkup: true,
clear: true });
}
if (actions.length) {
notification.setUseActionIcons(hints['action-icons'] == true);
for (let i = 0; i < actions.length - 1; i += 2)
notification.addButton(actions[i], actions[i + 1]);
}
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);
},
CloseNotification: function(id) {
let notification = this._currentNotifications[id];
if (notification)
notification.destroy();
this._emitNotificationClosed(id, NotificationClosedReason.APP_CLOSED);
let ndata = this._notifications[id];
if (ndata) {
if (ndata.notification)
ndata.notification.destroy(MessageTray.NotificationDestroyedReason.SOURCE_CLOSED);
delete this._notifications[id];
}
},
GetCapabilities: function() {
return [
'actions',
'action-icons',
'body',
// 'body-hyperlinks',
// 'body-images',
'body-markup',
// 'icon-multi',
'icon-static'
'icon-static',
'persistence',
// 'sound',
];
},
GetServerInformation: function() {
return [
'GNOME Shell',
Config.PACKAGE_NAME,
'GNOME',
'0.1', // FIXME, get this from somewhere
'1.0'
Config.PACKAGE_VERSION,
'1.2'
];
},
_onFocusAppChanged: function() {
let tracker = Shell.WindowTracker.get_default();
if (tracker.focus_app)
Main.messageTray.removeSourceByApp(tracker.focus_app);
},
if (!tracker.focus_app)
return;
_actionInvoked: function(notification, action, source, id) {
this._emitActionInvoked(id, action);
source.destroy();
for (let id in this._sources) {
let source = this._sources[id];
if (source.app == tracker.focus_app) {
if (source.notification && !source.notification.resident)
source.notification.destroy();
return;
}
}
},
_emitNotificationClosed: function(id, reason) {
delete this._currentNotifications[id];
DBus.session.emit_signal('/org/freedesktop/Notifications',
'org.freedesktop.Notifications',
'NotificationClosed', 'uu',
@ -283,85 +434,88 @@ NotificationDaemon.prototype = {
'org.freedesktop.Notifications',
'ActionInvoked', 'us',
[id, action]);
},
_onTrayIconAdded: function(o, icon) {
let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null);
source.setTrayIcon(icon);
},
_onTrayIconRemoved: function(o, icon) {
let source = this._sources[icon.pid];
if (source)
source.destroy();
}
};
DBus.conformExport(NotificationDaemon.prototype, NotificationDaemonIface);
function Source(sourceId, title, icon, hints) {
this._init(sourceId, title, icon, hints);
function Source(title, pid) {
this._init(title, pid);
}
Source.prototype = {
__proto__: MessageTray.Source.prototype,
_init: function(sourceId, title, icon, hints) {
MessageTray.Source.prototype._init.call(this, sourceId, title);
_init: function(title, pid) {
MessageTray.Source.prototype._init.call(this, title);
this.app = null;
this._openAppRequested = false;
this.update(icon, hints);
this._pid = pid;
this._setApp();
if (this.app)
this.title = this.app.get_name();
else
this.useNotificationIcon = true;
this._isTrayIcon = false;
},
update: function(icon, hints) {
this._icon = icon;
this._iconData = hints.icon_data;
this._urgency = hints.urgency;
notify: function(notification, icon) {
if (!this.app)
this._setApp();
if (!this.app && icon)
this._setSummaryIcon(icon);
MessageTray.Source.prototype.notify.call(this, notification);
},
createIcon: function(size) {
let textureCache = St.TextureCache.get_default();
_setApp: function() {
if (this.app)
return;
if (this._icon) {
if (this._icon.substr(0, 7) == 'file://')
return textureCache.load_uri_async(this._icon, size, size);
else if (this._icon[0] == '/') {
let uri = GLib.filename_to_uri(this._icon, null);
return textureCache.load_uri_async(uri, size, size);
} else
return textureCache.load_icon_name(this._icon, size);
} else if (this._iconData) {
let [width, height, rowStride, hasAlpha,
bitsPerSample, nChannels, data] = this._iconData;
return textureCache.load_from_raw(data, data.length, hasAlpha,
width, height, rowStride, size);
} else {
let stockIcon;
switch (this._urgency) {
case Urgency.LOW:
case Urgency.NORMAL:
stockIcon = 'gtk-dialog-info';
break;
case Urgency.CRITICAL:
stockIcon = 'gtk-dialog-error';
break;
}
return textureCache.load_icon_name(stockIcon, size);
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) or if it was unset before
if (!this._isTrayIcon) {
this.useNotificationIcon = false;
this._setSummaryIcon(this.app.create_icon_texture (this.ICON_SIZE));
}
},
clicked: function() {
this.openApp();
MessageTray.Source.prototype.clicked.call(this);
setTrayIcon: function(icon) {
this._setSummaryIcon(icon);
this.useNotificationIcon = false;
this._isTrayIcon = true;
},
setApp: function(app) {
this.app = app;
if (this._openAppRequested)
this.openApp();
_notificationClicked: function(notification) {
this.openApp();
},
_notificationRemoved: function() {
if (!this._isTrayIcon)
this.destroy();
},
openApp: function() {
if (this.app == null) {
this._openAppRequested = true;
if (this.app == null)
return;
}
let windows = this.app.get_windows();
if (windows.length > 0) {
let mostRecentWindow = windows[0];
Main.activateWindow(mostRecentWindow);
}
this._openAppRequested = false;
}
};

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,23 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter;
const GConf = imports.gi.GConf;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Signals = imports.signals;
const DBus = imports.dbus;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const AppDisplay = imports.ui.appDisplay;
const BoxPointer = imports.ui.boxpointer;
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;
@ -30,20 +27,31 @@ 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;
const STANDARD_TRAY_ICON_ORDER = ['keyboard', 'volume', 'bluetooth', 'network', 'battery'];
const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
'bluetooth-applet': 'bluetooth',
'gnome-volume-control-applet': 'volume',
'nm-applet': 'network',
'gnome-power-manager': 'battery'
const STANDARD_TRAY_ICON_ORDER = ['a11y', 'display', 'keyboard', 'volume', 'bluetooth', 'network', 'battery'];
const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
'a11y': imports.ui.status.accessibility.ATIndicator,
'volume': imports.ui.status.volume.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;
const STANDARD_TRAY_INDICATOR_FACTORIES = [
imports.ui.status.keyboard.ModifierIndicatorFactory
];
// 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';
@ -176,38 +184,6 @@ TextShadower.prototype = {
}
};
function PanelMenuButton(menuAlignment) {
this._init(menuAlignment);
}
PanelMenuButton.prototype = {
_init: function(menuAlignment) {
this.actor = new St.Bin({ style_class: 'panel-button',
reactive: true,
x_fill: true,
y_fill: false,
track_hover: true });
this.actor._delegate = this;
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
this.menu = new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP, /* FIXME */ 0);
this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
Main.chrome.addActor(this.menu.actor, { visibleInOverview: true,
affectsStruts: false });
this.menu.actor.hide();
},
_onButtonPress: function(actor, event) {
this.menu.toggle();
},
_onOpenStateChanged: function(menu, open) {
if (open)
this.actor.add_style_pseudo_class('pressed');
else
this.actor.remove_style_pseudo_class('pressed');
}
};
/**
* AppMenuButton:
*
@ -221,13 +197,14 @@ function AppMenuButton() {
}
AppMenuButton.prototype = {
__proto__: PanelMenuButton.prototype,
__proto__: PanelMenu.Button.prototype,
_init: function() {
PanelMenuButton.prototype._init.call(this, St.Align.START);
PanelMenu.Button.prototype._init.call(this, St.Align.START);
this._metaDisplay = global.screen.get_display();
this._startingApps = [];
this._focusedApp = null;
this._targetApp = null;
let bin = new St.Bin({ name: 'appMenu' });
this.actor.set_child(bin);
@ -258,10 +235,11 @@ AppMenuButton.prototype = {
this._updateId = 0;
this._animationStep = 0;
this._clipWidth = AppDisplay.APPICON_SIZE / 2;
this._clipWidth = PANEL_ICON_SIZE;
this._direction = SPINNER_SPEED;
this._spinner = new AnimatedIcon('process-working.png', 24);
this._spinner = new AnimatedIcon('process-working.png',
PANEL_ICON_SIZE);
this._container.add_actor(this._spinner.actor);
this._spinner.actor.lower_bottom();
@ -273,6 +251,8 @@ AppMenuButton.prototype = {
tracker.connect('notify::focus-app', Lang.bind(this, this._sync));
tracker.connect('app-state-changed', Lang.bind(this, this._onAppStateChanged));
global.window_manager.connect('switch-workspace', Lang.bind(this, this._sync));
this._sync();
},
@ -341,11 +321,9 @@ AppMenuButton.prototype = {
this._stopAnimation(true);
return false;
}
if (this._animationStep < 0 || this._animationStep > 1) {
this._direction = -this._direction;
this._animationStep += 2 * this._direction;
}
this._clipWidth = this._label.actor.width - (this._label.actor.width - AppDisplay.APPICON_SIZE / 2) * (1 - this._animationStep);
if (this._animationStep > 1)
this._animationStep = 1;
this._clipWidth = this._label.actor.width - (this._label.actor.width - PANEL_ICON_SIZE) * (1 - this._animationStep);
if (this.actor.get_direction() == St.TextDirection.LTR) {
this._label.actor.set_clip(0, 0, this._clipWidth + this._shadow.width, this.actor.height);
} else {
@ -445,18 +423,19 @@ AppMenuButton.prototype = {
},
_onQuit: function() {
if (this._focusedApp == null)
if (this._targetApp == null)
return;
this._focusedApp.request_quit();
this._targetApp.request_quit();
},
_onAppStateChanged: function(tracker, app) {
let state = app.state;
if (app == this._lastStartedApp
&& state != Shell.AppState.STARTING) {
this._lastStartedApp = null;
if (state != Shell.AppState.STARTING) {
this._startingApps = this._startingApps.filter(function(a) {
return a != app;
});
} else if (state == Shell.AppState.STARTING) {
this._lastStartedApp = app;
this._startingApps.push(app);
}
// For now just resync on all running state changes; this is mainly to handle
// cases where the focused window's application changes without the focus
@ -467,14 +446,27 @@ AppMenuButton.prototype = {
_sync: function() {
let tracker = Shell.WindowTracker.get_default();
let lastStartedApp = null;
let workspace = global.screen.get_active_workspace();
for (let i = 0; i < this._startingApps.length; i++)
if (this._startingApps[i].is_on_workspace(workspace))
lastStartedApp = this._startingApps[i];
let focusedApp = tracker.focus_app;
if (focusedApp == this._focusedApp) {
if (focusedApp && focusedApp.get_state() != Shell.AppState.STARTING)
let targetApp = focusedApp != null ? focusedApp : lastStartedApp;
if (targetApp == this._targetApp) {
if (targetApp && targetApp.get_state() != Shell.AppState.STARTING)
this.stopAnimation();
return;
} else {
this._stopAnimation();
}
this._stopAnimation();
if (!focusedApp) {
// If the app has just lost focus to the panel, pretend
// nothing happened; otherwise you can't keynav to the
// app menu.
if (global.stage_input_mode == Shell.StageInputMode.FOCUSED)
return;
}
if (this._iconBox.child != null)
@ -483,15 +475,13 @@ AppMenuButton.prototype = {
this._label.setText('');
this.actor.reactive = false;
this._focusedApp = focusedApp;
let targetApp = this._focusedApp != null ? this._focusedApp : this._lastStartedApp;
this._targetApp = targetApp;
if (targetApp != null) {
let icon = targetApp.get_faded_icon(AppDisplay.APPICON_SIZE);
let icon = targetApp.get_faded_icon(2 * PANEL_ICON_SIZE);
this._label.setText(targetApp.get_name());
// TODO - _quit() doesn't really work on apps in state STARTING yet
this._quitMenu.label.set_text(_('Quit %s').format(targetApp.get_name()));
this._quitMenu.label.set_text(_("Quit %s").format(targetApp.get_name()));
this.actor.reactive = true;
this._iconBox.set_child(icon);
@ -507,147 +497,6 @@ AppMenuButton.prototype = {
Signals.addSignalMethods(AppMenuButton.prototype);
function ClockButton() {
this._init();
}
ClockButton.prototype = {
__proto__: PanelMenuButton.prototype,
_init: function() {
PanelMenuButton.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();
}
@ -659,6 +508,13 @@ Panel.prototype = {
reactive: true });
this.actor._delegate = this;
Main.overview.connect('shown', Lang.bind(this, function () {
this.actor.add_style_class_name('in-overview');
}));
Main.overview.connect('hiding', Lang.bind(this, function () {
this.actor.remove_style_class_name('in-overview');
}));
this._menus = new PopupMenu.PopupMenuManager(this);
this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
@ -761,10 +617,24 @@ Panel.prototype = {
/* Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview". */
let label = new St.Label({ text: _("Activities") });
this.button = new St.Clickable({ name: 'panelActivities',
style_class: 'panel-button',
reactive: true });
style_class: 'panel-button',
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
@ -802,6 +672,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);
@ -811,50 +693,27 @@ 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 */
// Yet-another-Ubuntu-workaround - we have to kill their
// 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();
// The tray icons live in trayBox within trayContainer.
// On-off indicators (for keyboard leds and accessx) are in indicatorBox
// System status applets live in statusBox, and legacy tray icons
// live in trayBox
// The trayBox is hidden when there are no tray icons.
let trayContainer = new St.Bin({ y_align: St.Align.MIDDLE });
this._rightBox.add(trayContainer);
let trayBox = new St.BoxLayout({ name: 'statusTray' });
this._trayBox = trayBox;
this._indicatorBox = new St.BoxLayout({ name: 'indicatorBox' });
this._trayBox = new St.BoxLayout({ name: 'legacyTray' });
this._statusBox = new St.BoxLayout({ name: 'statusTray' });
trayBox.hide();
trayContainer.add_actor(trayBox);
this._trayBox.hide();
this._rightBox.add(this._indicatorBox);
this._rightBox.add(this._trayBox);
this._rightBox.add(this._statusBox);
this._traymanager = new Shell.TrayManager();
this._traymanager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
this._traymanager.connect('tray-icon-removed',
Lang.bind(this, function(o, icon) {
trayBox.remove_actor(icon);
if (trayBox.get_children().length == 0)
trayBox.hide();
this._recomputeTraySize();
}));
this._traymanager.manage_stage(global.stage);
// We need to do this here to avoid a circular import with
// prototype dependencies.
let StatusMenu = imports.ui.statusMenu;
this._statusmenu = new StatusMenu.StatusMenuButton();
this._menus.addMenu(this._statusmenu.menu);
this._rightBox.add(this._statusmenu.actor);
Main.statusIconDispatcher.connect('status-icon-added', Lang.bind(this, this._onTrayIconAdded));
Main.statusIconDispatcher.connect('status-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
// 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
@ -881,8 +740,48 @@ 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_INDICATOR_FACTORIES.length; i++) {
let factory = new STANDARD_TRAY_INDICATOR_FACTORIES[i];
let indicators = factory.getIndicators();
for (let j = 0; j < indicators.length; j++)
this._indicatorBox.add(indicators[j]);
}
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() {
@ -894,49 +793,40 @@ Panel.prototype = {
});
},
_onTrayIconAdded: function(o, icon, wmClass) {
_onTrayIconAdded: function(o, icon, role) {
icon.height = PANEL_ICON_SIZE;
let role = STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass];
if (!role) {
// Unknown icons go first in undefined order
if (STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION[role]) {
// This icon is legacy, and replaced by a Shell version
// Hide it
return;
}
// Figure out the index in our well-known order for this icon
let position = STANDARD_TRAY_ICON_ORDER.indexOf(role);
icon._rolePosition = position;
let children = this._trayBox.get_children();
let i;
// Walk children backwards, until we find one that isn't
// well-known, or one where we should follow
for (i = children.length - 1; i >= 0; i--) {
let rolePosition = children[i]._rolePosition;
if (!rolePosition || position > rolePosition) {
this._trayBox.insert_actor(icon, i + 1);
break;
}
}
if (i == -1) {
// If we didn't find a position, we must be first
this._trayBox.insert_actor(icon, 0);
} else {
icon._role = role;
// Figure out the index in our well-known order for this icon
let position = STANDARD_TRAY_ICON_ORDER.indexOf(role);
icon._rolePosition = position;
let children = this._trayBox.get_children();
let i;
// Walk children backwards, until we find one that isn't
// well-known, or one where we should follow
for (i = children.length - 1; i >= 0; i--) {
let rolePosition = children[i]._rolePosition;
if (!rolePosition || position > rolePosition) {
this._trayBox.insert_actor(icon, i + 1);
break;
}
}
if (i == -1) {
// If we didn't find a position, we must be first
this._trayBox.insert_actor(icon, 0);
}
}
// Make sure the trayBox is shown.
this._trayBox.show();
this._recomputeTraySize();
},
// By default, tray icons have a spacing of TRAY_SPACING. However this
// starts to fail if we have too many as can sadly happen; just jump down
// to a spacing of 8 if we're over 6.
// http://bugzilla.gnome.org/show_bug.cgi?id=590495
_recomputeTraySize: function () {
if (this._trayBox.get_children().length > 6)
this._trayBox.add_style_pseudo_class('compact');
else
this._trayBox.remove_style_pseudo_class('compact');
_onTrayIconRemoved: function(o, icon) {
if (icon.get_parent() != null)
this._trayBox.remove_actor(icon);
},
_addRipple : function(delay, time, startScale, startOpacity, finalScale, finalOpacity) {
@ -966,6 +856,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;
@ -974,14 +875,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();
}
}
@ -1028,6 +922,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' });
@ -1039,7 +936,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() {
@ -1052,7 +949,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,
@ -1076,10 +972,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);
}
};

97
js/ui/panelMenu.js Normal file
View File

@ -0,0 +1,97 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const St = imports.gi.St;
const Lang = imports.lang;
const PopupMenu = imports.ui.popupMenu;
const Main = imports.ui.main;
function Button(menuAlignment) {
this._init(menuAlignment);
}
Button.prototype = {
_init: function(menuAlignment) {
this.actor = new St.Bin({ style_class: 'panel-button',
reactive: true,
can_focus: true,
x_fill: true,
y_fill: false,
track_hover: true });
this.actor._delegate = this;
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPress));
this.menu = new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP, /* FIXME */ 0);
this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
Main.chrome.addActor(this.menu.actor, { visibleInOverview: true,
affectsStruts: false });
this.menu.actor.hide();
},
_onButtonPress: function(actor, event) {
this.menu.toggle();
},
_onKeyPress: function(actor, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
this.menu.toggle();
return true;
} else if (symbol == Clutter.KEY_Down) {
if (!this.menu.isOpen)
this.menu.toggle();
this.menu.activateFirst();
return true;
} else
return false;
},
_onOpenStateChanged: function(menu, open) {
if (open)
this.actor.add_style_pseudo_class('pressed');
else
this.actor.remove_style_pseudo_class('pressed');
}
};
/* SystemStatusButton:
*
* This class manages one System Status indicator (network, keyboard,
* volume, bluetooth...), which is just a PanelMenuButton with an
* icon and a tooltip
*/
function SystemStatusButton() {
this._init.apply(this, arguments);
}
SystemStatusButton.prototype = {
__proto__: Button.prototype,
_init: function(iconName,tooltipText) {
Button.prototype._init.call(this, St.Align.START);
this._iconActor = new St.Icon({ icon_name: iconName,
icon_type: St.IconType.SYMBOLIC,
style_class: 'system-status-icon' });
this.actor.set_child(this._iconActor);
this.setTooltip(tooltipText);
},
setIcon: function(iconName) {
this._iconActor.icon_name = iconName;
},
setGIcon: function(gicon) {
this._iconActor.gicon = gicon;
},
setTooltip: function(text) {
if (text != null) {
this.tooltip = text;
this.actor.has_tooltip = true;
this.actor.tooltip_text = text;
} else {
this.actor.has_tooltip = false;
this.tooltip = null;
}
}
};

View File

@ -1,8 +1,5 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Pango = imports.gi.Pango;
const GConf = imports.gi.GConf;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Shell = imports.gi.Shell;
@ -16,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,
@ -48,10 +41,14 @@ PlaceInfo.prototype = {
for (let i = 0; i < terms.length; i++) {
let term = terms[i];
let idx = this._lowerName.indexOf(term);
if (idx == 0)
return Search.MatchType.PREFIX;
else if (idx > 0)
mtype = Search.MatchType.SUBSTRING;
if (idx == 0) {
mtype = Search.MatchType.PREFIX;
} else if (idx > 0) {
if (mtype == Search.MatchType.NONE)
mtype = Search.MatchType.SUBSTRING;
} else {
return Search.MatchType.NONE;
}
}
return mtype;
},
@ -77,7 +74,7 @@ PlaceDeviceInfo.prototype = {
iconFactory: function(size) {
let icon = this._mount.get_icon();
return St.TextureCache.get_default().load_gicon(icon, size);
return St.TextureCache.get_default().load_gicon(null, icon, size);
},
launch: function() {
@ -107,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"));
}
@ -121,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();
@ -135,7 +128,7 @@ PlacesManager.prototype = {
let homeIcon = Shell.util_get_icon_for_uri (homeUri);
this._home = new PlaceInfo('special:home', homeLabel,
function(size) {
return St.TextureCache.get_default().load_gicon(homeIcon, size);
return St.TextureCache.get_default().load_gicon(null, homeIcon, size);
},
function() {
Gio.app_info_launch_default_for_uri(homeUri, global.create_app_launch_context());
@ -148,7 +141,7 @@ PlacesManager.prototype = {
let desktopIcon = Shell.util_get_icon_for_uri (desktopUri);
this._desktopMenu = new PlaceInfo('special:desktop', desktopLabel,
function(size) {
return St.TextureCache.get_default().load_gicon(desktopIcon, size);
return St.TextureCache.get_default().load_gicon(null, desktopIcon, size);
},
function() {
Gio.app_info_launch_default_for_uri(desktopUri, global.create_app_launch_context());
@ -156,10 +149,12 @@ PlacesManager.prototype = {
this._connect = new PlaceInfo('special:connect', _("Connect to..."),
function (size) {
return St.TextureCache.get_default().load_icon_name('applications-internet', size);
return new St.Icon({ icon_name: 'applications-internet',
icon_type: St.IconType.FULLCOLOR,
icon_size: size });
},
function () {
new Shell.Process({ args: ['nautilus-connect-server'] }).run();
Util.spawn(['nautilus-connect-server']);
});
let networkApp = null;
@ -184,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);
@ -225,9 +217,6 @@ PlacesManager.prototype = {
}));
this._reloadBookmarks();
gconf.notify_add(DESKTOP_IS_HOME_KEY, Lang.bind(this, this._updateDesktopMenuVisibility));
},
_updateDevices: function() {
@ -323,7 +312,7 @@ PlacesManager.prototype = {
let item = new PlaceInfo('bookmark:' + bookmark, label,
function(size) {
return St.TextureCache.get_default().load_gicon(icon, size);
return St.TextureCache.get_default().load_gicon(null, icon, size);
},
function() {
Gio.app_info_launch_default_for_uri(bookmark, global.create_app_launch_context());
@ -336,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);
@ -398,148 +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 = St.TextureCache.get_default().load_icon_name ('media-eject', 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();
@ -573,8 +407,9 @@ PlaceSearchProvider.prototype = {
},
_searchPlaces: function(places, terms) {
let multipleResults = [];
let multiplePrefixResults = [];
let prefixResults = [];
let multipleSubstringResults = [];
let substringResults = [];
terms = terms.map(String.toLowerCase);
@ -582,17 +417,20 @@ PlaceSearchProvider.prototype = {
for (let i = 0; i < places.length; i++) {
let place = places[i];
let mtype = place.matchTerms(terms);
if (mtype == Search.MatchType.MULTIPLE)
multipleResults.push(place.id);
if (mtype == Search.MatchType.MULTIPLE_PREFIX)
multiplePrefixResults.push(place.id);
else if (mtype == Search.MatchType.PREFIX)
prefixResults.push(place.id);
else if (mtype == Search.MatchType.MULTIPLE_SUBSTRING)
multipleSubstringResults.push(place.id);
else if (mtype == Search.MatchType.SUBSTRING)
substringResults.push(place.id);
}
multipleResults.sort(this._compareResultMeta);
multiplePrefixResults.sort(this._compareResultMeta);
prefixResults.sort(this._compareResultMeta);
multipleSubstringResults.sort(this._compareResultMeta);
substringResults.sort(this._compareResultMeta);
return multipleResults.concat(prefixResults.concat(substringResults));
return multiplePrefixResults.concat(prefixResults.concat(multipleSubstringResults.concat(substringResults)));
},
getInitialResultSet: function(terms) {

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,6 @@ const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
@ -12,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();
@ -63,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;
@ -101,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) {
@ -176,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');
@ -208,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();
@ -276,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) {
@ -350,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;
@ -370,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();
})
});
}
}
}
}
@ -401,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,6 +1,5 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Mainloop = imports.mainloop;

View File

@ -1,18 +1,31 @@
/* -*- 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 St = imports.gi.St;
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
// implementations.
const MatchType = {
NONE: 0,
MULTIPLE: 1,
PREFIX: 2,
SUBSTRING: 3
SUBSTRING: 1,
MULTIPLE_SUBSTRING: 2,
PREFIX: 3,
MULTIPLE_PREFIX: 4
};
function SearchResultDisplay(provider) {
@ -108,7 +121,7 @@ SearchProvider.prototype = {
/**
* getInitialResultSet:
* @terms: Array of search terms, treated as logical OR
* @terms: Array of search terms, treated as logical AND
*
* Called when the user first begins a search (most likely
* therefore a single term of length one or two), or when
@ -120,7 +133,8 @@ SearchProvider.prototype = {
* item. Ordering of returned results is up to the discretion of the provider,
* but you should follow these heruistics:
*
* * Put items which match multiple search terms before single matches
* * Put items where the term matches multiple criteria (e.g. name and
* description) before single matches
* * Put items which match on a prefix before non-prefix substring matches
*
* This function should be fast; do not perform unindexed full-text searches
@ -181,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;
@ -210,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();
}
@ -257,16 +372,24 @@ SearchSystem.prototype = {
if (isSubSearch) {
for (let i = 0; i < this._previousResults.length; i++) {
let [provider, previousResults] = this._previousResults[i];
let providerResults = provider.getSubsearchResultSet(previousResults, terms);
if (providerResults.length > 0)
results.push([provider, providerResults]);
try {
let providerResults = provider.getSubsearchResultSet(previousResults, terms);
if (providerResults.length > 0)
results.push([provider, providerResults]);
} catch (error) {
global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
}
}
} else {
for (let i = 0; i < this._providers.length; i++) {
let provider = this._providers[i];
let providerResults = provider.getInitialResultSet(terms);
if (providerResults.length > 0)
results.push([provider, providerResults]);
try {
let providerResults = provider.getInitialResultSet(terms);
if (providerResults.length > 0)
results.push([provider, providerResults]);
} catch (error) {
global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
}
}
}

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

@ -1,9 +1,6 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const DBus = imports.dbus;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Mainloop = imports.mainloop;
const Main = imports.ui.main;

View File

@ -0,0 +1,226 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const DBus = imports.dbus;
const GConf = imports.gi.GConf;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
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;
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 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 DPI_LOW_REASONABLE_VALUE = 50;
const DPI_HIGH_REASONABLE_VALUE = 500;
const DPI_FACTOR_LARGE = 1.25;
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 DESKTOP_INTERFACE_SCHEMA = 'org.gnome.desktop.interface';
const KEY_GTK_THEME = 'gtk-theme';
const KEY_ICON_THEME = 'icon-theme';
const HIGH_CONTRAST_THEME = 'HighContrast';
function getDPIFromX() {
let screen = global.get_gdk_screen();
if (screen) {
let width_dpi = (screen.get_width() / (screen.get_width_mm() / 25.4));
let height_dpi = (screen.get_height() / (screen.get_height_mm() / 25.4));
if (width_dpi < DPI_LOW_REASONABLE_VALUE
|| width_dpi > DPI_HIGH_REASONABLE_VALUE
|| height_dpi < DPI_LOW_REASONABLE_VALUE
|| height_dpi > DPI_HIGH_REASONABLE_VALUE)
return DPI_DEFAULT;
else
return (width_dpi + height_dpi) / 2;
}
return DPI_DEFAULT;
}
function ATIndicator() {
this._init.apply(this, arguments);
}
ATIndicator.prototype = {
__proto__: PanelMenu.SystemStatusButton.prototype,
_init: function() {
PanelMenu.SystemStatusButton.prototype._init.call(this, 'preferences-desktop-accessibility', null);
let client = GConf.Client.get_default();
client.add_dir(KEY_META_DIR, GConf.ClientPreloadType.PRELOAD_ONELEVEL, null);
client.notify_add(KEY_META_DIR, Lang.bind(this, this._keyChanged), null, null);
let highContrast = this._buildHCItem();
this.menu.addMenuItem(highContrast);
let magnifier = this._buildItem(_("Zoom"), MAGNIFIER_SCHEMA, 'show-magnifier');
this.menu.addMenuItem(magnifier);
let textZoom = this._buildFontItem();
this.menu.addMenuItem(textZoom);
let screenReader = this._buildItem(_("Screen Reader"), AT_SCREEN_READER_SCHEMA, 'startup');
this.menu.addMenuItem(screenReader);
let screenKeyboard = this._buildItem(_("Screen Keyboard"), AT_SCREEN_KEYBOARD_SCHEMA, 'startup');
this.menu.addMenuItem(screenKeyboard);
let visualBell = this._buildItemGConf(_("Visual Alerts"), client, KEY_VISUAL_BELL);
this.menu.addMenuItem(visualBell);
let stickyKeys = this._buildItem(_("Sticky Keys"), A11Y_SCHEMA, KEY_STICKY_KEYS_ENABLED);
this.menu.addMenuItem(stickyKeys);
let slowKeys = this._buildItem(_("Slow Keys"), A11Y_SCHEMA, KEY_SLOW_KEYS_ENABLED);
this.menu.addMenuItem(slowKeys);
let bounceKeys = this._buildItem(_("Bounce Keys"), A11Y_SCHEMA, KEY_BOUNCE_KEYS_ENABLED);
this.menu.addMenuItem(bounceKeys);
let mouseKeys = this._buildItem(_("Mouse Keys"), A11Y_SCHEMA, KEY_MOUSE_KEYS_ENABLED);
this.menu.addMenuItem(mouseKeys);
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Universal Access Settings"), function() {
Util.spawnDesktop('gnome-universal-access-panel');
});
},
_buildItemExtended: function(string, initial_value, writable, on_set) {
let widget = new PopupMenu.PopupSwitchMenuItem(string, initial_value);
if (!writable)
widget.actor.reactive = false;
else
widget.connect('toggled', function(item) {
on_set(item.state);
});
return widget;
},
_buildItemGConf: function(string, client, key) {
function on_get() {
return client.get_bool(key);
}
let widget = this._buildItemExtended(string,
client.get_bool(key),
client.key_is_writable(key),
function(enabled) {
client.set_bool(key, enabled);
});
this.connect('gconf-changed', function() {
widget.setToggleState(client.get_bool(key));
});
return widget;
},
_buildItem: function(string, schema, key) {
let settings = new Gio.Settings({ schema: schema });
let widget = this._buildItemExtended(string,
settings.get_boolean(key),
settings.is_writable(key),
function(enabled) {
return settings.set_boolean(key, enabled);
});
settings.connect('changed::'+key, function() {
widget.setToggleState(settings.get_boolean(key));
});
return widget;
},
_buildHCItem: function() {
let settings = new Gio.Settings({ schema: DESKTOP_INTERFACE_SCHEMA });
let gtkTheme = settings.get_string(KEY_GTK_THEME);
let iconTheme = settings.get_string(KEY_ICON_THEME);
let hasHC = (gtkTheme == HIGH_CONTRAST_THEME);
let highContrast = this._buildItemExtended(
_("High Contrast"),
hasHC,
settings.is_writable(KEY_GTK_THEME) && settings.is_writable(KEY_ICON_THEME),
function (enabled) {
if (enabled) {
settings.set_string(KEY_GTK_THEME, HIGH_CONTRAST_THEME);
settings.set_string(KEY_ICON_THEME, HIGH_CONTRAST_THEME);
} else {
settings.set_string(KEY_GTK_THEME, gtkTheme);
settings.set_string(KEY_ICON_THEME, iconTheme);
}
});
settings.connect('changed::' + KEY_GTK_THEME, function() {
let value = settings.get_string(KEY_GTK_THEME);
if (value == HIGH_CONTRAST_THEME) {
highContrast.setToggleState(true);
} else {
highContrast.setToggleState(false);
gtkTheme = value;
}
});
settings.connect('changed::' + KEY_ICON_THEME, function() {
let value = settings.get_string(KEY_ICON_THEME);
if (value != HIGH_CONTRAST_THEME)
iconTheme = value;
});
return highContrast;
},
_buildFontItem: function() {
let settings = new Gio.Settings({ schema: XSETTINGS_SCHEMA });
// we assume this never changes (which is not true if resolution
// is changed, but we would need XRandR events for that)
let x_value = getDPIFromX();
let user_value;
function on_get() {
user_value = settings.get_double(KEY_DPI);
return (user_value - (DPI_FACTOR_LARGE * x_value) > -1);
}
let initial_setting = on_get();
let default_value = initial_setting ? x_value : user_value;
let widget = this._buildItemExtended(_("Large Text"),
initial_setting,
settings.is_writable(KEY_DPI),
function (enabled) {
if (enabled)
settings.set_double(KEY_DPI, DPI_FACTOR_LARGE * default_value);
else
settings.set_double(KEY_DPI, default_value);
});
settings.connect('changed::' + KEY_DPI, function() {
let active = on_get();
default_value = active ? x_value : user_value;
widget.setToggleState(active);
});
return widget;
},
_keyChanged: function() {
this.emit('gconf-changed');
}
};
Signals.addSignalMethods(ATIndicator.prototype);

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);
}
}

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

@ -0,0 +1,255 @@
/* -*- 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);
}
};
function ModifierIndicatorFactory() {
this._init.call(this);
}
ModifierIndicatorFactory.prototype = {
_init: function() {
this._settings = new Gio.Settings({ schema: INDICATOR_SCHEMA });
this._settings.connect('changed::show-keyboard-leds-indicator', Lang.bind(this, this._changed));
this._config = Gkbd.Configuration.get();
this._config.connect('indicators-changed', Lang.bind(this, this._changed));
this._scrollLock = new St.Icon({ icon_name: 'kbdled-scroll-lock', icon_type: St.IconType.SYMBOLIC, style_class: 'system-status-icon' });
this._numLock = new St.Icon({ icon_name: 'kbdled-num-lock', icon_type: St.IconType.SYMBOLIC, style_class: 'system-status-icon' });
this._capsLock = new St.Icon({ icon_name: 'kbdled-caps-lock', icon_type: St.IconType.SYMBOLIC, style_class: 'system-status-icon' });
this._changed();
},
getIndicators: function() {
return [this._scrollLock, this._numLock, this._capsLock];
},
_changed: function() {
let enable = this._settings.get_boolean('show-keyboard-leds-indicator');
if (enable) {
if (this._config.get_scroll_lock_state())
this._scrollLock.show();
else
this._scrollLock.hide();
if (this._config.get_num_lock_state())
this._numLock.show();
else
this._numLock.hide();
if (this._config.get_caps_lock_state())
this._capsLock.show();
else
this._capsLock.hide();
} else {
this._scrollLock.hide();
this._numLock.hide();
this._capsLock.hide();
}
}
};

260
js/ui/status/power.js Normal file
View File

@ -0,0 +1,260 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Gio = imports.gi.Gio;
const DBus = imports.dbus;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
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;
const BUS_NAME = 'org.gnome.PowerManager';
const OBJECT_PATH = '/org/gnome/PowerManager';
const UPDeviceType = {
UNKNOWN: 0,
AC_POWER: 1,
BATTERY: 2,
UPS: 3,
MONITOR: 4,
MOUSE: 5,
KEYBOARD: 6,
PDA: 7,
PHONE: 8,
MEDIA_PLAYER: 9,
TABLET: 10,
COMPUTER: 11
};
const UPDeviceState = {
UNKNOWN: 0,
CHARGING: 1,
DISCHARGING: 2,
EMPTY: 3,
FULLY_CHARGED: 4,
PENDING_CHARGE: 5,
PENDING_DISCHARGE: 6
};
const PowerManagerInterface = {
name: 'org.gnome.PowerManager',
methods: [
{ name: 'GetDevices', inSignature: '', outSignature: 'a(susbut)' },
{ name: 'GetPrimaryDevice', inSignature: '', outSignature: '(susbut)' },
],
signals: [
{ name: 'Changed', outSignature: '' },
],
properties: [
{ name: 'Icon', signature: 's', access: 'read' },
]
};
let PowerManagerProxy = DBus.makeProxyClass(PowerManagerInterface);
function Indicator() {
this._init.apply(this, arguments);
}
Indicator.prototype = {
__proto__: PanelMenu.SystemStatusButton.prototype,
_init: function() {
PanelMenu.SystemStatusButton.prototype._init.call(this, 'battery-missing');
this._proxy = new PowerManagerProxy(DBus.session, BUS_NAME, OBJECT_PATH);
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(_("Power Settings"),function() {
Util.spawnDesktop('gnome-power-panel');
});
this._proxy.connect('Changed', Lang.bind(this, this._devicesChanged));
this._devicesChanged();
},
_readPrimaryDevice: function() {
this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(device, error) {
if (error) {
this._checkError(error);
this._hasPrimary = false;
this._primaryDeviceId = null;
this._batteryItem.actor.hide();
this._deviceSep.actor.hide();
return;
}
let [device_id, device_type, icon, percentage, state, seconds] = device;
if (device_type == UPDeviceType.BATTERY) {
this._hasPrimary = true;
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();
} else {
this._hasPrimary = false;
this._batteryItem.actor.hide();
this._deviceSep.actor.hide();
}
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;
}
}));
},
_readOtherDevices: function() {
this._proxy.GetDevicesRemote(Lang.bind(this, function(devices, error) {
this._deviceItems.forEach(function(i) { i.destroy(); });
this._deviceItems = [];
if (error) {
this._checkError(error);
this._deviceSep.actor.hide();
return;
}
let position = 0;
for (let i = 0; i < devices.length; i++) {
let [device_id, device_type] = devices[i];
if (device_type == UPDeviceType.AC_POWER || device_id == this._primaryDeviceId)
continue;
let item = new DeviceItem (devices[i]);
item.connect('activate', function() {
Util.spawn(['gnome-power-statistics', '--device', device_id]);
});
this._deviceItems.push(item);
this.menu.addMenuItem(item, this._otherDevicePosition + position);
position++;
}
if (this._hasPrimary && position > 0)
this._deviceSep.actor.show();
else
this._deviceSep.actor.hide();
}));
},
_devicesChanged: function() {
this._proxy.GetRemote('Icon', Lang.bind(this, function(icon, error) {
if (icon) {
let gicon = Shell.util_icon_from_string (icon);
this.setGIcon(gicon);
this.actor.show();
} else {
this._checkError(error);
this.menu.close();
this.actor.hide();
}
}));
this._readPrimaryDevice();
this._readOtherDevices();
},
_checkError: function(error) {
if (!this._restarted && error && error.message.match(/org\.freedesktop\.DBus\.Error\.(UnknownMethod|InvalidArgs)/)) {
Util.killall('gnome-power-manager');
Util.spawn(['gnome-power-manager']);
this._restarted = true;
}
}
};
function DeviceItem() {
this._init.apply(this, arguments);
}
DeviceItem.prototype = {
__proto__: PopupMenu.PopupBaseMenuItem.prototype,
_init: function(device) {
PopupMenu.PopupBaseMenuItem.prototype._init.call(this);
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: this._deviceTypeToString(device_type) });
this._icon = new St.Icon({ gicon: Shell.util_icon_from_string(icon),
icon_type: St.IconType.SYMBOLIC,
style_class: 'popup-menu-icon' });
this._box.add_actor(this._icon);
this._box.add_actor(this._label);
this.addActor(this._box);
let percentLabel = new St.Label({ text: '%d%%'.format(Math.round(percentage)) });
this.addActor(percentLabel, { align: St.Align.END });
},
_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");
}
}
}

216
js/ui/status/volume.js Normal file
View File

@ -0,0 +1,216 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const DBus = imports.dbus;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const Gvc = imports.gi.Gvc;
const Signals = imports.signals;
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;
const VOLUME_MAX = 65536.0; /* PA_VOLUME_NORM */
const VOLUME_ADJUSTMENT_STEP = 0.05; /* Volume adjustment step in % */
function Indicator() {
this._init.apply(this, arguments);
}
Indicator.prototype = {
__proto__: PanelMenu.SystemStatusButton.prototype,
_init: function() {
PanelMenu.SystemStatusButton.prototype._init.call(this, 'audio-volume-muted', null);
this._control = new Gvc.MixerControl({ name: 'GNOME Shell Volume Control' });
this._control.connect('ready', Lang.bind(this, this._onControlReady));
this._control.connect('default-sink-changed', Lang.bind(this, this._readOutput));
this._control.connect('default-source-changed', Lang.bind(this, this._readInput));
this._control.connect('stream-added', Lang.bind(this, this._maybeShowInput));
this._control.connect('stream-removed', Lang.bind(this, this._maybeShowInput));
this._output = null;
this._outputVolumeId = 0;
this._outputMutedId = 0;
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._outputTitle);
this.menu.addMenuItem(this._outputSlider);
this._separator = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(this._separator);
this._input = null;
this._inputVolumeId = 0;
this._inputMutedId = 0;
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._inputTitle);
this.menu.addMenuItem(this._inputSlider);
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Sound Settings"), function() {
Util.spawnDesktop('gnome-sound-panel');
});
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
this._control.open();
},
_onScrollEvent: function(actor, event) {
let direction = event.get_scroll_direction();
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();
}
},
_onControlReady: function() {
this._readOutput();
this._readInput();
},
_readOutput: function() {
if (this._outputVolumeId) {
this._output.disconnect(this._outputVolumeId);
this._output.disconnect(this._outputMutedId);
this._outputVolumeId = 0;
this._outputMutedId = 0;
}
this._output = this._control.get_default_sink();
if (this._output) {
this._outputMutedId = this._output.connect('notify::is-muted', Lang.bind(this, this._mutedChanged, '_output'));
this._outputVolumeId = this._output.connect('notify::volume', Lang.bind(this, this._volumeChanged, '_output'));
this._mutedChanged (null, null, '_output');
this._volumeChanged (null, null, '_output');
} else {
this._outputSlider.setValue(0);
this.setIcon('audio-volume-muted-symbolic');
}
},
_readInput: function() {
if (this._inputVolumeId) {
this._input.disconnect(this._inputVolumeId);
this._input.disconnect(this._inputMutedId);
this._inputVolumeId = 0;
this._inputMutedId = 0;
}
this._input = this._control.get_default_source();
if (this._input) {
this._inputMutedId = this._input.connect('notify::is-muted', Lang.bind(this, this._mutedChanged, '_input'));
this._inputVolumeId = this._input.connect('notify::volume', Lang.bind(this, this._volumeChanged, '_input'));
this._mutedChanged (null, null, '_input');
this._volumeChanged (null, null, '_input');
} else {
this._separator.actor.hide();
this._inputTitle.actor.hide();
this._inputSlider.actor.hide();
}
},
_maybeShowInput: function() {
// only show input widgets if any application is recording audio
let showInput = false;
let recordingApps = this._control.get_source_outputs();
if (this._input && recordingApps) {
for (let i = 0; i < recordingApps.length; i++) {
let outputStream = recordingApps[i];
let id = outputStream.get_application_id();
// but skip gnome-volume-control and pavucontrol
// (that appear as recording because they show the input level)
if (!id || (id != 'org.gnome.VolumeControl' && id != 'org.PulseAudio.pavucontrol')) {
showInput = true;
break;
}
}
}
if (showInput) {
this._separator.actor.show();
this._inputTitle.actor.show();
this._inputSlider.actor.show();
} else {
this._separator.actor.hide();
this._inputTitle.actor.hide();
this._inputSlider.actor.hide();
}
},
_volumeToIcon: function(volume) {
if (volume <= 0) {
return 'audio-volume-muted';
} else {
let v = volume / VOLUME_MAX;
if (v < 0.33)
return 'audio-volume-low';
if (v > 0.8)
return 'audio-volume-high';
return 'audio-volume-medium';
}
},
_sliderChanged: function(slider, value, property) {
if (this[property] == null) {
log ('Volume slider changed for %s, but %s does not exist'.format(property, property));
return;
}
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();
},
_notifyVolumeChange: function() {
global.play_theme_sound('audio-volume-change');
},
_mutedChanged: function(object, param_spec, property) {
let muted = this[property].is_muted;
let slider = this[property+'Slider'];
slider.setValue(muted ? 0 : (this[property].volume / VOLUME_MAX));
if (property == '_output') {
if (muted)
this.setIcon('audio-volume-muted');
else
this.setIcon(this._volumeToIcon(this._output.volume));
}
},
_volumeChanged: function(object, param_spec, property) {
this[property+'Slider'].setValue(this[property].volume / VOLUME_MAX);
if (property == '_output' && !this._output.is_muted)
this.setIcon(this._volumeToIcon(this._output.volume));
}
};

View File

@ -0,0 +1,61 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Lang = imports.lang;
const Shell = imports.gi.Shell;
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',
'gnome-volume-control-applet': 'volume', // renamed to gnome-sound-applet
// when moved to control center
'gnome-sound-applet': 'volume',
'nm-applet': 'network',
'gnome-power-manager': 'battery',
'keyboard': 'keyboard',
'a11y-keyboard': 'a11y',
'kbd-scrolllock': 'keyboard',
'kbd-numlock': 'keyboard',
'kbd-capslock': 'keyboard'
};
function StatusIconDispatcher() {
this._init();
}
StatusIconDispatcher.prototype = {
_init: function() {
this._traymanager = new Shell.TrayManager();
this._traymanager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
this._traymanager.connect('tray-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
this._traymanager.manage_stage(global.stage);
// Yet-another-Ubuntu-workaround - we have to kill their
// app-indicators, so that applications fall back to normal
// status icons
// http://bugzilla.gnome.org/show_bug.cgi=id=621382
Util.killall('indicator-application-service');
},
_onTrayIconAdded: function(o, icon) {
let wmClass = (icon.wm_class || 'unknown').toLowerCase();
let role = STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass];
if (role)
this.emit('status-icon-added', icon, role);
else
this.emit('message-icon-added', icon);
},
_onTrayIconRemoved: function(o, icon) {
let wmClass = (icon.wm_class || 'unknown').toLowerCase();
let role = STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass];
if (role)
this.emit('status-icon-removed', icon);
else
this.emit('message-icon-removed', icon);
}
};
Signals.addSignalMethods(StatusIconDispatcher.prototype);

View File

@ -10,8 +10,9 @@ const _ = Gettext.gettext;
const GnomeSession = imports.misc.gnomeSession;
const Main = imports.ui.main;
const Panel = imports.ui.panel;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
// Adapted from gdm/gui/user-switch-applet/applet.c
//
@ -23,16 +24,19 @@ function StatusMenuButton() {
}
StatusMenuButton.prototype = {
__proto__: Panel.PanelMenuButton.prototype,
__proto__: PanelMenu.Button.prototype,
_init: function() {
Panel.PanelMenuButton.prototype._init.call(this, St.Align.START);
PanelMenu.Button.prototype._init.call(this, St.Align.START);
let box = new St.BoxLayout({ name: 'panelStatusMenu' });
this.actor.set_child(box);
this._gdm = Gdm.UserManager.ref_default();
this._gdm.queue_load();
this._user = this._gdm.get_user(GLib.get_user_name());
this._presence = new GnomeSession.Presence();
this._presenceItems = {};
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
@ -40,35 +44,39 @@ StatusMenuButton.prototype = {
box.add(this._iconBox, { y_align: St.Align.MIDDLE, y_fill: false });
let textureCache = St.TextureCache.get_default();
this._availableIcon = textureCache.load_icon_name('user-available', 16);
this._busyIcon = textureCache.load_icon_name('user-busy', 16);
this._invisibleIcon = textureCache.load_icon_name('user-invisible', 16);
this._idleIcon = textureCache.load_icon_name('user-idle', 16);
this._availableIcon = new St.Icon({ icon_name: 'user-available', style_class: 'popup-menu-icon' });
this._busyIcon = new St.Icon({ icon_name: 'user-busy', style_class: 'popup-menu-icon' });
this._invisibleIcon = new St.Icon({ icon_name: 'user-invisible', style_class: 'popup-menu-icon' });
this._idleIcon = new St.Icon({ icon_name: 'user-idle', style_class: 'popup-menu-icon' });
this._presence.connect('StatusChanged', Lang.bind(this, this._updatePresenceIcon));
this._presence.getStatus(Lang.bind(this, this._updatePresenceIcon));
this._name = new St.Label({ text: this._user.get_real_name() });
this._name = new St.Label();
box.add(this._name, { y_align: St.Align.MIDDLE, y_fill: false });
this._userNameChangedId = this._user.connect('notify::display-name', Lang.bind(this, this._updateUserName));
this._userLoadedId = this._user.connect('notify::is-loaded', Lang.bind(this, this._updateUserName));
this._userChangedId = this._user.connect('changed', Lang.bind(this, this._updateUserName));
this._createSubMenu();
this._gdm.connect('users-loaded', Lang.bind(this, this._updateSwitchUser));
this._gdm.connect('notify::is-loaded', Lang.bind(this, this._updateSwitchUser));
this._gdm.connect('user-added', Lang.bind(this, this._updateSwitchUser));
this._gdm.connect('user-removed', Lang.bind(this, this._updateSwitchUser));
},
_onDestroy: function() {
this._user.disconnect(this._userNameChangedId);
this._user.disconnect(this._userLoadedId);
this._user.disconnect(this._userChangedId);
},
_updateUserName: function() {
this._name.set_text(this._user.get_real_name());
if (this._user.is_loaded)
this._name.set_text(this._user.get_real_name());
else
this._name.set_text("");
},
_updateSwitchUser: function() {
let users = this._gdm.list_users();
if (users.length > 1)
if (this._gdm.can_switch ())
this._loginScreenItem.actor.show();
else
this._loginScreenItem.actor.hide();
@ -83,6 +91,9 @@ StatusMenuButton.prototype = {
this._iconBox.child = this._invisibleIcon;
else
this._iconBox.child = this._idleIcon;
for (let itemStatus in this._presenceItems)
this._presenceItems[itemStatus].setShowDot(itemStatus == status);
},
_createSubMenu: function() {
@ -91,43 +102,48 @@ StatusMenuButton.prototype = {
item = new PopupMenu.PopupImageMenuItem(_("Available"), 'user-available', true);
item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSession.PresenceStatus.AVAILABLE));
this.menu.addMenuItem(item);
this._presenceItems[GnomeSession.PresenceStatus.AVAILABLE] = item;
item = new PopupMenu.PopupImageMenuItem(_("Busy"), 'user-busy', true);
item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSession.PresenceStatus.BUSY));
this.menu.addMenuItem(item);
item = new PopupMenu.PopupImageMenuItem(_("Invisible"), 'user-invisible', true);
item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSession.PresenceStatus.INVISIBLE));
this.menu.addMenuItem(item);
this._presenceItems[GnomeSession.PresenceStatus.BUSY] = item;
item = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(item);
item = new PopupMenu.PopupImageMenuItem(_("Account Information..."), 'user-info');
item.connect('activate', Lang.bind(this, this._onAccountInformationActivate));
item = new PopupMenu.PopupMenuItem(_("My Account"));
item.connect('activate', Lang.bind(this, this._onMyAccountActivate));
this.menu.addMenuItem(item);
item = new PopupMenu.PopupImageMenuItem(_("System Preferences..."), 'preferences-desktop');
item = new PopupMenu.PopupMenuItem(_("System Settings"));
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
this.menu.addMenuItem(item);
item = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(item);
item = new PopupMenu.PopupImageMenuItem(_("Lock Screen"), 'system-lock-screen');
item = new PopupMenu.PopupMenuItem(_("Lock Screen"));
item.connect('activate', Lang.bind(this, this._onLockScreenActivate));
this.menu.addMenuItem(item);
item = new PopupMenu.PopupImageMenuItem(_("Switch User"), 'system-users');
item = new PopupMenu.PopupMenuItem(_("Switch User"));
item.connect('activate', Lang.bind(this, this._onLoginScreenActivate));
this.menu.addMenuItem(item);
this._loginScreenItem = item;
item = new PopupMenu.PopupImageMenuItem(_("Log Out..."), 'system-log-out');
item = new PopupMenu.PopupMenuItem(_("Log Out..."));
item.connect('activate', Lang.bind(this, this._onQuitSessionActivate));
this.menu.addMenuItem(item);
item = new PopupMenu.PopupImageMenuItem(_("Shut Down..."), 'system-shutdown');
item = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(item);
item = new PopupMenu.PopupMenuItem(_("Suspend..."));
item.connect('activate', Lang.bind(this, this._onShutDownActivate));
this.menu.addMenuItem(item);
item = new PopupMenu.PopupMenuItem(_("Shut Down..."));
item.connect('activate', Lang.bind(this, this._onShutDownActivate));
this.menu.addMenuItem(item);
},
@ -136,19 +152,19 @@ StatusMenuButton.prototype = {
this._presence.setStatus(status);
},
_onAccountInformationActivate: function() {
_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() {
@ -159,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

@ -1,10 +1,9 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const DBus = imports.dbus;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
@ -18,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;
@ -44,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
@ -213,7 +217,7 @@ ContactManager.prototype = {
throw new Error('Could not parse connection path ' + connPath);
info.cacheDir = this._cacheDir + '/' + match[1];
GLib.mkdir_with_parents(info.cacheDir, 0700);
GLib.mkdir_with_parents(info.cacheDir, 0x1c0); // 0x1c0 = octal 0700
// info.names[handle] is @handle's real name
// info.tokens[handle] is the token for @handle's avatar
@ -349,7 +353,9 @@ ContactManager.prototype = {
let uri = GLib.filename_to_uri(file, null);
iconBox.child = textureCache.load_uri_async(uri, iconBox._size, iconBox._size);
} else {
iconBox.child = textureCache.load_icon_name('stock_person', iconBox._size);
iconBox.child = new St.Icon({ icon_name: 'stock_person',
icon_type: St.IconType.FULLCOLOR,
icon_size: iconBox._size });
}
},
@ -447,7 +453,7 @@ Source.prototype = {
__proto__: MessageTray.Source.prototype,
_init: function(accountPath, connPath, channelPath, targetHandle, targetHandleType, targetId) {
MessageTray.Source.prototype._init.call(this, targetId, targetId);
MessageTray.Source.prototype._init.call(this, targetId);
this._accountPath = accountPath;
@ -469,21 +475,28 @@ 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));
this._setSummaryIcon(this.createNotificationIcon());
},
createIcon: function(size) {
return contactManager.createAvatar(this._conn, this._targetHandle, size);
createNotificationIcon: function() {
return contactManager.createAvatar(this._conn, this._targetHandle,
this.ICON_SIZE);
},
clicked: function() {
_notificationClicked: function(notification) {
channelDispatcher.EnsureChannelRemote(this._accountPath,
{ 'org.freedesktop.Telepathy.Channel.ChannelType': Telepathy.CHANNEL_TEXT_NAME,
'org.freedesktop.Telepathy.Channel.TargetHandle': this._targetHandle,
@ -491,8 +504,6 @@ Source.prototype = {
global.get_current_time(),
'',
Lang.bind(this, this._gotChannelRequest));
MessageTray.Source.prototype.clicked.call(this);
},
_gotChannelRequest: function (chanReqPath, ex) {
@ -516,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._targetId, 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) {
@ -539,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.name);
notify = (this._presence == Telepathy.ConnectionPresenceType.OFFLINE);
msg = _("%s is online.").format(this.title);
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.name);
notify = (this._presence != Telepathy.ConnectionPresenceType.OFFLINE);
msg = _("%s is offline.").format(this.title);
shouldNotify = (this._presence != Telepathy.ConnectionPresenceType.OFFLINE);
} else if (presence == Telepathy.ConnectionPresenceType.AWAY) {
msg = _("%s is away.").format(this.name);
notify = false;
msg = _("%s is away.").format(this.title);
shouldNotify = false;
} else if (presence == Telepathy.ConnectionPresenceType.BUSY) {
msg = _("%s is busy.").format(this.name);
notify = false;
msg = _("%s is busy.").format(this.title);
shouldNotify = false;
} else
return;
@ -563,47 +579,62 @@ 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();
}
};
function Notification(id, source) {
this._init(id, source);
function Notification(source) {
this._init(source);
}
Notification.prototype = {
__proto__: MessageTray.Notification.prototype,
_init: function(id, source) {
MessageTray.Notification.prototype._init.call(this, id, source, source.title);
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
_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('key-focus-in', Lang.bind(this, this._onEntryFocused));
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);
else
this.update(this.source.title, text);
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
@ -612,71 +643,59 @@ 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();
}
}
},
_onButtonPress: function(notification, event) {
if (!this._active)
return false;
_appendTimestamp: function() {
let lastMessageTime = this._history[0].time;
let lastMessageDate = new Date(lastMessageTime * 1000);
let source = event.get_source ();
if (source && notification.contains(source))
return false;
/* 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 });
// @source is outside @notification, which has to mean that
// we have a pointer grab, and the user clicked outside the
// notification, so we should deactivate.
this._deactivate();
return true;
this._timestampTimeoutId = 0;
return false;
},
_onEntryFocused: function() {
if (this._active)
return;
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});
},
if (!Main.pushModal(this.actor))
return;
Clutter.grab_pointer(this.actor);
this._active = true;
Main.messageTray.lock();
grabFocus: function(lockTray) {
// Need to call the base class function first so that
// it saves where the key focus was before.
MessageTray.Notification.prototype.grabFocus.call(this, lockTray);
global.stage.set_key_focus(this._responseEntry.clutter_text);
},
_onEntryActivated: function() {
let text = this._responseEntry.get_text();
if (text == '') {
this._deactivate();
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);
},
_deactivate: function() {
if (this._active) {
Clutter.ungrab_pointer(this.actor);
Main.popModal(this.actor);
global.stage.set_key_focus(null);
// We have to do this after calling popModal(), because
// that will return the keyboard focus to
// this._responseEntry (because that's where it was when
// pushModal() was called), which will cause
// _onEntryFocused() to be called again, but we don't want
// it to do anything.
this._active = false;
Main.messageTray.unlock();
}
}
};

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

@ -1,9 +1,7 @@
/* -*- 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 Meta = imports.gi.Meta;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
@ -16,10 +14,12 @@ function WindowAttentionHandler() {
WindowAttentionHandler.prototype = {
_init : function() {
this._startupIds = {};
this._sources = {};
let display = global.screen.get_display();
display.connect('window-demands-attention', Lang.bind(this, this._onWindowDemandsAttention));
let tracker = Shell.WindowTracker.get_default();
this._startupIds = {};
tracker.connect('startup-sequence-changed', Lang.bind(this, this._onStartupSequenceChanged));
},
@ -31,10 +31,6 @@ WindowAttentionHandler.prototype = {
}
},
_sourceId : function(appId) {
return 'attention-' + appId;
},
_getTitle : function(app, window) {
if (this._startupIds[window.get_startup_id()])
return app.get_name();
@ -63,19 +59,21 @@ WindowAttentionHandler.prototype = {
let tracker = Shell.WindowTracker.get_default();
let app = tracker.get_window_app(window);
let appId = app.get_id();
let source = Main.messageTray.getSource(this._sourceId(app.get_id()));
let source = this._sources[appId];
if (source == null) {
source = new Source(this._sourceId(app.get_id()), app, window);
source = new Source(app, window);
this._sources[appId] = source;
Main.messageTray.add(source);
source.connect('clicked', Lang.bind(this, function() { source.destroy(); }));
source.connect('destroy', Lang.bind(this, function() { delete this._sources[appId]; }));
}
let notification = new MessageTray.Notification(window.get_startup_id(), source, this._getTitle(app, window), this._getBanner(app, window), true);
let notification = new MessageTray.Notification(source, this._getTitle(app, window), this._getBanner(app, window));
source.notify(notification);
window.connect('notify::title', Lang.bind(this, function(win) {
notification.update(this._getTitle(app, win), this._getBanner(app, win), false);
notification.update(this._getTitle(app, win), this._getBanner(app, win));
}));
window.connect('notify::demands-attention', Lang.bind(this, function() { source.destroy(); }));
window.connect('focus', Lang.bind(this, function() { source.destroy(); }));
@ -84,26 +82,26 @@ WindowAttentionHandler.prototype = {
}
};
function Source(sourceId, app, window) {
this._init(sourceId, app, window);
function Source(app, window) {
this._init(app, window);
}
Source.prototype = {
__proto__ : MessageTray.Source.prototype,
_init: function(sourceId, app, window) {
MessageTray.Source.prototype._init.call(this, sourceId, app.get_name());
_init: function(app, window) {
MessageTray.Source.prototype._init.call(this, app.get_name());
this._window = window;
this._app = app;
this._setSummaryIcon(this.createNotificationIcon());
},
createIcon : function(size) {
return this._app.create_icon_texture(size);
createNotificationIcon : function() {
return this._app.create_icon_texture(this.ICON_SIZE);
},
clicked : function() {
_notificationClicked : function(notification) {
Main.activateWindow(this._window);
MessageTray.Source.prototype.clicked.call(this);
this.destroy();
}
};

View File

@ -1,10 +1,10 @@
/* -*- 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 Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const AltTab = imports.ui.altTab;
@ -13,6 +13,68 @@ const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const WINDOW_ANIMATION_TIME = 0.25;
const DIM_TIME = 0.500;
const UNDIM_TIME = 0.250;
var dimShader = undefined;
function getDimShader() {
if (dimShader === null)
return null;
if (!dimShader) {
let [success, source, length] = GLib.file_get_contents(global.datadir +
'/shaders/dim-window.glsl');
try {
let shader = new Clutter.Shader();
shader.set_fragment_source(source, -1);
shader.compile();
dimShader = shader;
} catch (e) {
log(e.message);
dimShader = null;
}
}
return dimShader;
}
function WindowDimmer(actor) {
this._init(actor);
}
WindowDimmer.prototype = {
_init: function(actor) {
this.actor = actor;
},
set dimFraction(fraction) {
this._dimFraction = fraction;
let shader = getDimShader();
if (!Meta.prefs_get_attach_modal_dialogs() || !shader) {
this.actor.set_shader(null);
return;
}
if (fraction > 0.01) {
this.actor.set_shader(shader);
this.actor.set_shader_param_float('height', this.actor.get_height());
this.actor.set_shader_param_float('fraction', fraction);
} else
this.actor.set_shader(null);
},
get dimFraction() {
return this._dimFraction;
},
_dimFraction: 0.0
};
function getWindowDimmer(texture) {
if (!texture._windowDimmer)
texture._windowDimmer = new WindowDimmer(texture);
return texture._windowDimmer;
}
function WindowManager() {
this._init();
@ -29,6 +91,8 @@ WindowManager.prototype = {
this._mapping = [];
this._destroying = [];
this._dimmedWindows = [];
this._switchData = null;
this._shellwm.connect('kill-switch-workspace', Lang.bind(this, this._switchWorkspaceDone));
this._shellwm.connect('kill-window-effects', Lang.bind(this, function (shellwm, actor) {
@ -52,6 +116,15 @@ WindowManager.prototype = {
this.setKeybindingHandler('switch_to_workspace_up', Lang.bind(this, this._showWorkspaceSwitcher));
this.setKeybindingHandler('switch_to_workspace_down', Lang.bind(this, this._showWorkspaceSwitcher));
this.setKeybindingHandler('switch_windows', Lang.bind(this, this._startAppSwitcher));
Main.overview.connect('showing', Lang.bind(this, function() {
for (let i = 0; i < this._dimmedWindows.length; i++)
this._undimParentWindow(this._dimmedWindows[i], true);
}));
Main.overview.connect('hiding', Lang.bind(this, function() {
for (let i = 0; i < this._dimmedWindows.length; i++)
this._dimParentWindow(this._dimmedWindows[i], true);
}));
},
setKeybindingHandler: function(keybinding, handler){
@ -67,7 +140,7 @@ WindowManager.prototype = {
_shouldAnimate : function(actor) {
if (Main.overview.visible)
return false;
if (actor && (actor.get_window_type() != Meta.CompWindowType.NORMAL))
if (actor && (actor.meta_window.get_window_type() != Meta.WindowType.NORMAL))
return false;
return true;
},
@ -149,7 +222,108 @@ WindowManager.prototype = {
_unmaximizeWindowDone : function(shellwm, actor) {
},
_parentHasOtherAttachedDialog: function(parent, self) {
var count = 0;
parent.foreach_transient(function(win) {
if (win.get_window_type() == Meta.WindowType.MODAL_DIALOG && win != self)
count++;
return false;
});
return count != 0;
},
_markParentWindowAsDimmable: function(actor, animate) {
if (Meta.prefs_get_attach_modal_dialogs()) {
this._dimmedWindows.push(actor);
if (this._shouldAnimate())
this._dimParentWindow(actor, animate);
}
},
_unmarkParentWindowAsDimmable: function(actor, animate) {
if (!Main.overview.visible)
this._undimParentWindow(actor, true);
this._dimmedWindows = this._dimmedWindows.filter(function(win) {
return win != actor;
});
},
_dimParentWindow: function(actor, animate) {
let meta = actor.get_meta_window();
let parent = meta.get_transient_for();
if (!parent)
return;
let parentActor = parent.get_compositor_private();
if (!parentActor || this._parentHasOtherAttachedDialog(parent, meta))
return;
let texture = parentActor.get_texture();
if (animate)
Tweener.addTween(getWindowDimmer(texture),
{ dimFraction: 1.0,
time: DIM_TIME,
transition: 'linear'
});
else
getWindowDimmer(texture).dimFraction = 1.0;
},
_undimParentWindow: function(actor, animate) {
let meta = actor.get_meta_window();
let parent = meta.get_transient_for();
if (!parent)
return;
let parentActor = parent.get_compositor_private();
if (!parentActor || this._parentHasOtherAttachedDialog(parent, meta))
return;
let texture = parentActor.get_texture();
if (animate)
Tweener.addTween(getWindowDimmer(texture),
{ dimFraction: 0.0,
time: UNDIM_TIME,
transition: 'linear'
});
else
getWindowDimmer(texture).dimFraction = 0.0;
},
_mapWindow : function(shellwm, actor) {
actor._windowType = actor.meta_window.get_window_type();
actor._notifyWindowTypeSignalId = actor.meta_window.connect('notify::window-type', Lang.bind(this, function () {
let type = actor.meta_window.get_window_type();
if (type == actor._windowType)
return;
if (type == Meta.WindowType.MODAL_DIALOG)
this._markParentWindowAsDimmable(actor, true);
else if (actor._windowType == Meta.WindowType.MODAL_DIALOG)
this._unmarkParentWindowAsDimmable(actor, true);
actor._windowType = type;
}));
if (actor.meta_window.get_window_type() == Meta.WindowType.MODAL_DIALOG
&& Meta.prefs_get_attach_modal_dialogs()
&& actor.get_meta_window().get_transient_for()) {
this._markParentWindowAsDimmable(actor, true);
if (this._shouldAnimate()) {
actor.set_scale(1.0, 0.0);
actor.show();
this._mapping.push(actor);
Tweener.addTween(actor,
{ scale_y: 1,
time: WINDOW_ANIMATION_TIME,
transition: "easeOutQuad",
onComplete: this._mapWindowDone,
onCompleteScope: this,
onCompleteParams: [shellwm, actor],
onOverwrite: this._mapWindowOverwrite,
onOverwriteScope: this,
onOverwriteParams: [shellwm, actor]
});
return;
}
shellwm.completed_map(actor);
return;
}
if (!this._shouldAnimate(actor)) {
shellwm.completed_map(actor);
return;
@ -188,10 +362,51 @@ WindowManager.prototype = {
},
_destroyWindow : function(shellwm, actor) {
let parent = actor.meta_window.get_transient_for();
if (actor._notifyWindowTypeSignalId) {
actor.meta_window.disconnect(actor._notifyWindowTypeSignalId);
actor._notifyWindowTypeSignalId = 0;
}
while (actor.meta_window.get_window_type() == Meta.WindowType.MODAL_DIALOG
&& parent) {
this._unmarkParentWindowAsDimmable(actor, true);
if (!Meta.prefs_get_attach_modal_dialogs()
|| !this._shouldAnimate())
break;
actor.set_scale(1.0, 1.0);
actor.show();
this._destroying.push(actor);
actor._parentDestroyId = parent.connect('unmanaged', Lang.bind(this, function () {
Tweener.removeTweens(actor);
this._destroyWindowDone(shellwm, actor);
}));
Tweener.addTween(actor,
{ scale_y: 0,
time: WINDOW_ANIMATION_TIME,
transition: "easeOutQuad",
onComplete: this._destroyWindowDone,
onCompleteScope: this,
onCompleteParams: [shellwm, actor],
onOverwrite: this._destroyWindowDone,
onOverwriteScope: this,
onOverwriteParams: [shellwm, actor]
});
return;
}
shellwm.completed_destroy(actor);
},
_destroyWindowDone : function(shellwm, actor) {
if (this._removeEffect(this._destroying, actor)) {
let parent = actor.get_meta_window().get_transient_for();
if (parent && actor._parentDestroyId) {
parent.disconnect(actor._parentDestroyId);
actor._parentDestroyId = 0;
}
shellwm.completed_destroy(actor);
}
},
_switchWorkspace : function(shellwm, from, to, direction) {
@ -200,7 +415,7 @@ WindowManager.prototype = {
return;
}
let windows = global.get_windows();
let windows = global.get_window_actors();
/* @direction is the direction that the "camera" moves, so the
* screen contents have to move one screen's worth in the
@ -282,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();
@ -328,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

@ -1,9 +1,6 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const GdkPixbuf = imports.gi.GdkPixbuf;
const Gdk = imports.gi.Gdk;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
@ -23,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;
@ -57,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;
@ -143,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 () {
@ -250,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();
@ -286,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: Main.background.source });
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
@ -464,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;
@ -537,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;
},
@ -556,23 +486,14 @@ WindowOverlay.prototype = {
_onStyleChanged: function() {
let titleNode = this.title.get_theme_node();
let [success, len] = titleNode.get_length('-shell-caption-spacing',
false);
if (success)
this.title._spacing = len;
this.title._spacing = titleNode.get_length('-shell-caption-spacing');
let closeNode = this.closeButton.get_theme_node();
[success, len] = closeNode.get_length('-shell-close-overlap',
false);
if (success)
this.closeButton._overlap = len;
this.closeButton._overlap = closeNode.get_length('-shell-close-overlap');
this._parentActor.queue_relayout();
}
};
Signals.addSignalMethods(WindowOverlay.prototype);
const WindowPositionFlags = {
@ -613,37 +534,12 @@ Workspace.prototype = {
this.actor.height = global.screen_height;
this.scale = 1.0;
let windows = global.get_windows().filter(this._isMyWindow, this);
// Find the desktop window
for (let i = 0; i < windows.length; i++) {
if (windows[i].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);
let windows = global.get_window_actors().filter(this._isMyWindow, this);
// 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]);
@ -660,10 +556,6 @@ Workspace.prototype = {
Lang.bind(this, this._windowRemoved));
this._repositionWindowsId = 0;
this._visible = false;
this._frame = null;
this.leavingOverview = false;
},
@ -703,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();
@ -725,9 +621,6 @@ Workspace.prototype = {
this._lightbox.show();
else
this._lightbox.hide();
if (this._frame)
this._frame.set_opacity(showLightbox ? 150 : 255);
},
/**
@ -748,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
@ -781,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) {
@ -799,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.
@ -807,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))
@ -819,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];
@ -1013,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;
@ -1081,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];
@ -1097,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
@ -1127,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()]; });
@ -1148,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);
@ -1156,7 +1016,7 @@ Workspace.prototype = {
}
},
_fadeInWindowOverlay: function(clone, overlay) {
_showWindowOverlay: function(clone, overlay, fade) {
if (clone.inDrag)
return;
@ -1168,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;
@ -1178,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();
}
@ -1208,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
@ -1224,7 +1088,7 @@ Workspace.prototype = {
showWindowsOverlays: function() {
this._windowOverlaysGroup.show();
this._fadeInAllOverlays();
this._showAllOverlays();
},
hideWindowsOverlays: function() {
@ -1320,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 &&
@ -1333,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.
@ -1341,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();
@ -1364,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();
@ -1394,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() {
@ -1486,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 = [];
},
@ -1517,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',
@ -1533,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);
@ -1545,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;
@ -1589,6 +1385,15 @@ Workspace.prototype = {
},
// Draggable target interface
handleDragOver : function(source, actor, x, y, time) {
if (source instanceof WindowClone)
return DND.DragMotionResult.MOVE_DROP;
if (source.shellWorkspaceLaunch)
return DND.DragMotionResult.COPY_DROP;
return DND.DragMotionResult.CONTINUE;
},
acceptDrop : function(source, actor, x, y, time) {
if (source instanceof WindowClone) {
let win = source.realWindow;
@ -1645,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

@ -33,8 +33,7 @@ WorkspaceSwitcherPopup.prototype = {
this._list = new Shell.GenericContainer({ style_class: 'workspace-switcher' });
this._itemSpacing = 0;
this._list.connect('style-changed', Lang.bind(this, function() {
let [found, spacing] = this._list.get_theme_node().get_length('spacing', false);
this._itemSpacing = (found) ? spacing : 0;
this._itemSpacing = this._list.get_theme_node().get_length('spacing');
}));
this._list.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
@ -90,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++) {
@ -99,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

@ -7,6 +7,8 @@ de
el
en_GB
es
et
fa
fi
fr
ga
@ -15,12 +17,15 @@ he
hu
id
it
ja
ko
lt
nb
nl
nn
pa
pl
pt
pt_BR
ro
ru
@ -28,8 +33,12 @@ sl
sr
sr@latin
sv
ta
th
tr
ug
uk
vi
zh_CN
zh_HK
zh_TW

View File

@ -1,19 +1,32 @@
data/gnome-shell.desktop.in.in
data/gnome-shell-clock-preferences.desktop.in.in
data/org.gnome.shell.gschema.xml.in
[type: gettext/glade]data/clock-preferences.ui
data/org.gnome.accessibility.magnifier.gschema.xml.in
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
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

919
po/ar.po

File diff suppressed because it is too large Load Diff

413
po/bg.po
View File

@ -7,10 +7,11 @@ msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-18 13:09+0200\n"
"PO-Revision-Date: 2010-03-18 11:30+0200\n"
"POT-Creation-Date: 2010-07-25 18:40+0300\n"
"PO-Revision-Date: 2010-07-25 18:35+0300\n"
"Last-Translator: Ivaylo Valkov <ivaylo@e-valkov.org>\n"
"Language-Team: Bulgarian <dict@fsa-bg.org>\n"
"Language: bg\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@ -24,32 +25,260 @@ msgstr "Обвивка на GNOME"
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 ""
"Разширенията на Обвивката на 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“."
#: ../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 ""
"Списък на идентификаторите на файловете във формат .desktop за любими "
"програми"
#: ../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 ""
"Задава конвейера на GStreamer, който ще се използва за кодиране на записите. "
"Използвайте синтаксиса на gst-launch. Конвейерът трябва да бъде с несвързан "
"блок-приемник, където се записва видеото. Обикновено конвейерът е с "
"несвързан блок-източник. Изходът от този блок ще бъде записан в изходния "
"файл. Въпреки това конвейерът може да задава собствен изход — това може да "
"се използва за изпращане на изхода към icecast сървър чрез „shout2send“ или "
"подобен елемент. Когато този ключ не е зададен или стойността му e празна, "
"се използва стандартния конвейер. За момента това е „videorate ! theoraenc ! "
"oggmux“ и записва видео във формат Ogg Theora."
#: ../data/org.gnome.shell.gschema.xml.in.h:15
msgid "Show date in clock"
msgstr "Показване на дата в часовника"
#: ../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 ""
"Честота на кадрите за записа на екрана създаден от записващата програма на "
"Обвивката на GNOME в кадри за секунда."
#: ../data/org.gnome.shell.gschema.xml.in.h:21
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
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_data и 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/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 "12-_часов формат"
#: ../data/clock-preferences.ui.h:7
msgid "_24 hour format"
msgstr "24-ч_асов формат"
#. **** Applications ****
#: ../js/ui/appDisplay.js:311 ../js/ui/dash.js:852
#: ../js/ui/appDisplay.js:384 ../js/ui/dash.js:773
msgid "APPLICATIONS"
msgstr "ПРОГРАМИ"
#: ../js/ui/appDisplay.js:343
#: ../js/ui/appDisplay.js:416
msgid "PREFERENCES"
msgstr "ПРЕДПОЧИТАНИЯ"
#: ../js/ui/appDisplay.js:728
#: ../js/ui/appDisplay.js:721
msgid "New Window"
msgstr "Нов прозорец"
#: ../js/ui/appDisplay.js:732
#: ../js/ui/appDisplay.js:725
msgid "Remove from Favorites"
msgstr "Премахване от „Любими“"
#: ../js/ui/appDisplay.js:733
#: ../js/ui/appDisplay.js:726
msgid "Add to Favorites"
msgstr "Добавяне в „Любими“"
#: ../js/ui/appDisplay.js:1085
#: ../js/ui/appDisplay.js:1033
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“ беше добавена в „Любими“"
@ -59,179 +288,235 @@ msgstr "Програмата „%s“ беше добавена в „Любим
msgid "%s has been removed from your favorites."
msgstr "Програмата „%s“ беше премахната от „Любими“"
#: ../js/ui/dash.js:194
#: ../js/ui/dash.js:142
msgid "Find"
msgstr "Търсене"
#: ../js/ui/dash.js:507
#: ../js/ui/dash.js:471
msgid "Searching..."
msgstr "Търсене…"
#: ../js/ui/dash.js:521
#: ../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:871 ../js/ui/placeDisplay.js:536
#: ../js/ui/dash.js:792 ../js/ui/placeDisplay.js:550
msgid "PLACES & DEVICES"
msgstr "МЕСТА И УСТРОЙСТВА"
#. **** Documents ****
#: ../js/ui/dash.js:878 ../js/ui/docDisplay.js:488
#: ../js/ui/dash.js:799 ../js/ui/docDisplay.js:494
msgid "RECENT ITEMS"
msgstr "СКОРО ОТВАРЯНИ"
#: ../js/ui/lookingGlass.js:363
#: ../js/ui/lookingGlass.js:471
msgid "No extensions installed"
msgstr "Няма инсталирани разширения"
#: ../js/ui/lookingGlass.js:400
#: ../js/ui/lookingGlass.js:508
msgid "Enabled"
msgstr "Включено"
#: ../js/ui/lookingGlass.js:402
#: ../js/ui/lookingGlass.js:510
msgid "Disabled"
msgstr "Изключено"
#: ../js/ui/lookingGlass.js:404
#: ../js/ui/lookingGlass.js:512
msgid "Error"
msgstr "Грешка"
#: ../js/ui/lookingGlass.js:406
#: ../js/ui/lookingGlass.js:514
msgid "Out of date"
msgstr "Остаряло"
#: ../js/ui/lookingGlass.js:431
#: ../js/ui/lookingGlass.js:539
msgid "View Source"
msgstr "Преглед на програмния код"
#: ../js/ui/lookingGlass.js:437
#: ../js/ui/lookingGlass.js:545
msgid "Web Page"
msgstr "Домашна страница"
#: ../js/ui/overview.js:182
#: ../js/ui/overview.js:159
msgid "Undo"
msgstr "Отмяна"
#. 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:385
msgid "Activities"
msgstr "Дейности"
#. TODO - _quit() doesn't really work on apps in state STARTING yet
#: ../js/ui/panel.js:473
#, c-format
msgid "Quit %s"
msgstr "Спиране на програмата „%s“"
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:616
#: ../js/ui/panel.js:498
msgid "Preferences"
msgstr "Настройки"
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:584
msgid "%a %b %e, %R:%S"
msgstr "%a, %e %b, %R:%S"
#: ../js/ui/panel.js:585
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:589
msgid "%a %R:%S"
msgstr "%a, %R:%S"
#: ../js/ui/panel.js:590
msgid "%a %R"
msgstr "%a, %R"
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:619
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:597
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a, %e %b, %l:%M:%S %p"
#: ../js/ui/panel.js:598
msgid "%a %b %e, %l:%M %p"
msgstr "%a, %e %b, %l:%M %p"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:602
msgid "%a %l:%M:%S %p"
msgstr "%a %l:%M:%S %p"
#: ../js/ui/panel.js:603
msgid "%a %l:%M %p"
msgstr "%a, %H:%M"
#: ../js/ui/placeDisplay.js:103
#. 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
msgid "Activities"
msgstr "Дейности"
#: ../js/ui/placeDisplay.js:107
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Неуспех при демонтиране на „%s“"
#: ../js/ui/placeDisplay.js:106
#: ../js/ui/placeDisplay.js:110
msgid "Retry"
msgstr "Повторен опит"
#: ../js/ui/placeDisplay.js:151
#: ../js/ui/placeDisplay.js:155
msgid "Connect to..."
msgstr "Свързване към…"
#: ../js/ui/runDialog.js:221
#. 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/popupMenu.js:31 ../js/ui/popupMenu.js:45
msgid "OFF"
msgstr "ИЗКЛ"
#: ../js/ui/runDialog.js:233
msgid "Please enter a command:"
msgstr "Въведете команда:"
#: ../js/ui/runDialog.js:344
#: ../js/ui/runDialog.js:378
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Неуспешно изпълнение на „%s“:"
#: ../js/ui/statusMenu.js:107
#: ../js/ui/statusMenu.js:91
msgid "Available"
msgstr "Налично"
#: ../js/ui/statusMenu.js:112
#: ../js/ui/statusMenu.js:95
msgid "Busy"
msgstr "Заето"
#: ../js/ui/statusMenu.js:117
#: ../js/ui/statusMenu.js:99
msgid "Invisible"
msgstr "Невидимо"
#: ../js/ui/statusMenu.js:126
#: ../js/ui/statusMenu.js:106
msgid "Account Information..."
msgstr "Информация за настройките на потребителя…"
#: ../js/ui/statusMenu.js:132
msgid "Sidebar"
msgstr "Странична лента"
#: ../js/ui/statusMenu.js:142
#: ../js/ui/statusMenu.js:110
msgid "System Preferences..."
msgstr "Системни настройки…"
#: ../js/ui/statusMenu.js:151
#: ../js/ui/statusMenu.js:117
msgid "Lock Screen"
msgstr "Заключване на екрана"
#: ../js/ui/statusMenu.js:156
#: ../js/ui/statusMenu.js:121
msgid "Switch User"
msgstr "Смяна на потребител"
#: ../js/ui/statusMenu.js:162
#: ../js/ui/statusMenu.js:126
msgid "Log Out..."
msgstr "Изход…"
#: ../js/ui/statusMenu.js:167
#: ../js/ui/statusMenu.js:130
msgid "Shut Down..."
msgstr "Изключване на компютъра…"
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%H:%M"
#: ../js/ui/windowAttentionHandler.js:45
#, c-format
msgid "%s has finished starting"
msgstr "Програмата „%s“ стартира успешно"
#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "Програми"
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "'%s' is ready"
msgstr "Програмата „%s“ е готова за употреба"
#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "Скоро отваряни документи"
#: ../js/ui/workspacesView.js:230
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
msgstr ""
"Неуспех при добавяне на нов работен плот. Достигнат е максималният брой на "
"възможните работни плотове."
#: ../src/shell-global.c:967
#: ../js/ui/workspacesView.js:247
msgid "Can't remove the first workspace."
msgstr "Премахването на първия работен плот не е възможно."
#: ../src/shell-global.c:1105
msgid "Less than a minute ago"
msgstr "Преди по-малко от минута"
#: ../src/shell-global.c:971
#: ../src/shell-global.c:1109
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "преди %d минута"
msgstr[1] "преди %d минути"
#: ../src/shell-global.c:976
#: ../src/shell-global.c:1114
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "преди %d час"
msgstr[1] "преди %d часа"
#: ../src/shell-global.c:981
#: ../src/shell-global.c:1119
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "преди %d ден"
msgstr[1] "преди %d дни"
#: ../src/shell-global.c:986
#: ../src/shell-global.c:1124
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"

655
po/cs.po
View File

@ -7,15 +7,16 @@ msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-29 00:49+0200\n"
"PO-Revision-Date: 2010-03-29 00:49+0200\n"
"POT-Creation-Date: 2010-10-31 12:09+0100\n"
"PO-Revision-Date: 2010-10-31 12:09+0100\n"
"Last-Translator: Petr Kovar <pknbe@volny.cz>\n"
"Language-Team: Czech <gnome-cs-list@gnome.org>\n"
"Language: cs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"X-Generator: Lokalize 1.0\n"
"X-Generator: Lokalize 1.1\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
@ -25,32 +26,380 @@ msgstr "Prostředí GNOME Shell"
msgid "Window management and application launching"
msgstr "Správa oken a spouštění aplikací"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:1
msgid "Clock"
msgstr "Hodiny"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:2
msgid "Customize the panel clock"
msgstr "Přizpůsobit hodiny na panelu"
#: ../data/org.gnome.shell.gschema.xml.in.h:1
msgid ""
"Allows access to internal debugging and monitoring tools using the Alt-F2 "
"dialog."
msgstr ""
"Poskytuje přístup k vnitřním ladicím a monitorovacím nástrojům pomocí okna "
"ovládaného přes Alt-F2."
#: ../data/org.gnome.shell.gschema.xml.in.h:2
msgid "Custom format of the clock"
msgstr "Vlastní formát hodin"
#: ../data/org.gnome.shell.gschema.xml.in.h:3
msgid "Enable internal tools useful for developers and testers from Alt-F2"
msgstr "Povolit přes Alt-F2 vnitřní nástroje určené pro vývojáře a testery"
#: ../data/org.gnome.shell.gschema.xml.in.h:4
msgid "File extension used for storing the screencast"
msgstr "Přípona souboru s nahrávkou dění na obrazovce"
#: ../data/org.gnome.shell.gschema.xml.in.h:5
msgid "Framerate used for recording screencasts."
msgstr "Frekvence snímků při nahrávání dění na obrazovce."
#: ../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 ""
"Rozšíření GNOME Shell mají vlastnost uuid; tento klíč uvádí rozšíření, která "
"by neměla být načítána."
#: ../data/org.gnome.shell.gschema.xml.in.h:7
msgid "History for command (Alt-F2) dialog"
msgstr "Historie příkazového dialogového okna (Alt-F2)"
#: ../data/org.gnome.shell.gschema.xml.in.h:8
msgid "Hour format"
msgstr "Formát hodin"
#: ../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 ""
"Je-li \"true\" a formát je buď \"12-hour\" nebo \"24-hour\", zobrazovat v "
"hodinách kromě času i datum."
#: ../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 ""
"Je-li \"true\" a formát je buď \"12-hour\" nebo \"24-hour\", zobrazovat čas "
"včetně sekund."
#: ../data/org.gnome.shell.gschema.xml.in.h:11
msgid "If true, display the ISO week date in the calendar."
msgstr "Je-li \"true\", zobrazovat v kalendáři čísla týdnů dle ISO."
#: ../data/org.gnome.shell.gschema.xml.in.h:12
msgid "List of desktop file IDs for favorite applications"
msgstr "Seznam ID souboru desktop oblíbených aplikací"
#: ../data/org.gnome.shell.gschema.xml.in.h:13
msgid "Overview workspace view mode"
msgstr "Režim přehledu pracovních ploch"
#: ../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 ""
"Nastavuje rouru systému GStreamer určenou ke kódování nahrávek. Respektuje "
"syntax gst-launch. Roura by měla mít nepřipojený cíl, ve kterém se video "
"nahrává. Obvykle má nepřipojený zdroj; výstup z takového zdroje bude "
"zapisován do výstupního souboru. Roura je ale schopna zabezpečit i vlastní "
"výstup, což lze využít při odeslání výstupu na server icecast přes "
"shout2send apod. Není-li nastaveno nebo je-li nastaveno na prázdnou hodnotu, "
"bude použita výchozí roura. Aktuálně to je 'videorate ! theoraenc ! oggmux' "
"s nahráváním do Ogg Theora."
#: ../data/org.gnome.shell.gschema.xml.in.h:15
msgid "Show date in clock"
msgstr "Zobrazovat v hodinách datum"
#: ../data/org.gnome.shell.gschema.xml.in.h:16
msgid "Show the week date in the calendar"
msgstr "Zobrazovat v kalendáři čísla týdnů"
#: ../data/org.gnome.shell.gschema.xml.in.h:17
msgid "Show time with seconds"
msgstr "Zobrazovat čas včetně sekund"
#: ../data/org.gnome.shell.gschema.xml.in.h:18
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
msgstr ""
"Aplikace odpovídající těmto identifikátorům budou zobrazeny oblasti "
"oblíbených."
#: ../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 ""
"Název souboru nahraných dění na obrazovce se bude sestávat z jedinečného "
"názvu vycházejícího z aktuálního data a bude používat tuto příponu. Při "
"nahrávání do jiného formátu kontejneru by měla být provedena úprava pravidel."
#: ../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 ""
"Frekvence snímků za sekundu výsledné nahrávky dění na obrazovce, která byla "
"nahrána záznamovým programem GNOME Shell."
#: ../data/org.gnome.shell.gschema.xml.in.h:21
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "Roura systému gstreamer určená ke kódování nahrávky dění na obrazovce"
#: ../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 ""
"Vybraný režim zobrazení pracovních ploch v přehledu. Podporované hodnoty "
"jsou \"single\" a \"grid\"."
#: ../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 ""
"Program GNOME Shell obvykle sleduje aktivní aplikace, aby mohl nabídnout ty "
"nejpoužívanější (např. ve spouštěčích). Data budou uchovávána v soukromí, "
"přesto ale můžete z důvodu ochrany soukromí tuto funkci zakázat. Vezměte "
"prosím v potaz skutečnost, že zakázaní funkce neodstraní již uložená data."
#: ../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 ""
"Tento klíč určuje formát používaný hodinami na panelu, když je klíč format "
"nastaven na \"custom\". K získání konkrétního formátu můžete použít "
"specifikátory převodu, kterým rozumí strftime(). Více informací viz manuál k "
"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 ""
"Tento klíč určuje formát používaný hodinami na panelu. Možné hodnoty jsou "
"\"12-hour\", \"24-hour\", \"unix\" a \"custom\". Je-li nastaven na \"unix\", "
"hodiny budou zobrazovat čas v sekundách od počátku epochy, tj. 1970-01-01. "
"Je-li nastaven na \"custom\", hodiny budou zobrazovat čas s ohledem na "
"formát určený klíčem custom_format key. Je-li klíč nastaven buď na \"unix\" "
"nebo \"custom\", budou ignorovány klíče show_date a show_seconds."
#: ../data/org.gnome.shell.gschema.xml.in.h:26
msgid "Uuids of extensions to disable"
msgstr "Uuid rozšíření určených k vypnutí"
#: ../data/org.gnome.shell.gschema.xml.in.h:27
msgid "Whether to collect stats about applications usage"
msgstr "Zda sbírat statistická data o používání aplikací"
#: ../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
#, fuzzy
msgid "Enable lens mode"
msgstr "Povoleno"
#: ../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 "Formát hodin"
#: ../data/clock-preferences.ui.h:2
msgid "Clock Preferences"
msgstr "Předvolby hodin"
#: ../data/clock-preferences.ui.h:3
msgid "Panel Display"
msgstr "Zobrazení panelu"
#: ../data/clock-preferences.ui.h:4
msgid "Show seco_nds"
msgstr "Zobrazit seku_ndy"
#: ../data/clock-preferences.ui.h:5
msgid "Show the _date"
msgstr "Zobrazit _datum"
#: ../data/clock-preferences.ui.h:6
msgid "_12 hour format"
msgstr "_12hodinový formát"
#: ../data/clock-preferences.ui.h:7
msgid "_24 hour format"
msgstr "_24hodinový formát"
#. **** Applications ****
#: ../js/ui/appDisplay.js:312 ../js/ui/dash.js:855
#: ../js/ui/appDisplay.js:316 ../js/ui/dash.js:778
msgid "APPLICATIONS"
msgstr "APLIKACE"
#: ../js/ui/appDisplay.js:344
#: ../js/ui/appDisplay.js:348
msgid "PREFERENCES"
msgstr "PŘEDVOLBY"
#: ../js/ui/appDisplay.js:756
#: ../js/ui/appDisplay.js:647
msgid "New Window"
msgstr "Nové okno"
#: ../js/ui/appDisplay.js:760
#: ../js/ui/appDisplay.js:651
msgid "Remove from Favorites"
msgstr "Odstranit z oblíbených"
#: ../js/ui/appDisplay.js:761
#: ../js/ui/appDisplay.js:652
msgid "Add to Favorites"
msgstr "Přidat mezi oblíbené"
#: ../js/ui/appDisplay.js:1113
#: ../js/ui/appDisplay.js:829
msgid "Drag here to add favorites"
msgstr "Oblíbené přidáte přetažením sem"
#: ../js/ui/appFavorites.js:89
#: ../js/ui/appFavorites.js:88
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s byl přidán mezi oblíbené."
@ -60,170 +409,297 @@ msgstr "%s byl přidán mezi oblíbené."
msgid "%s has been removed from your favorites."
msgstr "%s byl odstraněn z oblíbených."
#: ../js/ui/dash.js:194
#: ../js/ui/dash.js:142
msgid "Find"
msgstr "Najít"
#: ../js/ui/dash.js:510
#: ../js/ui/dash.js:473
msgid "Searching..."
msgstr "Hledá se..."
#: ../js/ui/dash.js:524
#: ../js/ui/dash.js:487
msgid "No matching results."
msgstr "Neodpovídá ani jeden z výsledků."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:874 ../js/ui/placeDisplay.js:582
#: ../js/ui/dash.js:797 ../js/ui/placeDisplay.js:554
msgid "PLACES & DEVICES"
msgstr "MÍSTA A ZAŘÍZENÍ"
#. **** Documents ****
#: ../js/ui/dash.js:881 ../js/ui/docDisplay.js:488
#: ../js/ui/dash.js:804 ../js/ui/docDisplay.js:494
msgid "RECENT ITEMS"
msgstr "NEDÁVNÉ POLOŽKY"
#: ../js/ui/lookingGlass.js:363
#: ../js/ui/lookingGlass.js:552
msgid "No extensions installed"
msgstr "Nejsou nainstalována žádná rozšíření"
#: ../js/ui/lookingGlass.js:400
#: ../js/ui/lookingGlass.js:589
msgid "Enabled"
msgstr "Povoleno"
#: ../js/ui/lookingGlass.js:402
#. translators:
#. * The device has been disabled
#: ../js/ui/lookingGlass.js:591 ../src/gvc/gvc-mixer-control.c:1087
msgid "Disabled"
msgstr "Zakázáno"
#: ../js/ui/lookingGlass.js:404
#: ../js/ui/lookingGlass.js:593
msgid "Error"
msgstr "Chyba"
#: ../js/ui/lookingGlass.js:406
#: ../js/ui/lookingGlass.js:595
msgid "Out of date"
msgstr "Neaktuální"
#: ../js/ui/lookingGlass.js:431
#: ../js/ui/lookingGlass.js:620
msgid "View Source"
msgstr "Zobrazit zdroj"
#: ../js/ui/lookingGlass.js:437
#: ../js/ui/lookingGlass.js:626
msgid "Web Page"
msgstr "Webová stránka"
#: ../js/ui/overview.js:182
#: ../js/ui/overview.js:160
msgid "Undo"
msgstr "Zpět"
#. 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:385
msgid "Activities"
msgstr "Činnosti"
#. TODO - _quit() doesn't really work on apps in state STARTING yet
#: ../js/ui/panel.js:469
#, c-format
msgid "Quit %s"
msgstr "Ukončit %s"
#: ../js/ui/panel.js:494
msgid "Preferences"
msgstr "Předvolby"
# Not sure whether we've enough space for it, but anyway, looks more aesthetically with "%A".
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:616
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:580
msgid "%a %b %e, %R:%S"
msgstr "%A, %e. %B, %R:%S"
# Not sure whether we've enough space for it, but anyway, looks more aesthetically with "%A".
#: ../js/ui/panel.js:581
msgid "%a %b %e, %R"
msgstr "%A, %e. %B, %R"
# Not sure whether we've enough space for it, but anyway, looks more aesthetically with "%A".
#. Translators: This is the time format without date used
#. in 24-hour mode.
#: ../js/ui/panel.js:585
msgid "%a %R:%S"
msgstr "%A, %R:%S"
# Not sure whether we've enough space for it, but anyway, looks more aesthetically with "%A".
#: ../js/ui/panel.js:586
msgid "%a %R"
msgstr "%A, %R"
# Not sure whether we've enough space for it, but anyway, looks more aesthetically with "%A".
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:619
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:593
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%A, %e. %B, %l:%M:%S %p"
# Not sure whether we've enough space for it, but anyway, looks more aesthetically with "%A".
#: ../js/ui/panel.js:594
msgid "%a %b %e, %l:%M %p"
msgstr "%A, %e. %B, %l:%M %p"
# Not sure whether we've enough space for it, but anyway, looks more aesthetically with "%A".
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:598
msgid "%a %l:%M:%S %p"
msgstr "%A, %l:%M:%S %p"
# Not sure whether we've enough space for it, but anyway, looks more aesthetically with "%A".
#: ../js/ui/panel.js:599
msgid "%a %l:%M %p"
msgstr "%A, %l:%M %p"
#: ../js/ui/placeDisplay.js:108
#. 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
msgid "Activities"
msgstr "Činnosti"
#: ../js/ui/placeDisplay.js:111
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Nelze odpojit \"%s\""
#: ../js/ui/placeDisplay.js:111
#: ../js/ui/placeDisplay.js:114
msgid "Retry"
msgstr "Opakovat"
#: ../js/ui/placeDisplay.js:156
#: ../js/ui/placeDisplay.js:159
msgid "Connect to..."
msgstr "Připojit se k..."
#: ../js/ui/runDialog.js:232
#. 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 "Zadejte prosím příkaz:"
#: ../js/ui/runDialog.js:376
#: ../js/ui/runDialog.js:378
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Vykonání \"%s\" selhalo:"
#: ../js/ui/statusMenu.js:107
#: ../js/ui/statusMenu.js:101
msgid "Available"
msgstr "Přítomen"
#: ../js/ui/statusMenu.js:112
#: ../js/ui/statusMenu.js:106
msgid "Busy"
msgstr "Zaneprázdněn"
#: ../js/ui/statusMenu.js:117
#: ../js/ui/statusMenu.js:111
msgid "Invisible"
msgstr "Neviditelný"
#: ../js/ui/statusMenu.js:126
msgid "Account Information..."
msgstr "Informace o účtu..."
#: ../js/ui/statusMenu.js:119
msgid "My Account..."
msgstr "Můj účet..."
#: ../js/ui/statusMenu.js:132
msgid "Sidebar"
msgstr "Postranní lišta"
#: ../js/ui/statusMenu.js:123
msgid "System Settings..."
msgstr "Nastavení systému..."
#: ../js/ui/statusMenu.js:142
msgid "System Preferences..."
msgstr "Předvolby systému..."
#: ../js/ui/statusMenu.js:151
#: ../js/ui/statusMenu.js:130
msgid "Lock Screen"
msgstr "Uzamknout obrazovku"
#: ../js/ui/statusMenu.js:156
#: ../js/ui/statusMenu.js:134
msgid "Switch User"
msgstr "Přepnout uživatele"
#: ../js/ui/statusMenu.js:162
#: ../js/ui/statusMenu.js:139
msgid "Log Out..."
msgstr "Odhlásit..."
#: ../js/ui/statusMenu.js:167
#: ../js/ui/statusMenu.js:146
msgid "Suspend"
msgstr "Uspat do paměti"
#: ../js/ui/statusMenu.js:150
msgid "Restart..."
msgstr "Restartovat..."
#: ../js/ui/statusMenu.js:154
msgid "Shut Down..."
msgstr "Vypnout..."
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%H:%M"
#: ../js/ui/status/accessibility.js:88
msgid "Screen Reader"
msgstr "Čtení obrazovky"
#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "Aplikace"
#: ../js/ui/status/accessibility.js:91
msgid "Screen Keyboard"
msgstr "Klávesnice na obrazovce"
#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "Nedávné dokumenty"
#: ../js/ui/status/accessibility.js:94
msgid "Visual Alerts"
msgstr "Vizuální upozornění"
#: ../js/ui/windowAttentionHandler.js:47
#: ../js/ui/status/accessibility.js:97
msgid "Sticky Keys"
msgstr "Lepící klávesy"
#: ../js/ui/status/accessibility.js:100
msgid "Slow Keys"
msgstr "Pomalé klávesy"
#: ../js/ui/status/accessibility.js:103
msgid "Bounce Keys"
msgstr "Vícenásobné stisky kláves"
#: ../js/ui/status/accessibility.js:106
msgid "Mouse Keys"
msgstr "Myš klávesnicí"
#: ../js/ui/status/accessibility.js:110
msgid "Universal Access Settings"
msgstr "Nastavení zpřístupnění"
#: ../js/ui/status/accessibility.js:163
msgid "High Contrast"
msgstr "Vysoký kontrast"
#: ../js/ui/status/accessibility.js:202
msgid "Large Text"
msgstr "Styl velkého textu"
#: ../js/ui/status/accessibility.js:223
msgid "Zoom"
msgstr "Zvětšení"
#: ../js/ui/windowAttentionHandler.js:43
#, c-format
msgid "%s has finished starting"
msgstr "Spouštění %s dokončeno"
#: ../js/ui/windowAttentionHandler.js:49
#: ../js/ui/windowAttentionHandler.js:45
#, c-format
msgid "'%s' is ready"
msgstr "Připraveno \"%s\""
#: ../src/shell-global.c:967
#: ../js/ui/workspacesView.js:229
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
msgstr ""
"Novou pracovní plochu nelze přidat, jelikož byl dosažen maximální počet "
"pracovních ploch."
#: ../js/ui/workspacesView.js:246
msgid "Can't remove the first workspace."
msgstr "Nelze odstranit první pracovní plochu."
#. 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 výstup"
msgstr[1] "%u výstupy"
msgstr[2] "%u výstupů"
#. 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 vstup"
msgstr[1] "%u vstupy"
msgstr[2] "%u vstupů"
#: ../src/gvc/gvc-mixer-control.c:1402
msgid "System Sounds"
msgstr "Systémové zvuky"
#: ../src/shell-global.c:1219
msgid "Less than a minute ago"
msgstr "Před méně než minutou"
#: ../src/shell-global.c:971
#: ../src/shell-global.c:1223
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
@ -231,7 +707,7 @@ msgstr[0] "Před %d minutou"
msgstr[1] "Před %d minutami"
msgstr[2] "Před %d minutami"
#: ../src/shell-global.c:976
#: ../src/shell-global.c:1228
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
@ -239,7 +715,7 @@ msgstr[0] "Před %d hodinou"
msgstr[1] "Před %d hodinami"
msgstr[2] "Před %d hodinami"
#: ../src/shell-global.c:981
#: ../src/shell-global.c:1233
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
@ -247,7 +723,7 @@ msgstr[0] "Před %d dnem"
msgstr[1] "Před %d dny"
msgstr[2] "Před %d dny"
#: ../src/shell-global.c:986
#: ../src/shell-global.c:1238
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
@ -279,38 +755,5 @@ msgstr "Hledat"
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Frequent"
#~ msgstr "Časté"
#~ msgid "More"
#~ msgstr "Více"
#~ msgid "(see all)"
#~ msgstr "(zobrazit vše)"
#~ msgid "PLACES"
#~ msgstr "MÍSTA"
#~ msgid "SEARCH RESULTS"
#~ msgstr "VÝSLEDKY HLEDÁNÍ"
#~ msgid "Unknown"
#~ msgstr "Neznámé"
#~ msgid "Can't lock screen: %s"
#~ msgstr "Nelze uzamknout obrazovku: %s"
#~ msgid "Can't temporarily set screensaver to blank screen: %s"
#~ msgstr "Šetřič obrazovky nelze dočasně nastavit na prázdnou obrazovku: %s"
#~ msgid "Can't logout: %s"
#~ msgstr "Nelze se odhlásit: %s"
#~ msgid "Browse"
#~ msgstr "Procházet"
#~ msgid "Manager"
#~ msgstr "Správce"
#~ msgid "The user manager object this user is controlled by."
#~ msgstr "Objekt správce uživatele, kterým je tento uživatel ovládán."
#~ msgid "Account Information..."
#~ msgstr "Informace o účtu..."

907
po/de.po

File diff suppressed because it is too large Load Diff

1025
po/el.po

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,15 @@
# British English translation for gnome-shell.
# Copyright (C) 2009 gnome-shell's COPYRIGHT HOLDER
# This file is distributed under the same license as the gnome-shell package.
# Philip Withnall <philip@tecnocode.co.uk>, 2009.
# Philip Withnall <philip@tecnocode.co.uk>, 2009, 2010.
# Bruce Cowan <bcowan@fastmail.co.uk>, 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-03-20 22:31+0000\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-08-31 09:25+0100\n"
"PO-Revision-Date: 2010-03-20 22:32+0100\n"
"Last-Translator: Bruce Cowan <bcowan@fastmail.co.uk>\n"
"Last-Translator: Philip Withnall <philip@tecnocode.co.uk>\n"
"Language-Team: British English <en@li.org>\n"
"Language: en_GB\n"
"MIME-Version: 1.0\n"
@ -27,32 +26,254 @@ msgstr "GNOME Shell"
msgid "Window management and application launching"
msgstr "Window management and application launching"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:1
msgid "Clock"
msgstr "Clock"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:2
msgid "Customize the panel clock"
msgstr "Customise the panel clock"
#: ../data/org.gnome.shell.gschema.xml.in.h:1
msgid ""
"Allows access to internal debugging and monitoring tools using the Alt-F2 "
"dialog."
msgstr ""
"Allows access to internal debugging and monitoring tools using the Alt+F2 "
"dialogue."
#: ../data/org.gnome.shell.gschema.xml.in.h:2
msgid "Custom format of the clock"
msgstr "Custom format of the clock"
#: ../data/org.gnome.shell.gschema.xml.in.h:3
msgid "Enable internal tools useful for developers and testers from Alt-F2"
msgstr "Enable internal tools useful for developers and testers from Alt+F2"
#: ../data/org.gnome.shell.gschema.xml.in.h:4
msgid "File extension used for storing the screencast"
msgstr "File extension used for storing the screencast"
#: ../data/org.gnome.shell.gschema.xml.in.h:5
msgid "Framerate used for recording screencasts."
msgstr "Framerate used for recording screencasts."
#: ../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 Shell extensions have a 'uuid' property; this key lists extensions which "
"should not be loaded."
#: ../data/org.gnome.shell.gschema.xml.in.h:7
msgid "History for command (Alt-F2) dialog"
msgstr "History for command (Alt+F2) dialogue"
#: ../data/org.gnome.shell.gschema.xml.in.h:8
msgid "Hour format"
msgstr "Hour format"
#: ../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 ""
"If true and format is either \"12-hour\" or \"24-hour\", display date in the "
"clock, in addition to time."
#: ../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 ""
"If true and format is either \"12-hour\" or \"24-hour\", display seconds in "
"time."
#: ../data/org.gnome.shell.gschema.xml.in.h:11
msgid "If true, display the ISO week date in the calendar."
msgstr "If true, display the ISO week date in the calendar."
#: ../data/org.gnome.shell.gschema.xml.in.h:12
msgid "List of desktop file IDs for favorite applications"
msgstr "List of desktop file IDs for favourite applications"
#: ../data/org.gnome.shell.gschema.xml.in.h:13
msgid "Overview workspace view mode"
msgstr "Overview workspace view mode"
#: ../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 ""
"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."
#: ../data/org.gnome.shell.gschema.xml.in.h:15
msgid "Show date in clock"
msgstr "Show date in clock"
#: ../data/org.gnome.shell.gschema.xml.in.h:16
msgid "Show the week date in the calendar"
msgstr "Show the week date in the calendar"
#: ../data/org.gnome.shell.gschema.xml.in.h:17
msgid "Show time with seconds"
msgstr "Show time with seconds"
#: ../data/org.gnome.shell.gschema.xml.in.h:18
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
msgstr ""
"The applications corresponding to these identifiers will be displayed in the "
"favourites area."
#: ../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 ""
"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."
#: ../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 ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames per second."
#: ../data/org.gnome.shell.gschema.xml.in.h:21
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "The GStreamer pipeline used to encode the 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 ""
"The selected workspace view mode in the overview. Supported values are "
"\"single\" and \"grid\"."
#: ../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 ""
"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 existing data."
#: ../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 ""
"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."
#: ../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 ""
"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."
#: ../data/org.gnome.shell.gschema.xml.in.h:26
msgid "Uuids of extensions to disable"
msgstr "UUIDs of extensions to disable"
#: ../data/org.gnome.shell.gschema.xml.in.h:27
msgid "Whether to collect stats about applications usage"
msgstr "Whether to collect statistics about application usage"
#: ../data/clock-preferences.ui.h:1
msgid "Clock Format"
msgstr "Clock Format"
#: ../data/clock-preferences.ui.h:2
msgid "Clock Preferences"
msgstr "Clock Preferences"
#: ../data/clock-preferences.ui.h:3
msgid "Panel Display"
msgstr "Panel Display"
#: ../data/clock-preferences.ui.h:4
msgid "Show seco_nds"
msgstr "Show seco_nds"
#: ../data/clock-preferences.ui.h:5
msgid "Show the _date"
msgstr "Show the _date"
#: ../data/clock-preferences.ui.h:6
msgid "_12 hour format"
msgstr "_12 hour format"
#: ../data/clock-preferences.ui.h:7
msgid "_24 hour format"
msgstr "_24 hour format"
#. **** Applications ****
#: ../js/ui/appDisplay.js:311 ../js/ui/dash.js:852
#: ../js/ui/appDisplay.js:384 ../js/ui/dash.js:778
msgid "APPLICATIONS"
msgstr "APPLICATIONS"
#: ../js/ui/appDisplay.js:343
#: ../js/ui/appDisplay.js:416
msgid "PREFERENCES"
msgstr "PREFERENCES"
#: ../js/ui/appDisplay.js:728
#: ../js/ui/appDisplay.js:721
msgid "New Window"
msgstr "New Window"
#: ../js/ui/appDisplay.js:732
#: ../js/ui/appDisplay.js:725
msgid "Remove from Favorites"
msgstr "Remove from Favourites"
#: ../js/ui/appDisplay.js:733
#: ../js/ui/appDisplay.js:726
msgid "Add to Favorites"
msgstr "Add to Favourites"
#: ../js/ui/appDisplay.js:1085
#: ../js/ui/appDisplay.js:1033
msgid "Drag here to add favorites"
msgstr "Drag here to add favourites"
#: ../js/ui/appFavorites.js:89
#: ../js/ui/appFavorites.js:88
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s has been added to your favourites."
@ -62,179 +283,234 @@ msgstr "%s has been added to your favourites."
msgid "%s has been removed from your favorites."
msgstr "%s has been removed from your favourites."
#: ../js/ui/dash.js:194
#: ../js/ui/dash.js:142
msgid "Find"
msgstr "Find"
#: ../js/ui/dash.js:507
#: ../js/ui/dash.js:473
msgid "Searching..."
msgstr "Searching…"
#: ../js/ui/dash.js:521
#: ../js/ui/dash.js:487
msgid "No matching results."
msgstr "No matching results."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:871 ../js/ui/placeDisplay.js:579
#: ../js/ui/dash.js:797 ../js/ui/placeDisplay.js:554
msgid "PLACES & DEVICES"
msgstr "PLACES & DEVICES"
#. **** Documents ****
#: ../js/ui/dash.js:878 ../js/ui/docDisplay.js:488
#: ../js/ui/dash.js:804 ../js/ui/docDisplay.js:494
msgid "RECENT ITEMS"
msgstr "RECENT ITEMS"
#: ../js/ui/lookingGlass.js:363
#: ../js/ui/lookingGlass.js:552
msgid "No extensions installed"
msgstr "No extensions installed"
#: ../js/ui/lookingGlass.js:400
#: ../js/ui/lookingGlass.js:589
msgid "Enabled"
msgstr "Enabled"
#: ../js/ui/lookingGlass.js:402
#: ../js/ui/lookingGlass.js:591
msgid "Disabled"
msgstr "Disabled"
#: ../js/ui/lookingGlass.js:404
#: ../js/ui/lookingGlass.js:593
msgid "Error"
msgstr "Error"
#: ../js/ui/lookingGlass.js:406
#: ../js/ui/lookingGlass.js:595
msgid "Out of date"
msgstr "Out of date"
#: ../js/ui/lookingGlass.js:431
#: ../js/ui/lookingGlass.js:620
msgid "View Source"
msgstr "View Source"
#: ../js/ui/lookingGlass.js:437
#: ../js/ui/lookingGlass.js:626
msgid "Web Page"
msgstr "Web Page"
#: ../js/ui/overview.js:182
#: ../js/ui/overview.js:160
msgid "Undo"
msgstr "Undo"
#. 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:385
msgid "Activities"
msgstr "Activities"
#. TODO - _quit() doesn't really work on apps in state STARTING yet
#: ../js/ui/panel.js:473
#, c-format
msgid "Quit %s"
msgstr "Quit %s"
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:616
#: ../js/ui/panel.js:498
msgid "Preferences"
msgstr "Preferences"
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:584
msgid "%a %b %e, %R:%S"
msgstr "%a %e %b, %R:%S"
#: ../js/ui/panel.js:585
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:589
msgid "%a %R:%S"
msgstr "%a %R:%S"
#: ../js/ui/panel.js:590
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:619
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:597
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a %e %b, %l:%M:%S %p"
#: ../js/ui/panel.js:598
msgid "%a %b %e, %l:%M %p"
msgstr "%a %e %b, %l:%M %p"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:602
msgid "%a %l:%M:%S %p"
msgstr "%a %l:%M:%S %p"
#: ../js/ui/panel.js:603
msgid "%a %l:%M %p"
msgstr "%a %l:%M %p"
#: ../js/ui/placeDisplay.js:103
#. 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:748
msgid "Activities"
msgstr "Activities"
#: ../js/ui/placeDisplay.js:111
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Failed to unmount '%s'"
#: ../js/ui/placeDisplay.js:106
#: ../js/ui/placeDisplay.js:114
msgid "Retry"
msgstr "Retry"
#: ../js/ui/placeDisplay.js:151
#: ../js/ui/placeDisplay.js:159
msgid "Connect to..."
msgstr "Connect to…"
#: ../js/ui/runDialog.js:232
#. 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 "ON"
#: ../js/ui/popupMenu.js:31 ../js/ui/popupMenu.js:45
msgid "OFF"
msgstr "OFF"
#: ../js/ui/runDialog.js:233
msgid "Please enter a command:"
msgstr "Please enter a command:"
#: ../js/ui/runDialog.js:374
#: ../js/ui/runDialog.js:378
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Execution of '%s' failed:"
#: ../js/ui/statusMenu.js:107
#: ../js/ui/statusMenu.js:91
msgid "Available"
msgstr "Available"
#: ../js/ui/statusMenu.js:112
#: ../js/ui/statusMenu.js:95
msgid "Busy"
msgstr "Busy"
#: ../js/ui/statusMenu.js:117
#: ../js/ui/statusMenu.js:99
msgid "Invisible"
msgstr "Invisible"
#: ../js/ui/statusMenu.js:126
#: ../js/ui/statusMenu.js:106
msgid "Account Information..."
msgstr "Account Information…"
#: ../js/ui/statusMenu.js:132
msgid "Sidebar"
msgstr "Sidebar"
#: ../js/ui/statusMenu.js:142
#: ../js/ui/statusMenu.js:110
msgid "System Preferences..."
msgstr "System Preferences…"
#: ../js/ui/statusMenu.js:151
#: ../js/ui/statusMenu.js:117
msgid "Lock Screen"
msgstr "Lock Screen"
#: ../js/ui/statusMenu.js:156
#: ../js/ui/statusMenu.js:121
msgid "Switch User"
msgstr "Switch User"
#: ../js/ui/statusMenu.js:162
#: ../js/ui/statusMenu.js:126
msgid "Log Out..."
msgstr "Log Out…"
#: ../js/ui/statusMenu.js:167
#: ../js/ui/statusMenu.js:130
msgid "Shut Down..."
msgstr "Shut Down…"
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%H:%M"
#: ../js/ui/windowAttentionHandler.js:43
#, c-format
msgid "%s has finished starting"
msgstr "%s has finished starting"
#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "Applications"
#: ../js/ui/windowAttentionHandler.js:45
#, c-format
msgid "'%s' is ready"
msgstr "'%s' is ready"
#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "Recent Documents"
#: ../js/ui/workspacesView.js:230
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
msgstr ""
"Can't add a new workspace because maximum workspaces limit has been reached."
#: ../src/shell-global.c:967
#: ../js/ui/workspacesView.js:247
msgid "Can't remove the first workspace."
msgstr "Can't remove the first workspace."
#: ../src/shell-global.c:1105
msgid "Less than a minute ago"
msgstr "Less than a minute ago"
#: ../src/shell-global.c:971
#: ../src/shell-global.c:1109
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d minute ago"
msgstr[1] "%d minutes ago"
#: ../src/shell-global.c:976
#: ../src/shell-global.c:1114
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d hour ago"
msgstr[1] "%d hours ago"
#: ../src/shell-global.c:981
#: ../src/shell-global.c:1119
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d day ago"
msgstr[1] "%d days ago"
#: ../src/shell-global.c:986
#: ../src/shell-global.c:1124
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
@ -265,6 +541,18 @@ msgstr "Search"
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Sidebar"
#~ msgstr "Sidebar"
#~ msgid "%H:%M"
#~ msgstr "%H:%M"
#~ msgid "Applications"
#~ msgstr "Applications"
#~ msgid "Recent Documents"
#~ msgstr "Recent Documents"
#~ msgid "Browse"
#~ msgstr "Browse"

1021
po/es.po

File diff suppressed because it is too large Load Diff

825
po/et.po Normal file
View File

@ -0,0 +1,825 @@
# GNOME kesta eesti keele tõlge.
# Estonian translation for gnome-shell.
#
# 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, 2011.
# Ivar Smolin <okul linux ee>, 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: 2011-01-21 18:46+0000\n"
"PO-Revision-Date: 2011-01-24 08:04+0200\n"
"Last-Translator: Ivar Smolin <okul@linux.ee>\n"
"Language-Team: Estonian <gnome-et@linux.ee>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: et\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-Language: Estonian\n"
"X-Poedit-Country: Estonia\n"
msgid "GNOME Shell"
msgstr "GNOME kest"
msgid "Window management and application launching"
msgstr "Aknahaldur ja rakenduste käivitaja"
msgid ""
"Allows access to internal debugging and monitoring tools using the Alt-F2 "
"dialog."
msgstr ""
"Lubab ligipääsu sisemistele silumise ja monitoorimise tööriistadele Alt-F2 "
"dialoogi kaudu."
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 "Ekraanivideo salvestamisel kasutatav faililaiend"
msgid "Framerate used for recording screencasts."
msgstr "Ekraanivideo lindistamisel kasutatav kaadrikiirus."
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 "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, 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 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"
#, 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 "
"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 ! 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 kuupäeva nädalavormingus"
msgid "Show time with seconds"
msgstr "Kellaaega näidatakse sekunditega"
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
msgstr ""
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 ""
"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 "
"screencast recorder in frames-per-second."
msgstr ""
msgid "The gstreamer pipeline used to encode the screencast"
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 "
"want to disable this for privacy reasons. Please note that doing so won't "
"remove already saved data."
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"
msgid "Color of the crosshairs"
msgstr "Niitristi värvus"
msgid ""
"Determines the length of the vertical and horizontal lines that make up the "
"crosshairs."
msgstr ""
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 ""
msgid ""
"Determines the transparency of the crosshairs, from fully opaque to fully "
"transparent."
msgstr ""
"Määrab niitristi läbipaistvuse, alates täiesti läbipaistmatust kuni täiesti "
"läbipaistvani."
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 ""
"Määrab, kas niitrist kattub suurendatud hiire pildiga või on keskelt ära "
"lõigatud nii, et jooned ümbritsevad hiirekursori pilti."
msgid "Enable lens mode"
msgstr "Läätsede režiimi lubamine"
msgid ""
"Enables/disables display of crosshairs centered on the magnified mouse "
"sprite."
msgstr "Lubab/keelab niitristi kuvamise suurendatud hiirekursori kohal."
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 ""
msgid "Length of the crosshairs"
msgstr "Niitristi pikkus"
msgid "Magnification factor"
msgstr "Suurendustegur"
msgid "Mouse Tracking Mode"
msgstr "Hiire jälitamise režiim"
msgid "Opacity of the crosshairs"
msgstr "Niitristi läbipaistvus"
msgid "Screen position"
msgstr "Ekraani asukoht"
msgid "Scroll magnified contents beyond the edges of the desktop"
msgstr "Suurendusklaas võib liikuda töölauapiiridest väljapoole"
msgid "Show or hide crosshairs"
msgstr "Niitristi kuvamine või peitmine"
msgid "Show or hide the magnifier"
msgstr "Suurendusklaasi kuvamine või peitmine"
msgid "Show or hide the magnifier and all of its zoom regions."
msgstr ""
"Suurendusklaasi ja selle kõigi suurenduspiirkondade kuvamine või peitmine."
msgid ""
"The color of the the vertical and horizontal lines that make up the "
"crosshairs."
msgstr "Niitristi püst- ja rõhtjoone värvus."
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 ""
"Suurendatud vaade täidab kas kogu ekraani või täidab ülemise, alumise, "
"vasaku või parema ekraanipoole."
msgid ""
"The power of the magnification. A value of 1.0 means no magnification. A "
"value of 2.0 doubles the size."
msgstr "Suurendustegur. 1,0 tähendab originaalsuurust. 2,0 muudab kaks korda."
msgid "Thickness of the crosshairs"
msgstr "Niitristi paksus"
msgid ""
"Whether the magnified view should be centered over the location of the "
"system mouse and move with it."
msgstr ""
"Kas suurendatud vaate keskkoht peaks asetsema süsteemi hiire kohal ning "
"liikuma sellega kaasa."
msgid "Width of the vertical and horizontal lines that make up the crosshairs."
msgstr "Niitristi moodustavate püst- ja rõhtjoone laius"
#. Replace "Error invoking GLib.shell_parse_argv: " with
#. something nicer
msgid "Could not parse command:"
msgstr "Käsku pole võimalik analüüsida:"
msgid "No such application"
msgstr "Sellist rakendust ei ole"
#, c-format
msgid "Execution of '%s' failed:"
msgstr "'%s' käivitamine nurjus:"
#. Translators: Filter to display all applications
msgid "All"
msgstr "Kõik"
msgid "APPLICATIONS"
msgstr "Rakendused"
msgid "PREFERENCES"
msgstr "Eelistused"
msgid "New Window"
msgstr "Uus aken"
msgid "Remove from Favorites"
msgstr "Eemalda lemmikutest"
msgid "Add to Favorites"
msgstr "Lisa lemmikutesse"
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s lisati lemmikutesse."
#, c-format
msgid "%s has been removed from your favorites."
msgstr "%s eemaldati lemmikutest."
msgid "Remove"
msgstr "Eemalda"
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 "Seiska"
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 "Süsteem seisatakse automaatselt %d sekundi pärast."
msgid "Shutting down the system."
msgstr "Süsteemi seiskamine."
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"
msgid "Error"
msgstr "Viga"
msgid "Out of date"
msgstr "Pole värske"
msgid "View Source"
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"
#. Translators: This is the time format with date used
#. in 24-hour mode.
msgid "%a %b %e, %R:%S"
msgstr "%a, %e. %b, %R:%S"
msgid "%a %b %e, %R"
msgstr "%a, %e. %b, %R"
#. Translators: This is the time format without date used
#. in 24-hour mode.
msgid "%a %R:%S"
msgstr "%A %R:%S"
msgid "%a %R"
msgstr "%A %R"
#. Translators: This is a time format with date used
#. for AM/PM.
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a, %e. %b, %l:%M:%S %p"
msgid "%a %b %e, %l:%M %p"
msgstr "%a, %e. %b, %l:%M %p"
#. Translators: This is a time format without date used
#. for AM/PM.
msgid "%a %l:%M:%S %p"
msgstr "%A, %l:%M:%S %p"
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".
msgid "Activities"
msgstr "Tegevused"
#, c-format
msgid "Failed to unmount '%s'"
msgstr "'%s' lahtihaakimine nurjus"
msgid "Retry"
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
#. switches containing "◯" and "|"). Other values will
#. simply result in invisible toggle switches.
msgid "toggle-switch-us"
msgstr "toggle-switch-intl"
msgid "Please enter a command:"
msgstr "Palun sisesta käsk:"
msgid "Available"
msgstr "Saadaval"
msgid "Busy"
msgstr "Hõivatud"
msgid "My Account"
msgstr "Minu konto"
msgid "System Settings"
msgstr "Süsteemi sätted"
msgid "Lock Screen"
msgstr "Lukusta ekraan"
msgid "Switch User"
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"
#, c-format
msgid "'%s' is ready"
msgstr "'%s' on valmis"
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
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"
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d minut tagasi"
msgstr[1] "%d minutit tagasi"
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d tund tagasi"
msgstr[1] "%d tundi tagasi"
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d päev tagasi"
msgstr[1] "%d päeva tagasi"
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d nädal tagasi"
msgstr[1] "%d nädalat tagasi"
msgid "Home Folder"
msgstr "Kodukaust"
#. Translators: this is the same string as the one found in
#. * nautilus
msgid "File System"
msgstr "Failisüsteem"
msgid "Search"
msgstr "Otsing"
#. 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.
#.
#, 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 "اطلاعات جساب"

343
po/fr.po
View File

@ -11,8 +11,8 @@ msgstr ""
"Project-Id-Version: gnome-shell master fr\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&component=general\n"
"POT-Creation-Date: 2010-05-15 22:41+0000\n"
"PO-Revision-Date: 2010-03-09 22:55+0100\n"
"POT-Creation-Date: 2010-09-22 15:13+0000\n"
"PO-Revision-Date: 2010-09-05 21:03+0200\n"
"Last-Translator: Claude Paroz <claude@2xlibre.net>\n"
"Language-Team: GNOME French Team <gnomefr@traduc.org>\n"
"MIME-Version: 1.0\n"
@ -36,18 +36,215 @@ msgstr "Horloge"
msgid "Customize the panel clock"
msgstr "Personnaliser l'horloge du tableau de bord"
#: ../data/org.gnome.shell.gschema.xml.in.h:1
msgid ""
"Allows access to internal debugging and monitoring tools using the Alt-F2 "
"dialog."
msgstr ""
"Autoriser l'accès aux outils internes de débogage et de surveillance grâce à "
"la boîte de dialogue de lancement d'application (Alt-F2)."
#: ../data/org.gnome.shell.gschema.xml.in.h:2
msgid "Custom format of the clock"
msgstr "Format personnalisé de l'horloge"
#: ../data/org.gnome.shell.gschema.xml.in.h:3
msgid "Enable internal tools useful for developers and testers from Alt-F2"
msgstr ""
"Activer les outils internes pour les développeurs et les testeurs depuis Alt-"
"F2"
#: ../data/org.gnome.shell.gschema.xml.in.h:4
msgid "File extension used for storing the screencast"
msgstr "Extension de fichier à utiliser pour enregistrer l'animation d'écran"
#: ../data/org.gnome.shell.gschema.xml.in.h:5
msgid "Framerate used for recording screencasts."
msgstr ""
"Nombre d'images par seconde pour l'enregistrement des animations d'écran."
#: ../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 ""
"Les extensions GNOME Shell ont une propriété uuid ; cette clé énumère les "
"extensions qui ne doivent pas être chargées."
#: ../data/org.gnome.shell.gschema.xml.in.h:7
msgid "History for command (Alt-F2) dialog"
msgstr "Historique de la boîte de dialogue des commandes (Alt-F2)"
#: ../data/org.gnome.shell.gschema.xml.in.h:8
msgid "Hour format"
msgstr "Mode d'affichage de l'heure"
#: ../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 ""
"Si vrai (case cochée) et que le mode d'affichage de l'heure est « 12 heures » "
"ou « 24 heures », la date est affichée dans l'horloge, en plus de l'heure."
#: ../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 ""
"Si vrai (case cochée) et que le mode d'affichage de l'heure est « 12 heures » "
"ou « 24 heures », les secondes sont affichées avec l'heure."
#: ../data/org.gnome.shell.gschema.xml.in.h:11
msgid "If true, display the ISO week date in the calendar."
msgstr ""
"Si vrai (case cochée), le calendrier utilise la numérotation ISO des "
"semaines."
#: ../data/org.gnome.shell.gschema.xml.in.h:12
msgid "List of desktop file IDs for favorite applications"
msgstr ""
"Liste d'identifiants de fichiers desktop pour les applications favorites"
#: ../data/org.gnome.shell.gschema.xml.in.h:13
msgid "Overview workspace view mode"
msgstr "Mode d'aperçu des espaces de travail"
#: ../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 ""
"Définition du pipeline GStreamer utilisé pour coder les enregistrements "
"vidéo. La syntaxe est identique à celle de gst-launch. Le connecteur "
"d'entrée (sink pad) du pipeline devrait être non connecté là où la vidéo est "
"enregistrée. Le connecteur source devrait normalement être non connecté ; la "
"sortie de ce connecteur est écrite dans le fichier de sortie. Cependant, le "
"pipeline peut aussi se charger de sa propre sortie, par exemple pour diriger "
"la sortie vers un serveur icecast via shout2send ou autre. Si cette clé "
"n'est pas définie ou si elle est vide, c'est le pipeline par défaut qui est "
"utilisé. Celui-ci est actuellement « videorate ! theoraenc ! oggmux » et "
"l'enregistrement utilise le format Ogg Theora."
#: ../data/org.gnome.shell.gschema.xml.in.h:15
msgid "Show date in clock"
msgstr "Afficher la date dans l'horloge"
#: ../data/org.gnome.shell.gschema.xml.in.h:16
msgid "Show the week date in the calendar"
msgstr "Afficher la numérotation des semaines dans le calendrier"
#: ../data/org.gnome.shell.gschema.xml.in.h:17
msgid "Show time with seconds"
msgstr "Afficher l'heure avec les secondes"
#: ../data/org.gnome.shell.gschema.xml.in.h:18
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
msgstr ""
"Les applications correspondant à ces identifiants sont affichées dans la "
"zone des favoris."
#: ../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 ""
"Le nom de fichier des animations d'écran est unique, se base sur la date, et "
"utilise cette extension. Elle devrait être modifiée si le format du "
"conteneur utilisé pour l'enregistrement est différent."
#: ../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 ""
"Le nombre d'images par seconde des animations d'écran enregistrées par "
"l'outil idoine de GNOME Shell."
#: ../data/org.gnome.shell.gschema.xml.in.h:21
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "Le pipeline gstreamer utilisé pour coder l'animation d'écran"
#: ../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 ""
"Le mode d'aperçu des espaces de travail. Les valeurs prises en charge sont : "
 single » (unique) et « grid » (grille)."
#: ../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 ""
"GNOME Shell surveille normalement les applications actives afin de "
"déterminer les plus utilisées (par ex. pour les lanceurs). Bien que ces "
"données sont gardées secrètes, des motifs de confidentialité peuvent vous "
"pousser à désactiver cette fonctionnalité. Remarquez que cette désactivation "
"ne supprime pas d'éventuelles données déjà enregistrées."
#: ../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 ""
"Cette clé définit le format utilisé par l'horloge du tableau de bord quand "
"le format de l'heure est « custom » (personnalisé). Vous pouvez utiliser des "
"indicateurs de conversion que strftime() comprend afin d'obtenir un format "
"particulier. Consultez le manuel de strftime() pour plus d'informations."
#: ../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 ""
"Cette clé définit le format de l'heure utilisé par l'horloge du tableau de "
"bord. Les valeurs possibles sont « 12-hour » (12 heures), « 24-hour » (24 "
"heures), « unix » et « custom » (personnalisé). Si vous choisissez « unix », "
"l'horloge affiche l'heure en secondes depuis Epoch, c'est-à-dire le "
"01/01/1970. Si vous choisissez « custom », l'horloge affiche la date et "
"l'heure selon le format défini dans la clé « custom_format ». Remarquez que "
"si vous choisissez « unix » ou « custom », les clés « show_date » et "
 show_seconds » seront ignorées."
#: ../data/org.gnome.shell.gschema.xml.in.h:26
msgid "Uuids of extensions to disable"
msgstr "Identifiants UUID des extensions à désactiver"
#: ../data/org.gnome.shell.gschema.xml.in.h:27
msgid "Whether to collect stats about applications usage"
msgstr "Collecter des statistiques sur l'utilisation des applications"
#: ../data/clock-preferences.ui.h:1
msgid "Clock Format"
msgstr "Format de l'horloge"
#: ../data/clock-preferences.ui.h:2
msgid "Panel Display"
msgstr "Affichage dans le tableau de bord"
#: ../data/clock-preferences.ui.h:3
msgid "Clock Preferences"
msgstr "Préférences de l'horloge"
#: ../data/clock-preferences.ui.h:3
msgid "Panel Display"
msgstr "Affichage dans le tableau de bord"
#: ../data/clock-preferences.ui.h:4
msgid "Show seco_nds"
msgstr "Afficher les _secondes"
@ -65,31 +262,31 @@ msgid "_24 hour format"
msgstr "Format _24 heures"
#. **** Applications ****
#: ../js/ui/appDisplay.js:306 ../js/ui/dash.js:850
#: ../js/ui/appDisplay.js:316 ../js/ui/dash.js:778
msgid "APPLICATIONS"
msgstr "APPLICATIONS"
#: ../js/ui/appDisplay.js:338
#: ../js/ui/appDisplay.js:348
msgid "PREFERENCES"
msgstr "PRÉFÉRENCES"
#: ../js/ui/appDisplay.js:705
#: ../js/ui/appDisplay.js:653
msgid "New Window"
msgstr "Nouvelle fenêtre"
#: ../js/ui/appDisplay.js:709
#: ../js/ui/appDisplay.js:657
msgid "Remove from Favorites"
msgstr "Enlever des favoris"
#: ../js/ui/appDisplay.js:710
#: ../js/ui/appDisplay.js:658
msgid "Add to Favorites"
msgstr "Ajouter aux favoris"
#: ../js/ui/appDisplay.js:1037
#: ../js/ui/appDisplay.js:986
msgid "Drag here to add favorites"
msgstr "Glisser ici pour ajouter aux favoris"
#: ../js/ui/appFavorites.js:89
#: ../js/ui/appFavorites.js:88
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s a été ajouté à vos favoris."
@ -99,217 +296,232 @@ msgstr "%s a été ajouté à vos favoris."
msgid "%s has been removed from your favorites."
msgstr "%s a été supprimé de vos favoris."
#: ../js/ui/dash.js:189
#: ../js/ui/dash.js:142
msgid "Find"
msgstr "Rechercher"
#: ../js/ui/dash.js:505
#: ../js/ui/dash.js:473
msgid "Searching..."
msgstr "Recherche en cours..."
#: ../js/ui/dash.js:519
#: ../js/ui/dash.js:487
msgid "No matching results."
msgstr "Aucun résultat correspondant."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:869 ../js/ui/placeDisplay.js:543
#: ../js/ui/dash.js:797 ../js/ui/placeDisplay.js:554
msgid "PLACES & DEVICES"
msgstr "RACCOURCIS et PÉRIPHÉRIQUES"
#. **** Documents ****
#: ../js/ui/dash.js:876 ../js/ui/docDisplay.js:489
#: ../js/ui/dash.js:804 ../js/ui/docDisplay.js:494
msgid "RECENT ITEMS"
msgstr "ÉLÉMENTS RÉCENTS"
#: ../js/ui/lookingGlass.js:354
#: ../js/ui/lookingGlass.js:552
msgid "No extensions installed"
msgstr "Aucune extension installée"
#: ../js/ui/lookingGlass.js:391
#: ../js/ui/lookingGlass.js:589
msgid "Enabled"
msgstr "Activé"
#: ../js/ui/lookingGlass.js:393
#: ../js/ui/lookingGlass.js:591
msgid "Disabled"
msgstr "Désactivé"
#: ../js/ui/lookingGlass.js:395
#: ../js/ui/lookingGlass.js:593
msgid "Error"
msgstr "Erreur"
#: ../js/ui/lookingGlass.js:397
#: ../js/ui/lookingGlass.js:595
msgid "Out of date"
msgstr "Périmé"
#: ../js/ui/lookingGlass.js:422
#: ../js/ui/lookingGlass.js:620
msgid "View Source"
msgstr "Afficher la source"
#: ../js/ui/lookingGlass.js:428
#: ../js/ui/lookingGlass.js:626
msgid "Web Page"
msgstr "Page Web"
#: ../js/ui/overview.js:161
#: ../js/ui/overview.js:160
msgid "Undo"
msgstr "Annuler"
#: ../js/ui/panel.js:535
msgid "Quit"
msgstr "Quitter"
#. TODO - _quit() doesn't really work on apps in state STARTING yet
#: ../js/ui/panel.js:467
#, c-format
msgid "Quit %s"
msgstr "Quitter %s"
#. 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:740
msgid "Activities"
msgstr "Activités"
#: ../js/ui/panel.js:492
msgid "Preferences"
msgstr "Préférences"
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:955
#: ../js/ui/panel.js:578
msgid "%a %b %e, %R:%S"
msgstr "%a %e %b, %R:%S"
#: ../js/ui/panel.js:956
#: ../js/ui/panel.js:579
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:960
#: ../js/ui/panel.js:583
msgid "%a %R:%S"
msgstr "%a %R:%S"
#: ../js/ui/panel.js:961
#: ../js/ui/panel.js:584
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:968
#: ../js/ui/panel.js:591
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a %e %b, %l:%M:%S %p"
#: ../js/ui/panel.js:969
#: ../js/ui/panel.js:592
msgid "%a %b %e, %l:%M %p"
msgstr "%a %e %b, %l:%M %p"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:973
#: ../js/ui/panel.js:596
msgid "%a %l:%M:%S %p"
msgstr "%a %l:%M:%S %p"
#: ../js/ui/panel.js:974
#: ../js/ui/panel.js:597
msgid "%a %l:%M %p"
msgstr "%a %l:%M %p"
#: ../js/ui/placeDisplay.js:108
#. 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:742
msgid "Activities"
msgstr "Activités"
#: ../js/ui/placeDisplay.js:111
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Impossible de monter « %s »"
#: ../js/ui/placeDisplay.js:111
#: ../js/ui/placeDisplay.js:114
msgid "Retry"
msgstr "Réessayer"
#: ../js/ui/placeDisplay.js:156
#: ../js/ui/placeDisplay.js:159
msgid "Connect to..."
msgstr "Connexion à..."
#: ../js/ui/runDialog.js:231
#. 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:32
msgid "toggle-switch-us"
msgstr "toggle-switch-intl"
#: ../js/ui/runDialog.js:233
msgid "Please enter a command:"
msgstr "Veuillez saisir une commande :"
#: ../js/ui/runDialog.js:375
#: ../js/ui/runDialog.js:378
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Exécution de « %s » impossible :"
#: ../js/ui/statusMenu.js:90
#: ../js/ui/statusMenu.js:91
msgid "Available"
msgstr "Disponible"
#: ../js/ui/statusMenu.js:94
#: ../js/ui/statusMenu.js:95
msgid "Busy"
msgstr "Occupé"
#: ../js/ui/statusMenu.js:98
#: ../js/ui/statusMenu.js:99
msgid "Invisible"
msgstr "Invisible"
#: ../js/ui/statusMenu.js:105
#: ../js/ui/statusMenu.js:106
msgid "Account Information..."
msgstr "Informations personnelles..."
#: ../js/ui/statusMenu.js:109
#: ../js/ui/statusMenu.js:110
msgid "System Preferences..."
msgstr "Préférences du système..."
#: ../js/ui/statusMenu.js:116
#: ../js/ui/statusMenu.js:117
msgid "Lock Screen"
msgstr "Verrouiller l'écran"
#: ../js/ui/statusMenu.js:120
#: ../js/ui/statusMenu.js:121
msgid "Switch User"
msgstr "Changer d'utilisateur"
#: ../js/ui/statusMenu.js:125
#: ../js/ui/statusMenu.js:126
msgid "Log Out..."
msgstr "Fermer la session..."
#: ../js/ui/statusMenu.js:129
#: ../js/ui/statusMenu.js:130
msgid "Shut Down..."
msgstr "Éteindre..."
#: ../js/ui/windowAttentionHandler.js:47
#: ../js/ui/windowAttentionHandler.js:43
#, c-format
msgid "%s has finished starting"
msgstr "Lancement de %s terminé"
#: ../js/ui/windowAttentionHandler.js:49
#: ../js/ui/windowAttentionHandler.js:45
#, c-format
msgid "'%s' is ready"
msgstr "« %s » est prêt"
#: ../js/ui/workspacesView.js:239
#: ../js/ui/workspacesView.js:230
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
msgstr ""
"Impossible d'ajouter un espace de travail car le nombre maximum d'espaces de "
"travail est atteint."
#: ../js/ui/workspacesView.js:256
#: ../js/ui/workspacesView.js:247
msgid "Can't remove the first workspace."
msgstr "Impossible de supprimer le premier espace de travail."
#: ../src/shell-global.c:979
#: ../src/shell-global.c:1189
msgid "Less than a minute ago"
msgstr "Il y a moins d'une minute"
#: ../src/shell-global.c:983
#: ../src/shell-global.c:1193
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "Il y a %d minute"
msgstr[1] "Il y a %d minutes"
#: ../src/shell-global.c:988
#: ../src/shell-global.c:1198
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "Il y a %d heure"
msgstr[1] "Il y a %d heures"
#: ../src/shell-global.c:993
#: ../src/shell-global.c:1203
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "Il y a %d jour"
msgstr[1] "Il y a %d jours"
#: ../src/shell-global.c:998
#: ../src/shell-global.c:1208
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
@ -339,3 +551,4 @@ msgstr "Recherche"
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s : %2$s"

1045
po/gl.po

File diff suppressed because it is too large Load Diff

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